通过互操作接收字符串
我无法从我写的一些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
作为第一个参数。