通过以sdk方式编制windows窗口程序,对理解windows消息驱动机制和delphi消息编程有很大的帮助。
sdk编制windows窗口程序的步骤:
1、对TWndClass对象进行赋值;
2、向系统注册wndclass对象(RegisterClass);
3、CreateWindow创建窗口,获得窗口句柄Hwnd;
4、显示窗口(ShowWindow);
5、通过GetMessage函数不断获取系统消息,交给程序处理,程序过通回调函数(wndproc)处理系统消息。(消息处理部分)
程序代码如下:
program Project2;

//{$APPTYPE CONSOLE}

uses
Windows,
Messages; //==============================================================================
// 定义回调函数 Wndproc(),处理windows消息;
// 参数说明:
// HWND 可以理解为窗口句柄
// AMessage 可理解为消息的编号
// Wparam 消息的高位
// Lparam 消息的低位
//============================================================================== function Wndproc(HWND: Thandle; AMessage: LongInt; wparam: wparam; lParam: lParam): Lresult; stdcall;
begin
case AMessage of
WM_DESTROY: //处理窗口退出消息
begin
PostQuitMessage(0);
Result := 0;
end
else {将未处理的消息交给系统处理}
Result := DefWindowProcW(HWND, AMessage, wparam, lParam);
end;
end; procedure WndMain;
var
msg: TMsg;
Wndclass: TWndClass;
Hwnd: THandle;
begin
{给窗口类赋值}
Wndclass.lpfnWndProc := @Wndproc; //窗口回调函数,处理windows消息
Wndclass.style := CS_HREDRAW or CS_VREDRAW;
; //窗口类型
Wndclass.cbClsExtra := 0;
Wndclass.cbWndExtra := 0;
Wndclass.hInstance := HInstance;
Wndclass.hIcon := LoadIcon(0, IDI_APPLICATION);
Wndclass.hCursor := LoadCursor(0, IDC_ARROW);
Wndclass.lpszClassName := 'MyWndClass';
Wndclass.lpszMenuName := nil;
Wndclass.hbrBackground := GetStockObject(GRAY_BRUSH);
{向系统注册窗口类}
RegisterClass(Wndclass);
{创建窗口}
Hwnd := CreateWindow(Wndclass.lpszClassName, '用sdk编写的windows窗口', WS_OVERLAPPED, 100, 100, 300, 200, 0, 0, HInstance, 0); if Hwnd <> 0 then
begin
{显示窗口}
ShowWindow(Hwnd, SW_SHOWNORMAL);
UpdateWindow(Hwnd);
{处理窗口消息}
while GetMessage(msg, 0, 0, 0) do
begin
TranslateMessage(msg);
DispatchMessage(msg);
end;
end; end; begin
WndMain;
{ TODO -oUser -cConsole Main : Insert code here }
end.

一、运行界面如下:

二、程序函数说明:

  (一)、窗口类型 TWndClass 其实是一个结构, 是 tagWNDCLASSA 结构的重命名.

