Windows入门:
一、API函数
概念
API(Application Programming Interface,应用程序接口):“‘电脑操作系统(Operating system)’或‘程序库’提供给应用程序调用使用的代码”。其主要目的是让应用程序开发人员得以调用一组例程功能,而无须考虑其底层的源代码为何、或理解其内部工作机制的细节。API本身是抽象的,它仅定义了一个接口,而不涉及应用程序在实际实现过程中的具体操作。
API函数是一些预先定义的函数。操作系统除了协调应用程序的执行、内存分配、系统资源管理外,同时也是一个很大的服务中心,调用这个服务中心的各种服务(每一种服务是一个函数),可以帮助应用程序达到开启视窗、描绘图形、使用周边设备的目的。(以上来自百度百科)
笔记
FindWindows()
HWND FindWindow( //定义
LPCTSTR lpClassName, //窗口类名
LPCTSTR lpWindowName //窗口标题
);
功能:通过指定的窗口类名或窗口标题查找匹配的窗口并返回最上层的窗口句柄。
当使用FindWindow()函数获取窗口句柄是,指定窗口名是比较直观和容易的。但是,如果窗口名经常发生变化,那就不得不使用窗口类名了(SPY++获取窗口类名)。
SendMessage()
LRESULT SendMessage( //定义
HWND hWnd, //要接收消息的窗口的窗口句柄
UINT Msg, //要发送消息的消息类型
WPARAM wParam, //附加参数
LPARAM lParam //附加参数
);
功能:根据指定窗口句柄将消息发送给指定的窗口。
hWnd:通过FindWindow()函数获取。
Msg:WM_CLOSE 、 WM_SETTEXT 、 WM_GETTEXT
WM_CLOSE:关闭目标窗口或应用程序。该消息没有需要的附加参数,因此wParam和lParam两个阐述都为NULL。
WM_SETTEXT:对窗口的文本进行设置。该消息需要附加参数,wParam未被使用,必须指定为0,lParam参数是一个指向以NULL为结尾的字符串的指针。
WM_GETTEXT:将对应窗口的文本复制到调用者的缓冲区。该消息需要附加参数,wParam参数指定要复制的字符数的数量,lParam是接受文本的缓冲区。
二、Windows窗口应用程序的主函数——WinMain()
参数
int WINAPI WinMain(
HINSTANCE hInstance, //应用程序的实例句柄
HINSTANCE hPrevInstance, //同一文件创建的上一个实例的实例句柄
LPSTR lpCmdLine, //程序启动时给进程传递参数
int nCmdShow //进程显示方式
);
hInstance:应用程序的实例句柄。磁盘上静态的程序文件被加载到内存中时,被分配了CPU、内存等进程所需的资源后,一个静态的程序就被实例化为了一个有各种执行资源的进程了。
hPrevInstance:同一文件创建的上一个实例的实例句柄。这个参数时Win16的遗留物,Win32下已经不再使用。
lpCmdLine:程序启动时给进程传递参数。在双击一个文件时,系统会调用相应的程序来打开文件。如:在“运行”中输入“notepad c:\boot.ini”,这样就通过记事本打开了C盘下的boot.ini文件。C:\boot.ini文件通过WinMain()函数的lpCmdLine参数传递给notepad.exe程序的。
nCmdShow:进程显示方式 。指定窗口如何显bai示。如果发送应用程序的程序提供了STARTUPINFO结构,则应用程序第一次调用ShowWindow时该参数被忽略。否则,在第一次调用ShowWindow函数时,该值应为在函数WinMain中nCmdShow参数。在随后的调用中,该参数可以为下列值之一:
SW_FORCEMINIMIZE:在WindowNT5.0中最小化窗口,即使拥有窗口的线程被挂起也会最小化。在从其他线程最小化窗口时才使用这个参数。
SW_HIDE:隐藏窗口并激活其他窗口。
SW_MAXIMIZE:最大化指定的窗口。
SW_MINIMIZE:最小化指定的窗口并且激活在Z序中的下一个顶层窗口。
SW_RESTORE:激活并显示窗口。如果窗口最小化或最大化,则系统将窗口恢复到原来的尺寸和位置。在恢复最小化窗口时,应用程序应该指定这个标志。
SW_SHOW:在窗口原来的位置以原来的尺寸激活和显示窗口。
SW_SHOWDEFAULT:依据在STARTUPINFO结构中指定的SW_FLAG标志设定显示状态,STARTUPINFO 结构是由启动应用程序的程序传递给CreateProcess函数的。
SW_SHOWMAXIMIZED:激活窗口并将其最大化。
SW_SHOWMINIMIZED:激活窗口并将其最小化。
SW_SHOWMINNOACTIVE:窗口最小化,激活窗口仍然维持激活状态。
SW_SHOWNA:以窗口原来的状态显示窗口。激活窗口仍然维持激活状态。
SW_SHOWNOACTIVATE:以窗口最近一次的大小和状态显示窗口。激活窗口仍然维持激活状态。
SW_SHOWNORMAL:激活并显示一个窗口。如果窗口被最小化或最大化,系统将其恢复到原来的尺寸和大小。应用程序在第一次显示窗口的时候应该指定此标志。
三、WinMain()函数中的流程
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG Msg;
BOOL bRet;
//注册窗口类
MyRegisterClass(hInstance);
//创建窗口并显示窗口
if( !InitInstance(hInstance, SW_SHOWNORMAL) )
{
return FALSE;
}
//消息循环
//获取属于自己的消息并进行分发
while( (bRet = GetMessage(&Msg, NULL, 0, 0)) != 0)
{
if( bRet == -1)
{
break;
}
else
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
return Msg.wParam;
}
其中MyRegisterClass()和InitInstance()是两个自定义的函数,分别用来注册窗口类,创建窗口并显示创建的窗口。后面的消息循环部分用来获得消息并进行消息分发。
代码中主要的API函数:GetMessage()、TranslateMessage()和DispatchMessage()。
BOOL GetMessage(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax
);
GetMessage():用来获取属于自己的消息,并填充MSG结构体。PeekMessage()类似,它可以判断消息队列中是否有消息,如果没有消息,可以主动让出CPU时间给其他进程。
BOOL TranslateMessage(CONST MSG *lpMsg) ;
TranslateMessage():处理键盘消息。它将虚拟码消息转换为字符消息,也就是WM_KEYDOWN消息和WM_KEYUP消息转换为WM_CHAR消息,将WM_SYSKEYDOWN消息和WM_SYSKEYUP消息转换为WM_SYSCHAR消息。
LRESULT DispatchMessage(CONST MSG *lpMsg);
DispatchMessage():将消息分发到窗口过程中。
3.1 MyRegisterClass() —— 注册窗口类的自定义函数
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX WndCls;
ZeroMemory(&WndCls, sizeof(WNDCLASSEX)); //填充结构体为0
WndCls.cbSize = sizeof(WNDCLASSEX); //结构体大小
WndCls.style = CS_HREDRAW | CS_VREDRAW; //窗口风格
WndCls.lpfnWndProc = WindowProc; //窗口过程地址
WndCls.hInstance = hInstance; //实例句柄
WndCls.hIcon = LoadIcon(NULL, IDI_QUESTION);//图标句柄
WndCls.hCursor = LoadCursor(NULL, IDC_ARROW); //鼠标句柄
WndCls.hbrBackground = (HBRUSH)COLOR_WINDOWFRAME + 1;//窗口类背景色(此处是黑色)
WndCls.lpszClassName = "hello"; //窗口类类名
//其他
WndCls.cbClsExtra = 0;
WndCls.cbWndExtra = 0;
return RegisterClassEx(&WndCls);
}
其中最重要的字段是lpfnWNdProc,它保存的是窗口过程的地址:窗口过程是对各种消息进行处理的“汇集地”,也是编写Windows应用程序的重点部分。
3.2 创建主窗口并显示更新
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{//hInstance、nCmdShow通过WinMain()的参数指定
HWND hWnd = NULL;
//创建窗口
hWnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
"hello",
"MyFirstWindow",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
if( NULL == hWnd )
{
return FALSE;
}
//显示窗口
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//CreateWindowExA()函数原型:
/*
HWND CreateWindowExA(
DWORD dwExStyle,
LPCSTR lpClassName,//已经注册的类名,即WNDCLASSEX结构体的lpszClassName字段
LPCSTR lpWindowName,
DWORD dwStyle,
int X,
int Y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);
*/
至此,WinMain()主函数的部分已经都实现完成了。接下来是程序中的关键部分——窗口过程。
3.3 处理消息的窗口过程
WinMain()主函数中没有任何地方直接调用窗口过程,只是在注册窗口类时制定了窗口过程的地址:
WndCls.lpfnWndProc = WindowProc;
窗口类由谁调用?——操作系统。
窗口过程的代码如下:
LRESULT CALLBACK WindowProc(
HWND hwnd, //句柄
UINT uMsg, //消息值
WPARAM wParam,
LPARAM lParam
)
{
PAINTSTRUCT ps;
HDC hDC;
RECT rt;
char *pszDrawText = "Hello Windows Program.";
switch(uMsg)
{
case WM_PAINT:
{
hDC = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rt);
DrawTextA(
hDC,
pszDrawText,
strlen(pszDrawText),
&rt,
DT_CENTER | DT_VCENTER | DT_SINGLELINE
);
EndPaint(hwnd, &ps);
break;
}
case WM_CLOSE:
{
if( IDYES == MessageBox(hwnd,"是否退出程序","MyFirstWin",MB_YESNO))
{
DestroyWindow(hwnd);
PostQuitMessage(0);
}
break;
}
default:
{
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
}
WindowProc是窗口过程的函数名,可以随意改变,但是窗口过程的函数名必须与WNDCLASSEX结构体中的lpfnWndProc的成员变量的值一致:WndCls.lpfnWndProc = WindowProc;
这里的窗口过程只演示两个简单的对消息的处理:WM_PAINT、WM_CLOSE。
DefWindowProc()将其余的消息传递给了操作系统,由操作系统来处理程序中没有处理的消息。
至此,一个最简单的Windows窗口已经建立完成,上述代码中,API函数(包括:FindWindows()、SendMessage()、GetMessage()、TranslateMessage()、DispatchMessage())无需自己定义。
运行效果如下:
代码汇总如下:
#include<iostream>
#include<windows.h>
using namespace std;
//HWND FindWindow(
// LPCTSTR lpClassName,
// LPCTSTR lpWindowName
//);
//LRESULT SendMessage( //定义
// HWND hWnd, //要接收消息的窗口的窗口句柄,通过FindWindow()获取
// UINT Msg, //要发送消息的消息类型
// WPARAM wParam, //附加参数
// LPARAM lParam //附加参数
//);
//BOOL GetMessage(
// LPMSG lpMsg,
// HWND hWnd,
// UINT wMsgFilterMin,
// UINT wMsgFilterMax
//);
//BOOL TranslateMessage(CONST MSG *lpMsg) ;
//LRESULT DispatchMessage(CONST MSG *lpMsg);
LRESULT CALLBACK WindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);//窗口过程
ATOM MyRegisterClass(HINSTANCE hInstance);//注册窗口类
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow);//创建主窗口
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{//主流程
MSG Msg;
BOOL bRet;
//注册窗口类
MyRegisterClass(hInstance);
//创建窗口并显示窗口
if(!InitInstance(hInstance, SW_SHOWNORMAL))
{
return FALSE;
}
//消息循环
//获取属于自己的消息并进行分发
while( (bRet = GetMessage(&Msg, NULL, 0, 0)) != 0)
{
if( bRet == -1)
{
break;
}
else
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
return Msg.wParam;
}
LRESULT CALLBACK WindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
PAINTSTRUCT ps;
HDC hDC;
RECT rt;
char *pszDrawText = (char*)"Hello Windows Program.";
switch(uMsg)
{
case WM_PAINT:
{
hDC = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rt);
DrawTextA(
hDC,
pszDrawText,
strlen(pszDrawText),
&rt,
DT_CENTER | DT_VCENTER | DT_SINGLELINE
);
EndPaint(hwnd, &ps);
break;
}
case WM_CLOSE:
{
if( IDYES == MessageBox(hwnd,"是否退出程序","MyFirstWin",MB_YESNO))
{
DestroyWindow(hwnd);
PostQuitMessage(0);
}
break;
}
default:
{
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX WndCls;
ZeroMemory(&WndCls, sizeof(WNDCLASSEX)); //填充结构体为0
WndCls.cbSize = sizeof(WNDCLASSEX); //结构体大小
WndCls.style = CS_HREDRAW | CS_VREDRAW; //窗口风格
WndCls.lpfnWndProc = WindowProc; //窗口过程地址
WndCls.hInstance = hInstance; //实例句柄
WndCls.hIcon = LoadIcon(NULL, IDI_QUESTION);//图标句柄
WndCls.hCursor = LoadCursor(NULL, IDC_ARROW); //鼠标句柄
WndCls.hbrBackground = (HBRUSH)COLOR_WINDOWFRAME + 1;//窗口类背景色
WndCls.lpszClassName = "hello"; //窗口类类名
//其他
WndCls.cbClsExtra = 0;
WndCls.cbWndExtra = 0;
return RegisterClassEx(&WndCls);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd = NULL;
//创建窗口
hWnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
"hello",
"MyFirstWindow",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
if( NULL == hWnd)
{
return FALSE;
}
//显示窗口
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}