當(dāng)Windows操作系統(tǒng)啟動(dòng)一個(gè)程序時(shí),它調(diào)用的就是該程序的WinMain函數(shù)( 實(shí)際是由插入到可執(zhí)行文件中的啟動(dòng)代碼調(diào)用的)。 WinMain是Windows程序的入口點(diǎn)函數(shù),與DOS程序的入口點(diǎn)函數(shù)main的作用相同,當(dāng)WinMain 函數(shù)結(jié)束或返回時(shí),Windows應(yīng)用程序結(jié)束。
 什么是Windows API編程
- 應(yīng)用編程接口
 - Application Programming Interface
 
WinMain函數(shù)
當(dāng)Windows操作系統(tǒng)啟動(dòng)一個(gè)程序時(shí),它調(diào)用的就是該程序的WinMain函數(shù)( 實(shí)際是由插入到可執(zhí)行文件中的啟動(dòng)代碼調(diào)用的)。 WinMain是Windows程序的入口點(diǎn)函數(shù),與DOS程序的入口點(diǎn)函數(shù)main的作用相同,當(dāng)WinMain 函數(shù)結(jié)束或返回時(shí),Windows應(yīng)用程序結(jié)束。
int WINAPI WinMain(
    HINSTANCE hInstance,        //應(yīng)用程序?qū)嵗?/span>
    HINSTANCE hPrevInstance,    //上一個(gè)應(yīng)用程序?qū)嵗?/span>
    LPSTR lpCmdLine,            //命令行參數(shù)
    int nShowCmd                //窗口顯示的樣式
);
- WINAPI:是一個(gè)宏,它代表的是__stdcall(注意是兩個(gè)下劃線(xiàn)),表示的是參數(shù)傳遞的順序:從右往左入棧,同時(shí)在函數(shù)返回前自動(dòng)清空堆棧。
 - hInstance:表示該程序當(dāng)前運(yùn)行的實(shí)例的句柄,這是一個(gè)數(shù)值。當(dāng)程序在Windows下運(yùn)行時(shí),它唯一標(biāo)識(shí)運(yùn)行中的實(shí)例(注意,只有運(yùn)行中的程序?qū)嵗?才有實(shí)例句柄)。一個(gè)應(yīng)用程序可以運(yùn)行多個(gè)實(shí)例,每運(yùn)行一個(gè)實(shí)例,系統(tǒng)都會(huì)給該實(shí)例分配一個(gè)句柄值,并通過(guò)hInstance參數(shù)傳遞給 WinMain 函數(shù)。
 - hPrevInstance:表示當(dāng)前實(shí)例的前一個(gè)實(shí)例的句柄。在Win32環(huán)境下,這個(gè)參數(shù)總是NULL,即在Win32環(huán)境下,這個(gè)參數(shù)不再起作用。
 - lpCmdLine:是一個(gè)以空終止的字符串, 指定傳遞給應(yīng)用程序的命令行參數(shù),相當(dāng)于C或C++中的main函數(shù)中的參數(shù)char *argv[]。
 - nShowCmd:表示一個(gè)窗口的顯示,表示它是要最大化顯示、最小化顯示、正常大小顯示還是隱藏顯示。
 
