tags:

views:

36

answers:

1

I am writing a master installer with the following ShellExecuteEx() function that call a few Advanced Installer created installers (installing multiple products) one by one through a loop construct.

// Shell Execute 
bool CFileHelper::ShellExecute(CString strCommandPath, CString strOptions)
{

    CString strQCommandPath = CString(_T("\"")) + strCommandPath +  CString(_T("\""));  //place the command in the quote to handle path with space

    LPWSTR szInstallerPath = strQCommandPath.GetBuffer();
    LPWSTR szOptions = strOptions.GetBuffer(MAX_PATH);

    SHELLEXECUTEINFO ShellInfo; // Name structure

    memset(&ShellInfo, 0, sizeof(ShellInfo)); // Set up memory block
    ShellInfo.cbSize = sizeof(ShellInfo); // Set up structure size
    ShellInfo.hwnd = 0; // Calling window handle
    ShellInfo.lpVerb = _T("open"); 
    ShellInfo.lpFile = szInstallerPath; 
    ShellInfo.fMask = SEE_MASK_NOCLOSEPROCESS; //| SEE_MASK_NOASYNC | SEE_MASK_WAITFORINPUTIDLE;
    ShellInfo.lpParameters = szOptions;
    bool res = ShellExecuteEx(&ShellInfo); // Call to function
    if (!res)
    {
        //printf( "CreateProcess failed (%d).\n", GetLastError() );
        CString strMsg = CString(_T("Failed to execute command ")) + strCommandPath +  CString(_T("!"));
        AfxMessageBox(strMsg);
        return false;
    }

    WaitForSingleObject(ShellInfo.hProcess, INFINITE); // wait forever for process to finish
    //WaitForInputIdle(ShellInfo.hProcess, INFINITE);

    CloseHandle( ShellInfo.hProcess);

    strQCommandPath.ReleaseBuffer();
    strOptions.ReleaseBuffer();
    return true;
}

The function work every well when I have this master installer and other individual product installers on hard drive.

However, if I move all of them to either USB drive or CD, the ShellExecuteEx() didn't wait for the previous product installer to complete its task. So all product installers get lunched at once; giving me the error message "Another installation is in progress. You must complete that installation before continuing this one.".

One thing puzzle me is why it works on hard drive but not on USB drive and CD drive. I need to distribute the products on CD.

Putting Sleep(500) before WaitForSingleObject(ShellInfo.hProcess, INFINITE) didn't help as well.

+2  A: 

Work from the assumption that this is real. The installer might have noticed it was started from a removable drive and copied itself to the hard disk. Launched that copy and quit. This avoids trouble when the user pops out the media, that produces a very low-level paging fault that the process itself cannot catch. The Windows dialog isn't great and may well run counter to the installer's request to insert the next disk.

Verify this guess by comparing the process ID of the process you started vs the one you see running in Taskmgr.exe. Reliably fixing this ought to be quite a headache.

Hans Passant
But I have the handle ShellInfo.hProcess here. How can I get PID from this handle?
david.healed
@david - use GetProcessId().
Hans Passant
@Hans - You are right. I have tested and found out that once they are on the removable drive, the process IDs are different. Any idea how to address this?
david.healed
Ah, score one for psychic debugging. I think what I would try is iterate the running processes with CreateToolhelp32Snapshot() when the process completes. Process32First/Next, looking for PROCESSENTRY32.th32ParentProcessID to find a child process that was started by the installer. No idea if that still works when the process is completed.
Hans Passant
@Hans - It works. Thank you very much!
david.healed