In primo luogo, stai passando al costruttore di Bitmap una bitmap correntemente selezionata in un DC, il che non va bene (come spiegato nella documentazione del costruttore della classe Bitmap). Inoltre la bitmap creata deve essere compatibile con il DC dello schermo, non con quello di destinazione (visto che esso quando viene creato contiene una bitmap 1x1 1bpp). In sostanza:
codice:
int MakeScreenShot_GDIPlus(void)
{
//N.B.: codice di gestione degli errori completamente omesso
//Ottiene un device context relativo a tutto lo schermo
HDC ScreenDC = GetDC(NULL);
//Ottiene le dimensioni dello schermo
int ResX = GetSystemMetrics(SM_CXSCREEN);
int ResY = GetSystemMetrics(SM_CYSCREEN);
//Crea un device context in cui verrà selezionata la DIB su cui verrà copiato il contenuto del desktop
HDC DestDC = CreateCompatibleDC(NULL);
//Crea una DDB in memoria con la stessa profondità di colori del desktop
HBITMAP DestBitmap = CreateCompatibleBitmap(ScreenDC,ResX,ResY);
//Salva la bitmap attualmente selezionata nel DC per ripristinarla in seguito (per poter poi eliminare DestBitmap) e seleziona nel DC DestDC la DDB appena creata
HBITMAP OldBitmap = (HBITMAP)SelectObject(DestDC,DestBitmap);
//Copia il contenuto del DC del desktop nel DC che contiene la DDB DestBitmap, che quindi ora conterrà una copia del contenuto del desktop
BitBlt(DestDC,0,0,ResX,ResY,ScreenDC,0,0,SRCCOPY);
//Deseleziona dal DC DestDC la DIB, selezionando la vecchia bitmap che in esso era prima contenuta
SelectObject(DestDC,OldBitmap);
//Elimina il DC di destinazione
DeleteDC(DestDC);
//Rilascia il DC relativo allo schermo
ReleaseDC(NULL,ScreenDC);
ULONG_PTR gditoken;
GdiplusStartupInput input;
GdiplusStartup(&gditoken,&input,NULL);
CLSID jpgsid;
{
//Dichiaro la variabile all'interno di uno scope in modo che venga distrutta appena si esce da esso, così da poter eliminare DestBitmap
Bitmap GBitmap(DestBitmap,NULL);
GetEncoderClsid(L"image/jpeg",&jpgsid);
GBitmap.Save(L"image.jpeg",&jpgsid,NULL);
}
GdiplusShutdown(gditoken);
//Ora che la DDB è deselezionata la si può cancellare
DeleteObject(DestBitmap);
return 0;
}
In ogni caso puoi ottenere lo stesso risultato (salvando in bmp) anche con le normali GDI, che hanno il pregio di essere presenti su tutte le versioni di Windows, ma devi faticare un po' di più.
codice:
int MakeScreenShot_GDI()
{
//N.B.: codice di gestione degli errori completamente omesso
//Ottiene un device context relativo a tutto lo schermo
HDC ScreenDC = GetDC(NULL);
//Ottiene le dimensioni dello schermo
int ResX = GetSystemMetrics(SM_CXSCREEN);
int ResY = GetSystemMetrics(SM_CYSCREEN);
//Crea un device context in cui verrà selezionata la DIB su cui verrà copiato il contenuto del desktop
HDC DestDC = CreateCompatibleDC(NULL);
//Crea una DIB in memoria con la stessa profondità di colori del desktop
HBITMAP DestBitmap = CreateCompatibleBitmap(ScreenDC,ResX,ResY);
//Salva la bitmap attualmente selezionata nel DC per ripristinarla in seguito (per poter poi eliminare DestBitmap) e seleziona nel DC DestDC la DIB appena creata
HBITMAP OldBitmap = (HBITMAP)SelectObject(DestDC,DestBitmap);
//Copia il contenuto del DC del desktop nel DC che contiene la DIB DestBitmap, che quindi ora conterrà una copia del contenuto del desktop
BitBlt(DestDC,0,0,ResX,ResY,ScreenDC,0,0,SRCCOPY);
//Deseleziona dal DC DestDC la DIB, selezionando la vecchia bitmap che in esso era prima contenuta
SelectObject(DestDC,OldBitmap);
//Rilascia il DC relativo allo schermo
ReleaseDC(NULL,ScreenDC);
//Costruisce la DIB in memoria
//Headers
BITMAPINFO BitInfo={0};
BitInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BitInfo.bmiHeader.biWidth = ResX;
BitInfo.bmiHeader.biHeight = ResY;
BitInfo.bmiHeader.biPlanes = 1;
BitInfo.bmiHeader.biBitCount = 16;
BitInfo.bmiHeader.biCompression = BI_RGB;
BitInfo.bmiHeader.biSizeImage = (BitInfo.bmiHeader.biWidth * BitInfo.bmiHeader.biHeight) * 2;
BITMAPFILEHEADER bitheader;
bitheader.bfReserved1 = 0;
bitheader.bfReserved2 = 0;
bitheader.bfType = 0x4d42;
bitheader.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);
bitheader.bfSize = bitheader.bfOffBits + BitInfo.bmiHeader.biSizeImage;
//Alloca lo spazio per i byte dell'immagine
void *bits = malloc(BitInfo.bmiHeader.biSizeImage);
GetDIBits(DestDC,DestBitmap,0,BitInfo.bmiHeader.biHeight,bits,&BitInfo,DIB_PAL_COLORS);
//Crea il file
HANDLE bmfile = CreateFile("image.bmp",GENERIC_WRITE,NULL,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
//Scrive i dati su file
DWORD bytes;
WriteFile(bmfile,&bitheader,sizeof(BITMAPFILEHEADER),&bytes,NULL);
WriteFile(bmfile,&BitInfo.bmiHeader,sizeof(BITMAPINFOHEADER),&bytes,NULL);
WriteFile(bmfile,bits,BitInfo.bmiHeader.biSizeImage,&bytes,NULL);
//Delloca la memoria
free(bits);
//Chiude il file
CloseHandle(bmfile);
//Elimina il DC di destinazione
DeleteDC(DestDC);
//Ora che la DIB è deselezionata la si può cancellare
DeleteObject(DestBitmap);
return 0;
}