api编程初步.doc

上传人:asd****56 文档编号:79333536 上传时间:2023-03-21 格式:DOC 页数:12 大小:81KB
返回 下载 相关 举报
api编程初步.doc_第1页
第1页 / 共12页
api编程初步.doc_第2页
第2页 / 共12页
点击查看更多>>
资源描述

《api编程初步.doc》由会员分享,可在线阅读,更多相关《api编程初步.doc(12页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。

1、使用RAD类型工具的人越来越多了,虽然我对于RAD类的工具向来不多作评议,但我还是常常使用的。所以我深深的知道这类工具虽然给我们带来了便利,使我们能不用将更多的精力放在界面上,但同时也将初学者紧紧的圈在了他所提供的控件和组件中。所以很多人并不能真正的了解windows的消息驱动原理以及windows的运作过程。本文中我们就一起来学习一下windows的运作过程,使我们对delphi这样一个优秀的编程工具有一个新的认识,并对windows下的程序编写有更深刻、透辟的了解和认识。一、消息的定义我们先从使用的角度看看windows的运作过程。我们都知道windows是一个多任务的平台,使用这个平台,

2、我们可以一边工作,一边听歌曲,等等。所以对于这个操作平台可以想象到它除了一般操作系统所提供的对文件系统,内存系统等的管理之外,更重要的就是我们所熟知的消息驱动了,也就是说,要通过一定的方法和结构可以给每一个运行中的程序实例以及其中的每一个窗口传递其中所触发的事件。Windows中究竟是怎样做到的呢?让我们打开安装delphi的目录,在其中的sourcertlWinWindows.pas文件(或者在一个工程文件,找到uses,在其中找到indows,然后按下Ctrl键,用鼠标点击单词),在其中的第18919行,我们可以看到这样一个结构的定义: Message structure PMsg = T

3、Msg ;tagMSG = packed recordhwnd : HWND ;message : UINT ;wParam : WPARAM ;lParam : LPARAM ;time : DWORD ;pt : TPoint ;end ; $ EXTERNALSYM tagMSG TMsg = tagMSG ;MSG = tagMSG ; $ EXTERNALSYM MSG 其中hwnd字段表示触发了消息的窗口的ID,由此可以保证消息正确的发送到每一个窗口去。 Message 表示消息的类型,其中更细致的解释要通过wParam和lParam一起来进行,不同的消息,wParam和lPara

4、m的值也就不相同。time用来记录消息触发的时间。Pt则表示触发的位置(毕竟window中有了鼠标)。我们也可以用同样的方法打开Messages文件。其中定义了windows中的绝大部分消息和结构。下面是我们截取的其中一部分。const $ EXTERNALSYM WM_NULL WM_NULL = $0000 ; $ EXTERNALSYM WM_CREATE WM_CREATE = $0001 ; $ EXTERNALSYM WM_DESTROY WM_DESTROY = $0002 ; $ EXTERNALSYM WM_MOVE WM_MOVE = $0003 ; $ EXTERNALS

5、YM WM_SIZE WM_SIZE = $0005 ; WM_APP = $8000 ; NOTE : All Message Numbers below 0x0400 are RESERVED Private Window Messages Start Here $ EXTERNALSYM WM_USER WM_USER = $0400 ; Dialog messages $ EXTERNALSYM DM_GETDEFID DM_GETDEFID = ( WM_USER+0 ) ; $ EXTERNALSYM DM_SETDEFID DM_SETDEFID = ( WM_USER+1 )

6、; $ EXTERNALSYM DM_REPOSITION DM_REPOSITION = ( WM_USER+2 ) ; $ EXTERNALSYM PSM_PAGEINFO PSM_PAGEINFO = ( WM_USER+100 ) ; $ EXTERNALSYM PSM_SHEETINFO PSM_SHEETINFO = ( WM_USER+101 ) ; Button Notification Codes 可以看到,windows中每一个消息都对应着一个唯一的数值。当然我们也可以定义自己的消息,它的数值只要定义在WM_USER之后,保证和其中的定义不想重复即可。二、消息的接收消息到是

7、有了,但怎样才能让程序以及窗口接收到呢?还是从使用的角度考虑,可以想象到,对于一个程序或窗口可以接收到来自鼠标、键盘等输入设备的消息,也可以接收到来自程序传递的消息,因为有了前面的tagMSG结构,我们就可以被动的在程序中接收消息了。这个功能的实现就是由下面的程序实现的(同样的这段程序来自于delphi的元代码):function Tapplication . ProcessMessage ( var Msg : TMsg ) : Boolean;varHandled : Boolean ;beginResult : = False ;if PeekMessage ( Msg , 0 , 0

8、, 0 , PM_REMOVE ) thenbegin Result : = True ; if Msg.Message WM_QUIT then begin Handled := False ; if Assigned ( FonMessage ) then FonMessage ( Msg , Handled ) ; if not IsHintMsg ( Msg ) and not Handled and not IsMDIMsg ( Msg ) and not IsKeyMsg ( Msg ) and not IsDlgMsg ( Msg ) then begin TranslateMe

9、ssage ( Msg ) ; DispatchMessage ( Msg ) ; end ; end ; else FTerminate : = True ; end ;end ;其中主要的是这几句:if PeekMessage ( Msg , 0 , 0 , 0 , PM_REMOVE ) thenbegin TranslateMessage ( Msg ) ; DispatchMessage ( Msg ) ;end ;但更常见的是:while GetMessage ( Msg , 0 , 0 , 0 ) dobegin TranslateMessage ( Msg ) ; Dispat

10、chMessage ( Msg ) ;End ;PeekMessage和GetMessage都是从消息队列中得到发给程序的消息,只要有消息,就通过TranslateMessage ( Msg )和DispatchMessage ( Msg )两句将消息翻译为可处理的格式并分派给应用程序所注册的回调函数进行处理。三、消息的处理那么消息是怎样被处理的呢?回调函数又有什么作用呢?有了前面的知识,我们只要能对不同的消息进行正确的解释,就可以做到对消息的正确处理了。但前面我们提到了对于不同的消息传递的信息使不相同的,所以这是API编程中最麻烦的一部分了。我们这里先给出一个常见而又必须的消息框架。func

11、tion WindowProc ( hwnd : HWnd ; Msg : UINT; Wparam : WPARAM ; Lparam : LPARAM ) : LRESULT ; stdcall ; export ;vardc : hdc ;rc : Trect ;ps : TpaintStruct ;begin case Msg of WM_PAINT : Begin dc : = BeginPaint ( hwnd , ps ) ; EndPaint (hwnd, &ps) ; Exit ;end;WM_COMMAND : WM_DESTROY :Begin PostQuitMessa

12、ge ( 0 ) ; Exit ;end ;end;Result : = DefWindowProc ( hWnd , Msg , wParam , lParam ) ;end ;在这个框架中,WindowProc就是我们前面提到的回调函数。它是windows程序设计中的重点。无论是从输入输出等硬件设备传来的消息,还是从软件传来的消息,都要保存到系统的消息队列中,这个消息队列有两种,一种是系统消息队列,主要是用来保存从输入输出等硬件设备传来的消息,另一种是每个程序窗口的窗口消息队列,主要保存每个窗口的发送来的消息。之后对消息的获取和分发工作,当然是由前面讲到的GetMessage 、 Tran

13、slateMessage和DispatchMessage三个函数来完成。至于消息的处理工作,则是由WindowProc函数来完成了。也就是说它是由系统在程序有消息到达时才调用的,所以我们称之为回调函数。WindowProc是在注册窗口类时,注册的窗口消息处理函数,当然名字可以自己命名。其中的参数有hwnd : HWnd ; Msg : UINT; Wparam : WPARAM ; Lparam : LPARAM ,这也就是我们前面谈到的消息和窗体。这里我们主要使用了三种消息:WM_PAINT , WM_COMMAND和WM_DESTROY ,但是我们可以随着程序而是用各种各样的消息。为了处理

14、不同的消息,在程序中使用了分支结构,所以随着程序的规模越来越大,这个分支结构也会越来越庞大。在这些消息中有两个点是最为重要的,其一是WM_DESTROY消息,它表示一个销毁窗口退出应用程序的消息。也是每个程序所必备的。对于这个消息的处理方式就是通过调用PostQuitMessage ( 0 )函数传递一个WM_QUIT消息,准备让由GetMessage 、 TranslateMessage和DispatchMessage三个函数组成的消息循环中的GetMessage取得。当消息循环中的收到WM_QUIT消息时,GetMessage会传回0,从而结束消息循环。进而释放各种资源,结束整个程序。另一

15、个重要的地方是DefWindowProc函数。我们的程序无论多大都不可能将所有的消息都处理,所以我们必须有一个机制让不重要的不需要我们处理的消息,交给windows操作系统为我们处理,这个过程就是由DefWindowProc函数来实现的。因此当我们按下窗口右上角的差号或者按下左上角系统菜单中的Close命令时,系统会送出WM_CLOSE消息。通常程序的窗口函数不拦截此消息,于是交由DefWindowProc函数来处理。DefWindowProc函数在受到WM_CLOSE消息后,调用DestroyWindow把窗口清除。DestroyWindow又会送出WM_DESTROY消息。程序又如前面讲到

16、的一样来结束程序释放资源。四、建立窗口类知道了消息的传递和处理之后,我们来看看有关窗口的知识。Windows带给我们的不仅是技术上的创新,更重要的是统一而又便捷的窗口。那么它是怎样创建的呢?这就要从窗口类tagWNDCLASSA说起了。让我们先打开delphi目录下的sourcertlWinWindows.pas文件,18875行,可以看到这样一个结构:tagWNDCLASSA = packed recordstyle : UINT ;lpfnWndProc : TFNWndProc ;cbClsExtra : Integer ;cbWndExtra : Integer ;hInstance

17、: HINST ;hIcon : HICON ;hCursor : HCURSOR ;hbrBackground : HBRUSH ;lpszMenuName : PansiChar ;lpszClassName : PansiChar ;end ;其中存储了一个窗口的所有相关信息。style : UINT 表示窗口的风格;lpfnWndProc : TFNWndProc 表示窗口的消息处理函数;hInstance : HINST 表示窗口的一个应用实例;Icon : HICON 用来记录窗口的图标;hCursor : HCURSOR 记录窗口的光标;hbrBackground : HBRUS

18、H 用来记录窗口的背景色;lpszMenuName : PansiChar 表示窗口中的菜单资源的名称; lpszClassName : PansiChar 记录窗口类的名称。下面是一个例子:WindowClass . style : = CS_VREDRAW + CS_HREDRAW + CS_DBLCLKS ;WindowClass . lpfnWndProc : = DefWindowProc ;WindowClass . hCursor : = LoadCursor ( 0 , IDC_ARROW ) ;WindowClass . hbrBackground : = 0 ;Window

19、Class . hInstance : = Hinstance ;StrPCopy ( WinClassName , ClassName ) ;五、注册窗口类当我们按照程序的要求创建了这个窗口类之后,我们就可以在系统中注册它了。这就要用到function RegisterClass(const lpWndClass: TWndClass): ATOM; stdcall;这样一个函数了。他只有一个参数,就是我们先前说注册的窗口类。六、创建窗口有了前面几步,现在我们可以创建我们所注册的窗口,看看她的真面目了。function CreateWindow ( lpClassName : Pchar ;

20、 lpWindowName : PChar ;dwStyle : DWORD ; X , Y , nWidth , nHeight : Integer ; hWndParent : HWND ;hMenu : HMENU ; hInstance : HINST ; lpParam : Pointer ) : HWND ;这个函数可以帮助我们创建我们先前注册的窗口。其中的参数lpClassName : Pchar表示我们前面注册的窗口类的名称。lpWindowName : PChar 表示窗口的标题; dwStyle : DWORD 表示窗口的风格; X , Y , nWidth , nHeig

21、ht : Integer ; 表示窗口的位置和宽度高度;七、显示窗口窗口创建了,但我们只有在调用function ShowWindow ( hWnd : HWND ; nCmdShow : Integer ) : BOOL ; stdcall ;函数之后才会显示出来。这个函数很简单,hWnd : HWND 表示窗口的句柄, nCmdShow : Integer则是窗口的显示方式。function UpdateWindow ( hWnd : HWND ) : BOOL ; stdcal l ;函数则会送出一个WM_PAINT消息,使窗体得到更新。也许你会觉得很烦人,但这是所有windows程序的

22、基础,即便是我们用delphi编程时,程序也都是这样运行的,只是delphi的创造者将一切都隐藏到了一个美丽外表之下。下面我们用大家最常见的一个例子对前面的知识加以总结。在这个例子中,我们将在窗体中显示“ hello , world ! ” 。下面是程序及其运行效果:program Project1; $ APPTYPE CONSOLE usesWindows ,Messages ; uses SysUtils ; varwClass : TWndClass; / 主窗口类hInst , /应用程序句柄Handle : HWnd ; / 主窗口aMsg : TMsg ; /消息RCT : TR

23、ect ; /区域ps : TPaintStruct ; /显示dc : hdc ; /设备上下文/函数:WindowProc/作用:处理主窗口的消息function WindowProc ( hWnd , Msg , wParam , lParam : Longint ) : Longint ; stdcall ;beginWindowProc : = 0 ; case Msg of WM_PAINT : begin dc : =BeginPaint ( hWnd , ps ) ; GetClientRect ( hWnd , RCT ) ; DrawText ( dc , hello ,

24、world ! , -1 , RCT , Dt_SINGLELINE or DT_CENTER or DT_VCENTER ) ; EndPaint ( hWnd , ps ) ; Exit ; end ; WM_DESTROY : /结束应用程序 Begin PostQuitMessage ( 0 ) ; Exit ; end ;end ;Result : = DefWindowProc ( hWnd , Msg , wParam , lParam ) ; /消息默认处理end ;/主窗口begin/ hInst : = GetModuleHandle ( nil ) ; / 获得应用程序句

25、柄with wClass do /初始化窗口类beginhInstance : = system.MainInstance ;Style : = CS_HREDRAW or CS_VREDRAW ;HIcon : = LoadIcon ( 0 , IDI_APPLICATION ) ;LpfnWndProc : = WindowProc ;HbrBackground : = GetStockObject ( WHITE_BRUSH ) ;lpszClassName : = Sample Class ;hCursor : = LoadCursor ( 0 , IDC_ARROW ) ;end ;

26、RegisterClass ( wClass ) ; / 注册窗口类/创建主窗口Handle : = CreateWindow ( Sample Class , / 窗口类名 Windows API在Delphi中的应用 , /窗口标题 WS_OVERLAPPEDWINDOW or WS_VISIBLE , / 窗口风格 10 , /左边界坐标 10 , /上边界坐标 400 , / 宽度 300 , / 高度 0 , / 父窗口句柄 0 , /菜单句柄 system . MainInstance , / 应用程序实例 nil /创建窗口的附加参数) ;if Handle 0 thenbegi

27、n ShowWindow ( Handle , SW_SHOW ) ; UpdateWindow ( Handle ) ;end ;while ( GetMessage ( aMsg , Handle , 0 , 0 ) ) do /消息循环begin TranslateMessage ( aMsg ) ; /翻译消息 DispatchMessage ( aMsg ) ; /发送消息end ;end .效果如下图:八、初步的封装, 面向过程的方式的编写可以看到对于任何一个Windows程序的创建和运行都要经过上面的几个步骤,而且这些步骤又很有条理,所以我们又可以将不同的功能封装在几个命名规范且

28、容易理解的函数之中。下面是修改后的程序代码:program Project1; $ APPTYPE CONSOLE usesWindows ,Messages ; uses SysUtils ; varwClass : TWndClass; / 主窗口类hInst , /应用程序句柄Handle : HWnd ; / 主窗口aMsg : TMsg ; /消息RCT : TRect ; /区域ps : TPaintStruct ; /显示dc : hdc ; /设备上下文/函数:WindowProc/作用:处理主窗口的消息function WindowProc ( hWnd , Msg , wP

29、aram , lParam : Longint ) : Longint ; stdcall ;beginWindowProc : = 0 ; case Msg of WM_PAINT : begin dc : =BeginPaint ( hWnd , ps ) ; GetClientRect ( hWnd , RCT ) ; DrawText ( dc , hello , world ! , -1 , RCT , Dt_SINGLELINE or DT_CENTER or DT_VCENTER ) ; EndPaint ( hWnd , ps ) ; Exit ; end ; WM_DESTR

30、OY : /结束应用程序 Begin PostQuitMessage ( 0 ) ; Exit ; end ;end ;Result : = DefWindowProc ( hWnd , Msg , wParam , lParam ) ; /消息默认处理end ;/函数:WinRegister/作用:注册窗口类function WinRegister : Boolean ;begin with wClass do /初始化窗口类 begin hInstance : = system.MainInstance ; Style : = CS_HREDRAW or CS_VREDRAW ; HIco

31、n : = LoadIcon ( 0 , IDI_APPLICATION ) ; LpfnWndProc : = WindowProc ; HbrBackground : = GetStockObject ( WHITE_BRUSH ) ; lpszClassName : = Sample Class ; hCursor : = LoadCursor ( 0 , IDC_ARROW ) ; end ;ReSult : = RegisterClass ( wClass ) 0 ; / 注册窗口类end ;/函数:WinCreate/作用:创建窗口function WinCreate : HWnd

32、 ;begin/创建主窗口Handle : = CreateWindow ( Sample Class , / 窗口类名 Windows API在Delphi中的应用 , /窗口标题 WS_OVERLAPPEDWINDOW or WS_VISIBLE , / 窗口风格 10 , /左边界坐标 10 , /上边界坐标 400 , / 宽度 300 , / 高度 0 , / 父窗口句柄 0 , /菜单句柄 system . MainInstance , / 应用程序实例 nil /创建窗口的附加参数) ; if Handle 0 then begin ShowWindow ( Handle , S

33、W_SHOW ) ; UpdateWindow ( Handle ) ; end ; Result : = Handle ;end ;/主窗口/程序的进入点begin if not WinRegister then /调用函数:WinRegister注册窗口类 begin MessageBox ( 0 , Register failed , nil , MB_OK ) ; Exit ; end ; Handle : = WinCreate ; /调用函数:WinCreate创建窗口 if longint ( Handle ) = 0 then begin MessageBox ( 0 , Wi

34、nCreate failed , nil , MB_OK ) ; Exit ; end; while ( GetMessage ( aMsg , Handle , 0 , 0 ) ) do /消息循环 begin TranslateMessage ( aMsg ) ; /翻译消息 DispatchMessage ( aMsg ) ; /发送消息 end ;end .九、进一步封装,面向对象的方法编写更进一步的话,我们就可以考虑用面向对象的方法来编写。可以看到如果我们要用上面的方法编写程序的话,工作量是十分繁重的,尤其在程序规模越来越大的情况下,出错的可能性也就会成指数性的增长。即使我们使用粘贴

35、拷贝仍然要对程序进行修改,出错的可能人不会避免。而面向对象的编程方法可以有效的克服以上的不足,大大的提高了代码的利用率。所以下面我们就用面向对象的方法来看一看同样的程序我们应该怎样编写。面向对象的核心就是要用类的方法来建立程序框架,然后用类的实例调用类的方法属性等手段来实现最终的效果。所以第一步我们首先又来建立一个窗口程序类,其中共有成员函数Create和 Destroy分别用来创建和销毁一个我们建立的窗口程序类的实例。共有成员函数WinCreate则调用私有成员函数WinRegister和 CreateMyWindow来注册和创建窗口。其中的属性变量ApplicationName 和 Win

36、dowProcedure 则是用来获得窗口程序类名和窗口消息处理函数的。下面是修改后的源代码:/用面向对象的方法来编写program TMyWindowClass;usesWindows,Messages,SysUtils;/创建窗口类typeTMyWindow = class ( TObject )private 定义私有变量 WindowClass : WndClass;hWindow : HWnd ;AMessage : TMsg ;FAppName : String ;FWndProc : TFNWndProc ;function WinRegister : Boolean ; vir

37、tual ;procedure CreateMyWindow ;public定义公有变量 constructor Create ;destructor Destroy ; override ;procedure WinCreate ; virtual ;procedure Run ;定义属性 property ApplicationName : String read FAppName write FAppName ;property WindowProcedure : TFNWndProc read FWndProc write FWndProc ;end ;constAppName = M

38、yClassshili ;varmyWindow : tMyWindow ; TMyWindow类中公有函数的实现 constructor TMyWindow . Create ;beginend ;destructor TMyWindow . Destroy ;begin inherited ;end ;procedure TMyWindow . CreateMyWindow ; /创建窗口begin hWindow : = CreateWindow ( AppName , hello , world , ws_OverlappedWindow , cw_UseDefault , cw_Us

39、eDefault , cw_UseDefault , cw_UseDefault , 0 , 0 , system . MainInstance , nil ) ; if hWindow 0 then begin ShowWindow ( hWindow , CmdShow ) ; ShowWindow ( hWindow , SW_SHOW ) ; UpdateWindow ( hWindow ) ; end ;end ;procedure TMyWindow . WinCreate ;begin if WinRegister then begin CreateMyWindow ; end

40、;end ;function TMyWindow . WinRegister : Boolean ; /注册窗口类begin WindowClass.Style : = cs_hRedraw or cs_vRedraw ; WindowClass . lpfnWndProc : = FWndProc ; WindowClass . cbClsExtra : = 0 ; WindowClass . cbWndExtra : = 0 ; WindowClass . hInstance : = system.MainInstance ; WindowClass . hIcon : = LoadIco

41、n ( 0 , idi_Application ) ; WindowClass . hCursor : = LoadCursor ( 0 , idc_Arrow ) ; WindowClass . hbrBackground : = GetStockObject ( WHITE_BRUSH ) ; WindowClass . lpszMenuName : = nil ; WindowClass . lpszClassName : = PChar ( FAppName ) ; Result : = RegisterClass ( WindowClass ) 0 ;end ;function Wi

42、ndowProc ( Window : HWnd ; Amessage : UINT ; WParam : WPARAM ;LParam : LPARAM ) : LRESULT ; stdcall ; export ;/消息处理函数vardc : hdc ;ps : TPaintStruct ;r : TRect ;begin WindowProc : = 0 ; case AMessage of WM_PAINT : begin dc : = BeginPaint ( Window , ps ) ; GetClientRect ( Window , r ) ; DrawText ( dc

43、, hello , world ! ! , -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 ;procedure TMyWindow . MyRun ;begin while GetMessage ( AMessage , 0 , 0 , 0 ) do begin TranslateMessage ( AMessage ) ; DispatchMessage ( AMessage ) ; end ; Halt ( AMessage . wParam ) ;end ;/主程序,程序运行的进入口beginmyWindow : = TMyWindow . Create ;myWindow . ApplicationName : = AppName ;my

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 技术资料 > 其他杂项

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知得利文库网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号-8 |  经营许可证:黑B2-20190332号 |   黑公网安备:91230400333293403D

© 2020-2023 www.deliwenku.com 得利文库. All Rights Reserved 黑龙江转换宝科技有限公司 

黑龙江省互联网违法和不良信息举报
举报电话:0468-3380021 邮箱:hgswwxb@163.com