问题
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