Windows API Function AVIFileOpenW takes PAVISTREAM as input but AVIStreamSetFormat takes PAVIFILE - c++

I am making a clipping software which clips the last 30 seconds of your screen. I am trying to write the results to an AVI file, but I am running into issues. Here is my code:
#include <Windows.h>
#include <Vfw.h>
#include <iostream>
#include <vector>
const int BUFFER_SIZE = 30 * 60; // 30 seconds at 60 fps
int main() {
HMONITOR hMonitor = MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY);
MONITORINFO info;
info.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(hMonitor, &info);
int width = info.rcMonitor.right - info.rcMonitor.left;
int height = info.rcMonitor.bottom - info.rcMonitor.top;
HDC hDC = GetDC(NULL);
HBITMAP hBitmap = CreateCompatibleBitmap(hDC, width, height);
// Create a device context for the bitmap
HDC hMemDC = CreateCompatibleDC(hDC);
SelectObject(hMemDC, hBitmap);
std::vector<HBITMAP> buffer(BUFFER_SIZE);
int index = 0;
while (true) {
BitBlt(hMemDC, 0, 0, width, height, hDC, 0, 0, SRCCOPY);
buffer[index] = hBitmap;
index = (index + 1) % BUFFER_SIZE;
if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) {
break;
}
}
// PROBLEM HERE:
PAVISTREAM pStream;
AVIFileInit();
AVIFileOpenW(&pStream, L"screen_recording.avi", OF_WRITE | OF_CREATE, NULL); // takes PAVIFILE as first parameter
AVIStreamSetFormat(pStream, 0, &hBitmap, sizeof(BITMAPINFOHEADER)); // takes PAVISTREAM as first parameter
// Write the stored frames to the AVISTREAM object
for (int i = 0; i < BUFFER_SIZE; i++) {
AVIStreamWrite(pStream, i, 1, &buffer[i], sizeof(BITMAPINFOHEADER), AVIIF_KEYFRAME, NULL, NULL);
}
AVIStreamClose(pStream);
AVIFileExit();
ReleaseDC(NULL, hDC);
DeleteDC(hMemDC);
DeleteObject(hBitmap);
return 0;
}
Am I doing this right? I am new to C++, so I am not sure if this is what I should be doing.

You can use the function AVIStreamOpenFromFile to open the avi file as stream, that will give the pointer to PAVISTREAM. So, not necessary to call the AVIFileOpen function.

Related

Create Device Context with Icon and transparent background

