Printwindow prints with empty space - winapi

The width and height of application Melon is 438 x 615 pixels and ::GetWindowRect() function grab it correctly.
However, ::PrintWindow() function draws smaller size which is 348 x 489 pixels, rest of them filled with black blank(may be draw nothing)
...may the one picture will be better than hundreds of discription.
here is result of the code
bool result = true;
HWND appHWnd = ::FindWindow(nullptr, TEXT("Melon"));
RECT appWindowRect; ::GetWindowRect(appHWnd, &appWindowRect);
HDC appDC = ::GetWindowDC(appHWnd);
// HDC appDC = ::GetDC(appHWnd); // same issue occured either
// HDC appDC = ::GetDC(nullptr);
HDC memoryDC = ::CreateCompatibleDC(appDC);
HBITMAP capturedScreenBitmap = ::CreateCompatibleBitmap(
appDC,
appWindowRect.right - appWindowRect.left,
appWindowRect.bottom - appWindowRect.top
);
HBITMAP memoryBitmap = static_cast<HBITMAP>(::SelectObject(memoryDC, capturedScreenBitmap));
result = ::PrintWindow(appHWnd, memoryDC, 0);
//copy to clipboard
OpenClipboard(nullptr);
EmptyClipboard();
SetClipboardData(CF_BITMAP, capturedScreenBitmap);
CloseClipboard();
::SelectObject(memoryDC, memoryBitmap);
::DeleteObject(capturedScreenBitmap);
::DeleteDC(memoryDC);
::ReleaseDC(appHWnd, appDC);
Strangely, C# version of the code works correctly. import same user32 library, use same of it and output different result? why?

It will be down to DPI awareness – David Heffernan
::GetWindowRect, which used to c# project and C++ console project in Visual Studio, aren't affected from the scaling by dpi awareness. but, what used to qt studio are affected from it.
here is my solution.
RECT appWindowRect; {
::GetWindowRect(hwnd, &appWindowRect);
}
POINT appWindowSize; {
qreal dotsPerInch = QApplication::screens().at(0)->logicalDotsPerInch();
appWindowSize.x = static_cast<LONG>((appWindowRect.right - appWindowRect.left) * 96 / dotsPerInch);
appWindowSize.y = static_cast<LONG>((appWindowRect.bottom - appWindowRect.top) * 96 / dotsPerInch);
}

Related

WinAPI + Cmake + Aero

I have a CMake project with an executable and a static library (linked to the exe). The library is responsible for implementing the creation of the window (using WinAPI for Windows OS), and the executable contains the main entry point (in this case a simple int main(...) function).
I've been googling for a day but cannot find a way to create a window with Aero support (can maximize by dropping to the top, the title bar is a little bit transparent, etc). I've read the Enabling Visual Styles MSDN article but I'm not sure how I should handle this with CMake. Especially that the window implementation is hidden to the client (since it's implemented in the library).
The windowing code is really basic right now for simplicity. Some of the code will be refactored, the point is not that right now. Here is the (almost) full code for creating the window.
bool WindowsWindow::create(const WindowCreateInfo& info)
{
// register custom window class
{
WNDCLASSEX wnd = { 0 };
wnd.cbSize = sizeof(wnd);
wnd.lpszClassName = CLASS_NAME;
wnd.hInstance = GetModuleHandle(nullptr);
wnd.lpfnWndProc = wndProc;
wnd.style = CS_OWNDC;
wnd.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW);
wnd.hCursor = LoadCursor(NULL, IDC_ARROW);
if (RegisterClassEx(&wnd) == 0) {
return false;
}
hInstance = wnd.hInstance;
}
HMONITOR monitor = MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY);
MONITORINFO monitorInfo;
monitorInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(monitor, &monitorInfo);
LONG style = 0;
LONG exStyle = WS_EX_APPWINDOW;
int x = CW_USEDEFAULT;
int y = CW_USEDEFAULT;
int width = info.width;
int height = info.height;
if (info.isWindowed) {
style = WS_OVERLAPPED | WS_BORDER | WS_CAPTION;
if (info.hasSysMenu) {
style |= WS_SYSMENU;
}
if (info.allowMinimize) {
style |= WS_MINIMIZEBOX;
}
if (info.allowMaximize) {
style |= WS_MAXIMIZEBOX;
}
// ... positioning, adjusting size, etc.
} else {
style = WS_POPUP;
x = monitorInfo.rcMonitor.left;
y = monitorInfo.rcMonitor.top;
width = monitorInfo.rcMonitor.right - x;
height = monitorInfo.rcMonitor.bottom - y;
}
handle = CreateWindowEx(
exStyle,
CLASS_NAME,
info.title,
style,
x,
y,
width,
height,
HWND_DESKTOP,
nullptr,
hInstance,
nullptr
);
if (!handle) {
return false;
}
running = true;
ShowWindow(handle, SW_SHOW);
return true;
}
The loop is the standard Peek-Translate-Dispatch trio and the WndProc only handles the WM_CLOSE message, otherwise returns with DefWindowProc.
How could I enable the Aero support in this kind of setup?
If the proper manifest file would be the solution, how should I handle it correctly? I mean the client (the executable) should not care that the underlying library is using WinAPI or not
A CMake example would be really helpful
Current solution
I was able to find an example (actually from a Vulkan SDK) that pointed out that I need the WS_THICKFRAME style (a resize border) in order to my window become modern looking (Aero-like).

DirectWrite rendering issues - quads seem to be overlapping, with some aliasing

Screenshot of the problem:
Here are the relevant bits of code - error handling etc. are omitted for clarity.
D2D1_BITMAP_PROPERTIES1 bp;
bp.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE;
bp.dpiX = 96.0f;
bp.dpiY = 96.0f;
bp.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW;
bp.colorContext = nullptr;
...
d2dDeviceContext->SetTarget(targetBitmap);
....
writeFactory->CreateTextFormat(L"Arial", nullptr, DWRITE_FONT_WEIGHT_LIGHT, DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL, 32.0f, L"en-US", &textFormatAccountCreds);
textFormatAccountCreds->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
textFormatAccountCreds->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
std::wostringstream outAccountName;
outAccountName << "Account Name:";
writeFactory->CreateTextLayout(outAccountName.str().c_str(), (UINT32)outAccountName.str().size(), textFormatAccountCreds, (float)800,
(float)600, &textLayoutAccountName);
const float color[4] = { 1.0f, 0.5f, 0.3f, 1.0f };
immediateContext->ClearRenderTargetView(renderTargetView, color);
d2dDeviceContext->BeginDraw();
d2dDeviceContext->DrawTextLayout(D2D1::Point2F(2.0f, 5.0f), textLayoutAccountName, blackBrush);
d2dDeviceContext->EndDraw();
swapChain->Present(0, 0);
As you can see in the screenshot, the text is rendering very poorly - specifically, the first "n" seems to be cut off on the left, as well as the first "u", and the capital "N" has some weird aliasing going on. I can change the size/position of the text, and the rendering issues manifest differently, but they still persist.
What am I missing here? I've been through most of the DirectWrite docs on MSDN and it's not clear what my problem is. I do see some mention that I should specify the starting position of my text relative to the dpi scale, but the example is very vague.
It's also worth mentioning that I'm using Direct3D and DirectWrite with Direct2D all together, in a similar fashion as seen in this tutorial. Not sure if that's causing my problem.
I would be very grateful for any assistance. Thanks much.
I figured it out. Cheers to VTT for pointing me in the right direction.
HWND hWnd = CreateWindow(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
800,
600,
NULL,
NULL,
hInstance,
NULL
);
...
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory(&sd, sizeof(sd));
sd.BufferCount = 1;
sd.BufferDesc.Width = 800;
sd.BufferDesc.Height = 600;
sd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = hWnd;
sd.SampleDesc.Count = 4;
sd.SampleDesc.Quality = m4xMsaaQuality - 1;
sd.Windowed = TRUE;
sd.Flags = 0;
Apparently the dimensions you pass into CreateWindow INCLUDE space for the window's menu and borders, so the ACTUAL dimensions of the space you can draw within the window are smaller.
RECT rect;
GetClientRect(hWnd, &rect);
// Returns 784 x 561
So the solution was to:
-Omit specifying sd.BufferDesc.Width and sd.BufferDesc.Height in DXGI_SWAP_CHAIN_DESC, because when they're set to 0, they will inherit dimensions from the parent window.
-Get the actual dimensions using GetClientRect when actual window dimensions are needed later on.