{tagWNDCLASSA 结构:}
tagWNDCLASSA = packed record
style: UINT; {窗口风格, 见下表}
lpfnWndProc: TFNWndProc; {窗口回调函数的指针, 后面要详细分析}
cbClsExtra: Integer; {为窗口类分配的额外空间, 一般为 0}
cbWndExtra: Integer; {为窗口实例分配的额外空间, 一般为 0}
hInstance: HINST; {窗口所在程序实例的句柄, 就是 HInstance}
hIcon: HICON; {指定窗口图标, 一般用 LoadIcon 加载; 不指定可设为 0}
hCursor: HCURSOR; {指定窗口光标, 一般用 LoadCursor 加载; 不指定可设为 0}
hbrBackground: HBRUSH; {指定窗口背景画刷, 这需要用 GetStockObject 函数检索; 也可以直接指定系统颜色}
lpszMenuName: PAnsiChar; {菜单资源名称; 一般置为 nil, 表示窗口没有默认菜单}
lpszClassName: PAnsiChar; {给该窗口类命名; CreateWindow 函数将使用这个名称}
end; //窗口风格参数 style 可选值:
CS_VREDRAW = DWORD(1); {窗口高度变化时将被重绘}
CS_HREDRAW = DWORD(2); {窗口宽度变化时将被重绘}
CS_KEYCVTWINDOW = 4; {}
CS_DBLCLKS = 8; {不忽略鼠标双击的消息}
CS_OWNDC = $20; {给用该类建立的每一个窗口分配独立的设备 DC}
CS_CLASSDC = $40; {让属于该类的所有窗口共享一个设备 DC}
CS_PARENTDC = $80; {允许窗口的子窗口继承一些共同特性}
CS_NOKEYCVT = $100; {}
CS_NOCLOSE = $200; {禁用系统菜单的 Close命令,同时窗口没有关闭按钮}
CS_SAVEBITS = $800; {当窗口被覆盖时, 用位图缓存被覆盖区, 从而避免 WM_PAINT 消息, 一般用于菜单或对话框}
CS_BYTEALIGNCLIENT = $1000; {通过字节对齐, 增强客户区的绘制性能}
CS_BYTEALIGNWINDOW = $2000; {通过字节对齐, 增强窗口的绘制性能}
CS_GLOBALCLASS = $4000; {全局窗口类, 一般用于 DLL; 没有此选项, 窗口类和窗口建立函数中指定的实例句柄须相同} //关于窗口背景画刷:
{系统预定义了一些画刷, 需要用 GetStockObject 根据指定的常数检索;}
{但 GetStockObject 返回的句柄有可能是画刷、画笔、调色板或系统字体的句柄,}
{所以还需要把 GetStockObject 返回的句柄进行类型转换, 譬如: HBRUSH(GetStockObject(常数))}
//下面是 GetStockObject 函数参数的可选值:
WHITE_BRUSH = 0;
LTGRAY_BRUSH = 1;
GRAY_BRUSH = 2;
DKGRAY_BRUSH = 3;
BLACK_BRUSH = 4;
NULL_BRUSH = 5;
HOLLOW_BRUSH = NULL_BRUSH;
WHITE_PEN = 6;
BLACK_PEN = 7;
NULL_PEN = 8;
OEM_FIXED_FONT = 10;
ANSI_FIXED_FONT = 11;
ANSI_VAR_FONT = 12;
SYSTEM_FONT = 13;
DEVICE_DEFAULT_FONT = 14;
DEFAULT_PALETTE = 15;
SYSTEM_FIXED_FONT = $10;
DEFAULT_GUI_FONT = 17;
DC_BRUSH = 18;
DC_PEN = 19;
STOCK_LAST = 19; {另外背景画刷还可以使用 Windows 定义系统颜色常量, 譬如: HBRUSH(COLOR_WINDOW + 1) }
COLOR_SCROLLBAR = 0;
COLOR_BACKGROUND = 1;
COLOR_ACTIVECAPTION = 2;
COLOR_INACTIVECAPTION = 3;
COLOR_MENU = 4;
COLOR_WINDOW = 5;
COLOR_WINDOWFRAME = 6;
COLOR_MENUTEXT = 7;
COLOR_WINDOWTEXT = 8;
COLOR_CAPTIONTEXT = 9;
COLOR_ACTIVEBORDER = 10;
COLOR_INACTIVEBORDER = 11;
COLOR_APPWORKSPACE = 12;
COLOR_HIGHLIGHT = 13;
COLOR_HIGHLIGHTTEXT = 14;
COLOR_BTNFACE = 15;
COLOR_BTNSHADOW = $10;
COLOR_GRAYTEXT = 17;
COLOR_BTNTEXT = 18;
COLOR_INACTIVECAPTIONTEXT = 19;
COLOR_BTNHIGHLIGHT = 20;
COLOR_3DDKSHADOW = 21;
COLOR_3DLIGHT = 22;
COLOR_INFOTEXT = 23;
COLOR_INFOBK = 24;
COLOR_HOTLIGHT = 26;
COLOR_GRADIENTACTIVECAPTION = 27;
COLOR_GRADIENTINACTIVECAPTION = 28;
COLOR_MENUHILIGHT = 29;
COLOR_MENUBAR = 30;
COLOR_ENDCOLORS = COLOR_MENUBAR;
COLOR_DESKTOP = COLOR_BACKGROUND;
COLOR_3DFACE = COLOR_BTNFACE;
COLOR_3DSHADOW = COLOR_BTNSHADOW;
COLOR_3DHIGHLIGHT = COLOR_BTNHIGHLIGHT;
COLOR_3DHILIGHT = COLOR_BTNHIGHLIGHT;
COLOR_BTNHILIGHT = COLOR_BTNHIGHLIGHT;
(二)、认识 CreateWindow 函数


CreateWindow(
lpClassName: PChar; {窗口类的名字}
lpWindowName: PChar; {窗口标题}
dwStyle: DWORD; {窗口样式, 参加下表}
X,Y: Integer; {位置; 默认的X,Y可以指定为: Integer(CW_USEDEFAULT)}
nWidth,nHeight: Integer;{大小; 默认的宽度、高度可以指定为: Integer(CW_USEDEFAULT)}}
hWndParent: HWND; {父窗口句柄}
hMenu: HMENU; {主菜单句柄}
hInstance: HINST; {模块实例句柄, 也就是当前 exe 的句柄}
lpParam: Pointer {附加参数, 创建多文档界面时才用到, 一般设为 nil}
): HWND; {返回所创建的窗口的句柄} //dwStyle 窗口样式参数可选值:
WS_OVERLAPPED = 0; {重叠式窗口, 应带标题栏和边框}
WS_POPUP = DWORD($80000000); {弹出式窗口, 不能与 WS_CHILD 一起使用}
WS_CHILD = $40000000; {子窗口, 不能与 WS_POPUP 一起使用}
WS_MINIMIZE = $20000000; {最小化窗口}
WS_VISIBLE = $10000000; {初始时可见}
WS_DISABLED = $8000000; {禁止输入}
WS_CLIPSIBLINGS = $4000000; {裁剪子窗口, 也就是子窗口重绘不影响重叠的其他子窗口, 应与 WS_CHILD 一起使用}
WS_CLIPCHILDREN = $2000000; {在父窗口中绘图时绕开子窗口区域, 创建父窗口是使用}
WS_MAXIMIZE = $1000000; {最大化窗口}
WS_CAPTION = $C00000; {有标题栏}
WS_BORDER = $800000; {有细线边框}
WS_DLGFRAME = $400000; {对话框窗口}
WS_VSCROLL = $200000; {有垂直滚动条}
WS_HSCROLL = $100000; {有水平滚动条}
WS_SYSMENU = $80000; {带系统标题栏, 须同时指定 WS_CAPTION}
WS_THICKFRAME = $40000; {带宽边框, 宽边框用于改变窗口大小}
WS_GROUP = $20000; {能用方向键转移焦点}
WS_TABSTOP = $10000; {能用 TAB 转移焦点}
WS_MINIMIZEBOX = $20000; {有最小化按钮}
WS_MAXIMIZEBOX = $10000; {有最大化按钮}
WS_TILED = WS_OVERLAPPED;
WS_ICONIC = WS_MINIMIZE;
WS_SIZEBOX = WS_THICKFRAME;
WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED or WS_CAPTION or WS_SYSMENU or WS_THICKFRAME or WS_MINIMIZEBOX or WS_MAXIMIZEBOX);
WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW;
WS_POPUPWINDOW = (WS_POPUP or WS_BORDER or WS_SYSMENU);
WS_CHILDWINDOW = (WS_CHILD); //另外还有一些扩展样式:
WS_EX_DLGMODALFRAME = 1; {指定双边界窗口; 藉此指定 WS_CAPTION 创建标题栏}
WS_EX_NOPARENTNOTIFY = 4; {在窗口创建或取消时不向父窗口发送 WM_PARENTNOTIFY 消息}
WS_EX_TOPMOST = 8; {在所有非最顶层窗口的上面}
WS_EX_ACCEPTFILES = $10; {可接受拖放文件}
WS_EX_TRANSPARENT = $20; {透明样式, 在同属窗口已重画时该窗口才可重画}
WS_EX_MDICHILD = $40; {创建一个 MDI 子窗口}
WS_EX_TOOLWINDOW = $80; {工具窗口}
WS_EX_WINDOWEDGE = $100; {带立体的边框}
WS_EX_CLIENTEDGE = $200; {带阴影的边界}
WS_EX_CONTEXTHELP = $400; {标题包含一个问号标志, 不能与 WS_MAXIMIZEBOX 和 WS_MINIMIZEBOX 同时使用}
WS_EX_RIGHT = $1000; {窗口具有右对齐属性}
WS_EX_LEFT = 0; {窗口具有左对齐属性, WS_EX_LEFT 是缺省设置}
WS_EX_RTLREADING = $2000; {窗口文本从右到左}
WS_EX_LTRREADING = 0; {窗口文本从左到右, WS_EX_LTRREADING 是缺省设置}
WS_EX_LEFTSCROLLBAR = $4000; {垂直滚动条在左边界, 只用于特殊语言环境}
WS_EX_RIGHTSCROLLBAR = 0; {垂直滚动条在右边界, WS_EX_RIGHTSCROLLBAR 是缺省设置}
WS_EX_CONTROLPARENT = $10000; {允许用户使用 Tab 键在窗口的子窗口间搜索}
WS_EX_STATICEDGE = $20000; {窗口不可用时创建一个三维边界}
WS_EX_APPWINDOW = $40000; {当窗口可见时, 将一个顶层窗口放置到任务条上}
WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE or WS_EX_CLIENTEDGE); {立体边框并带阴影}
WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE or WS_EX_TOOLWINDOW or WS_EX_TOPMOST); {立体边框、工具条窗口样式、在顶层}
WS_EX_LAYERED = $00080000; {分层或透明窗口, 该样式可使用混合特效}
WS_EX_NOINHERITLAYOUT = $00100000; {子窗口不继承父窗口的布局}
WS_EX_LAYOUTRTL = $00400000; {从右到左的布局}
WS_EX_COMPOSITED = $02000000; {用双缓冲从下到上绘制窗口的所有子孙}
WS_EX_NOACTIVATE = $08000000; {处于顶层但不激活}
分析:  
  首先要用 CreateWindow 创建窗口, 才能用 ShowWindow 显示窗口; 因为 ShowWindow 需要 CreateWindow 返回的句柄.
  在 CreateWindow 的参数中, 位置与大小与窗口标题无须多说;
  父窗口与菜单, 暂时都不需要, 先可置为 0;
  程序实例的句柄, Delphi 已经为我们准备好了: HInstance; (参见原来的说明)
  窗口样式在前面的例子中我们使用了: WS_OVERLAPPEDWINDOW, 它代表几种特点的组合, 表示了常规窗口.
  CreateWindow 还有一个重要参数(第一个参数 lpClassName): 窗口类的名字.
  Windows 要求我们要登记并注册一个窗口类以后, 才可以用 CreateWindow 建立窗口! (三)认识消息机制函数
  一个程序会有一个或多个线程, 系统有一个线程队列(就是个链表)管理所有这些线程, 并为每个线程建立一个消息队列.  
  当消息产生时(譬如点击了窗口), 系统会把该消息放到窗口所在的消息队列, 等待窗口处理.
  窗口应该时刻待命, 准备从所在的线程队列中取出消息并处理! 
  从消息队列中取出消息, 一般用 GetMessage 函数; 要随时取出消息, 需要用个循环, 譬如:


