如何使用动态链接库中的资源
近來在論壇上很有多帖子問到如何使用DLL中的資源(包括對話框,圖標等)的問題,現在筆者就來就此問題談談,包含在DLL內部使用資源,DLL中使用其它DLL中的資源和在應用程序中使用資源。
?????? 我們先以圖標為例說起(其它的資源與此圖標的加載原理大致相同),我們要加載圖標,一般是調用AfxGetApp()->LoadIcon(…);下面是CWinApp::LoadIcon的實現(afxwin2.inl):
_AFXWIN_INLINE HICON CWinApp::LoadIcon(LPCTSTR lpszResourceName) const
{ return ::LoadIcon(AfxFindResourceHandle(lpszResourceName,
???????? RT_GROUP_ICON), lpszResourceName); }
_AFXWIN_INLINE HICON CWinApp::LoadIcon(UINT nIDResource) const
{ return ::LoadIcon(AfxFindResourceHandle(MAKEINTRESOURCE(nIDResource),
???????? RT_GROUP_ICON), MAKEINTRESOURCE(nIDResource)); }
?????? 可以看到CWinApp::LoadIcon實際上調用了API .LoadIcon,下面是API LoadIcon的原型:
HICON?LoadIcon(??????HINSTANCE?hInstance,????LPCTSTR?lpIconName);?
hInstance
[in]?Handle to an instance of the module whose executable file contains the icon to be loaded. This parameter must be NULL when a standard icon is being loaded.
hInstance是我們要加載ICON的模塊實例,這個實例從何來,當然我們可以直接傳入DLL的實例,對于通過LoadLibrary動態加載的DLL我們可以很容易的得到其句柄,但對于我們直接鏈接的DLL得到其句柄則要費一番周折??梢钥吹紺WinApp::LoadIcon是通過AfxFindResouceHandle找到此句柄的。下面是AfxFindResourceHandle的定義(afxwin.h):
#ifndef _AFXDLL
#define AfxFindResourceHandle(lpszResource, lpszType) AfxGetResourceHandle()
#else
HINSTANCE AFXAPI AfxFindResourceHandle(LPCTSTR lpszName, LPCTSTR lpszType);
#endif
?????? 我們先討論在靜態鏈接庫中使用MFC DLL的情況。可以看到,我們如果在靜態庫中使用MFC DLL的話(#ifndef _AFXDLL),實際上就是調用的AfxGetResourceHandle,MSDN中的說明是
AfxGetResourceHandle??
This function accesses the application’s resources directly by using the?HINSTANCE?handle returned, for example, in calls to the Windows function?FindResource.
HINSTANCE AfxGetResourceHandle( );
Return Value
An?HINSTANCE?handle where the default resources of the application are loaded.
函數返回的應用程序加載的缺省資源的HINSTANCE句柄,HINSTANCE相當于HMODULE,也就是資源所在的模塊句柄。顯然在此,我們使用的是DLL中的資源,那么我們就應該返回此DLL中的HINSTANCE了,如果讓AfxGetResourceHandle返回DLL的HINSTANCE呢?答案是通過AfxSetResourceHandle設置。MSDN中AfxSetResouceHandle的說明如下:
AfxSetResourceHandle
This function sets the?HINSTANCE?handle that determines where the default resources of the application are loaded.
void AfxSetResourceHandle(
HINSTANCE?hInstResource?);
Parameters
hInstResource
Specifies the instance or module handle to an .EXE or DLL file from which the application’s resources are loaded.
我們只需將DLL的HINSTANCE傳入AfxSetResouceHanle就行了。如何得到DLL的HINSTANCE呢,我們可以通過DLL聲明一個接口HINSTANCE GetInstance獲得,也可以通過EnumProcessMoudules找到(詳細的過程見MSDN中EnumProcessModules的說明和示例)。
我們使用完DLL中的資源要使用EXE中的資源的資源怎么辦呢?我們需要在使用完成后用AfxSetResource重新將資源模塊的句柄設置為原來的值,如果來保證在資源使用完成后完成這一個工作呢,即使在使用過程中發生異常了,為此我們利C++類的構造和析構機制創建了這一類:
class CLocalResource?
{
public:
???????? CLocalResource(HINSTANCE hInstance)
{
???????? m_hInstOld=AfxGetInstanceHandle();
???????? AfxSetInstanceHandle(hInstance);
}
???????? virtual ~CLocalResource()
{
???????? AfxSetInstanceHandle(m_hInstOld);
}
protected:
???????? HINSTANCE m_hInstOld;
};
???????? 我們只需在使用DLL的資源之前構造一個CLocalInstance就行了。
void CXXXX::LoadResouceFromDLL(HINSTANCE hInst,UINT nResID,…)
{
???????? CLocalResouce localRes(hInst);
???????? …
}
下面來討論在動態庫中使用MFC DLL的情況(也就是定義了_AFXDLL的情況)
來看看AfxGetInstanceHandle ,AfxGetResourceHandle和AfxSetResouceHandle的實現(afxwin1.inl中):
_AFXWIN_INLINE HINSTANCE AFXAPI AfxGetInstanceHandle()
???????? { ASSERT(afxCurrentInstanceHandle != NULL);
???????? return afxCurrentInstanceHandle; }
_AFXWIN_INLINE HINSTANCE AFXAPI AfxGetResourceHandle()
{ ASSERT(afxCurrentResourceHandle != NULL);
return afxCurrentResourceHandle; }
_AFXWIN_INLINE void AFXAPI AfxSetResourceHandle(HINSTANCE hInstResource)
{ ASSERT(hInstResource != NULL); afxCurrentResourceHandle = hInstResource; }
實際上訪問的就是afxCurrentInstanceHandle,afxCurrentResourceHandle。
/
// Global functions for access to the one and only CWinApp
…
#define afxCurrentInstanceHandle??? AfxGetModuleState()->m_hCurrentInstanceHandle
#define afxCurrentResourceHandle?? AfxGetModuleState()->m_hCurrentResourceHandle
….
AFX_MODULE_STATE* AFXAPI AfxGetModuleState()
{
???????? _AFX_THREAD_STATE* pState = _afxThreadState;
???????? AFX_MODULE_STATE* pResult;
???????? if (pState->m_pModuleState != NULL)
???????? {
?????????????????? // thread state's module state serves as override
?????????????????? pResult = pState->m_pModuleState;
???????? }
???????? else
???????? {
?????????????????? // otherwise, use global app state
?????????????????? pResult = _afxBaseModuleState.GetData();
???????? }
???????? ASSERT(pResult != NULL);
???????? return pResult;
}
其中的_AFX_THREAD_STATE在此我們就不討論了,有興趣的讀者可以閱讀(afxstat_.h和afxstate.cpp)。
???????? 那AfxGetModuleState()->m_hCurrentResourceHandle又是在哪初始化的呢?
我們可以在appinit.cpp中的BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)看到
// set resource handles
???????? AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
???????? pModuleState->m_hCurrentInstanceHandle = hInstance;
???????? pModuleState->m_hCurrentResourceHandle = hInstance;
?????? 和appinit.cpp中的void CWinApp::SetCurrentHandles()中看到
???????? AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
???????? pModuleState->m_hCurrentInstanceHandle = m_hInstance;
???????? pModuleState->m_hCurrentResourceHandle = m_hInstance;
???????? CWinApp::SetCurrentHandles()也是由AfxWinInit調用的,那AfxWinInit又由誰調用呢?
我們可以在DllMain(dllinit.cpp和dllmodul.cpp,分別對應于MFC擴展DLL和MFC規則DLL)看到
(dllinit.cpp,MFC擴展DLL)
static AFX_EXTENSION_MODULE coreDLL;
….
extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
???????? if (dwReason == DLL_PROCESS_ATTACH)
???????? {
?????????????????? …….
?????????????????? // initialize this DLL's extension module
?????????????????? VERIFY(AfxInitExtensionModule(coreDLL, hInstance));
#ifdef _AFX_OLE_IMPL
?????????????????? AfxWinInit(hInstance, NULL, _T(""), 0);
?
?????????????????? ….
#endif
….
?????????????????? // wire up this DLL into the resource chain
?????????????????? CDynLinkLibrary* pDLL = new CDynLinkLibrary(coreDLL, TRUE);
?????????????????? ASSERT(pDLL != NULL);
?????????????????? pDLL->m_factoryList.m_pHead = NULL;
?????????????????? ….
???????? }
???????? else if (dwReason == DLL_PROCESS_DETACH)
???????? {
?????????????????? ….
?????????????????? // cleanup module state for this process
?????????????????? AfxTermExtensionModule(coreDLL);
?????????????????? ….
?????????????????? // cleanup module state in OLE private module state
?????????????????? AfxTermExtensionModule(coreDLL, TRUE);
?????????????????? ….
???????? }
???????? …
}
可以看到在提供自動化支持時,將調用AfxWinInit(但MFC的DLL向導,對于擴展DLL卻不允許添加自動化支持)。
(在dllmodul.cpp中,MFC常規DLL)
#ifdef _AFXDLL
static AFX_EXTENSION_MODULE controlDLL;
….
#endif
?
extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
???????? if (dwReason == DLL_PROCESS_ATTACH)
???????? {
….
?????????????????? _AFX_THREAD_STATE* pState = AfxGetThreadState();
?????????????????? AFX_MODULE_STATE* pPrevModState = pState->m_pPrevModuleState;
?
?????????????????? // Initialize DLL's instance(/module) not the app's
?????????????????? if (!AfxWinInit(hInstance, NULL, _T(""), 0))
?????????????????? {
??????????????????????????? AfxWinTerm();
??????????????????????????? goto Cleanup;?????? // Init Failed
?????????????????? }
?
?????????????????? ….
#ifdef _AFXDLL
?????????????????? // wire up this DLL into the resource chain
?????????????????? VERIFY(AfxInitExtensionModule(controlDLL, hInstance));
?????????????????? CDynLinkLibrary* pDLL; pDLL = new CDynLinkLibrary(controlDLL);
?????????????????? ASSERT(pDLL != NULL);
#else
?????????????????? AfxInitLocalData(hInstance);
#endif
…
???????? }
???????? else if (dwReason == DLL_PROCESS_DETACH)
???????? {
….
#ifdef _AFXDLL
?????????????????? AfxTermExtensionModule(controlDLL, TRUE);
#else
?????????????????? AfxTermLocalData(hInstance, TRUE);
#endif
???????? }
???????? …
}
???????? 看到上面的代碼,其實與MFC擴展DLL的代碼大同小異,只過是MFC常規DLL可以支持在靜態鏈接庫全用MFC DLL,相應的初始化/反初始化函數就變為了AfxInitLocalData/ AfxTermLocalData,在此我們不對在靜態鏈接庫中使用MFC DLL的情況作更多討論。
以及在winmain.cpp中的int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow),在appmodul.cpp中我們可以看到入口函數的實現:
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
???????? LPTSTR lpCmdLine, int nCmdShow)
{
???????? // call shared/exported WinMain
???????? return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
看看AfxInitExtensionModule , AfxTermExtensionModule CDynLinkLibrary的定義(afxdll_.h)和實現(在dllinit.cpp中)就明白了DllMain做了什么:
?
BOOL AFXAPI AfxInitExtensionModule(AFX_EXTENSION_MODULE& state, HMODULE hModule)
{
???????? // only initialize once
???????? if (state.bInitialized)
???????? {
?????????????????? AfxInitLocalData(hModule);
?????????????????? return TRUE;
???????? }
???????? state.bInitialized = TRUE;
???????? // save the current HMODULE information for resource loading
???????? ASSERT(hModule != NULL);
???????? state.hModule = hModule;
???????? state.hResource = hModule;
???????? // save the start of the runtime class list
???????? AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
???????? state.pFirstSharedClass = pModuleState->m_classList.GetHead();
???????? pModuleState->m_classList.m_pHead = pModuleState->m_pClassInit;
?
#ifndef _AFX_NO_OLE_SUPPORT
???????? // save the start of the class factory list
???????? state.pFirstSharedFactory = pModuleState->m_factoryList.GetHead();
???????? pModuleState->m_factoryList.m_pHead = pModuleState->m_pFactoryInit;
#endif
???????? return TRUE;
}
…
void AFXAPI AfxTermExtensionModule(AFX_EXTENSION_MODULE& state, BOOL bAll)
{
???????? // make sure initialized
???????? if (!state.bInitialized)
?????????????????? return;
?
???????? // search for CDynLinkLibrary matching state.hModule and delete it
???????? ASSERT(state.hModule != NULL);
???????? AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
???????? AfxLockGlobals(CRIT_DYNLINKLIST);
???????? for (CDynLinkLibrary* pDLL = pModuleState->m_libraryList; pDLL != NULL; )
???????? {
?????????????????? CDynLinkLibrary* pNextDLL = pDLL->m_pNextDLL;
?????????????????? if (bAll || pDLL->m_hModule == state.hModule)
??????????????????????????? delete pDLL;??? // will unwire itself
?????????????????? pDLL = pNextDLL;
???????? }
???????? AfxUnlockGlobals(CRIT_DYNLINKLIST);
???????? // delete any local storage attached to this module
???????? AfxTermLocalData(state.hModule, TRUE);
???????? // remove any entries from the CWnd message map cache
???????? AfxResetMsgCache();
}
?
class CDynLinkLibrary : public CCmdTarget
{
???????? DECLARE_DYNAMIC(CDynLinkLibrary)
public:
?
// Constructor
???????? explicit CDynLinkLibrary(AFX_EXTENSION_MODULE& state, BOOL bSystem = FALSE);
???????? CDynLinkLibrary(HINSTANCE hModule, HINSTANCE hResource);
?
// Attributes
???????? HMODULE m_hModule;
???????? HMODULE m_hResource;??????????????? // for shared resources
???????? ….
???????? BOOL m_bSystem;???????????????????? // TRUE only for MFC DLLs
// Implementation
public:
???????? CDynLinkLibrary* m_pNextDLL;??????? // simple singly linked list
???????? virtual ~CDynLinkLibrary();
….
};
?
CDynLinkLibrary::CDynLinkLibrary(AFX_EXTENSION_MODULE& state, BOOL bSystem)
{
…
???????? // copy info from AFX_EXTENSION_MODULE struct
???????? ASSERT(state.hModule != NULL);
???????? m_hModule = state.hModule;
???????? m_hResource = state.hResource;
???????? m_classList.m_pHead = state.pFirstSharedClass;
….
???????? m_bSystem = bSystem;
????????
// insert at the head of the list (extensions will go in front of core DLL)
???????? DEBUG_ONLY(m_pNextDLL = NULL);
???????? AfxLockGlobals(CRIT_DYNLINKLIST);
???????? m_pModuleState->m_libraryList.AddHead(this);
???????? AfxUnlockGlobals(CRIT_DYNLINKLIST);
}
?
CDynLinkLibrary::CDynLinkLibrary(HINSTANCE hModule, HINSTANCE hResource)
{
…
???????? m_hModule = hModule;
???????? m_hResource = hResource;
???????? m_classList.m_pHead = NULL;
???????? …
???????? m_bSystem = FALSE;
???????? // insert at the head of the list (extensions will go in front of core DLL)
???????? DEBUG_ONLY(m_pNextDLL = NULL);
???????? AfxLockGlobals(CRIT_DYNLINKLIST);
???????? m_pModuleState->m_libraryList.AddHead(this);
???????? AfxUnlockGlobals(CRIT_DYNLINKLIST);
}
…
CDynLinkLibrary::~CDynLinkLibrary()
{
???????? // remove this frame window from the list of frame windows
???????? AfxLockGlobals(CRIT_DYNLINKLIST);
???????? m_pModuleState->m_libraryList.Remove(this);
???????? AfxUnlockGlobals(CRIT_DYNLINKLIST);
}
?????? 由此我們可以看出DLL初始化時先調AfxInitExtensionModule是為了構造一個AFX_EXTENSION_MODULE,然后將它插入插入一個AFX_MODULE_STATE鏈表中,同時將當前DLL的HINSTANCE插入此AFX_MODULE_STATE的CDynLinkLibrary鏈表中,以便稍后講到的AfxFindResourceHandle找到。DLL從內存移出時就從此鏈表中刪除自己。
讓我們來看看AfxFindResourceHandle的實現(dllinit.cpp):
HINSTANCE AFXAPI AfxFindResourceHandle(LPCTSTR lpszName, LPCTSTR lpszType)
{
???????? ASSERT(lpszName != NULL);
???????? ASSERT(lpszType != NULL);
?
???????? HINSTANCE hInst;
?
???????? // first check the main module state
???????? AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
???????? if (!pModuleState->m_bSystem)
???????? {
?????????????????? hInst = AfxGetResourceHandle();
?????????????????? if (::FindResource(hInst, lpszName, lpszType) != NULL)
??????????????????????????? return hInst;
???????? }
?
???????? // check for non-system DLLs in proper order
???????? AfxLockGlobals(CRIT_DYNLINKLIST);
???????? CDynLinkLibrary* pDLL;
???????? for (pDLL = pModuleState->m_libraryList; pDLL != NULL;
?????????????????? pDLL = pDLL->m_pNextDLL)
???????? {
?????????????????? if (!pDLL->m_bSystem && pDLL->m_hResource != NULL &&
??????????????????????????? ::FindResource(pDLL->m_hResource, lpszName, lpszType) != NULL)
?????????????????? {
??????????????????????????? // found it in a DLL
??????????????????????????? AfxUnlockGlobals(CRIT_DYNLINKLIST);
??????????????????????????? return pDLL->m_hResource;
?????????????????? }
???????? }
???????? AfxUnlockGlobals(CRIT_DYNLINKLIST);
?
???????? // check language specific resource next
???????? hInst = pModuleState->m_appLangDLL;
???????? if (hInst != NULL && ::FindResource(hInst, lpszName, lpszType) != NULL)
?????????????????? return hInst;
?
???????? // check the main system module state
???????? if (pModuleState->m_bSystem)
???????? {
?????????????????? hInst = AfxGetResourceHandle();
?????????????????? if (::FindResource(hInst, lpszName, lpszType) != NULL)
??????????????????????????? return hInst;
???????? }
?
???????? // check for system DLLs in proper order
???????? AfxLockGlobals(CRIT_DYNLINKLIST);
???????? for (pDLL = pModuleState->m_libraryList; pDLL != NULL; pDLL = pDLL->m_pNextDLL)
???????? {
?????????????????? if (pDLL->m_bSystem && pDLL->m_hResource != NULL &&
??????????????????????????? ::FindResource(pDLL->m_hResource, lpszName, lpszType) != NULL)
?????????????????? {
??????????????????????????? // found it in a DLL
??????????????????????????? AfxUnlockGlobals(CRIT_DYNLINKLIST);
??????????????????????????? return pDLL->m_hResource;
?????????????????? }
???????? }
???????? AfxUnlockGlobals(CRIT_DYNLINKLIST);
?
???????? // if failed to find resource, return application resource
???????? return AfxGetResourceHandle();
}
上面的代碼首先檢查主模塊的狀態,通過返回的是個AFX_MODULE_STATE的類對象指針. AFX_MODULE_STATE又是個什么呢?下面看看AFX_MODULE_STATE的定義(afxstat_.h中,它的實現在afxstate.cpp中,有興趣的讀者可以讀讀):
// AFX_MODULE_STATE (global data for a module)
class AFX_MODULE_STATE : public CNoTrackObject
{
public:
#ifdef _AFXDLL
???????? AFX_MODULE_STATE(BOOL bDLL, WNDPROC pfnAfxWndProc, DWORD dwVersion,
?????????????????? BOOL bSystem = FALSE);
#else
???????? explicit AFX_MODULE_STATE(BOOL bDLL);
#endif
???????? ~AFX_MODULE_STATE();
?
???????? CWinApp* m_pCurrentWinApp;
???????? HINSTANCE m_hCurrentInstanceHandle;
???????? HINSTANCE m_hCurrentResourceHandle;
???????? LPCTSTR m_lpszCurrentAppName;
???????? BYTE m_bDLL;??? // TRUE if module is a DLL, FALSE if it is an EXE
???????? BYTE m_bSystem; // TRUE if module is a "system" module, FALSE if not
???????? …
?
#ifdef _AFXDLL
???????? // CDynLinkLibrary objects (for resource chain)
???????? CTypedSimpleList<CDynLinkLibrary*> m_libraryList;
?
???????? // special case for MFC71XXX.DLL (localized MFC resources)
???????? HINSTANCE m_appLangDLL;
#endif
….
};
我們來看看我們關心的屬性
CWinApp* m_pCurrentWinApp;
HINSTANCE m_hCurrentInstanceHandle;
HINSTANCE m_hCurrentResourceHandle;
LPCTSTR m_lpszCurrentAppName;
?
BYTE m_bDLL;??? // TRUE if module is a DLL, FALSE if it is an EXE
BYTE m_bSystem; // TRUE if module is a "system" module, FALSE if not
…
// CDynLinkLibrary objects (for resource chain)
CTypedSimpleList<CDynLinkLibrary*> m_libraryList;
?
// special case for MFC71XXX.DLL (localized MFC resources)
HINSTANCE m_appLangDLL;
看了相關注釋,也就明白什么意思了,在此就不多解釋了。
?
如果當前主模塊是系統模塊(通過m_bSystem標識),并且從當前模塊中找到了相應的資源就返回此模塊的HINSTANCE。接下來當前模塊所載的DLL鏈表中的所有用戶模塊中查找,本地化的MFC資源DLL中查找,系統DLL中查找。如果都找不到則從EXE(或者通過AfxSetResouceHandle中設置的HINSTANCE)中查找。
如果不考慮DLL鏈表,則需要我們每次使用DLL中的資源前調用AfxSetResouceHandle,使用后再調用AfxSetResourceHandle,就同前面講的在靜態鏈接庫中使用MFC DLL一樣。麻不麻煩?
怎么解決呢?解決方法是用資源DLL的HINSTANCE構造一CDynLinkLibrary對象插入主模塊(EXE)的AFX_MODULE_STATE的m_libraryList中。怎么做?
看了上面DllMain的實現代碼,我們可以照著做。
static AFX_EXTENSION_MODULE ResouceDLL = { NULL, NULL }
BOOL CXApp::InitInstance()
{
// Get the resource DLL instance
???????? if (!AfxInitExtensionModule(ResouceDLL, hResourceModule))
???????? ???????? return 0;
new CDynLinkLibrary(ResouceDLL);??
…
}
int CGenericMFCApp::ExitInstance()
{
AfxTermExtensionModule(ResouceDLL);
???????? return CWinApp::ExitInstance();
}
這樣我們就可以在應用程序中安全的使用DLL中的資源了,就好比EXE中的一樣。對于我們自己編寫入口函數的DLL,如果其中涉及到資源的話,我們可以參考上述的MFC常規DLL的實現。
對于我們在ActiveX和一些DLL中的AFX_MANAGE_STATE(AfxGetStaticModuleState());我們又怎么理解呢?看看afxstat_.h:
#ifdef _AFXDLL
…
class _AFX_THREAD_STATE;
struct AFX_MAINTAIN_STATE2
{
???????? explicit AFX_MAINTAIN_STATE2(AFX_MODULE_STATE* pModuleState);
???????? ~AFX_MAINTAIN_STATE2();
protected:
???????? AFX_MODULE_STATE* m_pPrevModuleState;
???????? _AFX_THREAD_STATE* m_pThreadState;
};
#define AFX_MANAGE_STATE(p) AFX_MAINTAIN_STATE2 _ctlState(p);
#else? // _AFXDLL
#define AFX_MANAGE_STATE(p)
#endif //!_AFXDLL
?
對于在靜態庫中使用MFC DLL時它就相當于不存在,反之,它構造一個AFX_MAINTAIN_STATE2對象,在afxstate.cpp中
#ifdef _AFXDLL
…
?
AFX_MAINTAIN_STATE2::AFX_MAINTAIN_STATE2(AFX_MODULE_STATE* pNewState)
{
???????? m_pThreadState = _afxThreadState;
???????? m_pPrevModuleState = m_pThreadState->m_pModuleState;
???????? m_pThreadState->m_pModuleState = pNewState;
}
#endif //_AFXDLL
,
再看dllmodul.cpp中有關AfxGetStaticModuleState的實現:
?
static _AFX_DLL_MODULE_STATE afxModuleState;
?
…
?
AFX_MODULE_STATE* AFXAPI AfxGetStaticModuleState()
{
???????? AFX_MODULE_STATE* pModuleState = &afxModuleState;
???????? return pModuleState;
}
?
(MFC中太多的全局變量的確不雅!)
可以看到通過構造一個AFX_MAINTAIN_STATE2對象(再結合AfxGetResouceHandle的實現),就使AfxFindResourceHandle返回的是ActiveX控件(實際上也是一個常規DLL)或DLL的HINSTANE了,這樣AfxFindResourceHandle就不必須在DLL鏈表中查找了,但缺點是每次使用資源(或響應消息)時都要構造一個AFX_MAINTAIN_STATE2對象,并且,而且使用這種方法在此DLL中無法使用其它DLL中的資源或在EXE中使用DLL中的資源(在不使用AfxSetResourceHandle/AfxGetResourceHandle的前提下)。當然,我們這兒關心的只是資源的使用,如果涉及到其它,包括事件響應或多個UI線程時,AFX_MODULE_STATE還是不能少的。
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的如何使用动态链接库中的资源的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 蔬菜销售策划
- 下一篇: paip.mysql 5.6 安装总结