zoukankan      html  css  js  c++  java
  • 浅尝辄止——在C++中调用C#的回调函数——COM方式

    这种方式比较简单,给大家分享一下,同时讲一下SafeArray内定义结构体的方法

    1. 需求描述

    需求是这样的,C++代码和C#代码相互通信(C++一般做服务,C#做客户端),C++一侧准备好数据,然后发给C#端解析,这种需求还是比较常见的。

    但是由于数据比较复杂,是一个数据结构,还可能数据结构里套用数据结构,总之数据很复杂(其实我觉得使用xml字符串传递比较理想,兼容性也比较好,但作为程序员有时候没有选择的权利)

    2. 定义COM文件,idl文件

    对于这个文件不熟悉的自己百度谷歌查查吧。

    首先在文件里定义回调接口,也就是C#端需要继承的接口

    [object, uuid, oleautomation,helpstring,...] // 内容自己填吧

    interface IDataEvent : IUnknown{

      HRESULT OnDataEvent([in] SAFEARRAY(struct SData)* psaDataList);

    };

    其次定义C++导出接口,也就是C++端需要继承的接口

    [object, uuid, dual, nonextensible,...]

    interface IDataServer : IDispatch{

      ......

      [id(n)] InitCallback([in] IDataEvent* pCallback);  // 你也可以改为AddListener什么的

    };

    然后需要定义你的结构体和相关的其他信息

    [uuid...]

    library DataServer{

      enum EnumType{

        XXX_YYY = 0x01,......

      };

      [uuid...]

      struct SData{

        BSTR name;

        LONGLONG time;  // 使用longlong表示filetime,这个里边不仅有年月日十分秒,还有毫秒信息,更重要的是UTC时间

        VARIANT saValueList;  // 在C#端变成object,根据具体的类型再强转吧,或者在C#端一直保持object类型的状态,你也可以直接使用double或BSTR等类型

        SAFEARAY(xxxx) saList;  // 定义你自己的类型,别忘了xxxx需要定义好哦!

      };

      ......

    };

    这个文件编译时会生成tlb文件,交给C#直接添加reference就可以啦,如果添加失败,可以手动转换,使用.NET提供的编译工具“Tlbimp”,命令行参考如下

    tlbimp myLib.tlb /out:myLib.dll

    也可以直接在代码里import这个tlb文件,只不过使用tlb里导出的类型有点不太方便。

    3. C#端处理

    一般的处理过程是这样的

    (1)启动部分,通过各自的手段获得C++端提供的服务对象,将其强转成导出接口对象IDataServer

    (2)自己创建一个类用于接受数据 class DataClient : IDataEvent,调用IDataServer的注册回调的函数,将DataClient对象传给C++端

    (3)在DataClient类中实现这个函数 public void OnDataEvent(ref Array psaDataList),解析数据吧,遍历Array,将内容强转成SData

    这里需要注意的是,一般服务端返回数据时,由于数据量可能比较大,都是通过一个子线程完成的,所以C#端的这个OnDataEvent函数需要判断当前是否是UI线程,如果不是的话,不要直接改变UI,这可能导致UI锁住,正确的做法使用异步处理方式,比如将数据缓存起来,等待UI处理,或者使用UI.InvokeRequired方法与UI抢控制权,然后再处理UI。

    4. C++端处理数据

    C++端填充数据的过程是这样的

    CComPtr<IRecordInfo> pRecord;
    GetRecordInfoFromGuids(LIBID_xxx, 1, 0, ::GetUserDefaultLCID(), __uuid(SData), &pRecord);
    ......
    SAFEARAY *psa = ::SafeArrayCreateEx(VT_RECORD, 1, &bound, pRecord);
    ::SafeArrayAccessData(psa, (void**)&pList);
    ...... // fill data
    ::SafeArrayUnaccessData(psa);

    CSharpObj->OnDataEvent(&psa); // send to C# object

    ::SafeArrayAccessData(psa, (void**)&pList);
    ...... // release data
    ::SafeArrayUnaccessData(psa);
    ::SafeArrayDestory(psa);

  • 相关阅读:
    Pig设计模式概要以及与SQL的设计模式的对比
    Pig设计模式概要以及与SQL的设计模式的对比
    ArcGIS API for Silverlight 学习笔记
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
  • 原文地址:https://www.cnblogs.com/atlaser/p/6247612.html
Copyright © 2011-2022 走看看