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.

414 lines
10 KiB

  1. /*****************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 1999 - 2001
  4. *
  5. * TITLE: preview.cpp
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: RickTu
  10. *
  11. * DATE: 10/30/99
  12. *
  13. * DESCRIPTION: Implements preview class for directshow devices in WIA
  14. *
  15. *****************************************************************************/
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. VOID CALLBACK PreviewTimerProc( HWND hDlg, UINT uMsg, UINT_PTR idEvent, DWORD dwTime )
  19. {
  20. switch (idEvent)
  21. {
  22. case TIMER_CLOSE_DIALOG:
  23. WIA_TRACE((TEXT("PreviewTimerProc -- got TIMER_CLOSE_DIALOG")));
  24. EndDialog( hDlg, -2 );
  25. break;
  26. }
  27. }
  28. /*****************************************************************************
  29. PreviewDialogProc
  30. Dialog proc for preview dialog.
  31. *****************************************************************************/
  32. INT_PTR CALLBACK PreviewDialogProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
  33. {
  34. switch (uMsg)
  35. {
  36. case WM_INITDIALOG:
  37. {
  38. WIA_TRACE((TEXT("PreviewDialogProc -- WM_INITDIALOG")));
  39. SetTimer( hDlg, TIMER_CLOSE_DIALOG, 30000, PreviewTimerProc );
  40. PREVIEW_INFO_STRUCT * ppis = reinterpret_cast<PREVIEW_INFO_STRUCT *>(lParam);
  41. if (ppis)
  42. {
  43. ppis->hDlg = hDlg;
  44. if (ppis->hEvent)
  45. {
  46. SetEvent( ppis->hEvent );
  47. }
  48. }
  49. }
  50. return TRUE;
  51. case PM_GOAWAY:
  52. WIA_TRACE((TEXT("PreviewDialogProc -- PM_GOAWAY")));
  53. EndDialog( hDlg, 0 );
  54. return TRUE;
  55. }
  56. return FALSE;
  57. }
  58. /*****************************************************************************
  59. PreviewThreadProc
  60. We spin a thread to put up the status dialog
  61. *****************************************************************************/
  62. DWORD WINAPI PreviewThreadProc( LPVOID lpv )
  63. {
  64. INT_PTR iRes;
  65. WIA_TRACE((TEXT("PreviewThreadProc enter")));
  66. iRes = DialogBoxParam( _Module.m_hInst,
  67. MAKEINTRESOURCE(IDD_INIT_DEVICE),
  68. NULL,
  69. PreviewDialogProc,
  70. reinterpret_cast<LPARAM>(lpv)
  71. );
  72. WIA_TRACE((TEXT("IDD_INIT_DEVICE dialog returned %d"),iRes));
  73. #ifdef DEBUG
  74. if (iRes==-1)
  75. {
  76. WIA_ERROR((TEXT("DialogBoxParam failed w/GLE = %d"),GetLastError()));
  77. }
  78. #endif
  79. if (iRes < 0)
  80. {
  81. PREVIEW_INFO_STRUCT * ppis = reinterpret_cast<PREVIEW_INFO_STRUCT *>(lpv);
  82. if (ppis && ppis->hEvent)
  83. {
  84. SetEvent( ppis->hEvent );
  85. }
  86. }
  87. WIA_TRACE((TEXT("PreviewThreadProc exit")));
  88. return 0;
  89. }
  90. /*****************************************************************************
  91. CVideoPreview::Device
  92. Hand us a device pointer for the camera (or DS device) we're connected to.
  93. *****************************************************************************/
  94. STDMETHODIMP
  95. CVideoPreview::Device(IUnknown * pDevice)
  96. {
  97. HRESULT hr = S_OK;
  98. WIA_PUSHFUNCTION((TEXT("CVideoPreview::Device")));
  99. // Create the WiaVideo object
  100. hr = CoCreateInstance(CLSID_WiaVideo, NULL, CLSCTX_INPROC_SERVER,
  101. IID_IWiaVideo, (LPVOID *)&m_pWiaVideo);
  102. WIA_CHECK_HR(hr,"CoCreateInstance( WiaVideo )");
  103. m_pDevice = pDevice;
  104. // if we've already been created, redo everything
  105. if (m_bCreated)
  106. {
  107. BOOL bDummy;
  108. OnCreate(WM_CREATE, 0, 0, bDummy);
  109. }
  110. return hr;
  111. }
  112. /*****************************************************************************
  113. CVideoPreview::InPlaceDeactivate
  114. Trap in place deactivate so we can unhook the dshow preview window from
  115. ours before both are destroyed.
  116. *****************************************************************************/
  117. STDMETHODIMP
  118. CVideoPreview::InPlaceDeactivate()
  119. {
  120. HRESULT hr = E_FAIL;
  121. WIA_PUSHFUNCTION((TEXT("CVideoPreview::InPlaceDeactivate")));
  122. //
  123. // Make sure we have a pointer to the device...
  124. //
  125. if (m_pWiaVideo.p)
  126. {
  127. //
  128. // Tell the device to close the graph
  129. //
  130. m_pWiaVideo->DestroyVideo();
  131. m_pWiaVideo = NULL;
  132. }
  133. else
  134. {
  135. WIA_ERROR((TEXT("m_pWiaVideo is NULL")));
  136. }
  137. //
  138. // Always return S_OK so that InPlaceDeactivate happens.
  139. //
  140. return S_OK;
  141. }
  142. /*****************************************************************************
  143. CVideoPreview::OnSize
  144. Called when our window is resized. We want to let the streaming
  145. preview know we've been resized so it can reposition itself accordingly.
  146. *****************************************************************************/
  147. LRESULT
  148. CVideoPreview::OnSize(UINT , WPARAM , LPARAM lParam, BOOL& )
  149. {
  150. WIA_PUSHFUNCTION((TEXT("CVideoPreview::OnSize")));
  151. if (m_pWiaVideo)
  152. {
  153. m_pWiaVideo->ResizeVideo(FALSE);
  154. }
  155. else
  156. {
  157. WIA_ERROR((TEXT("m_pWiaVideo is NULL!")));
  158. }
  159. return 0;
  160. }
  161. LRESULT
  162. CVideoPreview::OnCreate(UINT uMsg, WPARAM wp, LPARAM lp, BOOL &bHandled)
  163. {
  164. HRESULT hr = S_OK;
  165. WIA_PUSHFUNCTION(TEXT("CVideoPreview::OnCreate"));
  166. WIA_ASSERT(::IsWindow(m_hWnd));
  167. if (m_pDevice.p && m_pWiaVideo.p)
  168. {
  169. HANDLE hThread = NULL;
  170. DWORD dwId = 0;
  171. PREVIEW_INFO_STRUCT pis;
  172. //
  173. // Creating the graph can be quite time consuming, so put up
  174. // a dialog if it takes more than a couple of seconds. We start
  175. // a thread so that the UI doesn't hang, and that thread
  176. // puts up UI saying the device may take a while to initialize.
  177. //
  178. pis.hDlg = NULL;
  179. pis.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  180. hThread = CreateThread( NULL, 0, PreviewThreadProc, reinterpret_cast<LPVOID>(&pis), 0, &dwId );
  181. //
  182. // Tell the device to build the DShow graph
  183. //
  184. BOOL bSuccess = TRUE;
  185. HWND hwndFore = ::GetForegroundWindow();
  186. HWND hwndFocus = ::GetFocus();
  187. CSimpleString strDeviceID;
  188. CSimpleString strImagesDirectory;
  189. CComQIPtr<IWiaItem, &IID_IWiaItem> pRootDevice(m_pDevice);
  190. if (pRootDevice == NULL)
  191. {
  192. hr = E_FAIL;
  193. bSuccess = FALSE;
  194. }
  195. //
  196. // Get the WIA Device ID
  197. //
  198. if (bSuccess)
  199. {
  200. bSuccess = PropStorageHelpers::GetProperty(pRootDevice,
  201. WIA_DIP_DEV_ID,
  202. strDeviceID);
  203. }
  204. //
  205. // Get the directory the images will be stored in.
  206. //
  207. if (bSuccess)
  208. {
  209. bSuccess = PropStorageHelpers::GetProperty(pRootDevice,
  210. WIA_DPV_IMAGES_DIRECTORY,
  211. strImagesDirectory);
  212. }
  213. //
  214. // Create the Video if it isn't already created.
  215. if (bSuccess)
  216. {
  217. if (hr == S_OK)
  218. {
  219. WIAVIDEO_STATE VideoState = WIAVIDEO_NO_VIDEO;
  220. //
  221. // Get the current state of the WiaVideo object. If we
  222. // just created it then the state will be NO_VIDEO,
  223. // otherwise, it could already be previewing video,
  224. // in which case we shouldn't do anything.
  225. //
  226. hr = m_pWiaVideo->GetCurrentState(&VideoState);
  227. if (VideoState == WIAVIDEO_NO_VIDEO)
  228. {
  229. //
  230. // Set the directory we want to save our images to.
  231. // We got the image directory from the Wia Video Driver
  232. // IMAGES_DIRECTORY property
  233. //
  234. if (hr == S_OK)
  235. {
  236. hr = m_pWiaVideo->put_ImagesDirectory(CSimpleBStr(strImagesDirectory));
  237. }
  238. //
  239. // Create the video preview as a child of the hwnd
  240. // and automatically begin playback after creating the preview.
  241. //
  242. if (hr == S_OK)
  243. {
  244. hr = m_pWiaVideo->CreateVideoByWiaDevID(CSimpleBStr(strDeviceID),
  245. m_hWnd,
  246. FALSE,
  247. TRUE);
  248. }
  249. }
  250. }
  251. }
  252. if (!bSuccess)
  253. {
  254. hr = E_FAIL;
  255. }
  256. if (FAILED(hr))
  257. {
  258. //
  259. // Let the user know that the graph is most likely already
  260. // in use...
  261. //
  262. ::MessageBox( NULL,
  263. CSimpleString(IDS_VIDEO_BUSY_TEXT, _Module.m_hInst),
  264. CSimpleString(IDS_VIDEO_BUSY_TITLE, _Module.m_hInst ),
  265. MB_OK | MB_ICONWARNING | MB_TOPMOST | MB_SETFOREGROUND
  266. );
  267. }
  268. //
  269. // Restore foreground window & focus, as it seems the
  270. // active movie window does not preserve these things...
  271. //
  272. if (hwndFore)
  273. {
  274. ::SetForegroundWindow( hwndFore );
  275. }
  276. if (hwndFocus)
  277. {
  278. ::SetFocus(hwndFocus);
  279. }
  280. //
  281. // Tell the dialog to go away
  282. //
  283. if (hThread)
  284. {
  285. if (pis.hEvent)
  286. {
  287. //
  288. // Wait for 45 seconds
  289. //
  290. WaitForSingleObject( pis.hEvent, 45 * 1000 );
  291. if (pis.hDlg)
  292. {
  293. ::PostMessage( pis.hDlg, PM_GOAWAY, 0, 0 );
  294. }
  295. CloseHandle( pis.hEvent );
  296. pis.hEvent = NULL;
  297. }
  298. CloseHandle( hThread );
  299. hThread = NULL;
  300. }
  301. }
  302. bHandled = TRUE;
  303. m_bCreated = TRUE;
  304. return 0;
  305. }
  306. LRESULT
  307. CVideoPreview::OnEraseBkgnd(UINT uMsg, WPARAM wp, LPARAM lp, BOOL &bHandled)
  308. {
  309. HDC hdc = (HDC)wp;
  310. RECT rc;
  311. GetClientRect(&rc);
  312. SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  313. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  314. bHandled = TRUE;
  315. return TRUE;
  316. }