MegRay
MegRay

Reputation: 65

CloseWindow doesn't minimize window from the process I just launched

Well I want to minimize the window after starting the window but it doesn't take effect and I don't know what I'm doing wrong. Can you please point out the mistake in the code below?

Nothing happens other than that a window is opened.

HWND  g_hwnd;
int  g_nFound;

BOOL CALLBACK FindHwndFromPID(HWND hwnd, LPARAM lParam);

HWND GetHwndFromPID(DWORD dwProcessId)
{
g_hwnd = NULL;
g_nFound = 0;

EnumWindows(FindHwndFromPID, (LPARAM)dwProcessId);

if (g_hwnd)  // we found one...
    return (g_hwnd);

// nothing found :-(

return (NULL);
}

BOOL CALLBACK FindHwndFromPID(HWND hwnd, LPARAM lParam)
{
DWORD   dwPID2Find = (DWORD)lParam;
DWORD   dwPID = 0;

if (GetWindowThreadProcessId(hwnd, &dwPID))
{
    if (dwPID == dwPID2Find)
    {
        g_hwnd = hwnd;


        return  (FALSE);
    }
}

return  (TRUE);
}


 int main
 {
     ..../
 if (!CreateProcessA(NULL,     // No module name (use command line)
     command_line.GetBuffer(),
     NULL,           // Process handle not inheritable
     NULL,           // Thread handle not inhberitable
     FALSE,          // Set handle inheritance to FALSE
     0,              // No creation flags
     NULL,           // Use parent's environment block
     NULL,           // Use parent's starting directory 
     &si,            // Pointer to STARTUPINFO structure
     &pi)           // Pointer to PROCESS_INFORMATION structure
     )
 {

     //... error handling
     return 0;
 }

 WaitForInputIdle(pi.hProcess, 1000);
 HWND hwnds = GetHwndFromPID(pi.dwProcessId);

 printf("Process Handle %d, hwnd id: %p ",pi.dwProcessId, hwnds);

 CloseWindow(hwnds);

That code is supposed to minimize the window but I don't know why it doesn't.

Upvotes: 0

Views: 439

Answers (2)

milevyo
milevyo

Reputation: 2180

because the application window may not belong to the started process, but instead it belongs to its child process, you have to go deeper in FindHwndFromPID by including the parent process in the comparison.

also we shall not count on WaitForInputIdle() by it self, you have to give the created process enough time to fully initialize.

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <tlhelp32.h>

HWND  g_hwnd;
int  g_nFound;

BOOL CALLBACK FindHwndFromPID(HWND hwnd, LPARAM lParam);
/*___________________________________________________________________________________________________
*/
HWND GetHwndFromPID(DWORD dwProcessId)
{
    g_hwnd = NULL;
    g_nFound = 0;

    EnumWindows(FindHwndFromPID, (LPARAM)dwProcessId);

    if (g_hwnd)  // we found one...
        return (g_hwnd);

    // nothing found :-(

    return (NULL);
}
/*___________________________________________________________________________________________________
*/
DWORD GetParentProcess(DWORD pid){
    PROCESSENTRY32 p32={sizeof(PROCESSENTRY32)};
    DWORD ParentPID=0;
    HANDLE hSnapShot =  CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0 );
    if(Process32First(hSnapShot,&p32)){
        do{
            if(p32.th32ProcessID==pid){
                ParentPID = p32.th32ParentProcessID;
                break;
            }
        }while(Process32Next(hSnapShot,&p32));
    }
    CloseHandle(hSnapShot);

    return ParentPID;

}
/*___________________________________________________________________________________________________
*/
int __stdcall WindowText(HWND hWnd,LPSTR lpString,int nMaxCount){
    int ret;
    ret=SendMessage(hWnd,WM_GETTEXTLENGTH,0,0);
    if(ret){
        ret=SendMessage(hWnd,WM_GETTEXT,nMaxCount,(LPARAM)lpString);
    }
    return ret;
}
/*___________________________________________________________________________________________________
*/
BOOL CALLBACK FindHwndFromPID(HWND hwnd, LPARAM lParam){
    DWORD   dwPID2Find = (DWORD)lParam;
    DWORD   dwPID = 0;

    if(GetWindowLong(hwnd,GWLP_HWNDPARENT) || !IsWindowVisible(hwnd))
        return 1;

    if (GetWindowThreadProcessId(hwnd, &dwPID)){
        if ((dwPID == dwPID2Find) || ( GetParentProcess(dwPID) == dwPID2Find)){
            g_hwnd = hwnd;
            return  (FALSE);
        }
    }

    return  (TRUE);
}
/*___________________________________________________________________________________________________
*/

