⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 csdn_文档中心_com深入理解(下)——方法参数类型为cruntimeclass、void等.htm

📁 csdn10年中间经典帖子
💻 HTM
📖 第 1 页 / 共 4 页
字号:
            style="COLOR: blue">void</SPAN> *pA )<BR>{<BR>&nbsp;&nbsp;&nbsp; 
            <SPAN style="COLOR: blue">if</SPAN>( !pA 
            )<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN 
            style="COLOR: blue">return</SPAN> 
            E_INVALIDARG;<BR>&nbsp;&nbsp;&nbsp; CA *pAA = <SPAN 
            style="COLOR: blue">reinterpret_cast</SPAN>&lt; CA* &gt;( pA 
            );<BR><BR><SPAN style="COLOR: green">// 
            调用远程版的代理函数以传递参数,由MIDL生成</SPAN><BR>&nbsp;&nbsp;&nbsp; <SPAN 
            style="COLOR: blue">return</SPAN> IAbc_RemoteGetA_Proxy( This, 
            &amp;pAA-&gt;m_a, &amp;pAA-&gt;m_b );<BR>}<BR>HRESULT 
            STDMETHODCALLTYPE IAbc_GetA_Stub( IAbc *This, <SPAN 
            style="COLOR: blue">long</SPAN> *pA, <SPAN 
            style="COLOR: blue">long</SPAN> *pB )<BR>{<BR>&nbsp;&nbsp;&nbsp; 
            <SPAN style="COLOR: blue">void</SPAN> *p = CoTaskMemAlloc( <SPAN 
            style="COLOR: blue">sizeof</SPAN>( CA ) );<BR>&nbsp;&nbsp;&nbsp; 
            <SPAN style="COLOR: blue">if</SPAN>( !p 
            )<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN 
            style="COLOR: blue">return</SPAN> E_FAIL;<BR>&nbsp;&nbsp;&nbsp; CA 
            *pAA = <SPAN style="COLOR: blue">new</SPAN>( p ) CA;&nbsp; <SPAN 
            style="COLOR: green">// 生成一个类对象</SPAN><BR><BR><SPAN 
            style="COLOR: green">// 调用对象的本地方法</SPAN><BR>&nbsp;&nbsp;&nbsp; 
            HRESULT hr = This-&gt;GetA( pAA );<BR>&nbsp;&nbsp;&nbsp; <SPAN 
            style="COLOR: blue">if</SPAN>( SUCCEEDED( hr ) 
            )<BR>&nbsp;&nbsp;&nbsp; 
            {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *pA = 
            pAA-&gt;m_a;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *pB = 
            pAA-&gt;m_b;<BR>&nbsp;&nbsp;&nbsp; }<BR><BR><SPAN 
            style="COLOR: green">// 释放资源</SPAN><BR>&nbsp;&nbsp;&nbsp; 
            pAA-&gt;~CA();<BR>&nbsp;&nbsp;&nbsp; CoTaskMemFree( p 
            );<BR>&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: blue">return</SPAN> 
            hr;<BR>}<BR>&nbsp;&nbsp;&nbsp; 
            最后添加预定义宏REGISTER_PROXY_DLL和_WIN32_WINNT=0x500,并连接rpcrt4.lib库文件,确保没有打开/TC或/TP编译开关以保证对上面的abc.cpp进行C++编译,而对MIDL生成的.c的源文件进行C编译。<BR>&nbsp;&nbsp;&nbsp; 
            使用时如下:<BR>IAbc *pA;&nbsp; <SPAN style="COLOR: green">// 
            假设已初始化</SPAN><BR>CA&nbsp;&nbsp;&nbsp; a;<BR>pA-&gt;GetA( <SPAN 
            style="COLOR: blue">reinterpret_cast</SPAN>&lt; <SPAN 
            style="COLOR: blue">void</SPAN>* &gt;( &amp;a ) 
            );<BR>&nbsp;&nbsp;&nbsp; 而组件实现的代码如下:<BR>STDMETHODIMP CAbc::GetA( 
            <SPAN style="COLOR: blue">void</SPAN> *pA 
            )<BR>{<BR>&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: blue">if</SPAN>( 
            !pA )<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN 
            style="COLOR: blue">return</SPAN> 
            E_INVALIDARG;<BR><BR>&nbsp;&nbsp;&nbsp; *<SPAN 
            style="COLOR: blue">reinterpret_cast</SPAN>&lt; CA* &gt;( pA ) = 
            m_A;<BR>&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: blue">return</SPAN> 
            S_OK;<BR>}<BR>&nbsp;&nbsp;&nbsp; 
            如上就实现了将类CA的对象进行传值操作,但不是传址操作。前面已说明,欲进行后者,必须编写相应的代理类。先使用上面的方法将必要的信息传递后,再根据传递的信息初始化类CA的代理对象以建立连接。一般如非得已最好不要编写代理对象,而通过将类转成接口形式,由MIDL辅助生成代理/占位组件以变相实现。<BR>&nbsp;&nbsp;&nbsp; 
            下面介绍使用[wire_marshal()]属性进行传值操作。</P>
            <P><BR><FONT face=楷体_GB2312 
            size=4><STRONG>[wire_marshal()]</STRONG></FONT></P>&nbsp;&nbsp;&nbsp; 
            前面使用方法别名机制实现了传递自定义数据类型,但是其是以方法为单位进行处理的,当要多次使用某一个数据类型时,如前面的CA*,如果对每个使用到CA*的方法都进行上面的操作,很明显地效率低下,为此MIDL提供了[wire_marshal()]属性(当然不止这么一个属性)。<BR>&nbsp;&nbsp;&nbsp; 
            [wire_marshal()]属性只能用于类型定义,即typedef中,使用语法如下:<BR><SPAN 
            style="COLOR: blue">typedef</SPAN> [wire_marshal(<I>wire_type</I>)] 
            <I>type-specifier</I> <I>userm-type</I>;<BR>&nbsp;&nbsp;&nbsp; 
            其将一个线类型(wire-type,即MIDL可以直接处理的类型)和一个描述类型(type-specifier,即不能或不打算被MIDL处理的特殊数据类型)相关联,并用一个可识别名字(userm-type)标识。其和[transmit_as()]属性类似,都是将两个类型进行关联,就如前面的[local]和[call_as()]将两个方法进行关联一样,只不过[wire_marshal()]是直接将描述类型按IDL的列集格式(网络数据描述NDR——Network 
            Data 
            Representation)列集到指定的缓冲区中,而[transmit_as()]还需汇集代码在中间再转换一次,因此[wire_marshal()]的效率要更高,只不过由于需要编写列集代码,因此需要了解NDR格式,处理数据对齐等问题,所以显得麻烦和复杂。最常见的应用就是句柄的定义,如下:<BR><SPAN 
            style="COLOR: blue">typedef</SPAN> <SPAN 
            style="COLOR: blue">union</SPAN> _RemotableHandle <SPAN 
            style="COLOR: blue">switch</SPAN>( <SPAN 
            style="COLOR: blue">long</SPAN> fContext ) 
            u<BR>{<BR>&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: blue">case</SPAN> 
            WDT_INPROC_CALL:&nbsp;&nbsp; <SPAN 
            style="COLOR: blue">long</SPAN>&nbsp;&nbsp; 
            hInproc;<BR>&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: blue">case</SPAN> 
            WDT_REMOTE_CALL:&nbsp;&nbsp; <SPAN 
            style="COLOR: blue">long</SPAN>&nbsp;&nbsp; hRemote;<BR>} 
            RemotableHandle;<BR><SPAN style="COLOR: blue">typedef</SPAN> [<SPAN 
            style="COLOR: blue">unique</SPAN>] RemotableHandle * 
            wireHWND;<BR><SPAN style="COLOR: blue">#define</SPAN> 
            DECLARE_WIREM_HANDLE(name)&nbsp; 
            \<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            <SPAN style="COLOR: blue">typedef</SPAN> [wire_marshal(wire ## 
            name)] <SPAN style="COLOR: blue">void</SPAN> * 
            name<BR>DECLARE_WIREM_HANDLE( HWND );<BR>&nbsp;&nbsp;&nbsp; 
            也就是说我们常用的HWND类型是:<BR><SPAN style="COLOR: blue">typedef</SPAN> 
            [wire_marshal( wireHWND )] <SPAN style="COLOR: blue">void</SPAN>* 
            HWND;<BR>&nbsp;&nbsp;&nbsp; 
            即其在应用程序中(即客户或组件,即代理/占位的使用者)是void*类型,当需要传输时,实际是传输结构RemotableHandle的一个实例,而此结构是一个以fContext为标识的联合,实际为8字节长。<BR>&nbsp;&nbsp;&nbsp; 
            为了实现上面提到的void*和RemotableHandle*的关联,开发人员必须提供下面四个函数的定义:<BR><SPAN 
            style="COLOR: blue">unsigned long</SPAN> __RPC_USER &lt; 
            <I>userm-type</I> &gt;_UserSize(&nbsp; <SPAN style="COLOR: green">// 
            返回欲请求的缓冲区大小</SPAN><BR>&nbsp;&nbsp;&nbsp; <SPAN 
            style="COLOR: blue">unsigned long</SPAN> __RPC_FAR *pFlags,&nbsp; 
            <SPAN style="COLOR: green">// 一个标志参数,后叙</SPAN><BR>&nbsp;&nbsp;&nbsp; 
            <SPAN style="COLOR: green">// 
            给出当前已经请求的缓冲区大小,返回的大小应该以此作为起点</SPAN><BR>&nbsp;&nbsp;&nbsp; <SPAN 
            style="COLOR: blue">unsigned long</SPAN> 
            StartingSize,<BR>&nbsp;&nbsp;&nbsp; &lt; <I>userm-type</I> &gt; 
            __RPC_FAR * pUser_typeObject );&nbsp; <SPAN style="COLOR: green">// 
            欲传递的描述类型的实例</SPAN><BR><SPAN style="COLOR: blue">unsigned char</SPAN> 
            __RPC_FAR * __RPC_USER &lt; <I>userm-type</I> 
            &gt;_UserMarshal(&nbsp; <SPAN style="COLOR: green">// 
            列集</SPAN><BR>&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: blue">unsigned 
            long</SPAN> __RPC_FAR * pFlags,&nbsp;&nbsp; <SPAN 
            style="COLOR: green">// 标志参数</SPAN><BR>&nbsp;&nbsp;&nbsp; <SPAN 
            style="COLOR: blue">unsigned char</SPAN> __RPC_FAR * 
            Buffer,&nbsp;&nbsp; <SPAN style="COLOR: green">// 
            已分配的缓冲器有效指针</SPAN><BR>&nbsp;&nbsp;&nbsp; &lt; <I>userm-type</I> &gt; 
            __RPC_FAR * pUser_typeObject );&nbsp; <SPAN style="COLOR: green">// 
            欲列集的描述类型的实例</SPAN><BR><SPAN style="COLOR: blue">unsigned char</SPAN> 
            __RPC_FAR * __RPC_USER &lt; <I>userm-type</I> 
            &gt;_UserUnmarshal(&nbsp; <SPAN style="COLOR: green">// 
            散集</SPAN><BR>&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: blue">unsigned 
            long</SPAN> __RPC_FAR *&nbsp; pFlags,&nbsp;&nbsp; <SPAN 
            style="COLOR: green">// 标志参数</SPAN><BR>&nbsp;&nbsp;&nbsp; <SPAN 
            style="COLOR: blue">unsigned char</SPAN> __RPC_FAR *&nbsp; 
            Buffer,&nbsp;&nbsp; <SPAN style="COLOR: green">// 
            列集数据的缓冲器指针</SPAN><BR>&nbsp;&nbsp;&nbsp; <SPAN 
            style="COLOR: green">// 
            描述类型的实例指针,从列集数据中散集出描述类型后,放在此指针所指内存之中</SPAN><BR>&nbsp;&nbsp;&nbsp; 
            &lt; <I>userm-type</I> &gt; __RPC_FAR * pUser_typeObject );<BR><SPAN 
            style="COLOR: blue">void</SPAN> __RPC_USER &lt; <I>userm-type</I> 
            &gt;_UserFree(&nbsp; <SPAN style="COLOR: green">// 
            释放UserUnmarshal中分配的内存</SPAN><BR>&nbsp;&nbsp;&nbsp; <SPAN 
            style="COLOR: blue">unsigned long</SPAN> __RPC_FAR * 
            pFlags,&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: green">// 
            标志参数</SPAN><BR>&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: green">// 
            UserUnmarshal中的pUser_typeObject参数,一个描述类型的实例的指针</SPAN><BR>&nbsp;&nbsp;&nbsp; 
            &lt; <I>userm-type</I> &gt; __RPC_FAR * pUser_typeObject 
            );<BR>&nbsp;&nbsp;&nbsp; 
            对于前面的HWND,开发人员就必须提供如下四个函数的定义(当然Microsoft是已经提供了的):<BR><SPAN 
            style="COLOR: blue">unsigned long</SPAN> 
            __RPC_USER<BR>&nbsp;&nbsp;&nbsp; HWND_UserSize( <SPAN 
            style="COLOR: blue">unsigned long</SPAN>*, <SPAN 
            style="COLOR: blue">unsigned long</SPAN>, HWND* );<BR><SPAN 
            style="COLOR: blue">unsigned char</SPAN>* 
            __RPC_USER<BR>&nbsp;&nbsp;&nbsp; HWND_UserMarshal</SPAN>( <SPAN 
            style="COLOR: blue">unsigned long</SPAN>*, <SPAN 
            style="COLOR: blue">unsigned</SPAN><SPAN style="COLOR: blue"> 
            char</SPAN>*, HWND* );<BR><SPAN style="COLOR: blue">unsigned 
            char</SPAN>* __RPC_USER<BR>&nbsp;&nbsp;&nbsp; 
            HWND_UserUnmarshal</SPAN>( <SPAN style="COLOR: blue">unsigned 
            long</SPAN>*, <SPAN style="COLOR: blue">unsigned char</SPAN>*, HWND* 
            );<BR><SPAN style="COLOR: blue">void</SPAN> 
            __RPC_USER<BR>&nbsp;&nbsp;&nbsp; HWND_UserFree( <SPAN 
            style="COLOR: blue">unsigned long</SPAN>*, HWND* 
            );<BR>&nbsp;&nbsp;&nbsp; 
            在MIDL生成的汇集代码中,遇到方法参数类型为HWND时,发生如下事情:<BR>&nbsp;&nbsp;&nbsp; 1. 
            调用HWND_UserSize并传递应用程序(客户或组件,视HWND是in参数还是out参数)传进来的HWND的实例以得到欲传递此实例需要的缓冲区大小<BR>&nbsp;&nbsp;&nbsp; 
            2. 在RPC通道上分配相应的内存块<BR>&nbsp;&nbsp;&nbsp; 3. 
            调用HWND_UserMarshal,依旧传递前面的HWND实例以及分配到的缓冲区的指针以将此HWND实例列集到缓冲区中<BR>&nbsp;&nbsp;&nbsp; 
            4. 通过RPC通道将缓冲区内容传递到对方进程空间中<BR>&nbsp;&nbsp;&nbsp; 5. 
            调用HWND_UserUnmarshal,并传递通过RPC通道得到的列集数据缓冲区的指针和生成的一临时HWND实例的指针以记录散集出来的HWND实例<BR>&nbsp;&nbsp;&nbsp; 
            6. 以返回的HWND实例为参数调用应用程序的方法<BR>&nbsp;&nbsp;&nbsp; 7. 
            调用HWND_UserFree,传递前面因调用HWND_UserUnmarshal而生成的临时记录散集出的HWND实例的指针以释放因此分配的内存<BR>&nbsp;&nbsp;&nbsp; 
            以上,就是[wire_marshal()]属性对线类型和描述类型的绑定的实现。但其中漏了一点,就是标志参数pFlags的使用。此标志参数是一个4字节数字,其高16位是一些关于NDR格式的编码规则,以使得NDR引擎(将填写好的缓冲区内容按NDR格式串的规则进行排列以在网上传输的程序)能做出正确的数据转换。其低16位是一个MSHCTX枚举值,指明调用环境,是进程内还是跨进程、是远程还是本地(具体信息还请查阅MSDN),因而可以在上面的四个函数中根据此值作出相应的优化。<BR>&nbsp;&nbsp;&nbsp; 
            下面为上面的CA*实现[wire_marshal()]属性。<BR>&nbsp;&nbsp;&nbsp; 
            前面已经了解到,CA*由于在IDL中没有对应的类型,应该使用void*来进行传递,在abc.idl中增加如下代码:<BR><SPAN 
            style="COLOR: blue">typedef</SPAN> <SPAN 
            style="COLOR: blue">struct</SPAN> _SA<BR>{<BR>&nbsp;&nbsp;&nbsp; 
            <SPAN style="COLOR: blue">long</SPAN> a, b;<BR>} *PSA;<BR><SPAN 
            style="COLOR: blue">typedef</SPAN> [wire_marshal( PSA )] <SPAN 
            style="COLOR: blue">void</SPAN>* PA;<BR>&nbsp;&nbsp;&nbsp; 
            并为接口IAbc增加一个方法:<BR>HRESULT SetA( [<SPAN 
            style="COLOR: blue">in</SPAN>] PA a );<BR>&nbsp;&nbsp;&nbsp; 
            接着在abc.cpp中增加如下代码:<BR><SPAN style="COLOR: blue">unsigned</SPAN> 
            <SPAN style="COLOR: blue">long</SPAN> __RPC_USER PA_UserSize( <SPAN 
            style="COLOR: blue">unsigned</SPAN> <SPAN 
            style="COLOR: blue">long</SPAN>* <SPAN style="COLOR: green">/* 
            pFlags 
            */</SPAN>,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -