C ++ Снимок экрана при щелчке мыши не работает - PullRequest
0 голосов
/ 25 сентября 2018

Я использую Visual Studio 2017, я написал код, который должен создать папку, сделать снимок экрана при нажатии кнопки мыши и сохранить снимок экрана в файл .bmp.Но я не знаю, почему этот скрипт не работает.Visual Studio скомпилирует его без ошибок / предупреждений.

Вот код:

    // variable to store the HANDLE to the hook. Don't declare it anywhere else then globally
    // or you will get problems since every function uses this variable.
    HHOOK _hook;

    // This struct contains the data received by the hook callback. As you see in the callback function
    // it contains the thing you will need: vkCode = virtual key code.
    KBDLLHOOKSTRUCT kbdStruct;

    int filenum = 1;
    // This is the callback function. Consider it the event that is raised when, in this case, 
    // a key is pressed.
void TakeScreenShot(const char* filename)
{
    //keybd_event(VK_SNAPSHOT, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
    //keybd_event(VK_SNAPSHOT, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
    HBITMAP h;

    POINT a, b;
    a.x = 0;
    a.y = 0;

    b.x = GetSystemMetrics(SM_CXSCREEN);
    b.y = GetSystemMetrics(SM_CYSCREEN);

    HDC     hScreen = GetDC(NULL);
    HDC     hDC = CreateCompatibleDC(hScreen);
    HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, abs(b.x - a.x), abs(b.y - a.y));
    HGDIOBJ old_obj = SelectObject(hDC, hBitmap);
    BOOL    bRet = BitBlt(hDC, 0, 0, abs(b.x - a.x), abs(b.y - a.y), hScreen, a.x, a.y, SRCCOPY);


    // save bitmap to clipboard
    OpenClipboard(NULL);
    EmptyClipboard();
    SetClipboardData(CF_BITMAP, hBitmap);
    CloseClipboard();

    // clean up
    SelectObject(hDC, old_obj);
    DeleteDC(hDC);
    ReleaseDC(NULL, hScreen);
    DeleteObject(hBitmap);

    OpenClipboard(NULL);
    h = (HBITMAP)GetClipboardData(CF_BITMAP);
    CloseClipboard();
    HDC hdc = NULL;
    FILE*fp = NULL;
    LPVOID pBuf = NULL;
    BITMAPINFO bmpInfo;
    BITMAPFILEHEADER bmpFileHeader;
    do
    {
        hdc = GetDC(NULL);
        ZeroMemory(&bmpInfo, sizeof(BITMAPINFO));
        bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        GetDIBits(hdc, h, 0, 0, NULL, &bmpInfo, DIB_RGB_COLORS);
        if (bmpInfo.bmiHeader.biSizeImage <= 0)
            bmpInfo.bmiHeader.biSizeImage = bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount + 7) / 8;
        if ((pBuf = malloc(bmpInfo.bmiHeader.biSizeImage)) == NULL)
        {
            MessageBox(NULL, TEXT("Unable to Allocate Bitmap Memory"), TEXT("Error"), MB_OK | MB_ICONERROR);
            break;
        }
        bmpInfo.bmiHeader.biCompression = BI_RGB;
        GetDIBits(hdc, h, 0, bmpInfo.bmiHeader.biHeight, pBuf, &bmpInfo, DIB_RGB_COLORS);
        if ((fp = fopen(filename, "wb")) == NULL)
        {
            MessageBox(NULL, TEXT("Unable to Create Bitmap File"), TEXT("Error"), MB_OK | MB_ICONERROR);
            break;
        }
        bmpFileHeader.bfReserved1 = 0;
        bmpFileHeader.bfReserved2 = 0;
        bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + bmpInfo.bmiHeader.biSizeImage;
        bmpFileHeader.bfType = 'MB';
        bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
        fwrite(&bmpFileHeader, sizeof(BITMAPFILEHEADER), 1, fp);
        fwrite(&bmpInfo.bmiHeader, sizeof(BITMAPINFOHEADER), 1, fp);
        fwrite(pBuf, bmpInfo.bmiHeader.biSizeImage, 1, fp);
    }

    while (false);
    if (hdc)ReleaseDC(NULL, hdc);
    if (pBuf) free(pBuf);
    if (fp)fclose(fp);
}

LRESULT __stdcall HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode >= 0)
    {
        // the action is valid: HC_ACTION.
        if (wParam == WM_LBUTTONDOWN)
        {
            std::string OutputFolder = "C:\\temp";
            std::string filename = "ss";
            if (CreateDirectory(OutputFolder.c_str(), NULL) ||
                ERROR_ALREADY_EXISTS == GetLastError())
            {

            }
            else
            {
                // Failed to create directory.
            }
            auto numfile = std::to_string(filenum);
            TakeScreenShot((OutputFolder + "\\" + filename + std::to_string(filenum) + ".bmp").c_str());
            filenum++;
        }
    }

    // call the next hook in the hook chain. This is nessecary or your hook chain will break and the hook stops
    return CallNextHookEx(_hook, nCode, wParam, lParam);
}



void ReleaseHook()
{
    UnhookWindowsHookEx(_hook);
}


int main()
{
    // Don't mind this, it is a meaningless loop to keep a console application running.
    // I used this to test the keyboard hook functionality. If you want to test it, keep it in ;)
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {

    }
}

Если щелкнуть по нему, каталог не создастся (если он не существует) и не создаст.bmp файл.

1 Ответ

0 голосов
/ 27 сентября 2018

Как уже говорили другие, вы никогда не устанавливаете свой крюк!Кроме того, из моих тестов видно, что вам нужно отправлять сообщения в какое-то окно, чтобы вызывался хук WH_MOUSE.

Вот минимальная версия main (), которая работает для меня:

int main()
{
    _hook = SetWindowsHookEx (WH_MOUSE, HookCallback, NULL, GetCurrentThreadId ());
    if (_hook == NULL)
        ...
    MessageBox (NULL, "Click OK to quit", "Screen Grabber", MB_OK);
    UnhookWindowsHookEx (_hook);
}

Тогда остальная часть вашего кода работает нормально, хотя и немного грязно, как говорили другие.

Однако , это будет ловить только щелчки мыши в пределахсамо окно сообщения, и я не думаю, что это то, что вам нужно.

Если вы хотите поймать их глобально, вам нужно будет установить «низкоуровневый» крючок мыши.Это должен быть глобальный хук, но в остальном код выглядит примерно так же.Код для установки и запуска ловушки:

int main()
{
    _hook = SetWindowsHookEx (WH_MOUSE_LL, HookCallback, NULL, 0);
    MSG msg;
    while (GetMessage (&msg, NULL, 0, 0))
        DispatchMessage (&msg);
    UnhookWindowsHookEx(_hook);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...