int main(){
    PROCESS_INFORMATION pi;
    STARTUPINFO si={sizeof(si)};
    TCHAR exename[]=TEXT("write.exe"); // writable buffer (for Unicode bug.)
    if (!CreateProcess(NULL,exename,NULL,    NULL,FALSE, 0,     NULL,NULL,&si,     &pi)){
        return 0;
    }


   //WaitForInputIdle(pi.hProcess, 1000); // this alown will not always work (process may have children)

   // give enough time to process to fully initialize
   // put all in a loop until you
   // get the window handle or timeout.

HWND hwnds = GetHwndFromPID(pi.dwProcessId);
for( int i=0 ;i<1000;i++ ){
    if(hwnds)
        break;
    Sleep(10); 
    hwnds = GetHwndFromPID(pi.dwProcessId);
}

    printf("Process Handle %d, hwnd id: %p ",pi.dwProcessId, hwnds);

    CloseWindow(hwnds);


    return 0;
}

Upvotes: 1

Remy Lebeau
Remy Lebeau

Reputation: 595377

You are going about this the wrong way. The official and documented way to ask a spawned process to run initially minimized is to use the STARTUPINFO structure when calling CreateProcess(), eg:

int main()
{
    STARTUPINFO si;
    ZeroMemory(&si, sizeof(si));
    si.cbSize = sizeof(si);
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_MINIMIZE;

    //...

    if (!CreateProcessA(..., &si, ...))
    {
        //... error handling
        return 0;
    }

    //...

    return 0;
}

STARTUPINFO structure

wShowWindow
If dwFlags specifies STARTF_USESHOWWINDOW, this member can be any of the values that can be specified in the nCmdShow parameter for the ShowWindow function, except for SW_SHOWDEFAULT. Otherwise, this member is ignored.

For GUI processes, the first time ShowWindow is called, its nCmdShow parameter is ignored wShowWindow specifies the default value. In subsequent calls to ShowWindow, the wShowWindow member is used if the nCmdShow parameter of ShowWindow is set to SW_SHOWDEFAULT.

ShowWindow function

nCmdShow [in]
Type: int

Controls how the window is to be shown. This parameter is ignored the first time an application calls ShowWindow, if the program that launched the application provides a STARTUPINFO structure. Otherwise, the first time ShowWindow is called, the value should be the value obtained by the WinMain function in its nCmdShow parameter.

...

The first time an application calls ShowWindow, it should use the WinMain function's nCmdShow parameter as its nCmdShow parameter. Subsequent calls to ShowWindow must use one of the values in the given list, instead of the one specified by the WinMain function's nCmdShow parameter.

As noted in the discussion of the nCmdShow parameter, the nCmdShow value is ignored in the first call to ShowWindow if the program that launched the application specifies startup information in the structure. In this case, ShowWindow uses the information specified in the STARTUPINFO structure to show the window. On subsequent calls, the application must call ShowWindow with nCmdShow set to SW_SHOWDEFAULT to use the startup information provided by the program that launched the application. This behavior is designed for the following situations:

• Applications create their main window by calling CreateWindow with the WS_VISIBLE flag set.

• Applications create their main window by calling CreateWindow with the WS_VISIBLE flag cleared, and later call ShowWindow with the SW_SHOW flag set to make it visible.

Upvotes: 4

Related Questions