Click to See Complete Forum and Search --> : P/Invoke and strings callback problem


olekba
August 24th, 2009, 05:13 AM
Hi All,

I have a problem with found a bug here. Maybe someone can help me. From c# I call a c++ function (in dll via P/Invoke). One function give a handle form manage code to a unmanage code. Next after call another function from manage code unmanage call this callback in manage. In c# it is look like:

[DllImport("tttddd.dll", CharSet = CharSet.Ansi)]
public static extern void CallBackFire();

public delegate void InterfaceGroupEvent([MarshalAs(UnmanagedType.LPStr)] string ord);

[DllImport("tttddd.dll", CharSet = CharSet.Ansi)]
public static extern void set_InterfaceGroupEventCallback(InterfaceGroupEvent f);

private void button1_Click(object sender, EventArgs e)
{
set_InterfaceGroupEventCallback(InterfaceGroupEventCallbackFunction);
CallBackFire();
}

public void InterfaceGroupEventCallbackFunction( string str)
{
MessageBox.Show(str);
}

Unmanage part:

static const void*(*InterfaceGroupEventCallback)(char*);
__declspec(dllexport)void set_InterfaceGroupEventCallback(const void*(*f)(char*))
{
InterfaceGroupEventCallback=f;
}

__declspec(dllexport)void CallBackFire()
{
char *s=(char*)CoTaskMemAlloc(100);
sprintf(s,"Cat");
InterfaceGroupEventCallback(s);
}

All look to work good in runtime (message box is show) but next come a bug:

"Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. THis is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention"

But funtions look to have same conventions....

Any ideas ?

Thnx in advance

Olekba

vcdebugger
August 24th, 2009, 06:08 AM
Here in the unmanaged code , the callback function is declared as :

static const void*(*InterfaceGroupEventCallback)(char*);

but in the managed C# code the decleration is :

public void InterfaceGroupEventCallbackFunction( string str)


there seems to be some mismatch in the return type in both cases .. Is n't it ?

olekba
August 24th, 2009, 06:26 AM
I't not a problem with a return type. This is standard way, how this is declarate (static pointer to function in c++). Problem is with a string conversion. If I modify it, that char* parameter not exist, all work fine. But propably is somethink wrong with a string conversion...

Another ideas ?

Olekba

vcdebugger
August 24th, 2009, 06:34 AM
Instead of using basic 'string' type in C# try using the class "String"..
something like this :

[MarshalAs(UnmanagedType.LPStr)]
public String _name;
public String Name
{
get { return _name; }
set { _name = value; }
}

Mutant_Fruit
August 24th, 2009, 07:22 AM
"Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. THis is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention"

The more general cause of this error is that the stack pointer has been corrupted. One way this can happen is if the return types don't match.


static const void (*InterfaceGroupEventCallback)(char*);

I'm fairly sure this is what you actually meant. The return type is void, not void*.


Instead of using basic 'string' type in C# try using the class "String"..

Won't make one bit of difference. You were right in your initial observation though, it's a return type mismatch.

olekba
August 24th, 2009, 07:52 AM
static const void (*InterfaceGroupEventCallback)(char*);

I tested it like that, directly after previous sugestion, but this not help.

But stay with this same "void" but without string parameter help. This is why I deducatie, that this is a parameter problem.

olekba
August 24th, 2009, 08:01 AM
I solve it like that, that callback function is without parameters and text is get from a buffer from not manage part in additional function (called under callback by manage part).

But if someone have idea how to modyfi my first program (convert from string to String and remove a '*' after void not change a problem)....

Olek

Mutant_Fruit
August 24th, 2009, 08:31 AM
Change your original function to use an 'IntPtr' type instead of a 'string' type. Then use Marshal.PtrToString to convert it to a string. What you *could* be experiencing is a crash when the .NET runtime attempts to free the unmanaged string.

darwen
August 24th, 2009, 09:43 AM
Your declaration :


__declspec(dllexport)void set_InterfaceGroupEventCallback(const void*(*f)(char*))


has the callback method declared as using the C++ default calling convention i.e. cdecl.

But the default calling convention of PInvoke is stdcall.

Try this :


static void (__stdcall *InterfaceGroupEventCallback)(char*);

__declspec(dllexport)void set_InterfaceGroupEventCallback(void(__stdcall *f)(char*))


Remove the 'void *' return type as well (as I have above).

Darwen.
Darwen.

olekba
August 24th, 2009, 09:54 AM
THNX DARWEN ! This is it. Also thnx for rest, what try to help me.

For future analizers, source in unmanage part shoud look like:

static const void(__stdcall *InterfaceGroupEventCallback)(char *x);


__declspec(dllexport)void set_InterfaceGroupEventCallback(const void(__stdcall *f)(char *x))
{
InterfaceGroupEventCallback=f;