I'm trying to get a image with HICON but the background is not transparent. How can I make it transparent? I need a winapi example because the code is in Dart, but it has all the windows calls/functions.
I've tried different version I've found on the internet but it didn't worked. I can access icon mask if that can help for a solution.
Current code:
var icon = SendMessage(hWnd, WM_GETICON, 2, 0); // ICON_SMALL2 - User Made Apps
if (icon == 0) icon = GetClassLongPtr(hWnd, -14); // GCLP_HICON - Microsoft Win Apps
final int hScreen = GetDC(hWnd);
final int hDC = CreateCompatibleDC(hScreen);
final int hBitmap = CreateCompatibleBitmap(hScreen, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
SelectObject(hDC, hBitmap);
// SetBkMode(hDC, TRANSPARENT); - Works for text only
// PatBlt(hDC, 0, 0, 545, 850, WHITENESS); - only white/black;
DrawIconEx(hDC, 0, 0, icon, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), NULL, NULL, 3);
The icon is transparent:
Even if I don't draw the icon, the output is a black square.
Can you suggest how to remove the background? In basic winapi calls. The code can be in cpp if it doesn't use special classes from libraries, I can use only dllCalls
Here is full working code:
// ignore_for_file: depend_on_referenced_packages, non_constant_identifier_names, avoid_print, unrelated_type_equality_checks
import 'dart:ffi';
import 'dart:io';
import 'package:win32/win32.dart';
import 'package:ffi/ffi.dart';
int enumWindowsProc(int hWnd, int lparam) {
if (IsWindowVisible(hWnd) == FALSE) return TRUE;
final length = GetWindowTextLength(hWnd);
if (length == 0) return TRUE;
var icon = SendMessage(hWnd, WM_GETICON, 2, 0); // ICON_SMALL2 - User Made Apps
if (icon == 0) icon = GetClassLongPtr(hWnd, -14); // GCLP_HICON - Microsoft Win Apps
if (icon == 0) {
icon = 0;
return 1;
}
final int hScreen = GetDC(hWnd);
final int hDC = CreateCompatibleDC(hScreen);
final int hBitmap = CreateCompatibleBitmap(hScreen, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
SelectObject(hDC, hBitmap);
SetBkMode(hDC, TRANSPARENT); //- Works for text only
PatBlt(hDC, 0, 0, GetSystemMetrics(SM_CXICON) ~/ 2, GetSystemMetrics(SM_CYICON), WHITENESS); // test, half white half black.
DrawIconEx(hDC, 0, 0, icon, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), NULL, NULL, 3);
//Turn to bytes
final bmpScreen = calloc<BITMAP>();
GetObject(hBitmap, sizeOf<BITMAP>(), bmpScreen);
final bitmapFileHeader = calloc<BITMAPFILEHEADER>();
final bitmapInfoHeader = calloc<BITMAPINFOHEADER>()
..ref.biSize = sizeOf<BITMAPINFOHEADER>()
..ref.biWidth = bmpScreen.ref.bmWidth
..ref.biHeight = bmpScreen.ref.bmHeight
..ref.biPlanes = 1
..ref.biBitCount = 32
..ref.biCompression = BI_RGB;
final dwBmpSize = ((bmpScreen.ref.bmWidth * bitmapInfoHeader.ref.biBitCount + 31) / 32 * 4 * bmpScreen.ref.bmHeight).toInt();
final lpBitmap = calloc<Uint8>(dwBmpSize);
GetDIBits(hDC, hBitmap, 0, bmpScreen.ref.bmHeight, lpBitmap, bitmapInfoHeader.cast(), DIB_RGB_COLORS);
final dwSizeOfDIB = dwBmpSize + sizeOf<BITMAPFILEHEADER>() + sizeOf<BITMAPINFOHEADER>();
bitmapFileHeader.ref.bfOffBits = sizeOf<BITMAPFILEHEADER>() + sizeOf<BITMAPINFOHEADER>();
bitmapFileHeader.ref.bfSize = dwSizeOfDIB;
bitmapFileHeader.ref.bfType = 0x4D42; // BM
var b = BytesBuilder();
b.add(Pointer<Uint8>.fromAddress(bitmapFileHeader.address).asTypedList(sizeOf<BITMAPFILEHEADER>()));
b.add(Pointer<Uint8>.fromAddress(bitmapInfoHeader.address).asTypedList(sizeOf<BITMAPINFOHEADER>()));
b.add(lpBitmap.asTypedList(dwBmpSize));
// I need the Bitmap in Bytes, I save it to file just for debugging.
//capture?.icon = b.takeBytes();
//
DeleteDC(hDC);
DeleteObject(hBitmap);
free(bmpScreen);
free(bitmapFileHeader);
free(bitmapInfoHeader);
free(lpBitmap);
Directory current = Directory.current;
File("${current.path}/imgs/i_${icon.toString()}.bmp").writeAsBytes(b.takeBytes());
return 1;
}
void main() {
final imgs = "${Directory.current.path}/imgs";
if (Directory(imgs).exists() == true) {
Directory(imgs).deleteSync(recursive: true);
}
final wndProc = Pointer.fromFunction<EnumWindowsProc>(enumWindowsProc, 0);
EnumWindows(wndProc, 0);
}
final _user32 = DynamicLibrary.open('user32.dll');
int DrawIconEx(int hdc, int xLeft, int yTop, int hIcon, int cxWidth, int cyWidth, int istepIfAniCur, int hbrFlickerFreeDraw, int diFlags) =>
_DrawIconEx(hdc, xLeft, yTop, hIcon, cxWidth, cyWidth, istepIfAniCur, hbrFlickerFreeDraw, diFlags);
final _DrawIconEx = _user32.lookupFunction<
Int32 Function(IntPtr hdc, Int32 xLeft, Int32 yTop, IntPtr hIcon, Int32 cxWidth, Int32 cyWidth, Uint32 istepIfAniCur, IntPtr hbrFlickerFreeDraw, Uint32 diFlags),
int Function(int hdc, int xLeft, int yTop, int hIcon, int cxWidth, int cyWidth, int istepIfAniCur, int hbrFlickerFreeDraw, int diFlags)>('DrawIconEx');
final _gdi32 = DynamicLibrary.open('gdi32.dll');
int PatBlt(int hdc, int x, int y, int w, int h, int rop) => _PatBlt(hdc, x, y, w, h, rop);
final _PatBlt =
_gdi32.lookupFunction<Int32 Function(IntPtr hdc, Int32 x, Int32 y, Int32 w, Int32 h, Uint32 rop), int Function(int hdc, int x, int y, int w, int h, int rop)>('PatBlt');
Found a even better solution, works with buffer and write to file, alpha channel and everything :)
https://github.com/pelayomendez/exe-icon-extractor/blob/master/src/module.cc
#include <tchar.h>
#include <iostream>
#include <windows.h>
#include <fstream>
#include <cassert>
using namespace std;
// Check windows
#if _WIN32 || _WIN64
#if _WIN64
#define ENV64BIT
#else
#define ENV32BIT
#endif
#endif
// Check GCC
#if __GNUC__
#if __x86_64__ || __ppc64__
#define ENV64BIT
#else
#define ENV32BIT
#endif
#endif
typedef struct
{
WORD idReserved; // must be 0
WORD idType; // 1 = ICON, 2 = CURSOR
WORD idCount; // number of images (and ICONDIRs)
// ICONDIR [1...n]
// ICONIMAGE [1...n]
} ICONHEADER;
//
// An array of ICONDIRs immediately follow the ICONHEADER
//
typedef struct
{
BYTE bWidth;
BYTE bHeight;
BYTE bColorCount;
BYTE bReserved;
WORD wPlanes; // for cursors, this field = wXHotSpot
WORD wBitCount; // for cursors, this field = wYHotSpot
DWORD dwBytesInRes;
DWORD dwImageOffset; // file-offset to the start of ICONIMAGE
} ICONDIR;
//
// After the ICONDIRs follow the ICONIMAGE structures -
// consisting of a BITMAPINFOHEADER, (optional) RGBQUAD array, then
// the color and mask bitmap bits (all packed together
//
typedef struct
{
BITMAPINFOHEADER biHeader; // header for color bitmap (no mask header)
//RGBQUAD rgbColors[1...n];
//BYTE bXOR[1]; // DIB bits for color bitmap
//BYTE bAND[1]; // DIB bits for mask bitmap
} ICONIMAGE;
//
// Return the number of BYTES the bitmap will take ON DISK
//
static UINT NumBitmapBytes(BITMAP* pBitmap)
{
int nWidthBytes = pBitmap->bmWidthBytes;
// bitmap scanlines MUST be a multiple of 4 bytes when stored
// inside a bitmap resource, so round up if necessary
if (nWidthBytes & 3)
nWidthBytes = (nWidthBytes + 4) & ~3;
return nWidthBytes * pBitmap->bmHeight;
}
static BOOL GetIconBitmapInfo(HICON hIcon, ICONINFO* pIconInfo, BITMAP* pbmpColor, BITMAP* pbmpMask)
{
if (!GetIconInfo(hIcon, pIconInfo))
return FALSE;
if (!GetObject(pIconInfo->hbmColor, sizeof(BITMAP), pbmpColor))
return FALSE;
if (!GetObject(pIconInfo->hbmMask, sizeof(BITMAP), pbmpMask))
return FALSE;
return TRUE;
}
//
// Write one icon directory entry - specify the index of the image
//
static void WriteIconDirectoryEntry(BYTE* buffer, int* pBufferOffset, int nIdx, HICON hIcon, UINT nImageOffset)
{
ICONINFO iconInfo;
ICONDIR iconDir;
BITMAP bmpColor;
BITMAP bmpMask;
UINT nColorCount;
UINT nImageBytes;
GetIconBitmapInfo(hIcon, &iconInfo, &bmpColor, &bmpMask);
nImageBytes = NumBitmapBytes(&bmpColor) + NumBitmapBytes(&bmpMask);
if (bmpColor.bmBitsPixel >= 8)
nColorCount = 0;
else
nColorCount = 1 << (bmpColor.bmBitsPixel * bmpColor.bmPlanes);
// Create the ICONDIR structure
iconDir.bWidth = (BYTE)bmpColor.bmWidth;
iconDir.bHeight = (BYTE)bmpColor.bmHeight;
iconDir.bColorCount = nColorCount;
iconDir.bReserved = 0;
iconDir.wPlanes = bmpColor.bmPlanes;
iconDir.wBitCount = bmpColor.bmBitsPixel;
iconDir.dwBytesInRes = sizeof(BITMAPINFOHEADER) + nImageBytes;
iconDir.dwImageOffset = nImageOffset;
// Write to disk
memcpy(&buffer[*pBufferOffset], &iconDir, sizeof(iconDir));
(*pBufferOffset) += sizeof(iconDir);
// Free resources
DeleteObject(iconInfo.hbmColor);
DeleteObject(iconInfo.hbmMask);
}
static UINT WriteIconData(BYTE* buffer, int* pBufferOffset, HBITMAP hBitmap)
{
BITMAP bmp;
int i;
BYTE* pIconData;
UINT nBitmapBytes;
GetObject(hBitmap, sizeof(BITMAP), &bmp);
nBitmapBytes = NumBitmapBytes(&bmp);
pIconData = (BYTE*)malloc(nBitmapBytes);
GetBitmapBits(hBitmap, nBitmapBytes, pIconData);
// bitmaps are stored inverted (vertically) when on disk..
// so write out each line in turn, starting at the bottom + working
// towards the top of the bitmap. Also, the bitmaps are stored in packed
// in memory - scanlines are NOT 32bit aligned, just 1-after-the-other
for (i = bmp.bmHeight - 1; i >= 0; i--)
{
memcpy(&buffer[*pBufferOffset], pIconData + (i * bmp.bmWidthBytes), bmp.bmWidthBytes);
(*pBufferOffset) += bmp.bmWidthBytes;
// extend to a 32bit boundary (in the file) if necessary
if (bmp.bmWidthBytes & 3)
{
DWORD padding = 0;
memcpy(&buffer[*pBufferOffset], &padding, 4 - bmp.bmWidthBytes);
(*pBufferOffset) += 4 - bmp.bmWidthBytes;
}
}
free(pIconData);
return nBitmapBytes;
}
//
// Create a .ICO file, using the specified array of HICON images
//
BOOL SaveIcon3(HICON hIcon[], int nNumIcons, BYTE* buffer, int* pWritten)
{
int i;
int* pImageOffset = (int*)malloc(nNumIcons * sizeof(int));
int bufferOffset = 0;
if (hIcon == 0 || nNumIcons < 1)
return 0;
//
// Write the iconheader first of all
//
ICONHEADER iconheader;
// Setup the icon header
iconheader.idReserved = 0; // Must be 0
iconheader.idType = 1; // Type 1 = ICON (type 2 = CURSOR)
iconheader.idCount = nNumIcons; // number of ICONDIRs
// Write the header to disk
memcpy(&(buffer[bufferOffset]), &iconheader, sizeof(iconheader));
bufferOffset += sizeof(iconheader);
//
// Leave space for the IconDir entries
//
bufferOffset += sizeof(ICONDIR) * nNumIcons;
//
// Now write the actual icon images!
//
for (i = 0; i < nNumIcons; i++) {
ICONINFO iconInfo;
BITMAP bmpColor, bmpMask;
// GetIconBitmapInfo
GetIconBitmapInfo(hIcon[i], &iconInfo, &bmpColor, &bmpMask);
// record the file-offset of the icon image for when we write the icon directories
pImageOffset[i] = bufferOffset;
// WriteIconImageHeader
BITMAPINFOHEADER biHeader;
UINT nImageBytes;
// calculate how much space the COLOR and MASK bitmaps take
nImageBytes = NumBitmapBytes(&bmpColor) + NumBitmapBytes(&bmpMask);
// write the ICONIMAGE to disk (first the BITMAPINFOHEADER)
ZeroMemory(&biHeader, sizeof(biHeader));
// Fill in only those fields that are necessary
biHeader.biSize = sizeof(biHeader);
biHeader.biWidth = bmpColor.bmWidth;
biHeader.biHeight = bmpColor.bmHeight * 2; // height of color+mono
biHeader.biPlanes = bmpColor.bmPlanes;
biHeader.biBitCount = bmpColor.bmBitsPixel;
biHeader.biSizeImage = nImageBytes;
// write the BITMAPINFOHEADER
memcpy(&(buffer[bufferOffset]), &biHeader, sizeof(biHeader));
bufferOffset += sizeof(biHeader);
// color and mask bitmaps
WriteIconData(buffer, &bufferOffset, iconInfo.hbmColor);
WriteIconData(buffer, &bufferOffset, iconInfo.hbmMask);
DeleteObject(iconInfo.hbmColor);
DeleteObject(iconInfo.hbmMask);
}
*pWritten = bufferOffset;
//
// Lastly, skip back and write the icon directories.
//
bufferOffset = sizeof(ICONHEADER);
for (i = 0; i < nNumIcons; i++)
{
WriteIconDirectoryEntry(buffer, &bufferOffset, i, hIcon[i], pImageOffset[i]);
}
free(pImageOffset);
return 1;
}
void main()
{
HICON hIconLarge;
HICON hIconSmall;
int extractIcon = ExtractIconExW(L"E:\\Program Files\\Microsoft VS Code Insiders\\Code - Insiders.exe", 0, &hIconLarge, &hIconSmall, 1);
if (extractIcon <= 0) {
std::cout << "No icon";
return;
}
BYTE buffer[(256 * 256) * 4]; // (256x256) Max Windows Icon Size x 4 bytes (32 bits)
int written;
SaveIcon3(&hIconLarge, 1, buffer, &written);
std::ofstream file;
file.open("E:/t.ico", std::ios_base::binary);
assert(file.is_open());
for (int i = 0; i < sizeof(buffer) / sizeof(buffer[0]); ++i)
file.write((char*)(buffer + i * sizeof(buffer[0])), sizeof(buffer[0]));
file.close();
}
Found a solution.
static BITMAP_AND_BYTES createAlphaChannelBitmapFromIcon(HICON hIcon) {
// Get the icon info
ICONINFO iconInfo = {0};
GetIconInfo(hIcon, &iconInfo);
// Get the screen DC
HDC dc = GetDC(NULL);
// Get icon size info
BITMAP bm = {0};
GetObject( iconInfo.hbmColor, sizeof( BITMAP ), &bm );
// Set up BITMAPINFO
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = bm.bmWidth;
bmi.bmiHeader.biHeight = -bm.bmHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
// Extract the color bitmap
int nBits = bm.bmWidth * bm.bmHeight;
int32_t* colorBits = new int32_t[nBits];
GetDIBits(dc, iconInfo.hbmColor, 0, bm.bmHeight, colorBits, &bmi, DIB_RGB_COLORS);
// Check whether the color bitmap has an alpha channel.
// (On my Windows 7, all file icons I tried have an alpha channel.)
BOOL hasAlpha = FALSE;
for (int i = 0; i < nBits; i++) {
if ((colorBits[i] & 0xff000000) != 0) {
hasAlpha = TRUE;
break;
}
}
// If no alpha values available, apply the mask bitmap
if (!hasAlpha) {
// Extract the mask bitmap
int32_t* maskBits = new int32_t[nBits];
GetDIBits(dc, iconInfo.hbmMask, 0, bm.bmHeight, maskBits, &bmi, DIB_RGB_COLORS);
// Copy the mask alphas into the color bits
for (int i = 0; i < nBits; i++) {
if (maskBits[i] == 0) {
colorBits[i] |= 0xff000000;
}
}
delete[] maskBits;
}
// Release DC and GDI bitmaps
ReleaseDC(NULL, dc);
::DeleteObject(iconInfo.hbmColor);
::DeleteObject(iconInfo.hbmMask);
// Create GDI+ Bitmap
Gdiplus::Bitmap* bmp = new Gdiplus::Bitmap(bm.bmWidth, bm.bmHeight, bm.bmWidth*4, PixelFormat32bppARGB, (BYTE*)colorBits);
BITMAP_AND_BYTES ret = {bmp, colorBits};
return ret;
}
Original post: https://stackoverflow.com/a/22885412/1456151
And also from PowerToys source code:
HBITMAP CreateBitmapFromIcon(_In_ HICON hIcon, _In_opt_ UINT width, _In_opt_ UINT height)
{
HBITMAP hBitmapResult = NULL;
// Create compatible DC
HDC hDC = CreateCompatibleDC(NULL);
if (hDC != NULL)
{
// Get bitmap rectangle size
RECT rc = { 0 };
rc.left = 0;
rc.right = (width != 0) ? width : GetSystemMetrics(SM_CXSMICON);
rc.top = 0;
rc.bottom = (height != 0) ? height : GetSystemMetrics(SM_CYSMICON);
// Create bitmap compatible with DC
BITMAPINFO BitmapInfo;
ZeroMemory(&BitmapInfo, sizeof(BITMAPINFO));
BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BitmapInfo.bmiHeader.biWidth = rc.right;
BitmapInfo.bmiHeader.biHeight = rc.bottom;
BitmapInfo.bmiHeader.biPlanes = 1;
BitmapInfo.bmiHeader.biBitCount = 32;
BitmapInfo.bmiHeader.biCompression = BI_RGB;
HDC hDCBitmap = GetDC(NULL);
HBITMAP hBitmap = CreateDIBSection(hDCBitmap, &BitmapInfo, DIB_RGB_COLORS, NULL, NULL, 0);
ReleaseDC(NULL, hDCBitmap);
if (hBitmap != NULL)
{
// Select bitmap into DC
HBITMAP hBitmapOld = (HBITMAP)SelectObject(hDC, hBitmap);
if (hBitmapOld != NULL)
{
// Draw icon into DC
if (DrawIconEx(hDC, 0, 0, hIcon, rc.right, rc.bottom, 0, NULL, DI_NORMAL))
{
// Restore original bitmap in DC
hBitmapResult = (HBITMAP)SelectObject(hDC, hBitmapOld);
hBitmapOld = NULL;
hBitmap = NULL;
}
if (hBitmapOld != NULL)
{
SelectObject(hDC, hBitmapOld);
}
}
if (hBitmap != NULL)
{
DeleteObject(hBitmap);
}
}
DeleteDC(hDC);
}
return hBitmapResult;
}

Capture pixel data from only a specified window

I want the code below to take a screenshot of a specified window only, becuse this way BitBlt is faster.
The code below takes a screenshot of a window, specified by the name of window, loads the pixel data in a buffer and then re-draws the picture on your screen just to prove the copying worked.
I'd like to take screenshots of browser windows like Google Chrome, but it doesn't seem to work. It draws a black rectangle on my screen with the correct dimensions of the window.
Seems to be working all the time with the window of Minecraft.
Also worked with the Tor Browser.
I noticed that after querying window info, minecraft's window had no child-windows, but when it didn't work with the others, all of them had multiple child-windows.
#include<iostream>
#include<Windows.h>
#include<vector>
using namespace std;
int main() {
HWND wnd = FindWindow(NULL, "Minecraft 1.15.1");//Name of window to be screenshoted
if (!wnd) {
std::cout << "e1\n";
std::cin.get();
return 0;
}
WINDOWINFO wi = { 0 };
wi.cbSize = sizeof(WINDOWINFO);
GetWindowInfo(wnd, &wi);
RECT rect;
GetWindowRect(wnd, &rect);
int width = wi.rcClient.right - wi.rcClient.left;
int height = wi.rcClient.bottom - wi.rcClient.top;
cout << width << height;
/////Fetch window info^^^^^^^^
BYTE* ScreenData = new BYTE[4 * width*height];
// copy screen to bitmap
HDC hScreen = GetWindowDC(wnd);
HDC hDC = CreateCompatibleDC(hScreen);
HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, width, height);
HGDIOBJ old_obj = SelectObject(hDC, hBitmap);
BitBlt(hDC, 0, 0, width, height, hScreen, 0, 0, SRCCOPY);
SelectObject(hDC, old_obj);
BITMAPINFO bmi = { 0 };
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
std::cout << GetDIBits(hDC, hBitmap, 0, 0, NULL, &bmi, DIB_RGB_COLORS)<<endl;
//std::cout << bmi.bmiHeader.biHeight<< " "<< bmi.bmiHeader.biWidth<<endl;
BYTE*buffer = new BYTE[4* bmi.bmiHeader.biHeight*bmi.bmiHeader.biWidth];
bmi.bmiHeader.biHeight *= -1;
std::cout<<GetDIBits(hDC, hBitmap, 0, bmi.bmiHeader.biHeight, buffer, &bmi, DIB_RGB_COLORS)<<endl;//DIB_PAL_COLORS
/////Load window pixels into a buffer^^^^^^^^
POINT p;
int r = 0;
int g = 0;
int b = 0;
int x = 0;
int y = 0;
HDC sc = GetDC(NULL);
COLORREF color;
while (true) {
if ((y*-1) == bmi.bmiHeader.biHeight+1 && x == bmi.bmiHeader.biWidth-1) { break; }
r = (int)buffer[4 * ((y*bmi.bmiHeader.biWidth) + x)+2];
g = (int)buffer[4 * ((y*bmi.bmiHeader.biWidth) + x)+1];
b = (int)buffer[4 * ((y*bmi.bmiHeader.biWidth) + x) ];
color = RGB(r, g, b);
SetPixel(sc, x, y, color);
x++;
if (x == bmi.bmiHeader.biWidth) {
y++;
x = 0;
}
}
/////Prove that the copying was successful and buffer is full^^^^^^^^
Sleep(5000);
std::cout << "fin\n";
std::cin.get();
return 0;
}
I think the problem is the order you're doing things.
Before you put the bitmap on the clipboard, you should select it out of your memory device context.
Once you put the bitmaps on the clipboard, you no longer own it, so you shouldn't try to delete it.
The best way to do that is probably to move your // clean up section before the // save bitmap to clipboard section and to eliminate your DelectObject(hBitmap) statement. So the tail end of your code should probably be:
BitBlt(hDC, 0, 0, width, height, hScreen, 0, 0, SRCCOPY);
// clean up
SelectObject(hDC, old_obj); // selects hBitmap out of hDC
DeleteDC(hDC);
ReleaseDC(NULL, hScreen);
// save bitmap to clipboard
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(CF_BITMAP, hBitmap); // clipboard now owns the bitmap
CloseClipboard();
If you still have a problem after those changes, I would check the return value of the SetClipboardData call. If that's failing, GetLastError may give a clue.

