消息处理函数的转移

本文介绍如何使用 SetWindowLong 函数替换 Windows CE 中窗口的消息处理函数,并提供了一个简单示例,演示如何在 EditBox 控件输入特定字符时触发自定义行为。

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

//========================================================================
//TITLE:
// 消息处理函数的转移
//AUTHOR:
// norains
//DATE:
// Wednesday 03-January-2008
//Environment:
// VS2005 + SDK-WINCE5.0-MIPSII
// EVC + SDK-WINCE5.0-MIPSII
//========================================================================

Windows CE有一个很有意思的API函数,通过SetWindowLong函数可以转移原窗口的消息处理函数为自定义的.敏感的朋友估计一看见,就已经明白可以做什么了.呵呵,难道不是么?


1.函数使用

SetWindowLong的使用及其简单,比如我们将m_hEdWord窗口的消息处理函数置换为CtrlProc:

SetWindowLong(m_hEdWord,GWL_WNDPROC,(DWORD)CtrlProc);

就这么简单,现在只要m_hEdWord窗口收到消息,那么就会自动调用预先定义的CtrlProc.

有设置,自然也有获取,不过这次我们是通过GetWindowLong函数:
m_pPreProcEdWord=(WNDPROC)GetWindowLong(m_hEdWord,GWL_WNDPROC);

现在m_pPreProcEdWord存储的就是目前m_hEdWord的消息处理函数地址.不过,其实通过SetWindowLong函数也能获取消息函数地址:
m_pPreProcEdWord=SetWindowLong(m_hEdWord,GWL_WNDPROC,(DWORD)CtrlProc);

不过这时候获取的却是在设置CtrlProc消息处理函数之前的函数地址.也就是说,这两段代码中m_pPreProcEdWord等价:
1).
m_pPreProcEdWord
=SetWindowLong(m_hEdWord,GWL_WNDPROC,(DWORD)CtrlProc);

2).
m_pPreProcEdWord
=(WNDPROC)GetWindowLong(m_hEdWord,GWL_WNDPROC);
SetWindowLong(m_hEdWord,GWL_WNDPROC,(DWORD)CtrlProc);

如果需要调用m_pPreProcEdWord指向的函数,则需要用上CallWindowProc:
CallWindowProc(m_pPreProcEdWord,hWnd,wMsg,wParam,lParam);


2.接管Windows Control消息

说了一大堆似乎很有哲理的话,现在就让我们来看看有什么实际的作用吧.

估计这个函数用得最多是在Windows Control中.比如,你想在Edit Box输入某个字符时做一些特殊处理,只能通过SetWindowLong来置换内部的处理函数进而调用自己的特殊处理函数.

