BIGMAN的文章

  • BMP位图的绘制

    背景我曾开发过一些小软件,里面有许多自己使用VC6.0和VS2013写的小游戏。所以,也有很多人向我请教,怎么用VC或者VS绘制位图。其实,绘制位图不是很复杂,只是固定的几个步骤,正确无误地编码下来就好了。
    现在,我还是觉得有必要把这一知识点总结为文档,分享出来,方便大家参考。
    函数介绍GetDC 函数
    该函数检索一指定窗口的客户区域或整个屏幕的显示设备上下文环境的句柄,以后可以在GDI函数中使用该句柄来在设备上下文环境中绘图。
    函数声明
    HDC GetDC( HWND hWnd);
    参数

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

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

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

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

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

    LoadImage 函数
    该函数装载图标,光标,或位图。
    函数声明
    HANDLE LoadImage( HINSTANCE hInst, LPCTSTR lpszName, UINT uType, int cxDesired, int cyDesired, UINT fuLoad);
    参数

    hInst:从其中载入图象的DLL或应用程序模块或实例句柄。零表示装载一幅固有图象。
    lpszName:欲载入图象的名字。如指定了hInst,就用这个参数指定资源或资源的标志符(标志符是一个长整数)。如hInst为空,且已指定LR_LOADFROMFILE,那么这个参数代表文件名(位图、图标或指针文件)。如果是个Long型值,这个参数就代表固有位图、图标或指针的编号。
    uType:指定被装载图像类型。此参数可以为下列值,其含义如下:




    VALUE
    MEANING




    IMAGE_BITMAP
    装载位图


    IMAGE_CURSOR
    装载光标


    IMAGE_ICON
    装载图标




    cxDesired:指定图标或光标的宽度,以像素为单位。如果此参数为零并且参数fuLoad值为LR_DEFAULTSIZE,那么函数使用SM_CXICON或SM_CXCURSOR系统公制值设定宽度;如果此参数为零并且值LR_DEFAULTSIZE没有被使用,那么函数使用目前的资源宽度。
    cyDesired:指定图标或光标的高度,以像素为单位。如果此参数为零并且参数fuLoad值为LR_DEFAULTSIZE,那么函数使用SM_CXICON或SM_CXCURSOR系统公制值设定高度;如果此参数为零并且值LR_DEFAULTSIZE没有被使用,那么函数使用目前的资源高度。
    fuLoad:根据下面复合值列表指定函数值,值含义如下:




    VALUE
    MEANING




    LR_DEFAULTCOLOR
    以常规方式载入图象


    LR_LOADREALSIZE
    不对图象进行缩放处理。忽略cxDesired和cyDesired的设置


    LR_CREATEDIBSECTION
    如果指定了IMAGE_BITMAP,就返回DIBSection的句柄,而不是位图的句柄


    LR_DEFAULTSIZE
    如果cxDesired和cyDesired为零,就使用由系统定义的图象默认大小,而不是图象本身定义的大小


    LR_LOADFROMFILE
    根据参数lpszName的值装载图像。如hInst为零,lpszName的值为资源名称


    LR_LOADMAP3DCOLORS
    将图象中的深灰、灰、以及浅灰像素都替换成COLOR_3DSHADOW,COLOR_3DFACE以及COLOR_3DLIGHT的当前设置


    LR_LOADTRANSPARENT
    与图象中第一个像素相符的所有像素都由系统替换


    LR_MONOCHROME
    将图象转换成单色,即黑白图。


    LR_SHARED
    若图像将被多次装载则共享。如果LR_SHARED未被设置,则再向同一个资源第二次调用这个图像时就会再装载一遍这个图像且返回不同的句柄。



    返回值

    如果函数运行成功,返回值是相关资源的数据的句柄。如果函数运行失败,返回值为NULL。若想获得更多的错误信息,请调用GetLastError函数。

    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:指定光栅操作代码。这些代码将定义源矩形区域的颜色数据,如何与目标矩形区域的颜色数据组合以完成最后的颜色。
    返回值

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

    实现原理绘制位图的流程就是:

    首先,根据窗口句柄获取窗口的客户区域的显示设备上下文环境的句柄hDC
    然后,创建一个与hDC兼容的内存设备上下文环境
    接着,加载位图, 获取位图句柄
    接着,选中位图到兼容绘图设备上下文中,并绘制位图
    最后,还原位图,并释放对象,删除兼容显示设备上下文,释放显示设备上下文

    编码实现BOOL PaintBmp(HWND hWnd){ // 获取窗口的客户区域的显示设备上下文环境的句柄 HDC hDC = ::GetDC(hWnd); // 创建一个与hDC兼容的内存设备上下文环境 HDC hBuf = ::CreateCompatibleDC(hDC); // 加载位图, 获取位图句柄 HBITMAP hBmp = (HBITMAP)::LoadImage(NULL, "bg.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); // 选择位图句柄到hBuf中, 并获取返回的原来位图句柄 HBITMAP hOldBmp = (HBITMAP)::SelectObject(hBuf, hBmp); // 绘图 ::BitBlt(hDC, 0, 0, 651, 516, hBuf, 0, 0, SRCCOPY); // 还原位图对象 ::SelectObject(hBuf, hOldBmp); // 释放位图 ::DeleteObject(hBmp); // 释放兼容的内存设备上下文环境 ::DeleteDC(hBuf); // 释放设备上下文环境 ::ReleaseDC(hWnd, hDC); return TRUE;}
    程序测试调用上述封装好的绘制位图函数,位图能够正确显示:

    所以,测试测功。
    总结对于这个小程序,逻辑并不复杂,只需要多练一两遍,熟悉下绘制的流程就好了。
    参考参考自《Windows黑客编程技术详解》一书
    1  留言 2019-01-05 09:25:58
  • BMP位图的绘制

    背景我曾开发过一些小软件,里面有许多自己使用VC6.0和VS2013写的小游戏。所以,也有很多人向我请教,怎么用VC或者VS绘制位图。其实,绘制位图不是很复杂,只是固定的几个步骤,正确无误地编码下来就好了。
    现在,我还是觉得有必要把这一知识点总结为文档,分享出来,方便大家参考。
    函数介绍GetDC 函数
    该函数检索一指定窗口的客户区域或整个屏幕的显示设备上下文环境的句柄,以后可以在GDI函数中使用该句柄来在设备上下文环境中绘图。
    函数声明
    HDC GetDC( HWND hWnd);
    参数

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

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

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

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

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

    LoadImage 函数
    该函数装载图标,光标,或位图。
    函数声明
    HANDLE LoadImage( HINSTANCE hInst, LPCTSTR lpszName, UINT uType, int cxDesired, int cyDesired, UINT fuLoad);
    参数

    hInst:从其中载入图象的DLL或应用程序模块或实例句柄。零表示装载一幅固有图象。
    lpszName:欲载入图象的名字。如指定了hInst,就用这个参数指定资源或资源的标志符(标志符是一个长整数)。如hInst为空,且已指定LR_LOADFROMFILE,那么这个参数代表文件名(位图、图标或指针文件)。如果是个Long型值,这个参数就代表固有位图、图标或指针的编号。
    uType:指定被装载图像类型。此参数可以为下列值,其含义如下:




    VALUE
    MEANING




    IMAGE_BITMAP
    装载位图


    IMAGE_CURSOR
    装载光标


    IMAGE_ICON
    装载图标




    cxDesired:指定图标或光标的宽度,以像素为单位。如果此参数为零并且参数fuLoad值为LR_DEFAULTSIZE,那么函数使用SM_CXICON或SM_CXCURSOR系统公制值设定宽度;如果此参数为零并且值LR_DEFAULTSIZE没有被使用,那么函数使用目前的资源宽度。
    cyDesired:指定图标或光标的高度,以像素为单位。如果此参数为零并且参数fuLoad值为LR_DEFAULTSIZE,那么函数使用SM_CXICON或SM_CXCURSOR系统公制值设定高度;如果此参数为零并且值LR_DEFAULTSIZE没有被使用,那么函数使用目前的资源高度。
    fuLoad:根据下面复合值列表指定函数值,值含义如下:




    VALUE
    MEANING




    LR_DEFAULTCOLOR
    以常规方式载入图象


    LR_LOADREALSIZE
    不对图象进行缩放处理。忽略cxDesired和cyDesired的设置


    LR_CREATEDIBSECTION
    如果指定了IMAGE_BITMAP,就返回DIBSection的句柄,而不是位图的句柄


    LR_DEFAULTSIZE
    如果cxDesired和cyDesired为零,就使用由系统定义的图象默认大小,而不是图象本身定义的大小


    LR_LOADFROMFILE
    根据参数lpszName的值装载图像。如hInst为零,lpszName的值为资源名称


    LR_LOADMAP3DCOLORS
    将图象中的深灰、灰、以及浅灰像素都替换成COLOR_3DSHADOW,COLOR_3DFACE以及COLOR_3DLIGHT的当前设置


    LR_LOADTRANSPARENT
    与图象中第一个像素相符的所有像素都由系统替换


    LR_MONOCHROME
    将图象转换成单色,即黑白图。


    LR_SHARED
    若图像将被多次装载则共享。如果LR_SHARED未被设置,则再向同一个资源第二次调用这个图像时就会再装载一遍这个图像且返回不同的句柄。



    返回值

    如果函数运行成功,返回值是相关资源的数据的句柄。如果函数运行失败,返回值为NULL。若想获得更多的错误信息,请调用GetLastError函数。

    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:指定光栅操作代码。这些代码将定义源矩形区域的颜色数据,如何与目标矩形区域的颜色数据组合以完成最后的颜色。
    返回值

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

    实现原理绘制位图的流程就是:

    首先,根据窗口句柄获取窗口的客户区域的显示设备上下文环境的句柄hDC
    然后,创建一个与hDC兼容的内存设备上下文环境
    接着,加载位图, 获取位图句柄
    接着,选中位图到兼容绘图设备上下文中,并绘制位图
    最后,还原位图,并释放对象,删除兼容显示设备上下文,释放显示设备上下文

    编码实现BOOL PaintBmp(HWND hWnd){ // 获取窗口的客户区域的显示设备上下文环境的句柄 HDC hDC = ::GetDC(hWnd); // 创建一个与hDC兼容的内存设备上下文环境 HDC hBuf = ::CreateCompatibleDC(hDC); // 加载位图, 获取位图句柄 HBITMAP hBmp = (HBITMAP)::LoadImage(NULL, "bg.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); // 选择位图句柄到hBuf中, 并获取返回的原来位图句柄 HBITMAP hOldBmp = (HBITMAP)::SelectObject(hBuf, hBmp); // 绘图 ::BitBlt(hDC, 0, 0, 651, 516, hBuf, 0, 0, SRCCOPY); // 还原位图对象 ::SelectObject(hBuf, hOldBmp); // 释放位图 ::DeleteObject(hBmp); // 释放兼容的内存设备上下文环境 ::DeleteDC(hBuf); // 释放设备上下文环境 ::ReleaseDC(hWnd, hDC); return TRUE;}
    程序测试调用上述封装好的绘制位图函数,位图能够正确显示:

    所以,测试测功。
    总结对于这个小程序,逻辑并不复杂,只需要多练一两遍,熟悉下绘制的流程就好了。
    参考参考自《Windows黑客编程技术详解》一书
    1  留言 2018-11-06 22:13:00

发送私信

期待与你的不期而遇

8
文章数
11
评论数
eject