PDA

View Full Version : LaunchAppAndWait privilege elevation problem - Error 740 on Vista



djappy
07-02-2007, 05:18 AM
I am attempting to launch another process using LaunchAppAndWait from within an IS2008 Basic MSI project. However, on Vista, the app fails to launch and the return code from LaunchAppAndWait is 740 - which I believe is ERROR_ELEVATION_REQUIRED. That makes sense since the launched app is another install (I know that nested installs are bad - but this worked before on Vista using IS12).

Is there a way around this problem? - I don't mind another UAC dialog popping up if it has to - I'd just prefer that the system attempted to gain elevated privileges somehow rather than just failing.

MichaelU
07-02-2007, 10:40 AM
I would suggest using the new LaunchApplication API with the LAAW_OPTION_USE_SHELLEXECUTE flag. This makes it use ShellExecute (which can show UAC prompts) instead of CreateProcess (which won't). Don't forget to fill in the SHELLEXECUTEINFO structure.

peterbi
04-03-2008, 01:39 PM
Hi,

I got problem calling LaunchAppAndWait() on Vista, but it sounds different from the one posted here.

In a Basic MSI project (IS 2008), we call our CA by a dll function, the (C++) function itself calls (c) LaunchAppAndWait(), which I posted the function code here:
/////////////////////////////////////////////////////////////////////////////
int LaunchAppAndWait
(
const char* szProgram, // Executable to be launched with command-line
// parameters.
BOOL bWait, // TRUE = Launch exe and wait until it's done.
// FALSE = Launch exe and continue.
int iShow, // SW_SHOWNORMAL = Normal console window (if applicable).
// SW_HIDE = Launch the program invisibly.
// Other ShowWindow() switches can be used.
int iTimeOut, // Time-out interval, in milliseconds. The function
// returns if the interval elapses, even if the
// launched process is not finished (only if WAIT
// was specified in the third parameter).
// Use INFINITE to wait indefinitely.
ULONG& ulReturn // Returns the result code of the launched program
// (only if bWait = TRUE). If the function returns
// before the launched process is finished (because
// the time-out interval has elapsed) STILL_ACTIVE
// is returned in this parameter.
)
{
STARTUPINFO stStartupInfo;
PROCESS_INFORMATION stProcessInfo;

// Initialize the process structures.
ZeroMemory(&stStartupInfo,sizeof(stStartupInfo));
stStartupInfo.cb = sizeof(stStartupInfo);
stStartupInfo.dwFlags = STARTF_USESHOWWINDOW;
stStartupInfo.wShowWindow = iShow;
ZeroMemory(&stProcessInfo,sizeof(stProcessInfo));

// CreateProcess has difficulties with its first and second arguments. So,
// combine everything and pass it all into the second parameter.
int iLen = strlen(szProgram) + 1;
char* szExe = new char[iLen];
strcpy_s(szExe,iLen,szProgram);

// Start the process.
if (!CreateProcess(0,szExe,0,0,FALSE,0,0,0,&stStartupInfo,&stProcessInfo)) {
// Process didn't start.
if (szExe) delete []szExe;
return -1;
}

// Not waiting for process to end. Set the return codes.
if (!bWait) {
ulReturn = 1;
return 0;
}

// Wait until the process is done, then get the return code.
WaitForSingleObject(stProcessInfo.hProcess,iTimeOut);
GetExitCodeProcess(stProcessInfo.hProcess,&ulReturn);
CloseHandle(stProcessInfo.hProcess);
CloseHandle(stProcessInfo.hThread);
if (szExe) delete []szExe;
return 0;
}
/////////////////////////////////////////////////////////////

And the CA function is:

//////////////////////////////////////////
UINT WINAPI ManagePeernet
(
MSIHANDLE hMSI // Handle to the MSI database.
)
{
int iErr = 0;
ULONG ulReturn = 0;
CString sDestUNCPath(""),sExe(""),sKey(""),sPeerNet(""),sRemove("");

PeernetSetupProps* pPnProps = new PeernetSetupProps(hMSI);
sRemove = pPnProps->m_szRemove;
sPeerNet = pPnProps->m_szPeerNet;
sDestUNCPath = pPnProps->m_szMapDriveUNCPath;

// Check if the Target Directory is a map drive or not.
if (sDestUNCPath != "0") {
// Mapped Drive.
CStrPathAppend(sDestUNCPath,"MyProd\\Peernet\\");
sPeerNet = sDestUNCPath;
}

CString sLog("");
sLog.Format("sPeerNet = %s ",sPeerNet);
LogStr(hMSI,"ManagePeernet",sLog);

// Install Peernet.
// PDF driver.
sExe = sPeerNet;
CStrPathAppend(sExe,"pdf\\PNSetup.exe");
LogStr(hMSI,"ManagePeernet",sExe);
iErr = LaunchAppAndWait(sExe,TRUE,SW_SHOWNORMAL,INFINITE,ulReturn);

//debug
CString sDbg("");
sDbg.Format("iErr=%d, ulReturn=%d", iErr, ulReturn);
LogStr(hMSI, "LaunchAppAndWait return for PDF", sDbg);

// TIFF driver.
sExe = sPeerNet;
CStrPathAppend(sExe,"tiff\\PNSetup.exe");
LogStr(hMSI,"ManagePeernet",sExe);
iErr = LaunchAppAndWait(sExe,TRUE,SW_SHOWNORMAL,INFINITE,ulReturn);

//debug
sDbg.Format("iErr=%d, ulReturn=%d", iErr, ulReturn);
LogStr(hMSI, "LaunchAppAndWait return for tiff", sDbg);

return ERROR_SUCCESS;
}
////////////////////////////////////////////////

The installation worked fine on systems except Vista, here are the installation log results from the above (ManagePeernet) function from a W2K (succeeded to install Peernet) and a Vista (failed to install Peernet):

//////////////////////////////////////////////////////////
from W2K:
----------
Custom Function: PeerNetSetupProps: 0|M:\MyComp\PeerNet\|\\Mylab7112\My_test|
Custom Function: PeernetSetupProps: LogClass
m_szRemove = 0
m_szPeerNet = M:\MyComp\PeerNet\
m_szMapDriveUNCPath = \\Mylab7112\My_test

Custom Function: ManagePeernet: sPeerNet = \\Mylab7112\My_test\MyComp\Peernet\
Custom Function: ManagePeernet: \\Mylab7112\My_test\MyComp\Peernet\pdf\PNSetup.exe
Custom Function: LaunchAppAndWait return for PDF: iErr=0, ulReturn=0
Custom Function: ManagePeernet: \\Mylab7112\My_test\MyComp\Peernet\tiff\PNSetup.exe
Custom Function: LaunchAppAndWait return for PDF: iErr=0, ulReturn=0
-----------------------------


from Vista:
-----------
Custom Function: PeerNetSetupProps: 0|M:\MyComp\PeerNet\|\\Mylab7112\My_test|
Custom Function: PeernetSetupProps: LogClass
m_szRemove = 0
m_szPeerNet = M:\MyComp\PeerNet\
m_szMapDriveUNCPath = \\Mylab7112\My_test

Custom Function: ManagePeernet: sPeerNet = \\Mylab7112\My_test\MyComp\Peernet\
Custom Function: ManagePeernet: \\Mylab7112\My_test\MyComp\Peernet\pdf\PNSetup.exe
Custom Function: LaunchAppAndWait return for PDF: iErr=-1, ulReturn=0
Custom Function: ManagePeernet: \\Mylab7112\My_test\MyComp\Peernet\tiff\PNSetup.exe
Custom Function: LaunchAppAndWait return for PDF: iErr=-1, ulReturn=0
------------------------------------------------

I am confused that in both cases, the CreateProcess() call failed (ulReturn=0), why is it to W2K (since it succeeded to install peernet)? How can I know what's wrong with Vista (I bet something wrong on CreateProcess() call on Vista?)?

I saw MichaelU suggested to use LaunchApplication on Vista instead of LaunchAppAndWait, how can I do it in my c/c++ code (I have the functions above), can you give some samples?


Thanks,
Peter

peterbi
04-03-2008, 06:30 PM
Some updates -

First of all, I think I forgot to mention that our installation environment might be different from others: we run installation on one a mapped drive (say 'M', the drive mapps to a shared folder created on the system) of a system as server, and under the installation there is a 'setup' folder contains another installer to allow clients' installation, the only requirement is that a client needs to create the same mapped drive ('M') to point to the server's shared folder (eg. \\server_system\shared_folder).

My problem (failed on Vista) only happens when: a Vista has different domain/workgroup from the other system(s) AND the Vista is a client (i.e. running setup will try to execute files from drive that is mapped to other machine in different domain/workgroup). The opposite works - if the Vista is installed as server, other non Vista systems (W2K, XP, W2K3, in different domain/workgroup) can install as client without problems.

Now I used 'ShellExecute' instead of LaunchAppAndWait (for Vista only) in my code as following:


////////////////////////////////////////
UINT WINAPI ManagePeernet
(
MSIHANDLE hMSI // Handle to the MSI database.
)
{
int iErr = 0;
ULONG ulReturn = 0;
CString sDestUNCPath(""),sExe(""),sKey(""),sPeerNet(""),sRemove("");

PeernetSetupProps* pPnProps = new PeernetSetupProps(hMSI);
sRemove = pPnProps->m_szRemove;
sPeerNet = pPnProps->m_szPeerNet;
sDestUNCPath = pPnProps->m_szMapDriveUNCPath;

// Check if the Target Directory is a map drive or not.
if (sDestUNCPath != "0") {
// Mapped Drive.
CStrPathAppend(sDestUNCPath,"MyComp\\Peernet\\");
sPeerNet = sDestUNCPath;
}

CString sLog("");
sLog.Format("sPeerNet = %s ",sPeerNet);
LogStr(hMSI,"ManagePeernet",sLog);


CString sOS(""),sSP("");
int iVersion = GetOSInfo(hMSI,sOS,sSP);

//For Vista
SHELLEXECUTEINFO shExecInfo;

shExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);

CString sRunAs("runas");

shExecInfo.fMask = NULL;
shExecInfo.hwnd = NULL;
shExecInfo.lpVerb = sRunAs;
shExecInfo.lpParameters = NULL;
shExecInfo.lpDirectory = NULL;
shExecInfo.nShow = SW_MAXIMIZE;
shExecInfo.hInstApp = NULL;

if (sRemove != "ALL") {
// Install Peernet.

// PDF driver.
sExe = sPeerNet;
CStrPathAppend(sExe,"pdf\\PNSetup.exe");
LogStr(hMSI,"ManagePeernet",sExe);
if (iVersion >= IOsWinVista)
{
shExecInfo.lpFile = sExe;
ShellExecuteEx(&shExecInfo);
}
else
iErr = LaunchAppAndWait(sExe,TRUE,SW_SHOWNORMAL,INFINITE,ulReturn);

// TIFF driver.
sExe = sPeerNet;
CStrPathAppend(sExe,"tiff\\PNSetup.exe");
LogStr(hMSI,"ManagePeernet",sExe);
if (iVersion >= IOsWinVista)
{
shExecInfo.lpFile = sExe;
ShellExecuteEx(&shExecInfo);
}
else
iErr = LaunchAppAndWait(sExe,TRUE,SW_SHOWNORMAL,INFINITE,ulReturn);

return ERROR_SUCCESS;
}
/////////////////////////////////////////////////////

Installation on Vista resulted in the attached error messages, which is for authority or credentials, and Peernet drivers are not installed. Anybody knows how to overcome the problems?

I hope somebody there knows what I am saying and doing, and gets clues on the issue(s) I am facing - I am really frustrated to it!

Thanks,
Peter