Start chromium browser in minimized state (Win32/WinAPI) - c++

I want to start browser in minimized state, however in this list there's no option for minimizing. So I thought of using ShowWindow() but some issues arise. I don't know how to use EnumWindows() or its derivatives. Only alternative I know is GetWindow() but I'm not sure of the position of window at Z-order. This is my solution:
HWND hwnd,hwnd2; //hwnd is my application's top level window
char t[128];
std::string t2;
for(int i=0; i<128&&t2!="found"; i++)
{
if(!i||i==64) hwnd2=hwnd; //turn direction
hwnd2=GetWindow(hwnd2,i<64?2:3); //loop backwards and forwards
GetWindowText(hwnd2,t,GetWindowTextLength(hwnd2)+1);
t2=t; if(t2.find("New")!=-1) t2="Found"; //Default title is "New Tab..."
}
ShowWindow(hwnd2,SW_MINIMIZE);
Assuming there won't be more than 128 windows, it works fine but since a window takes ~2 seconds to open, at the time ShowWindow() occurs, the window is not yet ready. So I used a timer for it.
SetTimer(hwnd,1,2000,0);
and
case WM_TIMER:
KillTimer(hwnd,1);
ShowWindow(hwnd2,SW_MINIMIZE);
break;
But it's impossible to know the exact time so the window gets minimized after it's shown for some milliseconds. I tried setting multiple timers in an interval of 50ms.
for(int i=0; i<50; i++) SetTimer(hwnd,1+i,i*50,0);
and
case WM_TIMER:
KillTimer(hwnd,wParam);
ShowWindow(hwnd2,SW_MINIMIZE);
break;
It usually minimizes window before it's shown, not always though. Also it changes the cursor to busy state every 50ms. Is there a way to stop this when the minimizing successfully performed once? It's not possible to determine this from the return value of ShowWindow() so is there a way? How can minimizing window before it's shown be guaranteed? Can I somehow make it wait till browser window is ready then sending ShowWindow() on the right time at once? How can I improve my solution into an easier one?

WinExec gives you very little control over spawned process.
Use CreateProcess, and set LPSTARTUPINFOA lpStartupInfo's WORD wShowWindow; to SW_MINIMIZE
Make sure that dwFlags contains STARTF_USESHOWWINDOW
Here is how to use it:
#include <windows.h>
int main()
{
PROCESS_INFORMATION processInformation = { 0 };
STARTUPINFO startupInfo = { sizeof STARTUPINFO };
startupInfo.dwFlags = STARTF_USESHOWWINDOW;
startupInfo.wShowWindow = SW_MINIMIZE;
wchar_t cmd[] = L"C:\\Program Files\\Internet Explorer\\iexplore.exe";
// Create the process
BOOL result = CreateProcess(NULL,
cmd, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
FALSE, // handles are not inherited
NORMAL_PRIORITY_CLASS |
CREATE_NO_WINDOW, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&startupInfo, // STARTUPINFO pointer
&processInformation); // receives PROCESS_INFORMATION
}
UPDATE
In the referenced doc, they state:
the wShowWindow member is used if the nCmdShow parameter of ShowWindow is set to SW_SHOWDEFAULT.
There is similar comment on the position and size field.
Apparently, some application do NOT use the defaults. For example, chrome and calc open their window at the position it was closed previously.
You can find that stored location in the Registry and update it.
More info
Google Chrome default opening position and size suggests to edit Preferences file. It looks like this:
"window_placement":{"bottom":1363,"left":406,"maximized":false,"right":1356,"top":217,"visible":false,"work_area_bottom":1400,"work_area_left":0,"work_area_right":2560,"work_area_top":0}
I've tried to invent keys like minimized, hidden, visible - no luck :)
You could shift the window off-screen; I have partial success - chrome moves it back in so at least a few pixels show...

Related

Redirecting child process stdout via console screen buffer in Windows 10 C++

I am trying to redirect the stdout of a child process in Windows. Both are console programs. I don't have the source code of the child process, so I can't force it to flush the buffer. As discussed here and here, for the implementation of printf and similar, the C runtime buffers everything except consoles and printers. So the solution is apparently to create a console screen buffer using, appropriately enough, CreateConsoleScreenBuffer. I'm using the approach from codeproject.
PROCESS_INFORMATION pi;
HANDLE hConsole;
const COORD origin = { 0, 0 };
// Default security descriptor. Set inheritable.
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE; // So the child can use it
// Create and initialize screen buffer
hConsole = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE, // Desired access
FILE_SHARE_WRITE | FILE_SHARE_READ, // share mode to child processes
&sa, // SECURITY_ATTRIBUTES
CONSOLE_TEXTMODE_BUFFER, // Must be this.
NULL // Reserved. Must be NULL
);
DWORD dwDummy;
FillConsoleOutputCharacter(hConsole, '\0', MAXLONG, origin, &dwDummy)
Now I direct the child's stdout to the console and start the process
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_FORCEOFFFEEDBACK | STARTF_USESTDHANDLES; // first one prevents cursor from showing loading.
si.hStdOutput = hConsole;
//...
// Get the command line and environmental block
//...
if (! CreateProcess(
NULL, // module name.
(char*)command_line.c_str(), // command line
NULL, // process SECURITY_ATTRIBUTES
NULL, // thread SECURITY_ATTRIBUTES
TRUE, // inherit handles
NULL, // creation flags
enviros, // environmentBlock (enviros=NULL for testing)
cDir, // working directory
&si, // STARTUP_INFO object
&pi // PROCESSINFO
) ){
auto test = GetLastError();
CloseHandle(hConsole);
return false;
}
CloseHandle(pi.hThread);
Then, in a loop, I can use ReadConsoleOutputCharacter to grab output, as shown at the codeproject link. It looks like
//... some initialization
GetConsoleScreenBufferInfo(hConsole, &csbi);
DWORD count = (csbi.dwCursorPosition.Y - lastpos.Y)*lineWidth + csbi.dwCursorPosition.X - lastpos.X;
LPTSTR buffer = (LPTSTR)LocalAlloc(0, count * sizeof(TCHAR));
ReadConsoleOutputCharacter(hConsole, buffer, count, lastpos, &count);
DWORD dwDummy;
FillConsoleOutputCharacter(hConsole, '\0', count, lastpos, &dwDummy);
//... Now move the cursor and grab the data from `buffer`
On Windows 7/8.1 this works fine for all programs. On Windows 10, some programs seem to be bypassing the supplied handles and printing directly to the parent console, preventing me from grabbing the output as I need.
I do have an additional clue. If I force the process to create a new console window, i.e.
CreateProcess(NULL, (char*)command_line.c_str(), NULL, NULL, TRUE, CREATE_NEW_CONSOLE, enviros, cDir, &si, &pi)
but still redirect the handles in the STARTUPINFO object, the new console will display a single line that says The system cannot write to the specified device, which just happens to be the exact wording of Windows error code ERROR_WRITE_FAULT = 29 in the MSDN docs. This happens only for those programs which aren't working as expected. Other programs, the new console is blank and they still function as expected.
My first thought is a permissions problem, but I have wide open permissions on the directories of the relevant executables.
Things I've tried
A different computer with Windows 10
Different versions of MS Visual C++ runtime
Setting the working directory explicitly in CreateProcess
Adding a super-permissive DACL to a SECURITY_ATTRIBUTES object passed to CreateProcess
Adding a super-permissive DACL to a SECURITY_ATTRIBUTES object passed to CreateConsoleScreenBuffer
Moving everything to a newly created directory under my Windows user directory
Running as administrator
Deeper
Thank you #PaulSanders for your suggestion.
To aid with anyone who might want to assist, I've made available a modified version of the RTConsole code from the codeproject page. It should compile in Visual Studio with just a retarget, I think. Around line 135, I've prepended a little string to the front of the output which takes the expected path. I've provided a pre-compiled version in there for convenience, as well.
One example of software that doesn't work is EWBF miner. For a quick test using the code I provided above, you could run
RTConsole2.exe "path\to\ewbf.exe" --help
You'll see that the prepended flag is not present in the output.
On the other hand, with ccminer, you'll get the expected behavior when running
RTConsole2.exe "path\to\ccminer.exe" --help
The new console implementation in Windows 10 has a bug in which high-level WriteConsole and WriteFile to a non-active screen buffer instead always writes to the active screen buffer. Low-level WriteConsoleOutput[Character] works correctly. Using the legacy console also works. You can enable the legacy console in the properties dialog.
Note that a process cannot use an inherited handle for a screen buffer in the parent's console if it allocates a new console due to the CREATE_NEW_CONSOLE flag. Trying to write to the screen-buffer file will fail because it's not bound to the caller's attached console (i.e. instance of conhost.exe).
Console files that are bound include "CON", "CONIN$", "CONOUT$", and a new screen buffer from CreateConsoleScreenBuffer. There are also unbound input and output console files, which are set as the standard handles when allocating a new console (e.g. via AllocConsole()). These handles access the input buffer and active screen buffer of any attached console [*]. Note that a process can have handles for console files that are bound to multiple consoles and can switch between consoles using AttachConsole.
Note also that some programs open "CONOUT$" instead of writing to the StandardOutput and StandardError handles, especially if they require a console instead of whatever the standard handles might be (e.g. a pipe or disk file). In this case it is not enough to set hStdOutput in STARTUPINFO. You have to temporarily make the new screen buffer active via SetConsoleActiveScreenBuffer. This does not affect the caller's standard handles. It sets the active screen buffer in the attached console, which is what "CONOUT$" opens. The previous screen buffer can be restored after the child process exits, or after you know the child has already opened and written to the new screen buffer.
[*] In Windows 8+, these console files are implemented by the condrv.sys device driver and opened on "\Device\ConDrv". They are respectively named "Console", "CurrentIn", "CurrentOut", "ScreenBuffer", "Input", and "Output". The filename for the console connection itself is "Connect". Internally the latter is opened as the process ConsoleHandle, which is used implicitly by the console API in some cases (e.g. GetConsoleWindow, GetConsoleCP, and GetConsoleTitle).

