suiyunonghen 发表于 2010-6-7 12:27:30

[Delphi]Windows SDK编程(Delphi版) 之 Windows应用程序框架

既然前面讲了Windows SDK编程的一些基本知识,现在就需要用这些知识来实现一点简单的功能。不像以前咱们用C编写DOs模式的程序时一样,可能最小的程序只用三行,WIndows程序至少有几十行的代码。因此编写Windows程序时,通常会使用一些框架或者封装(比如MFC,VCL)等,但是这里我们只讲SDK的框架。使用C来实现的话,必须有的东西就是WinMain入口函数。WinMain中的常见写法顺序:
    1、定义一个窗口类
    2、注册类
    3、创建窗口
    4、显示窗口
    5、开始消息循环
对于Delphi来讲,Delphi已经将WinMain编译在Delphi的内部,我们可以省去WinMain的入口函数这一步,后面的步骤和上面一样。所以,一般我们还是写一个函数比如就叫做WinMain,实现了上面的方法之后,直接在工程文件的
begin...end之间加上WinMain()的调用就可。下面,就来给一个这样的框架program Project1;

uses
WIndows,messages;



//窗口过程
function WndProc(hwnd: THandle;MsgId: Longint;wParam: WParam;lParam: LParam): LRESULT;stdcall;
begin
Case msgId of
WM_DESTROY:
begin
    PostQuitMessage(0);
    result := 1;
end;
else
    result := DefWindowProc(Hwnd,MsgId,WParam,LParam);
end;

end;

procedure WinMain(HthisInstance: LongInt);
var
msg: Tmsg;
MainHwnd: THandle;
WndClass: TWNdClassex;
begin
WndClass.cbSize := Sizeof(WNdClass);//指定结构大小
WndClass.hInstance := HThisInstance;//指定宿主为当前应用程序的实例
WndClass.lpszClassName := 'DxWindow';//指定类名
WndClass.lpfnWndProc := @WndProc;//指定窗口过程
WndClass.style := 0;//指定样式为普通样式
WndClass.hIcon := LoadIcon(0,IDI_Application);//普通图标32*32大小的
WndClass.hIconSm := LoadIcon(0,IDI_WINLogo);//指定小图标16*16的
WndClass.hCursor := LoadCursor(0,IDC_Arrow);//指定光标
WndClass.lpszMenuName := nil;//指定菜单
WndClass.cbClsExtra := 0;
WndClass.cbWndExtra := 0;
WndClass.hbrBackground := GetStockObject(White_Brush);
if RegisterClassex(WndClass) <> 0 then
begin
    MainHwnd := CreateWindowEx(0,WndClass.lpszClassName,'测试窗口标题',WS_OVERLAPPEDWINDOW,
                               CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,0,0,hTHisInstance,nil);
    if MainHwnd <> 0 then
    begin
      ShowWindow(MainHwnd,sw_ShowNormal);
      UpdateWindow(MainHwnd);
      while GetMessage(msg,0,0,0) do
      begin      //这里开始消息循环
      TranslateMessage(msg);
      DIspatchMessage(msg);
      end;
      ExitCOde := Msg.wParam;//退出
    end;
end;
end;

begin
WinMain(Hinstance);
end.
用C来实现这个,也是一样的啦,只是多一个WInMain的入口声明。当然这个框架程序无任何功能,只是显示窗体。
然后我们来逐渐研究这个框架程序,首先,我们必须引用Windows,Message这两个单元,Windows单元中包括了大部分windows API的函数声明,Messages单元包含了Windows大部分消息的声明。所以这两个单元咱是需要的。程序中有一个窗口函数WndProc,这个窗口函数就是Windows用来与应用程序交互通信的函数。因此,它被说明为一个回调函数。在上一篇中,已经说了,Windows程序由WInMain入口,只是我们在Delphi中不用来声明这个WinMain入口函数,而实际上,这个WinMain有四个参数,真实声明应该为:
C格式
int WINAPI WinMain(Hinstance HThisInst,Hinstance hPrevInst,LPSTR lpszArgs,Int nWinMode);
Delphi格式
function WinMain(HThisInst: LongInt;hPrevInst: LogInt;lpszArgs: Pchar;nWinMode: integer);
有四个参数,HThisInst表示为当前程序实例,因为Windows是多任务系统,所以一个程序可能运行有多个实例,所以由HThisInst来指定是属于哪个程序实例,便于Windows管理
hPrevInst是指定为前一个实例,而这个是为了与以前的Win3.1相兼容,现在的Windows系统中,本参数永远为nil。
lpszArgs是一个字符串参数,表示的是传递给程序的命令行参数,比如Delphi的Paramstr()这个就是可以获得参数。
nWInMode指定为窗口的显示模式。

然后我们声明了几个变量
var
msg: Tmsg;
MainHwnd: THandle;
WndClass: TWNdClassex;
msg用来进行消息循环的结构体
MainHwnd指定为窗口句柄,至于这个句柄是啥,那是众说纷纭啊,不过个人认为是唯一标记窗口的一个指针。
WndClass用来指定要注册的窗口样式的结构。

然后程序开始对WndClass这个样式类进行了设置,设置中,我们指定了窗口的光标,窗口过程,窗口类的类名还有菜单,背景等。可以看到我在上面指定光标用的是LoadCursor,指定图标用的是LoadIcon这两个函数。
两个函数声明为:
function LoadIcon(hInstance: HINST; lpIconName: PChar): HICON; stdcall;
本函数返回一个图标句柄,Hinstance指定我们前面说的实例句柄,这里可不能指定为我们的Hinstance了哈,因为这里调用的是系统的的默认图标,所以我们指定为0,如果是指定我们程序内部的资源图标,那么就是指定为本程序实例。第二个参数指定为图标资源名称。系统有一些默认图标资源
IDI_APPLICATION 缺省图标
IDI_ERROR错误符号
IDI_INFORMATION信息
IDI_QUESTION问号
IDI_WARNING感叹号
IDI_WINLOGO窗口标志

function LoadCursor(hInstance: HINST; lpCursorName: PChar): HCURSOR; stdcall;
使用方法和上面的差不多,系统默认的光标样式为:
IDC_ARROW缺省箭头光标
IDC_CROSS十字线
IDC_IBEAM垂直工字型
IDC_WAIT沙漏

然后是背景的设置,我上面指定的背景是白色的。通过GetStockObject来获得一个指定的GDIObject的句柄,我那个指定的是画刷句柄,系统默认的集中画刷样式为:
BLACK_BRUSH黑色
DKGRAY_BRUSH黑灰色
HOLLOW_BRUSH从窗口中看到的
LIGRAY_BRUSH浅色
WHITE_BURSHE白色。
你可以使用GetStockObject来获得系统默认的画刷,也可以使用CreateSolidBrush来创建一个画刷,比如CreateSolidBrush(RGB(236,233,216));就可以创建一个和我们默认用Delphi创建的窗体一样的背景了。
这些都指定好了之后,就可以注册这个窗口类到Windows中了,注册了之后,就可以使用CreateWindow这样的函数来根据我们的样式创建窗口。
CreateWindowEx的原型为
function CreateWindowEx(dwExStyle: DWORD; lpClassName: PChar;
lpWindowName: PChar; dwStyle: DWORD; X, Y, nWidth, nHeight: Integer;
hWndParent: HWND; hMenu: HMENU; hInstance: HINST; lpParam: Pointer): HWND;
dwExStyle表示为扩展样式
lpClassName指定为类名,直接使用WndClass.lpSzClassName则可,
LpWindowName指定为窗口标题
DwStyle指定为窗口样式,我这里指定的为WS_OVERLAPPEDWINDOW,表示为边框重叠的窗口,共有
WS_OVERLAPPEDWINDOW边框重叠的窗口
WS_MAXIMIZEBOX 最大化
WS_MINIMIZEBOX 最小化
WS_SYSMENU系统菜单
WS_HSCROLL水平滚动条
WS_VSCROLL垂直滚动条

