C++ C++;鼠标单击屏幕截图不起作用

C++ C++;鼠标单击屏幕截图不起作用,c++,winapi,C++,Winapi,我使用的是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 si

我使用的是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))
    {

    }
}
//用于将句柄存储到挂钩的变量。在全球范围内,不要在其他任何地方声明它
//或者你会遇到问题,因为每个函数都使用这个变量。
HHOOK_hook;
//此结构包含钩子回调接收的数据。正如您在回调函数中看到的
//它包含您需要的东西:vkCode=虚拟密钥代码。
KBDLLHOOKSTRUCT kbdStruct;
int filenum=1;
//这是回调函数。在这种情况下,将其视为引发的事件。
//按下一个键。
无效截图(常量字符*文件名)
{
//keybd_事件(VK_快照,0x45,KEYEVENTF_扩展键,0);
//keybd_事件(VK_快照,0x45,KEYEVENTF_扩展键| KEYEVENTF_KEYUP,0);
hbith;
a、b点;
a、 x=0;
a、 y=0;
b、 x=GetSystemMetrics(SM\U CXSCREEN);
b、 y=GetSystemMetrics(SM\u CYSCREEN);
HDC hScreen=GetDC(空);
HDC HDC=CreateCompatibleDC(hs屏幕);
HBITMAP HBITMAP=CreateCompatibleBitmap(hs屏幕,abs(b.x-a.x),abs(b.y-a.y));
hgdobj old_obj=选择对象(hDC、hBitmap);
BOOL-bRet=BitBlt(hDC,0,0,abs(b.x-a.x),abs(b.y-a.y),hScreen,a.x,a.y,srcopy);
//将位图保存到剪贴板
OpenClipboard(空);
清空电路板();
SetClipboardData(CF_位图,hBitmap);
CloseClipboard();
//清理
选择对象(hDC、旧对象);
DeleteDC(hDC);
释放DC(空,hs屏幕);
删除对象(hBitmap);
OpenClipboard(空);
h=(HBITMAP)GetClipboardData(CF_位图);
CloseClipboard();
HDC HDC=NULL;
FILE*fp=NULL;
LPVOID pBuf=NULL;
BITMAPINFO-bmpInfo;
BITMAPFILEHEADER bmpFileHeader;
做
{
hdc=GetDC(空);
零内存(&bmpInfo,sizeof(BITMAPINFO));
bmpInfo.bmiHeader.biSize=sizeof(BitMapInfo头文件);
GetDIBits(hdc、h、0、0、NULL和bmpInfo、DIB_RGB_颜色);
如果(bmpInfo.bmiHeader.biSizeImage=0)
{
//该操作有效:HC_操作。
如果(wParam==WM_LBUTTONDOWN)
{
std::string OutputFolder=“C:\\temp”;
std::string filename=“ss”;
if(CreateDirectory(OutputFolder.c_str(),NULL)||
错误\u已\u存在==GetLastError()
{
}
其他的
{
//无法创建目录。
}
自动numfile=std::to_字符串(filenum);
截图((OutputFolder+“\\”+文件名+std::to_字符串(filenum)+“.bmp”).c_str());
filenum++;
}
}
//呼叫钩链中的下一个钩。这是nessecary,否则您的钩链将断裂,钩停止
返回CallNextHookEx(_hook,nCode,wParam,lParam);
}
无效释放挂钩()
{
解开钩(_钩);
}
int main()
{
//不要介意,保持控制台应用程序运行是一个毫无意义的循环。
//我使用它来测试键盘挂钩功能。如果要测试它,请将其保留在;)
味精;
while(GetMessage(&msg,NULL,0,0))
{
}
}

如果单击它不会生成目录(如果它不存在),也不会创建.bmp文件。

正如其他人所说,您永远不会安装钩子!此外,从我的测试中可以看出,您需要向某种窗口发送消息,以便调用WH_鼠标钩子

下面是一个适用于我的
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);
}

您确实会检查一些错误,但不会对错误采取任何行动,也不会告诉用户(或您自己)有错误。如果您无法以其他方式调试代码,则报告错误并详细记录这些错误是非常好的。代码编译的事实对于它是否按预期工作几乎毫无意义(正如你所发现的)所有“它编译”的意思都是“它在语法上是有效的”-它在逻辑上或语义上是否有效仍然未知。无处安装钩子??显然您忘记调用“SetWindowsHookEx”。可能还有更多问题。要了解堆栈溢出的工作原理,请阅读。您好。我使用您的解决方案,但仍然不创建目录。哪个解决方案是
main我发布的还是低级钩子的东西?如果是前者,请单击消息框!嘿,大体上,我只使用_钩子的声明,但我不想要窗口应用,我需要全局地使用它,并将其作为控制台应用(或.dll添加到我的脚本中)更新了我的帖子-使用低级的东西非常感谢兄弟,但是我还有一个小问题。这个截图有1280x720px,我想要全屏