0

I'm working on a driver for a scanner. Got dll and header files from provider, aside of a manual in PDF, written in native C++ (dont have source code). Need to use it within a C# project but I'm having problems with the structs (either trying to read or send them).

I got the dll methods using the Command Prompt, demangling them in a website (since it has +100). Of course, I wont use all of them, just the ones I need. Didn't have problems with the ones using primitive data types, in fact, made the scanner turn on/off, scan and such.

My main problem is the following: I need to set some parameters, because with the default ones I'm not getting the needed info (and that's the MOST important thing I need, actually). The only way to do it is with a method that include 2 params: the ID (just an int) and the setting (an struct). That struct has internally not one, but 2 different structs instances (and one of them is an array, within another kind of struct as one of the params). In other words, gonna need to work with 4 different structs.

I declared all my structs, following the template provided in the .h file, and inmported the method. When I try to do a test it keeps giving me an error. I believe the problem is the array of structs. I tried with a normal passing, Marshaling, using a pin to array, changing data type, adding a "MarshalAs" with all bool vars... nothing seems to work.

Been trying to solve this for days already. Dont know what am I doing wrong (because this is my first time importing methods). I read about the C++/Cli thing but never worked with that either.

See code below (I kinda modified a little because of confidentiality of the information)

This is how is defined in the .h file (C++)

// The structs (won't add all parameters, but are basically the same type)
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.

// This is how is defined
BOOL SetParameters( DWORD ID, DevParams DParam )

This is how I build the structs in 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;
   public bool Milli;

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

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

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

// Commented code is from another attemp
[StructLayout(LayoutKind.Sequential)]
public struct DevParam
{
   public bool Enable;
   public uint Font;
   public char Symbol;
   public ImParam Image1;
   public ImParam Image2;
   public IntPtr Properties;
   //public sProperties[] Properties;
   public uint FeedMode;

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

// .dll file path definition, some methods imported, etc. etc.
[DllImport(path, EntryPoint = "?SetParameters@@YGHKU_DevParam@@@Z")]
public static extern bool SetParameters(int ID, DevParam dParam);

And this is when I do call it (added commented code to show you my attemps)

static void Main(string[] args)
{
    bool res = false;
    int ID;
    sProperties[] SnP = new sProperties[10];
    for (int i = 0; i < 10; i++)
        SnP[i] = new sProperties(0);

    try
    {
        // Some code to turn on scanner, get ID value and such

        /* Attemp1: Passing the struct normaly.
         * Result: ArgumentException [HRESULT: 0x80070057 (E_INVALIDARG))]
         * try
         * {
         *     DevParam dParam = new DevParam(10);
         *     res = Class1.SetParameters(ID, dParam);
         *     Console.WriteLine(res);
         * }
         * catch (Exception e) { Console.WriteLine(e); }*/

        /* Attemp2: Marshaling each element of the array.
         * Result: The managed PInvoke signature doesnt mach the destination one
         * int S = Marshal.SizeOf(typeof(sProperties));
         * DevParam dParam = new DevParam(Marshal.AllocHGlobal(SnP.Length*S));
         * IntPtr ptr = dParam.Properties;
         * for (int i = 0; i < SnP.Length; i++)
         * {
         *     Marshal.StructureToPtr(SnP[i], ptr, false);
         *     ptr += S;
         * }
         * try
         * {
         *     res = Class1.SetDevParam(ID, dParam);
         *     Console.WriteLine(res);
         * }
         * finally { Marshal.FreeHGlobal(dParam.sProperties); }*/

         /* Attemp3: Adding a Pin Pointer to struct
          * Result: Exception (Object has no primitive data and it can't
          *     be transfered into bits blocks) */
         GCHandle SpHandle = GCHandle.Alloc(SnP, GCHandleType.Pinned);
         try
         {
             DevParam dParam = new DevParam(SpHandle.AddrOfPinnedObject());
             res = Class1.SetParameters(ID, dParam);
             Console.WriteLine(res);
         }
         catch (Exception e) { Console.WriteLine(e); }
         finally { SpHandle.Free(); }

         // More code for testing other methods and blahblahblah
     }
     catch (Exception e) { Console.WriteLine(e); }
     Console.WriteLine("Finished");
     Console.ReadKey();
}

What do I expect? Getting just a boolean result to see if method executed sucessfully (and of course, if true, scanner should have defined the new parameters)

What do I get? A bunch of exceptions.

Please, any help would be great. Thanks in advance.

PD: Sorry for that long post. PD2: I'm quite rockie, so please try to explain it "for dummies"

4
  • Hello and welcome to StackOverflow. It is a long post indeed, yet it would probably help to post the first exception you're getting, at least. Commented Mar 27, 2019 at 21:08
  • An embedded array is not IntPtr. Just use a normal array[]. It needs [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] to marshal correctly. Commented Mar 27, 2019 at 21:59
  • Thanks Pedro. Those exceptions are in the comments. The first one.... It's like that (that's what system says) Commented Mar 28, 2019 at 1:15
  • Hey Hans. Was hopping you would reply. Gonna try with that. Perhaps adapting the "Attempt2" code? I'll try tomorrow at job and gonna let you know. Thanks for feedback Commented Mar 28, 2019 at 1:18

1 Answer 1

1

Thanks Hans. Seems it worked!

Just modiffied the struct as suggested:

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

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

And used the "Attemp1" code.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.