MFC DLL PreTranslateMessage 导致的快捷键不响应的问题?

解决办法:

http://blog.sina.com.cn/s/blog_53d9f7e901000aef.html

http://zhidao.baidu.com/link?url=wl3LlUGz_oCQplgHV6vyf-c0dOsBW4xNa68dQJJL_KH1WcjaETEdTvPRlf3ZgdXQ3vKpKRKmHYYOL02mW2vDGtbVrc-4pJuvPXDB_tnJSKu

上面贴出了方法,自己也验证了。

但这篇文章说不解决的问题的方法,而是说说MFC 为什么要用PreTranslateMessage原因!

故事开始:最近在视频播放器的界面,界面用DUILIB开发,界面全部封装在DLL里面,发现不能过滤快捷键,当时也没有想为什么?,那问题来了,窗口消息只会发送对应的窗口处理函数里面去,那我怎么在一个窗口统一处理呢?这个时候我想到用键盘钩子去处理。直接用HOOK 键盘钩子获取按键消息,比喻回车全屏,空格暂定。后面想想其实想想 PreTranslateMessage其实也是做同样事情,你是否有感觉了,你仔细想你就会发现为什么MFC 里面有一个afxMapHWND
这个东西了,因为保存整个 window hwnd的列表。

因为HWND 只是窗口句柄,但并没用,我们处理所有事情都是在窗口类中处理,所以我们通过afxMapHWND  获取对应的实体类。

说了这个么多,我直接用代码说事情,

我们window核心 消息循环来说:

BOOL AFXAPI AfxInternalPumpMessage()
{
	_AFX_THREAD_STATE *pState = AfxGetThreadState();

	if (!::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))
	{
#ifdef _DEBUG
		TRACE(traceAppMsg, 1, "CWinThread::PumpMessage - Received WM_QUIT.\n");
			pState->m_nDisablePumpCount++; // application must die
#endif
		// Note: prevents calling message loop things in 'ExitInstance'
		// will never be decremented
		return FALSE;
	}

#ifdef _DEBUG
  if (pState->m_nDisablePumpCount != 0)
	{
	  TRACE(traceAppMsg, 0, "Error: CWinThread::PumpMessage called when not permitted.\n");
	  ASSERT(FALSE);
	}
#endif

#ifdef _DEBUG
	_AfxTraceMsg(_T("PumpMessage"), &(pState->m_msgCur));
#endif

  // process this message

	if (pState->m_msgCur.message != WM_KICKIDLE && !AfxPreTranslateMessage(&(pState->m_msgCur)))
	{
		::TranslateMessage(&(pState->m_msgCur));
		::DispatchMessage(&(pState->m_msgCur));
	}
  return TRUE;
}

这个代码和我们常写的win32代码和类似吧。

AfxPreTranslateMessage(&(pState->m_msgCur)
BOOL AfxInternalPreTranslateMessage(MSG* pMsg)
{
//	ASSERT_VALID(this);

	CWinThread *pThread = AfxGetThread();
	if( pThread )
	{
		// if this is a thread-message, short-circuit this function
		if (pMsg->hwnd == NULL && pThread->DispatchThreadMessageEx(pMsg))
			return TRUE;
	}

	// walk from target to main window
	CWnd* pMainWnd = AfxGetMainWnd();
	if (CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg))
		return TRUE;

	// in case of modeless dialogs, last chance route through main
	//   window's accelerator table
	if (pMainWnd != NULL)
	{
		 CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd);
		 if (pWnd->GetTopLevelParent() != pMainWnd)
			return pMainWnd->PreTranslateMessage(pMsg);
	}

	return FALSE;   // no special processing
}
BOOL PASCAL CWnd::WalkPreTranslateTree(HWND hWndStop, MSG* pMsg)
{
	ASSERT(hWndStop == NULL || ::IsWindow(hWndStop));
	ASSERT(pMsg != NULL);

	// walk from the target window up to the hWndStop window checking
	//  if any window wants to translate this message

	for (HWND hWnd = pMsg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
	{
		CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
		if (pWnd != NULL)
		{
			// target window is a C++ window
			if (pWnd->PreTranslateMessage(pMsg))
				return TRUE; // trapped by target window (eg: accelerators)
		}

		// got to hWndStop window without interest
		if (hWnd == hWndStop)
			break;
	}
	return FALSE;       // no special processing
}
CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg)

从pMsg->hwnd

处理这个消息,如果自己不处理,就要爸爸窗口处理,爸爸窗口不处理,就要爷爷窗口处理,如果都没有返回FALSE,另外的代码块处理。

如果窗口类实在exe里面这里就会正常处理了。但在DLL 里面

CWnd* pWnd = CWnd::FromHandlePermanent(hWnd); 代码就会问题了,因为MFC是模块分开的不同的。比喻DLL1 是模块1 DLL2模块2 exe也是另一个模块。每个模块都有自己的窗口类列表。。。所以我在exe不能遍历到你的dll里面的窗口的。所以才不能运行。
</pre><p></p><p></p><p>上面的<pre name="code" class="cpp">AfxInternalPreTranslateMessage

// in case of modeless dialogs, last chance route through main
	//   window's accelerator table
	if (pMainWnd != NULL)
	{
		 CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd);
		 if (pWnd->GetTopLevelParent() != pMainWnd)
			return pMainWnd->PreTranslateMessage(pMsg);
	}

如果上面还是没有处理,检测这个窗口不是WS_CHILD窗口的话就找他的归属的窗口去处理。

如果还没有归属者就找到最顶层窗口处理,反正就MFC就尽量找一个合适窗口来处理,总会找到一个合适来处理。

看代码还是看框架代码,一些代码细节代码看的真累,我现在看chromuni代码真新感觉有点累。。还是找自己感兴趣的模块看吧。

