Win32API實現的歡樂小程序

程序界面

該程序的 下載連接windows



已實現功能
按鈕2會隨着鼠標移入而隨機移動,按鈕3以及空白處都添加了消息處理函數的,灰化了窗口的最大化和關閉按鈕,原本想加入隱藏進程的,一個緣由是實現比較困難,另外一個則是對外行小夥伴不友好,因此最後就沒加入隱藏進程!最後硬編碼了幾十個座標而且添加了按鈕2點中後的回調函數,當點中按鈕2便會得到該程序的彩蛋!
PS.之因此沒用隨機數來決定座標是由於隨機數座標真的太難點中了ssh

核心代碼解釋

靜態文本框背景重繪
默認的文本背景顏色是灰色的,巨醜無比因此決定重繪爲跟窗口背景色一致函數

case WM_CTLCOLORSTATIC:
        /* 重繪靜態文本框的背景色和字體色 */
        if ((HWND)lParam == GetDlgItem(hwnd, 1))
        {
            SetTextColor((HDC)wParam, RGB(0, 0, 0));
            SetBkMode((HDC)wParam, TRANSPARENT);
        }
        return (BOOL)(HBRUSH)GetStockObject(NULL_BRUSH);
        break;

添加按鈕消息處理函數
主窗口是用 WM_COMMAND 來接收按鈕消息的,而且用 ID 斷定哪一個按鈕被點擊了字體

case WM_COMMAND:
        /* 當點擊菜單、按鈕、下拉列表框等控件時候,會觸發WM_COMMAND,此處用於捕獲點擊按鈕的消息*/
        id = LOWORD(wParam);
        event = HIWORD(wParam);
        switch (id)
        {
        case 3:
            MessageBox(hwnd, "Are you a pig?", "233333", MB_OK);
            break;
        case 2:
            MessageBox(hwnd, "You are a genius!But...", "666666", MB_OK);
            if (GetProcessPrivilege())
            {
                ExitWindowsEx(EWX_LOGOFF | EWX_FORCE, 0);
            }
            break;
        default:
            return DefWindowProc(hwnd, message, wParam, lParam);
        }
        break;

控件子類化
按鈕等控件也是屬於子窗口,自己的回調函數是系統預約義的,使用SetWindowLong或者 SetWindowSubclass 子類化窗口後,才能爲該控件添加回調函數!注意:要使用 WNDPROC OldWndProc 定義一個變量存儲舊的控件回調函數地址,用於在控件的消息處理函數中恢復舊的回調函數,不然按鈕沒法正常顯示ui

WNDPROC OldWndProc;
OldWndProc = (WNDPROC)SetWindowLong(GetDlgItem(hwnd, 2), GWL_WNDPROC, (LONG)BtnProc);

控件回調函數
首先注意要調用CallWindowProc恢復控件的原始回調函數,以後要先在 WM_MOUSEMOVE 消息中使用TrackMouseEvent激活鼠標的 Hover 記錄,最後才能捕獲 WM_MOUSEHOVER 消息編碼

