1

I'm trying to use a method from a C++ DLL in a C# project, but I'm, having problems calling it correctly. The method is this:

As said in the SDK manual

DWORD WINAPI PrtRead (HANDLE hPrt, DWORD dwTimeout, DWORD *pdwType, LPDWORD pdwParArray, LPDWORD pdwArraySize, LPBYTE pbReadData, LPDWORD pdwReadDataLen)

As really defined on code

extern "C" __declspec(dllimport) DWORD PrtRead (HANDLE hPRT, DWORD dwTimeout, DWORD *pdwType, LPDWORD pdwParArray, LPDWORD pdwArraySize,LPBYTE  pbReadData, LPDWORD pdwReadDataLen);

and in the SDK C++ sample they call it like this:

DWORD       dwPar[2];
pdwParArray = &dwPar[0];
dwPar[0] = 0;
dwPar[1] = 0;

DWORD dwRet = PrtRead(hPrinter, dwCurrentTimeout, &dwType, pdwParArray, &dwArraySize, NULL, &dwReadDataLen);

My problem is getting the value LPDWORD pdwParArray.

The DLL always returns one of the following values in position [0]: 1, 2 or 20 and in postion [1]: 1, 2 or 4, but I'm unbale to make it do this.

I've tryed defining the import like this:

[DllImport("HPRDH.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern ulong PrtRead(IntPtr hPrt, ulong dwTimeout, ref ulong pdwType, XXXXXXXXX , ref ulong pdwArraySize, ref byte[] pbReadData, ref ulong pdwReadDataLen);

and varied XXXXXXXXX like this


Method definition:

out ulong[] pdwParArray

Variable Initialization:

ulong[] pdwParArray;

Method returns:

pdwParArray = null

Method definition:

ref ulong[] pdwParArray

Variable Initialization:

ulong[] pdwParArray = new ulong[2];
pdwParArray[0] = 0;
pdwParArray[1] = 0;

Method returns: pdwParArray[0] = 0; pdwParArray[1] = Out of bounds array index;


Method definition: out ulong pdwParArray

Variable Initialization: ulong[] pdwParArray = new ulong[2];

Method returns: pdwParArray[0] = 0; pdwParArray[1] = 0;


Method definition: ref ulong pdwParArray

Variable Initialization: ulong[] pdwParArray = new ulong[2];

Method returns: pdwParArray[0] = 0; pdwParArray[1] = 0;


How should I define the LPDWORD pdwParArray in my C# import, how to initialize it and call it?

Thanks in advance

_
_
_
_

EDIT: @TheMathemagician

Tried the following with these results:

Definition:

[MarshalAs(UnManagedType.LPArray)] ulong[] pdwParArray

Result:

pdwParArray[0] = 0;

pdwParArray[1] = 0;


Definition:

[MarshalAs(UnmanagedType.LPArray)] out ulong[] pdwParArray

Result:

pdwParArray[0] = null;

pdwParArray[1] = null;


Definition:

[MarshalAs(UnmanagedType.LPArray)] ulong pdwParArray

Result:

Cannot marshal 'parameter #4': Invalid managed/unmanaged type combination (Int64/UInt64 must be paired with I8 or U8).


Definition:

[MarshalAs(UnmaDefinition:nagedType.LPArray)] out ulong pdwParArray

Result:

Cannot marshal 'parameter #4': Invalid managed/unmanaged type combination (Int64/UInt64 must be paired with I8 or U8).

Gonçalo Cardoso
  • 2,253
  • 4
  • 34
  • 63
  • Are you on 32 or 64 bit windows. Have a look here http://stackoverflow.com/questions/39419/visual-c-how-large-is-a-dword-with-32-and-64-bit-code - your whole code depends on this question. – weismat Jan 30 '12 at 11:55
  • I'm running a 64 bit windows, but tried forcing the program to compile on x86 and got the same results – Gonçalo Cardoso Jan 30 '12 at 12:09

5 Answers5

1

you said the method is a WINAPI call,not a cdecl in your c# application you declared it as cdecl

Volker Mauel
  • 514
  • 3
  • 21
  • 1
    Retried all the tests with the declaration like you said and in every case I got: A call to PInvoke function 'WincorNixdorf!WincorNixdorf.WincorNixdorfDriver::PrtRead' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature. – Gonçalo Cardoso Jan 30 '12 at 11:16
1

As almost all the answers where about the same thing, and even so It wasn't working, I decided to look even deeper into the SDK sample, and realized I needed to call PrtRead(...) a second time to get the correct values.

I ended up by using:

[DllImport("HPRDH.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern UInt32 PrtRead(IntPtr hPrt, UInt32 dwTimeout, ref UInt32 pdwType, out UInt32 pdwParArray, ref UInt32 pdwArraySize, ref byte[] pbReadData, ref UInt32 pdwReadDataLen);
Gonçalo Cardoso
  • 2,253
  • 4
  • 34
  • 63
0

Try declaring it as [MarshalAs(UnManagedType.LPArray)] ulong[] pdwParArray

OK ulong in C# is a 64-bit integer (on Windows 7) and I found if I changed all the ulong's to Int32's it worked for a DLL function I constructed with the same signature.

So I have: [DllImport("SPLibNet.dll", CallingConvention=CallingConvention.StdCall)] public static extern Int32 PrtRead(IntPtr hPtr, Int32 dwTimeout, ref Int32 pdwType, [MarshalAs(UnmanagedType.LPArray)] Int32[] pdwParArray, ...

And my DLL is able to set values in pdwParArray

TheMathemagician
  • 968
  • 9
  • 21
  • Added the results to the original question – Gonçalo Cardoso Jan 30 '12 at 11:42
  • Tried that, just replaced StdCall with Cdecl and the DLL name and got the same result – Gonçalo Cardoso Jan 30 '12 at 12:36
  • Why did you replace StdCall with Cdecl? It wont work then. WINAPI is StdCall as Volker Mauel and Tom Knapen said. – TheMathemagician Jan 30 '12 at 14:15
  • Because the method definition is **extern "C" __declspec(dllimport) DWORD PrtRead (HANDLE hPRT, DWORD dwTimeout, DWORD *pdwType, LPDWORD pdwParArray, LPDWORD pdwArraySize,LPBYTE pbReadData, LPDWORD pdwReadDataLen);** and when I put StdCall I get **'WincorNixdorf!WincorNixdorf.WincorNixdorfDriver::PrtRead' has unbalanced the stack.** – Gonçalo Cardoso Jan 30 '12 at 14:46
  • [DllImport("HPRDH.dll", CallingConvention=CallingConvention.Cdecl)] public static extern Int32 PrtRead(IntPtr hPrt, Int32 dwTimeout, ref Int32 pdwType, [MarshalAs(UnmanagedType.LPArray)] Int32[] pdwParArray, ref Int32 pdwArraySize, byte[] pbReadData, ref Int32 pdwReadDataLen); – TheMathemagician Jan 30 '12 at 15:37
0

One thing I notice is that you specify the wrong CallingConvention for the imported function.

In C++ WINAPI is defined as

#define WINAPI __stdcall

So your C# import should be

[DllImport("HPRDH.dll", CallingConvention = CallingConvention.StdCall)]
public static extern ulong PrtRead(IntPtr hPrt, ulong dwTimeout, ref ulong pdwType, XXXXXXXXX , ref ulong pdwArraySize, ref byte[] pbReadData, ref ulong pdwReadDataLen);
Tom Knapen
  • 2,277
  • 16
  • 31
  • Tried that and got the same error. So I decided to see the source code instead of the manual and it really defined as: extern "C" __declspec(dllimport) DWORD PrtRead (HANDLE hPRT, DWORD dwTimeout, DWORD *pdwType,LPDWORD pdwParArray,LPDWORD pdwArraySize,LPBYTE pbReadData,LPDWORD pdwReadDataLen); – Gonçalo Cardoso Jan 30 '12 at 11:55
0

Use the table from here for your conversions and also correct the calling convention: Pinvoke.net

weismat
  • 7,195
  • 3
  • 43
  • 58