Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

285 lines
7.1 KiB

//+---------------------------------------------------------------------------
//
// 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 <headers.cxx>
#pragma hdrstop
#include <ole2int.h>
#include <taskmap.h>
#include <call32.hxx>
#include <apilist.hxx>
#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;
#ifndef _MAC
// 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);
#ifdef WIN32
if (hInst == NULL)
#else
if (hInst < HINSTANCE_ERROR)
#endif
return hInst;
#else
hInst = WinLoadLibrary(pLibName);
if (hInst == HINSTANCE_ERROR)
return hInst;
#endif
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,"<unknown>");
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;
#if 0
// Do we need this? We won't be loading any class objects?
ReleaseDemandLoadCO(etask);
#endif
etask.m_pDlls->FreeUnusedLibraries();
// Also thunk the call to 32-bits
CallObjectInWOW(THK_API_METHOD(THK_API_CoFreeUnusedLibraries), NULL);
}