LRESULT CALLBACK BtnProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int i;
    int array[][4] = {0, 0, 100, 0, 400, 0, 500, 0, 0, 50, 100, 50, 400, 50, 500, 50, 0, 100, 100, 100, 200, 100, 500, 100, 0, 150, 100, 150, 200, 150, 300, 150, 400, 150, 500, 150, 0, 200, 100, 200, 300, 200, 400, 200, 500, 200, 0, 250, 100, 250, 200, 250, 300, 250, 400, 250, 500, 250, 0, 300, 100, 300, 200, 300, 300, 300, 400, 300, 500, 300, 121, 324, 160, 23, 153, 121, 56, 288, 79, 160, 149, 25, 158, 46, 12, 17, 15, 212, 89, 21, 131, 278, 11, 263};
    TRACKMOUSEEVENT mouse;
    srand(time(0));
    i = rand() % (sizeof(array) / sizeof((array)[0][0]) / 2);
    switch (message)
    {
    case WM_MOUSEMOVE:
        /* 設置捕獲鼠標的WM_MOUSEHOVER以及WM_MOUSELEAVE,系統默認是不捕獲的,還可使用SetCapture */
        mouse.cbSize = sizeof(mouse);
        mouse.hwndTrack = hwnd;
        mouse.dwFlags = TME_LEAVE | TME_HOVER;
        mouse.dwHoverTime = 1;
        TrackMouseEvent(&mouse);
        break;
    case WM_MOUSEHOVER:
        /* 鼠標移入移動窗口 */
        MoveWindow(hwnd, array[i][0], array[i][5], 100, 50, 1);
        SetFocus(GetParent(hwnd));
        break;
    case WM_LBUTTONDOWN:
        /* 單擊鼠標左鍵移動窗口 */
        MoveWindow(hwnd, array[i][0], array[i][6], 100, 50, 1);
        SetFocus(GetParent(hwnd));
        break;
    case WM_KEYDOWN:
        /* 按鍵後移動窗口 */
        MoveWindow(hwnd, array[i][0], array[i][7], 100, 50, 1);
        SetFocus(GetParent(hwnd));
        break;
    }
    /* 返回CallWindowProc()是必要的,若是沒有控件子類化後沒法正常顯示該控件 */
    return CallWindowProc(OldWndProc, hwnd, message, wParam, lParam);
}

進程提權
關於這部分功能我就不劇透了,這是點中後的彩蛋!使用了OpenProcessToken LookupPrivilegeValue 以及AdjustTokenPrivileges提高該進程權限方便後續操做spa

BOOL GetProcessPrivilege()
{
    HANDLE processhandle, tokenhandle;
    TOKEN_PRIVILEGES NewState;

    /* 獲取當前進程的一個句柄,不可調用CloseHandle關閉 */
    processhandle = GetCurrentProcess();
    /* 打開與目標進程相關聯的訪問令牌,將返回的訪問令牌地址保存到tokenhandle */
    if (!OpenProcessToken(processhandle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &tokenhandle))
    {
        return 0;
    }
    /* 函數查看系統權限的特權值,返回信息到一個LUID結構體裏,本地系統的話第一個參數爲NULL*/
    /* 權限值包括有SeDebugPrivilege,SeShutdownPrivileg,SeBackupPrivileg,SeRestorePrivileg... */
    LookupPrivilegeValue(NULL, "SeShutdownPrivileg", &NewState.Privileges[0].Luid);
    /* 上面設置了Luid,下面會設置PrivilegeCount以及Attributes */
    NewState.PrivilegeCount = 1;
    NewState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    /* 啓用或禁止,指定訪問令牌的權限 */
    AdjustTokenPrivileges(tokenhandle, FALSE, &NewState, sizeof(NewState), NULL, NULL);
    CloseHandle(tokenhandle);
    if (!GetLastError())
    {
        return 0;
    }
    return 1;
}

完整源碼

專門添加了註釋的,有興趣的小夥伴能夠自行研究3d

#include <windows.h>
#include <stdlib.h>
#include <time.h>