其实上面书了那么多,总结是 MFC 每一个模块保存窗口列表模块,每个模块独立。

______________________________________________________________________________________________

如果是我纯win32 去写这样的PreTranslateMessage 方式函数会怎么做呢? 我不用列表,在HWND 创建绑定一个数据结构,如果是用c++ 绑定 一个窗口c++ 类,如果c就绑定一个c的指针,这样就不会出现上面的模块的问题,但要考虑线程竞争的问题。所以MFC为什么要线程独立,模块独立的原因了。一旦多线程搞进来,很多东西就不能掌控了。

时间: 2024-08-01 12:49:17

MFC DLL PreTranslateMessage 导致的快捷键不响应的问题?的相关文章

如何在MFC DLL中向C#类发送消息

如何在MFC DLL中向C#类发送消息 一. 引言 由于Windows Message才是Windows平台的通用数据流通格式,故在跨语言传输数据时,Message是一个不错的选择,本文档将描述如何在MFC DLL中向C#窗口类发送消息. 二. 实现过程 1. 新建一个基于MFC的DLL工程,在工程作用是用于生成Dll库函数: 2. 在该工程中新增一个类,CMessager: 3. 在头文件中添加代码如下: 1 #define ZS_API extern "C" _declspec (

(转载)DLL动态链接库编程入门之二:非MFC DLL

上一节中讲解的是DLL概论及其调试和查看,本节将为大家详解非MFC DLL的相关内容.  1.一个简单的DLL 上一节给出了以静态链接库方式提供add函数接口的方法,接下来我们来看看怎样用动态链接库实现一个同样功能的add函数. 如图1,在VC++中new一个Win32 Dynamic-Link Library工程dllTest.注意不要选择MFC AppWizard(dll),因为用MFC AppWizard(dll)建立的将是后面要讲述的MFC动态链接库. 图1 建立一个非MFC DLL 在

解决Windows资源管理器右键菜单打开EditPlus容易导致资源管理器无响应问题

这个问题确实很烦人,经常导致 资源管理器无响应,关闭后整个资源管理器彻底崩溃,原因未知.本着折腾和强迫症精神,这个问题一定要解决.方法如下: 1.不要用EditPlus自带的添加到系统右键菜单选项. 2.导入下列注册表内容: Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\*\shell\EditPlus] @="EditPlus" "icon"="F:\\develop\\EditPlus\

因为计算机中丢失opencv_world310d.dll,导致opencv程序无法运行问题

运行opencv程序时,将代码从一台电脑移动到另一台电脑时,就提示如题目的问题:因为计算机中丢失opencv_world310d.dll,导致opencv程序无法运行问题 . 网上找了许多方式依然没用,说是64位电脑下  把自己opencv文件目录下的E:\openCV\opencv\build\x64\vc14\bin(本人的路径)中的三个dll文件,拷贝到 C:\window\SysWOW64 中.再去VS下运行即可,但发现依然没用. 用来又把这些dll文件拷贝到 C:\window\Sys

2015.3.3 VC++6制作MFC dll并在其中使用对话框、引入类的操作

上例建立的dll为非MFC的,不能使用MFC框架,如CString.对话框等类型,使用起来有一定限制.可以建立MFC的Dll来改进.建立MFC Dll的方法: 1.在VC6中新建工程时选择:MFC AppWizard(dll) 2.保持默认的 Regular Dll using shared MFC DLL完成. 3.此时生成的App具有.h .cpp两个文件,与上面只有.cpp有所不同 4.相同的是在.cpp文件中 添加函数 extern "C" __declspec(dllexpo

MFC DLL导出类

MFC DLL导出类 2011-06-15 10:54 2718人阅读 评论(0) 收藏 举报 dllmfcinterfaceparameterslibrarynull 方法1:   在VC上new一个名为dll的MFC DLL工程. 第一步,创建一个interface.h文件来定义接口,代码如下: //file interface.h #ifndef _INTERFACE_H_ #define _INTERFACE_H_ interface ITest { virtual int Print(

php使用fsockopen时,fwrite中的\r\n及\n结束符导致,smtp.qq.com响应出现问题

<?php $t= time(); $sk = fsockopen('tcp://smtp.qq.com',25, $errno, $errstr, 5); echo "sockect ok:".(time()-$t)."\n"; if ( ! is_resource($sk) ) exit('connect error:'. $errno." ".$errstr); //设置成阻塞模式 stream_set_blocking ($sk,1

如何制作带MFC界面的MFC DLL

最近在做基于组件化MFC界面的开发,需要把界面封装到动态库中. 一:工程创建步骤 1.创建MFC DLL工程,选择 “在共享 DLL 中使用 MFC”. 2.运行时库选择:c/c++-->代码生成-->运行库  “多线程调试 DLL (/MDd)”. 二:定义导出界面基类 定义导出界面接口类,待导出界面需要继承该接口类,并实现该接口定义的虚函数.如下: class IHpDllWin :public CDialog { public: // 构造函数,ID为窗口资源ID IHpDllWin(i

关于SpeedButton中使用下划线快捷键不响应的问题

在Windows应用程序,很多都有快捷键功能,这个Delphi也有,就是一个按钮上面有一个比如剪切(&X),这个时候剪切的快捷键就是Alt+X,这个功能有时候还是挺好用的,最近,公司中有同事,好些使用了SpeedButton,然后使用本方式整的快捷键,都不能用,于是问我,这个是神马问题,实际上确切的说,也不是不能用,而是在某些情况下不能用,比如说使用PageControl等一类控件,然后再TabSheet下面再放一个Panel,然后再Panel上放SpeedButton,这个时候,使用快捷键就会