Marshalling a Callback with BOOL parameter

M

markb

Hi

My C# app is being called from a callback from an unmanaged DLL. One of
the parameters of the callback is of type BOOL. I am using PInvoke to
marshal this to a (managed) bool. The problem is that no matter if we
pass TRUE or FALSE, the bool is always marshalled as true.

// unmanaged code in dll

typedef bool (__stdcall *BoolCallBack)(short b);

extern "C" BOOL __declspec(dllexport) __stdcall
BoolCallback(BoolCallBack lpBoolCallBack, BOOL b)
{
return lpBoolCallBack(b);
}

// c#
private delegate bool BoolCallbackDelegate(bool b);

[DllImport("UnmanagedDll")]
private static extern bool BoolCallback(BoolCallbackDelegate
lpBoolCallBack, bool b);

private static bool BoolCallbackDelgate(bool b)
{
return b;
}

static void Main(string[] args)
{
bool b = BoolCallback(BoolCallbackDelgate, true);
Debug.Assert(b == true);

b = BoolCallback(BoolCallbackDelgate, false);
Debug.Assert(b == false);
}

The second Assert alwasys asserts because the callback is returning
true when it should be false.

I think that this is a bug somewhere in c#/clr/PInkove because this
doesnt happen in c++ clr. I think it was fixed for c++ clr under this
kb article http://support.microsoft.com/default.aspx?kbid=823071 but
not fixed for c#.

Any thoughts?

Mark
 
W

Willy Denoyette [MVP]

| Hi
|
| My C# app is being called from a callback from an unmanaged DLL. One of
| the parameters of the callback is of type BOOL. I am using PInvoke to
| marshal this to a (managed) bool. The problem is that no matter if we
| pass TRUE or FALSE, the bool is always marshalled as true.
|
| // unmanaged code in dll
|
| typedef bool (__stdcall *BoolCallBack)(short b);
|
| extern "C" BOOL __declspec(dllexport) __stdcall
| BoolCallback(BoolCallBack lpBoolCallBack, BOOL b)
| {
| return lpBoolCallBack(b);
| }
|
| // c#
| private delegate bool BoolCallbackDelegate(bool b);
|
| [DllImport("UnmanagedDll")]
| private static extern bool BoolCallback(BoolCallbackDelegate
| lpBoolCallBack, bool b);
|
| private static bool BoolCallbackDelgate(bool b)
| {
| return b;
| }
|
| static void Main(string[] args)
| {
| bool b = BoolCallback(BoolCallbackDelgate, true);
| Debug.Assert(b == true);
|
| b = BoolCallback(BoolCallbackDelgate, false);
| Debug.Assert(b == false);
| }
|
| The second Assert alwasys asserts because the callback is returning
| true when it should be false.
|
| I think that this is a bug somewhere in c#/clr/PInkove because this
| doesnt happen in c++ clr. I think it was fixed for c++ clr under this
| kb article http://support.microsoft.com/default.aspx?kbid=823071 but
| not fixed for c#.
|
| Any thoughts?
|
| Mark
|
A BOOL is a typedef'd DWORD in C or an int, while a 'bool' is a single byte
in C# (and C++)
So you need to declare the return as int or you need to tag the return like
this:

