summaryrefslogtreecommitdiff
path: root/src/windows/installer/wix/custom/custom.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/windows/installer/wix/custom/custom.cpp')
-rw-r--r--src/windows/installer/wix/custom/custom.cpp833
1 files changed, 833 insertions, 0 deletions
diff --git a/src/windows/installer/wix/custom/custom.cpp b/src/windows/installer/wix/custom/custom.cpp
new file mode 100644
index 000000000000..3ef726d1dea0
--- /dev/null
+++ b/src/windows/installer/wix/custom/custom.cpp
@@ -0,0 +1,833 @@
+#ifdef __NMAKE__
+
+# NMAKE portion.
+# Build with : nmake /f custom.cpp
+# Clean with : nmake /f custom.cpp clean
+
+# Builds custom.dll
+
+OUTPATH = .
+
+# program name macros
+CC = cl /nologo
+
+LINK = link /nologo
+
+RM = del
+
+DLLFILE = $(OUTPATH)\custom.dll
+
+DLLEXPORTS =\
+ -EXPORT:EnableAllowTgtSessionKey \
+ -EXPORT:RevertAllowTgtSessionKey \
+ -EXPORT:AbortMsiImmediate \
+ -EXPORT:UninstallNsisInstallation \
+ -EXPORT:KillRunningProcesses \
+ -EXPORT:ListRunningProcesses \
+ -EXPORT:InstallNetProvider \
+ -EXPORT:UninstallNetProvider
+
+$(DLLFILE): $(OUTPATH)\custom.obj
+ $(LINK) /OUT:$@ /DLL $** $(DLLEXPORTS)
+
+$(OUTPATH)\custom.obj: custom.cpp custom.h
+ $(CC) /c /Fo$@ custom.cpp
+
+all: $(DLLFILE)
+
+clean:
+ $(RM) $(DLLFILE)
+ $(RM) $(OUTPATH)\custom.obj
+ $(RM) $(OUTPATH)\custom.exp
+
+!IFDEF __C_TEXT__
+#else
+/*
+
+Copyright 2004,2005 by the Massachusetts Institute of Technology
+
+All rights reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of the Massachusetts
+Institute of Technology (M.I.T.) not be used in advertising or publicity
+pertaining to distribution of the software without specific, written
+prior permission.
+
+M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+*/
+
+/**************************************************************
+* custom.cpp : Dll implementing custom action to install Kerberos for Windows
+*
+* The functions in this file are for use as entry points
+* for calls from MSI only. The specific MSI parameters
+* are noted in the comments section of each of the
+* functions.
+*
+* rcsid: $Id$
+**************************************************************/
+
+#pragma unmanaged
+
+// Only works for Win2k and above
+#define _WIN32_WINNT 0x500
+#include "custom.h"
+#include <shellapi.h>
+
+// linker stuff
+#pragma comment(lib, "msi")
+#pragma comment(lib, "advapi32")
+#pragma comment(lib, "shell32")
+#pragma comment(lib, "user32")
+
+void ShowMsiError( MSIHANDLE hInstall, DWORD errcode, DWORD param ){
+ MSIHANDLE hRecord;
+
+ hRecord = MsiCreateRecord(3);
+ MsiRecordClearData(hRecord);
+ MsiRecordSetInteger(hRecord, 1, errcode);
+ MsiRecordSetInteger(hRecord, 2, param);
+
+ MsiProcessMessage( hInstall, INSTALLMESSAGE_ERROR, hRecord );
+
+ MsiCloseHandle( hRecord );
+}
+
+static void ShowMsiErrorEx(MSIHANDLE hInstall, DWORD errcode, LPTSTR str,
+ DWORD param )
+{
+ MSIHANDLE hRecord;
+
+ hRecord = MsiCreateRecord(3);
+ MsiRecordClearData(hRecord);
+ MsiRecordSetInteger(hRecord, 1, errcode);
+ MsiRecordSetString(hRecord, 2, str);
+ MsiRecordSetInteger(hRecord, 3, param);
+
+ MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecord);
+
+ MsiCloseHandle(hRecord);
+}
+
+#define LSA_KERBEROS_KEY "SYSTEM\\CurrentControlSet\\Control\\Lsa\\Kerberos"
+#define LSA_KERBEROS_PARM_KEY "SYSTEM\\CurrentControlSet\\Control\\Lsa\\Kerberos\\Parameters"
+#define KFW_CLIENT_KEY "SOFTWARE\\MIT\\Kerberos\\Client\\"
+#define SESSKEY_VALUE_NAME "AllowTGTSessionKey"
+
+#define SESSBACKUP_VALUE_NAME "AllowTGTSessionKeyBackup"
+#define SESSXPBACKUP_VALUE_NAME "AllowTGTSessionKeyBackupXP"
+
+
+/* Set the AllowTGTSessionKey registry keys on install. Called as a deferred custom action. */
+MSIDLLEXPORT EnableAllowTgtSessionKey( MSIHANDLE hInstall ) {
+ return SetAllowTgtSessionKey( hInstall, TRUE );
+}
+
+/* Unset the AllowTGTSessionKey registry keys on uninstall. Called as a deferred custom action. */
+MSIDLLEXPORT RevertAllowTgtSessionKey( MSIHANDLE hInstall ) {
+ return SetAllowTgtSessionKey( hInstall, FALSE );
+}
+
+UINT SetAllowTgtSessionKey( MSIHANDLE hInstall, BOOL pInstall ) {
+ TCHAR tchVersionString[1024];
+ TCHAR tchVersionKey[2048];
+ DWORD size;
+ DWORD type;
+ DWORD value;
+ HKEY hkKfwClient = NULL;
+ HKEY hkLsaKerberos = NULL;
+ HKEY hkLsaKerberosParm = NULL;
+ UINT rv;
+ DWORD phase = 0;
+
+ // construct the backup key path
+ size = sizeof(tchVersionString) / sizeof(TCHAR);
+ rv = MsiGetProperty( hInstall, _T("CustomActionData"), tchVersionString, &size );
+ if(rv != ERROR_SUCCESS) {
+ if(pInstall) {
+ ShowMsiError( hInstall, ERR_CUSTACTDATA, rv );
+ return rv;
+ } else {
+ return ERROR_SUCCESS;
+ }
+ }
+
+ _tcscpy( tchVersionKey, _T( KFW_CLIENT_KEY ) );
+ _tcscat( tchVersionKey, tchVersionString );
+
+ phase = 1;
+
+ rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, tchVersionKey, 0, ((pInstall)?KEY_WRITE:KEY_READ), &hkKfwClient );
+ if(rv != ERROR_SUCCESS)
+ goto cleanup;
+
+ phase = 2;
+
+ rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, _T( LSA_KERBEROS_KEY ), 0, KEY_READ | KEY_WRITE, &hkLsaKerberos );
+ if(rv != ERROR_SUCCESS)
+ goto cleanup;
+
+ phase = 3;
+
+ rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, _T( LSA_KERBEROS_PARM_KEY ), 0, KEY_READ | KEY_WRITE, &hkLsaKerberosParm );
+ if(rv != ERROR_SUCCESS) {
+ hkLsaKerberosParm = NULL;
+ }
+
+ if(pInstall) {
+ // backup the existing values
+ if(hkLsaKerberosParm) {
+ phase = 4;
+
+ size = sizeof(value);
+ rv = RegQueryValueEx( hkLsaKerberosParm, _T( SESSKEY_VALUE_NAME ), NULL, &type, (LPBYTE) &value, &size );
+ if(rv != ERROR_SUCCESS)
+ value = 0;
+
+ phase = 5;
+ rv = RegSetValueEx( hkKfwClient, _T( SESSBACKUP_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value));
+ if(rv != ERROR_SUCCESS)
+ goto cleanup;
+ }
+
+ phase = 6;
+ size = sizeof(value);
+ rv = RegQueryValueEx( hkLsaKerberos, _T( SESSKEY_VALUE_NAME ), NULL, &type, (LPBYTE) &value, &size );
+ if(rv != ERROR_SUCCESS)
+ value = 0;
+
+ phase = 7;
+ rv = RegSetValueEx( hkKfwClient, _T( SESSXPBACKUP_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value));
+ if(rv != ERROR_SUCCESS)
+ goto cleanup;
+
+ // and now write the actual values
+ phase = 8;
+ value = 1;
+ rv = RegSetValueEx( hkLsaKerberos, _T( SESSKEY_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value));
+ if(rv != ERROR_SUCCESS)
+ goto cleanup;
+
+ if(hkLsaKerberosParm) {
+ phase = 9;
+ value = 1;
+ rv = RegSetValueEx( hkLsaKerberosParm, _T( SESSKEY_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value));
+ if(rv != ERROR_SUCCESS)
+ goto cleanup;
+ }
+
+ } else { // uninstalling
+ // Don't fail no matter what goes wrong. This is also a rollback action.
+ if(hkLsaKerberosParm) {
+ size = sizeof(value);
+ rv = RegQueryValueEx( hkKfwClient, _T( SESSBACKUP_VALUE_NAME ), NULL, &type, (LPBYTE) &value, &size );
+ if(rv != ERROR_SUCCESS)
+ value = 0;
+
+ RegSetValueEx( hkLsaKerberosParm, _T( SESSKEY_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value));
+ }
+
+ size = sizeof(value);
+ rv = RegQueryValueEx( hkKfwClient, _T( SESSXPBACKUP_VALUE_NAME ), NULL, &type, (LPBYTE) &value, &size );
+ if(rv != ERROR_SUCCESS)
+ value = 0;
+
+ RegSetValueEx( hkLsaKerberos, _T( SESSKEY_VALUE_NAME ), 0, REG_DWORD, (LPBYTE) &value, sizeof(value));
+
+ RegDeleteValue( hkKfwClient, _T( SESSXPBACKUP_VALUE_NAME ) );
+ RegDeleteValue( hkKfwClient, _T( SESSBACKUP_VALUE_NAME ) );
+ }
+
+ // all done
+ rv = ERROR_SUCCESS;
+
+cleanup:
+ if(rv != ERROR_SUCCESS && pInstall) {
+ ShowMsiError(hInstall, 4005, phase);
+ }
+ if(hkKfwClient) RegCloseKey( hkKfwClient );
+ if(hkLsaKerberos) RegCloseKey( hkLsaKerberos );
+ if(hkLsaKerberosParm) RegCloseKey( hkLsaKerberosParm );
+
+ return rv;
+}
+
+/* Abort the installation (called as an immediate custom action) */
+MSIDLLEXPORT AbortMsiImmediate( MSIHANDLE hInstall ) {
+ DWORD rv;
+ DWORD dwSize = 0;
+ LPTSTR sReason = NULL;
+ LPTSTR sFormatted = NULL;
+ MSIHANDLE hRecord = NULL;
+ LPTSTR cAbortReason = _T("ABORTREASON");
+
+ rv = MsiGetProperty( hInstall, cAbortReason, _T(""), &dwSize );
+ if(rv != ERROR_MORE_DATA) goto _cleanup;
+
+ sReason = new TCHAR[ ++dwSize ];
+
+ rv = MsiGetProperty( hInstall, cAbortReason, sReason, &dwSize );
+
+ if(rv != ERROR_SUCCESS) goto _cleanup;
+
+ hRecord = MsiCreateRecord(3);
+ MsiRecordClearData(hRecord);
+ MsiRecordSetString(hRecord, 0, sReason);
+
+ dwSize = 0;
+
+ rv = MsiFormatRecord(hInstall, hRecord, "", &dwSize);
+ if(rv != ERROR_MORE_DATA) goto _cleanup;
+
+ sFormatted = new TCHAR[ ++dwSize ];
+
+ rv = MsiFormatRecord(hInstall, hRecord, sFormatted, &dwSize);
+
+ if(rv != ERROR_SUCCESS) goto _cleanup;
+
+ MsiCloseHandle(hRecord);
+
+ hRecord = MsiCreateRecord(3);
+ MsiRecordClearData(hRecord);
+ MsiRecordSetInteger(hRecord, 1, ERR_ABORT);
+ MsiRecordSetString(hRecord,2, sFormatted);
+ MsiProcessMessage(hInstall, INSTALLMESSAGE_ERROR, hRecord);
+
+_cleanup:
+ if(sFormatted) delete sFormatted;
+ if(hRecord) MsiCloseHandle( hRecord );
+ if(sReason) delete sReason;
+
+ return ~ERROR_SUCCESS;
+}
+
+/* Kill specified processes that are running on the system */
+/* Uses the custom table KillProcess. Called as an immediate action. */
+
+#define MAX_KILL_PROCESSES 255
+#define FIELD_SIZE 256
+
+struct _KillProc {
+ TCHAR * image;
+ TCHAR * desc;
+ BOOL found;
+ DWORD pid;
+};
+
+#define RV_BAIL if(rv != ERROR_SUCCESS) goto _cleanup
+
+MSIDLLEXPORT KillRunningProcesses( MSIHANDLE hInstall ) {
+ return KillRunningProcessesSlave( hInstall, TRUE );
+}
+
+/* When listing running processes, we populate the ListBox table with
+ values associated with the property 'KillableProcesses'. If we
+ actually find any processes worth killing, then we also set the
+ 'FoundProcceses' property to '1'. Otherwise we set it to ''.
+*/
+
+MSIDLLEXPORT ListRunningProcesses( MSIHANDLE hInstall ) {
+ return KillRunningProcessesSlave( hInstall, FALSE );
+}
+
+UINT KillRunningProcessesSlave( MSIHANDLE hInstall, BOOL bKill )
+{
+ UINT rv = ERROR_SUCCESS;
+ _KillProc * kpList;
+ int nKpList = 0;
+ int i;
+ int rowNum = 1;
+ DWORD size;
+ BOOL found = FALSE;
+
+ MSIHANDLE hDatabase = NULL;
+ MSIHANDLE hView = NULL;
+ MSIHANDLE hViewInsert = NULL;
+ MSIHANDLE hRecord = NULL;
+ MSIHANDLE hRecordInsert = NULL;
+
+ HANDLE hSnapshot = NULL;
+
+ PROCESSENTRY32 pe;
+
+ kpList = new _KillProc[MAX_KILL_PROCESSES];
+ memset(kpList, 0, sizeof(*kpList) * MAX_KILL_PROCESSES);
+
+ hDatabase = MsiGetActiveDatabase( hInstall );
+ if( hDatabase == NULL ) {
+ rv = GetLastError();
+ goto _cleanup;
+ }
+
+ // If we are only going to list out the processes, delete all the existing
+ // entries first.
+
+ if(!bKill) {
+
+ rv = MsiDatabaseOpenView( hDatabase,
+ _T( "DELETE FROM `ListBox` WHERE `ListBox`.`Property` = 'KillableProcesses'" ),
+ &hView); RV_BAIL;
+
+ rv = MsiViewExecute( hView, NULL ); RV_BAIL;
+
+ MsiCloseHandle( hView );
+
+ hView = NULL;
+
+ rv = MsiDatabaseOpenView( hDatabase,
+ _T( "SELECT * FROM `ListBox` WHERE `Property` = 'KillableProcesses'" ),
+ &hViewInsert); RV_BAIL;
+
+ MsiViewExecute(hViewInsert, NULL);
+
+ hRecordInsert = MsiCreateRecord(4);
+
+ if(hRecordInsert == NULL) {
+ rv = GetLastError();
+ goto _cleanup;
+ }
+ }
+
+ // Open a view
+ rv = MsiDatabaseOpenView( hDatabase,
+ _T( "SELECT `Image`,`Desc` FROM `KillProcess`" ),
+ &hView); RV_BAIL;
+
+ rv = MsiViewExecute( hView, NULL ); RV_BAIL;
+
+ do {
+ rv = MsiViewFetch( hView, &hRecord );
+ if(rv != ERROR_SUCCESS) {
+ if(hRecord)
+ MsiCloseHandle(hRecord);
+ hRecord = NULL;
+ break;
+ }
+
+ kpList[nKpList].image = new TCHAR[ FIELD_SIZE ]; kpList[nKpList].image[0] = _T('\0');
+ kpList[nKpList].desc = new TCHAR[ FIELD_SIZE ]; kpList[nKpList].desc[0] = _T('\0');
+ nKpList++;
+
+ size = FIELD_SIZE;
+ rv = MsiRecordGetString(hRecord, 1, kpList[nKpList-1].image, &size); RV_BAIL;
+
+ size = FIELD_SIZE;
+ rv = MsiRecordGetString(hRecord, 2, kpList[nKpList-1].desc, &size); RV_BAIL;
+
+ MsiCloseHandle(hRecord);
+ } while(nKpList < MAX_KILL_PROCESSES);
+
+ hRecord = NULL;
+
+ // now we have all the processes in the array. Check if they are running.
+
+ hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
+ if(hSnapshot == INVALID_HANDLE_VALUE) {
+ rv = GetLastError();
+ goto _cleanup;
+ }
+
+ pe.dwSize = sizeof( PROCESSENTRY32 );
+
+ if(!Process32First( hSnapshot, &pe )) {
+ // technically we should at least find the MSI process, but we let this pass
+ rv = ERROR_SUCCESS;
+ goto _cleanup;
+ }
+
+ do {
+ for(i=0; i<nKpList; i++) {
+ if(!_tcsicmp( kpList[i].image, pe.szExeFile )) {
+ // got one
+ if(bKill) {
+ // try to kill the process
+ HANDLE hProcess = NULL;
+
+ // If we encounter an error, instead of bailing
+ // out, we continue on to the next process. We
+ // may not have permission to kill all the
+ // processes we want to kill anyway. If there are
+ // any files that we want to replace that is in
+ // use, Windows Installer will schedule a reboot.
+ // Also, it's not like we have an exhaustive list
+ // of all the programs that use Kerberos anyway.
+
+ hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pe.th32ProcessID);
+ if(hProcess == NULL) {
+ rv = GetLastError();
+ break;
+ }
+
+ if(!TerminateProcess(hProcess, 0)) {
+ rv = GetLastError();
+ CloseHandle(hProcess);
+ break;
+ }
+
+ CloseHandle(hProcess);
+
+ } else {
+ TCHAR buf[256];
+
+ // we are supposed to just list out the processes
+ rv = MsiRecordClearData( hRecordInsert ); RV_BAIL;
+ rv = MsiRecordSetString( hRecordInsert, 1, _T("KillableProcesses"));
+ rv = MsiRecordSetInteger( hRecordInsert, 2, rowNum++ ); RV_BAIL;
+ _itot( rowNum, buf, 10 );
+ rv = MsiRecordSetString( hRecordInsert, 3, buf ); RV_BAIL;
+ if(_tcslen(kpList[i].desc)) {
+ rv = MsiRecordSetString( hRecordInsert, 4, kpList[i].desc ); RV_BAIL;
+ } else {
+ rv = MsiRecordSetString( hRecordInsert, 4, kpList[i].image ); RV_BAIL;
+ }
+ MsiViewModify(hViewInsert, MSIMODIFY_INSERT_TEMPORARY, hRecordInsert); RV_BAIL;
+
+ found = TRUE;
+ }
+ break;
+ }
+ }
+ } while( Process32Next( hSnapshot, &pe ) );
+
+ if(!bKill) {
+ // set the 'FoundProcceses' property
+ if(found) {
+ MsiSetProperty( hInstall, _T("FoundProcesses"), _T("1"));
+ } else {
+ MsiSetProperty( hInstall, _T("FoundProcesses"), _T(""));
+ }
+ }
+
+ // Finally:
+ rv = ERROR_SUCCESS;
+
+_cleanup:
+
+ if(hRecordInsert) MsiCloseHandle(hRecordInsert);
+ if(hViewInsert) MsiCloseHandle(hView);
+
+ if(hSnapshot && hSnapshot != INVALID_HANDLE_VALUE) CloseHandle(hSnapshot);
+
+ while(nKpList) {
+ nKpList--;
+ delete kpList[nKpList].image;
+ delete kpList[nKpList].desc;
+ }
+ delete kpList;
+
+ if(hRecord) MsiCloseHandle(hRecord);
+ if(hView) MsiCloseHandle(hView);
+
+ if(hDatabase) MsiCloseHandle(hDatabase);
+
+ if(rv != ERROR_SUCCESS) {
+ ShowMsiError(hInstall, ERR_PROC_LIST, rv);
+ }
+
+ return rv;
+}
+
+static bool IsNSISInstalled()
+{
+ HKEY nsisKfwKey = NULL;
+ // Note: check Wow6432 node if 64 bit build
+ HRESULT res = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ "SOFTWARE\\Microsoft\\Windows\\CurrentVersion"
+ "\\Uninstall\\Kerberos for Windows",
+ 0,
+ KEY_READ | KEY_WOW64_32KEY,
+ &nsisKfwKey);
+ if (res != ERROR_SUCCESS)
+ return FALSE;
+
+ RegCloseKey(nsisKfwKey);
+ return TRUE;
+}
+
+static HANDLE NSISUninstallShellExecute(LPTSTR pathUninstall)
+{
+ SHELLEXECUTEINFO sei;
+ ZeroMemory ( &sei, sizeof(sei) );
+
+ sei.cbSize = sizeof(sei);
+ sei.hwnd = GetForegroundWindow();
+ sei.fMask = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI |
+ SEE_MASK_NOCLOSEPROCESS;
+ sei.lpVerb = _T("runas"); // run as administrator
+ sei.lpFile = pathUninstall;
+ sei.lpParameters = _T("");
+ sei.nShow = SW_SHOWNORMAL;
+
+ if (!ShellExecuteEx(&sei)) {
+ // FAILED! TODO: report details?
+ }
+ return sei.hProcess;
+}
+
+static HANDLE NSISUninstallCreateProcess(LPTSTR pathUninstall)
+{
+ STARTUPINFO sInfo;
+ PROCESS_INFORMATION pInfo;
+ pInfo.hProcess = NULL;
+ pInfo.hThread = NULL;
+
+ // Create a process for the uninstaller
+ sInfo.cb = sizeof(sInfo);
+ sInfo.lpReserved = NULL;
+ sInfo.lpDesktop = _T("");
+ sInfo.lpTitle = _T("NSIS Uninstaller for Kerberos for Windows");
+ sInfo.dwX = 0;
+ sInfo.dwY = 0;
+ sInfo.dwXSize = 0;
+ sInfo.dwYSize = 0;
+ sInfo.dwXCountChars = 0;
+ sInfo.dwYCountChars = 0;
+ sInfo.dwFillAttribute = 0;
+ sInfo.dwFlags = 0;
+ sInfo.wShowWindow = 0;
+ sInfo.cbReserved2 = 0;
+ sInfo.lpReserved2 = 0;
+ sInfo.hStdInput = 0;
+ sInfo.hStdOutput = 0;
+ sInfo.hStdError = 0;
+
+ if (!CreateProcess(pathUninstall,
+ _T("Uninstall /S"),
+ NULL,
+ NULL,
+ FALSE,
+ CREATE_SUSPENDED,
+ NULL,
+ NULL,
+ &sInfo,
+ &pInfo)) {
+ // failure; could grab info, but we should be able to recover by
+ // using NSISUninstallShellExecute...
+ } else {
+ // success
+ // start up the thread
+ ResumeThread(pInfo.hThread);
+ // done with thread handle
+ CloseHandle(pInfo.hThread);
+ }
+ return pInfo.hProcess;
+}
+
+
+/* Uninstall NSIS */
+MSIDLLEXPORT UninstallNsisInstallation( MSIHANDLE hInstall )
+{
+ DWORD rv = ERROR_SUCCESS;
+ DWORD lastError;
+ // lookup the NSISUNINSTALL property value
+ LPTSTR cNsisUninstall = _T("UPGRADENSIS");
+ LPTSTR strPathUninst = NULL;
+ DWORD dwSize = 0;
+ HANDLE hProcess = NULL;
+ HANDLE hIo = NULL;
+ HANDLE hJob = NULL;
+
+ rv = MsiGetProperty( hInstall, cNsisUninstall, _T(""), &dwSize );
+ if(rv != ERROR_MORE_DATA) goto _cleanup;
+
+ strPathUninst = new TCHAR[ ++dwSize ];
+
+ rv = MsiGetProperty(hInstall, cNsisUninstall, strPathUninst, &dwSize);
+ if(rv != ERROR_SUCCESS) goto _cleanup;
+
+ hProcess = NSISUninstallCreateProcess(strPathUninst);
+ if (hProcess == NULL) // expected when run on UAC-limited account
+ hProcess = NSISUninstallShellExecute(strPathUninst);
+
+ if (hProcess == NULL) {
+ // still no uninstall process? ick...
+ lastError = GetLastError();
+ rv = 40;
+ goto _cleanup;
+ }
+ // note that it is not suffiecient to wait for the initial process to
+ // finish; there is a whole process tree that we need to wait for. sigh.
+ JOBOBJECT_ASSOCIATE_COMPLETION_PORT acp;
+ acp.CompletionKey = 0;
+ hJob = CreateJobObject(NULL, _T("NSISUninstallObject"));
+ if(!hJob) {
+ rv = 41;
+ goto _cleanup;
+ }
+
+ hIo = CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0);
+ if(!hIo) {
+ rv = 42;
+ goto _cleanup;
+ }
+
+ acp.CompletionPort = hIo;
+
+ SetInformationJobObject(hJob,
+ JobObjectAssociateCompletionPortInformation,
+ &acp,
+ sizeof(acp));
+
+ AssignProcessToJobObject(hJob, hProcess);
+
+ DWORD msgId;
+ ULONG_PTR unusedCompletionKey;
+ LPOVERLAPPED unusedOverlapped;
+ for (;;) {
+ if (!GetQueuedCompletionStatus(hIo,
+ &msgId,
+ &unusedCompletionKey,
+ &unusedOverlapped,
+ INFINITE)) {
+ Sleep(1000);
+ } else if (msgId == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO) {
+ break;
+ }
+ }
+
+_cleanup:
+ if (hProcess) CloseHandle(hProcess);
+ if (hIo) CloseHandle(hIo);
+ if (hJob) CloseHandle(hJob);
+
+ if (IsNSISInstalled()) {
+ // uninstall failed: maybe user cancelled uninstall, or something else
+ // went wrong...
+ if (rv == ERROR_SUCCESS)
+ rv = 43;
+ } else {
+ // Maybe something went wrong, but it doesn't matter as long as nsis
+ // is gone now...
+ rv = ERROR_SUCCESS;
+ }
+
+ if (rv == 40) {
+ // CreateProcess() / ShellExecute() errors get extra data
+ ShowMsiErrorEx(hInstall, ERR_NSS_FAILED_CP, strPathUninst, lastError);
+ } else if (rv != ERROR_SUCCESS) {
+ ShowMsiError(hInstall, ERR_NSS_FAILED, rv);
+ }
+
+ if (strPathUninst) delete strPathUninst;
+ return rv;
+}
+
+/* Check and add or remove networkprovider key value
+ str : target string
+ str2: string to add/remove
+ bInst: == 1 if string should be added to target if not already there,
+ otherwise remove string from target if present.
+*/
+int npi_CheckAndAddRemove( LPTSTR str, LPTSTR str2, int bInst ) {
+
+ LPTSTR target, charset, match;
+ int ret=0;
+
+ target = new TCHAR[lstrlen(str)+3];
+ lstrcpy(target,_T(","));
+ lstrcat(target,str);
+ lstrcat(target,_T(","));
+ charset = new TCHAR[lstrlen(str2)+3];
+ lstrcpy(charset,_T(","));
+ lstrcat(charset,str2);
+ lstrcat(charset,_T(","));
+
+ match = _tcsstr(target, charset);
+
+ if ((match) && (bInst)) {
+ ret = INP_ERR_PRESENT;
+ goto cleanup;
+ }
+
+ if ((!match) && (!bInst)) {
+ ret = INP_ERR_ABSENT;
+ goto cleanup;
+ }
+
+ if (bInst) // && !match
+ {
+ lstrcat(str, _T(","));
+ lstrcat(str, str2);
+ ret = INP_ERR_ADDED;
+ goto cleanup;
+ }
+
+ // if (!bInst) && (match)
+ {
+ lstrcpy(str+(match-target),match+lstrlen(str2)+2);
+ str[lstrlen(str)-1]=_T('\0');
+ ret = INP_ERR_REMOVED;
+ goto cleanup;
+ }
+
+cleanup:
+
+ delete target;
+ delete charset;
+ return ret;
+}
+
+/* Sets the registry keys required for the functioning of the network provider */
+
+DWORD InstNetProvider(MSIHANDLE hInstall, int bInst) {
+ LPTSTR strOrder;
+ HKEY hkOrder;
+ LONG rv;
+ DWORD dwSize;
+ HANDLE hProcHeap;
+
+ strOrder = (LPTSTR) 0;
+
+ CHECK(rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, STR_KEY_ORDER, 0, KEY_READ | KEY_WRITE, &hkOrder ));
+
+ dwSize = 0;
+ CHECK(rv = RegQueryValueEx( hkOrder, STR_VAL_ORDER, NULL, NULL, NULL, &dwSize ) );
+
+ strOrder = new TCHAR[ (dwSize + STR_SERVICE_LEN + 4) * sizeof(TCHAR) ];
+
+ CHECK(rv = RegQueryValueEx( hkOrder, STR_VAL_ORDER, NULL, NULL, (LPBYTE) strOrder, &dwSize));
+
+ strOrder[dwSize] = '\0'; /* reg strings are not always nul terminated */
+
+ npi_CheckAndAddRemove( strOrder, STR_SERVICE , bInst);
+
+ dwSize = (lstrlen( strOrder ) + 1) * sizeof(TCHAR);
+
+ CHECK(rv = RegSetValueEx( hkOrder, STR_VAL_ORDER, NULL, REG_SZ, (LPBYTE) strOrder, dwSize ));
+
+ /* everything else should be set by the MSI tables */
+ rv = ERROR_SUCCESS;
+_cleanup:
+
+ if( rv != ERROR_SUCCESS ) {
+ ShowMsiError( hInstall, ERR_NPI_FAILED, rv );
+ }
+
+ if(strOrder) delete strOrder;
+
+ return rv;
+}
+
+MSIDLLEXPORT InstallNetProvider( MSIHANDLE hInstall ) {
+ return InstNetProvider( hInstall, 1 );
+}
+
+MSIDLLEXPORT UninstallNetProvider( MSIHANDLE hInstall) {
+ return InstNetProvider( hInstall, 0 );
+}
+
+#endif
+#ifdef __NMAKE__
+!ENDIF
+#endif