截屏后程序卡住

Program gets stuck after taking screenshot

#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();截图前();在我的主要工作中,一切正常,但如果我像上面那样,就不行了。我需要我的程序在更改墙纸之前截取屏幕截图,所以我不能只切换它们。有谁知道可能是什么问题?我一头雾水

一些变化。范围界定对于使位图超出范围并自行清理是必要的。第二个是释放 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);

作为@xsoftie,你挂在 image::~image().

根据 GdiplusShutdown :

you must delete all of your GDI+ objects (or have them go out of scope) before you call 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);

或者,将GdiplusStartupGdiplusShutdown放在主函数中:

int main()
{
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    screenshot();
    changewallpaper();
    GdiplusShutdown(gdiplusToken);
}

此外,当您不再需要 hScreenDC 时,请调用 DeleteDC 函数。