📄 mfc dll向导(2).htm
字号:
</td>
</tr>
</table>
<p class=MsoNormal align=left style='text-align:left;mso-pagination:widow-orphan'><span
lang=EN-US style='font-size:9.0pt;font-family:宋体;mso-bidi-font-family:宋体;
display:none;mso-hide:all;mso-font-kerning:0pt'><o:p> </o:p></span></p>
<div align=center>
<table class=MsoNormalTable border=0 cellspacing=0 cellpadding=0 width="96%"
style='width:96.0%;mso-cellspacing:0cm;mso-padding-alt:0cm 0cm 0cm 0cm'>
<tr style='mso-yfti-irow:0;mso-yfti-firstrow:yes;height:3.0pt'>
<td colspan=3 style='padding:0cm 0cm 0cm 0cm;height:3.0pt'>
<p class=MsoNormal align=left style='text-align:left;mso-pagination:widow-orphan'><span
lang=EN-US style='font-size:3.0pt;mso-bidi-font-size:9.0pt;font-family:宋体;
mso-bidi-font-family:宋体;mso-font-kerning:0pt'><o:p> </o:p></span></p>
</td>
</tr>
<tr style='mso-yfti-irow:1;mso-yfti-lastrow:yes'>
<td valign=top style='padding:0cm 0cm 0cm 0cm' id=fontzoom>
<p class=MsoNormal align=left style='text-align:left;line-height:15.0pt;
mso-pagination:widow-orphan'><span lang=EN-US style='font-size:10.0pt;
font-family:宋体;mso-bidi-font-family:宋体;mso-font-kerning:0pt'><o:p> </o:p></span></p>
<p class=MsoNormal align=left style='text-align:left;line-height:15.0pt;
mso-pagination:widow-orphan'><span style='font-size:10.0pt;font-family:宋体;
mso-bidi-font-family:宋体;mso-font-kerning:0pt'> 使用<span lang=EN-US>DLL</span>的一个比较严重的问题就是编译器之间的兼容性问题。不同的编译器对<span
lang=EN-US>c </span>函数在二进制级别的实现方式是不同的。所以对基于<span lang=EN-US>C </span>的<span
lang=EN-US>DLL</span>,如果编译器不同就有很麻烦的。如果创建的是<span lang=EN-US>MFC</span>扩展<span
lang=EN-US>DLL</span>,就不会存在问题,因为它只能被动态连接到<span lang=EN-US>MFC</span>的客户应用程序。这里不是本文讨论的重点。<span
lang=EN-US><br>
<br>
</span></span><b><span style='font-size:10.0pt;mso-bidi-font-size:12.0pt;
font-family:宋体;mso-bidi-font-family:宋体;color:blue;mso-font-kerning:0pt'>一、重新编译问题</span></b><b><span
lang=EN-US style='font-size:10.0pt;font-family:宋体;mso-bidi-font-family:宋体;
color:blue;mso-font-kerning:0pt'><br>
</span></b><span style='font-size:10.0pt;font-family:宋体;mso-bidi-font-family:
宋体;mso-font-kerning:0pt'>我们先来看一个在实际中可能遇到的问题:<span lang=EN-US><br>
</span> 比如现在建立好了一个<span lang=EN-US>DLL</span>导出了<span class=SpellE><span
lang=EN-US>CMyClass</span></span>类,客户也能正常使用这个<span lang=EN-US>DLL</span>,假设<span
class=SpellE><span lang=EN-US>CMyClass</span></span>对象的大小为<span lang=EN-US>30</span>字节。如果我们需要修改<span
lang=EN-US>DLL</span>中的<span class=SpellE><span lang=EN-US>CMyClass</span></span>类,让它有相同的函数和成员变量,但是给增加了一个私有的成员变量<span
class=SpellE><span lang=EN-US>int</span></span>类型,现在<span class=SpellE><span
lang=EN-US>CMyClass</span></span>对象的大小就是<span lang=EN-US>34</span>字节了。当直接把这个新的<span
lang=EN-US>DLL</span>给客户使用替换掉原来<span lang=EN-US>30</span>字节大小的<span
lang=EN-US>DLL</span>,客户应用程序期望的是<span lang=EN-US>30</span>字节大小的对象,而现在却变成了一个<span
lang=EN-US>34</span>字节大小的对象,糟糕,客户程序出错了。<span lang=EN-US><br>
</span> 类似的问题,如果不是导出<span class=SpellE><span lang=EN-US>CMyClass</span></span>类,而在导出的函数中使用了<span
class=SpellE><span lang=EN-US>CMyClass</span></span>,改变对象的大小仍然会有问题的。这个时候修改这个问题的唯一办法就是替换客户程序中的<span
class=SpellE><span lang=EN-US>CMyClass</span></span>的头文件,全部重新编译整个应用程序,让客户程序使用大小为<span
lang=EN-US>34</span>字节的对象。<span lang=EN-US><br>
</span> 这就是一个严重的问题,有的时候如果没有客户程序的源代码,那么我们就不能使用这个新的<span lang=EN-US>DLL</span>了。<span
lang=EN-US><br>
<br>
</span></span><b><span style='font-size:10.0pt;mso-bidi-font-size:12.0pt;
font-family:宋体;mso-bidi-font-family:宋体;color:blue;mso-font-kerning:0pt'>二、解决方法</span></b><span
style='font-size:10.0pt;font-family:宋体;mso-bidi-font-family:宋体;mso-font-kerning:
0pt'> <span lang=EN-US> <br>
</span>为了能避免重新编译客户程序,这里介绍两个方法:(<span lang=EN-US>1</span>)使用接口类。(<span
lang=EN-US>2</span>)使用创建和销毁类的静态函数。<span lang=EN-US><br>
1</span>、使用接口类<span lang=EN-US><br>
</span> 接口类的也就是创建第二个类,它作为要导出类的接口,所以在导出类改变时,也不需要重新编译客户程序,因为接口<span
class=GramE>类没有</span>发生变化。<span lang=EN-US><br>
</span> 假设导出的<span class=SpellE><span lang=EN-US>CMyClass</span></span>类有两个函数<span
class=SpellE><span lang=EN-US>FunctionA</span></span><span lang=EN-US> <span
class=SpellE>FunctionB</span></span>。现在创建一个接口类<span class=SpellE><span
lang=EN-US>CMyInterface</span></span>,下面就是在<span lang=EN-US>DLL</span>中的<span
class=SpellE><span lang=EN-US>CMyInterface</span></span>类的头文件的代码:<span
lang=EN-US><br>
# include "<span class=SpellE>MyClass.h</span>"<br>
class _<span class=SpellE>declspec</span>(<span class=SpellE>dllexport</span>)
<span class=SpellE>CMyInterface</span><br>
{<br>
</span> <span lang=EN-US> <span class=SpellE>CMyClass</span> *<span
class=SpellE>pmyclass</span>;<br>
</span> <span lang=EN-US> <span class=SpellE>CMyInterface</span>();<br>
</span> <span lang=EN-US> ~<span class=SpellE>CMyInterface</span>();<br>
public:<br>
</span> <span class=SpellE><span lang=EN-US>int</span></span><span
lang=EN-US> <span class=SpellE>FunctionA</span>(<span class=SpellE>int</span>);<br>
</span> <span lang=EN-US> <span class=SpellE>int</span> <span class=SpellE>FunctionB</span>(<span
class=SpellE>int</span>);<br>
};<br>
</span>而在客户程序中的头文件稍不同,不需要<span lang=EN-US>INCLUDE</span>语句,因为客户程序没有它的拷贝。相反,使用一个<span
class=SpellE><span lang=EN-US>CMyClass</span></span>的向前声明,即使没有头文件也能编译:<span
lang=EN-US><br>
class _<span class=SpellE>declspec</span>(<span class=SpellE>dllexport</span>)
<span class=SpellE>CMyInterface</span><br>
{<br>
</span> <span lang=EN-US> class <span class=SpellE>CMyClass</span>;//</span>向前声明<span
lang=EN-US><br>
</span> <span lang=EN-US> <span class=SpellE>CMyClass</span> *<span
class=SpellE>pmyclass</span>;<br>
</span> <span lang=EN-US> <span class=SpellE>CMyInterface</span>();<br>
</span> <span lang=EN-US> ~<span class=SpellE>CMyInterface</span>();<br>
public:<br>
</span> <span lang=EN-US> <span class=SpellE>int</span> <span class=SpellE>FunctionA</span>(<span
class=SpellE>int</span>);<br>
</span> <span lang=EN-US> <span class=SpellE>int</span> <span class=SpellE>FunctionB</span>(<span
class=SpellE>int</span>);<br>
};<br>
</span>在<span lang=EN-US>DLL</span>中的<span class=SpellE><span lang=EN-US>CMyInterface</span></span>的实现如下:<span
lang=EN-US><br>
<span class=SpellE>CMyInterface::CMyInterface</span>()<br>
{<br>
</span> <span lang=EN-US> <span class=SpellE>pmyclass</span> = new <span
class=SpellE>CMyClass</span>();<br>
}<br>
<span class=SpellE>CMyInterface::~CMyInterface</span>()<br>
{<br>
</span> <span lang=EN-US> delete <span class=SpellE>pmyclass</span>;<br>
}<br>
<span class=SpellE>int</span> <span class=SpellE>CMyInterface::FunctionA</span>()<br>
{<br>
</span> <span lang=EN-US> return <span class=SpellE>pmyclass</span>-><span
class=SpellE>FunctionA</span>();<br>
}<br>
<span class=SpellE>int</span> <span class=SpellE>CMyInterface::FunctionB</span>()<br>
{<br>
</span> <span lang=EN-US> return <span class=SpellE>pmyclass</span>-><span
class=SpellE>FunctionB</span>();</span> <span lang=EN-US> <br>
}<br>
.....<br>
</span>对导出类<span class=SpellE><span lang=EN-US>CMyClass</span></span>的每个成员函数,<span
class=SpellE><span lang=EN-US>CMyInterface</span></span>类都提供自己的对应的函数。客户程序与<span
class=SpellE><span lang=EN-US>CMyClass</span></span>没有联系,这样任意改<span
class=SpellE><span lang=EN-US>CMyClass</span></span>也不会有问题,因为<span
class=SpellE><span lang=EN-US>CMyInterface</span></span>类的大小没有发生变化。即使为了能访问<span
class=SpellE><span lang=EN-US>CMyClass</span></span>中的新增变量而给<span
class=SpellE><span lang=EN-US>CMyInterface</span></span>类加了函数也不会有问题的。<span
lang=EN-US><br>
</span> 但是这种方法也存在明显的问题,对导出类的每个函数和成员变量都要对应实现,有的时候这个接口类会很庞大。同时增加了客户程序调用所需要的时间。增加了程序的开销。
<span lang=EN-US><o:p></o:p></span></span></p>
<p class=MsoNormal align=left style='mso-margin-top-alt:auto;mso-margin-bottom-alt:
auto;text-align:left;line-height:15.0pt;mso-pagination:widow-orphan'><span
lang=EN-US style='font-size:10.0pt;font-family:宋体;mso-bidi-font-family:宋体;
mso-font-kerning:0pt'>2</span><span style='font-size:10.0pt;font-family:宋体;
mso-bidi-font-family:宋体;mso-font-kerning:0pt'>、使用静态函数<span lang=EN-US><br>
</span> 还可以使用静态函数来创建和销毁类对象。创建一个导出类的时候,增加两个静态的公有函数<span class=SpellE><span
lang=EN-US>CreateMe</span></span><span lang=EN-US>()/<span class=SpellE>DestroyMe</span>()</span>,头文件如下:<span
lang=EN-US><br>
class _<span class=SpellE>declspec</span>(<span class=SpellE>dllexport</span>)
<span class=SpellE>CMyClass</span><br>
{<br>
</span> <span lang=EN-US> <span class=SpellE>CMyClass</span>();<br>
</span> <span lang=EN-US> ~<span class=SpellE>CMyClass</span>();<br>
public:<br>
</span> <span lang=EN-US> static <span class=SpellE>CMyClass</span> *<span
class=SpellE>CreateMe</span>();<br>
</span> <span lang=EN-US> static void <span class=SpellE>DestroyMe</span>(<span
class=SpellE>CMyClass</span> *<span class=SpellE>ptr</span>);<br>
};<br>
</span>实现函数就是:<span lang=EN-US><br>
<span class=SpellE>CMyClass</span> * <span class=SpellE>CMyClass::CMyClass</span>()<br>
{<br>
</span> <span lang=EN-US> return new <span class=SpellE>CMyClass</span>;<br>
}<br>
void <span class=SpellE>CMyClass::DestroyMe</span>(<span class=SpellE>CMyClass</span>
*<span class=SpellE>ptr</span>)<br>
{<br>
</span> <span lang=EN-US> delete <span class=SpellE>ptr</span>;<br>
}<br>
</span>然后<span class=GramE>象</span>其他<span class=GramE>类一样</span>导出<span
class=SpellE><span lang=EN-US>CMyClass</span></span>类,这个时候在客户程序中使用这个类的方法稍有不同了。如若想创建一个<span
class=SpellE><span lang=EN-US>CMyClass</span></span>对象,就应该是:<span lang=EN-US><br>
<span class=SpellE>CMyClass</span> x;<br>
<span class=SpellE>CMyClass</span> *<span class=SpellE>ptr</span> = <span
class=SpellE>CMyClass::CreateMe</span>();<br>
</span>在使用完后删除:<span lang=EN-US><br>
<span class=SpellE>CMyClass::DestroyMe</span>(<span class=SpellE>ptr</span>);<o:p></o:p></span></span></p>
</td>
<td style='padding:0cm 0cm 0cm 0cm'>
<p class=MsoNormal align=left style='text-align:left;mso-pagination:widow-orphan'><span
lang=EN-US style='font-size:10.0pt;mso-font-kerning:0pt'><o:p> </o:p></span></p>
</td>
<td style='padding:0cm 0cm 0cm 0cm'>
<p class=MsoNormal align=left style='text-align:left;mso-pagination:widow-orphan'><span
lang=EN-US style='font-size:10.0pt;mso-font-kerning:0pt'><o:p> </o:p></span></p>
</td>
</tr>
</table>
</div>
<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>
</div>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -