Create Square Window C++ - c++

Stuck on a little fiddly problem. I'm creating a GUI in C++ using XP and VS C++ using the command CreateWindow().
My question is, how do I make the inside paintable region a perfect square. When passing in the size of the window to create, some of this is deducted for the menu bar at the top, border all around etc. Are there any real time variables I can pass in, e.g. to create a 500x500 window would be:
...500+BORDER,500+MENU_TOP+BORDER...
Thanks everyone

The way I usually do it is with AdjustWindowRect. I find it simpler than the other suggested methods (which should work just as well, it's your choice). Use it as such:
RECT rect = {0, 0, desiredWidth, desiredHeight};
AdjustWindowRect(&rect, windowStyle, hasMenu);
const int realWidth = rect.right - rect.left;
const int realHeight = rect.bottom - rect.top;
And pass realWidth & realHeight to CreateWindow.
The function will, as its name suggests, adjust the window according to your window style and menu use, so that the client region matches your desired size.

you can find all the relevant size (windows framewidth, menubar height, etc) here: GetSystemMetrics(). Using these values you should be able to create a perfect square window

You can get all the UI metrics from the GetSystemMetrics() API call.
For example, the menu will be SM_CXMENU and SM_CYMENU.

Related

How to get the "display stream" of a MS Windows window?

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.

Nested panel not scrolling as expected. Why not?

I am creating a GUI using C++ and winapi. I have been able to work out a lot of details, but I'm having a bit of trouble with the scrolling of panels within another panel. I know how to do this in c#, but with c++ I am defeated.
I have created class which generates a panel for a generic "Topic" and I can designate the name of the topic (e.g., "Topic A"). I have create a separate class which generates a Panel to contain all of these topics. That is the TopicHolder. So I pass in a vector with the names as strings. I then generate new Topic objects, each with their own GUI control. I then update the layout of TopicHolder, including all of the Topics, giving them x and y locations based on their standard size.
Everything looks more or less like I want it to initially. If this was c# the topic holder would scroll and the various topics would scroll in and out of sight depending on the exact portion of the larger panel which was visible. In this case, however, scrolling has absolutley no effect. This is my first time working with scrolling on a c++ gui, so I might be missing something.
Below are some of the key code segments. I'd welcome any helpful tips.
Thanks
Adding the topics
void TopicHolder::SetTopics(std::vector<std::string> t)
{
for(unsigned i=0;i<t.size();i++)
{
//I give the topic the HWND of the TopicHolder so it can
//be properly parented on that GUI element
Topic* tmp = new Topic(myHWND, t[i]);
vectorOfTopics.push_back(tmp);
}
UpdateLayout(holderRect);
}
Handling topic layout relative to TopicHolder
void TopicHolder::UpdateLayout(RECT r)
{
int buffer = 5;//buffer between elements
int x = buffer;
int y = buffer;
for(unsigned i=0;i<vectorOfTopics.size();i++)
{
RECT tmp;
tmp.left=x;
tmp.top=y;
tmp.right = r.right-(2*buffer);
tmp.bottom = y+Topic::HEIGHT;//standard height per topic
vectorOfTopics[i].Layout(tmp);
y+= Topic::HEIGHT+buffer;
}
}
Layout in Topic object
void Topic::Layout(RECT r)
{
SetWindowPos(myHWND, //this is the HWND of the topic
HWND_TOP, r.left, r.top, Topic::WIDTH, Topic::HEIGHT, SWP_SHOWWINDOW);
}
-------------------Edit-----------------------------------------
Grr... Okay, so C++ has no support for this as many of you have explained. I have (painfully) been learning to set up my scroll parameters. Mostly it is working as expected, but I still have a problem with the scrollbar. I expected the scrollbar to show up on the right side of the panel and leave the rest of the space for my Topic panels. Instead it is slightly offset and the rest of the area is painted a light gray rather than the background color of the TopicHolder. Right now it's just irritating, but I would like to see it resolved. Again, any help would be appreciated.
Starting y position of topics in UpdateLayout always remains 5, so no scrolling happens. You should keep some offset value and change it if scrolling up and down happens so y will start from this offset.
You need to call SetScrollPos() to change the scrolling position or the window contents.
i.e:
// hwnd is your control window, SB_VERT refers to its verti8cal scrollbar.
SetScrollPos(hwnd, SB_VERT, topicHeight * topicToBringToTop, TRUE);
InvalidateRect(hwnd, NULL, TRUE); // redraw the control.

Different Window Form

I have been using directx for a while now and one thing that has always bothered me is that windows are squares (I guess this applies to most programs). Now as creation often happens by defining a rectangle shape and drawing that, black for example. I have been thinking of 2 approaches to this:
Define a bigger rectangle and draw parts of the background transparent.
I decided not to go for this one as I have absolutely no idea how to do this.
See what microsoft offers when it comes to window shapes.
And while they did have a lot of win32 configuration settings (no border etc) I couldn't find anything about drawing in a particular shape (like using a triangle for example).
Does anyone have experience with window shapes or drawing a background transparent? Maybe even a better option that I missed? Thanks in advance!
This can be done quite simply using the SetWindowRgn API call. What this does is define the area within which the system will allow drawing to appear.
As a simple example, lets punch a hole in one of our windows. The following can be done in the WM_CREATE handler of the window:
case WM_CREATE:
{
// Get the window rect
RECT r;
GetWindowRect(m_hwnd, &r);
MapWindowPoints(NULL, m_hwnd, reinterpret_cast<LPPOINT>(&r), 2);
// Work out the size of the window
LONG w = r.right - r.left;
LONG h = r.bottom - r.top;
// Create a rectangular region to cover the window (almost)
HRGN hRgn = CreateRectRgnIndirect(&r);
// and a smaller elliptical window
r.left += w/4;
r.right -= w/4;
r.top += h/4;
r.bottom -= h/4;
HRGN rgnCirc = CreateEllipticRgnIndirect(&r);
// Now we combine the two regions, using XOR to create a hole
int cres = CombineRgn(hRgn, rgnCirc, hRgn, RGN_XOR);
// And set the region.
SetWindowRgn(m_hwnd, hRgn, TRUE);
}
break;
Some important notes. The region that is passed to SetWindowRgn is from that point on owned by the system, so do not perform any more operations on it. Also, you would need to modify the region if the window is resized - I only put the example in WM_CREATE as... an example.
Another little caveat about the above, it doesn't perform the calculation of window size correctly... as I said, this is just an example that punches a hole in a window.
Finally, I tried it with a simple Direct-X program, and it works with that too. Hoorah!

How to display framerate in window title?

I think this is going to be an easy one for you guys :)
I am trying to get FPS displayed in the window title in my Directx application (written in C++). I do not really know how to do this as my app assigns title in this manner
any ideas how to do this (so that I can see the FPS when I minimise my app) ?
I think you can use SetWindowText() to accomplish this, e.g.:
HWND window = CreateWindow(windowClass.lpszClassName, title, WS_OVERLAPPEDWINDOW, x, y, width, height, GetDesktopWindow(),NULL,windowClass.hInstance,NULL);
... then later ...
SetWindowText(window, "XXXX FPS");
See:
http://msdn.microsoft.com/en-us/library/aa302340.aspx#win32map_windowfunctions

How to create a window based on only the size of the screen not including the windows border with C++/Windows?

When creating a window using CreateWindow(...), which requires the window width and height, I have to enter the values 656 and 516, instead of 640 and 480, so as to account for the windows border.
I'm wondering if there is a way to create a window based only on the portion of the window not including the border, especially considering that if different versions of windows have different size borders, than the program might be displayed differently when I run it on said different versions
(ie: using 640 - object.width will place the object not quite on the edge of the screen if the user's version of windows has different sized borders).
So is there a way to create a window based only on the portion of the screen relevant to the program, or at the vary least a function along the lines of GetVericalBorder()/GetHorizontalBorder() so that I use these in CreateWindow()'s parameters instead of arbitrary and vague values like 656 and 516?
Have a look at AdjustWindowRectEx. You pass this function a rectangle containing the desired size of your windows' client area, and the window style flags, and it calculates how big to make the overall window so that the client area is the desired size.
You can use the SystemParametersInfo() API to get this kind of window information. See the SPI_GETBORDER and/or SPI_GETNONCLIENTMETRICS parameters refer Microsoft Library
SystemParametersInfo should allow you to account for borders, menus, etc.
int WINAPI GetSystemMetrics(
__in int nIndex
);
Refer Microsoft Library