Windows - GDI - Scaling a screen DC to a printer DC without modifying the draw functions

I'm writing a Windows application showing a document to the user. The content is painted using the GDI functions, and all appears as expected on the screen.
Now I want to print this document. I get a printer device context, and I do the exact same drawing as I do on the screen. Of course the printed content appears tiny on the top of the printed page. The reason of this behavior is clear for me, and is fully explained here:
https://www.codeproject.com/Articles/764057/GDI-Drawing-and-Printing
So I need to add a scaled viewport on my printer DC, and there are several functions to achieve that in the GDI. However I'm a little puzzled about HOW to configure these functions. I tried various examples found on the internet, but none of them worked for me.
My screen resolution is 1920x1080 pixels, and I'm trying to print on an A4 portrait page. I tested various configurations, and I found that the best approximation to fit on my printed page is the following:
::SetMapMode(hDC, MM_ISOTROPIC);
::SetWindowExtEx(hDC, 1, 1, NULL);
::SetViewportExtEx(hDC, 5, 5, NULL);
::SetViewportOrgEx(hDC, -10200, 0, NULL);
As the screen and print configurations may, of course, change on other PC, I need to know how the above values may be calculated, but I cannot find a formula that works in my case. Especially I don't know why I need to scale my canvas origin using the SetViewportOrgEx() function, nobody mentioned that on the documents I read.
So what is the correct manner to calculate my print DC viewport, considering that:
The exactly same painting functions will be used for both the screen and printer drawing, and I will NEVER write different functions to print on the screen and the printer
The screen and printer devices may be entirely configured by the user, but the printed result should always fit the document on both the screen and the printer
And as an additional question, it would be better to use a metafile to do this kind of job?
In order to map the screen coordinates to paper coordinates, we need the width and length of the paper. This information is available in GetDeviceCaps(hdc, PHYSICALWIDTH) and GetDeviceCaps(hdc, PHYSICALHEIGHT), where hdc is printer's device context. We already have the screen coordinates somewhere.
The printer cannot print on the edges of the paper. We can get that information from PHYSICALOFFSETX and PHYSICALOFFSETY.
The example below uses uses a common function paint which does all the painting. print doesn't do any painting, it calls paint instead.
This assumes that rc.left and rc.right is (0,0) in screen coordinates.
void paint(HDC hdc, RECT rc)
{
HBRUSH brush = GetSysColorBrush(COLOR_WINDOWTEXT);
InflateRect(&rc, -10, -10);
FrameRect(hdc, &rc, brush);
DrawText(hdc, L"hello world", -1, &rc, 0);
}
void print(HWND hWnd, RECT rc)
{
PRINTDLG pd = { sizeof(pd) };
pd.hwndOwner = hWnd;
pd.Flags = PD_RETURNDC;
if(!PrintDlg(&pd))
return;
HDC hdc = pd.hDC;
DOCINFO doc = { sizeof(doc) };
StartDoc(hdc, &doc);
StartPage(hdc);
SetMapMode(hdc, MM_ISOTROPIC);
SetWindowExtEx(hdc, rc.right, rc.bottom, NULL);
SetViewportExtEx(hdc,
GetDeviceCaps(hdc, PHYSICALWIDTH), GetDeviceCaps(hdc, PHYSICALHEIGHT), NULL);
SetViewportOrgEx(hdc,
-GetDeviceCaps(hdc, PHYSICALOFFSETX), -GetDeviceCaps(hdc, PHYSICALOFFSETY), NULL);
paint(hdc, rc);
EndPage(hdc);
EndDoc(hdc);
DeleteObject(hdc);
}
Testing:
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rc;
GetClientRect(hwnd, &rc);
paint(hdc, rc);
EndPaint(hwnd, &ps);
break;
}
case WM_LBUTTONDOWN:
{
RECT rc;
GetClientRect(hwnd, &rc);
print(hwnd, rc);
break;
}

In WinAPI, how to make a stretchable OpenGL window with correct mouse, trapped properly for games?

