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.

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