📄 csdn_文档中心_com深入理解(上)——方法参数类型为cruntimeclass、void等.htm
字号:
<SCRIPT language=JavaScript>
<!--
document.ns = navigator.appName == "Netscape"
tmpDate = new Date();
date = tmpDate.getDate();
month= tmpDate.getMonth() + 1 ;
if(document.ns)
{
year1=tmpDate.getYear()
year= year1.toString().substr(1,2);
}
else
year= tmpDate.getYear();
document.write(year);
document.write(".");
document.write(month);
document.write(".");
document.write(date);
// -->
</SCRIPT>
</B> </TD></TR>
<TR bgColor=#999999>
<TD colSpan=3 height=1></TD></TR></TBODY></TABLE>
<TABLE border=0 width=770>
<TBODY>
<TR>
<TD align=middle bgColor=#fafafa class=td1 vAlign=top width=150><BR>
<SCRIPT
src="CSDN_文档中心_COM深入理解(上)——方法参数类型为CRuntimeClass、void等.files/microsoft.js"></SCRIPT>
</TD>
<TD align=middle width=620>
<TABLE bgColor=#eeeeee border=0 cellPadding=0 cellSpacing=0 width=600>
<TBODY>
<TR bgColor=#ffffff>
<TD align=middle height=10 width=50></TD>
<TD align=right><A href="http://www.csdn.net/">CSDN</A> - <A
href="http://www.csdn.net/develop/">文档中心</A> - <FONT
color=#003399>Visual C++</FONT> </TD></TR>
<TR>
<TD align=middle height=5></TD>
<TD align=middle width=500></TD></TR>
<TR>
<TD align=middle bgColor=#003399 height=10><FONT
color=#ffffff>标题</FONT></TD>
<TD><B> COM深入理解(上)——方法参数类型为CRuntimeClass*、void*等</B> lop5712(原作)
</TD></TR>
<TR>
<TD align=middle height=5></TD>
<TD align=middle width=500></TD></TR>
<TR>
<TD align=middle bgColor=#003399><FONT color=#ffffff>关键字</FONT></TD>
<TD width=500> COM void*</TD></TR>
<TR>
<TD align=middle height=5></TD>
<TD align=middle width=500></TD></TR></TBODY></TABLE><!--文章说明信息结束//-->
<TABLE border=0 width=600>
<TBODY>
<TR>
<TD align=left><BR><FONT
style="FONT-FAMILY: '宋体'; FONT-SIZE: 10pt; LINE-HEIGHT: 150%">
<P align=center><FONT face=楷体_GB2312
size=5><STRONG>COM深入理解(上)</STRONG></FONT> </P>
<P align=right><FONT face=楷体_GB2312
size=4><STRONG>——方法参数类型为CRuntimeClass*、void*等</STRONG></FONT> </P>
<P> 经常见到论坛上有问如何传递void*或一个自定义类,如:class CA;
CA*等。本文就COM的运作方式说明如何传递一自定义类对象的指针,并澄清MIDL的作用,以说明其并不是必须的。注意,本文所说的自定义类型传递与自动化技术(基于IDispatch)中的自定义结构的传递不是同一个概念,没有任何关系。</P>
<P><BR><FONT face=楷体_GB2312
size=4><STRONG>COM的服务提供方式</STRONG></FONT></P>
<P>
COM这个数学模型的本质是一个服务提供方式,与DLL(动态连接库技术)一样,都是对外提供服务,在某种意义上这又被称作代码重用,但应分清它们之间的区别——代码重用只是提供服务的一种方式,这也正是DLL的目的。<BR>
DLL在其PE格式(Portable Executable
Format,一种文件格式,exe、dll、obj等多种可执行文件都是这种格式)中定义一个节(section,即一段连续存储空间),称为导出节。在这个节中,记录着当前DLL文件中每个导出函数的入口代码的相对虚拟地址(Relative
Virtual
Address——RVA),其相当于是函数地址。当此DLL文件被映射进装载进程的虚拟内存空间时,线程就可以根据导出节中的相对虚拟地址而跳到DLL的导出函数入口处执行导出函数的代码。此时就称导出函数的代码被重用了。<BR>
上面的实现方式中,DLL的函数导出方式是静态导出(即使在文件映射时刻可能由于重定位的要求而使函数地址发生变换,但在其整个载入期间函数地址都不发生变化)。COM与此完全不同,其是动态导出的,即又增加了一级指针,客户得到的不是函数指针,而是函数指针数组,虽然DLL的导出节也相当于函数指针数组,但COM在此又增加一级包装,通过一个函数获得动态的通过在堆或栈上分配的内存构建的函数指针数组,而不是DLL导出节那样的只读型(顶多可以Copy-On-Write)内存(虽然不是重点),且只有一个。<BR>
前面提到的函数指针数组在COM的实现中就表示经常听说的接口。而获得动态函数指针数组的函数,COM运行时期库则提供了一个函数来实现——CoGetClassObject,其返回客户使用的第一个函数指针数组(接口),其功能上和GetProcAddress非常类似,只不过后者只返回一个函数指针,而前者返回的是函数指针数组。由于返回函数指针数组的方式是传递一个指针(即传递函数指针的指针,而不是调用什么API),因此此方法可以被随意的应用于任何地方,包括接口导出的函数中。COM中的IUnknown::QueryInterface就专门用于此项服务。<BR>
由于C++提供的虚函数实现机制中也有函数指针数组,故用C++编写COM组件时,接口一般就用一纯虚基类来表示。而C中,由于没有虚函数的概念,只好使用结构来定义一个函数指针数组。</P>
<P><BR><FONT face=楷体_GB2312
size=4><STRONG>C++类的实现方式</STRONG></FONT></P>
<P>
二进制代码,即机器代码中,是没有类的概念的。但COM是建立在二进制基础上的服务提供,因此下面简略说明一下C++中的类的实现方式。<BR>
类其实就是一块连续内存和一些在此内存块上执行操作的函数,而此连续内存块就是一个结构的实例,而成员函数其实只是多了一个以此结构为类型的名字为this的参数的普通C函数。如下一个类定义:<BR><SPAN
style="COLOR: blue">class</SPAN> CA<BR>{<BR> <SPAN
style="COLOR: blue">long</SPAN> a;<BR><SPAN
style="COLOR: blue">public</SPAN>:<BR> CA() : a( 0
) {}<BR> <SPAN style="COLOR: blue">long</SPAN>
GetA()<BR>
{<BR> <SPAN
style="COLOR: blue">return</SPAN> a;<BR>
}<BR>};<BR>CA aa;<BR><SPAN style="COLOR: blue">long</SPAN> a =
aa.GetA();<BR> 其实际为:<BR><SPAN
style="COLOR: blue">struct</SPAN> S_CA<BR>{<BR>
<SPAN style="COLOR: blue">long</SPAN> a;<BR>};<BR><SPAN
style="COLOR: blue">long</SPAN> S_CA_GetA( S_CA *<SPAN
style="COLOR: blue">this</SPAN> )<BR>{<BR> <SPAN
style="COLOR: blue">return</SPAN> <SPAN
style="COLOR: blue">this</SPAN>->a;<BR>}<BR><SPAN
style="COLOR: blue">void</SPAN> S_CA_CA( S_CA *<SPAN
style="COLOR: blue">this</SPAN> )<BR>{<BR> <SPAN
style="COLOR: blue">this</SPAN>->a = 0; <SPAN
style="COLOR: green">// 假设没开任何优化开关</SPAN><BR>}<BR>S_CA
s_aa;<BR>S_CA_CA( &s_aa );<BR><SPAN
style="COLOR: blue">long</SPAN> a = S_CA_GetA( &s_aa
);<BR>
因此,类其实就是一个结构和一些其相关的函数,其存在的目的就是便于代码的书写并引入了语义以提供对面向对象编程思想的支持。而当类有虚函数时,和上面一样,只不过结构中多了一个成员专门记录一个函数指针数组,代表此类的所有虚函数,这也正是COM接口的实现形式。如下:<BR><SPAN
style="COLOR: blue">class</SPAN> CA<BR>{<BR> <SPAN
style="COLOR: blue">long</SPAN> a;<BR><SPAN
style="COLOR: blue">public</SPAN>:<BR> CA() : a( 0
) {}<BR> <SPAN style="COLOR: blue">virtual</SPAN>
<SPAN style="COLOR: blue">long</SPAN> GetA()<BR>
{<BR> <SPAN
style="COLOR: blue">return</SPAN> a;<BR>
}<BR> <SPAN style="COLOR: blue">virtual</SPAN>
<SPAN style="COLOR: blue">void</SPAN> SetA( <SPAN
style="COLOR: blue">long</SPAN> var )<BR>
{<BR> a =
var;<BR> }<BR>};<BR>CA aa;<BR><SPAN
style="COLOR: blue">long</SPAN> a = aa.GetA();<BR>aa.SetA( 34
);<BR> 变为:<BR><SPAN
style="COLOR: blue">struct</SPAN> S_CA_D;<BR><SPAN
style="COLOR: blue">struct</SPAN> S_CA_F <SPAN
style="COLOR: green">//
相当于一个只有两个元素的函数指针数组</SPAN><BR>{<BR> <SPAN
style="COLOR: blue">long</SPAN> ( *GetA )( S_CA_D*
);<BR> <SPAN style="COLOR: blue">void</SPAN> (
*SetA )( S_CA_D*, <SPAN style="COLOR: blue">long</SPAN>
);<BR>};<BR><SPAN style="COLOR: blue">struct</SPAN>
S_CA_D<BR>{<BR> S_CA_F *pF;<BR>
<SPAN style="COLOR: blue">long</SPAN> a;<BR>};<BR><SPAN
style="COLOR: blue">long</SPAN> S_CA_GetA( S_CA_D *<SPAN
style="COLOR: blue">this</SPAN> )<BR>{<BR> <SPAN
style="COLOR: blue">return</SPAN> <SPAN
style="COLOR: blue">this</SPAN>->a;<BR>}<BR><SPAN
style="COLOR: blue">void</SPAN> S_CA_SetA( S_CA_D *<SPAN
style="COLOR: blue">this</SPAN>, <SPAN
style="COLOR: blue">long</SPAN> var )<BR>{<BR>
<SPAN style="COLOR: blue">this</SPAN>->a = var;<BR>}<BR>S_CA_F
g_S_CA_F = { S_CA_GetA, S_CA_SetA };<BR><SPAN
style="COLOR: blue">void</SPAN> S_CA_CA( S_CA_D *<SPAN
style="COLOR: blue">this</SPAN> )<BR>{<BR> <SPAN
style="COLOR: blue">this</SPAN>->pF = &g_S_CA_F; <SPAN
style="COLOR: green">// 设置虚函数指针</SPAN><BR> <SPAN
style="COLOR: blue">this</SPAN>->a = 0; <SPAN
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -