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.

665 lines
17 KiB

  1. //==========================================================================;
  2. //
  3. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. // PURPOSE.
  7. //
  8. // Copyright (c) 2001 Microsoft Corporation. All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11. //----------------------------------------------------------------------------
  12. // VMRProp.cpp
  13. //
  14. // Created 3/18/2001
  15. // Author: Steve Rowe [StRowe]
  16. //
  17. //----------------------------------------------------------------------------
  18. #include <windowsx.h>
  19. #include <streams.h>
  20. #include <atlbase.h>
  21. #include <commctrl.h>
  22. #include <stdio.h>
  23. #include <shlobj.h> // for SHGetSpecialFolderPath
  24. #include "resource.h"
  25. #ifdef FILTER_DLL
  26. #include <initguid.h>
  27. #endif
  28. #include "vmrprop.h"
  29. #ifdef FILTER_DLL
  30. STDAPI DllRegisterServer()
  31. {
  32. AMTRACE((TEXT("DllRegisterServer")));
  33. return AMovieDllRegisterServer2( TRUE );
  34. }
  35. STDAPI DllUnregisterServer()
  36. {
  37. AMTRACE((TEXT("DllUnregisterServer")));
  38. return AMovieDllRegisterServer2( FALSE );
  39. }
  40. CFactoryTemplate g_Templates[] = {
  41. {
  42. L"",
  43. &CLSID_VMRFilterConfigProp,
  44. CVMRFilterConfigProp::CreateInstance
  45. }
  46. };
  47. int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
  48. #endif // #ifdef FILTER_DLL
  49. //
  50. // Constructor
  51. //
  52. CVMRFilterConfigProp::CVMRFilterConfigProp(LPUNKNOWN pUnk, HRESULT *phr) :
  53. CBasePropertyPage(NAME("Filter Config Page"),pUnk,IDD_FILTERCONFIG,IDS_TITLE_FILTERCONFIG),
  54. m_pIFilterConfig(NULL),
  55. m_pIMixerControl(NULL),
  56. m_dwNumPins(1),
  57. m_pEventSink(NULL),
  58. m_CurPin(0),
  59. m_XPos(0.0F),
  60. m_YPos(0.0F),
  61. m_XSize(1.0F),
  62. m_YSize(1.0F),
  63. m_Alpha(1.0F)
  64. {
  65. ASSERT(phr);
  66. }
  67. //
  68. // Create a quality properties object
  69. //
  70. CUnknown * CVMRFilterConfigProp::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
  71. {
  72. ASSERT(phr);
  73. CUnknown * pUnknown = new CVMRFilterConfigProp(pUnk, phr);
  74. if (pUnknown == NULL)
  75. {
  76. *phr = E_OUTOFMEMORY;
  77. }
  78. return pUnknown;
  79. }
  80. //
  81. // OnConnect
  82. //
  83. // Override CBasePropertyPage method.
  84. // Notification of which filter this property page will communicate with
  85. // We query the object for the IVMRFilterConfig interface.
  86. //
  87. HRESULT CVMRFilterConfigProp::OnConnect(IUnknown *pUnknown)
  88. {
  89. ASSERT(NULL != pUnknown);
  90. ASSERT(NULL == m_pIFilterConfig);
  91. ASSERT(NULL == m_pIMixerControl);
  92. HRESULT hr = pUnknown->QueryInterface(IID_IVMRFilterConfig, (void **) &m_pIFilterConfig);
  93. if (FAILED(hr) || NULL == m_pIFilterConfig)
  94. {
  95. return E_NOINTERFACE;
  96. }
  97. // Get the IMediaEventSink interface. We use this later to tell graphedit that we updated the number of pins
  98. CComPtr<IBaseFilter> pFilter;
  99. hr = pUnknown->QueryInterface(IID_IBaseFilter, (void **) &pFilter);
  100. if (FAILED(hr) || !pFilter)
  101. {
  102. return E_NOINTERFACE;
  103. }
  104. FILTER_INFO Info;
  105. hr = pFilter->QueryFilterInfo(&Info);
  106. if (FAILED(hr))
  107. {
  108. return E_FAIL;
  109. }
  110. hr = Info.pGraph->QueryInterface(IID_IMediaEventSink, (void**) &m_pEventSink);
  111. Info.pGraph->Release(); // the IFilterGraph pointer is ref counted. We need to release it or leak.
  112. if (FAILED(hr) || NULL == m_pEventSink)
  113. {
  114. return E_NOINTERFACE;
  115. }
  116. return NOERROR;
  117. } // OnConnect
  118. //
  119. // OnDisconnect
  120. //
  121. // Override CBasePropertyPage method.
  122. // Release all interfaces we referenced in OnConnect
  123. //
  124. HRESULT CVMRFilterConfigProp::OnDisconnect(void)
  125. {
  126. if (m_pIFilterConfig)
  127. {
  128. m_pIFilterConfig->Release();
  129. m_pIFilterConfig = NULL;
  130. }
  131. if (m_pIMixerControl)
  132. {
  133. m_pIMixerControl->Release();
  134. m_pIMixerControl = NULL;
  135. }
  136. if (m_pEventSink)
  137. {
  138. m_pEventSink->Release();
  139. m_pEventSink = NULL;
  140. }
  141. return NOERROR;
  142. } // OnDisconnect
  143. //
  144. // OnReceiveMessage
  145. //
  146. // Override CBasePropertyPage method.
  147. // Handles the messages for our property window
  148. //
  149. INT_PTR CVMRFilterConfigProp::OnReceiveMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  150. {
  151. switch (uMsg)
  152. {
  153. HANDLE_MSG(hwnd, WM_COMMAND, OnCommand);
  154. HANDLE_MSG(hwnd, WM_HSCROLL, OnHScroll);
  155. } // switch
  156. return CBasePropertyPage::OnReceiveMessage(hwnd,uMsg,wParam,lParam);
  157. } // OnReceiveMessage
  158. //
  159. // OnCommand
  160. //
  161. // Handles the command messages for our property window
  162. //
  163. void CVMRFilterConfigProp::OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  164. {
  165. switch(id)
  166. {
  167. case IDC_NUMPINS:
  168. if (EN_CHANGE == codeNotify)
  169. {
  170. SetDirty();
  171. break;
  172. }
  173. break;
  174. // the selected pin changed
  175. case IDC_PINSELECT:
  176. if (CBN_SELCHANGE == codeNotify)
  177. {
  178. m_CurPin = ComboBox_GetCurSel(GetDlgItem(m_Dlg, IDC_PINSELECT));
  179. InitConfigControls(m_CurPin);
  180. break;
  181. }
  182. break;
  183. // Reset X position to center
  184. case IDC_XPOS_STATIC:
  185. if (STN_CLICKED == codeNotify)
  186. {
  187. m_XPos = 0.0F;
  188. UpdatePinPos(m_CurPin);
  189. HWND hwndT;
  190. int pos;
  191. TCHAR sz[32];
  192. hwndT = GetDlgItem(m_Dlg, IDC_XPOS_SLIDER );
  193. pos = int(1000 * m_XPos) + 1000;
  194. SendMessage(hwndT, TBM_SETPOS, TRUE, (LPARAM)(pos));
  195. _stprintf(sz, TEXT("%.3f"), m_XPos);
  196. SetDlgItemText(m_Dlg, IDC_XPOS, sz);
  197. }
  198. break;
  199. // Reset Y position to center
  200. case IDC_YPOS_STATIC:
  201. if (STN_CLICKED == codeNotify)
  202. {
  203. m_YPos = 0.0F;
  204. UpdatePinPos(m_CurPin);
  205. HWND hwndT;
  206. int pos;
  207. TCHAR sz[32];
  208. pos = int(1000 * m_YPos) + 1000;
  209. hwndT = GetDlgItem(m_Dlg, IDC_YPOS_SLIDER );
  210. SendMessage(hwndT, TBM_SETPOS, TRUE, (LPARAM)(pos));
  211. _stprintf(sz, TEXT("%.3f"), m_YPos);
  212. SetDlgItemText(m_Dlg, IDC_YPOS, sz);
  213. }
  214. break;
  215. // Capture the current video image
  216. case IDC_SNAPSHOT:
  217. CaptureCurrentImage();
  218. break;
  219. }
  220. } // OnCommand
  221. //
  222. // OnApplyChanges
  223. //
  224. // Override CBasePropertyPage method.
  225. // Called when the user clicks ok or apply.
  226. // We update the number of pins on the VMR.
  227. //
  228. HRESULT CVMRFilterConfigProp::OnApplyChanges()
  229. {
  230. ASSERT(m_pIFilterConfig);
  231. BOOL Success;
  232. m_dwNumPins = GetDlgItemInt(m_Dlg, IDC_NUMPINS, &Success, FALSE);
  233. //
  234. // Set Number of Streams
  235. //
  236. HRESULT hr = m_pIFilterConfig->SetNumberOfStreams(m_dwNumPins);
  237. if (SUCCEEDED(hr) && !m_pIMixerControl)
  238. {
  239. hr = m_pIFilterConfig->QueryInterface(IID_IVMRMixerControl, (void **) &m_pIMixerControl);
  240. if (SUCCEEDED(hr))
  241. {
  242. // select the last pin connected because this will be highest in the z-order
  243. m_CurPin = m_dwNumPins - 1;
  244. InitConfigControls(m_CurPin);
  245. }
  246. }
  247. // Notify the graph so it will draw the new pins
  248. if (m_pEventSink)
  249. {
  250. hr = m_pEventSink->Notify(EC_GRAPH_CHANGED, 0, 0);
  251. }
  252. return NOERROR;
  253. } // OnApplyChanges
  254. //
  255. // SetDirty
  256. //
  257. // Sets m_hrDirtyFlag and notifies the property page site of the change
  258. //
  259. void CVMRFilterConfigProp::SetDirty()
  260. {
  261. m_bDirty = TRUE;
  262. if (m_pPageSite)
  263. {
  264. m_pPageSite->OnStatusChange(PROPPAGESTATUS_DIRTY);
  265. }
  266. } // SetDirty
  267. //
  268. // OnActivate
  269. //
  270. // Override CBasePropertyPage method.
  271. // Called when the page is being displayed. Used to initialize page contents.
  272. //
  273. HRESULT CVMRFilterConfigProp::OnActivate()
  274. {
  275. ASSERT(m_pIFilterConfig);
  276. HRESULT hr = m_pIFilterConfig->GetNumberOfStreams(&m_dwNumPins);
  277. if (NULL == m_pIMixerControl)
  278. {
  279. hr = m_pIFilterConfig->QueryInterface(IID_IVMRMixerControl, (void **) &m_pIMixerControl);
  280. // if IMixerControl is exposed, the VMR is in mixing mode
  281. if (S_OK == hr && m_pIMixerControl)
  282. {
  283. // if this is the first time, select the last pin connected because this will be highest in the z-order
  284. m_CurPin = m_dwNumPins - 1;
  285. InitConfigControls(m_CurPin);
  286. }
  287. }
  288. else
  289. {
  290. InitConfigControls(m_CurPin);
  291. }
  292. BOOL bSet = SetDlgItemInt(m_Dlg, IDC_NUMPINS, m_dwNumPins, 0);
  293. ASSERT(bSet);
  294. // Set the range of the spin control
  295. HWND hSpin = GetDlgItem(m_Dlg, IDC_PINSPIN);
  296. if(hSpin)
  297. {
  298. SendMessage(hSpin, UDM_SETRANGE32, 1, 16);
  299. }
  300. return NOERROR;
  301. } // OnActivate
  302. //
  303. // InitConfigControls
  304. //
  305. // Enable and update the content of the configuration controls .
  306. //
  307. void CVMRFilterConfigProp::InitConfigControls(DWORD pin)
  308. {
  309. // If this call fails, the pins are not connected or there is no mixing control.
  310. if (FAILED(UpdateMixingData(pin)))
  311. {
  312. return;
  313. }
  314. //
  315. // Populate Combo List Box and Enable Pin Config Controls
  316. //
  317. CComPtr<IBaseFilter> pFilter;
  318. HRESULT hr = m_pIFilterConfig->QueryInterface(IID_IBaseFilter, (void **) &pFilter);
  319. if (FAILED(hr) || !pFilter)
  320. {
  321. return;
  322. }
  323. CComPtr<IEnumPins> pEnum;
  324. hr = pFilter->EnumPins(&pEnum);
  325. if (FAILED(hr) || !pEnum)
  326. {
  327. return;
  328. }
  329. HWND hCtl = GetDlgItem(m_Dlg, IDC_PINSELECT);
  330. ComboBox_ResetContent(GetDlgItem(m_Dlg, IDC_PINSELECT));
  331. pEnum->Reset();
  332. IPin * pPin;
  333. PIN_INFO Info;
  334. TCHAR szPinName[255]; // pin names are 32 characters or less. This should be sufficient for a long time to come.
  335. while (S_OK == pEnum->Next(1, &pPin, NULL))
  336. {
  337. hr = pPin->QueryPinInfo(&Info);
  338. if (SUCCEEDED(hr))
  339. {
  340. #ifdef UNICODE
  341. _tcscpy(szPinName, Info.achName);
  342. #else
  343. WideCharToMultiByte(CP_ACP, NULL, Info.achName, -1, szPinName, 255, NULL, NULL);
  344. #endif
  345. ComboBox_AddString(GetDlgItem(m_Dlg, IDC_PINSELECT), szPinName);
  346. pPin->Release();
  347. Info.pFilter->Release();
  348. }
  349. }
  350. ComboBox_SetCurSel(GetDlgItem(m_Dlg, IDC_PINSELECT), pin); // select the pin
  351. ComboBox_Enable(GetDlgItem(m_Dlg, IDC_PINSELECT), TRUE);
  352. ComboBox_Enable(GetDlgItem(m_Dlg, IDC_XPOS_SLIDER), TRUE);
  353. ComboBox_Enable(GetDlgItem(m_Dlg, IDC_YPOS_SLIDER), TRUE);
  354. ComboBox_Enable(GetDlgItem(m_Dlg, IDC_XSIZE_SLIDER), TRUE);
  355. ComboBox_Enable(GetDlgItem(m_Dlg, IDC_YSIZE_SLIDER), TRUE);
  356. ComboBox_Enable(GetDlgItem(m_Dlg, IDC_ALPHA_SLIDER), TRUE);
  357. // Initialize the sliders
  358. HWND hwndT;
  359. int pos;
  360. TCHAR sz[32];
  361. hwndT = GetDlgItem(m_Dlg, IDC_XPOS_SLIDER );
  362. pos = int(1000 * m_XPos) + 1000;
  363. SendMessage(hwndT, TBM_SETRANGE, TRUE, MAKELONG(0, (WORD)(2000)));
  364. SendMessage(hwndT, TBM_SETPOS, TRUE, (LPARAM)(pos));
  365. _stprintf(sz, TEXT("%.3f"), m_XPos);
  366. SetDlgItemText(m_Dlg, IDC_XPOS, sz);
  367. pos = int(1000 * m_YPos) + 1000;
  368. hwndT = GetDlgItem(m_Dlg, IDC_YPOS_SLIDER );
  369. SendMessage(hwndT, TBM_SETRANGE, TRUE, MAKELONG(0, (WORD)(2000)));
  370. SendMessage(hwndT, TBM_SETPOS, TRUE, (LPARAM)(pos));
  371. _stprintf(sz, TEXT("%.3f"), m_YPos);
  372. SetDlgItemText(m_Dlg, IDC_YPOS, sz);
  373. pos = int(1000 * m_XSize) + 1000;
  374. hwndT = GetDlgItem(m_Dlg, IDC_XSIZE_SLIDER );
  375. SendMessage(hwndT, TBM_SETRANGE, TRUE, MAKELONG(0, (WORD)(2000)));
  376. SendMessage(hwndT, TBM_SETPOS, TRUE, (LPARAM)(pos));
  377. _stprintf(sz, TEXT("%.3f"), m_XSize);
  378. SetDlgItemText(m_Dlg, IDC_XSIZE, sz);
  379. pos = int(1000 * m_YSize) + 1000;
  380. hwndT = GetDlgItem(m_Dlg, IDC_YSIZE_SLIDER );
  381. SendMessage(hwndT, TBM_SETRANGE, TRUE, MAKELONG(0, (WORD)(2000)));
  382. SendMessage(hwndT, TBM_SETPOS, TRUE, (LPARAM)(pos));
  383. _stprintf(sz, TEXT("%.3f"), m_YSize);
  384. SetDlgItemText(m_Dlg, IDC_YSIZE, sz);
  385. pos = int(1000 * m_Alpha);
  386. hwndT = GetDlgItem(m_Dlg, IDC_ALPHA_SLIDER );
  387. SendMessage(hwndT, TBM_SETRANGE, TRUE, MAKELONG(0, (WORD)(1000)));
  388. SendMessage(hwndT, TBM_SETPOS, TRUE, (LPARAM)(pos));
  389. _stprintf(sz, TEXT("%.3f"), m_Alpha);
  390. SetDlgItemText(m_Dlg, IDC_ALPHA, sz);
  391. }// InitConfigControls
  392. //
  393. // OnHScroll
  394. //
  395. // Handles the scroll messages for our property window
  396. //
  397. void CVMRFilterConfigProp::OnHScroll(HWND hwnd, HWND hwndCtrl, UINT code, int pos)
  398. {
  399. ASSERT(m_pIMixerControl);
  400. TCHAR sz[32];
  401. if (GetDlgItem(m_Dlg, IDC_ALPHA_SLIDER ) == hwndCtrl) {
  402. pos = (int)SendMessage(hwndCtrl, TBM_GETPOS, 0, 0);
  403. m_Alpha = (FLOAT)pos / 1000.0F;
  404. UpdatePinAlpha(m_CurPin);
  405. _stprintf(sz, TEXT("%.3f"), m_Alpha);
  406. SetDlgItemText(m_Dlg, IDC_ALPHA, sz);
  407. }
  408. else if (GetDlgItem(m_Dlg, IDC_XPOS_SLIDER ) == hwndCtrl) {
  409. pos = (int)SendMessage(hwndCtrl, TBM_GETPOS, 0, 0);
  410. m_XPos = ((FLOAT)pos - 1000.0F) / 1000.0F;
  411. UpdatePinPos(m_CurPin);
  412. _stprintf(sz, TEXT("%.3f"), m_XPos);
  413. SetDlgItemText(m_Dlg, IDC_XPOS, sz);
  414. }
  415. else if (GetDlgItem(m_Dlg, IDC_YPOS_SLIDER ) == hwndCtrl) {
  416. pos = (int)SendMessage(hwndCtrl, TBM_GETPOS, 0, 0);
  417. m_YPos = ((FLOAT)pos - 1000.0F) / 1000.0F;
  418. UpdatePinPos(m_CurPin);
  419. _stprintf(sz, TEXT("%.3f"), m_YPos);
  420. SetDlgItemText(m_Dlg, IDC_YPOS, sz);
  421. }
  422. else if (GetDlgItem(m_Dlg, IDC_XSIZE_SLIDER ) == hwndCtrl) {
  423. pos = (int)SendMessage(hwndCtrl, TBM_GETPOS, 0, 0);
  424. m_XSize = ((FLOAT)pos - 1000.0F) / 1000.0F;
  425. UpdatePinPos(m_CurPin);
  426. _stprintf(sz, TEXT("%.3f"), m_XSize);
  427. SetDlgItemText(m_Dlg, IDC_XSIZE, sz);
  428. }
  429. else if (GetDlgItem(m_Dlg, IDC_YSIZE_SLIDER ) == hwndCtrl) {
  430. pos = (int)SendMessage(hwndCtrl, TBM_GETPOS, 0, 0);
  431. m_YSize = ((FLOAT)pos - 1000.0F) / 1000.0F;
  432. UpdatePinPos(m_CurPin);
  433. _stprintf(sz, TEXT("%.3f"), m_YSize);
  434. SetDlgItemText(m_Dlg, IDC_YSIZE, sz);
  435. }
  436. } // OnHScroll
  437. //
  438. // UpdatePinAlpha
  439. //
  440. // Update the alpha value of a stream
  441. //
  442. void CVMRFilterConfigProp::UpdatePinAlpha(DWORD dwStreamID)
  443. {
  444. if (m_pIMixerControl)
  445. {
  446. m_pIMixerControl->SetAlpha(dwStreamID, m_Alpha);
  447. }
  448. } // UpdatePinAlpha
  449. //
  450. // UpdatePinPos
  451. //
  452. // Update the position rectangle of a stream
  453. //
  454. void CVMRFilterConfigProp::UpdatePinPos(DWORD dwStreamID)
  455. {
  456. NORMALIZEDRECT r = {m_XPos, m_YPos, m_XPos + m_XSize, m_YPos + m_YSize};
  457. if (m_pIMixerControl)
  458. {
  459. m_pIMixerControl->SetOutputRect(dwStreamID, &r);
  460. }
  461. } // UpdatePinPos
  462. //
  463. // UpdateMixingData
  464. //
  465. // Query the filter for the current alpha value and position of a stream
  466. //
  467. HRESULT CVMRFilterConfigProp::UpdateMixingData(DWORD dwStreamID)
  468. {
  469. NORMALIZEDRECT r;
  470. if (m_pIMixerControl)
  471. {
  472. HRESULT hr = m_pIMixerControl->GetOutputRect(dwStreamID, &r);
  473. if (FAILED(hr))
  474. {
  475. return hr;
  476. }
  477. m_XPos = r.left;
  478. m_YPos = r.top;
  479. m_XSize = r.right - r.left;
  480. m_YSize = r.bottom - r.top;
  481. return m_pIMixerControl->GetAlpha(dwStreamID, &m_Alpha);
  482. }
  483. return E_NOINTERFACE;
  484. } // UpdateMixingData
  485. //
  486. // Data types and macros used for image capture
  487. //
  488. typedef LPBITMAPINFOHEADER PDIB;
  489. #define BFT_BITMAP 0x4d42 /* 'BM' */
  490. #define DibNumColors(lpbi) ((lpbi)->biClrUsed == 0 && (lpbi)->biBitCount <= 8 \
  491. ? (int)(1 << (int)(lpbi)->biBitCount) \
  492. : (int)(lpbi)->biClrUsed)
  493. #define DibSize(lpbi) ((lpbi)->biSize + (lpbi)->biSizeImage + \
  494. (int)(lpbi)->biClrUsed * sizeof(RGBQUAD))
  495. #define DibPaletteSize(lpbi) (DibNumColors(lpbi) * sizeof(RGBQUAD))
  496. //
  497. // SaveCapturedImage
  498. //
  499. // Save a captured image (bitmap) to a file
  500. //
  501. bool CVMRFilterConfigProp::SaveCapturedImage(TCHAR* szFile, BYTE* lpCurrImage)
  502. {
  503. BITMAPFILEHEADER hdr;
  504. DWORD dwSize;
  505. PDIB pdib = (PDIB)lpCurrImage;
  506. //fh = OpenFile(szFile,&of,OF_CREATE|OF_READWRITE);
  507. HANDLE hFile = CreateFile(szFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
  508. NULL);
  509. if (INVALID_HANDLE_VALUE == hFile)
  510. return FALSE;
  511. dwSize = DibSize(pdib);
  512. hdr.bfType = BFT_BITMAP;
  513. hdr.bfSize = dwSize + sizeof(BITMAPFILEHEADER);
  514. hdr.bfReserved1 = 0;
  515. hdr.bfReserved2 = 0;
  516. hdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + pdib->biSize +
  517. DibPaletteSize(pdib);
  518. DWORD dwWritten;
  519. WriteFile(hFile, (LPVOID)&hdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
  520. if (sizeof(BITMAPFILEHEADER) != dwWritten)
  521. return FALSE;
  522. WriteFile(hFile, (LPVOID)pdib, dwSize, &dwWritten, NULL);
  523. if (dwSize != dwWritten)
  524. return FALSE;
  525. CloseHandle(hFile);
  526. return TRUE;
  527. }
  528. //
  529. // CaptureCurrentImage
  530. //
  531. // Captures the current VMR image and save it to a file
  532. //
  533. void CVMRFilterConfigProp::CaptureCurrentImage(void)
  534. {
  535. IBasicVideo* iBV;
  536. BYTE* lpCurrImage = NULL;
  537. HRESULT hr = m_pIFilterConfig->QueryInterface(IID_IBasicVideo, (LPVOID*)&iBV);
  538. if (SUCCEEDED(hr)) {
  539. LONG BuffSize = 0;
  540. hr = iBV->GetCurrentImage(&BuffSize, NULL);
  541. if (SUCCEEDED(hr)) {
  542. lpCurrImage = new BYTE[BuffSize];
  543. if (lpCurrImage) {
  544. hr = iBV->GetCurrentImage(&BuffSize, (long*)lpCurrImage);
  545. if (FAILED(hr)) {
  546. delete lpCurrImage;
  547. lpCurrImage = NULL;
  548. }
  549. }
  550. }
  551. } // QI
  552. if (lpCurrImage) {
  553. // Get the path to the My Pictures folder. Create it if it doesn't exist.
  554. // If we can't get it, don't use a path. Picture will then be saved in
  555. // current working directory.
  556. TCHAR tszPath[MAX_PATH];
  557. if (!SHGetSpecialFolderPath(NULL, tszPath, CSIDL_MYPICTURES, TRUE))
  558. {
  559. tszPath[0]=TEXT('\0');
  560. }
  561. DWORD dwTime = timeGetTime();
  562. TCHAR szFile[MAX_PATH];
  563. wsprintf(szFile, TEXT("%s\\VMRImage%X.bmp"), tszPath, dwTime);
  564. SaveCapturedImage(szFile, lpCurrImage);
  565. delete lpCurrImage;
  566. }
  567. if (iBV) {
  568. iBV->Release();
  569. }
  570. }