/*
Programme pour enregistrer dans un fichier le contenu bitmap du presse papier.

source :
Pour la gestion du presse papier : http://msdn2.microsoft.com/en-us/library/ms674551(VS.85).aspx
Pour l'enregistrement des bitmap : http://msdn2.microsoft.com/en-us/library/ms532340.aspx
*/

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>

char file[] = "F:\\test.bmp";

PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp);
void CreateBMPFile(LPCSTR pszFile,PBITMAPINFO pbi,HBITMAP hBMP, HDC hDC);

#define failwith(x) {printf("%s\n", #x );system("pause");exit(1);}

void main(void)
{
  if (!OpenClipboard(NULL))
    failwith(Le presse papier ne peut pas être ouvert.);

  HDC hdc = GetWindowDC(NULL);

  HBITMAP hbmp = reinterpret_cast<HBITMAP>(GetClipboardData(CF_BITMAP));
  if (!hbmp)
    failwith(Le presse papier ne contient pas de bitmap.);

  PBITMAPINFO pbi = CreateBitmapInfoStruct(hbmp);

  CreateBMPFile((LPCSTR)file,pbi,hbmp,hdc);

  ReleaseDC(NULL,hdc);
  CloseClipboard(); 

  system("pause");
}



PBITMAPINFO CreateBitmapInfoStruct(HBITMAP hBmp)
{ 
  BITMAP bmp; 
  PBITMAPINFO pbmi; 
  WORD    cClrBits; 

  GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp);

  cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); 
  if (cClrBits == 1) cClrBits = 1; 
  else if (cClrBits <= 4) cClrBits = 4; 
  else if (cClrBits <= 8) cClrBits = 8; 
  else if (cClrBits <= 16) cClrBits = 16; 
  else if (cClrBits <= 24) cClrBits = 24; 
  else cClrBits = 32; 

  if (cClrBits != 24) 
    pbmi = (PBITMAPINFO) LocalAlloc(LPTR,sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*(1<< cClrBits)); 
  else 
    pbmi = (PBITMAPINFO) LocalAlloc(LPTR,sizeof(BITMAPINFOHEADER)); 

  pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
  pbmi->bmiHeader.biWidth = bmp.bmWidth; 
  pbmi->bmiHeader.biHeight = bmp.bmHeight; 
  pbmi->bmiHeader.biPlanes = bmp.bmPlanes; 
  pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel; 
  if (cClrBits < 24)
    pbmi->bmiHeader.biClrUsed = (1<<cClrBits); 
  pbmi->bmiHeader.biCompression = BI_RGB; 
  pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31)/8*pbmi->bmiHeader.biHeight; 
  pbmi->bmiHeader.biClrImportant = 0; 
  return pbmi; 
}

void CreateBMPFile(LPCSTR pszFile,PBITMAPINFO pbi,HBITMAP hBMP, HDC hDC) 
{ 
  HANDLE hf;                 // file handle 
  BITMAPFILEHEADER hdr;       // bitmap file-header 
  PBITMAPINFOHEADER pbih;     // bitmap info-header 
  LPBYTE lpBits;              // memory pointer 
  //DWORD dwTotal;              // total count of bytes 
  DWORD cb;                   // incremental count of bytes 
  BYTE *hp;                   // byte pointer 
  DWORD dwTmp; 

  pbih = (PBITMAPINFOHEADER) pbi; 
  lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);

  GetDIBits(hDC,hBMP,0,(WORD)pbih->biHeight,lpBits,pbi,DIB_RGB_COLORS);

  hf = CreateFileA(pszFile,GENERIC_READ|GENERIC_WRITE,(DWORD)0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,(HANDLE)NULL); 
  hdr.bfType = 0x4d42;        // 0x42 = "B" 0x4d = "M" 

  hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER)+pbih->biSize+pbih->biClrUsed* sizeof(RGBQUAD) + pbih->biSizeImage); 
  hdr.bfReserved1 = 0; 
  hdr.bfReserved2 = 0; 

  hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER)+pbih->biSize+pbih->biClrUsed*sizeof(RGBQUAD); 
  WriteFile(hf,(LPVOID)&hdr,sizeof(BITMAPFILEHEADER),(LPDWORD)&dwTmp,NULL);
  WriteFile(hf,(LPVOID)pbih,sizeof(BITMAPINFOHEADER)+pbih->biClrUsed*sizeof(RGBQUAD),(LPDWORD)&dwTmp,(NULL));

  /*dwTotal = */cb = pbih->biSizeImage; 
  hp = lpBits; 
  WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL);

  CloseHandle(hf); 
  GlobalFree((HGLOBAL)lpBits);
}
