1、经过这么多年发展的VCL到底是什么?
2、我们为什么需要VCL?
3、VCL和Windows程序设计有什么关系?
4、delphi不使用VCL可以写Windows应用程序吗?
5、VCL与其他的WINdows Framework有何不同?
6、windows上到底有多少Framework?他们之间有何不同?
第一章:回到从前
消息驱动模型:因为我们不知道每一个应用程序在何时回发生/出发事件,以及会触发什么事件,更不知道何时会点击鼠标、键盘,因此我们无法设计一个大型循环,然后在此循环中不断检查每一个应用程序是否触发了特定的事件。即便能够设计出来,我们可以想象,这仍然是非常愚蠢的做法,因为这样会让系统不时的处于百分百的运作当中。因此,反过来想:既然系统适应不了事件,何不让事件来适应系统,让事件来驱动系统。
由于执行环境必须转换事件为消息,因此我们可以说消息既是事件。因此我们要为消息(事件)定义一个结构,我们暂时取名:MyMessage。当然,需要一个ID来表示发生的特定事件。
MyMessage = packed record MessageID: LongInt; end;
当然,一个消息不可能只有一个ID,还必须有一些其他的成员。
MyMessage = packed record hwnd: HWND; //应用程序窗口识别值 MessageID: Longint; wParam: Longint; lParam: Longint; time: Longint; pt: TPoint; end;
这样,基本一个消息就算完善了。这里顺便说一下packed record 与 record之间的区别:Record的数据各个字节都是对齐的,数据格式比较完整,所以这种格式相对packed占用的内存比较大, 但是因为格式比较整齐,所以电脑读取这个类型的数据的时候速度比较快。 而Packed Record对数据进行了压缩,节省了内存空间,当然他的速度也变的慢了。
此时,对于多窗口的应用程序,消息是如何分派的呢,对了,就是消息中的hwnd字段。在此之前,消息会进入消息队列中,然后系统根据hwnd字段分派消息到各个窗口中。
现在消息有了,但消息一般是通过窗口触发事件响应的,接下来我们看看windows到底是如何创建窗口的,下面例子说明了这一点:
//============================================================================== // 创建窗口的步骤: // 1、定义窗口类的内容,已决定窗口的创建格式以及回调函数 // 2、注册窗口类 // 3、创建窗口 // 4、进入窗口消息循环以便让回调函数处理窗口消息,直到应用程序结束为止。 //============================================================================== program Project1; uses Forms,windows,Messages,sysUtils, Unit1 in 'Unit1.pas' {Form1}; const AppName = 'ddd'; {$R *.res} function WindowProc(window: HWND; AMessage: UINT; WParam: WPARAM; LParam: LPARAM):LRESULT; stdcall;export; var dc: HDC; ps: TPaintStruct; r : TRect; s: TFNWndProc; begin WindowProc := 0; case AMessage of WM_PAINT: begin dc := BeginPaint(window,ps); GetClientRect(window,r) ; DrawText(dc,'使用pascal撰写的Native Windows 程序',1,r,DT_SINGLELINE or DT_CENTER or DT_VCENTER); EndPaint(window,ps); Exit; end; WM_DESTROY: begin PostQuitMessage(0); Exit; end; end; WindowProc := DefWindowProc(window,AMessage,WParam,LParam); end; { Register the window class} function WinRegister: Boolean; var WindowClass: WNDCLASS; begin WindowClass.style := CS_VREDRAW or CS_HREDRAW; //窗口格式 WindowClass.lpfnWndProc := TFNWndProc(@WindowProc);//回调函数指针 WindowClass.cbClsExtra := 0; WindowClass.cbWndExtra := 0; WindowClass.hInstance := SYSTEM.MainInstance; WindowClass.hCursor := LoadCursor(0,IDC_ARROW) ; //窗口光标 WindowClass.hIcon := LoadIcon(0,IDI_APPLICATION) ; WindowClass.hbrBackground := GetStockObject(WHITE_BRUSH); WindowClass.lpszMenuName := nil; WindowClass.lpszClassName := AppName; Result := RegisterClass(WindowClass) <> 0 ; end; { create the window class} function WinCreate: HWND; var hWindow: HWND; begin hWindow := CreateWindow(AppName,'dddddddddd',WS_OVERLAPPEDWINDOW,cw_UseDefault, cw_UseDefault,cw_UseDefault,cw_UseDefault,0,0,system.MainInstance,nil); if hWindow <> 0 then begin ShowWindow(hWindow,CmdShow); ShowWindow(hWindow,SW_SHOW); UpdateWindow(hWindow); end; Result := hWindow; end; var AMessage: TMsg; hWindow: HWND; begin if not WinRegister then begin MessageBox(hWindow,'',nil,MB_OK); Exit; end; hWindow := WinCreate; if LongInt(hWindow) = 0 then begin MessageBox(hWindow,'',nil,MB_OK); Exit; end; while GetMessage(AMessage,0,0,0) do begin TranslateMessage(AMessage); DispatchMessage(AMessage); end; Halt(AMessage.wParam); end. begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end.