如何使用动态链接库中的资源
2个回答
展开全部
先以图标为例说起(其它的资源与此图标的加载原理大致相同),我们要加载图标,一般是调用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得到其句柄则要费一番周折。可以看到CWinApp::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做了什么
_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得到其句柄则要费一番周折。可以看到CWinApp::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做了什么
Storm代理
2023-07-25 广告
2023-07-25 广告
StormProxies是一家提供动态代理服务器服务的企业,旨在帮助用户更好地管理网络访问和安全。以下是一些关于StormProxies的IP动态代理服务的特点:1. 高匿名性:StormProxies的动态代理服务器具有高匿名性,可以有效...
点击进入详情页
本回答由Storm代理提供
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询