深⼊解析C++的WNDCLASS结构体及其在Windows中的应⽤
WNDCLASS是⼀个由系统⽀持的结构,⽤来储存某⼀类窗⼝的信息,如ClassStyle,消息处理函数,Icon,Cursor,背景Brush等。也就是说,CreateWindow只是将某个WNDCLASS定义的窗体变成实例。要
得到某⼀窗⼝的WNDCLASS数据,可以⽤GetClassLong();
  RegisterClass()就是在系统注册某⼀类型的窗体。也就是将你提供的WNDCLASS数据注册为⼀个窗⼝类,在WNDCLASS.lpszClassName中定义该WNDCLASS的标识,⽆论CreateWindow或CreateWindowEx创建的窗⼝都必须对应⼀个WNDCLASS,但⼀个WNDCLASS可以有多个窗⼝对象。
  有⼀些系统预定义的窗⼝类,如:ClassName=_T("BUTTON" or "COMBOBOX" or "EDIT" or "LISTBOX" or "MDICLIENT" or "SCOLLBAR" or "STATIC"),要⽤这些窗体,直接⽤CreateWindow创
建相应对象就是了。要得到某⼀窗⼝的窗⼝类,可以⽤GetClassName();
  WNDCLASS中的回调函数是窗体的消息处理函数:CALLBACK WinProc(MESSAGE msg,LPARAM lparam,WPARAM wParam);
窗⼝类属性定义
  结构WNDCLASS包含⼀个窗⼝类的全部信息,也是Windows编程中使⽤的基本数据结构之⼀,应⽤程序通过定义⼀个窗⼝类确定窗⼝的属性,定义如下:
typedef struct _WNDCLASS {
  UINT style;
  WNDPROC lpfnWndProc;
  int cbClsExtra;
  int cbWndExtra;
  HINSTANCE hInstance;
  HICON hIcon;
  HCURSOR hCursor;
  HBRUSH hbrBackground;
  LPCTSTR lpszMenuName;
  LPCTSTR lpszClassName;
  } WNDCLASS, *PWNDCLASS;
