ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

整理SAFEARRAY变量,这些变量是C#的BYTE

2019-11-18 02:18:40  阅读:285  来源: 互联网

标签:byte com-interop safearray c c-4


我创建了一个SAFEARRAY,用于存储在C中为BYTE的变量.

当此结构编组到C#时,发生了一件奇怪的事情.

如果我在C#中将此结构的内容打印到WinForms ListBox中,例如:

byte data[]
TestSafeArray(out data);

lstOutput.Items.Clear();    
foreach (byte x in data)
{
    lstOutput.Items.Add(x); // Strange numbers
}

我得到一些似乎与原始数字无关的数字.此外,每次我运行C#客户端进行新测试时,都会得到一组不同的数字.

请注意,如果我使用Visual Studio调试器检查该数据数组的内容,则会得到正确的数字,如以下屏幕快照所示:

VS debugger shows the correct numbers

但是,如果将CopyTo编组的数据数组复制到一个新数组,则会得到正确的数字:

        byte[] data;
        TestSafeArray(out data);

        // Copy to a new byte array
        byte[] byteData = new byte[data.Length];
        data.CopyTo(byteData, 0);

        lstOutput.Items.Clear();
        foreach (byte x in byteData)
        {               
            lstOutput.Items.Add(x); // ** WORKS! **
        }

这是我用来构建SAFEARRAY的C repro代码(此函数从本地DLL导出):

extern "C" HRESULT __stdcall TestSafeArray(/* [out] */ SAFEARRAY** ppsa)
{
    HRESULT hr = S_OK;
    try 
    {
        const std::vector<BYTE> v{ 11, 22, 33, 44 };

        const int count = static_cast<int>(v.size());
        CComSafeArray<VARIANT> sa(count);

        for (int i = 0; i < count; i++)
        {
            CComVariant var(v[i]);

            hr = sa.SetAt(i, var);
            if (FAILED(hr))
            {
                return hr;
            }
        }

        *ppsa = sa.Detach();
    } 
    catch (const CAtlException& e)
    {
        hr = e;
    }

    return hr;
}

这是我使用的C#P / Invoke:

[DllImport("NativeDll.dll", PreserveSig = false)]
private static extern void TestSafeArray(
    [Out, MarshalAs(UnmanagedType.SafeArray, 
                    SafeArraySubType = VarEnum.VT_VARIANT)]
    out byte[] result);

请注意,如果在C中创建一个直接存储BYTE的SAFEARRAY(而不是SAFEARRAY(VARIANT)),那么我将立即在C#中获得正确的值,而无需中间的CopyTo操作.

解决方法:

[Out, MarshalAs(UnmanagedType.SafeArray, 
                SafeArraySubType = VarEnum.VT_VARIANT)]
out byte[] result);

你开玩笑了您告诉编组器,您想要一组变量,这些变量确实与C编译器产生的变量兼容.它将忠实地产生一个object [],object是VARIANT的标准封送处理.数组的元素是装箱的字节.

但这并没有愚弄调试器,它忽略了程序声明,而是查看了数组类型和发现的object [],这些在屏幕快照中很容易看到.因此,它可以正确访问装箱的字节.而且它没有欺骗Array.CopyTo(),它接受Array参数,因此被迫查看元素类型.并将装箱的字节正确转换为字节,它知道该怎么做.

但是C#编译器被愚弄了.它不知道它需要发出一个拆箱指令.实际不确定出什么问题,您可能正在获取对象地址的低字节.确实是相当随机的:)

在pinvoke声明中进行纤维化非常有用.如果数组包含实际对象(例如字符串,数组或接口指针),则在这种特殊情况下效果很好.警官没有尖叫血腥谋杀的可能原因.不在这里,拳击很糟糕.您必须修复声明,使用object [].

标签:byte,com-interop,safearray,c,c-4
来源: https://codeday.me/bug/20191118/2024756.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有