先占个位,文章正在写

关于WinAPI

WinAPI 程序开发属于基础层面的软件开发, 抽象程度较高, 建议掌握了类的使用和一定Windows系统底层原理后再阅读本文.

本文中提到的所有关于WinAPI的内容均包含于头文件 <Windows.h>.

严格意义上讲, WinAPI属于C语言的范畴, c++拥有更高级,更简便的窗口函数库<afxwin.h>(MFC).

文中使用的IDEVisual 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"

0 comments

No comments so far...