while(GetMessage(Msg, 0, 0, 0)) do
begin
...
end;

  取出消息怎么处理? 用 DispatchMessage 函数将消息交给(前面提到的)窗口回调函数, 一般是这样:


while(GetMessage(Msg, 0, 0, 0)) do
begin
TranslateMessage(Msg); {有些键盘消息需要用 TranslateMessage 函数并发出系统需要的更具体的键盘消息}
DispatchMessage(Msg);
end;

  如果 GetMessage 函数不返回 0 ; 这个消息循环就是死循环, 什么时候 GetMessage 可以返回 0 呢?
  只有当 GetMessage 收到 WM_QUIT 消息时才返回 0. 
  我们可在需要的时候, 在回调函数中通过 PostQuitMessage 函数向线程的消息队列中发送一条 WM_QUIT 消息, 以关闭线程.
  PostQuitMessage 函数的参数是给应用程序的退出码, PostQuitMessage(0) 中的 0 就是我们指定的退出码, 它将作为 WM_QUIT 消息的 wParam 参数. 譬如:

function WndProc(wnd: HWND; msg: UINT; wParam: Integer; lParam: Integer): LResult; stdcall;
begin
Result := 0;
if msg = WM_DESTROY then
PostQuitMessage(0)
else
Result := DefWindowProc(wnd, msg, wParam, lParam);
end;

