【发布时间】:2010-12-24 07:13:11
【问题描述】:
我正在尝试调用 C++ dll 中声明为 __declspec(dllexport) 的方法以在 C# 中使用,但我不知道如何从 C++ 返回字符串值以及如何使用 DllImport 声明签名在 C# 中。
C++ 代码“VNVAPI.dll”
__declspec(dllexport) char * GetGpuName(int phyGPUid)
{
CNvidia * pInstance = CNvidia::GetInstance();
char szName[512]={0};
pInstance->GetGpuName(phyGPUid,szName,512);
return szName;
}
C#方法签名:
[DllImport("VNVAPI.dll")]
public static extern char GetGpuName(int phyGPUid);
产生错误:
调用 PInvoke 函数 '核心!Core.Hardware.IO.NVAPI::GetGpuName' 使堆栈不平衡。这是 可能是因为托管的 PInvoke 签名与非托管的不匹配 目标签名。检查 调用约定和参数 PInvoke 签名匹配目标 非托管签名。
谢谢。
【问题讨论】:
-
C++ 代码无效,它返回一个指向栈上缓冲区的指针。很经典的bug。这个函数也不能从 C++ 程序中安全地调用,尽管它往往会意外工作。它可以绝对不被 pinvoked,pinvoker marshaller 将破坏缓冲区内容。
-
@Hans Passant:当你说 C++ 时,这是否意味着在 C 中做同样的事情有不同的语义?
-
@Hans Passant:Drat,我再次感到困惑,我以为你在这里提到了
static场景。我的脑海中仍然有@David Heffernan 的答案。 C 和 C++ 之间为static分配内存的方式有什么区别吗? -
@leppie,同样的事情。使用
static不是解决办法,pinvoke marshaller 将尝试使用 CoTaskMemFree 释放字符串。这在 Vista 和 Win7 上大放异彩。真正的解决方法是将缓冲区 + 长度作为参数传递,StringBuilder 在托管端。 -
@Hans Passant:我确实理解正确和理智的方式。但是为什么编组器会尝试释放它没有分配的内存呢?当然,它应该只是尝试复制指向的缓冲区(或使字符串指向内存位置,如果可能的话)。
标签: c# c++ visual-studio-2010