如何从c#调用C ++ DLL导出函数

时间:2011-03-20 08:42:43

标签: c# .net c++ windows pinvoke

这是我第一次尝试将c#与非托管C ++混合使用,所以这可能是一个非常简单的问题,但我不明白。

我需要将C ++ dll中的一些函数调用到C#代码中。这是dll项目的代码:

.h文件:

#pragma once 
#include <iostream>
#if defined FIRSTDLL_EXPORTS
    #define DECLDIR __declspec(dllexport)
#else
    #define DECLDIR __declspec(dllimport)
#endif

extern "C"
    {
      DECLDIR int Add( int a, int b );
      DECLDIR void Function( void );
    }

.cpp文件

#include "stdafx.h"
#include "myFct.h"
#include <iostream>

extern "C"
{
      DECLDIR int Add( int a, int b )
      {
          return( a + b );
}

      DECLDIR void Function( void )
      {
          std::cout << "DLL Called!" << std::endl;
      }
}

我为debug和releas编译了这个,并将它复制到我的C#项目的debug文件夹中。这两个版本都没有用。

这是c#代码:

[DllImport("firstDLL.Dll")]
public static extern int Add(int a, int b);


var cyu = Add(3, 5);

当我尝试运行时,我得到了

“托管调试助手'PInvokeStackImbalance'在'C:\ Program Files \ Microsoft Office \ Office14 \ WINWORD.EXE'中检测到问题。 附加信息:调用PInvoke函数'MyAddin!MyAddin.ThisAddIn :: Add'使堆栈失去平衡。这很可能是因为托管PInvoke签名与非托管目标签名不匹配。检查PInvoke签名的调用约定和参数是否与目标非托管签名匹配。“

但是我看到签名是一样的。我错过了什么?

谢谢!

1 个答案:

答案 0 :(得分:7)

DLLImport的默认调用约定是stdcall,但是C ++代码的默认值是cdecl。您看到的错误消息是调用约定不匹配时显示的内容。这两个调用约定的参数堆栈清理要求是不同的,P / Invoke marshaller检测并报告这个。

修复方法是让您的呼叫约定匹配。

例如,您可以像这样更改P / Invoke:

[DllImport("firstDLL.Dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int Add(int a, int b);

另一种选择是改变你的C ++:

#if defined FIRSTDLL_EXPORTS(returntype)
    #define DECLDIR __declspec(dllexport) returntype __stdcall
#else
    #define DECLDIR __declspec(dllimport) returntype __stdcall
#endif

显然你应该只做其中一个。如果您同时更改C#和C ++,则反向会遇到同样的问题!

如果我是你,我会将C ++代码保留为cdecl并更改C#以匹配。