C#调用C++ Com方法具有二级指针的结构体输出参数

时间:2022-08-30 21:35:42
C++:
方法原型:
        virtual HRESULT STDMETHODCALLTYPE Read( 
            /* [in] */  IItemIdentity *IdItems,
            /* [in] */ unsigned int ItemsCount,
            /* [out] */  DataUpdate **pDataUpdates,
            /* [retval][out] */ unsigned int *UpdatesCount) = 0;

参数“IItemIdentity”结构体原型:

typedef struct  _IItemIdentity    {
    WCHAR *ContextName;
    unsigned __int64 Id;
    WCHAR *Name;
    int ReferenceType;
    int Type;
    }  IItemIdentity;

参数“DataUpdate ”结构体原型:

typedef struct  _DataUpdate    {
    unsigned __int64 ItemId;
    unsigned long StatusCode;
    FILETIME Timestamp;
    unsigned long Quality;
     IVariant Value;
    }  DataUpdate;

参数“IVariant”结构体原型:

typedef struct  _IVariant    {
    int Length;
     IWS_BYTES Payload;
    int Type;
    }  IVariant;

参数“IWS_BYTES ”结构体原型:

typedef struct  _IWS_BYTES    {
    ULONG length;
    BYTE *bytes;
    }  IWS_BYTES;

=====================================
C#调用:

参数“DataUpdate”结构体转换到C#结构体如下:

        //To C# structure
        [StructLayout(LayoutKind.Explicit)]
        public struct DataUpdate
        {
            [FieldOffset(0)]
            public Int64 ItemId;
            [FieldOffset(0)]
            public Int32 Quality;
            [FieldOffset(0)]
            public Int32 StatusCode;
            [FieldOffset(0)]
            MXDATACONSUMERLib._FILETIME Timestamp;
            [FieldOffset(0)]
            MXDATACONSUMERLib._IVariant Value;
        }

MXDATACONSUMERLib.IDataClient iDataClient = new MXDATACONSUMERLib.DataClient();

//Read one or more items registered.
public List<long> Read(ref List<MXDATACONSUMERLib._IItemIdentity> itemIdentitys, out List<DataUpdate> itemDataUpdates, out string error)
        {
            error = null;
            itemDataUpdates = null;
            List<DataUpdate> tempDataUpdate = new List<DataUpdate>();
            uint itemid = 0;
            int m = 0;
            List<long> list = new List<long>();

            DataUpdate dataUpdate = new DataUpdate();
            IntPtr dataUpdatePtr = Marshal.AllocHGlobal(Marshal.SizeOf(dataUpdate));
            Marshal.StructureToPtr(dataUpdate, dataUpdatePtr, false);

            try
            {
                foreach (MXDATACONSUMERLib._IItemIdentity itemIdentity in itemIdentitys)
                {
                    itemid = iDataClient. Read(itemIdentity, 1, dataUpdatePtr);
                    list.Add(itemid);

                    dataUpdate = (DataUpdate)Marshal.PtrToStructure(dataUpdatePtr, typeof(DataUpdate));
                    tempDataUpdate.Insert(m, dataUpdate);
                    itemDataUpdates = tempDataUpdate;

                    m = m + 1;
                }
            }
            catch (SystemException se)
            {
                error = se.Message.ToString();
            }

            return list;
        }

调用Read(...)方法最后提示“The operation did not complete within the time allotted. (Exception from HRESULT: 0x803D0006)”

本人没有完过C#调用C++ Com方法,不知哪位“大虾”能解燃眉之急,跪谢!

7 个解决方案

#1


楼主,你明白[FieldOffset(0)]的意思吗?

既然是COM组件,那么它里面的涉及的数据类型:IItemIdentity 、DataUpdate 、FILETIME 、_IVariant、_IWS_BYTES等会自然在IDL接口里面声明,也就是说,你直接把这个组件的dll添加到C#的工程中,如果普通的托管代码写的dll一样使用!

#2


楼主,你好,"FieldOffset"这个东东也在是网上看C++结构体在转化成C#结构体是要用,本人也不甚了解,甚求解。
本人现在最大的症结在于C#如何调用及使用C++方法具有out二级指针参数,如:
C++:
        virtual HRESULT STDMETHODCALLTYPE Read( 
            /* [in] */  IItemIdentity *IdItems,
            /* [in] */ unsigned int ItemsCount,
            /* [out] */  DataUpdate **pDataUpdates,
            /* [retval][out] */ unsigned int *UpdatesCount) = 0;

