我无法从我编写的某些c代码中获取字符串。
首先是一些通常未分离的背景信息:我想从TAPI API接收TAPI TSP的用户可读字符串。我已经实现了一个半可行的TAPI解决方案,依赖于匹配的驱动程序名称到存储的字符串,但是我想改变它以使用permanant line id,因为我们的一个客户有一个拒绝以任何其他方式工作的(阿尔卡特)PBX
在C中,我将头文件中的函数定义为:
__declspec(dllexport) void GetDeviceName(long DeviceId, wchar_t* DeviceName);
这样写的功能是:
__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(This is recommended by MS)中设置。我还将返回类型设置为void
,希望这也会影响某些内容(请参阅this半有用的单篇文章,了解部分伪科学解释)。
并称之为:
StringBuilder name = new StringBuilder();
name.EnsureCapacity(100);
long n = 0;
GetDeviceName(n, name);
我将调试器附加到正在运行的进程,设置断点,并在C代码中注意StringBuilder以某种方式变态,并作为空指针提供给非托管代码。
随后在C#中抛出AccessViolationException。
出了什么问题?
删除long参数有帮助。我可以在C中的我的DeviceName参数中添加“abc”。但我想要那个长变量!我做错了什么或让我感到沮丧,以便通过在那里设置那个长参数来强制崩溃?
答案 0 :(得分:2)
我想要那个长变量
然后,您应该将C中的参数定义为long long
。正如Lucero所指出的,C ++中的长整数是32位,而C#中的长整数是64位。因此,如果您传递一个64位值,其中C函数需要32位值,该函数会读取额外的32位作为第二个参数,这显然会导致缓冲区的地址错误...
答案 1 :(得分:1)
c ++ long
是32位,C#long
是64位,不是吗?因此,您需要使用int
作为第一个参数。
答案 2 :(得分:1)
在32位平台上long
在.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位平台上具有相同的宽度。