OCX视频控件双击事件实现

本文介绍了一种在OCX控件中实现双击鼠标放大和缩小视频播放窗口的方法。通过设置钩子和禁用VLC播放器子窗口事件,解决了播放RTSP视频流时双击事件丢失的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我的OCX控件是利用LIBVLC库写的,为了实现鼠标双击放大缩小功能,折腾了我一天时间。下面记录下解决经历。

1、首先,在网上能找到的方法是用钩子的方法:

钩子生成方法:

/*定义全局钩子*/
static  HHOOK hHook = NULL;

/*回调接口*/
LRESULT CALLBACK GetMessageProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());//模块切换时的状态保护指向当前模块状态
	LPMSG lpMsg = (LPMSG)lParam;
	if ((nCode >= 0) && (PM_REMOVE == wParam) &&
		AfxGetApp()->PreTranslateMessage(lpMsg))
	{
		lpMsg->message = WM_NULL;
		lpMsg->lParam = 0L;
		lpMsg->wParam = 0;
	}
	// 将钩子消息传递给当前钩子链中的下一个钩子
	return ::CallNextHookEx(hHook, nCode, wParam, lParam);
}

接着可以在你的对话框ONCREATE内加入设置钩子的实现:

// CMainDialog message handlers

int CMainDialog::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CDialog::OnCreate(lpCreateStruct) == -1)
		return -1;

	hHook = ::SetWindowsHookEx(WH_GETMESSAGE, GetMessageProc,
		AfxGetInstanceHandle(), GetCurrentThreadId());

	return 0;
}

OK,钩子设置好了,后面重载pretranslateMessage方法:

BOOL CMainDialog::PreTranslateMessage(MSG* pMsg)
{
	// TODO: 在此添加专用代码和/或调用基类  
	//MessageBox(_T("PreTranslateMessage"));
	if (pMsg->message == WM_LBUTTONDBLCLK) //处理鼠标左键双击事件响应
	{
		CWnd *pWnd = FromHandle(pMsg->hwnd);
		//MessageBox(_T("Get hook"));
		if (!m_bFullScreen)
		{
			m_hWndParent = GetParent()->m_hWnd;
			m_bFullScreen = TRUE;
		}
		::SendMessage(m_hWndParent, WM_LBUTTONDBLCLK, 0, 0);//在此向父窗口传递双击事件消息,交给父窗口来处理
	}
	return CDialog::PreTranslateMessage(pMsg);//其它消息在此不响应,交给父对话框处理
}

最后,在父窗口类里加入双击事件的响应即可。 至此,钩子生成完毕,测试时发现,当插件没有播放RTSP视频流数据时,它能正确的将消息捕获,这没什么问题。然而,当我进行了视频流播放时,发现双击事件怎么都不响应,钩子并没有捕获到此事件。

后来经过大量的GOOGLE后,才找到原因,原来我用的控件是用VLC库实现的,而VLC在播放时,它有自己的一套消息处理机制,或者直白的说就是消息被VLC给吞掉了,所以在顶层窗口上捕获不到。

GOOGLE给出的方法如下:

// First step is start a timer when you play a video,

// Second step : in the timer function i call :
EnumChildWindows(MyWindow_HWND, EnumerateVLC, NULL);

// Third step : if EnumerateVlc get some child window these window is the VlcEventWindow, and need disable it, to reach mouse events on MyWindow
BOOL CALLBACK EnumerateVLC(HWND hWndvlc, LPARAM lParam) {
   EnableWindow(hWndvlc, FALSE); 
   // And kill timer, i only need get this handle one time.
   return TRUE;
}

// When EnumerateVLC is called all mouse events are redirected to MyWindow

OK,照着前人的步骤进行,1、先新建一个定时器,作用是VLC在播放实例是需要时间的,留出些时间给它正常开始播放。2、在定时器处理函数里,用EnumChildWindows接口去找到其所有的子窗口,回调接口EnumerateVLC,禁用子窗口来响应事件,即可由本窗口进行响应了。 3、关闭定时器。

这样子修改后,发现在播放过程中,小窗口能响应我的双击事件了,哈哈。

双击处理接口也给出吧:

ULONG CMyActiveXCtrl::setVideoFullscreen(void)
{
	SetFocus();
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	// TODO: 在此添加调度处理程序代码
	if(video_mp == NULL)
		return -1;
	if( libvlc_media_player_has_vout(video_mp) < 1)
		return -1;

	 if(!m_bFullScreen)
	 {//双击窗口时,放大到全屏
		 //SetFocus();
		 //获取控件窗口的绝对位置
		  GetWindowRect(m_rcCtrlRect);  
		  ::SetParent(m_MainDialog.GetSafeHwnd(),::GetDesktopWindow());//将父窗口设置成桌面窗口,即顶层显示
		  
		  int cx = ::GetSystemMetrics(SM_CXFULLSCREEN);//屏幕分辨率
		  int cy = ::GetSystemMetrics(SM_CYFULLSCREEN);

		  MoveWindow(0, 0, cx, cy);
		  ::SetWindowPos(m_MainDialog.GetSafeHwnd(),HWND_TOPMOST,0,0,cx,cy,SWP_FRAMECHANGED|SWP_DEFERERASE); //全屏
		  m_bFullScreen = TRUE;	  
	 }
	 else
	 {//双击全屏窗口时,缩小到原来的尺寸
		  ::SetParent(m_MainDialog.GetSafeHwnd(),m_hWnd);  //
		 //MoveWindow使用相对窗口坐标,所以必须先转化为相对坐标
		  CPoint LeftTop(m_rcCtrlRect.TopLeft());
		  CPoint BottomRight(m_rcCtrlRect.BottomRight());
		  ::ScreenToClient(m_hWnd,&LeftTop); 
		  ::ScreenToClient(m_hWnd,&BottomRight); 

		  ::MoveWindow(m_hWnd,LeftTop.x,LeftTop.y,m_rcCtrlRect.Width(),m_rcCtrlRect.Height(),TRUE);
		  ::SetWindowPos(m_MainDialog.GetSafeHwnd(),HWND_NOTOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);//缩小到正常尺寸
		  m_bFullScreen = FALSE;
	 } 
	 InvalidateRect(false);//刷新显示
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值