WIN32汇编: 18.通用控件

AgentVerse实战:构建多智能体协作系统的关键技术与应用场景 本文深入探讨了AgentVerse框架在构建多智能体协作系统中的关键技术及应用场景。通过分析智能体通信协议、环境交互机制和任务分解算法,展示了如何利用大型语言模型(LLM)实现智能体间的专业化分工与动态协作。文章还提供了智能软件开发团队和智能客服系统等典型应用案例,以及部署优化实践,为开发者构建高效的多智能体系统提供实用指导。 阅读详情

第十八课 通用控件


本课中我们将学习什么是通用控件和如何使用它们。

理论:

WIN95相对于WIN3X有几个加强的用户界面控件。其实在WIN95正式发行前这些控件就在使用,譬如:状态条、工具条等。以前程序员要自己去编程使用它们,现在微软已经把它们包含到了WIN9X和WINNT中了。
  • Toolbar ---工具条
  • Tooltip ---提示文本
  • Status bar ---状态条
  • Property sheet ---属性页单
  • Property page ---属性页
  • Tree view ---树型视图
  • List view ---列表视图
  • Animation ---动画
  • Drag list ---能够处理Drag-Drop的列表框
  • Header ---
  • Hot-key ---热键
  • Image list ---图象链表
  • Progress bar ---进程状态条
  • Right edit ---
  • Tab ---跳格表
  • Trackbar ---跟踪条
  • Up-down ---滚动条
因为通用控件的数量非常多,把它们全部装入内存并注册它们是非常浪费内存的。除了“RTF文本编辑”控件外其他控件的可执行代码都放在comctl32.dll中,这样其他的应用程序就可以使用它们了。“RTF文本编辑”控件在richedXX.dll中,由于该控件非常的复杂,所以也比其它控件大。
要加载comctl32.dll可以在您的应用程序中调用函数InitCommonControls。InitCommonControls函数是动态链接库comctl32.dll中的一个函数,只要在您的程序中的任意地方引用了该函数就、会使得WINDOWS的程序加载器PE Loader加载该库。函数InitCommonControls其实只有一条指令“ret”,它的唯一目的是为了使得在调用了个该函数的应用程序的可执行文件的PE头中的“引入”段中包含有comctl32.dll,这样无论什么时候该应用程序都会为您加载该库。所以真正初始化的工作是在该库的入口点处做的,在这里会注册所有的通用控件类,然后所有的通用控件就可以在这些类上进行创建,这就象创建其它的子窗口控件一样。
RTF文本编辑控件则不同。如果您要使用它,就必须调用LoadLibrary函数来动态加载,并调用FreeLibrary来动态地卸载。
现在我们学习如何创建这些通用控件。您可以用资源编辑器把它们放到一个对话框中,或者您也可以自己调用相关的函数来手动创建它们。几乎所有的通用控件都是调用函数CreateWindowEx或CreateWindow来创建的,您只要在其中传递通用控件的类名即可。有一些通用控件有一些特别的创建函数,但是其实这些函数在内部都调用了CreateWindowEx,只是包装后的函数更方便使用而已。经过包装的函数有:
  • CreateToolbarEx
  • CreateStatusWindow
  • CreatePropertySheetPage
  • PropertySheet
  • ImageList_Create
为了创建通用控件您必须要知道它们的类名,我们把类名列于如下:
 
类名
通用控件
ToolbarWindow32Toolbar
tooltips_class32Tooltip
msctls_statusbar32Status bar
SysTreeView32Tree view
SysListView32List view
SysAnimate32Animation
SysHeader32Header
msctls_hotkey32Hot-key
msctls_progress32Progress bar
RICHEDITRich edit
msctls_updown32Up-down
SysTabControl32Tab

 

Property sheets、property pages和image list控件有它们自己的创建函数。Drag list其实是可以伸缩的listbox控件,所以它没有自己的类名。上面的类名是VC++的资源编辑器提供的,它们和Borland公司的WIN32 API指南中提出的不一样,和Petzold的书《Programming Windows 95》也不一样。可以肯定的是我们上面列出的类名绝对准确。 这些通用控件可以有通用的窗口类的一些风格,譬如WS_CHILD等。它们当然还有其他的特殊风格,譬如树型视图控件就有TVS_XXXXX风格,列表控件就有LVS_xxxx风格。具体的最好查找有关的WIN32 API函数指南。 既然我们已经知道了如何创建一个通用控件,我们就可以讨论这些通用控件之间以及和它们的父窗口之间是如何通讯的了。不象子窗口控件,通用控件在某些状态发生变化时不是通过发送WM_COMMAND而是发送WM_NOTIFY消息和父窗口通讯的。父窗口可以通过发送消息来控制子窗口的行为。对于那些新的通用控件,还有一些新的消息类型。您可以参考您的WIN32 API手册。

在下面的例子中我们将要实验一下进度条和状态条。

例子代码:
.386
.model flat,stdcall
option casemap:none
include /masm32/include/windows.inc
include /masm32/include/user32.inc
include /masm32/include/kernel32.inc
include /masm32/include/comctl32.inc
includelib /masm32/lib/comctl32.lib
includelib /masm32/lib/user32.lib
includelib /masm32/lib/kernel32.lib

WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD

.const
IDC_PROGRESS equ 1            ; control IDs
IDC_STATUS equ 2
IDC_TIMER  equ 3

.data
ClassName  db "CommonControlWinClass",0
AppName    db "Common Control Demo",0
ProgressClass  db "msctls_progress32",0       ; the class name of the progress bar
Message  db "Finished!",0
TimerID  dd 0

.data?
hInstance  HINSTANCE ?
hwndProgress dd ?
hwndStatus dd ?
CurrentStep dd ?
.code
start:
    invoke GetModuleHandle, NULL
    mov    hInstance,eax
    invoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULT
    invoke ExitProcess,eax
    invoke InitCommonControls

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
    LOCAL wc:WNDCLASSEX
    LOCAL msg:MSG
    LOCAL hwnd:HWND

    mov   wc.cbSize,SIZEOF WNDCLASSEX
    mov   wc.style, CS_HREDRAW or CS_VREDRAW
    mov   wc.lpfnWndProc, OFFSET WndProc
    mov   wc.cbClsExtra,NULL
    mov   wc.cbWndExtra,NULL
    push  hInst
    pop   wc.hInstance
    mov   wc.hbrBackground,COLOR_APPWORKSPACE
    mov   wc.lpszMenuName,NULL
    mov   wc.lpszClassName,OFFSET ClassName
    invoke LoadIcon,NULL,IDI_APPLICATION
    mov   wc.hIcon,eax
    mov   wc.hIconSm,eax
    invoke LoadCursor,NULL,IDC_ARROW
    mov   wc.hCursor,eax
    invoke RegisterClassEx, addr wc
    invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,/
WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+WS_MINIMIZEBOX+WS_MAXIMIZEBOX+WS_VISIBLE,CW_USEDEFAULT,/
           CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,/
           hInst,NULL
    mov   hwnd,eax
    .while TRUE
         invoke GetMessage, ADDR msg,NULL,0,0
        .BREAK .IF (!eax)
        invoke TranslateMessage, ADDR msg
        invoke DispatchMessage, ADDR msg
    .endw
    mov eax,msg.wParam
    ret
WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    .if uMsg==WM_CREATE
         invoke CreateWindowEx,NULL,ADDR ProgressClass,NULL,/
            WS_CHILD+WS_VISIBLE,100,/
            200,300,20,hWnd,IDC_PROGRESS,/
            hInstance,NULL
        mov hwndProgress,eax
        mov eax,1000               ; the lParam of PBM_SETRANGE message contains the range
        mov CurrentStep,eax
        shl eax,16                   ; the high range is in the high word
        invoke SendMessage,hwndProgress,PBM_SETRANGE,0,eax
        invoke SendMessage,hwndProgress,PBM_SETSTEP,10,0
        invoke CreateStatusWindow,WS_CHILD+WS_VISIBLE,NULL,hWnd,IDC_STATUS
        mov hwndStatus,eax
        invoke SetTimer,hWnd,IDC_TIMER,100,NULL        ; create a timer
        mov TimerID,eax
    .elseif uMsg==WM_DESTROY
        invoke PostQuitMessage,NULL
        .if TimerID!=0
            invoke KillTimer,hWnd,TimerID
        .endif
    .elseif uMsg==WM_TIMER        ; when a timer event occurs
        invoke SendMessage,hwndProgress,PBM_STEPIT,0,0    ; step up the progress in the progress bar
        sub CurrentStep,10
        .if CurrentStep==0
            invoke KillTimer,hWnd,TimerID
            mov TimerID,0
            invoke SendMessage,hwndStatus,SB_SETTEXT,0,addr Message
            invoke MessageBox,hWnd,addr Message,addr AppName,MB_OK+MB_ICONINFORMATION
            invoke SendMessage,hwndStatus,SB_SETTEXT,0,0
            invoke SendMessage,hwndProgress,PBM_SETPOS,0,0
        .endif
    .else
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        ret
    .endif
    xor eax,eax
    ret
WndProc endp
end start

分析:
  •     invoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULT
        invoke ExitProcess,eax
        invoke InitCommonControls
我故意把函数InitCommonControls放到ExitProcess后,这样就可以验证调用该函数仅仅是为了在我们程序的可执行文件的PE头中的引入段中放入引用了comctl32.dll的信息。您可以看到,即使该函数什么都没有做,我们的通用控件对话框依旧可以正常工作。
  •     .if uMsg==WM_CREATE
             invoke CreateWindowEx,NULL,ADDR ProgressClass,NULL,/
                WS_CHILD+WS_VISIBLE,100,/
                200,300,20,hWnd,IDC_PROGRESS,/
                hInstance,NULL
            mov hwndProgress,eax
在这里我们创建了通用控件。注意CreateWindowEx函数中的参数hWnd是父窗口的句柄。另外它也指定了通用控件的ID号。因为我们直接使用控件的窗口句柄,所以就没有使用该ID号。所有的窗口都必须具有WS_CHILD风格。
  •         mov eax,1000
            mov CurrentStep,eax
            shl eax,16
            invoke SendMessage,hwndProgress,PBM_SETRANGE,0,eax
            invoke SendMessage,hwndProgress,PBM_SETSTEP,10,0
在创建了进度条后我们先设定它的范围。缺省的范围是0-100。如果您不满意,可以重新设置,这通过传递PBM_SETRANGE消息来实现。参数lParam中包含了范围值,其中底字和高字分别是范围的起始和终了的值。您可以指定进度条每移动一格的步长。本例子中把步长设置成10,意味着每发送一次PBM_STEPIT消息给进度条,它的显示指针就会移动10。当然您可以调用PBM_SETPOS 来直接设定进度条上的指针的位置。用该消息您可以更方便地设定进度条了。
  •         invoke CreateStatusWindow,WS_CHILD+WS_VISIBLE,NULL,hWnd,IDC_STATUS
            mov hwndStatus,eax
            invoke SetTimer,hWnd,IDC_TIMER,100,NULL        ; create a timer
            mov TimerID,eax
下面我们调用CreateStatusWindow来创建状态条。这个调用很好理解,无需我多解释。在状态条创建后我们创建一个计时器。在本例中我们每隔100毫秒就更新一次进度条。下面时创建记时器的函数原型:
  • SetTimer PROTO hWnd:DWORD, TimerID:DWORD, TimeInterval:DWORD, lpTimerProc:DWORD
hWnd : 父窗口的句柄。
TimerID : 计时器的ID号。您可以指定一个唯一的非零值。
TimerInterval : 以毫秒计的时间间隔。
lpTimerProc : 计时器回调函数的地址。每当时间间隔到了的时候,该函数就会被系统调用。如果该值为NULL,计时器就会把WM_TIMER消息发送到父窗口。

如果SetTimer调用成功的话就会返回计时器的ID号值,否则返回0。这也是为什么计时器的ID号必须为非零值的原因。

  •     .elseif uMsg==WM_TIMER
            invoke SendMessage,hwndProgress,PBM_STEPIT,0,0
            sub CurrentStep,10
            .if CurrentStep==0
                invoke KillTimer,hWnd,TimerID
                mov TimerID,0
                invoke SendMessage,hwndStatus,SB_SETTEXT,0,addr Message
                invoke MessageBox,hWnd,addr Message,addr AppName,MB_OK+MB_ICONINFORMATION
                invoke SendMessage,hwndStatus,SB_SETTEXT,0,0
                invoke SendMessage,hwndProgress,PBM_SETPOS,0,0
            .endif
当指定的时间到了的时候,计时器将发送WM_TIMER消息。您可以在处理该消息时作适当的处理。本例中我们将更新进度条,并检查进度条是否超过最大的值。如果超过了的话,我们通过发送SB_SETTEXT消息来在状态条中设置文本。这时,弹出一个对话框,当用户关闭掉对话框后,我们去除掉进度条和状态条中的文本。
Windows通用控件 立即下载

相关推荐

阿里云消息队列(MQS)用户指南

阿里MQS的官方介绍文档,简单说明了阿里MQS的注册、使用、开发

7.3 通用控件

7.3 通用控件

qq_36314864的博客 802

通用控件程序

MFC基本控件用法,包括button ,list 等

InitCommonControls

InitCommonControlsInitCommonControlsEx    从Win95开始,Windows提供了一些新的Win32控件,称为通用控件.:Toolbar,Status bar,Tree view,List view,Animation,Hot-key,Image list,Tab等等.这些控件的可执行代码都放在comctl32.dll中.要使用通用控件,必须加载co...

qq_20848403的博客 1654

使用Win API创建工具栏

