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

Posted

技术标签:

【中文标题】“运行时检查失败 #0 - ESP 的值未在函数调用中正确保存”从 C++ 代码成功 C# 回调后【英文标题】:"Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call" after successful C# callback from the C++ code 【发布时间】:2010-11-30 17:09:24 【问题描述】:

我正在制作一个使用 GameSpy C 代码(GP 部分)的 C# 应用程序。 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 中的调用约定(这可能吗?)。还有其他想法吗?

【问题讨论】:

【参考方案1】:

我自己出乎意料地解决了问题(经过 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
);

【讨论】:

【参考方案2】:

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

 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]

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

【讨论】:

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