通过互操作接收字符串

我无法从我写的一些c代码中获取字符串。

首先是一些通常未分离的背景信息:我想从TAPI API接收TAPI TSP的用户可读字符串。 我已经实现了一个半可行的TAPI解决方案,依赖于匹配的驱动程序名称到存储的字符串,但是想要改变它以使用permanant line id,因为我们的一个客户有一个(阿尔卡特)PBX拒绝以任何其他方式工作。

在C中,我将头文件中的函数定义为:

__declspec(dllexport) void GetDeviceName(long DeviceId, wchar_t* DeviceName); 

这样写的function如下:

 __declspec(dllexport) void GetDeviceName(long DeviceId, wchar_t* DeviceName) { //tapi code here... //copy the string to DeviceName wcscpy(DeviceName, (wchar_t*)((char *)devCaps + devCaps->dwLineNameOffset)); } 

如上所述,这最终会做一些有用的事情,但是现在我很高兴如果abc放在我的wchar_t * / StringBuilder中,我可以在C#中看到它。

在C#中我将函数定义为:

  [DllImport("SBW.Tapi.TapiInterop.dll", CharSet = CharSet.Auto)] static extern void GetDeviceName(long DeviceId, StringBuilder DeviceName); 

我将DeviceName定义为StringBuilder,因为字符串是不可移植的,我希望DeviceName在C中设置( 这是MS推荐的 )。 我还将返回类型设置为void ,因为它也会影响某些东西(请参阅这篇半有用的单篇文章,以获得部分伪科学解释)。

并称之为:

 StringBuilder name = new StringBuilder(); name.EnsureCapacity(100); long n = 0; GetDeviceName(n, name); 

我将调试器附加到正在运行的进程,设置断点,并在C代码中注意StringBuilder以某种方式变态,并作为空指针提供给非托管代码。

随后在C#中抛出AccessViolationException。

出了什么问题?

删除long参数有帮助。 我能够在C中的我的DeviceName参数中添加“abc”。但我想要那个长变量! 我做错了什么或让我感到沮丧,以便通过在那里设置那个长参数来强制崩溃?

在32位平台上,.NET在.NET中为8字节(64位)宽,在本机代码中为4字节(32位)宽。 您需要像这样更改P / Invoke方法:

 [DllImport("SBW.Tapi.TapiInterop.dll", CharSet = CharSet.Auto)] static extern void GetDeviceName(int DeviceId, StringBuilder DeviceName); 

这样,C# int和C long在32位平台上具有相同的宽度。

但我想要那个长变量

然后你应该在C中定义参数long long 。 正如Lucero所指出的,C ++中的长整数是32位,而C#中的长整数是64位。 因此,如果您传递一个64位值,其中C函数需要32位值,该函数会读取额外的32位作为第二个参数,这显然会导致缓冲区的地址错误…

c ++ long是32位,C# long是64位,不是吗? 因此,您需要使用int作为第一个参数。