Windows应用程序的每一个窗口都有一个大的消息循环以及一个窗口函数(WndProc)用以分发和处理消息。VCL作为一个Framework,当然会将这些东西隐藏起来,而重新提供一种易用的、易理解的虚拟机制给程序员。
那么VCL是如何做到的呢?
本节就来解答这个问题。
只要代码单元中包含了Forms.pas,就会得到一个对象——Application。利用它可以帮助我们完成许多工作。例如要退出应用程序,可以使用
Application.Terminate();
Application对象是VCL提供的,在Forms.pas中可以看到如下这个定义:
var
Application: TApplication;
当创建一个默认的应用程序时,会自动得到以下几行代码:
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
这几行代码很简洁地展示了TApplication的功能、初始化、创建必要的窗体、运行……
但是,这几行代码具体做了什么幕后操作呢?Application.Run之后,程序流程走向了哪里?
1.脱离VCL的Windows程序
    在此,给出一个用纯Pascal所编写的十分简单的Windows应用程序,以演示标准Windows程序是如何被建立及运行的。
TApplication与主消息循环program WindowDemo;
TApplication与主消息循环uses Windows, Messages;
TApplication与主消息循环
// 窗口函数,窗口接到消息时被Windows所调用
TApplication与主消息循环
function WindowProc(hwnd : HWND; uMsg : Cardinal; wParam : WPARAM;
TApplication与主消息循环lParam : LPARAM) : LResult; stdcall;
TApplication与主消息循环begin
TApplication与主消息循环Result :
= 0;
TApplication与主消息循环
case uMsg of
TApplication与主消息循环
// 关闭窗口消息,当用户关闭窗口后,通知主消息循环结束程序
TApplication与主消息循环WM_CLOSE : PostMessage(hwnd, WM_QUIT, 
00);
TApplication与主消息循环
// 鼠标左键按下消息
TApplication与主消息循环WM_LBUTTONDOWN : MessageBox(hwnd, 
'Hello!', '和您打个招呼',
TApplication与主消息循环
MB_ICONINFORMATION);
TApplication与主消息循环
else
TApplication与主消息循环
// 其他消息做默认处理
TApplication与主消息循环Result :
= DefWindowProc(hWnd, uMsg, wParam, lParam);
TApplication与主消息循环
end;
TApplication与主消息循环
end;
TApplication与主消息循环var
TApplication与主消息循环wndcls : WNDCLASS; 
// 窗口类的记录(结构)类型
TApplication与主消息循环hWnd : THandle;
TApplication与主消息循环Msg : tagMSG; 
// 消息类型
TApplication与主消息循环begin
TApplication与主消息循环wndcls.style :
= CS_DBLCLKS; // 允许窗口接受鼠标双击
TApplication与主消息循环wndcls.lpfnWndProc :
= @WindowProc; // 为窗口类指定窗口函数
TApplication与主消息循环wndcls.cbClsExtra :
= 0;
TApplication与主消息循环wndcls.cbWndExtra :
= 0;
TApplication与主消息循环wndcls.hInstance :
= hInstance;
TApplication与主消息循环wndcls.hIcon :
= 0;
TApplication与主消息循环wndcls.hCursor :
= LoadCursor(hInstance, 'IDC_ARROW');
TApplication与主消息循环
wndcls.hbrBackground := COLOR_WINDOWFRAME;
TApplication与主消息循环wndcls.lpszMenuName :
= nil;
TApplication与主消息循环wndcls.lpszClassName :
= 'WindowClassDemo'; // 窗口类名称
TApplication与主消息循环
// 注册窗口类
TApplication与主消息循环
if RegisterClass(wndcls) = 0 then
TApplication与主消息循环
Exit;
TApplication与主消息循环
// 创建窗口
TApplication与主消息循环hWnd :
= CreateWindow(
TApplication与主消息循环
'WindowClassDemo', // 窗口类名称
TApplication与主消息循环'
WindowDemo', // 窗口名称
TApplication与主消息循环
WS_BORDER or WS_CAPTION or WS_SYSMENU, // 窗口类型
TApplication与主消息循环
Integer(CW_USEDEFAULT),
TApplication与主消息循环
Integer(CW_USEDEFAULT),
TApplication与主消息循环
Integer(CW_USEDEFAULT),
TApplication与主消息循环
Integer(CW_USEDEFAULT),
TApplication与主消息循环
0,
TApplication与主消息循环
0,
TApplication与主消息循环hInstance,
TApplication与主消息循环nil
TApplication与主消息循环);
TApplication与主消息循环
if hWnd = 0 then
TApplication与主消息循环
Exit;
TApplication与主消息循环
// 显示窗口
TApplication与主消息循环ShowWindow(hWnd, SW_SHOWNORMAL);
TApplication与主消息循环UpdateWindow(hWnd);
TApplication与主消息循环
// 创建主消息循环,处理消息队列中的消息并分发
TApplication与主消息循环
// 直至收到WM_QUIT消息,退出主消息循环,并结束程序
TApplication与主消息循环
// WM_QUIT消息由PostMessage()函数发送
TApplication与主消息循环
while GetMessage(Msg, hWnd, 00do
TApplication与主消息循环begin
TApplication与主消息循环TranslateMessage(Msg);
TApplication与主消息循环DispatchMessage(Msg);
TApplication与主消息循环
end;
TApplication与主消息循环
end.
TApplication与主消息循环
该程序没有使用VCL,它所做的事情就是显示一个窗口。当在窗口上单击鼠标右键时,会弹出一个友好的对话框向您问好。如果从来不曾了解过这些,那么建议您实际运行一下光盘上的这个程序,对其多一些感性认识。
就是这样一个简单的程序,演示了标准Windows程序的流程:
(1)从入口函数WinMain开始。
(2)注册窗口类及窗口函数(Window Procedure)。
(3)创建并显示窗口。
(4)进入主消息循环,从消息队列中获取并分发消息。
(5)消息被分发后,由Windows操作系统调用窗口函数,由窗口函数对消息进行 处理。
在Object Pascal中看不到所谓的“WinMain”函数。不过,其实整个program的begin处就是Windows程序的入口。
注册窗口类通过系统API函数RegisterClass()来完成,它向Windows系统注册一个窗口的类型。
注册窗口类型完成后,就可以创建这个类型的窗口实例。创建出一个真正的窗口可通过API函数CreateWindow()来实现。
创建出的窗口实例通过API函数ShowWindow()来使得它显示在屏幕上。
当这一切都完成后,窗口开始进入一个while循环以处理各种消息,直至API函数GetMessage()返回0才退出程序。循环中,程序需要从主线程的消息队列中取出各种消息,并将它分发给系统,然后由Windows系统调用窗口的窗口函数(WndProc),以完成窗口对消息的响应处理。
         TApplication除了定义一个应用程序的特性及行为外,另一个重要的使命就是封装以上的那些令人讨厌的、繁琐的步骤。

2.Application对象的本质
注意:Application是一个0*0大小的不可见窗口!并且这个窗口是windows应用程序的主窗口,delphi应用程序的主窗体是这个窗口的子窗口,因此会以一个消息循环接受窗口消息并且加以分派和处理。TApplication类封装了创建秘密窗口和消息循环的程序代码。所有的事情发生在全局对象Application对象被创建之时。
   TApplication的构造函数中:
TApplication与主消息循环constructor TApplication.Create(AOwner: TComponent)
TApplication与主消息循环var
TApplication与主消息循环  TApplication与主消息循环
TApplication与主消息循环  
if not IsLibrary then CreateHandle;
TApplication与主消息循环  TApplication与主消息循环
TApplication与主消息循环
end;

  构造函数会调用CreateHandle方法(非常重要的函数)。查看该方法源代码可知,该方法的任务正是注册窗口类,并创建一个窗口实例。
TApplication与主消息循环procedure TApplication.CreateHandle;
TApplication与主消息循环var
TApplication与主消息循环  TempClass: TWndClass;
TApplication与主消息循环  SysMenu: HMenu;
TApplication与主消息循环begin
TApplication与主消息循环  
if not FHandleCreated and not IsConsole then
TApplication与主消息循环  begin
TApplication与主消息循环    FObjectInstance :
= Classes.MakeObjectInstance(WndProc);
TApplication与主消息循环    
// 如果窗口类不存在,则注册窗口类
TApplication与主消息循环    
if not GetClassInfo(HInstance, WindowClass.lpszClassName, TempClass) then
TApplication与主消息循环    begin
TApplication与主消息循环      WindowClass.hInstance :
= HInstance;
TApplication与主消息循环      
if Windows.RegisterClass(WindowClass) = 0 then
TApplication与主消息循环        raise EOutOfResources.Create(SWindowClass);
TApplication与主消息循环    
end;
TApplication与主消息循环   
// 创建窗口,长度和宽度都是0,位置在屏幕中央,返回的句柄FHandle
TApplication与主消息循环   
// 也就是Tapplication.Handle的值
TApplication与主消息循环    FHandle :
= CreateWindow(WindowClass.lpszClassName, PChar(FTitle),
TApplication与主消息循环      WS_POPUP 
or WS_CAPTION or WS_CLIPSIBLINGS or WS_SYSMENU
TApplication与主消息循环      
or WS_MINIMIZEBOX,
TApplication与主消息循环      GetSystemMetrics(SM_CXSCREEN) div 
2,
TApplication与主消息循环      GetSystemMetrics(SM_CYSCREEN) div 
2,
TApplication与主消息循环      
0000, HInstance, nil);
TApplication与主消息循环    FTitle :
= '';
TApplication与主消息循环
    FHandleCreated := True;
TApplication与主消息循环   
// 调用SetWindowLong设置窗口的窗口函数(WndProc)
TApplication与主消息循环    SetWindowLong(FHandle, GWL_WNDPROC, Longint(FObjectInstance));
TApplication与主消息循环    
if NewStyleControls then
TApplication与主消息循环    begin
TApplication与主消息循环      SendMessage(FHandle, WM_SETICON, 
1, GetIconHandle);
TApplication与主消息循环      SetClassLong(FHandle, GCL_HICON, GetIconHandle);
TApplication与主消息循环    
end;
TApplication与主消息循环    SysMenu :
= GetSystemMenu(FHandle, False);
TApplication与主消息循环    DeleteMenu(SysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
TApplication与主消息循环    DeleteMenu(SysMenu, SC_SIZE, MF_BYCOMMAND);
TApplication与主消息循环    
if NewStyleControls then DeleteMenu(SysMenu, SC_MOVE, MF_BYCOMMAND);
TApplication与主消息循环  
end;
TApplication与主消息循环
end;
TApplication与主消息循环
对照一下此前使用纯API编写的窗口程序,就会发现一些它们的相似之处。在CreateHandle()中,可以看到熟悉的RegisterClass()、CreateWindow()等API函数的调用。比较特别的是,CreateHandle()中通过API函数SetWindowLong()来设置窗口的窗口函数:
SetWindowLong(FHandle, GWL_WNDPROC, Longint(FObjectInstance));
此时,SetWindowLong()的第3个参数为窗口函数实例的地址,其中FObjectInstance是由CreateHandle()的第1行代码
FObjectInstance := Classes.MakeObjectInstance(WndProc);
所创建的实例的指针,而WndProc()则成了真正的窗口函数。
          TApplication本身有一个private成员FMainForm,它指向程序员所定义的主窗体,并在TApplication.CreateForm方法中判断并赋值:
TApplication与主消息循环procedure TApplication.CreateForm(InstanceClass: TComponentClass; var Reference);
TApplication与主消息循环var
TApplication与主消息循环  Instance: TComponent;
TApplication与主消息循环begin
TApplication与主消息循环  Instance :
= TComponent(InstanceClass.NewInstance);
TApplication与主消息循环  TComponent(Reference) :
= Instance;
TApplication与主消息循环  try
TApplication与主消息循环    Instance.Create(Self);
TApplication与主消息循环  except
TApplication与主消息循环    TComponent(Reference) :
= nil;
TApplication与主消息循环    raise;
TApplication与主消息循环  
end;
TApplication与主消息循环   
// 第一个创建的窗体实例就是MainForm
TApplication与主消息循环  
if (FMainForm = nil) and (Instance is TForm) then
TApplication与主消息循环  begin
TApplication与主消息循环    TForm(Instance).HandleNeeded;
TApplication与主消息循环    FMainForm :
= TForm(Instance);
TApplication与主消息循环  
end;
TApplication与主消息循环
end;

因此,Delphi为每个应用程序自动生成的代码中就有对CreateForm的调用,如:
Application.CreateForm(TForm1, Form1);
值得注意的是,如果有一系列的多个CreateForm的调用,则第一个调用CreateForm被创建的窗体,就是整个Application的MainForm。

3.TApplication创建主消息循环
      在TApplication的CreateHandle方法中可以看到,SetWindowLong()的调用将TApplication.WndProc设置成了那个0×0大小窗口的窗口函数。
也就是说,在TApplication的构造函数中主要完成了两件事情:注册窗口类及窗口函数,创建Application窗口实例。TApplication类的Run方法中:
TApplication与主消息循环procedure TApplication.Run;
TApplication与主消息循环begin
TApplication与主消息循环  FRunning :
= True;
TApplication与主消息循环  try
TApplication与主消息循环    AddExitProc(DoneApplication);
TApplication与主消息循环    
if FMainForm <> nil then
TApplication与主消息循环    begin
TApplication与主消息循环      
case CmdShow of
TApplication与主消息循环        SW_SHOWMINNOACTIVE: FMainForm.FWindowState :
= wsMinimized;
TApplication与主消息循环        SW_SHOWMAXIMIZED: MainForm.WindowState :
= wsMaximized;
TApplication与主消息循环      
end;
TApplication与主消息循环      
if FShowMainForm then
TApplication与主消息循环        
if FMainForm.FWindowState = wsMinimized then
TApplication与主消息循环          Minimize 
else
TApplication与主消息循环          FMainForm.Visible :
= True;
TApplication与主消息循环      repeat
TApplication与主消息循环        try
TApplication与主消息循环          HandleMessage;
TApplication与主消息循环        except
TApplication与主消息循环          HandleException(Self);
TApplication与主消息循环        
end;
TApplication与主消息循环      until Terminated;
TApplication与主消息循环    
end;
TApplication与主消息循环  finally
TApplication与主消息循环    FRunning :
= False;
TApplication与主消息循环  
end;
TApplication与主消息循环
end;
TApplication与主消息循环

是的,这就是主消息循环。看上去似乎没有取消息、分发消息的过程,其实它们都被包含在HandleMessage()方法中了。HandleMessage()方法其实是对ProcessMessage()方法的调用,而在ProcessMessage()中就可以看到取消息、分发消息的动作了。
TApplication与主消息循环procedure TApplication.HandleMessage;
TApplication与主消息循环var
TApplication与主消息循环  Msg: TMsg;
TApplication与主消息循环begin
TApplication与主消息循环  
if not ProcessMessage(Msg) then Idle(Msg);
TApplication与主消息循环
end;
TApplication与主消息循环
TApplication与主消息循环
function TApplication.ProcessMessage(var Msg: TMsg): Boolean;
TApplication与主消息循环var
TApplication与主消息循环  Handled: 
Boolean;
TApplication与主消息循环begin
TApplication与主消息循环  Result :
= False;
TApplication与主消息循环  
// 取消息
TApplication与主消息循环  
if PeekMessage(Msg, 000, PM_REMOVE) then
TApplication与主消息循环  begin
TApplication与主消息循环    Result :
= True;
TApplication与主消息循环    
if Msg.Message <> WM_QUIT then
TApplication与主消息循环    begin
TApplication与主消息循环      Handled :
= False;
TApplication与主消息循环      
if Assigned(FOnMessage) then FOnMessage(Msg, Handled);
TApplication与主消息循环      
if not IsHintMsg(Msg) and not Handled and not IsMDIMsg(Msg) and
TApplication与主消息循环        
not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then
TApplication与主消息循环      begin
TApplication与主消息循环        
// 熟悉的分发消息过程
TApplication与主消息循环        TranslateMessage(Msg);
TApplication与主消息循环        DispatchMessage(Msg);
TApplication与主消息循环      
end;
TApplication与主消息循环    
end
TApplication与主消息循环    
else
TApplication与主消息循环      
// 如果取到的消息为WM_QUIT,则将Fterminate设为真
TApplication与主消息循环       
// 以通知主消息循环退出
TApplication与主消息循环       
// 这和WindowDemo程序中判断GetMessage()函数返回值是否为0等效
TApplication与主消息循环       
// 因为GetMessage()函数取出的消息如果是WM_QUIT,它的返回值为0
TApplication与主消息循环      FTerminate :
= True;
TApplication与主消息循环  
end;
TApplication与主消息循环
end;


4.窗口函数(WndProc)处理消息
窗口函数是一个回调函数,它被Windows系统所调用,其参数会被给出消息编号、消息参数等信息,以便进行处理。
典型的窗口函数中会包含一个大的case分支,以处理不同的消息。TApplication.CreateHandle()的代码时提到过,CreateHandle()将Application窗口的窗口函数设置为WndProc()。那么,现在就来看一下这个WndProc:
TApplication与主消息循环procedure TApplication.WndProc(var Message: TMessage);
TApplication与主消息循环type 
// 函数内嵌定义的类型,只限函数内部使用
TApplication与主消息循环  TInitTestLibrary 
= function(Size: DWord; PAutoClassInfo: Pointer): Boolean; stdcall;
TApplication与主消息循环
TApplication与主消息循环var
TApplication与主消息循环  I: 
Integer;
TApplication与主消息循环  SaveFocus, TopWindow: HWnd;
TApplication与主消息循环  InitTestLibrary: TInitTestLibrary;
TApplication与主消息循环  
// 内嵌函数,默认的消息处理
TApplication与主消息循环   
// 调用Windows的API函数DefWindowProc
TApplication与主消息循环  procedure Default;
TApplication与主消息循环  begin
TApplication与主消息循环    
with Message do
TApplication与主消息循环      Result :
= DefWindowProc(FHandle, Msg, WParam, LParam);
TApplication与主消息循环  
end;
TApplication与主消息循环
TApplication与主消息循环  procedure DrawAppIcon;
TApplication与主消息循环  var
TApplication与主消息循环    DC: HDC;
TApplication与主消息循环    PS: TPaintStruct;
TApplication与主消息循环  begin
TApplication与主消息循环    
with Message do
TApplication与主消息循环    begin
TApplication与主消息循环      DC :
= BeginPaint(FHandle, PS);
TApplication与主消息循环      DrawIcon(DC, 
00, GetIconHandle);
TApplication与主消息循环      EndPaint(FHandle, PS);
TApplication与主消息循环    
end;
TApplication与主消息循环  
end;
TApplication与主消息循环
TApplication与主消息循环begin
TApplication与主消息循环  try
TApplication与主消息循环    Message.Result :
= 0;
TApplication与主消息循环    
for I := 0 to FWindowHooks.Count - 1 do
TApplication与主消息循环      
if TWindowHook(FWindowHooks[I]^)(Message) then Exit;
TApplication与主消息循环    CheckIniChange(Message);
TApplication与主消息循环    
with Message do
TApplication与主消息循环      
// 开始庞大的case分支,对不同的消息做出不同的处理
TApplication与主消息循环      
case Msg of
TApplication与主消息循环        WM_SYSCOMMAND:
TApplication与主消息循环          
case WParam and $FFF0 of
TApplication与主消息循环            SC_MINIMIZE: Minimize;
TApplication与主消息循环            SC_RESTORE: Restore;
TApplication与主消息循环          
else
TApplication与主消息循环            Default;
TApplication与主消息循环          
end;
TApplication与主消息循环        WM_CLOSE:
TApplication与主消息循环          
if MainForm <> nil then MainForm.Close;
TApplication与主消息循环        WM_PAINT:
TApplication与主消息循环          
if IsIconic(FHandle) then DrawAppIcon else Default;
TApplication与主消息循环        WM_ERASEBKGND:
TApplication与主消息循环          begin
TApplication与主消息循环            Message.Msg :
= WM_ICONERASEBKGND;
TApplication与主消息循环            Default;
TApplication与主消息循环          
end;
TApplication与主消息循环        WM_QUERYDRAGICON:
TApplication与主消息循环          Result :
= GetIconHandle;
TApplication与主消息循环        WM_SETFOCUS:
TApplication与主消息循环          begin
TApplication与主消息循环            PostMessage(FHandle, CM_ENTER, 
00);
TApplication与主消息循环            Default;
TApplication与主消息循环          
end;
TApplication与主消息循环        WM_ACTIVATEAPP:
TApplication与主消息循环          begin
TApplication与主消息循环            Default;
TApplication与主消息循环            FActive :
= TWMActivateApp(Message).Active;
TApplication与主消息循环            
if TWMActivateApp(Message).Active then
TApplication与主消息循环            begin
TApplication与主消息循环              RestoreTopMosts;
TApplication与主消息循环              PostMessage(FHandle, CM_ACTIVATE, 
00)
TApplication与主消息循环            
end
TApplication与主消息循环            
else
TApplication与主消息循环            begin
TApplication与主消息循环              NormalizeTopMosts;
TApplication与主消息循环              PostMessage(FHandle, CM_DEACTIVATE, 
00);
TApplication与主消息循环            
end;
TApplication与主消息循环          
end;
TApplication与主消息循环        WM_ENABLE:
TApplication与主消息循环          
if TWMEnable(Message).Enabled then
TApplication与主消息循环          begin
TApplication与主消息循环            RestoreTopMosts;
TApplication与主消息循环            
if FWindowList <> nil then
TApplication与主消息循环            begin
TApplication与主消息循环              EnableTaskWindows(FWindowList);
TApplication与主消息循环              FWindowList :
= nil;
TApplication与主消息循环            
end;
TApplication与主消息循环            Default;
TApplication与主消息循环          
end else
TApplication与主消息循环          begin
TApplication与主消息循环            Default;
TApplication与主消息循环            
if FWindowList = nil then
TApplication与主消息循环              FWindowList :
= DisableTaskWindows(Handle);
TApplication与主消息循环            NormalizeAllTopMosts;
TApplication与主消息循环          
end;
TApplication与主消息循环        WM_CTLCOLORMSGBOX..WM_CTLCOLORSTATIC:
TApplication与主消息循环          Result :
= SendMessage(LParam, CN_BASE + Msg, WParam, LParam);
TApplication与主消息循环        WM_ENDSESSION: 
if TWMEndSession(Message).EndSession then FTerminate := True;
TApplication与主消息循环        WM_COPYDATA:
TApplication与主消息循环          
if (PCopyDataStruct(Message.lParam)^.dwData = DWORD($DE534454)) and
TApplication与主消息循环            (FAllowTesting) 
then
TApplication与主消息循环            
if FTestLib = 0 then
TApplication与主消息循环            begin
TApplication与主消息循环              FTestLib :
= SafeLoadLibrary('vcltest3.dll');
TApplication与主消息循环
              if FTestLib <> 0 then
TApplication与主消息循环              begin
TApplication与主消息循环                Result :
= 0;
TApplication与主消息循环                @InitTestLibrary :
= GetProcAddress(FTestLib, 'RegisterAutomation');
TApplication与主消息循环
                if @InitTestLibrary <> nil then
TApplication与主消息循环                  InitTestLibrary(PCopyDataStruct(Message.lParam)
^.cbData,
TApplication与主消息循环                    PCopyDataStruct(Message.lParam)
^.lpData);
TApplication与主消息循环              
end
TApplication与主消息循环              
else
TApplication与主消息循环              begin
TApplication与主消息循环                Result :
= GetLastError;
TApplication与主消息循环                FTestLib :
= 0;
TApplication与主消息循环              
end;
TApplication与主消息循环            
end
TApplication与主消息循环            
else
TApplication与主消息循环              Result :
= 0;
TApplication与主消息循环        CM_ACTIONEXECUTE, CM_ACTIONUPDATE:
TApplication与主消息循环          Message.Result :
= Ord(DispatchAction(Message.Msg, TBasicAction(Message.LParam)));
TApplication与主消息循环        CM_APPKEYDOWN:
TApplication与主消息循环          
if IsShortCut(TWMKey(Message)) then Result := 1;
TApplication与主消息循环        CM_APPSYSCOMMAND:
TApplication与主消息循环          
if MainForm <> nil then
TApplication与主消息循环            
with MainForm do
TApplication与主消息循环              
if (Handle <> 0and IsWindowEnabled(Handle) and
TApplication与主消息循环                IsWindowVisible(Handle) 
then
TApplication与主消息循环              begin
TApplication与主消息循环                FocusMessages :
= False;
TApplication与主消息循环                SaveFocus :
= GetFocus;
TApplication与主消息循环                Windows.SetFocus(Handle);
TApplication与主消息循环                Perform(WM_SYSCOMMAND, WParam, LParam);
TApplication与主消息循环                Windows.SetFocus(SaveFocus);
TApplication与主消息循环                FocusMessages :
= True;
TApplication与主消息循环                Result :
= 1;
TApplication与主消息循环              
end;
TApplication与主消息循环        CM_ACTIVATE:
TApplication与主消息循环          
if Assigned(FOnActivate) then FOnActivate(Self);
TApplication与主消息循环        CM_DEACTIVATE:
TApplication与主消息循环          
if Assigned(FOnDeactivate) then FOnDeactivate(Self);
TApplication与主消息循环        CM_ENTER:
TApplication与主消息循环          
if not IsIconic(FHandle) and (GetFocus = FHandle) then
TApplication与主消息循环          begin
TApplication与主消息循环            TopWindow :
= FindTopMostWindow(0);
TApplication与主消息循环            
if TopWindow <> 0 then Windows.SetFocus(TopWindow);
TApplication与主消息循环          
end;
TApplication与主消息循环        WM_HELP,   
// MessageBox(TApplication与主消息循环 MB_HELP)
TApplication与主消息循环        CM_INVOKEHELP: InvokeHelp(WParam, LParam);
TApplication与主消息循环        CM_WINDOWHOOK:
TApplication与主消息循环          
if wParam = 0 then
TApplication与主消息循环            HookMainWindow(TWindowHook(Pointer(LParam)
^)) else
TApplication与主消息循环            UnhookMainWindow(TWindowHook(Pointer(LParam)
^));
TApplication与主消息循环        CM_DIALOGHANDLE:
TApplication与主消息循环          
if wParam = 1 then
TApplication与主消息循环            Result :
= FDialogHandle
TApplication与主消息循环          
else
TApplication与主消息循环            FDialogHandle :
= lParam;
TApplication与主消息循环        WM_SETTINGCHANGE:
TApplication与主消息循环          begin
TApplication与主消息循环            Mouse.SettingChanged(wParam);
TApplication与主消息循环            SettingChange(TWMSettingChange(Message));
TApplication与主消息循环            Default;
TApplication与主消息循环          
end;
TApplication与主消息循环        WM_FONTCHANGE:
TApplication与主消息循环          begin
TApplication与主消息循环            Screen.ResetFonts;
TApplication与主消息循环            Default;
TApplication与主消息循环          
end;
TApplication与主消息循环        WM_NULL:
TApplication与主消息循环          CheckSynchronize;  
TApplication与主消息循环      
else
TApplication与主消息循环        Default;
TApplication与主消息循环      
end;
TApplication与主消息循环  except
TApplication与主消息循环    HandleException(Self);
TApplication与主消息循环  
end;
TApplication与主消息循环
end;

整个WndProc()方法,基本上只包含了一个庞大的case分支,其中给出了每个消息的处理代码,“WM_”打头的为Windows定义的窗口消息,“CM_”打头的为VCL库自定义的消息。
需要注意的是,这里给出WndProc是属于TApplication的,也就是那个0×0大小的Application窗口的窗口函数,而每个Form另外都有自己的窗口函数。

相关文章: