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.

378 lines
12 KiB

  1. //---------------------------------------------------------------------------
  2. // RenderList.cpp - manages list of CRemderObj objects
  3. //---------------------------------------------------------------------------
  4. #include "stdafx.h"
  5. #include "RenderList.h"
  6. #include "Render.h"
  7. //---------------------------------------------------------------------------
  8. #define MAKE_HTHEME(recycle, slot) (HTHEME)IntToPtr((recycle << 16) | (slot & 0xffff))
  9. //---------------------------------------------------------------------------
  10. CRenderList::CRenderList()
  11. {
  12. _iNextUniqueId = 0;
  13. InitializeCriticalSection(&_csListLock);
  14. }
  15. //---------------------------------------------------------------------------
  16. CRenderList::~CRenderList()
  17. {
  18. for (int i=0; i < _RenderEntries.m_nSize; i++)
  19. {
  20. //---- ignore refcount here (end of process) ----
  21. if (_RenderEntries[i].pRenderObj)
  22. {
  23. //Log(LOG_RFBUG, L"DELETED CRenderObj at: 0x%08x", _RenderEntries[i].pRenderObj);
  24. delete _RenderEntries[i].pRenderObj;
  25. }
  26. }
  27. DeleteCriticalSection(&_csListLock);
  28. }
  29. //---------------------------------------------------------------------------
  30. HRESULT CRenderList::OpenRenderObject(CUxThemeFile *pThemeFile, int iThemeOffset,
  31. int iClassNameOffset, CDrawBase *pDrawBase, CTextDraw *pTextObj, HWND hwnd,
  32. DWORD dwOtdFlags, HTHEME *phTheme)
  33. {
  34. HRESULT hr = S_OK;
  35. CAutoCS autoCritSect(&_csListLock);
  36. CRenderObj *pRender = NULL;
  37. int iUsedSlot = -1;
  38. int iNextAvailSlot = -1;
  39. //---- see if OK to share an existing CRenderObj ----
  40. BOOL fShare = ((! pDrawBase) && (! pTextObj) && (! LogOptionOn(LO_TMHANDLE)));
  41. if (fShare)
  42. {
  43. if ((dwOtdFlags) && (dwOtdFlags != OTD_NONCLIENT)) // bits other than nonclient are set
  44. fShare = FALSE;
  45. }
  46. //---- loop for sharing and finding first avail entry ----
  47. for (int i=0; i < _RenderEntries.m_nSize; i++)
  48. {
  49. RENDER_OBJ_ENTRY *pEntry = &_RenderEntries[i];
  50. pRender = pEntry->pRenderObj;
  51. //---- skip over available entries ----
  52. if (! pRender)
  53. {
  54. if (iNextAvailSlot == -1) // take first found slot
  55. iNextAvailSlot = i;
  56. continue;
  57. }
  58. if ((fShare) && (! pEntry->fClosing))
  59. {
  60. pRender->ValidateObj();
  61. int iOffset = int(pRender->_pbSectionData - pRender->_pbThemeData);
  62. if ((pRender->_pThemeFile == pThemeFile) && (iOffset == iThemeOffset))
  63. {
  64. pEntry->iRefCount++;
  65. iUsedSlot = i;
  66. Log(LOG_CACHE, L"OpenRenderObject: found match for Offset=%d (slot=%d, refcnt=%d)",
  67. iThemeOffset, i, pEntry->iRefCount);
  68. break;
  69. }
  70. }
  71. }
  72. if (iUsedSlot == -1) // not found
  73. {
  74. if (iNextAvailSlot == -1) // add to end
  75. iUsedSlot = _RenderEntries.m_nSize ;
  76. else
  77. iUsedSlot = iNextAvailSlot;
  78. _iNextUniqueId++;
  79. hr = CreateRenderObj(pThemeFile, iUsedSlot, iThemeOffset, iClassNameOffset,
  80. _iNextUniqueId, TRUE, pDrawBase, pTextObj, dwOtdFlags, &pRender);
  81. if (FAILED(hr))
  82. goto exit;
  83. //Log(LOG_RFBUG, L"ALLOCATED CRenderObj at: 0x%08x", pRender);
  84. //---- extract theme file Load ID ----
  85. THEMEHDR *th = (THEMEHDR *)pRender->_pbThemeData;
  86. int iLoadId = 0;
  87. if (th)
  88. iLoadId = th->iLoadId;
  89. RENDER_OBJ_ENTRY entry = {pRender, 1, 1, 0, iLoadId, FALSE, hwnd};
  90. if (iUsedSlot == _RenderEntries.m_nSize) // add new entry
  91. {
  92. if (! _RenderEntries.Add(entry))
  93. {
  94. delete pRender;
  95. hr = MakeError32(E_OUTOFMEMORY);
  96. goto exit;
  97. }
  98. Log(LOG_CACHE, L"OpenRenderObject: created new obj AT END (slot=%d, refcnt=%d)",
  99. pRender->_iCacheSlot, 1);
  100. }
  101. else // use an existing slot
  102. {
  103. entry.dwRecycleNum = _RenderEntries[iUsedSlot].dwRecycleNum + 1;
  104. _RenderEntries[iUsedSlot] = entry;
  105. Log(LOG_CACHE, L"OpenRenderObject: created new obj SLOT REUSE (slot=%d, refcnt=%d, recycle=%d)",
  106. iUsedSlot, 1, _RenderEntries[iUsedSlot].dwRecycleNum);
  107. }
  108. }
  109. if (SUCCEEDED(hr))
  110. {
  111. RENDER_OBJ_ENTRY *pEntry = &_RenderEntries[iUsedSlot];
  112. *phTheme = MAKE_HTHEME(pEntry->dwRecycleNum, iUsedSlot);
  113. //---- for debugging refcount issues ----
  114. if (LogOptionOn(LO_TMHANDLE))
  115. {
  116. WCHAR buff[MAX_PATH];
  117. if (hwnd)
  118. GetClassName(hwnd, buff, ARRAYSIZE(buff));
  119. else
  120. buff[0] = 0;
  121. //if (lstrcmpi(pRender->_pszClassName, L"window")==0)
  122. {
  123. //Log(LOG_TMHANDLE, L"OTD: cls=%s (%s), hwnd=0x%x, htheme=0x%x, new refcnt=%d",
  124. // pRender->_pszClassName, buff, hwnd, *phTheme, pEntry->iRefCount);
  125. }
  126. }
  127. }
  128. exit:
  129. return hr;
  130. }
  131. //---------------------------------------------------------------------------
  132. BOOL CRenderList::DeleteCheck(RENDER_OBJ_ENTRY *pEntry)
  133. {
  134. BOOL fClosed = FALSE;
  135. if ((! pEntry->iRefCount) && (! pEntry->iInUseCount))
  136. {
  137. //Log(LOG_RFBUG, L"DELETED CRenderObj at: 0x%08x", pEntry->pRenderObj);
  138. delete pEntry->pRenderObj;
  139. //---- important: don't use RemoveAt() or entries will shift and ----
  140. //---- our "SlotNumber" model between RenderList & CacheList will ----
  141. //---- be broken ----
  142. pEntry->pRenderObj = NULL;
  143. pEntry->fClosing = FALSE;
  144. fClosed = TRUE;
  145. }
  146. return fClosed;
  147. }
  148. //---------------------------------------------------------------------------
  149. HRESULT CRenderList::CloseRenderObject(HTHEME hTheme)
  150. {
  151. CAutoCS autoCritSect(&_csListLock);
  152. HRESULT hr = S_OK;
  153. int iSlotNum = (DWORD(PtrToInt(hTheme)) & 0xffff);
  154. DWORD dwRecycleNum = (DWORD(PtrToInt(hTheme)) >> 16);
  155. if (iSlotNum >= _RenderEntries.m_nSize)
  156. {
  157. Log(LOG_BADHTHEME, L"Illegal Theme Handle: 0x%x", hTheme);
  158. hr = MakeError32(E_HANDLE);
  159. goto exit;
  160. }
  161. RENDER_OBJ_ENTRY *pEntry = &_RenderEntries[iSlotNum];
  162. if ((! pEntry->pRenderObj) || (pEntry->fClosing) || (pEntry->dwRecycleNum != dwRecycleNum))
  163. {
  164. Log(LOG_BADHTHEME, L"Expired Theme Handle: 0x%x", hTheme);
  165. hr = MakeError32(E_HANDLE);
  166. goto exit;
  167. }
  168. //---- allow for our iRefCount to have been set to zero explicitly ----
  169. if (pEntry->iRefCount > 0)
  170. pEntry->iRefCount--;
  171. #if 0
  172. //---- for debugging refcount issues ----
  173. if (LogOptionOn(LO_TMHANDLE))
  174. {
  175. CRenderObj *pRender = pEntry->pRenderObj;
  176. Log(LOG_TMHANDLE, L"CTD: cls=%s, hwnd=0x%x, htheme=0x%x, new refcnt=%d",
  177. pRender->_pszClassName, pEntry->hwnd, hTheme, pEntry->iRefCount);
  178. }
  179. #endif
  180. DeleteCheck(pEntry);
  181. exit:
  182. return hr;
  183. }
  184. //---------------------------------------------------------------------------
  185. HRESULT CRenderList::OpenThemeHandle(HTHEME hTheme, CRenderObj **ppRenderObj, int *piSlotNum)
  186. {
  187. CAutoCS autoCritSect(&_csListLock);
  188. HRESULT hr = S_OK;
  189. int iSlotNum = (int)(DWORD(PtrToInt(hTheme)) & 0xffff);
  190. DWORD dwRecycleNum = (DWORD(PtrToInt(hTheme)) >> 16);
  191. if (iSlotNum >= _RenderEntries.m_nSize)
  192. {
  193. Log(LOG_BADHTHEME, L"Illegal Theme Handle: 0x%x", hTheme);
  194. hr = MakeError32(E_HANDLE);
  195. goto exit;
  196. }
  197. RENDER_OBJ_ENTRY *pEntry = &_RenderEntries[iSlotNum];
  198. if ((! pEntry->pRenderObj) || (pEntry->fClosing) || (pEntry->dwRecycleNum != dwRecycleNum))
  199. {
  200. Log(LOG_BADHTHEME, L"Expired Theme Handle: 0x%x", hTheme);
  201. hr = MakeError32(E_HANDLE);
  202. goto exit;
  203. }
  204. if (pEntry->iInUseCount > 25)
  205. {
  206. Log(LOG_BADHTHEME, L"Warning BREAK: high ThemeHandle inuse count=%d", pEntry->iInUseCount);
  207. }
  208. pEntry->iInUseCount++;
  209. *ppRenderObj = pEntry->pRenderObj;
  210. *piSlotNum = iSlotNum;
  211. exit:
  212. return hr;
  213. }
  214. //---------------------------------------------------------------------------
  215. void CRenderList::CloseThemeHandle(int iSlotNum)
  216. {
  217. CAutoCS autoCritSect(&_csListLock);
  218. RENDER_OBJ_ENTRY *pEntry = &_RenderEntries[iSlotNum];
  219. if (pEntry->iInUseCount <= 0)
  220. {
  221. Log(LOG_ERROR, L"Bad iUseCount on CRenderObj at slot=%d", iSlotNum);
  222. }
  223. else
  224. {
  225. pEntry->iInUseCount--;
  226. DeleteCheck(pEntry);
  227. }
  228. }
  229. //---------------------------------------------------------------------------
  230. void CRenderList::FreeRenderObjects(int iThemeFileLoadId)
  231. {
  232. CAutoCS autoCritSect(&_csListLock);
  233. int iFoundCount = 0;
  234. int iClosedCount = 0;
  235. //---- theme hooking has been turned off - mark all ----
  236. //---- our objects so they can be freed as soon ----
  237. //---- as all wrapper API's are exited so that ----
  238. //---- we don't hold open those big theme files in memory ----
  239. for (int i=0; i < _RenderEntries.m_nSize; i++)
  240. {
  241. RENDER_OBJ_ENTRY *pEntry = &_RenderEntries[i];
  242. if (pEntry->pRenderObj)
  243. {
  244. if ((iThemeFileLoadId == -1) || (iThemeFileLoadId == pEntry->iLoadId))
  245. {
  246. iFoundCount++;
  247. HTHEME hTheme = MAKE_HTHEME(pEntry->dwRecycleNum, i);
  248. Log(LOG_BADHTHEME, L"Unclosed RenderList[]: class=%s, hwnd=0x%x, htheme=0x%x, refcnt=%d",
  249. pEntry->pRenderObj->_pszClassName, pEntry->hwnd, hTheme, pEntry->iRefCount);
  250. pEntry->fClosing = TRUE; // don't grant further access to this obj
  251. pEntry->iRefCount = 0; // free it as soon as callers have exited
  252. if (DeleteCheck(pEntry)) // delete now or mark for "delete on API exit"
  253. {
  254. //---- just deleted it ----
  255. iClosedCount++;
  256. }
  257. }
  258. }
  259. }
  260. Log(LOG_TMHANDLE, L"FreeRenderObjects: iLoadId=%d, found-open=%d, closed-now=%d",
  261. iThemeFileLoadId, iFoundCount, iClosedCount);
  262. }
  263. //---------------------------------------------------------------------------
  264. #ifdef DEBUG
  265. void CRenderList::DumpFileHolders()
  266. {
  267. CAutoCS autoCritSect(&_csListLock);
  268. if (LogOptionOn(LO_TMHANDLE))
  269. {
  270. //---- find number of CRenderObj's ----
  271. int iCount = 0;
  272. _RenderEntries.m_nSize;
  273. for (int i=0; i < _RenderEntries.m_nSize; i++)
  274. {
  275. if (_RenderEntries[i].pRenderObj)
  276. iCount++;
  277. }
  278. if (! iCount)
  279. {
  280. Log(LOG_TMHANDLE, L"---- No CRenderObj objects ----");
  281. }
  282. else
  283. {
  284. Log(LOG_TMHANDLE, L"---- Dump of %d CRenderObj objects ----", iCount);
  285. for (int i=0; i < _RenderEntries.m_nSize; i++)
  286. {
  287. RENDER_OBJ_ENTRY *pEntry = &_RenderEntries[i];
  288. if (pEntry->pRenderObj)
  289. {
  290. CRenderObj *pr = pEntry->pRenderObj;
  291. THEMEHDR *th = (THEMEHDR *)pr->_pbThemeData;
  292. int iLoadId = 0;
  293. if (th)
  294. iLoadId = th->iLoadId;
  295. LPCWSTR pszClass = NULL;
  296. if (pr->_pszClassName)
  297. pszClass = pr->_pszClassName;
  298. Log(LOG_TMHANDLE, L" RenderObj[%d]: class=%s, refcnt=%d, hwnd=0x%x",
  299. i, pszClass, pEntry->iRefCount, pEntry->hwnd);
  300. }
  301. }
  302. }
  303. }
  304. }
  305. #endif
  306. //---------------------------------------------------------------------------