Reputation: 1231
I have an .exe file to be executed during installation. It is executed well when msi file is launched by bootstrapper(an .exe file that launches main msi file) but is not executed properly when launched by msi itself. It seems that this problem is related to privilege, because my bootstrapper acquires privilege when it is launched and if I execute msi in cmd.exe that has privilege, it executes the .exe file well.
It's real problem comes when I enter maintenance mode from ARP menu in Control Panel. The .exe file is executed according to some feature's action state. It is executed well when I enter maintenance mode from original msi launched by bootstrapper(it has privilege), but is not executed well when I enter maintenance mode from ARP menu in Control Panel.
I want it to be executed equally well when I enter manintenance mode from ARP menu in Control Panel.
Below is part of my code.
<CustomAction Id="CA1" BinaryKey="file.exe" ExeCommand="" Execute="deferred" Return="asyncNoWait" />
...
<Custom Action="CA1" Before="InstallFinalize"><![CDATA[&Feat1=3]]></Custom>
Thank you.
Upvotes: 0
Views: 1452
Reputation: 55571
You're custom action is already scheduled in the deferred between InstallInitialize and InstallFinalize. What's missing is the Impesonate attribute that needs to be set to 'no'. This will cause it to run elevated in the system context. Currently it's impersonating the user who started the install and if that process isn't elevated your EXE won't be elevated.
Also for calling an EXE I'd look at the WiX Quiet Execute Custom Action. Finally be sure to read and understand Installation Phases and In-Script Execution Options for Custom Actions in Windows Installer.
Upvotes: 1
Reputation: 3797
This is how I do it, I know it is not the correct way but for the moment it is the only way I could achieve what was needed.
My custom action to extract the binary data, write to a new file in Temp Folder and execute the file.
extern "C" UINT __stdcall InstallDrivers(MSIHANDLE hInstall)
{
//AssertSz(FALSE, "debug here");
//DebugBreak();
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
HANDLE hFile = INVALID_HANDLE_VALUE;
BYTE* pbData = NULL;
DWORD cbData = 0, hProcess = 0;
char pwzFilename[MAX_PATH], szDriverType[MAX_PATH], pwzSentinelFilename[MAX_PATH], szIsInstalled[MAX_PATH];
LPWSTR szValueBuf = NULL, szIsHaspInstalled = NULL, szIsSentinelInstalled = NULL;
SHELLEXECUTEINFO ShExecInfo;
WINDOWPROCESSINFO info;
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = NULL;
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = _T("open");
ShExecInfo.lpParameters = NULL;
ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_SHOWNORMAL;
ShExecInfo.hInstApp = NULL;
ShExecInfo.hProcess = NULL;
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC | SEE_MASK_WAITFORINPUTIDLE;
hr = WcaInitialize(hInstall, "InstallDrivers");
ExitOnFailure(hr, "Failed to initialize");
WcaLog(LOGMSG_STANDARD, "Initialized.");
CreateDirectory("C:\\Temp", NULL);
strcpy_s(pwzFilename, "C:\\Temp\\HASPUserSetup.exe");
hr = ExtractBinary(L"Hasp", &pbData, &cbData);
ExitOnFailure(hr, "failed to extract binary data");
if ((hFile = CreateFile(pwzFilename, GENERIC_WRITE,FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
{
PMSIHANDLE hRecord = MsiCreateRecord(0);
MsiRecordSetString(hRecord, 0, TEXT("Could not create new temporary file"));
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord);
return ERROR_INSTALL_USEREXIT;
}
DWORD cbWritten = 0;
if ( !WriteFile(hFile, pbData, cbData, &cbWritten, NULL) )
{
PMSIHANDLE hRecord = MsiCreateRecord(0);
MsiRecordSetString(hRecord, 0, TEXT("Could not write to file"));
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord);
return ERROR_INSTALL_USEREXIT;
}
CloseHandle(hFile);
strcpy_s(pwzSentinelFilename, "C:\\Temp\\sentinel_setup.exe");
hr = ExtractBinary(L"Sentinel", &pbData, &cbData);
ExitOnFailure(hr, "failed to extract binary data");
if ((hFile = CreateFile(pwzSentinelFilename, GENERIC_WRITE,FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
{
PMSIHANDLE hRecord = MsiCreateRecord(0);
MsiRecordSetString(hRecord, 0, TEXT("Could not create new temporary file"));
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord);
return ERROR_INSTALL_USEREXIT;
}
if ( !WriteFile(hFile, pbData, cbData, &cbWritten, NULL) )
{
PMSIHANDLE hRecord = MsiCreateRecord(0);
MsiRecordSetString(hRecord, 0, TEXT("Could not write to file"));
MsiProcessMessage(hInstall, INSTALLMESSAGE(INSTALLMESSAGE_ERROR + MB_OK), hRecord);
return ERROR_INSTALL_USEREXIT;
}
CloseHandle(hFile);
hr = WcaGetProperty(L"DRIVER", &szValueBuf);
ExitOnFailure(hr, "failed to get driver info");
wcstombs(szDriverType, szValueBuf, 260);
if (strcmp(szDriverType, "Hasp") == 0)
{
hr = WcaGetProperty(L"SENTINELINSTALLED", &szIsSentinelInstalled);
ExitOnFailure(hr, "failed to get driver info");
wcstombs(szIsInstalled, szValueBuf, 260);
if (strcmp(szIsInstalled, "Sentinel Protection Installer 7.6.5") == 0)
{
ShExecInfo.lpFile = pwzSentinelFilename;
ShellExecuteEx(&ShExecInfo);
info.pid = GetProcessId(ShExecInfo.hProcess);
info.hwnd = 0;
AllowSetForegroundWindow(info.pid);
EnumWindows(OnGetWindowByProcess, (LPARAM)&info);
SetWindowPos( info.hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
if (info.hwnd != 0)
{
SetForegroundWindow(info.hwnd);
SetActiveWindow(info.hwnd);
}
WaitForSingleObject(ShExecInfo.hProcess,INFINITE);
CloseHandle(ShExecInfo.hProcess);
}
ShExecInfo.lpFile = pwzFilename;
ShellExecuteEx(&ShExecInfo);
info.pid = GetProcessId(ShExecInfo.hProcess);
info.hwnd = 0;
AllowSetForegroundWindow(info.pid);
EnumWindows(OnGetWindowByProcess, (LPARAM)&info);
SetWindowPos( info.hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
if (info.hwnd != 0)
{
SetForegroundWindow(info.hwnd);
SetActiveWindow(info.hwnd);
}
WaitForSingleObject(ShExecInfo.hProcess,INFINITE);
CloseHandle(ShExecInfo.hProcess);
}else
{
hr = WcaGetProperty(L"HASPINSTALLED", &szIsHaspInstalled);
ExitOnFailure(hr, "failed to get driver info");
wcstombs(szIsInstalled, szIsHaspInstalled, 260);
if (strcmp(szIsInstalled, "Sentinel Runtime") == 0)
{
ShExecInfo.lpFile = pwzFilename;
ShellExecuteEx(&ShExecInfo);
info.pid = GetProcessId(ShExecInfo.hProcess);
info.hwnd = 0;
AllowSetForegroundWindow(info.pid);
EnumWindows(OnGetWindowByProcess, (LPARAM)&info);
SetWindowPos( info.hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
if (info.hwnd != 0)
{
SetForegroundWindow(info.hwnd);
SetActiveWindow(info.hwnd);
}
WaitForSingleObject(ShExecInfo.hProcess,INFINITE);
CloseHandle(ShExecInfo.hProcess);
}
ShExecInfo.lpFile = pwzSentinelFilename;
ShellExecuteEx(&ShExecInfo);
info.pid = GetProcessId(ShExecInfo.hProcess);
info.hwnd = 0;
AllowSetForegroundWindow(info.pid);
EnumWindows(OnGetWindowByProcess, (LPARAM)&info);
SetWindowPos( info.hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
if (info.hwnd != 0)
{
SetForegroundWindow(info.hwnd);
SetActiveWindow(info.hwnd);
}
WaitForSingleObject(ShExecInfo.hProcess,INFINITE);
CloseHandle(ShExecInfo.hProcess);
}
LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
And the extract binary code:
/********************************************************************
ExtractBinary - helper function
********************************************************************/
HRESULT ExtractBinary(
__in LPCWSTR wzBinaryId,
__out BYTE** pbData,
__out DWORD* pcbData
)
{
HRESULT hr = S_OK;
LPWSTR pwzSql = NULL;
PMSIHANDLE hView;
PMSIHANDLE hRec;
// make sure we're not horked from the get-go
hr = WcaTableExists(L"Binary");
if (S_OK != hr)
{
if (SUCCEEDED(hr))
{
hr = E_UNEXPECTED;
}
ExitOnFailure(hr, "There is no Binary table.");
}
ExitOnNull(wzBinaryId, hr, E_INVALIDARG, "Binary ID cannot be null");
ExitOnNull(*wzBinaryId, hr, E_INVALIDARG, "Binary ID cannot be empty string");
hr = StrAllocFormatted(&pwzSql, L"SELECT `Data` FROM `Binary` WHERE `Name`=\'%s\'", wzBinaryId);
ExitOnFailure(hr, "Failed to allocate Binary table query.");
hr = WcaOpenExecuteView(pwzSql, &hView);
ExitOnFailure(hr, "Failed to open view on Binary table");
hr = WcaFetchSingleRecord(hView, &hRec);
ExitOnFailure(hr, "Failed to retrieve request from Binary table");
hr = WcaGetRecordStream(hRec, 1, pbData, pcbData);
ExitOnFailure(hr, "Failed to read Binary.Data.");
LExit:
ReleaseStr(pwzSql);
return hr;
}
Upvotes: 0