Reputation: 735
I am making use of an API from Nikon to control a microscope. The API is written in C++ while I am implementing a driver in C#. To open a connection with the microscope, I must use an Open method with the following Syntax:
lx_result MIC_Open ( const lx_int32 iDeviceIndex, lx_uint64& uiConnectedAccessoryMask, const lx_uint32 uiErrMsgMaxSize, lx_wchar* pwszErrMsg)
If I marshal the technique as follows, the code crashes whenever a Garbage Collection is performed:
[DllImport("/filepath/Ni_Mic_Driver.dll")]
protected static extern int MIC_Open ( int deviceIndex , ref ulong accessoryMask , uint errorMessageMaxSize , [MarshalAsAttribute(UnmanagedType.LPWStr)] string error);
A 0xc000005 exception is thrown with error code 80131506, indicating the Garbage Collector has attempted to dispose of an object with an invalid pointer. An error message produced by Visual Studio 2013 indicates:
"This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshalling errors for COM-Interop or PInvoke, which may corrupt the stack."
Following the messages advice, I adjusted the marshalling to the following, which results in no CLR crash.
[DllImport("/filepath/Ni_Mic_Driver.dll")]
protected static extern int MIC_Open ( int deviceIndex , ref ulong accessoryMask , uint errorMessageMaxSize , [MarshalAsAttribute(UnmanagedType.LPStr)] string error);
I am confused because it is my understanding that wchar* indicates a pointer to a string of null-terminated 16-bit Unicode characters, which should map to UnamagedType.LPWStr. However, the code works only if I use UnmanagedType.LPStr.
The following also works, but should require more work to then extract the corresponding string.
[DllImport("/filepath/Ni_Mic_Driver.dll")]
protected static extern int MIC_Open ( int deviceIndex , ref ulong accessoryMask , uint errorMessageMaxSize , IntPtr errorPointer );
Any thoughts on why UnamagedType.LPWStr would cause the crash while it behaves with UnmanagedType.LPStr or IntPtr?
Upvotes: 2
Views: 1222
Reputation: 735
Thank you to Hans Passant for his recommendation. I corrected the marshalling as follows:
[DllImport("/filepath/Ni_Mic_Driver.dll")]
protected static extern int MIC_Open ( int deviceIndex , ref ulong accessoryMask , uint errorMessageMaxSize , [MarshalAsAttribute(UnmanagedType.LPWStr)] StringBuilder errorString);
I then use this method as follows (simplified here for display):
NikonDefinitions.accessory = 0;
int errorMessageCapacity = 256;
int nikonErrorMessageMaxSize = errorMessageCapacity - 1;
StringBuilder errorMessage = new StringBuilder(errorMessageCapacity);
int nikonReturn = NikonDefinitions.MIC_Open(Convert.ToInt32(1),ref NikonDefinitions.accessory,nikonErrorMessageMaxSize,errorMessage);
Upvotes: 1