C # p / invoke difficulties sorting pointers

I am trying to call native.dll from C # using p / invoke. I can make a call (no failure, the function returns a value), but the return code indicates "The pointer parameter does not indicate the available memory." I resorted to trial and error to solve this problem, but I have not made any progress so far.

Here is the signature of the native function that I am calling:

LONG extern WINAPI MyFunction ( LPSTR lpszLogicalName, //input HANDLE hApp, //input LPSTR lpszAppID, //input DWORD dwTraceLevel, //input DWORD dwTimeOut, //input DWORD dwSrvcVersionsRequired, //input LPWFSVERSION lpSrvcVersion, //WFSVERSION*, output LPWFSVERSION lpSPIVersion, //WFSVERSION*, output LPHSERVICE lphService //unsigned short*, output ); 

Here's the imported signature in C #:

  [DllImport("my.dll")] public static extern int MyFunction( [MarshalAs(UnmanagedType.LPStr)] string logicalName, IntPtr hApp, [MarshalAs(UnmanagedType.LPStr)] string appID, int traceLevel, int timeout, int srvcVersionsRequired, [Out] WFSVersion srvcVersion, [Out] WFSVersion spiVersion, [Out] UInt16 hService ); 

Here's the definition of C WFSVERSION:

 typedef struct _wfsversion { WORD wVersion; WORD wLowVersion; WORD wHighVersion; CHAR szDescription[257]; CHAR szSystemStatus[257]; } WFSVERSION, * LPWFSVERSION; 

Here is the C # definition for WFSVersion:

 [StructLayout(LayoutKind.Sequential)] public class WFSVersion { public Int16 wVersion; public Int16 wLowVersion; public Int16 wHighVersion; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 257)] public char[] szDescription; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 257)] public char[] szSystemStatus; } 

Here's the call to MyFunction from C #:

 WFSVersion srvcVersionInfo = new WFSVersion(); WFSVersion spiVersionInfo = new WFSVersion(); UInt16 hService = 0; IntPtr hApp = IntPtr.Zero; string logicalServiceName = tbServiceName.Text; int openResult = MyFunction(logicalServiceName, hApp, null, 0, XFSConstants.WFS_INDEFINITE_WAIT, 0x00000004, srvcVersionInfo, spiVersionInfo, hService); 

As I said, this call returns, but the return value is an error code indicating "The pointer parameter does not indicate available memory." I should be doing something wrong with parameters 1,3,7,8 or 9. However, I made successful calls for other functions in this .dll that required WFSVERSION * as parameters, so I don't think that parameters 7 or 8 here.

I would appreciate any thoughts that might arise about this issue, or any constructive criticisms about my code. This is my first experience with P / Invoke, so I'm not sure where to start. Is there a way to narrow down the problem or trial error only for my option?

+4
source share
6 answers

You have two obvious mistakes here. In the structure definition, you should use byte [] instead of char [] for szDescription and szSystemStatus.

Also, the last parameter in the pInvoke call is not a pointer. When you make your call to MyFunction, hService is zero and therefore has an invalid pointer regarding the function. [Out] is a Marshaling directive that indicates the runtime, when and where to copy data, and not an indicator that the parameter is a pointer. You need to change [Out] to out or ref, this tells runtime that hService is a pointer:

 [DllImport("my.dll")] public static extern int MyFunction( [MarshalAs(UnmanagedType.LPStr)] string logicalName, IntPtr hApp, [MarshalAs(UnmanagedType.LPStr)] string appID, int traceLevel, int timeout, int srvcVersionsRequired, [Out] WFSVersion srvcVersion, [Out] WFSVersion spiVersion, out UInt16 hService); 
+2
source

Some ideas:

  • The C # WFSVersion class should probably be struct . I don't know if P / Invoke marshaller is interested, but I always saw the structures used.

  • There may be a problem with character size.

    C CHAR is 8 bits wide (ANSI) and .Net System.Char is 16 bits wide (Unicode). To give the marshaller as much information as possible so that he does the correct conversion, try adding β€œCharSet = CharSet.Ansi” to the DllImport and StructLayout attributes and change the line declarations in WFSVersion:

     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)] public string szDescription; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)] public string szSystemStatus; 
  • Another problem may be data alignment in structures. If alignment was not specified when compiling the C structure, the data elements in the structure were probably aligned on one or two byte boundaries. Try using Pack in the WFSVersion StructLayout attribute:

     [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] // Try pack values of 2, 4 and 8 if 1 doesn't work. 

And some questions:

  • Was MyFunction supposed to be called from code other than C? The original author may have a written code assuming that the transferred data is distributed using the C memory manager.

  • Does the C DLL code use pointers passed to it for further processing after returning MyFunction? If this is the case - and assuming it is possible / wise / common sense to go ahead with such a situation - it may be necessary to "bind" the structures passed to MyFunction using the fixed keyword. In addition, there may be security issues.

+1
source

I'm not sure the problem is with this, but hopefully this will be the starting point.

Try to study the parameters of the DllImport attribute, this may be due to the sorting of strings.

  [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 

The CharSet parameter is one that I think you might need.

0
source

I found AppVerifier useful for tracking issues of P / Invoke Marshal. It is free from Microsoft.

0
source

I assume that one of your pointers (lpSrvcVersion, lpSPIVersion or lphService) is not available from your .NET application. Can you try changing the DLL (if it's yours) and see if you can make it work without pointers? (I know you will have to add them later, but at least you can narrow down the problem.)

0
source

Are you sure this is not hApp? It looks like an input parameter, the handle of the requesting application. Quick google ... yes, there is a function for creating an application descriptor and a default parameter that you can use.

0
source

Source: https://habr.com/ru/post/1285628/


All Articles