2014-02-06 59 views
1

我在这里找到了一个屏幕截图代码,但是当我试图构建它时,它不会构建,因此我自己修复了代码,现在构建了它,但我认为它不起作用,因为在调试时VS说它无法读取hBitmap(无数据?)。我是新手程序员,所以我真的不知道该怎么做在这一点上...我可能没有正确地修复代码...这个屏幕截图代码有什么问题?

我感谢您的帮助。

#include <Windows.h> 

int main() 
{ 
    // get the device context of the screen 
    HDC hScreenDC = CreateDC(L"DISPLAY", NULL, NULL, NULL);  
    // and a device context to put it in 
    HDC hMemoryDC = CreateCompatibleDC(hScreenDC); 

    int x = GetDeviceCaps(hScreenDC, HORZRES); 
    int y = GetDeviceCaps(hScreenDC, VERTRES); 

    // maybe worth checking these are positive values 
    HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, x, y); 

    // get a new bitmap 
    HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, hBitmap); 

    BitBlt(hMemoryDC, 0, 0, 640, 480, hScreenDC, 0, 0, SRCCOPY); 
    hBitmap = (HBITMAP)SelectObject(hMemoryDC, hOldBitmap); 
    // now your image is held in hBitmap. You can save it or do whatever with it 
} 

回答

2

简答:没什么错。

hBitmap包含一个位图句柄,该句柄的屏幕截图数据通过BitBlt检索。当您将鼠标悬停在Visual Studio中的hBitmap上时,它只是通知您,hBitmap不是指向内存的有效指针,这是一个正确的报告 - Windows句柄只是解析为内存位置和实现由窗口私人管理的结构的标记API。

为了证明您的代码确实从屏幕上拉出某些东西,请尝试将其写入文件。使用GDI +写入文件是有帮助的,因为它将为您节省大量您必须手动编写的初始化代码。

这是一个快速的控制台应用程序,它将使用您的代码和a helper function GetEncoderClsid to get the PNG encoder发出PNG文件。

#include "stdafx.h" 
#include <Windows.h> 
#include <gdiplus.h> 

using namespace Gdiplus; 

int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) 
{ 
    UINT num = 0;   // number of image encoders 
    UINT size = 0;   // size of the image encoder array in bytes 

    ImageCodecInfo* pImageCodecInfo = NULL; 

    GetImageEncodersSize(&num, &size); 
    if (size == 0) 
    return -1; // Failure 

    pImageCodecInfo = (ImageCodecInfo*)(malloc(size)); 
    if (pImageCodecInfo == NULL) 
    return -1; // Failure 

    GetImageEncoders(num, size, pImageCodecInfo); 

    for (UINT j = 0; j < num; ++j) 
    { 
    if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0) 
    { 
     *pClsid = pImageCodecInfo[j].Clsid; 
     free(pImageCodecInfo); 
     return j; // Success 
    } 
    } 

    free(pImageCodecInfo); 
    return -1; // Failure 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    GdiplusStartupInput gdiplusStartupInput; 
    ULONG_PTR gdiplusToken; 
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); 

    // get the device context of the screen 
    HDC hScreenDC = CreateDC(L"DISPLAY", NULL, NULL, NULL); 
    // and a device context to put it in 
    HDC hMemoryDC = CreateCompatibleDC(hScreenDC); 

    int x = GetDeviceCaps(hScreenDC, HORZRES); 
    int y = GetDeviceCaps(hScreenDC, VERTRES); 

    // maybe worth checking these are positive values 
    HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, x, y); 

    // get a new bitmap 
    HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, hBitmap); 

    BitBlt(hMemoryDC, 0, 0, 640, 480, hScreenDC, 0, 0, SRCCOPY); 
    hBitmap = (HBITMAP)SelectObject(hMemoryDC, hOldBitmap); 
    // now your image is held in hBitmap. You can save it or do whatever with it 

    CLSID pngClsid; 
    GetEncoderClsid(L"image/png", &pngClsid); 

    Bitmap *bmp = new Bitmap(hBitmap, NULL); 
    bmp->Save(L"desktop_slice.png", &pngClsid, NULL); 
    delete bmp; 

    GdiplusShutdown(gdiplusToken); 
    return 0; 
} 

确保将gdiplus.lib添加到您的项目设置中的源库列表中。运行此命令将创建一个名为“desktop_slice.png”的文件,以便发射。

如果您需要检索含有屏幕数据的位图后做额外的工作,你应该选择它变成一个兼容的DC,并呼吁更多的GDI函数与DC,或SelectObject换出位图前进行其他修改hMemoryDC

如果您需要在像素级别执行较低级的工作,您应该查看创建一个已知像素格式的DIB部分以满足您的需求,并使用从ppvBits参数返回的指针。

CreateDIBSection @ MSDN

+0

我有一个问题,用的#include “stdafx.h中”(没有这样的文件或目录) 。 (我创建了一个空的Win32项目...) – Tez

+0

如果我评论stdafx,我仍然得到一个diff错误:错误C2061:语法错误:标识符'_TCHAR'。如果我包含tchar.h,我得到一个diff错误:错误LNK2019:无法解析的外部符号_WinMain @ 16在函数中引用___tmainCRTStartup – Tez

+0

'int main()'可以代替int _tmain(int argc,_TCHAR * argv [])',但你应该看看在UNICODE下编译,你是对的,如果你创建一个空的Win32项目(尝试创建一个控制台项目),“stdafx.h”将不存在 – meklarian

1

让我们来看看。当您使用SelectObject()首次

HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, hBitmap); 

关联时HBITMAP与hMemoryDC。你不能删除hBitmap只要hMemoryDC存在!因此致电

DeleteObject(hBitmap); 

什么都不做。为了正确删除hBitmap你使用hOldBitmap,你做

SelectObject(hMemoryDC, hOldBitmap); 

在此之后,你不能再使用hMemoryDC。所以抹掉你的最后一行

hBitmap = (HBITMAP)SelectObject(hMemoryDC, hOldBitmap); 

你应该没问题。当你不需要hMemoryDC时释放资源。

编辑

释放的正确方法HBITMAP和hMemoryDC是:

SelectObject(hMemoryDC, hOldBitmap); 
DeleteObject(hBitmap); 
hBitmap = NULL; 
DeleteDC(hMemoryDC); 
hMemoryDC = NULL; 

瓦尔特

+0

对不起,你是那种失去了我。 – Tez

+0

@Tez第一个'SelectObject()'使得hMemoryDC从1x1到XxY的尺寸。第二个'SelectObject()'使hMemoryDC从XxY回到1x1,所以你不能使用它。 –

+0

换句话说,一切都是正确的,除了我只需要删除:hBitmap =(HBITMAP)SelectObject(hMemoryDC,hOldBitmap);并从hOldBitmap获取位图信息?那个bitblt呢? hOldBitmap之后是否可以? – Tez