|
|
// Copyright (C) 1997 Microsoft Corporation
//
// Dialog to display promotion progress
//
// 12-29-97 sburns
#include "headers.hxx"
#include "ProgressDialog.hpp"
#include "indicate.hpp"
#include "resource.h"
const UINT ProgressDialog::THREAD_SUCCEEDED = WM_USER + 999; const UINT ProgressDialog::THREAD_FAILED = WM_USER + 1000;
// this string must match that in the CLASS specification of the
// dialog template in the .rc file!
static TCHAR PROGRESS_DIALOG_CLASS_NAME[] = L"dcpromo_progress";
static const DWORD HELP_MAP[] = { 0, 0 };
struct WrapperThreadProcParams { ProgressDialog* dialog; ProgressDialog::ThreadProc realProc; };
void _cdecl wrapperThreadProc(void* p) { ASSERT(p);
WrapperThreadProcParams* params = reinterpret_cast<WrapperThreadProcParams*>(p); ASSERT(params->dialog); ASSERT(params->realProc);
params->realProc(*(params->dialog)); }
ProgressDialog::ProgressDialog( ThreadProc threadProc_, int animationResId_) : Dialog(IDD_PROGRESS, HELP_MAP), animationResId(animationResId_), threadProc(threadProc_), threadParams(0), buttonEventHandle(0) { LOG_CTOR(ProgressDialog); ASSERT(threadProc); ASSERT(animationResId > 0);
// we subclass the window so we can change the cursor to the wait cursor
WNDCLASSEX wndclass; memset(&wndclass, 0, sizeof(wndclass));
static const wchar_t* DIALOG_WINDOW_CLASS_NAME = L"#32770";
HRESULT hr = Win::GetClassInfoEx(DIALOG_WINDOW_CLASS_NAME, wndclass); ASSERT(SUCCEEDED(hr));
wndclass.lpfnWndProc = ::DefDlgProc; wndclass.hInstance = Win::GetModuleHandle(); wndclass.lpszClassName = PROGRESS_DIALOG_CLASS_NAME;
hr = Win::LoadCursor(IDC_WAIT, wndclass.hCursor); ASSERT(SUCCEEDED(hr));
ATOM unused = 0; hr = Win::RegisterClassEx(wndclass, unused); ASSERT(SUCCEEDED(hr));
hr = Win::CreateEvent(0, false, false, buttonEventHandle); ASSERT(SUCCEEDED(hr)); }
ProgressDialog::~ProgressDialog() { LOG_DTOR(ProgressDialog);
delete threadParams;
Win::UnregisterClass(PROGRESS_DIALOG_CLASS_NAME, Win::GetModuleHandle()); }
void ProgressDialog::UpdateText(const String& message) { LOG_FUNCTION2(ProgressDialog::UpdateText, message);
Win::ShowWindow( Win::GetDlgItem(hwnd, IDC_MESSAGE), message.empty() ? SW_HIDE : SW_SHOW); Win::SetDlgItemText(hwnd, IDC_MESSAGE, message); }
void ProgressDialog::UpdateText(int textStringResID) { LOG_FUNCTION(ProgressDialog::UpdateText); ASSERT(textStringResID > 0);
UpdateText(String::load(textStringResID)); }
void ProgressDialog::UpdateButton(int textStringResID) { LOG_FUNCTION(ProgressDialog::UpdateButton); ASSERT(textStringResID > 0);
UpdateButton(String::load(textStringResID)); }
void ProgressDialog::UpdateButton(const String& text) { LOG_FUNCTION2(ProgressDialog::UpdateButton, text); HWND button = Win::GetDlgItem(hwnd, IDC_BUTTON);
DWORD waitResult = WAIT_FAILED; HRESULT hr = Win::WaitForSingleObject(buttonEventHandle, 0, waitResult);
ASSERT(SUCCEEDED(hr));
if (waitResult == WAIT_OBJECT_0) { // event is still signalled, so reset it.
Win::ResetEvent(buttonEventHandle); } bool empty = text.empty();
// Hide the button before we adjust the geometry. On slow or heavily
// loaded machines, the repaints show a noticable delay that has frightened
// at least one user.
// NTRAID#NTBUG9-353799-2001/04/05-sburns
Win::ShowWindow(button, SW_HIDE); Win::EnableWindow(button, false);
if (empty) { // leave the button hidden and disabled.
return; }
// resize and recenter the button
RECT buttonRect; Win::GetWindowRect(button, buttonRect); Win::ScreenToClient(hwnd, buttonRect);
HDC hdc = GetWindowDC(button); SIZE textExtent; Win::GetTextExtentPoint32(hdc, text, textExtent); Win::ReleaseDC(button, hdc);
// add a bit of whitespace to the button label
// NTRAID#NTBUG9-40855-2001/02/28-sburns
textExtent.cx += 40;
RECT dialogRect; hr = Win::GetClientRect(hwnd, dialogRect);
ASSERT(SUCCEEDED(hr));
Win::MoveWindow( button, dialogRect.left + (dialogRect.right - dialogRect.left - textExtent.cx) / 2, buttonRect.top, textExtent.cx, buttonRect.bottom - buttonRect.top, true);
// display the button only after we have adjusted it's geometry
Win::SetDlgItemText(hwnd, IDC_BUTTON, text); Win::ShowWindow(button, SW_SHOW); Win::EnableWindow(button, true); }
void ProgressDialog::OnDestroy() { LOG_FUNCTION(ProgressDialog::OnDestroy);
// we don't delete things here, as a WM_DESTROY message may never be sent
}
void ProgressDialog::OnInit() { LOG_FUNCTION(ProgressDialog::OnInit);
Win::Animate_Open( Win::GetDlgItem(hwnd, IDC_ANIMATION), MAKEINTRESOURCE(animationResId));
UpdateText(String()); UpdateButton(String());
// deleted in the dtor, not in the wrapperThreadProc, in case the
// wrapperThreadProc terminates abnormally.
threadParams = new WrapperThreadProcParams; threadParams->dialog = this; threadParams->realProc = threadProc;
_beginthread(wrapperThreadProc, 0, threadParams); }
bool ProgressDialog::OnCommand( HWND windowFrom, unsigned controlIDFrom, unsigned code) { if (code == BN_CLICKED) { switch (controlIDFrom) { case IDC_BUTTON: { LOG(L"ProgressDialog::OnCommand -- cancel button pressed"); // Since the response to the button press may be some time
// coming, disable the button to prevent the user from pressing
// it over and over in a frantic panic.
Win::EnableWindow(windowFrom, false); Win::SetEvent(buttonEventHandle); break; } default: { // do nothing
} } }
return false; }
bool ProgressDialog::OnMessage( UINT message, WPARAM /* wparam */ , LPARAM /* lparam */ ) { // LOG_FUNCTION(ProgressDialog::OnMessage);
switch (message) { case THREAD_SUCCEEDED: { Win::Animate_Stop(Win::GetDlgItem(hwnd, IDC_ANIMATION)); UpdateText(String::load(IDS_OPERATION_DONE));
HRESULT unused = Win::EndDialog(hwnd, THREAD_SUCCEEDED);
ASSERT(SUCCEEDED(unused));
return true; } case THREAD_FAILED: { Win::Animate_Stop(Win::GetDlgItem(hwnd, IDC_ANIMATION)); UpdateText(String::load(IDS_OPERATION_TERMINATED));
HRESULT unused = Win::EndDialog(hwnd, THREAD_FAILED);
ASSERT(SUCCEEDED(unused));
return true; } default: { // do nothing
break; } }
return false; }
ProgressDialog::WaitCode ProgressDialog::WaitForButton(int timeoutMillis) { // LOG_FUNCTION(ProgressDialog::WaitForButton);
DWORD result = WAIT_FAILED; HRESULT hr = Win::WaitForSingleObject(buttonEventHandle, timeoutMillis, result);
ASSERT(SUCCEEDED(hr));
switch (result) { case WAIT_OBJECT_0: { return PRESSED; } case WAIT_TIMEOUT: { return TIMEOUT; } case WAIT_FAILED: { // we squeltch the failure, and equate it to timeout
// fall thru
} default: { ASSERT(false); } }
return TIMEOUT; }
|