//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1994. // // File: dlltable.cxx // // Contents: DLL table management // // History: 16-Mar-94 DrewB Taken from OLE2 16-bit sources // //---------------------------------------------------------------------------- #include #pragma hdrstop #include #include #include #include #include "dlltable.h" // FUTURE: move to some private header file INTERNAL_(void) ReleaseDemandLoadCO(Etask FAR& etask); // Keep only hInst. Always do LoadLibrary; if hInst already exist // do FreeLibrary. This is because GetModuleHandle(pLibName) doesn't // neccessarily return same value as LoadLibrary(pLibName). // HINSTANCE CDlls::GetLibrary(LPSTR pLibName, BOOL fAutoFree) { UINT i, nFree, nOldErrorMode; HINSTANCE hInst; // REVIEW: The SetErrorMode calls turn of the Windows "File not found" // message box, assuming that the app will respond to the error code. // The name of the file that was not found will be lost by the time we // return to the app, however. We may want to reconsider this. nOldErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX); hInst = LoadLibrary(pLibName); SetErrorMode(nOldErrorMode); if (hInst < HINSTANCE_ERROR) return hInst; for (nFree = m_size, i = 0; i < m_size; i++) { if (m_pDlls[i].refsTotal == 0) { if (nFree > i) nFree = i; continue; } if (hInst == m_pDlls[i].hInst) { m_pDlls[i].refsTotal++; if (fAutoFree) m_pDlls[i].refsAuto++; FreeLibrary(hInst); return hInst; } } if (nFree == m_size) { UINT newsize = m_size + 10; void FAR* pMem = NULL; IMalloc FAR* pMalloc; if (CoGetMalloc(MEMCTX_TASK, &pMalloc) == 0) { pMem = pMalloc->Realloc(m_pDlls, newsize * sizeof(m_pDlls[0])); pMalloc->Release(); } if (pMem == NULL) { FreeLibrary(hInst); return NULL; // Out of memory } _fmemset(((char FAR*) pMem) + m_size * sizeof(m_pDlls[0]),0, (newsize - m_size) * sizeof(m_pDlls[0])); *((void FAR* FAR*) &m_pDlls) = pMem; m_size = newsize; } m_pDlls[nFree].hInst = hInst; m_pDlls[nFree].refsTotal = 1; m_pDlls[nFree].refsAuto = fAutoFree != 0; m_pDlls[nFree].lpfnDllCanUnloadNow = (LPFNCANUNLOADNOW)IGetProcAddress(hInst, "DllCanUnloadNow"); #ifdef _DEBUG // call it now to prevent dlls from using it to indicate they will be // unloaded. if (m_pDlls[nFree].lpfnDllCanUnloadNow != NULL) (void)(*m_pDlls[nFree].lpfnDllCanUnloadNow)(); #endif // _DEBUG return hInst; } // unload library. void CDlls::ReleaseLibrary(HINSTANCE hInst) { UINT i; for (i = 0; i < m_size; i++) { if (m_pDlls[i].refsTotal == 0) continue; if (hInst == m_pDlls[i].hInst) { if (--m_pDlls[i].refsTotal == 0) { Assert(m_pDlls[i].refsAuto == 0); FreeLibrary(m_pDlls[i].hInst); m_pDlls[i].hInst = NULL; m_pDlls[i].lpfnDllCanUnloadNow = NULL; } return; } } } void CDlls::FreeAllLibraries(void) { UINT i; for (i = 0; i < m_size; i++) { if (m_pDlls[i].refsTotal == 0) continue; // A dll loaded on behalf of this app hasn't been freed by it // #ifdef _DEBUG if (m_pDlls[i].refsTotal != m_pDlls[i].refsAuto) { // not all references to this dll are auto load; print message char pln[_MAX_PATH]; if (GetModuleFileName(m_pDlls[i].hInst,pln,_MAX_PATH) == 0) lstrcpy(pln,""); Puts("WARNING in Uninitialize: Did not free "); Puts(pln); Puts("\r\n"); } #endif FreeLibrary(m_pDlls[i].hInst); } CoMemFree(m_pDlls, MEMCTX_TASK); m_size = 0; m_pDlls = NULL; } // for all dlls, find lpfnDllCanUnloadNow; call it; do it void CDlls::FreeUnusedLibraries(void) { static BOOL v_fReadUnloadOption = FALSE; static BOOL v_fAllowUnloading = TRUE; UINT i; for (i = 0; i < m_size; i++) { if (m_pDlls[i].refsTotal == 0) continue; if (m_pDlls[i].refsTotal != m_pDlls[i].refsAuto) continue; // have an auto-free dll (total refs == auto refs) if (m_pDlls[i].lpfnDllCanUnloadNow == NULL) continue; if (!v_fReadUnloadOption) { v_fAllowUnloading = GetProfileInt("windows", "AllowOptimalDllUnload", TRUE); v_fReadUnloadOption = TRUE; } // we want to actually make the call and then check the flag; that // way, we ensure that the dlls are exercising their code, but we // don't take action on it. if ((*m_pDlls[i].lpfnDllCanUnloadNow)() == NOERROR && v_fAllowUnloading) { FreeLibrary(m_pDlls[i].hInst); m_pDlls[i].refsTotal = NULL; m_pDlls[i].refsAuto = NULL; m_pDlls[i].hInst = NULL; m_pDlls[i].lpfnDllCanUnloadNow = NULL; } } } static INTERNAL_(BOOL) EnsureDllMap(CDlls FAR* FAR* ppDlls) { HTASK hTask; Etask etask; if (!LookupEtask(hTask, etask)) return FALSE; // NOTE - The original code used TASK-allocating operator new if (etask.m_pDlls == NULL) { if ((etask.m_pDlls = new FAR CDlls) == NULL) return FALSE; SetEtask(hTask, etask); } *ppDlls = etask.m_pDlls; return TRUE; } STDAPI_(HINSTANCE) CoLoadLibrary(LPSTR pLibName, BOOL fAutoFree) { CDlls FAR* pCDlls; if (!EnsureDllMap(&pCDlls)) return NULL; return pCDlls->GetLibrary(pLibName, fAutoFree); } STDAPI_(void) CoFreeLibrary(HINSTANCE hInst) { CDlls FAR* pCDlls; if (!EnsureDllMap(&pCDlls)) return; pCDlls->ReleaseLibrary(hInst); } STDAPI_(void) CoFreeAllLibraries(void) { thkDebugOut((DEB_ITRACE, "CoFreeAllLibraries\n")); CDlls FAR* pCDlls; if (!EnsureDllMap(&pCDlls)) return; pCDlls->FreeAllLibraries(); // Also thunk the call to 32-bits CallObjectInWOW(THK_API_METHOD(THK_API_CoFreeAllLibraries), NULL); thkDebugOut((DEB_ITRACE, "CoFreeAllLibraries exit\n")); } STDAPI_(void) CoFreeUnusedLibraries(void) { HTASK hTask; Etask etask; if (!LookupEtask(hTask, etask) || etask.m_pDlls == NULL) return; etask.m_pDlls->FreeUnusedLibraries(); // Also thunk the call to 32-bits CallObjectInWOW(THK_API_METHOD(THK_API_CoFreeUnusedLibraries), NULL); }