从C ++代码成功进行C#回调后,“运行时检查失败#0 - ESP的值未在函数调用中正确保存”

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从C ++代码成功进行C#回调后,“运行时检查失败#0 - ESP的值未在函数调用中正确保存”相关的知识,希望对你有一定的参考价值。

我正在制作一个使用GameSpy C代码的C#应用​​程序(GP部分)。 C代码成功地调用了一个回调(它是C#代码),但是在回调完成后我得到了这个错误Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call。我用C代码制作了一个DLL,像这样:


    // 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#就像这样调用它:


   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);
   }
  }

我相信我需要在回调中清除堆栈或更改DLL中的调用约定(可能吗?)。还有其他想法吗?

答案

检查您正在使用的调用约定。

 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]

参考其他相关问题:Callback from C function - crash

另一答案

问题意外地解决了我自己(在谷歌上搜索5小时后)。我已经怀疑一个错误的调用约定,但我不知道如何正确切换它。我在这里建议的C代码中更改了它(http://computerarts.com.cn/dotnet-tech/1691/):

// GPCallback
/////////////
//__declspec(dllexport) typedef void (* GPCallback)(
//typedef __declspec(dllexport) void (* GPCallback)(
typedef void (_stdcall * GPCallback)(
  GPConnection * connection,
  void * arg,
  void * param
);

以上是关于从C ++代码成功进行C#回调后,“运行时检查失败#0 - ESP的值未在函数调用中正确保存”的主要内容,如果未能解决你的问题,请参考以下文章

运行时检查失败 #2 - 变量“cid1”周围的堆栈已损坏

运行时检查失败 #2 - 变量周围的堆栈已损坏

运行时检查失败 #2 - 变量“结果”周围的堆栈已损坏

(C++/CLI) 如何在 C++ CLI 中获取从本机代码到托管代码的回调?

实验总结

关于promise的几个认知