zoukankan      html  css  js  c++  java
  • 在非托管C++/CLI引用托管对象

    一个技术研究工作,需要使用native代码构建一个dll,并实现其中的函数:

    HRESULT WMCreateStreamForURL( LPCWSTR pwszURL,
    BOOL* pfCorrectSource,
    IStream** ppStream
    )

    因为未来项目准备使用C#编程,所以很自然想到了C++/CLI来实现这个dll,并且将调用转发到C#的实现里。做起来很容易,我用C#实现了一个StreamManager,负责检查传入的url并返回相应的IStream实现。

    这里环境为VS2005。用C#实现的工程叫做protocol,用C++/CLI实现的工程名字为protocol_stub(必须使用/cli参数编译)。

    首先遇到的是C++/CLI中的托管代码和非托管代码的相互调用问题,查阅了一下帮助,发现使用#pragma managed和#pragma unmanaged就可以划定函数的编译方式到底是native还是cli。

    其次,在C++中调用StreamManager时候报告找不到。经过检查,发现要在C++工程中添加对protocol的引用,同时,要在C++代码的managed部分使用指令

    #pragma managed

    #import "protocol.tlb" raw_interfaces_only
    using namespace protocol;
    using namespace System;
    using namespace System::Runtime::InteropServices;

    这样才可以正常编译代码StreamManager^ mgr = StreamManager::Instance;其中,protocol.tlb是用VS自带工具TlbExp生成的。

    第三个问题是导出.net对象的问题。两个工程可以正常编译,但是测试运行时候却报告异常。经过检查,原来是System::Runtime::InteropServices::ComTypes::IStream虽然就是IStream的实现,但是却无法进行强制转换。用如下的代码虽然编译可以过去,但是不能工作

    ComTypes::IStream^ s = mgr->getStream(url);
    cli::pin_ptr<ComTypes::IStream^> p = &s;
    *ppStream = (IStream*)p;

    经过查询,发现解决的方法很简单,代码如下:

    ComTypes::IStream^ s = mgr->getStream(url);
    IntPtr^ handle = Marshal::GetComInterfaceForObject(s, ComTypes::IStream::typeid);
    *ppStream = (IStream*)handle->ToPointer();

    这样,整个工作顺利完成。

    总结:C++/CLI经过vs2003之后变动很大,从丑小鸭终于变成了白天鹅,不仅实现了C++和CLI的无缝整合,而且保留了原先C++语法的优美和简洁。因为可以支持本地代码和CLI代码的混合调用,不仅可以充分利用Windows系统和.net的资源,而且因为本地代码的不可反编译性,使得C++/CLI天生就有了安全保密性。看来要在项目中的一些关键算法部分使用C++了。

    另外,几个要注意的地方:

    C#中xxx.getType()或者typeof(ClassXXX)在C++/CLI中对应代码是 ClassXXX::typeid
    在C++/CLI中#import 比较重要,要注意
    在C#中,所有对象天生就是COM对象(好在我一直没有弄错)

  • 相关阅读:
    如何读入位图(五)
    如何读入位图(四)
    绘制正弦曲线
    图像灰度均衡
    色彩填充及使用
    彩色扇形
    如何读入位图(三)
    ARCGIS FOR SILVERLIGHT Layer
    sqlserver2008多数据库操作(未完)
    SQLSERVER 2008 远程无法连接问题
  • 原文地址:https://www.cnblogs.com/BigTall/p/555653.html
Copyright © 2011-2022 走看看