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.

676 lines
19 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: viewer.cxx
  3. *
  4. * Copyright (c) 2000 Microsoft Corporation
  5. *
  6. \**************************************************************************/
  7. #include "precomp.hxx"
  8. #include <tchar.h>
  9. LRESULT CALLBACK ViewerWndProc(HWND, UINT, WPARAM, LPARAM);
  10. typedef struct {
  11. HWND hViewerWnd; // To be set by created thread
  12. PDEBUG_CLIENT Client;
  13. PSURF_INFO SurfInfo;
  14. } ViewerThreadParams;
  15. DWORD WINAPI ViewerThread(ViewerThreadParams *);
  16. const _TCHAR szClassName[] = _T("KD GDI Viewer");
  17. const _TCHAR szWindowName[] = _T("KD GDI Viewer");
  18. ATOM gViewerAtom;
  19. HBRUSH ghbrWhite;
  20. HPEN ghBorderPen;
  21. const LONG DEFAULT_SCALE = 2;
  22. class ViewerManager
  23. {
  24. public:
  25. ViewerManager(ULONG GrowLength = 4)
  26. {
  27. BeingDestroyed = FALSE;
  28. Wnds = 0;
  29. MaxWnds = 0;
  30. phWndList = NULL;
  31. GrowLen = (GrowLength == 0) ? 4 : GrowLength;
  32. __try {
  33. InitializeCriticalSection(&CritSect);
  34. CritOk = TRUE;
  35. Grow();
  36. }
  37. __except (STATUS_NO_MEMORY) {
  38. CritOk = FALSE;
  39. }
  40. }
  41. ~ViewerManager()
  42. {
  43. if (CritOk) EnterCriticalSection(&CritSect);
  44. BeingDestroyed = TRUE;
  45. if (CritOk) LeaveCriticalSection(&CritSect);
  46. DestroyAll();
  47. // If we have Wnds left at this point all of them
  48. // are now tracked as threads. Wait for each
  49. // thread to completely finish.
  50. if (Wnds)
  51. {
  52. DWORD WaitReturn;
  53. DbgPrint("Waiting for remaining %lu threads...\n", Wnds);
  54. WaitReturn = WaitForMultipleObjects(Wnds, (HANDLE *)phWndList, TRUE, INFINITE);
  55. DbgPrint("WaitForMultipleObjects returned %lx.\n", WaitReturn);
  56. while (Wnds-- > 0)
  57. {
  58. CloseHandle(phWndList[Wnds]);
  59. DbgPrint("ViewerManager::~ViewerManager calling ExtRelease().\n");
  60. ExtRelease();
  61. }
  62. }
  63. HeapFree(hHeap, 0, phWndList);
  64. if (CritOk) DeleteCriticalSection(&CritSect);
  65. }
  66. BOOL Grow();
  67. BOOL Destroy(HWND);
  68. void DestroyAll()
  69. {
  70. ULONG i = Wnds;
  71. while (i-- > 0)
  72. {
  73. Destroy(phWndList[i]);
  74. }
  75. }
  76. private:
  77. ULONG Wnds;
  78. ULONG MaxWnds;
  79. HWND *phWndList;
  80. HANDLE hHeap;
  81. ULONG GrowLen;
  82. BOOL BeingDestroyed;
  83. BOOL CritOk;
  84. CRITICAL_SECTION CritSect;
  85. friend DWORD WINAPI ViewerThread(ViewerThreadParams *);
  86. BOOL Track(HWND hWnd)
  87. {
  88. if (this == NULL || !CritOk) return FALSE;
  89. BOOL bTracked = FALSE;
  90. EnterCriticalSection(&CritSect);
  91. if (!BeingDestroyed &&
  92. ((Wnds < MaxWnds) || Grow()))
  93. {
  94. DbgPrint("ViewerManager: Tracking %lx.\n", hWnd);
  95. phWndList[Wnds++] = hWnd;
  96. bTracked = TRUE;
  97. }
  98. LeaveCriticalSection(&CritSect);
  99. return bTracked;
  100. }
  101. BOOL Untrack(HWND hWnd)
  102. {
  103. if (this == NULL || !CritOk) return FALSE;
  104. BOOL bFound = FALSE;
  105. EnterCriticalSection(&CritSect);
  106. ULONG i = Wnds;
  107. while (i-- > 0)
  108. {
  109. if (phWndList[i] == hWnd)
  110. {
  111. DbgPrint("ViewerManager: No longer tracking %lx.\n", hWnd);
  112. phWndList[i] = phWndList[--Wnds];
  113. phWndList[Wnds] = NULL;
  114. bFound = TRUE;
  115. if (!BeingDestroyed)
  116. {
  117. DbgPrint("ViewerManager::Untrack calling ExtRelease().\n");
  118. ExtRelease();
  119. }
  120. break;
  121. }
  122. }
  123. if (!bFound)
  124. DbgPrint("ViewerManager::Untrack didn't find %lx.\n", hWnd);
  125. LeaveCriticalSection(&CritSect);
  126. return bFound;
  127. }
  128. };
  129. BOOL ViewerManager::Grow()
  130. {
  131. if (MaxWnds > 0)
  132. {
  133. HWND *pNewList = (HWND *)HeapReAlloc(hHeap, HEAP_ZERO_MEMORY, phWndList, (MaxWnds + GrowLen)*sizeof(HWND));
  134. if (pNewList != NULL)
  135. {
  136. phWndList = pNewList;
  137. MaxWnds += GrowLen;
  138. return TRUE;
  139. }
  140. }
  141. else
  142. {
  143. hHeap = GetProcessHeap();
  144. if (hHeap)
  145. {
  146. phWndList = (HWND *)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, GrowLen*sizeof(HWND));
  147. if (phWndList != NULL)
  148. {
  149. MaxWnds = GrowLen;
  150. return TRUE;
  151. }
  152. }
  153. }
  154. DbgPrint("ViewerManager::Grow FAILED!\n");
  155. return FALSE;
  156. }
  157. BOOL ViewerManager::Destroy(HWND hWnd)
  158. {
  159. ULONG i = Wnds;
  160. DbgPrint("Looking for window %lx in %lu entries.\n", hWnd, i);
  161. while (i-- > 0)
  162. {
  163. if (phWndList[i] == hWnd)
  164. {
  165. DbgPrint("Destroying window %lx at entry %lu.\n", hWnd, i);
  166. DWORD ThreadID = GetWindowThreadProcessId(hWnd, NULL);
  167. HANDLE hThread;
  168. if (hThread = OSCompat_OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, FALSE, ThreadID))
  169. {
  170. BOOL bCloseHandle = TRUE;
  171. DWORD ExitCode = STILL_ACTIVE;
  172. while (!PostMessage(hWnd, WM_DESTROY, 0, 0))
  173. {
  174. DbgPrint("Waiting on post msg to %lx...\n", hWnd);
  175. Sleep(10);
  176. if (GetExitCodeThread(hThread, &ExitCode) &&
  177. ExitCode != STILL_ACTIVE)
  178. {
  179. break;
  180. }
  181. }
  182. // Check thread exit status
  183. if (ExitCode == STILL_ACTIVE)
  184. {
  185. if (!GetExitCodeThread(hThread, &ExitCode))
  186. {
  187. DbgPrint("GetExitCodeThread returned error %lx.\n", GetLastError());
  188. }
  189. }
  190. // Give the thread a chance to exit
  191. if (ExitCode == STILL_ACTIVE)
  192. {
  193. DWORD WaitReturn;
  194. DbgPrint("Waiting for hThread: %lx, ThreadID: %lx, hWnd: %lx.\n", hThread, ThreadID, hWnd);
  195. if (WAIT_OBJECT_0 != (WaitReturn = WaitForSingleObject(hThread, 100)))
  196. {
  197. DbgPrint("WaitForSingleObject returned %lx.\n", WaitReturn);
  198. // If it hasn't exited and it called untrack
  199. // to remove the hWnd we're concerned with,
  200. // replace it with the thread handle so we may
  201. // wait on it later.
  202. EnterCriticalSection(&CritSect);
  203. if (phWndList[i] == hWnd)
  204. {
  205. phWndList[i] = (HWND)hThread;
  206. bCloseHandle = FALSE;
  207. }
  208. LeaveCriticalSection(&CritSect);
  209. }
  210. }
  211. if (bCloseHandle)
  212. {
  213. // If the thread was still active, but the track entry
  214. // has been removed, we have to wait for the thread to
  215. // completely terminate.
  216. if (ExitCode == STILL_ACTIVE)
  217. {
  218. DbgPrint("Inifinitely waiting for thread %lx to complete.\n", ThreadID);
  219. WaitForSingleObject(hThread, INFINITE);
  220. if (!GetExitCodeThread(hThread, &ExitCode))
  221. {
  222. DbgPrint("GetExitCodeThread returned error %lx.\n", GetLastError());
  223. }
  224. else
  225. {
  226. DbgPrint("Thread exit code was %lx.\n", ExitCode);
  227. }
  228. }
  229. DbgPrint("Closing hThread: %lx\n", hThread);
  230. CloseHandle(hThread);
  231. if (BeingDestroyed)
  232. {
  233. DbgPrint("ViewerManager::Destroy calling ExtRelease().\n");
  234. ExtRelease();
  235. }
  236. }
  237. }
  238. else
  239. {
  240. // This really hurts.
  241. // We have a tracked window, but we can't get
  242. // information on it's thread, we have to stop
  243. // tracking it.
  244. DbgPrint("ViewerManager::Destroy: OpenThread returned error %lx!\n", GetLastError());
  245. EnterCriticalSection(&CritSect);
  246. if (phWndList[i] == hWnd)
  247. {
  248. phWndList[i] = phWndList[--Wnds];
  249. phWndList[Wnds] = NULL;
  250. }
  251. LeaveCriticalSection(&CritSect);
  252. }
  253. return TRUE;
  254. }
  255. }
  256. return FALSE;
  257. }
  258. ViewerManager *ViewerMgr;
  259. void ViewerInit()
  260. {
  261. if (ViewerMgr == NULL)
  262. {
  263. ViewerMgr = new ViewerManager;
  264. if (ViewerMgr == NULL) return;
  265. }
  266. if (! ghbrWhite)
  267. {
  268. DbgPrint("ViewerInit: Creating white brush\n");
  269. ghbrWhite = CreateSolidBrush(RGB(0xFF,0xFF,0xFF));
  270. DbgPrint("ViewerInit: Created brush %lx\n", ghbrWhite);
  271. }
  272. if (! ghBorderPen)
  273. {
  274. DbgPrint("ViewerInit: Creating redish pen\n");
  275. ghBorderPen = CreatePen(PS_SOLID, 1, RGB(0xF0, 0x00, 0x3F));
  276. DbgPrint("ViewerInit: Created pen %lx\n", ghBorderPen);
  277. }
  278. if (! gViewerAtom)
  279. {
  280. WNDCLASSEX wcex;
  281. DbgPrint("ViewerInit: Registering Class\n");
  282. DbgPrint("ViewerInit: ghDllInst = %lx\n", ghDllInst);
  283. wcex.cbSize = sizeof(wcex);
  284. wcex.style = CS_VREDRAW | CS_HREDRAW;
  285. wcex.lpfnWndProc = ViewerWndProc;
  286. wcex.cbClsExtra = 0;
  287. wcex.cbWndExtra = 0;
  288. wcex.hInstance = ghDllInst;
  289. wcex.hIcon = NULL;
  290. wcex.hCursor = LoadCursor( NULL, IDC_ARROW );
  291. wcex.hbrBackground = (HBRUSH)( COLOR_WINDOW+1 );
  292. wcex.lpszMenuName = NULL;
  293. wcex.lpszClassName = szClassName;
  294. wcex.hIconSm = NULL;
  295. gViewerAtom = RegisterClassEx( &wcex );
  296. }
  297. }
  298. void ViewerExit()
  299. {
  300. if (ViewerMgr != NULL)
  301. {
  302. delete ViewerMgr;
  303. ViewerMgr = NULL;
  304. }
  305. if (gViewerAtom)
  306. {
  307. DbgPrint("ViewerExit: Unregistering Class\n");
  308. UnregisterClass((LPCSTR)gViewerAtom, 0);
  309. gViewerAtom = 0;
  310. }
  311. if (ghBorderPen)
  312. {
  313. DbgPrint("ViewerExit: Deleting border pen\n");
  314. DeleteObject(ghBorderPen);
  315. ghBorderPen = NULL;
  316. }
  317. if (ghbrWhite)
  318. {
  319. DbgPrint("ViewerInit: Deleting white brush\n");
  320. DeleteObject(ghbrWhite);
  321. ghbrWhite = NULL;
  322. }
  323. }
  324. BOOL
  325. CALLBACK
  326. ViewerWndEnumProc(
  327. HWND hWnd,
  328. LPARAM lParam
  329. )
  330. {
  331. HWND *phWndParent = (HWND *)lParam;
  332. DbgPrint("Found hWnd %lx.\n", hWnd);
  333. if (*phWndParent == NULL)
  334. {
  335. *phWndParent = hWnd;
  336. }
  337. return TRUE;
  338. }
  339. DWORD
  340. WINAPI
  341. ViewerThread(
  342. ViewerThreadParams *Params
  343. )
  344. {
  345. HWND hWnd;
  346. BOOL bGetMsg;
  347. MSG msg;
  348. _TCHAR ViewerWndName[sizeof(szWindowName) + sizeof(Params->SurfInfo->SurfName) + 20];
  349. _TCHAR *pszName = Params->SurfInfo->SurfName;
  350. if (!pszName[0]) pszName = _T("UNAMED");
  351. _stprintf(ViewerWndName, "%s: %s (%ldx%ldx%hubpp)", szWindowName, pszName,
  352. Params->SurfInfo->Width,
  353. Params->SurfInfo->Height,
  354. Params->SurfInfo->BitsPixel);
  355. hWnd = CreateWindowEx(WS_EX_LEFT,
  356. (LPCSTR)gViewerAtom,
  357. ViewerWndName,
  358. WS_OVERLAPPEDWINDOW,// | WS_HSCROLL | WS_VSCROLL,
  359. 0,
  360. 0,
  361. Params->SurfInfo->Width*DEFAULT_SCALE+10,//32,
  362. Params->SurfInfo->Height*DEFAULT_SCALE+29,//48,
  363. NULL,
  364. NULL,
  365. ghDllInst,
  366. Params->SurfInfo // lParam passed to WM_CREATE handler
  367. );
  368. if (hWnd)
  369. {
  370. ViewerMgr->Track(hWnd);
  371. Params->hViewerWnd = hWnd; // Params may no longer be valid.
  372. ShowWindow(hWnd, SW_SHOWDEFAULT);
  373. UpdateWindow(hWnd);
  374. while( (bGetMsg = GetMessage(&msg, NULL, 0, 0 )) != 0 )
  375. {
  376. if (bGetMsg == -1)
  377. {
  378. DbgPrint("ViewerThread exiting due to GetMessage error 0x%lx.\n",
  379. GetLastError());
  380. break;
  381. }
  382. else
  383. {
  384. TranslateMessage( &msg );
  385. DispatchMessage( &msg );
  386. }
  387. }
  388. DbgPrint("ViewerThread exiting properly.\n");
  389. ViewerMgr->Untrack(hWnd);
  390. }
  391. else
  392. {
  393. DbgPrint("CreateWindow returned error %lx.\n", GetLastError());
  394. msg.wParam = -1;
  395. }
  396. DbgPrint("ViewerThread calling ExitThread().\n");
  397. ExitThread((DWORD)msg.wParam);
  398. }
  399. DWORD
  400. CreateViewer(
  401. PDEBUG_CLIENT Client,
  402. PSURF_INFO SurfInfo
  403. )
  404. {
  405. ViewerThreadParams NewThreadParams = { NULL, Client, SurfInfo };
  406. HRESULT Status;
  407. // Reference Debug Client for ViewerThread
  408. // since dbgeng/dbghelp aren't thread safe.
  409. // ViewerManager will release client in a safe manner.
  410. if ((Status = ExtQuery(Client)) != S_OK) return 0;
  411. HWND hWndParent = NULL;
  412. EnumThreadWindows(GetCurrentThreadId(), (WNDENUMPROC)ViewerWndEnumProc, (LPARAM)&hWndParent);
  413. HANDLE hThread;
  414. DWORD ThreadID = 0;
  415. hThread = CreateThread(NULL,
  416. 0,
  417. (LPTHREAD_START_ROUTINE)ViewerThread,
  418. &NewThreadParams,
  419. 0,
  420. &ThreadID);
  421. if (hThread)
  422. {
  423. while (NewThreadParams.hViewerWnd == NULL)
  424. {
  425. DWORD ExitCode = 0;
  426. if (!GetExitCodeThread(hThread, &ExitCode))
  427. DbgPrint("GetExitCodeThread returned error %lx.\n", GetLastError());
  428. if (ExitCode != STILL_ACTIVE)
  429. {
  430. ThreadID = 0;
  431. break;
  432. }
  433. SleepEx(10, TRUE);
  434. }
  435. CloseHandle(hThread);
  436. }
  437. if (ThreadID == 0)
  438. {
  439. ExtRelease();
  440. }
  441. return ThreadID;
  442. }
  443. // DelPropProc is a callback function
  444. // that deletes a window property.
  445. BOOL CALLBACK DelPropProc(
  446. HWND hwndSubclass, // handle of window with property
  447. LPCSTR lpszString, // property string or atom
  448. HANDLE hData) // data handle
  449. {
  450. RemoveProp(hwndSubclass, lpszString);
  451. return TRUE;
  452. }
  453. LRESULT
  454. CALLBACK
  455. ViewerWndProc(
  456. HWND hWnd,
  457. UINT msg,
  458. WPARAM wParam,
  459. LPARAM lParam
  460. )
  461. {
  462. // DbgPrint("ViewerWndProc(%lx, %lx, , )\n", hWnd, msg);
  463. switch( msg )
  464. {
  465. case WM_CREATE:
  466. {
  467. LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam;
  468. PSURF_INFO SurfInfo = (PSURF_INFO) CreateStruct->lpCreateParams;
  469. DbgPrint("ViewerWndProc: WM_CREATE\n");
  470. if (SurfInfo)
  471. {
  472. SetProp(hWnd, "hBitmap", SurfInfo->hBitmap);
  473. SetProp(hWnd, "xOrigin", LongToHandle(SurfInfo->xOrigin));
  474. SetProp(hWnd, "yOrigin", LongToHandle(SurfInfo->yOrigin));
  475. SetProp(hWnd, "Width", LongToHandle(SurfInfo->Width));
  476. SetProp(hWnd, "Height", LongToHandle(SurfInfo->Height));
  477. SetProp(hWnd, "BPP", LongToHandle(SurfInfo->BitsPixel));
  478. SetProp(hWnd, "Scale", LongToHandle(DEFAULT_SCALE));
  479. // SetProp(hWnd, "", SurfInfo->);
  480. }
  481. else
  482. {
  483. ExtErr("ViewerWindow created with NULL PSURF_INFO.\n");
  484. return -1;
  485. }
  486. }
  487. return 0;
  488. case WM_KEYDOWN:
  489. if (wParam == VK_DOWN || wParam == VK_UP)
  490. {
  491. LONG Scale = HandleToLong(GetProp(hWnd, "Scale"));
  492. if (wParam == VK_DOWN)
  493. {
  494. if (Scale > 1)
  495. {
  496. SetProp(hWnd, "Scale", LongToHandle((Scale-1)));
  497. InvalidateRect(hWnd, NULL, TRUE);
  498. }
  499. }
  500. else
  501. {
  502. if (Scale < 16)
  503. {
  504. SetProp(hWnd, "Scale", LongToHandle((Scale+1)));
  505. InvalidateRect(hWnd, NULL, TRUE);
  506. }
  507. }
  508. return 0;
  509. }
  510. break;
  511. case WM_PAINT:
  512. {
  513. PAINTSTRUCT ps;
  514. HDC hdc;
  515. HBITMAP hBitmapOrg;
  516. HBRUSH hBrushOrg;
  517. HPEN hPenOrg;
  518. BeginPaint(hWnd, &ps);
  519. hdc = CreateCompatibleDC(ps.hdc);
  520. hBitmapOrg = (HBITMAP)SelectObject(hdc, (HBITMAP)GetProp(hWnd, "hBitmap"));
  521. if (hBitmapOrg == NULL)
  522. {
  523. DbgPrint("Error from SelectObject(, HBITMAP): %lx\n", GetLastError());
  524. }
  525. hBrushOrg = (HBRUSH)SelectObject(ps.hdc, ghbrWhite);
  526. hPenOrg = (HPEN)SelectObject(ps.hdc, ghBorderPen);
  527. LONG xOrigin = HandleToLong(GetProp(hWnd, "xOrigin"));
  528. LONG yOrigin = HandleToLong(GetProp(hWnd, "yOrigin"));
  529. LONG Width = HandleToLong(GetProp(hWnd, "Width"));
  530. LONG Height = HandleToLong(GetProp(hWnd, "Height"));
  531. LONG Scale = HandleToLong(GetProp(hWnd, "Scale"));
  532. Rectangle(ps.hdc, 0, 0, Width*Scale+2, Height*Scale+2);
  533. if (!StretchBlt(ps.hdc, 1, 1, Width*Scale, Height*Scale, hdc, xOrigin, yOrigin, Width, Height, SRCCOPY))
  534. {
  535. DbgPrint("Error from StrectBlt): %lx\n", GetLastError());
  536. }
  537. SelectObject(ps.hdc, hPenOrg);
  538. SelectObject(ps.hdc, hBrushOrg);
  539. SelectObject(hdc, hBitmapOrg);
  540. DeleteDC(hdc);
  541. EndPaint(hWnd, &ps);
  542. }
  543. return DefWindowProc( hWnd, msg, wParam, lParam );
  544. case WM_DESTROY:
  545. DbgPrint("ViewerWndProc: WM_DESTROY\n");
  546. DeleteObject((HBITMAP)GetProp(hWnd, "hBitmap"));
  547. EnumPropsEx(hWnd, (PROPENUMPROCEX)DelPropProc, NULL);
  548. PostQuitMessage(0);
  549. break;
  550. default:
  551. // DbgPrint("ViewerWndProc: unhandled msg %lx\n", msg);
  552. break;
  553. }
  554. return DefWindowProc( hWnd, msg, wParam, lParam );
  555. }