截图后程序卡住了
Posted
技术标签:
【中文标题】截图后程序卡住了【英文标题】:Program gets stuck after taking screenshot 【发布时间】:2020-01-26 22:29:52 【问题描述】:#include "screenshot.h"
#include "changewallpaper.h"
using namespace std;
int main()
screenshot();
changewallpaper();
我的截图();
#include <windows.h>
#include <gdiplus.h>
#include <stdio.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
void screenshot()
// get the device context of the screen
HDC hScreenDC = CreateDC("DISPLAY", NULL, NULL, NULL);
int width = GetDeviceCaps(hScreenDC, HORZRES);
int height = GetDeviceCaps(hScreenDC, VERTRES);
POINT a,b;
a.x=0;
a.y=0;
b.x=width;
b.y=height;
// copy screen to bitmap
HDC hScreen = GetDC(NULL);
HDC hDC = CreateCompatibleDC(hScreen);
HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, abs(b.x-a.x), abs(b.y-a.y));
HGDIOBJ old_obj = SelectObject(hDC, hBitmap);
BOOL bRet = BitBlt(hDC, 0, 0, abs(b.x-a.x), abs(b.y-a.y), hScreen, a.x, a.y, SRCCOPY);
//Initialize GDI+
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
Gdiplus::Bitmap bitmap(hBitmap, NULL);
CLSID pngClsid;
GetEncoderClsid(L"image/png", &pngClsid);
bitmap.Save(L"D:\\Pictures\\screen.png", &pngClsid, NULL);
// clean up
SelectObject(hDC, old_obj);
DeleteDC(hDC);
ReleaseDC(NULL, hScreen);
DeleteObject(hBitmap);
//delete image;
GdiplusShutdown(gdiplusToken);
我的问题是 changewallpaper();从不跑。如果我放置 changewallpaper();在屏幕截图()之前;在我的主要一切工作,但如果我有它像上面那样。我需要我的程序在更改壁纸之前截取屏幕截图,所以我不能只是切换它们。有谁知道可能是什么问题?我一无所知。
【问题讨论】:
当你说它没有按当前顺序工作时,你是什么意思——它是挂起的吗?您是否尝试过使用调试器单步执行它以查看它在screenshot()
中的进展情况?如果屏幕截图成功返回,则问题可能出在其他函数中(现在不是问题的一部分)。
请出示changewallpaper
的代码
GDI+ 使用 WIC,这是一个通过 COM 公开的接口。据推测,GDI+ 在调用线程上初始化 COM。如果它选择单线程单元,则需要运行消息循环。
@IInspectable,假设您尝试了我的修复并且它仍然挂起,您能告诉我它挂在哪里吗?我想尝试并从中学习。在确定 gdi 对象范围后的调试器中,我可以看到所有三个 GDI 线程都干净地退出。
【参考方案1】:
作为@xsoftie,你挂在image::~image()
。
根据GdiplusShutdown :
您必须删除所有 GDI+ 对象(或让它们退出 范围)在调用 GdiplusShutdown 之前。
Gdiplus::Bitmap bitmap(hBitmap, NULL);
bitmap
存储在堆栈中,系统会在其生命周期结束时( 之后)自动释放它们。 scoftie 的方法是一种可行的解决方案。
当然你也可以使用new
在堆上请求GDI+对象指针,就像sample:
Gdiplus::Bitmap *bitmap = new Gdiplus::Bitmap(hBitmap, NULL);
CLSID pngClsid;
GetEncoderClsid(L"image/png", &pngClsid);
bitmap->Save(L"D:\\Pictures\\screen.png", &pngClsid, NULL);
//...
delete bitmap;
GdiplusShutdown(gdiplusToken);
或者,将GdiplusStartup
和GdiplusShutdown
放在主函数中:
int main()
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
screenshot();
changewallpaper();
GdiplusShutdown(gdiplusToken);
此外,当您不再需要hScreenDC
时,请调用DeleteDC
函数。
【讨论】:
【参考方案2】:一些变化。范围界定对于使位图超出范围并自行清理是必要的。第二个是发布 hScreenDC,尽管我将把它作为练习留给你看是否有必要。你挂在 image::~image 函数中。让我知道它是否为您解决了问题。
Gdiplus::Bitmap bitmap(hBitmap, NULL);
CLSID pngClsid;
GetEncoderClsid(L"image/png", &pngClsid);
bitmap.Save(L"c:\\temp\\screen.png", &pngClsid, NULL);
// clean up
SelectObject(hDC, old_obj);
DeleteDC(hDC);
ReleaseDC(NULL, hScreen);
DeleteObject(hBitmap);
DeleteDC(hScreenDC);
【讨论】:
以上是关于截图后程序卡住了的主要内容,如果未能解决你的问题,请参考以下文章
第一个 epoch 完成后模型训练卡住了……第二个 epoch 甚至不会开始,也不会抛出任何错误,它只是保持空闲