Click here to Skip to main content
15,878,959 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Greetings.

I'm working on a scanner management project. Provider sent me the .dll and .h files (C++ native) for I need to build a wrapper to use it in my C# project. Some functions had no problems, but others are really difficult to invoke (or at least I dont have enought experience for doing that).

One of them involves a pointer to struck, that internally has other structs.

This is the code in C++

C++
typedef struct _ImParam
{
  UINT Format;
  UINT Resolution;
  UINT ColorDepth;
} IM_PARAM;

typedef struct _sValues
{
  UINT Xpos;
  UINT Ypos;
  UINT Width;
  UINT Height;
  BOOL Milli; 
} S_VALUES;

typedef struct _sProperties
{
  BOOL Enable;
  S_VALUES Properties;
} S_PROPERTIES;

typedef struct _DevParam
{
  BOOL Enable;
  UINT Font;
  char Symbol;
  IM_PARAM Image1;
  IM_PARAM Image2;
  S_PROPERTIES Properties[10];
  UINT FeedMode;
} DevParam;

// more code, comments, etc. etc.

// The function I want to use
BOOL GetParameters( DWORD ID, DevParam  *dParam );


and this is how I defined the structs in C#

C#
[StructLayout(LayoutKind.Sequential)]
public struct ImParam
{
   public uint Format;
   public uint Resolution;
   public uint ColorDepth;

   public ImParam(uint n)
   {
       Format = n;
       Resolution = 300;
       ColorDepth = 256;
   }
};

[StructLayout(LayoutKind.Sequential)]
public struct sValues
{
   public uint Xpos;
   public uint Ypos;
   public uint Width;
   public uint Height;
   [MarshalAs(UnmanagedType.Bool)]
   public bool Milli;

   public sValues(uint n)
   {
       Xpos = n;
       Ypos = n;
       Width = n;
       Height = n;
       Milli = false;
   }
};

[StructLayout(LayoutKind.Sequential)]
public struct sProperties
{
   [MarshalAs(UnmanagedType.Bool)]
   public bool Enable;
   public sValues Properties;

   public sProperties(int n)
   {
       Enable = false;
       Properties = new sValues(n);
   }
};

[StructLayout(LayoutKind.Sequential)]
public struct DevParam
{
   [MarshalAs(UnmanagedType.Bool)]
   public bool Enable;
   public uint Font;
   public char Symbol;
   public ImParam Image1;
   public ImParam Image2;
   [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
   public sProperties[] Properties;
   public uint FeedMode;

   public DeviceParameters(int n)
   {
       Enable = true;
       Font = 0;
       Symbol = '?';
       Image1 = new ImParam(3);
       Image2 = new ImParam(3);
       Properties = new sProperties[10];
       for(int i = 0; i < 10; i++)
          Properties[i] = new sProperties(n);
       FeedMode = 1;
   }
};


What I need is to get the struct from the C++.

What I have tried:

I tried adding a ref to the struct

C#
// At the wrapper class
[DllImport(path, EntryPoint = "?GetParameters@@YGHKPAU_DevParam@@@Z")]
public static extern bool GetParameters(int ID, out DevParam dParam);

// At main
DevParam DP; // Got ID previously
bool res = Class1.GetParameters(ID, out DP);
Console.WriteLine("Result: " + res);


Also tried using an IntPtr

C#
// At the dll wrapper class
[DllImport(path, EntryPoint = "?GetParameters@@YGHKPAU_DevParam@@@Z")]
public static extern bool GetParameters(int ID, ref IntPtr dParam);

// At main
int size = Marshal.SizeOf(typeof(DevParam));
IntPtr Ptr = Marshal.AllocHGlobal(size);
bool res = Class1.GetParameters(ID, ref Ptr);
Console.WriteLine("Result: " + res);
var test = Marshal.PtrToStructure(Ptr, typeof(DevParam));
// No idea what I'll do here
Marshal.FreeHGlobal(Ptr);


In both cases the result "res" is true (means function was called correctly) but I'm not getting the struct. With the first solution the struct members have default values (all 0 with numbers, all false with bool), and with the second one, Ptr is 0, that means didn't get a correct memory address.

Any help? Been working in this for weeks already and I'm completely stuck.

Note: Don't have source code of the .dll
Note2: Don't have enough experience with dll imports. Would be good an explanation "for dummies"
Note3: Sorry for such a long post
Posted
Updated 2-Apr-19 4:09am
v5
Comments
11917640 Member 2-Apr-19 9:25am    
C# bool is not equal to WinAPI BOOL. C# char is not equal to C++ char. Check all types in PInvoke C# definitions. Check also, whether GetParameters function works properly when called from C++.
Member 14150748 2-Apr-19 9:46am    
I know there are the differences. But didnt have problems with other methods (as you can see, added the MarshalAs with all bools, the return doesnt mater much, I can change it to int). About the char, I read the equivalent is byte. was thinking to declare it as byte but then use a Convert.To with the symbol.

My main isue is with the struct. Dont have experience with them, let alone the PInvoke (it's my dfirst time using it). I dont know what else to do, been trying for weeks already, I feel frustrated, tired, and almost giving up (and I can't since it's for job purpoises)
11917640 Member 2-Apr-19 9:51am    
There are no "small" errors in PInvoke. Every incorrect definition means undefined behavior.
11917640 Member 2-Apr-19 9:49am    
In the second call ref IntPtr dParam should be IntPtr dParam. So, many small errors in the code, check everything carefully, especially C# - C++ - WinAPI types match.
Member 14150748 2-Apr-19 9:56am    
Without ref the result of the method is false (and should be true). that's why I added it.

just trying many options. I'm not really sure what I'm really doing. Just need something that works

I do not see anywhere in your code where you calling GetParameters() function. Also you need to know the exact name of the entry point and "mangledFunction" does not sound right (I am not a C# guru though). if you do not have the source code for the DLL and if it uses C++ mangling, you can use "DEPENDS.EXE" tool to lookup exact entry point name spelling
 
Share this answer
 
Comments
Member 14150748 2-Apr-19 9:27am    
Sorry, I had some typos. Fixed question.
Here comes the solution:

C#
// At the dll wrapper class
[DllImport(path, EntryPoint = "?GetParameters@@YGHKPAU_DevParam@@@Z")]
public static extern bool GetParameters(int ID, IntPtr dParam);

// At main
int size = Marshal.SizeOf(typeof(DevParam));
IntPtr Ptr = Marshal.AllocHGlobal(size);
bool res = Class1.GetParameters(ID, Ptr);
DevParam test = (DevParam)Marshal.PtrToStructure(Ptr, typeof(DevParam));

// For testing purpoises, previously changed the default values with another method
Console.WriteLine(test.Enable);

Marshal.FreeHGlobal(Ptr);


Thank you!
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900