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.

409 lines
8.8 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. // REVIEWED-2002/02/26-sburns correct byte count passed
  50. ::ZeroMemory(&wndclass, sizeof wndclass);
  51. static const wchar_t* DIALOG_WINDOW_CLASS_NAME = L"#32770";
  52. HRESULT hr = Win::GetClassInfoEx(DIALOG_WINDOW_CLASS_NAME, wndclass);
  53. ASSERT(SUCCEEDED(hr));
  54. wndclass.lpfnWndProc = ::DefDlgProc;
  55. wndclass.hInstance = Win::GetModuleHandle();
  56. wndclass.lpszClassName = PROGRESS_DIALOG_CLASS_NAME;
  57. hr = Win::LoadCursor(IDC_WAIT, wndclass.hCursor);
  58. ASSERT(SUCCEEDED(hr));
  59. ATOM unused = 0;
  60. hr = Win::RegisterClassEx(wndclass, unused);
  61. ASSERT(SUCCEEDED(hr));
  62. // REVIEWED-2002/02/26-sburns this is an unnamed event, so no squatting
  63. // attack exposure
  64. hr = Win::CreateEvent(0, false, false, buttonEventHandle);
  65. // in the case that the CreateEvent fails (very unlikely), there's not
  66. // much we can do. In this case, the result will be that nothing will
  67. // happen when the user clicks the cancel button.
  68. ASSERT(SUCCEEDED(hr));
  69. }
  70. ProgressDialog::~ProgressDialog()
  71. {
  72. LOG_DTOR(ProgressDialog);
  73. delete threadParams;
  74. Win::UnregisterClass(PROGRESS_DIALOG_CLASS_NAME, Win::GetModuleHandle());
  75. }
  76. void
  77. ProgressDialog::UpdateText(const String& message)
  78. {
  79. LOG_FUNCTION2(ProgressDialog::UpdateText, message);
  80. Win::ShowWindow(
  81. Win::GetDlgItem(hwnd, IDC_MESSAGE),
  82. message.empty() ? SW_HIDE : SW_SHOW);
  83. Win::SetDlgItemText(hwnd, IDC_MESSAGE, message);
  84. }
  85. void
  86. ProgressDialog::UpdateText(int textStringResID)
  87. {
  88. LOG_FUNCTION(ProgressDialog::UpdateText);
  89. ASSERT(textStringResID > 0);
  90. UpdateText(String::load(textStringResID));
  91. }
  92. void
  93. ProgressDialog::UpdateButton(int textStringResID)
  94. {
  95. LOG_FUNCTION(ProgressDialog::UpdateButton);
  96. ASSERT(textStringResID > 0);
  97. UpdateButton(String::load(textStringResID));
  98. }
  99. void
  100. ProgressDialog::UpdateButton(const String& text)
  101. {
  102. LOG_FUNCTION2(ProgressDialog::UpdateButton, text);
  103. HWND button = Win::GetDlgItem(hwnd, IDC_BUTTON);
  104. DWORD waitResult = WAIT_FAILED;
  105. HRESULT hr = Win::WaitForSingleObject(buttonEventHandle, 0, waitResult);
  106. ASSERT(SUCCEEDED(hr));
  107. if (waitResult == WAIT_OBJECT_0)
  108. {
  109. // event is still signalled, so reset it.
  110. Win::ResetEvent(buttonEventHandle);
  111. }
  112. bool empty = text.empty();
  113. // Hide the button before we adjust the geometry. On slow or heavily
  114. // loaded machines, the repaints show a noticable delay that has frightened
  115. // at least one user.
  116. // NTRAID#NTBUG9-353799-2001/04/05-sburns
  117. Win::ShowWindow(button, SW_HIDE);
  118. Win::EnableWindow(button, false);
  119. if (empty)
  120. {
  121. // leave the button hidden and disabled.
  122. return;
  123. }
  124. // resize and recenter the button
  125. RECT buttonRect;
  126. Win::GetWindowRect(button, buttonRect);
  127. Win::ScreenToClient(hwnd, buttonRect);
  128. HDC hdc = GetWindowDC(button);
  129. SIZE textExtent;
  130. Win::GetTextExtentPoint32(hdc, text, textExtent);
  131. Win::ReleaseDC(button, hdc);
  132. // add a bit of whitespace to the button label
  133. // NTRAID#NTBUG9-40855-2001/02/28-sburns
  134. textExtent.cx += 40;
  135. RECT dialogRect;
  136. hr = Win::GetClientRect(hwnd, dialogRect);
  137. ASSERT(SUCCEEDED(hr));
  138. Win::MoveWindow(
  139. button,
  140. dialogRect.left
  141. + (dialogRect.right - dialogRect.left - textExtent.cx)
  142. / 2,
  143. buttonRect.top,
  144. textExtent.cx,
  145. buttonRect.bottom - buttonRect.top,
  146. true);
  147. // display the button only after we have adjusted it's geometry
  148. Win::SetDlgItemText(hwnd, IDC_BUTTON, text);
  149. Win::ShowWindow(button, SW_SHOW);
  150. Win::EnableWindow(button, true);
  151. }
  152. void
  153. ProgressDialog::OnDestroy()
  154. {
  155. LOG_FUNCTION(ProgressDialog::OnDestroy);
  156. // we don't delete things here, as a WM_DESTROY message may never be sent
  157. Win::Animate_Close(Win::GetDlgItem(hwnd, IDC_ANIMATION));
  158. }
  159. void
  160. ProgressDialog::OnInit()
  161. {
  162. LOG_FUNCTION(ProgressDialog::OnInit);
  163. Win::Animate_Open(
  164. Win::GetDlgItem(hwnd, IDC_ANIMATION),
  165. MAKEINTRESOURCE(animationResId));
  166. UpdateText(String());
  167. UpdateButton(String());
  168. // deleted in the dtor, not in the wrapperThreadProc, in case the
  169. // wrapperThreadProc terminates abnormally.
  170. threadParams = new WrapperThreadProcParams;
  171. threadParams->dialog = this;
  172. threadParams->realProc = threadProc;
  173. _beginthread(wrapperThreadProc, 0, threadParams);
  174. }
  175. bool
  176. ProgressDialog::OnCommand(
  177. HWND windowFrom,
  178. unsigned controlIDFrom,
  179. unsigned code)
  180. {
  181. if (code == BN_CLICKED)
  182. {
  183. switch (controlIDFrom)
  184. {
  185. case IDC_BUTTON:
  186. {
  187. LOG(L"ProgressDialog::OnCommand -- cancel button pressed");
  188. // Since the response to the button press may be some time
  189. // coming, disable the button to prevent the user from pressing
  190. // it over and over in a frantic panic.
  191. Win::EnableWindow(windowFrom, false);
  192. Win::SetEvent(buttonEventHandle);
  193. break;
  194. }
  195. default:
  196. {
  197. // do nothing
  198. }
  199. }
  200. }
  201. return false;
  202. }
  203. bool
  204. ProgressDialog::OnMessage(
  205. UINT message,
  206. WPARAM /* wparam */ ,
  207. LPARAM /* lparam */ )
  208. {
  209. // LOG_FUNCTION(ProgressDialog::OnMessage);
  210. switch (message)
  211. {
  212. case THREAD_SUCCEEDED:
  213. {
  214. Win::Animate_Stop(Win::GetDlgItem(hwnd, IDC_ANIMATION));
  215. UpdateText(String::load(IDS_OPERATION_DONE));
  216. HRESULT unused = Win::EndDialog(hwnd, THREAD_SUCCEEDED);
  217. ASSERT(SUCCEEDED(unused));
  218. return true;
  219. }
  220. case THREAD_FAILED:
  221. {
  222. Win::Animate_Stop(Win::GetDlgItem(hwnd, IDC_ANIMATION));
  223. UpdateText(String::load(IDS_OPERATION_TERMINATED));
  224. HRESULT unused = Win::EndDialog(hwnd, THREAD_FAILED);
  225. ASSERT(SUCCEEDED(unused));
  226. return true;
  227. }
  228. default:
  229. {
  230. // do nothing
  231. break;
  232. }
  233. }
  234. return false;
  235. }
  236. ProgressDialog::WaitCode
  237. ProgressDialog::WaitForButton(int timeoutMillis)
  238. {
  239. // LOG_FUNCTION(ProgressDialog::WaitForButton);
  240. DWORD result = WAIT_FAILED;
  241. HRESULT hr =
  242. Win::WaitForSingleObject(buttonEventHandle, timeoutMillis, result);
  243. ASSERT(SUCCEEDED(hr));
  244. switch (result)
  245. {
  246. case WAIT_OBJECT_0:
  247. {
  248. return PRESSED;
  249. }
  250. case WAIT_TIMEOUT:
  251. {
  252. return TIMEOUT;
  253. }
  254. case WAIT_FAILED:
  255. {
  256. // we squeltch the failure, and equate it to timeout
  257. // fall thru
  258. }
  259. default:
  260. {
  261. ASSERT(false);
  262. }
  263. }
  264. return TIMEOUT;
  265. }
  266. void
  267. ProgressDialog::RevertToOriginalAnimation()
  268. {
  269. LOG_FUNCTION(ProgressDialog::RevertToOriginalAnimation);
  270. Win::Animate_Close(Win::GetDlgItem(hwnd, IDC_ANIMATION));
  271. Win::Animate_Open(
  272. Win::GetDlgItem(hwnd, IDC_ANIMATION),
  273. MAKEINTRESOURCE(animationResId));
  274. }
  275. void
  276. ProgressDialog::UpdateAnimation(int newAnimationResId)
  277. {
  278. LOG_FUNCTION(ProgressDialog::UpdateAnimation);
  279. Win::Animate_Close(Win::GetDlgItem(hwnd, IDC_ANIMATION));
  280. Win::Animate_Open(
  281. Win::GetDlgItem(hwnd, IDC_ANIMATION),
  282. MAKEINTRESOURCE(newAnimationResId));
  283. }