Question

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?

Was it helpful?

Solution

I see the following issues:

  1. LRESULT is a pointer sized signed integer. That's IntPtr on C#.
  2. 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.
  3. The struct declaration is wrong (see below). And you fail to pass the struct by reference.
  4. The macro CALLBACK means that the function is stdcall.
  5. There is also no need at all for 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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top