简体   繁体   中英

Importing DLL's doesn't work the same (VS2003 to VS2010, multithreaded to multithreaded DLL)

During a massive code update from a mix of VC6, VS2003, and VS2005, I am running into a problem where VS2010 doesn't behave like VS2003 did. The application will scan a directory of DLL's and attempt to load them in one by one. This is done here:

CConfigPlugin::CConfigPlugin(LPCTSTR szPluginName)
{
    ASSERT(szPluginName);
    ASSERT(AfxIsValidString(szPluginName));

    m_csFullpath = szPluginName;
    m_hModule = LoadLibrary(m_csFullpath);
    m_pInterface = (IConfigDllInterface *) NULL;
    pInterface pPtr = pInterface(NULL);

    if (m_hModule != NULL)
    {
        //  If we loaded the DLL get the interface pointer
        pPtr = pInterface(GetProcAddress(m_hModule, "GetInterface"));
    }
    if (pPtr != NULL)
    {
        pPtr(&m_pInterface);
    }
    else
    {
        ::FreeLibrary(m_hModule);
        m_hModule = HMODULE(NULL);
    }
}

All DLL's show as being loaded: ... 'GenConfig.exe': Loaded 'C:\\src\\Debug\\config\\GenLogonConfig.dll', Symbols loaded. 'GenConfig.exe': Loaded 'C:\\src\\Debug\\config\\GenReportConfig.dll', Symbols loaded. 'GenConfig.exe': Loaded 'C:\\src\\Debug\\config\\ImportConfig.dll', Symbols loaded. ...

Each DLL has an identical GetInterface implementation shown below:

CConfigDllInterfaceImpl<CParentDlg> gdllObj;

BOOL GetInterface(IConfigDllInterface **ppPtr)
{
    *ppPtr = &gdllObj;

    // Temporary edit to test if gdllObj is set to proper parent.
    CString name;
    name = gdllObj.GetDisplayName();
    // End edit

    return true;
}

With a template as shown below:

__declspec(selectany) UINT guiAdvise;

template <class T> class CConfigDllInterfaceImpl : public IConfigDllInterface
{
public:
    CConfigDllInterfaceImpl()
    {
        guiAdvise = RegisterWindowMessage(_T("GenConfig"));
        m_pDlg = NULL;
    }

    virtual LPCTSTR GetDisplayName() const
    {
        static CString csTemp;

        csTemp.LoadString(IDS_DISPLAY_NAME);
        return csTemp;
    }

    //  Can't be virtual because it uses the template T argument
    BOOL            DoModal(HWND hParent)
    {
        ASSERT(IsWindow(hParent));
        if (m_pDlg == (T *) NULL)
        {
            m_pDlg = new T(CWnd::FromHandle(hParent));
            return m_pDlg->Create();
        }
        else if (IsWindow(m_pDlg->GetSafeHwnd()))
        {
            m_pDlg->PostMessage(guiAdvise, eAdviseSwitchViews);
            m_pDlg->SetActiveWindow();
        }
        return TRUE;
    } // SNIP...

I can tell that my template isn't properly registering to its intended parent. GetDisplayName just returns "". My suspicion the cause of my problem is that I made a decision a month ago to change everything to Multithreaded DLL from Multithreaded. These are all MFC projects and it seemed the simplest and easiest way to just use _AFXDLL and make everything properly compile and link. All of the rest of my projects work fine, but I believe that because of the way this DLL is loaded:

CConfigDllInterfaceImpl gdllObj;

No longer works the way it used to.

So, question 1: Is my suspicion correct? Or am I completely offbase? Question 2: If my suspicion is correct, how do I work around this? It isn't an option to go back to multithreaded at this point.

Thanks in advance.

I finally have some time to get back to answering this. Collin Dauphinee was correct in that it was a resource issue. I don't know why VS2003 is different from VS2010, but the solution was very simple.

CConfigPlugin::CConfigPlugin(LPCTSTR szPluginName)
{
    ASSERT(szPluginName);
    ASSERT(AfxIsValidString(szPluginName));

    // Save off current Afx resource handle.
    HINSTANCE hCurrentAfx = AfxGetResourceHandle();  // <---  Didn't need to
                                                     // do this before.

    m_csFullpath = szPluginName;
    m_hModule = NULL;
    m_hModule = LoadLibrary(m_csFullpath);
    m_pInterface = (IConfigDllInterface *) NULL;
    pInterface pPtr = pInterface(NULL);

    if (m_hModule != NULL)
    {
        AfxSetResourceHandle(m_hModule);   // <--- here is where the resources
                                           // get properly set.  This is the
                                           // solution to the problem.

        //  If we loaded the DLL get the interface pointer
        pPtr = pInterface(GetProcAddress(m_hModule, "GetInterface"));
    }
    if (pPtr != NULL)
    {
        pPtr(&m_pInterface);
    }
    else
    {
        ::FreeLibrary(m_hModule);
        m_hModule = HMODULE(NULL);
    }

    // Now put Afx back.
    AfxSetResourceHandle(hCurrentAfx);
}

I hope this helps someone else. I was stuck for days on this one.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM