程式語言 - Wine - C/C++ - Capture Window Screen



main.c

#include <windows.h>
#include <tlhelp32.h>
  
struct FindWindowData {
    DWORD pid;
    HWND hwnd;
};
 
static int CaptureImage(HWND hWnd, const char *pFileName)
{
    RECT rt = { 0 };
    HDC hdcWindow = 0;
    HDC hdcMemDC = NULL;
    HBITMAP hbmScreen = NULL;
    BITMAP bmpScreen = { 0 };
 
    hdcWindow = GetDC(NULL);
    hdcMemDC = CreateCompatibleDC(hdcWindow);
 
    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);
    SelectObject(hdcMemDC, hbmScreen);
 
    BitBlt(hdcMemDC, 0, 0, rt.right - rt.left, rt.bottom - rt.top, hdcWindow, rt.left, rt.top, SRCCOPY);
 
    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(pFileName, 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);
 
    DeleteObject(hbmScreen);
    DeleteObject(hdcMemDC);
    ReleaseDC(NULL, hdcWindow);

    return 0;
}
 
static 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;
}
 
static HWND FindMainWindowFromPid(DWORD pid)
{
    struct FindWindowData data = { 0 };
    data.pid = pid;
    data.hwnd = NULL;
 
    EnumWindows(EnumWindowsProc, (LPARAM)&data);

    return data.hwnd;
}
 
static DWORD FindProcessID(const char *pName)
{
    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, pName) == 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, "main.bmp");
    CaptureImage(NULL, "desktop.bmp");

    return 0;
}

編譯、執行

$ winegcc main.c -o main -lgdi32
$ wine main.exe.so