struct和IntPtr的元数据数组

姆莱加

我非常接近解决问题的方法,但是我需要一些收尾指导以使一切正常进行。在过去的一周里,我学到了很多关于

只是作为参考,我上周针对同一主题问了类似的问题,但是由于我方面的巨大监督,我提出了错误的问题。

我正在尝试使用非托管的c ++ dll,该dll是用于与连接的设备进行通信的API。我已经成功创建了包装器以及其他大多数函数调用,但是最后一个使我发疯。

有关某些背景信息(可能不需要回答此问题,请记住我当时的基本思维过程存在缺陷)在此处:用指针调用非托管代码(已更新)

在我最初的问题中,我问的是为包含一个struct(2)数组的struct(1)创建一个IntPtr。实际上,struct(1)根本不包含数组,它包含一个指向数组。

这是我尝试实现作为参考的API文档:

extern “C” long WINAPI PassThruIoctl
(
    unsigned long ChannelID,
    unsigned long IoctlID,
    void *pInput,
    void *pOutput
)


// *pInput Points to the structure SCONFIG_LIST, which is defined as follows:
// *pOutput is not used in this function and is a null pointer

typedef struct
{
    unsigned long NumOfParams; /* number of SCONFIG elements */
    SCONFIG *ConfigPtr; /* array of SCONFIG */
} SCONFIG_LIST

// Where:
// NumOfParms is an INPUT, which contains the number of SCONFIG elements in the array pointed to by ConfigPtr.
// ConfigPtr is a pointer to an array of SCONFIG structures.

// The structure SCONFIG is defined as follows:
typedef struct
{
    unsigned long Parameter; /* name of parameter */
    unsigned long Value; /* value of the parameter */
} SCONFIG

这是我目前定义的结构定义

[StructLayout(LayoutKind.Sequential)] // Also tried with Pack=1
public struct SConfig 
{
   public UInt32 Parameter;
   public UInt32 Value;
}



[StructLayout(LayoutKind.Sequential)] // Also tried with Pack=1
public struct SConfig_List
{
    public UInt32 NumOfParams;
    public IntPtr configPtr;

    public SConfig_List(UInt32 nParams, SConfig[] config)
    {
        this.NumOfParams = nParams;

        //  I have tried these 2 lines together
        IntPtr temp = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MyNameSpace.SConfig)) * (int)nParams);
        this.configPtr = new IntPtr(temp.ToInt32());

        // I have tried this by itself
        // this.configPtr  = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MyNameSpace.SConfig)) * (int)nParams);


        // and this line
        // this.configPtr = Marshal.AllocHGlobal(sizeof(SConfig)*(int)nParams);  // this only complies with unsafe struct
    }
}

这是将这些代码设置为变量并调用与API接口的函数的代码段

SConfig[] arr_sconfig;
arr_sconfig = new SConfig[1];

arr_sconfig[0].Parameter = 0x04;
arr_sconfig[0].Value = 0xF1;
SConfig_List myConfig = new SConfig_List(1, arr_sconfig);

m_status = m_APIBox.SetConfig(m_channelId, ref myConfig);

最后,这是将这些信息传递给dll的函数:

public APIErr SetConfig(int channelId, ref SConfig_List config)
{
    unsafe
    {
        IntPtr output = IntPtr.Zero; // Output not used, just a null pointer for this function

        //   These 2 lines of code cause API dll to yell about invalid pointer (C# is happy but it doesnt work with dll)
        //   IntPtr temp = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(J_2534_API.SConfig_List)));
        //   IntPtr input = new IntPtr(temp.ToInt32());

        //  The following 2 lines only compile with unsafe - but API dll "likes" the pointer - but I am not getting desired results
        //  The dll is properly getting the Number of Parameters (NumOfParams), but the data within the array is not being
        //  referenced correctly
        IntPtr input = Marshal.AllocHGlobal(sizeof(SConfig_List)); // Only works with unsafe
        Marshal.StructureToPtr(config, input, true);

        APIErr returnVal = (APIErr)m_wrapper.Ioctl(channelId, (int)Ioctl.SET_CONFIG, input, output);

        return returnVal;
    }
}

在我意识到基本概念的巨大监督之前,我什至无法使C#高兴,要么我的语法错误并且代码无法编译,要么会编译但给出运行时错误(甚至都不会调用外部dll) )

这些问题在我身后。该代码现在可以正常编译,并且可以在没有任何运行时错误的情况下执行。此外,我正在使用的dll具有日志记录功能,因此我可以看到实际上正在调用正确的函数。我什至正确地传递了一些数据。该函数已正确读取NumOfParams变量,但结构数组似乎是垃圾数据。

我在这里阅读了一篇非常有帮助的文章:http : //limbioliong.wordpress.com/2012/02/28/marshaling-a-safearray-of-managed-structures-by-pinvoke-part-1/

而且我一直在阅读MSDN,但是到目前为止,我还没有发现使这件事起作用的神奇代码组合,因此我要花更多时间寻求帮助。

我很确定我的问题是我没有正确设置IntPtr变量,并且它们没有指向内存中的正确区域。

我尝试了不安全代码和安全代码的各种组合。另外,我知道我现在还没有显式释放内存,因此在该指针上也将有所帮助。在我的研究中,这里有一些可能有用的想法,但我似乎无法使它们正确无误

[MarshalAs(UnmanagedType.LPWStr)]

[MarshalAs(UnmanagedType.ByValArray, SizeConst=...)]

[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst=100)]

最后一个问题:我假设既然c ++声明是无符号的,那么UInt32是C#中正确的类型吗?

汉斯·帕桑特

代码段中的SConfig_List构造函数有很多错误。最大的问题是,它为数组分配了内存,但是完全忘记了复制结构。因此,本机代码可以正常使用指针,但可以查看未初始化的内存。您可以这样解决:

    public SConfig_List(SConfig[] config) {
        this.NumOfParams = config.Length;
        int size = Marshal.SizeOf(config[0]);
        IntPtr mem = this.configPtr = Marshal.AllocHGlobal(size * config.Length);
        for (int ix = 0; ix < config.Length; ++ix) {
            Marshal.StructureToPtr(config[ix], mem, false);
            mem = new IntPtr((long)mem + size);
        }
    }

请确保不要忘记在调用完成后再次调用Marshal.FreeHGlobal(),否则会浪费内存。

避免封送SConfig_List的最简单方法是为C函数提供更好的声明:

[DllImport(...)]
private static extern ApiErr PassThruIoctl(
    int channelID, 
    uint ioctlID,
    ref SConfig_List input,
    IntPtr output);

这使得像样的包装方法看起来像这样:

public APIErr SetConfig(int channelId, SConfig[] config) {
    var list = new SConfig_List(config);
    var retval = PassThruIoctl(channelId, Ioctl.SET_CONFIG, ref list, IntPtr.Zero);
    Marshal.FreeHGlobal(list.configPtr);
    return retval;
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

struct和struct成员的数组元素

来自分类Dev

numpy数组元数据更改

来自分类Dev

MBeanOperationInfo和MBeanAttributeInfo元数据?

来自分类Dev

SPFieldUserValue和SharePoint元数据

来自分类Dev

获取IntPtr指向的数组的大小

来自分类Dev

Clojure基本数组类型元数据

来自分类Dev

在数组内过滤元数据

来自分类Dev

Clojure基本数组类型元数据

来自分类Dev

struct和malloc中的动态数组失败

来自分类Dev

converting IntPtr as c# struct pointer

来自分类Dev

MATLAB元胞数组索引和循环

来自分类Dev

正确比较IntPtr和int

来自分类Dev

Marshal.Copy,将IntPtr数组复制到IntPtr

来自分类Dev

PHP:将元数据数组添加到 JSON 数组

来自分类Dev

Hive与Spark和MySQL元数据存储

来自分类Dev

从Ember路由添加和检索元数据

来自分类Dev

SqlDataReader和元数据的内部工作

来自分类Dev

反射和元数据之间的区别

来自分类Dev

MySQL搜索,结合表和元数据

来自分类Dev

视图和布局中的元数据/元素

来自分类Dev

查找命令和对媒体元数据的支持

来自分类Dev

分配和检查bash函数元数据

来自分类Dev

存储库元数据和本地包

来自分类Dev

Spring组件扫描注释和元数据

来自分类Dev

提取,编辑和保存.dwg元数据

来自分类Dev

JPEG 和 PNG 元数据压缩

来自分类Dev

SimpleSAMLphp 设置和 SP 元数据

来自分类Dev

Intptr,Intptr.Zero和ref int in Java等效项:

来自分类Dev

AngularJS和PHP数组数据