📄 mfc dll向导(1).htm
字号:
<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
lang=EN-US>DLL</span>的不同类型</span></b><span lang=EN-US style='font-size:10.0pt;
font-family:宋体;mso-bidi-font-family:宋体;mso-font-kerning:0pt'><br>
</span><span style='font-size:10.0pt;font-family:宋体;mso-bidi-font-family:
宋体;mso-font-kerning:0pt'> 使用<span lang=EN-US>MFC</span>可以生成两种类型的<span
lang=EN-US>DLL</span>:<span lang=EN-US>MFC</span>扩展<span lang=EN-US>DLL</span>和常规<span
lang=EN-US>DLL</span>。常规<span lang=EN-US>DLL</span>有可以分为动态连接和静态连接。<span
lang=EN-US>Visual C </span>还可以生成<span lang=EN-US>WIN32 DLL</span>,但不是这里讨论的主要对象。<span
lang=EN-US><br>
1</span>、<span lang=EN-US>MFC</span>扩展<span lang=EN-US>DLL<br>
</span> 每个<span lang=EN-US>DLL</span>都有某种类型的接口:变量、指针、函数、客户程序访问的类。它们的作用是让客户程序使用<span
lang=EN-US>DLL</span>,<span lang=EN-US>MFC</span>扩展<span lang=EN-US>DLL</span>可以有<span
lang=EN-US>C </span>的接口。也就是它可以导出<span lang=EN-US>C </span>类给客户端。导出的函数可以使用<span
lang=EN-US>C /MFC</span>数据类型做参数或返回值,导出一个类时客户端能创建<span class=GramE>类对象</span>或者派生这个类。同时,在<span
lang=EN-US>DLL</span>中也可以使用<span lang=EN-US>DLL</span>和<span lang=EN-US>MFC</span>。<span
lang=EN-US><br>
</span> <span lang=EN-US> Visual C </span>使用的<span lang=EN-US>MFC</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>DLL</span>,客户程序也必须要动态连接到<span
lang=EN-US>MFC</span>代码库的<span lang=EN-US>DLL</span>。(这里谈到的两个<span
lang=EN-US>DLL</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>DLL</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>DLL</span>能很好的工作,扩展<span lang=EN-US>DLL</span>和客户程序都必须动态连接到<span
lang=EN-US>MFC</span>代码库<span lang=EN-US>DLL</span>。而这个<span lang=EN-US>DLL</span>必须在客户程序运行的计算机上。<span
lang=EN-US><br>
2</span>、常规<span lang=EN-US>DLL<br>
</span> 使用<span lang=EN-US>MFC</span>扩展<span lang=EN-US>DLL</span>的一个问题就是<span
lang=EN-US>DLL</span>仅能和<span lang=EN-US>MFC</span>客户程序一起工作,如果需要一个使用更广泛的<span
lang=EN-US>DLL</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>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>
</span> 当在常规<span lang=EN-US>DLL</span>的内部使用<span lang=EN-US>MFC</span>代码库的<span
lang=EN-US>DLL</span>时,可以是动态连接<span lang=EN-US>/</span>静态连接。如果是动态连接,也就是常规<span
lang=EN-US>DLL</span>需要的<span lang=EN-US>MFC</span>代码没有构建到<span lang=EN-US>DLL</span>中,这种情况有点和扩展<span
lang=EN-US>DLL</span>类似,在<span lang=EN-US>DLL</span>运行的计算机上必须要<span
lang=EN-US>MFC</span>代码库的<span lang=EN-US>DLL</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>DLL</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'><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 lang=EN-US>DLL</span></span></b><span
lang=EN-US style='font-size:10.0pt;font-family:宋体;mso-bidi-font-family:宋体;
mso-font-kerning:0pt'><br>
</span><span style='font-size:10.0pt;font-family:宋体;mso-bidi-font-family:
宋体;mso-font-kerning:0pt'> 利用<span lang=EN-US>Visual C </span>提供的向导功能可以很容易建立一个不完成任何实质任务的<span
lang=EN-US>DLL</span>,这里就不多讲了,主要的任务是如何给<span lang=EN-US>DLL</span>添加功能,以及在客户程序中利用这个<span
lang=EN-US>DLL<br>
1</span>、导出类<span lang=EN-US><br>
</span> 用向导建立好框架后,就可以添加需要导出类的<span lang=EN-US>.<span class=SpellE>cpp</span>
.h</span>文件到<span lang=EN-US>DLL</span>中来,或者用向导创建<span lang=EN-US>C Herder
File/C Source File</span>。为了能导出这个类,在类声明的时候要加<span lang=EN-US>“_<span
class=SpellE>declspec</span>(<span class=SpellE>dllexport</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>声明<span lang=EN-US><br>
}<br>
</span>如果创建的<span lang=EN-US>MFC</span>扩展<span lang=EN-US>DLL</span>,可以使用宏:<span
lang=EN-US>AFX_EXT_CLASS:<br>
class AFX_EXT_CLASS <span class=SpellE>CMyClass</span><br>
{<br>
</span> <span lang=EN-US> ...//</span>声明<span lang=EN-US><br>
}<br>
</span>这样导出类的方法是最简单的,也可以采用<span lang=EN-US>.def</span>文件导出,这里暂不详谈。<span
lang=EN-US><br>
2</span>、导出变量、常量、对象<span lang=EN-US><br>
</span> 很多时候不需要导出一个类,可以让<span lang=EN-US>DLL</span>导出一个变量、常量、对象,导出它们只需要进行简单的声明:<span
lang=EN-US>_<span class=SpellE>declspec</span>(<span class=SpellE>dllexport</span>)
<span class=SpellE>int</span> <span class=SpellE>MyInt</span>;<br>
_<span class=SpellE>declspec</span>(<span class=SpellE>dllexport</span>)
extern const COLORREF <span class=SpellE>MyColor</span>=RGB(0,0,0);<br>
_<span class=SpellE>declspec</span>(<span class=SpellE>dllexport</span>) <span
class=SpellE>CRect</span> <span class=SpellE>rect</span>(10,10,20,20);<br>
</span>要导出一个常量时必须使用关键字<span lang=EN-US>extern</span>,否则会发生连接错误。<span
lang=EN-US><br>
</span>注意:如果客户程序识别这个<span class=GramE>类而且</span>有自己的头文件,则只能导出一个类对象。如果在<span
lang=EN-US>DLL</span>中创建一个类,客户程序不使用头文件就无法识别这个类。<span lang=EN-US><br>
</span>当导出一个对象或者变量时,载入<span lang=EN-US>DLL</span>的每个客户程序都有一个自己的拷贝。也就是如果两个程序使用的是同一个<span
lang=EN-US>DLL</span>,一个应用程序所做的修改不会影响另一个应用程序。<span lang=EN-US><br>
</span>我们在导出的时候只能导出<span lang=EN-US>DLL</span>中的全局变量或对象,而不能导出局部的变量和对象,因为它们过了作用域也就不存在了,那样<span
lang=EN-US>DLL</span>就不能正常工作。如:<span lang=EN-US><br>
<span class=SpellE>MyFunction</span>()<br>
{<br>
</span> <span lang=EN-US> _<span class=SpellE>declspec</span>(<span
class=SpellE>dllexport</span>) <span class=SpellE>int</span> <span
class=SpellE>MyInt</span>;<br>
</span> <span lang=EN-US> _<span class=SpellE>declspec</span>(<span
class=SpellE>dllexport</span>) <span class=SpellE>CMyClass</span> object;<br>
}<br>
3</span>、导出函数<span lang=EN-US><br>
</span>导出函数和导出变量<span lang=EN-US>/</span>对象类似,只要把<span lang=EN-US>_<span
class=SpellE>declspec</span>(<span class=SpellE>dllexport</span>)</span>加到函数原型开始的位置:<span
lang=EN-US><br>
_<span class=SpellE>declspec</span>(<span class=SpellE>dllexport</span>) <span
class=SpellE>int</span> <span class=SpellE>MyFunction</span>(<span
class=SpellE>int</span>);<br>
</span>如果是常规<span lang=EN-US>DLL</span>,它将和<span lang=EN-US>C</span>写的程序使用,声明方式如下:<span
lang=EN-US><br>
extern "c" _<span class=SpellE>declspec</span>(<span class=SpellE>dllexport</span>)
<span class=SpellE>int</span> <span class=SpellE>MyFunction</span>(<span
class=SpellE>int</span>);<br>
</span>实现:<span lang=EN-US><br>
extern "c" _<span class=SpellE>declspec</span>(<span class=SpellE>dllexport</span>)
<span class=SpellE>int</span> <span class=SpellE>MyFunction</span>(<span
class=SpellE>int</span> x)<br>
{<br>
</span> <span lang=EN-US> ...//</span>操作<span lang=EN-US><br>
}<br>
</span>如果创建的是动态连接到<span lang=EN-US>MFC</span>代码库<span lang=EN-US>DLL</span>的常规<span
lang=EN-US>DLL</span>,则必须插入<span lang=EN-US>AFX_MANAGE_STATE</span>作为导出函数的首行,因此定义如下:<span
lang=EN-US><br>
extern "c" _<span class=SpellE>declspec</span>(<span class=SpellE>dllexport</span>)
<span class=SpellE>int</span> <span class=SpellE>MyFunction</span>(<span
class=SpellE>int</span> x)<br>
{<br>
</span> <span lang=EN-US> AFX_MANAGE_STATE(<span class=SpellE>AfxGetStaticModuleState</span>());<br>
</span> <span lang=EN-US> ...//</span>操作<span lang=EN-US><br>
}<br>
</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>
4</span>、导出指针<span lang=EN-US><br>
</span>导出指针的方式如下:<span lang=EN-US><br>
_<span class=SpellE>declspec</span>(<span class=SpellE>dllexport</span>) <span
class=SpellE>int</span> *pint;<br>
_<span class=SpellE>declspec</span>(<span class=SpellE>dllexport</span>) <span
class=SpellE>CMyClass</span> object = new <span class=SpellE>CMyClass</span>;<br>
</span>如果声明的时候同时初始化了指针,就需要找到合适的地方类释放指针。在扩展<span lang=EN-US>DLL</span>中有个函数<span
class=SpellE><span lang=EN-US>DllMain</span></span><span lang=EN-US>()</span>。(注意函数名中的两个<span
lang=EN-US>l</span>要是小写字母),可以在这个函数中处理指针:<span lang=EN-US><br>
# include "<span class=SpellE>MyClass.h</span>"<br>
_<span class=SpellE>declspec</span>(<span class=SpellE>dllexport</span>) <span
class=SpellE>CMyClass</span> *<span class=SpellE>pobject</span> = new <span
class=SpellE>CMyClass</span>;<br>
<span class=SpellE>DllMain</span>(HINSTANCE <span class=SpellE>hInstance,DWORD</span>
<span class=SpellE>dwReason,LPVOID</span> <span class=SpellE>lpReserved</span>)<br>
{<br>
</span> <span lang=EN-US> if(<span class=SpellE>dwReason</span> ==
DLL_PROCESS_ATTACH)<br>
</span> <span lang=EN-US> {<br>
</span> <span class=GramE> </span><span lang=EN-US> .....//<br>
</span> <span lang=EN-US> }<br>
</span> <span lang=EN-US> else if(<span class=SpellE>dwReason</span> ==
DLL_PROCESS_DETACH)<br>
</span> <span lang=EN-US> {<br>
</span> <span class=GramE> </span><span lang=EN-US> delete <span
class=SpellE>pobject</span>;<br>
</span> <span lang=EN-US> }<br>
}<br>
</span>常规<span lang=EN-US>DLL</span>有一个从<span class=SpellE><span lang=EN-US>CWinApp</span></span>派生的<span
class=GramE>类对象</span>处理<span lang=EN-US>DLL</span>的开和关,可以使用类向导添加<span
class=SpellE><span lang=EN-US>InitInstance/ExitInstance</span></span>函数。<span
lang=EN-US><br>
<span class=SpellE>int</span> <span class=SpellE>CMyDllApp::ExitInstance</span>()<br>
{<br>
</span> <span lang=EN-US> delete <span class=SpellE>pobject</span>;<br>
</span> <span lang=EN-US> return <span class=SpellE>CWinApp::ExitInstance</span>();<br>
}<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
lang=EN-US>DLL</span></span></b><span lang=EN-US style='font-size:10.0pt;
font-family:宋体;mso-bidi-font-family:宋体;mso-font-kerning:0pt'><br>
</span><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>.<span class=SpellE>dll</span></span>文件和<span lang=EN-US>.lib</span>文件。首先将这两个文件复制到客户程序项目的文件夹里,这里需要注意<span
lang=EN-US>DLL</span>和客户程序的版本问题,尽量使用相同的版本,都使用<span lang=EN-US>RELEASE</span>或者都是<span
lang=EN-US>DEBUG</span>版本。<span lang=EN-US><br>
</span> 接着就需要在客户程序中设置<span lang=EN-US>LIB</span>文件,打开<span lang=EN-US>Project
Settings--->Link--->Object/library Modules</span>中输入<span lang=EN-US>LIB</span>的文件名和路径。如:<span
lang=EN-US>Debug/<span class=SpellE>SampleDll.lib</span></span>。除了<span
lang=EN-US>DLL</span>和<span lang=EN-US>LIB</span>文件外,客户程序需要针对导出类、函数、对象和变量的头文件,现在进行导入添加的关键字就是:<span
lang=EN-US>_<span class=SpellE>declspec</span>(<span class=SpellE>dllimport</span>)</span>,如:<span
lang=EN-US><br>
_<span class=SpellE>declspec</span>(<span class=SpellE>dllimport</span>) <span
class=SpellE>int</span> <span class=SpellE>MyFunction</span>(<span
class=SpellE>int</span>);<br>
_<span class=SpellE>declspec</span>(<span class=SpellE>dllimport</span>) <span
class=SpellE>int</span> <span class=SpellE>MyInt</span>;<br>
_<span class=SpellE>declspec</span>(<span class=SpellE>dllimport</span>) <span
class=SpellE>CMyClass</span> object;<br>
extern "C" _<span class=SpellE>declspec</span>(<span class=SpellE>dllimport</span>)
<span class=SpellE>int</span> <span class=SpellE>MyFunction</span>(<span
class=SpellE>int</span>);<br>
</span>在有的时候为了导入类,要把相应类的头文件添加到客户程序中,不同的是要修改类声明的标志:<span lang=EN-US><br>
class _<span class=SpellE>declspec</span>(<span class=SpellE>dllimport</span>)
<span class=SpellE>CMyClass</span></span>,如果创建的是扩展<span lang=EN-US>DLL</span>,两个位置都是<span
lang=EN-US>:<br>
class AFX_EXT_CLASS <span class=SpellE>CMyClass</span></span>。<span
lang=EN-US><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 + -