Search code examples
c++windowswinapimedia-playershellexecute

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).

Solution

  • 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.