动态链接库DLL

这是转载博客园的一篇文章,我进行了一下简单的整理
原文链接:http://www.cnblogs.com/lidabo/archive/2013/08/30/3291784.html

我们先以图标为例说起(其它的资源与此图标的加载原理大致相同),我们要加载图标,一般是调用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,
关于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.

我们只需将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却不允许添加自动化支持)。

#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
     }      
    …
}

猜你喜欢

转载自blog.csdn.net/u010503121/article/details/45692847
今日推荐