#include <Windows.h>
#include <cstdio>
#pragma comment(linker, "/subsystem:\"console\" /entry:\"WinMainCRTStartup\"")
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow) {
    printf("%p %p %p\n", hInstance, hPrevInstance, GetModuleHandleA(NULL));
    printf("%d %d\n", nCmdShow, SW_SHOWNORMAL);
    printf("%s\n", lpCmdLine);
    MessageBoxA(NULL, TEXT("第一個(gè) Windows API 程序"), TEXT("黑貓編程"), MB_OK);
    return 0;
}
字符集
#include <Windows.h>
#include <cstdio>
#include <cstring>
#include <clocale>
int main() {
    const char* str1 = "Abc中國(guó)";
    printf("%s  %d\n", str1, strlen(str1));
    _wsetlocale(LC_ALL, L"chs");
    const wchar_t* str2 = L"ABC中國(guó)文字";
    wprintf(L"%s  %d\n", str2, wcslen(str2));
    MessageBoxW(NULL, TEXT("hello cat."), L"coding", MB_OK);
    return 0;
}
Windows 編程模型
一個(gè)完整的Win32程序(#include <windows.h>),該程序?qū)崿F(xiàn)的功能是創(chuàng)建一個(gè)窗口,并在該窗口中響應(yīng)鍵盤(pán)及鼠標(biāo)消息,程序的實(shí)現(xiàn)步驟為:
- WinMain函數(shù)的定義
 - 創(chuàng)建一個(gè)窗口
 - 進(jìn)行消息循環(huán)
 - 編寫(xiě)窗口過(guò)程函數(shù)
 

項(xiàng)目創(chuàng)建


窗口程序模板代碼
#include <Windows.h>
// 自定義窗口過(guò)程回調(diào)函數(shù)
LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
    switch (Msg) {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProcA(hwnd, Msg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
    // 注冊(cè)窗口類(lèi)
    WNDCLASS wnd;
    wnd.cbClsExtra = 0;
    wnd.cbWndExtra = 0;
    wnd.hbrBackground = (HBRUSH)(GetStockObject(WHITE_BRUSH));
    wnd.hCursor = LoadIcon(NULL, IDC_ARROW);
    wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wnd.lpfnWndProc = MyWindowProc;
    wnd.lpszClassName = TEXT("blackcat");
    wnd.lpszMenuName = NULL;
    wnd.style = CS_HREDRAW;
    wnd.hInstance = hInstance;
    RegisterClassA(&wnd);
    // 創(chuàng)建窗口 返回之前發(fā)送 VW_CREATE
    HWND hwnd = CreateWindowA(
        TEXT("blackcat"),
        TEXT("黑貓編程"),
        WS_OVERLAPPEDWINDOW,
        100, 100, 300, 300, NULL, NULL, hInstance, NULL
    );
    // 顯示窗口
    ShowWindow(hwnd, nShowCmd);
    // 更新窗口
    UpdateWindow(hwnd);
    // 消息循環(huán) 收到 VM_QUIT 退出
    MSG msg;
    while (GetMessageA(&msg, hwnd, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessageA(&msg);
    }
    return 0;
}
線(xiàn)程和窗口
在WIN32中,消息隊(duì)列是與線(xiàn)程(Thread)相關(guān)的,一個(gè)線(xiàn)程只能有一個(gè)消息隊(duì)列(queue)與之相對(duì)應(yīng)。當(dāng)一個(gè)線(xiàn)程里面首次調(diào)用User32.dll或GDI32.dll中的函數(shù)時(shí),系統(tǒng)會(huì)為該線(xiàn)程創(chuàng)建一個(gè)消息隊(duì)列,否則就沒(méi)有消息隊(duì)列。
在一個(gè)線(xiàn)程中可以產(chǎn)生多個(gè)窗口,所以每個(gè)窗口課共用一個(gè)線(xiàn)程消息隊(duì)列,所有產(chǎn)生給某個(gè)窗口的消息,都先由創(chuàng)建這個(gè)窗口的線(xiàn)程處理,窗口在任何線(xiàn)程中都可以創(chuàng)建,但消息循環(huán)必須要和創(chuàng)建窗口在同一線(xiàn)程,否則窗口將無(wú)法從DispatchMessage()獲取任何消息,為了使窗口接受這些消息,線(xiàn)程必須有自己的循環(huán)。

消息分類(lèi)
- 標(biāo)準(zhǔn)消息:所有以WM_開(kāi)頭的消息,除了WM_COMMAND
 - 命令消息:來(lái)自菜單欄、工具欄、按鈕或者快捷鍵的消息。WM_COMMAND
 - 通告消息:由控件產(chǎn)生的消息,例如按鈕單擊、列表項(xiàng)的選擇等,為了向其父窗口通知事件的發(fā)生。
 
SendMessage和PostMessage

PostThreadMessage