深入delphi编程理解之消息(一)WINDOWS原生窗口编写及消息处理过程的更多相关文章

  1. 深入delphi编程理解之消息(二)发送消息函数及消息编号、消息结构体的理解

    一.delphi发送消息的函数主要有以下三个: (一).SendMessage函数,其原型如下: function SendMessage( hWnd: HWND; {目标句柄} Msg: UINT; ...

  2. 深入delphi编程理解之消息(六)无窗口单元消息的创建、接受及dispatch模式编程

    一.程序界面 二.程序代码 (一).主界面代码 //========================================================================== ...

  3. 深入delphi编程理解之消息(五)重写(override)dispatch、wndproc方法和Application.OnMessage事件

    dispatch.wndproc是VCL framework在TWinCtronl定义的虚拟方法,下面程序通过重写(override)这两函数拦截WM_LBUTTONDOWN消息,来与Applicat ...

  4. 深入delphi编程理解之消息(四)使用TWMSysCommand结构体的WM_SysCommand消息应用

    通过以下实例拦截窗体WM_SysCommand消息,我们可以获取到很多有趣的数据. 一.程序界面 二.程序代码 unit Unit1; interface uses Windows, Messages ...

  5. 深入delphi编程理解之消息(三)发送消息函数的一般应用实例

    通过对消息函数(SendMessage.PostMessage.Perform)的一般应用,来说明sendmessage.postmessage函数和perform 方法调用方式和结果的区别. 一.程 ...

  6. 深入delphi编程理解之接口(一)接口与类的异同及接口的声明和实现

    一.抽象类与接口的异同 接口简单的理解可认为是一个抽象类,我们先定义一个抽象类和接口来对比之间的异同,代码如下: type IFormattedNumber = interface //定义接口 fu ...

  7. TMsgThread, TCommThread -- 在delphi线程中实现消息循环

    http://delphi.cjcsoft.net//viewthread.php?tid=635 在delphi线程中实现消息循环 在delphi线程中实现消息循环 Delphi的TThread类使 ...

  8. Delphi编程中资源文件的应用

    Delphi编程中资源文件的应用/转自 http://chamlly.spaces.live.com/blog/cns!548f73d8734d3acb!236.entry一.引子: 现在的Windo ...

  9. TMsgThread, TCommThread -- 在delphi线程中实现消息循环(105篇博客,好多研究消息的文章)

    在delphi线程中实现消息循环 在delphi线程中实现消息循环 Delphi的TThread类使用很方便,但是有时候我们需要在线程类中使用消息循环,delphi没有提供.   花了两天的事件研究了 ...

随机推荐

  1. IDEA工具java开发之 运行与调试

    一.运行项目 ◆右键运行 ◆菜单运行 ◆run窗口运行 ◆启动参数 作用:经常用在本地开发环境要去连测试的数据库的时候使用.正常的情况下是连开发环境的数据库的,但是有些情况是需要连测试数据库的.所以这 ...

  2. 如何用python操作XML文件

    备注: 基于python3 背景:在统计覆盖率的时候希望绕属性name为test的节点 具体实现源码如下所示,基本都是基于节点属性操作的,当然也就可以基于tag等其他标签去做,可根据需要调整 from ...

  3. 栈的简单应用之中缀表达式转后缀表达式(C语言实现逆波兰式)

    一.前言   普通人在书写计算式时会选择中缀表达式,这样符合人脑的认知习惯.可计算机处理时后缀表达式才能使处理速度更快,其原因是利用堆栈结构减少计算机内存访问.同时它也是一个很好锻炼栈这个数据结构的应 ...

  4. git命令全景图

  5. 页面回显与URL模板映射

    一.页面回显 对于需要返回界面的数据,可以将后台封装好的数据回显至原始jsp界面中. 举个例子: User.java package com.zk.data; public class User { ...

  6. python3练习100题——013

    熟悉的水仙花数来了,,,... 原题链接:http://www.runoob.com/python/python-exercise-example13.html 题目:打印出所有的"水仙花数 ...

  7. 一键安装各个版本boost库(无需编译)

    1.NuGet 最简单的,用VS自带的NuGet包管理器安装,一般比较常用的上面都有 2.下载exe安装包 在这里https://sourceforge.net/projects/boost/file ...

  8. 剑指offer 面试题. 按之字形顺序打印二叉树

    题目描述 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推.   方法1: 正常层次遍历,利用普通队列.逢 ...

  9. 2019kali安装以及汉化

    Kali Linux2019.4版本包括了一些令人兴奋的新更新: 一个新的默认桌面环境,Xfce 新的GTK3主题(用于Gnome和Xfce) “Kali Undercover”模式介绍 Kali文档 ...

  10. Apache Kafka(九)- Kafka Consumer 消费行为

    1. Poll Messages 在Kafka Consumer 中消费messages时,使用的是poll模型,也就是主动去Kafka端取数据.其他消息管道也有的是push模型,也就是服务端向con ...