For my Console Application, I needed to prevent user input and window resizing. I used
HWND consoleWindow = GetConsoleWindow();
SetWindowLong(consoleWindow, GWL_STYLE, GetWindowLong(consoleWindow, GWL_STYLE) & ~WS_MAXIMIZEBOX & ~WS_SIZEBOX);
and
void disableInput()
{
DWORD prev_mode;
GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &prev_mode);
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_EXTENDED_FLAGS |
(prev_mode & ~ENABLE_QUICK_EDIT_MODE));
}
However, after finishing the program, it would be nice to enable these settings again.
I think this
void enableInput()
{
DWORD prev_mode;
GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &prev_mode);
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS);
}
should work for the input but how do I enable window resizing again?
Also, a little bit off this topic but how to enable/disable console resizing and input for Linux?
Related
I have a function that sets a Win32 console to full screen. The problem is when it goes into full screen, it's not hiding the mouse cursor.
It doesn't seem to matter if it's in full screen or not. The mouse cursor still shows when I call ShowCursor(FALSE). How can it be hidden?
As in the docs for ShowCursor(), the cursor will hide if the function returns a value greater than 0. If it's negative, it will hide. The value is returning -2 for me, so it should hide in this case, but it is not.
bool Console::setFullScreen(const bool fullScreen)
{
HWND handle;
if (fullScreen)
{
// Hide the scrollbar
showScrollBar(false);
// Set the window style
handle = GetConsoleWindow();
LONG style = GetWindowLong(handle, GWL_STYLE);
style &= ~(WS_BORDER | WS_CAPTION | WS_THICKFRAME);
SetWindowLong(handle, GWL_STYLE, style);
// Set the window to full screen in windowed mode
ShowWindow(getHandle(), SW_MAXIMIZE);
// Hide the cursor
ShowCursor(FALSE); // Fails
}
else
{
showScrollBar(true);
// Set the window style
handle = GetConsoleWindow();
LONG style = GetWindowLong(handle, GWL_STYLE);
style |= WS_BORDER;
style |= WS_CAPTION;
style |= WS_THICKFRAME;
SetWindowLong(handle, GWL_STYLE, style);
// Set the window to full screen in windowed mode
ShowWindow(getHandle(), SW_NORMAL);
// Show the cursor
ShowCursor(TRUE);
}
return true;
}
I haven't tried this, but you can probably change the mouse cursor of the console window by calling GetConsoleWindow to get the HWND of the console window, then calling SetClassLong to set the cursor.
HCURSOR hNewCursor = LoadCursor(/* whatever*/);
SetClassLong(GetConsoleWindow(), GCL_HCURSOR, hNewCursor);
To make the cursor disappear, create a cursor which is entirely transparent.
I've made a little timer program in c++ and once the timer has run out I want the console window to pop up to the foreground in Windows to display the "finished" message. I read about using "SetForegroundWindow(hwnd)" which does exactly what I want when I run the code from visual studio, but when I build a release and run the exe from outside of VS, the console window doesn't pop up, instead it's icon in the system tray flashes. Any ideas why this might be? I've tested it on 64 bit Windows 7 and 10 and both did the same thing.
In most cases you can use SetForegroundWindow as long as the window is properly restored. Sometimes the system may refuse the request (see documentation) There is usually a good reason for it and you should not try to override the system. If SetForegroundWindow failed then you still have the backup option where you get that blinking button in the task bar to alert the user.
void show(HWND hwnd)
{
WINDOWPLACEMENT place = { sizeof(WINDOWPLACEMENT) };
GetWindowPlacement(hwnd, &place);
switch(place.showCmd)
{
case SW_SHOWMAXIMIZED:
ShowWindow(hwnd, SW_SHOWMAXIMIZED);
break;
case SW_SHOWMINIMIZED:
ShowWindow(hwnd, SW_RESTORE);
break;
default:
ShowWindow(hwnd, SW_NORMAL);
break;
}
SetWindowPos(0, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE);
SetForegroundWindow(hwnd);
}
int main()
{
HWND hwnd = GetConsoleWindow();
ShowWindow(hwnd, SW_SHOWMINIMIZED);
//Test: manually click another window, to bring that other window on top
Sleep(5000);
//this window should restore itself
show(hwnd);
system("pause");
return 0;
}
I am using Windows MFC to create a small program.
I would like to make multiple instances of the program appear in a cascaded position(s).
Currently the program always appear centered, i.e. it is not possible to see it multiple windows.
Is there an automatic way to let windows create multiple instance in cascaded positions?
To test i use a batch script with multiple lines of:
"start MyProgram.exe"
"start MyProgram.exe"
"start MyProgram.exe"
The dialogs i use are derived from CDialogEx (but i had same using CDialog)
I expected this to be a flag/properties of the dialog.
Before changing the .rc-file have properties like this
IDD_MAIN_DLG DIALOGEX 0, 0, 260, 185 STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION
I am aware of the CascadeWindows() function, but to my knowledge it requires more awareness of which instances that already run
How about the following code as a starting point?
#include <Psapi.h>
namespace {
size_t nWnds = 0;
HWND hWnds[10];
BOOL CALLBACK enumerate(HWND hWnd, LPARAM This)
{
HWND hWndThis = reinterpret_cast<HWND>(This);
TCHAR nameThis[MAX_PATH], nameOther[MAX_PATH];
VERIFY(GetWindowModuleFileName(hWndThis, nameThis, _countof(nameThis)));
TCHAR wndclass[32];
VERIFY(RealGetWindowClass(hWnd, wndclass, _countof(wndclass)));
if (_tcscmp(wndclass, _T("#32770")) == 0) {
DWORD pid;
GetWindowThreadProcessId(hWnd, &pid);
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess != NULL) {
if (GetModuleFileNameEx(hProcess, NULL, nameOther, _countof(nameOther))) {
if (_tcscmp(nameThis, nameOther) == 0) {
hWnds[nWnds++] = hWnd;
}
}
VERIFY(CloseHandle(hProcess));
hProcess = NULL;
}
}
return TRUE;
}
}
BOOL CMFCApplication1Dlg::OnInitDialog()
{
// ...
VERIFY(EnumWindows(enumerate, reinterpret_cast<LPARAM>(m_hWnd)));
if (nWnds > 1) {
VERIFY(CascadeWindows(NULL, MDITILE_ZORDER, NULL, nWnds, hWnds));
}
return TRUE;
}
It consists of a change to OnInitDialog to scan for all top level dialogs that have been created by your executable and then call CascadeWindows. Of course in enumerate you can also move every window you find to a point that starts at CPoint(x, y) and changes by CSize(xoffset, yoffset) with every found window.
Some things to keep in mind:
CascadeWindows does not look like the right solution, it restores all maximized windows and does not only touch windows created by your process (which I would prefer).
If your process creates multiple top level dialogs, then you might need to detect which dialogs to move.
If the user makes a copy of your program file then the module file name will be different.
Just proof of concept code, you'll need to add error checking and bounds checking.
To do a "fake" fullscreen window in SDL2 without a modeset you can create a borderless, maximized window using something like this.
int idx = SDL_GetWindowDisplayIndex(g_displayWindow);
SDL_Rect bounds;
SDL_GetDisplayBounds(idx, &bounds);
//SDL_SetWindowResizable(g_displayWindow, SDL_FALSE);
SDL_SetWindowBordered(g_displayWindow, SDL_FALSE);
SDL_SetWindowPosition(g_displayWindow, bounds.x, bounds.y);
SDL_SetWindowSize(g_displayWindow, bounds.w, bounds.h);
For non-resizable windows, this works perfectly. On windows created with SDL_WINDOW_RESIZABLE there is an annoying grey border on the bottom and right edges of the screen (on windows). Unfortunately there isn't a SDL_SetWindowResizable function (as of SDL 2.0.4). How can we get rid of the resizing border without recreating the window?
SDL_WINDOW_FULLSCREEN_DESKTOP and SDL_WINDOW_FULLSCREEN both do a modeset which I want to avoid - it takes longer, it's harder to alt-tab out of, and if the game hits a breakpoint in the debugger it can lock up the whole system.
This is what I came up with - tested and works on windows.
void SDL_SetWindowResizable(SDL_Window *win, SDL_bool resizable)
{
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
SDL_GetWindowWMInfo(g_displayWindow, &info);
#if WIN32
HWND hwnd = info.info.win.window;
DWORD style = GetWindowLong(hwnd, GWL_STYLE);
if (resizable)
style |= WS_THICKFRAME;
else
style &= ~WS_THICKFRAME;
SetWindowLong(hwnd, GWL_STYLE, style);
#endif
}
The SDL_SetWindowResizable() function was added in SDL 2.0.5 which was released in Oct 2016. Announcing SDL 2.0.5
Assuming your SDL_Window pointer (that you got from SDL_CreateWindow()) is named window, use:
/* To disable resizing: */
SDL_SetWindowResizable(window, SDL_FALSE);
/* To enable resizing: */
SDL_SetWindowResizable(window, SDL_TRUE);
For my application I need to create a Dialog Box without using resource.
I am trying to do it with DialogBoxInderect function.
The code is unbelievably ugly but somehow I succeeded to do it.
The problem is that dialog, for some reason, is much bigger than I asked with much bigger fonts.
Here is how the dialog looks like if I load it from resource:
And here is the dialog with the same size stated when I call DialogBoxInderect function.
Here is how it is defined in code:
HGLOBAL hGlobal;
LPDLGTEMPLATE wlsDialogTemplate;
LPDLGITEMTEMPLATE wlsDialogItemTemplate;
LPWORD nextItem;
LPWSTR itemString;
int32_t itemStringLength;
// Check for memory allocation errors
hGlobal = GlobalAlloc(GMEM_ZEROINIT, 1024);
if (!hGlobal)
return -1;
wlsDialogTemplate = (LPDLGTEMPLATE)GlobalLock(hGlobal);
// Define a dialog box.
wlsDialogTemplate->style = WS_CAPTION;
wlsDialogTemplate->x = 0;
wlsDialogTemplate->y = 0;
wlsDialogTemplate->cx = 320;
wlsDialogTemplate->cy = 115;
GlobalUnlock(hGlobal);
retCode = DialogBoxIndirect(0, (LPDLGTEMPLATE)hGlobal, 0, ActivateWlsMsgDialog);
And here is how it is defined in RC file:
IDD_WLS_SMALL_MESSAGE_DLG DIALOGEX 0, 0, 320, 115
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",ID_CUSTOM_OK,175,95,120,15
PUSHBUTTON "Cancel",ID_CUSTOM_CANCEL,45,95,120,15
CTEXT "Static",IDC_HEADER_TEXT,120,10,170,70
CONTROL "",IDC_LOGO,"Static",SS_BITMAP,16,10,83,70
END
As you can see, the second dialog is much bigger than defined. I tried to play with various style flags but without any success (That is why there is red cross on the bigger dialog).
Any help with that?
Thanks!
The larger size is easy to explain. Windows automatically sizes the dialog in accordance with its font, and the larger dialog uses a different font. In fact, it is using the default system font (more info on the confusing issue of Windows dialog fonts is found in my answer here).
So the real issue to focus on is why it's using a different font, and fixing that will solve the size problem.
In the dialog box resource file, you specify the DS_SETFONT flag as one of the dialog box styles. According to the documentation, this flag
[i]ndicates that the header of the dialog box template (either standard or extended) contains additional data specifying the font to use for text in the client area and controls of the dialog box. If possible, the system selects a font according to the specified font data. The system passes a handle to the font to the dialog box and to each control by sending them the WM_SETFONT message.
So that explains why that one is displaying with the expected font.
The next logical question is what's different about your dynamically-created dialog template, shown with the DialogBoxIndirect function. The culprit is, once again, the DS_SETFONT flag, but in this case, the flag is absent. That means that the dialog doesn't contain any information about which font to use to display its controls, and the system defaults to the default system font (which is the ugly Windows 2.0-era font that you see in the second screenshot).
Once we've come to this understanding, the solution should be obvious: you need to tell the dialog which font you want it to use. There are two possible ways of doing so that come to mind:
You can set the DS_SETFONT flag and provide the font information in the header of the dialog box template as described in the above-linked documentation.
Or you can simply create and set the dialog's font in response to the WM_INITDIALOG message.
The latter is probably what you really want to do, as it allows you to use the actual system font (which, confusingly, is different from what I've been calling the "default" system font), which is Segoe UI in Windows Vista and later. Note that even in your first screenshot, it's using MS Sans Serif and therefore sticks out like a sore thumb in the Aero interface. Again, see this answer for more about fonts than you ever wanted to know and sample code for making this work. You'll need to make sure that you set the font for the dialog itself and all of its child controls.
I had played with DialogBoxIndirect (actually with DialogBoxIndirectParam), and here's the part of the code that sets the font. Observe the DS_SHELLFONT option.
LPWORD lpwAlign(LPWORD lpIn, int nAlignment)
{
return (LPWORD)(((ULONG_PTR)lpIn + nAlignment - 1) & -nAlignment);
}
LRESULT DisplayMyMessage(HINSTANCE hinst, HWND hwndOwner, LPMYMESSAGEPARAMS pParams)
{
WORD mem[1024]; // Buffer for dialog resource
LPDLGTEMPLATEW lpdt; // Pointer to heading resource structure
LPDLGITEMTEMPLATEW lpdit; // Pointer to current control
LPWORD lpw; // Cursor to resource buffer
LPWSTR lpwsz; // Cursor to resource buffer (of type WCHAR)
LPCWSTR lpwszCaption; // Aux pointer for text copying
LRESULT ret; // Function's return value
lpdt = (LPDLGTEMPLATEW)lpwAlign( mem, 4 );
//-----------------------
// Define a dialog box.
//-----------------------
lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION |
DS_MODALFRAME | DS_CENTER | DS_SHELLFONT;
lpdt->dwExtendedStyle = 0;
lpdt->cdit = 3; // number of controls
lpdt->x = 0; lpdt->y = 0;
lpdt->cx = 164; lpdt->cy = 49;
lpw = (LPWORD)(lpdt + 1);
// Dialog menu
*lpw++ = 0;
// Dialog class
*lpw++ = 0;
// Dialog title
for (lpwsz = (LPWSTR)lpw, lpwszCaption = L"Choose language";
*lpwsz++ = *lpwszCaption++;
);
lpw = (LPWORD)lpwsz;
// Dialog font
if ( lpdt->style & (DS_SETFONT | DS_SHELLFONT) )
{
// Size
*lpw++ = 8;
// Typeface name
for (lpwsz = (LPWSTR)lpw, lpwszCaption = L"MS Shell Dlg";
*lpwsz++ = *lpwszCaption++;
);
lpw = (LPWORD)lpwsz;
}
// Define the rest of the controls
...
ret = DialogBoxIndirectParamW( hinst, lpdt,
hwndOwner, MyMessageProc, (LPARAM)pParams );
return ret;
}
This can be solved in your dialog handler by looking for the WM_INITDIALOG message, and then setting the font for all the controls in the dialog.
int CALLBACK SetChildFont(HWND child, LPARAM font) {
SendMessage(child, WM_SETFONT, font, TRUE);
return TRUE;
}
static int CALLBACK MyMessageProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_INITDIALOG:
/* Set font for dialog and all child controls */
EnumChildWindows(hwnd, (WNDENUMPROC)SetChildFont, (LPARAM)GetStockObject(DEFAULT_GUI_FONT));
break;
}
return 0;
}