receiving strings through interop

随声附和 提交于 2020-01-30 08:12:29

问题


I'm having trouble getting a string back from some c code I wrote.

First some generally unrealated background info: I'd like to receive the user readable string for a TAPI TSP from the TAPI API. I've implemented a semi workable TAPI solution relying on matching driver names to stored strings, but would like to change this to work on permanant line id's instead, as one of our customers has an (Alcatel) PBX that refuses to work any other way.

In C, I define the function in my header file as:

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

The function is written thusly:

__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));
}

As stated above, this will eventually do something useful but for now I'll be happy if abc is placed in my wchar_t*/StringBuilder and I can see that in C#.

In C# I define the function as:

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

I define DeviceName as a StringBuilder because a string is immuatable and I want the DeviceName to be set in C (This is recommended by MS). I also set the return type to void on the slim hope that that also affects something (see this semi helpful mono article for a partial pseudo scientific explanation).

And call it so:

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

I attach my debugger to the running process, set a breakpoint, and notice in the C code that somehow the StringBuilder is perverted and is provided to the unmanaged code as a null pointer.

An AccessViolationException is subsequently thrown in C#.

What's gone wrong?

removing the long parameter helps. I'm able to add "abc" to my DeviceName parameter in C. I want that long variable however! What am I doing wrong or upsetting so as to force a crash by having that long parameter there?


回答1:


On 32 bits platforms long is 8 bytes (64 bits) wide in .NET and 4 bytes (32 bits) wide in native code. You need to change your P/Invoke method like this:

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

This way, C# int and C long have the same width on 32 bits platforms.




回答2:


I want that long variable however

Then you should define the parameter in C as long long. As Lucero pointed out, a long in C++ is 32 bits, while a long in C# is 64 bits. So if you pass a 64 bit value where the C function expects a 32 bit value, the function reads the extra 32 bits as the second parameter, which obviously results in a wrong address for the buffer...




回答3:


The c++ long is 32 bits, the C# long is 64 bits, isn't it? Therefore you'd need to use an int for the first parameter.



来源:https://stackoverflow.com/questions/2027022/receiving-strings-through-interop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!