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

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1994.
  5. //
  6. // File: dlltable.cxx
  7. //
  8. // Contents: DLL table management
  9. //
  10. // History: 16-Mar-94 DrewB Taken from OLE2 16-bit sources
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <headers.cxx>
  14. #pragma hdrstop
  15. #include <ole2int.h>
  16. #include <taskmap.h>
  17. #include <call32.hxx>
  18. #include <apilist.hxx>
  19. #include "dlltable.h"
  20. // FUTURE: move to some private header file
  21. INTERNAL_(void) ReleaseDemandLoadCO(Etask FAR& etask);
  22. // Keep only hInst. Always do LoadLibrary; if hInst already exist
  23. // do FreeLibrary. This is because GetModuleHandle(pLibName) doesn't
  24. // neccessarily return same value as LoadLibrary(pLibName).
  25. //
  26. HINSTANCE CDlls::GetLibrary(LPSTR pLibName, BOOL fAutoFree)
  27. {
  28. UINT i, nFree, nOldErrorMode;
  29. HINSTANCE hInst;
  30. #ifndef _MAC
  31. // REVIEW: The SetErrorMode calls turn of the Windows "File not found"
  32. // message box, assuming that the app will respond to the error code.
  33. // The name of the file that was not found will be lost by the time we
  34. // return to the app, however. We may want to reconsider this.
  35. nOldErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX);
  36. hInst = LoadLibrary(pLibName);
  37. SetErrorMode(nOldErrorMode);
  38. #ifdef WIN32
  39. if (hInst == NULL)
  40. #else
  41. if (hInst < HINSTANCE_ERROR)
  42. #endif
  43. return hInst;
  44. #else
  45. hInst = WinLoadLibrary(pLibName);
  46. if (hInst == HINSTANCE_ERROR)
  47. return hInst;
  48. #endif
  49. for (nFree = m_size, i = 0; i < m_size; i++) {
  50. if (m_pDlls[i].refsTotal == 0) {
  51. if (nFree > i)
  52. nFree = i;
  53. continue;
  54. }
  55. if (hInst == m_pDlls[i].hInst) {
  56. m_pDlls[i].refsTotal++;
  57. if (fAutoFree)
  58. m_pDlls[i].refsAuto++;
  59. FreeLibrary(hInst);
  60. return hInst;
  61. }
  62. }
  63. if (nFree == m_size) {
  64. UINT newsize = m_size + 10;
  65. void FAR* pMem = NULL;
  66. IMalloc FAR* pMalloc;
  67. if (CoGetMalloc(MEMCTX_TASK, &pMalloc) == 0) {
  68. pMem = pMalloc->Realloc(m_pDlls, newsize * sizeof(m_pDlls[0]));
  69. pMalloc->Release();
  70. }
  71. if (pMem == NULL) {
  72. FreeLibrary(hInst);
  73. return NULL; // Out of memory
  74. }
  75. _fmemset(((char FAR*) pMem) + m_size * sizeof(m_pDlls[0]),0,
  76. (newsize - m_size) * sizeof(m_pDlls[0]));
  77. *((void FAR* FAR*) &m_pDlls) = pMem;
  78. m_size = newsize;
  79. }
  80. m_pDlls[nFree].hInst = hInst;
  81. m_pDlls[nFree].refsTotal = 1;
  82. m_pDlls[nFree].refsAuto = fAutoFree != 0;
  83. m_pDlls[nFree].lpfnDllCanUnloadNow =
  84. (LPFNCANUNLOADNOW)IGetProcAddress(hInst, "DllCanUnloadNow");
  85. #ifdef _DEBUG
  86. // call it now to prevent dlls from using it to indicate they will be
  87. // unloaded.
  88. if (m_pDlls[nFree].lpfnDllCanUnloadNow != NULL)
  89. (void)(*m_pDlls[nFree].lpfnDllCanUnloadNow)();
  90. #endif // _DEBUG
  91. return hInst;
  92. }
  93. // unload library.
  94. void CDlls::ReleaseLibrary(HINSTANCE hInst)
  95. {
  96. UINT i;
  97. for (i = 0; i < m_size; i++) {
  98. if (m_pDlls[i].refsTotal == 0)
  99. continue;
  100. if (hInst == m_pDlls[i].hInst) {
  101. if (--m_pDlls[i].refsTotal == 0) {
  102. Assert(m_pDlls[i].refsAuto == 0);
  103. FreeLibrary(m_pDlls[i].hInst);
  104. m_pDlls[i].hInst = NULL;
  105. m_pDlls[i].lpfnDllCanUnloadNow = NULL;
  106. }
  107. return;
  108. }
  109. }
  110. }
  111. void CDlls::FreeAllLibraries(void)
  112. {
  113. UINT i;
  114. for (i = 0; i < m_size; i++) {
  115. if (m_pDlls[i].refsTotal == 0)
  116. continue;
  117. // A dll loaded on behalf of this app hasn't been freed by it
  118. //
  119. #ifdef _DEBUG
  120. if (m_pDlls[i].refsTotal != m_pDlls[i].refsAuto) {
  121. // not all references to this dll are auto load; print message
  122. char pln[_MAX_PATH];
  123. if (GetModuleFileName(m_pDlls[i].hInst,pln,_MAX_PATH) == 0)
  124. lstrcpy(pln,"<unknown>");
  125. Puts("WARNING in Uninitialize: Did not free ");
  126. Puts(pln);
  127. Puts("\r\n");
  128. }
  129. #endif
  130. FreeLibrary(m_pDlls[i].hInst);
  131. }
  132. CoMemFree(m_pDlls, MEMCTX_TASK);
  133. m_size = 0;
  134. m_pDlls = NULL;
  135. }
  136. // for all dlls, find lpfnDllCanUnloadNow; call it; do it
  137. void CDlls::FreeUnusedLibraries(void)
  138. {
  139. static BOOL v_fReadUnloadOption = FALSE;
  140. static BOOL v_fAllowUnloading = TRUE;
  141. UINT i;
  142. for (i = 0; i < m_size; i++) {
  143. if (m_pDlls[i].refsTotal == 0)
  144. continue;
  145. if (m_pDlls[i].refsTotal != m_pDlls[i].refsAuto)
  146. continue;
  147. // have an auto-free dll (total refs == auto refs)
  148. if (m_pDlls[i].lpfnDllCanUnloadNow == NULL)
  149. continue;
  150. if (!v_fReadUnloadOption) {
  151. v_fAllowUnloading = GetProfileInt("windows",
  152. "AllowOptimalDllUnload", TRUE);
  153. v_fReadUnloadOption = TRUE;
  154. }
  155. // we want to actually make the call and then check the flag; that
  156. // way, we ensure that the dlls are exercising their code, but we
  157. // don't take action on it.
  158. if ((*m_pDlls[i].lpfnDllCanUnloadNow)() == NOERROR &&
  159. v_fAllowUnloading) {
  160. FreeLibrary(m_pDlls[i].hInst);
  161. m_pDlls[i].refsTotal = NULL;
  162. m_pDlls[i].refsAuto = NULL;
  163. m_pDlls[i].hInst = NULL;
  164. m_pDlls[i].lpfnDllCanUnloadNow = NULL;
  165. }
  166. }
  167. }
  168. static INTERNAL_(BOOL) EnsureDllMap(CDlls FAR* FAR* ppDlls)
  169. {
  170. HTASK hTask;
  171. Etask etask;
  172. if (!LookupEtask(hTask, etask))
  173. return FALSE;
  174. // NOTE - The original code used TASK-allocating operator new
  175. if (etask.m_pDlls == NULL) {
  176. if ((etask.m_pDlls = new FAR CDlls) == NULL)
  177. return FALSE;
  178. SetEtask(hTask, etask);
  179. }
  180. *ppDlls = etask.m_pDlls;
  181. return TRUE;
  182. }
  183. STDAPI_(HINSTANCE) CoLoadLibrary(LPSTR pLibName, BOOL fAutoFree)
  184. {
  185. CDlls FAR* pCDlls;
  186. if (!EnsureDllMap(&pCDlls))
  187. return NULL;
  188. return pCDlls->GetLibrary(pLibName, fAutoFree);
  189. }
  190. STDAPI_(void) CoFreeLibrary(HINSTANCE hInst)
  191. {
  192. CDlls FAR* pCDlls;
  193. if (!EnsureDllMap(&pCDlls))
  194. return;
  195. pCDlls->ReleaseLibrary(hInst);
  196. }
  197. STDAPI_(void) CoFreeAllLibraries(void)
  198. {
  199. thkDebugOut((DEB_ITRACE, "CoFreeAllLibraries\n"));
  200. CDlls FAR* pCDlls;
  201. if (!EnsureDllMap(&pCDlls))
  202. return;
  203. pCDlls->FreeAllLibraries();
  204. // Also thunk the call to 32-bits
  205. CallObjectInWOW(THK_API_METHOD(THK_API_CoFreeAllLibraries), NULL);
  206. thkDebugOut((DEB_ITRACE, "CoFreeAllLibraries exit\n"));
  207. }
  208. STDAPI_(void) CoFreeUnusedLibraries(void)
  209. {
  210. HTASK hTask;
  211. Etask etask;
  212. if (!LookupEtask(hTask, etask) || etask.m_pDlls == NULL)
  213. return;
  214. #if 0
  215. // Do we need this? We won't be loading any class objects?
  216. ReleaseDemandLoadCO(etask);
  217. #endif
  218. etask.m_pDlls->FreeUnusedLibraries();
  219. // Also thunk the call to 32-bits
  220. CallObjectInWOW(THK_API_METHOD(THK_API_CoFreeUnusedLibraries), NULL);
  221. }