I'm making a C# application which is using GameSpy C code (the GP part). The C code is calling a callback (which is C# code) succesfully, but I get this error Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call
right after the callback is done. I've made a DLL out of C code, like this:
// GPCallback
/////////////
__declspec(dllexport) typedef void (* GPCallback)(
GPConnection * connection,
void * arg,
void * param
);
// gpConnect
////////////
__declspec(dllexport) GPResult gpConnect
(
GPConnection * connection,
const gsi_char nick[GP_NICK_LEN],
const gsi_char email[GP_EMAIL_LEN],
const gsi_char password[GP_PASSWORD_LEN],
GPEnum firewall,
GPEnum blocking,
GPCallback callback,
void * param
);
C# is calling it like this:
unsafe public delegate void GPCallback(
GPConnection * connection,
//GPConnectResponseArg arg,
IntPtr arg,
IntPtr param
);
[DllImport("saketestd.dll")]
unsafe static extern GPResult gpConnect(
GPConnection * connection,
gsi_char nick,
gsi_char email,
gsi_char password,
GPEnum firewall,
GPEnum blocking,
GPCallback callback,
IntPtr param
);
unsafe public bool gpConnectE() {
bool ret = false;
try {
GPResult res;
debug.AddLine(this.getMethodName() + ": " + "connection before connect: " + connection.ToString("x"));
fixed (int* pconn = &connection) {
res = gpConnect(
pconn,
this.NICK,
this.EMAIL,
this.PASSWORD,
GPEnum.GP_NO_FIREWALL,
GPEnum.GP_BLOCKING,
new GPCallback(this.ConnectResponse),
IntPtr.Zero
);
}
debug.AddLine(this.getMethodName() + ": " + "connection after connect: " + connection.ToString("x"));
if (res != GPResult.GP_NO_ERROR) {
debug.AddLine(this.getMethodName() + ": " + "failed: " + res);
} else {
debug.AddLine(this.getMethodName() + ": " + "OK");
ret = true;
}
} catch (Exception ex) {
debug.Text += ex.ToString();
}
return ret;
}
unsafe public void ConnectResponse(
GPConnection * connection,
//GPConnectResponseArg arg,
IntPtr argPtr,
IntPtr param
) {
debug.AddLine(this.getMethodName() + " called with connection: " + (*connection).ToString("x"));
GPConnectResponseArg arg;
arg = (GPConnectResponseArg)Marshal.PtrToStructure(argPtr, typeof(GPConnectResponseArg));
if (arg.result == GPResult.GP_NO_ERROR) {
debug.AddLine(this.getMethodName() + ": Connected to GP");
this.profileid = arg.profile;
} else {
debug.AddLine(this.getMethodName() + ": failed");
debug.AddLine(this.getMethodName() + ": result: " + arg.result);
debug.AddLine(this.getMethodName() + ": profile: " + arg.profile);
debug.AddLine(this.getMethodName() + ": uniquenick: " + arg.uniquenick);
}
}
I believe that I need to clear the stack in my callback or change the calling convention in the DLL (is that possible?). Any other ideas?
Problem solved unexpectedly my myself (after 5 hours googling). I suspected a wrong calling convention already, but I didn't know how to switch it correctly. I've changed it in the C code as suggested here (http://computerarts.com.cn/dotnet-tech/1691/):
Check the calling conventions you are using.
Reference to other related question: Callback from C function - crash