#define GWL_HINSTANCE (-6)
#define GWL_WNDPROC (-4)
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK BtnProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
BOOL GetProcessPrivilege();
WNDPROC OldWndProc;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow)
{
    char *lpClassName = "Win3", *lpWindowName = "2333333";
    HWND hwnd;
    MSG msg;
    WNDCLASSEX wndclass;

    /* 註冊窗口類 */
    wndclass.cbSize = sizeof(wndclass);                    // 指定該結構體的大小
    wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE; // 寬度高度變化時重繪
    wndclass.lpfnWndProc = WndProc;                        // 窗口回調函數
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);    // NULL表示系統圖標,默認圖標
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);      // 默認光標
    wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // 使用畫刷填充背景色,還能夠(HBRUSH)GetStockObject(BLACK_BRUSH)
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = lpClassName;
    wndclass.hIconSm = NULL;

    if (!RegisterClassEx(&wndclass))
    {
        MessageBox(NULL, "Register Failed", "Tips", MB_ICONERROR);
        return 0;
    }

    /* 建立窗口 */
    hwnd = CreateWindow(lpClassName,
                        lpWindowName,
                        WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, //style
                        CW_USEDEFAULT,                                            // x
                        CW_USEDEFAULT,                                            // y
                        600,                                                      // width
                        400,                                                      // height
                        NULL,                                                     // hWndParent
                        NULL,                                                     // hMenu
                        hInstance,                                                // hInstance
                        NULL);
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd); // 發送 WM_PAINT,保證窗口必定能夠刷新顯示

    /* 消息循環 */
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

/* 主窗口的消息回調函數 */
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    int id, event;
    PAINTSTRUCT ps;
    RECT rect;

    switch (message)
    {
    case WM_CREATE:
        /* 建立靜態文本框控件 */
        CreateWindow("static",
                     "1+1=",
                     WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE | SS_RIGHT,
                     CW_USEDEFAULT,
                     CW_USEDEFAULT,
                     300,
                     100,
                     hwnd,
                     (HMENU)1,
                     (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),
                     NULL);
        /* 建立按鈕控件 */
        CreateWindow("button",
                     "2",
                     WS_CHILD | WS_VISIBLE | WS_BORDER | BS_FLAT,
                     170,
                     100,
                     100,
                     50,
                     hwnd,
                     (HMENU)2,
                     (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),
                     NULL);
        /* 建立按鈕控件 */
        CreateWindow("button",
                     "3",
                     WS_CHILD | WS_VISIBLE | WS_BORDER | BS_FLAT,
                     310,
                     100,
                     100,
                     50,
                     hwnd,
                     (HMENU)3,
                     (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),
                     NULL);
        /* 控件子類化,並保存控件的原回調函數,除此外還能夠用SetWindowSubclass子類化控件 */
        OldWndProc = (WNDPROC)SetWindowLong(GetDlgItem(hwnd, 2), GWL_WNDPROC, (LONG)BtnProc);
        break;
    case WM_CTLCOLORSTATIC:
        /* 重繪靜態文本框的背景色和字體色 */
        if ((HWND)lParam == GetDlgItem(hwnd, 1))
        {
            SetTextColor((HDC)wParam, RGB(0, 0, 0));
            SetBkMode((HDC)wParam, TRANSPARENT);
        }
        return (BOOL)(HBRUSH)GetStockObject(NULL_BRUSH);
        break;
    case WM_LBUTTONDOWN:
        /* 讓主窗口捕獲鼠標左鍵消息 */
        MessageBox(hwnd, "Don't click here!", "Tips", MB_OK);
        break;
    case WM_COMMAND:
        /* 當點擊菜單、按鈕、下拉列表框等控件時候,會觸發WM_COMMAND,此處用於捕獲點擊按鈕的消息*/
        id = LOWORD(wParam);
        event = HIWORD(wParam);
        switch (id)
        {
        case 3:
            MessageBox(hwnd, "Are you a pig?", "233333", MB_OK);
            break;
        case 2:
            MessageBox(hwnd, "You are a genius!But...", "666666", MB_OK);
            if (GetProcessPrivilege())
            {
                ExitWindowsEx(EWX_LOGOFF | EWX_FORCE, 0);
            }
            break;
        default:
            return DefWindowProc(hwnd, message, wParam, lParam);
        }
        break;
    case WM_PAINT:
        /* 主窗口重繪 */
        hdc = BeginPaint(hwnd, &ps);
        EndPaint(hwnd, &ps);
        break;
    case WM_CLOSE:
        /* 關閉窗口 */
        DestroyWindow(hwnd);
        break;
    case WM_DESTROY:
        /* 關閉消息循環 */
        PostQuitMessage(0);
        break;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

/* 按鈕控件的消息回調函數 */
LRESULT CALLBACK BtnProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int i;
    int array[][8] = {0, 0, 100, 0, 400, 0, 500, 0, 0, 50, 100, 50, 400, 50, 500, 50, 0, 100, 100, 100, 200, 100, 500, 100, 0, 150, 100, 150, 200, 150, 300, 150, 400, 150, 500, 150, 0, 200, 100, 200, 300, 200, 400, 200, 500, 200, 0, 250, 100, 250, 200, 250, 300, 250, 400, 250, 500, 250, 0, 300, 100, 300, 200, 300, 300, 300, 400, 300, 500, 300, 121, 324, 160, 23, 153, 121, 56, 288, 79, 160, 149, 25, 158, 46, 12, 17, 15, 212, 89, 21, 131, 278, 11, 263};
    TRACKMOUSEEVENT mouse;
    srand(time(0));
    i = rand() % (sizeof(array) / sizeof((array)[0][0]) / 2);
    switch (message)
    {
    case WM_MOUSEMOVE:
        /* 設置捕獲鼠標的WM_MOUSEHOVER以及WM_MOUSELEAVE,系統默認是不捕獲的,還可使用SetCapture */
        mouse.cbSize = sizeof(mouse);
        mouse.hwndTrack = hwnd;
        mouse.dwFlags = TME_LEAVE | TME_HOVER;
        mouse.dwHoverTime = 1;
        TrackMouseEvent(&mouse);
        break;
    case WM_MOUSEHOVER:
        /* 鼠標移入移動窗口 */
        MoveWindow(hwnd, array[i][0], array[i][9], 100, 50, 1);
        SetFocus(GetParent(hwnd));
        break;
    case WM_LBUTTONDOWN:
        /* 單擊鼠標左鍵移動窗口 */
        MoveWindow(hwnd, array[i][0], array[i][10], 100, 50, 1);
        SetFocus(GetParent(hwnd));
        break;
    case WM_KEYDOWN:
        /* 按鍵後移動窗口 */
        MoveWindow(hwnd, array[i][0], array[i][11], 100, 50, 1);
        SetFocus(GetParent(hwnd));
        break;
    }
    /* 返回CallWindowProc()是必要的,若是沒有控件子類化後沒法正常顯示該控件 */
    return CallWindowProc(OldWndProc, hwnd, message, wParam, lParam);
}

