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.

575 lines
17 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 2000
  4. *
  5. * TITLE: PROGDLG.CPP
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: ShaunIv
  10. *
  11. * DATE: 5/2/2000
  12. *
  13. * DESCRIPTION: Generic WIA progress dialog
  14. *
  15. *******************************************************************************/
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. #include "wiadefui.h"
  19. #include "wiauiext.h"
  20. #include "simrect.h"
  21. #include "movewnd.h"
  22. #include "dlgunits.h"
  23. //
  24. // Private window messages
  25. //
  26. #define PDM_SHOW (WM_USER+1)
  27. #define PDM_GETCANCELSTATE (WM_USER+2)
  28. #define PDM_SETTITLE (WM_USER+3)
  29. #define PDM_SETMESSAGE (WM_USER+4)
  30. #define PDM_SETPERCENT (WM_USER+5)
  31. #define PDM_CLOSE (WM_USER+6)
  32. class CProgressDialog
  33. {
  34. public:
  35. struct CData
  36. {
  37. LONG lFlags;
  38. HWND hwndParent;
  39. };
  40. private:
  41. HWND m_hWnd;
  42. bool m_bCancelled;
  43. private:
  44. //
  45. // Not implemented
  46. //
  47. CProgressDialog( const CProgressDialog & );
  48. CProgressDialog(void);
  49. CProgressDialog &operator=( const CProgressDialog & );
  50. private:
  51. //
  52. // Sole constructor
  53. //
  54. explicit CProgressDialog( HWND hWnd )
  55. : m_hWnd(hWnd),
  56. m_bCancelled(false)
  57. {
  58. }
  59. ~CProgressDialog(void)
  60. {
  61. m_hWnd = NULL;
  62. }
  63. LRESULT OnInitDialog( WPARAM, LPARAM lParam )
  64. {
  65. //
  66. // Prevent the animation control from starting up a new thread to play the AVI by setting the ACS_TIMER style
  67. //
  68. SetWindowLong( GetDlgItem( m_hWnd, IDC_PROGRESS_ANIMATION ), GWL_STYLE, ACS_TIMER | GetWindowLong( GetDlgItem( m_hWnd, IDC_PROGRESS_ANIMATION ), GWL_STYLE ) );
  69. //
  70. // Set up the progress control
  71. //
  72. SendDlgItemMessage( m_hWnd, IDC_PROGRESS_PERCENT, PBM_SETRANGE, 0, MAKELPARAM(0,100) );
  73. //
  74. // Get the data for this dialog
  75. //
  76. CData *pData = reinterpret_cast<CData*>(lParam);
  77. if (pData)
  78. {
  79. //
  80. // The number of pixels to shrink the progress dialog if we hide any controls
  81. //
  82. int nDeltaY = 0;
  83. //
  84. // Calculate the dialog units settings for this dialog
  85. //
  86. CDialogUnits DialogUnits(m_hWnd);
  87. //
  88. // Hide the progress control if requested
  89. //
  90. if (WIA_PROGRESSDLG_NO_PROGRESS & pData->lFlags)
  91. {
  92. EnableWindow( GetDlgItem( m_hWnd, IDC_PROGRESS_PERCENT ), FALSE );
  93. ShowWindow( GetDlgItem( m_hWnd, IDC_PROGRESS_PERCENT ), SW_HIDE );
  94. CSimpleRect rcPercentWindow( GetDlgItem( m_hWnd, IDC_PROGRESS_PERCENT ), CSimpleRect::WindowRect );
  95. CMoveWindow mw;
  96. mw.Move( GetDlgItem( m_hWnd, IDCANCEL ),
  97. 0,
  98. CSimpleRect(GetDlgItem( m_hWnd, IDCANCEL ), CSimpleRect::WindowRect ).ScreenToClient(m_hWnd).top - rcPercentWindow.Height() - DialogUnits.Y(3),
  99. CMoveWindow::NO_MOVEX );
  100. nDeltaY += rcPercentWindow.Height() + DialogUnits.Y(3);
  101. }
  102. //
  103. // If we are to hide the cancel button, hide it and disable closing the dialog from the system menu
  104. //
  105. if (WIA_PROGRESSDLG_NO_CANCEL & pData->lFlags)
  106. {
  107. EnableWindow( GetDlgItem( m_hWnd, IDCANCEL ), FALSE );
  108. ShowWindow( GetDlgItem( m_hWnd, IDCANCEL ), SW_HIDE );
  109. HMENU hSystemMenu = GetSystemMenu(m_hWnd,FALSE);
  110. if (hSystemMenu)
  111. {
  112. EnableMenuItem( hSystemMenu, SC_CLOSE, MF_GRAYED|MF_BYCOMMAND );
  113. }
  114. nDeltaY += CSimpleRect( GetDlgItem( m_hWnd, IDCANCEL ), CSimpleRect::WindowRect ).Height() + DialogUnits.Y(7);
  115. }
  116. //
  117. // Assume we'll be hiding the animation
  118. //
  119. bool bHideAviControl = true;
  120. if ((WIA_PROGRESSDLG_NO_ANIM & pData->lFlags) == 0)
  121. {
  122. //
  123. // Set up the relationship between animation flags and resource IDs
  124. //
  125. static const struct
  126. {
  127. LONG nFlag;
  128. int nResourceId;
  129. }
  130. s_AnimationResources[] =
  131. {
  132. { WIA_PROGRESSDLG_ANIM_SCANNER_COMMUNICATE, IDA_PROGDLG_SCANNER_COMMUNICATE },
  133. { WIA_PROGRESSDLG_ANIM_CAMERA_COMMUNICATE, IDA_PROGDLG_CAMERA_COMMUNICATE },
  134. { WIA_PROGRESSDLG_ANIM_VIDEO_COMMUNICATE, IDA_PROGDLG_VIDEO_COMMUNICATE },
  135. { WIA_PROGRESSDLG_ANIM_SCANNER_ACQUIRE, IDA_PROGDLG_SCANNER_ACQUIRE },
  136. { WIA_PROGRESSDLG_ANIM_CAMERA_ACQUIRE, IDA_PROGDLG_CAMERA_ACQUIRE },
  137. { WIA_PROGRESSDLG_ANIM_VIDEO_ACQUIRE, IDA_PROGDLG_VIDEO_ACQUIRE },
  138. { WIA_PROGRESSDLG_ANIM_DEFAULT_COMMUNICATE, IDA_PROGDLG_DEFAULT_COMMUNICATE },
  139. };
  140. //
  141. // Assume we won't find an animation
  142. //
  143. int nAnimationResourceId = 0;
  144. //
  145. // Find the first animation for which we have a match
  146. //
  147. for (int i=0;i<ARRAYSIZE(s_AnimationResources);i++)
  148. {
  149. if (s_AnimationResources[i].nFlag & pData->lFlags)
  150. {
  151. nAnimationResourceId = s_AnimationResources[i].nResourceId;
  152. break;
  153. }
  154. }
  155. //
  156. // If we found an animation flag and we are able to open the animation, play it and don't hide the control
  157. //
  158. if (nAnimationResourceId && Animate_OpenEx( GetDlgItem(m_hWnd,IDC_PROGRESS_ANIMATION), g_hInstance, MAKEINTRESOURCE(nAnimationResourceId)))
  159. {
  160. bHideAviControl = false;
  161. Animate_Play( GetDlgItem(m_hWnd,IDC_PROGRESS_ANIMATION), 0, -1, -1 );
  162. }
  163. }
  164. //
  165. // If we need to hide the animation control, do so, and move all of the other controls up
  166. //
  167. if (bHideAviControl)
  168. {
  169. EnableWindow( GetDlgItem( m_hWnd, IDC_PROGRESS_ANIMATION ), FALSE );
  170. ShowWindow( GetDlgItem( m_hWnd, IDC_PROGRESS_ANIMATION ), SW_HIDE );
  171. CSimpleRect rcAnimWindow( GetDlgItem( m_hWnd, IDC_PROGRESS_ANIMATION ), CSimpleRect::WindowRect );
  172. CMoveWindow mw;
  173. mw.Move( GetDlgItem( m_hWnd, IDC_PROGRESS_MESSAGE ),
  174. 0,
  175. CSimpleRect(GetDlgItem( m_hWnd, IDC_PROGRESS_MESSAGE ), CSimpleRect::WindowRect ).ScreenToClient(m_hWnd).top - rcAnimWindow.Height() - DialogUnits.Y(7),
  176. CMoveWindow::NO_MOVEX );
  177. mw.Move( GetDlgItem( m_hWnd, IDC_PROGRESS_PERCENT ),
  178. 0,
  179. CSimpleRect(GetDlgItem( m_hWnd, IDC_PROGRESS_PERCENT ), CSimpleRect::WindowRect ).ScreenToClient(m_hWnd).top - rcAnimWindow.Height() - DialogUnits.Y(7),
  180. CMoveWindow::NO_MOVEX );
  181. mw.Move( GetDlgItem( m_hWnd, IDCANCEL ),
  182. 0,
  183. CSimpleRect(GetDlgItem( m_hWnd, IDCANCEL ), CSimpleRect::WindowRect ).ScreenToClient(m_hWnd).top - rcAnimWindow.Height() - DialogUnits.Y(7),
  184. CMoveWindow::NO_MOVEX );
  185. nDeltaY += rcAnimWindow.Height() + DialogUnits.Y(7);
  186. }
  187. //
  188. // Resize the dialog in case we hid any controls
  189. //
  190. CMoveWindow().Size( m_hWnd, 0, CSimpleRect( m_hWnd, CSimpleRect::WindowRect ).Height() - nDeltaY, CMoveWindow::NO_SIZEX );
  191. //
  192. // Center the dialog on the parent
  193. //
  194. WiaUiUtil::CenterWindow( m_hWnd, pData->hwndParent );
  195. }
  196. return 0;
  197. }
  198. LRESULT OnDestroy( WPARAM, LPARAM )
  199. {
  200. //
  201. // Cause the thread to exit
  202. //
  203. PostQuitMessage(0);
  204. return 0;
  205. }
  206. void OnCancel( WPARAM, LPARAM )
  207. {
  208. if (!m_bCancelled)
  209. {
  210. m_bCancelled = true;
  211. //
  212. // Tell the user to wait. It could take a while for the caller to check the cancelled flag.
  213. //
  214. CSimpleString( IDS_PROGRESS_WAIT, g_hInstance ).SetWindowText( GetDlgItem( m_hWnd, IDCANCEL ) );
  215. }
  216. }
  217. LRESULT OnCommand( WPARAM wParam, LPARAM lParam )
  218. {
  219. SC_BEGIN_COMMAND_HANDLERS()
  220. {
  221. SC_HANDLE_COMMAND(IDCANCEL,OnCancel);
  222. }
  223. SC_END_COMMAND_HANDLERS();
  224. }
  225. LRESULT OnShow( WPARAM wParam, LPARAM lParam )
  226. {
  227. ShowWindow( m_hWnd, wParam ? SW_SHOW : SW_HIDE );
  228. return 0;
  229. }
  230. LRESULT OnGetCancelState( WPARAM wParam, LPARAM lParam )
  231. {
  232. return (m_bCancelled != false);
  233. }
  234. LRESULT OnSetTitle( WPARAM wParam, LPARAM lParam )
  235. {
  236. CSimpleStringConvert::NaturalString(CSimpleStringWide(reinterpret_cast<LPCTSTR>(lParam))).SetWindowText(m_hWnd);
  237. return 0;
  238. }
  239. LRESULT OnSetMessage( WPARAM wParam, LPARAM lParam )
  240. {
  241. CSimpleStringConvert::NaturalString(CSimpleStringWide(reinterpret_cast<LPCTSTR>(lParam))).SetWindowText(GetDlgItem(m_hWnd,IDC_PROGRESS_MESSAGE));
  242. return 0;
  243. }
  244. LRESULT OnSetPercent( WPARAM wParam, LPARAM lParam )
  245. {
  246. SendDlgItemMessage( m_hWnd, IDC_PROGRESS_PERCENT, PBM_SETPOS, lParam, 0 );
  247. return 0;
  248. }
  249. LRESULT OnClose( WPARAM wParam, LPARAM lParam )
  250. {
  251. DestroyWindow(m_hWnd);
  252. return 0;
  253. }
  254. public:
  255. static INT_PTR DialogProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  256. {
  257. SC_BEGIN_DIALOG_MESSAGE_HANDLERS(CProgressDialog)
  258. {
  259. SC_HANDLE_DIALOG_MESSAGE( WM_INITDIALOG, OnInitDialog );
  260. SC_HANDLE_DIALOG_MESSAGE( WM_DESTROY, OnDestroy );
  261. SC_HANDLE_DIALOG_MESSAGE( WM_COMMAND, OnCommand );
  262. SC_HANDLE_DIALOG_MESSAGE( PDM_SHOW, OnShow );
  263. SC_HANDLE_DIALOG_MESSAGE( PDM_GETCANCELSTATE, OnGetCancelState );
  264. SC_HANDLE_DIALOG_MESSAGE( PDM_SETTITLE, OnSetTitle );
  265. SC_HANDLE_DIALOG_MESSAGE( PDM_SETMESSAGE, OnSetMessage );
  266. SC_HANDLE_DIALOG_MESSAGE( PDM_SETPERCENT, OnSetPercent );
  267. SC_HANDLE_DIALOG_MESSAGE( PDM_CLOSE, OnClose );
  268. }
  269. SC_END_DIALOG_MESSAGE_HANDLERS();
  270. }
  271. };
  272. class CProgressDialogThread
  273. {
  274. private:
  275. HWND m_hwndParent;
  276. LONG m_lFlags;
  277. HANDLE m_hCreationEvent;
  278. HWND *m_phwndDialog;
  279. private:
  280. //
  281. // Not implemented
  282. //
  283. CProgressDialogThread(void);
  284. CProgressDialogThread( const CProgressDialogThread & );
  285. CProgressDialogThread &operator=( const CProgressDialogThread & );
  286. private:
  287. //
  288. // Sole constructor
  289. //
  290. CProgressDialogThread( HWND hwndParent, LONG lFlags, HANDLE hCreationEvent, HWND *phwndDialog )
  291. : m_hwndParent(hwndParent),
  292. m_lFlags(lFlags),
  293. m_hCreationEvent(hCreationEvent),
  294. m_phwndDialog(phwndDialog)
  295. {
  296. }
  297. ~CProgressDialogThread(void)
  298. {
  299. m_hwndParent = NULL;
  300. m_hCreationEvent = NULL;
  301. m_phwndDialog = NULL;
  302. }
  303. void Run(void)
  304. {
  305. //
  306. // Make sure we have valid thread data
  307. //
  308. if (m_phwndDialog && m_hCreationEvent)
  309. {
  310. //
  311. // Prepare the dialog data
  312. //
  313. CProgressDialog::CData Data;
  314. Data.lFlags = m_lFlags;
  315. Data.hwndParent = m_hwndParent;
  316. //
  317. // Decide which dialog resource to use
  318. //
  319. int nDialogResId = IDD_PROGRESS_DIALOG;
  320. if (m_lFlags & WIA_PROGRESSDLG_NO_TITLE)
  321. {
  322. nDialogResId = IDD_PROGRESS_DIALOG_NO_TITLE;
  323. }
  324. //
  325. // Create the dialog
  326. //
  327. HWND hwndDialog = CreateDialogParam( g_hInstance, MAKEINTRESOURCE(nDialogResId), NULL, CProgressDialog::DialogProc, reinterpret_cast<LPARAM>(&Data) );
  328. //
  329. // Store the dialog's HWND in the HWND ptr and set the creation event, to give the calling thread a window handle
  330. //
  331. *m_phwndDialog = hwndDialog;
  332. SetEvent(m_hCreationEvent);
  333. //
  334. // Start up our message loop
  335. //
  336. if (hwndDialog)
  337. {
  338. MSG msg;
  339. while (GetMessage(&msg,NULL,0,0))
  340. {
  341. if (!IsDialogMessage(hwndDialog,&msg))
  342. {
  343. TranslateMessage(&msg);
  344. DispatchMessage(&msg);
  345. }
  346. }
  347. //
  348. // If we have a parent, bring it to the foreground
  349. //
  350. if (m_hwndParent)
  351. {
  352. SetForegroundWindow(m_hwndParent);
  353. }
  354. }
  355. }
  356. }
  357. static DWORD ThreadProc( PVOID pvParam )
  358. {
  359. CProgressDialogThread *pProgressDialogThread = reinterpret_cast<CProgressDialogThread*>(pvParam);
  360. if (pProgressDialogThread)
  361. {
  362. pProgressDialogThread->Run();
  363. delete pProgressDialogThread;
  364. }
  365. //
  366. // Just before we quit, decrement the module refcount
  367. //
  368. DllRelease();
  369. return 0;
  370. }
  371. public:
  372. static HWND Create( HWND hWndParent, LONG lFlags )
  373. {
  374. //
  375. // Assume failure
  376. //
  377. HWND hwndResult = NULL;
  378. //
  379. // Create an event that will allow us to synchronize initialization of the HWND
  380. //
  381. HANDLE hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  382. if (hEvent)
  383. {
  384. //
  385. // Create the progress dialog thread data
  386. //
  387. CProgressDialogThread *pProgressDialogThread = new CProgressDialogThread( hWndParent, lFlags, hEvent, &hwndResult );
  388. if (pProgressDialogThread)
  389. {
  390. //
  391. // Increment the global refcount, so this DLL can't be released until we decrement
  392. //
  393. DllAddRef();
  394. //
  395. // Create the thread, passing the thread class as the thread data
  396. //
  397. DWORD dwThreadId;
  398. HANDLE hThread = CreateThread( NULL, 0, ThreadProc, pProgressDialogThread, 0, &dwThreadId );
  399. if (hThread)
  400. {
  401. //
  402. // Wait until the dialog is created
  403. //
  404. WiaUiUtil::MsgWaitForSingleObject( hEvent, INFINITE );
  405. if (hwndResult)
  406. {
  407. //
  408. // Make the dialog active
  409. //
  410. SetForegroundWindow(hwndResult);
  411. }
  412. //
  413. // Done with this handle
  414. //
  415. CloseHandle(hThread);
  416. }
  417. else
  418. {
  419. //
  420. // If we were unable to create the thread, decrement the module refcount
  421. //
  422. DllRelease();
  423. }
  424. }
  425. //
  426. // Done with this handle
  427. //
  428. CloseHandle(hEvent);
  429. }
  430. //
  431. // If hwndResult is non-NULL, we succeeded
  432. //
  433. return hwndResult;
  434. }
  435. };
  436. // *** IWiaProgressDialog methods ***
  437. STDMETHODIMP CWiaDefaultUI::Create( HWND hwndParent, LONG lFlags )
  438. {
  439. m_hWndProgress = CProgressDialogThread::Create(hwndParent,lFlags);
  440. return m_hWndProgress ? S_OK : E_FAIL;
  441. }
  442. STDMETHODIMP CWiaDefaultUI::Show(void)
  443. {
  444. if (!m_hWndProgress)
  445. {
  446. return E_FAIL;
  447. }
  448. SendMessage(m_hWndProgress,PDM_SHOW,1,0);
  449. return S_OK;
  450. }
  451. STDMETHODIMP CWiaDefaultUI::Hide(void)
  452. {
  453. if (!m_hWndProgress)
  454. {
  455. return E_FAIL;
  456. }
  457. SendMessage(m_hWndProgress,PDM_SHOW,0,0);
  458. return S_OK;
  459. }
  460. STDMETHODIMP CWiaDefaultUI::Cancelled( BOOL *pbCancelled )
  461. {
  462. if (!pbCancelled)
  463. {
  464. return E_POINTER;
  465. }
  466. if (!m_hWndProgress)
  467. {
  468. return E_FAIL;
  469. }
  470. *pbCancelled = (SendMessage(m_hWndProgress,PDM_GETCANCELSTATE,0,0) != 0);
  471. return S_OK;
  472. }
  473. STDMETHODIMP CWiaDefaultUI::SetTitle( LPCWSTR pszTitle )
  474. {
  475. if (!pszTitle)
  476. {
  477. return E_POINTER;
  478. }
  479. if (!m_hWndProgress)
  480. {
  481. return E_FAIL;
  482. }
  483. SendMessage(m_hWndProgress,PDM_SETTITLE,0,reinterpret_cast<LPARAM>(pszTitle));
  484. return S_OK;
  485. }
  486. STDMETHODIMP CWiaDefaultUI::SetMessage( LPCWSTR pszMessage )
  487. {
  488. if (!pszMessage)
  489. {
  490. return E_POINTER;
  491. }
  492. if (!m_hWndProgress)
  493. {
  494. return E_FAIL;
  495. }
  496. SendMessage(m_hWndProgress,PDM_SETMESSAGE,0,reinterpret_cast<LPARAM>(pszMessage));
  497. return S_OK;
  498. }
  499. STDMETHODIMP CWiaDefaultUI::SetPercentComplete( UINT nPercent )
  500. {
  501. if (!m_hWndProgress)
  502. {
  503. return E_FAIL;
  504. }
  505. SendMessage(m_hWndProgress,PDM_SETPERCENT,0,nPercent);
  506. return S_OK;
  507. }
  508. STDMETHODIMP CWiaDefaultUI::Destroy(void)
  509. {
  510. if (!m_hWndProgress)
  511. {
  512. return E_FAIL;
  513. }
  514. SendMessage(m_hWndProgress,PDM_CLOSE,0,0);
  515. m_hWndProgress = NULL;
  516. return S_OK;
  517. }