Leaked source code of windows server 2003
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.

270 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. // REVIEW: The SetErrorMode calls turn of the Windows "File not found"
  31. // message box, assuming that the app will respond to the error code.
  32. // The name of the file that was not found will be lost by the time we
  33. // return to the app, however. We may want to reconsider this.
  34. nOldErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX);
  35. hInst = LoadLibrary(pLibName);
  36. SetErrorMode(nOldErrorMode);
  37. if (hInst < HINSTANCE_ERROR)
  38. return hInst;
  39. for (nFree = m_size, i = 0; i < m_size; i++) {
  40. if (m_pDlls[i].refsTotal == 0) {
  41. if (nFree > i)
  42. nFree = i;
  43. continue;
  44. }
  45. if (hInst == m_pDlls[i].hInst) {
  46. m_pDlls[i].refsTotal++;
  47. if (fAutoFree)
  48. m_pDlls[i].refsAuto++;
  49. FreeLibrary(hInst);
  50. return hInst;
  51. }
  52. }
  53. if (nFree == m_size) {
  54. UINT newsize = m_size + 10;
  55. void FAR* pMem = NULL;
  56. IMalloc FAR* pMalloc;
  57. if (CoGetMalloc(MEMCTX_TASK, &pMalloc) == 0) {
  58. pMem = pMalloc->Realloc(m_pDlls, newsize * sizeof(m_pDlls[0]));
  59. pMalloc->Release();
  60. }
  61. if (pMem == NULL) {
  62. FreeLibrary(hInst);
  63. return NULL; // Out of memory
  64. }
  65. _fmemset(((char FAR*) pMem) + m_size * sizeof(m_pDlls[0]),0,
  66. (newsize - m_size) * sizeof(m_pDlls[0]));
  67. *((void FAR* FAR*) &m_pDlls) = pMem;
  68. m_size = newsize;
  69. }
  70. m_pDlls[nFree].hInst = hInst;
  71. m_pDlls[nFree].refsTotal = 1;
  72. m_pDlls[nFree].refsAuto = fAutoFree != 0;
  73. m_pDlls[nFree].lpfnDllCanUnloadNow =
  74. (LPFNCANUNLOADNOW)IGetProcAddress(hInst, "DllCanUnloadNow");
  75. #ifdef _DEBUG
  76. // call it now to prevent dlls from using it to indicate they will be
  77. // unloaded.
  78. if (m_pDlls[nFree].lpfnDllCanUnloadNow != NULL)
  79. (void)(*m_pDlls[nFree].lpfnDllCanUnloadNow)();
  80. #endif // _DEBUG
  81. return hInst;
  82. }
  83. // unload library.
  84. void CDlls::ReleaseLibrary(HINSTANCE hInst)
  85. {
  86. UINT i;
  87. for (i = 0; i < m_size; i++) {
  88. if (m_pDlls[i].refsTotal == 0)
  89. continue;
  90. if (hInst == m_pDlls[i].hInst) {
  91. if (--m_pDlls[i].refsTotal == 0) {
  92. Assert(m_pDlls[i].refsAuto == 0);
  93. FreeLibrary(m_pDlls[i].hInst);
  94. m_pDlls[i].hInst = NULL;
  95. m_pDlls[i].lpfnDllCanUnloadNow = NULL;
  96. }
  97. return;
  98. }
  99. }
  100. }
  101. void CDlls::FreeAllLibraries(void)
  102. {
  103. UINT i;
  104. for (i = 0; i < m_size; i++) {
  105. if (m_pDlls[i].refsTotal == 0)
  106. continue;
  107. // A dll loaded on behalf of this app hasn't been freed by it
  108. //
  109. #ifdef _DEBUG
  110. if (m_pDlls[i].refsTotal != m_pDlls[i].refsAuto) {
  111. // not all references to this dll are auto load; print message
  112. char pln[_MAX_PATH];
  113. if (GetModuleFileName(m_pDlls[i].hInst,pln,_MAX_PATH) == 0)
  114. lstrcpy(pln,"<unknown>");
  115. Puts("WARNING in Uninitialize: Did not free ");
  116. Puts(pln);
  117. Puts("\r\n");
  118. }
  119. #endif
  120. FreeLibrary(m_pDlls[i].hInst);
  121. }
  122. CoMemFree(m_pDlls, MEMCTX_TASK);
  123. m_size = 0;
  124. m_pDlls = NULL;
  125. }
  126. // for all dlls, find lpfnDllCanUnloadNow; call it; do it
  127. void CDlls::FreeUnusedLibraries(void)
  128. {
  129. static BOOL v_fReadUnloadOption = FALSE;
  130. static BOOL v_fAllowUnloading = TRUE;
  131. UINT i;
  132. for (i = 0; i < m_size; i++) {
  133. if (m_pDlls[i].refsTotal == 0)
  134. continue;
  135. if (m_pDlls[i].refsTotal != m_pDlls[i].refsAuto)
  136. continue;
  137. // have an auto-free dll (total refs == auto refs)
  138. if (m_pDlls[i].lpfnDllCanUnloadNow == NULL)
  139. continue;
  140. if (!v_fReadUnloadOption) {
  141. v_fAllowUnloading = GetProfileInt("windows",
  142. "AllowOptimalDllUnload", TRUE);
  143. v_fReadUnloadOption = TRUE;
  144. }
  145. // we want to actually make the call and then check the flag; that
  146. // way, we ensure that the dlls are exercising their code, but we
  147. // don't take action on it.
  148. if ((*m_pDlls[i].lpfnDllCanUnloadNow)() == NOERROR &&
  149. v_fAllowUnloading) {
  150. FreeLibrary(m_pDlls[i].hInst);
  151. m_pDlls[i].refsTotal = NULL;
  152. m_pDlls[i].refsAuto = NULL;
  153. m_pDlls[i].hInst = NULL;
  154. m_pDlls[i].lpfnDllCanUnloadNow = NULL;
  155. }
  156. }
  157. }
  158. static INTERNAL_(BOOL) EnsureDllMap(CDlls FAR* FAR* ppDlls)
  159. {
  160. HTASK hTask;
  161. Etask etask;
  162. if (!LookupEtask(hTask, etask))
  163. return FALSE;
  164. // NOTE - The original code used TASK-allocating operator new
  165. if (etask.m_pDlls == NULL) {
  166. if ((etask.m_pDlls = new FAR CDlls) == NULL)
  167. return FALSE;
  168. SetEtask(hTask, etask);
  169. }
  170. *ppDlls = etask.m_pDlls;
  171. return TRUE;
  172. }
  173. STDAPI_(HINSTANCE) CoLoadLibrary(LPSTR pLibName, BOOL fAutoFree)
  174. {
  175. CDlls FAR* pCDlls;
  176. if (!EnsureDllMap(&pCDlls))
  177. return NULL;
  178. return pCDlls->GetLibrary(pLibName, fAutoFree);
  179. }
  180. STDAPI_(void) CoFreeLibrary(HINSTANCE hInst)
  181. {
  182. CDlls FAR* pCDlls;
  183. if (!EnsureDllMap(&pCDlls))
  184. return;
  185. pCDlls->ReleaseLibrary(hInst);
  186. }
  187. STDAPI_(void) CoFreeAllLibraries(void)
  188. {
  189. thkDebugOut((DEB_ITRACE, "CoFreeAllLibraries\n"));
  190. CDlls FAR* pCDlls;
  191. if (!EnsureDllMap(&pCDlls))
  192. return;
  193. pCDlls->FreeAllLibraries();
  194. // Also thunk the call to 32-bits
  195. CallObjectInWOW(THK_API_METHOD(THK_API_CoFreeAllLibraries), NULL);
  196. thkDebugOut((DEB_ITRACE, "CoFreeAllLibraries exit\n"));
  197. }
  198. STDAPI_(void) CoFreeUnusedLibraries(void)
  199. {
  200. HTASK hTask;
  201. Etask etask;
  202. if (!LookupEtask(hTask, etask) || etask.m_pDlls == NULL)
  203. return;
  204. etask.m_pDlls->FreeUnusedLibraries();
  205. // Also thunk the call to 32-bits
  206. CallObjectInWOW(THK_API_METHOD(THK_API_CoFreeUnusedLibraries), NULL);
  207. }