I have read a lot of Stack Overflow over the years when struggling with making sense of Microsoft Windows' strange world of CreateWindowEx() .. etc. This question, when originally asked was "What is the best way to create a fluidly resizable OpenGL window in WinAPI?"
I've been struggling with getting WinAPI to make a window that:
Has an OpenGL context
Is properly centered on the main monitor (or any monitor determined by command line signal) in both multi-monitor and single-monitor displays when in "Windowed" mode or in "Fullscreen" mode
Has a fixed internal client screen size (viewport 2d)
Doesn't allow you to click outside causing it to lose focus at the wrong times or in special cases for multi-monitor
Can be resized fluidly, but doesn't change internal "client size" (meaning that it stretches the OpenGL content which is a fixed size to the new screen size) ... the idea here is to add a layer of virtualization, so that all pixels are expressed in the same 1920x1080 (1080p) coordinate system. This part is no problem for me.
Correctly handles mouse event translation from screen_size -> client_size equivalent via the screen->client ratio
In my homegrown App framework, I have to set the display size, and even then, Windows doesn't give me the right sized window. (Sometimes the title bar is subtracted, sometimes the scrollbars are subtracted, but the context draws under the title bar, for example.)
Also, recently when moving from 2010 EE (Win32 / Windows 7) to 2015 (win32 / Windows 10), I had to change the parameters to recenter the view because it was off-centered on the main display. Now, only sometimes are these values correct or incorrect. If I go "fullscreen" for example, the same values will draw above the top of the screen such that there is an area at the bottom of the screen that shows the "gl clear color" (in my case, orange)
I can play with these things by providing the following command line parameters:
-bordered (default, and has no effect really, is the default windowed mode with the title bar and such)
-borderless (seems to go into fullscreen mode, with the app off-center where win 0,0 is actually in screen center)
-windowed (or -window)
If I don't provide -window, it defaults to "full screen" resolution-adjusted (but only if supported I assume, otherwise it might throw an error).
Anyway, all of this is very bad because
a) I have to write a bajillion cases for each resolution I'm working in, rather than write everything for 1080p and have it adjust to display size, which is what i want because it handles most new displays on laptops and desktops (this is Windows remember) (and only slightly squishes things in those corner cases)
b) I cannot resize the window fluidly, also i have to trap the mouse at center and recalculate the mouse position, so I record only the deltas -- this is to avoid the mouse leaving the window and clicking the desktop, or floating off the monitor to some other monitor, even when it is hidden. I also have to make the mouse cursor invisible so the user doesn't see this, then show a simulated mouse cursor.
c) Users who don't support specifically 1920x1080 won't be able to use full screen mode
Someone pointed this article out in another question (window border width and height in Win32 - how do I get it?):
https://web.archive.org/web/20120716062211/http://suite101.com/article/client-area-size-with-movewindow-a17846
And I've read through this, learning that AdjustWindowRectEx() has some issues:
AdjustWindowRectEx() and GetWindowRect() give wrong size with WS_OVERLAPPED
I don't use WS_OVERLAPPED, so this was only moderately helpful:
AdjustWindowRectEx() and GetWindowRect() give wrong size with WS_OVERLAPPED
Here's how I do it now:
display.Resized(display.w,display.h);
// Fill in the window class structure for testing display type.
winclass.cbSize = sizeof(WNDCLASSEX);
winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc = WinProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hInstance = hinstance;
winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winclass.lpszMenuName = NULL;
winclass.lpszClassName = WINDOW_CLASS_NAME;
// Save the game instance handle
display.hinstance = game_instance = hinstance;
// Register the window class
if (!RegisterClassEx(&winclass)) return(0);
if (!gl.Init(hinstance, display.bits)) {
return(0);
}
// Detect the display size and create the final display profile
DWORD winStyle=
WS_EX_APPWINDOW |
WS_EX_TOPMOST /*|
WS_EX_ACCEPTFILES*/ ;
// Adjust Window, Account For Window Borders
int xPos = GetSystemMetrics(SM_CXSCREEN) - display.w;
int yPos = GetSystemMetrics(SM_CYSCREEN) - display.h;
RECT windowRect = {0, 0, display.w, display.h}; // Define Our Window Coordinates
AdjustWindowRectEx (&windowRect, WS_POPUP, 0, winStyle );
// Create the window
if (!(hwnd = CreateWindowEx(
winStyle, // extended style
WINDOW_CLASS_NAME, // class
gl.winTitle.c_str(), // title
( gl.borderless || CmdLine.Option("-borderless") ) ? (WS_POPUPWINDOW | WS_VISIBLE)
: (gl.noFullscreen ? ((CmdLine.Option("-bordered") ? WS_BORDER : 0) | WS_VISIBLE)
: (WS_POPUP | WS_VISIBLE)), // use POPUP for full screen
gl.noFullscreen && !CmdLine.Option("-recenter") ? xPos / 2 : 0,
gl.noFullscreen && !CmdLine.Option("-recenter") ? yPos / 2 : 0, // initial game window x,y
display.w, // initial game width
display.h, // initial game height
HWND_DESKTOP, // handle to parent
NULL, // handle to menu
hinstance, // instance of this application
NULL)
) // extra creation parms
) {
OUTPUT("WinAPI ERROR: Could not open window.\n");
return(0);
}
if (gl.borderless || CmdLine.Option("-borderless") ) {
LONG lStyle = GetWindowLong(hwnd, GWL_STYLE);
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
SetWindowLong(hwnd, GWL_STYLE, lStyle);
LONG lExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
lExStyle &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
SetWindowLong(hwnd, GWL_EXSTYLE, lExStyle);
SetWindowPos(hwnd, NULL, 0, 0, display.w, display.h, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
}
// Temporary change to full screen mode
ZeroMemory(&game_screen, sizeof(game_screen)); // clear out size of DEVMODE struct
game_screen.dmSize = sizeof(game_screen);
game_screen.dmPelsWidth = display.w;
game_screen.dmPelsHeight = display.h;
game_screen.dmBitsPerPel = display.bits;
game_screen.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
ChangeDisplaySettings(&game_screen, CDS_FULLSCREEN);
// save the game window handle
display.hwnd = game_window = hwnd;
display.hdc = game_dc = GetDC(display.hwnd = game_window); // get the GDI device context
// set up the pixel format desc struct
pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // size of this PFD
1, // version number
PFD_DRAW_TO_WINDOW | // supports window
PFD_SUPPORT_OPENGL | // supports OpenGL
PFD_DOUBLEBUFFER, // support double buff
PFD_TYPE_RGBA, // request RGBA format
(BYTE)display.bits, // select color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buff
0, // shift bit ignored
0, // no accum buff
0, 0, 0, 0, // accum bits ignored
16, // 16-bit Z-buff (depth buff)
0, // no stencil buff
0, // no aux buff
PFD_MAIN_PLANE, // main drawing layer
0, // reserved
0, 0, 0 // layer masks ignored
};
int pf; // pixel format
if (!gl.arbMultisampleSupported) {
if (!(pf = ChoosePixelFormat(game_dc, &pfd))) // match the pixel format
{
MessageBox(game_window, "OpenGL could not be initialized -- ChoosePixelFormat Error ; report this to program authors for help!", "OpenGL Error", MB_OK);
return FALSE; // error returned
}
} else {
pf = gl.arbMultisampleFormat;
}
if (!SetPixelFormat(game_dc, pf, &pfd)) // set the pixel format
{
MessageBox(game_window, "OpenGL could not be initialized -- SetPixelFormat Error ; report this to program authors for help!", "OpenGL Error", MB_OK);
return FALSE; // error returned
}
if (!(game_rc = wglCreateContext(game_dc))) // create the rendering context
{
MessageBox(game_window, "OpenGL could not be initialized -- CreateContext Error ; report this to program authors for help!", "OpenGL Error", MB_OK);
return FALSE; // error returned
}
if (!(upload_rc = wglCreateContext(game_dc))) // create the rendering context
{
MessageBox(game_window, "Multiple OpenGL contexts could not be initialized -- CreateContext Error ; report this to program authors for help!", "OpenGL Error", MB_OK);
return FALSE; // error returned
} else { // Share as much as you can between two contexts
if (!wglShareLists(game_rc, upload_rc)) {
// could use GetLastError here
MessageBox(game_window, "wglShareLists -- Error ; report this to program authors for help!", "OpenGL Error", MB_OK);
return FALSE; // error returned
}
}
if (!wglMakeCurrent(game_dc, display.hglrc = game_rc)) // make it current
{
MessageBox(game_window, "OpenGL could not be initialized -- MakeCurrent Error ; report this to program authors for help!", "OpenGL Error", MB_OK);
return FALSE; // error returned
}
ShowCursor(false);
ShowWindow(game_window, SW_SHOWNORMAL);
SetForegroundWindow(game_window);
In the above code, what I get is a window that has no resize functionality, hides the OS mouse cursor, and can only be exitted with ALT-TAB (or ALT-F4), and when it is exitted appears at the back of the windows Z-order. I always open my window using a parameter that sets display.w to 1920 and display.h to 1080, either in full screen or in Windowed mode. WM_SIZE is then called to adjust it to the client area.
Please note that the following WM_SIZE is called during the WinProc right after the initial time I set display.Resized(w,h):
case WM_SIZE:
{
display.Resized(LOWORD(lparam), HIWORD(lparam));
return (0);
}
break;
This is executed exactly once during app load, and in the first case it looks like the values are: 1918,1078
UPDATE: If I use the result of GetWindowRect() here, or GetClientRect() as shown below, the window mysteriously moves to Center-X,Center-Y of screen! What gives??
// RECT rect;
// if ( GetClientRect(hwnd,&rect) ) {
// display.Resized((int)rect.right,(int)rect.bottom);
// }
//if ( GetWindowRect( hwnd, &rect ) ) {
// display.Resized((int)ADIFF(rect.left,rect.right),(int)ADIFF(rect.top,rect.bottom));
//}
display.Resized(LOWORD(lparam), HIWORD(lparam));
return (0);
What steps do I need to take to make the window stretchable such that the context is resized to the view, and the mouse is properly adjusted based on the screen ratio?
Basically, there are too many edge cases to make sense of all of this. As time has gone on since the 2 years ago that I asked this question, I've had other inconsistencies between full screen and window emerge.
From what I understand there are basically 3 types of windows:
Your normal on-screen moveable/resizable window for windowing GUIs, like this browser window (if you are not on mobile)
One matched to a display's resolution support (including resolutions smaller than its native) -- we call this "Full screen" (or Fullscreen, which isn't even a word)
One that is a normal on-screen window, but lacks a title bar, borders and scroll bars, and appears as large as the screen. Referred to "on the street" as a "Borderless Window"
I want to master all of these but in a way that makes them all accessible and doesn't require special cases. I've basically given up on doing so with WinAPI, but obviously multiple companies do this. Following Microsoft's documentation isn't very helpful, and I've experimented with a lot of different CreateWindow CreateWindowEx -- many of these features are deprecated by the way, or don't work at all.
(Maybe the best question is, WHEN WILL MICROSOFT CLEAN UP THIS CRAP? But I think we all know the answer.) .. any help to get it working would be appreciated.
I'm now working in: C++, Windows API, OpenGL 3.x / 4.x, Windows 10.

