C++ Creating enhanced metafile results in an empty file - c++

I'm trying to create an enhanced metafile like this:
// Obtain a handle to a reference device context.
HDC hdcRef = GetDC(hwnd);
// Determine the picture frame dimensions.
int iWidthMM = GetDeviceCaps(hdcRef, HORZSIZE);
int iHeightMM = GetDeviceCaps(hdcRef, VERTSIZE);
int iWidthPels = GetDeviceCaps(hdcRef, HORZRES);
int iHeightPels = GetDeviceCaps(hdcRef, VERTRES);
// Retrieve the coordinates of the client
// rectangle, in pixels.
RECT rect;
GetClientRect(hwnd, &rect);
// Convert client coordinates to .01-mm units.
// Use iWidthMM, iWidthPels, iHeightMM, and
// iHeightPels to determine the number of
// .01-millimeter units per pixel in the x-
// and y-directions.
rect.left = (rect.left * iWidthMM * 100)/iWidthPels;
rect.top = (rect.top * iHeightMM * 100)/iHeightPels;
rect.right = (rect.right * iWidthMM * 100)/iWidthPels;
rect.bottom = (rect.bottom * iHeightMM * 100)/iHeightPels;
// Create the metafile device context.
CreateEnhMetaFile(hdcRef, (LPTSTR)"temp.emf", &rect, NULL);
// Release the reference device context.
ReleaseDC(hwnd, hdcRef);
Took the code here
All I got in the end is some 0 bytes non-extension file with strangely encoded name, smth like 整灭攮晭.
What can be the problem?
P.S. Also, I'm calling it in a mixed-mode app, from c# through a c++/cli object.
EDIT The problem with the strange encoding is solved, but the file created is still 0 bytes length. How can it be solved?

The cast is the problem, don't use casts unless you really have to.
Amazing that you got that cast from a Microsoft web site! You have to wonder about the quality of people MS hire. But in their code it's not wrong just superfluous. When you translated it to your code it is wrong.
CreateEnhMetaFile(hdcRef, _T("temp.emf"), &rect, NULL);
The _T macro is the official way to write a string literal that will be interpreted as either a Unicode string or a ANSI string depending on your compiler settings.

Related

PrintWindow and BitBlt of hidden windows

