求助:窗口过程的问题!

qingsebaobei 2009-08-06 10:50:06
#include <windows.h>

#define ID_LIST 1

#define DIRATTR (DDL_READWRITE|DDL_READONLY| DDL_SYSTEM |DDL_DIRECTORY)
LRESULT CALLBACK listproc(HWND,UINT,WPARAM,LPARAM);
LRESULT CALLBACK WinProc(HWND,UINT,WPARAM,LPARAM);
WNDPROC oldproc;
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
static TCHAR szAppName[]=TEXT("MyApp");
MSG msg;
HWND hwnd;
WNDCLASS wndcls;
wndcls.cbClsExtra=0;
wndcls.cbWndExtra=0;
wndcls.hbrBackground=(HBRUSH)GetStockObject(COLOR_BTNFACE+1);
wndcls.hCursor=LoadCursor(NULL,IDC_ARROW);
wndcls.hIcon=LoadIcon(NULL,NULL);
wndcls.hInstance=hInstance;
wndcls.lpfnWndProc=WinProc;
wndcls.lpszClassName=szAppName;
wndcls.lpszMenuName=NULL;
wndcls.style=CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wndcls);
hwnd=CreateWindow(szAppName,"app",
WS_CAPTION | WS_SYSMENU,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,SW_SHOWNORMAL);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_CREATE:
hwndlist=CreateWindow(TEXT("listbox"),NULL,WS_CHILDWINDOW|WS_VISIBLE|LBS_STANDARD | WS_BORDER,
150,45,180,200,hwnd,(HMENU)ID_LIST,(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),NULL);

oldproc=(WNDPROC)SetWindowLong(hwndlist,GWL_WNDPROC,(LPARAM)listproc);
return 0;
case WM_PAINT:
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd,message,wParam,lParam);
}
return 0;
}


LRESULT CALLBACK listproc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)
{
if((message==WM_KEYDOWN)&&(wparam==VK_RETURN))
SendMessage(GetParent(hwnd),WM_COMMAND,MAKELONG(1,LBN_DBLCLK),(LPARAM)hwnd);
return CallWindowProc(oldproc,hwnd,message,wparam,lparam);
}

oldproc=(WNDPROC)SetWindowLong(hwndlist,GWL_WNDPROC,(LPARAM)listproc);
这个意思是说将hwndlist的窗口过程换成listproc而不用主窗口的窗口过程吗?

return CallWindowProc(oldproc,hwnd,message,wparam,lparam);
那这个oldproc又是什么意思呢?oldproc不是在上面等于listproc。可是我看有的地方说
是如在本程序中只处理if((message==WM_KEYDOWN)&&(wparam==VK_RETURN))这个,其他消息
就交给上一个窗口过程程序。这上一个窗口过程我理解可能是主窗口的处理程序。只是这里
用oldproc=(WNDPROC)SetWindowLong(hwndlist,GWL_WNDPROC,(LPARAM)listproc);后将hwndlist
这个子窗口的窗口过程从WndProc换成了listproc.但return CallWindowProc(oldproc,hwnd,message,wparam,lparam);
我又不明白了,我认为应该是CallWindowProc(Wndproc,hwnd,message,wparam,lparam);
这样才是把消息发给以前的窗口过程,就是父窗口处理程序才对啊。
各位友友谁能给我解释一下SetWindowLong和CallWindowProc
到底是怎么是怎么换窗口过程,又是怎么把不处理的消息交给以前的窗口过程处理的,
谢谢大家了。
...全文
166 11 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
scsnsjsl_cs_dn 2009-08-09
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 wltg2001 的回复:]
oldproc=(WNDPROC)SetWindowLong(hwndlist,GWL_WNDPROC,(LPARAM)listproc); 这个API的功能是将窗口的处理函数进行修改,上面的作用是将list控件的处理过程由窗口类指定的默认处理过程改为listproc,上面这个做法一般又叫做窗口子类化,也就是将默认的处理过程改成你自定义的过程,它的返回值oldproc是一个函数指针,针向原来的窗口处理函数,也就是说,现在oldproc现在相当于是这个控件的默认处理函数了。之所以这样做,是因为窗口子类化一般只是用来处理一些特殊消息,对特殊消息作特殊处理,上面的例子从代码上看是想对键盘的回车键进行特殊处理,从代码上看它是想将回车模拟成鼠标双击事件,所以在它的处理函数中用SendMessage向父窗口发送消息。
在窗口子类化中,对于它不处理的消息,还是要由原来的处理函数进行处理,原来的处理函数由oldproc保存着呢,所以最后调用return CallWindowProc(listproc,hwnd,message,wparam,lparam)
楼主两个地方理解错了,一个是oldproc是什么不知道,它是由SetWindowLong返回的,并不是listproc,而控件的原来的内置处理函数
第二个错误在于:其他消息就交给上一个窗口过程程序。这上一个窗口过程我理解可能是主窗口的处理程序。
这里上一个窗口过程不是主窗口处理程序,而是控件本身内置的处理过程。
[/Quote]
wltg2001 2009-08-07
  • 打赏
  • 举报
回复
我看楼主没有明白是每一个控件本身也是窗口,所以每个控件本身在系统内部有一个窗口处理过程,楼主可能没有意识到这个内置的窗口处理过程,将它和父窗口处理过程弄混了。
xylicon 2009-08-07
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 qingsebaobei 的回复:]
是不是这样。
就是在Listproc 里只拦截if((message==WM_KEYDOWN)&&(wparam==VK_RETURN))
这个消息,如果是这个消息就处理。如果不是这个消息就交个WndProc来处理。
大概是这个意思吗?

[/Quote]