Improper width and height for second monitor from GetMonitorInfo and GetDeviceCaps

I am trying to get the top left x,y and bottom right x,y. And calculat the width and height of displays.
My secondary monitor is 1920x1080 as seen in my display settings screenshot:
I am getting the monitor dimensions in two ways. The code below is js-ctypes but I simplified out all the error checking and other ctypes stuff and tried to make it look like c. But this is a winapi issue not ctypes hence I didn't tag the topic with it.
First approach:
cPoint = POINT();
GetCursorPos(&cPoint);
cMon = MonitorFromPoint(cPoint, MONITOR_DEFAULTTONEAREST);
cMonInfo = MONITORINFOEX();
cMonInfo.cbSize = MONITORINFOEX.size;
GetMonitorInfo(cMon, &cMonInfo);
lpszDriver = null;
lpszDevice = cMonInfo.szDevice;
xTopLeft = cMonInfo.rcMonitor.left;
yTopLeft = cMonInfo.rcMonitor.top;
nWidth = cMonInfo.rcMonitor.right - xTopLeft;
nHeight = cMonInfo.rcMonitor.bottom - yTopLeft;
This is giving me a rect of the following:
_RECT(-1920, -1080, -640, -360)
Doing right - left gives 1280
Doing bottom - top gives 720
The dimensions are definitely wrong. It should have been width of 1920 and height of 1080.
I then try the second method:
hdcScreen = CreateDC(lpszDriver, lpszDevice, null, null);
nWidth = GetDeviceCaps(hdcScreen, HORZRES);
nHeight = GetDeviceCaps(hdcScreen, VERTRES);
This gives me the same thing, width of 1280 and height of 720. My mind is boggled! How can I get 1920x1080?
This same method gives me correct dimensions for my primary monitor, so I am very confused.
EDIT
I just now tried a third method, and still same issues:
var jsMonitorEnumProc = function(hMonitor, hdcMonitor, lprcMonitor, dwData) {
xTopLeft = lprcMonitor.contents.left;
yTopLeft = lprcMonitor.contents.top;
nWidth = lprcMonitor.contents.right - xTopLeft;
nHeight = lprcMonitor.contents.bottom - yTopLeft;
return true;
}
EnumDisplayMonitors(null, null, jsMonitorEnumProc, 0);
This gives me rects of the following:
_RECT(0, 0, 1280, 1024)
_RECT(-1920, -1080, -640, -360)
The first one is my primary monitor and we see doing bottom - top gives 1280 and right - left gives 1024 which is correct my primary monitor is 1280 x 1024.
But the second monitor again is -360 - -1080 for 720 height and -640 - -1920 for 1280 width. I am using this to take screenshots of all the monitors and second ones is coming out clipped.
In my non-dpi aware app 32bit Firefox on Win 8.1 64bit, I was able to get the proper dimensions by using EnumDisplaySettings using the DISPLAY_DEVICE struct of size 220.
js-ctypes:
// start - get all monitor resolutions
var iDevNum = -1;
while (true) {
iDevNum++;
var lpDisplayDevice = ostypes.TYPE.DISPLAY_DEVICE();
lpDisplayDevice.cb = ostypes.TYPE.DISPLAY_DEVICE.size;
var rez_EnumDisplayDevices = ostypes.API('EnumDisplayDevices')(null, iDevNum, lpDisplayDevice.address(), 0);
//console.info('rez_EnumDisplayDevices:', rez_EnumDisplayDevices.toString(), uneval(rez_EnumDisplayDevices), cutils.jscGetDeepest(rez_EnumDisplayDevices));
if (cutils.jscEqual(rez_EnumDisplayDevices, 0)) { // ctypes.winLastError != 0
// iDevNum is greater than the largest device index.
break;
}
console.info('lpDisplayDevice.DeviceName:', lpDisplayDevice.DeviceName.readString()); // "\\.\DISPLAY1" till "\\.\DISPLAY4"
if (lpDisplayDevice.StateFlags & ostypes.CONST.DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) {
console.log('is monitor');
var dm = ostypes.TYPE.DEVMODE(); // SIZEOF_DEVMODE = 148
console.info('dm.size:', ostypes.TYPE.DEVMODE.size);
//dm.dmFields = ostypes.CONST.DM_PELSWIDTH;
//dm.dmSize = ostypes.TYPE.DEVMODE.size;
console.log('iDevNum:', iDevNum, lpDisplayDevice.DeviceName.readString());
var rez_EnumDisplaySettings = ostypes.API('EnumDisplaySettings')(lpDisplayDevice.DeviceName, ostypes.CONST.ENUM_CURRENT_SETTINGS, dm.address());
//console.info('rez_EnumDisplaySettings:', rez_EnumDisplaySettings.toString(), uneval(rez_EnumDisplaySettings), cutils.jscGetDeepest(rez_EnumDisplaySettings));
//console.info('dm:', dm.toString());
collMonInfos.push({
x: parseInt(cutils.jscGetDeepest(dm.u.dmPosition.x)),
y: parseInt(cutils.jscGetDeepest(dm.u.dmPosition.y)),
w: parseInt(cutils.jscGetDeepest(dm.dmPelsWidth)),
h: parseInt(cutils.jscGetDeepest(dm.dmPelsHeight)),
screenshot: null, // for winnt, each collMonInfos entry has screenshot data
otherInfo: {
nBPP: parseInt(cutils.jscGetDeepest(dm.dmBitsPerPel)),
lpszDriver: null,
lpszDevice: lpDisplayDevice.DeviceName
}
});
}
}
// end - get all monitor resolutions

Resources