|
|
//=======================================================================
//
// Copyright (c) 1998-2001 Microsoft Corporation. All Rights Reserved.
//
// File: install.cpp
//
// Description:
//
// Functions called to install Active Setup/Windows Installer/and Custom Installer
// type components.
//
//=======================================================================
#include <windows.h>
#include <iucommon.h>
#include <tchar.h>
#include <shlwapi.h>
#include <install.h>
#include <advpub.h>
#include <memutil.h>
#include <fileutil.h>
#include <WaitUtil.h>
#include <strsafe.h>
#include <wusafefn.h>
typedef struct { char szInfname[MAX_PATH]; char szSection[MAX_PATH]; char szDir[MAX_PATH]; char szCab[MAX_PATH]; DWORD dwFlags; DWORD dwType; } INF_ARGUMENTS;
DWORD WINAPI LaunchInfCommand(void *p);
HRESULT InstallSoftwareItem(LPTSTR pszInstallSourcePath, BOOL fRebootRequired, LONG lNumberOfCommands, PINSTALLCOMMANDINFO pCommandInfoArray, DWORD *pdwStatus) { LOG_Block("InstallASItem");
HRESULT hr = S_OK; TCHAR szCommand[MAX_PATH+1]; // sourcepath + commandname from INSTALLCOMMANDINFO array
TCHAR szCommandTemp[MAX_PATH+1]; // temporary buffer used to wrap the command line in quotes for CreateProcess
TCHAR szDecompressFile[MAX_PATH]; WIN32_FIND_DATA fd; HANDLE hProc; HANDLE hFind; BOOL fMore; LONG lCnt; DWORD dwRet; DWORD dwThreadId;
USES_IU_CONVERSION;
if ((NULL == pszInstallSourcePath) || (NULL == pCommandInfoArray) || (0 == lNumberOfCommands) || (NULL == pdwStatus)) { hr = E_INVALIDARG; hr = LOG_ErrorMsg(hr); return hr; }
*pdwStatus = ITEM_STATUS_FAILED; // default to failed in case no commands match known installers
// Need to enumerate all .CAB files in the Install Source Path and Decompress them
// before executing commands.
hr = PathCchCombine(szCommand, ARRAYSIZE(szCommand), pszInstallSourcePath, _T("*.cab")); if (FAILED(hr)) { LOG_ErrorMsg(hr); return hr; } hFind = FindFirstFile(szCommand, &fd); fMore = (INVALID_HANDLE_VALUE != hFind); while (fMore) { if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { hr = PathCchCombine(szDecompressFile, ARRAYSIZE(szDecompressFile), pszInstallSourcePath, fd.cFileName); if (FAILED(hr)) { LOG_ErrorMsg(hr); } else { if (!IUExtractFiles(szDecompressFile, pszInstallSourcePath)) { LOG_Software(_T("Failed to Decompress file %s"), szDecompressFile); // ISSUE: do we abort this item?, or try the install anyway?
} } } fMore = FindNextFile(hFind, &fd); }
if (INVALID_HANDLE_VALUE != hFind) { FindClose(hFind); }
for (lCnt = 0; lCnt < lNumberOfCommands; lCnt++) { // the szCommand variable is used to launch a process (msi or exe installer), but because of
// oddities in the CreateProcess API's handling of the commandline parameter we need to wrap
// the command line in quotes.
hr = SafePathCombine(szCommandTemp, ARRAYSIZE(szCommandTemp), pszInstallSourcePath, pCommandInfoArray[lCnt].szCommandLine, SPC_FILE_MUST_EXIST); if (SUCCEEDED(hr)) hr = StringCchPrintf(szCommand, ARRAYSIZE(szCommand), _T("\"%s\""), szCommandTemp); if (FAILED(hr)) { LOG_ErrorMsg(hr); return hr; }
switch (pCommandInfoArray[lCnt].iCommandType) { case COMMANDTYPE_INF: case COMMANDTYPE_ADVANCEDINF: { // Call INF Installer Passing Commandline and Parameters (if any)
INF_ARGUMENTS infArgs; infArgs.dwType = pCommandInfoArray[lCnt].iCommandType;
hr = StringCchCopyA(infArgs.szInfname, ARRAYSIZE(infArgs.szInfname), T2A(pCommandInfoArray[lCnt].szCommandLine)); if (SUCCEEDED(hr)) { hr = StringCchCopyA(infArgs.szSection, ARRAYSIZE(infArgs.szSection), ""); // use default
} if (SUCCEEDED(hr)) { hr = StringCchCopyA(infArgs.szDir, ARRAYSIZE(infArgs.szDir), T2A(pszInstallSourcePath)); } if (SUCCEEDED(hr)) { hr = StringCchCopyA(infArgs.szCab, ARRAYSIZE(infArgs.szCab), ""); } if (FAILED(hr)) { LOG_ErrorMsg(hr); break; }
infArgs.dwFlags = StrToInt(pCommandInfoArray[lCnt].szCommandParameters); LOG_Software(_T("Launching Inf - inf: %hs, section: %hs"), infArgs.szInfname, lstrlenA(infArgs.szSection) ? infArgs.szSection : "Default");
hr = E_FAIL; // default INF result to E_FAIL.. if GetExitCodeThread fails so did the install
hProc = CreateThread(NULL, 0, LaunchInfCommand, &infArgs, 0, &dwThreadId); if (NULL != hProc) { WaitAndPumpMessages(1, &hProc, QS_ALLINPUT); if (GetExitCodeThread(hProc, &dwRet)) { hr = HRESULT_FROM_WIN32(dwRet); if (SUCCEEDED(hr) || hr == HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED)) { *pdwStatus = ITEM_STATUS_SUCCESS; if (hr == HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED)) { hr = S_OK; *pdwStatus = ITEM_STATUS_SUCCESS_REBOOT_REQUIRED; } } else { LOG_Error(_T("Inf Failed - return code %x"), hr); } } else { LOG_Software(_T("Failed to get Install Thread Exit Code")); } } else { hr = GetLastError(); LOG_ErrorMsg(hr); } CloseHandle(hProc); break; } case COMMANDTYPE_EXE: { // Call EXE Installer Passing Commandline and Parameters (if any)
STARTUPINFO startInfo; PROCESS_INFORMATION processInfo; ZeroMemory(&startInfo, sizeof(startInfo)); startInfo.cb = sizeof(startInfo); startInfo.dwFlags |= STARTF_USESHOWWINDOW; startInfo.wShowWindow = SW_SHOWNORMAL;
if (NULL != pCommandInfoArray[lCnt].szCommandParameters) { hr = StringCchCat(szCommand, ARRAYSIZE(szCommand), _T(" ")); if (FAILED(hr)) { LOG_ErrorMsg(hr); break; } hr = StringCchCat(szCommand, ARRAYSIZE(szCommand), pCommandInfoArray[lCnt].szCommandParameters); if (FAILED(hr)) { LOG_ErrorMsg(hr); break; } }
if (CreateProcess(NULL, szCommand, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, pszInstallSourcePath, &startInfo, &processInfo)) { CloseHandle(processInfo.hThread); hr = S_OK; // Default EXE result to S_OK, if GetExitCodeProcess fails result was unknown assume success
WaitAndPumpMessages(1, &processInfo.hProcess, QS_ALLINPUT); if (GetExitCodeProcess(processInfo.hProcess, &dwRet)) { hr = HRESULT_FROM_WIN32(dwRet); if (SUCCEEDED(hr) || hr == HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED)) { *pdwStatus = ITEM_STATUS_SUCCESS; if (hr == HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED)) { hr = S_OK; *pdwStatus = ITEM_STATUS_SUCCESS_REBOOT_REQUIRED; } } else { LOG_Software(_T("EXE Install Failed - return code %x"), hr); } } else { LOG_Software(_T("Failed to get Install Process Exit Code")); } } else { hr = GetLastError(); LOG_ErrorMsg(hr); } CloseHandle(processInfo.hProcess); break; } case COMMANDTYPE_MSI: { // Call MSI Installer Passing MSI Package and Parameters (if any)
STARTUPINFO startInfo; PROCESS_INFORMATION processInfo; ZeroMemory(&startInfo, sizeof(startInfo)); startInfo.cb = sizeof(startInfo); startInfo.dwFlags |= STARTF_USESHOWWINDOW; startInfo.wShowWindow = SW_SHOWNORMAL;
// The MSI Installer is run a little differently than a normal EXE package. The command line in
// CommandInfo Array will actually be the MSI package name. We are going to form a new set of
// parameters to include the MSI package name and command line will be MSIEXEC.
TCHAR szCommandLine[MAX_PATH]; hr = StringCchPrintf( szCommandLine, ARRAYSIZE(szCommandLine), _T("msiexec.exe /i %s %s"), pCommandInfoArray[lCnt].szCommandLine, pCommandInfoArray[lCnt].szCommandParameters ); if (FAILED(hr)) { LOG_ErrorMsg(hr); break; } if (CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, pszInstallSourcePath, &startInfo, &processInfo)) { CloseHandle(processInfo.hThread); hr = E_FAIL; // Default MSI install result to Error
WaitAndPumpMessages(1, &processInfo.hProcess, QS_ALLINPUT); if (GetExitCodeProcess(processInfo.hProcess, &dwRet)) { hr = HRESULT_FROM_WIN32(dwRet); if (SUCCEEDED(hr) || hr == HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED)) { *pdwStatus = ITEM_STATUS_SUCCESS; if (hr == HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED)) { hr = S_OK; *pdwStatus = ITEM_STATUS_SUCCESS_REBOOT_REQUIRED; } } else { LOG_Software(_T("MSI Install Failed - return code %x"), hr); } } else { LOG_Software(_T("Failed to get Install Process Exit Code")); } } else { hr = GetLastError(); LOG_ErrorMsg(hr); } CloseHandle(processInfo.hProcess); break; } case COMMANDTYPE_CUSTOM: LOG_Software(_T("Custom Install Command Type Not Implemented Yet")); break; default: LOG_Software(_T("Unknown Command Type, No Install Action")); break; } }
return hr; }
DWORD WINAPI LaunchInfCommand(void *p) { HRESULT hr = S_OK;
INF_ARGUMENTS *pinfArgs = (INF_ARGUMENTS *)p;
if(pinfArgs->dwType == COMMANDTYPE_ADVANCEDINF) { CABINFO cabinfo; cabinfo.pszCab = pinfArgs->szCab; cabinfo.pszInf = pinfArgs->szInfname; cabinfo.pszSection = pinfArgs->szSection;
// cabinfo.szSrcPath is a char[MAXPATH] in the CABINFO struct
StringCchCopyA(cabinfo.szSrcPath, ARRAYSIZE(cabinfo.szSrcPath), pinfArgs->szDir); cabinfo.dwFlags = pinfArgs->dwFlags;
hr = ExecuteCab(NULL, &cabinfo, 0); } else { hr = RunSetupCommand(NULL, pinfArgs->szInfname, lstrlenA(pinfArgs->szSection) ? pinfArgs->szSection : NULL, pinfArgs->szDir, NULL, NULL, pinfArgs->dwFlags, NULL ); } return hr; }
|