交不交给原来的窗口过程。是你决定的,你调用了return CallWindowProc(oldproc,hwnd,message,wparam,lparam); 就交给原来的窗口过程,要是return 0或者其他值,就不会再交给原来的窗口过程处理了。

[Quote=引用 6 楼 qingsebaobei 的回复:]
当程序的子窗口 收到消息 全部交给 ListProc来处理。而在ListProc只处理按下接盘回车键。如果是
别的消息,就通过CallWindowProc将这个消息交给WndProc就是父窗口的处理程序来处理?
[/Quote]
按照你的代码来看
LRESULT CALLBACK listproc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam) 
{
if((message==WM_KEYDOWN)&&(wparam==VK_RETURN))
SendMessage(GetParent(hwnd),WM_COMMAND,MAKELONG(1,LBN_DBLCLK),(LPARAM)hwnd);
return CallWindowProc(oldproc,hwnd,message,wparam,lparam);
}


是当程序的子窗口 收到消息,先到listproc中去处理,然后再return CallWindowProc(oldproc,hwnd,message,wparam,lparam);
到oldproc去处理。

也就是说,拦截消息处理完后,还是交给oldproc的。即使if((message==WM_KEYDOWN)&&(wparam==VK_RETURN)) 是这2个消息在listproc中处理过了,但还是会在oldproc中去处理一次。
见习学术士 2009-08-07
  • 打赏
  • 举报
回复
看来楼主明白了
wltg2001 2009-08-07
  • 打赏
  • 举报
回复
oldproc=(WNDPROC)SetWindowLong(hwndlist,GWL_WNDPROC,(LPARAM)listproc); 这个API的功能是将窗口的处理函数进行修改,上面的作用是将list控件的处理过程由窗口类指定的默认处理过程改为listproc,上面这个做法一般又叫做窗口子类化,也就是将默认的处理过程改成你自定义的过程,它的返回值oldproc是一个函数指针,针向原来的窗口处理函数,也就是说,现在oldproc现在相当于是这个控件的默认处理函数了。之所以这样做,是因为窗口子类化一般只是用来处理一些特殊消息,对特殊消息作特殊处理,上面的例子从代码上看是想对键盘的回车键进行特殊处理,从代码上看它是想将回车模拟成鼠标双击事件,所以在它的处理函数中用SendMessage向父窗口发送消息。
在窗口子类化中,对于它不处理的消息,还是要由原来的处理函数进行处理,原来的处理函数由oldproc保存着呢,所以最后调用return CallWindowProc(listproc,hwnd,message,wparam,lparam)
楼主两个地方理解错了,一个是oldproc是什么不知道,它是由SetWindowLong返回的,并不是listproc,而控件的原来的内置处理函数
第二个错误在于:其他消息就交给上一个窗口过程程序。这上一个窗口过程我理解可能是主窗口的处理程序。
这里上一个窗口过程不是主窗口处理程序,而是控件本身内置的处理过程。
qingsebaobei 2009-08-07
  • 打赏
  • 举报
回复
当程序的子窗口 收到消息 全部交给 ListProc来处理。而在ListProc只处理按下接盘回车键。如果是
别的消息,就通过CallWindowProc将这个消息交给WndProc就是父窗口的处理程序来处理?
qingsebaobei 2009-08-07
  • 打赏
  • 举报
回复
是不是这样。
就是在Listproc 里只拦截if((message==WM_KEYDOWN)&&(wparam==VK_RETURN))
这个消息,如果是这个消息就处理。如果不是这个消息就交个WndProc来处理。
大概是这个意思吗?
jasonM2008 2009-08-07
  • 打赏
  • 举报
回复
oldproc=(WNDPROC)SetWindowLong(hwndlist,GWL_WNDPROC,(LPARAM)listproc);
这个意思是说将hwndlist的窗口过程换成listproc而不用主窗口的窗口过程吗?

不是不用主窗口过程,而是不用默认的listbox的窗口过程,用自己的窗口过程来替换!!

return CallWindowProc(oldproc,hwnd,message,wparam,lparam);
因为你在上一步骤把先前的LISTBOX的默认窗口过程替换了,这次是调用先前的窗口过程!!!
xylicon 2009-08-07
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 qingsebaobei 的回复:]
那return CallWindowProc(oldproc,hwnd,message,wparam,lparam);
中的oldproc就是Wndproc的地址吗?先前不是已经把oldproc=listproc,那现在再用
oldproc做参数不是就相当于
return CallWindowProc(listproc,hwnd,message,wparam,lparam); 吗?
[/Quote]

oldproc 是上一个窗口过程,也就是你这里用listproc的窗口过程拦截了窗口消息,而当你完成你的窗口过程之后,希望上一个窗口过程,也就是之前那个窗口过程也能得到处理,你就调用return CallWindowProc(oldproc,hwnd,message,wparam,lparam);

这个之前的窗口过程,一般是默认的窗口过程,所以这里调用return CallWindowProc(oldproc,hwnd,message,wparam,lparam);
是为了你的窗口的一些消息,特别是没被拦截的窗口消息得到默认的处理。
socoola 2009-08-07
  • 打赏
  • 举报
回复
SetWindowLong(hwndlist,GWL_WNDPROC,(LPARAM)listproc)返回的是替换之前的函数指针,而不是listproc
qingsebaobei 2009-08-07
  • 打赏
  • 举报
回复
那return CallWindowProc(oldproc,hwnd,message,wparam,lparam);
中的oldproc就是Wndproc的地址吗?先前不是已经把oldproc=listproc,那现在再用
oldproc做参数不是就相当于
return CallWindowProc(listproc,hwnd,message,wparam,lparam); 吗?

16,548

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