Dreamlover的文章

  • 包含鼠标位置的屏幕截屏并保存为图片文件

    背景在开发自己的专属程序“恶魔的结界”的时候,里面就有一个功能,实现屏幕的截屏,而且是包含鼠标位置的截屏。因为,通常情况下,我们看到的截屏都是没有显示鼠标的截屏,这次我们需要实现显示鼠标的截屏。而且,保存为本地的图片文件。
    现在,我就把这个小程序的实现过程和实现原理写成文档,分享给大家。
    函数介绍GetDesktopWindow 函数
    该函数返回桌面窗口的句柄。桌面窗口覆盖整个屏幕。桌面窗口是一个要在其上绘制所有的图标和其他窗口的区域。
    函数声明
    HWND WINAPI GetDesktopWindow(void);
    参数

    无参数。
    返回值

    返回桌面窗口的句柄。

    GetDC 函数
    该函数检索一指定窗口的客户区域或整个屏幕的显示设备上下文环境的句柄,以后可以在GDI函数中使用该句柄来在设备上下文环境中绘图。
    函数声明
    HDC GetDC( HWND hWnd);
    参数

    hWnd:设备上下文环境被检索的窗口的句柄,如果该值为NULL,GetDC则检索整个屏幕的设备上下文环境。
    返回值

    若执行成功,则返回指定窗口的客户区域或整个屏幕的显示设备上下文环境的句柄;若执行失败,则返回NULL。

    CreateCompatibleDC 函数
    该函数创建一个与指定设备兼容的内存设备上下文环境(DC)。
    函数声明
    HDC CreateCompatibleDC( HDC hdc );
    参数

    hdc:现有设备上下文环境的句柄,如果该句柄为NULL,该函数创建一个与应用程序的当前显示器兼容的内存设备上下文环境。
    返回值

    如果成功,则返回内存设备上下文环境的句柄;如果失败,则返回值为NULL。

    CreateCompatibleBitmap 函数
    创建与与指定设备上下文关联的设备兼容的位图。
    函数声明
    HBITMAP CreateCompatibleBitmap( _In_ HDC hdc, _In_ int nWidth, _In_ int nHeight);
    参数

    hdc [in]设备上下文的句柄。nWidth [in]位图宽度,以像素为单位。nHeight [in]位图高度,以像素为单位。
    返回值

    如果函数成功,则返回值是兼容位图(DDB)的句柄。如果函数失败,返回值为NULL。

    SelectObject 函数
    该函数选择一对象到指定的设备上下文环境中,该新对象替换先前的相同类型的对象。
    函数声明
    HGDIOBJ SelectObject( HDC hdc, HGDIOBJ hgdiobj );
    参数

    hdc:设备上下文环境的句柄。hgdiobj:被选择的对象的句柄,该指定对象必须由如下的函数创建。
    返回值

    如果选择对象不是区域并且函数执行成功,那么返回值是被取代的对象的句柄;如果选择对象是区域并且函数执行成功,返回如下一值:
    ​ SIMPLEREGION:区域由单个矩形组成;
    ​ COMPLEXREGION:区域由多个矩形组成;
    ​ NULLREGION:区域为空。
    如果发生错误并且选择对象不是一个区域,那么返回值为NULL,否则返回HGDI_ERROR。


    BitBlt 函数
    对指定的源设备环境区域中的像素进行位块(bit_block)转换,以传送到目标设备环境。
    函数声明
    BOOL BitBlt( HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, DWORD dwRop);
    参数

    hdcDest:指向目标设备环境的句柄。nXDest:指定目标矩形区域左上角的X轴逻辑坐标。nYDest:指定目标矩形区域左上角的Y轴逻辑坐标。nWidth:指定源在目标矩形区域的逻辑宽度。nHeight:指定源在目标矩形区域的逻辑高度。hdcSrc:指向源设备环境的句柄。nXSrc:指定源矩形区域左上角的X轴逻辑坐标。nYSrc:指定源矩形区域左上角的Y轴逻辑坐标。dwRop:指定光栅操作代码。这些代码将定义源矩形区域的颜色数据,如何与目标矩形区域的颜色数据组合以完成最后的颜色。
    返回值

    如果函数成功,那么返回值非零;如果函数失败,则返回值为零。

    GetSystemMetrics 函数
    检索指定的系统度量或系统配置设置。
    函数声明
    int WINAPI GetSystemMetrics( _In_ int nIndex);
    参数

    nIndex [in]要检索的系统度量或配置设置。 此参数可以是以下值之一。 请注意,所有SM_CX 值都是宽度,所有SM_CY 值都是高度。 还要注意,设计为返回布尔数据的所有设置都表示TRUE作为任何非零值,FALSE为零值。
    其中,SM_CXSCREEN表示主显示屏的屏幕宽度,以像素为单位。 这是通过调用GetDeviceCaps获得的相同的值;SM_CYSCREEN表示主显示屏的屏幕高度,以像素为单位。 这是通过调用GetDeviceCaps获得的相同的值。

    返回值

    如果函数成功,则返回值是所请求的系统度量或配置设置。如果函数失败,则返回值为0。

    实现原理获取桌面屏幕位图句柄的实现原理是:

    首先,使用GetDesktopWindow获取桌面窗口的句柄
    然后,根据句柄使用GetDC获取桌面窗口的设备环境上下文句柄。同时使用CreateCompatibleDC创建与桌面窗口兼容的内存设备上下文环境
    接着,使用GetSystemMetrics获取计算机显示屏幕的宽和高的像素值,并调用CreateCompatibleBitmap兼容位图
    最后,使用SelectObject将把创建的兼容位图选进兼容内存设备上下文环境中,并使用BitBlt函数把桌面内容绘制到兼容位图上

    这样,我们就获取了屏幕内容的位图句柄了.
    对于鼠标的获取,则需要另外绘制上去。

    首先,使用GetCursorPos获取以屏幕坐标表示的鼠标的位置
    然后,使用GetCursor函数获取当前光标的句柄
    最后,调用DrawIcon函数将鼠标绘制到兼容设备上下文环境中,也就是在上述屏幕截屏的基础上,绘制鼠标

    最后,我们就可以使用基于 CImage 类的方法保存位图。
    编码实现截屏,获取屏幕位图的句柄 // 获取屏幕截屏 // 获取桌面窗口句柄 HWND hDesktop = ::GetDesktopWindow(); // 获取桌面窗口DC HDC hdc = ::GetDC(hDesktop); // 创建兼容DC HDC mdc = ::CreateCompatibleDC(hdc); // 获取计算机屏幕的宽和高 DWORD dwWidth = ::GetSystemMetrics(SM_CXSCREEN); DWORD dwHeight = ::GetSystemMetrics(SM_CYSCREEN); // 创建兼容位图 HBITMAP bmp = ::CreateCompatibleBitmap(hdc, dwWidth, dwHeight); // 选中位图 HBITMAP holdbmp = (HBITMAP)::SelectObject(mdc, bmp); // 将窗口内容绘制到位图上 ::BitBlt(mdc, 0, 0, dwWidth, dwHeight, hdc, 0, 0, SRCCOPY);
    绘制鼠标 // 绘制鼠标 POINT p; //获取当前屏幕的鼠标的位置 ::GetCursorPos(&p); //获得鼠标图片的句柄 HICON hIcon = (HICON)::GetCursor(); //绘制鼠标图标 ::DrawIcon(mdc, p.x, p.y, hIcon);
    根据位图句柄保存为文件BOOL SaveBmp(HBITMAP hBmp){ CImage image; // 附加位图句柄 image.Attach(hBmp); // 保存成jpg格式图片 image.Save("mybmp1.jpg"); return TRUE;}
    程序测试运行程序,生成图像文件。查看图片,程序截屏成功,而且包含鼠标位置和状态。

    总结通常情况下的截屏,之所以没有鼠标,是因为鼠标需要另外绘制上去。所以我们获取鼠标的位置以及当时的鼠标状态图标,绘制到图像上,这样就实现了带鼠标位置信息的截屏功能。
    参考参考自《Windows黑客编程技术详解》一书
    2  留言 2019-01-06 10:19:44
  • 包含鼠标位置的屏幕截屏并保存为图片文件

    背景在开发自己的专属程序“恶魔的结界”的时候,里面就有一个功能,实现屏幕的截屏,而且是包含鼠标位置的截屏。因为,通常情况下,我们看到的截屏都是没有显示鼠标的截屏,这次我们需要实现显示鼠标的截屏。而且,保存为本地的图片文件。
    现在,我就把这个小程序的实现过程和实现原理写成文档,分享给大家。
    函数介绍GetDesktopWindow 函数
    该函数返回桌面窗口的句柄。桌面窗口覆盖整个屏幕。桌面窗口是一个要在其上绘制所有的图标和其他窗口的区域。
    函数声明
    HWND WINAPI GetDesktopWindow(void);
    参数

    无参数。
    返回值

    返回桌面窗口的句柄。

    GetDC 函数
    该函数检索一指定窗口的客户区域或整个屏幕的显示设备上下文环境的句柄,以后可以在GDI函数中使用该句柄来在设备上下文环境中绘图。
    函数声明
    HDC GetDC( HWND hWnd);
    参数

    hWnd:设备上下文环境被检索的窗口的句柄,如果该值为NULL,GetDC则检索整个屏幕的设备上下文环境。
    返回值

    若执行成功,则返回指定窗口的客户区域或整个屏幕的显示设备上下文环境的句柄;若执行失败,则返回NULL。

    CreateCompatibleDC 函数
    该函数创建一个与指定设备兼容的内存设备上下文环境(DC)。
    函数声明
    HDC CreateCompatibleDC( HDC hdc );
    参数

    hdc:现有设备上下文环境的句柄,如果该句柄为NULL,该函数创建一个与应用程序的当前显示器兼容的内存设备上下文环境。
    返回值

    如果成功,则返回内存设备上下文环境的句柄;如果失败,则返回值为NULL。

    CreateCompatibleBitmap 函数
    创建与与指定设备上下文关联的设备兼容的位图。
    函数声明
    HBITMAP CreateCompatibleBitmap( _In_ HDC hdc, _In_ int nWidth, _In_ int nHeight);
    参数

    hdc [in]设备上下文的句柄。nWidth [in]位图宽度,以像素为单位。nHeight [in]位图高度,以像素为单位。
    返回值

    如果函数成功,则返回值是兼容位图(DDB)的句柄。如果函数失败,返回值为NULL。

    SelectObject 函数
    该函数选择一对象到指定的设备上下文环境中,该新对象替换先前的相同类型的对象。
    函数声明
    HGDIOBJ SelectObject( HDC hdc, HGDIOBJ hgdiobj );
    参数

    hdc:设备上下文环境的句柄。hgdiobj:被选择的对象的句柄,该指定对象必须由如下的函数创建。
    返回值

    如果选择对象不是区域并且函数执行成功,那么返回值是被取代的对象的句柄;如果选择对象是区域并且函数执行成功,返回如下一值:
    ​ SIMPLEREGION:区域由单个矩形组成;
    ​ COMPLEXREGION:区域由多个矩形组成;
    ​ NULLREGION:区域为空。
    如果发生错误并且选择对象不是一个区域,那么返回值为NULL,否则返回HGDI_ERROR。


    BitBlt 函数
    对指定的源设备环境区域中的像素进行位块(bit_block)转换,以传送到目标设备环境。
    函数声明
    BOOL BitBlt( HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, DWORD dwRop);
    参数

    hdcDest:指向目标设备环境的句柄。nXDest:指定目标矩形区域左上角的X轴逻辑坐标。nYDest:指定目标矩形区域左上角的Y轴逻辑坐标。nWidth:指定源在目标矩形区域的逻辑宽度。nHeight:指定源在目标矩形区域的逻辑高度。hdcSrc:指向源设备环境的句柄。nXSrc:指定源矩形区域左上角的X轴逻辑坐标。nYSrc:指定源矩形区域左上角的Y轴逻辑坐标。dwRop:指定光栅操作代码。这些代码将定义源矩形区域的颜色数据,如何与目标矩形区域的颜色数据组合以完成最后的颜色。
    返回值

    如果函数成功,那么返回值非零;如果函数失败,则返回值为零。

    GetSystemMetrics 函数
    检索指定的系统度量或系统配置设置。
    函数声明
    int WINAPI GetSystemMetrics( _In_ int nIndex);
    参数

    nIndex [in]要检索的系统度量或配置设置。 此参数可以是以下值之一。 请注意,所有SM_CX 值都是宽度,所有SM_CY 值都是高度。 还要注意,设计为返回布尔数据的所有设置都表示TRUE作为任何非零值,FALSE为零值。
    其中,SM_CXSCREEN表示主显示屏的屏幕宽度,以像素为单位。 这是通过调用GetDeviceCaps获得的相同的值;SM_CYSCREEN表示主显示屏的屏幕高度,以像素为单位。 这是通过调用GetDeviceCaps获得的相同的值。

    返回值

    如果函数成功,则返回值是所请求的系统度量或配置设置。如果函数失败,则返回值为0。

    实现原理获取桌面屏幕位图句柄的实现原理是:

    首先,使用GetDesktopWindow获取桌面窗口的句柄
    然后,根据句柄使用GetDC获取桌面窗口的设备环境上下文句柄。同时使用CreateCompatibleDC创建与桌面窗口兼容的内存设备上下文环境
    接着,使用GetSystemMetrics获取计算机显示屏幕的宽和高的像素值,并调用CreateCompatibleBitmap兼容位图
    最后,使用SelectObject将把创建的兼容位图选进兼容内存设备上下文环境中,并使用BitBlt函数把桌面内容绘制到兼容位图上

    这样,我们就获取了屏幕内容的位图句柄了.
    对于鼠标的获取,则需要另外绘制上去。

    首先,使用GetCursorPos获取以屏幕坐标表示的鼠标的位置
    然后,使用GetCursor函数获取当前光标的句柄
    最后,调用DrawIcon函数将鼠标绘制到兼容设备上下文环境中,也就是在上述屏幕截屏的基础上,绘制鼠标

    最后,我们就可以使用基于 CImage 类的方法保存位图。
    编码实现截屏,获取屏幕位图的句柄 // 获取屏幕截屏 // 获取桌面窗口句柄 HWND hDesktop = ::GetDesktopWindow(); // 获取桌面窗口DC HDC hdc = ::GetDC(hDesktop); // 创建兼容DC HDC mdc = ::CreateCompatibleDC(hdc); // 获取计算机屏幕的宽和高 DWORD dwWidth = ::GetSystemMetrics(SM_CXSCREEN); DWORD dwHeight = ::GetSystemMetrics(SM_CYSCREEN); // 创建兼容位图 HBITMAP bmp = ::CreateCompatibleBitmap(hdc, dwWidth, dwHeight); // 选中位图 HBITMAP holdbmp = (HBITMAP)::SelectObject(mdc, bmp); // 将窗口内容绘制到位图上 ::BitBlt(mdc, 0, 0, dwWidth, dwHeight, hdc, 0, 0, SRCCOPY);
    绘制鼠标 // 绘制鼠标 POINT p; //获取当前屏幕的鼠标的位置 ::GetCursorPos(&p); //获得鼠标图片的句柄 HICON hIcon = (HICON)::GetCursor(); //绘制鼠标图标 ::DrawIcon(mdc, p.x, p.y, hIcon);
    根据位图句柄保存为文件BOOL SaveBmp(HBITMAP hBmp){ CImage image; // 附加位图句柄 image.Attach(hBmp); // 保存成jpg格式图片 image.Save("mybmp1.jpg"); return TRUE;}
    程序测试运行程序,生成图像文件。查看图片,程序截屏成功,而且包含鼠标位置和状态。

    总结通常情况下的截屏,之所以没有鼠标,是因为鼠标需要另外绘制上去。所以我们获取鼠标的位置以及当时的鼠标状态图标,绘制到图像上,这样就实现了带鼠标位置信息的截屏功能。
    参考参考自《Windows黑客编程技术详解》一书
    1  留言 2018-11-07 10:24:59
eject