It's only for 'debugging' purposes, so I don't want to spend a lot of time with this, nor it is very important. The program exports the data as a png, jpg, svg, etc... -so it's not a big deal, though it could be good to see the image while it is being generated. Also, the program is going to be used in a Linux server; but I'll limit this 'feature' to the Win version.
I also don't want to use a library, except if it is very, very lightweight (I used CImg for a while, but I wasn't very happy with its speed, so I ended up writing the important functions myself and just using libjpeg and libpng directly).
I have the image in an ARGB format (32bpp), though converting the format won't be a problem at all. I would like to use Win32, creating a window from a function deep inside the code (no known hInstance, etc), and writing the bitmap. Fast and easy, hopefully.
But I don't know the win32api enough. I've seen that the only option to draw (GDI) is trough a HBITMAP object... Any code snippet or example I can rely on? Any consideration I might not overlook? Or maybe -considering my time constrains- should I just forget it?
Thanks!
The biggest piece of work here is actually registering the window class and writing a minimal window procedure. But if this is debug only code, you can actually skip that part. (I'll come back to that later).
If you have an HBITMAP, then you would use BitBlt or StretchBlt to draw it, but if you don't already have the image as an HBITMAP, then StretchDIBits is probably a better choice since you can use it if you only have a pointer to the bitmap data. You have to pass it a source and destination rectangle, a BITMAPINFOHEADER and a pointer to the raw bitmap data. Something like this
SIZE sBmp = { 100, 200 };
LPBITMAPINFOHEADER pbi; // the bitmap header from the file, etc.
LPVOID pvBits; // the raw bitmap bits
StretchDIBits (hdc, 0, 0, sBmp.cx, sBmp.cy,
0, 0, sBmp.cx, sBmp.cy,
pvBits, pbi,
DIB_RGB_COLORS,
SRCCOPY);
So the next part is how do I get a HDC to draw in? Well for Debug code, I often draw directly to the screen. HDC hdc = GetDC(NULL) will get a DC that can draw to the screen, but there are security issues and it doesnt' work the same with Aero in Windows Vista, so the other way is to draw onto a window. If you have a window that you can just draw over, then HDC hdc = GetDC(hwnd) will work.
The advantage of doing it this way is that you don't have to create and show a window, so it's less disruptive of code flow, It's helpful for debugging a specific problem, but not the sort of thing you can leave turned on all of the time.
For a longer term solution, You could create a dialog box and put your bitmap drawing call in the WM_PAINT or WM_ERASEBKGND message handler for the dialog box. But I don't recommend that you show a dialog box from deep inside code that isn't supposed to be doing UI. Showing a window, especially a dialog window will interfere with normal message flow in your application. If you want to use a dialog box for this bitmap viewer, then you want that dialog window to be something that the User shows, and that you just draw onto if it's there.
If you don't have access to an HINSTANCE, it's still possible to show a dialog box, it's just more work. That's sort of a different question.
About all you need is a handle to a device context (HDC). To display your data on it:
CreateDibSection to create a DIBSection.
Copy your data to the memory block returned by CreateDibSection.
create a DC compatible with the target DC.
Select the DIBSection into your newly created DC.
BitBlt (or StretchBlt) from your DC to the target DC.
Related
I have a program (we will call it the "virtual screen") that create a full screen window and start arbitrary programs, and with the help of hooks (CBTProc) get handles to windows that started programs create. From those handles I retrieve the content of the windows (using GetDIBits) and displays it in the "virtual screen" window.
Currently, this "virtual screen" copy content of windows and then redraw them, which make it work, sort of like a mirroring software.
Here is how I get the content of a window:
struct WindowContent {
void *pixel;
int width;
int height;
};
WindowContent getWindowContent(HWND hWnd, int height, int width)
{
WindowContent content;
WINDOWINFO windowInfo;
GetWindowInfo(hWnd, &windowInfo);
content.height = windowInfo.rcClient.right - windowInfo.rcClient.left;
content.width = windowInfo.rcClient.bottom - windowInfo.rcClient.top;
HDC hdc = GetDC(hWnd);
HDC captureHdc = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, content.width, content.height);
HGDIOBJ oldHdc = SelectObject(captureHdc, hBitmap);
BitBlt(captureHdc, 0, 0, content.width, content.height, hdc, 0, 0, SRCCOPY|CAPTUREBLT);
SelectObject(captureHdc, oldHdc);
DeleteDC(captureHdc);
BITMAPINFO outputBitmapInfo = {};
outputBitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
GetDIBits(hdc, hBitmap, 0, 0, NULL, &outputBitmapInfo, DIB_RGB_COLORS);
content.pixel = (BYTE *)malloc(outputBitmapInfo.bmiHeader.biSizeImage);
outputBitmapInfo.bmiHeader.biCompression = BI_RGB;
outputBitmapInfo.bmiHeader.biBitCount = 32;
GetDIBits(hdc, hBitmap, 0, outputBitmapInfo.bmiHeader.biHeight, content.pixel, &outputBitmapInfo, DIB_RGB_COLORS);
return content;
}
My question is, how do I remove the copying part, how can I make an area on my "virtual screen" the window output for those programs ?
Emphasis on the fact that I'm trying to make created windows be the area on the "virtual screen", I don't want an additional window hidden or living on the desktop.
In my research, I've looked into Windows DWM DLLs and found some undocumented function (SignalRedirectionStartComplete or MilConnection_CreateChannel) which names look linked to what I want to do, but I don't think I should use them, as they are undocumented.
Also, the code is using Win32 API but I don't mind using another Windows API or another language (C#, DX* ...).
Forgot to mention, I have already thought about using the DWM thumbnail stuff, but it's not that reliable enough for what I'm trying to do.
As far as I understand Windows 10 uses DX under the hood for all display output, for GDI, and even for Vulkan / OpenGL programs, and someone used it to make a lib that
gets DX 10 texture from a window (). Is it possible to make something similar, that, for a specific HWND, set its "output" to a texture or some region in
memory (swapchain redirection ?) instead of the screen and then display the output in another program (in my case, on the "virtual screen" window) ?
The DWM was a reasonable place to look. It has some documented functions to get you at least a little closer to what you want.
You can register your window as a "thumbnail" viewer using DwmRegisterThumbnail. Then you (probably) call DwmUpdateThumbnailProperties to tell it how to draw to your window (e.g., set opacity, rectangle to draw to, and whether to draw the whole source window, or just its client area). When you're done, you call DwmUnregisterThumbnail to unhook from displaying it.
This is only a little closer to what you want though--it eliminates your having to copy bitmaps from the source into your own window--but that's about all it does. The target application will still have its own window running elsewhere.
If you want to do more to hide the application, you could create another desktop, and display the application in that desktop. If you don't provide a way to switch desktops, that can keep it pretty well hidden. On the other hand, there are external tools that will let the user change desktops, which would let them see the application directly.
One other avenue to consider (for a subset of applications) would be COM. Part of what COM supports is having a COM server that displays its output inside the frame of some COM client's window. That's no longer nearly the big thing it once was, but (I believe) all the code to support it is still available. But, it only works for applications that are specifically written to support it (which, honestly, isn't a huge number). The code for this isn't exactly trivial either.
I am trying to render a PNG on a button control for my dialog box (Visual Studio 2010 Professional). After doing some research, I found the following method which works for BMP files:
HBITMAP hBitmap = (HBITMAP) LoadImage(NULL, L"test.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
SendMessage(GetDlgItem(hDlg, IDC_BUTTON1), BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap);
This does not work with PNG files, though. After some more research, I found that there is a simple way to do this using GDI+:
HBITMAP hBitmap;
Gdiplus::Bitmap b(L"a.png");
b.GetHBITMAP(NULL, &hBitmap);
SendMessage(GetDlgItem(hDlg, IDC_BUTTON1), BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap);
I am not using GDI+ anywhere else in my program but I still need to include the headers, link to the library and initialize it just to accomplish this simple task. Is it worth all of this trouble? Is there a more standard way to do this?
I plan to render multiple PNGs (some transparent) on a single button.
EDIT: The (slightly modified) CreateDIBSectionFromBitmapSource() function that I am using to create the HBITMAP can be found here:
http://archive.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=win7wicsamples&DownloadId=7549
Can you be a bit more specific about you mean by "Rendering" a PNG on a button control...
If you mean that you are trying to stick a .PNG image on a button, then yes there is an easier way. Just click on the button and go to 'Appearance in the properties menu. Click on 'BackgroundImage', select local resource, then browse to the image and load it. Done.
If this isn't what you mean to do, then I might suggest researching
System.Drawing.Image and using the GDI+
I am actually sitting here learning GDI+ as we speak. Be forewarned, it's a time and a half to learn.
GDI+ is a standard way for reading and rendering images in different format. Other way of doing this would be to create the PNG decoder component and acquiring the stream from it and pass it to LoadImage function, which is exactly what GDI+ does for you in the back ground. The image format encoders and decoders are part of window imaging component.
In terms of how decoding and rendering is going to perform for multiple images depends on what you are looking for and I am not sure about it. Let me just leave a few comments. What you may do and are doing now (through button's back-ground image option) is to decode the images once and keep them as bit map so when painting has to be done the bitmap is ready and no decoding needs to be done. This is what button's back-ground image painting does too, the button component keeps the bitmap handle you pass it and would just paint the same every it has to repaint. I don't think you need to worry about performance of painting a bitmap because it is done using Bitblt to the display device directly.
I have a win32 application which was developed in c++. The application draws some stuff on the window using basic shapes (rectangles). The windows is repainted every 20ms (50hz) using InvalidateRect. All works well but the drawing is flickering. How can i prevent the flickering? In c# i normally use a double buffered component (such as pictureBox), how could i get rid of this in c++ using win32?
You can create an in-memory device context, draw those shapes to it (just like you would to the window's device context) and then blit from it to window's device context when the window is invalidated.
You also need to disable background clearing (handle WM_ERASEBKGND window message appropriately) before the draw happens.
Edit: I stumbled upon a pretty exhaustive tutorial on flicker-free drawing in GDI, which explains all aspects of drawing in Windows and comes with examples.
You can easily implement double buffering in Win32 as well. Assuming you are doing your painting directly on the Window using its device context, do this instead:
Create a "memory" device context and do all your drawing on that device context, then copy the invalidated portions of the window to the actual device context when appropriate, using the BitBlt() function
There's a pretty good (albeit high level) overview here.
You can double buffer in C++, too.
When you get the DC to paint to, you create an offscreen bitmap (CreateCompatibleBitmap) and a memory DC (CreateCompatibleDC). Do all your painting to that DC. At the end, do a BitBlt from the memory DC to the actual DC.
For performance, you might want to cache the offscreen bitmap and DC, but remember to recreate them when the window size changes.
Here's the greatest tutorial i've found yet:
https://msdn.microsoft.com/en-us/library/ms969905.aspx
In short - yes, you have to implement the double-buffering. It's done through creating the in-memory DC and then drawing everything you want to an in-memory bitmap using that DC, only afterwards commiting this bitmap to an actual DC.
I'm drawing into a WinAPI-Window by using the SetPixel()-Function.
If I scale the window or lose focus (another window is on top) I lose the whole content that I draw into the window.
I just used
RECT rc;
GetClientRect(hwnd, &rc);
RedrawWindow(hwnd, &rc, NULL, RDW_NOERASE | RDW_NOFRAME | RDW_VALIDATE);
which helped to avoid redrawing the content when I move the window but scaling and losing focus still removes the content.
Does anyone have an idea what I missed?
Draw it to a buffer/bitmap and then draw that to your window.
When a window needs to be repainted it will be sent a WM_PAINT message. At this point you must redraw all of the window, or at least all parts of it which are contained within a clipping region. Windows does some buffering and automatic painting, specifically it will repaint parts of a window which are covered by other windows then uncovered. Once the window has been resized though, or (presumably) invalidated, you're on your own.
As #daniel suggested, if painting is an intensive process and you don't want to do it every time a repaint is required, render your content into a bitmap (which in this case will be an off-screen buffer) and BitBlt (copy) it into the window as necessary.
Grab yourself a copy of Charles Petzold's book "Programming Windows" for information about how you should go about painting. If you are writing a WinAPI app but have used SetPixel I'd recommend reading the entirety of the first few chapters to get an idea of how an old-school Windows programme should be structured.
SetPixel is very slow, you cannot improve your program significantly. Create in-memory bitmap and draw it on the window. For example, you can do this using StretchDIBits function, which draws the whole memory area as bitmap to the window, instead of SetPixel.
The most important StretchDIBits parameters are:
CONST VOID *lpBits - memory array (pixels). You need to fill it in memory instead of SetPixel calls.
CONST BITMAPINFO *lpBitsInfo - BITMAPINFO structure which must describe bitmap structure. For example, if lpBits has BGRW structure (4 bytes per pixel), BITMAPINFO must describe true color bitmap.
You need to draw the content into memory and then draw it to the window when you got WM_PAINT message. There is no way to avoid using memory buffer because window device context does not save what you draw.
Create a DIB surface and draw into it instead. Then redraw the bitmap when redrawing a window.
You're trying to draw with a pre-Windows way in Windows. ;)
I'm writing an unmanaged Win32 C++ function that gets a handle to a bitmap, and I need to draw on it.
My problem is that to draw I need to get a device context, but when I do GetDC (NULL), it gives me a device context for the WINDOW! The parameter for GetDC () is a window handle (HWND), but I don't have a window; just a bitmap handle.
How can I draw on this bitmap? Thanks!
In addition to Pavel's answer, the "compatible with the screen" always bugged me too, but, since CreateCompatibleDC(NULL) is universally used for that purpose, I assume it is correct.
I think that the "compatible" thing is related just to DDB (the DC is set up to write on the correct DDB type for the current screen), but does not affect read/writes on DIBs.
So, to be safe, always use DIBs and not DDBs if you need to work on bitmaps that doesn't just have to go temporarily onscreen, nowadays the difference in performance is negligible. See here for more info about DIBs and DDBs.
CreateCompatibleDC() and SelectObject() your bitmap into it.
However, not every bitmap can be selected into any DC.
You might have to play with mapping mode and other options of memory DCs.
The basic win32 paradigm for drawing on a bitmap is that you select the bitmap onto a device context, after which, all drawing operations on that device context are stored in the bitmap. You then use one of the various 'blit' operations (e.g. StretchBlt) to transfer this to a display surface, which is just the device context of a window client area.
Others have provided better detail, this is just the high-level view.
Well, this is a bit outside the box.. I guess.. But I do know that Graphics can return a HDC, and Graphics take a Bitmap as an argument to its ctor . A Bitmap in turn can be created from a HBITMAP and a HPALETTE. The only problem here is that I do not know if the HPALETTE argument can be NULL.
Graphics* g;
Bitmap* bitmap;
HBITMAP _bitmap; // <- this one is yours
bitmap = Bitmap::FromHBITMAP(_bitmap, NULL);
g = new Graphics(bitmap);
HDC hdc = g->GetHDC();
// when done, call g->ReleaseHDC(hdc);
However, I would urge you to receive the HDC as an argument to your function as well.. I do not think that anyone will have a BITMAP and NOT have the DC to it.
If you're having these issues with finding a HDC to a HBITMAP, so will everyone else.