VS2005---MFC应用程序向Win32DLL程序转换

本次项目有两个工程,一个是VS2005工程,一个是VC6工程。对于这两个工程,先是做的MFC exe应用程序,然后客户又要求把exe转换成dll工程,因此就开始了痛苦的转换工程。本章将要记录的是VS2005工程的转换。下一章将记录的是另一个VC6工程的转化。两个IDE平台下的转换方法不能通用,不知道为什么啊!

 

新建立了DllMain.cpp、entpoint.cpp、API.cpp 、XXX_main.cpp这几个文件,其中API.cpp 是相关库函数(无关紧要)。

 

 

DLLMain.cpp内容如下:

#include "stdafx.h" #ifdef _MANAGED #pragma managed(push, off) #endif #if 1 // ADD By 2009/3/25 STA HINSTANCE hTheApp; #endif // ADD By 2009/3/25 END static AFX_EXTENSION_MODULE PMFMarkDrawingDLL = { NULL, NULL }; BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { // lpReserved を使う場合はここを削除してください UNREFERENCED_PARAMETER(lpReserved); #if 1 // ADD By 2009/3/25 STA hTheApp = hModule; #endif // ADD By 2009/3/25 END if (ul_reason_for_call == DLL_PROCESS_ATTACH) { // 拡張 DLL を1回だけ初期化します。 if (!AfxInitExtensionModule(PMFMarkDrawingDLL, hModule)) return 0; // この DLL をリソース チェインへ挿入します。 // メモ: 拡張 DLL が MFC アプリケーションではなく // MFC 標準 DLL (ActiveX コントロールのような) // に暗黙的にリンクされる場合、この行を DllMain // から削除して、この拡張 DLL からエクスポート // された別の関数内へ追加してください。 // この拡張 DLL を使用する標準 DLL はこの拡張 DLL // を初期化するために明示的にその関数を呼び出します。 // それ以外の場合は、CDynLinkLibrary オブジェクトは // 標準 DLL のリソース チェインへアタッチされず、 // その結果重大な問題となります。 new CDynLinkLibrary(PMFMarkDrawingDLL); } else if (ul_reason_for_call == DLL_PROCESS_DETACH) { // デストラクタが呼び出される前にライブラリを終了します AfxTermExtensionModule(PMFMarkDrawingDLL); } return 1; // ok // return TRUE; } #ifdef _MANAGED #pragma managed(pop) #endif

 

 

entpoint.cpp内容如下:

#if 1 // ADD By 2009/3/25 STA extern HINSTANCE hTheApp; #endif // ADD By 2009/3/25 END // Protos extern "C"{ int GetGlobals(char *appname,HWND *hwnd,HINSTANCE *hInstance); } void __declspec(dllexport) EntryPoint(HWND hWnd); void __declspec(dllexport) EntryPoint(HWND hWnd) { #if 1 // ADD By 2009/3/25 STA AfxSetResourceHandle(hTheApp); AfxGetModuleState()->m_hCurrentInstanceHandle = hTheApp; //AFX_MANAGE_STATE(AfxGetStaticModuleState()); #endif // ADD By 2009/3/25 END int i,j; for(i=0; i<=3; i++) for(j=0; j<=3; j++) sds_identmat[i][j]=0.0; for(i=0; i<=3; i++) sds_identmat[i][i]=1.0; SDS_GetGlobals(adsw_AppName,&adsw_hwndAcad,&adsw_hInstance); strncpy(sds_appname,adsw_AppName,sizeof(sds_appname)-1); SDS_main(1,&sds_argVec); return; }

 

 

XXX_main.cpp内容如下:

#include "stdafx.h" #include "XXXDrawingDlg.h" #include "XXX_main.h" CWnd* m_pMainWnd; // main window // ADD //HINSTANCE g_hModuleInstance = NULL; //HINSTANCE g_hOldModuleInstance = NULL; // ADD // ADD //void SetResourceHandle() //{ // g_hOldModuleInstance = AfxGetModuleState()->m_hCurrentResourceHandle; // AfxGetModuleState()->m_hCurrentResourceHandle = g_hModuleInstance; //} // //void RestoreResourceHandle() //{ // AfxGetModuleState()->m_hCurrentResourceHandle =g_hOldModuleInstance; //} // ADD /*:********************************************************************** 機   能:PMF前処理コマンド 戻 り 値:0 正常終了 1 異常終了 備   考: ************************************************************************/ int XXXDrawing_Main() { setlocale(LC_ALL,""); g_strMarkDrawingFileName = _T(""); try { // initialize DWGdirect odInitialize(&g_svcs); } catch (OdError) { ::AfxMessageBox( _T("DWGdirectの初期設定は失敗してしまいました。") );//, err); return FALSE; } catch (...) { ::AfxMessageBox( _T("DWGdirectの初期設定は失敗してしまいました。") );//, eNotHandled); return FALSE; } // 標準的な初期化処理 // もしこれらの機能を使用せず、実行ファイルのサイズを小さくしたけ // れば以下の特定の初期化ルーチンの中から不必要なものを削除して // ください。 #if 1 // ADD By 2009/3/25 STA //initialize OLE controller(for example: FlexGrid) OleInitialize(NULL); //COleObjectFactory::RegisterAll(); AfxEnableControlContainer(); #endif // ADD By 2009/3/25 END XXXDrawingDlg dlg; m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); if (nResponse == IDOK) { // TODO: ダイアログが で消された時のコードを // 記述してください。 } else if (nResponse == IDCANCEL) { // TODO: ダイアログが <キャンセル> で消された時のコードを // 記述してください。 } odUninitialize(); // DWGdirect termination #if 1 // ADD By 2009/3/25 STA //uninitialize OLE controller(for example: FlexGrid) OleUninitialize(); #endif // ADD By 2009/3/25 END return(0); }

 

 

解释:

(1)XXXDrawing.cpp文件是MFC exe应用程序的CWinApp类文件,即XXXDrawing.cpp文件中定义XXXDrawingApp类,

class XXXDrawingApp: public CWinApp
{

};

 

我们向Win32 DLL转换时,从工程中去掉XXXDrawing.cpp文件,把XXXDrawing.cpp文件中的XXXDrawing::InitInstance()中的内容全部拷贝到XXX_main.cpp文件的XXXDrawing_Main()函数中,XXXDrawing_Main()函数会被导出函数EntryPoint()间接调用。

 

(2)entpoint.cpp文件的导出函数EntryPoint(HWND hWnd) 中有如下两行代码:
#if 1 // ADD By  2009/3/25 STA
 AfxSetResourceHandle(hTheApp);
 AfxGetModuleState()->m_hCurrentInstanceHandle = hTheApp;
 //AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif // ADD By  2009/3/25 END

 

 

 hTheApp是此DLL的句柄,在DLLmain()函数中被复制。我写这两行代码的原因是这样的:经过debug跟踪,发现

AfxGetModuleState()->m_hCurrentInstanceHandle
AfxGetModuleState()->m_hCurrentResourceHandle

这两个句柄始终为空,于是就上网查资料,据说是DLL状态切换问题,因此我就在导出函数开头加上了状态转化语句“AFX_MANAGE_STATE(AfxGetStaticModuleState());”,但是不知道为什么使用了此语句后还是为空,因此我就这样强制的给这两个handle赋成了hTheApp。这样 在以后的程序debug执行过程中,就不会出现因为handle为空而产生的assert错误了。

 (3)添加了上述两句后,又出现了类似这样的错误:" uafxcwd.lib(dllmodul.obj) : error LNK2005: _DllMain@12 already defined in main.obj "。到网上查了一下,据说把VS安装目录下的MFC源文件dllmodul.cpp加入工程中重新编译链接就可以了,但是还是会出现这种错误,因此我就浏览了一下dllmodul.cpp文件,发现这里也有一个dllmain()函数,因此我就把dllmodul.cpp中的dllmain()函数注释掉,然后编译链接就可以了。

 

(4)加载完此dll后,运行程序,发现不能运行,一运行就崩溃,再进一步debug发现是VSFlex Grid ocx控件没有加载成功,因此我就在XXXDrawing_Main()中加入这两句:

OleInitialize(NULL);

 AfxEnableControlContainer();”,而后就ok了。

总结上述解决办法虽然可行,但自己对这些原理不是很清楚,还是迷糊啊。

余留bug:本项目有两个vs2005的MFC工程需要转换成DLL,现在转化已经成功,当单独加载某一个dll运行程序时没有问题,但同时加载两个dll运行程序时会出现程序崩溃,调查了一下,跟VSFlex Grid ocx控件加载卸载有关系,还得继续调查。

你可能感兴趣的:(VC,MFC,相关)