My program is taking screenshots of other application windows to automate some tasks on them. Those windows can be hidden offscreen or obscured by other windows from time to time.
To reduce clutter, I have removed any error checking from the code listings. I am preparing the both types of screenshots with
// Get size of the target window.
RECT clientRect;
GetClientRect(hwnd, &clientRect);
int width = clientRect.right - clientRect.left;
int height = clientRect.bottom - clientRect.top;
// Create a memory device context.
HDC windowDC = GetDC(hwnd);
HDC memoryDC = CreateCompatibleDC(windowDC);
// Create a bitmap for rendering.
BITMAPINFO bitmapInfo;
ZeroMemory(&bitmapInfo, sizeof(BITMAPINFO));
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.bmiHeader.biWidth = width;
bitmapInfo.bmiHeader.biHeight = -height;
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biBitCount = 32;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
bitmapInfo.bmiHeader.biSizeImage = width * height * 4;
RGBQUAD* buffer;
HBITMAP bitmap = CreateDIBSection(windowDC, &bitmapInfo, DIB_RGB_COLORS, (void**)&buffer, 0, 0);
HGDIOBJ previousObject = SelectOBject(memoryDC, bitmap);
then I am taking the actual screenshots with either
PrintWindow(hwnd, memoryDC, PW_CLIENTONLY);
GdiFlush();
or
UpdateWindow(hwnd);
BitBlt(memoryDC, 0, 0, width, height, windowDC, 0, 0, SRCCOPY);
GdiFlush();
then I copy the buffer contents to a vector
std::vector<RGBQUAD> pixels;
pixels.resize(width * height, { 0, 0, 0, 0 });
memcpy(&pixels[0], buffer, bitmapInfo.bmiHeader.biSizeImage);
and finally I am cleaning everything up with
ReleaseDC(hwnd, windowDC);
SelectObject(memoryDC, previousObject);
DeleteDC(memoryDC);
DeleteObject(bitmap);
I have a three of questions about the code above:
Do I need to call GdiFlush()? I read the documentation and did some Google research, but I am still not sure if it makes sense to call it or not.
Does the call to UpdateWindow() right before the BitBlt() make a difference? Does this help, so that the Device Context contents are "more up to date"?
Am I right in assuming that for PrintWindow() all the work is done from within the target application (increasing the target application's CPU usage), while BitBlt() is fully executed from within the calling thread (thus increasing the CPU usage of my own application)?
Under which circumstances might any of the above functions fail? I know that BitBlt() only works for hidden windows if Desktop Composition (DWM) is enabled, but on a very small set of systems (Windows 8/10) BitBlt() and PrintWindow() seem to fail for windows for which they work just fine on other systems (even though DWM is enabled). I could not spot any patterns as to why, though.
Any information is appreciated, thanks.
finally, after some hours of investigation, I found a solution for that issue:
It's sufficient to call the following command within the ACTIVATE event of the form to be imaged (example in VB coding):
Call SetWindowLong(me.hwnd, GWL_EXSTYLE, WS_EX_LAYERED)
Whereas this command is defined as follows:
Private Declare Function SetWindowLong Lib "User32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Const GWL_EXSTYLE = (-20)
Private Const WS_EX_LAYERED = &H80000
Please try this!
Best regards,
Bambi66
After more than two months I finally realized that this only occurs with the Windows update 1809 from late 2018. Apparently, Windows changed the way it handles clipping with that update so that the Device Context contents are no longer updated for parts of windows that are located offscreen.
To answer the individual questions:
1) GdiFlush doesn't seem to make a difference, at least from what I can tell so far.
2) Still not 100% sure about it, but I also think it doesn't make a difference.
3) Still no idea.
4) See answer above.

Editing bitmap in memory using C++