How to force open file "silently" (minimized, not active) using c++ WinAPI functional?

In my WinAPI C++ application I am trying to open an audio file with the default system player using ShellExecuteEx:
int OpenFileWithDefaultProgram(const std::wstring& path, int showMode, HANDLE* hProc) {
SHELLEXECUTEINFO shInfo;
::ZeroMemory(&shInfo, sizeof(SHELLEXECUTEINFO));
shInfo.cbSize = sizeof(SHELLEXECUTEINFO);
shInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
shInfo.hwnd = NULL;
shInfo.lpVerb = L"open";
shInfo.lpFile = path.c_str();
shInfo.nShow = showMode;
::ShellExecuteEx(&shInfo);
*hProc = shInfo.hProcess;
return (int)shInfo.hInstApp;
}
The OpenFileWithDefaultProgram function is called this way:
HANDLE hProc;
int error = OpenFileWithDefaultProgram(path, SW_SHOWMINNOACTIVE, &hProc);
if (error <= 32) {
// Process error
} else {
// Some actions
}
However SW_SHOWMINNOACTIVE parameter is ignored by some players (e.g. MediaPlayerClassic HomeCinema - MPC HC), which leads to opening a player with changing the foreground window and even showing player window not minimized on some PCs.
The first question is: is it possible to force opening player in "silent" mode (minimized and not becoming active)?
I have also tried using GetForegroundWindow and SetForegroundWindow, which didn't help until I added Sleep right after OpenFileWithDefaultProgram (as I understand, the player needs some time to initialize and during this time the foreground window doesn't change):
HWND hWndForeground = GetForegroundWindow();
HANDLE hProc;
int error = OpenFileWithDefaultProgram(path, SW_SHOWMINNOACTIVE, &hProc);
if (error <= 32) {
// Process error
} else {
Sleep(100);
SetForegroundWindow(hWndForeground);
// Some actions
}
This code restored the foreground window perfectly, but I do not like the constant I need to use as a parameter of Sleep function.
Consequently, the second question is: is it possible to "wake up" the thread at the exact moment when the player is initialized? Alternatively, how should I determine the time needed for player initialization (considering that the default player can be anything and take really different time to start)?
Note:
I tried calling WaitForSingleObject(hProc, INFINITE), it just doesn't finish waiting since the player is not terminating after the playback;
I tried calling WaitForInputIdle(hProc, INFINITE), it returns immediately without waiting (probably, since the player does not have a message queue).
The first question is: is it possible to force opening player in "silent" mode (minimized and not becoming active)?
No, the best you can do is request it, and requests can be ignored. You already discovered that part.
The second question: is it possible to "wake up" the thread at the exact moment when the player is initialized?
No, there's no moment defined when a process is fully initialized. You already discovered WaitForInputIdle and its restrictions. But imagine a media player that fetches a CD cover image in the background (not that far-fetched, no need to delay audio for that)—when does it finish initialization?
Also, keep in mind that ShellExecute might not even start a new process. If there is an existing one, it may use it to open the file.

