我正在使用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文件。
答案 0 :(得分:1)
正如其他人所说,您永远不会安装钩子!另外,从我的测试中可以看出,您需要将消息分发到某种形式的窗口中才能调用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);
}