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.

1629 lines
33 KiB

  1. // File: videview.cpp
  2. #include "precomp.h"
  3. #include "vidview.h"
  4. #include "resource.h"
  5. #include "confman.h"
  6. #include "rtoolbar.h"
  7. #include "pfndrawd.h"
  8. #include "NmManager.h"
  9. #include "cmd.h"
  10. #define DibHdrSize(lpbi) ((lpbi)->biSize + (int)(lpbi)->biClrUsed * sizeof(RGBQUAD))
  11. #define DibDataSize(lpbi) ((lpbi)->biSizeImage)
  12. #define DibSize(lpbi) (DibHdrSize(lpbi) + DibDataSize(lpbi))
  13. typedef struct
  14. {
  15. DWORD *pdwCapDevIDs;
  16. LPTSTR pszCapDevNames;
  17. DWORD dwNumCapDev;
  18. } ENUM_CAP_DEV;
  19. CSimpleArray<CVideoWindow *> *CVideoWindow::g_pVideos;
  20. BOOL CVideoWindow::g_fMirror = FALSE;
  21. BOOL CVideoWindow::g_bLocalOneTimeInited = FALSE;
  22. static const TCHAR REGVAL_VIDEO_QUALITY[] = TEXT("ImageQuality");
  23. static const UINT VIDEO_ZOOM_MIN = 50;
  24. static const UINT VIDEO_ZOOM_MAX = 400;
  25. static const UINT QCIF_WIDTH = 176;
  26. static const UINT QCIF_HEIGHT = 144;
  27. CVideoWindow::CVideoWindow(VideoType eType, BOOL bEmbedded) :
  28. m_dwFrameSize(NM_VIDEO_MEDIUM),
  29. m_hdd(NULL),
  30. #ifdef DISPLAYFPS
  31. m_cFrame (0),
  32. m_dwTick (GetTickCount()),
  33. #endif // DISPLAYFPS
  34. m_pActiveChannel(NULL),
  35. m_dwCookie(0),
  36. m_dwImageQuality(NM_VIDEO_MIN_QUALITY),
  37. m_pNotify(NULL),
  38. m_fLocal(REMOTE!=eType),
  39. m_hBitmapMirror(NULL),
  40. m_hDCMirror(NULL),
  41. m_fZoomable(TRUE),
  42. m_bEmbedded(bEmbedded),
  43. m_hGDIObj(NULL)
  44. {
  45. if (NULL == g_pVideos)
  46. {
  47. g_pVideos = new CSimpleArray<CVideoWindow*>;
  48. }
  49. if (NULL != g_pVideos)
  50. {
  51. CVideoWindow* p = static_cast<CVideoWindow*>(this);
  52. g_pVideos->Add(p);
  53. }
  54. m_sizeVideo.cx = 0;
  55. m_sizeVideo.cy = 0;
  56. RegEntry reAudio(AUDIO_KEY); // HKCU
  57. RegEntry reVideo( IsLocal() ? VIDEO_LOCAL_KEY : VIDEO_REMOTE_KEY,
  58. HKEY_CURRENT_USER );
  59. DWORD dwFrameSizeDefault = FRAME_QCIF;
  60. DWORD dwImageQualityDefault = NM_VIDEO_DEFAULT_QUALITY;
  61. int nVideoWidthDefault = VIDEO_WIDTH_QCIF;
  62. int nVideoHeightDefault = VIDEO_HEIGHT_QCIF;
  63. UINT uBandWidth = reAudio.GetNumber(REGVAL_TYPICALBANDWIDTH, BW_DEFAULT);
  64. if (uBandWidth == BW_144KBS)
  65. {
  66. dwImageQualityDefault = NM_VIDEO_MIN_QUALITY;
  67. }
  68. m_dwFrameSize = reVideo.GetNumber(
  69. REGVAL_VIDEO_FRAME_SIZE, dwFrameSizeDefault );
  70. if (!IsLocal())
  71. {
  72. m_dwImageQuality = reVideo.GetNumber(
  73. REGVAL_VIDEO_QUALITY, dwImageQualityDefault );
  74. }
  75. m_nXferOnConnect =
  76. IsLocal() ? VIDEO_SEND_CONNECT_DEFAULT :
  77. VIDEO_RECEIVE_CONNECT_DEFAULT;
  78. m_nXferOnConnect = reVideo.GetNumber(
  79. REGVAL_VIDEO_XFER_CONNECT,
  80. m_nXferOnConnect);
  81. m_zoom = 100;
  82. }
  83. VOID CVideoWindow::OnNCDestroy()
  84. {
  85. // remote channel will get released upon the NM_CHANNEL_REMOVED
  86. // notification. The preview channel needs to be released here,
  87. // and not in the destructor because of a circular ref count
  88. if (NULL != m_pActiveChannel)
  89. {
  90. NmUnadvise(m_pActiveChannel, IID_INmChannelVideoNotify, m_dwCookie);
  91. m_dwCookie = 0;
  92. m_pActiveChannel->Release();
  93. m_pActiveChannel = NULL;
  94. }
  95. if (NULL != m_pNotify)
  96. {
  97. m_pNotify->Release();
  98. m_pNotify = NULL;
  99. }
  100. }
  101. CVideoWindow::~CVideoWindow()
  102. {
  103. CVideoWindow* p = static_cast<CVideoWindow*>(this);
  104. g_pVideos->Remove(p);
  105. if (0 == g_pVideos->GetSize())
  106. {
  107. delete g_pVideos;
  108. g_pVideos = NULL;
  109. }
  110. if (NULL != m_hdd)
  111. {
  112. DRAWDIB::DrawDibClose(m_hdd);
  113. }
  114. // BUGBUG PhilF: Does DrawDibClose() nuke the selected palette?
  115. // release resources related to mirror preview
  116. UnInitMirroring();
  117. }
  118. BOOL CVideoWindow::Create(HWND hwndParent, HPALETTE hpal, IVideoChange *pNotify)
  119. {
  120. if (FAILED(DRAWDIB::Init()))
  121. {
  122. return(FALSE);
  123. }
  124. if (!CGenWindow::Create(
  125. hwndParent,
  126. 0,
  127. IsLocal() ? TEXT("NMLocalVideo") : TEXT("NMRemoteVideo"),
  128. WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
  129. WS_EX_CLIENTEDGE))
  130. {
  131. return(FALSE);
  132. }
  133. SetWindowPos(GetWindow(), NULL, 0, 0, m_sizeVideo.cx, m_sizeVideo.cy,
  134. SWP_NOZORDER|SWP_NOACTIVATE);
  135. // We do NOT own this palette
  136. m_hPal = hpal;
  137. m_hdd = DRAWDIB::DrawDibOpen();
  138. if (NULL != m_hdd)
  139. {
  140. // Use the Indeo palette in 8 bit mode only if the decompressed
  141. // video data is H.261 or H.263. We will create this palette as
  142. // an identity palette.
  143. // PhilF: If the user is utilizing an installable codec, do we still want to do this?
  144. // Update the palette in the DrawDib surface
  145. if (NULL != hpal)
  146. {
  147. DRAWDIB::DrawDibSetPalette(m_hdd, hpal);
  148. }
  149. }
  150. if (NULL != pNotify)
  151. {
  152. m_pNotify = pNotify;
  153. m_pNotify->AddRef();
  154. }
  155. if (IsLocal())
  156. {
  157. // need to get PreviewChannel;
  158. INmManager2 *pManager = CConfMan::GetNmManager();
  159. ASSERT (NULL != pManager);
  160. pManager->GetPreviewChannel(&m_pActiveChannel);
  161. pManager->Release();
  162. if (m_pActiveChannel)
  163. {
  164. NmAdvise(m_pActiveChannel, static_cast<INmChannelVideoNotify*>(this),
  165. IID_INmChannelVideoNotify, &m_dwCookie);
  166. DWORD_PTR dwFrameSize = GetFrameSize();
  167. if (g_bLocalOneTimeInited)
  168. {
  169. m_pActiveChannel->GetProperty(NM_VIDPROP_IMAGE_PREFERRED_SIZE, &dwFrameSize);
  170. }
  171. else
  172. {
  173. DWORD dwSizes = GetFrameSizes();
  174. // if frame size is not valid
  175. if (!(m_dwFrameSize & dwSizes))
  176. {
  177. // find an alternate size
  178. if (FRAME_QCIF & dwSizes)
  179. {
  180. dwFrameSize = FRAME_QCIF;
  181. }
  182. else if (FRAME_SQCIF & dwSizes)
  183. {
  184. dwFrameSize = FRAME_SQCIF;
  185. }
  186. else if (FRAME_CIF & dwSizes)
  187. {
  188. dwFrameSize = FRAME_CIF;
  189. }
  190. }
  191. RegEntry reVideo( IsLocal() ? VIDEO_LOCAL_KEY : VIDEO_REMOTE_KEY,
  192. HKEY_CURRENT_USER );
  193. SetMirror(reVideo.GetNumber(REGVAL_VIDEO_MIRROR, TRUE));
  194. g_bLocalOneTimeInited = TRUE;
  195. }
  196. SetFrameSize((DWORD)dwFrameSize);
  197. }
  198. }
  199. ResizeWindowsToFrameSize();
  200. return TRUE;
  201. }
  202. DWORD CVideoWindow::GetFrameSizes()
  203. {
  204. DWORD_PTR dwSizes = 0;
  205. if (NULL != m_pActiveChannel)
  206. {
  207. m_pActiveChannel->GetProperty(NM_VIDPROP_IMAGE_SIZES, &dwSizes);
  208. }
  209. return (DWORD)dwSizes;
  210. }
  211. VOID CVideoWindow::SetFrameSize(DWORD dwSize)
  212. {
  213. DWORD dwPrevSize = m_dwFrameSize;
  214. m_dwFrameSize = dwSize;
  215. if (IsLocal())
  216. {
  217. if (NULL != m_pActiveChannel)
  218. {
  219. m_pActiveChannel->SetProperty(NM_VIDPROP_IMAGE_PREFERRED_SIZE, dwSize);
  220. }
  221. }
  222. if (dwPrevSize != dwSize)
  223. {
  224. if ((NULL == m_pActiveChannel) ||
  225. (!IsLocal() && (S_OK != m_pActiveChannel->IsActive())) ||
  226. (IsLocal() && IsPaused()))
  227. {
  228. ResizeWindowsToFrameSize();
  229. }
  230. }
  231. }
  232. VOID CVideoWindow::ResizeWindowsToFrameSize()
  233. {
  234. SIZE size;
  235. switch(m_dwFrameSize)
  236. {
  237. case FRAME_SQCIF:
  238. size.cx = VIDEO_WIDTH_SQCIF;
  239. size.cy = VIDEO_HEIGHT_SQCIF;
  240. break;
  241. case FRAME_CIF:
  242. if (IsLocal())
  243. {
  244. size.cx = VIDEO_WIDTH_CIF;
  245. size.cy = VIDEO_HEIGHT_CIF;
  246. break;
  247. }
  248. // else fall through to QCIF
  249. case FRAME_QCIF:
  250. default:
  251. size.cx = VIDEO_WIDTH_QCIF;
  252. size.cy = VIDEO_HEIGHT_QCIF;
  253. break;
  254. }
  255. SetVideoSize(&size);
  256. }
  257. STDMETHODIMP CVideoWindow::QueryInterface(REFIID riid, PVOID *ppv)
  258. {
  259. HRESULT hr = S_OK;
  260. if ((riid == IID_INmChannelVideoNotify) || (riid == IID_IUnknown))
  261. {
  262. *ppv = static_cast<INmChannelVideoNotify *>(this);
  263. DbgMsgApi("CVideoWindow::QueryInterface()");
  264. }
  265. else
  266. {
  267. hr = E_NOINTERFACE;
  268. *ppv = NULL;
  269. DbgMsgApi("CVideoWindow::QueryInterface(): Called on unknown interface.");
  270. }
  271. if (S_OK == hr)
  272. {
  273. AddRef();
  274. }
  275. return hr;
  276. }
  277. STDMETHODIMP CVideoWindow::NmUI(CONFN uNotify)
  278. {
  279. return S_OK;
  280. }
  281. STDMETHODIMP CVideoWindow::MemberChanged(NM_MEMBER_NOTIFY uNotify, INmMember *pMember)
  282. {
  283. return S_OK;
  284. }
  285. STDMETHODIMP CVideoWindow::StateChanged(NM_VIDEO_STATE uState)
  286. {
  287. InvalidateRect(GetWindow(), NULL, TRUE);
  288. if (NULL != m_pNotify)
  289. {
  290. m_pNotify->StateChange(this, uState);
  291. }
  292. CNmManagerObj::VideoChannelStateChanged(uState, !m_fLocal);
  293. return S_OK;
  294. }
  295. STDMETHODIMP CVideoWindow::PropertyChanged(DWORD dwReserved)
  296. {
  297. if (NM_VIDPROP_FRAME == dwReserved)
  298. {
  299. OnFrameAvailable();
  300. }
  301. return S_OK;
  302. }
  303. HRESULT CVideoWindow::OnChannelChanged(NM_CHANNEL_NOTIFY uNotify, INmChannel *pChannel)
  304. {
  305. INmChannelVideo* pChannelVideo;
  306. if (SUCCEEDED(pChannel->QueryInterface(IID_INmChannelVideo, (void**)&pChannelVideo)))
  307. {
  308. BOOL bIncoming = (S_OK == pChannelVideo->IsIncoming());
  309. if ((bIncoming && !IsLocal()) || (!bIncoming && IsLocal()))
  310. {
  311. switch (uNotify)
  312. {
  313. case NM_CHANNEL_ADDED:
  314. if (NULL == m_pActiveChannel)
  315. {
  316. pChannelVideo->AddRef();
  317. m_pActiveChannel = pChannelVideo;
  318. NmAdvise(m_pActiveChannel,static_cast<INmChannelVideoNotify*>(this),
  319. IID_INmChannelVideoNotify, &m_dwCookie);
  320. SetImageQuality(m_dwImageQuality);
  321. }
  322. if (!_Module.InitControlMode())
  323. {
  324. switch(m_nXferOnConnect)
  325. {
  326. case VIDEO_XFER_START:
  327. if (IsPaused())
  328. {
  329. Pause(FALSE);
  330. }
  331. break;
  332. case VIDEO_XFER_STOP:
  333. Pause(TRUE);
  334. break;
  335. default:
  336. if (!IsLocal())
  337. {
  338. Pause(TRUE);
  339. }
  340. break;
  341. }
  342. }
  343. break;
  344. case NM_CHANNEL_REMOVED:
  345. if (!IsLocal() && (pChannel == m_pActiveChannel))
  346. {
  347. NmUnadvise(m_pActiveChannel, IID_INmChannelVideoNotify, m_dwCookie);
  348. m_pActiveChannel->Release();
  349. m_pActiveChannel = NULL;
  350. m_dwCookie = 0;
  351. ResizeWindowsToFrameSize();
  352. }
  353. }
  354. // just in case we missed a notification
  355. // (in final version this should not be the case)
  356. // m_VideoWindow.OnStateChange();
  357. }
  358. pChannelVideo->Release();
  359. }
  360. return S_OK;
  361. }
  362. HRESULT CVideoWindow::SetImageQuality(DWORD dwQuality)
  363. {
  364. HRESULT hr = E_FAIL;
  365. m_dwImageQuality = dwQuality;
  366. if (NULL != m_pActiveChannel)
  367. {
  368. hr = m_pActiveChannel->SetProperty(NM_VIDPROP_IMAGE_QUALITY, dwQuality);
  369. CNmManagerObj::VideoPropChanged(NM_VIDPROP_IMAGE_QUALITY, !IsLocal());
  370. }
  371. return hr;
  372. }
  373. HRESULT CVideoWindow::SetCameraDialog(ULONG ul)
  374. {
  375. if(IsLocal())
  376. {
  377. return m_pActiveChannel->SetProperty(NM_VIDPROP_CAMERA_DIALOG, ul);
  378. CNmManagerObj::VideoPropChanged(NM_VIDPROP_CAMERA_DIALOG, IsLocal());
  379. }
  380. return E_FAIL;
  381. }
  382. HRESULT CVideoWindow::GetCameraDialog(ULONG* pul)
  383. {
  384. HRESULT hr;
  385. DWORD_PTR dwPropVal;
  386. if(IsLocal())
  387. {
  388. hr = m_pActiveChannel->GetProperty(NM_VIDPROP_CAMERA_DIALOG, &dwPropVal);
  389. *pul = (ULONG)dwPropVal;
  390. return hr;
  391. }
  392. return E_FAIL;
  393. }
  394. BOOL CVideoWindow::IsXferAllowed()
  395. {
  396. if (IsLocal())
  397. {
  398. return FIsSendVideoAllowed() && (NULL != m_pActiveChannel);
  399. }
  400. else
  401. {
  402. return FIsReceiveVideoAllowed();
  403. }
  404. }
  405. BOOL CVideoWindow::IsAutoXferEnabled()
  406. {
  407. return(VIDEO_XFER_START == m_nXferOnConnect);
  408. }
  409. BOOL CVideoWindow::IsXferEnabled()
  410. {
  411. if (NULL != m_pActiveChannel)
  412. {
  413. NM_VIDEO_STATE state;
  414. if (SUCCEEDED(m_pActiveChannel->GetState(&state)))
  415. {
  416. switch (state)
  417. {
  418. case NM_VIDEO_PREVIEWING:
  419. case NM_VIDEO_TRANSFERRING:
  420. case NM_VIDEO_REMOTE_PAUSED:
  421. return TRUE;
  422. case NM_VIDEO_IDLE:
  423. case NM_VIDEO_LOCAL_PAUSED:
  424. case NM_VIDEO_BOTH_PAUSED:
  425. default:
  426. return FALSE;
  427. }
  428. }
  429. }
  430. return FALSE;
  431. }
  432. HRESULT CVideoWindow::GetVideoState(NM_VIDEO_STATE* puState)
  433. {
  434. if(m_pActiveChannel)
  435. {
  436. return m_pActiveChannel->GetState(puState);
  437. }
  438. return E_FAIL;
  439. }
  440. VOID CVideoWindow::Pause(BOOL fPause)
  441. {
  442. if (NULL != m_pActiveChannel)
  443. {
  444. m_pActiveChannel->SetProperty(NM_VIDPROP_PAUSE, (ULONG)fPause);
  445. CNmManagerObj::VideoPropChanged(NM_VIDPROP_PAUSE, !IsLocal());
  446. }
  447. }
  448. BOOL CVideoWindow::IsPaused()
  449. {
  450. if (NULL != m_pActiveChannel)
  451. {
  452. ULONG_PTR uPause;
  453. if (SUCCEEDED(m_pActiveChannel->GetProperty(NM_VIDPROP_PAUSE, &uPause)))
  454. {
  455. return (BOOL)uPause;
  456. }
  457. }
  458. return TRUE;
  459. }
  460. BOOL CVideoWindow::IsConnected()
  461. {
  462. if (NULL != m_pActiveChannel)
  463. {
  464. NM_VIDEO_STATE state;
  465. if (SUCCEEDED(m_pActiveChannel->GetState(&state)))
  466. {
  467. switch (state)
  468. {
  469. case NM_VIDEO_LOCAL_PAUSED:
  470. case NM_VIDEO_TRANSFERRING:
  471. case NM_VIDEO_BOTH_PAUSED:
  472. case NM_VIDEO_REMOTE_PAUSED:
  473. return TRUE;
  474. case NM_VIDEO_IDLE:
  475. case NM_VIDEO_PREVIEWING:
  476. default:
  477. return FALSE;
  478. }
  479. }
  480. }
  481. return FALSE;
  482. }
  483. DWORD CVideoWindow::GetNumCapDev()
  484. {
  485. DWORD_PTR dwNumDevs = 0;
  486. if (NULL != m_pActiveChannel)
  487. {
  488. m_pActiveChannel->GetProperty(NM_VIDPROP_NUM_CAPTURE_DEVS, &dwNumDevs);
  489. }
  490. return (DWORD)dwNumDevs;
  491. }
  492. DWORD CVideoWindow::GetMaxCapDevNameLen()
  493. {
  494. DWORD_PTR dwLen = 0;
  495. if (NULL != m_pActiveChannel)
  496. {
  497. m_pActiveChannel->GetProperty(NM_VIDPROP_MAX_CAPTURE_NAME, &dwLen);
  498. }
  499. return (DWORD)dwLen;
  500. }
  501. DWORD CVideoWindow::GetCurrCapDevID()
  502. {
  503. DWORD_PTR dwID = 0;
  504. if (NULL != m_pActiveChannel)
  505. {
  506. m_pActiveChannel->GetProperty(NM_VIDPROP_CAPTURE_DEV_ID, &dwID);
  507. }
  508. return (DWORD)dwID;
  509. }
  510. VOID CVideoWindow::SetCurrCapDevID(DWORD dwID)
  511. {
  512. if (NULL != m_pActiveChannel)
  513. {
  514. m_pActiveChannel->SetProperty(NM_VIDPROP_CAPTURE_DEV_ID, dwID);
  515. InvalidateRect(GetWindow(), NULL, TRUE);
  516. }
  517. }
  518. VOID CVideoWindow::EnableAutoXfer(BOOL fEnable)
  519. {
  520. m_nXferOnConnect = fEnable ? VIDEO_XFER_START : VIDEO_XFER_NOP;
  521. RegEntry reXfer( IsLocal() ? VIDEO_LOCAL_KEY : VIDEO_REMOTE_KEY,
  522. HKEY_CURRENT_USER );
  523. reXfer.SetValue ( REGVAL_VIDEO_XFER_CONNECT, m_nXferOnConnect);
  524. }
  525. VOID CVideoWindow::EnumCapDev(DWORD *pdwCapDevIDs, LPTSTR pszCapDevNames, DWORD dwNumCapDev)
  526. {
  527. ENUM_CAP_DEV enumCapDev;
  528. enumCapDev.pdwCapDevIDs = pdwCapDevIDs;
  529. enumCapDev.pszCapDevNames = pszCapDevNames;
  530. enumCapDev.dwNumCapDev = dwNumCapDev;
  531. if (NULL != m_pActiveChannel)
  532. {
  533. m_pActiveChannel->GetProperty(NM_VIDPROP_CAPTURE_LIST, (DWORD_PTR *)&enumCapDev);
  534. }
  535. }
  536. VOID CVideoWindow::GetDesiredSize(SIZE *ppt)
  537. {
  538. ppt->cx = m_sizeVideo.cx*m_zoom/100;
  539. ppt->cy = m_sizeVideo.cy*m_zoom/100;
  540. if (m_bEmbedded)
  541. {
  542. ppt->cx = min(ppt->cx, QCIF_WIDTH);
  543. ppt->cy = min(ppt->cy, QCIF_HEIGHT);
  544. }
  545. SIZE sGen;
  546. CGenWindow::GetDesiredSize(&sGen);
  547. ppt->cx += sGen.cx;
  548. ppt->cy += sGen.cy;
  549. }
  550. VOID CVideoWindow::SetVideoSize(LPSIZE lpsize)
  551. {
  552. m_sizeVideo = *lpsize;
  553. OnDesiredSizeChanged();
  554. }
  555. #ifdef DEBUG
  556. DWORD g_fDisplayFPS = FALSE;
  557. #ifdef DISPLAYFPS
  558. VOID CVideoWindow::UpdateFps(void)
  559. {
  560. DWORD dwTick = GetTickCount();
  561. m_cFrame++;
  562. // Update display every 4 seconds
  563. if ((dwTick - m_dwTick) < 4000)
  564. return;
  565. TCHAR sz[32];
  566. wsprintf(sz, "%d FPS", m_cFrame / 4);
  567. SetWindowText(m_hwndParent, sz);
  568. m_cFrame = 0;
  569. m_dwTick = dwTick;
  570. }
  571. #endif /* DISPLAYFPS */
  572. #endif // DEBUG
  573. VOID CVideoWindow::OnFrameAvailable(void)
  574. {
  575. ::InvalidateRect(GetWindow(), NULL, FALSE);
  576. #ifdef DISPLAYFPS
  577. if (g_fDisplayFPS)
  578. {
  579. UpdateFps();
  580. }
  581. #endif // DISPLAYFPS
  582. }
  583. VOID CVideoWindow::PaintDib(HDC hdc, FRAMECONTEXT *pFrame)
  584. {
  585. RECT rcVideo;
  586. GetClientRect(GetWindow(), &rcVideo);
  587. HPALETTE hpOld = NULL;
  588. if (NULL != m_hPal)
  589. {
  590. hpOld = SelectPalette(hdc, m_hPal, FALSE);
  591. RealizePalette(hdc);
  592. }
  593. // create the bitmap object, only if it doesn't exist
  594. // and if the mirror bitmap object isn't the right size
  595. if (!ShouldMirror() || !InitMirroring(rcVideo))
  596. {
  597. // ISSUE: (ChrisPi 2-19-97) should we use DDF_SAME_HDC?
  598. DRAWDIB::DrawDibDraw(m_hdd,hdc,
  599. rcVideo.left,
  600. rcVideo.top,
  601. RectWidth(rcVideo),
  602. RectHeight(rcVideo),
  603. &pFrame->lpbmi->bmiHeader,
  604. pFrame->lpData,
  605. pFrame->lpClipRect->left,
  606. pFrame->lpClipRect->top,
  607. RectWidth(pFrame->lpClipRect),
  608. RectHeight(pFrame->lpClipRect),
  609. 0);
  610. }
  611. else
  612. {
  613. if (NULL != m_hPal)
  614. {
  615. SelectPalette(m_hDCMirror, m_hPal, FALSE);
  616. RealizePalette(m_hDCMirror);
  617. }
  618. DRAWDIB::DrawDibDraw(m_hdd,
  619. m_hDCMirror,
  620. 0,
  621. 0,
  622. RectWidth(rcVideo),
  623. RectHeight(rcVideo),
  624. &pFrame->lpbmi->bmiHeader,
  625. pFrame->lpData,
  626. pFrame->lpClipRect->left,
  627. pFrame->lpClipRect->top,
  628. RectWidth(pFrame->lpClipRect),
  629. RectHeight(pFrame->lpClipRect),
  630. 0);
  631. ::StretchBlt(hdc,
  632. rcVideo.right,
  633. rcVideo.top,
  634. -RectWidth(rcVideo),
  635. RectHeight(rcVideo),
  636. m_hDCMirror,
  637. 0,
  638. 0,
  639. RectWidth(rcVideo),
  640. RectHeight(rcVideo),
  641. SRCCOPY);
  642. // HACKHACK georgep; don't worry about deselecting the palette in
  643. // the temp DC
  644. }
  645. if (NULL != hpOld)
  646. {
  647. SelectPalette(hdc, hpOld, FALSE);
  648. }
  649. }
  650. /* P A I N T L O G O */
  651. /*-------------------------------------------------------------------------
  652. %%Function: PaintLogo
  653. Display the 256 color NetMeeting logo in the video window.
  654. -------------------------------------------------------------------------*/
  655. VOID CVideoWindow::PaintLogo(HDC hdc, UINT idbLargeLogo, UINT idbSmallLogo)
  656. {
  657. RECT rcVideo;
  658. GetClientRect(GetWindow(), &rcVideo);
  659. ::FillRect(hdc, &rcVideo, (HBRUSH)::GetStockObject(WHITE_BRUSH));
  660. // Create the memory DC
  661. HDC hdcMem = ::CreateCompatibleDC(hdc);
  662. if (NULL == hdcMem)
  663. {
  664. ERROR_OUT(("PaintLogo: Unable to CreateCompatibleDC"));
  665. return;
  666. }
  667. // Load the bitmap (LoadBitmap doesn't work for 256 color images)
  668. HANDLE hBitmap = LoadImage(::GetInstanceHandle(),
  669. MAKEINTRESOURCE(idbLargeLogo), IMAGE_BITMAP, 0, 0,
  670. LR_CREATEDIBSECTION);
  671. if (NULL != hBitmap)
  672. {
  673. BITMAP bitmap;
  674. ::GetObject(hBitmap, sizeof(bitmap), &bitmap);
  675. int cx = bitmap.bmWidth;
  676. int cy = bitmap.bmHeight;
  677. if (RectWidth(rcVideo) < cx || RectHeight(rcVideo) < cy)
  678. {
  679. HANDLE hNew = LoadImage(::GetInstanceHandle(),
  680. MAKEINTRESOURCE(idbSmallLogo), IMAGE_BITMAP, 0, 0,
  681. LR_CREATEDIBSECTION);
  682. if (NULL != hNew)
  683. {
  684. DeleteObject(hBitmap);
  685. hBitmap = hNew;
  686. ::GetObject(hBitmap, sizeof(bitmap), &bitmap);
  687. cx = bitmap.bmWidth;
  688. cy = bitmap.bmHeight;
  689. }
  690. }
  691. HBITMAP hBmpTmp = (HBITMAP)::SelectObject(hdcMem, hBitmap);
  692. // Select and realize the palette
  693. HPALETTE hPalette = m_hPal;
  694. if (NULL != hPalette)
  695. {
  696. SelectPalette(hdcMem, hPalette, FALSE);
  697. RealizePalette(hdcMem);
  698. SelectPalette(hdc, hPalette, FALSE);
  699. RealizePalette(hdc);
  700. }
  701. int x = rcVideo.left + (RectWidth(rcVideo) - cx) / 2;
  702. int y = rcVideo.top + (RectHeight(rcVideo) - cy) / 2;
  703. ::BitBlt(hdc, x, y, cx, cy, hdcMem, 0, 0, SRCCOPY);
  704. ::SelectObject(hdcMem, hBmpTmp);
  705. ::DeleteObject(hBitmap);
  706. }
  707. ::DeleteDC(hdcMem);
  708. }
  709. VOID CVideoWindow::OnPaint()
  710. {
  711. PAINTSTRUCT ps;
  712. HDC hdc;
  713. hdc = ::BeginPaint(GetWindow(), &ps);
  714. if( hdc )
  715. {
  716. if( RectWidth(ps.rcPaint) && RectHeight(ps.rcPaint) )
  717. {
  718. // This means that we have a non-zero surface area ( there may be something to paint )
  719. DBGENTRY(CVideoWindow::ProcessPaint);
  720. // paint the video rect
  721. FRAMECONTEXT fc;
  722. if ((S_OK == GetFrame(&fc)))
  723. {
  724. if (!IsPaused())
  725. {
  726. SIZE vidSize =
  727. {
  728. RectWidth(fc.lpClipRect),
  729. RectHeight(fc.lpClipRect)
  730. } ;
  731. if ((vidSize.cx != m_sizeVideo.cx) || (vidSize.cy != m_sizeVideo.cy))
  732. {
  733. // save the new image size
  734. SetVideoSize(&vidSize);
  735. }
  736. }
  737. PaintDib(hdc, &fc);
  738. ReleaseFrame(&fc);
  739. }
  740. else
  741. {
  742. PaintLogo(hdc, IDB_VIDEO_LOGO, IDB_VIDEO_LOGO_SMALL);
  743. }
  744. // check to see if needs painting outside the video rect
  745. #if FALSE
  746. // Currently just stretching the video to the window size
  747. if (ps.rcPaint.left < m_rcVideo.left ||
  748. ps.rcPaint.top < m_rcVideo.top ||
  749. ps.rcPaint.right > m_rcVideo.right ||
  750. ps.rcPaint.bottom > m_rcVideo.bottom)
  751. {
  752. HFONT hfOld;
  753. int nBkModeOld;
  754. RECT rc, rcClient;
  755. ::GetClientRect(GetWindow(), &rcClient);
  756. // erase the background if requested
  757. if (ps.fErase)
  758. {
  759. ::ExcludeClipRect(hdc,
  760. m_rcVideo.left,
  761. m_rcVideo.top,
  762. m_rcVideo.right,
  763. m_rcVideo.bottom);
  764. ::FillRect(hdc, &rcClient, ::GetSysColorBrush(COLOR_BTNFACE));
  765. }
  766. nBkModeOld = ::SetBkMode(hdc, TRANSPARENT);
  767. hfOld = (HFONT)::SelectObject(hdc, g_hfontDlg);
  768. // paint the status text
  769. // first erase the old text if not already done
  770. if (!ps.fErase)
  771. {
  772. ::FillRect(hdc, &m_rcStatusText, ::GetSysColorBrush(COLOR_BTNFACE));
  773. }
  774. TCHAR szState[MAX_PATH];
  775. if (GetState(szState, CCHMAX(szState)))
  776. {
  777. COLORREF crOld;
  778. crOld = ::SetTextColor(hdc, ::GetSysColor(COLOR_BTNTEXT));
  779. rc = m_rcStatusText;
  780. rc.left += STATUS_MARGIN;
  781. ::DrawText(hdc,
  782. szState,
  783. -1,
  784. &rc,
  785. DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX);
  786. ::SetTextColor(hdc, crOld);
  787. }
  788. // paint border around video
  789. rc = m_rcVideo;
  790. ::InflateRect(&rc,
  791. ::GetSystemMetrics(SM_CXEDGE),
  792. ::GetSystemMetrics(SM_CYEDGE));
  793. ::DrawEdge(hdc, &rc, EDGE_SUNKEN , BF_RECT);
  794. // restore DC stuff
  795. ::SelectObject(hdc, hfOld);
  796. ::SetBkMode(hdc, nBkModeOld);
  797. }
  798. #endif // FALSE
  799. DBGEXIT(CVideoWindow::ProcessPaint);
  800. }
  801. ::EndPaint(GetWindow(), &ps);
  802. }
  803. }
  804. VOID CVideoWindow::SetZoom(UINT zoom)
  805. {
  806. if (m_zoom == zoom)
  807. {
  808. return;
  809. }
  810. m_zoom = zoom;
  811. OnDesiredSizeChanged();
  812. }
  813. void CVideoWindow::OnCommand(int idCmd)
  814. {
  815. switch (idCmd)
  816. {
  817. case IDM_VIDEO_GETACAMERA:
  818. CmdLaunchWebPage(idCmd);
  819. break;
  820. case IDM_VIDEO_COPY:
  821. CopyToClipboard();
  822. break;
  823. case IDM_VIDEO_FREEZE:
  824. Pause(!IsPaused());
  825. break;
  826. case IDM_VIDEO_UNDOCK:
  827. CMainUI::NewVideoWindow(GetConfRoom());
  828. break;
  829. case IDM_VIDEO_ZOOM1:
  830. SetZoom(100);
  831. break;
  832. case IDM_VIDEO_ZOOM2:
  833. SetZoom(200);
  834. break;
  835. case IDM_VIDEO_ZOOM3:
  836. SetZoom(300);
  837. break;
  838. case IDM_VIDEO_ZOOM4:
  839. SetZoom(400);
  840. break;
  841. case IDM_VIDEO_PROPERTIES:
  842. LaunchConfCpl(GetWindow(), OPTIONS_VIDEO_PAGE);
  843. break;
  844. }
  845. }
  846. void CVideoWindow::UpdateVideoMenu(HMENU hMenu)
  847. {
  848. EnableMenuItem(hMenu, IDM_VIDEO_COPY, MF_BYCOMMAND|(CanCopy() ? MF_ENABLED : MF_GRAYED|MF_DISABLED));
  849. EnableMenuItem(hMenu, IDM_VIDEO_UNDOCK, MF_BYCOMMAND|(IsLocal() ? MF_ENABLED : MF_GRAYED|MF_DISABLED));
  850. if (!FIsSendVideoAllowed() && !FIsReceiveVideoAllowed())
  851. {
  852. EnableMenuItem(hMenu, IDM_VIDEO_FREEZE, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED);
  853. EnableMenuItem(hMenu, IDM_VIDEO_PROPERTIES, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED);
  854. EnableMenuItem(hMenu, IDM_VIDEO_GETACAMERA, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED);
  855. }
  856. else
  857. {
  858. CheckMenuItem(hMenu, IDM_VIDEO_FREEZE, MF_BYCOMMAND|(IsPaused() ? MF_CHECKED : MF_UNCHECKED));
  859. UINT uEnable = ::CanShellExecHttp() ? MF_ENABLED : MF_GRAYED;
  860. ::EnableMenuItem(hMenu, IDM_VIDEO_GETACAMERA, uEnable);
  861. }
  862. int nZoom = GetZoom();
  863. int idZoom;
  864. if (350 < nZoom) idZoom = IDM_VIDEO_ZOOM4;
  865. else if (250 < nZoom) idZoom = IDM_VIDEO_ZOOM3;
  866. else if (150 < nZoom) idZoom = IDM_VIDEO_ZOOM2;
  867. else idZoom = IDM_VIDEO_ZOOM1;
  868. UINT uFlags = IsZoomable() && !m_bEmbedded
  869. ? MF_ENABLED : MF_GRAYED|MF_DISABLED;
  870. for (int id=IDM_VIDEO_ZOOM1; id<=IDM_VIDEO_ZOOM4; ++id)
  871. {
  872. EnableMenuItem(hMenu, id, MF_BYCOMMAND|uFlags);
  873. CheckMenuItem(hMenu, id, MF_BYCOMMAND|MF_UNCHECKED);
  874. }
  875. CheckMenuItem(hMenu, idZoom, MF_BYCOMMAND|MF_CHECKED);
  876. uFlags = CanLaunchConfCpl()
  877. ? MF_ENABLED : MF_GRAYED|MF_DISABLED;
  878. EnableMenuItem(hMenu, IDM_VIDEO_PROPERTIES, MF_BYCOMMAND|uFlags);
  879. }
  880. void CVideoWindow::OnContextMenu(HWND hwnd, HWND hwndContext, UINT xPos, UINT yPos)
  881. {
  882. HMENU hmLoad = LoadMenu(_Module.GetModuleInstance(), MAKEINTRESOURCE(IDR_VIDEO_POPUP));
  883. if (NULL != hmLoad)
  884. {
  885. HMENU hmPopup = GetSubMenu(hmLoad, 0);
  886. ASSERT(NULL != hmPopup);
  887. UpdateVideoMenu(hmPopup);
  888. int idCmd = TrackPopupMenu(hmPopup, TPM_RETURNCMD|TPM_RIGHTBUTTON,
  889. xPos, yPos, 0, hwnd, NULL);
  890. if (0 != idCmd)
  891. {
  892. OnCommand(idCmd);
  893. }
  894. DestroyMenu(hmLoad);
  895. }
  896. }
  897. LRESULT CVideoWindow::ProcessMessage(HWND hwnd, UINT message,
  898. WPARAM wParam, LPARAM lParam)
  899. {
  900. switch (message)
  901. {
  902. HANDLE_MSG(hwnd, WM_CONTEXTMENU, OnContextMenu);
  903. case WM_ERASEBKGND:
  904. return 0;
  905. case WM_PAINT:
  906. OnPaint();
  907. return 0;
  908. case WM_NCDESTROY:
  909. OnNCDestroy();
  910. return 0;
  911. case WM_SIZE:
  912. // Need to redraw the whole window
  913. InvalidateRect(GetWindow(), NULL, FALSE);
  914. break;
  915. default:
  916. break;
  917. }
  918. return CGenWindow::ProcessMessage(hwnd, message, wParam, lParam) ;
  919. }
  920. #if FALSE
  921. int CVideoWindow::GetState(LPTSTR lpszState, int nStateMax)
  922. {
  923. int uStringID;
  924. NM_VIDEO_STATE state = NM_VIDEO_IDLE;
  925. if (NULL != m_pActiveChannel)
  926. {
  927. m_pActiveChannel->GetState(&state);
  928. }
  929. if (IsLocal())
  930. {
  931. switch (state)
  932. {
  933. case NM_VIDEO_PREVIEWING:
  934. uStringID = IDS_VIDEO_STATE_PREVIEWING;
  935. break;
  936. case NM_VIDEO_TRANSFERRING:
  937. uStringID = IDS_VIDEO_STATE_SENDING;
  938. break;
  939. case NM_VIDEO_REMOTE_PAUSED:
  940. uStringID = IDS_VIDEO_STATE_REMOTEPAUSED;
  941. break;
  942. case NM_VIDEO_LOCAL_PAUSED:
  943. case NM_VIDEO_BOTH_PAUSED:
  944. uStringID = IDS_VIDEO_STATE_PAUSED;
  945. break;
  946. case NM_VIDEO_IDLE:
  947. default:
  948. uStringID = IDS_VIDEO_STATE_NOTSENDING;
  949. break;
  950. }
  951. }
  952. else
  953. {
  954. switch (state)
  955. {
  956. case NM_VIDEO_TRANSFERRING:
  957. uStringID = IDS_VIDEO_STATE_RECEIVING;
  958. break;
  959. case NM_VIDEO_REMOTE_PAUSED:
  960. uStringID = IDS_VIDEO_STATE_REMOTEPAUSED;
  961. break;
  962. case NM_VIDEO_LOCAL_PAUSED:
  963. case NM_VIDEO_BOTH_PAUSED:
  964. uStringID = IDS_VIDEO_STATE_PAUSED;
  965. break;
  966. case NM_VIDEO_IDLE:
  967. case NM_VIDEO_PREVIEWING:
  968. default:
  969. uStringID = IDS_VIDEO_STATE_NOTRECEIVING;
  970. break;
  971. }
  972. }
  973. return ::LoadString(
  974. ::GetInstanceHandle(),
  975. uStringID,
  976. lpszState,
  977. nStateMax);
  978. }
  979. #endif // FALSE
  980. // Return value will be TRUE if Windows can handle the format
  981. static BOOL IsKnownDIBFormat(BITMAPINFOHEADER *pbmih)
  982. {
  983. if (sizeof(BITMAPINFOHEADER) != pbmih->biSize)
  984. {
  985. return(FALSE);
  986. }
  987. if (1 != pbmih->biPlanes)
  988. {
  989. return(FALSE);
  990. }
  991. int bits = pbmih->biBitCount;
  992. int comp = pbmih->biCompression;
  993. switch (bits)
  994. {
  995. case 1:
  996. if (BI_RGB == comp)
  997. {
  998. return(TRUE);
  999. }
  1000. break;
  1001. case 4:
  1002. if (BI_RGB == comp || BI_RLE4 == comp)
  1003. {
  1004. return(TRUE);
  1005. }
  1006. break;
  1007. case 8:
  1008. if (BI_RGB == comp || BI_RLE8 == comp)
  1009. {
  1010. return(TRUE);
  1011. }
  1012. break;
  1013. case 16:
  1014. if (BI_RGB == comp || BI_BITFIELDS == comp)
  1015. {
  1016. return(TRUE);
  1017. }
  1018. break;
  1019. case 24:
  1020. case 32:
  1021. if (BI_RGB == comp)
  1022. {
  1023. return(TRUE);
  1024. }
  1025. break;
  1026. default:
  1027. break;
  1028. }
  1029. return(FALSE);
  1030. }
  1031. #ifdef TryPaintDIB
  1032. BOOL CVideoWindow::CopyToClipboard()
  1033. {
  1034. FRAMECONTEXT fc;
  1035. BOOL fSuccess = FALSE;
  1036. // Get the current frame and open the clipboard
  1037. if (S_OK == GetFrame(&fc))
  1038. {
  1039. HWND hwnd = GetWindow();
  1040. if (OpenClipboard(hwnd))
  1041. {
  1042. // Allocate memory that we will be giving to the clipboard
  1043. BITMAPINFOHEADER *pbmih = &fc.lpbmi->bmiHeader;
  1044. BOOL bCopy = IsKnownDIBFormat(pbmih);
  1045. // BUGBUG georgep; I think this doesn't work for 15 or 16 bit DIBs
  1046. int nColors = pbmih->biClrUsed;
  1047. if (0 == nColors && pbmih->biBitCount <= 8)
  1048. {
  1049. nColors = 1 << pbmih->biBitCount;
  1050. }
  1051. // Special case for 16-bit bitfield bitmaps
  1052. if (16 == pbmih->biBitCount && BI_BITFIELDS == pbmih->biCompression)
  1053. {
  1054. nColors = 3;
  1055. }
  1056. int nHdrSize = pbmih->biSize + nColors * sizeof(RGBQUAD);
  1057. int bitsPer = pbmih->biBitCount;
  1058. if (!bCopy)
  1059. {
  1060. bitsPer *= pbmih->biPlanes;
  1061. if (bitsPer > 24)
  1062. {
  1063. bitsPer = 32;
  1064. }
  1065. // LAZYLAZY georgep: Skipping 16-bit format
  1066. else if (bitsPer > 8)
  1067. {
  1068. bitsPer = 24;
  1069. }
  1070. else if (bitsPer > 4)
  1071. {
  1072. bitsPer = 8;
  1073. }
  1074. else if (bitsPer > 1)
  1075. {
  1076. bitsPer = 4;
  1077. }
  1078. else
  1079. {
  1080. bitsPer = 1;
  1081. }
  1082. }
  1083. int nDataSize = bCopy ? pbmih->biSizeImage : 0;
  1084. if (0 == nDataSize)
  1085. {
  1086. // Make an uncompressed DIB
  1087. int nByteWidth = (pbmih->biWidth*bitsPer+7) / 8;
  1088. nDataSize = ((nByteWidth + 3)&~3) * pbmih->biHeight;
  1089. }
  1090. // Allocate the total memory for the DIB
  1091. HGLOBAL hCopy = GlobalAlloc(GHND, nHdrSize + nDataSize);
  1092. if (NULL != hCopy)
  1093. {
  1094. BITMAPINFO *lpvCopy = reinterpret_cast<BITMAPINFO*>(GlobalLock(hCopy));
  1095. CopyMemory(lpvCopy, pbmih, nHdrSize);
  1096. // Create a temporary DC for drawing into
  1097. HDC hdc = GetDC(hwnd);
  1098. if (NULL != hdc)
  1099. {
  1100. HDC hdcTemp = CreateCompatibleDC(hdc);
  1101. ReleaseDC(hwnd, hdc);
  1102. hdc = hdcTemp;
  1103. }
  1104. if (NULL != hdc)
  1105. {
  1106. if (bCopy)
  1107. {
  1108. if (ShouldMirror())
  1109. {
  1110. // Create a DIB section for drawing into
  1111. LPVOID pData;
  1112. HBITMAP hDIB = CreateDIBSection(hdc, lpvCopy, DIB_RGB_COLORS, &pData, NULL, 0);
  1113. if (NULL != hDIB)
  1114. {
  1115. // Draw into the DIB, and then copy the bits
  1116. HGDIOBJ hOld = SelectObject(hdc, hDIB);
  1117. RECT rc = { 0, 0, pbmih->biWidth, pbmih->biHeight };
  1118. StretchDIBits(hdc, 0, 0, pbmih->biWidth, pbmih->biHeight,
  1119. pbmih->biWidth, 0, -pbmih->biWidth, pbmih->biHeight,
  1120. fc.lpData, lpvCopy, DIB_RGB_COLORS, SRCCOPY);
  1121. CopyMemory(&lpvCopy->bmiColors[nColors], pData, nDataSize);
  1122. // Start cleaning up
  1123. SelectObject(hdc, hOld);
  1124. DeleteObject(hDIB);
  1125. }
  1126. }
  1127. else
  1128. {
  1129. CopyMemory(&lpvCopy->bmiColors[nColors], fc.lpData, nDataSize);
  1130. }
  1131. fSuccess = TRUE;
  1132. }
  1133. else
  1134. {
  1135. lpvCopy->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  1136. lpvCopy->bmiHeader.biPlanes = 1;
  1137. lpvCopy->bmiHeader.biBitCount = bitsPer;
  1138. lpvCopy->bmiHeader.biCompression = BI_RGB;
  1139. lpvCopy->bmiHeader.biSizeImage = nDataSize;
  1140. // Create a DIB section for drawing into
  1141. LPVOID pData;
  1142. HBITMAP hDIB = CreateDIBSection(hdc, lpvCopy, DIB_RGB_COLORS, &pData, NULL, 0);
  1143. if (NULL != hDIB)
  1144. {
  1145. // Draw into the DIB, and then copy the bits
  1146. HGDIOBJ hOld = SelectObject(hdc, hDIB);
  1147. RECT rc = { 0, 0, pbmih->biWidth, pbmih->biHeight };
  1148. PaintDib(hdc, &fc, &rc);
  1149. CopyMemory(&lpvCopy->bmiColors[nColors], pData, nDataSize);
  1150. // Start cleaning up
  1151. SelectObject(hdc, hOld);
  1152. DeleteObject(hDIB);
  1153. fSuccess = TRUE;
  1154. }
  1155. }
  1156. DeleteDC(hdc);
  1157. }
  1158. GlobalUnlock(hCopy);
  1159. if (fSuccess)
  1160. {
  1161. // Set the DIB into the clipboard
  1162. EmptyClipboard();
  1163. fSuccess = (NULL != SetClipboardData(CF_DIB, (HANDLE)hCopy));
  1164. }
  1165. if (!fSuccess)
  1166. {
  1167. GlobalFree(hCopy);
  1168. }
  1169. }
  1170. CloseClipboard();
  1171. }
  1172. ReleaseFrame(&fc);
  1173. }
  1174. return fSuccess;
  1175. }
  1176. #else // TryPaintDIB
  1177. BOOL CVideoWindow::CopyToClipboard()
  1178. {
  1179. FRAMECONTEXT fc;
  1180. BOOL fSuccess = FALSE;
  1181. if (S_OK == GetFrame(&fc))
  1182. {
  1183. if (OpenClipboard(GetWindow()))
  1184. {
  1185. EmptyClipboard();
  1186. {
  1187. HGLOBAL hCopy;
  1188. BITMAPINFOHEADER *pbmih;
  1189. pbmih = &fc.lpbmi->bmiHeader;
  1190. hCopy = GlobalAlloc(GHND, DibSize(pbmih));
  1191. if (NULL != hCopy)
  1192. {
  1193. LPVOID lpvCopy = GlobalLock(hCopy);
  1194. int nHdrSize = DibHdrSize(pbmih);
  1195. CopyMemory(lpvCopy, pbmih, nHdrSize);
  1196. CopyMemory((LPBYTE)lpvCopy + nHdrSize, fc.lpData, DibDataSize(pbmih));
  1197. GlobalUnlock(hCopy);
  1198. fSuccess = (NULL != SetClipboardData(CF_DIB, (HANDLE)hCopy));
  1199. if (!fSuccess)
  1200. {
  1201. GlobalFree(hCopy);
  1202. }
  1203. }
  1204. }
  1205. CloseClipboard();
  1206. }
  1207. ReleaseFrame(&fc);
  1208. }
  1209. return fSuccess;
  1210. }
  1211. #endif // TryPaintDIB
  1212. HRESULT CVideoWindow::GetFrame(FRAMECONTEXT *pFrameContext)
  1213. {
  1214. HRESULT hr = E_FAIL;
  1215. if (NULL != m_pActiveChannel)
  1216. {
  1217. hr = m_pActiveChannel->GetProperty(NM_VIDPROP_FRAME, (DWORD_PTR *)pFrameContext);
  1218. }
  1219. return hr;
  1220. }
  1221. HRESULT CVideoWindow::ReleaseFrame(FRAMECONTEXT *pFrameContext)
  1222. {
  1223. HRESULT hr = E_FAIL;
  1224. if (NULL != m_pActiveChannel)
  1225. {
  1226. hr = m_pActiveChannel->SetProperty(NM_VIDPROP_FRAME, (DWORD_PTR)pFrameContext);
  1227. }
  1228. return hr;
  1229. }
  1230. void CVideoWindow::SaveSettings()
  1231. {
  1232. RegEntry re( IsLocal() ? VIDEO_LOCAL_KEY : VIDEO_REMOTE_KEY,
  1233. HKEY_CURRENT_USER );
  1234. re.SetValue(REGVAL_VIDEO_FRAME_SIZE, m_dwFrameSize);
  1235. if (!IsLocal())
  1236. {
  1237. re.SetValue(REGVAL_VIDEO_QUALITY, m_dwImageQuality);
  1238. }
  1239. else
  1240. {
  1241. re.SetValue(REGVAL_VIDEO_MIRROR, GetMirror());
  1242. }
  1243. }
  1244. VOID CVideoWindow::ForwardSysChangeMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
  1245. {
  1246. switch (uMsg)
  1247. {
  1248. case WM_PALETTECHANGED:
  1249. OnPaletteChanged();
  1250. break;
  1251. }
  1252. }
  1253. VOID CVideoWindow::OnPaletteChanged(void)
  1254. {
  1255. ::RedrawWindow(GetWindow(), NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
  1256. }
  1257. BOOL CVideoWindow::HasDialog(DWORD dwDialog)
  1258. {
  1259. DWORD_PTR dwDialogs = 0;
  1260. if (NULL != m_pActiveChannel)
  1261. {
  1262. m_pActiveChannel->GetProperty(NM_VIDPROP_CAMERA_DIALOG, &dwDialogs);
  1263. }
  1264. return (BOOL)(dwDialogs & dwDialog);
  1265. }
  1266. VOID CVideoWindow::ShowDialog(DWORD dwDialog)
  1267. {
  1268. if (NULL != m_pActiveChannel)
  1269. {
  1270. m_pActiveChannel->SetProperty(NM_VIDPROP_CAMERA_DIALOG, dwDialog);
  1271. }
  1272. }
  1273. BOOL CVideoWindow::InitMirroring(RECT &rcVideo)
  1274. {
  1275. HDC hdcWindow;
  1276. if ((m_hBitmapMirror != NULL) &&
  1277. (RectWidth(rcVideo) == m_sizeBitmapMirror.cx) &&
  1278. (RectHeight(rcVideo) == m_sizeBitmapMirror.cy))
  1279. {
  1280. return TRUE;
  1281. }
  1282. hdcWindow = ::GetDC(NULL);
  1283. UnInitMirroring();
  1284. m_hBitmapMirror = ::CreateCompatibleBitmap(hdcWindow, RectWidth(rcVideo), RectHeight(rcVideo));
  1285. if (m_hBitmapMirror == NULL)
  1286. {
  1287. ReleaseDC(NULL, hdcWindow);
  1288. return FALSE;
  1289. }
  1290. m_hDCMirror = ::CreateCompatibleDC(hdcWindow);
  1291. if (m_hDCMirror == NULL)
  1292. {
  1293. UnInitMirroring();
  1294. ReleaseDC(NULL, hdcWindow);
  1295. return FALSE;
  1296. }
  1297. // preserve the handle of the object being replaced
  1298. m_hGDIObj = ::SelectObject(m_hDCMirror, m_hBitmapMirror);
  1299. ::SetMapMode(m_hDCMirror, GetMapMode(hdcWindow));
  1300. m_sizeBitmapMirror.cx = RectWidth(rcVideo);
  1301. m_sizeBitmapMirror.cy = RectHeight(rcVideo);
  1302. ReleaseDC(NULL, hdcWindow);
  1303. return TRUE;
  1304. }
  1305. VOID CVideoWindow::UnInitMirroring()
  1306. {
  1307. if (m_hBitmapMirror)
  1308. {
  1309. if (m_hDCMirror)
  1310. {
  1311. ::SelectObject(m_hDCMirror, m_hGDIObj);
  1312. }
  1313. ::DeleteObject(m_hBitmapMirror);
  1314. m_hBitmapMirror = NULL;
  1315. }
  1316. if (m_hDCMirror)
  1317. {
  1318. ::DeleteObject(m_hDCMirror);
  1319. m_hDCMirror = NULL;
  1320. }
  1321. }
  1322. VOID CVideoWindow::InvalidateAll()
  1323. {
  1324. for(int i = g_pVideos->GetSize()-1; i >= 0 ; --i)
  1325. {
  1326. CVideoWindow *pVideo = (*g_pVideos)[i];
  1327. HWND hwnd = pVideo->GetWindow();
  1328. if (NULL != hwnd)
  1329. {
  1330. InvalidateRect(hwnd, NULL, FALSE);
  1331. }
  1332. }
  1333. }
  1334. VOID CVideoWindow::SetMirror(BOOL bMirror)
  1335. {
  1336. bMirror = bMirror != FALSE;
  1337. if (g_fMirror != bMirror)
  1338. {
  1339. g_fMirror = bMirror;
  1340. InvalidateAll();
  1341. }
  1342. }
  1343. BOOL CVideoWindow::CanCopy()
  1344. {
  1345. BOOL bCopy = (IsXferEnabled() && IsLocal()) || IsConnected();
  1346. if (bCopy)
  1347. {
  1348. bCopy = FALSE;
  1349. FRAMECONTEXT fc;
  1350. if (S_OK == GetFrame(&fc))
  1351. {
  1352. BITMAPINFOHEADER *pbmih = &fc.lpbmi->bmiHeader;
  1353. bCopy = IsKnownDIBFormat(pbmih);
  1354. ReleaseFrame(&fc);
  1355. }
  1356. }
  1357. return(bCopy);
  1358. }
  1359. BOOL CVideoWindow::FDidNotDisplayIntelLogo()
  1360. {
  1361. return FALSE;
  1362. }
  1363. VOID CVideoWindow::DisplayIntelLogo( BOOL bDisplay )
  1364. {
  1365. }