- 分享
Re:从零开始的WinAPI学习
- 2024-2-27 23:37:31 @
先占个位,文章正在写
关于WinAPI
WinAPI 程序开发属于基础层面的软件开发, 抽象程度较高, 建议掌握了类的使用和一定Windows系统底层原理后再阅读本文.
本文中提到的所有关于WinAPI的内容均包含于头文件 <Windows.h>.
严格意义上讲, WinAPI属于C语言的范畴, c++拥有更高级,更简便的窗口函数库<afxwin.h>(MFC).
文中使用的IDE是Visual Studio 2022 , 使用 cl.exe 作为编译器, 可能会 包含部分c++17和c++20的特性 , 你也可以使用最新的gcc.exe作为编译器.
如果有任何关于文章内容的问题,可以在 评论区提出或到Microsoft Learn 官网查看详细介绍 .
使用WinAPI编写控制台程序
使用WinAPI编写的控制台程序通过系统默认控制台运行, 并以main()作为主函数入口, 返回值类型为int. 使用WinAPI编写的控制台程序与普通的使用c++标准库编写的控制台程序外观上区别不大. 但可以在普通控制台程序的基础上做到窗口刷新,播放音频,设置消息循环等高级操作.
例程
#include <Windows.h>
int nfieldwidth = 12;
int nfieldheight = 18;
int nScreenWidth = 80;
int nScreenHeight = 30;
unsigned char* pField = nullptr;
bool Quit = 0;
int main(int argc, char** argv){
pField = new unsigned char[nfieldwidth * nfieldheight];
for (int x = 0; x < nfieldwidth; x++)
for (int y = 0; y < nfieldheight; y++)
pField[y * nfieldwidth + x]
= (x == 0 ||
x == nfieldwidth - 1 ||
y == nfieldheight - 1)
? 9 : 0;
wchar_t* screen = new wchar_t[nScreenWidth * nScreenHeight];
for (int i = 0; i < nScreenWidth * nScreenHeight; i++)
screen[i] = L' ';
HANDLE hConsole = CreateConsoleScreenBuffer (
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
SetConsoleActiveScreenBuffer(hConsole);
DWORD dwBytesWritten = 0;
MSG Message;
while (!Quit)
{
Switch (GetMessage(&Message, NULL, 0, 0)){
default :
break;
}
}
WriteConsoleOutputCharacter(
hConsole,
screen,
nScreenWidth * nScreenHeight,
{ 0,0 },
&dwBytesWritten
);
return 0;
}
这个程序将生成一个12*18宽字符宽度的控制台窗口,并用宽字符空格(L" ")填充.
编译控制台应用程序时需要在编译器选项里将编译系统改为"控制台", 否则将提示"无法找到程序入口"等报错. 一般情况下, 大多数编译器的默认编译系统就是"控制台". 如果需要调整, 具体的方法因不同编译器而不同, 自行搜索.
注意: 该源文件编译完成后的名字应为"${fileBasenameNoExtension}.exe"
解释
主函数人口是int main(int argc, char** argv), 主函数名称是"main", 所以系统将以控制台的方式运行这个程序.
使用WinAPI编写窗口程序
Windows窗口程序基于WNDCLASS构建, 并以WinMAIN()作为主函数入口, 返回值类型为int.
例程
#include <windows.h>
LRESULT CALLBACK DealMessage(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
WNDCLASS wc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)GetStockObject(HOLLOW_BRUSH);
wc.hCursor = NULL;
wc.hIcon = NULL;
wc.hInstance = hInstance;
wc.lpfnWndProc = DealMessage;
wc.lpszClassName = TEXT("WindowClass");
wc.lpszMenuName = NULL;
wc.style = nCmdShow;
if (!RegisterClass(&wc))
{
MessageBox(
NULL,
TEXT("This program requires Windows NT!"),
TEXT("Windowlass"),
MB_ICONERROR
);
return 0;
}
HWND hWnd = CreateWindow(
TEXT("WindowClass"),
TEXT("Hello Windows!"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG Message;
while (GetMessage(&Message, NULL, 0, 0))
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return Message.wParam;
}
该程序将生成一个名叫"Hello Windows!"的默认大小的Windows默认窗口, 并使用默认应用程序图标和默认运行图标.
编译Win32项目时需要在编译器选项里将编译系统改为"窗口", 否则将提示"无法找到main()"或"无法找到程序入口"等报错. 具体的方法因不同编译器而不同, 自行搜索.
注意: 该源文件编译完成后的名字应为"${fileBasenameNoExtension}.exe"
使用WinAPI编写内核驱动程序
Windows内核驱动程序直接操控Windows基层系统运行, 并以DriverEntry()作为主函数入口, 返回值类型为NTSTATUS.
例程
#include <Windows.h>
#include <Ntddk.h>
DRIVER_INITIALIZE MyDriverEntry;
NTSTATUS DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath
)
{
return STATUS_SUCCESS;
}
这个程序将生成一个后台应用程序,你需要使用工具来将它加载至系统驱动程序中, 随后才会有足够的权限运行.
编译驱动程序时需要在编译器选项里将编译系统改为"驱动程序", 否则将提示"无法找到程序入口"等报错. 具体的方法因不同编译器而不同, 自行搜索.
注意: 该源文件编译完成后的名字应为"${fileBasenameNoExtension}.sys"