C#调用如下:
uint Read( ref MXDATACONSUMERLib._IItemIdentity IdItems, uint ItemsCount, System.IntPtr  pDataUpdates)

一级指针在C#里“IItemIdentity ”似乎传递没有多大问题,但二级指针我做了如下处理:
             MXDATACONSUMERLib._DataUpdate dataUpdate = new  MXDATACONSUMERLib._DataUpdate();
            IntPtr dataUpdatePtr = Marshal.AllocHGlobal(Marshal.SizeOf(dataUpdate));
            Marshal.StructureToPtr(dataUpdate, dataUpdatePtr, false);

然后再把“dataUpdatePtr”传递给Read(...)方法, 总是出现了错误提示:“The operation did not complete within the time allotted. (Exception from HRESULT: 0x803D0006)”,折腾了我好久,总是不知道如何解决啊,求“大虾”再次指点迷津,跪谢!




#3


你把这com的dll,还有测试它的Demo程序,一起发给我看看:
   sdl2002lyx@163.com

#4


楼主,你好,我们这个Demo需要特殊的运行环境,给了你也运行不起来,谢谢你的好意!
本人现在最大的症结在于C#如何调用及使用C++方法具有out二级指针参数,如何传递的问题,再次谢先了!

#5


你发给我,我只是编译测试,不运行,这样说来说去,很久都说不清楚。我写好传入参数,发给你测试,知道吗?

#6


请问 void ** 二级指针如何声明成托管类型?
谢谢

#7


http://blog.csdn.net/emailqjc/article/details/6704435
hope it helps

#1


楼主,你明白[FieldOffset(0)]的意思吗?

既然是COM组件,那么它里面的涉及的数据类型:IItemIdentity 、DataUpdate 、FILETIME 、_IVariant、_IWS_BYTES等会自然在IDL接口里面声明,也就是说,你直接把这个组件的dll添加到C#的工程中,如果普通的托管代码写的dll一样使用!

#2


楼主,你好,"FieldOffset"这个东东也在是网上看C++结构体在转化成C#结构体是要用,本人也不甚了解,甚求解。
本人现在最大的症结在于C#如何调用及使用C++方法具有out二级指针参数,如:
C++:
        virtual HRESULT STDMETHODCALLTYPE Read( 
            /* [in] */  IItemIdentity *IdItems,
            /* [in] */ unsigned int ItemsCount,
            /* [out] */  DataUpdate **pDataUpdates,
            /* [retval][out] */ unsigned int *UpdatesCount) = 0;

C#调用如下:
uint Read( ref MXDATACONSUMERLib._IItemIdentity IdItems, uint ItemsCount, System.IntPtr  pDataUpdates)

一级指针在C#里“IItemIdentity ”似乎传递没有多大问题,但二级指针我做了如下处理:
             MXDATACONSUMERLib._DataUpdate dataUpdate = new  MXDATACONSUMERLib._DataUpdate();
            IntPtr dataUpdatePtr = Marshal.AllocHGlobal(Marshal.SizeOf(dataUpdate));
            Marshal.StructureToPtr(dataUpdate, dataUpdatePtr, false);

然后再把“dataUpdatePtr”传递给Read(...)方法, 总是出现了错误提示:“The operation did not complete within the time allotted. (Exception from HRESULT: 0x803D0006)”,折腾了我好久,总是不知道如何解决啊,求“大虾”再次指点迷津,跪谢!




#3


你把这com的dll,还有测试它的Demo程序,一起发给我看看:
   sdl2002lyx@163.com

#4


楼主,你好,我们这个Demo需要特殊的运行环境,给了你也运行不起来,谢谢你的好意!
本人现在最大的症结在于C#如何调用及使用C++方法具有out二级指针参数,如何传递的问题,再次谢先了!

#5


你发给我,我只是编译测试,不运行,这样说来说去,很久都说不清楚。我写好传入参数,发给你测试,知道吗?

#6


请问 void ** 二级指针如何声明成托管类型?
谢谢

#7


http://blog.csdn.net/emailqjc/article/details/6704435
hope it helps