Source code of Windows XP (NT5)
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.

373 lines
7.4 KiB

  1. // Copyright (C) 1997 Microsoft Corporation
  2. //
  3. // Dialog to display promotion progress
  4. //
  5. // 12-29-97 sburns
  6. #include "headers.hxx"
  7. #include "ProgressDialog.hpp"
  8. #include "indicate.hpp"
  9. #include "resource.h"
  10. const UINT ProgressDialog::THREAD_SUCCEEDED = WM_USER + 999;
  11. const UINT ProgressDialog::THREAD_FAILED = WM_USER + 1000;
  12. // this string must match that in the CLASS specification of the
  13. // dialog template in the .rc file!
  14. static TCHAR PROGRESS_DIALOG_CLASS_NAME[] = L"dcpromo_progress";
  15. static const DWORD HELP_MAP[] =
  16. {
  17. 0, 0
  18. };
  19. struct WrapperThreadProcParams
  20. {
  21. ProgressDialog* dialog;
  22. ProgressDialog::ThreadProc realProc;
  23. };
  24. void _cdecl
  25. wrapperThreadProc(void* p)
  26. {
  27. ASSERT(p);
  28. WrapperThreadProcParams* params =
  29. reinterpret_cast<WrapperThreadProcParams*>(p);
  30. ASSERT(params->dialog);
  31. ASSERT(params->realProc);
  32. params->realProc(*(params->dialog));
  33. }
  34. ProgressDialog::ProgressDialog(
  35. ThreadProc threadProc_,
  36. int animationResId_)
  37. :
  38. Dialog(IDD_PROGRESS, HELP_MAP),
  39. animationResId(animationResId_),
  40. threadProc(threadProc_),
  41. threadParams(0),
  42. buttonEventHandle(0)
  43. {
  44. LOG_CTOR(ProgressDialog);
  45. ASSERT(threadProc);
  46. ASSERT(animationResId > 0);
  47. // we subclass the window so we can change the cursor to the wait cursor
  48. WNDCLASSEX wndclass;
  49. memset(&wndclass, 0, sizeof(wndclass));
  50. static const wchar_t* DIALOG_WINDOW_CLASS_NAME = L"#32770";
  51. HRESULT hr = Win::GetClassInfoEx(DIALOG_WINDOW_CLASS_NAME, wndclass);
  52. ASSERT(SUCCEEDED(hr));
  53. wndclass.lpfnWndProc = ::DefDlgProc;
  54. wndclass.hInstance = Win::GetModuleHandle();
  55. wndclass.lpszClassName = PROGRESS_DIALOG_CLASS_NAME;
  56. hr = Win::LoadCursor(IDC_WAIT, wndclass.hCursor);
  57. ASSERT(SUCCEEDED(hr));
  58. ATOM unused = 0;
  59. hr = Win::RegisterClassEx(wndclass, unused);
  60. ASSERT(SUCCEEDED(hr));
  61. hr = Win::CreateEvent(0, false, false, buttonEventHandle);
  62. ASSERT(SUCCEEDED(hr));
  63. }
  64. ProgressDialog::~ProgressDialog()
  65. {
  66. LOG_DTOR(ProgressDialog);
  67. delete threadParams;
  68. Win::UnregisterClass(PROGRESS_DIALOG_CLASS_NAME, Win::GetModuleHandle());
  69. }
  70. void
  71. ProgressDialog::UpdateText(const String& message)
  72. {
  73. LOG_FUNCTION2(ProgressDialog::UpdateText, message);
  74. Win::ShowWindow(
  75. Win::GetDlgItem(hwnd, IDC_MESSAGE),
  76. message.empty() ? SW_HIDE : SW_SHOW);
  77. Win::SetDlgItemText(hwnd, IDC_MESSAGE, message);
  78. }
  79. void
  80. ProgressDialog::UpdateText(int textStringResID)
  81. {
  82. LOG_FUNCTION(ProgressDialog::UpdateText);
  83. ASSERT(textStringResID > 0);
  84. UpdateText(String::load(textStringResID));
  85. }
  86. void
  87. ProgressDialog::UpdateButton(int textStringResID)
  88. {
  89. LOG_FUNCTION(ProgressDialog::UpdateButton);
  90. ASSERT(textStringResID > 0);
  91. UpdateButton(String::load(textStringResID));
  92. }
  93. void
  94. ProgressDialog::UpdateButton(const String& text)
  95. {
  96. LOG_FUNCTION2(ProgressDialog::UpdateButton, text);
  97. HWND button = Win::GetDlgItem(hwnd, IDC_BUTTON);
  98. DWORD waitResult = WAIT_FAILED;
  99. HRESULT hr = Win::WaitForSingleObject(buttonEventHandle, 0, waitResult);
  100. ASSERT(SUCCEEDED(hr));
  101. if (waitResult == WAIT_OBJECT_0)
  102. {
  103. // event is still signalled, so reset it.
  104. Win::ResetEvent(buttonEventHandle);
  105. }
  106. bool empty = text.empty();
  107. // Hide the button before we adjust the geometry. On slow or heavily
  108. // loaded machines, the repaints show a noticable delay that has frightened
  109. // at least one user.
  110. // NTRAID#NTBUG9-353799-2001/04/05-sburns
  111. Win::ShowWindow(button, SW_HIDE);
  112. Win::EnableWindow(button, false);
  113. if (empty)
  114. {
  115. // leave the button hidden and disabled.
  116. return;
  117. }
  118. // resize and recenter the button
  119. RECT buttonRect;
  120. Win::GetWindowRect(button, buttonRect);
  121. Win::ScreenToClient(hwnd, buttonRect);
  122. HDC hdc = GetWindowDC(button);
  123. SIZE textExtent;
  124. Win::GetTextExtentPoint32(hdc, text, textExtent);
  125. Win::ReleaseDC(button, hdc);
  126. // add a bit of whitespace to the button label
  127. // NTRAID#NTBUG9-40855-2001/02/28-sburns
  128. textExtent.cx += 40;
  129. RECT dialogRect;
  130. hr = Win::GetClientRect(hwnd, dialogRect);
  131. ASSERT(SUCCEEDED(hr));
  132. Win::MoveWindow(
  133. button,
  134. dialogRect.left
  135. + (dialogRect.right - dialogRect.left - textExtent.cx)
  136. / 2,
  137. buttonRect.top,
  138. textExtent.cx,
  139. buttonRect.bottom - buttonRect.top,
  140. true);
  141. // display the button only after we have adjusted it's geometry
  142. Win::SetDlgItemText(hwnd, IDC_BUTTON, text);
  143. Win::ShowWindow(button, SW_SHOW);
  144. Win::EnableWindow(button, true);
  145. }
  146. void
  147. ProgressDialog::OnDestroy()
  148. {
  149. LOG_FUNCTION(ProgressDialog::OnDestroy);
  150. // we don't delete things here, as a WM_DESTROY message may never be sent
  151. }
  152. void
  153. ProgressDialog::OnInit()
  154. {
  155. LOG_FUNCTION(ProgressDialog::OnInit);
  156. Win::Animate_Open(
  157. Win::GetDlgItem(hwnd, IDC_ANIMATION),
  158. MAKEINTRESOURCE(animationResId));
  159. UpdateText(String());
  160. UpdateButton(String());
  161. // deleted in the dtor, not in the wrapperThreadProc, in case the
  162. // wrapperThreadProc terminates abnormally.
  163. threadParams = new WrapperThreadProcParams;
  164. threadParams->dialog = this;
  165. threadParams->realProc = threadProc;
  166. _beginthread(wrapperThreadProc, 0, threadParams);
  167. }
  168. bool
  169. ProgressDialog::OnCommand(
  170. HWND windowFrom,
  171. unsigned controlIDFrom,
  172. unsigned code)
  173. {
  174. if (code == BN_CLICKED)
  175. {
  176. switch (controlIDFrom)
  177. {
  178. case IDC_BUTTON:
  179. {
  180. LOG(L"ProgressDialog::OnCommand -- cancel button pressed");
  181. // Since the response to the button press may be some time
  182. // coming, disable the button to prevent the user from pressing
  183. // it over and over in a frantic panic.
  184. Win::EnableWindow(windowFrom, false);
  185. Win::SetEvent(buttonEventHandle);
  186. break;
  187. }
  188. default:
  189. {
  190. // do nothing
  191. }
  192. }
  193. }
  194. return false;
  195. }
  196. bool
  197. ProgressDialog::OnMessage(
  198. UINT message,
  199. WPARAM /* wparam */ ,
  200. LPARAM /* lparam */ )
  201. {
  202. // LOG_FUNCTION(ProgressDialog::OnMessage);
  203. switch (message)
  204. {
  205. case THREAD_SUCCEEDED:
  206. {
  207. Win::Animate_Stop(Win::GetDlgItem(hwnd, IDC_ANIMATION));
  208. UpdateText(String::load(IDS_OPERATION_DONE));
  209. HRESULT unused = Win::EndDialog(hwnd, THREAD_SUCCEEDED);
  210. ASSERT(SUCCEEDED(unused));
  211. return true;
  212. }
  213. case THREAD_FAILED:
  214. {
  215. Win::Animate_Stop(Win::GetDlgItem(hwnd, IDC_ANIMATION));
  216. UpdateText(String::load(IDS_OPERATION_TERMINATED));
  217. HRESULT unused = Win::EndDialog(hwnd, THREAD_FAILED);
  218. ASSERT(SUCCEEDED(unused));
  219. return true;
  220. }
  221. default:
  222. {
  223. // do nothing
  224. break;
  225. }
  226. }
  227. return false;
  228. }
  229. ProgressDialog::WaitCode
  230. ProgressDialog::WaitForButton(int timeoutMillis)
  231. {
  232. // LOG_FUNCTION(ProgressDialog::WaitForButton);
  233. DWORD result = WAIT_FAILED;
  234. HRESULT hr =
  235. Win::WaitForSingleObject(buttonEventHandle, timeoutMillis, result);
  236. ASSERT(SUCCEEDED(hr));
  237. switch (result)
  238. {
  239. case WAIT_OBJECT_0:
  240. {
  241. return PRESSED;
  242. }
  243. case WAIT_TIMEOUT:
  244. {
  245. return TIMEOUT;
  246. }
  247. case WAIT_FAILED:
  248. {
  249. // we squeltch the failure, and equate it to timeout
  250. // fall thru
  251. }
  252. default:
  253. {
  254. ASSERT(false);
  255. }
  256. }
  257. return TIMEOUT;
  258. }