将复杂的Struct(带有内部结构数组)从C#传递到C ++ [英] Passing a complex Struct (with inner array of struct) from C# to C++

查看:121
本文介绍了将复杂的Struct(带有内部结构数组)从C#传递到C ++的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为扫描仪驱动程序.除了本手册中的PDF之外,还使用本地C ++编写了提供程序提供的dll和头文件(没有源代码).需要在C#项目中使用它,但是我在结构上遇到了问题(尝试读取或发送它们).

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).

我使用命令提示符获取了dll方法,并在网站中对其进行了分解(因为它具有+100).当然,我不会使用所有它们,只是我需要的那些.实际上,使用原始数据类型的扫描仪没有问题,实际上使扫描仪处于打开/关闭,扫描等状态.

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.

我的主要问题如下:我需要设置一些参数,因为使用默认参数时,我没有获得所需的信息(实际上,这是我需要的最重要的东西).唯一的方法是使用包含2个参数的方法:ID(仅一个int)和设置(一个struct).该结构在内部没有一个结构实例,而是2个不同的结构实例(其中一个是数组,在另一种结构中作为参数之一).换句话说,需要使用4种不同的结构.

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.

我按照.h文件中提供的模板声明了所有结构,并导入了该方法.当我尝试进行测试时,它总是给我一个错误.我相信问题在于结构数组.我尝试了常规传递,封送处理,使用引脚排列,更改数据类型,为所有布尔变量添加了"MarshalAs"……似乎无济于事.

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.

过去几天试图解决这个问题.不知道我在做什么错(因为这是我第一次导入方法).我读到有关C ++/Cli的东西,但也从未使用过.

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)

.h文件(C ++)中的定义方式

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 )

这就是我在C#中构建结构的方式

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();
}

我期望什么?仅获取布尔值结果以查看方法是否成功执行(当然,如果为true,则扫描程序应该已经定义了新参数)

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.

请帮忙.预先感谢.

PD:很抱歉,我的帖子很长. PD2:我挺罗基的,所以请尝试解释一下傻瓜"

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

推荐答案

感谢汉斯.似乎有效!

只是按照建议修改了结构:

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;
   }
};

并使用了"Attemp1"代码.

And used the "Attemp1" code.

这篇关于将复杂的Struct(带有内部结构数组)从C#传递到C ++的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