Screenshot code works but goes on taking RAM and crashes

I'm trying to make a program which makes screenshot of the entire desktop or a specific window, and draw it in a SFML window. Initially it goes fine but after 10 seconds it stop capturing. I also noticed that it go on consuming RAM even though we talk about only 20kb per second. I tried to join code found around the web. When it stops working it prints "2" and then infinite "1", from the code you quickly realize where these errors are.
#include <SFML/Graphics.hpp>
#include <Windows.h>
HBITMAP ScreenShot(HWND hParent, int x, int y, int nWidth, int nHeight)
{
//Get a DC from the parent window
HDC hDC = GetDC(hParent);
//Create a memory DC to store the picture to
HDC hMemDC = CreateCompatibleDC(hDC);
//Create the actual picture
HBITMAP hBackground = CreateCompatibleBitmap(hDC, nWidth, nHeight);
//Select the object and store what we got back
HBITMAP hOld = (HBITMAP)SelectObject(hMemDC, hBackground);
//Now do the actually painting into the MemDC (result will be in the selected object)
//Note: We ask to return on 0,0,Width,Height and take a blit from x,y
BitBlt(hMemDC, 0, 0, nWidth, nHeight, hDC, x, y, SRCCOPY);
//Restore the old bitmap (if any)
SelectObject(hMemDC, hOld);
//Release the DCs we created
ReleaseDC(hParent, hMemDC);
ReleaseDC(hParent, hDC);
//Return the picture (not a clean method, but you get the drill)
return hBackground;
}
bool SFMLLoadHBitmapAsImage(HBITMAP hBitmap, sf::Image *pPicture)
{
HWND hParent = FindWindow(NULL, TEXT("Calculator"));
//if (hParent == NULL)printf("%s", "w");
//Create a DC to get hBitmap information
HDC hDC = GetDC(hParent);
//Create BITMAPINFO variable, set size
BITMAPINFO MyBMInfo = { 0 };
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
//Get the BITMAPINFO structure from the bitmap
if (0 == GetDIBits(hDC, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS))
{
printf("%s", "1");
return false;
}
//Create the bitmap pixel array each element is [b,g,r]
BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage];
//Setting up the structure of the buffer to be received
MyBMInfo.bmiHeader.biCompression = BI_RGB; // No-compression
//Now get the actual data from the picture
if (0 == GetDIBits(hDC, hBitmap, 0, MyBMInfo.bmiHeader.biHeight, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS))
{
printf("%s", "2");
return false;
}
//Now create an array of SFML pixels we want to fill
sf::Uint8 *lpPixelWithAlpha = new sf::Uint8[MyBMInfo.bmiHeader.biSizeImage +
(MyBMInfo.bmiHeader.biSizeImage / 3) / 3]; //Add room for alpha
//Loop through each pixel, with steps of four RGBA!
for (int x = 0; x < MyBMInfo.bmiHeader.biSizeImage; x += 4)
{
lpPixelWithAlpha[x] = lpPixels[x + 2]; //lpPixels = r
lpPixelWithAlpha[x + 1] = lpPixels[x + 1]; //lpPixels = g
lpPixelWithAlpha[x + 2] = lpPixels[x]; //lpPixels = b
lpPixelWithAlpha[x + 3] = 255; //Nada alpha (just to adjust if you like)
}
//Remove old DIBsection
delete[] lpPixels;
//Load picture, now with correct pixels and alpha channel
pPicture->create(MyBMInfo.bmiHeader.biWidth,
MyBMInfo.bmiHeader.biHeight, lpPixelWithAlpha);
//Remove the pixels with alphachannel
delete[] lpPixelWithAlpha;
//Release the DC
ReleaseDC(hParent, hDC);//::GDW()
//Notify ok!
return true;
}
int main()
{
.....
hBitmap = ScreenShot(FindWindow(NULL, TEXT("Calculator")), 0, 0, 640, 400);
SFMLLoadHBitmapAsImage(hBitmap, &picture);
.....
}