之后是指定窗口的位置,以及宽和高(在上面我用的是系统默认CW_USEDEFAULT),然后指定他的父窗口句柄,这里我们是没有父窗口的,所以指定为桌面为0,无菜单,指定为0,然后是指定窗口所属的程序实例。最后指定一些其他附加信息,这里无附加信息,所以指定为nil。

到这里为止 ,窗口就创建完成了,运行一下,可以发现窗口并不会显示,要显示窗口,我们必须调用ShowWindow这个API来显示
Bool ShowWindow(HWnd hwnd,int nhow)
nhow指定为显示模式,常用的几种显示模式为
SW_HIDE隐藏窗口
SW_MINIMIZE 窗口最小化
SW_RESTORE恢复窗口
ShowWindow返回窗口的前一个显示状态,如果显示窗口则返回非0值,如果没显示则返回0
另外,还有一个UpdateWindow函数,目的是告诉Windows向用户的应用程序中发送一条消息,用该消息来更新主窗口。

最后就是消息循环了,消息循环是Windows程序的重要组成部分,它的作用是接收系统发送的消息,运行程序的时候,他不断的接收消息,直到这些消息被读取以及处理,否则他们一直保存在应用程序的消息队列里。每次应用程序准备好去读取另一个消息时,就必须调用API函数GetMessage()
Bool GetMessage(LPMSG msg,HWND hwnd,UINT min,UINT Max);
参数msg指定消息结构体,其中包括了消息ID,消息对应的响应消息的窗口句柄,以及消息的参数等。
tagMSG = packed record
    hwnd: HWND;
    message: UINT;
    wParam: WPARAM;
    lParam: LPARAM;
    time: DWORD;
    pt: TPoint;
end;
WParam和lparam中存放着每条消息相关的附加信息。
time中放着消息的发送时间,以毫秒为单位指定
pt包含着鼠标的坐标。
在应用程序的消息队列中如果没有一条消息,则GetMessage()调用会向Windows回传一个控制指令(这个,咱么在以后在说)
GetMessage的hwnd参数将指定所获得的消息传给哪个窗口,一个应用程序可能有很多窗口,用户也许指向接收某个具体窗口的消息。如果用户想接收指向应用程序的所有消息,则指定为0。其余两个参数指定了要接收的消息的范围。通常用户希望自己的应用程序能够接收所有的消息,此时将min和max都指定为0。
当用户结束程序时,GetMessage()返回0,于是消息循环结束。如果发生从无,返回-1。此外,在消息循环中还有两个函数TranslateMessage和DIspatchMessage,
TranslateMessage的目的是将系统产生的虚拟键码转换成字符消息。以使用户的应用程序能响应所有的键盘。当转换了消息之后,使用DIspatchMessage函数来派发消息返回给Windows,于是Windows保存该消息,直到能将他传递给程序的窗口为止。
最后当用户退出程序,消息循环结束,并且将msg.WParam的值返回给Windows就是我上面指定的ExitCode.

gix76 发表于 2012-6-5 19:18:32

看帖子的要发表下看法

wjrice 发表于 2014-12-8 10:47:55

虽然帖子比较老,但比较经典,讲的也详细,谢谢楼主

ni88yy 发表于 2018-7-1 16:26:31

看上去不错,感谢分享

wyiman 发表于 2018-12-9 16:15:34

太好了,哈哈哈

昆仔 发表于 2018-12-15 10:48:10

Delphi现在还有人用这东西啊?

zhuixin 发表于 2019-2-15 18:01:31

学习一下顶!!!!!!!!!!!

chunwei_2015 发表于 2019-2-28 13:24:38

多谢楼主分享~~,收藏了~~

捍卫飘云阁尊严 发表于 2022-6-11 14:55:02

感谢分享这些知识   学习
页: [1]
查看完整版本: [Delphi]Windows SDK编程(Delphi版) 之 Windows应用程序框架