I have a two dimensional array of data that I want to display as an image.
The plan goes something like this -
Create a bitmap using CreateCompatibleBitmap (this results in a solid black bitmap and I can display this with no problems)
Edit the pixels of this bitmap to match my data
BitBlt the bitmap to the window
I think that I need a pointer to the place in memory where the pixel data begins. I've tried many different methods of doing this and googled it for 3 days and still haven't been able to even edit a single pixel.
Using a loop of SetPixel(HDC, x, y, Color) to set each pixel works but VERY slowly.
I have accomplished this in C# by locking the bitmap and editing the bits, but I am new to C++ and can't seem to figure out how to do something similar.
I have mostly been trying to use memset(p, value, length)
For "p" I have tried using the handle returned from CreateCompatibleBitmap, the DC for the bitmap, and the DC for the window. I have tried all sorts of values for the value and length.
I'm not sure if this is the right thing to use though.
I don't have to use a bitmap, that's just the only thing I know to do. Actually it would be awesome to find a way to directly change the main window's DC.
I do want to avoid libraries though. I am doing this purely for learning C++.
This took QUITE a bit of research so I'll post exactly how it is done for anyone else who may be looking.
This colors every pixel red.
hDC = BeginPaint(hWnd, &Ps);
const int
width = 400,
height = 400,
size = width * height * 3;
byte * data;
data = new byte[size];
for (int i = 0; i < size; i += 3)
{
data[i] = 0;
data[i + 1] = 0;
data[i + 2] = 255;
}
BITMAPINFOHEADER bmih;
bmih.biBitCount = 24;
bmih.biClrImportant = 0;
bmih.biClrUsed = 0;
bmih.biCompression = BI_RGB;
bmih.biWidth = width;
bmih.biHeight = height;
bmih.biPlanes = 1;
bmih.biSize = 40;
bmih.biSizeImage = size;
BITMAPINFO bmpi;
bmpi.bmiHeader = bmih;
SetDIBitsToDevice(hDC, 0, 0, width, height, 0, 0, 0, height, data, &bmpi, DIB_RGB_COLORS);
delete[] data;
memset can be used on the actually RGB information array (but you need to also know the format of the bitmap, if a pixel has 32 or 24 bits ).
From a bit of research on msdn, it seems that what you want to get is the BITMAP structure :
http://msdn.microsoft.com/en-us/library/k1sf4cx2.aspx
There you have the bmBits on which you can memset.
How to get there from your function ?
Well, CreateCompatibleBitmap returns a HBITMAP structure and it seems you can get BITMAP from HBITMAP with the following code :
BITMAP bmp;
GetObject(hBmp, sizeof(BITMAP), &bmp);
This however seems to get a you copy of the existing bitmap info, which only solves your memset problem (you can now set the bitmap information with memset, eventhou I don't see any other use for memeset besides making the bmp all white or black).
There should be a function that allows you to set the DC bites to a bitmap thou, so you should be able to use the new bitmap as a parameter.

Render Buffer on Screen in Windows

I'm searching for a way rendering a char buffer onto the content-area of a window. This is just pseudo but intended to demonstrate what I actually want to do:
char buffer[300][200][3]; // 300px x 200px x RGB bytes
// ... render stuff into buffer
FancyWindowsFunctionToRenderBufferOnWindow(my_hwnd, buffer, 300, 200, offset_x, offset_y);
Is there a way to do something similar?
I think you need to create a device independent bitmap (DIB). If you already have an array of pixels that is ready to be put on an application window, you may need to copy the whole array to the buffer allocated by the CreateDIBSection API and call BitBlt to transfer the DIB to the window. This is the only way I know to show a mere array of pixels as a visible picture on the computer screen on Win32 platform and it is highly complicated and difficult to understand.
Here are the steps I used to take to test things similar to what you want to do:
Creating DIB:
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = /* Width of your image buffer */
bmi.bmiHeader.biHeight = - /* Height of your image buffer */
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
HDC hDesktopDC = GetDC(GetDesktopWindow());
HBITMAP hDib = CreateDIBSection(hDesktopDC, &bmi, DIB_RGB_COLORS, (void **)&buffer, 0, 0);
if (buffer == NULL) { /* ERROR */ }
HDC hDibDC = CreateCompatibleDC(hDesktopDC);
HGDIOBJ hOldObj = SelectObject(hDibDC, hDib);
/* Copy your array of pixels to buffer allocated above. */
ReleaseDC(GetDesktopWindow(), hDesktopDC);
Implementing WM_PAINT event handler (the hWnd variable holds the window handle below):
case WM_PAINT:
PAINTSTRUCT paint;
HDC hWndDc = BeginPaint(hWnd, &paint);
BitBlt(hWndDC, 0, 0, /* Width of DIB */, /* Height of DIB */,
/* HDC of DIB (hDibDC in the above) */, 0, 0, SRCCOPY);
EndPaint(hWnd, &paint);
break;
I don't really expect the above code snippets would directly help you. If you are determined to use GDI functions like ones in the above snippets, I recommend you to read very carefully their API documents on MSDN. Because it is very tricky to properly release or delete DCs or GDI objects acquired during using the APIs.
It sounds like you have an image (raster) stored as an array of chars (which is an odd choice, since you'd usually want an array of unsigned chars for raw bitmap images).
If you meet certain alignment constraints, you can display your bitmap pretty directly with SetDIBits. You fill out a BITMAPINFO structure that describes the pixel format and image dimensions, and then you pass that along with your data to SetDIBits. It'll paint them to a DC. It can be a little tricky to get all the parameters right.
The alignment requirement is that each scanline must begin on a 4-byte boundary. If you don't meet that requirement, you'll get garbage similar to having the wrong stride. You can make a copy of the data with the correct alignment if necessary.

HBITMAP adding transparency / alpha channel

I'm trying to add transparency to a hbitmap object but it never draw anything :/
this is the code i use to draw the handle
HDC hdcMem = CreateCompatibleDC(hDC);
HBITMAP hbmOld = (HBITMAP) SelectObject(hdcMem, m_hBitmap);
BLENDFUNCTION blender = {AC_SRC_OVER, 0, (int) (2.55 * 100), AC_SRC_ALPHA}; // blend function combines opacity and pixel based transparency
AlphaBlend(hDC, x, y, rect.right - rect.left, rect.bottom - rect.top, hdcMem, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, blender);
SelectObject(hdcMem, hbmOld);
DeleteDC(hdcMem);
and this is the code which should add a alpha channel to the hbitmap
BITMAPINFOHEADER bminfoheader;
::ZeroMemory(&bminfoheader, sizeof(BITMAPINFOHEADER));
bminfoheader.biSize = sizeof(BITMAPINFOHEADER);
bminfoheader.biWidth = m_ResX;
bminfoheader.biHeight = m_ResY;
bminfoheader.biPlanes = 1;
bminfoheader.biBitCount = 32;
bminfoheader.biCompression = BI_RGB;
HDC windowDC = CreateCompatibleDC(0);
unsigned char* pPixels = new unsigned char[m_ResX * m_ResY * 4];
GetDIBits(windowDC, m_hBitmap, 0, m_ResY, pPixels, (BITMAPINFO*) &bminfoheader, DIB_RGB_COLORS); // load pixel info
// add alpha channel values of 255 for every pixel if bmp
for (int count = 0; count < m_ResX * m_ResY; count++)
{
pPixels[count * 4 + 3] = 255; <---- here i've tried to change the value to test different transparency, but it doesn't change anything
}
SetDIBits(windowDC, m_hBitmap, 0, GetHeight(), pPixels, (BITMAPINFO*) &bminfoheader, DIB_RGB_COLORS); // save the pixel info for later manipulation
DeleteDC(windowDC);
edit:
this is the code how I create the bitmap
I fill the pixeldata in later in some code
m_hBuffer = CreateBitmap( m_ResX, m_ResY, 1, 32, nullptr );
This is a fun one!
Guess what this prints out?
#include <stdio.h>
int main()
{
printf("%d\n", (int) (2.55 * 100));
return 0;
}
Answer: 254 - not 255. Two things happening here:
Floats are often inexact - that 2.55 doesn't get represented by a binary value that represents 2.55 exactly - it's probably something like 2.5499963... (I just made that up, but you get the idea - essentially the number is represented as a sum of fractions of 2 - since binary is base 2 - so something like .5 or .25 can likely be represented exactly, but most other numbers will be represented as an approximation. You typically don't notice this because float print routines will convert back to base 10 for display, which essentially introduces another inexactness that ends up cancelling out the first one: so what you see as the assigned value or the printed out value are not exactly the value of the representation as stored in memory).
Casting to int truncates - ie rounds down.
Put these together, and your (2.55 * 100) is getting you 254, not 255 - and you have to have the magic value 255 for per-pixel alpha to work.
So lesson here is stick with pure integers. Or, if you ever do need to convert from float to integers, be aware of what's going on, and work around it (eg. add .5, then truncate - or use a similar technique.)
By the way, this is one of those cases where stepping through code line by line and checking all inputs and outputs at each step (you can never be too paranoid when debugging!) might have shown the issue; right before you step into AlphaBlend, you should see a 254 when you hover over that param (assuming using DevStudio or similar editor) and realize that something's up.

Display 32bit bitmap - Palette

I have an image data in a buffer(type - long) from a scanner which is 32 bit.
For example, buffer[0]'s corresponding pixel value is 952 which is [184, 3, 0, 0] <-[R,G,B,A];
I want to display/Paint/draw on to the screen; I am confused when i tried to read about displying bitmaps. I looked at win32 functions, CBitmap class, windows forms (picture box) etc I am hard to understand the general idea/appraoch for displaying this buffer data on to a application window.
I have constructed the BITMAPFILEHEADER AND BITMAPINFOHEADER; Has the pixel data in a buffer, (unsigned char *)vInBuff whose size is vImageSz;
//construct the BMP file Header
vBmfh.bfType = 19778;
vBmfh.bfSize = 54+vImageSz;//size of the whole image
vBmfh.bfReserved2 = 0;
vBmfh.bfReserved1 = 0;
vBmfh.bfOffBits = 54;//offset from where the pixel data can be found
//Construct the BMP info header
vBmih.biSize = 40;//size of header from this point
vBmih.biWidth = 1004;
vBmih.biHeight = 1002;
vBmih.biPlanes = 1;
vBmih.biCompression = BI_RGB;
vBmih.biSizeImage = vBmih.biWidth*vBmih.biHeight*4;
vBmih.biBitCount = 32;
vBmih.biClrUsed = 0;
vBmih.biClrUsed = 0;
1.What is that i should be doing next to display this?
2 What should i be using to display the 32bit bitmap? I see people using createwindows functions, windows forms, MFC etc;
3.I also understand that BitBlt,createDIBSection, OnPaint etc are being used? I am confused by these various functions and coding platforms? Please suggest me a simple approach.
4.How can i create a palette to display a 32 bit image?
Thanks
Raj
EDITED TRYING TO IMPLEMENT DAVE'S APPROACH, CAN SOMEBODY COMMENT ON MY IMPLEMTATION. I couldn't continue to the bitblt as i donot have two HDC, i donot know how to get this one? Any help please
DisplayDataToImageOnScreen(unsigned char* vInBuff, int vImageSz) // buffer with pixel data, Size of pixel data
{
unsigned char* vImageBuff = NULL;
HDC hdcMem=CreateCompatibleDC(NULL);
HBITMAP hBitmap = CreateDIBSection(hdcMem,
(BITMAPINFO*)&vBmih,
DIB_RGB_COLORS,
(void **)&vImageBuff,
NULL, 0);
GetDIBits(hdcMem,
hBitmap,
0,
1,
(void**)&vImageBuff,
(BITMAPINFO*)&vBmih,
DIB_RGB_COLORS);
memcpy(vImageBuff,vInBuff,vImageSz);
}
An alternative if you just want to plot it on screen is to use TinyPTC ( http://sourceforge.net/projects/tinyptc/files/ ). It's just 3 functions and very simple if you just want to plot some pixels.
EDIT: Seems like http://www.pixeltoaster.com is a continuation of TinyPTC, probably preffered.
If you have image's bytes already in a buffer you can use:
a CBitmap object (MFC) and the method CBitmap::CreateBitmapIndirect
or
win32 routine CreateBitmapIndirect.
Now you can use BitBlt to draw it on a DC. To get a window DC use GetDC.
There is no need to create a pallete for 32 bit images.
Here's a simplified approach you can try, broken down into steps:
BITMAPINFO bitmapinfo = { 0 };
bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapinfo.bmiHeader.biWidth = 1004;
bitmapinfo.bmiHeader.biHeight = -1002;
bitmapinfo.bmiHeader.biPlanes = 1;
bitmapinfo.bmiHeader.biCompression = BI_RGB;
HBITMAP hBitmap = CreateDIBSection(NULL,
&bitmapinfo,
DIB_RGB_COLORS,
(void **)&vImageBuff,
NULL,
0);
Now party on vImageBuff and then cache hBitmap somewhere so that within your wndproc you can then in the WM_PAINT handler:
select hBitmap into temp compatible HDC
call BitBlt(..., SRCCOPY) from the compatible HDC to the window's HDC. the other parameters should be obvious. don't try to stretch or do anything fancy at first.
remember to select the original dummy bitmap into the temp HDC before destroying it.
If you aren't seeing results try looping through vImageBuff and just set every pixel to RGB(255, 0, 0), or something like that, just to sanity check the rest of the logic.
If nothing is drawing make sure that the alpha component for each pixel is 255.
If you're getting a garbled image then you need to double-check pixelformat, stride, etc.
Here's a strategy you might like:
Create a bitmap with the same size as your scanned data, and the same format (use CreateDIBSection).
Use GetDIBits to get the base address of the pixel data.
Copy your data (from the scanner) to the address GetDIBits returns.
Now render your bitmap! (use BitBlt, or somesuch).
Regarding palettes- a 32bit image does not, generally, have an explicit palette - you'd need 16.7million (assuming 8bits of alpha) values in the palette. Generally the palette is assumed to be 8bits red, 8bits green, 8bits blue, as you've described above.