我们来举一个非常简单的例子,首先创建一个Edit Box控件,如果在该控件中按下键盘的"ESC",则会退出应用程序.为了方便突出问题的重点,我们的CMainWnd窗口继承于CWndBase(关于CWndBase请见:http://blog.youkuaiyun.com/norains/archive/2007/11/10/1878218.aspx)

#pragmaonce
#include
"wndbase.h"

classCMainWnd:
publicCWndBase
{
public:
CMainWnd(
void);
~CMainWnd(void);
BOOLCreate(HINSTANCEhInst,HWNDhWndParent,
constTCHAR*pcszWndClass,constTCHAR*pcszWndName);

protected:
staticLRESULTCtrlProc(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam);

private:
HWNDm_hEdWord;
//Thewindowisforinputingtheword
WNDPROCm_pPreProcEdWord;//Pointertothepreviouswindowprocedurefortheinputwordwindow.
};



#include
"stdafx.h"
#include
"MainWnd.h"

//---------------------------------------------------------------------------------------
//Defaultvalue
#defineIDC_EDIT_WORD101


//////////////////////////////////////////////////////////////////////
//Construction/Destruction
//////////////////////////////////////////////////////////////////////
CMainWnd::CMainWnd(void)
{
}

CMainWnd::
~CMainWnd(void)
{
}


//----------------------------------------------------------------------
//Description:
//Createthewindow.It'soverridefunction
//
//----------------------------------------------------------------------
BOOLCMainWnd::Create(HINSTANCEhInst,HWNDhWndParent,constTCHAR*pcszWndClass,constTCHAR*pcszWndName)
{
if(CWndBase::Create(hInst,hWndParent,pcszWndClass,pcszWndName)==FALSE)
{
returnFALSE;
}

//Theeditwindowforinputtheword
m_hEdWord=CreateWindowEx(WS_EX_TOPMOST,
TEXT(
"EDIT"),
TEXT(
""),
ES_LEFT
|WS_TABSTOP|WS_VISIBLE|WS_CHILD|WS_BORDER,
GetSystemMetrics(SM_CXSCREEN)
/3,
GetSystemMetrics(SM_CYSCREEN)
/3,
GetSystemMetrics(SM_CXSCREEN)
/3,
GetSystemMetrics(SM_CYSCREEN)
/3,
m_hWnd,
(HMENU)IDC_EDIT_WORD,
m_hInst,
NULL);

//Storethepointerinthewindow
SetWindowLong(m_hEdWord,GWL_USERDATA,(DWORD)this);
//Getthepreviouswindowprocedure
m_pPreProcEdWord=(WNDPROC)GetWindowLong(m_hEdWord,GWL_WNDPROC);
//Setthenewwindowprocedure
SetWindowLong(m_hEdWord,GWL_WNDPROC,(DWORD)CtrlProc);

returnTRUE;
}


//----------------------------------------------------------------------
//Description:
//Windowscontrolprocess.
//
//----------------------------------------------------------------------
LRESULTCMainWnd::CtrlProc(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam)
{
CMainWnd
*pObject=(CMainWnd*)GetWindowLong(hWnd,GWL_USERDATA);

if(pObject->m_hEdWord==hWnd)
{
switch(wMsg)
{
caseWM_CHAR:
{
if((TCHAR)wParam==VK_ESCAPE)
{
PostQuitMessage(
0x00);
}
break;
}
}
returnCallWindowProc(pObject->m_pPreProcEdWord,hWnd,wMsg,wParam,lParam);
}


//Itshouldnevergethere!
returnDefWindowProc(hWnd,wMsg,wParam,lParam);
}


程序代码段很短,但有几点需要注意的地方.

CtrlProc是我们用来置换原有过程的消息处理函数,因为CtrlProc为静态才能回调,而静态函数无法调用成员变量,所以我们在创建Edit Box实例之后在GWL_USERDATA地址存储了当前对象指针:

SetWindowLong(m_hEdWord,GWL_USERDATA,(DWORD)this);

然后在CtrlProc函数中获取存储在GWL_USERDATA中的对象指针,用该指针调用成员变量及函数:

CMainWnd*pObject=(CMainWnd*)GetWindowLong(hWnd,GWL_USERDATA);

因为我们只是处理WM_CHAR消息,其它消息都采用默认处理方式,所以直接返回调用先前的消息函数:

returnCallWindowProc(pObject->m_pPreProcEdWord,hWnd,wMsg,wParam,lParam);

这个例子很简单,该工程可以在此下载:http://download.youkuaiyun.com/source/324833


3.系统必崩溃代码

如果将消息处理函数处理转移到已经释放的内存上,那么会有什么结果呢?结果就是,系统崩溃!有兴趣的朋友可以试试这段代码:

LRESULTMyProc(HWNDhWnd,UINTwMsg,WPARAMwParam,LPARAMlParam)
{
returnDefWindowProc(hWnd,wMsg,wParam,lParam);
}

intWINAPIWinMain(HINSTANCEhInstance,
HINSTANCEhPrevInstance,
LPTSTRlpCmdLine,
intnCmdShow)
{
//TODO:Placecodehere.

HWNDhWnd
=GetForegroundWindow();
SetWindowLong(hWnd,GWL_WNDPROC,(DWORD)MyProc);
return0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值