I'm trying to import a C DLL into my C# project. The .h code looks like this:
_declspec(dllexport) LRESULT CALLBACK SensFindDeviceW(LONG n, LPWSTR pwszMask, PSENSDEVICEW pDevice);
the _SENSDEVICEW struct:
typedef struct _SENSDEVICEW
{
WCHAR szSerialNo[32];
WCHAR szDeviceID[32];
LONG nIndex;
} SENSDEVICEW, * PSENSDEVICEW;
So what I have done in C# until now is using the DLLImport:
[DllImport("dll/UFTAccess.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
static extern unsafe long SensFindDeviceW(long n, String pszMask, SENSDEVICEW pDevice);
Defining a struct:
[StructLayout(LayoutKind.Sequential)]
unsafe struct SENSDEVICEW
{
public char[] szSerialNo;
public char[] szDeviceID;
public long nIndex;
}
And trying to use it in a method:
SENSDEVICEW myDevice = new SENSDEVICEW();
myDevice.szSerialNo = new char[32];
myDevice.szDeviceID = new char[32];
long test = SensFindDeviceW(1, "", myDevice);
With this a get System.Runtime.InteropServices.SafeArrayTypeMismatchException.
If I don't initialize the arrays I get a stack imbalance error.
I already tried using stringbuilder (which doesn't work) and marshalling the char-arrays like this:
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
string szSerialNo;
but it results in a stack imbalance.
Maybe anyone of you has an idea what else I can try to get the dll to work?
I see the following issues:
LRESULT
is a pointer sized signed integer. That's IntPtr
on C#.LONG
is a macro that expands to long
. And on Windows, C++ long
is a 32 bit signed integer. So on the C# side you need to use int
. CALLBACK
means that the function is stdcall
.unsafe
. You should remove that.The code should be:
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct SENSDEVICEW
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
public string szSerialNo;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
public string szDeviceID;
public int nIndex;
}
[DllImport("...", CallingConvention=CallingConvention.Stdcall,
CharSet=CharSet.Unicode)]
static extern IntPtr SensFindDeviceW(int n, string pszMask,
ref SENSDEVICEW pDevice);
Finally, I am assuming that pszMask
is an input parameter. And hence string
would be correct. However, the C++ code declares it as LPWSTR
when an input parameter ought to be LPCWSTR
. You might like to check the semantics of this parameter. It certainly feels like an input parameter in which case the C++ coder was a little sloppy.