程式語言 - Wine - C/C++ - Screenshot



main.c

#include <windows.h>
#include <tlhelp32.h>
 
int CaptureImage(HWND hWnd)
{
    int ret = 0;
    RECT rt={ 0 };
    HDC hdcWindow = 0;
    HDC hdcMemDC = NULL;
    HBITMAP hbmScreen = NULL;
    BITMAP bmpScreen = { 0 };

    hdcWindow = GetDC(NULL);
    hdcMemDC = CreateCompatibleDC(hdcWindow);
    if (!hdcMemDC) {
        ret = -1;
        goto done;
    }

    rt.right = GetSystemMetrics(SM_CXSCREEN);
    rt.bottom = GetSystemMetrics(SM_CYSCREEN);
    if (hWnd != NULL) {
        GetWindowRect(hWnd, &rt);
    }

    hbmScreen = CreateCompatibleBitmap(hdcWindow, rt.right-rt.left, rt.bottom-rt.top);
    if (!hbmScreen) {
        ret = -2;
        goto done;
    }
    SelectObject(hdcMemDC, hbmScreen);

    if (!BitBlt(hdcMemDC, 0, 0, rt.right - rt.left, rt.bottom - rt.top, hdcWindow, rt.left, rt.top, SRCCOPY)) {
        ret = -3;
        goto done;
    }

    GetObject(hbmScreen, sizeof(BITMAP), &bmpScreen);
    BITMAPFILEHEADER bmfHeader;
    BITMAPINFOHEADER bi;
    bi.biSize = sizeof(BITMAPINFOHEADER);
    bi.biWidth = bmpScreen.bmWidth;
    bi.biHeight = bmpScreen.bmHeight;
    bi.biPlanes = 1;
    bi.biBitCount = 32;
    bi.biCompression = BI_RGB;
    bi.biSizeImage = 0;
    bi.biXPelsPerMeter = 0;
    bi.biYPelsPerMeter = 0;
    bi.biClrUsed = 0;
    bi.biClrImportant = 0;

    DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;
    HANDLE hDIB = GlobalAlloc(GHND, dwBmpSize);
    char *lpbitmap = (char*)GlobalLock(hDIB);
    GetDIBits(hdcWindow, hbmScreen, 0, (UINT)bmpScreen.bmHeight, lpbitmap, (BITMAPINFO*)&bi, DIB_RGB_COLORS);

    HANDLE hFile = CreateFile("main.bmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
    bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
    bmfHeader.bfSize = dwSizeofDIB;
    bmfHeader.bfType = 0x4D42;

    DWORD dwBytesWritten = 0;
    WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
    WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
    WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
    GlobalUnlock(hDIB);
    GlobalFree(hDIB);
    CloseHandle(hFile);

done:
    DeleteObject(hbmScreen);
    DeleteObject(hdcMemDC);
    ReleaseDC(NULL, hdcWindow);
    return ret;
}

struct FindWindowData {
    DWORD pid;
    HWND hwnd;
};

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
    struct FindWindowData* data = (struct FindWindowData *)lParam;

    DWORD windowPid = 0;
    GetWindowThreadProcessId(hwnd, &windowPid);

    if (windowPid == data->pid) {
        data->hwnd = hwnd;
        return FALSE;
    }
    return TRUE;
}

HWND FindMainWindowFromPid(DWORD pid)
{
    struct FindWindowData data = { 0 };
    data.pid = pid;
    data.hwnd = NULL;

    EnumWindows(EnumWindowsProc, (LPARAM)&data);
    return data.hwnd;
}

DWORD FindProcessID(const char *processName)
{
    DWORD processId = 0;
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    if (snapshot == INVALID_HANDLE_VALUE) {
        return 0;
    }

    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(entry);

    if (Process32First(snapshot, &entry)) {
        do {
            if (strcmp(entry.szExeFile, processName) == 0) {
                processId = entry.th32ProcessID;
                break;
            }
        } while (Process32Next(snapshot, &entry));
    }

    CloseHandle(snapshot);
    return processId;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    DWORD pid = FindProcessID("hello.exe");
    HWND hwnd = FindMainWindowFromPid(pid);

    CaptureImage(hwnd);
    ExitProcess(0);
    return 0;
}