Issues trying to display a configuration window for my screensaver (from a GUI app running with high mandatory integrity level)

I have an old project that comes with its own screensaver. The GUI application for the project has an option to "Configure screensaver" that should bring up my screensaver configuration window (that you would normally get from a Control Panel -> Display -> Personalization -> Screensaver -> Settings.)
To display the configuration window, one needs to call the screensaver process with the /c parameter as described here. The screensaver itself is placed into the system directory, i.e. "C:\Windows\System32".
So to emulate this from my (32-bit) GUI application I do the following:
//Error checks are omitted for brevity
BOOL bResult = FALSE;
TCHAR buffSysFldr[MAX_PATH];
buffSysFldr[0] = 0;
::GetSystemDirectory(buffSysFldr, SIZEOF(buffSysFldr));
//Make the path, which basically becomes:
// "C:\Windows\System32\mysvr.scr" /c
TCHAR buff[MAX_PATH];
buff[0] = 0;
::StringCbPrintf(buff, sizeof(buff), L"\"%s\\mysvr.scr\" /c", buffSysFldr);
STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0};
ZeroMemory(&si,sizeof(si));
ZeroMemory(&pi,sizeof(pi));
si.cb = sizeof(si);
PVOID OldValue;
Wow64DisableWow64FsRedirection(&OldValue);
//And run it
if(CreateProcess(NULL, buff, NULL, NULL, FALSE,
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
NULL, NULL, &si, &pi))
{
//Success
bResult = TRUE;
}
Wow64RevertWow64FsRedirection(OldValue);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
When I deploy it to the Windows 7 machine, the code above returns bResult = TRUE but my screensaver's configuration window is never shown.
I tried it on both 32-bit and 64-bit Windows 7 thinking that Wow64 redirection has something to do with it, but it still didn't change the outcome.
Any idea why this doesn't work?
PS. When I copy and paste that command into a command prompt it runs just fine and displays my configuration window w/o a problem:
EDIT: After further review, it turns out that the issue seems to be connected to the fact that my GUI applications runs with High Mandatory Integrity Level, or S-1-16-12288, which seems to be the reason why the screensaver's configuration window is not shown. If I run my GUI app with its regular Medium integrity level, or S-1-16-8192, the configuration window shows OK.
Otherwise, I can see that my screensaver's RegisterDialogClasses method is called OK, but then when I return TRUE from it, ScreenSaverConfigureDialog is never called.
Since integrity level was introduced to prevent processes with lower levels to send messages to processes with higher levels, evidently the screensaver configuration mechanism tries to send some messages to my GUI app (for whatever undocumented reason) and fails and then silently fails as well ...
So this is the latest. I'll appreciate any input on this from whoever knows how to solve this (apart from lowering the integrity level of my GUI app, that I obviously don't want to do.)
God damn Microsoft documentation (sorry, I just wasted the whole day today trying to fix it.)
For whoever else runs into this -- it turns out one needs to call it as such:
"C:\Windows\System32\mysvr.scr" /c:N
where N is a window handle of the parent window expressed as an integer. Found it out by checking command line of the configuration window displayed via Control Panel (did it using Process Explorer.)
In my case, since my GUI process runs with higher integrity level, doing the following will suffice:
HWND hWndToUse = ::GetDesktopWindow();
::StringCbPrintf(buff, sizeof(buff), L"\"%s\\mysvr.scr\" /c:%d", buffSysFldr, (int)hWndToUse);
And that's it!

