通过互操作接收字符串

时间:2010-01-08 10:52:35

标签: c# c interop stringbuilder

我无法从我编写的某些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”。但我想要那个长变量!我做错了什么或让我感到沮丧,以便通过在那里设置那个长参数来强制崩溃?

3 个答案:

答案 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位平台上具有相同的宽度。