到网上查了下资料,初步实现了使用WinAPI创建工具栏。         下面是创建一个标准工具栏的函数,(这里所谓标准工具栏是指工具栏按钮图片是WinSDK内置的) [cpp] view plaincopyprint? BOOL CreateStandardToolbar(HWND hParent)  {      // 首先需要先调用InitCommonCon

joinwilson的专栏 894

InitCommonControls()

函数InitCommonControls是个空函数,不做任何事情。 但如果你调用了该函数,则链接器会将你的程序链接到comctl32.lib,然后在程序启动时,会加载comctl32.dll。 真正初始化的工作是在该库的入口点处做的,在这里会注册通用控件窗口类。 然后应用程序就可以创建控件窗口,就象创建其它的子窗口控件一样。 !!!!!!!!!!!!!!!!!!!!!!!!

a498506133的专栏 2343

PropertySheet最简化例子

一、PropertySheet说明 1.PropertySheet是对话框而非控件,虽然微软将他放在控件文章中来说明。但实际上PropertySheet是一个对话框容器,而非控件的容器。原因是其内部的Page页面,都是标准的对话框。所以应该将它划分为通用对话框一边。 2. PropertySheet的两种典型的使用方式是:Wizard和Tab标签页。一种方式是Wizard式的向导式对话

zzidea的专栏 2061

转载,ps杀进程的总结

学习

abitnervous的博客 499

Ubuntu ps 命令杀进程

1. ps 显示进程 显示进程信息,参数可省略 参数: -aux 以BSD风格显示进程 常用 -efH 以System V风格显示进程 -e , -A 显示所有进程 a 显示终端上所有用户的进程 x 显示无终端进程 u 显示详细信息 f 树状显示...

Luckcat 2688

58-awk 与 ps 杀进程

打印执行的命令: ps -ef | grep /usr/local/qfqz/qfqz.jar | grep -v grep | awk ‘{print "kill -9 " $2}’ 直接执行杀进程: ps -ef | grep /usr/local/qfqz/qfqz.jar | grep -v grep | awk ‘{print "kill -9 " $2}’ | sh

1165

linux ps -a ps -aux 杀进程

杀进程ps -axf |grep ./das | awk 'NR==1 {print $1}' | xargs kill -2Linux下显示系统进程的命令ps,最常用的有ps -ef 和ps aux。区别:两者输出格式不一样ps aux|grep ./update_stock root 14232 0.0 0.0 5928 724 pts/1 S+ 18:16 0:00 grep ./up...

weixin_33968104的博客 965

批量杀进程 ps awk grep

ps aux |grep lt-newindexclient |grep -v grep |awk '{print $2}'|xargs kill -9 grep -v 反向输出,即过滤掉带有grep的输出。 xargs:传递参数 转载于:https://www.cnblogs.com/zl1991/p/7365815.html...

weixin_30446197的博客 132

Linux查看进程ps -ef、杀进程kill

查看某个服务的进程 例如mysql: ps -ef|grep mysql 查看所有进程: ps -ef 结束进程(一般说杀进程): 注意:当一个服务无法用命令结束时,需要用杀进程 第一张图的pid为:第三行的90154 第二张图有一个pid列 kill pid //杀死该pid的进程 kill -9 pid //强制杀死该进程 ...

杨咩咩 6405

Linux命令基础15-ps和kill命令

本文介绍Linux下ps和kill的使用,ps是process status的缩写,kill在linunx中是杀进程的意思。就像windows,有时候那个程序没响应,你就可以去任务管理中删除那个没有响应的程序。 1.ps -ux, 查看当前的激活的进程 2.ps -aux,查看当前所有进程,a是all的意思 3.ps -U shiyanlou,查看shiyanlou这个用户有关的进程 4.打开实验...

weixin_43639443的博客 366

ps -ef与kill结合杀进程

4.xargs 命令把前面的输出作为后面命令kill -9 的输入,也就是传左边命令截取的进程号给命令kill -9。2.grep -v grep 命令可以忽略grep这个进程。3.awk ‘{print $2}’ 命令截取进程号。

wzj的博客 3453

ubuntu如何杀进程_Ubuntu 查看和杀死进程

今天在netbeans中关闭webrick时,发现没有关闭掉,打入localhost:3000 依然显示页面,发现无法从nb中再次关闭只有进入ubuntu的进程下关闭查看进程:1,ps -e 命令2,feng@feng:~$ sudo netstat -antupActive Internet connections (servers and established)Proto Recv-Q Se...

weixin_39981093的博客 364

linux根据ps杀进程,Linux_PS_查看进程_杀死进程_启动进程命令

进程是一个其中运行着一个或多个线程的地址空间和这些线程所需要的系统资源。一般来说,Linux系统会在进程之间共享程序代码和系统函数库,所以在任何时刻内存中都只有代码的一份拷贝。查进程ps命令查找与进程相关的PID号:ps a 显示现行终端机下的所有程序,包括其他用户的程序。ps -A 显示所有程序。ps c 列出程序时,显示每个程序真正的指令名称,而不包含路径,参数或常驻服务的标示。ps -e 此...

weixin_42169674的博客 879

Linux:使用ps-grep-awk批量kill杀进程

scheduler_center.py 为我要杀掉的进程 # ps -ef|grep scheduler_center.py root 12013 python3 scheduler_center.py root 12030 grep --color=auto scheduler_center.py # ps -ef|grep scheduler_center.py|gr...

彭世瑜的博客 4154

linux批量杀进程_Linux下批量杀掉筛选进程

1. 使用awk批量杀进程的命令碰到需要杀掉某一类进程的时候,如何批量杀掉这些进程,使用awk命令是很好的选择。ps -ef|grep xxx|grep -v grep就是从当前系统运行的进程的进程名中帅选包含xxx关键字的进程awk ‘pattern {action}’print是打印,kill -9 是强制停止进程的命令, $2就是前面有ps -ef命令得出的结果的第二列上显示的内容ps -e...

weixin_39757122的博客 432
上一篇: WIN32汇编: 19.树型视图控件
下一篇: WIN32汇编: 20.窗口子类化
GodDragon
博客等级 码龄25年 9粉丝 40原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值