[DllImport("UnmanagedDll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool BoolCallback(BoolCallbackDelegate

Willy.
 
M

markb

Willy said:
| Hi
|
| My C# app is being called from a callback from an unmanaged DLL. One of
| the parameters of the callback is of type BOOL. I am using PInvoke to
| marshal this to a (managed) bool. The problem is that no matter if we
| pass TRUE or FALSE, the bool is always marshalled as true.
|
| // unmanaged code in dll
|
| typedef bool (__stdcall *BoolCallBack)(short b);
|
| extern "C" BOOL __declspec(dllexport) __stdcall
| BoolCallback(BoolCallBack lpBoolCallBack, BOOL b)
| {
| return lpBoolCallBack(b);
| }
|
| // c#
| private delegate bool BoolCallbackDelegate(bool b);
|
| [DllImport("UnmanagedDll")]
| private static extern bool BoolCallback(BoolCallbackDelegate
| lpBoolCallBack, bool b);
|
| private static bool BoolCallbackDelgate(bool b)
| {
| return b;
| }
|
| static void Main(string[] args)
| {
| bool b = BoolCallback(BoolCallbackDelgate, true);
| Debug.Assert(b == true);
|
| b = BoolCallback(BoolCallbackDelgate, false);
| Debug.Assert(b == false);
| }
|
| The second Assert alwasys asserts because the callback is returning
| true when it should be false.
|
| I think that this is a bug somewhere in c#/clr/PInkove because this
| doesnt happen in c++ clr. I think it was fixed for c++ clr under this
| kb article http://support.microsoft.com/default.aspx?kbid=823071 but
| not fixed for c#.
|
| Any thoughts?
|
| Mark
|
A BOOL is a typedef'd DWORD in C or an int, while a 'bool' is a single byte
in C# (and C++)
So you need to declare the return as int or you need to tag the return like
this:

[DllImport("UnmanagedDll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool BoolCallback(BoolCallbackDelegate

Willy.

Thanks for your reply Willy

Perhaps my example was unclear. The problem does not lie with passing
the bool to the unmanaged dll nor does it lie with with the return from
the unmanaged dll, it lies with the unmanaged dll calling a managed
callback with a BOOL as a parameter. (FYI it doesn't matter if you use
a c++ bool, a char, DWORD or whatever - the problem is still the same)

If you step through the code, the unmanaged dll, cleary calls the
callback with TRUE but it appears as false in the csharp code. Even
changing the delegate prototype to the following does not solve the
problem:

private static extern bool BoolCallback(BoolCallbackDelegate
lpBoolCallBack,[MarshalAs(UnmanagedType.Bool)]bool b);

The c++ clr version (below) of my csharp example works so it looks like
a problem with csharp?!?

ref class Program
{
private:
delegate bool BoolCallbackDelgate(bool b);

static bool GetBool(bool b)
{
return b;
}

public:
static void Main()
{
BoolCallbackDelgate^ fp = gcnew BoolCallbackDelgate(GetBool);
GCHandle gch = GCHandle::Alloc(fp);
IntPtr ip = Marshal::GetFunctionPointerForDelegate(fp);
BoolCallBack cb = static_cast<BoolCallBack>(ip.ToPointer());


bool b = BoolCallback(cb, true);
Debug::Assert(b == true);

b = BoolCallback(cb, false);
Debug::Assert(b == false);
}
};

Mark
 
W

Willy Denoyette [MVP]

markb said:
Willy said:
| Hi
|
| My C# app is being called from a callback from an unmanaged DLL. One of
| the parameters of the callback is of type BOOL. I am using PInvoke to
| marshal this to a (managed) bool. The problem is that no matter if we
| pass TRUE or FALSE, the bool is always marshalled as true.
|
| // unmanaged code in dll
|
| typedef bool (__stdcall *BoolCallBack)(short b);
|
| extern "C" BOOL __declspec(dllexport) __stdcall
| BoolCallback(BoolCallBack lpBoolCallBack, BOOL b)
| {
| return lpBoolCallBack(b);
| }
|
| // c#
| private delegate bool BoolCallbackDelegate(bool b);
|
| [DllImport("UnmanagedDll")]
| private static extern bool BoolCallback(BoolCallbackDelegate
| lpBoolCallBack, bool b);
|
| private static bool BoolCallbackDelgate(bool b)
| {
| return b;
| }
|
| static void Main(string[] args)
| {
| bool b = BoolCallback(BoolCallbackDelgate, true);
| Debug.Assert(b == true);
|
| b = BoolCallback(BoolCallbackDelgate, false);
| Debug.Assert(b == false);
| }
|
| The second Assert alwasys asserts because the callback is returning
| true when it should be false.
|
| I think that this is a bug somewhere in c#/clr/PInkove because this
| doesnt happen in c++ clr. I think it was fixed for c++ clr under this
| kb article http://support.microsoft.com/default.aspx?kbid=823071 but
| not fixed for c#.
|
| Any thoughts?
|
| Mark
|
A BOOL is a typedef'd DWORD in C or an int, while a 'bool' is a single byte
in C# (and C++)
So you need to declare the return as int or you need to tag the return like
this:

[DllImport("UnmanagedDll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool BoolCallback(BoolCallbackDelegate

Willy.

Thanks for your reply Willy

Perhaps my example was unclear. The problem does not lie with passing
the bool to the unmanaged dll nor does it lie with with the return from
the unmanaged dll, it lies with the unmanaged dll calling a managed
callback with a BOOL as a parameter. (FYI it doesn't matter if you use
a c++ bool, a char, DWORD or whatever - the problem is still the same)

If you step through the code, the unmanaged dll, cleary calls the
callback with TRUE but it appears as false in the csharp code. Even
changing the delegate prototype to the following does not solve the
problem:

private static extern bool BoolCallback(BoolCallbackDelegate
lpBoolCallBack,[MarshalAs(UnmanagedType.Bool)]bool b);

The c++ clr version (below) of my csharp example works so it looks like
a problem with csharp?!?

ref class Program
{
private:
delegate bool BoolCallbackDelgate(bool b);

static bool GetBool(bool b)
{
return b;
}

public:
static void Main()
{
BoolCallbackDelgate^ fp = gcnew BoolCallbackDelgate(GetBool);
GCHandle gch = GCHandle::Alloc(fp);
IntPtr ip = Marshal::GetFunctionPointerForDelegate(fp);
BoolCallBack cb = static_cast<BoolCallBack>(ip.ToPointer());


bool b = BoolCallback(cb, true);
Debug::Assert(b == true);

b = BoolCallback(cb, false);
Debug::Assert(b == false);
}
};

Mark


typedef bool (__stdcall *BoolCallBack)(short b);
should be:
typedef bool (__stdcall *BoolCallBack)(BOOL b);

Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top