Saving Image to Memory

I have an dev-c++ Application which makes an Screenshot and writes it into an File. Now I want to write the image into an Variable/Stream. Originally I used three Writefile Functions, which write the header, the info and the hbitmap into an file. Now I want to save the data not to the file, but to an Stream, so I can use it for further processing. The Code I use is this:
/* <Include> */
#include <windows.h>
#include <iostream>
#include <sstream>
/* </Include> */
/* <Const> */
const char *AppName="Yeah";
using namespace std;
/* </Const> */
/* <Function> */
void SaveScreen(HWND pScreen, stringstream Path)
{
int Width = GetSystemMetrics(SM_CXSCREEN);//1280;
int Height = GetSystemMetrics(SM_CYSCREEN);//1024;
HDC hdcScreen;
HBITMAP hbmScreen;
//---------------Bitmap Informationen
BITMAPINFO infobmp;
infobmp.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
infobmp.bmiHeader.biWidth = Width;
infobmp.bmiHeader.biHeight = Height;
infobmp.bmiHeader.biPlanes = 1;
infobmp.bmiHeader.biBitCount = 24;
infobmp.bmiHeader.biCompression = 0;
infobmp.bmiHeader.biSizeImage = 0;
infobmp.bmiHeader.biXPelsPerMeter = 0;
infobmp.bmiHeader.biYPelsPerMeter = 0;
infobmp.bmiHeader.biClrUsed = 0;
infobmp.bmiHeader.biClrImportant = 0;
int* bitmap = new int[Width*Height*3];
BITMAPFILEHEADER bfheader;
bfheader.bfType = 19778;
bfheader.bfSize = sizeof(BITMAPFILEHEADER) + Width*Height*3 + sizeof(BITMAPINFOHEADER);
bfheader.bfReserved1 = 0;
bfheader.bfReserved2 = 0;
bfheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
//Bitmap ----------------------- Informationen
hdcScreen = GetWindowDC(pScreen);
hbmScreen = CreateCompatibleBitmap(hdcScreen, Width, Height);
// tempor?rer DC
HDC hdcTemp = CreateCompatibleDC(hdcScreen);
// Bitmap reinselektieren
HBITMAP hbmOld = (HBITMAP)SelectObject(hdcTemp, hbmScreen);
// Inhalt von Desktop ?bertragen
BitBlt(hdcTemp, 0, 0, Width, Height, hdcScreen, 0, 0, SRCCOPY);
int iResult = GetDIBits(hdcTemp, hbmScreen, 0, Height, bitmap, &infobmp, DIB_RGB_COLORS);
// aufr?umen
SelectObject(hdcTemp, hbmOld);
DeleteObject(hbmScreen);
DeleteDC(hdcTemp);
// HANDLE hfile = CreateFile(Path, GENERIC_WRITE, 0, 0, OPEN_ALWAYS, 0, 0);
//Datei Schreiben
DWORD word;
WriteFile(Path, &bfheader, 14, &word, NULL);
WriteFile(Path, &infobmp, 40,& word, NULL);
WriteFile(Path, bitmap, Width*Height*3, &word,NULL);
// Path = &bfheader & &infobmp & bitmap;
ReleaseDC(pScreen, hdcScreen);
// CloseHandle(hfile);
delete[] bitmap;
}
/* </Function> */
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hWnd = FindWindow(NULL, AppName);
stringstream ms;
SaveScreen(hWnd, ms);
return 0;
}
Can someone please show me what I am doing wrong?
You can create a structure like this:
struct ScreenShotBuffer
{
BITMAPFILEHEADER bfheader;
BITMAPINFO infobmp;
int* bitmap;
};
Then create a global variable using that structure.
struct ScreenShotBuffer myScreenShot;
Anyway you are allocating the "memory" to hold the data using malloc.
So you can just use these three lines instead of WriteBuffer() :
myScreenShot.bfheader=bfheader;
myScreenShot.infobmp=infobmp;
myScreenShot.bitmap=bitmap;

