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

📄 在dll中使用资源(2).htm

📁 我在网上收集的一些有关vcDLL编程的文章。
💻 HTM
📖 第 1 页 / 共 2 页
字号:
  lang=EN-US> <br>
  <br>
  <br>
  <br>
  </span>继续使用上面的<span lang=EN-US>Use</span>工程,将前面生成的<span lang=EN-US>DLLShared.dll</span>和<span
  lang=EN-US>DLLShared.lib</span>两个文件复制到工程的<span lang=EN-US>Debug</span>目录内,并将<span
  lang=EN-US> <br>
  <br>
  <br>
  <br>
  extern &quot;C&quot; __declspec(dllexport) void ShowDlg(); <br>
  <br>
  #pragma comment(lib,&quot;debug/DLLStatic&quot;) <br>
  <br>
  <br>
  <br>
  </span>这两行改为:<span lang=EN-US> <br>
  <br>
  <br>
  <br>
  void ShowDlg(); <br>
  <br>
  #pragma comment(lib,&quot;debug/DLLShared&quot;) <br>
  <br>
  <br>
  <br>
  </span>编译并运行<span lang=EN-US>Use.exe</span>。点击按钮,这次你看到了什么?对,没错,这次弹出的是<span
  lang=EN-US>Use.exe</span>的关于对话框。将上述例子的<span lang=EN-US>DLL</span>类型换成<span
  lang=EN-US>MFC Extension DLL(using shared MFC DLL)</span>也会出现相同的问题。<span
  lang=EN-US> <br>
  <br>
  <br>
  <br>
  </span>为什么会出现上面的问题?这是因为在使用了<span lang=EN-US>MFC</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>Use.exe</span>中寻找相应的对话框模板。由于在<span
  lang=EN-US>DLL</span>中所定义的对话框资源<span lang=EN-US>ID</span>与主应用程序中所定义的关于对话框的资源<span
  lang=EN-US>ID</span>相同,所以<span lang=EN-US>MFC</span>就把主应用程序中的关于对话框显示了出来。如果二者不同,则<span
  lang=EN-US>MFC</span>就认为<span lang=EN-US>DLL</span>中所定义的对话框资源不存在,<span
  lang=EN-US>dlg.DoModal</span>会返回<span lang=EN-US>0</span>,也就是什么都不会显示。<span
  lang=EN-US> <br>
  <br>
  <br>
  <br>
  </span>那么如何解决上述问题呢?解决办法就是在适当的时候进行模块状态切换,以保证具有当前状态的模块是我们所需要的模块从而使用正确的资源。<span
  lang=EN-US>MFC</span>提供了下列函数和宏来完成这些工作:<span lang=EN-US> <br>
  <br>
  <br>
  <br>
  AfxGetStaticModuleState</span>:这是一个函数,其函数原型为:<span lang=EN-US> <br>
  <br>
  <br>
  <br>
  AFX_MODULE_STATE* AFXAPI AfxGetStaticModuleState( ); <br>
  <br>
  <br>
  <br>
  </span>此函数在堆栈上构造<span lang=EN-US>AFX_MODULE_STATE</span>类的实例<span lang=EN-US>pModuleState</span>并对其赋值后将其返回。在<span
  lang=EN-US>AFX_MODULE_STATE</span>类的构造函数中,该类获取指向当前模块状态的指针并将其存储在成员变量中,然后将<span
  lang=EN-US>pModuleState</span>设置为新的有效模块状态。在它的析构函数中,该类将存储在其成员变量中的指针还原为存贮的前一个模块状态。<span
  lang=EN-US> <br>
  <br>
  <br>
  <br>
  AFX_MANAGE_STATE</span>:这是一个宏,其原型为:<span lang=EN-US> <br>
  <br>
  <br>
  <br>
  AFX_MANAGE_STATE( AFX_MODULE_STATE* pModuleState ) <br>
  <br>
  <br>
  <br>
  </span>该宏用于将<span lang=EN-US>pModuleState</span>(指向包含模块全局数据也就是模块状态的<span
  lang=EN-US>AFX_MODULE_STATE</span>结构的指针)设置为当前的即时作用空间中(<span lang=EN-US>the
  remainder of the immediate containing scope</span>)的有效模块状态。在离开包含该宏的作用空间时,前一个有效的模块状态自动还原。<span
  lang=EN-US> <br>
  <br>
  <br>
  <br>
  AfxGetResourceHandle</span>:这个函数的原型为:<span lang=EN-US> <br>
  <br>
  <br>
  <br>
  </span> <span lang=EN-US> HINSTANCE AfxGetResourceHandle( ); <br>
  <br>
  <br>
  <br>
  </span>  该函数返回了一个保存了<span lang=EN-US>HINSTANCE</span>类型的、应用程序默认所加载资源的模块的句柄。<span
  lang=EN-US> <br>
  <br>
  <br>
  <br>
  AfxSetResourceHandle</span>:这个函数的原型为:<span lang=EN-US> <br>
  <br>
  <br>
  <br>
  void AfxSetResourceHandle( HINSTANCE hInstResource ); <br>
  <br>
  <br>
  <br>
  </span>该函数将<span lang=EN-US>hInstResource</span>所代表的模块设置为具有当前状态的模块。<span
  lang=EN-US> <br>
  <br>
  <br>
  <br>
  </span>通过使用上述四个函数或宏就可以正确的在动态链接到<span lang=EN-US>MFC</span>的<span lang=EN-US>DLL</span>中切换模块状态。接下来我们将通过修改上面出现问题的那个例子来介绍如何使用上述四个函数或宏。先来看看<span
  lang=EN-US>Regular DLL using shared MFC DLL</span>类型:<span lang=EN-US> <br>
  <br>
  <br>
  <br>
  </span>在上述例子的第三步的<span lang=EN-US>ShowDlg</span>函数的第一条语句前加上如下语句(要确保该语句在函数实现的第一行):<span
  lang=EN-US> <br>
  <br>
  <br>
  <br>
  AFX_MANAGE_STATE(AfxGetStaticModuleState()); <br>
  <br>
  <br>
  <br>
  </span>之后重新编译生成<span lang=EN-US>DLLShared.dll</span>和<span lang=EN-US>DLLShared.lib</span>,并将这两个文件重新拷贝到<span
  lang=EN-US>Use</span>工程的<span lang=EN-US>Debug</span>目录内。这次编译生成<span
  lang=EN-US>Use.exe</span>并运行,点击按钮,可以看到弹出的时我们在<span lang=EN-US>DLL</span>中所加入的那个对话框,而不再是<span
  lang=EN-US>Use.exe</span>的关于对话框了。<span lang=EN-US> <br>
  <br>
  <br>
  <br>
  </span>通过上面的讲解,相信你已经知道该语句的作用了。在函数<span lang=EN-US>ShowDlg</span>的第一行加上这么一句后,每次调用<span
  lang=EN-US>DLL</span>的应用程序使用该函数的时候,<span lang=EN-US>MFC</span>库都会自动切换当前模块状态,这样就保证了资源读取的正确性。<span
  lang=EN-US> <br>
  <br>
  <br>
  <br>
  AFX_MANAGE_STATE(AfxGetStaticModuleState());</span>是自动切换当前模块状态,也可以通过使用<span
  lang=EN-US>AfxGetResourceHandle</span>和<span lang=EN-US>AfxSetResourceHandle</span>来手动切换当前模块状态。具体使用方法如下:<span
  lang=EN-US> <br>
  <br>
  <br>
  <br>
  </span>在上述例子的第三步的<span lang=EN-US>ShowDlg</span>函数的第一条语句前加上如下语句(要确保该语句在函数实现的第一行):<span
  lang=EN-US> <br>
  <br>
  <br>
  <br>
  HINSTANCE save_hInstance = AfxGetResourceHandle(); <br>
  <br>
  </span> <span lang=EN-US> AfxSetResourceHandle(theApp.m_hInstance); <br>
  <br>
  <br>
  <br>
  </span>在调用对话框成功之后,也就是<span lang=EN-US>dlg.DoModal();</span>之后,添加:<span
  lang=EN-US> <br>
  <br>
  <br>
  <br>
  AfxSetResourceHandle(save_hInstance); <br>
  <br>
  <br>
  <br>
  </span>  这种方法在进入<span lang=EN-US>ShowDlg</span>函数之后,通过<span lang=EN-US>AfxGetResourceHandle</span>来获得并保存当前状态模块的句柄。然后获得<span
  lang=EN-US>DLL</span>模块的句柄<span lang=EN-US>theApp.m_hInstance</span>(当然,也可以使用<span
  lang=EN-US>GetModuleHandle</span>函数来获得<span lang=EN-US>DLL</span>模块的句柄),并使用<span
  lang=EN-US>AfxSetResourceHandle</span>函数来将其设置为当前状态状态。最后在调用对话框成功之后再用恢复<span
  lang=EN-US>AfxSetResourceHandle</span>资源句柄,将当前模块状态恢复。<span lang=EN-US> <br>
  <br>
  <br>
  <br>
  </span>  这样做有些麻烦,但是有一点好处是可以在完成使用资源的任务之后就可以立即恢复资源句柄。而<span lang=EN-US>AFX_MANAGE_STATE(AfxGetStaticModuleState());</span>的方法只能等函数的作用空间结束之后才恢复资源句柄。由于可执行文件必须重画工具条等原因,因此建议只要有可能就必须恢复资源句柄,否则可能会遇到许多问题。比如说,如果用户移动<span
  lang=EN-US>DLL</span>的对话框,而此时资源句柄仍然为<span lang=EN-US>DLL</span>的资源,那么程序就会崩溃。最好的恢复句柄的时机在对话框响应<span
  lang=EN-US>WM_INITDIALOG</span>消息的时候,因为这时对话框的模板等已经读出了。<span lang=EN-US> <br>
  <br>
  <br>
  <br>
  </span>  对于<span lang=EN-US>MFC Extension DLL(using shared MFC DLL)</span>类型的<span
  lang=EN-US>MFC DLL</span>,切换当前模块状态的方法与<span lang=EN-US>Regular DLL using
  shared MFC DLL</span>类型的<span lang=EN-US>MFC DLL</span>所使用的方法很相似,这里不再举例实现。二者不同的地方如下:<span
  lang=EN-US> <br>
  <br>
  <br>
  <br>
  </span>  在<span lang=EN-US>MFC</span>扩展<span lang=EN-US>DLL</span>中使用<span
  lang=EN-US>AFX_MANAGE_STATE(AfxGetStaticModuleState());</span>时,会产生如下错误:<span
  lang=EN-US> <br>
  <br>
  <br>
  <br>
  mfcs42d.lib(dllmodul.obj) : error LNK2005: __pRawDllMain already defined in
  dllextend.obj <br>
  <br>
  mfcs42d.lib(dllmodul.obj) : error LNK2005: _DllMain@12 already defined in
  dllextend.obj <br>
  <br>
  mfcs42d.lib(dllmodul.obj) : error LNK2005: __pRawDllMain already defined in
  dllextend.obj <br>
  <br>
  <br>
  <br>
  </span>因此在<span lang=EN-US>MFC</span>扩展<span lang=EN-US>DLL</span>中需要将<span
  lang=EN-US>AFX_MANAGE_STATE(AfxGetStaticModuleState());</span>换成<span
  lang=EN-US>AFX_MANAGE_STATE(AfxGetAppModuleState());</span>才能正确切换当前模块状态。<span
  lang=EN-US> <br>
  <br>
  <br>
  <br>
  </span>在<span lang=EN-US>MFC</span>扩展<span lang=EN-US>DLL</span>中使用<span
  lang=EN-US>AfxGetResourceHandle</span>和<span lang=EN-US>AfxSetResourceHandle</span>的方法与在<span
  lang=EN-US>Regular DLL using shared MFC DLL</span>类型的<span lang=EN-US>MFC DLL</span>中所使用的方法相同。并且,<span
  lang=EN-US>DLL</span>模块的句柄可以通过<span lang=EN-US>MFC</span>提供的<span lang=EN-US>DlgextentDLL</span>这个结构的<span
  lang=EN-US>hModule</span>成员来获得。即使用<span lang=EN-US>AfxSetResourceHandle(DlgextentDLL.hModule);</span>语句。<span
  lang=EN-US> <br>
  <br>
  <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>MFC</span>应用程序中使用<span lang=EN-US>AfxGetResourceHandle</span>和<span
  lang=EN-US>AfxSetResourceHandle</span>两个函数来切换当前状态模块。该<span lang=EN-US>DLL</span>模块的句柄可以用<span
  lang=EN-US>GetModuleHandle</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>&nbsp;</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>&nbsp;</o:p></span></p>
  </td>
 </tr>
</table>

</div>

<p class=MsoNormal><span lang=EN-US><o:p>&nbsp;</o:p></span></p>

</div>

</body>

</html>

⌨️ 快捷键说明

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