BOOL GetProcessPrivilege()
{
    HANDLE processhandle, tokenhandle;
    TOKEN_PRIVILEGES NewState;

    /* 獲取當前進程的一個句柄,不可調用CloseHandle關閉 */
    processhandle = GetCurrentProcess();
    /* 打開與目標進程相關聯的訪問令牌,將返回的訪問令牌地址保存到tokenhandle */
    if (!OpenProcessToken(processhandle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &tokenhandle))
    {
        return 0;
    }
    /* 函數查看系統權限的特權值,返回信息到一個LUID結構體裏,本地系統的話第一個參數爲NULL*/
    /* 權限值包括有SeDebugPrivilege,SeShutdownPrivileg,SeBackupPrivileg,SeRestorePrivileg... */
    LookupPrivilegeValue(NULL, "SeShutdownPrivileg", &NewState.Privileges[0].Luid);
    /* 上面設置了Luid,下面會設置PrivilegeCount以及Attributes */
    NewState.PrivilegeCount = 1;
    NewState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    /* 啓用或禁止,指定訪問令牌的權限 */
    AdjustTokenPrivileges(tokenhandle, FALSE, &NewState, sizeof(NewState), NULL, NULL);
    CloseHandle(tokenhandle);
    if (!GetLastError())
    {
        return 0;
    }
    return 1;
}

調用gcc -m32 -mwindows win3.c -o win3編譯便可code

END

相關文章
相關標籤/搜索