1

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

首先是一些通常未实现的背景信息:我想从 TAPI API 接收 TAPI TSP 的用户可读字符串。我已经实现了一个半可行的 TAPI 解决方案,它依赖于将驱动程序名称与存储的字符串匹配,但我想将其更改为在永久线路 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 因为字符串是不可变的,并且我希望在 C 中设置 DeviceName (这是 MS 推荐的)。我还将返回类型设置为void希望这也会影响某些东西(请参阅这篇半有用的单声道文章以获得部分伪科学解释)。

并这样称呼它:

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

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

随后在 C# 中引发 AccessViolationException。

出了什么问题?

删除 long 参数会有所帮助。我可以在 C 中将“abc”添加到我的 DeviceName 参数中。但是我想要那个长变量!我在做什么错或不安,以便通过在那里设置那个长参数来强制崩溃?

4

3 回答 3

2

但是我想要那个长变量

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

于 2010-01-08T14:31:09.037 回答
1

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

于 2010-01-08T11:00:06.077 回答
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和 Clong在 32 位平台上具有相同的宽度。

于 2010-01-08T14:31:06.993 回答