私はフォローしています: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183402%28v=vs.85%29.aspx
Windows の描画領域 (別名 printscreen) をキャプチャします。
重要な機能は「int CaptureAnImage(HWND hWnd)」であり、それをそのままコピーして正当な hWnd を送信すると、すべてが正常に機能します。
ただし、その関数の外に保存できるようにする必要があるため (ビットマップとして返す)、独自の "printscreen" 構造体を作成しました。
struct PrintScreen {
BITMAP * bmpScreen;
BITMAPFILEHEADER * bmfHeader;
BITMAPINFOHEADER * bi;
char * data;
DWORD len;
};
メモリを割り当てるように変更し、代わりに関数でポインターを使用します。
(割り当てられたメモリとポインタを使用した新しいコード)
struct PrintScreen * CaptureAnImage(HWND hWnd)
{
HDC hdcScreen;
HDC hdcWindow;
HDC hdcMemDC = NULL;
HBITMAP hbmScreen = NULL;
BITMAP * bmpScreen = GlobalAlloc(GMEM_FIXED,sizeof(BITMAP));
BITMAPFILEHEADER * bmfHeader = GlobalAlloc(GMEM_FIXED,sizeof(BITMAPFILEHEADER));
BITMAPINFOHEADER * bi = GlobalAlloc(GMEM_FIXED,sizeof(BITMAPINFOHEADER));
struct PrintScreen * printScreen = GlobalAlloc(GMEM_FIXED,sizeof(struct PrintScreen));
// Retrieve the handle to a display device context for the client
// area of the window.
hdcScreen = GetDC(NULL);
hdcWindow = GetDC(hWnd);
// Create a compatible DC which is used in a BitBlt from the window DC
hdcMemDC = CreateCompatibleDC(hdcWindow);
if(!hdcMemDC)
{
printf("Bajs");
MessageBox(hWnd, _T("CreateCompatibleDC has failed"),_T("Failed"), MB_OK);
goto done;
}
// Get the client area for size calculation
RECT rcClient;
if(!GetClientRect(hWnd, &rcClient)) {
printf("Treash");
}
printf("Rect:%d,%d,%d,%d\n",rcClient.right,rcClient.top, rcClient.left,rcClient.bottom);
//This is the best stretch mode
SetStretchBltMode(hdcWindow,HALFTONE);
SetBrushOrgEx(hdcWindow,0,0,NULL);
//The source DC is the entire screen and the destination DC is the current window (HWND)
if(!StretchBlt(hdcWindow,
0,0,
rcClient.right, rcClient.bottom,
hdcScreen,
0,0,
GetSystemMetrics (SM_CXSCREEN),
GetSystemMetrics (SM_CYSCREEN),
SRCCOPY))
{
printf("Bajs");
MessageBox(hWnd, _T("StretchBlt has failed"),_T("Failed"), MB_OK);
goto done;
}
// Create a compatible bitmap from the Window DC
hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top);
printf("\n%ld\n",rcClient.right);
if(!hbmScreen)
{
MessageBox(hWnd, _T("CreateCompatibleBitmap Failed"),_T("Failed"), MB_OK);
goto done;
}
// Select the compatible bitmap into the compatible memory DC.
SelectObject(hdcMemDC,hbmScreen);
// Bit block transfer into our compatible memory DC.
if(!BitBlt(hdcMemDC,
0,0,
rcClient.right-rcClient.left, rcClient.bottom-rcClient.top,
hdcWindow,
0,0,
SRCCOPY))
{
MessageBox(hWnd, _T("BitBlt has failed"), _T("Failed"), MB_OK);
goto done;
}
// Get the BITMAP from the HBITMAP
GetObject(hbmScreen,sizeof(BITMAP),bmpScreen);
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;
// Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that
// call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc
// have greater overhead than HeapAlloc.
char *lpbitmap = (char *)GlobalAlloc(GMEM_FIXED,dwBmpSize);
// Gets the "bits" from the bitmap and copies them into a buffer
// which is pointed to by lpbitmap.
GetDIBits(hdcWindow, hbmScreen, 0,
(UINT)bmpScreen->bmHeight,
lpbitmap,
(BITMAPINFO *)bi, DIB_RGB_COLORS);
//findInvWindow(bmpScreen, lpbitmap);
// A file is created, this is where we will save the screen capture.
HANDLE hFile = CreateFile(_T("C:\\Users\\Hugo\\Dropbox\\Code blocks\\Test\\Poe Test\\bin\\Debug\\captureqwsx.bmp"),
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE) {
printf("Error creating file");
}
printf("Done");
// Add the size of the headers to the size of the bitmap to get the total file size
DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
printf("Size:%d\n",dwBmpSize);
//Offset to where the actual bitmap bits start.
bmfHeader->bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
//Size of the file
bmfHeader->bfSize = dwSizeofDIB;
//bfType must always be BM for Bitmaps
bmfHeader->bfType = 0x4D42; //BM
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);
//Close the handle for the file that was created
CloseHandle(hFile);
printScreen->bmpScreen = bmpScreen;
printScreen->bmfHeader = bmfHeader;
printScreen->bi = bi;
printScreen->data = lpbitmap;
printScreen->len = dwSizeofDIB;
//Clean up
done:
DeleteObject(hbmScreen);
DeleteObject(hdcMemDC);
ReleaseDC(NULL,hdcScreen);
ReleaseDC(hWnd,hdcWindow);
return printScreen;
}
私の問題は、時々それがうまく動作し、フレームのない正当なプリントスクリーンを取得することですが、フレームも取得することがよくありますが、画像のサイズは変わりませんが、ウィンドウのフレームも内側にあります。
どの関数がこれを引き起こす可能性があるかなどをデバッグしようとしましたが、C には少し慣れていないので、すべての関数が成功したと言っています。
編集: フレーム 付き http://i62.tinypic.com/2uifyj4.jpg
なしで、あるべきように:(リンクを編集) http://i.stack.imgur.com/iMxhM.jpg
直接リンクしていなくて申し訳ありませんが、そのためには少し担当者が必要です。そして、どうやら2つ以上のリンクを投稿することはできません。
EDIT2: どうやらエラーはフレームが追加されることではなく、ウィンドウ データをキャプチャするのではなく、フレームを含むウィンドウ全体の「上/内側」にあるものをすべてキャプチャします。
正しいデータを取得する場合と取得しない場合がある原因はまだわかりません。すべての関数が成功を返します... (エラーを表示するために「フレーム」画像を更新)