如何使用GDI API在Windows桌面上绘图?

时间:2012-11-21 12:04:57

标签: c++ winapi bitmap gdi

  

可能重复:
  Draw on screen with GDI+ (or GDI) similar to Inspect

我正在尝试编写一个没有窗户的蛇游戏,但冻结前景并在其上方绘制蛇。当游戏结束时,前景应该解冻。

我已经编写了一些测试代码,它应该在前景上绘制一个正方形,但它似乎只是将桌面冻结一秒钟并将窗口冻结在前景中,直到我最小化,最大化,关闭它,或者将另一个窗口带入前景,它不会绘制任何东西。在代码中,我尝试存储桌面的位图,以便我可以基本上将其重置为原始状态并将方块绘制在不同的位置。有人能用我的代码发现问题吗?

//Handle to the desktop window
HWND hDesktopWindow = GetDesktopWindow();

//Lock the window to prevent other applications drawing on it
if(!LockWindowUpdate(hDesktopWindow)){
    return 1;
}

//Calling GetDC with argument NULL retrieves the desktop's DC
HDC hdcDesktop = GetDCEx(hDesktopWindow, NULL, DCX_CACHE | DCX_LOCKWINDOWUPDATE);

//Create a compatible DC to allow us to store a bitmap of the desktop
HDC hdcCompatible;
if((hdcCompatible = CreateCompatibleDC(hdcDesktop)) == NULL){
    return 1;
}

//Create a compatible bitmap with the same dimensions as the desktop
HBITMAP hScrBitmap;
int cx = GetSystemMetrics(SM_CXSCREEN);
int cy = GetSystemMetrics(SM_CYSCREEN);
if((hScrBitmap = CreateCompatibleBitmap(hdcDesktop, cx, cy)) == NULL){
    return 1;
}

//Select the bitmap into the compatible DC
SelectObject(hdcCompatible, hScrBitmap);

//Copy the Desktop into the bitmap
if(!BitBlt(hdcCompatible, 0, 0, cx, cy, hdcDesktop, 0, 0, SRCCOPY)){
    return 1;
}

//Create a DC compatible with the bitmaps DC for drawing the rectangle
HDC hdcRectangle;
if(!CreateCompatibleDC((HDC)hScrBitmap)){
    return 1;
}

//Create a compatible bitmap for the rectangle to be drawn in
HBITMAP hRectangleBitmap;
if(!CreateCompatibleBitmap(hdcRectangle, 100, 100)){
    return 1;
}

//Fill the rectangle bitmap
if(!FloodFill(hdcRectangle, 0, 0, RGB(255,0,0))){
    return 1;
}

//Copy the rectangle onto the desktop bitmap
if(!BitBlt(hdcCompatible, 100, 100, 100, 100, hdcRectangle, 0, 0, SRCCOPY)){
    return 1;
}

//Copy the bitmap onto the actual desktop
if(!BitBlt(hdcDesktop, 0, 0, cx, cy, hdcCompatible, 0, 0, SRCCOPY)){
    return 1;
}

//Allow time to view the result
Sleep(1000);

//Allow other applications to draw on the desktop again
LockWindowUpdate(NULL);

//Cleanup
ReleaseDC(hDesktopWindow, hdcDesktop);
DeleteDC(hdcCompatible);
DeleteObject(hScrBitmap);

非常感谢任何帮助:)

2 个答案:

答案 0 :(得分:4)

尝试在桌面上直接执行此操作将会出现问题。通过拍摄桌面快照,然后创建一个与整个桌面大小相同的窗口,将快照复制到窗口,并在那里完成所有绘图,你会感觉更好。 (这是在旧版屏幕保护程序中执行的常见技巧,它可以“侵蚀”桌面。)

您不拥有桌面窗口,因此您始终会遇到无效和重新绘制的问题。

答案 1 :(得分:2)

if(!CreateCompatibleDC((HDC)hScrBitmap)){
    return 1;
}

当你编写像这样的C代码时,单点返回往往非常重要。像这样的调用将返回FALSE,无法将HBITMAP强制转换为HDC,并且节目结果非常糟糕。没有诊断,也没有再次解锁的电话。

支持C ++ RAII模式以确保始终解锁:

class DesktopLocker {
public:
    DesktopLocker() { LockWindowUpdate(GetDesktopWindow()); }
    ~DesktopLocker() { LockWindowUpdate(NULL); }
};

void foo() {
   DesktopLocker lock;
   // etc...
}

没有太多的智慧直接绘制到桌面窗口,几乎没有保证你画的任何东西都会持续。睡眠和锁定更新只是创可贴。看看source of Rainmeter,它做得很好。