1.标准控件
可以在win32窗口程序中添加资源脚本来给程序添加标准控件;
具体操作为:新建资源脚本 ->在.rc文件中添加控件 ->给控件绑定事件;
常用的标准控件:
Static ->组框,用来将窗口分成多个块
Group Box
Button
Check Box
Radio Button
Edit
ComboBox
ListBox
2.通用控件
标准控件是一些常用的控件,因此每当程序编译时,会将这些控件加到exe程序中;
因此标准控件总是可用的;
还有一些不常用的控件,因为不常用,每次编译时加到程序中会浪费空间;
这些控件就是通用控件;
微软为了节省程序空间,将不常用的通用控件放在Comctrl32.dll中;
如果要使用通用控件,首先要引入该动态链接库:
#include <commctrl.h>
#pragma comment(lib,"comctl32.lib")
常用的通用控件:
Animation
ComboBoxEx
Date_and_Time_Picker
Drag_List_Box
Flat_Scroll_Bar
Header
HotKey
ImageList
IPAddress
List_View
Month_Calendar
Pager
Progress_Bar
Property_Sheets
Rebar
Status Bars
SysLink
Tab
Toolbar
ToolTip
Trackbar
TreeView
Up_and_Down
特别说明:
通用控件在使用前,需要通过INITCOMMONCONTROLSEX进行初始化
只要在您的程序中的任意地方引用了该函数就、会使得WINDOWS的程序加载器PE Loader加载该库
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&icex);
也就是告诉PE Loader到底要dll中的哪些通用控件;
这段代码一般放winmain刚开始的地方;
在msdn中搜索INITCOMMONCONTROLSEX结构,可以看到哪个参数对应的是哪个控件,例如:ICC_WIN95_CLASSES表示包含大多数常用通用控件;
3.ListView的使用
ListView是一种通用控件;用来显示多条信息;
往listView中添加数据:
#include <windows.h>
#include "resource.h"
#include <commctrl.h>
#pragma comment(lib,"comctl32.lib")
//给进程窗口添加内容;就是给ListView控件添加列,本来是要遍历进程的,为了简单填假数据
void EnumProcess(HWND hListProcess){
LV_ITEM vitem;
//初始化
memset(&vitem,0,sizeof(LV_ITEM));
vitem.mask = LVIF_TEXT;
vitem.pszText = "csrss.exe"; //值
vitem.iItem = 0; //行
vitem.iSubItem = 0; //列
//ListView_InsertItem(hListProcess, &vitem); //一个宏和SendMessage作用一样
SendMessage(hListProcess, LVM_INSERTITEM,0,(DWORD)&vitem); //如果用SendMessage,给第一列赋值用LVM_INSERTITEM,其它列用LVM_SETITEM,用ListView同理
vitem.pszText = TEXT("448");
vitem.iItem = 0;
vitem.iSubItem = 1;
ListView_SetItem(hListProcess, &vitem);
vitem.pszText = TEXT("56590000");
vitem.iItem = 0;
vitem.iSubItem = 2;
ListView_SetItem(hListProcess, &vitem);
vitem.pszText = TEXT("000F0000");
vitem.iItem = 0;
vitem.iSubItem = 3;
ListView_SetItem(hListProcess, &vitem);
vitem.pszText = TEXT("winlogon.exe");
vitem.iItem = 1;
vitem.iSubItem = 0;
//ListView_InsertItem(hListProcess, &vitem);
SendMessage(hListProcess, LVM_INSERTITEM,0,(DWORD)&vitem);
vitem.pszText = TEXT("456");
vitem.iSubItem = 1;
ListView_SetItem(hListProcess, &vitem);
vitem.pszText = TEXT("10000000");
vitem.iSubItem = 2;
ListView_SetItem(hListProcess, &vitem);
vitem.pszText = TEXT("000045800");
vitem.iSubItem = 3;
ListView_SetItem(hListProcess, &vitem);
}
//初始化进程窗口,就是给ListView控件添加列
void initProcessView(HWND hDlg){
LV_COLUMN lv;
HWND hListProcess;
//初始化,局部变量堆栈中分配,不知道是什么数据所以先清零
memset(&lv,0,sizeof(LV_COLUMN));
//获取IDC_LIST_PROCESS句柄
hListProcess = GetDlgItem(hDlg,IDC_LIST_PROCESS);
//设置整行选中,窗口是windows来管理的无法直接操作,程序能做的只能发送一个消息来让windows直到该怎么做
SendMessage(hListProcess,LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_FULLROWSELECT,LVS_EX_FULLROWSELECT);
//第一列
lv.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
lv.pszText = TEXT("进程"); //列标题
lv.cx = 150; //列宽
lv.iSubItem = 0;
//ListView_InsertColumn(hListProcess, 0, &lv);
SendMessage(hListProcess,LVM_INSERTCOLUMN,0,(DWORD)&lv);
//第二列
lv.pszText = TEXT("PID");
lv.cx = 90;
lv.iSubItem = 1;
//ListView_InsertColumn(hListProcess, 1, &lv);
SendMessage(hListProcess,LVM_INSERTCOLUMN,1,(DWORD)&lv);
//第三列
lv.pszText = TEXT("镜像基址");
lv.cx = 100;
lv.iSubItem = 2;
ListView_InsertColumn(hListProcess, 2, &lv);
//第四列
lv.pszText = TEXT("镜像大小");
lv.cx = 100;
lv.iSubItem = 3;
ListView_InsertColumn(hListProcess, 3, &lv);
EnumProcess(hListProcess);
}
//回调函数
BOOL CALLBACK DialogProc(
HWND hwndDlg, // handle to dialog box
UINT uMsg, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
switch(uMsg)
{
case WM_INITDIALOG :
initProcessView(hwndDlg); //初始化列表
return TRUE;
case WM_COMMAND :
switch (LOWORD (wParam))
{
case IDC_BUTTON_SHOW:
return TRUE;
case IDC_BUTTON_ABOUT:
return TRUE;
case IDC_BUTTON_OUT:
EndDialog(hwndDlg, 0);
return TRUE;
}
break ;
}
return FALSE ;
}
//程序入口
int CALLBACK WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevHinstance,
LPSTR lpCmdLine,
int nCmdShow
){
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&icex);
//创建对话框窗口
DialogBox(
hInstance,
MAKEINTRESOURCE(DLG_MAIN),
NULL,
DialogProc
);
return 0;
}
结果:
3.WM_NOTIFY消息
该消息类型与WM_COMMAND类型相似,都是由子窗口向父窗口发送的消息。
WM_NOTIFY可以包含比WM_COMMAND更丰富的信息
Windows通用组件中有很多消息,都是通过WM_NOTIFY来描述的.
例如:
当点击按钮时,按钮自身的回调函数会将消息转为WM_COMMAND消息给主窗口的回调函数;
如果是想处理ListView的列的点击事件,则是通过WM_NOTIFY;
WM_NOTIFY消息参数如下:
wParam:控件ID
lParam:指向一个结构,并且这个结构是可以拓展的,因此比WM_COMMAND能传递更多消息
typedef struct tagNMHDR {
HWND hwndFrom; //发送通知消息的控件窗口句柄; ->哪个子窗口发的消息
UINT idFrom; //发送通知消息的控件ID值; ->子窗口的哪个控件发过来的
UINT code; //通知码,如LVM_SELCHANGED; -> 做了那些事:点左键、点右键、值改变等等
} NMHDR;
这个结构体能满足一般的要求,但能描述的信息还是有限的
解决方案:对每种不同用途的通知消息都定义另一种结构来表示
typedef struct tagNMLVCACHEHINT {
NMHDR hdr;
int iFrom;
int iTo;
} NMLVCACHEHINT, *PNMLVCACHEHINT;
typedef struct tagLVDISPINFO {
NMHDR hdr;
LVITEM item;
} NMLVDISPINFO, FAR *LPNMLVDISPINFO;
typedef struct _NMLVFINDITEM {
NMHDR hdr;
int iStart;
LVFINDINFO lvfi;
} NMLVFINDITEM, *PNMLVFINDITEM;
这些结构有个特点:
它们的第一个成员都是NMHDR结构;
相当于c++中的继承,拓展了NMHDR结构;