如何在C#.Net CF中使用以下任务执行memcpy

如何在C#.Net CF中使用以下任务执行memcpy,c#,c++,.net,windows-embedded-compact,C#,C++,.net,Windows Embedded Compact,您好,我正在尝试将C/C++结构转换为C#,以及如何用C#中另一个结构的地址填充结构成员 C/C++结构看起来像: typedef struct _NDISUIO_QUERY_OID { NDIS_OID Oid; PTCHAR ptcDeviceName; UCHAR Data[sizeof(ULONG)]; } NDI

您好,我正在尝试将C/C++结构转换为C#,以及如何用C#中另一个结构的地址填充结构成员

C/C++结构看起来像:

         typedef struct _NDISUIO_QUERY_OID
         {
           NDIS_OID        Oid;
           PTCHAR          ptcDeviceName;  
           UCHAR           Data[sizeof(ULONG)];
         } NDISUIO_QUERY_OID, *PNDISUIO_QUERY_OID;

         typedef struct My_Struct
         {
           //les have 2 variables...  
            UINT    a;
            UINT    b;
         }My_STATS, *PMy_STATS;

         PNDISUIO_QUERY_OID     pQueryOid = NULL;

         pQueryOid = (PNDISUIO_QUERY_OID)malloc(sizeof(NDISUIO_QUERY_OID)+ sizeof(My_STATS)) ;

         PMy_STATS   Statistics;
          pQueryOid->Oid = ulOIDCode;//Required OID
      pQueryOid->ptcDeviceName = AUB_NAME;//REquired STRING

         memcpy(pQueryOid->Data, Statistics, sizeof(My_STATS));
我的C#Struct是:

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]

    public struct _NDISUIO_QUERY_OID
    {
        public uint        Oid;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string          ptcDeviceName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = sizeof(uint))]
        public string Data;
    };
问题:如何将统计结构复制到C#中的数据数组


谢谢:)

安全地说,你不能。NET强制执行类型安全性,这意味着您不能强制字符串成为结构。但是,您可以查看数据,而不是执行不安全的类型转换(为什么首先要将两个
uint
s存储在一个字符串中?并将其编组为unicode

首先,您必须将
数据
制作成一个字节数组。也可以使用字符串来实现这一点,但这只是在混合中增加了编码问题;如果可以,可以使用
字节[]
。此外,如果您不需要在其中包含不同类型的数据(看起来是这样的),您可以简单地将两个
uint
字段放在结构内部,它应该可以正常工作:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct _NDISUIO_QUERY_OID
{
    public uint Oid;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string ptcDeviceName;
    public uint DataA;
    public uint DataB;
};
第二种方法将使用常量大小的字节数组,长度足以容纳两个UINT:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct _NDISUIO_QUERY_OID
{
    public uint Oid;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string ptcDeviceName;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = sizeof(ulong))]
    public byte[] Data;
};
前四个字节将是第一个
uint
,下一个字节将是第二个

当然,您也可以像在原始代码中一样使用.NET结构-只需确保在
\NDISUIO\u QUERY\u OID
中使用正确的数据类型,它就可以自动工作


但需要注意的是,返回的数据实际上不一定是固定长度的。这相当棘手,基本上意味着您必须根据指针和长度手动反序列化结构。

安全地说,您不能..NET强制执行类型安全,这意味着您无法强制字符串成为stru但是,您可以查看数据,而不是执行不安全的类型转换(为什么首先要将两个
uint
s存储在一个字符串中?并将其编组为unicode

首先,您必须将
数据
制作成一个字节数组。也可以使用字符串来实现这一点,但这只是在混合中增加了编码问题;如果可以,可以使用
字节[]
。此外,如果您不需要在其中包含不同类型的数据(看起来是这样的),您可以简单地将两个
uint
字段放在结构内部,它应该可以正常工作:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct _NDISUIO_QUERY_OID
{
    public uint Oid;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string ptcDeviceName;
    public uint DataA;
    public uint DataB;
};
第二种方法将使用常量大小的字节数组,长度足以容纳两个UINT:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct _NDISUIO_QUERY_OID
{
    public uint Oid;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string ptcDeviceName;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = sizeof(ulong))]
    public byte[] Data;
};
前四个字节将是第一个
uint
,下一个字节将是第二个

当然,您也可以像在原始代码中一样使用.NET结构-只需确保在
\NDISUIO\u QUERY\u OID
中使用正确的数据类型,它就可以自动工作

但需要注意的是,返回的数据实际上不一定是固定长度的。这相当棘手,基本上意味着您必须根据得到的指针和长度手动反序列化结构。

这是我的实现(仅供参考,SDF包含所有这些代码和更多)

请注意,在我的使用中,NDIS IOCT接收一个指针(我的大部分NDIS工作都是不安全的),因此您必须在那里进行一些调整

例如,如果您正在查询BSSID,我知道BSSID数据是36字节,所以我会创建如下内容:

var queryOID = new NDISQueryOid(36);
int len = BitConverter.ToInt32(data, 0);
if (len > 0)
{
    ssid = System.Text.Encoding.ASCII.GetString(data, 4, len);
}
然后分配名称并调用NDI(生产代码的检查比这多得多):

编辑

因此,上面的
result
成员是查询“result”的字节数组。它的含义和解释方式取决于您查询的OID是什么。例如,如果您正在查询当前连接的SSID(即
NDIS_OID.SSID
),然后返回为4字节长度,后跟ASCII编码的名称,因此您可以这样破译它:

var queryOID = new NDISQueryOid(36);
int len = BitConverter.ToInt32(data, 0);
if (len > 0)
{
    ssid = System.Text.Encoding.ASCII.GetString(data, 4, len);
}
但同样,这只适用于一个特定的OID。您必须为您决定支持的每个传入OID处理每个返回案例。

这是我的实现(仅供参考,SDF包含所有这些代码和更多)

请注意,在我的使用中,NDIS IOCT接收一个指针(我的大部分NDIS工作都是不安全的),因此您必须在那里进行一些调整

例如,如果您正在查询BSSID,我知道BSSID数据是36字节,所以我会创建如下内容:

var queryOID = new NDISQueryOid(36);
int len = BitConverter.ToInt32(data, 0);
if (len > 0)
{
    ssid = System.Text.Encoding.ASCII.GetString(data, 4, len);
}
然后分配名称并调用NDI(生产代码的检查比这多得多):

编辑

因此,上面的
result
成员是查询“result”的字节数组。它的含义和解释方式取决于您查询的OID是什么。例如,如果您正在查询当前连接的SSID(即
NDIS_OID.SSID
),然后返回为4字节长度,后跟ASCII编码的名称,因此您可以这样破译它:

var queryOID = new NDISQueryOid(36);
int len = BitConverter.ToInt32(data, 0);
if (len > 0)
{
    ssid = System.Text.Encoding.ASCII.GetString(data, 4, len);
}

<>但是,这只针对一个特定的OID。你必须处理每一个你决定支持的IOR的返回情况。

< P>你的C++代码的翻译是错误的:C++的代码等价于C++ > char []/Cord>不是字符串,它是<代码>字节[]。一旦具备了这些功能,您通常只需要知道如何将结构复制到字节数组中。下面是一个可编译的示例:

using System;
using System.Runtime.InteropServices;


    struct Dest
    {
        public byte[] Data;
    }

    struct Src
    {
        public GCHandle StringHandle;
        public long A;
        public long B;
    }

    class Program
    {
        static void Main()
        {
            Copy();
        }

        static void Copy()
        {
            var str = "Hello";
            var src = new Src { 
                A = 3, 
                B = 4, 
                StringHandle = GCHandle.Alloc(str, GCHandleType.Normal) 
            };
            var dst = new Dest();

            unsafe
            {
                Src* srcPtr = &src;
                dst.Data = new byte[sizeof(Src)];
                Marshal.Copy((IntPtr)srcPtr, dst.Data, 0, sizeof(Src));
            }

            // When you're sure no one can reference the string anymore
            // (Including by accessing the data you put in dst.Data!)
            src.StringHandle.Free();
        }

编辑:添加了如何处理引用类型(如字符串)的例子。

< P>首先,您的C++代码的翻译错误:C++的代码等价于C++ > char []/COD>不是字符串,它是<代码>字节[]。一旦具备了这些功能,您通常只需要知道如何将结构复制到字节数组中。下面是一个可编译的示例:

using System;
using System.Runtime.InteropServices;


    struct Dest
    {
        public byte[] Data;
    }

    struct Src
    {
        public GCHandle StringHandle;
        public long A;
        public long B;
    }

    class Program
    {
        static void Main()
        {
            Copy();
        }

        static void Copy()
        {
            var str = "Hello";
            var src = new Src { 
                A = 3, 
                B = 4, 
                StringHandle = GCHandle.Alloc(str, GCHandleType.Normal) 
            };
            var dst = new Dest();

            unsafe
            {
                Src* srcPtr = &src;
                dst.Data = new byte[sizeof(Src)];
                Marshal.Copy((IntPtr)srcPtr, dst.Data, 0, sizeof(Src));
            }

            // When you're sure no one can reference the string anymore
            // (Including by accessing the data you put in dst.Data!)
            src.StringHandle.Free();
        }

编辑:添加了如何处理引用类型(如字符串)的示例。

我的任务是将结构“Statistics”地址复制到查询OID结构中的“Data”中。在byte[]中,我们如何复制另一个结构地址?@arya2arya您不能。但是,这并不重要,因为您可以序列化结构i