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.

214 lines
5.2 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. extern const IMallocVtbl c_CShellMallocVtbl;
  4. const IMalloc c_mem = { &c_CShellMallocVtbl };
  5. STDMETHODIMP CShellMalloc_QueryInterface(IMalloc *pmem, REFIID riid, LPVOID * ppvObj)
  6. {
  7. ASSERT(pmem == &c_mem);
  8. if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMalloc))
  9. {
  10. *ppvObj = pmem;
  11. return NOERROR;
  12. }
  13. *ppvObj = NULL;
  14. return E_NOINTERFACE;
  15. }
  16. STDMETHODIMP_(ULONG) CShellMalloc_AddRefRelease(IMalloc *pmem)
  17. {
  18. ASSERT(pmem == &c_mem);
  19. return 1; // static object
  20. }
  21. STDMETHODIMP_(void *) CShellMalloc_Alloc(IMalloc *pmem, SIZE_T cb)
  22. {
  23. ASSERT(pmem == &c_mem);
  24. return (void*)LocalAlloc(LPTR, cb);
  25. }
  26. //
  27. // IMalloc::Realloc is slightly different from LocalRealloc.
  28. //
  29. // IMalloc::Realloc(NULL, 0) = return NULL
  30. // IMalloc::Realloc(pv, 0) = IMalloc::Free(pv)
  31. // IMalloc::Realloc(NULL, cb) = IMalloc::Alloc(cb)
  32. // IMalloc::Realloc(pv, cb) = LocalRealloc()
  33. //
  34. STDMETHODIMP_(void *) CShellMalloc_Realloc(IMalloc *pmem, void *pv, SIZE_T cb)
  35. {
  36. ASSERT(pmem == &c_mem);
  37. if (cb == 0)
  38. {
  39. if (pv) LocalFree(pv);
  40. return NULL;
  41. }
  42. else if (pv == NULL)
  43. {
  44. return LocalAlloc(LPTR, cb);
  45. }
  46. else
  47. return LocalReAlloc(pv, cb, LMEM_MOVEABLE|LMEM_ZEROINIT);
  48. }
  49. //
  50. // IMalloc::Free is slightly different from LocalFree.
  51. //
  52. // IMalloc::Free(NULL) - nop
  53. // IMalloc::Free(pv) - LocalFree()
  54. //
  55. STDMETHODIMP_(void) CShellMalloc_Free(IMalloc *pmem, void *pv)
  56. {
  57. ASSERT(pmem == &c_mem);
  58. if (pv) LocalFree(pv);
  59. }
  60. STDMETHODIMP_(SIZE_T) CShellMalloc_GetSize(IMalloc *pmem, void *pv)
  61. {
  62. ASSERT(pmem == &c_mem);
  63. return LocalSize(pv);
  64. }
  65. STDMETHODIMP_(int) CShellMalloc_DidAlloc(IMalloc *pmem, void *pv)
  66. {
  67. ASSERT(pmem == &c_mem);
  68. return -1; // don't know
  69. }
  70. STDMETHODIMP_(void) CShellMalloc_HeapMinimize(IMalloc *pmem)
  71. {
  72. ASSERT(pmem == &c_mem);
  73. }
  74. const IMallocVtbl c_CShellMallocVtbl = {
  75. CShellMalloc_QueryInterface, CShellMalloc_AddRefRelease, CShellMalloc_AddRefRelease,
  76. CShellMalloc_Alloc,
  77. CShellMalloc_Realloc,
  78. CShellMalloc_Free,
  79. CShellMalloc_GetSize,
  80. CShellMalloc_DidAlloc,
  81. CShellMalloc_HeapMinimize,
  82. };
  83. typedef HRESULT (STDAPICALLTYPE * LPFNCOGETMALLOC)(DWORD dwMemContext, IMalloc **ppmem);
  84. IMalloc *g_pmemTask = NULL; // No default task allocator.
  85. #ifdef DEBUG
  86. extern void WINAPI DbgRegisterMallocSpy();
  87. #endif
  88. // on DEBUG builds, mostly for NT, we force using OLE's task allocator at all times.
  89. // for retail we only use OLE if ole32 is already loaded in this process.
  90. //
  91. // this is because OLE's DEBUG allocator will complain if we pass it LocalAlloc()ed
  92. // memory. this can happen if we start up without OLE loaded, then delay load it.
  93. // retail OLE uses LocalAlloc() so we can use our own allocator and switch
  94. // on the fly with no complains from OLE in retail. a common case here would be
  95. // using the file dialogs with notepad
  96. void _GetTaskAllocator(IMalloc **ppmem)
  97. {
  98. if (g_pmemTask == NULL)
  99. {
  100. #ifndef DEBUG
  101. if (GetModuleHandle(TEXT("OLE32.DLL"))) // retail
  102. #endif
  103. {
  104. CoGetMalloc(MEMCTX_TASK, &g_pmemTask);
  105. }
  106. if (g_pmemTask == NULL)
  107. {
  108. // use the shell task allocator (which is LocalAlloc).
  109. g_pmemTask = (IMalloc *)&c_mem; // const -> non const
  110. }
  111. }
  112. else
  113. {
  114. // handing out cached version, add ref it first
  115. g_pmemTask->lpVtbl->AddRef(g_pmemTask);
  116. }
  117. *ppmem = g_pmemTask;
  118. }
  119. //
  120. // To be exported
  121. //
  122. STDAPI SHGetMalloc(IMalloc **ppmem)
  123. {
  124. _GetTaskAllocator(ppmem);
  125. return NOERROR;
  126. }
  127. // BOGUS, NT redefines these to HeapAlloc variants...
  128. #ifdef Alloc
  129. #undef Alloc
  130. #undef Free
  131. #undef GetSize
  132. #endif
  133. __inline void FAST_GetTaskAllocator()
  134. {
  135. IMalloc *pmem;
  136. if (g_pmemTask == NULL) {
  137. // perf: avoid calling unless really need to
  138. _GetTaskAllocator(&pmem);
  139. ASSERT(g_pmemTask != NULL);
  140. ASSERT(g_pmemTask == pmem);
  141. }
  142. // else n.b. no AddRef! but we have a refcnt of >=1, and we never Release
  143. // so who cares...
  144. return;
  145. }
  146. STDAPI_(void *) SHAlloc(SIZE_T cb)
  147. {
  148. FAST_GetTaskAllocator();
  149. return g_pmemTask->lpVtbl->Alloc(g_pmemTask, cb);
  150. }
  151. STDAPI_(void *) SHRealloc(LPVOID pv, SIZE_T cbNew)
  152. {
  153. IMalloc *pmem;
  154. _GetTaskAllocator(&pmem);
  155. return pmem->lpVtbl->Realloc(pmem, pv, cbNew);
  156. }
  157. STDAPI_(void) SHFree(LPVOID pv)
  158. {
  159. FAST_GetTaskAllocator();
  160. g_pmemTask->lpVtbl->Free(g_pmemTask, pv);
  161. }
  162. STDAPI_(SIZE_T) SHGetSize(LPVOID pv)
  163. {
  164. IMalloc *pmem;
  165. _GetTaskAllocator(&pmem);
  166. return (SIZE_T) pmem->lpVtbl->GetSize(pmem, pv);
  167. }
  168. #ifdef DEBUG
  169. void TaskMem_MakeInvalid(void)
  170. {
  171. static IMalloc c_memDummy = { &c_CShellMallocVtbl };
  172. //
  173. // so we can catch calls to the allocator after PROCESS_DETATCH
  174. // which should be illegal because OLE32.DLL can be unloaded before our
  175. // DLL (unload order is not deterministic) we switch the allocator
  176. // to this dummy one that will cause our asserts to trip.
  177. //
  178. // note, runnin the dummy alllocator is actually fine as it will free
  179. // memory with LocalAlloc(), which is what the OLE alocator uses in all
  180. // cases except debug. and besides, our process is about to go away and
  181. // all process memory will be freed anyway!
  182. //
  183. g_pmemTask = &c_memDummy;
  184. }
  185. #endif