举例说明
例⼦:
long CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);//声明
//WinMain函数是所有Windows应⽤程序的⼊⼝,类似c语⾔中的main函数其功能是完成//⼀系列的定义和初始化,并产⽣消息循环。函数说明:
int WINAPI WinMain(HINSTANCE hInstance,    // handle to current instance
              HINSTANCE hPrevInstance, // handle to previous instance
              LPSTR lpCmdLine,      // command line
                int nCmdShow          // show state
)
{
//初始化,初始化包括窗⼝类的定义、注册、创建窗⼝实例和显⽰窗⼝四部分
  HWND hwnd;
  MSG Msg;
  WNDCLASS wndclass;
  char lpszClassName[]="窗⼝"; //窗⼝类名
  char lpszTitle[]="测试窗⼝"; //窗⼝标题名
  //窗⼝类定义,窗⼝类定义了窗⼝的形式与功能,窗⼝类定义通过给窗⼝类数据结构WNDCLASS赋值完成
  //该数据结构中包含窗⼝类的各种属性
  wndclass.style =0; // 窗⼝类型为缺省类型CS_  Class Style
  wndclass.lpfnWndProc=WndProc; //定义窗⼝处理函数
  wndclass.cbClsExtra=0; //窗⼝类⽆扩展
  wndclass.cbWndExtra=0; //窗⼝实例⽆扩展
  wndclass.hInstance=hInstance; //当前实例句柄
  wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION); //窗⼝的最⼩化图标为缺省图标
  wndclass.hCursor=LoadCursor(NULL,IDC_ARROW); // 窗⼝采⽤箭头光标
  wndclass.hbrBackground=(HBRUSH)(GetStockObject(WHITE_BRUSH)); //窗⼝背景为⽩⾊
  wndclass.lpszMenuName=NULL; //窗⼝⽆菜单
  wndclass.lpszClassName=lpszClassName; //窗⼝类名为“窗⼝”
  //以下是窗⼝类的注册-----------Windows系统本⾝提供部分预定义的窗⼝类,程序员也可以⾃定义窗⼝类,窗⼝类必须先注册后使⽤。
  if(!RegisterClass(&wndclass)) //如果注册失败发出警告
    {MessageBeep(0); return FALSE;}
  //创建窗⼝创建⼀个窗⼝的实例由函数CreateWindow()实现
  hwnd=CreateWindow( lpszClassName, //窗⼝类名,创建窗⼝时⼀定要基于我们已经注册过的窗⼝类名,即"窗⼝"。
                    lpszTitle, //窗⼝标题名
                    WS_OVERLAPPEDWINDOW, //窗⼝的风格 WS_ Windows Style
                    CW_USEDEFAULT, //窗⼝左上⾓坐标值为缺省值 CW_ Create Wndow
  CW_USEDEFAULT,
  CW_USEDEFAULT, //窗⼝的⾼和宽为缺省值
CW_USEDEFAULT,
  NULL, //此窗⼝⽆⽗窗⼝
  NULL, //此窗⼝⽆⼦菜单
  hInstance, //创建此窗⼝的应⽤程序的当前句柄
  NULL //不使⽤该值
  );
  //显⽰窗⼝
  ShowWindow(hwnd,nCmdShow);
  //绘制⽤户区
  UpdateWindow(hwnd);
  //消息循环
  while(GetMessage(&Msg,NULL,0,0)) //GetMessage()函数是从调⽤线程的消息队列中取出⼀条消息;对于每⼀个应⽤程序窗⼝线程,操作系统都会为其建⽴⼀个消息队列,当我们的窗⼝有消息时(即所有与这个窗⼝线程相关的消息),操纵系统会把这个消息放  {
  TranslateMessage(&Msg);//对"消息对"的转化,如对键盘的WM_KEYDOWN和WM_KEYUP消息对转化为WM_CHAR消息,并且将转换后的新消息投递到我们的消息队列中去,这个转化操作不会影响原来的消息,只会产⽣⼀个新的消息。
  DispatchMessage(&Msg);//DispatchMessage()函数是将我们取出的消息传到窗⼝的回调函数去处理;可以理解为该函数将取出的消息路由给操作系统,然后操作系统去调⽤我们的窗⼝回调函数对这个消息进⾏处理。
}
  return Msg.wParam; //消息循环结束即程序结束时将信息返回系统
}
//窗⼝函数,窗⼝函数定义了应⽤程序对接收到的不同消息的响应,其中包含了应⽤程序对各种可能接受到的消息的处理过程,时消息处理分⽀控制语句的集合
long CALLBACK WndProc(HWND hwnd,
                  UINT message,
                    WPARAM wParam,
LPARAM lParam)
{
  switch(message)
  {
    case WM_DESTROY:
      PostQuitMessage(0);
    default: //缺省时采⽤系统消息缺省处理函数
      return DefWindowProc(hwnd,message,wParam,lParam);
  }
  return (0);
}
注:窗⼝回调函数的函数指针定义typedef LRESULT CALLBACK  (* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
结构体sizeofWNDPROC OldWndProc;
LRESULT CALLBACK NewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
switch (Msg)
{
......
}
return CallWindowProc(OldWndProc,g_Wnd,Msg,wParam,lParam);
}
OldWndProc = (WNDPROC)GetWindowLong(g_Wnd,GWL_WNDPROC);
SetWindowLong(hwnd, GWL_WNDPROC,(LPARAM)(WNDPROC)NewWndProc);
通过调⽤SetWindowLong函数可以修改该窗体类的回调函数。
CallBack 函数中的wParam和lParam有什么区别:
WPARAM  wParam,    定义成WORD型
LPARAM  lParam        定义成LONG型
在Win 3.x中,WPARAM是16位的,⽽LPARAM是32位的,两者有明显的区别。
在Win32 API中,WPARAM和LPARAM都是32位,所以没有什么本质的区别。
但是习惯上,我们愿意使⽤LPARAM传递地址,⽽WPARAM传递其他参数。
function MouseHookProc(nCode: Integer; wPar: WPARAM; lPar: LPARAM): lResult; stdcall;
如果我要判断⿏标左键是否按下,⽤wParam==WM_LBUTTONDOWN判断.
lParam 是 (tagMOUSEHOOKSTRUCT的指针)PMouseHookStruct类型,主要是获得发送窗⼝句柄,⿏标坐标,以及其他⼀些信息。
lParam ⽤的时候需要强制转换,转换成PMouseHookStruct类型.
PMouseHookStruct = ^TMouseHookStruct;
tagMOUSEHOOKSTRUCT = packed record
pt: TPoint;
hwnd: HWND;
wHitTestCode: UINT;
dwExtraInfo: DWORD;
end;
TMouseHookStruct = tagMOUSEHOOKSTRUCT;
例如:
function GetMsgProc(nCode: Integer; wPara: WPARAM; lPara: LPARAM)
: lResult; stdcall;
var
hGetMsgHook:HHOOK;
Msg: TMsg;
begin
if (nCode >= 0) then
begin
FillChar(pMsgData^, Sizeof(TMessageRecord), #0);
Msg := TMsg(Pointer(lPara)^);
end;
Result := CallNextHookEx(hGetMsgHook, nCode, wPara, lPara);
end;
数据结构原型
typedef struct _WNDCLASS{
          UINT style;
WNDPROC lpfnWndProc;
          int cbClsExtra;
          int cbWndExtra;
HANDLE hInstance;
          HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
          LPCTSTR lpszClassName;
}WNDCLASS;
结构说明
  WNDCLASS 结构包含了RegisterClass函数注册的类属性
分量简介
style: 指定类风格。这些风格可通过按位或操作组合起来。风格如下:
  CS_BYTEALIGNCLIENT: 在字节边界上(在x⽅向上)定位窗⼝的⽤户区域的位置
  CS_BYTEALIGNWINDOW: 在字节边界上(在x⽅向上)定位窗⼝的位置
  CS_CLASSDC: 该窗⼝类的所有窗⼝实例都共享⼀个窗⼝类DC
  CS_DBLCLKS: 允许向窗⼝发送双击⿏标键的消息
  CS_GLOBALCLASS: 当调⽤CreateWindow 或 CreateWindowEx 函数来创建窗⼝时允许它的hInstance参数和注册窗⼝类时传递给RegisterClass 的 hInstance参数不同。如果不指定该风格,则这两个 hInstance 必须相同。
  CS_HREDRAW: 当⽔平长度改变或移动窗⼝时,重画整个窗⼝
  CS_NOCLOSE: 禁⽌系统菜单的关闭选项
  CS_OWNDC: 给予每个窗⼝实例它本⾝的DC。注意,尽管这样是很⽅便,但它必须慎重使⽤,因为每个DC⼤约要占800个字节的内存。
  CS_PARENTDC: 将⼦窗⼝的裁剪区域设置到⽗窗⼝的DC中去,这样⼦窗⼝便可以在⽗窗⼝上绘制⾃⾝。注意,这是⼦窗⼝还是从系统缓存中获取DC,⽽不是使⽤⽗窗⼝的DC。使⽤该风格可以提⾼系统性能。
  CS_SAVEBITS: 以位图形式保存被该窗⼝遮挡的屏幕部分,这样当给窗⼝移动以后,系统便可以⽤该保存的位图恢复屏幕移动的相应部分,从⽽系统不⽤向被该窗⼝遮挡的窗⼝发送WM_PAINT 消息。该特性对于菜单类型的窗⼝⽐较合适,因为它通常是简短的显⽰⼀下之后便消失。设置该特性将增加显⽰该窗⼝的时间,因为它通常要先分配保存位图的内存。
  CS_VREDRAW: 当垂直长度改变或移动窗⼝时,重画整个窗⼝
lpfnWndProc: 指向窗⼝过程
cbClsExtra: 指定紧随在 WNDCLASS 数据结构后分配的字节数。系统将其初始化为零。
cbWndExtra: 指定紧随在窗⼝实例之后分配的字节数,系统将其初始化为零。如果应⽤程序正在⽤WNDCLASS结构注册⼀个在RC资源描述⽂件中⽤CLASS指令创建的对话框时,它必须设置这个字段为DLGWINDOWEXTRA。
hInstance: 标识了该窗⼝类的窗⼝过程所在的模块实例的句柄,不能为NULL。
hIcon: 标识了该窗⼝类的图标。hIcon字段必须是⼀个图标的句柄;若hIcon字段为NULL,则⽆论何时⽤户把应⽤程序缩⾄最⼩时,应⽤程序必须画⼀个图标。
hCursor: 标识该窗⼝类的光标,hCursor必须是⼀个光标资源的句柄。若hCursor字段为NULL,则⽆论何时⿏标移到应⽤程序窗⼝时,应⽤程序必须显式设置光标形状。
hbrBackground: 标识了该窗⼝类的背景画笔。hbrBackground字段必须是⽤于绘制背景的物理刷⼦的句柄,或者是⼀个颜⾊的值。如果给出⼀个颜⾊的值,它必须是下⾯列出的标准系统颜⾊之⼀(系统将对所选颜⾊加1)。如果给出了颜⾊值,它必须是转换成下列的HBRUSH类型之⼀的颜⾊:
  COLOR_ACTIVEBORDER
  COLOR_ACTIVECAPTION
  COLOR_APPWORKSPACE
  COLOR_BACKGROUND
  COLOR_BTNFACE
  COLOR_BTHSHADOW
  COLOR_BTNTEXT
  COLOR_CAPTIONTEXT
  COLOR_GRAYTEXT
  COLOR_HIGHLIGHT
  COLOR_HIGHLIGHTTEXT
  COLOR_INACTIVEBORDER
  COLOR_INACTIVECAPTION
  COLOR_MENU
  COLOR_MENUTEXT
  COLOR_SCROLLBAR
  COLOR_WINDOW
  COLOR_WINDOWFRAME
  COLOR_WINDOWTEXT
  当hbrBackground字段为NULL时,每当需要绘制其⽤户区域时,应⽤程序必须⾃⼰来绘制其背景。应⽤程序可以通过处理WM_ERASEBKGND 消息或检查由 BeginPaint 函数填写的PAINTSTRUCT 结构的fErase 字段来确定背景什么时候需要着⾊。
lpszMenuName:指向NULL结束的字符串,该字符串描述菜单的资源名,如同在资源⽂件⾥显⽰的名字⼀样。若使⽤⼀个整数标识菜单,可以使⽤MAKEINTRESOURCE宏。如果lpszMenuName为NULL,
  那么该窗⼝类的窗⼝将没有默认菜单。
lpszClassName:指向NULL结束的字符串,或者是⼀个原型(atom)。若该参数是⼀个原型,它必须是⼀个有先前调⽤RegisterClass或者 RegisterClassEx函数产⽣的类原型。类原型必须作为lpszClassName的低字,⾼字必须为0.若lpszClassName是⼀个字符串,它描述了窗⼝类名。这个类名可以是由RegisterClass或者RegisterClassEx注册的名字,或者是任何预定义的控件类名。
  结构信息Header 在winuser.h声明,包含windows.h

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。