array[byte] to HBITMAP or CBitmap

I have an array of bytes (which I read through a stream directly from a .bmp and then store as a BLOB in a database) which I want to display as icons in a CImageList. Therefore I want to somehow load my data into an HBITMAP or CBitmap. I have done it like this up to now, reading from a file:
hPic = (HBITMAP)LoadImage(NULL, strPath, IMAGE_BITMAP, dwWidth, dwHeight, LR_LOADFROMFILE | LR_VGACOLOR);
...
CBitmap bitmap;
bitmap.Attach(hPicRet);
But obviously, that only works for files, but not for byte-arrays. How can I get the same result, but reading from an array of byte?
Edit:
Note that my array does not contain just the colour information, but rather the complete file as it is written on disk, including all headers and meta-data. It seems to me that discarding all that information is a bad idea.
Assuming you have the information loaded into a BYTE array named bytes....
BITMAPFILEHEADER* bmfh;
bmfh = (BITMAPFILEHEADER*)bytes;
BITMAPINFOHEADER* bmih;
bmih = (BITMAPINFOHEADER*)(bytes + sizeof(BITMAPFILEHEADER));
BITMAPINFO* bmi;
bmi = (BITMAPINFO*)bmih;
void* bits;
bits = (void*)(bytes + bmfh->bfOffBits);
HDC hdc = ::GetDC(NULL);
HBITMAP hbmp = CreateDIBitmap(hdc, bmih, CBM_INIT, bits, bmi, DIB_RGB_COLORS) ;
::ReleaseDC(NULL, hdc);
It's a little messy and could use a hefty dose of error checking, but the basic idea is sound.
Following sample could help you.
BITMAPINFO bmInfo;
BITMAPINFOHEADER &bmInfohdr = (BITMAPINFOHEADER)bmInfo.bmiHeader;
bmInfohdr.biSize = 40 + 255; //I think it's not of use
bmInfohdr.biWidth = x;
bmInfohdr.biHeight = y;
bmInfohdr.biPlanes=1;
bmInfohdr.biBitCount=8;
bmInfohdr.biCompression=0;
bmInfohdr.biSizeImage=0;
bmInfohdr.biXPelsPerMeter = 0;
bmInfohdr.biYPelsPerMeter = 0;
bmInfohdr.biClrUsed = 0;
bmInfohdr.biClrImportant = 0;
// should I allocate memory further than the
// bmColors[1]?? anyway the compiler gives an
// error for type mismatch!
//bmInfo.bmiColors = (RGBQUAD *)
malloc(sizeof(RGBQUAD) * 256);
// here I define the 256 graylevel palette
for (int i=0; i<256; i++)
{
bmInfo.bmiColors[i].rgbRed = i;
bmInfo.bmiColors[i].rgbGreen = i;
bmInfo.bmiColors[i].rgbBlue = i;
}
BYTE *matrix;
matrix = (BYTE*)malloc(size*sizeof(BYTE));
// here I put the BYTE values of the pixels
CDC *pdcDest = this->GetDC();
HBITMAP hBmp = CreateDIBitmap( pdcDest->m_hDC,
&bmInfohdr,
CBM_INIT,
matrix,
&bmInfo,
DIB_RGB_COLORS);
m_bmpBitmap.Attach( hBmp );
Something like this worked for me:
int bitmap[WX*WY]; // truecolor bitmap data
BITMAPINFO bm = { sizeof(BITMAPINFOHEADER), WX, WY, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
HBITMAP bmp = CreateDIBSection( GetDC(win), &bm, DIB_RGB_COLORS, (void**)&bitmap, 0,0 );
(This is specifically configured for 32-bit colors, but you can specify any kind).
Ok, here's a complete example: http://nishi.dreamhosters.com/u/so_bmp_v0.zip
#include <stdio.h>
#include <windows.h>
#pragma comment(lib,"gdi32.lib")
#pragma comment(lib,"user32.lib")
char buf[1<<22];
int main( int argc, char **argv ) {
FILE* f = fopen( "winnt.bmp", "rb" ); if( f==0 ) return 1;
fread( buf, 1,sizeof(buf), f );
fclose(f);
BITMAPFILEHEADER& bfh = (BITMAPFILEHEADER&)buf[0];
BITMAPINFO& bi = (BITMAPINFO&)buf[sizeof(BITMAPFILEHEADER)];
BITMAPINFOHEADER& bih = bi.bmiHeader;
char* bitmap = &buf[bfh.bfOffBits];
int WX=1024, WY=512; // window's width/height
int SX=bih.biWidth, SY=bih.biHeight;
HWND win = CreateWindow( "STATIC", "Bitmap test", 0x90C0, 0,0, WX,WY, 0,0, GetModuleHandle(0), 0 );
MSG msg;
PAINTSTRUCT ps;
HDC DC = GetDC(win); // window's DC
HBITMAP dib = CreateDIBitmap( DC, &bih, CBM_INIT, bitmap, &bi, DIB_RGB_COLORS );
HDC dibDC = CreateCompatibleDC( DC ); SelectObject( dibDC, dib );
ShowWindow( win, SW_SHOWNOACTIVATE );
SetFocus( win );
while( GetMessage(&msg,win,0,0) ) {
int m = msg.message;
if( m==WM_PAINT ) {
DC = BeginPaint( win, &ps );
StretchBlt( DC, 0,0,WX,WY, dibDC,0,0,SX,SY, SRCCOPY );
EndPaint( win, &ps );
} else if( (m==WM_KEYDOWN) || (m==WM_SYSKEYDOWN) ) {
break;
} else {
DispatchMessage(&msg);
}
}
return 0;
}