374 lines
7.4 KiB
C++
374 lines
7.4 KiB
C++
// 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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|