Make interactive console/window interaction in gui application

What i want:
An application, where there are a gui window and console window. Window can be clicked on, dragged, etcetera. At any given moment, console can be chosen, and a line entered, that will be processed.
What i already have:
An application, that allocates and attaches console to itself, then redirects standard streams to it. Code is:
AllocConsole() ;
AttachConsole( GetCurrentProcessId());
freopen("CONIN$","rb",stdin); // reopen stdin handle as console window input
freopen("CONOUT$","wb",stdout); // reopen stout handle as console window output
freopen("CONOUT$","wb",stderr); // reopen stderr handle as console window output
Then registers window class, creates and shows a window. Output into console works fine, interaction with window is correct.
However, i cannot input anything into console. I can make a guess about it: if i call something like std::cin >> my_string, i will be able to enter a line - but interaction with a window will stop until the input is completed. Is that correct? How can i make application behave in a way i described above?
update:
I have found related question: Test if stdin has input for C++ (windows and/or linux)
The code for determining, whether there are characters in console input was given there as follows:
bool StdinOpen() {
static HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
DWORD bytes_left;
PeekNamedPipe(handle, NULL, 0, NULL, &bytes_left, NULL);
return bytes_left;
}
However, it returns some exorbitant numbers, as if there always is input in console.
I'd start by initializing the bytes_left variable and check the return value.
bool StdinOpen() {
static HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
DWORD bytes_left = 0;
if (!PeekNamedPipe(handle, NULL, 0, NULL, &bytes_left, NULL))
return false;
return bytes_left != 0;
}

First and last window don't show up

I'm creating a WinApi application for my programming course. The program is supposed to show an LED clock using a separate window for each 'block'. I have figured most of it out, except for one thing: when creating the two-dimensional array of windows, the first and last window never show up. Here's the piece of code from the InitInstance function:
for (int x=0;x<8;x++)
for (int y=0;y<7;y++) {
digitWnd[x][y] = CreateWindowEx((WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOACTIVATE | WS_EX_STATICEDGE),
szWindowClass, szTitle, (WS_POPUP| WS_BORDER), NULL, NULL, NULL, NULL, dummyWnd, NULL, hInstance, NULL);
ShowWindow(digitWnd[x][y], nCmdShow);
UpdateWindow(digitWnd[x][y]);
}
The same loop bounds are used everytime I interact with the windows (set position and enable/disable). All the windows seem to be working fine, except for digitWnd[0][0] and digitWnd[7][6]... Any ideas as to what is happening?
Open Spy++ and check if the missing windows are really missing or just overlapped by other windows. It's possible that you have some small error in the position calculations code that puts them behind another window or outside of the screen.
To validate your creation mechanism I would check:
the array initialisation HWND digitWnd[8][7]
if the parent window dummyWnd is valid
the return value of CreateWindowEx() != NULL
Another point which comes to my mind is, that you create windows with dimension 0 - no width or height. So maybe it would be a good idea to set the size within CreateWindowEx(...)
Is this your first call to ShowWindow()? If so, according to MSDN, "nCmdShow: [in] Specifies how the window is to be shown. This parameter is ignored the first time an application calls ShowWindow". This could mean that you can fix your program by simply calling ShowWindow() twice. Give it a try and see if it works. Other than that, you'll probably have to provide more of the code for us to look at.