【问题标题】:A call to PInvoke function has unbalanced the stack when including a C DLL into C#将 C DLL 包含到 C# 中时,对 PInvoke 函数的调用使堆栈不平衡
【发布时间】:2011-01-19 04:47:06
【问题描述】:

我编写了一个 C DLL 和一些 C# 代码来测试,包括这个 DLL 并从中执行函数。我对这个过程不太熟悉,每当从 C# 源代码调用我的 DLL 函数时,都会收到 PInvokeStackImbalance 异常。代码如下(我已经注释掉大部分代码来隔离这个问题):

C# 包含代码:

using System;
using System.Runtime.InteropServices;
using System.IO;

namespace TestConsoleGrids
{
    class Program
    {

        [DllImport("LibNonthreaded.dll", EntryPoint = "process")]
            public unsafe static extern void process( long high, long low);

        static void Main(string[] args)
        {
            System.Console.WriteLine("Starting program for 3x3 grid");

            process( (long)0, (long)0 );

            System.Console.ReadKey();
        }
    }
}

C++ DLL 函数代码

extern "C" __declspec(dllexport) void process( long high, long low );

void process( long high, long low )
{
    // All code commented out
}

Visual Studio 生成的 dllmain 代码(我不明白这个结构,所以我把它包括在内)

// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
      )
{
 switch (ul_reason_for_call)
 {
 case DLL_PROCESS_ATTACH:
 case DLL_THREAD_ATTACH:
 case DLL_THREAD_DETACH:
 case DLL_PROCESS_DETACH:
  break;
 }
 return TRUE;
}

异常详情如下:

对 PInvoke 函数“TestConsoleGrids!TestConsoleGrids.Program::process”的调用使堆栈失衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。

【问题讨论】:

  • 您不需要 pinvoke 签名上的 unsafe 关键字。 PInvoke 处理从 .net 到本机的编组
  • 您是否已按照详细信息的要求进行操作?检查调用约定?检查 DllImportAttribute 类的文档,msdn.microsoft.com/en-us/library/…,它具有 CallingConvention 属性,尝试将其设置为 CallingConvention.Cdecl。 [DllImport(..., CallingConvention=Callingconvention.Cdecl)]
  • 谢谢拉瑟!这正是问题所在。我一直在关注教程,但没有人提到这一点。

标签: c# windows dll pinvoke dllimport


【解决方案1】:

在 C++ 中,long 是 32 位的。在 C# 中,它是 64 位的。在 C# 声明中使用 int

您也可以尝试将__stdcall 添加到 C++ 函数中。见:What is __stdcall?

【讨论】:

  • 好的洞察力,你必须对参数正确,因为删除它们可以完全解决问题。只是在 C# 中将它们声明为 int 并没有。
【解决方案2】:

在 C# 中 long 表示 64 位 int 而在 C++ 中 long 表示 32 位 int,您需要将 pinvoke 声明更改为

 [DllImport("LibNonthreaded.dll", EntryPoint = "process")]
     public unsafe static extern void process( int high, int low);

您也可以尝试将 C++ 声明更改为 stdcall,这是 Windows 环境中大多数导出函数使用的调用约定。

 __stdcall  __declspec(dllexport) void process( long high, long low );

【讨论】:

  • 不幸的是,这并不能解决问题。感谢您指导我使用 Type Marshalling,但是我正在研究这个。
【解决方案3】:

调用约定错误。如果删除 int 参数不会触发 MDA,那么它是 Cdecl:

 [DllImport("LibNonthreaded.dll", CallingConvention = CallingConvention.Cdecl)]
 public static extern void process(int high, int low);

这不是导出 DLL 函数的标准调用约定,如果可以的话,您可以考虑在 C/C++ 代码中更改它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多