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

/******************************Module*Header*******************************\
* Module Name: viewer.cxx
*
* Copyright (c) 2000 Microsoft Corporation
*
\**************************************************************************/
#include "precomp.hxx"
#include <tchar.h>
LRESULT CALLBACK ViewerWndProc(HWND, UINT, WPARAM, LPARAM);
typedef struct {
HWND hViewerWnd; // To be set by created thread
PDEBUG_CLIENT Client;
PSURF_INFO SurfInfo;
} ViewerThreadParams;
DWORD WINAPI ViewerThread(ViewerThreadParams *);
const _TCHAR szClassName[] = _T("KD GDI Viewer");
const _TCHAR szWindowName[] = _T("KD GDI Viewer");
ATOM gViewerAtom;
HBRUSH ghbrWhite;
HPEN ghBorderPen;
const LONG DEFAULT_SCALE = 2;
class ViewerManager
{
public:
ViewerManager(ULONG GrowLength = 4)
{
BeingDestroyed = FALSE;
Wnds = 0;
MaxWnds = 0;
phWndList = NULL;
GrowLen = (GrowLength == 0) ? 4 : GrowLength;
__try {
InitializeCriticalSection(&CritSect);
CritOk = TRUE;
Grow();
}
__except (STATUS_NO_MEMORY) {
CritOk = FALSE;
}
}
~ViewerManager()
{
if (CritOk) EnterCriticalSection(&CritSect);
BeingDestroyed = TRUE;
if (CritOk) LeaveCriticalSection(&CritSect);
DestroyAll();
// If we have Wnds left at this point all of them
// are now tracked as threads. Wait for each
// thread to completely finish.
if (Wnds)
{
DWORD WaitReturn;
DbgPrint("Waiting for remaining %lu threads...\n", Wnds);
WaitReturn = WaitForMultipleObjects(Wnds, (HANDLE *)phWndList, TRUE, INFINITE);
DbgPrint("WaitForMultipleObjects returned %lx.\n", WaitReturn);
while (Wnds-- > 0)
{
CloseHandle(phWndList[Wnds]);
DbgPrint("ViewerManager::~ViewerManager calling ExtRelease().\n");
ExtRelease();
}
}
HeapFree(hHeap, 0, phWndList);
if (CritOk) DeleteCriticalSection(&CritSect);
}
BOOL Grow();
BOOL Destroy(HWND);
void DestroyAll()
{
ULONG i = Wnds;
while (i-- > 0)
{
Destroy(phWndList[i]);
}
}
private:
ULONG Wnds;
ULONG MaxWnds;
HWND *phWndList;
HANDLE hHeap;
ULONG GrowLen;
BOOL BeingDestroyed;
BOOL CritOk;
CRITICAL_SECTION CritSect;
friend DWORD WINAPI ViewerThread(ViewerThreadParams *);
BOOL Track(HWND hWnd)
{
if (this == NULL || !CritOk) return FALSE;
BOOL bTracked = FALSE;
EnterCriticalSection(&CritSect);
if (!BeingDestroyed &&
((Wnds < MaxWnds) || Grow()))
{
DbgPrint("ViewerManager: Tracking %lx.\n", hWnd);
phWndList[Wnds++] = hWnd;
bTracked = TRUE;
}
LeaveCriticalSection(&CritSect);
return bTracked;
}
BOOL Untrack(HWND hWnd)
{
if (this == NULL || !CritOk) return FALSE;
BOOL bFound = FALSE;
EnterCriticalSection(&CritSect);
ULONG i = Wnds;
while (i-- > 0)
{
if (phWndList[i] == hWnd)
{
DbgPrint("ViewerManager: No longer tracking %lx.\n", hWnd);
phWndList[i] = phWndList[--Wnds];
phWndList[Wnds] = NULL;
bFound = TRUE;
if (!BeingDestroyed)
{
DbgPrint("ViewerManager::Untrack calling ExtRelease().\n");
ExtRelease();
}
break;
}
}
if (!bFound)
DbgPrint("ViewerManager::Untrack didn't find %lx.\n", hWnd);
LeaveCriticalSection(&CritSect);
return bFound;
}
};
BOOL ViewerManager::Grow()
{
if (MaxWnds > 0)
{
HWND *pNewList = (HWND *)HeapReAlloc(hHeap, HEAP_ZERO_MEMORY, phWndList, (MaxWnds + GrowLen)*sizeof(HWND));
if (pNewList != NULL)
{
phWndList = pNewList;
MaxWnds += GrowLen;
return TRUE;
}
}
else
{
hHeap = GetProcessHeap();
if (hHeap)
{
phWndList = (HWND *)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, GrowLen*sizeof(HWND));
if (phWndList != NULL)
{
MaxWnds = GrowLen;
return TRUE;
}
}
}
DbgPrint("ViewerManager::Grow FAILED!\n");
return FALSE;
}
BOOL ViewerManager::Destroy(HWND hWnd)
{
ULONG i = Wnds;
DbgPrint("Looking for window %lx in %lu entries.\n", hWnd, i);
while (i-- > 0)
{
if (phWndList[i] == hWnd)
{
DbgPrint("Destroying window %lx at entry %lu.\n", hWnd, i);
DWORD ThreadID = GetWindowThreadProcessId(hWnd, NULL);
HANDLE hThread;
if (hThread = OSCompat_OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, FALSE, ThreadID))
{
BOOL bCloseHandle = TRUE;
DWORD ExitCode = STILL_ACTIVE;
while (!PostMessage(hWnd, WM_DESTROY, 0, 0))
{
DbgPrint("Waiting on post msg to %lx...\n", hWnd);
Sleep(10);
if (GetExitCodeThread(hThread, &ExitCode) &&
ExitCode != STILL_ACTIVE)
{
break;
}
}
// Check thread exit status
if (ExitCode == STILL_ACTIVE)
{
if (!GetExitCodeThread(hThread, &ExitCode))
{
DbgPrint("GetExitCodeThread returned error %lx.\n", GetLastError());
}
}
// Give the thread a chance to exit
if (ExitCode == STILL_ACTIVE)
{
DWORD WaitReturn;
DbgPrint("Waiting for hThread: %lx, ThreadID: %lx, hWnd: %lx.\n", hThread, ThreadID, hWnd);
if (WAIT_OBJECT_0 != (WaitReturn = WaitForSingleObject(hThread, 100)))
{
DbgPrint("WaitForSingleObject returned %lx.\n", WaitReturn);
// If it hasn't exited and it called untrack
// to remove the hWnd we're concerned with,
// replace it with the thread handle so we may
// wait on it later.
EnterCriticalSection(&CritSect);
if (phWndList[i] == hWnd)
{
phWndList[i] = (HWND)hThread;
bCloseHandle = FALSE;
}
LeaveCriticalSection(&CritSect);
}
}
if (bCloseHandle)
{
// If the thread was still active, but the track entry
// has been removed, we have to wait for the thread to
// completely terminate.
if (ExitCode == STILL_ACTIVE)
{
DbgPrint("Inifinitely waiting for thread %lx to complete.\n", ThreadID);
WaitForSingleObject(hThread, INFINITE);
if (!GetExitCodeThread(hThread, &ExitCode))
{
DbgPrint("GetExitCodeThread returned error %lx.\n", GetLastError());
}
else
{
DbgPrint("Thread exit code was %lx.\n", ExitCode);
}
}
DbgPrint("Closing hThread: %lx\n", hThread);
CloseHandle(hThread);
if (BeingDestroyed)
{
DbgPrint("ViewerManager::Destroy calling ExtRelease().\n");
ExtRelease();
}
}
}
else
{
// This really hurts.
// We have a tracked window, but we can't get
// information on it's thread, we have to stop
// tracking it.
DbgPrint("ViewerManager::Destroy: OpenThread returned error %lx!\n", GetLastError());
EnterCriticalSection(&CritSect);
if (phWndList[i] == hWnd)
{
phWndList[i] = phWndList[--Wnds];
phWndList[Wnds] = NULL;
}
LeaveCriticalSection(&CritSect);
}
return TRUE;
}
}
return FALSE;
}
ViewerManager *ViewerMgr;
void ViewerInit()
{
if (ViewerMgr == NULL)
{
ViewerMgr = new ViewerManager;
if (ViewerMgr == NULL) return;
}
if (! ghbrWhite)
{
DbgPrint("ViewerInit: Creating white brush\n");
ghbrWhite = CreateSolidBrush(RGB(0xFF,0xFF,0xFF));
DbgPrint("ViewerInit: Created brush %lx\n", ghbrWhite);
}
if (! ghBorderPen)
{
DbgPrint("ViewerInit: Creating redish pen\n");
ghBorderPen = CreatePen(PS_SOLID, 1, RGB(0xF0, 0x00, 0x3F));
DbgPrint("ViewerInit: Created pen %lx\n", ghBorderPen);
}
if (! gViewerAtom)
{
WNDCLASSEX wcex;
DbgPrint("ViewerInit: Registering Class\n");
DbgPrint("ViewerInit: ghDllInst = %lx\n", ghDllInst);
wcex.cbSize = sizeof(wcex);
wcex.style = CS_VREDRAW | CS_HREDRAW;
wcex.lpfnWndProc = ViewerWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = ghDllInst;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor( NULL, IDC_ARROW );
wcex.hbrBackground = (HBRUSH)( COLOR_WINDOW+1 );
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szClassName;
wcex.hIconSm = NULL;
gViewerAtom = RegisterClassEx( &wcex );
}
}
void ViewerExit()
{
if (ViewerMgr != NULL)
{
delete ViewerMgr;
ViewerMgr = NULL;
}
if (gViewerAtom)
{
DbgPrint("ViewerExit: Unregistering Class\n");
UnregisterClass((LPCSTR)gViewerAtom, 0);
gViewerAtom = 0;
}
if (ghBorderPen)
{
DbgPrint("ViewerExit: Deleting border pen\n");
DeleteObject(ghBorderPen);
ghBorderPen = NULL;
}
if (ghbrWhite)
{
DbgPrint("ViewerInit: Deleting white brush\n");
DeleteObject(ghbrWhite);
ghbrWhite = NULL;
}
}
BOOL
CALLBACK
ViewerWndEnumProc(
HWND hWnd,
LPARAM lParam
)
{
HWND *phWndParent = (HWND *)lParam;
DbgPrint("Found hWnd %lx.\n", hWnd);
if (*phWndParent == NULL)
{
*phWndParent = hWnd;
}
return TRUE;
}
DWORD
WINAPI
ViewerThread(
ViewerThreadParams *Params
)
{
HWND hWnd;
BOOL bGetMsg;
MSG msg;
_TCHAR ViewerWndName[sizeof(szWindowName) + sizeof(Params->SurfInfo->SurfName) + 20];
_TCHAR *pszName = Params->SurfInfo->SurfName;
if (!pszName[0]) pszName = _T("UNAMED");
_stprintf(ViewerWndName, "%s: %s (%ldx%ldx%hubpp)", szWindowName, pszName,
Params->SurfInfo->Width,
Params->SurfInfo->Height,
Params->SurfInfo->BitsPixel);
hWnd = CreateWindowEx(WS_EX_LEFT,
(LPCSTR)gViewerAtom,
ViewerWndName,
WS_OVERLAPPEDWINDOW,// | WS_HSCROLL | WS_VSCROLL,
0,
0,
Params->SurfInfo->Width*DEFAULT_SCALE+10,//32,
Params->SurfInfo->Height*DEFAULT_SCALE+29,//48,
NULL,
NULL,
ghDllInst,
Params->SurfInfo // lParam passed to WM_CREATE handler
);
if (hWnd)
{
ViewerMgr->Track(hWnd);
Params->hViewerWnd = hWnd; // Params may no longer be valid.
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
while( (bGetMsg = GetMessage(&msg, NULL, 0, 0 )) != 0 )
{
if (bGetMsg == -1)
{
DbgPrint("ViewerThread exiting due to GetMessage error 0x%lx.\n",
GetLastError());
break;
}
else
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
DbgPrint("ViewerThread exiting properly.\n");
ViewerMgr->Untrack(hWnd);
}
else
{
DbgPrint("CreateWindow returned error %lx.\n", GetLastError());
msg.wParam = -1;
}
DbgPrint("ViewerThread calling ExitThread().\n");
ExitThread((DWORD)msg.wParam);
}
DWORD
CreateViewer(
PDEBUG_CLIENT Client,
PSURF_INFO SurfInfo
)
{
ViewerThreadParams NewThreadParams = { NULL, Client, SurfInfo };
HRESULT Status;
// Reference Debug Client for ViewerThread
// since dbgeng/dbghelp aren't thread safe.
// ViewerManager will release client in a safe manner.
if ((Status = ExtQuery(Client)) != S_OK) return 0;
HWND hWndParent = NULL;
EnumThreadWindows(GetCurrentThreadId(), (WNDENUMPROC)ViewerWndEnumProc, (LPARAM)&hWndParent);
HANDLE hThread;
DWORD ThreadID = 0;
hThread = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)ViewerThread,
&NewThreadParams,
0,
&ThreadID);
if (hThread)
{
while (NewThreadParams.hViewerWnd == NULL)
{
DWORD ExitCode = 0;
if (!GetExitCodeThread(hThread, &ExitCode))
DbgPrint("GetExitCodeThread returned error %lx.\n", GetLastError());
if (ExitCode != STILL_ACTIVE)
{
ThreadID = 0;
break;
}
SleepEx(10, TRUE);
}
CloseHandle(hThread);
}
if (ThreadID == 0)
{
ExtRelease();
}
return ThreadID;
}
// DelPropProc is a callback function
// that deletes a window property.
BOOL CALLBACK DelPropProc(
HWND hwndSubclass, // handle of window with property
LPCSTR lpszString, // property string or atom
HANDLE hData) // data handle
{
RemoveProp(hwndSubclass, lpszString);
return TRUE;
}
LRESULT
CALLBACK
ViewerWndProc(
HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam
)
{
// DbgPrint("ViewerWndProc(%lx, %lx, , )\n", hWnd, msg);
switch( msg )
{
case WM_CREATE:
{
LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam;
PSURF_INFO SurfInfo = (PSURF_INFO) CreateStruct->lpCreateParams;
DbgPrint("ViewerWndProc: WM_CREATE\n");
if (SurfInfo)
{
SetProp(hWnd, "hBitmap", SurfInfo->hBitmap);
SetProp(hWnd, "xOrigin", LongToHandle(SurfInfo->xOrigin));
SetProp(hWnd, "yOrigin", LongToHandle(SurfInfo->yOrigin));
SetProp(hWnd, "Width", LongToHandle(SurfInfo->Width));
SetProp(hWnd, "Height", LongToHandle(SurfInfo->Height));
SetProp(hWnd, "BPP", LongToHandle(SurfInfo->BitsPixel));
SetProp(hWnd, "Scale", LongToHandle(DEFAULT_SCALE));
// SetProp(hWnd, "", SurfInfo->);
}
else
{
ExtErr("ViewerWindow created with NULL PSURF_INFO.\n");
return -1;
}
}
return 0;
case WM_KEYDOWN:
if (wParam == VK_DOWN || wParam == VK_UP)
{
LONG Scale = HandleToLong(GetProp(hWnd, "Scale"));
if (wParam == VK_DOWN)
{
if (Scale > 1)
{
SetProp(hWnd, "Scale", LongToHandle((Scale-1)));
InvalidateRect(hWnd, NULL, TRUE);
}
}
else
{
if (Scale < 16)
{
SetProp(hWnd, "Scale", LongToHandle((Scale+1)));
InvalidateRect(hWnd, NULL, TRUE);
}
}
return 0;
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc;
HBITMAP hBitmapOrg;
HBRUSH hBrushOrg;
HPEN hPenOrg;
BeginPaint(hWnd, &ps);
hdc = CreateCompatibleDC(ps.hdc);
hBitmapOrg = (HBITMAP)SelectObject(hdc, (HBITMAP)GetProp(hWnd, "hBitmap"));
if (hBitmapOrg == NULL)
{
DbgPrint("Error from SelectObject(, HBITMAP): %lx\n", GetLastError());
}
hBrushOrg = (HBRUSH)SelectObject(ps.hdc, ghbrWhite);
hPenOrg = (HPEN)SelectObject(ps.hdc, ghBorderPen);
LONG xOrigin = HandleToLong(GetProp(hWnd, "xOrigin"));
LONG yOrigin = HandleToLong(GetProp(hWnd, "yOrigin"));
LONG Width = HandleToLong(GetProp(hWnd, "Width"));
LONG Height = HandleToLong(GetProp(hWnd, "Height"));
LONG Scale = HandleToLong(GetProp(hWnd, "Scale"));
Rectangle(ps.hdc, 0, 0, Width*Scale+2, Height*Scale+2);
if (!StretchBlt(ps.hdc, 1, 1, Width*Scale, Height*Scale, hdc, xOrigin, yOrigin, Width, Height, SRCCOPY))
{
DbgPrint("Error from StrectBlt): %lx\n", GetLastError());
}
SelectObject(ps.hdc, hPenOrg);
SelectObject(ps.hdc, hBrushOrg);
SelectObject(hdc, hBitmapOrg);
DeleteDC(hdc);
EndPaint(hWnd, &ps);
}
return DefWindowProc( hWnd, msg, wParam, lParam );
case WM_DESTROY:
DbgPrint("ViewerWndProc: WM_DESTROY\n");
DeleteObject((HBITMAP)GetProp(hWnd, "hBitmap"));
EnumPropsEx(hWnd, (PROPENUMPROCEX)DelPropProc, NULL);
PostQuitMessage(0);
break;
default:
// DbgPrint("ViewerWndProc: unhandled msg %lx\n", msg);
break;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}