diff options
| author | Paolo Bonzini <pbonzini@redhat.com> | 2012-10-22 12:13:38 +0200 |
|---|---|---|
| committer | Paolo Bonzini <pbonzini@redhat.com> | 2012-12-06 20:25:48 +0100 |
| commit | 849e863a16e216100a711bb0fe0da33ab64ec577 (patch) | |
| tree | a25456396769472110093b61ebffbdda8f9c5e1f | |
| parent | 722565ce6f7bb2361207c43769f27c76864fdae1 (diff) | |
| download | msitools-849e863a16e216100a711bb0fe0da33ab64ec577.tar.gz msitools-849e863a16e216100a711bb0fe0da33ab64ec577.tar.xz msitools-849e863a16e216100a711bb0fe0da33ab64ec577.zip | |
remove most of the run-time processing
| -rw-r--r-- | libmsi/Makefile.am | 19 | ||||
| -rw-r--r-- | libmsi/action.c | 7683 | ||||
| -rw-r--r-- | libmsi/appsearch.c | 1189 | ||||
| -rw-r--r-- | libmsi/assembly.c | 694 | ||||
| -rw-r--r-- | libmsi/classes.c | 1565 | ||||
| -rw-r--r-- | libmsi/cond-parser.y | 869 | ||||
| -rw-r--r-- | libmsi/custom.c | 1311 | ||||
| -rw-r--r-- | libmsi/dialog.c | 4151 | ||||
| -rw-r--r-- | libmsi/events.c | 449 | ||||
| -rw-r--r-- | libmsi/files.c | 1330 | ||||
| -rw-r--r-- | libmsi/font.c | 385 | ||||
| -rw-r--r-- | libmsi/format.c | 1012 | ||||
| -rw-r--r-- | libmsi/instabsent.bmp | bin | 374 -> 0 bytes | |||
| -rw-r--r-- | libmsi/instadvert.bmp | bin | 374 -> 0 bytes | |||
| -rw-r--r-- | libmsi/install.c | 1307 | ||||
| -rw-r--r-- | libmsi/instlocal.bmp | bin | 374 -> 0 bytes | |||
| -rw-r--r-- | libmsi/media.c | 321 | ||||
| -rw-r--r-- | libmsi/msi.c | 815 | ||||
| -rw-r--r-- | libmsi/msi.rc | 9 | ||||
| -rw-r--r-- | libmsi/msi_main.c | 1 | ||||
| -rw-r--r-- | libmsi/msipriv.h | 1 | ||||
| -rw-r--r-- | libmsi/package.c | 287 | ||||
| -rw-r--r-- | libmsi/patch.c | 37 | ||||
| -rw-r--r-- | libmsi/script.c | 46 | ||||
| -rw-r--r-- | libmsi/upgrade.c | 235 |
25 files changed, 151 insertions, 23565 deletions
diff --git a/libmsi/Makefile.am b/libmsi/Makefile.am index 2261c22..049dbd5 100644 --- a/libmsi/Makefile.am +++ b/libmsi/Makefile.am @@ -2,7 +2,7 @@ lib_LTLIBRARIES = libmsi.la AM_CPPFLAGS = -I$(srcdir) -I. -D__WINESRC__ -DUNICODE -D_UNICODE AM_YFLAGS = -d -BUILT_SOURCES = sql-parser.c sql-parser.h cond-parser.c cond-parser.h +BUILT_SOURCES = sql-parser.c sql-parser.h noinst_HEADERS = \ msi.h \ @@ -11,19 +11,18 @@ noinst_HEADERS = \ msiserver.h \ query.h -libmsi_la_SOURCES = action.c alter.c appsearch.c assembly.c \ - classes.c create.c custom.c database.c delete.c \ - dialog.c distinct.c drop.c events.c files.c font.c format.c \ - handle.c insert.c install.c media.c msi.c msi_main.c msiquery.c \ - package.c patch.c record.c registry.c script.c select.c source.c \ +libmsi_la_SOURCES = alter.c create.c database.c delete.c distinct.c \ + drop.c handle.c insert.c media.c msi.c msi_main.c msiquery.c \ + package.c patch.c record.c registry.c select.c source.c \ storages.c streams.c string.c suminfo.c table.c tokenize.c update.c \ - upgrade.c where.c \ - msiserver_i.c \ - cond-parser.y sql-parser.y + where.c \ + sql-parser.y \ + msiserver_i.c libmsi_la_DEPENDENCIES = \ msi.res +libmsi_la_LDFLAGS = -no-undefined libmsi_la_LIBADD = \ $(libmsi_la_DEPENDENCIES) \ -luuid \ @@ -44,7 +43,5 @@ libmsi_la_LIBADD = \ -lcrypt32 \ -limagehlp -msi.res: msi.rc instabsent.bmp instadvert.bmp instlocal.bmp - %.res: %.rc $(RC) $(RCFLAGS) -o $@ $< diff --git a/libmsi/action.c b/libmsi/action.c deleted file mode 100644 index 0019b28..0000000 --- a/libmsi/action.c +++ /dev/null @@ -1,7683 +0,0 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2004,2005 Aric Stewart for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include <stdarg.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winreg.h" -#include "winsvc.h" -#include "odbcinst.h" -#include "wine/debug.h" -#include "msidefs.h" -#include "msipriv.h" -#include "wingdi.h" -#include "winuser.h" -#include "shlobj.h" -#include "objbase.h" -#include "mscoree.h" -#include "shlwapi.h" -#include "imagehlp.h" -#include "wine/unicode.h" -#include "winver.h" - -#define REG_PROGRESS_VALUE 13200 -#define COMPONENT_PROGRESS_VALUE 24000 - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -static const WCHAR szCreateFolders[] = - {'C','r','e','a','t','e','F','o','l','d','e','r','s',0}; -static const WCHAR szCostFinalize[] = - {'C','o','s','t','F','i','n','a','l','i','z','e',0}; -static const WCHAR szWriteRegistryValues[] = - {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0}; -static const WCHAR szFileCost[] = - {'F','i','l','e','C','o','s','t',0}; -static const WCHAR szInstallInitialize[] = - {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0}; -static const WCHAR szInstallValidate[] = - {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0}; -static const WCHAR szLaunchConditions[] = - {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0}; -static const WCHAR szProcessComponents[] = - {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0}; -static const WCHAR szRegisterTypeLibraries[] = - {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0}; -static const WCHAR szCreateShortcuts[] = - {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0}; -static const WCHAR szPublishProduct[] = - {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0}; -static const WCHAR szWriteIniValues[] = - {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0}; -static const WCHAR szSelfRegModules[] = - {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0}; -static const WCHAR szPublishFeatures[] = - {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0}; -static const WCHAR szRegisterProduct[] = - {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0}; -static const WCHAR szInstallExecute[] = - {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0}; -static const WCHAR szInstallExecuteAgain[] = - {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0}; -static const WCHAR szInstallFinalize[] = - {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0}; -static const WCHAR szForceReboot[] = - {'F','o','r','c','e','R','e','b','o','o','t',0}; -static const WCHAR szResolveSource[] = - {'R','e','s','o','l','v','e','S','o','u','r','c','e',0}; -static const WCHAR szAllocateRegistrySpace[] = - {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0}; -static const WCHAR szBindImage[] = - {'B','i','n','d','I','m','a','g','e',0}; -static const WCHAR szDeleteServices[] = - {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0}; -static const WCHAR szDisableRollback[] = - {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0}; -static const WCHAR szExecuteAction[] = - {'E','x','e','c','u','t','e','A','c','t','i','o','n',0}; -static const WCHAR szInstallAdminPackage[] = - {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0}; -static const WCHAR szInstallSFPCatalogFile[] = - {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0}; -static const WCHAR szIsolateComponents[] = - {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0}; -static const WCHAR szMigrateFeatureStates[] = - {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0}; -static const WCHAR szMsiUnpublishAssemblies[] = - {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0}; -static const WCHAR szInstallODBC[] = - {'I','n','s','t','a','l','l','O','D','B','C',0}; -static const WCHAR szInstallServices[] = - {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0}; -static const WCHAR szPublishComponents[] = - {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0}; -static const WCHAR szRegisterComPlus[] = - {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0}; -static const WCHAR szRegisterUser[] = - {'R','e','g','i','s','t','e','r','U','s','e','r',0}; -static const WCHAR szRemoveEnvironmentStrings[] = - {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0}; -static const WCHAR szRemoveExistingProducts[] = - {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0}; -static const WCHAR szRemoveFolders[] = - {'R','e','m','o','v','e','F','o','l','d','e','r','s',0}; -static const WCHAR szRemoveIniValues[] = - {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0}; -static const WCHAR szRemoveODBC[] = - {'R','e','m','o','v','e','O','D','B','C',0}; -static const WCHAR szRemoveRegistryValues[] = - {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0}; -static const WCHAR szRemoveShortcuts[] = - {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0}; -static const WCHAR szRMCCPSearch[] = - {'R','M','C','C','P','S','e','a','r','c','h',0}; -static const WCHAR szScheduleReboot[] = - {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0}; -static const WCHAR szSelfUnregModules[] = - {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0}; -static const WCHAR szSetODBCFolders[] = - {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0}; -static const WCHAR szStartServices[] = - {'S','t','a','r','t','S','e','r','v','i','c','e','s',0}; -static const WCHAR szStopServices[] = - {'S','t','o','p','S','e','r','v','i','c','e','s',0}; -static const WCHAR szUnpublishComponents[] = - {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0}; -static const WCHAR szUnpublishFeatures[] = - {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0}; -static const WCHAR szUnregisterComPlus[] = - {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0}; -static const WCHAR szUnregisterTypeLibraries[] = - {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0}; -static const WCHAR szValidateProductID[] = - {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0}; -static const WCHAR szWriteEnvironmentStrings[] = - {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0}; - -static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action) -{ - static const WCHAR Query_t[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','A','c','t','i','o', 'n','T','e','x','t','`',' ', - 'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=', - ' ','\'','%','s','\'',0}; - MSIRECORD * row; - - row = MSI_QueryGetRecord( package->db, Query_t, action ); - if (!row) - return; - MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row); - msiobj_release(&row->hdr); -} - -static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, - UINT rc) -{ - MSIRECORD * row; - static const WCHAR template_s[]= - {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ', - '%','s', '.',0}; - static const WCHAR template_e[]= - {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ', - '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ', - '%','i','.',0}; - static const WCHAR format[] = - {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0}; - WCHAR message[1024]; - WCHAR timet[0x100]; - - GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100); - if (start) - sprintfW(message,template_s,timet,action); - else - sprintfW(message,template_e,timet,action,rc); - - row = MSI_CreateRecord(1); - MSI_RecordSetStringW(row,1,message); - - MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row); - msiobj_release(&row->hdr); -} - -enum parse_state -{ - state_whitespace, - state_token, - state_quote -}; - -static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes ) -{ - enum parse_state state = state_quote; - const WCHAR *p; - WCHAR *out = value; - int ignore, in_quotes = 0, count = 0, len = 0; - - for (p = str; *p; p++) - { - ignore = 0; - switch (state) - { - case state_whitespace: - switch (*p) - { - case ' ': - in_quotes = 1; - ignore = 1; - len++; - break; - case '"': - state = state_quote; - if (in_quotes && p[1] != '\"') count--; - else count++; - break; - default: - state = state_token; - in_quotes = 1; - len++; - break; - } - break; - - case state_token: - switch (*p) - { - case '"': - state = state_quote; - if (in_quotes) count--; - else count++; - break; - case ' ': - state = state_whitespace; - if (!count) goto done; - in_quotes = 1; - len++; - break; - default: - if (!count) in_quotes = 0; - else in_quotes = 1; - len++; - break; - } - break; - - case state_quote: - switch (*p) - { - case '"': - if (in_quotes && p[1] != '\"') count--; - else count++; - break; - case ' ': - state = state_whitespace; - if (!count || (count > 1 && !len)) goto done; - in_quotes = 1; - len++; - break; - default: - state = state_token; - if (!count) in_quotes = 0; - else in_quotes = 1; - len++; - break; - } - break; - - default: break; - } - if (!ignore) *out++ = *p; - } - -done: - if (!len) *value = 0; - else *out = 0; - - *quotes = count; - return p - str; -} - -static void remove_quotes( WCHAR *str ) -{ - WCHAR *p = str; - int len = strlenW( str ); - - while ((p = strchrW( p, '"' ))) - { - memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) ); - p++; - } -} - -UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine, - BOOL preserve_case ) -{ - LPCWSTR ptr, ptr2; - int num_quotes; - DWORD len; - WCHAR *prop, *val; - UINT r; - - if (!szCommandLine) - return ERROR_SUCCESS; - - ptr = szCommandLine; - while (*ptr) - { - while (*ptr == ' ') ptr++; - if (!*ptr) break; - - ptr2 = strchrW( ptr, '=' ); - if (!ptr2) return ERROR_INVALID_COMMAND_LINE; - - len = ptr2 - ptr; - if (!len) return ERROR_INVALID_COMMAND_LINE; - - prop = msi_alloc( (len + 1) * sizeof(WCHAR) ); - memcpy( prop, ptr, len * sizeof(WCHAR) ); - prop[len] = 0; - if (!preserve_case) struprW( prop ); - - ptr2++; - while (*ptr2 == ' ') ptr2++; - - num_quotes = 0; - val = msi_alloc( (strlenW( ptr2 ) + 1) * sizeof(WCHAR) ); - len = parse_prop( ptr2, val, &num_quotes ); - if (num_quotes % 2) - { - WARN("unbalanced quotes\n"); - msi_free( val ); - msi_free( prop ); - return ERROR_INVALID_COMMAND_LINE; - } - remove_quotes( val ); - TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val)); - - r = msi_set_property( package->db, prop, val ); - if (r == ERROR_SUCCESS && !strcmpW( prop, szSourceDir )) - msi_reset_folders( package, TRUE ); - - msi_free( val ); - msi_free( prop ); - - ptr = ptr2 + len; - } - - return ERROR_SUCCESS; -} - -WCHAR **msi_split_string( const WCHAR *str, WCHAR sep ) -{ - LPCWSTR pc; - LPWSTR p, *ret = NULL; - UINT count = 0; - - if (!str) - return ret; - - /* count the number of substrings */ - for ( pc = str, count = 0; pc; count++ ) - { - pc = strchrW( pc, sep ); - if (pc) - pc++; - } - - /* allocate space for an array of substring pointers and the substrings */ - ret = msi_alloc( (count+1) * sizeof (LPWSTR) + - (lstrlenW(str)+1) * sizeof(WCHAR) ); - if (!ret) - return ret; - - /* copy the string and set the pointers */ - p = (LPWSTR) &ret[count+1]; - lstrcpyW( p, str ); - for( count = 0; (ret[count] = p); count++ ) - { - p = strchrW( p, sep ); - if (p) - *p++ = 0; - } - - return ret; -} - -static BOOL ui_sequence_exists( MSIPACKAGE *package ) -{ - static const WCHAR query [] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ', - 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ', - 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc == ERROR_SUCCESS) - { - msiobj_release(&view->hdr); - return TRUE; - } - return FALSE; -} - -UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace) -{ - LPWSTR source, check; - - if (msi_get_property_int( package->db, szInstalled, 0 )) - { - HKEY hkey; - - MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE ); - source = msi_reg_get_val_str( hkey, INSTALLPROPERTY_INSTALLSOURCEW ); - RegCloseKey( hkey ); - } - else - { - LPWSTR p, db; - DWORD len; - - db = msi_dup_property( package->db, szOriginalDatabase ); - if (!db) - return ERROR_OUTOFMEMORY; - - p = strrchrW( db, '\\' ); - if (!p) - { - p = strrchrW( db, '/' ); - if (!p) - { - msi_free(db); - return ERROR_SUCCESS; - } - } - - len = p - db + 2; - source = msi_alloc( len * sizeof(WCHAR) ); - lstrcpynW( source, db, len ); - msi_free( db ); - } - - check = msi_dup_property( package->db, szSourceDir ); - if (!check || replace) - { - UINT r = msi_set_property( package->db, szSourceDir, source ); - if (r == ERROR_SUCCESS) - msi_reset_folders( package, TRUE ); - } - msi_free( check ); - - check = msi_dup_property( package->db, szSOURCEDIR ); - if (!check || replace) - msi_set_property( package->db, szSOURCEDIR, source ); - - msi_free( check ); - msi_free( source ); - - return ERROR_SUCCESS; -} - -static BOOL needs_ui_sequence(MSIPACKAGE *package) -{ - return (package->ui_level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED; -} - -UINT msi_set_context(MSIPACKAGE *package) -{ - UINT r = msi_locate_product( package->ProductCode, &package->Context ); - if (r != ERROR_SUCCESS) - { - int num = msi_get_property_int( package->db, szAllUsers, 0 ); - if (num == 1 || num == 2) - package->Context = MSIINSTALLCONTEXT_MACHINE; - else - package->Context = MSIINSTALLCONTEXT_USERUNMANAGED; - } - return ERROR_SUCCESS; -} - -static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param) -{ - UINT rc; - LPCWSTR cond, action; - MSIPACKAGE *package = param; - - action = MSI_RecordGetString(row,1); - if (!action) - { - ERR("Error is retrieving action name\n"); - return ERROR_FUNCTION_FAILED; - } - - /* check conditions */ - cond = MSI_RecordGetString(row,2); - - /* this is a hack to skip errors in the condition code */ - if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE) - { - TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action)); - return ERROR_SUCCESS; - } - - if (needs_ui_sequence(package)) - rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE); - else - rc = ACTION_PerformAction(package, action, SCRIPT_NONE); - - msi_dialog_check_messages( NULL ); - - if (package->CurrentInstallState != ERROR_SUCCESS) - rc = package->CurrentInstallState; - - if (rc == ERROR_FUNCTION_NOT_CALLED) - rc = ERROR_SUCCESS; - - if (rc != ERROR_SUCCESS) - ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc); - - if (package->need_reboot_now) - { - TRACE("action %s asked for immediate reboot, suspending installation\n", - debugstr_w(action)); - rc = ACTION_ForceReboot( package ); - } - return rc; -} - -UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`', - ' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ', - '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ', - '`','S','e','q','u','e','n','c','e','`',0}; - MSIQUERY *view; - UINT r; - - TRACE("%p %s\n", package, debugstr_w(table)); - - r = MSI_OpenQuery( package->db, &view, query, table ); - if (r == ERROR_SUCCESS) - { - r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package ); - msiobj_release(&view->hdr); - } - return r; -} - -static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', - '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e', - 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ', - '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ', - 'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0}; - static const WCHAR query_validate[] = { - 'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`', - ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l', - 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ', - 'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=', - ' ','\'', 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','\'',0}; - MSIQUERY *view; - INT seq = 0; - UINT rc; - - if (package->script->ExecuteSequenceRun) - { - TRACE("Execute Sequence already Run\n"); - return ERROR_SUCCESS; - } - - package->script->ExecuteSequenceRun = TRUE; - - /* get the sequence number */ - if (UIran) - { - MSIRECORD *row = MSI_QueryGetRecord(package->db, query_validate); - if (!row) return ERROR_FUNCTION_FAILED; - seq = MSI_RecordGetInteger(row,1); - msiobj_release(&row->hdr); - } - rc = MSI_OpenQuery(package->db, &view, query, seq); - if (rc == ERROR_SUCCESS) - { - TRACE("Running the actions\n"); - - msi_set_property(package->db, szSourceDir, NULL); - rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package); - msiobj_release(&view->hdr); - } - return rc; -} - -static UINT ACTION_ProcessUISequence(MSIPACKAGE *package) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ', - 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ', - 'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc == ERROR_SUCCESS) - { - TRACE("Running the actions\n"); - rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package); - msiobj_release(&view->hdr); - } - return rc; -} - -/******************************************************** - * ACTION helper functions and functions that perform the actions - *******************************************************/ -static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action, - UINT* rc, UINT script, BOOL force ) -{ - BOOL ret=FALSE; - UINT arc; - - arc = ACTION_CustomAction(package, action, script, force); - - if (arc != ERROR_CALL_NOT_IMPLEMENTED) - { - *rc = arc; - ret = TRUE; - } - return ret; -} - -MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component ) -{ - MSICOMPONENT *comp; - - LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) - { - if (!strcmpW( Component, comp->Component )) return comp; - } - return NULL; -} - -MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature ) -{ - MSIFEATURE *feature; - - LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) - { - if (!strcmpW( Feature, feature->Feature )) return feature; - } - return NULL; -} - -MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key ) -{ - MSIFILE *file; - - LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) - { - if (!strcmpW( key, file->File )) return file; - } - return NULL; -} - -MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key ) -{ - MSIFILEPATCH *patch; - - /* FIXME: There might be more than one patch */ - LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry ) - { - if (!strcmpW( key, patch->File->File )) return patch; - } - return NULL; -} - -MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir ) -{ - MSIFOLDER *folder; - - LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry ) - { - if (!strcmpW( dir, folder->Directory )) return folder; - } - return NULL; -} - -/* - * Recursively create all directories in the path. - * shamelessly stolen from setupapi/queue.c - */ -BOOL msi_create_full_path( const WCHAR *path ) -{ - BOOL ret = TRUE; - WCHAR *new_path; - int len; - - new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) ); - strcpyW( new_path, path ); - - while ((len = strlenW( new_path )) && new_path[len - 1] == '\\') - new_path[len - 1] = 0; - - while (!CreateDirectoryW( new_path, NULL )) - { - WCHAR *slash; - DWORD last_error = GetLastError(); - if (last_error == ERROR_ALREADY_EXISTS) break; - if (last_error != ERROR_PATH_NOT_FOUND) - { - ret = FALSE; - break; - } - if (!(slash = strrchrW( new_path, '\\' ))) - { - ret = FALSE; - break; - } - len = slash - new_path; - new_path[len] = 0; - if (!msi_create_full_path( new_path )) - { - ret = FALSE; - break; - } - new_path[len] = '\\'; - } - msi_free( new_path ); - return ret; -} - -void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d ) -{ - MSIRECORD *row; - - row = MSI_CreateRecord( 4 ); - MSI_RecordSetInteger( row, 1, a ); - MSI_RecordSetInteger( row, 2, b ); - MSI_RecordSetInteger( row, 3, c ); - MSI_RecordSetInteger( row, 4, d ); - MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row ); - msiobj_release( &row->hdr ); - - msi_dialog_check_messages( NULL ); -} - -void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record ) -{ - static const WCHAR query[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','A','c','t','i','o', 'n','T','e','x','t','`',' ', - 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0}; - WCHAR message[1024]; - MSIRECORD *row = 0; - DWORD size; - - if (!package->LastAction || strcmpW( package->LastAction, action )) - { - if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return; - - if (MSI_RecordIsNull( row, 3 )) - { - msiobj_release( &row->hdr ); - return; - } - /* update the cached action format */ - msi_free( package->ActionFormat ); - package->ActionFormat = msi_dup_record_field( row, 3 ); - msi_free( package->LastAction ); - package->LastAction = strdupW( action ); - msiobj_release( &row->hdr ); - } - size = 1024; - MSI_RecordSetStringW( record, 0, package->ActionFormat ); - MSI_FormatRecordW( package, record, message, &size ); - row = MSI_CreateRecord( 1 ); - MSI_RecordSetStringW( row, 1, message ); - MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row ); - msiobj_release( &row->hdr ); -} - -INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp ) -{ - if (!comp->Enabled) - { - TRACE("component is disabled: %s\n", debugstr_w(comp->Component)); - return INSTALLSTATE_UNKNOWN; - } - if (package->need_rollback) return comp->Installed; - if (comp->num_clients > 0 && comp->ActionRequest == INSTALLSTATE_ABSENT) - { - TRACE("%s has %u clients left\n", debugstr_w(comp->Component), comp->num_clients); - return INSTALLSTATE_UNKNOWN; - } - return comp->ActionRequest; -} - -INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature ) -{ - if (package->need_rollback) return feature->Installed; - return feature->ActionRequest; -} - -static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param) -{ - MSIPACKAGE *package = param; - LPCWSTR dir, component, full_path; - MSIRECORD *uirow; - MSIFOLDER *folder; - MSICOMPONENT *comp; - - component = MSI_RecordGetString(row, 2); - if (!component) - return ERROR_SUCCESS; - - comp = msi_get_loaded_component(package, component); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_LOCAL) - { - TRACE("component not scheduled for installation: %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - - dir = MSI_RecordGetString(row,1); - if (!dir) - { - ERR("Unable to get folder id\n"); - return ERROR_SUCCESS; - } - - uirow = MSI_CreateRecord(1); - MSI_RecordSetStringW(uirow, 1, dir); - msi_ui_actiondata(package, szCreateFolders, uirow); - msiobj_release(&uirow->hdr); - - full_path = msi_get_target_folder( package, dir ); - if (!full_path) - { - ERR("Unable to retrieve folder %s\n", debugstr_w(dir)); - return ERROR_SUCCESS; - } - TRACE("folder is %s\n", debugstr_w(full_path)); - - folder = msi_get_loaded_folder( package, dir ); - if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path ); - folder->State = FOLDER_STATE_CREATED; - return ERROR_SUCCESS; -} - -static UINT ACTION_CreateFolders(MSIPACKAGE *package) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package); - msiobj_release(&view->hdr); - return rc; -} - -static void remove_persistent_folder( MSIFOLDER *folder ) -{ - FolderList *fl; - - LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry ) - { - remove_persistent_folder( fl->folder ); - } - if (folder->persistent && folder->State != FOLDER_STATE_REMOVED) - { - if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED; - } -} - -static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param ) -{ - MSIPACKAGE *package = param; - LPCWSTR dir, component, full_path; - MSIRECORD *uirow; - MSIFOLDER *folder; - MSICOMPONENT *comp; - - component = MSI_RecordGetString(row, 2); - if (!component) - return ERROR_SUCCESS; - - comp = msi_get_loaded_component(package, component); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_ABSENT) - { - TRACE("component not scheduled for removal %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - - dir = MSI_RecordGetString( row, 1 ); - if (!dir) - { - ERR("Unable to get folder id\n"); - return ERROR_SUCCESS; - } - - full_path = msi_get_target_folder( package, dir ); - if (!full_path) - { - ERR("Unable to resolve folder %s\n", debugstr_w(dir)); - return ERROR_SUCCESS; - } - TRACE("folder is %s\n", debugstr_w(full_path)); - - uirow = MSI_CreateRecord( 1 ); - MSI_RecordSetStringW( uirow, 1, dir ); - msi_ui_actiondata( package, szRemoveFolders, uirow ); - msiobj_release( &uirow->hdr ); - - folder = msi_get_loaded_folder( package, dir ); - remove_persistent_folder( folder ); - return ERROR_SUCCESS; -} - -static UINT ACTION_RemoveFolders( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package ); - msiobj_release( &view->hdr ); - return rc; -} - -static UINT load_component( MSIRECORD *row, LPVOID param ) -{ - MSIPACKAGE *package = param; - MSICOMPONENT *comp; - - comp = msi_alloc_zero( sizeof(MSICOMPONENT) ); - if (!comp) - return ERROR_FUNCTION_FAILED; - - list_add_tail( &package->components, &comp->entry ); - - /* fill in the data */ - comp->Component = msi_dup_record_field( row, 1 ); - - TRACE("Loading Component %s\n", debugstr_w(comp->Component)); - - comp->ComponentId = msi_dup_record_field( row, 2 ); - comp->Directory = msi_dup_record_field( row, 3 ); - comp->Attributes = MSI_RecordGetInteger(row,4); - comp->Condition = msi_dup_record_field( row, 5 ); - comp->KeyPath = msi_dup_record_field( row, 6 ); - - comp->Installed = INSTALLSTATE_UNKNOWN; - comp->Action = INSTALLSTATE_UNKNOWN; - comp->ActionRequest = INSTALLSTATE_UNKNOWN; - - comp->assembly = msi_load_assembly( package, comp ); - return ERROR_SUCCESS; -} - -UINT msi_load_all_components( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','C','o','m','p','o','n','e','n','t','`',0}; - MSIQUERY *view; - UINT r; - - if (!list_empty(&package->components)) - return ERROR_SUCCESS; - - r = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (r != ERROR_SUCCESS) - return r; - - if (!msi_init_assembly_caches( package )) - { - ERR("can't initialize assembly caches\n"); - msiobj_release( &view->hdr ); - return ERROR_FUNCTION_FAILED; - } - - r = MSI_IterateRecords(view, NULL, load_component, package); - msiobj_release(&view->hdr); - return r; -} - -typedef struct { - MSIPACKAGE *package; - MSIFEATURE *feature; -} _ilfs; - -static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp ) -{ - ComponentList *cl; - - cl = msi_alloc( sizeof (*cl) ); - if ( !cl ) - return ERROR_NOT_ENOUGH_MEMORY; - cl->component = comp; - list_add_tail( &feature->Components, &cl->entry ); - - return ERROR_SUCCESS; -} - -static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child ) -{ - FeatureList *fl; - - fl = msi_alloc( sizeof(*fl) ); - if ( !fl ) - return ERROR_NOT_ENOUGH_MEMORY; - fl->feature = child; - list_add_tail( &parent->Children, &fl->entry ); - - return ERROR_SUCCESS; -} - -static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param) -{ - _ilfs* ilfs = param; - LPCWSTR component; - MSICOMPONENT *comp; - - component = MSI_RecordGetString(row,1); - - /* check to see if the component is already loaded */ - comp = msi_get_loaded_component( ilfs->package, component ); - if (!comp) - { - WARN("ignoring unknown component %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - add_feature_component( ilfs->feature, comp ); - comp->Enabled = TRUE; - - return ERROR_SUCCESS; -} - -static UINT load_feature(MSIRECORD * row, LPVOID param) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','`','C','o','m','p','o','n','e','n','t','_','`', - ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e', - 'C','o','m','p','o','n','e','n','t','s','`',' ','W','H','E','R','E',' ', - '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0}; - MSIPACKAGE *package = param; - MSIFEATURE *feature; - MSIQUERY *view; - _ilfs ilfs; - UINT rc; - - /* fill in the data */ - - feature = msi_alloc_zero( sizeof (MSIFEATURE) ); - if (!feature) - return ERROR_NOT_ENOUGH_MEMORY; - - list_init( &feature->Children ); - list_init( &feature->Components ); - - feature->Feature = msi_dup_record_field( row, 1 ); - - TRACE("Loading feature %s\n",debugstr_w(feature->Feature)); - - feature->Feature_Parent = msi_dup_record_field( row, 2 ); - feature->Title = msi_dup_record_field( row, 3 ); - feature->Description = msi_dup_record_field( row, 4 ); - - if (!MSI_RecordIsNull(row,5)) - feature->Display = MSI_RecordGetInteger(row,5); - - feature->Level= MSI_RecordGetInteger(row,6); - feature->Directory = msi_dup_record_field( row, 7 ); - feature->Attributes = MSI_RecordGetInteger(row,8); - - feature->Installed = INSTALLSTATE_UNKNOWN; - feature->Action = INSTALLSTATE_UNKNOWN; - feature->ActionRequest = INSTALLSTATE_UNKNOWN; - - list_add_tail( &package->features, &feature->entry ); - - /* load feature components */ - - rc = MSI_OpenQuery( package->db, &view, query, feature->Feature ); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - ilfs.package = package; - ilfs.feature = feature; - - rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs); - msiobj_release(&view->hdr); - return rc; -} - -static UINT find_feature_children(MSIRECORD * row, LPVOID param) -{ - MSIPACKAGE *package = param; - MSIFEATURE *parent, *child; - - child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) ); - if (!child) - return ERROR_FUNCTION_FAILED; - - if (!child->Feature_Parent) - return ERROR_SUCCESS; - - parent = msi_get_loaded_feature( package, child->Feature_Parent ); - if (!parent) - return ERROR_FUNCTION_FAILED; - - add_feature_child( parent, child ); - return ERROR_SUCCESS; -} - -UINT msi_load_all_features( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',' ','B','Y',' ', - '`','D','i','s','p','l','a','y','`',0}; - MSIQUERY *view; - UINT r; - - if (!list_empty(&package->features)) - return ERROR_SUCCESS; - - r = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (r != ERROR_SUCCESS) - return r; - - r = MSI_IterateRecords( view, NULL, load_feature, package ); - if (r != ERROR_SUCCESS) - { - msiobj_release( &view->hdr ); - return r; - } - r = MSI_IterateRecords( view, NULL, find_feature_children, package ); - msiobj_release( &view->hdr ); - return r; -} - -static LPWSTR folder_split_path(LPWSTR p, WCHAR ch) -{ - if (!p) - return p; - p = strchrW(p, ch); - if (!p) - return p; - *p = 0; - return p+1; -} - -static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', - '`','M','s','i','F','i','l','e','H','a','s','h','`',' ', - 'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0}; - MSIQUERY *view = NULL; - MSIRECORD *row = NULL; - UINT r; - - TRACE("%s\n", debugstr_w(file->File)); - - r = MSI_OpenQuery(package->db, &view, query, file->File); - if (r != ERROR_SUCCESS) - goto done; - - r = MSI_ViewExecute(view, NULL); - if (r != ERROR_SUCCESS) - goto done; - - r = MSI_ViewFetch(view, &row); - if (r != ERROR_SUCCESS) - goto done; - - file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO); - file->hash.dwData[0] = MSI_RecordGetInteger(row, 3); - file->hash.dwData[1] = MSI_RecordGetInteger(row, 4); - file->hash.dwData[2] = MSI_RecordGetInteger(row, 5); - file->hash.dwData[3] = MSI_RecordGetInteger(row, 6); - -done: - if (view) msiobj_release(&view->hdr); - if (row) msiobj_release(&row->hdr); - return r; -} - -static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file ) -{ - MSIRECORD *row; - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','`','D','i','s','k','I','d','`',' ', 'F','R','O','M',' ', - '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ', - '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',' ','%','i',0}; - - row = MSI_QueryGetRecord( package->db, query, file->Sequence ); - if (!row) - { - WARN("query failed\n"); - return ERROR_FUNCTION_FAILED; - } - - file->disk_id = MSI_RecordGetInteger( row, 1 ); - msiobj_release( &row->hdr ); - return ERROR_SUCCESS; -} - -static UINT load_file(MSIRECORD *row, LPVOID param) -{ - MSIPACKAGE* package = param; - LPCWSTR component; - MSIFILE *file; - - /* fill in the data */ - - file = msi_alloc_zero( sizeof (MSIFILE) ); - if (!file) - return ERROR_NOT_ENOUGH_MEMORY; - - file->File = msi_dup_record_field( row, 1 ); - - component = MSI_RecordGetString( row, 2 ); - file->Component = msi_get_loaded_component( package, component ); - - if (!file->Component) - { - WARN("Component not found: %s\n", debugstr_w(component)); - msi_free(file->File); - msi_free(file); - return ERROR_SUCCESS; - } - - file->FileName = msi_dup_record_field( row, 3 ); - msi_reduce_to_long_filename( file->FileName ); - - file->ShortName = msi_dup_record_field( row, 3 ); - file->LongName = strdupW( folder_split_path(file->ShortName, '|')); - - file->FileSize = MSI_RecordGetInteger( row, 4 ); - file->Version = msi_dup_record_field( row, 5 ); - file->Language = msi_dup_record_field( row, 6 ); - file->Attributes = MSI_RecordGetInteger( row, 7 ); - file->Sequence = MSI_RecordGetInteger( row, 8 ); - - file->state = msifs_invalid; - - /* if the compressed bits are not set in the file attributes, - * then read the information from the package word count property - */ - if (package->WordCount & msidbSumInfoSourceTypeAdminImage) - { - file->IsCompressed = FALSE; - } - else if (file->Attributes & - (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded)) - { - file->IsCompressed = TRUE; - } - else if (file->Attributes & msidbFileAttributesNoncompressed) - { - file->IsCompressed = FALSE; - } - else - { - file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed; - } - - load_file_hash(package, file); - load_file_disk_id(package, file); - - TRACE("File Loaded (%s)\n",debugstr_w(file->File)); - - list_add_tail( &package->files, &file->entry ); - - return ERROR_SUCCESS; -} - -static UINT load_all_files(MSIPACKAGE *package) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', - '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ', - '`','S','e','q','u','e','n','c','e','`', 0}; - MSIQUERY *view; - UINT rc; - - if (!list_empty(&package->files)) - return ERROR_SUCCESS; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, load_file, package); - msiobj_release(&view->hdr); - return rc; -} - -static UINT load_media( MSIRECORD *row, LPVOID param ) -{ - MSIPACKAGE *package = param; - UINT disk_id = MSI_RecordGetInteger( row, 1 ); - const WCHAR *cabinet = MSI_RecordGetString( row, 4 ); - - /* FIXME: load external cabinets and directory sources too */ - if (!cabinet || cabinet[0] != '#') return ERROR_SUCCESS; - msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet ); - return ERROR_SUCCESS; -} - -static UINT load_all_media( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`', - 'M','e','d','i','a','`',' ','O','R','D','E','R',' ','B','Y',' ', - '`','D','i','s','k','I','d','`',0}; - MSIQUERY *view; - UINT r; - - r = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (r != ERROR_SUCCESS) - return ERROR_SUCCESS; - - r = MSI_IterateRecords( view, NULL, load_media, package ); - msiobj_release( &view->hdr ); - return r; -} - -static UINT load_patch(MSIRECORD *row, LPVOID param) -{ - MSIPACKAGE *package = param; - MSIFILEPATCH *patch; - LPWSTR file_key; - - patch = msi_alloc_zero( sizeof (MSIFILEPATCH) ); - if (!patch) - return ERROR_NOT_ENOUGH_MEMORY; - - file_key = msi_dup_record_field( row, 1 ); - patch->File = msi_get_loaded_file( package, file_key ); - msi_free(file_key); - - if( !patch->File ) - { - ERR("Failed to find target for patch in File table\n"); - msi_free(patch); - return ERROR_FUNCTION_FAILED; - } - - patch->Sequence = MSI_RecordGetInteger( row, 2 ); - - /* FIXME: The database should be properly transformed */ - patch->Sequence += MSI_INITIAL_MEDIA_TRANSFORM_OFFSET; - - patch->PatchSize = MSI_RecordGetInteger( row, 3 ); - patch->Attributes = MSI_RecordGetInteger( row, 4 ); - patch->IsApplied = FALSE; - - /* FIXME: - * Header field - for patch validation. - * _StreamRef - External key into MsiPatchHeaders (instead of the header field) - */ - - TRACE("Patch Loaded (%s)\n", debugstr_w(patch->File->File)); - - list_add_tail( &package->filepatches, &patch->entry ); - - return ERROR_SUCCESS; -} - -static UINT load_all_patches(MSIPACKAGE *package) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','P','a','t','c','h','`',' ','O','R','D','E','R',' ','B','Y',' ', - '`','S','e','q','u','e','n','c','e','`',0}; - MSIQUERY *view; - UINT rc; - - if (!list_empty(&package->filepatches)) - return ERROR_SUCCESS; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, load_patch, package); - msiobj_release(&view->hdr); - return rc; -} - -static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','C','r','e','a','t','e','F','o','l','d','e','r','`',' ','W','H','E','R','E',' ', - '`','D','i','r','e','c','t','o','r','y','_','`',' ','=','\'','%','s','\'',0}; - MSIQUERY *view; - - folder->persistent = FALSE; - if (!MSI_OpenQuery( package->db, &view, query, folder->Directory )) - { - if (!MSI_ViewExecute( view, NULL )) - { - MSIRECORD *rec; - if (!MSI_ViewFetch( view, &rec )) - { - TRACE("directory %s is persistent\n", debugstr_w(folder->Directory)); - folder->persistent = TRUE; - msiobj_release( &rec->hdr ); - } - } - msiobj_release( &view->hdr ); - } - return ERROR_SUCCESS; -} - -static UINT load_folder( MSIRECORD *row, LPVOID param ) -{ - MSIPACKAGE *package = param; - static WCHAR szEmpty[] = { 0 }; - LPWSTR p, tgt_short, tgt_long, src_short, src_long; - MSIFOLDER *folder; - - if (!(folder = msi_alloc_zero( sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY; - list_init( &folder->children ); - folder->Directory = msi_dup_record_field( row, 1 ); - folder->Parent = msi_dup_record_field( row, 2 ); - p = msi_dup_record_field(row, 3); - - TRACE("%s\n", debugstr_w(folder->Directory)); - - /* split src and target dir */ - tgt_short = p; - src_short = folder_split_path( p, ':' ); - - /* split the long and short paths */ - tgt_long = folder_split_path( tgt_short, '|' ); - src_long = folder_split_path( src_short, '|' ); - - /* check for no-op dirs */ - if (tgt_short && !strcmpW( szDot, tgt_short )) - tgt_short = szEmpty; - if (src_short && !strcmpW( szDot, src_short )) - src_short = szEmpty; - - if (!tgt_long) - tgt_long = tgt_short; - - if (!src_short) { - src_short = tgt_short; - src_long = tgt_long; - } - - if (!src_long) - src_long = src_short; - - /* FIXME: use the target short path too */ - folder->TargetDefault = strdupW(tgt_long); - folder->SourceShortPath = strdupW(src_short); - folder->SourceLongPath = strdupW(src_long); - msi_free(p); - - TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault )); - TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath )); - TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath )); - - load_folder_persistence( package, folder ); - - list_add_tail( &package->folders, &folder->entry ); - return ERROR_SUCCESS; -} - -static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child ) -{ - FolderList *fl; - - if (!(fl = msi_alloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY; - fl->folder = child; - list_add_tail( &parent->children, &fl->entry ); - return ERROR_SUCCESS; -} - -static UINT find_folder_children( MSIRECORD *row, LPVOID param ) -{ - MSIPACKAGE *package = param; - MSIFOLDER *parent, *child; - - if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) ))) - return ERROR_FUNCTION_FAILED; - - if (!child->Parent) return ERROR_SUCCESS; - - if (!(parent = msi_get_loaded_folder( package, child->Parent ))) - return ERROR_FUNCTION_FAILED; - - return add_folder_child( parent, child ); -} - -static UINT load_all_folders( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','D','i','r','e','c','t','o','r','y','`',0}; - MSIQUERY *view; - UINT r; - - if (!list_empty(&package->folders)) - return ERROR_SUCCESS; - - r = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (r != ERROR_SUCCESS) - return r; - - r = MSI_IterateRecords( view, NULL, load_folder, package ); - if (r != ERROR_SUCCESS) - { - msiobj_release( &view->hdr ); - return r; - } - r = MSI_IterateRecords( view, NULL, find_folder_children, package ); - msiobj_release( &view->hdr ); - return r; -} - -static UINT ACTION_CostInitialize(MSIPACKAGE *package) -{ - msi_set_property( package->db, szCostingComplete, szZero ); - msi_set_property( package->db, szRootDrive, szCRoot ); - - load_all_folders( package ); - msi_load_all_components( package ); - msi_load_all_features( package ); - load_all_files( package ); - load_all_patches( package ); - load_all_media( package ); - - return ERROR_SUCCESS; -} - -static UINT execute_script_action( MSIPACKAGE *package, UINT script, UINT index ) -{ - const WCHAR *action = package->script->Actions[script][index]; - ui_actionstart( package, action ); - TRACE("executing %s\n", debugstr_w(action)); - return ACTION_PerformAction( package, action, script ); -} - -static UINT execute_script( MSIPACKAGE *package, UINT script ) -{ - UINT i, rc = ERROR_SUCCESS; - - TRACE("executing script %u\n", script); - - if (!package->script) - { - ERR("no script!\n"); - return ERROR_FUNCTION_FAILED; - } - if (script == SCRIPT_ROLLBACK) - { - for (i = package->script->ActionCount[script]; i > 0; i--) - { - rc = execute_script_action( package, script, i - 1 ); - if (rc != ERROR_SUCCESS) break; - } - } - else - { - for (i = 0; i < package->script->ActionCount[script]; i++) - { - rc = execute_script_action( package, script, i ); - if (rc != ERROR_SUCCESS) break; - } - } - msi_free_action_script(package, script); - return rc; -} - -static UINT ACTION_FileCost(MSIPACKAGE *package) -{ - return ERROR_SUCCESS; -} - -static void get_client_counts( MSIPACKAGE *package ) -{ - MSICOMPONENT *comp; - HKEY hkey; - - LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) - { - if (!comp->ComponentId) continue; - - if (MSIREG_OpenUserDataComponentKey( comp->ComponentId, szLocalSid, &hkey, FALSE ) && - MSIREG_OpenUserDataComponentKey( comp->ComponentId, NULL, &hkey, FALSE )) - { - comp->num_clients = 0; - continue; - } - RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, NULL, (DWORD *)&comp->num_clients, - NULL, NULL, NULL, NULL ); - RegCloseKey( hkey ); - } -} - -static void ACTION_GetComponentInstallStates(MSIPACKAGE *package) -{ - MSICOMPONENT *comp; - UINT r; - - LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry) - { - if (!comp->ComponentId) continue; - - r = MsiQueryComponentStateW( package->ProductCode, NULL, - MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId, - &comp->Installed ); - if (r == ERROR_SUCCESS) continue; - - r = MsiQueryComponentStateW( package->ProductCode, NULL, - MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId, - &comp->Installed ); - if (r == ERROR_SUCCESS) continue; - - r = MsiQueryComponentStateW( package->ProductCode, NULL, - MSIINSTALLCONTEXT_MACHINE, comp->ComponentId, - &comp->Installed ); - if (r == ERROR_SUCCESS) continue; - - comp->Installed = INSTALLSTATE_ABSENT; - } -} - -static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package) -{ - MSIFEATURE *feature; - - LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) - { - INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature ); - - if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG) - feature->Installed = INSTALLSTATE_ABSENT; - else - feature->Installed = state; - } -} - -static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level ) -{ - return (feature->Level > 0 && feature->Level <= level); -} - -static BOOL process_state_property(MSIPACKAGE* package, int level, - LPCWSTR property, INSTALLSTATE state) -{ - LPWSTR override; - MSIFEATURE *feature; - - override = msi_dup_property( package->db, property ); - if (!override) - return FALSE; - - LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) - { - if (strcmpW( property, szRemove ) && !is_feature_selected( feature, level )) - continue; - - if (!strcmpW(property, szReinstall)) state = feature->Installed; - - if (!strcmpiW( override, szAll )) - { - if (feature->Installed != state) - { - feature->Action = state; - feature->ActionRequest = state; - } - } - else - { - LPWSTR ptr = override; - LPWSTR ptr2 = strchrW(override,','); - - while (ptr) - { - int len = ptr2 - ptr; - - if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len)) - || (!ptr2 && !strcmpW(ptr, feature->Feature))) - { - if (feature->Installed != state) - { - feature->Action = state; - feature->ActionRequest = state; - } - break; - } - if (ptr2) - { - ptr=ptr2+1; - ptr2 = strchrW(ptr,','); - } - else - break; - } - } - } - msi_free(override); - return TRUE; -} - -static BOOL process_overrides( MSIPACKAGE *package, int level ) -{ - static const WCHAR szAddLocal[] = - {'A','D','D','L','O','C','A','L',0}; - static const WCHAR szAddSource[] = - {'A','D','D','S','O','U','R','C','E',0}; - static const WCHAR szAdvertise[] = - {'A','D','V','E','R','T','I','S','E',0}; - BOOL ret = FALSE; - - /* all these activation/deactivation things happen in order and things - * later on the list override things earlier on the list. - * - * 0 INSTALLLEVEL processing - * 1 ADDLOCAL - * 2 REMOVE - * 3 ADDSOURCE - * 4 ADDDEFAULT - * 5 REINSTALL - * 6 ADVERTISE - * 7 COMPADDLOCAL - * 8 COMPADDSOURCE - * 9 FILEADDLOCAL - * 10 FILEADDSOURCE - * 11 FILEADDDEFAULT - */ - ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL ); - ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT ); - ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE ); - ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN ); - ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED ); - - if (ret) - msi_set_property( package->db, szPreselected, szOne ); - - return ret; -} - -UINT MSI_SetFeatureStates(MSIPACKAGE *package) -{ - int level; - MSICOMPONENT* component; - MSIFEATURE *feature; - - TRACE("Checking Install Level\n"); - - level = msi_get_property_int(package->db, szInstallLevel, 1); - - if (!msi_get_property_int( package->db, szPreselected, 0 )) - { - LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) - { - if (!is_feature_selected( feature, level )) continue; - - if (feature->ActionRequest == INSTALLSTATE_UNKNOWN) - { - if (feature->Attributes & msidbFeatureAttributesFavorSource) - { - feature->Action = INSTALLSTATE_SOURCE; - feature->ActionRequest = INSTALLSTATE_SOURCE; - } - else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise) - { - feature->Action = INSTALLSTATE_ADVERTISED; - feature->ActionRequest = INSTALLSTATE_ADVERTISED; - } - else - { - feature->Action = INSTALLSTATE_LOCAL; - feature->ActionRequest = INSTALLSTATE_LOCAL; - } - } - } - /* disable child features of unselected parent or follow parent */ - LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) - { - FeatureList *fl; - - LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry ) - { - if (!is_feature_selected( feature, level )) - { - fl->feature->Action = INSTALLSTATE_UNKNOWN; - fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN; - } - else if (fl->feature->Attributes & msidbFeatureAttributesFollowParent) - { - TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n", - debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest, - debugstr_w(feature->Feature), feature->Level, feature->ActionRequest); - fl->feature->Action = feature->Action; - fl->feature->ActionRequest = feature->ActionRequest; - } - } - } - } - else /* preselected */ - { - LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) - { - if (!is_feature_selected( feature, level )) continue; - - if (feature->ActionRequest == INSTALLSTATE_UNKNOWN) - { - if (feature->Installed == INSTALLSTATE_ABSENT) - { - feature->Action = INSTALLSTATE_UNKNOWN; - feature->ActionRequest = INSTALLSTATE_UNKNOWN; - } - else - { - feature->Action = feature->Installed; - feature->ActionRequest = feature->Installed; - } - } - } - LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) - { - FeatureList *fl; - - LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry ) - { - if (fl->feature->Attributes & msidbFeatureAttributesFollowParent && - (!(feature->Attributes & msidbFeatureAttributesFavorAdvertise))) - { - TRACE("feature %s (level %d request %d) follows parent %s (level %d request %d)\n", - debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest, - debugstr_w(feature->Feature), feature->Level, feature->ActionRequest); - fl->feature->Action = feature->Action; - fl->feature->ActionRequest = feature->ActionRequest; - } - } - } - } - - /* now we want to set component state based based on feature state */ - LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) - { - ComponentList *cl; - - TRACE("examining feature %s (level %d installed %d request %d action %d)\n", - debugstr_w(feature->Feature), feature->Level, feature->Installed, - feature->ActionRequest, feature->Action); - - if (!is_feature_selected( feature, level )) continue; - - /* features with components that have compressed files are made local */ - LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) - { - if (cl->component->ForceLocalState && - feature->ActionRequest == INSTALLSTATE_SOURCE) - { - feature->Action = INSTALLSTATE_LOCAL; - feature->ActionRequest = INSTALLSTATE_LOCAL; - break; - } - } - - LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) - { - component = cl->component; - - switch (feature->ActionRequest) - { - case INSTALLSTATE_ABSENT: - component->anyAbsent = 1; - break; - case INSTALLSTATE_ADVERTISED: - component->hasAdvertiseFeature = 1; - break; - case INSTALLSTATE_SOURCE: - component->hasSourceFeature = 1; - break; - case INSTALLSTATE_LOCAL: - component->hasLocalFeature = 1; - break; - case INSTALLSTATE_DEFAULT: - if (feature->Attributes & msidbFeatureAttributesFavorAdvertise) - component->hasAdvertiseFeature = 1; - else if (feature->Attributes & msidbFeatureAttributesFavorSource) - component->hasSourceFeature = 1; - else - component->hasLocalFeature = 1; - break; - default: - break; - } - } - } - - LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry ) - { - /* check if it's local or source */ - if (!(component->Attributes & msidbComponentAttributesOptional) && - (component->hasLocalFeature || component->hasSourceFeature)) - { - if ((component->Attributes & msidbComponentAttributesSourceOnly) && - !component->ForceLocalState) - { - component->Action = INSTALLSTATE_SOURCE; - component->ActionRequest = INSTALLSTATE_SOURCE; - } - else - { - component->Action = INSTALLSTATE_LOCAL; - component->ActionRequest = INSTALLSTATE_LOCAL; - } - continue; - } - - /* if any feature is local, the component must be local too */ - if (component->hasLocalFeature) - { - component->Action = INSTALLSTATE_LOCAL; - component->ActionRequest = INSTALLSTATE_LOCAL; - continue; - } - if (component->hasSourceFeature) - { - component->Action = INSTALLSTATE_SOURCE; - component->ActionRequest = INSTALLSTATE_SOURCE; - continue; - } - if (component->hasAdvertiseFeature) - { - component->Action = INSTALLSTATE_ADVERTISED; - component->ActionRequest = INSTALLSTATE_ADVERTISED; - continue; - } - TRACE("nobody wants component %s\n", debugstr_w(component->Component)); - if (component->anyAbsent && - (component->Installed == INSTALLSTATE_LOCAL || component->Installed == INSTALLSTATE_SOURCE)) - { - component->Action = INSTALLSTATE_ABSENT; - component->ActionRequest = INSTALLSTATE_ABSENT; - } - } - - LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry ) - { - if (component->ActionRequest == INSTALLSTATE_DEFAULT) - { - TRACE("%s was default, setting to local\n", debugstr_w(component->Component)); - component->Action = INSTALLSTATE_LOCAL; - component->ActionRequest = INSTALLSTATE_LOCAL; - } - - if (component->ActionRequest == INSTALLSTATE_SOURCE && - component->Installed == INSTALLSTATE_SOURCE && - component->hasSourceFeature) - { - component->Action = INSTALLSTATE_UNKNOWN; - component->ActionRequest = INSTALLSTATE_UNKNOWN; - } - - TRACE("component %s (installed %d request %d action %d)\n", - debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action); - - if (component->Action == INSTALLSTATE_LOCAL || component->Action == INSTALLSTATE_SOURCE) - component->num_clients++; - else if (component->Action == INSTALLSTATE_ABSENT) - component->num_clients--; - } - - return ERROR_SUCCESS; -} - -static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param) -{ - MSIPACKAGE *package = param; - LPCWSTR name; - MSIFEATURE *feature; - - name = MSI_RecordGetString( row, 1 ); - - feature = msi_get_loaded_feature( package, name ); - if (!feature) - ERR("FAILED to find loaded feature %s\n",debugstr_w(name)); - else - { - LPCWSTR Condition; - Condition = MSI_RecordGetString(row,3); - - if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE) - { - int level = MSI_RecordGetInteger(row,2); - TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level); - feature->Level = level; - } - } - return ERROR_SUCCESS; -} - -VS_FIXEDFILEINFO *msi_get_disk_file_version( LPCWSTR filename ) -{ - static const WCHAR name[] = {'\\',0}; - VS_FIXEDFILEINFO *ptr, *ret; - LPVOID version; - DWORD versize, handle; - UINT sz; - - versize = GetFileVersionInfoSizeW( filename, &handle ); - if (!versize) - return NULL; - - version = msi_alloc( versize ); - if (!version) - return NULL; - - GetFileVersionInfoW( filename, 0, versize, version ); - - if (!VerQueryValueW( version, name, (LPVOID *)&ptr, &sz )) - { - msi_free( version ); - return NULL; - } - - ret = msi_alloc( sz ); - memcpy( ret, ptr, sz ); - - msi_free( version ); - return ret; -} - -int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version ) -{ - DWORD ms, ls; - - msi_parse_version_string( version, &ms, &ls ); - - if (fi->dwFileVersionMS > ms) return 1; - else if (fi->dwFileVersionMS < ms) return -1; - else if (fi->dwFileVersionLS > ls) return 1; - else if (fi->dwFileVersionLS < ls) return -1; - return 0; -} - -int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 ) -{ - DWORD ms1, ms2; - - msi_parse_version_string( ver1, &ms1, NULL ); - msi_parse_version_string( ver2, &ms2, NULL ); - - if (ms1 > ms2) return 1; - else if (ms1 < ms2) return -1; - return 0; -} - -DWORD msi_get_disk_file_size( LPCWSTR filename ) -{ - HANDLE file; - DWORD size; - - file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); - if (file == INVALID_HANDLE_VALUE) - return INVALID_FILE_SIZE; - - size = GetFileSize( file, NULL ); - TRACE("size is %u\n", size); - CloseHandle( file ); - return size; -} - -BOOL msi_file_hash_matches( MSIFILE *file ) -{ - UINT r; - MSIFILEHASHINFO hash; - - hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO); - r = MsiGetFileHashW( file->TargetPath, 0, &hash ); - if (r != ERROR_SUCCESS) - return FALSE; - - return !memcmp( &hash, &file->hash, sizeof(MSIFILEHASHINFO) ); -} - -static WCHAR *get_temp_dir( void ) -{ - static UINT id; - WCHAR tmp[MAX_PATH], dir[MAX_PATH]; - - GetTempPathW( MAX_PATH, tmp ); - for (;;) - { - if (!GetTempFileNameW( tmp, szMsi, ++id, dir )) return NULL; - if (CreateDirectoryW( dir, NULL )) break; - } - return strdupW( dir ); -} - -/* - * msi_build_directory_name() - * - * This function is to save messing round with directory names - * It handles adding backslashes between path segments, - * and can add \ at the end of the directory name if told to. - * - * It takes a variable number of arguments. - * It always allocates a new string for the result, so make sure - * to free the return value when finished with it. - * - * The first arg is the number of path segments that follow. - * The arguments following count are a list of path segments. - * A path segment may be NULL. - * - * Path segments will be added with a \ separating them. - * A \ will not be added after the last segment, however if the - * last segment is NULL, then the last character will be a \ - */ -WCHAR *msi_build_directory_name( DWORD count, ... ) -{ - DWORD sz = 1, i; - WCHAR *dir; - va_list va; - - va_start( va, count ); - for (i = 0; i < count; i++) - { - const WCHAR *str = va_arg( va, const WCHAR * ); - if (str) sz += strlenW( str ) + 1; - } - va_end( va ); - - dir = msi_alloc( sz * sizeof(WCHAR) ); - dir[0] = 0; - - va_start( va, count ); - for (i = 0; i < count; i++) - { - const WCHAR *str = va_arg( va, const WCHAR * ); - if (!str) continue; - strcatW( dir, str ); - if ( i + 1 != count && dir[0] && dir[strlenW( dir ) - 1] != '\\') strcatW( dir, szBackSlash ); - } - va_end( va ); - return dir; -} - -static void set_target_path( MSIPACKAGE *package, MSIFILE *file ) -{ - MSIASSEMBLY *assembly = file->Component->assembly; - - TRACE("file %s is named %s\n", debugstr_w(file->File), debugstr_w(file->FileName)); - - msi_free( file->TargetPath ); - if (assembly && !assembly->application) - { - if (!assembly->tempdir) assembly->tempdir = get_temp_dir(); - file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName ); - msi_track_tempfile( package, file->TargetPath ); - } - else - { - const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory ); - file->TargetPath = msi_build_directory_name( 2, dir, file->FileName ); - } - - TRACE("resolves to %s\n", debugstr_w(file->TargetPath)); -} - -static UINT calculate_file_cost( MSIPACKAGE *package ) -{ - VS_FIXEDFILEINFO *file_version; - WCHAR *font_version; - MSIFILE *file; - - LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) - { - MSICOMPONENT *comp = file->Component; - DWORD file_size; - - if (!comp->Enabled) continue; - - if (file->IsCompressed) - comp->ForceLocalState = TRUE; - - set_target_path( package, file ); - - if ((comp->assembly && !comp->assembly->installed) || - GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES) - { - comp->Cost += file->FileSize; - continue; - } - file_size = msi_get_disk_file_size( file->TargetPath ); - - if (file->Version) - { - if ((file_version = msi_get_disk_file_version( file->TargetPath ))) - { - if (msi_compare_file_versions( file_version, file->Version ) < 0) - { - comp->Cost += file->FileSize - file_size; - } - msi_free( file_version ); - continue; - } - else if ((font_version = msi_font_version_from_file( file->TargetPath ))) - { - if (msi_compare_font_versions( font_version, file->Version ) < 0) - { - comp->Cost += file->FileSize - file_size; - } - msi_free( font_version ); - continue; - } - } - if (file_size != file->FileSize) - { - comp->Cost += file->FileSize - file_size; - } - } - return ERROR_SUCCESS; -} - -WCHAR *msi_normalize_path( const WCHAR *in ) -{ - const WCHAR *p = in; - WCHAR *q, *ret; - int n, len = strlenW( in ) + 2; - - if (!(q = ret = msi_alloc( len * sizeof(WCHAR) ))) return NULL; - - len = 0; - while (1) - { - /* copy until the end of the string or a space */ - while (*p != ' ' && (*q = *p)) - { - p++, len++; - /* reduce many backslashes to one */ - if (*p != '\\' || *q != '\\') - q++; - } - - /* quit at the end of the string */ - if (!*p) - break; - - /* count the number of spaces */ - n = 0; - while (p[n] == ' ') - n++; - - /* if it's leading or trailing space, skip it */ - if ( len == 0 || p[-1] == '\\' || p[n] == '\\' ) - p += n; - else /* copy n spaces */ - while (n && (*q++ = *p++)) n--; - } - while (q - ret > 0 && q[-1] == ' ') q--; - if (q - ret > 0 && q[-1] != '\\') - { - q[0] = '\\'; - q[1] = 0; - } - return ret; -} - -static WCHAR *get_install_location( MSIPACKAGE *package ) -{ - HKEY hkey; - WCHAR *path; - - if (!package->ProductCode) return NULL; - if (MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE )) - return NULL; - path = msi_reg_get_val_str( hkey, szInstallLocation ); - RegCloseKey( hkey ); - return path; -} - -void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop ) -{ - FolderList *fl; - MSIFOLDER *folder, *parent, *child; - WCHAR *path, *normalized_path; - - TRACE("resolving %s\n", debugstr_w(name)); - - if (!(folder = msi_get_loaded_folder( package, name ))) return; - - if (!strcmpW( folder->Directory, szTargetDir )) /* special resolving for target root dir */ - { - if (!(path = get_install_location( package )) && - (!load_prop || !(path = msi_dup_property( package->db, szTargetDir )))) - { - path = msi_dup_property( package->db, szRootDrive ); - } - } - else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory ))) - { - if (folder->Parent && strcmpW( folder->Directory, folder->Parent )) - { - parent = msi_get_loaded_folder( package, folder->Parent ); - path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL ); - } - else - path = msi_build_directory_name( 2, folder->TargetDefault, NULL ); - } - normalized_path = msi_normalize_path( path ); - msi_free( path ); - if (folder->ResolvedTarget && !strcmpiW( normalized_path, folder->ResolvedTarget )) - { - TRACE("%s already resolved to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget)); - msi_free( normalized_path ); - return; - } - msi_set_property( package->db, folder->Directory, normalized_path ); - msi_free( folder->ResolvedTarget ); - folder->ResolvedTarget = normalized_path; - - LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry ) - { - child = fl->folder; - msi_resolve_target_folder( package, child->Directory, load_prop ); - } - TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget)); -} - -static UINT ACTION_CostFinalize(MSIPACKAGE *package) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','C','o','n','d','i','t','i','o','n','`',0}; - static const WCHAR szOutOfDiskSpace[] = { - 'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0}; - MSICOMPONENT *comp; - MSIQUERY *view; - LPWSTR level; - UINT rc; - - TRACE("Building directory properties\n"); - msi_resolve_target_folder( package, szTargetDir, TRUE ); - - TRACE("Evaluating component conditions\n"); - LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) - { - if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE) - { - TRACE("Disabling component %s\n", debugstr_w(comp->Component)); - comp->Enabled = FALSE; - } - else - comp->Enabled = TRUE; - } - get_client_counts( package ); - - /* read components states from the registry */ - ACTION_GetComponentInstallStates(package); - ACTION_GetFeatureInstallStates(package); - - if (!process_overrides( package, msi_get_property_int( package->db, szInstallLevel, 1 ) )) - { - TRACE("Evaluating feature conditions\n"); - - rc = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (rc == ERROR_SUCCESS) - { - rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package ); - msiobj_release( &view->hdr ); - if (rc != ERROR_SUCCESS) - return rc; - } - } - - TRACE("Calculating file cost\n"); - calculate_file_cost( package ); - - msi_set_property( package->db, szCostingComplete, szOne ); - /* set default run level if not set */ - level = msi_dup_property( package->db, szInstallLevel ); - if (!level) - msi_set_property( package->db, szInstallLevel, szOne ); - msi_free(level); - - /* FIXME: check volume disk space */ - msi_set_property( package->db, szOutOfDiskSpace, szZero ); - - return MSI_SetFeatureStates(package); -} - -static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type, DWORD *size) -{ - LPSTR data = NULL; - - if (!value) - { - data = (LPSTR)strdupW(szEmpty); - *size = sizeof(szEmpty); - *type = REG_SZ; - return data; - } - if (value[0]=='#' && value[1]!='#' && value[1]!='%') - { - if (value[1]=='x') - { - LPWSTR ptr; - CHAR byte[5]; - LPWSTR deformated = NULL; - int count; - - deformat_string(package, &value[2], &deformated); - - /* binary value type */ - ptr = deformated; - *type = REG_BINARY; - if (strlenW(ptr)%2) - *size = (strlenW(ptr)/2)+1; - else - *size = strlenW(ptr)/2; - - data = msi_alloc(*size); - - byte[0] = '0'; - byte[1] = 'x'; - byte[4] = 0; - count = 0; - /* if uneven pad with a zero in front */ - if (strlenW(ptr)%2) - { - byte[2]= '0'; - byte[3]= *ptr; - ptr++; - data[count] = (BYTE)strtol(byte,NULL,0); - count ++; - TRACE("Uneven byte count\n"); - } - while (*ptr) - { - byte[2]= *ptr; - ptr++; - byte[3]= *ptr; - ptr++; - data[count] = (BYTE)strtol(byte,NULL,0); - count ++; - } - msi_free(deformated); - - TRACE("Data %i bytes(%i)\n",*size,count); - } - else - { - LPWSTR deformated; - LPWSTR p; - DWORD d = 0; - deformat_string(package, &value[1], &deformated); - - *type=REG_DWORD; - *size = sizeof(DWORD); - data = msi_alloc(*size); - p = deformated; - if (*p == '-') - p++; - while (*p) - { - if ( (*p < '0') || (*p > '9') ) - break; - d *= 10; - d += (*p - '0'); - p++; - } - if (deformated[0] == '-') - d = -d; - *(LPDWORD)data = d; - TRACE("DWORD %i\n",*(LPDWORD)data); - - msi_free(deformated); - } - } - else - { - static const WCHAR szMulti[] = {'[','~',']',0}; - LPCWSTR ptr; - *type=REG_SZ; - - if (value[0]=='#') - { - if (value[1]=='%') - { - ptr = &value[2]; - *type=REG_EXPAND_SZ; - } - else - ptr = &value[1]; - } - else - ptr=value; - - if (strstrW(value, szMulti)) - *type = REG_MULTI_SZ; - - /* remove initial delimiter */ - if (!strncmpW(value, szMulti, 3)) - ptr = value + 3; - - *size = deformat_string(package, ptr,(LPWSTR*)&data); - - /* add double NULL terminator */ - if (*type == REG_MULTI_SZ) - { - *size += 2 * sizeof(WCHAR); /* two NULL terminators */ - data = msi_realloc_zero(data, *size); - } - } - return data; -} - -static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key ) -{ - const WCHAR *ret; - - switch (root) - { - case -1: - if (msi_get_property_int( package->db, szAllUsers, 0 )) - { - *root_key = HKEY_LOCAL_MACHINE; - ret = szHLM; - } - else - { - *root_key = HKEY_CURRENT_USER; - ret = szHCU; - } - break; - case 0: - *root_key = HKEY_CLASSES_ROOT; - ret = szHCR; - break; - case 1: - *root_key = HKEY_CURRENT_USER; - ret = szHCU; - break; - case 2: - *root_key = HKEY_LOCAL_MACHINE; - ret = szHLM; - break; - case 3: - *root_key = HKEY_USERS; - ret = szHU; - break; - default: - ERR("Unknown root %i\n", root); - return NULL; - } - - return ret; -} - -static WCHAR *get_keypath( MSICOMPONENT *comp, HKEY root, const WCHAR *path ) -{ - static const WCHAR prefixW[] = {'S','O','F','T','W','A','R','E','\\'}; - static const UINT len = sizeof(prefixW) / sizeof(prefixW[0]); - - if ((is_64bit || is_wow64) && - !(comp->Attributes & msidbComponentAttributes64bit) && - root == HKEY_LOCAL_MACHINE && !strncmpiW( path, prefixW, len )) - { - UINT size; - WCHAR *path_32node; - - size = (strlenW( path ) + strlenW( szWow6432Node ) + 2) * sizeof(WCHAR); - if (!(path_32node = msi_alloc( size ))) return NULL; - - memcpy( path_32node, path, len * sizeof(WCHAR) ); - strcpyW( path_32node + len, szWow6432Node ); - strcatW( path_32node, szBackSlash ); - strcatW( path_32node, path + len ); - return path_32node; - } - return strdupW( path ); -} - -static HKEY open_key( HKEY root, const WCHAR *path, BOOL create ) -{ - REGSAM access = KEY_ALL_ACCESS; - WCHAR *subkey, *p, *q; - HKEY hkey, ret = NULL; - LONG res; - - if (is_wow64) access |= KEY_WOW64_64KEY; - - if (!(subkey = strdupW( path ))) return NULL; - p = subkey; - if ((q = strchrW( p, '\\' ))) *q = 0; - if (create) - res = RegCreateKeyExW( root, subkey, 0, NULL, 0, access, NULL, &hkey, NULL ); - else - res = RegOpenKeyExW( root, subkey, 0, access, &hkey ); - if (res) - { - TRACE("failed to open key %s (%d)\n", debugstr_w(subkey), res); - msi_free( subkey ); - return NULL; - } - if (q && q[1]) - { - ret = open_key( hkey, q + 1, create ); - RegCloseKey( hkey ); - } - else ret = hkey; - msi_free( subkey ); - return ret; -} - -static BOOL is_special_entry( const WCHAR *name ) -{ - return (name && (name[0] == '*' || name[0] == '+') && !name[1]); -} - -static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param) -{ - MSIPACKAGE *package = param; - LPSTR value; - HKEY root_key, hkey; - DWORD type,size; - LPWSTR deformated, uikey, keypath; - LPCWSTR szRoot, component, name, key; - MSICOMPONENT *comp; - MSIRECORD * uirow; - INT root; - BOOL check_first = FALSE; - UINT rc; - - msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 ); - - component = MSI_RecordGetString(row, 6); - comp = msi_get_loaded_component(package,component); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_LOCAL) - { - TRACE("component not scheduled for installation %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - - name = MSI_RecordGetString(row, 4); - if( MSI_RecordIsNull(row,5) && name ) - { - /* null values can have special meanings */ - if (name[0]=='-' && name[1] == 0) - return ERROR_SUCCESS; - if ((name[0] == '+' || name[0] == '*') && !name[1]) - check_first = TRUE; - } - - root = MSI_RecordGetInteger(row,2); - key = MSI_RecordGetString(row, 3); - - szRoot = get_root_key( package, root, &root_key ); - if (!szRoot) - return ERROR_SUCCESS; - - deformat_string(package, key , &deformated); - size = strlenW(deformated) + strlenW(szRoot) + 1; - uikey = msi_alloc(size*sizeof(WCHAR)); - strcpyW(uikey,szRoot); - strcatW(uikey,deformated); - - keypath = get_keypath( comp, root_key, deformated ); - msi_free( deformated ); - if (!(hkey = open_key( root_key, keypath, TRUE ))) - { - ERR("Could not create key %s\n", debugstr_w(keypath)); - msi_free(uikey); - msi_free(keypath); - return ERROR_FUNCTION_FAILED; - } - value = parse_value(package, MSI_RecordGetString(row, 5), &type, &size); - deformat_string(package, name, &deformated); - - if (!is_special_entry( name )) - { - if (!check_first) - { - TRACE("Setting value %s of %s\n", debugstr_w(deformated), - debugstr_w(uikey)); - RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value, size); - } - else - { - DWORD sz = 0; - rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz); - if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA) - { - TRACE("value %s of %s checked already exists\n", debugstr_w(deformated), - debugstr_w(uikey)); - } - else - { - TRACE("Checked and setting value %s of %s\n", debugstr_w(deformated), - debugstr_w(uikey)); - if (deformated || size) - RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value, size); - } - } - } - RegCloseKey(hkey); - - uirow = MSI_CreateRecord(3); - MSI_RecordSetStringW(uirow,2,deformated); - MSI_RecordSetStringW(uirow,1,uikey); - if (type == REG_SZ || type == REG_EXPAND_SZ) - MSI_RecordSetStringW(uirow, 3, (LPWSTR)value); - msi_ui_actiondata( package, szWriteRegistryValues, uirow ); - msiobj_release( &uirow->hdr ); - - msi_free(value); - msi_free(deformated); - msi_free(uikey); - msi_free(keypath); - - return ERROR_SUCCESS; -} - -static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','R','e','g','i','s','t','r','y','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package); - msiobj_release(&view->hdr); - return rc; -} - -static void delete_key( HKEY root, const WCHAR *path ) -{ - REGSAM access = 0; - WCHAR *subkey, *p; - HKEY hkey; - LONG res; - - if (is_wow64) access |= KEY_WOW64_64KEY; - - if (!(subkey = strdupW( path ))) return; - for (;;) - { - if ((p = strrchrW( subkey, '\\' ))) *p = 0; - hkey = open_key( root, subkey, FALSE ); - if (!hkey) break; - if (p && p[1]) - res = RegDeleteKeyExW( hkey, p + 1, access, 0 ); - else - res = RegDeleteKeyExW( root, subkey, access, 0 ); - if (res) - { - TRACE("failed to delete key %s (%d)\n", debugstr_w(subkey), res); - break; - } - if (p && p[1]) RegCloseKey( hkey ); - else break; - } - msi_free( subkey ); -} - -static void delete_value( HKEY root, const WCHAR *path, const WCHAR *value ) -{ - LONG res; - HKEY hkey; - DWORD num_subkeys, num_values; - - if ((hkey = open_key( root, path, FALSE ))) - { - if ((res = RegDeleteValueW( hkey, value ))) - TRACE("failed to delete value %s (%d)\n", debugstr_w(value), res); - - res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, &num_subkeys, NULL, NULL, &num_values, - NULL, NULL, NULL, NULL ); - RegCloseKey( hkey ); - if (!res && !num_subkeys && !num_values) - { - TRACE("removing empty key %s\n", debugstr_w(path)); - delete_key( root, path ); - } - } -} - -static void delete_tree( HKEY root, const WCHAR *path ) -{ - LONG res; - HKEY hkey; - - if (!(hkey = open_key( root, path, FALSE ))) return; - res = RegDeleteTreeW( hkey, NULL ); - if (res) TRACE("failed to delete subtree of %s (%d)\n", debugstr_w(path), res); - delete_key( root, path ); - RegCloseKey( hkey ); -} - -static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param ) -{ - MSIPACKAGE *package = param; - LPCWSTR component, name, key_str, root_key_str; - LPWSTR deformated_key, deformated_name, ui_key_str, keypath; - MSICOMPONENT *comp; - MSIRECORD *uirow; - BOOL delete_key = FALSE; - HKEY hkey_root; - UINT size; - INT root; - - msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 ); - - component = MSI_RecordGetString( row, 6 ); - comp = msi_get_loaded_component( package, component ); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_ABSENT) - { - TRACE("component not scheduled for removal %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - - name = MSI_RecordGetString( row, 4 ); - if (MSI_RecordIsNull( row, 5 ) && name ) - { - if (name[0] == '+' && !name[1]) - return ERROR_SUCCESS; - if ((name[0] == '-' || name[0] == '*') && !name[1]) - { - delete_key = TRUE; - name = NULL; - } - } - - root = MSI_RecordGetInteger( row, 2 ); - key_str = MSI_RecordGetString( row, 3 ); - - root_key_str = get_root_key( package, root, &hkey_root ); - if (!root_key_str) - return ERROR_SUCCESS; - - deformat_string( package, key_str, &deformated_key ); - size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1; - ui_key_str = msi_alloc( size * sizeof(WCHAR) ); - strcpyW( ui_key_str, root_key_str ); - strcatW( ui_key_str, deformated_key ); - - deformat_string( package, name, &deformated_name ); - - keypath = get_keypath( comp, hkey_root, deformated_key ); - msi_free( deformated_key ); - if (delete_key) delete_tree( hkey_root, keypath ); - else delete_value( hkey_root, keypath, deformated_name ); - msi_free( keypath ); - - uirow = MSI_CreateRecord( 2 ); - MSI_RecordSetStringW( uirow, 1, ui_key_str ); - MSI_RecordSetStringW( uirow, 2, deformated_name ); - msi_ui_actiondata( package, szRemoveRegistryValues, uirow ); - msiobj_release( &uirow->hdr ); - - msi_free( ui_key_str ); - msi_free( deformated_name ); - return ERROR_SUCCESS; -} - -static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param ) -{ - MSIPACKAGE *package = param; - LPCWSTR component, name, key_str, root_key_str; - LPWSTR deformated_key, deformated_name, ui_key_str, keypath; - MSICOMPONENT *comp; - MSIRECORD *uirow; - BOOL delete_key = FALSE; - HKEY hkey_root; - UINT size; - INT root; - - component = MSI_RecordGetString( row, 5 ); - comp = msi_get_loaded_component( package, component ); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_LOCAL) - { - TRACE("component not scheduled for installation %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - - if ((name = MSI_RecordGetString( row, 4 ))) - { - if (name[0] == '-' && !name[1]) - { - delete_key = TRUE; - name = NULL; - } - } - - root = MSI_RecordGetInteger( row, 2 ); - key_str = MSI_RecordGetString( row, 3 ); - - root_key_str = get_root_key( package, root, &hkey_root ); - if (!root_key_str) - return ERROR_SUCCESS; - - deformat_string( package, key_str, &deformated_key ); - size = strlenW( deformated_key ) + strlenW( root_key_str ) + 1; - ui_key_str = msi_alloc( size * sizeof(WCHAR) ); - strcpyW( ui_key_str, root_key_str ); - strcatW( ui_key_str, deformated_key ); - - deformat_string( package, name, &deformated_name ); - - keypath = get_keypath( comp, hkey_root, deformated_key ); - msi_free( deformated_key ); - if (delete_key) delete_tree( hkey_root, keypath ); - else delete_value( hkey_root, keypath, deformated_name ); - msi_free( keypath ); - - uirow = MSI_CreateRecord( 2 ); - MSI_RecordSetStringW( uirow, 1, ui_key_str ); - MSI_RecordSetStringW( uirow, 2, deformated_name ); - msi_ui_actiondata( package, szRemoveRegistryValues, uirow ); - msiobj_release( &uirow->hdr ); - - msi_free( ui_key_str ); - msi_free( deformated_name ); - return ERROR_SUCCESS; -} - -static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package ) -{ - static const WCHAR registry_query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','R','e','g','i','s','t','r','y','`',0}; - static const WCHAR remove_registry_query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','R','e','m','o','v','e','R','e','g','i','s','t','r','y','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW( package->db, registry_query, &view ); - if (rc == ERROR_SUCCESS) - { - rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package ); - msiobj_release( &view->hdr ); - if (rc != ERROR_SUCCESS) - return rc; - } - rc = MSI_DatabaseOpenViewW( package->db, remove_registry_query, &view ); - if (rc == ERROR_SUCCESS) - { - rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package ); - msiobj_release( &view->hdr ); - if (rc != ERROR_SUCCESS) - return rc; - } - return ERROR_SUCCESS; -} - -static UINT ACTION_InstallInitialize(MSIPACKAGE *package) -{ - package->script->CurrentlyScripting = TRUE; - - return ERROR_SUCCESS; -} - - -static UINT ACTION_InstallValidate(MSIPACKAGE *package) -{ - static const WCHAR query[]= { - 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', - '`','R','e','g','i','s','t','r','y','`',0}; - MSICOMPONENT *comp; - DWORD total = 0, count = 0; - MSIQUERY *view; - MSIFEATURE *feature; - MSIFILE *file; - UINT rc; - - TRACE("InstallValidate\n"); - - rc = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (rc == ERROR_SUCCESS) - { - rc = MSI_IterateRecords( view, &count, NULL, package ); - msiobj_release( &view->hdr ); - if (rc != ERROR_SUCCESS) - return rc; - total += count * REG_PROGRESS_VALUE; - } - LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) - total += COMPONENT_PROGRESS_VALUE; - - LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) - total += file->FileSize; - - msi_ui_progress( package, 0, total, 0, 0 ); - - LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) - { - TRACE("Feature: %s Installed %d Request %d Action %d\n", - debugstr_w(feature->Feature), feature->Installed, - feature->ActionRequest, feature->Action); - } - return ERROR_SUCCESS; -} - -static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param) -{ - MSIPACKAGE* package = param; - LPCWSTR cond = NULL; - LPCWSTR message = NULL; - UINT r; - - static const WCHAR title[]= - {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0}; - - cond = MSI_RecordGetString(row,1); - - r = MSI_EvaluateConditionW(package,cond); - if (r == MSICONDITION_FALSE) - { - if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE) - { - LPWSTR deformated; - message = MSI_RecordGetString(row,2); - deformat_string(package,message,&deformated); - MessageBoxW(NULL,deformated,title,MB_OK); - msi_free(deformated); - } - - return ERROR_INSTALL_FAILURE; - } - - return ERROR_SUCCESS; -} - -static UINT ACTION_LaunchConditions(MSIPACKAGE *package) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0}; - MSIQUERY *view; - UINT rc; - - TRACE("Checking launch conditions\n"); - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package); - msiobj_release(&view->hdr); - return rc; -} - -static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp ) -{ - - if (!cmp->KeyPath) - return strdupW( msi_get_target_folder( package, cmp->Directory ) ); - - if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath) - { - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','R','e','g','i','s','t','r','y','`',' ','W','H','E','R','E',' ', - '`','R','e','g','i','s','t','r','y','`',' ','=',' ' ,'\'','%','s','\'',0}; - static const WCHAR fmt[] = {'%','0','2','i',':','\\','%','s','\\',0}; - static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0}; - MSIRECORD *row; - UINT root, len; - LPWSTR deformated, buffer, deformated_name; - LPCWSTR key, name; - - row = MSI_QueryGetRecord(package->db, query, cmp->KeyPath); - if (!row) - return NULL; - - root = MSI_RecordGetInteger(row,2); - key = MSI_RecordGetString(row, 3); - name = MSI_RecordGetString(row, 4); - deformat_string(package, key , &deformated); - deformat_string(package, name, &deformated_name); - - len = strlenW(deformated) + 6; - if (deformated_name) - len+=strlenW(deformated_name); - - buffer = msi_alloc( len *sizeof(WCHAR)); - - if (deformated_name) - sprintfW(buffer,fmt2,root,deformated,deformated_name); - else - sprintfW(buffer,fmt,root,deformated); - - msi_free(deformated); - msi_free(deformated_name); - msiobj_release(&row->hdr); - - return buffer; - } - else if (cmp->Attributes & msidbComponentAttributesODBCDataSource) - { - FIXME("UNIMPLEMENTED keypath as ODBC Source\n"); - return NULL; - } - else - { - MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath ); - - if (file) - return strdupW( file->TargetPath ); - } - return NULL; -} - -static HKEY openSharedDLLsKey(void) -{ - HKEY hkey=0; - static const WCHAR path[] = - {'S','o','f','t','w','a','r','e','\\', - 'M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s','\\', - 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'S','h','a','r','e','d','D','L','L','s',0}; - - RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey); - return hkey; -} - -static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll) -{ - HKEY hkey; - DWORD count=0; - DWORD type; - DWORD sz = sizeof(count); - DWORD rc; - - hkey = openSharedDLLsKey(); - rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz); - if (rc != ERROR_SUCCESS) - count = 0; - RegCloseKey(hkey); - return count; -} - -static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count) -{ - HKEY hkey; - - hkey = openSharedDLLsKey(); - if (count > 0) - msi_reg_set_val_dword( hkey, path, count ); - else - RegDeleteValueW(hkey,path); - RegCloseKey(hkey); - return count; -} - -static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp ) -{ - MSIFEATURE *feature; - INT count = 0; - BOOL write = FALSE; - - /* only refcount DLLs */ - if (comp->KeyPath == NULL || - comp->assembly || - comp->Attributes & msidbComponentAttributesRegistryKeyPath || - comp->Attributes & msidbComponentAttributesODBCDataSource) - write = FALSE; - else - { - count = ACTION_GetSharedDLLsCount( comp->FullKeypath); - write = (count > 0); - - if (comp->Attributes & msidbComponentAttributesSharedDllRefCount) - write = TRUE; - } - - /* increment counts */ - LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) - { - ComponentList *cl; - - if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL) - continue; - - LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) - { - if ( cl->component == comp ) - count++; - } - } - - /* decrement counts */ - LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) - { - ComponentList *cl; - - if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT) - continue; - - LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) - { - if ( cl->component == comp ) - count--; - } - } - - /* ref count all the files in the component */ - if (write) - { - MSIFILE *file; - - LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) - { - if (file->Component == comp) - ACTION_WriteSharedDLLsCount( file->TargetPath, count ); - } - } - - /* add a count for permanent */ - if (comp->Attributes & msidbComponentAttributesPermanent) - count ++; - - comp->RefCount = count; - - if (write) - ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount ); -} - -static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp ) -{ - if (comp->assembly) - { - const WCHAR prefixW[] = {'<','\\',0}; - DWORD len = strlenW( prefixW ) + strlenW( comp->assembly->display_name ); - WCHAR *keypath = msi_alloc( (len + 1) * sizeof(WCHAR) ); - - if (keypath) - { - strcpyW( keypath, prefixW ); - strcatW( keypath, comp->assembly->display_name ); - } - return keypath; - } - return resolve_keypath( package, comp ); -} - -static UINT ACTION_ProcessComponents(MSIPACKAGE *package) -{ - WCHAR squished_pc[GUID_SIZE], squished_cc[GUID_SIZE]; - UINT rc; - MSICOMPONENT *comp; - HKEY hkey; - - TRACE("\n"); - - squash_guid(package->ProductCode,squished_pc); - msi_set_sourcedir_props(package, FALSE); - - LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) - { - MSIRECORD *uirow; - INSTALLSTATE action; - - msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 ); - if (!comp->ComponentId) - continue; - - squash_guid( comp->ComponentId, squished_cc ); - msi_free( comp->FullKeypath ); - comp->FullKeypath = build_full_keypath( package, comp ); - - ACTION_RefCountComponent( package, comp ); - - if (package->need_rollback) action = comp->Installed; - else action = comp->ActionRequest; - - TRACE("Component %s (%s) Keypath=%s RefCount=%u Clients=%u Action=%u\n", - debugstr_w(comp->Component), debugstr_w(squished_cc), - debugstr_w(comp->FullKeypath), comp->RefCount, comp->num_clients, action); - - if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE) - { - if (package->Context == MSIINSTALLCONTEXT_MACHINE) - rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid, &hkey, TRUE); - else - rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE); - - if (rc != ERROR_SUCCESS) - continue; - - if (comp->Attributes & msidbComponentAttributesPermanent) - { - static const WCHAR szPermKey[] = - { '0','0','0','0','0','0','0','0','0','0','0','0', - '0','0','0','0','0','0','0','0','0','0','0','0', - '0','0','0','0','0','0','0','0',0 }; - - msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath); - } - if (action == INSTALLSTATE_LOCAL) - msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath); - else - { - MSIFILE *file; - MSIRECORD *row; - LPWSTR ptr, ptr2; - WCHAR source[MAX_PATH]; - WCHAR base[MAX_PATH]; - LPWSTR sourcepath; - - static const WCHAR fmt[] = {'%','0','2','d','\\',0}; - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', - '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ', - '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ', - '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ', - '`','D','i','s','k','I','d','`',0}; - - if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath))) - continue; - - row = MSI_QueryGetRecord(package->db, query, file->Sequence); - sprintfW(source, fmt, MSI_RecordGetInteger(row, 1)); - ptr2 = strrchrW(source, '\\') + 1; - msiobj_release(&row->hdr); - - lstrcpyW(base, package->PackagePath); - ptr = strrchrW(base, '\\'); - *(ptr + 1) = '\0'; - - sourcepath = msi_resolve_file_source(package, file); - ptr = sourcepath + lstrlenW(base); - lstrcpyW(ptr2, ptr); - msi_free(sourcepath); - - msi_reg_set_val_str(hkey, squished_pc, source); - } - RegCloseKey(hkey); - } - else if (action == INSTALLSTATE_ABSENT) - { - if (comp->num_clients <= 0) - { - if (package->Context == MSIINSTALLCONTEXT_MACHINE) - MSIREG_DeleteUserDataComponentKey( comp->ComponentId, szLocalSid ); - else - MSIREG_DeleteUserDataComponentKey( comp->ComponentId, NULL ); - } - } - - /* UI stuff */ - uirow = MSI_CreateRecord(3); - MSI_RecordSetStringW(uirow,1,package->ProductCode); - MSI_RecordSetStringW(uirow,2,comp->ComponentId); - MSI_RecordSetStringW(uirow,3,comp->FullKeypath); - msi_ui_actiondata( package, szProcessComponents, uirow ); - msiobj_release( &uirow->hdr ); - } - return ERROR_SUCCESS; -} - -typedef struct { - CLSID clsid; - LPWSTR source; - - LPWSTR path; - ITypeLib *ptLib; -} typelib_struct; - -static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, - LPWSTR lpszName, LONG_PTR lParam) -{ - TLIBATTR *attr; - typelib_struct *tl_struct = (typelib_struct*) lParam; - static const WCHAR fmt[] = {'%','s','\\','%','i',0}; - int sz; - HRESULT res; - - if (!IS_INTRESOURCE(lpszName)) - { - ERR("Not Int Resource Name %s\n",debugstr_w(lpszName)); - return TRUE; - } - - sz = strlenW(tl_struct->source)+4; - sz *= sizeof(WCHAR); - - if ((INT_PTR)lpszName == 1) - tl_struct->path = strdupW(tl_struct->source); - else - { - tl_struct->path = msi_alloc(sz); - sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName); - } - - TRACE("trying %s\n", debugstr_w(tl_struct->path)); - res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib); - if (FAILED(res)) - { - msi_free(tl_struct->path); - tl_struct->path = NULL; - - return TRUE; - } - - ITypeLib_GetLibAttr(tl_struct->ptLib, &attr); - if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid))) - { - ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr); - return FALSE; - } - - msi_free(tl_struct->path); - tl_struct->path = NULL; - - ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr); - ITypeLib_Release(tl_struct->ptLib); - - return TRUE; -} - -static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param) -{ - MSIPACKAGE* package = param; - LPCWSTR component; - MSICOMPONENT *comp; - MSIFILE *file; - typelib_struct tl_struct; - ITypeLib *tlib; - HMODULE module; - HRESULT hr; - - component = MSI_RecordGetString(row,3); - comp = msi_get_loaded_component(package,component); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_LOCAL) - { - TRACE("component not scheduled for installation %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - - if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath ))) - { - TRACE("component has no key path\n"); - return ERROR_SUCCESS; - } - msi_ui_actiondata( package, szRegisterTypeLibraries, row ); - - module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE ); - if (module) - { - LPCWSTR guid; - guid = MSI_RecordGetString(row,1); - CLSIDFromString( guid, &tl_struct.clsid); - tl_struct.source = strdupW( file->TargetPath ); - tl_struct.path = NULL; - - EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc, - (LONG_PTR)&tl_struct); - - if (tl_struct.path) - { - LPCWSTR helpid, help_path = NULL; - HRESULT res; - - helpid = MSI_RecordGetString(row,6); - - if (helpid) help_path = msi_get_target_folder( package, helpid ); - res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path ); - - if (FAILED(res)) - ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path)); - else - TRACE("Registered %s\n", debugstr_w(tl_struct.path)); - - ITypeLib_Release(tl_struct.ptLib); - msi_free(tl_struct.path); - } - else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source)); - - FreeLibrary(module); - msi_free(tl_struct.source); - } - else - { - hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib); - if (FAILED(hr)) - { - ERR("Failed to load type library: %08x\n", hr); - return ERROR_INSTALL_FAILURE; - } - - ITypeLib_Release(tlib); - } - - return ERROR_SUCCESS; -} - -static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','T','y','p','e','L','i','b','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package); - msiobj_release(&view->hdr); - return rc; -} - -static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param ) -{ - MSIPACKAGE *package = param; - LPCWSTR component, guid; - MSICOMPONENT *comp; - GUID libid; - UINT version; - LCID language; - SYSKIND syskind; - HRESULT hr; - - component = MSI_RecordGetString( row, 3 ); - comp = msi_get_loaded_component( package, component ); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_ABSENT) - { - TRACE("component not scheduled for removal %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - msi_ui_actiondata( package, szUnregisterTypeLibraries, row ); - - guid = MSI_RecordGetString( row, 1 ); - CLSIDFromString( guid, &libid ); - version = MSI_RecordGetInteger( row, 4 ); - language = MSI_RecordGetInteger( row, 2 ); - -#ifdef _WIN64 - syskind = SYS_WIN64; -#else - syskind = SYS_WIN32; -#endif - - hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind ); - if (FAILED(hr)) - { - WARN("Failed to unregister typelib: %08x\n", hr); - } - - return ERROR_SUCCESS; -} - -static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','T','y','p','e','L','i','b','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package ); - msiobj_release( &view->hdr ); - return rc; -} - -static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row ) -{ - static const WCHAR szlnk[] = {'.','l','n','k',0}; - LPCWSTR directory, extension, link_folder; - LPWSTR link_file, filename; - - directory = MSI_RecordGetString( row, 2 ); - link_folder = msi_get_target_folder( package, directory ); - if (!link_folder) - { - ERR("unable to resolve folder %s\n", debugstr_w(directory)); - return NULL; - } - /* may be needed because of a bug somewhere else */ - msi_create_full_path( link_folder ); - - filename = msi_dup_record_field( row, 3 ); - msi_reduce_to_long_filename( filename ); - - extension = strchrW( filename, '.' ); - if (!extension || strcmpiW( extension, szlnk )) - { - int len = strlenW( filename ); - filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) ); - memcpy( filename + len, szlnk, sizeof(szlnk) ); - } - link_file = msi_build_directory_name( 2, link_folder, filename ); - msi_free( filename ); - - return link_file; -} - -WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name ) -{ - static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0}; - static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0}; - WCHAR *folder, *dest, *path; - - if (package->Context == MSIINSTALLCONTEXT_MACHINE) - folder = msi_dup_property( package->db, szWindowsFolder ); - else - { - WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder ); - folder = msi_build_directory_name( 2, appdata, szMicrosoft ); - msi_free( appdata ); - } - dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode ); - msi_create_full_path( dest ); - path = msi_build_directory_name( 2, dest, icon_name ); - msi_free( folder ); - msi_free( dest ); - return path; -} - -static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param) -{ - MSIPACKAGE *package = param; - LPWSTR link_file, deformated, path; - LPCWSTR component, target; - MSICOMPONENT *comp; - IShellLinkW *sl = NULL; - IPersistFile *pf = NULL; - HRESULT res; - - component = MSI_RecordGetString(row, 4); - comp = msi_get_loaded_component(package, component); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_LOCAL) - { - TRACE("component not scheduled for installation %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - msi_ui_actiondata( package, szCreateShortcuts, row ); - - res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, - &IID_IShellLinkW, (LPVOID *) &sl ); - - if (FAILED( res )) - { - ERR("CLSID_ShellLink not available\n"); - goto err; - } - - res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf ); - if (FAILED( res )) - { - ERR("QueryInterface(IID_IPersistFile) failed\n"); - goto err; - } - - target = MSI_RecordGetString(row, 5); - if (strchrW(target, '[')) - { - deformat_string( package, target, &path ); - TRACE("target path is %s\n", debugstr_w(path)); - IShellLinkW_SetPath( sl, path ); - msi_free( path ); - } - else - { - FIXME("poorly handled shortcut format, advertised shortcut\n"); - IShellLinkW_SetPath(sl,comp->FullKeypath); - } - - if (!MSI_RecordIsNull(row,6)) - { - LPCWSTR arguments = MSI_RecordGetString(row, 6); - deformat_string(package, arguments, &deformated); - IShellLinkW_SetArguments(sl,deformated); - msi_free(deformated); - } - - if (!MSI_RecordIsNull(row,7)) - { - LPCWSTR description = MSI_RecordGetString(row, 7); - IShellLinkW_SetDescription(sl, description); - } - - if (!MSI_RecordIsNull(row,8)) - IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8)); - - if (!MSI_RecordIsNull(row,9)) - { - INT index; - LPCWSTR icon = MSI_RecordGetString(row, 9); - - path = msi_build_icon_path(package, icon); - index = MSI_RecordGetInteger(row,10); - - /* no value means 0 */ - if (index == MSI_NULL_INTEGER) - index = 0; - - IShellLinkW_SetIconLocation(sl, path, index); - msi_free(path); - } - - if (!MSI_RecordIsNull(row,11)) - IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11)); - - if (!MSI_RecordIsNull(row,12)) - { - LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 ); - full_path = msi_get_target_folder( package, wkdir ); - if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path ); - } - link_file = get_link_file(package, row); - - TRACE("Writing shortcut to %s\n", debugstr_w(link_file)); - IPersistFile_Save(pf, link_file, FALSE); - msi_free(link_file); - -err: - if (pf) - IPersistFile_Release( pf ); - if (sl) - IShellLinkW_Release( sl ); - - return ERROR_SUCCESS; -} - -static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','S','h','o','r','t','c','u','t','`',0}; - MSIQUERY *view; - HRESULT res; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - res = CoInitialize( NULL ); - - rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package); - msiobj_release(&view->hdr); - - if (SUCCEEDED(res)) CoUninitialize(); - return rc; -} - -static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param ) -{ - MSIPACKAGE *package = param; - LPWSTR link_file; - LPCWSTR component; - MSICOMPONENT *comp; - - component = MSI_RecordGetString( row, 4 ); - comp = msi_get_loaded_component( package, component ); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_ABSENT) - { - TRACE("component not scheduled for removal %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - msi_ui_actiondata( package, szRemoveShortcuts, row ); - - link_file = get_link_file( package, row ); - - TRACE("Removing shortcut file %s\n", debugstr_w( link_file )); - if (!DeleteFileW( link_file )) - { - WARN("Failed to remove shortcut file %u\n", GetLastError()); - } - msi_free( link_file ); - - return ERROR_SUCCESS; -} - -static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','S','h','o','r','t','c','u','t','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package ); - msiobj_release( &view->hdr ); - return rc; -} - -static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param) -{ - MSIPACKAGE* package = param; - HANDLE the_file; - LPWSTR FilePath; - LPCWSTR FileName; - CHAR buffer[1024]; - DWORD sz; - UINT rc; - - FileName = MSI_RecordGetString(row,1); - if (!FileName) - { - ERR("Unable to get FileName\n"); - return ERROR_SUCCESS; - } - - FilePath = msi_build_icon_path(package, FileName); - - TRACE("Creating icon file at %s\n",debugstr_w(FilePath)); - - the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL); - - if (the_file == INVALID_HANDLE_VALUE) - { - ERR("Unable to create file %s\n",debugstr_w(FilePath)); - msi_free(FilePath); - return ERROR_SUCCESS; - } - - do - { - DWORD write; - sz = 1024; - rc = MSI_RecordReadStream(row,2,buffer,&sz); - if (rc != ERROR_SUCCESS) - { - ERR("Failed to get stream\n"); - CloseHandle(the_file); - DeleteFileW(FilePath); - break; - } - WriteFile(the_file,buffer,sz,&write,NULL); - } while (sz == 1024); - - msi_free(FilePath); - CloseHandle(the_file); - - return ERROR_SUCCESS; -} - -static UINT msi_publish_icons(MSIPACKAGE *package) -{ - static const WCHAR query[]= { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','I','c','o','n','`',0}; - MSIQUERY *view; - UINT r; - - r = MSI_DatabaseOpenViewW(package->db, query, &view); - if (r == ERROR_SUCCESS) - { - r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package); - msiobj_release(&view->hdr); - if (r != ERROR_SUCCESS) - return r; - } - return ERROR_SUCCESS; -} - -static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey) -{ - UINT r; - HKEY source; - LPWSTR buffer; - MSIMEDIADISK *disk; - MSISOURCELISTINFO *info; - - r = RegCreateKeyW(hkey, szSourceList, &source); - if (r != ERROR_SUCCESS) - return r; - - RegCloseKey(source); - - buffer = strrchrW(package->PackagePath, '\\') + 1; - r = MsiSourceListSetInfoW(package->ProductCode, NULL, - package->Context, MSICODE_PRODUCT, - INSTALLPROPERTY_PACKAGENAMEW, buffer); - if (r != ERROR_SUCCESS) - return r; - - r = MsiSourceListSetInfoW(package->ProductCode, NULL, - package->Context, MSICODE_PRODUCT, - INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty); - if (r != ERROR_SUCCESS) - return r; - - r = MsiSourceListSetInfoW(package->ProductCode, NULL, - package->Context, MSICODE_PRODUCT, - INSTALLPROPERTY_DISKPROMPTW, szEmpty); - if (r != ERROR_SUCCESS) - return r; - - LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry) - { - if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW )) - msi_set_last_used_source(package->ProductCode, NULL, info->context, - info->options, info->value); - else - MsiSourceListSetInfoW(package->ProductCode, NULL, - info->context, info->options, - info->property, info->value); - } - - LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry) - { - MsiSourceListAddMediaDiskW(package->ProductCode, NULL, - disk->context, disk->options, - disk->disk_id, disk->volume_label, disk->disk_prompt); - } - - return ERROR_SUCCESS; -} - -static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey) -{ - MSIHANDLE hdb, suminfo; - WCHAR guids[MAX_PATH]; - WCHAR packcode[SQUISH_GUID_SIZE]; - LPWSTR buffer; - LPWSTR ptr; - DWORD langid; - DWORD size; - UINT r; - - static const WCHAR szARPProductIcon[] = - {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0}; - static const WCHAR szAssignment[] = - {'A','s','s','i','g','n','m','e','n','t',0}; - static const WCHAR szAdvertiseFlags[] = - {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0}; - static const WCHAR szClients[] = - {'C','l','i','e','n','t','s',0}; - static const WCHAR szColon[] = {':',0}; - - buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW); - msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer); - msi_free(buffer); - - langid = msi_get_property_int(package->db, szProductLanguage, 0); - msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid); - - /* FIXME */ - msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0); - - buffer = msi_dup_property(package->db, szARPProductIcon); - if (buffer) - { - LPWSTR path = msi_build_icon_path(package, buffer); - msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path); - msi_free(path); - msi_free(buffer); - } - - buffer = msi_dup_property(package->db, szProductVersion); - if (buffer) - { - DWORD verdword = msi_version_str_to_dword(buffer); - msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword); - msi_free(buffer); - } - - msi_reg_set_val_dword(hkey, szAssignment, 0); - msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184); - msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0); - msi_reg_set_val_str(hkey, szClients, szColon); - - hdb = alloc_msihandle(&package->db->hdr); - if (!hdb) - return ERROR_NOT_ENOUGH_MEMORY; - - r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo); - MsiCloseHandle(hdb); - if (r != ERROR_SUCCESS) - goto done; - - size = MAX_PATH; - r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL, - NULL, guids, &size); - if (r != ERROR_SUCCESS) - goto done; - - ptr = strchrW(guids, ';'); - if (ptr) *ptr = 0; - squash_guid(guids, packcode); - msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode); - -done: - MsiCloseHandle(suminfo); - return ERROR_SUCCESS; -} - -static UINT msi_publish_upgrade_code(MSIPACKAGE *package) -{ - UINT r; - HKEY hkey; - LPWSTR upgrade; - WCHAR squashed_pc[SQUISH_GUID_SIZE]; - - upgrade = msi_dup_property(package->db, szUpgradeCode); - if (!upgrade) - return ERROR_SUCCESS; - - if (package->Context == MSIINSTALLCONTEXT_MACHINE) - r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE); - else - r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE); - - if (r != ERROR_SUCCESS) - { - WARN("failed to open upgrade code key\n"); - msi_free(upgrade); - return ERROR_SUCCESS; - } - squash_guid(package->ProductCode, squashed_pc); - msi_reg_set_val_str(hkey, squashed_pc, NULL); - RegCloseKey(hkey); - msi_free(upgrade); - return ERROR_SUCCESS; -} - -static BOOL msi_check_publish(MSIPACKAGE *package) -{ - MSIFEATURE *feature; - - LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry) - { - feature->Action = msi_get_feature_action( package, feature ); - if (feature->Action == INSTALLSTATE_LOCAL) - return TRUE; - } - - return FALSE; -} - -static BOOL msi_check_unpublish(MSIPACKAGE *package) -{ - MSIFEATURE *feature; - - LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry) - { - feature->Action = msi_get_feature_action( package, feature ); - if (feature->Action != INSTALLSTATE_ABSENT) - return FALSE; - } - - return TRUE; -} - -static UINT msi_publish_patches( MSIPACKAGE *package ) -{ - static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0}; - WCHAR patch_squashed[GUID_SIZE]; - HKEY patches_key = NULL, product_patches_key = NULL, product_key; - LONG res; - MSIPATCHINFO *patch; - UINT r; - WCHAR *p, *all_patches = NULL; - DWORD len = 0; - - r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE ); - if (r != ERROR_SUCCESS) - return ERROR_FUNCTION_FAILED; - - res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL ); - if (res != ERROR_SUCCESS) - { - r = ERROR_FUNCTION_FAILED; - goto done; - } - - r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE ); - if (r != ERROR_SUCCESS) - goto done; - - LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry ) - { - squash_guid( patch->patchcode, patch_squashed ); - len += strlenW( patch_squashed ) + 1; - } - - p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) ); - if (!all_patches) - goto done; - - LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry ) - { - HKEY patch_key; - - squash_guid( patch->patchcode, p ); - p += strlenW( p ) + 1; - - res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ, - (const BYTE *)patch->transforms, - (strlenW(patch->transforms) + 1) * sizeof(WCHAR) ); - if (res != ERROR_SUCCESS) - goto done; - - r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE ); - if (r != ERROR_SUCCESS) - goto done; - - res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile, - (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) ); - RegCloseKey( patch_key ); - if (res != ERROR_SUCCESS) - goto done; - - if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE )) - { - res = GetLastError(); - ERR("Unable to copy patch package %d\n", res); - goto done; - } - res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL ); - if (res != ERROR_SUCCESS) - goto done; - - res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) ); - RegCloseKey( patch_key ); - if (res != ERROR_SUCCESS) - goto done; - } - - all_patches[len] = 0; - res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ, - (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) ); - if (res != ERROR_SUCCESS) - goto done; - - res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ, - (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) ); - if (res != ERROR_SUCCESS) - r = ERROR_FUNCTION_FAILED; - -done: - RegCloseKey( product_patches_key ); - RegCloseKey( patches_key ); - RegCloseKey( product_key ); - msi_free( all_patches ); - return r; -} - -static UINT ACTION_PublishProduct(MSIPACKAGE *package) -{ - UINT rc; - HKEY hukey = NULL, hudkey = NULL; - MSIRECORD *uirow; - - if (!list_empty(&package->patches)) - { - rc = msi_publish_patches(package); - if (rc != ERROR_SUCCESS) - goto end; - } - - /* FIXME: also need to publish if the product is in advertise mode */ - if (!msi_check_publish(package)) - return ERROR_SUCCESS; - - rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context, - &hukey, TRUE); - if (rc != ERROR_SUCCESS) - goto end; - - rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context, - NULL, &hudkey, TRUE); - if (rc != ERROR_SUCCESS) - goto end; - - rc = msi_publish_upgrade_code(package); - if (rc != ERROR_SUCCESS) - goto end; - - rc = msi_publish_product_properties(package, hukey); - if (rc != ERROR_SUCCESS) - goto end; - - rc = msi_publish_sourcelist(package, hukey); - if (rc != ERROR_SUCCESS) - goto end; - - rc = msi_publish_icons(package); - -end: - uirow = MSI_CreateRecord( 1 ); - MSI_RecordSetStringW( uirow, 1, package->ProductCode ); - msi_ui_actiondata( package, szPublishProduct, uirow ); - msiobj_release( &uirow->hdr ); - - RegCloseKey(hukey); - RegCloseKey(hudkey); - return rc; -} - -static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row ) -{ - WCHAR *filename, *ptr, *folder, *ret; - const WCHAR *dirprop; - - filename = msi_dup_record_field( row, 2 ); - if (filename && (ptr = strchrW( filename, '|' ))) - ptr++; - else - ptr = filename; - - dirprop = MSI_RecordGetString( row, 3 ); - if (dirprop) - { - folder = strdupW( msi_get_target_folder( package, dirprop ) ); - if (!folder) folder = msi_dup_property( package->db, dirprop ); - } - else - folder = msi_dup_property( package->db, szWindowsFolder ); - - if (!folder) - { - ERR("Unable to resolve folder %s\n", debugstr_w(dirprop)); - msi_free( filename ); - return NULL; - } - - ret = msi_build_directory_name( 2, folder, ptr ); - - msi_free( filename ); - msi_free( folder ); - return ret; -} - -static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param) -{ - MSIPACKAGE *package = param; - LPCWSTR component, section, key, value, identifier; - LPWSTR deformated_section, deformated_key, deformated_value, fullname; - MSIRECORD * uirow; - INT action; - MSICOMPONENT *comp; - - component = MSI_RecordGetString(row, 8); - comp = msi_get_loaded_component(package,component); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_LOCAL) - { - TRACE("component not scheduled for installation %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - - identifier = MSI_RecordGetString(row,1); - section = MSI_RecordGetString(row,4); - key = MSI_RecordGetString(row,5); - value = MSI_RecordGetString(row,6); - action = MSI_RecordGetInteger(row,7); - - deformat_string(package,section,&deformated_section); - deformat_string(package,key,&deformated_key); - deformat_string(package,value,&deformated_value); - - fullname = get_ini_file_name(package, row); - - if (action == 0) - { - TRACE("Adding value %s to section %s in %s\n", - debugstr_w(deformated_key), debugstr_w(deformated_section), - debugstr_w(fullname)); - WritePrivateProfileStringW(deformated_section, deformated_key, - deformated_value, fullname); - } - else if (action == 1) - { - WCHAR returned[10]; - GetPrivateProfileStringW(deformated_section, deformated_key, NULL, - returned, 10, fullname); - if (returned[0] == 0) - { - TRACE("Adding value %s to section %s in %s\n", - debugstr_w(deformated_key), debugstr_w(deformated_section), - debugstr_w(fullname)); - - WritePrivateProfileStringW(deformated_section, deformated_key, - deformated_value, fullname); - } - } - else if (action == 3) - FIXME("Append to existing section not yet implemented\n"); - - uirow = MSI_CreateRecord(4); - MSI_RecordSetStringW(uirow,1,identifier); - MSI_RecordSetStringW(uirow,2,deformated_section); - MSI_RecordSetStringW(uirow,3,deformated_key); - MSI_RecordSetStringW(uirow,4,deformated_value); - msi_ui_actiondata( package, szWriteIniValues, uirow ); - msiobj_release( &uirow->hdr ); - - msi_free(fullname); - msi_free(deformated_key); - msi_free(deformated_value); - msi_free(deformated_section); - return ERROR_SUCCESS; -} - -static UINT ACTION_WriteIniValues(MSIPACKAGE *package) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','I','n','i','F','i','l','e','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package); - msiobj_release(&view->hdr); - return rc; -} - -static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param ) -{ - MSIPACKAGE *package = param; - LPCWSTR component, section, key, value, identifier; - LPWSTR deformated_section, deformated_key, deformated_value, filename; - MSICOMPONENT *comp; - MSIRECORD *uirow; - INT action; - - component = MSI_RecordGetString( row, 8 ); - comp = msi_get_loaded_component( package, component ); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_ABSENT) - { - TRACE("component not scheduled for removal %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - - identifier = MSI_RecordGetString( row, 1 ); - section = MSI_RecordGetString( row, 4 ); - key = MSI_RecordGetString( row, 5 ); - value = MSI_RecordGetString( row, 6 ); - action = MSI_RecordGetInteger( row, 7 ); - - deformat_string( package, section, &deformated_section ); - deformat_string( package, key, &deformated_key ); - deformat_string( package, value, &deformated_value ); - - if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine) - { - filename = get_ini_file_name( package, row ); - - TRACE("Removing key %s from section %s in %s\n", - debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename)); - - if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename )) - { - WARN("Unable to remove key %u\n", GetLastError()); - } - msi_free( filename ); - } - else - FIXME("Unsupported action %d\n", action); - - - uirow = MSI_CreateRecord( 4 ); - MSI_RecordSetStringW( uirow, 1, identifier ); - MSI_RecordSetStringW( uirow, 2, deformated_section ); - MSI_RecordSetStringW( uirow, 3, deformated_key ); - MSI_RecordSetStringW( uirow, 4, deformated_value ); - msi_ui_actiondata( package, szRemoveIniValues, uirow ); - msiobj_release( &uirow->hdr ); - - msi_free( deformated_key ); - msi_free( deformated_value ); - msi_free( deformated_section ); - return ERROR_SUCCESS; -} - -static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param ) -{ - MSIPACKAGE *package = param; - LPCWSTR component, section, key, value, identifier; - LPWSTR deformated_section, deformated_key, deformated_value, filename; - MSICOMPONENT *comp; - MSIRECORD *uirow; - INT action; - - component = MSI_RecordGetString( row, 8 ); - comp = msi_get_loaded_component( package, component ); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_LOCAL) - { - TRACE("component not scheduled for installation %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - - identifier = MSI_RecordGetString( row, 1 ); - section = MSI_RecordGetString( row, 4 ); - key = MSI_RecordGetString( row, 5 ); - value = MSI_RecordGetString( row, 6 ); - action = MSI_RecordGetInteger( row, 7 ); - - deformat_string( package, section, &deformated_section ); - deformat_string( package, key, &deformated_key ); - deformat_string( package, value, &deformated_value ); - - if (action == msidbIniFileActionRemoveLine) - { - filename = get_ini_file_name( package, row ); - - TRACE("Removing key %s from section %s in %s\n", - debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename)); - - if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename )) - { - WARN("Unable to remove key %u\n", GetLastError()); - } - msi_free( filename ); - } - else - FIXME("Unsupported action %d\n", action); - - uirow = MSI_CreateRecord( 4 ); - MSI_RecordSetStringW( uirow, 1, identifier ); - MSI_RecordSetStringW( uirow, 2, deformated_section ); - MSI_RecordSetStringW( uirow, 3, deformated_key ); - MSI_RecordSetStringW( uirow, 4, deformated_value ); - msi_ui_actiondata( package, szRemoveIniValues, uirow ); - msiobj_release( &uirow->hdr ); - - msi_free( deformated_key ); - msi_free( deformated_value ); - msi_free( deformated_section ); - return ERROR_SUCCESS; -} - -static UINT ACTION_RemoveIniValues( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','I','n','i','F','i','l','e','`',0}; - static const WCHAR remove_query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (rc == ERROR_SUCCESS) - { - rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package ); - msiobj_release( &view->hdr ); - if (rc != ERROR_SUCCESS) - return rc; - } - rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view ); - if (rc == ERROR_SUCCESS) - { - rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package ); - msiobj_release( &view->hdr ); - if (rc != ERROR_SUCCESS) - return rc; - } - return ERROR_SUCCESS; -} - -static void register_dll( const WCHAR *dll, BOOL unregister ) -{ - HMODULE hmod; - - hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH ); - if (hmod) - { - HRESULT (WINAPI *func_ptr)( void ); - const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer"; - - func_ptr = (void *)GetProcAddress( hmod, func ); - if (func_ptr) - { - HRESULT hr = func_ptr(); - if (FAILED( hr )) - WARN("failed to register dll 0x%08x\n", hr); - } - else - WARN("entry point %s not found\n", func); - FreeLibrary( hmod ); - return; - } - WARN("failed to load library %u\n", GetLastError()); -} - -static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param) -{ - MSIPACKAGE *package = param; - LPCWSTR filename; - MSIFILE *file; - MSIRECORD *uirow; - - filename = MSI_RecordGetString( row, 1 ); - file = msi_get_loaded_file( package, filename ); - if (!file) - { - WARN("unable to find file %s\n", debugstr_w(filename)); - return ERROR_SUCCESS; - } - file->Component->Action = msi_get_component_action( package, file->Component ); - if (file->Component->Action != INSTALLSTATE_LOCAL) - { - TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component)); - return ERROR_SUCCESS; - } - - TRACE("Registering %s\n", debugstr_w( file->TargetPath )); - register_dll( file->TargetPath, FALSE ); - - uirow = MSI_CreateRecord( 2 ); - MSI_RecordSetStringW( uirow, 1, file->File ); - MSI_RecordSetStringW( uirow, 2, file->Component->Directory ); - msi_ui_actiondata( package, szSelfRegModules, uirow ); - msiobj_release( &uirow->hdr ); - - return ERROR_SUCCESS; -} - -static UINT ACTION_SelfRegModules(MSIPACKAGE *package) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','S','e','l','f','R','e','g','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package); - msiobj_release(&view->hdr); - return rc; -} - -static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param ) -{ - MSIPACKAGE *package = param; - LPCWSTR filename; - MSIFILE *file; - MSIRECORD *uirow; - - filename = MSI_RecordGetString( row, 1 ); - file = msi_get_loaded_file( package, filename ); - if (!file) - { - WARN("unable to find file %s\n", debugstr_w(filename)); - return ERROR_SUCCESS; - } - file->Component->Action = msi_get_component_action( package, file->Component ); - if (file->Component->Action != INSTALLSTATE_ABSENT) - { - TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component)); - return ERROR_SUCCESS; - } - - TRACE("Unregistering %s\n", debugstr_w( file->TargetPath )); - register_dll( file->TargetPath, TRUE ); - - uirow = MSI_CreateRecord( 2 ); - MSI_RecordSetStringW( uirow, 1, file->File ); - MSI_RecordSetStringW( uirow, 2, file->Component->Directory ); - msi_ui_actiondata( package, szSelfUnregModules, uirow ); - msiobj_release( &uirow->hdr ); - - return ERROR_SUCCESS; -} - -static UINT ACTION_SelfUnregModules( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','S','e','l','f','R','e','g','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package ); - msiobj_release( &view->hdr ); - return rc; -} - -static UINT ACTION_PublishFeatures(MSIPACKAGE *package) -{ - MSIFEATURE *feature; - UINT rc; - HKEY hkey = NULL, userdata = NULL; - - if (!msi_check_publish(package)) - return ERROR_SUCCESS; - - rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context, - &hkey, TRUE); - if (rc != ERROR_SUCCESS) - goto end; - - rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context, - &userdata, TRUE); - if (rc != ERROR_SUCCESS) - goto end; - - /* here the guids are base 85 encoded */ - LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) - { - ComponentList *cl; - LPWSTR data = NULL; - GUID clsid; - INT size; - BOOL absent = FALSE; - MSIRECORD *uirow; - - if (feature->Action != INSTALLSTATE_LOCAL && - feature->Action != INSTALLSTATE_SOURCE && - feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE; - - size = 1; - LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) - { - size += 21; - } - if (feature->Feature_Parent) - size += strlenW( feature->Feature_Parent )+2; - - data = msi_alloc(size * sizeof(WCHAR)); - - data[0] = 0; - LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry ) - { - MSICOMPONENT* component = cl->component; - WCHAR buf[21]; - - buf[0] = 0; - if (component->ComponentId) - { - TRACE("From %s\n",debugstr_w(component->ComponentId)); - CLSIDFromString(component->ComponentId, &clsid); - encode_base85_guid(&clsid,buf); - TRACE("to %s\n",debugstr_w(buf)); - strcatW(data,buf); - } - } - - if (feature->Feature_Parent) - { - static const WCHAR sep[] = {'\2',0}; - strcatW(data,sep); - strcatW(data,feature->Feature_Parent); - } - - msi_reg_set_val_str( userdata, feature->Feature, data ); - msi_free(data); - - size = 0; - if (feature->Feature_Parent) - size = strlenW(feature->Feature_Parent)*sizeof(WCHAR); - if (!absent) - { - size += sizeof(WCHAR); - RegSetValueExW(hkey,feature->Feature,0,REG_SZ, - (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size); - } - else - { - size += 2*sizeof(WCHAR); - data = msi_alloc(size); - data[0] = 0x6; - data[1] = 0; - if (feature->Feature_Parent) - strcpyW( &data[1], feature->Feature_Parent ); - RegSetValueExW(hkey,feature->Feature,0,REG_SZ, - (LPBYTE)data,size); - msi_free(data); - } - - /* the UI chunk */ - uirow = MSI_CreateRecord( 1 ); - MSI_RecordSetStringW( uirow, 1, feature->Feature ); - msi_ui_actiondata( package, szPublishFeatures, uirow ); - msiobj_release( &uirow->hdr ); - /* FIXME: call msi_ui_progress? */ - } - -end: - RegCloseKey(hkey); - RegCloseKey(userdata); - return rc; -} - -static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature) -{ - UINT r; - HKEY hkey; - MSIRECORD *uirow; - - TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature)); - - r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context, - &hkey, FALSE); - if (r == ERROR_SUCCESS) - { - RegDeleteValueW(hkey, feature->Feature); - RegCloseKey(hkey); - } - - r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context, - &hkey, FALSE); - if (r == ERROR_SUCCESS) - { - RegDeleteValueW(hkey, feature->Feature); - RegCloseKey(hkey); - } - - uirow = MSI_CreateRecord( 1 ); - MSI_RecordSetStringW( uirow, 1, feature->Feature ); - msi_ui_actiondata( package, szUnpublishFeatures, uirow ); - msiobj_release( &uirow->hdr ); - - return ERROR_SUCCESS; -} - -static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package) -{ - MSIFEATURE *feature; - - if (!msi_check_unpublish(package)) - return ERROR_SUCCESS; - - LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry) - { - msi_unpublish_feature(package, feature); - } - - return ERROR_SUCCESS; -} - -static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey) -{ - SYSTEMTIME systime; - DWORD size, langid; - WCHAR date[9], *val, *buffer; - const WCHAR *prop, *key; - - static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0}; - static const WCHAR modpath_fmt[] = - {'M','s','i','E','x','e','c','.','e','x','e',' ', - '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0}; - static const WCHAR szModifyPath[] = - {'M','o','d','i','f','y','P','a','t','h',0}; - static const WCHAR szUninstallString[] = - {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0}; - static const WCHAR szEstimatedSize[] = - {'E','s','t','i','m','a','t','e','d','S','i','z','e',0}; - static const WCHAR szDisplayVersion[] = - {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0}; - static const WCHAR szInstallSource[] = - {'I','n','s','t','a','l','l','S','o','u','r','c','e',0}; - static const WCHAR szARPAUTHORIZEDCDFPREFIX[] = - {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0}; - static const WCHAR szAuthorizedCDFPrefix[] = - {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0}; - static const WCHAR szARPCONTACT[] = - {'A','R','P','C','O','N','T','A','C','T',0}; - static const WCHAR szContact[] = - {'C','o','n','t','a','c','t',0}; - static const WCHAR szARPCOMMENTS[] = - {'A','R','P','C','O','M','M','E','N','T','S',0}; - static const WCHAR szComments[] = - {'C','o','m','m','e','n','t','s',0}; - static const WCHAR szProductName[] = - {'P','r','o','d','u','c','t','N','a','m','e',0}; - static const WCHAR szDisplayName[] = - {'D','i','s','p','l','a','y','N','a','m','e',0}; - static const WCHAR szARPHELPLINK[] = - {'A','R','P','H','E','L','P','L','I','N','K',0}; - static const WCHAR szHelpLink[] = - {'H','e','l','p','L','i','n','k',0}; - static const WCHAR szARPHELPTELEPHONE[] = - {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0}; - static const WCHAR szHelpTelephone[] = - {'H','e','l','p','T','e','l','e','p','h','o','n','e',0}; - static const WCHAR szARPINSTALLLOCATION[] = - {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0}; - static const WCHAR szManufacturer[] = - {'M','a','n','u','f','a','c','t','u','r','e','r',0}; - static const WCHAR szPublisher[] = - {'P','u','b','l','i','s','h','e','r',0}; - static const WCHAR szARPREADME[] = - {'A','R','P','R','E','A','D','M','E',0}; - static const WCHAR szReadme[] = - {'R','e','a','d','M','e',0}; - static const WCHAR szARPSIZE[] = - {'A','R','P','S','I','Z','E',0}; - static const WCHAR szSize[] = - {'S','i','z','e',0}; - static const WCHAR szARPURLINFOABOUT[] = - {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0}; - static const WCHAR szURLInfoAbout[] = - {'U','R','L','I','n','f','o','A','b','o','u','t',0}; - static const WCHAR szARPURLUPDATEINFO[] = - {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0}; - static const WCHAR szURLUpdateInfo[] = - {'U','R','L','U','p','d','a','t','e','I','n','f','o',0}; - static const WCHAR szARPSYSTEMCOMPONENT[] = - {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0}; - static const WCHAR szSystemComponent[] = - {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0}; - - static const WCHAR *propval[] = { - szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix, - szARPCONTACT, szContact, - szARPCOMMENTS, szComments, - szProductName, szDisplayName, - szARPHELPLINK, szHelpLink, - szARPHELPTELEPHONE, szHelpTelephone, - szARPINSTALLLOCATION, szInstallLocation, - szSourceDir, szInstallSource, - szManufacturer, szPublisher, - szARPREADME, szReadme, - szARPSIZE, szSize, - szARPURLINFOABOUT, szURLInfoAbout, - szARPURLUPDATEINFO, szURLUpdateInfo, - NULL - }; - const WCHAR **p = propval; - - while (*p) - { - prop = *p++; - key = *p++; - val = msi_dup_property(package->db, prop); - msi_reg_set_val_str(hkey, key, val); - msi_free(val); - } - - msi_reg_set_val_dword(hkey, szWindowsInstaller, 1); - if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 )) - { - msi_reg_set_val_dword( hkey, szSystemComponent, 1 ); - } - size = deformat_string(package, modpath_fmt, &buffer); - RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size); - RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size); - msi_free(buffer); - - /* FIXME: Write real Estimated Size when we have it */ - msi_reg_set_val_dword(hkey, szEstimatedSize, 0); - - GetLocalTime(&systime); - sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay); - msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date); - - langid = msi_get_property_int(package->db, szProductLanguage, 0); - msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid); - - buffer = msi_dup_property(package->db, szProductVersion); - msi_reg_set_val_str(hkey, szDisplayVersion, buffer); - if (buffer) - { - DWORD verdword = msi_version_str_to_dword(buffer); - - msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword); - msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24); - msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF); - msi_free(buffer); - } - - return ERROR_SUCCESS; -} - -static UINT ACTION_RegisterProduct(MSIPACKAGE *package) -{ - WCHAR squashed_pc[SQUISH_GUID_SIZE]; - MSIRECORD *uirow; - LPWSTR upgrade_code; - HKEY hkey, props, upgrade_key; - UINT rc; - - /* FIXME: also need to publish if the product is in advertise mode */ - if (!msi_check_publish(package)) - return ERROR_SUCCESS; - - rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE); - if (rc != ERROR_SUCCESS) - return rc; - - rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE); - if (rc != ERROR_SUCCESS) - goto done; - - rc = msi_publish_install_properties(package, hkey); - if (rc != ERROR_SUCCESS) - goto done; - - rc = msi_publish_install_properties(package, props); - if (rc != ERROR_SUCCESS) - goto done; - - upgrade_code = msi_dup_property(package->db, szUpgradeCode); - if (upgrade_code) - { - rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE ); - if (rc == ERROR_SUCCESS) - { - squash_guid( package->ProductCode, squashed_pc ); - msi_reg_set_val_str( upgrade_key, squashed_pc, NULL ); - RegCloseKey( upgrade_key ); - } - msi_free( upgrade_code ); - } - msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile ); - package->delete_on_close = FALSE; - -done: - uirow = MSI_CreateRecord( 1 ); - MSI_RecordSetStringW( uirow, 1, package->ProductCode ); - msi_ui_actiondata( package, szRegisterProduct, uirow ); - msiobj_release( &uirow->hdr ); - - RegCloseKey(hkey); - return ERROR_SUCCESS; -} - -static UINT ACTION_InstallExecute(MSIPACKAGE *package) -{ - return execute_script(package, SCRIPT_INSTALL); -} - -static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param ) -{ - MSIPACKAGE *package = param; - const WCHAR *icon = MSI_RecordGetString( row, 1 ); - WCHAR *p, *icon_path; - - if (!icon) return ERROR_SUCCESS; - if ((icon_path = msi_build_icon_path( package, icon ))) - { - TRACE("removing icon file %s\n", debugstr_w(icon_path)); - DeleteFileW( icon_path ); - if ((p = strrchrW( icon_path, '\\' ))) - { - *p = 0; - RemoveDirectoryW( icon_path ); - } - msi_free( icon_path ); - } - return ERROR_SUCCESS; -} - -static UINT msi_unpublish_icons( MSIPACKAGE *package ) -{ - static const WCHAR query[]= { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','I','c','o','n','`',0}; - MSIQUERY *view; - UINT r; - - r = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (r == ERROR_SUCCESS) - { - r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package ); - msiobj_release( &view->hdr ); - if (r != ERROR_SUCCESS) - return r; - } - return ERROR_SUCCESS; -} - -static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove ) -{ - static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0}; - WCHAR *upgrade, **features; - BOOL full_uninstall = TRUE; - MSIFEATURE *feature; - MSIPATCHINFO *patch; - UINT i; - - LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) - { - if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE; - } - features = msi_split_string( remove, ',' ); - for (i = 0; features && features[i]; i++) - { - if (!strcmpW( features[i], szAll )) full_uninstall = TRUE; - } - msi_free(features); - - if (!full_uninstall) - return ERROR_SUCCESS; - - MSIREG_DeleteProductKey(package->ProductCode); - MSIREG_DeleteUserDataProductKey(package->ProductCode); - MSIREG_DeleteUninstallKey(package->ProductCode, package->platform); - - MSIREG_DeleteLocalClassesProductKey(package->ProductCode); - MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode); - MSIREG_DeleteUserProductKey(package->ProductCode); - MSIREG_DeleteUserFeaturesKey(package->ProductCode); - - upgrade = msi_dup_property(package->db, szUpgradeCode); - if (upgrade) - { - MSIREG_DeleteUserUpgradeCodesKey(upgrade); - MSIREG_DeleteClassesUpgradeCodesKey(upgrade); - msi_free(upgrade); - } - - LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry) - { - MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context); - if (!strcmpW( package->ProductCode, patch->products )) - { - TRACE("removing local patch package %s\n", debugstr_w(patch->localfile)); - patch->delete_on_close = TRUE; - } - /* FIXME: remove local patch package if this is the last product */ - } - TRACE("removing local package %s\n", debugstr_w(package->localfile)); - package->delete_on_close = TRUE; - - msi_unpublish_icons( package ); - return ERROR_SUCCESS; -} - -static UINT ACTION_InstallFinalize(MSIPACKAGE *package) -{ - UINT rc; - WCHAR *remove; - - /* turn off scheduling */ - package->script->CurrentlyScripting= FALSE; - - /* first do the same as an InstallExecute */ - rc = ACTION_InstallExecute(package); - if (rc != ERROR_SUCCESS) - return rc; - - /* then handle commit actions */ - rc = execute_script(package, SCRIPT_COMMIT); - if (rc != ERROR_SUCCESS) - return rc; - - remove = msi_dup_property(package->db, szRemove); - rc = msi_unpublish_product(package, remove); - msi_free(remove); - return rc; -} - -UINT ACTION_ForceReboot(MSIPACKAGE *package) -{ - static const WCHAR RunOnce[] = { - 'S','o','f','t','w','a','r','e','\\', - 'M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s','\\', - 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'R','u','n','O','n','c','e',0}; - static const WCHAR InstallRunOnce[] = { - 'S','o','f','t','w','a','r','e','\\', - 'M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s','\\', - 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'I','n','s','t','a','l','l','e','r','\\', - 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0}; - - static const WCHAR msiexec_fmt[] = { - '%','s', - '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ', - '\"','%','s','\"',0}; - static const WCHAR install_fmt[] = { - '/','I',' ','\"','%','s','\"',' ', - 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ', - 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0}; - WCHAR buffer[256], sysdir[MAX_PATH]; - HKEY hkey; - WCHAR squished_pc[100]; - - squash_guid(package->ProductCode,squished_pc); - - GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0])); - RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey); - snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir, - squished_pc); - - msi_reg_set_val_str( hkey, squished_pc, buffer ); - RegCloseKey(hkey); - - TRACE("Reboot command %s\n",debugstr_w(buffer)); - - RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey); - sprintfW(buffer,install_fmt,package->ProductCode,squished_pc); - - msi_reg_set_val_str( hkey, squished_pc, buffer ); - RegCloseKey(hkey); - - return ERROR_INSTALL_SUSPEND; -} - -WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... ) -{ - static const WCHAR query[] = - {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ', - 'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ', - '`','E','r','r','o','r','`',' ','=',' ','%','i',0}; - MSIRECORD *rec, *row; - DWORD i, size = 0; - va_list va; - const WCHAR *str; - WCHAR *data; - - if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0; - - rec = MSI_CreateRecord( count + 2 ); - str = MSI_RecordGetString( row, 1 ); - MSI_RecordSetStringW( rec, 0, str ); - msiobj_release( &row->hdr ); - MSI_RecordSetInteger( rec, 1, error ); - - va_start( va, count ); - for (i = 0; i < count; i++) - { - str = va_arg( va, const WCHAR *); - MSI_RecordSetStringW( rec, i + 2, str ); - } - va_end( va ); - - MSI_FormatRecordW( package, rec, NULL, &size ); - size++; - data = msi_alloc( size * sizeof(WCHAR) ); - if (size > 1) MSI_FormatRecordW( package, rec, data, &size ); - else data[0] = 0; - msiobj_release( &rec->hdr ); - return data; -} - -static UINT ACTION_ResolveSource(MSIPACKAGE* package) -{ - DWORD attrib; - UINT rc; - - /* - * We are currently doing what should be done here in the top level Install - * however for Administrative and uninstalls this step will be needed - */ - if (!package->PackagePath) - return ERROR_SUCCESS; - - msi_set_sourcedir_props(package, TRUE); - - attrib = GetFileAttributesW(package->db->path); - if (attrib == INVALID_FILE_ATTRIBUTES) - { - LPWSTR prompt, msg; - DWORD size = 0; - - rc = MsiSourceListGetInfoW(package->ProductCode, NULL, - package->Context, MSICODE_PRODUCT, - INSTALLPROPERTY_DISKPROMPTW,NULL,&size); - if (rc == ERROR_MORE_DATA) - { - prompt = msi_alloc(size * sizeof(WCHAR)); - MsiSourceListGetInfoW(package->ProductCode, NULL, - package->Context, MSICODE_PRODUCT, - INSTALLPROPERTY_DISKPROMPTW,prompt,&size); - } - else - prompt = strdupW(package->db->path); - - msg = msi_build_error_string(package, 1302, 1, prompt); - msi_free(prompt); - while(attrib == INVALID_FILE_ATTRIBUTES) - { - rc = MessageBoxW(NULL, msg, NULL, MB_OKCANCEL); - if (rc == IDCANCEL) - { - msi_free(msg); - return ERROR_INSTALL_USEREXIT; - } - attrib = GetFileAttributesW(package->db->path); - } - msi_free(msg); - rc = ERROR_SUCCESS; - } - else - return ERROR_SUCCESS; - - return rc; -} - -static UINT ACTION_RegisterUser(MSIPACKAGE *package) -{ - HKEY hkey = 0; - LPWSTR buffer, productid = NULL; - UINT i, rc = ERROR_SUCCESS; - MSIRECORD *uirow; - - static const WCHAR szPropKeys[][80] = - { - {'P','r','o','d','u','c','t','I','D',0}, - {'U','S','E','R','N','A','M','E',0}, - {'C','O','M','P','A','N','Y','N','A','M','E',0}, - {0}, - }; - - static const WCHAR szRegKeys[][80] = - { - {'P','r','o','d','u','c','t','I','D',0}, - {'R','e','g','O','w','n','e','r',0}, - {'R','e','g','C','o','m','p','a','n','y',0}, - {0}, - }; - - if (msi_check_unpublish(package)) - { - MSIREG_DeleteUserDataProductKey(package->ProductCode); - goto end; - } - - productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW ); - if (!productid) - goto end; - - rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, - NULL, &hkey, TRUE); - if (rc != ERROR_SUCCESS) - goto end; - - for( i = 0; szPropKeys[i][0]; i++ ) - { - buffer = msi_dup_property( package->db, szPropKeys[i] ); - msi_reg_set_val_str( hkey, szRegKeys[i], buffer ); - msi_free( buffer ); - } - -end: - uirow = MSI_CreateRecord( 1 ); - MSI_RecordSetStringW( uirow, 1, productid ); - msi_ui_actiondata( package, szRegisterUser, uirow ); - msiobj_release( &uirow->hdr ); - - msi_free(productid); - RegCloseKey(hkey); - return rc; -} - - -static UINT ACTION_ExecuteAction(MSIPACKAGE *package) -{ - UINT rc; - - package->script->InWhatSequence |= SEQUENCE_EXEC; - rc = ACTION_ProcessExecSequence(package,FALSE); - return rc; -} - -WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature ) -{ - static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0}; - WCHAR productid_85[21], component_85[21], *ret; - GUID clsid; - DWORD sz; - - /* > is used if there is a component GUID and < if not. */ - - productid_85[0] = 0; - component_85[0] = 0; - CLSIDFromString( package->ProductCode, &clsid ); - - encode_base85_guid( &clsid, productid_85 ); - if (component) - { - CLSIDFromString( component->ComponentId, &clsid ); - encode_base85_guid( &clsid, component_85 ); - } - - TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature), - debugstr_w(component_85)); - - sz = 20 + strlenW( feature ) + 20 + 3; - ret = msi_alloc_zero( sz * sizeof(WCHAR) ); - if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 ); - return ret; -} - -static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param) -{ - MSIPACKAGE *package = param; - LPCWSTR compgroupid, component, feature, qualifier, text; - LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q; - HKEY hkey = NULL; - UINT rc; - MSICOMPONENT *comp; - MSIFEATURE *feat; - DWORD sz; - MSIRECORD *uirow; - int len; - - feature = MSI_RecordGetString(rec, 5); - feat = msi_get_loaded_feature(package, feature); - if (!feat) - return ERROR_SUCCESS; - - feat->Action = msi_get_feature_action( package, feat ); - if (feat->Action != INSTALLSTATE_LOCAL && - feat->Action != INSTALLSTATE_SOURCE && - feat->Action != INSTALLSTATE_ADVERTISED) - { - TRACE("feature not scheduled for installation %s\n", debugstr_w(feature)); - return ERROR_SUCCESS; - } - - component = MSI_RecordGetString(rec, 3); - comp = msi_get_loaded_component(package, component); - if (!comp) - return ERROR_SUCCESS; - - compgroupid = MSI_RecordGetString(rec,1); - qualifier = MSI_RecordGetString(rec,2); - - rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE); - if (rc != ERROR_SUCCESS) - goto end; - - advertise = msi_create_component_advertise_string( package, comp, feature ); - text = MSI_RecordGetString( rec, 4 ); - if (text) - { - p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) ); - strcpyW( p, advertise ); - strcatW( p, text ); - msi_free( advertise ); - advertise = p; - } - existing = msi_reg_get_val_str( hkey, qualifier ); - - sz = strlenW( advertise ) + 1; - if (existing) - { - for (p = existing; *p; p += len) - { - len = strlenW( p ) + 1; - if (strcmpW( advertise, p )) sz += len; - } - } - if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) ))) - { - rc = ERROR_OUTOFMEMORY; - goto end; - } - q = output; - if (existing) - { - for (p = existing; *p; p += len) - { - len = strlenW( p ) + 1; - if (strcmpW( advertise, p )) - { - memcpy( q, p, len * sizeof(WCHAR) ); - q += len; - } - } - } - strcpyW( q, advertise ); - q[strlenW( q ) + 1] = 0; - - msi_reg_set_val_multi_str( hkey, qualifier, output ); - -end: - RegCloseKey(hkey); - msi_free( output ); - msi_free( advertise ); - msi_free( existing ); - - /* the UI chunk */ - uirow = MSI_CreateRecord( 2 ); - MSI_RecordSetStringW( uirow, 1, compgroupid ); - MSI_RecordSetStringW( uirow, 2, qualifier); - msi_ui_actiondata( package, szPublishComponents, uirow ); - msiobj_release( &uirow->hdr ); - /* FIXME: call ui_progress? */ - - return rc; -} - -/* - * At present I am ignorning the advertised components part of this and only - * focusing on the qualified component sets - */ -static UINT ACTION_PublishComponents(MSIPACKAGE *package) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package); - msiobj_release(&view->hdr); - return rc; -} - -static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param ) -{ - static const WCHAR szInstallerComponents[] = { - 'S','o','f','t','w','a','r','e','\\', - 'M','i','c','r','o','s','o','f','t','\\', - 'I','n','s','t','a','l','l','e','r','\\', - 'C','o','m','p','o','n','e','n','t','s','\\',0}; - - MSIPACKAGE *package = param; - LPCWSTR compgroupid, component, feature, qualifier; - MSICOMPONENT *comp; - MSIFEATURE *feat; - MSIRECORD *uirow; - WCHAR squashed[GUID_SIZE], keypath[MAX_PATH]; - LONG res; - - feature = MSI_RecordGetString( rec, 5 ); - feat = msi_get_loaded_feature( package, feature ); - if (!feat) - return ERROR_SUCCESS; - - feat->Action = msi_get_feature_action( package, feat ); - if (feat->Action != INSTALLSTATE_ABSENT) - { - TRACE("feature not scheduled for removal %s\n", debugstr_w(feature)); - return ERROR_SUCCESS; - } - - component = MSI_RecordGetString( rec, 3 ); - comp = msi_get_loaded_component( package, component ); - if (!comp) - return ERROR_SUCCESS; - - compgroupid = MSI_RecordGetString( rec, 1 ); - qualifier = MSI_RecordGetString( rec, 2 ); - - squash_guid( compgroupid, squashed ); - strcpyW( keypath, szInstallerComponents ); - strcatW( keypath, squashed ); - - res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath ); - if (res != ERROR_SUCCESS) - { - WARN("Unable to delete component key %d\n", res); - } - - uirow = MSI_CreateRecord( 2 ); - MSI_RecordSetStringW( uirow, 1, compgroupid ); - MSI_RecordSetStringW( uirow, 2, qualifier ); - msi_ui_actiondata( package, szUnpublishComponents, uirow ); - msiobj_release( &uirow->hdr ); - - return ERROR_SUCCESS; -} - -static UINT ACTION_UnpublishComponents( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package ); - msiobj_release( &view->hdr ); - return rc; -} - -static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param) -{ - static const WCHAR query[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ', - '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0}; - MSIPACKAGE *package = param; - MSICOMPONENT *component; - MSIRECORD *row; - MSIFILE *file; - SC_HANDLE hscm = NULL, service = NULL; - LPCWSTR comp, key; - LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL; - LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL; - DWORD serv_type, start_type, err_control; - SERVICE_DESCRIPTIONW sd = {NULL}; - - comp = MSI_RecordGetString( rec, 12 ); - component = msi_get_loaded_component( package, comp ); - if (!component) - { - WARN("service component not found\n"); - goto done; - } - component->Action = msi_get_component_action( package, component ); - if (component->Action != INSTALLSTATE_LOCAL) - { - TRACE("component not scheduled for installation %s\n", debugstr_w(comp)); - goto done; - } - hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE); - if (!hscm) - { - ERR("Failed to open the SC Manager!\n"); - goto done; - } - - start_type = MSI_RecordGetInteger(rec, 5); - if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START) - goto done; - - deformat_string(package, MSI_RecordGetString(rec, 2), &name); - deformat_string(package, MSI_RecordGetString(rec, 3), &disp); - serv_type = MSI_RecordGetInteger(rec, 4); - err_control = MSI_RecordGetInteger(rec, 6); - deformat_string(package, MSI_RecordGetString(rec, 7), &load_order); - deformat_string(package, MSI_RecordGetString(rec, 8), &depends); - deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name); - deformat_string(package, MSI_RecordGetString(rec, 10), &pass); - deformat_string(package, MSI_RecordGetString(rec, 11), &args); - deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription); - - /* fetch the service path */ - row = MSI_QueryGetRecord(package->db, query, comp); - if (!row) - { - ERR("Query failed\n"); - goto done; - } - key = MSI_RecordGetString(row, 6); - file = msi_get_loaded_file(package, key); - msiobj_release(&row->hdr); - if (!file) - { - ERR("Failed to load the service file\n"); - goto done; - } - - if (!args || !args[0]) image_path = file->TargetPath; - else - { - int len = strlenW(file->TargetPath) + strlenW(args) + 2; - if (!(image_path = msi_alloc(len * sizeof(WCHAR)))) - return ERROR_OUTOFMEMORY; - - strcpyW(image_path, file->TargetPath); - strcatW(image_path, szSpace); - strcatW(image_path, args); - } - service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type, - start_type, err_control, image_path, load_order, - NULL, depends, serv_name, pass); - - if (!service) - { - if (GetLastError() != ERROR_SERVICE_EXISTS) - ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError()); - } - else if (sd.lpDescription) - { - if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd)) - WARN("failed to set service description %u\n", GetLastError()); - } - - if (image_path != file->TargetPath) msi_free(image_path); -done: - CloseServiceHandle(service); - CloseServiceHandle(hscm); - msi_free(name); - msi_free(disp); - msi_free(sd.lpDescription); - msi_free(load_order); - msi_free(serv_name); - msi_free(pass); - msi_free(depends); - msi_free(args); - - return ERROR_SUCCESS; -} - -static UINT ACTION_InstallServices( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package); - msiobj_release(&view->hdr); - return rc; -} - -/* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */ -static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs) -{ - LPCWSTR *vector, *temp_vector; - LPWSTR p, q; - DWORD sep_len; - - static const WCHAR separator[] = {'[','~',']',0}; - - *numargs = 0; - sep_len = sizeof(separator) / sizeof(WCHAR) - 1; - - if (!args) - return NULL; - - vector = msi_alloc(sizeof(LPWSTR)); - if (!vector) - return NULL; - - p = args; - do - { - (*numargs)++; - vector[*numargs - 1] = p; - - if ((q = strstrW(p, separator))) - { - *q = '\0'; - - temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR)); - if (!temp_vector) - { - msi_free(vector); - return NULL; - } - vector = temp_vector; - - p = q + sep_len; - } - } while (q); - - return vector; -} - -static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param) -{ - MSIPACKAGE *package = param; - MSICOMPONENT *comp; - MSIRECORD *uirow; - SC_HANDLE scm = NULL, service = NULL; - LPCWSTR component, *vector = NULL; - LPWSTR name, args, display_name = NULL; - DWORD event, numargs, len, wait, dummy; - UINT r = ERROR_FUNCTION_FAILED; - SERVICE_STATUS_PROCESS status; - ULONGLONG start_time; - - component = MSI_RecordGetString(rec, 6); - comp = msi_get_loaded_component(package, component); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_LOCAL) - { - TRACE("component not scheduled for installation %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - - deformat_string(package, MSI_RecordGetString(rec, 2), &name); - deformat_string(package, MSI_RecordGetString(rec, 4), &args); - event = MSI_RecordGetInteger(rec, 3); - wait = MSI_RecordGetInteger(rec, 5); - - if (!(event & msidbServiceControlEventStart)) - { - r = ERROR_SUCCESS; - goto done; - } - - scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); - if (!scm) - { - ERR("Failed to open the service control manager\n"); - goto done; - } - - len = 0; - if (!GetServiceDisplayNameW( scm, name, NULL, &len ) && - GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - if ((display_name = msi_alloc( ++len * sizeof(WCHAR )))) - GetServiceDisplayNameW( scm, name, display_name, &len ); - } - - service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS); - if (!service) - { - ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError()); - goto done; - } - - vector = msi_service_args_to_vector(args, &numargs); - - if (!StartServiceW(service, numargs, vector) && - GetLastError() != ERROR_SERVICE_ALREADY_RUNNING) - { - ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError()); - goto done; - } - - r = ERROR_SUCCESS; - if (wait) - { - /* wait for at most 30 seconds for the service to be up and running */ - if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, - (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy)) - { - TRACE("failed to query service status (%u)\n", GetLastError()); - goto done; - } - start_time = GetTickCount64(); - while (status.dwCurrentState == SERVICE_START_PENDING) - { - if (GetTickCount64() - start_time > 30000) break; - Sleep(1000); - if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, - (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy)) - { - TRACE("failed to query service status (%u)\n", GetLastError()); - goto done; - } - } - if (status.dwCurrentState != SERVICE_RUNNING) - { - WARN("service failed to start %u\n", status.dwCurrentState); - r = ERROR_FUNCTION_FAILED; - } - } - -done: - uirow = MSI_CreateRecord( 2 ); - MSI_RecordSetStringW( uirow, 1, display_name ); - MSI_RecordSetStringW( uirow, 2, name ); - msi_ui_actiondata( package, szStartServices, uirow ); - msiobj_release( &uirow->hdr ); - - CloseServiceHandle(service); - CloseServiceHandle(scm); - - msi_free(name); - msi_free(args); - msi_free(vector); - msi_free(display_name); - return r; -} - -static UINT ACTION_StartServices( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package); - msiobj_release(&view->hdr); - return rc; -} - -static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service) -{ - DWORD i, needed, count; - ENUM_SERVICE_STATUSW *dependencies; - SERVICE_STATUS ss; - SC_HANDLE depserv; - - if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL, - 0, &needed, &count)) - return TRUE; - - if (GetLastError() != ERROR_MORE_DATA) - return FALSE; - - dependencies = msi_alloc(needed); - if (!dependencies) - return FALSE; - - if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies, - needed, &needed, &count)) - goto error; - - for (i = 0; i < count; i++) - { - depserv = OpenServiceW(scm, dependencies[i].lpServiceName, - SERVICE_STOP | SERVICE_QUERY_STATUS); - if (!depserv) - goto error; - - if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss)) - goto error; - } - - return TRUE; - -error: - msi_free(dependencies); - return FALSE; -} - -static UINT stop_service( LPCWSTR name ) -{ - SC_HANDLE scm = NULL, service = NULL; - SERVICE_STATUS status; - SERVICE_STATUS_PROCESS ssp; - DWORD needed; - - scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); - if (!scm) - { - WARN("Failed to open the SCM: %d\n", GetLastError()); - goto done; - } - - service = OpenServiceW(scm, name, - SERVICE_STOP | - SERVICE_QUERY_STATUS | - SERVICE_ENUMERATE_DEPENDENTS); - if (!service) - { - WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError()); - goto done; - } - - if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, - sizeof(SERVICE_STATUS_PROCESS), &needed)) - { - WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError()); - goto done; - } - - if (ssp.dwCurrentState == SERVICE_STOPPED) - goto done; - - stop_service_dependents(scm, service); - - if (!ControlService(service, SERVICE_CONTROL_STOP, &status)) - WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError()); - -done: - CloseServiceHandle(service); - CloseServiceHandle(scm); - - return ERROR_SUCCESS; -} - -static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param ) -{ - MSIPACKAGE *package = param; - MSICOMPONENT *comp; - MSIRECORD *uirow; - LPCWSTR component; - LPWSTR name = NULL, display_name = NULL; - DWORD event, len; - SC_HANDLE scm; - - event = MSI_RecordGetInteger( rec, 3 ); - if (!(event & msidbServiceControlEventStop)) - return ERROR_SUCCESS; - - component = MSI_RecordGetString( rec, 6 ); - comp = msi_get_loaded_component( package, component ); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_ABSENT) - { - TRACE("component not scheduled for removal %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - - scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT ); - if (!scm) - { - ERR("Failed to open the service control manager\n"); - goto done; - } - - len = 0; - if (!GetServiceDisplayNameW( scm, name, NULL, &len ) && - GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - if ((display_name = msi_alloc( ++len * sizeof(WCHAR )))) - GetServiceDisplayNameW( scm, name, display_name, &len ); - } - CloseServiceHandle( scm ); - - deformat_string( package, MSI_RecordGetString( rec, 2 ), &name ); - stop_service( name ); - -done: - uirow = MSI_CreateRecord( 2 ); - MSI_RecordSetStringW( uirow, 1, display_name ); - MSI_RecordSetStringW( uirow, 2, name ); - msi_ui_actiondata( package, szStopServices, uirow ); - msiobj_release( &uirow->hdr ); - - msi_free( name ); - msi_free( display_name ); - return ERROR_SUCCESS; -} - -static UINT ACTION_StopServices( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package); - msiobj_release(&view->hdr); - return rc; -} - -static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param ) -{ - MSIPACKAGE *package = param; - MSICOMPONENT *comp; - MSIRECORD *uirow; - LPWSTR name = NULL, display_name = NULL; - DWORD event, len; - SC_HANDLE scm = NULL, service = NULL; - - comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) ); - if (!comp) - return ERROR_SUCCESS; - - event = MSI_RecordGetInteger( rec, 3 ); - deformat_string( package, MSI_RecordGetString(rec, 2), &name ); - - comp->Action = msi_get_component_action( package, comp ); - if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) && - !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete))) - { - TRACE("service %s not scheduled for removal\n", debugstr_w(name)); - msi_free( name ); - return ERROR_SUCCESS; - } - stop_service( name ); - - scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS ); - if (!scm) - { - WARN("Failed to open the SCM: %d\n", GetLastError()); - goto done; - } - - len = 0; - if (!GetServiceDisplayNameW( scm, name, NULL, &len ) && - GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - if ((display_name = msi_alloc( ++len * sizeof(WCHAR )))) - GetServiceDisplayNameW( scm, name, display_name, &len ); - } - - service = OpenServiceW( scm, name, DELETE ); - if (!service) - { - WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError()); - goto done; - } - - if (!DeleteService( service )) - WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError()); - -done: - uirow = MSI_CreateRecord( 2 ); - MSI_RecordSetStringW( uirow, 1, display_name ); - MSI_RecordSetStringW( uirow, 2, name ); - msi_ui_actiondata( package, szDeleteServices, uirow ); - msiobj_release( &uirow->hdr ); - - CloseServiceHandle( service ); - CloseServiceHandle( scm ); - msi_free( name ); - msi_free( display_name ); - - return ERROR_SUCCESS; -} - -static UINT ACTION_DeleteServices( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package ); - msiobj_release( &view->hdr ); - return rc; -} - -static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param ) -{ - MSIPACKAGE *package = param; - LPWSTR driver, driver_path, ptr; - WCHAR outpath[MAX_PATH]; - MSIFILE *driver_file = NULL, *setup_file = NULL; - MSICOMPONENT *comp; - MSIRECORD *uirow; - LPCWSTR desc, file_key, component; - DWORD len, usage; - UINT r = ERROR_SUCCESS; - - static const WCHAR driver_fmt[] = { - 'D','r','i','v','e','r','=','%','s',0}; - static const WCHAR setup_fmt[] = { - 'S','e','t','u','p','=','%','s',0}; - static const WCHAR usage_fmt[] = { - 'F','i','l','e','U','s','a','g','e','=','1',0}; - - component = MSI_RecordGetString( rec, 2 ); - comp = msi_get_loaded_component( package, component ); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_LOCAL) - { - TRACE("component not scheduled for installation %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - desc = MSI_RecordGetString(rec, 3); - - file_key = MSI_RecordGetString( rec, 4 ); - if (file_key) driver_file = msi_get_loaded_file( package, file_key ); - - file_key = MSI_RecordGetString( rec, 5 ); - if (file_key) setup_file = msi_get_loaded_file( package, file_key ); - - if (!driver_file) - { - ERR("ODBC Driver entry not found!\n"); - return ERROR_FUNCTION_FAILED; - } - - len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName); - if (setup_file) - len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName); - len += lstrlenW(usage_fmt) + 2; /* \0\0 */ - - driver = msi_alloc(len * sizeof(WCHAR)); - if (!driver) - return ERROR_OUTOFMEMORY; - - ptr = driver; - lstrcpyW(ptr, desc); - ptr += lstrlenW(ptr) + 1; - - len = sprintfW(ptr, driver_fmt, driver_file->FileName); - ptr += len + 1; - - if (setup_file) - { - len = sprintfW(ptr, setup_fmt, setup_file->FileName); - ptr += len + 1; - } - - lstrcpyW(ptr, usage_fmt); - ptr += lstrlenW(ptr) + 1; - *ptr = '\0'; - - if (!driver_file->TargetPath) - { - const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory ); - driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName ); - } - driver_path = strdupW(driver_file->TargetPath); - ptr = strrchrW(driver_path, '\\'); - if (ptr) *ptr = '\0'; - - if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH, - NULL, ODBC_INSTALL_COMPLETE, &usage)) - { - ERR("Failed to install SQL driver!\n"); - r = ERROR_FUNCTION_FAILED; - } - - uirow = MSI_CreateRecord( 5 ); - MSI_RecordSetStringW( uirow, 1, desc ); - MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) ); - MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory ); - msi_ui_actiondata( package, szInstallODBC, uirow ); - msiobj_release( &uirow->hdr ); - - msi_free(driver); - msi_free(driver_path); - - return r; -} - -static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param ) -{ - MSIPACKAGE *package = param; - LPWSTR translator, translator_path, ptr; - WCHAR outpath[MAX_PATH]; - MSIFILE *translator_file = NULL, *setup_file = NULL; - MSICOMPONENT *comp; - MSIRECORD *uirow; - LPCWSTR desc, file_key, component; - DWORD len, usage; - UINT r = ERROR_SUCCESS; - - static const WCHAR translator_fmt[] = { - 'T','r','a','n','s','l','a','t','o','r','=','%','s',0}; - static const WCHAR setup_fmt[] = { - 'S','e','t','u','p','=','%','s',0}; - - component = MSI_RecordGetString( rec, 2 ); - comp = msi_get_loaded_component( package, component ); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_LOCAL) - { - TRACE("component not scheduled for installation %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - desc = MSI_RecordGetString(rec, 3); - - file_key = MSI_RecordGetString( rec, 4 ); - if (file_key) translator_file = msi_get_loaded_file( package, file_key ); - - file_key = MSI_RecordGetString( rec, 5 ); - if (file_key) setup_file = msi_get_loaded_file( package, file_key ); - - if (!translator_file) - { - ERR("ODBC Translator entry not found!\n"); - return ERROR_FUNCTION_FAILED; - } - - len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */ - if (setup_file) - len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName); - - translator = msi_alloc(len * sizeof(WCHAR)); - if (!translator) - return ERROR_OUTOFMEMORY; - - ptr = translator; - lstrcpyW(ptr, desc); - ptr += lstrlenW(ptr) + 1; - - len = sprintfW(ptr, translator_fmt, translator_file->FileName); - ptr += len + 1; - - if (setup_file) - { - len = sprintfW(ptr, setup_fmt, setup_file->FileName); - ptr += len + 1; - } - *ptr = '\0'; - - translator_path = strdupW(translator_file->TargetPath); - ptr = strrchrW(translator_path, '\\'); - if (ptr) *ptr = '\0'; - - if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH, - NULL, ODBC_INSTALL_COMPLETE, &usage)) - { - ERR("Failed to install SQL translator!\n"); - r = ERROR_FUNCTION_FAILED; - } - - uirow = MSI_CreateRecord( 5 ); - MSI_RecordSetStringW( uirow, 1, desc ); - MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) ); - MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory ); - msi_ui_actiondata( package, szInstallODBC, uirow ); - msiobj_release( &uirow->hdr ); - - msi_free(translator); - msi_free(translator_path); - - return r; -} - -static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param ) -{ - MSIPACKAGE *package = param; - MSICOMPONENT *comp; - LPWSTR attrs; - LPCWSTR desc, driver, component; - WORD request = ODBC_ADD_SYS_DSN; - INT registration; - DWORD len; - UINT r = ERROR_SUCCESS; - MSIRECORD *uirow; - - static const WCHAR attrs_fmt[] = { - 'D','S','N','=','%','s',0 }; - - component = MSI_RecordGetString( rec, 2 ); - comp = msi_get_loaded_component( package, component ); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_LOCAL) - { - TRACE("component not scheduled for installation %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - - desc = MSI_RecordGetString(rec, 3); - driver = MSI_RecordGetString(rec, 4); - registration = MSI_RecordGetInteger(rec, 5); - - if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN; - else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN; - - len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */ - attrs = msi_alloc(len * sizeof(WCHAR)); - if (!attrs) - return ERROR_OUTOFMEMORY; - - len = sprintfW(attrs, attrs_fmt, desc); - attrs[len + 1] = 0; - - if (!SQLConfigDataSourceW(NULL, request, driver, attrs)) - { - ERR("Failed to install SQL data source!\n"); - r = ERROR_FUNCTION_FAILED; - } - - uirow = MSI_CreateRecord( 5 ); - MSI_RecordSetStringW( uirow, 1, desc ); - MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) ); - MSI_RecordSetInteger( uirow, 3, request ); - msi_ui_actiondata( package, szInstallODBC, uirow ); - msiobj_release( &uirow->hdr ); - - msi_free(attrs); - - return r; -} - -static UINT ACTION_InstallODBC( MSIPACKAGE *package ) -{ - static const WCHAR driver_query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'O','D','B','C','D','r','i','v','e','r',0}; - static const WCHAR translator_query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0}; - static const WCHAR source_query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view); - if (rc == ERROR_SUCCESS) - { - rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package); - msiobj_release(&view->hdr); - if (rc != ERROR_SUCCESS) - return rc; - } - rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view); - if (rc == ERROR_SUCCESS) - { - rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package); - msiobj_release(&view->hdr); - if (rc != ERROR_SUCCESS) - return rc; - } - rc = MSI_DatabaseOpenViewW(package->db, source_query, &view); - if (rc == ERROR_SUCCESS) - { - rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package); - msiobj_release(&view->hdr); - if (rc != ERROR_SUCCESS) - return rc; - } - return ERROR_SUCCESS; -} - -static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param ) -{ - MSIPACKAGE *package = param; - MSICOMPONENT *comp; - MSIRECORD *uirow; - DWORD usage; - LPCWSTR desc, component; - - component = MSI_RecordGetString( rec, 2 ); - comp = msi_get_loaded_component( package, component ); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_ABSENT) - { - TRACE("component not scheduled for removal %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - - desc = MSI_RecordGetString( rec, 3 ); - if (!SQLRemoveDriverW( desc, FALSE, &usage )) - { - WARN("Failed to remove ODBC driver\n"); - } - else if (!usage) - { - FIXME("Usage count reached 0\n"); - } - - uirow = MSI_CreateRecord( 2 ); - MSI_RecordSetStringW( uirow, 1, desc ); - MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) ); - msi_ui_actiondata( package, szRemoveODBC, uirow ); - msiobj_release( &uirow->hdr ); - - return ERROR_SUCCESS; -} - -static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param ) -{ - MSIPACKAGE *package = param; - MSICOMPONENT *comp; - MSIRECORD *uirow; - DWORD usage; - LPCWSTR desc, component; - - component = MSI_RecordGetString( rec, 2 ); - comp = msi_get_loaded_component( package, component ); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_ABSENT) - { - TRACE("component not scheduled for removal %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - - desc = MSI_RecordGetString( rec, 3 ); - if (!SQLRemoveTranslatorW( desc, &usage )) - { - WARN("Failed to remove ODBC translator\n"); - } - else if (!usage) - { - FIXME("Usage count reached 0\n"); - } - - uirow = MSI_CreateRecord( 2 ); - MSI_RecordSetStringW( uirow, 1, desc ); - MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) ); - msi_ui_actiondata( package, szRemoveODBC, uirow ); - msiobj_release( &uirow->hdr ); - - return ERROR_SUCCESS; -} - -static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param ) -{ - MSIPACKAGE *package = param; - MSICOMPONENT *comp; - MSIRECORD *uirow; - LPWSTR attrs; - LPCWSTR desc, driver, component; - WORD request = ODBC_REMOVE_SYS_DSN; - INT registration; - DWORD len; - - static const WCHAR attrs_fmt[] = { - 'D','S','N','=','%','s',0 }; - - component = MSI_RecordGetString( rec, 2 ); - comp = msi_get_loaded_component( package, component ); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_ABSENT) - { - TRACE("component not scheduled for removal %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - - desc = MSI_RecordGetString( rec, 3 ); - driver = MSI_RecordGetString( rec, 4 ); - registration = MSI_RecordGetInteger( rec, 5 ); - - if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN; - else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN; - - len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */ - attrs = msi_alloc( len * sizeof(WCHAR) ); - if (!attrs) - return ERROR_OUTOFMEMORY; - - FIXME("Use ODBCSourceAttribute table\n"); - - len = sprintfW( attrs, attrs_fmt, desc ); - attrs[len + 1] = 0; - - if (!SQLConfigDataSourceW( NULL, request, driver, attrs )) - { - WARN("Failed to remove ODBC data source\n"); - } - msi_free( attrs ); - - uirow = MSI_CreateRecord( 3 ); - MSI_RecordSetStringW( uirow, 1, desc ); - MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) ); - MSI_RecordSetInteger( uirow, 3, request ); - msi_ui_actiondata( package, szRemoveODBC, uirow ); - msiobj_release( &uirow->hdr ); - - return ERROR_SUCCESS; -} - -static UINT ACTION_RemoveODBC( MSIPACKAGE *package ) -{ - static const WCHAR driver_query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'O','D','B','C','D','r','i','v','e','r',0}; - static const WCHAR translator_query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0}; - static const WCHAR source_query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view ); - if (rc == ERROR_SUCCESS) - { - rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package ); - msiobj_release( &view->hdr ); - if (rc != ERROR_SUCCESS) - return rc; - } - rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view ); - if (rc == ERROR_SUCCESS) - { - rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package ); - msiobj_release( &view->hdr ); - if (rc != ERROR_SUCCESS) - return rc; - } - rc = MSI_DatabaseOpenViewW( package->db, source_query, &view ); - if (rc == ERROR_SUCCESS) - { - rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package ); - msiobj_release( &view->hdr ); - if (rc != ERROR_SUCCESS) - return rc; - } - return ERROR_SUCCESS; -} - -#define ENV_ACT_SETALWAYS 0x1 -#define ENV_ACT_SETABSENT 0x2 -#define ENV_ACT_REMOVE 0x4 -#define ENV_ACT_REMOVEMATCH 0x8 - -#define ENV_MOD_MACHINE 0x20000000 -#define ENV_MOD_APPEND 0x40000000 -#define ENV_MOD_PREFIX 0x80000000 -#define ENV_MOD_MASK 0xC0000000 - -#define check_flag_combo(x, y) ((x) & ~(y)) == (y) - -static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags ) -{ - LPCWSTR cptr = *name; - - static const WCHAR prefix[] = {'[','~',']',0}; - static const int prefix_len = 3; - - *flags = 0; - while (*cptr) - { - if (*cptr == '=') - *flags |= ENV_ACT_SETALWAYS; - else if (*cptr == '+') - *flags |= ENV_ACT_SETABSENT; - else if (*cptr == '-') - *flags |= ENV_ACT_REMOVE; - else if (*cptr == '!') - *flags |= ENV_ACT_REMOVEMATCH; - else if (*cptr == '*') - *flags |= ENV_MOD_MACHINE; - else - break; - - cptr++; - (*name)++; - } - - if (!*cptr) - { - ERR("Missing environment variable\n"); - return ERROR_FUNCTION_FAILED; - } - - if (*value) - { - LPCWSTR ptr = *value; - if (!strncmpW(ptr, prefix, prefix_len)) - { - if (ptr[prefix_len] == szSemiColon[0]) - { - *flags |= ENV_MOD_APPEND; - *value += lstrlenW(prefix); - } - else - { - *value = NULL; - } - } - else if (lstrlenW(*value) >= prefix_len) - { - ptr += lstrlenW(ptr) - prefix_len; - if (!strcmpW( ptr, prefix )) - { - if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0]) - { - *flags |= ENV_MOD_PREFIX; - /* the "[~]" will be removed by deformat_string */; - } - else - { - *value = NULL; - } - } - } - } - - if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) || - check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) || - check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) || - check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK)) - { - ERR("Invalid flags: %08x\n", *flags); - return ERROR_FUNCTION_FAILED; - } - - if (!*flags) - *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE; - - return ERROR_SUCCESS; -} - -static UINT open_env_key( DWORD flags, HKEY *key ) -{ - static const WCHAR user_env[] = - {'E','n','v','i','r','o','n','m','e','n','t',0}; - static const WCHAR machine_env[] = - {'S','y','s','t','e','m','\\', - 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', - 'C','o','n','t','r','o','l','\\', - 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\', - 'E','n','v','i','r','o','n','m','e','n','t',0}; - const WCHAR *env; - HKEY root; - LONG res; - - if (flags & ENV_MOD_MACHINE) - { - env = machine_env; - root = HKEY_LOCAL_MACHINE; - } - else - { - env = user_env; - root = HKEY_CURRENT_USER; - } - - res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key ); - if (res != ERROR_SUCCESS) - { - WARN("Failed to open key %s (%d)\n", debugstr_w(env), res); - return ERROR_FUNCTION_FAILED; - } - - return ERROR_SUCCESS; -} - -static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param ) -{ - MSIPACKAGE *package = param; - LPCWSTR name, value, component; - LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr; - DWORD flags, type, size; - UINT res; - HKEY env = NULL; - MSICOMPONENT *comp; - MSIRECORD *uirow; - int action = 0; - - component = MSI_RecordGetString(rec, 4); - comp = msi_get_loaded_component(package, component); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_LOCAL) - { - TRACE("component not scheduled for installation %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - name = MSI_RecordGetString(rec, 2); - value = MSI_RecordGetString(rec, 3); - - TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value)); - - res = env_parse_flags(&name, &value, &flags); - if (res != ERROR_SUCCESS || !value) - goto done; - - if (value && !deformat_string(package, value, &deformatted)) - { - res = ERROR_OUTOFMEMORY; - goto done; - } - - value = deformatted; - - res = open_env_key( flags, &env ); - if (res != ERROR_SUCCESS) - goto done; - - if (flags & ENV_MOD_MACHINE) - action |= 0x20000000; - - size = 0; - type = REG_SZ; - res = RegQueryValueExW(env, name, NULL, &type, NULL, &size); - if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) || - (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ)) - goto done; - - if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK))) - { - action = 0x2; - - /* Nothing to do. */ - if (!value) - { - res = ERROR_SUCCESS; - goto done; - } - - /* If we are appending but the string was empty, strip ; */ - if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++; - - size = (lstrlenW(value) + 1) * sizeof(WCHAR); - newval = strdupW(value); - if (!newval) - { - res = ERROR_OUTOFMEMORY; - goto done; - } - } - else - { - action = 0x1; - - /* Contrary to MSDN, +-variable to [~];path works */ - if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK)) - { - res = ERROR_SUCCESS; - goto done; - } - - data = msi_alloc(size); - if (!data) - { - RegCloseKey(env); - return ERROR_OUTOFMEMORY; - } - - res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size); - if (res != ERROR_SUCCESS) - goto done; - - if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value ))) - { - action = 0x4; - res = RegDeleteValueW(env, name); - if (res != ERROR_SUCCESS) - WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res); - goto done; - } - - size = (lstrlenW(data) + 1) * sizeof(WCHAR); - if (flags & ENV_MOD_MASK) - { - DWORD mod_size; - int multiplier = 0; - if (flags & ENV_MOD_APPEND) multiplier++; - if (flags & ENV_MOD_PREFIX) multiplier++; - mod_size = lstrlenW(value) * multiplier; - size += mod_size * sizeof(WCHAR); - } - - newval = msi_alloc(size); - ptr = newval; - if (!newval) - { - res = ERROR_OUTOFMEMORY; - goto done; - } - - if (flags & ENV_MOD_PREFIX) - { - lstrcpyW(newval, value); - ptr = newval + lstrlenW(value); - action |= 0x80000000; - } - - lstrcpyW(ptr, data); - - if (flags & ENV_MOD_APPEND) - { - lstrcatW(newval, value); - action |= 0x40000000; - } - } - TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval)); - res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size); - if (res) - { - WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res); - } - -done: - uirow = MSI_CreateRecord( 3 ); - MSI_RecordSetStringW( uirow, 1, name ); - MSI_RecordSetStringW( uirow, 2, newval ); - MSI_RecordSetInteger( uirow, 3, action ); - msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow ); - msiobj_release( &uirow->hdr ); - - if (env) RegCloseKey(env); - msi_free(deformatted); - msi_free(data); - msi_free(newval); - return res; -} - -static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','E','n','v','i','r','o','n','m','e','n','t','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package); - msiobj_release(&view->hdr); - return rc; -} - -static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param ) -{ - MSIPACKAGE *package = param; - LPCWSTR name, value, component; - LPWSTR deformatted = NULL; - DWORD flags; - HKEY env; - MSICOMPONENT *comp; - MSIRECORD *uirow; - int action = 0; - LONG res; - UINT r; - - component = MSI_RecordGetString( rec, 4 ); - comp = msi_get_loaded_component( package, component ); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_ABSENT) - { - TRACE("component not scheduled for removal %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - name = MSI_RecordGetString( rec, 2 ); - value = MSI_RecordGetString( rec, 3 ); - - TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value)); - - r = env_parse_flags( &name, &value, &flags ); - if (r != ERROR_SUCCESS) - return r; - - if (!(flags & ENV_ACT_REMOVE)) - { - TRACE("Environment variable %s not marked for removal\n", debugstr_w(name)); - return ERROR_SUCCESS; - } - - if (value && !deformat_string( package, value, &deformatted )) - return ERROR_OUTOFMEMORY; - - value = deformatted; - - r = open_env_key( flags, &env ); - if (r != ERROR_SUCCESS) - { - r = ERROR_SUCCESS; - goto done; - } - - if (flags & ENV_MOD_MACHINE) - action |= 0x20000000; - - TRACE("Removing %s\n", debugstr_w(name)); - - res = RegDeleteValueW( env, name ); - if (res != ERROR_SUCCESS) - { - WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res); - r = ERROR_SUCCESS; - } - -done: - uirow = MSI_CreateRecord( 3 ); - MSI_RecordSetStringW( uirow, 1, name ); - MSI_RecordSetStringW( uirow, 2, value ); - MSI_RecordSetInteger( uirow, 3, action ); - msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow ); - msiobj_release( &uirow->hdr ); - - if (env) RegCloseKey( env ); - msi_free( deformatted ); - return r; -} - -static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','E','n','v','i','r','o','n','m','e','n','t','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package ); - msiobj_release( &view->hdr ); - return rc; -} - -UINT msi_validate_product_id( MSIPACKAGE *package ) -{ - LPWSTR key, template, id; - UINT r = ERROR_SUCCESS; - - id = msi_dup_property( package->db, szProductID ); - if (id) - { - msi_free( id ); - return ERROR_SUCCESS; - } - template = msi_dup_property( package->db, szPIDTemplate ); - key = msi_dup_property( package->db, szPIDKEY ); - if (key && template) - { - FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) ); - r = msi_set_property( package->db, szProductID, key ); - } - msi_free( template ); - msi_free( key ); - return r; -} - -static UINT ACTION_ValidateProductID( MSIPACKAGE *package ) -{ - return msi_validate_product_id( package ); -} - -static UINT ACTION_ScheduleReboot( MSIPACKAGE *package ) -{ - TRACE("\n"); - package->need_reboot_at_end = 1; - return ERROR_SUCCESS; -} - -static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package ) -{ - static const WCHAR szAvailableFreeReg[] = - {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0}; - MSIRECORD *uirow; - int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 ); - - TRACE("%p %d kilobytes\n", package, space); - - uirow = MSI_CreateRecord( 1 ); - MSI_RecordSetInteger( uirow, 1, space ); - msi_ui_actiondata( package, szAllocateRegistrySpace, uirow ); - msiobj_release( &uirow->hdr ); - - return ERROR_SUCCESS; -} - -static UINT ACTION_DisableRollback( MSIPACKAGE *package ) -{ - TRACE("%p\n", package); - - msi_set_property( package->db, szRollbackDisabled, szOne ); - return ERROR_SUCCESS; -} - -static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package ) -{ - FIXME("%p\n", package); - return ERROR_SUCCESS; -} - -static UINT ACTION_SetODBCFolders( MSIPACKAGE *package ) -{ - static const WCHAR driver_query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'O','D','B','C','D','r','i','v','e','r',0}; - static const WCHAR translator_query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0}; - MSIQUERY *view; - UINT r, count; - - r = MSI_DatabaseOpenViewW( package->db, driver_query, &view ); - if (r == ERROR_SUCCESS) - { - count = 0; - r = MSI_IterateRecords( view, &count, NULL, package ); - msiobj_release( &view->hdr ); - if (r != ERROR_SUCCESS) - return r; - if (count) FIXME("ignored %u rows in ODBCDriver table\n", count); - } - r = MSI_DatabaseOpenViewW( package->db, translator_query, &view ); - if (r == ERROR_SUCCESS) - { - count = 0; - r = MSI_IterateRecords( view, &count, NULL, package ); - msiobj_release( &view->hdr ); - if (r != ERROR_SUCCESS) - return r; - if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count); - } - return ERROR_SUCCESS; -} - -static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param ) -{ - static const WCHAR fmtW[] = - {'m','s','i','e','x','e','c',' ','/','i',' ','%','s',' ','R','E','M','O','V','E','=','%','s',0}; - MSIPACKAGE *package = param; - const WCHAR *property = MSI_RecordGetString( rec, 7 ); - UINT len = sizeof(fmtW)/sizeof(fmtW[0]); - WCHAR *product, *features, *cmd; - STARTUPINFOW si; - PROCESS_INFORMATION info; - BOOL ret; - - if (!(product = msi_dup_property( package->db, property ))) return ERROR_SUCCESS; - - deformat_string( package, MSI_RecordGetString( rec, 6 ), &features ); - - len += strlenW( product ); - if (features) - len += strlenW( features ); - else - len += sizeof(szAll) / sizeof(szAll[0]); - - if (!(cmd = msi_alloc( len * sizeof(WCHAR) ))) - { - msi_free( product ); - msi_free( features ); - return ERROR_OUTOFMEMORY; - } - sprintfW( cmd, fmtW, product, features ? features : szAll ); - msi_free( product ); - msi_free( features ); - - memset( &si, 0, sizeof(STARTUPINFOW) ); - ret = CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info ); - msi_free( cmd ); - if (!ret) return GetLastError(); - CloseHandle( info.hThread ); - - WaitForSingleObject( info.hProcess, INFINITE ); - CloseHandle( info.hProcess ); - return ERROR_SUCCESS; -} - -static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','U','p','g','r','a','d','e',0}; - MSIQUERY *view; - UINT r; - - r = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (r == ERROR_SUCCESS) - { - r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package ); - msiobj_release( &view->hdr ); - if (r != ERROR_SUCCESS) - return r; - } - return ERROR_SUCCESS; -} - -static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param ) -{ - MSIPACKAGE *package = param; - int attributes = MSI_RecordGetInteger( rec, 5 ); - - if (attributes & msidbUpgradeAttributesMigrateFeatures) - { - const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 ); - const WCHAR *version_min = MSI_RecordGetString( rec, 2 ); - const WCHAR *version_max = MSI_RecordGetString( rec, 3 ); - const WCHAR *language = MSI_RecordGetString( rec, 4 ); - HKEY hkey; - UINT r; - - if (package->Context == MSIINSTALLCONTEXT_MACHINE) - { - r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE ); - if (r != ERROR_SUCCESS) - return ERROR_SUCCESS; - } - else - { - r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE ); - if (r != ERROR_SUCCESS) - return ERROR_SUCCESS; - } - RegCloseKey( hkey ); - - FIXME("migrate feature states from %s version min %s version max %s language %s\n", - debugstr_w(upgrade_code), debugstr_w(version_min), - debugstr_w(version_max), debugstr_w(language)); - } - return ERROR_SUCCESS; -} - -static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'U','p','g','r','a','d','e',0}; - MSIQUERY *view; - UINT r; - - if (msi_get_property_int( package->db, szInstalled, 0 )) - { - TRACE("product is installed, skipping action\n"); - return ERROR_SUCCESS; - } - if (msi_get_property_int( package->db, szPreselected, 0 )) - { - TRACE("Preselected property is set, not migrating feature states\n"); - return ERROR_SUCCESS; - } - r = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (r == ERROR_SUCCESS) - { - r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package ); - msiobj_release( &view->hdr ); - if (r != ERROR_SUCCESS) - return r; - } - return ERROR_SUCCESS; -} - -static void bind_image( const char *filename, const char *path ) -{ - if (!BindImageEx( 0, filename, path, NULL, NULL )) - { - WARN("failed to bind image %u\n", GetLastError()); - } -} - -static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param ) -{ - UINT i; - MSIFILE *file; - MSIPACKAGE *package = param; - const WCHAR *key = MSI_RecordGetString( rec, 1 ); - const WCHAR *paths = MSI_RecordGetString( rec, 2 ); - char *filenameA, *pathA; - WCHAR *pathW, **path_list; - - if (!(file = msi_get_loaded_file( package, key ))) - { - WARN("file %s not found\n", debugstr_w(key)); - return ERROR_SUCCESS; - } - if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS; - path_list = msi_split_string( paths, ';' ); - if (!path_list) bind_image( filenameA, NULL ); - else - { - for (i = 0; path_list[i] && path_list[i][0]; i++) - { - deformat_string( package, path_list[i], &pathW ); - if ((pathA = strdupWtoA( pathW ))) - { - bind_image( filenameA, pathA ); - msi_free( pathA ); - } - msi_free( pathW ); - } - } - msi_free( path_list ); - msi_free( filenameA ); - return ERROR_SUCCESS; -} - -static UINT ACTION_BindImage( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'B','i','n','d','I','m','a','g','e',0}; - MSIQUERY *view; - UINT r; - - r = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (r == ERROR_SUCCESS) - { - r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package ); - msiobj_release( &view->hdr ); - if (r != ERROR_SUCCESS) - return r; - } - return ERROR_SUCCESS; -} - -static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0}; - MSIQUERY *view; - DWORD count = 0; - UINT r; - - r = MSI_OpenQuery( package->db, &view, query, table ); - if (r == ERROR_SUCCESS) - { - r = MSI_IterateRecords(view, &count, NULL, package); - msiobj_release(&view->hdr); - if (r != ERROR_SUCCESS) - return r; - } - if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table)); - return ERROR_SUCCESS; -} - -static UINT ACTION_IsolateComponents( MSIPACKAGE *package ) -{ - static const WCHAR table[] = { - 'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 }; - return msi_unimplemented_action_stub( package, "IsolateComponents", table ); -} - -static UINT ACTION_RMCCPSearch( MSIPACKAGE *package ) -{ - static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 }; - return msi_unimplemented_action_stub( package, "RMCCPSearch", table ); -} - -static UINT ACTION_RegisterComPlus( MSIPACKAGE *package ) -{ - static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 }; - return msi_unimplemented_action_stub( package, "RegisterComPlus", table ); -} - -static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package ) -{ - static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 }; - return msi_unimplemented_action_stub( package, "UnregisterComPlus", table ); -} - -static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package ) -{ - static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 }; - return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table ); -} - -static const struct -{ - const WCHAR *action; - UINT (*handler)(MSIPACKAGE *); - const WCHAR *action_rollback; -} -StandardActions[] = -{ - { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL }, - { szAppSearch, ACTION_AppSearch, NULL }, - { szBindImage, ACTION_BindImage, NULL }, - { szCCPSearch, ACTION_CCPSearch, NULL }, - { szCostFinalize, ACTION_CostFinalize, NULL }, - { szCostInitialize, ACTION_CostInitialize, NULL }, - { szCreateFolders, ACTION_CreateFolders, szRemoveFolders }, - { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts }, - { szDeleteServices, ACTION_DeleteServices, szInstallServices }, - { szDisableRollback, ACTION_DisableRollback, NULL }, - { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles }, - { szExecuteAction, ACTION_ExecuteAction, NULL }, - { szFileCost, ACTION_FileCost, NULL }, - { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL }, - { szForceReboot, ACTION_ForceReboot, NULL }, - { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL }, - { szInstallExecute, ACTION_InstallExecute, NULL }, - { szInstallExecuteAgain, ACTION_InstallExecute, NULL }, - { szInstallFiles, ACTION_InstallFiles, szRemoveFiles }, - { szInstallFinalize, ACTION_InstallFinalize, NULL }, - { szInstallInitialize, ACTION_InstallInitialize, NULL }, - { szInstallODBC, ACTION_InstallODBC, szRemoveODBC }, - { szInstallServices, ACTION_InstallServices, szDeleteServices }, - { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL }, - { szInstallValidate, ACTION_InstallValidate, NULL }, - { szIsolateComponents, ACTION_IsolateComponents, NULL }, - { szLaunchConditions, ACTION_LaunchConditions, NULL }, - { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL }, - { szMoveFiles, ACTION_MoveFiles, NULL }, - { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies }, - { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies }, - { szPatchFiles, ACTION_PatchFiles, NULL }, - { szProcessComponents, ACTION_ProcessComponents, szProcessComponents }, - { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents }, - { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures }, - { szPublishProduct, ACTION_PublishProduct, NULL }, - { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo }, - { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus }, - { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo }, - { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts }, - { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo }, - { szRegisterProduct, ACTION_RegisterProduct, NULL }, - { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo }, - { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries }, - { szRegisterUser, ACTION_RegisterUser, NULL }, - { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles }, - { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings }, - { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL }, - { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles }, - { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders }, - { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues }, - { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC }, - { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues }, - { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts }, - { szResolveSource, ACTION_ResolveSource, NULL }, - { szRMCCPSearch, ACTION_RMCCPSearch, NULL }, - { szScheduleReboot, ACTION_ScheduleReboot, NULL }, - { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules }, - { szSelfUnregModules, ACTION_SelfUnregModules, szSelfRegModules }, - { szSetODBCFolders, ACTION_SetODBCFolders, NULL }, - { szStartServices, ACTION_StartServices, szStopServices }, - { szStopServices, ACTION_StopServices, szStartServices }, - { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents }, - { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures }, - { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo }, - { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus }, - { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo }, - { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts }, - { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo }, - { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo }, - { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries }, - { szValidateProductID, ACTION_ValidateProductID, NULL }, - { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings }, - { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues }, - { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues }, - { NULL, NULL, NULL } -}; - -static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc ) -{ - BOOL ret = FALSE; - UINT i; - - i = 0; - while (StandardActions[i].action != NULL) - { - if (!strcmpW( StandardActions[i].action, action )) - { - ui_actionstart( package, action ); - if (StandardActions[i].handler) - { - ui_actioninfo( package, action, TRUE, 0 ); - *rc = StandardActions[i].handler( package ); - ui_actioninfo( package, action, FALSE, *rc ); - - if (StandardActions[i].action_rollback && !package->need_rollback) - { - TRACE("scheduling rollback action\n"); - msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback ); - } - } - else - { - FIXME("unhandled standard action %s\n", debugstr_w(action)); - *rc = ERROR_SUCCESS; - } - ret = TRUE; - break; - } - i++; - } - return ret; -} - -UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script) -{ - UINT rc = ERROR_SUCCESS; - BOOL handled; - - TRACE("Performing action (%s)\n", debugstr_w(action)); - - handled = ACTION_HandleStandardAction(package, action, &rc); - - if (!handled) - handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE); - - if (!handled) - { - WARN("unhandled msi action %s\n", debugstr_w(action)); - rc = ERROR_FUNCTION_NOT_CALLED; - } - - return rc; -} - -UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script) -{ - UINT rc = ERROR_SUCCESS; - BOOL handled = FALSE; - - TRACE("Performing action (%s)\n", debugstr_w(action)); - - package->action_progress_increment = 0; - handled = ACTION_HandleStandardAction(package, action, &rc); - - if (!handled) - handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE); - - if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS ) - handled = TRUE; - - if (!handled) - { - WARN("unhandled msi action %s\n", debugstr_w(action)); - rc = ERROR_FUNCTION_NOT_CALLED; - } - - return rc; -} - -static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq) -{ - UINT rc = ERROR_SUCCESS; - MSIRECORD *row; - - static const WCHAR query[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e', - 'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ', - '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0}; - static const WCHAR ui_query[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e', - '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`', - ' ', '=',' ','%','i',0}; - - if (needs_ui_sequence(package)) - row = MSI_QueryGetRecord(package->db, ui_query, seq); - else - row = MSI_QueryGetRecord(package->db, query, seq); - - if (row) - { - LPCWSTR action, cond; - - TRACE("Running the actions\n"); - - /* check conditions */ - cond = MSI_RecordGetString(row, 2); - - /* this is a hack to skip errors in the condition code */ - if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE) - { - msiobj_release(&row->hdr); - return ERROR_SUCCESS; - } - - action = MSI_RecordGetString(row, 1); - if (!action) - { - ERR("failed to fetch action\n"); - msiobj_release(&row->hdr); - return ERROR_FUNCTION_FAILED; - } - - if (needs_ui_sequence(package)) - rc = ACTION_PerformUIAction(package, action, SCRIPT_NONE); - else - rc = ACTION_PerformAction(package, action, SCRIPT_NONE); - - msiobj_release(&row->hdr); - } - - return rc; -} - -/**************************************************** - * TOP level entry points - *****************************************************/ - -UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath, - LPCWSTR szCommandLine ) -{ - static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0}; - static const WCHAR szAction[] = {'A','C','T','I','O','N',0}; - static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0}; - WCHAR *reinstall = NULL; - BOOL ui_exists; - UINT rc; - - msi_set_property( package->db, szAction, szInstall ); - - package->script->InWhatSequence = SEQUENCE_INSTALL; - - if (szPackagePath) - { - LPWSTR p, dir; - LPCWSTR file; - - dir = strdupW(szPackagePath); - p = strrchrW(dir, '\\'); - if (p) - { - *(++p) = 0; - file = szPackagePath + (p - dir); - } - else - { - msi_free(dir); - dir = msi_alloc(MAX_PATH * sizeof(WCHAR)); - GetCurrentDirectoryW(MAX_PATH, dir); - lstrcatW(dir, szBackSlash); - file = szPackagePath; - } - - msi_free( package->PackagePath ); - package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR)); - if (!package->PackagePath) - { - msi_free(dir); - return ERROR_OUTOFMEMORY; - } - - lstrcpyW(package->PackagePath, dir); - lstrcatW(package->PackagePath, file); - msi_free(dir); - - msi_set_sourcedir_props(package, FALSE); - } - - rc = msi_parse_command_line( package, szCommandLine, FALSE ); - if (rc != ERROR_SUCCESS) - return rc; - - msi_apply_transforms( package ); - msi_apply_patches( package ); - - if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 )) - { - TRACE("setting reinstall property\n"); - msi_set_property( package->db, szReinstall, szAll ); - } - - /* properties may have been added by a transform */ - msi_clone_properties( package ); - - msi_parse_command_line( package, szCommandLine, FALSE ); - msi_adjust_privilege_properties( package ); - msi_set_context( package ); - - if (msi_get_property_int( package->db, szDisableRollback, 0 )) - { - TRACE("disabling rollback\n"); - msi_set_property( package->db, szRollbackDisabled, szOne ); - } - - if (needs_ui_sequence( package)) - { - package->script->InWhatSequence |= SEQUENCE_UI; - rc = ACTION_ProcessUISequence(package); - ui_exists = ui_sequence_exists(package); - if (rc == ERROR_SUCCESS || !ui_exists) - { - package->script->InWhatSequence |= SEQUENCE_EXEC; - rc = ACTION_ProcessExecSequence(package, ui_exists); - } - } - else - rc = ACTION_ProcessExecSequence(package, FALSE); - - package->script->CurrentlyScripting = FALSE; - - /* process the ending type action */ - if (rc == ERROR_SUCCESS) - ACTION_PerformActionSequence(package, -1); - else if (rc == ERROR_INSTALL_USEREXIT) - ACTION_PerformActionSequence(package, -2); - else if (rc == ERROR_INSTALL_SUSPEND) - ACTION_PerformActionSequence(package, -4); - else /* failed */ - { - ACTION_PerformActionSequence(package, -3); - if (!msi_get_property_int( package->db, szRollbackDisabled, 0 )) - { - package->need_rollback = TRUE; - } - } - - /* finish up running custom actions */ - ACTION_FinishCustomActions(package); - - if (package->need_rollback && !(reinstall = msi_dup_property( package->db, szReinstall ))) - { - WARN("installation failed, running rollback script\n"); - execute_script( package, SCRIPT_ROLLBACK ); - } - msi_free( reinstall ); - - if (rc == ERROR_SUCCESS && package->need_reboot_at_end) - return ERROR_SUCCESS_REBOOT_REQUIRED; - - return rc; -} diff --git a/libmsi/appsearch.c b/libmsi/appsearch.c deleted file mode 100644 index 21daf43..0000000 --- a/libmsi/appsearch.c +++ /dev/null @@ -1,1189 +0,0 @@ -/* - * Implementation of the AppSearch action of the Microsoft Installer (msi.dll) - * - * Copyright 2005 Juan Lang - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ -#include <stdarg.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "msi.h" -#include "msiquery.h" -#include "msidefs.h" -#include "winver.h" -#include "shlwapi.h" -#include "wine/unicode.h" -#include "wine/debug.h" -#include "msipriv.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -typedef struct tagMSISIGNATURE -{ - LPCWSTR Name; /* NOT owned by this structure */ - LPWSTR File; - DWORD MinVersionMS; - DWORD MinVersionLS; - DWORD MaxVersionMS; - DWORD MaxVersionLS; - DWORD MinSize; - DWORD MaxSize; - FILETIME MinTime; - FILETIME MaxTime; - LPWSTR Languages; -}MSISIGNATURE; - -void msi_parse_version_string(LPCWSTR verStr, PDWORD ms, PDWORD ls) -{ - const WCHAR *ptr; - int x1 = 0, x2 = 0, x3 = 0, x4 = 0; - - x1 = atoiW(verStr); - ptr = strchrW(verStr, '.'); - if (ptr) - { - x2 = atoiW(ptr + 1); - ptr = strchrW(ptr + 1, '.'); - } - if (ptr) - { - x3 = atoiW(ptr + 1); - ptr = strchrW(ptr + 1, '.'); - } - if (ptr) - x4 = atoiW(ptr + 1); - /* FIXME: byte-order dependent? */ - *ms = x1 << 16 | x2; - if (ls) *ls = x3 << 16 | x4; -} - -/* Fills in sig with the values from the Signature table, where name is the - * signature to find. Upon return, sig->File will be NULL if the record is not - * found, and not NULL if it is found. - * Warning: clears all fields in sig! - * Returns ERROR_SUCCESS upon success (where not finding the record counts as - * success), something else on error. - */ -static UINT ACTION_AppSearchGetSignature(MSIPACKAGE *package, MSISIGNATURE *sig, LPCWSTR name) -{ - static const WCHAR query[] = { - 's','e','l','e','c','t',' ','*',' ', - 'f','r','o','m',' ', - 'S','i','g','n','a','t','u','r','e',' ', - 'w','h','e','r','e',' ','S','i','g','n','a','t','u','r','e',' ','=',' ', - '\'','%','s','\'',0}; - LPWSTR minVersion, maxVersion, p; - MSIRECORD *row; - DWORD time; - - TRACE("package %p, sig %p\n", package, sig); - - memset(sig, 0, sizeof(*sig)); - sig->Name = name; - row = MSI_QueryGetRecord( package->db, query, name ); - if (!row) - { - TRACE("failed to query signature for %s\n", debugstr_w(name)); - return ERROR_SUCCESS; - } - - /* get properties */ - sig->File = msi_dup_record_field(row,2); - if ((p = strchrW(sig->File, '|'))) - { - p++; - memmove(sig->File, p, (strlenW(p) + 1) * sizeof(WCHAR)); - } - - minVersion = msi_dup_record_field(row,3); - if (minVersion) - { - msi_parse_version_string( minVersion, &sig->MinVersionMS, &sig->MinVersionLS ); - msi_free( minVersion ); - } - maxVersion = msi_dup_record_field(row,4); - if (maxVersion) - { - msi_parse_version_string( maxVersion, &sig->MaxVersionMS, &sig->MaxVersionLS ); - msi_free( maxVersion ); - } - sig->MinSize = MSI_RecordGetInteger(row,5); - if (sig->MinSize == MSI_NULL_INTEGER) - sig->MinSize = 0; - sig->MaxSize = MSI_RecordGetInteger(row,6); - if (sig->MaxSize == MSI_NULL_INTEGER) - sig->MaxSize = 0; - sig->Languages = msi_dup_record_field(row,9); - time = MSI_RecordGetInteger(row,7); - if (time != MSI_NULL_INTEGER) - DosDateTimeToFileTime(HIWORD(time), LOWORD(time), &sig->MinTime); - time = MSI_RecordGetInteger(row,8); - if (time != MSI_NULL_INTEGER) - DosDateTimeToFileTime(HIWORD(time), LOWORD(time), &sig->MaxTime); - - TRACE("Found file name %s for Signature_ %s;\n", - debugstr_w(sig->File), debugstr_w(name)); - TRACE("MinVersion is %d.%d.%d.%d\n", HIWORD(sig->MinVersionMS), - LOWORD(sig->MinVersionMS), HIWORD(sig->MinVersionLS), - LOWORD(sig->MinVersionLS)); - TRACE("MaxVersion is %d.%d.%d.%d\n", HIWORD(sig->MaxVersionMS), - LOWORD(sig->MaxVersionMS), HIWORD(sig->MaxVersionLS), - LOWORD(sig->MaxVersionLS)); - TRACE("MinSize is %d, MaxSize is %d;\n", sig->MinSize, sig->MaxSize); - TRACE("Languages is %s\n", debugstr_w(sig->Languages)); - - msiobj_release( &row->hdr ); - - return ERROR_SUCCESS; -} - -/* Frees any memory allocated in sig */ -static void ACTION_FreeSignature(MSISIGNATURE *sig) -{ - msi_free(sig->File); - msi_free(sig->Languages); -} - -static LPWSTR app_search_file(LPWSTR path, MSISIGNATURE *sig) -{ - VS_FIXEDFILEINFO *info; - DWORD attr, handle, size; - LPWSTR val = NULL; - LPBYTE buffer; - - if (!sig->File) - { - PathRemoveFileSpecW(path); - PathAddBackslashW(path); - - attr = GetFileAttributesW(path); - if (attr != INVALID_FILE_ATTRIBUTES && - (attr & FILE_ATTRIBUTE_DIRECTORY)) - return strdupW(path); - - return NULL; - } - - attr = GetFileAttributesW(path); - if (attr == INVALID_FILE_ATTRIBUTES || - (attr & FILE_ATTRIBUTE_DIRECTORY)) - return NULL; - - size = GetFileVersionInfoSizeW(path, &handle); - if (!size) - return strdupW(path); - - buffer = msi_alloc(size); - if (!buffer) - return NULL; - - if (!GetFileVersionInfoW(path, 0, size, buffer)) - goto done; - - if (!VerQueryValueW(buffer, szBackSlash, (LPVOID)&info, &size) || !info) - goto done; - - if (sig->MinVersionLS || sig->MinVersionMS) - { - if (info->dwFileVersionMS < sig->MinVersionMS) - goto done; - - if (info->dwFileVersionMS == sig->MinVersionMS && - info->dwFileVersionLS < sig->MinVersionLS) - goto done; - } - - if (sig->MaxVersionLS || sig->MaxVersionMS) - { - if (info->dwFileVersionMS > sig->MaxVersionMS) - goto done; - - if (info->dwFileVersionMS == sig->MaxVersionMS && - info->dwFileVersionLS > sig->MaxVersionLS) - goto done; - } - - val = strdupW(path); - -done: - msi_free(buffer); - return val; -} - -static UINT ACTION_AppSearchComponents(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATURE *sig) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ', - 'F','R','O','M',' ', - '`','C','o','m','p','L','o','c','a','t','o','r','`',' ', - 'W','H','E','R','E',' ','`','S','i','g','n','a','t','u','r','e','_','`',' ','=',' ', - '\'','%','s','\'',0}; - static const WCHAR sigquery[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','S','i','g','n','a','t','u','r','e','`',' ', - 'W','H','E','R','E',' ','`','S','i','g','n','a','t','u','r','e','`',' ','=',' ', - '\'','%','s','\'',0}; - - MSIRECORD *row, *rec; - LPCWSTR signature, guid; - BOOL sigpresent = TRUE; - BOOL isdir; - UINT type; - WCHAR path[MAX_PATH]; - DWORD size = MAX_PATH; - LPWSTR ptr; - DWORD attr; - - TRACE("%s\n", debugstr_w(sig->Name)); - - *appValue = NULL; - - row = MSI_QueryGetRecord(package->db, query, sig->Name); - if (!row) - { - TRACE("failed to query CompLocator for %s\n", debugstr_w(sig->Name)); - return ERROR_SUCCESS; - } - - signature = MSI_RecordGetString(row, 1); - guid = MSI_RecordGetString(row, 2); - type = MSI_RecordGetInteger(row, 3); - - rec = MSI_QueryGetRecord(package->db, sigquery, signature); - if (!rec) - sigpresent = FALSE; - - *path = '\0'; - MsiLocateComponentW(guid, path, &size); - if (!*path) - goto done; - - attr = GetFileAttributesW(path); - if (attr == INVALID_FILE_ATTRIBUTES) - goto done; - - isdir = (attr & FILE_ATTRIBUTE_DIRECTORY); - - if (type != msidbLocatorTypeDirectory && sigpresent && !isdir) - { - *appValue = app_search_file(path, sig); - } - else if (!sigpresent && (type != msidbLocatorTypeDirectory || isdir)) - { - if (type == msidbLocatorTypeFileName) - { - ptr = strrchrW(path, '\\'); - *(ptr + 1) = '\0'; - } - else - PathAddBackslashW(path); - - *appValue = strdupW(path); - } - else if (sigpresent) - { - PathAddBackslashW(path); - lstrcatW(path, MSI_RecordGetString(rec, 2)); - - attr = GetFileAttributesW(path); - if (attr != INVALID_FILE_ATTRIBUTES && - !(attr & FILE_ATTRIBUTE_DIRECTORY)) - *appValue = strdupW(path); - } - -done: - if (rec) msiobj_release(&rec->hdr); - msiobj_release(&row->hdr); - return ERROR_SUCCESS; -} - -static void ACTION_ConvertRegValue(DWORD regType, const BYTE *value, DWORD sz, - LPWSTR *appValue) -{ - static const WCHAR dwordFmt[] = { '#','%','d','\0' }; - static const WCHAR binPre[] = { '#','x','\0' }; - static const WCHAR binFmt[] = { '%','0','2','X','\0' }; - LPWSTR ptr; - DWORD i; - - switch (regType) - { - case REG_SZ: - if (*(LPCWSTR)value == '#') - { - /* escape leading pound with another */ - *appValue = msi_alloc(sz + sizeof(WCHAR)); - (*appValue)[0] = '#'; - strcpyW(*appValue + 1, (LPCWSTR)value); - } - else - { - *appValue = msi_alloc(sz); - strcpyW(*appValue, (LPCWSTR)value); - } - break; - case REG_DWORD: - /* 7 chars for digits, 1 for NULL, 1 for #, and 1 for sign - * char if needed - */ - *appValue = msi_alloc(10 * sizeof(WCHAR)); - sprintfW(*appValue, dwordFmt, *(const DWORD *)value); - break; - case REG_EXPAND_SZ: - sz = ExpandEnvironmentStringsW((LPCWSTR)value, NULL, 0); - *appValue = msi_alloc(sz * sizeof(WCHAR)); - ExpandEnvironmentStringsW((LPCWSTR)value, *appValue, sz); - break; - case REG_BINARY: - /* #x<nibbles>\0 */ - *appValue = msi_alloc((sz * 2 + 3) * sizeof(WCHAR)); - lstrcpyW(*appValue, binPre); - ptr = *appValue + lstrlenW(binPre); - for (i = 0; i < sz; i++, ptr += 2) - sprintfW(ptr, binFmt, value[i]); - break; - default: - WARN("unimplemented for values of type %d\n", regType); - *appValue = NULL; - } -} - -static UINT ACTION_SearchDirectory(MSIPACKAGE *package, MSISIGNATURE *sig, - LPCWSTR path, int depth, LPWSTR *appValue); - -static UINT ACTION_AppSearchReg(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATURE *sig) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'R','e','g','L','o','c','a','t','o','r',' ','W','H','E','R','E',' ', - 'S','i','g','n','a','t','u','r','e','_',' ','=',' ', '\'','%','s','\'',0}; - const WCHAR *keyPath, *valueName; - WCHAR *deformatted = NULL, *ptr = NULL, *end; - int root, type; - HKEY rootKey, key = NULL; - DWORD sz = 0, regType; - LPBYTE value = NULL; - MSIRECORD *row; - UINT rc; - - TRACE("%s\n", debugstr_w(sig->Name)); - - *appValue = NULL; - - row = MSI_QueryGetRecord( package->db, query, sig->Name ); - if (!row) - { - TRACE("failed to query RegLocator for %s\n", debugstr_w(sig->Name)); - return ERROR_SUCCESS; - } - - root = MSI_RecordGetInteger(row, 2); - keyPath = MSI_RecordGetString(row, 3); - valueName = MSI_RecordGetString(row, 4); - type = MSI_RecordGetInteger(row, 5); - - deformat_string(package, keyPath, &deformatted); - - switch (root) - { - case msidbRegistryRootClassesRoot: - rootKey = HKEY_CLASSES_ROOT; - break; - case msidbRegistryRootCurrentUser: - rootKey = HKEY_CURRENT_USER; - break; - case msidbRegistryRootLocalMachine: - rootKey = HKEY_LOCAL_MACHINE; - break; - case msidbRegistryRootUsers: - rootKey = HKEY_USERS; - break; - default: - WARN("Unknown root key %d\n", root); - goto end; - } - - rc = RegOpenKeyW(rootKey, deformatted, &key); - if (rc) - { - TRACE("RegOpenKeyW returned %d\n", rc); - goto end; - } - - msi_free(deformatted); - deformat_string(package, valueName, &deformatted); - - rc = RegQueryValueExW(key, deformatted, NULL, NULL, NULL, &sz); - if (rc) - { - TRACE("RegQueryValueExW returned %d\n", rc); - goto end; - } - /* FIXME: sanity-check sz before allocating (is there an upper-limit - * on the value of a property?) - */ - value = msi_alloc( sz ); - rc = RegQueryValueExW(key, deformatted, NULL, ®Type, value, &sz); - if (rc) - { - TRACE("RegQueryValueExW returned %d\n", rc); - goto end; - } - - /* bail out if the registry key is empty */ - if (sz == 0) - goto end; - - if ((regType == REG_SZ || regType == REG_EXPAND_SZ) && - (ptr = strchrW((LPWSTR)value, '"')) && (end = strchrW(++ptr, '"'))) - *end = '\0'; - else - ptr = (LPWSTR)value; - - switch (type & 0x0f) - { - case msidbLocatorTypeDirectory: - ACTION_SearchDirectory(package, sig, ptr, 0, appValue); - break; - case msidbLocatorTypeFileName: - *appValue = app_search_file(ptr, sig); - break; - case msidbLocatorTypeRawValue: - ACTION_ConvertRegValue(regType, value, sz, appValue); - break; - default: - FIXME("unimplemented for type %d (key path %s, value %s)\n", - type, debugstr_w(keyPath), debugstr_w(valueName)); - } -end: - msi_free( value ); - RegCloseKey( key ); - msi_free( deformatted ); - - msiobj_release(&row->hdr); - return ERROR_SUCCESS; -} - -static LPWSTR get_ini_field(LPWSTR buf, int field) -{ - LPWSTR beg, end; - int i = 1; - - if (field == 0) - return strdupW(buf); - - beg = buf; - while ((end = strchrW(beg, ',')) && i < field) - { - beg = end + 1; - while (*beg && *beg == ' ') - beg++; - - i++; - } - - end = strchrW(beg, ','); - if (!end) - end = beg + lstrlenW(beg); - - *end = '\0'; - return strdupW(beg); -} - -static UINT ACTION_AppSearchIni(MSIPACKAGE *package, LPWSTR *appValue, - MSISIGNATURE *sig) -{ - static const WCHAR query[] = { - 's','e','l','e','c','t',' ','*',' ', - 'f','r','o','m',' ', - 'I','n','i','L','o','c','a','t','o','r',' ', - 'w','h','e','r','e',' ', - 'S','i','g','n','a','t','u','r','e','_',' ','=',' ','\'','%','s','\'',0}; - MSIRECORD *row; - LPWSTR fileName, section, key; - int field, type; - WCHAR buf[MAX_PATH]; - - TRACE("%s\n", debugstr_w(sig->Name)); - - *appValue = NULL; - - row = MSI_QueryGetRecord( package->db, query, sig->Name ); - if (!row) - { - TRACE("failed to query IniLocator for %s\n", debugstr_w(sig->Name)); - return ERROR_SUCCESS; - } - - fileName = msi_dup_record_field(row, 2); - section = msi_dup_record_field(row, 3); - key = msi_dup_record_field(row, 4); - field = MSI_RecordGetInteger(row, 5); - type = MSI_RecordGetInteger(row, 6); - if (field == MSI_NULL_INTEGER) - field = 0; - if (type == MSI_NULL_INTEGER) - type = 0; - - GetPrivateProfileStringW(section, key, NULL, buf, MAX_PATH, fileName); - if (buf[0]) - { - switch (type & 0x0f) - { - case msidbLocatorTypeDirectory: - ACTION_SearchDirectory(package, sig, buf, 0, appValue); - break; - case msidbLocatorTypeFileName: - *appValue = app_search_file(buf, sig); - break; - case msidbLocatorTypeRawValue: - *appValue = get_ini_field(buf, field); - break; - } - } - - msi_free(fileName); - msi_free(section); - msi_free(key); - - msiobj_release(&row->hdr); - - return ERROR_SUCCESS; -} - -/* Expands the value in src into a path without property names and only - * containing long path names into dst. Replaces at most len characters of dst, - * and always NULL-terminates dst if dst is not NULL and len >= 1. - * May modify src. - * Assumes src and dst are non-overlapping. - * FIXME: return code probably needed: - * - what does AppSearch return if the table values are invalid? - * - what if dst is too small? - */ -static void ACTION_ExpandAnyPath(MSIPACKAGE *package, WCHAR *src, WCHAR *dst, - size_t len) -{ - WCHAR *ptr, *deformatted; - - if (!src || !dst || !len) - { - if (dst) *dst = '\0'; - return; - } - - dst[0] = '\0'; - - /* Ignore the short portion of the path */ - if ((ptr = strchrW(src, '|'))) - ptr++; - else - ptr = src; - - deformat_string(package, ptr, &deformatted); - if (!deformatted || strlenW(deformatted) > len - 1) - { - msi_free(deformatted); - return; - } - - lstrcpyW(dst, deformatted); - dst[lstrlenW(deformatted)] = '\0'; - msi_free(deformatted); -} - -static LANGID *parse_languages( const WCHAR *languages, DWORD *num_ids ) -{ - UINT i, count = 1; - WCHAR *str = strdupW( languages ), *p, *q; - LANGID *ret; - - if (!str) return NULL; - for (p = q = str; (q = strchrW( q, ',' )); q++) count++; - - if (!(ret = msi_alloc( count * sizeof(LANGID) ))) - { - msi_free( str ); - return NULL; - } - i = 0; - while (*p) - { - q = strchrW( p, ',' ); - if (q) *q = 0; - ret[i] = atoiW( p ); - if (!q) break; - p = q + 1; - i++; - } - msi_free( str ); - *num_ids = count; - return ret; -} - -static BOOL match_languages( const void *version, const WCHAR *languages ) -{ - struct lang - { - USHORT id; - USHORT codepage; - } *lang; - DWORD len, num_ids, i, j; - BOOL found = FALSE; - LANGID *ids; - - if (!languages || !languages[0]) return TRUE; - if (!VerQueryValueW( version, szLangResource, (void **)&lang, &len )) return FALSE; - if (!(ids = parse_languages( languages, &num_ids ))) return FALSE; - - for (i = 0; i < num_ids; i++) - { - found = FALSE; - for (j = 0; j < len / sizeof(struct lang); j++) - { - if (!ids[i] || ids[i] == lang[j].id) found = TRUE; - } - if (!found) goto done; - } - -done: - msi_free( ids ); - return found; -} - -/* Sets *matches to whether the file (whose path is filePath) matches the - * versions set in sig. - * Return ERROR_SUCCESS in case of success (whether or not the file matches), - * something else if an install-halting error occurs. - */ -static UINT ACTION_FileVersionMatches(const MSISIGNATURE *sig, LPCWSTR filePath, - BOOL *matches) -{ - UINT len; - void *version; - VS_FIXEDFILEINFO *info = NULL; - DWORD zero, size = GetFileVersionInfoSizeW( filePath, &zero ); - - *matches = FALSE; - - if (!size) return ERROR_SUCCESS; - if (!(version = msi_alloc( size ))) return ERROR_OUTOFMEMORY; - - if (GetFileVersionInfoW( filePath, 0, size, version )) - VerQueryValueW( version, szBackSlash, (void **)&info, &len ); - - if (info) - { - TRACE("comparing file version %d.%d.%d.%d:\n", - HIWORD(info->dwFileVersionMS), - LOWORD(info->dwFileVersionMS), - HIWORD(info->dwFileVersionLS), - LOWORD(info->dwFileVersionLS)); - if (info->dwFileVersionMS < sig->MinVersionMS - || (info->dwFileVersionMS == sig->MinVersionMS && - info->dwFileVersionLS < sig->MinVersionLS)) - { - TRACE("less than minimum version %d.%d.%d.%d\n", - HIWORD(sig->MinVersionMS), - LOWORD(sig->MinVersionMS), - HIWORD(sig->MinVersionLS), - LOWORD(sig->MinVersionLS)); - } - else if ((sig->MaxVersionMS || sig->MaxVersionLS) && - (info->dwFileVersionMS > sig->MaxVersionMS || - (info->dwFileVersionMS == sig->MaxVersionMS && - info->dwFileVersionLS > sig->MaxVersionLS))) - { - TRACE("greater than maximum version %d.%d.%d.%d\n", - HIWORD(sig->MaxVersionMS), - LOWORD(sig->MaxVersionMS), - HIWORD(sig->MaxVersionLS), - LOWORD(sig->MaxVersionLS)); - } - else if (!match_languages( version, sig->Languages )) - { - TRACE("languages %s not supported\n", debugstr_w( sig->Languages )); - } - else *matches = TRUE; - } - msi_free( version ); - return ERROR_SUCCESS; -} - -/* Sets *matches to whether the file in findData matches that in sig. - * fullFilePath is assumed to be the full path of the file specified in - * findData, which may be necessary to compare the version. - * Return ERROR_SUCCESS in case of success (whether or not the file matches), - * something else if an install-halting error occurs. - */ -static UINT ACTION_FileMatchesSig(const MSISIGNATURE *sig, - const WIN32_FIND_DATAW *findData, LPCWSTR fullFilePath, BOOL *matches) -{ - UINT rc = ERROR_SUCCESS; - - *matches = TRUE; - /* assumes the caller has already ensured the filenames match, so check - * the other fields.. - */ - if (sig->MinTime.dwLowDateTime || sig->MinTime.dwHighDateTime) - { - if (findData->ftCreationTime.dwHighDateTime < - sig->MinTime.dwHighDateTime || - (findData->ftCreationTime.dwHighDateTime == sig->MinTime.dwHighDateTime - && findData->ftCreationTime.dwLowDateTime < - sig->MinTime.dwLowDateTime)) - *matches = FALSE; - } - if (*matches && (sig->MaxTime.dwLowDateTime || sig->MaxTime.dwHighDateTime)) - { - if (findData->ftCreationTime.dwHighDateTime > - sig->MaxTime.dwHighDateTime || - (findData->ftCreationTime.dwHighDateTime == sig->MaxTime.dwHighDateTime - && findData->ftCreationTime.dwLowDateTime > - sig->MaxTime.dwLowDateTime)) - *matches = FALSE; - } - if (*matches && sig->MinSize && findData->nFileSizeLow < sig->MinSize) - *matches = FALSE; - if (*matches && sig->MaxSize && findData->nFileSizeLow > sig->MaxSize) - *matches = FALSE; - if (*matches && (sig->MinVersionMS || sig->MinVersionLS || - sig->MaxVersionMS || sig->MaxVersionLS)) - rc = ACTION_FileVersionMatches(sig, fullFilePath, matches); - return rc; -} - -/* Recursively searches the directory dir for files that match the signature - * sig, up to (depth + 1) levels deep. That is, if depth is 0, it searches dir - * (and only dir). If depth is 1, searches dir and its immediate - * subdirectories. - * Assumes sig->File is not NULL. - * Returns ERROR_SUCCESS on success (which may include non-critical errors), - * something else on failures which should halt the install. - */ -static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, LPWSTR *appValue, - MSISIGNATURE *sig, LPCWSTR dir, int depth) -{ - HANDLE hFind; - WIN32_FIND_DATAW findData; - UINT rc = ERROR_SUCCESS; - size_t dirLen = lstrlenW(dir), fileLen = lstrlenW(sig->File); - WCHAR subpath[MAX_PATH]; - WCHAR *buf; - DWORD len; - - static const WCHAR starDotStarW[] = { '*','.','*',0 }; - - TRACE("Searching directory %s for file %s, depth %d\n", debugstr_w(dir), - debugstr_w(sig->File), depth); - - if (depth < 0) - return ERROR_SUCCESS; - - *appValue = NULL; - /* We need the buffer in both paths below, so go ahead and allocate it - * here. Add two because we might need to add a backslash if the dir name - * isn't backslash-terminated. - */ - len = dirLen + max(fileLen, strlenW(starDotStarW)) + 2; - buf = msi_alloc(len * sizeof(WCHAR)); - if (!buf) - return ERROR_OUTOFMEMORY; - - lstrcpyW(buf, dir); - PathAddBackslashW(buf); - lstrcatW(buf, sig->File); - - hFind = FindFirstFileW(buf, &findData); - if (hFind != INVALID_HANDLE_VALUE) - { - if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) - { - BOOL matches; - - rc = ACTION_FileMatchesSig(sig, &findData, buf, &matches); - if (rc == ERROR_SUCCESS && matches) - { - TRACE("found file, returning %s\n", debugstr_w(buf)); - *appValue = buf; - } - } - FindClose(hFind); - } - - if (rc == ERROR_SUCCESS && !*appValue) - { - lstrcpyW(buf, dir); - PathAddBackslashW(buf); - lstrcatW(buf, starDotStarW); - - hFind = FindFirstFileW(buf, &findData); - if (hFind != INVALID_HANDLE_VALUE) - { - if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && - strcmpW( findData.cFileName, szDot ) && - strcmpW( findData.cFileName, szDotDot )) - { - lstrcpyW(subpath, dir); - PathAppendW(subpath, findData.cFileName); - rc = ACTION_RecurseSearchDirectory(package, appValue, sig, - subpath, depth - 1); - } - - while (rc == ERROR_SUCCESS && !*appValue && - FindNextFileW(hFind, &findData) != 0) - { - if (!strcmpW( findData.cFileName, szDot ) || - !strcmpW( findData.cFileName, szDotDot )) - continue; - - lstrcpyW(subpath, dir); - PathAppendW(subpath, findData.cFileName); - if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - rc = ACTION_RecurseSearchDirectory(package, appValue, - sig, subpath, depth - 1); - } - - FindClose(hFind); - } - } - - if (*appValue != buf) - msi_free(buf); - - return rc; -} - -static UINT ACTION_CheckDirectory(MSIPACKAGE *package, LPCWSTR dir, - LPWSTR *appValue) -{ - DWORD attr = GetFileAttributesW(dir); - - if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY)) - { - TRACE("directory exists, returning %s\n", debugstr_w(dir)); - *appValue = strdupW(dir); - } - - return ERROR_SUCCESS; -} - -static BOOL ACTION_IsFullPath(LPCWSTR path) -{ - WCHAR first = toupperW(path[0]); - BOOL ret; - - if (first >= 'A' && first <= 'Z' && path[1] == ':') - ret = TRUE; - else if (path[0] == '\\' && path[1] == '\\') - ret = TRUE; - else - ret = FALSE; - return ret; -} - -static UINT ACTION_SearchDirectory(MSIPACKAGE *package, MSISIGNATURE *sig, - LPCWSTR path, int depth, LPWSTR *appValue) -{ - UINT rc; - DWORD attr; - LPWSTR val = NULL; - - TRACE("%p, %p, %s, %d, %p\n", package, sig, debugstr_w(path), depth, - appValue); - - if (ACTION_IsFullPath(path)) - { - if (sig->File) - rc = ACTION_RecurseSearchDirectory(package, &val, sig, path, depth); - else - { - /* Recursively searching a directory makes no sense when the - * directory to search is the thing you're trying to find. - */ - rc = ACTION_CheckDirectory(package, path, &val); - } - } - else - { - WCHAR pathWithDrive[MAX_PATH] = { 'C',':','\\',0 }; - DWORD drives = GetLogicalDrives(); - int i; - - rc = ERROR_SUCCESS; - for (i = 0; rc == ERROR_SUCCESS && !val && i < 26; i++) - { - if (!(drives & (1 << i))) - continue; - - pathWithDrive[0] = 'A' + i; - if (GetDriveTypeW(pathWithDrive) != DRIVE_FIXED) - continue; - - lstrcpynW(pathWithDrive + 3, path, - sizeof(pathWithDrive) / sizeof(pathWithDrive[0]) - 3); - - if (sig->File) - rc = ACTION_RecurseSearchDirectory(package, &val, sig, - pathWithDrive, depth); - else - rc = ACTION_CheckDirectory(package, pathWithDrive, &val); - } - } - - attr = GetFileAttributesW(val); - if (attr != INVALID_FILE_ATTRIBUTES && - (attr & FILE_ATTRIBUTE_DIRECTORY) && - val && val[lstrlenW(val) - 1] != '\\') - { - val = msi_realloc(val, (lstrlenW(val) + 2) * sizeof(WCHAR)); - if (!val) - rc = ERROR_OUTOFMEMORY; - else - PathAddBackslashW(val); - } - - *appValue = val; - - TRACE("returning %d\n", rc); - return rc; -} - -static UINT ACTION_AppSearchSigName(MSIPACKAGE *package, LPCWSTR sigName, - MSISIGNATURE *sig, LPWSTR *appValue); - -static UINT ACTION_AppSearchDr(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNATURE *sig) -{ - static const WCHAR query[] = { - 's','e','l','e','c','t',' ','*',' ', - 'f','r','o','m',' ', - 'D','r','L','o','c','a','t','o','r',' ', - 'w','h','e','r','e',' ', - 'S','i','g','n','a','t','u','r','e','_',' ','=',' ', '\'','%','s','\'',0}; - LPWSTR parent = NULL; - LPCWSTR parentName; - WCHAR path[MAX_PATH]; - WCHAR expanded[MAX_PATH]; - MSIRECORD *row; - int depth; - DWORD sz, attr; - UINT rc; - - TRACE("%s\n", debugstr_w(sig->Name)); - - *appValue = NULL; - - row = MSI_QueryGetRecord( package->db, query, sig->Name ); - if (!row) - { - TRACE("failed to query DrLocator for %s\n", debugstr_w(sig->Name)); - return ERROR_SUCCESS; - } - - /* check whether parent is set */ - parentName = MSI_RecordGetString(row, 2); - if (parentName) - { - MSISIGNATURE parentSig; - - ACTION_AppSearchSigName(package, parentName, &parentSig, &parent); - ACTION_FreeSignature(&parentSig); - if (!parent) - { - msiobj_release(&row->hdr); - return ERROR_SUCCESS; - } - } - - sz = MAX_PATH; - MSI_RecordGetStringW(row, 3, path, &sz); - - if (MSI_RecordIsNull(row,4)) - depth = 0; - else - depth = MSI_RecordGetInteger(row,4); - - if (sz) - ACTION_ExpandAnyPath(package, path, expanded, MAX_PATH); - else - strcpyW(expanded, path); - - if (parent) - { - attr = GetFileAttributesW(parent); - if (attr != INVALID_FILE_ATTRIBUTES && - !(attr & FILE_ATTRIBUTE_DIRECTORY)) - { - PathRemoveFileSpecW(parent); - PathAddBackslashW(parent); - } - - strcpyW(path, parent); - strcatW(path, expanded); - } - else if (sz) - strcpyW(path, expanded); - - PathAddBackslashW(path); - - rc = ACTION_SearchDirectory(package, sig, path, depth, appValue); - - msi_free(parent); - msiobj_release(&row->hdr); - - TRACE("returning %d\n", rc); - return rc; -} - -static UINT ACTION_AppSearchSigName(MSIPACKAGE *package, LPCWSTR sigName, - MSISIGNATURE *sig, LPWSTR *appValue) -{ - UINT rc; - - *appValue = NULL; - rc = ACTION_AppSearchGetSignature(package, sig, sigName); - if (rc == ERROR_SUCCESS) - { - rc = ACTION_AppSearchComponents(package, appValue, sig); - if (rc == ERROR_SUCCESS && !*appValue) - { - rc = ACTION_AppSearchReg(package, appValue, sig); - if (rc == ERROR_SUCCESS && !*appValue) - { - rc = ACTION_AppSearchIni(package, appValue, sig); - if (rc == ERROR_SUCCESS && !*appValue) - rc = ACTION_AppSearchDr(package, appValue, sig); - } - } - } - return rc; -} - -static UINT iterate_appsearch(MSIRECORD *row, LPVOID param) -{ - MSIPACKAGE *package = param; - LPCWSTR propName, sigName; - LPWSTR value = NULL; - MSISIGNATURE sig; - MSIRECORD *uirow; - UINT r; - - /* get property and signature */ - propName = MSI_RecordGetString(row, 1); - sigName = MSI_RecordGetString(row, 2); - - TRACE("%s %s\n", debugstr_w(propName), debugstr_w(sigName)); - - r = ACTION_AppSearchSigName(package, sigName, &sig, &value); - if (value) - { - r = msi_set_property( package->db, propName, value ); - if (r == ERROR_SUCCESS && !strcmpW( propName, szSourceDir )) - msi_reset_folders( package, TRUE ); - - msi_free(value); - } - ACTION_FreeSignature(&sig); - - uirow = MSI_CreateRecord( 2 ); - MSI_RecordSetStringW( uirow, 1, propName ); - MSI_RecordSetStringW( uirow, 2, sigName ); - msi_ui_actiondata( package, szAppSearch, uirow ); - msiobj_release( &uirow->hdr ); - - return r; -} - -UINT ACTION_AppSearch(MSIPACKAGE *package) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'A','p','p','S','e','a','r','c','h',0}; - MSIQUERY *view; - UINT r; - - if (msi_action_is_unique(package, szAppSearch)) - { - TRACE("Skipping AppSearch action: already done in UI sequence\n"); - return ERROR_SUCCESS; - } - else - msi_register_unique_action(package, szAppSearch); - - r = MSI_OpenQuery( package->db, &view, query ); - if (r != ERROR_SUCCESS) - return ERROR_SUCCESS; - - r = MSI_IterateRecords( view, NULL, iterate_appsearch, package ); - msiobj_release( &view->hdr ); - return r; -} - -static UINT ITERATE_CCPSearch(MSIRECORD *row, LPVOID param) -{ - MSIPACKAGE *package = param; - LPCWSTR signature; - LPWSTR value = NULL; - MSISIGNATURE sig; - UINT r = ERROR_SUCCESS; - - static const WCHAR success[] = {'C','C','P','_','S','u','c','c','e','s','s',0}; - - signature = MSI_RecordGetString(row, 1); - - TRACE("%s\n", debugstr_w(signature)); - - ACTION_AppSearchSigName(package, signature, &sig, &value); - if (value) - { - TRACE("Found signature %s\n", debugstr_w(signature)); - msi_set_property(package->db, success, szOne); - msi_free(value); - r = ERROR_NO_MORE_ITEMS; - } - - ACTION_FreeSignature(&sig); - - return r; -} - -UINT ACTION_CCPSearch(MSIPACKAGE *package) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'C','C','P','S','e','a','r','c','h',0}; - MSIQUERY *view; - UINT r; - - if (msi_action_is_unique(package, szCCPSearch)) - { - TRACE("Skipping AppSearch action: already done in UI sequence\n"); - return ERROR_SUCCESS; - } - else - msi_register_unique_action(package, szCCPSearch); - - r = MSI_OpenQuery(package->db, &view, query); - if (r != ERROR_SUCCESS) - return ERROR_SUCCESS; - - r = MSI_IterateRecords(view, NULL, ITERATE_CCPSearch, package); - msiobj_release(&view->hdr); - return r; -} diff --git a/libmsi/assembly.c b/libmsi/assembly.c deleted file mode 100644 index 2f321db..0000000 --- a/libmsi/assembly.c +++ /dev/null @@ -1,694 +0,0 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2010 Hans Leidekker for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include <stdarg.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "wine/debug.h" -#include "wine/unicode.h" -#include "msipriv.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -static HRESULT (WINAPI *pCreateAssemblyCacheNet10)( IAssemblyCache **, DWORD ); -static HRESULT (WINAPI *pCreateAssemblyCacheNet11)( IAssemblyCache **, DWORD ); -static HRESULT (WINAPI *pCreateAssemblyCacheNet20)( IAssemblyCache **, DWORD ); -static HRESULT (WINAPI *pCreateAssemblyCacheNet40)( IAssemblyCache **, DWORD ); -static HRESULT (WINAPI *pCreateAssemblyCacheSxs)( IAssemblyCache **, DWORD ); -static HRESULT (WINAPI *pLoadLibraryShim)( LPCWSTR, LPCWSTR, LPVOID, HMODULE * ); -static HRESULT (WINAPI *pGetFileVersion)( LPCWSTR, LPWSTR, DWORD, DWORD * ); - -static HMODULE hfusion10, hfusion11, hfusion20, hfusion40, hmscoree, hsxs; - -static BOOL init_function_pointers( void ) -{ - static const WCHAR szFusion[] = {'f','u','s','i','o','n','.','d','l','l',0}; - static const WCHAR szMscoree[] = {'\\','m','s','c','o','r','e','e','.','d','l','l',0}; - static const WCHAR szSxs[] = {'s','x','s','.','d','l','l',0}; - static const WCHAR szVersion10[] = {'v','1','.','0','.','3','7','0','5',0}; - static const WCHAR szVersion11[] = {'v','1','.','1','.','4','3','2','2',0}; - static const WCHAR szVersion20[] = {'v','2','.','0','.','5','0','7','2','7',0}; - static const WCHAR szVersion40[] = {'v','4','.','0','.','3','0','3','1','9',0}; - WCHAR path[MAX_PATH]; - DWORD len = GetSystemDirectoryW( path, MAX_PATH ); - - if (!hsxs && !(hsxs = LoadLibraryW( szSxs ))) return FALSE; - if (!(pCreateAssemblyCacheSxs = (void *)GetProcAddress( hsxs, "CreateAssemblyCache" ))) - { - FreeLibrary( hsxs ); - hsxs = NULL; - return FALSE; - } - strcpyW( path + len, szMscoree ); - if (hmscoree || !(hmscoree = LoadLibraryW( path ))) return TRUE; - pGetFileVersion = (void *)GetProcAddress( hmscoree, "GetFileVersion" ); /* missing from v1.0.3705 */ - if (!(pLoadLibraryShim = (void *)GetProcAddress( hmscoree, "LoadLibraryShim" ))) - { - FreeLibrary( hmscoree ); - hmscoree = NULL; - return TRUE; - } - if (!pLoadLibraryShim( szFusion, szVersion10, NULL, &hfusion10 )) - pCreateAssemblyCacheNet10 = (void *)GetProcAddress( hfusion10, "CreateAssemblyCache" ); - - if (!pLoadLibraryShim( szFusion, szVersion11, NULL, &hfusion11 )) - pCreateAssemblyCacheNet11 = (void *)GetProcAddress( hfusion11, "CreateAssemblyCache" ); - - if (!pLoadLibraryShim( szFusion, szVersion20, NULL, &hfusion20 )) - pCreateAssemblyCacheNet20 = (void *)GetProcAddress( hfusion20, "CreateAssemblyCache" ); - - if (!pLoadLibraryShim( szFusion, szVersion40, NULL, &hfusion40 )) - pCreateAssemblyCacheNet40 = (void *)GetProcAddress( hfusion40, "CreateAssemblyCache" ); - - return TRUE; -} - -BOOL msi_init_assembly_caches( MSIPACKAGE *package ) -{ - if (!init_function_pointers()) return FALSE; - if (pCreateAssemblyCacheSxs( &package->cache_sxs, 0 ) != S_OK) return FALSE; - if (pCreateAssemblyCacheNet10) pCreateAssemblyCacheNet10( &package->cache_net[CLR_VERSION_V10], 0 ); - if (pCreateAssemblyCacheNet11) pCreateAssemblyCacheNet11( &package->cache_net[CLR_VERSION_V11], 0 ); - if (pCreateAssemblyCacheNet20) pCreateAssemblyCacheNet20( &package->cache_net[CLR_VERSION_V20], 0 ); - if (pCreateAssemblyCacheNet40) pCreateAssemblyCacheNet40( &package->cache_net[CLR_VERSION_V40], 0 ); - return TRUE; -} - -void msi_destroy_assembly_caches( MSIPACKAGE *package ) -{ - UINT i; - - if (package->cache_sxs) - { - IAssemblyCache_Release( package->cache_sxs ); - package->cache_sxs = NULL; - } - for (i = 0; i < CLR_VERSION_MAX; i++) - { - if (package->cache_net[i]) - { - IAssemblyCache_Release( package->cache_net[i] ); - package->cache_net[i] = NULL; - } - } - pCreateAssemblyCacheNet10 = NULL; - pCreateAssemblyCacheNet11 = NULL; - pCreateAssemblyCacheNet20 = NULL; - pCreateAssemblyCacheNet40 = NULL; - FreeLibrary( hfusion10 ); - FreeLibrary( hfusion11 ); - FreeLibrary( hfusion20 ); - FreeLibrary( hfusion40 ); - FreeLibrary( hmscoree ); - FreeLibrary( hsxs ); - hfusion10 = NULL; - hfusion11 = NULL; - hfusion20 = NULL; - hfusion40 = NULL; - hmscoree = NULL; - hsxs = NULL; -} - -static MSIRECORD *get_assembly_record( MSIPACKAGE *package, const WCHAR *comp ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','M','s','i','A','s','s','e','m','b','l','y','`',' ', - 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`', - ' ','=',' ','\'','%','s','\'',0}; - MSIQUERY *view; - MSIRECORD *rec; - UINT r; - - r = MSI_OpenQuery( package->db, &view, query, comp ); - if (r != ERROR_SUCCESS) - return NULL; - - r = MSI_ViewExecute( view, NULL ); - if (r != ERROR_SUCCESS) - { - msiobj_release( &view->hdr ); - return NULL; - } - r = MSI_ViewFetch( view, &rec ); - if (r != ERROR_SUCCESS) - { - msiobj_release( &view->hdr ); - return NULL; - } - if (!MSI_RecordGetString( rec, 4 )) - TRACE("component is a global assembly\n"); - - msiobj_release( &view->hdr ); - return rec; -} - -struct assembly_name -{ - UINT count; - UINT index; - WCHAR **attrs; -}; - -static UINT get_assembly_name_attribute( MSIRECORD *rec, LPVOID param ) -{ - static const WCHAR fmtW[] = {'%','s','=','"','%','s','"',0}; - static const WCHAR nameW[] = {'n','a','m','e',0}; - struct assembly_name *name = param; - const WCHAR *attr = MSI_RecordGetString( rec, 2 ); - const WCHAR *value = MSI_RecordGetString( rec, 3 ); - int len = strlenW( fmtW ) + strlenW( attr ) + strlenW( value ); - - if (!(name->attrs[name->index] = msi_alloc( len * sizeof(WCHAR) ))) - return ERROR_OUTOFMEMORY; - - if (!strcmpiW( attr, nameW )) strcpyW( name->attrs[name->index++], value ); - else sprintfW( name->attrs[name->index++], fmtW, attr, value ); - return ERROR_SUCCESS; -} - -static WCHAR *get_assembly_display_name( MSIDATABASE *db, const WCHAR *comp, MSIASSEMBLY *assembly ) -{ - static const WCHAR commaW[] = {',',0}; - static const WCHAR queryW[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','M','s','i','A','s','s','e','m','b','l','y','N','a','m','e','`',' ', - 'W','H','E','R','E',' ','`','C','o','m','p','o','n','e','n','t','_','`', - ' ','=',' ','\'','%','s','\'',0}; - struct assembly_name name; - WCHAR *display_name = NULL; - MSIQUERY *view; - UINT i, r; - int len; - - r = MSI_OpenQuery( db, &view, queryW, comp ); - if (r != ERROR_SUCCESS) - return NULL; - - name.count = 0; - name.index = 0; - name.attrs = NULL; - MSI_IterateRecords( view, &name.count, NULL, NULL ); - if (!name.count) goto done; - - name.attrs = msi_alloc( name.count * sizeof(WCHAR *) ); - if (!name.attrs) goto done; - - MSI_IterateRecords( view, NULL, get_assembly_name_attribute, &name ); - - len = 0; - for (i = 0; i < name.count; i++) len += strlenW( name.attrs[i] ) + 1; - - display_name = msi_alloc( (len + 1) * sizeof(WCHAR) ); - if (display_name) - { - display_name[0] = 0; - for (i = 0; i < name.count; i++) - { - strcatW( display_name, name.attrs[i] ); - if (i < name.count - 1) strcatW( display_name, commaW ); - } - } - -done: - msiobj_release( &view->hdr ); - if (name.attrs) - { - for (i = 0; i < name.count; i++) msi_free( name.attrs[i] ); - msi_free( name.attrs ); - } - return display_name; -} - -static BOOL is_assembly_installed( IAssemblyCache *cache, const WCHAR *display_name ) -{ - HRESULT hr; - ASSEMBLY_INFO info; - - if (!cache) return FALSE; - - memset( &info, 0, sizeof(info) ); - info.cbAssemblyInfo = sizeof(info); - hr = IAssemblyCache_QueryAssemblyInfo( cache, 0, display_name, &info ); - if (hr == S_OK /* sxs version */ || hr == HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER )) - { - return (info.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED); - } - TRACE("QueryAssemblyInfo returned 0x%08x\n", hr); - return FALSE; -} - -static const WCHAR clr_version_v10[] = {'v','1','.','0','.','3','7','0','5',0}; -static const WCHAR clr_version_v11[] = {'v','1','.','1','.','4','3','2','2',0}; -static const WCHAR clr_version_v20[] = {'v','2','.','0','.','5','0','7','2','7',0}; -static const WCHAR clr_version_v40[] = {'v','4','.','0','.','3','0','3','1','9',0}; -static const WCHAR clr_version_unknown[] = {'u','n','k','n','o','w','n',0}; - -static const WCHAR *clr_version[] = -{ - clr_version_v10, - clr_version_v11, - clr_version_v20, - clr_version_v40 -}; - -static const WCHAR *get_clr_version_str( enum clr_version version ) -{ - if (version >= sizeof(clr_version)/sizeof(clr_version[0])) return clr_version_unknown; - return clr_version[version]; -} - -/* assembly caches must be initialized */ -MSIASSEMBLY *msi_load_assembly( MSIPACKAGE *package, MSICOMPONENT *comp ) -{ - MSIRECORD *rec; - MSIASSEMBLY *a; - - if (!(rec = get_assembly_record( package, comp->Component ))) return NULL; - if (!(a = msi_alloc_zero( sizeof(MSIASSEMBLY) ))) - { - msiobj_release( &rec->hdr ); - return NULL; - } - a->feature = strdupW( MSI_RecordGetString( rec, 2 ) ); - TRACE("feature %s\n", debugstr_w(a->feature)); - - a->manifest = strdupW( MSI_RecordGetString( rec, 3 ) ); - TRACE("manifest %s\n", debugstr_w(a->manifest)); - - a->application = strdupW( MSI_RecordGetString( rec, 4 ) ); - TRACE("application %s\n", debugstr_w(a->application)); - - a->attributes = MSI_RecordGetInteger( rec, 5 ); - TRACE("attributes %u\n", a->attributes); - - if (!(a->display_name = get_assembly_display_name( package->db, comp->Component, a ))) - { - WARN("can't get display name\n"); - msiobj_release( &rec->hdr ); - msi_free( a->feature ); - msi_free( a->manifest ); - msi_free( a->application ); - msi_free( a ); - return NULL; - } - TRACE("display name %s\n", debugstr_w(a->display_name)); - - if (a->application) - { - /* We can't check the manifest here because the target path may still change. - So we assume that the assembly is not installed and lean on the InstallFiles - action to determine which files need to be installed. - */ - a->installed = FALSE; - } - else - { - if (a->attributes == msidbAssemblyAttributesWin32) - a->installed = is_assembly_installed( package->cache_sxs, a->display_name ); - else - { - UINT i; - for (i = 0; i < CLR_VERSION_MAX; i++) - { - a->clr_version[i] = is_assembly_installed( package->cache_net[i], a->display_name ); - if (a->clr_version[i]) - { - TRACE("runtime version %s\n", debugstr_w(get_clr_version_str( i ))); - a->installed = TRUE; - break; - } - } - } - } - TRACE("assembly is %s\n", a->installed ? "installed" : "not installed"); - msiobj_release( &rec->hdr ); - return a; -} - -static enum clr_version get_clr_version( const WCHAR *filename ) -{ - DWORD len; - HRESULT hr; - enum clr_version version = CLR_VERSION_V11; - WCHAR *strW; - - if (!pGetFileVersion) return CLR_VERSION_V10; - - hr = pGetFileVersion( filename, NULL, 0, &len ); - if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) return CLR_VERSION_V11; - if ((strW = msi_alloc( len * sizeof(WCHAR) ))) - { - hr = pGetFileVersion( filename, strW, len, &len ); - if (hr == S_OK) - { - UINT i; - for (i = 0; i < CLR_VERSION_MAX; i++) - if (!strcmpW( strW, clr_version[i] )) version = i; - } - msi_free( strW ); - } - return version; -} - -UINT msi_install_assembly( MSIPACKAGE *package, MSICOMPONENT *comp ) -{ - HRESULT hr; - const WCHAR *manifest; - IAssemblyCache *cache; - MSIASSEMBLY *assembly = comp->assembly; - MSIFEATURE *feature = NULL; - - if (comp->assembly->feature) - feature = msi_get_loaded_feature( package, comp->assembly->feature ); - - if (assembly->application) - { - if (feature) feature->Action = INSTALLSTATE_LOCAL; - return ERROR_SUCCESS; - } - if (assembly->attributes == msidbAssemblyAttributesWin32) - { - if (!assembly->manifest) - { - WARN("no manifest\n"); - return ERROR_FUNCTION_FAILED; - } - manifest = msi_get_loaded_file( package, assembly->manifest )->TargetPath; - cache = package->cache_sxs; - } - else - { - manifest = msi_get_loaded_file( package, comp->KeyPath )->TargetPath; - cache = package->cache_net[get_clr_version( manifest )]; - if (!cache) return ERROR_SUCCESS; - } - TRACE("installing assembly %s\n", debugstr_w(manifest)); - - hr = IAssemblyCache_InstallAssembly( cache, 0, manifest, NULL ); - if (hr != S_OK) - { - ERR("Failed to install assembly %s (0x%08x)\n", debugstr_w(manifest), hr); - return ERROR_FUNCTION_FAILED; - } - if (feature) feature->Action = INSTALLSTATE_LOCAL; - assembly->installed = TRUE; - return ERROR_SUCCESS; -} - -UINT msi_uninstall_assembly( MSIPACKAGE *package, MSICOMPONENT *comp ) -{ - HRESULT hr; - IAssemblyCache *cache; - MSIASSEMBLY *assembly = comp->assembly; - MSIFEATURE *feature = NULL; - - if (comp->assembly->feature) - feature = msi_get_loaded_feature( package, comp->assembly->feature ); - - if (assembly->application) - { - if (feature) feature->Action = INSTALLSTATE_ABSENT; - return ERROR_SUCCESS; - } - TRACE("removing %s\n", debugstr_w(assembly->display_name)); - - if (assembly->attributes == msidbAssemblyAttributesWin32) - { - cache = package->cache_sxs; - hr = IAssemblyCache_UninstallAssembly( cache, 0, assembly->display_name, NULL, NULL ); - if (FAILED( hr )) WARN("failed to uninstall assembly 0x%08x\n", hr); - } - else - { - unsigned int i; - for (i = 0; i < CLR_VERSION_MAX; i++) - { - if (!assembly->clr_version[i]) continue; - cache = package->cache_net[i]; - if (cache) - { - hr = IAssemblyCache_UninstallAssembly( cache, 0, assembly->display_name, NULL, NULL ); - if (FAILED( hr )) WARN("failed to uninstall assembly 0x%08x\n", hr); - } - } - } - if (feature) feature->Action = INSTALLSTATE_ABSENT; - assembly->installed = FALSE; - return ERROR_SUCCESS; -} - -static WCHAR *build_local_assembly_path( const WCHAR *filename ) -{ - UINT i; - WCHAR *ret; - - if (!(ret = msi_alloc( (strlenW( filename ) + 1) * sizeof(WCHAR) ))) - return NULL; - - for (i = 0; filename[i]; i++) - { - if (filename[i] == '\\' || filename[i] == '/') ret[i] = '|'; - else ret[i] = filename[i]; - } - ret[i] = 0; - return ret; -} - -static LONG open_assemblies_key( UINT context, BOOL win32, HKEY *hkey ) -{ - static const WCHAR path_win32[] = - {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', - 'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',0}; - static const WCHAR path_dotnet[] = - {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', - 'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',0}; - static const WCHAR classes_path_win32[] = - {'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\',0}; - static const WCHAR classes_path_dotnet[] = - {'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\',0}; - HKEY root; - const WCHAR *path; - - if (context == MSIINSTALLCONTEXT_MACHINE) - { - root = HKEY_CLASSES_ROOT; - if (win32) path = classes_path_win32; - else path = classes_path_dotnet; - } - else - { - root = HKEY_CURRENT_USER; - if (win32) path = path_win32; - else path = path_dotnet; - } - return RegCreateKeyW( root, path, hkey ); -} - -static LONG open_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename, HKEY *hkey ) -{ - LONG res; - HKEY root; - WCHAR *path; - - if (!(path = build_local_assembly_path( filename ))) - return ERROR_OUTOFMEMORY; - - if ((res = open_assemblies_key( context, win32, &root ))) - { - msi_free( path ); - return res; - } - res = RegCreateKeyW( root, path, hkey ); - RegCloseKey( root ); - msi_free( path ); - return res; -} - -static LONG delete_local_assembly_key( UINT context, BOOL win32, const WCHAR *filename ) -{ - LONG res; - HKEY root; - WCHAR *path; - - if (!(path = build_local_assembly_path( filename ))) - return ERROR_OUTOFMEMORY; - - if ((res = open_assemblies_key( context, win32, &root ))) - { - msi_free( path ); - return res; - } - res = RegDeleteKeyW( root, path ); - RegCloseKey( root ); - msi_free( path ); - return res; -} - -static LONG open_global_assembly_key( UINT context, BOOL win32, HKEY *hkey ) -{ - static const WCHAR path_win32[] = - {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', - 'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\', - 'G','l','o','b','a','l',0}; - static const WCHAR path_dotnet[] = - {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', - 'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\', - 'G','l','o','b','a','l',0}; - static const WCHAR classes_path_win32[] = - {'I','n','s','t','a','l','l','e','r','\\','W','i','n','3','2','A','s','s','e','m','b','l','i','e','s','\\', - 'G','l','o','b','a','l',0}; - static const WCHAR classes_path_dotnet[] = - {'I','n','s','t','a','l','l','e','r','\\','A','s','s','e','m','b','l','i','e','s','\\','G','l','o','b','a','l',0}; - HKEY root; - const WCHAR *path; - - if (context == MSIINSTALLCONTEXT_MACHINE) - { - root = HKEY_CLASSES_ROOT; - if (win32) path = classes_path_win32; - else path = classes_path_dotnet; - } - else - { - root = HKEY_CURRENT_USER; - if (win32) path = path_win32; - else path = path_dotnet; - } - return RegCreateKeyW( root, path, hkey ); -} - -UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package ) -{ - MSICOMPONENT *comp; - - LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry) - { - LONG res; - HKEY hkey; - GUID guid; - DWORD size; - WCHAR buffer[43]; - MSIRECORD *uirow; - MSIASSEMBLY *assembly = comp->assembly; - BOOL win32; - - if (!assembly || !comp->ComponentId) continue; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_LOCAL) - { - TRACE("component not scheduled for installation %s\n", debugstr_w(comp->Component)); - continue; - } - TRACE("publishing %s\n", debugstr_w(comp->Component)); - - CLSIDFromString( package->ProductCode, &guid ); - encode_base85_guid( &guid, buffer ); - buffer[20] = '>'; - CLSIDFromString( comp->ComponentId, &guid ); - encode_base85_guid( &guid, buffer + 21 ); - buffer[42] = 0; - - win32 = assembly->attributes & msidbAssemblyAttributesWin32; - if (assembly->application) - { - MSIFILE *file = msi_get_loaded_file( package, assembly->application ); - if ((res = open_local_assembly_key( package->Context, win32, file->TargetPath, &hkey ))) - { - WARN("failed to open local assembly key %d\n", res); - return ERROR_FUNCTION_FAILED; - } - } - else - { - if ((res = open_global_assembly_key( package->Context, win32, &hkey ))) - { - WARN("failed to open global assembly key %d\n", res); - return ERROR_FUNCTION_FAILED; - } - } - size = sizeof(buffer); - if ((res = RegSetValueExW( hkey, assembly->display_name, 0, REG_MULTI_SZ, (const BYTE *)buffer, size ))) - { - WARN("failed to set assembly value %d\n", res); - } - RegCloseKey( hkey ); - - uirow = MSI_CreateRecord( 2 ); - MSI_RecordSetStringW( uirow, 2, assembly->display_name ); - msi_ui_actiondata( package, szMsiPublishAssemblies, uirow ); - msiobj_release( &uirow->hdr ); - } - return ERROR_SUCCESS; -} - -UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package ) -{ - MSICOMPONENT *comp; - - LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry) - { - LONG res; - MSIRECORD *uirow; - MSIASSEMBLY *assembly = comp->assembly; - BOOL win32; - - if (!assembly || !comp->ComponentId) continue; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_ABSENT) - { - TRACE("component not scheduled for removal %s\n", debugstr_w(comp->Component)); - continue; - } - TRACE("unpublishing %s\n", debugstr_w(comp->Component)); - - win32 = assembly->attributes & msidbAssemblyAttributesWin32; - if (assembly->application) - { - MSIFILE *file = msi_get_loaded_file( package, assembly->application ); - if ((res = delete_local_assembly_key( package->Context, win32, file->TargetPath ))) - WARN("failed to delete local assembly key %d\n", res); - } - else - { - HKEY hkey; - if ((res = open_global_assembly_key( package->Context, win32, &hkey ))) - WARN("failed to delete global assembly key %d\n", res); - else - { - if ((res = RegDeleteValueW( hkey, assembly->display_name ))) - WARN("failed to delete global assembly value %d\n", res); - RegCloseKey( hkey ); - } - } - - uirow = MSI_CreateRecord( 2 ); - MSI_RecordSetStringW( uirow, 2, assembly->display_name ); - msi_ui_actiondata( package, szMsiPublishAssemblies, uirow ); - msiobj_release( &uirow->hdr ); - } - return ERROR_SUCCESS; -} diff --git a/libmsi/classes.c b/libmsi/classes.c deleted file mode 100644 index c3ec34b..0000000 --- a/libmsi/classes.c +++ /dev/null @@ -1,1565 +0,0 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2005 Aric Stewart for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/* Actions handled in this module: - * - * RegisterClassInfo - * RegisterProgIdInfo - * RegisterExtensionInfo - * RegisterMIMEInfo - * UnregisterClassInfo - * UnregisterProgIdInfo - * UnregisterExtensionInfo - * UnregisterMIMEInfo - */ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winreg.h" -#include "wine/debug.h" -#include "msipriv.h" -#include "wingdi.h" -#include "winuser.h" -#include "wine/unicode.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -static MSIAPPID *load_appid( MSIPACKAGE* package, MSIRECORD *row ) -{ - LPCWSTR buffer; - MSIAPPID *appid; - - /* fill in the data */ - - appid = msi_alloc_zero( sizeof(MSIAPPID) ); - if (!appid) - return NULL; - - appid->AppID = msi_dup_record_field( row, 1 ); - TRACE("loading appid %s\n", debugstr_w( appid->AppID )); - - buffer = MSI_RecordGetString(row,2); - deformat_string( package, buffer, &appid->RemoteServerName ); - - appid->LocalServer = msi_dup_record_field(row,3); - appid->ServiceParameters = msi_dup_record_field(row,4); - appid->DllSurrogate = msi_dup_record_field(row,5); - - appid->ActivateAtStorage = !MSI_RecordIsNull(row,6); - appid->RunAsInteractiveUser = !MSI_RecordIsNull(row,7); - - list_add_tail( &package->appids, &appid->entry ); - - return appid; -} - -static MSIAPPID *load_given_appid( MSIPACKAGE *package, LPCWSTR name ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','A','p','p','I','d','`',' ','W','H','E','R','E',' ', - '`','A','p','p','I','d','`',' ','=',' ','\'','%','s','\'',0}; - MSIRECORD *row; - MSIAPPID *appid; - - if (!name) - return NULL; - - /* check for appids already loaded */ - LIST_FOR_EACH_ENTRY( appid, &package->appids, MSIAPPID, entry ) - { - if (!strcmpiW( appid->AppID, name )) - { - TRACE("found appid %s %p\n", debugstr_w(name), appid); - return appid; - } - } - - row = MSI_QueryGetRecord(package->db, query, name); - if (!row) - return NULL; - - appid = load_appid(package, row); - msiobj_release(&row->hdr); - return appid; -} - -static MSIPROGID *load_given_progid(MSIPACKAGE *package, LPCWSTR progid); -static MSICLASS *load_given_class( MSIPACKAGE *package, LPCWSTR classid ); - -static MSIPROGID *load_progid( MSIPACKAGE* package, MSIRECORD *row ) -{ - MSIPROGID *progid; - LPCWSTR buffer; - - /* fill in the data */ - - progid = msi_alloc_zero( sizeof(MSIPROGID) ); - if (!progid) - return NULL; - - list_add_tail( &package->progids, &progid->entry ); - - progid->ProgID = msi_dup_record_field(row,1); - TRACE("loading progid %s\n",debugstr_w(progid->ProgID)); - - buffer = MSI_RecordGetString(row,2); - progid->Parent = load_given_progid(package,buffer); - if (progid->Parent == NULL && buffer) - FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer)); - - buffer = MSI_RecordGetString(row,3); - progid->Class = load_given_class(package,buffer); - if (progid->Class == NULL && buffer) - FIXME("Unknown class %s\n",debugstr_w(buffer)); - - progid->Description = msi_dup_record_field(row,4); - - if (!MSI_RecordIsNull(row,6)) - { - INT icon_index = MSI_RecordGetInteger(row,6); - LPCWSTR FileName = MSI_RecordGetString(row,5); - LPWSTR FilePath; - static const WCHAR fmt[] = {'%','s',',','%','i',0}; - - FilePath = msi_build_icon_path(package, FileName); - - progid->IconPath = msi_alloc( (strlenW(FilePath)+10)* sizeof(WCHAR) ); - - sprintfW(progid->IconPath,fmt,FilePath,icon_index); - - msi_free(FilePath); - } - else - { - buffer = MSI_RecordGetString(row,5); - if (buffer) - progid->IconPath = msi_build_icon_path(package, buffer); - } - - progid->CurVer = NULL; - progid->VersionInd = NULL; - - /* if we have a parent then we may be that parents CurVer */ - if (progid->Parent && progid->Parent != progid) - { - MSIPROGID *parent = progid->Parent; - - while (parent->Parent && parent->Parent != parent) - parent = parent->Parent; - - /* FIXME: need to determine if we are really the CurVer */ - - progid->CurVer = parent; - parent->VersionInd = progid; - } - - return progid; -} - -static MSIPROGID *load_given_progid(MSIPACKAGE *package, LPCWSTR name) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','P','r','o','g','I','d','`',' ','W','H','E','R','E',' ', - '`','P','r','o','g','I','d','`',' ','=',' ','\'','%','s','\'',0}; - MSIPROGID *progid; - MSIRECORD *row; - - if (!name) - return NULL; - - /* check for progids already loaded */ - LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry ) - { - if (!strcmpiW( progid->ProgID, name )) - { - TRACE("found progid %s (%p)\n",debugstr_w(name), progid ); - return progid; - } - } - - row = MSI_QueryGetRecord( package->db, query, name ); - if (!row) - return NULL; - - progid = load_progid(package, row); - msiobj_release(&row->hdr); - return progid; -} - -static MSICLASS *load_class( MSIPACKAGE* package, MSIRECORD *row ) -{ - MSICLASS *cls; - DWORD i; - LPCWSTR buffer; - - /* fill in the data */ - - cls = msi_alloc_zero( sizeof(MSICLASS) ); - if (!cls) - return NULL; - - list_add_tail( &package->classes, &cls->entry ); - - cls->clsid = msi_dup_record_field( row, 1 ); - TRACE("loading class %s\n",debugstr_w(cls->clsid)); - cls->Context = msi_dup_record_field( row, 2 ); - buffer = MSI_RecordGetString(row,3); - cls->Component = msi_get_loaded_component( package, buffer ); - - cls->ProgIDText = msi_dup_record_field(row,4); - cls->ProgID = load_given_progid(package, cls->ProgIDText); - - cls->Description = msi_dup_record_field(row,5); - - buffer = MSI_RecordGetString(row,6); - if (buffer) - cls->AppID = load_given_appid(package, buffer); - - cls->FileTypeMask = msi_dup_record_field(row,7); - - if (!MSI_RecordIsNull(row,9)) - { - - INT icon_index = MSI_RecordGetInteger(row,9); - LPCWSTR FileName = MSI_RecordGetString(row,8); - LPWSTR FilePath; - static const WCHAR fmt[] = {'%','s',',','%','i',0}; - - FilePath = msi_build_icon_path(package, FileName); - - cls->IconPath = msi_alloc( (strlenW(FilePath)+5)* sizeof(WCHAR) ); - - sprintfW(cls->IconPath,fmt,FilePath,icon_index); - - msi_free(FilePath); - } - else - { - buffer = MSI_RecordGetString(row,8); - if (buffer) - cls->IconPath = msi_build_icon_path(package, buffer); - } - - if (!MSI_RecordIsNull(row,10)) - { - i = MSI_RecordGetInteger(row,10); - if (i != MSI_NULL_INTEGER && i > 0 && i < 4) - { - static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0}; - static const WCHAR ole32[] = {'o','l','e','3','2','.','d','l','l',0}; - - switch(i) - { - case 1: - cls->DefInprocHandler = strdupW(ole2); - break; - case 2: - cls->DefInprocHandler32 = strdupW(ole32); - break; - case 3: - cls->DefInprocHandler = strdupW(ole2); - cls->DefInprocHandler32 = strdupW(ole32); - break; - } - } - else - { - cls->DefInprocHandler32 = msi_dup_record_field( row, 10 ); - msi_reduce_to_long_filename( cls->DefInprocHandler32 ); - } - } - buffer = MSI_RecordGetString(row,11); - deformat_string(package,buffer,&cls->Argument); - - buffer = MSI_RecordGetString(row,12); - cls->Feature = msi_get_loaded_feature(package, buffer); - - cls->Attributes = MSI_RecordGetInteger(row,13); - - return cls; -} - -/* - * the Class table has 3 primary keys. Generally it is only - * referenced through the first CLSID key. However when loading - * all of the classes we need to make sure we do not ignore rows - * with other Context and ComponentIndexs - */ -static MSICLASS *load_given_class(MSIPACKAGE *package, LPCWSTR classid) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','C','l','a','s','s','`',' ','W','H','E','R','E',' ', - '`','C','L','S','I','D','`',' ','=',' ','\'','%','s','\'',0}; - MSICLASS *cls; - MSIRECORD *row; - - if (!classid) - return NULL; - - /* check for classes already loaded */ - LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry ) - { - if (!strcmpiW( cls->clsid, classid )) - { - TRACE("found class %s (%p)\n",debugstr_w(classid), cls); - return cls; - } - } - - row = MSI_QueryGetRecord(package->db, query, classid); - if (!row) - return NULL; - - cls = load_class(package, row); - msiobj_release(&row->hdr); - return cls; -} - -static MSIEXTENSION *load_given_extension( MSIPACKAGE *package, LPCWSTR extension ); - -static MSIMIME *load_mime( MSIPACKAGE* package, MSIRECORD *row ) -{ - LPCWSTR extension; - MSIMIME *mt; - - /* fill in the data */ - - mt = msi_alloc_zero( sizeof(MSIMIME) ); - if (!mt) - return mt; - - mt->ContentType = msi_dup_record_field( row, 1 ); - TRACE("loading mime %s\n", debugstr_w(mt->ContentType)); - - extension = MSI_RecordGetString( row, 2 ); - mt->Extension = load_given_extension( package, extension ); - mt->suffix = strdupW( extension ); - - mt->clsid = msi_dup_record_field( row, 3 ); - mt->Class = load_given_class( package, mt->clsid ); - - list_add_tail( &package->mimes, &mt->entry ); - - return mt; -} - -static MSIMIME *load_given_mime( MSIPACKAGE *package, LPCWSTR mime ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','M','I','M','E','`',' ','W','H','E','R','E',' ', - '`','C','o','n','t','e','n','t','T','y','p','e','`',' ','=',' ','\'','%','s','\'',0}; - MSIRECORD *row; - MSIMIME *mt; - - if (!mime) - return NULL; - - /* check for mime already loaded */ - LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry ) - { - if (!strcmpiW( mt->ContentType, mime )) - { - TRACE("found mime %s (%p)\n",debugstr_w(mime), mt); - return mt; - } - } - - row = MSI_QueryGetRecord(package->db, query, mime); - if (!row) - return NULL; - - mt = load_mime(package, row); - msiobj_release(&row->hdr); - return mt; -} - -static MSIEXTENSION *load_extension( MSIPACKAGE* package, MSIRECORD *row ) -{ - MSIEXTENSION *ext; - LPCWSTR buffer; - - /* fill in the data */ - - ext = msi_alloc_zero( sizeof(MSIEXTENSION) ); - if (!ext) - return NULL; - - list_init( &ext->verbs ); - - list_add_tail( &package->extensions, &ext->entry ); - - ext->Extension = msi_dup_record_field( row, 1 ); - TRACE("loading extension %s\n", debugstr_w(ext->Extension)); - - buffer = MSI_RecordGetString( row, 2 ); - ext->Component = msi_get_loaded_component( package, buffer ); - - ext->ProgIDText = msi_dup_record_field( row, 3 ); - ext->ProgID = load_given_progid( package, ext->ProgIDText ); - - buffer = MSI_RecordGetString( row, 4 ); - ext->Mime = load_given_mime( package, buffer ); - - buffer = MSI_RecordGetString(row,5); - ext->Feature = msi_get_loaded_feature( package, buffer ); - - return ext; -} - -/* - * While the extension table has 2 primary keys, this function is only looking - * at the Extension key which is what is referenced as a foreign key - */ -static MSIEXTENSION *load_given_extension( MSIPACKAGE *package, LPCWSTR name ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','E','x','t','e','n','s','i','o','n','`',' ','W','H','E','R','E',' ', - '`','E','x','t','e','n','s','i','o','n','`',' ','=',' ','\'','%','s','\'',0}; - MSIEXTENSION *ext; - MSIRECORD *row; - - if (!name) - return NULL; - - if (name[0] == '.') - name++; - - /* check for extensions already loaded */ - LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry ) - { - if (!strcmpiW( ext->Extension, name )) - { - TRACE("extension %s already loaded %p\n", debugstr_w(name), ext); - return ext; - } - } - - row = MSI_QueryGetRecord( package->db, query, name ); - if (!row) - return NULL; - - ext = load_extension(package, row); - msiobj_release(&row->hdr); - return ext; -} - -static UINT iterate_load_verb(MSIRECORD *row, LPVOID param) -{ - MSIPACKAGE* package = param; - MSIVERB *verb; - LPCWSTR buffer; - MSIEXTENSION *extension; - - buffer = MSI_RecordGetString(row,1); - extension = load_given_extension( package, buffer ); - if (!extension) - { - ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer)); - return ERROR_SUCCESS; - } - - /* fill in the data */ - - verb = msi_alloc_zero( sizeof(MSIVERB) ); - if (!verb) - return ERROR_OUTOFMEMORY; - - verb->Verb = msi_dup_record_field(row,2); - TRACE("loading verb %s\n",debugstr_w(verb->Verb)); - verb->Sequence = MSI_RecordGetInteger(row,3); - - buffer = MSI_RecordGetString(row,4); - deformat_string(package,buffer,&verb->Command); - - buffer = MSI_RecordGetString(row,5); - deformat_string(package,buffer,&verb->Argument); - - /* associate the verb with the correct extension */ - list_add_tail( &extension->verbs, &verb->entry ); - - return ERROR_SUCCESS; -} - -static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param) -{ - MSICOMPONENT *comp; - LPCWSTR clsid; - LPCWSTR context; - LPCWSTR buffer; - MSIPACKAGE* package = param; - MSICLASS *cls; - BOOL match = FALSE; - - clsid = MSI_RecordGetString(rec,1); - context = MSI_RecordGetString(rec,2); - buffer = MSI_RecordGetString(rec,3); - comp = msi_get_loaded_component(package, buffer); - - LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry ) - { - if (strcmpiW( clsid, cls->clsid )) - continue; - if (strcmpW( context, cls->Context )) - continue; - if (comp == cls->Component) - { - match = TRUE; - break; - } - } - - if (!match) - load_class(package, rec); - - return ERROR_SUCCESS; -} - -static UINT load_all_classes( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ','`','C','l','a','s','s','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, iterate_all_classes, package); - msiobj_release(&view->hdr); - return rc; -} - -static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param) -{ - MSICOMPONENT *comp; - LPCWSTR buffer; - LPCWSTR extension; - MSIPACKAGE* package = param; - BOOL match = FALSE; - MSIEXTENSION *ext; - - extension = MSI_RecordGetString(rec,1); - buffer = MSI_RecordGetString(rec,2); - comp = msi_get_loaded_component(package, buffer); - - LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry ) - { - if (strcmpiW(extension, ext->Extension)) - continue; - if (comp == ext->Component) - { - match = TRUE; - break; - } - } - - if (!match) - load_extension(package, rec); - - return ERROR_SUCCESS; -} - -static UINT load_all_extensions( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','E','x','t','e','n','s','i','o','n','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, iterate_all_extensions, package); - msiobj_release(&view->hdr); - return rc; -} - -static UINT iterate_all_progids(MSIRECORD *rec, LPVOID param) -{ - LPCWSTR buffer; - MSIPACKAGE* package = param; - - buffer = MSI_RecordGetString(rec,1); - load_given_progid(package,buffer); - return ERROR_SUCCESS; -} - -static UINT load_all_progids( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ','F','R','O','M',' ', - '`','P','r','o','g','I','d','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, iterate_all_progids, package); - msiobj_release(&view->hdr); - return rc; -} - -static UINT load_all_verbs( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','V','e','r','b','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, iterate_load_verb, package); - msiobj_release(&view->hdr); - return rc; -} - -static UINT iterate_all_mimes(MSIRECORD *rec, LPVOID param) -{ - LPCWSTR buffer; - MSIPACKAGE* package = param; - - buffer = MSI_RecordGetString(rec,1); - load_given_mime(package,buffer); - return ERROR_SUCCESS; -} - -static UINT load_all_mimes( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','`','C','o','n','t','e','n','t','T','y','p','e','`',' ', - 'F','R','O','M',' ','`','M','I','M','E','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, iterate_all_mimes, package); - msiobj_release(&view->hdr); - return rc; -} - -static UINT load_classes_and_such( MSIPACKAGE *package ) -{ - UINT r; - - TRACE("Loading all the class info and related tables\n"); - - /* check if already loaded */ - if (!list_empty( &package->classes ) || - !list_empty( &package->mimes ) || - !list_empty( &package->extensions ) || - !list_empty( &package->progids )) return ERROR_SUCCESS; - - r = load_all_classes( package ); - if (r != ERROR_SUCCESS) return r; - - r = load_all_extensions( package ); - if (r != ERROR_SUCCESS) return r; - - r = load_all_progids( package ); - if (r != ERROR_SUCCESS) return r; - - /* these loads must come after the other loads */ - r = load_all_verbs( package ); - if (r != ERROR_SUCCESS) return r; - - return load_all_mimes( package ); -} - -static void mark_progid_for_install( MSIPACKAGE* package, MSIPROGID *progid ) -{ - MSIPROGID *child; - - if (!progid) - return; - - if (progid->InstallMe) - return; - - progid->InstallMe = TRUE; - - /* all children if this is a parent also install */ - LIST_FOR_EACH_ENTRY( child, &package->progids, MSIPROGID, entry ) - { - if (child->Parent == progid) - mark_progid_for_install( package, child ); - } -} - -static void mark_progid_for_uninstall( MSIPACKAGE *package, MSIPROGID *progid ) -{ - MSIPROGID *child; - - if (!progid) - return; - - if (!progid->InstallMe) - return; - - progid->InstallMe = FALSE; - - LIST_FOR_EACH_ENTRY( child, &package->progids, MSIPROGID, entry ) - { - if (child->Parent == progid) - mark_progid_for_uninstall( package, child ); - } -} - -static void mark_mime_for_install( MSIMIME *mime ) -{ - if (!mime) - return; - mime->InstallMe = TRUE; -} - -static void mark_mime_for_uninstall( MSIMIME *mime ) -{ - if (!mime) - return; - mime->InstallMe = FALSE; -} - -static UINT register_appid(const MSIAPPID *appid, LPCWSTR app ) -{ - static const WCHAR szRemoteServerName[] = - {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0}; - static const WCHAR szLocalService[] = - {'L','o','c','a','l','S','e','r','v','i','c','e',0}; - static const WCHAR szService[] = - {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0}; - static const WCHAR szDLL[] = - {'D','l','l','S','u','r','r','o','g','a','t','e',0}; - static const WCHAR szActivate[] = - {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0}; - static const WCHAR szY[] = {'Y',0}; - static const WCHAR szRunAs[] = {'R','u','n','A','s',0}; - static const WCHAR szUser[] = - {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0}; - - HKEY hkey2,hkey3; - - RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2); - RegCreateKeyW( hkey2, appid->AppID, &hkey3 ); - RegCloseKey(hkey2); - msi_reg_set_val_str( hkey3, NULL, app ); - - if (appid->RemoteServerName) - msi_reg_set_val_str( hkey3, szRemoteServerName, appid->RemoteServerName ); - - if (appid->LocalServer) - msi_reg_set_val_str( hkey3, szLocalService, appid->LocalServer ); - - if (appid->ServiceParameters) - msi_reg_set_val_str( hkey3, szService, appid->ServiceParameters ); - - if (appid->DllSurrogate) - msi_reg_set_val_str( hkey3, szDLL, appid->DllSurrogate ); - - if (appid->ActivateAtStorage) - msi_reg_set_val_str( hkey3, szActivate, szY ); - - if (appid->RunAsInteractiveUser) - msi_reg_set_val_str( hkey3, szRunAs, szUser ); - - RegCloseKey(hkey3); - return ERROR_SUCCESS; -} - -UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) -{ - static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0}; - const WCHAR *keypath; - MSIRECORD *uirow; - HKEY hkey, hkey2, hkey3; - MSICLASS *cls; - UINT r; - - r = load_classes_and_such( package ); - if (r != ERROR_SUCCESS) - return r; - - if (is_64bit && package->platform == PLATFORM_INTEL) - keypath = szWow6432NodeCLSID; - else - keypath = szCLSID; - - if (RegCreateKeyW(HKEY_CLASSES_ROOT, keypath, &hkey) != ERROR_SUCCESS) - return ERROR_FUNCTION_FAILED; - - LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry ) - { - MSICOMPONENT *comp; - MSIFILE *file; - DWORD size; - LPWSTR argument; - MSIFEATURE *feature; - - comp = cls->Component; - if ( !comp ) - continue; - - if (!comp->Enabled) - { - TRACE("component is disabled\n"); - continue; - } - - feature = cls->Feature; - if (!feature) - continue; - - feature->Action = msi_get_feature_action( package, feature ); - if (feature->Action != INSTALLSTATE_LOCAL && - feature->Action != INSTALLSTATE_ADVERTISED ) - { - TRACE("feature %s not scheduled for installation, skipping registration of class %s\n", - debugstr_w(feature->Feature), debugstr_w(cls->clsid)); - continue; - } - - if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath ))) - { - TRACE("COM server not provided, skipping class %s\n", debugstr_w(cls->clsid)); - continue; - } - TRACE("Registering class %s (%p)\n", debugstr_w(cls->clsid), cls); - - cls->Installed = TRUE; - mark_progid_for_install( package, cls->ProgID ); - - RegCreateKeyW( hkey, cls->clsid, &hkey2 ); - - if (cls->Description) - msi_reg_set_val_str( hkey2, NULL, cls->Description ); - - RegCreateKeyW( hkey2, cls->Context, &hkey3 ); - - /* - * FIXME: Implement install on demand (advertised components). - * - * ole32.dll should call msi.MsiProvideComponentFromDescriptor() - * when it needs an InProcServer that doesn't exist. - * The component advertise string should be in the "InProcServer" value. - */ - size = lstrlenW( file->TargetPath )+1; - if (cls->Argument) - size += lstrlenW(cls->Argument)+1; - - argument = msi_alloc( size * sizeof(WCHAR) ); - lstrcpyW( argument, file->TargetPath ); - - if (cls->Argument) - { - lstrcatW( argument, szSpace ); - lstrcatW( argument, cls->Argument ); - } - - msi_reg_set_val_str( hkey3, NULL, argument ); - msi_free(argument); - - RegCloseKey(hkey3); - - if (cls->ProgID || cls->ProgIDText) - { - LPCWSTR progid; - - if (cls->ProgID) - progid = cls->ProgID->ProgID; - else - progid = cls->ProgIDText; - - msi_reg_set_subkey_val( hkey2, szProgID, NULL, progid ); - - if (cls->ProgID && cls->ProgID->VersionInd) - { - msi_reg_set_subkey_val( hkey2, szVIProgID, NULL, - cls->ProgID->VersionInd->ProgID ); - } - } - - if (cls->AppID) - { - MSIAPPID *appid = cls->AppID; - msi_reg_set_val_str( hkey2, szAppID, appid->AppID ); - register_appid( appid, cls->Description ); - } - - if (cls->IconPath) - msi_reg_set_subkey_val( hkey2, szDefaultIcon, NULL, cls->IconPath ); - - if (cls->DefInprocHandler) - msi_reg_set_subkey_val( hkey2, szInprocHandler, NULL, cls->DefInprocHandler ); - - if (cls->DefInprocHandler32) - msi_reg_set_subkey_val( hkey2, szInprocHandler32, NULL, cls->DefInprocHandler32 ); - - RegCloseKey(hkey2); - - /* if there is a FileTypeMask, register the FileType */ - if (cls->FileTypeMask) - { - LPWSTR ptr, ptr2; - LPWSTR keyname; - INT index = 0; - ptr = cls->FileTypeMask; - while (ptr && *ptr) - { - ptr2 = strchrW(ptr,';'); - if (ptr2) - *ptr2 = 0; - keyname = msi_alloc( (strlenW(szFileType_fmt) + strlenW(cls->clsid) + 4) * sizeof(WCHAR)); - sprintfW( keyname, szFileType_fmt, cls->clsid, index ); - - msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, ptr ); - msi_free(keyname); - - if (ptr2) - ptr = ptr2+1; - else - ptr = NULL; - - index ++; - } - } - - uirow = MSI_CreateRecord(1); - MSI_RecordSetStringW( uirow, 1, cls->clsid ); - msi_ui_actiondata( package, szRegisterClassInfo, uirow ); - msiobj_release(&uirow->hdr); - } - RegCloseKey(hkey); - return ERROR_SUCCESS; -} - -UINT ACTION_UnregisterClassInfo( MSIPACKAGE *package ) -{ - static const WCHAR szFileType[] = {'F','i','l','e','T','y','p','e','\\',0}; - const WCHAR *keypath; - MSIRECORD *uirow; - MSICLASS *cls; - HKEY hkey, hkey2; - UINT r; - - r = load_classes_and_such( package ); - if (r != ERROR_SUCCESS) - return r; - - if (is_64bit && package->platform == PLATFORM_INTEL) - keypath = szWow6432NodeCLSID; - else - keypath = szCLSID; - - if (RegOpenKeyW( HKEY_CLASSES_ROOT, keypath, &hkey ) != ERROR_SUCCESS) - return ERROR_SUCCESS; - - LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry ) - { - MSIFEATURE *feature; - MSICOMPONENT *comp; - LPWSTR filetype; - LONG res; - - comp = cls->Component; - if (!comp) - continue; - - if (!comp->Enabled) - { - TRACE("component is disabled\n"); - continue; - } - - feature = cls->Feature; - if (!feature) - continue; - - feature->Action = msi_get_feature_action( package, feature ); - if (feature->Action != INSTALLSTATE_ABSENT) - { - TRACE("feature %s not scheduled for removal, skipping unregistration of class %s\n", - debugstr_w(feature->Feature), debugstr_w(cls->clsid)); - continue; - } - TRACE("Unregistering class %s (%p)\n", debugstr_w(cls->clsid), cls); - - cls->Installed = FALSE; - mark_progid_for_uninstall( package, cls->ProgID ); - - res = RegDeleteTreeW( hkey, cls->clsid ); - if (res != ERROR_SUCCESS) - WARN("Failed to delete class key %d\n", res); - - if (cls->AppID) - { - res = RegOpenKeyW( HKEY_CLASSES_ROOT, szAppID, &hkey2 ); - if (res == ERROR_SUCCESS) - { - res = RegDeleteKeyW( hkey2, cls->AppID->AppID ); - if (res != ERROR_SUCCESS) - WARN("Failed to delete appid key %d\n", res); - RegCloseKey( hkey2 ); - } - } - if (cls->FileTypeMask) - { - filetype = msi_alloc( (strlenW( szFileType ) + strlenW( cls->clsid ) + 1) * sizeof(WCHAR) ); - if (filetype) - { - strcpyW( filetype, szFileType ); - strcatW( filetype, cls->clsid ); - res = RegDeleteTreeW( HKEY_CLASSES_ROOT, filetype ); - msi_free( filetype ); - - if (res != ERROR_SUCCESS) - WARN("Failed to delete file type %d\n", res); - } - } - - uirow = MSI_CreateRecord( 1 ); - MSI_RecordSetStringW( uirow, 1, cls->clsid ); - msi_ui_actiondata( package, szUnregisterClassInfo, uirow ); - msiobj_release( &uirow->hdr ); - } - RegCloseKey( hkey ); - return ERROR_SUCCESS; -} - -static LPCWSTR get_clsid_of_progid( const MSIPROGID *progid ) -{ - while (progid) - { - if (progid->Class) - return progid->Class->clsid; - if (progid->Parent == progid) - break; - progid = progid->Parent; - } - return NULL; -} - -static UINT register_progid( const MSIPROGID* progid ) -{ - static const WCHAR szCurVer[] = {'C','u','r','V','e','r',0}; - HKEY hkey = 0; - UINT rc; - - rc = RegCreateKeyW( HKEY_CLASSES_ROOT, progid->ProgID, &hkey ); - if (rc == ERROR_SUCCESS) - { - LPCWSTR clsid = get_clsid_of_progid( progid ); - - if (clsid) - msi_reg_set_subkey_val( hkey, szCLSID, NULL, clsid ); - else - TRACE("%s has no class\n", debugstr_w( progid->ProgID ) ); - - if (progid->Description) - msi_reg_set_val_str( hkey, NULL, progid->Description ); - - if (progid->IconPath) - msi_reg_set_subkey_val( hkey, szDefaultIcon, NULL, progid->IconPath ); - - /* write out the current version */ - if (progid->CurVer) - msi_reg_set_subkey_val( hkey, szCurVer, NULL, progid->CurVer->ProgID ); - - RegCloseKey(hkey); - } - else - ERR("failed to create key %s\n", debugstr_w( progid->ProgID ) ); - - return rc; -} - -UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package) -{ - MSIPROGID *progid; - MSIRECORD *uirow; - UINT r; - - r = load_classes_and_such( package ); - if (r != ERROR_SUCCESS) - return r; - - LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry ) - { - /* check if this progid is to be installed */ - if (progid->Class && progid->Class->Installed) - progid->InstallMe = TRUE; - - if (!progid->InstallMe) - { - TRACE("progid %s not scheduled to be installed\n", - debugstr_w(progid->ProgID)); - continue; - } - - TRACE("Registering progid %s\n", debugstr_w(progid->ProgID)); - - register_progid( progid ); - - uirow = MSI_CreateRecord( 1 ); - MSI_RecordSetStringW( uirow, 1, progid->ProgID ); - msi_ui_actiondata( package, szRegisterProgIdInfo, uirow ); - msiobj_release( &uirow->hdr ); - } - return ERROR_SUCCESS; -} - -UINT ACTION_UnregisterProgIdInfo( MSIPACKAGE *package ) -{ - MSIPROGID *progid; - MSIRECORD *uirow; - LONG res; - UINT r; - - r = load_classes_and_such( package ); - if (r != ERROR_SUCCESS) - return r; - - LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry ) - { - /* check if this progid is to be removed */ - if (progid->Class && !progid->Class->Installed) - progid->InstallMe = FALSE; - - if (progid->InstallMe) - { - TRACE("progid %s not scheduled to be removed\n", debugstr_w(progid->ProgID)); - continue; - } - - TRACE("Unregistering progid %s\n", debugstr_w(progid->ProgID)); - - res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid->ProgID ); - if (res != ERROR_SUCCESS) - TRACE("Failed to delete progid key %d\n", res); - - uirow = MSI_CreateRecord( 1 ); - MSI_RecordSetStringW( uirow, 1, progid->ProgID ); - msi_ui_actiondata( package, szUnregisterProgIdInfo, uirow ); - msiobj_release( &uirow->hdr ); - } - return ERROR_SUCCESS; -} - -static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid, - MSICOMPONENT* component, const MSIEXTENSION* extension, - MSIVERB* verb, INT* Sequence ) -{ - LPWSTR keyname; - HKEY key; - static const WCHAR szShell[] = {'s','h','e','l','l',0}; - static const WCHAR szCommand[] = {'c','o','m','m','a','n','d',0}; - static const WCHAR fmt[] = {'\"','%','s','\"',' ','%','s',0}; - static const WCHAR fmt2[] = {'\"','%','s','\"',0}; - LPWSTR command; - DWORD size; - LPWSTR advertise; - - keyname = msi_build_directory_name(4, progid, szShell, verb->Verb, szCommand); - - TRACE("Making Key %s\n",debugstr_w(keyname)); - RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key); - size = strlenW(component->FullKeypath); - if (verb->Argument) - size += strlenW(verb->Argument); - size += 4; - - command = msi_alloc(size * sizeof (WCHAR)); - if (verb->Argument) - sprintfW(command, fmt, component->FullKeypath, verb->Argument); - else - sprintfW(command, fmt2, component->FullKeypath); - - msi_reg_set_val_str( key, NULL, command ); - msi_free(command); - - advertise = msi_create_component_advertise_string(package, component, - extension->Feature->Feature); - size = strlenW(advertise); - - if (verb->Argument) - size += strlenW(verb->Argument); - size += 4; - - command = msi_alloc_zero(size * sizeof (WCHAR)); - - strcpyW(command,advertise); - if (verb->Argument) - { - strcatW(command,szSpace); - strcatW(command,verb->Argument); - } - - msi_reg_set_val_multi_str( key, szCommand, command ); - - RegCloseKey(key); - msi_free(keyname); - msi_free(advertise); - msi_free(command); - - if (verb->Command) - { - keyname = msi_build_directory_name( 3, progid, szShell, verb->Verb ); - msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, verb->Command ); - msi_free(keyname); - } - - if (verb->Sequence != MSI_NULL_INTEGER) - { - if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence) - { - *Sequence = verb->Sequence; - keyname = msi_build_directory_name( 2, progid, szShell ); - msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, keyname, NULL, verb->Verb ); - msi_free(keyname); - } - } - return ERROR_SUCCESS; -} - -UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package) -{ - static const WCHAR szContentType[] = {'C','o','n','t','e','n','t',' ','T','y','p','e',0}; - HKEY hkey = NULL; - MSIEXTENSION *ext; - MSIRECORD *uirow; - BOOL install_on_demand = TRUE; - LONG res; - UINT r; - - r = load_classes_and_such( package ); - if (r != ERROR_SUCCESS) - return r; - - /* We need to set install_on_demand based on if the shell handles advertised - * shortcuts and the like. Because Mike McCormack is working on this i am - * going to default to TRUE - */ - - LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry ) - { - LPWSTR extension; - MSIFEATURE *feature; - - if (!ext->Component) - continue; - - if (!ext->Component->Enabled) - { - TRACE("component is disabled\n"); - continue; - } - - feature = ext->Feature; - if (!feature) - continue; - - /* - * yes. MSDN says that these are based on _Feature_ not on - * Component. So verify the feature is to be installed - */ - feature->Action = msi_get_feature_action( package, feature ); - if (feature->Action != INSTALLSTATE_LOCAL && - !(install_on_demand && feature->Action == INSTALLSTATE_ADVERTISED)) - { - TRACE("feature %s not scheduled for installation, skipping registration of extension %s\n", - debugstr_w(feature->Feature), debugstr_w(ext->Extension)); - continue; - } - TRACE("Registering extension %s (%p)\n", debugstr_w(ext->Extension), ext); - - ext->Installed = TRUE; - - /* this is only registered if the extension has at least 1 verb - * according to MSDN - */ - if (ext->ProgID && !list_empty( &ext->verbs ) ) - mark_progid_for_install( package, ext->ProgID ); - - mark_mime_for_install(ext->Mime); - - extension = msi_alloc( (strlenW( ext->Extension ) + 2) * sizeof(WCHAR) ); - if (extension) - { - extension[0] = '.'; - strcpyW( extension + 1, ext->Extension ); - res = RegCreateKeyW( HKEY_CLASSES_ROOT, extension, &hkey ); - msi_free( extension ); - if (res != ERROR_SUCCESS) - WARN("Failed to create extension key %d\n", res); - } - - if (ext->Mime) - msi_reg_set_val_str( hkey, szContentType, ext->Mime->ContentType ); - - if (ext->ProgID || ext->ProgIDText) - { - static const WCHAR szSN[] = - {'\\','S','h','e','l','l','N','e','w',0}; - HKEY hkey2; - LPWSTR newkey; - LPCWSTR progid; - MSIVERB *verb; - INT Sequence = MSI_NULL_INTEGER; - - if (ext->ProgID) - progid = ext->ProgID->ProgID; - else - progid = ext->ProgIDText; - - msi_reg_set_val_str( hkey, NULL, progid ); - - newkey = msi_alloc( (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR)); - - strcpyW(newkey,progid); - strcatW(newkey,szSN); - RegCreateKeyW(hkey,newkey,&hkey2); - RegCloseKey(hkey2); - - msi_free(newkey); - - /* do all the verbs */ - LIST_FOR_EACH_ENTRY( verb, &ext->verbs, MSIVERB, entry ) - { - register_verb( package, progid, ext->Component, - ext, verb, &Sequence); - } - } - - RegCloseKey(hkey); - - uirow = MSI_CreateRecord(1); - MSI_RecordSetStringW( uirow, 1, ext->Extension ); - msi_ui_actiondata( package, szRegisterExtensionInfo, uirow ); - msiobj_release(&uirow->hdr); - } - return ERROR_SUCCESS; -} - -UINT ACTION_UnregisterExtensionInfo( MSIPACKAGE *package ) -{ - MSIEXTENSION *ext; - MSIRECORD *uirow; - LONG res; - UINT r; - - r = load_classes_and_such( package ); - if (r != ERROR_SUCCESS) - return r; - - LIST_FOR_EACH_ENTRY( ext, &package->extensions, MSIEXTENSION, entry ) - { - LPWSTR extension; - MSIFEATURE *feature; - - if (!ext->Component) - continue; - - if (!ext->Component->Enabled) - { - TRACE("component is disabled\n"); - continue; - } - - feature = ext->Feature; - if (!feature) - continue; - - feature->Action = msi_get_feature_action( package, feature ); - if (feature->Action != INSTALLSTATE_ABSENT) - { - TRACE("feature %s not scheduled for removal, skipping unregistration of extension %s\n", - debugstr_w(feature->Feature), debugstr_w(ext->Extension)); - continue; - } - TRACE("Unregistering extension %s\n", debugstr_w(ext->Extension)); - - ext->Installed = FALSE; - - if (ext->ProgID && !list_empty( &ext->verbs )) - mark_progid_for_uninstall( package, ext->ProgID ); - - mark_mime_for_uninstall( ext->Mime ); - - extension = msi_alloc( (strlenW( ext->Extension ) + 2) * sizeof(WCHAR) ); - if (extension) - { - extension[0] = '.'; - strcpyW( extension + 1, ext->Extension ); - res = RegDeleteTreeW( HKEY_CLASSES_ROOT, extension ); - msi_free( extension ); - if (res != ERROR_SUCCESS) - WARN("Failed to delete extension key %d\n", res); - } - - if (ext->ProgID || ext->ProgIDText) - { - static const WCHAR shellW[] = {'\\','s','h','e','l','l',0}; - LPCWSTR progid; - LPWSTR progid_shell; - - if (ext->ProgID) - progid = ext->ProgID->ProgID; - else - progid = ext->ProgIDText; - - progid_shell = msi_alloc( (strlenW( progid ) + strlenW( shellW ) + 1) * sizeof(WCHAR) ); - if (progid_shell) - { - strcpyW( progid_shell, progid ); - strcatW( progid_shell, shellW ); - res = RegDeleteTreeW( HKEY_CLASSES_ROOT, progid_shell ); - msi_free( progid_shell ); - if (res != ERROR_SUCCESS) - WARN("Failed to delete shell key %d\n", res); - RegDeleteKeyW( HKEY_CLASSES_ROOT, progid ); - } - } - - uirow = MSI_CreateRecord( 1 ); - MSI_RecordSetStringW( uirow, 1, ext->Extension ); - msi_ui_actiondata( package, szUnregisterExtensionInfo, uirow ); - msiobj_release( &uirow->hdr ); - } - return ERROR_SUCCESS; -} - -UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package) -{ - static const WCHAR szExtension[] = {'E','x','t','e','n','s','i','o','n',0}; - MSIRECORD *uirow; - MSIMIME *mt; - UINT r; - - r = load_classes_and_such( package ); - if (r != ERROR_SUCCESS) - return r; - - LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry ) - { - LPWSTR extension, key; - - /* - * check if the MIME is to be installed. Either as requested by an - * extension or Class - */ - mt->InstallMe = (mt->InstallMe || - (mt->Class && mt->Class->Installed) || - (mt->Extension && mt->Extension->Installed)); - - if (!mt->InstallMe) - { - TRACE("MIME %s not scheduled to be installed\n", debugstr_w(mt->ContentType)); - continue; - } - - TRACE("Registering MIME type %s\n", debugstr_w(mt->ContentType)); - - extension = msi_alloc( (strlenW( mt->Extension->Extension ) + 2) * sizeof(WCHAR) ); - key = msi_alloc( (strlenW( mt->ContentType ) + strlenW( szMIMEDatabase ) + 1) * sizeof(WCHAR) ); - - if (extension && key) - { - extension[0] = '.'; - strcpyW( extension + 1, mt->Extension->Extension ); - - strcpyW( key, szMIMEDatabase ); - strcatW( key, mt->ContentType ); - msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, key, szExtension, extension ); - - if (mt->clsid) - msi_reg_set_subkey_val( HKEY_CLASSES_ROOT, key, szCLSID, mt->clsid ); - } - msi_free( extension ); - msi_free( key ); - - uirow = MSI_CreateRecord( 2 ); - MSI_RecordSetStringW( uirow, 1, mt->ContentType ); - MSI_RecordSetStringW( uirow, 2, mt->suffix ); - msi_ui_actiondata( package, szRegisterMIMEInfo, uirow ); - msiobj_release( &uirow->hdr ); - } - return ERROR_SUCCESS; -} - -UINT ACTION_UnregisterMIMEInfo( MSIPACKAGE *package ) -{ - MSIRECORD *uirow; - MSIMIME *mime; - UINT r; - - r = load_classes_and_such( package ); - if (r != ERROR_SUCCESS) - return r; - - LIST_FOR_EACH_ENTRY( mime, &package->mimes, MSIMIME, entry ) - { - LONG res; - LPWSTR mime_key; - - mime->InstallMe = (mime->InstallMe || - (mime->Class && mime->Class->Installed) || - (mime->Extension && mime->Extension->Installed)); - - if (mime->InstallMe) - { - TRACE("MIME %s not scheduled to be removed\n", debugstr_w(mime->ContentType)); - continue; - } - - TRACE("Unregistering MIME type %s\n", debugstr_w(mime->ContentType)); - - mime_key = msi_alloc( (strlenW( szMIMEDatabase ) + strlenW( mime->ContentType ) + 1) * sizeof(WCHAR) ); - if (mime_key) - { - strcpyW( mime_key, szMIMEDatabase ); - strcatW( mime_key, mime->ContentType ); - res = RegDeleteKeyW( HKEY_CLASSES_ROOT, mime_key ); - if (res != ERROR_SUCCESS) - WARN("Failed to delete MIME key %d\n", res); - msi_free( mime_key ); - } - - uirow = MSI_CreateRecord( 2 ); - MSI_RecordSetStringW( uirow, 1, mime->ContentType ); - MSI_RecordSetStringW( uirow, 2, mime->suffix ); - msi_ui_actiondata( package, szUnregisterMIMEInfo, uirow ); - msiobj_release( &uirow->hdr ); - } - return ERROR_SUCCESS; -} diff --git a/libmsi/cond-parser.y b/libmsi/cond-parser.y deleted file mode 100644 index d6c39c7..0000000 --- a/libmsi/cond-parser.y +++ /dev/null @@ -1,869 +0,0 @@ -%{ - -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2003 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define COBJMACROS - -#include "config.h" - -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "msi.h" -#include "msiquery.h" -#include "objbase.h" -#include "oleauto.h" - -#include "msipriv.h" -#include "msiserver.h" -#include "wine/debug.h" -#include "wine/unicode.h" -#include "wine/list.h" - -#define YYLEX_PARAM info -#define YYPARSE_PARAM info - -static int cond_error(const char *str); - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -typedef struct tag_yyinput -{ - MSIPACKAGE *package; - LPCWSTR str; - INT n; - MSICONDITION result; - struct list mem; -} COND_input; - -struct cond_str { - LPCWSTR data; - INT len; -}; - -static LPWSTR COND_GetString( COND_input *info, const struct cond_str *str ); -static LPWSTR COND_GetLiteral( COND_input *info, const struct cond_str *str ); -static int cond_lex( void *COND_lval, COND_input *info); - -static void *cond_alloc( COND_input *cond, unsigned int sz ); -static void *cond_track_mem( COND_input *cond, void *ptr, unsigned int sz ); -static void cond_free( void *ptr ); - -static INT compare_int( INT a, INT operator, INT b ); -static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b, BOOL convert ); - -static INT compare_and_free_strings( LPWSTR a, INT op, LPWSTR b, BOOL convert ) -{ - INT r; - - r = compare_string( a, op, b, convert ); - cond_free( a ); - cond_free( b ); - return r; -} - -static BOOL num_from_prop( LPCWSTR p, INT *val ) -{ - INT ret = 0, sign = 1; - - if (!p) - return FALSE; - if (*p == '-') - { - sign = -1; - p++; - } - if (!*p) - return FALSE; - while (*p) - { - if( *p < '0' || *p > '9' ) - return FALSE; - ret = ret*10 + (*p - '0'); - p++; - } - *val = ret*sign; - return TRUE; -} - -%} - -%define api.prefix "cond_" -%pure-parser - -%union -{ - struct cond_str str; - LPWSTR string; - INT value; -} - -%token COND_SPACE COND_EOF -%token COND_OR COND_AND COND_NOT COND_XOR COND_IMP COND_EQV -%token COND_LT COND_GT COND_EQ COND_NE COND_GE COND_LE -%token COND_ILT COND_IGT COND_IEQ COND_INE COND_IGE COND_ILE -%token COND_LPAR COND_RPAR COND_TILDA COND_SS COND_ISS -%token COND_ILHS COND_IRHS COND_LHS COND_RHS -%token COND_PERCENT COND_DOLLARS COND_QUESTION COND_AMPER COND_EXCLAM -%token <str> COND_IDENT <str> COND_NUMBER <str> COND_LITER - -%nonassoc COND_ERROR COND_EOF - -%type <value> expression boolean_term boolean_factor -%type <value> value_i integer operator -%type <string> identifier symbol_s value_s literal - -%% - -condition: - expression - { - COND_input* cond = (COND_input*) info; - cond->result = $1; - } - | /* empty */ - { - COND_input* cond = (COND_input*) info; - cond->result = MSICONDITION_NONE; - } - ; - -expression: - boolean_term - { - $$ = $1; - } - | expression COND_OR boolean_term - { - $$ = $1 || $3; - } - | expression COND_IMP boolean_term - { - $$ = !$1 || $3; - } - | expression COND_XOR boolean_term - { - $$ = ( $1 || $3 ) && !( $1 && $3 ); - } - | expression COND_EQV boolean_term - { - $$ = ( $1 && $3 ) || ( !$1 && !$3 ); - } - ; - -boolean_term: - boolean_factor - { - $$ = $1; - } - | boolean_term COND_AND boolean_factor - { - $$ = $1 && $3; - } - ; - -boolean_factor: - COND_NOT boolean_factor - { - $$ = $2 ? 0 : 1; - } - | value_i - { - $$ = $1 ? 1 : 0; - } - | value_s - { - $$ = ($1 && $1[0]) ? 1 : 0; - cond_free( $1 ); - } - | value_i operator value_i - { - $$ = compare_int( $1, $2, $3 ); - } - | symbol_s operator value_i - { - int num; - if (num_from_prop( $1, &num )) - $$ = compare_int( num, $2, $3 ); - else - $$ = ($2 == COND_NE || $2 == COND_INE ); - cond_free( $1 ); - } - | value_i operator symbol_s - { - int num; - if (num_from_prop( $3, &num )) - $$ = compare_int( $1, $2, num ); - else - $$ = ($2 == COND_NE || $2 == COND_INE ); - cond_free( $3 ); - } - | symbol_s operator symbol_s - { - $$ = compare_and_free_strings( $1, $2, $3, TRUE ); - } - | symbol_s operator literal - { - $$ = compare_and_free_strings( $1, $2, $3, TRUE ); - } - | literal operator symbol_s - { - $$ = compare_and_free_strings( $1, $2, $3, TRUE ); - } - | literal operator literal - { - $$ = compare_and_free_strings( $1, $2, $3, FALSE ); - } - | literal operator value_i - { - $$ = 0; - cond_free( $1 ); - } - | value_i operator literal - { - $$ = 0; - cond_free( $3 ); - } - | COND_LPAR expression COND_RPAR - { - $$ = $2; - } - ; - -operator: - /* common functions */ - COND_EQ { $$ = COND_EQ; } - | COND_NE { $$ = COND_NE; } - | COND_LT { $$ = COND_LT; } - | COND_GT { $$ = COND_GT; } - | COND_LE { $$ = COND_LE; } - | COND_GE { $$ = COND_GE; } - | COND_SS { $$ = COND_SS; } - | COND_IEQ { $$ = COND_IEQ; } - | COND_INE { $$ = COND_INE; } - | COND_ILT { $$ = COND_ILT; } - | COND_IGT { $$ = COND_IGT; } - | COND_ILE { $$ = COND_ILE; } - | COND_IGE { $$ = COND_IGE; } - | COND_ISS { $$ = COND_ISS; } - | COND_LHS { $$ = COND_LHS; } - | COND_RHS { $$ = COND_RHS; } - | COND_ILHS { $$ = COND_ILHS; } - | COND_IRHS { $$ = COND_IRHS; } - ; - -value_s: - symbol_s - { - $$ = $1; - } - | literal - { - $$ = $1; - } - ; - -literal: - COND_LITER - { - COND_input* cond = (COND_input*) info; - $$ = COND_GetLiteral( cond, &$1 ); - if( !$$ ) - YYABORT; - } - ; - -value_i: - integer - { - $$ = $1; - } - | COND_DOLLARS identifier - { - COND_input* cond = (COND_input*) info; - INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; - - MSI_GetComponentStateW(cond->package, $2, &install, &action ); - $$ = action; - cond_free( $2 ); - } - | COND_QUESTION identifier - { - COND_input* cond = (COND_input*) info; - INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; - - MSI_GetComponentStateW(cond->package, $2, &install, &action ); - $$ = install; - cond_free( $2 ); - } - | COND_AMPER identifier - { - COND_input* cond = (COND_input*) info; - INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; - - MSI_GetFeatureStateW(cond->package, $2, &install, &action ); - if (action == INSTALLSTATE_UNKNOWN) - $$ = MSICONDITION_FALSE; - else - $$ = action; - - cond_free( $2 ); - } - | COND_EXCLAM identifier - { - COND_input* cond = (COND_input*) info; - INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; - - MSI_GetFeatureStateW(cond->package, $2, &install, &action ); - $$ = install; - cond_free( $2 ); - } - ; - -symbol_s: - identifier - { - COND_input* cond = (COND_input*) info; - UINT len; - - $$ = msi_dup_property( cond->package->db, $1 ); - if ($$) - { - len = (lstrlenW($$) + 1) * sizeof (WCHAR); - $$ = cond_track_mem( cond, $$, len ); - } - cond_free( $1 ); - } - | COND_PERCENT identifier - { - COND_input* cond = (COND_input*) info; - UINT len = GetEnvironmentVariableW( $2, NULL, 0 ); - $$ = NULL; - if (len++) - { - $$ = cond_alloc( cond, len*sizeof (WCHAR) ); - if( !$$ ) - YYABORT; - GetEnvironmentVariableW( $2, $$, len ); - } - cond_free( $2 ); - } - ; - -identifier: - COND_IDENT - { - COND_input* cond = (COND_input*) info; - $$ = COND_GetString( cond, &$1 ); - if( !$$ ) - YYABORT; - } - ; - -integer: - COND_NUMBER - { - COND_input* cond = (COND_input*) info; - LPWSTR szNum = COND_GetString( cond, &$1 ); - if( !szNum ) - YYABORT; - $$ = atoiW( szNum ); - cond_free( szNum ); - } - ; - -%% - - -static int COND_IsAlpha( WCHAR x ) -{ - return( ( ( x >= 'A' ) && ( x <= 'Z' ) ) || - ( ( x >= 'a' ) && ( x <= 'z' ) ) || - ( ( x == '_' ) ) ); -} - -static int COND_IsNumber( WCHAR x ) -{ - return( (( x >= '0' ) && ( x <= '9' )) || (x =='-') || (x =='.') ); -} - -static WCHAR *strstriW( const WCHAR *str, const WCHAR *sub ) -{ - LPWSTR strlower, sublower, r; - strlower = CharLowerW( strdupW( str ) ); - sublower = CharLowerW( strdupW( sub ) ); - r = strstrW( strlower, sublower ); - if (r) - r = (LPWSTR)str + (r - strlower); - msi_free( strlower ); - msi_free( sublower ); - return r; -} - -static BOOL str_is_number( LPCWSTR str ) -{ - int i; - - if (!*str) - return FALSE; - - for (i = 0; i < lstrlenW( str ); i++) - if (!isdigitW(str[i])) - return FALSE; - - return TRUE; -} - -static INT compare_substring( LPCWSTR a, INT operator, LPCWSTR b ) -{ - int lhs, rhs; - - /* substring operators return 0 if LHS is missing */ - if (!a || !*a) - return 0; - - /* substring operators return 1 if RHS is missing */ - if (!b || !*b) - return 1; - - /* if both strings contain only numbers, use integer comparison */ - lhs = atoiW(a); - rhs = atoiW(b); - if (str_is_number(a) && str_is_number(b)) - return compare_int( lhs, operator, rhs ); - - switch (operator) - { - case COND_SS: - return strstrW( a, b ) != 0; - case COND_ISS: - return strstriW( a, b ) != 0; - case COND_LHS: - { - int l = strlenW( a ); - int r = strlenW( b ); - if (r > l) return 0; - return !strncmpW( a, b, r ); - } - case COND_RHS: - { - int l = strlenW( a ); - int r = strlenW( b ); - if (r > l) return 0; - return !strncmpW( a + (l - r), b, r ); - } - case COND_ILHS: - { - int l = strlenW( a ); - int r = strlenW( b ); - if (r > l) return 0; - return !strncmpiW( a, b, r ); - } - case COND_IRHS: - { - int l = strlenW( a ); - int r = strlenW( b ); - if (r > l) return 0; - return !strncmpiW( a + (l - r), b, r ); - } - default: - ERR("invalid substring operator\n"); - return 0; - } - return 0; -} - -static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b, BOOL convert ) -{ - if (operator >= COND_SS && operator <= COND_RHS) - return compare_substring( a, operator, b ); - - /* null and empty string are equivalent */ - if (!a) a = szEmpty; - if (!b) b = szEmpty; - - if (convert && str_is_number(a) && str_is_number(b)) - return compare_int( atoiW(a), operator, atoiW(b) ); - - /* a or b may be NULL */ - switch (operator) - { - case COND_LT: - return strcmpW( a, b ) < 0; - case COND_GT: - return strcmpW( a, b ) > 0; - case COND_EQ: - return strcmpW( a, b ) == 0; - case COND_NE: - return strcmpW( a, b ) != 0; - case COND_GE: - return strcmpW( a, b ) >= 0; - case COND_LE: - return strcmpW( a, b ) <= 0; - case COND_ILT: - return strcmpiW( a, b ) < 0; - case COND_IGT: - return strcmpiW( a, b ) > 0; - case COND_IEQ: - return strcmpiW( a, b ) == 0; - case COND_INE: - return strcmpiW( a, b ) != 0; - case COND_IGE: - return strcmpiW( a, b ) >= 0; - case COND_ILE: - return strcmpiW( a, b ) <= 0; - default: - ERR("invalid string operator\n"); - return 0; - } - return 0; -} - - -static INT compare_int( INT a, INT operator, INT b ) -{ - switch (operator) - { - case COND_LT: - case COND_ILT: - return a < b; - case COND_GT: - case COND_IGT: - return a > b; - case COND_EQ: - case COND_IEQ: - return a == b; - case COND_NE: - case COND_INE: - return a != b; - case COND_GE: - case COND_IGE: - return a >= b; - case COND_LE: - case COND_ILE: - return a <= b; - case COND_SS: - case COND_ISS: - return ( a & b ) ? 1 : 0; - case COND_RHS: - return ( ( a & 0xffff ) == b ) ? 1 : 0; - case COND_LHS: - return ( ( (a>>16) & 0xffff ) == b ) ? 1 : 0; - default: - ERR("invalid integer operator\n"); - return 0; - } - return 0; -} - - -static int COND_IsIdent( WCHAR x ) -{ - return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' ) - || ( x == '#' ) || (x == '.') ); -} - -static int COND_GetOperator( COND_input *cond ) -{ - static const struct { - const WCHAR str[4]; - int id; - } table[] = { - { {'~','<','=',0}, COND_ILE }, - { {'~','>','<',0}, COND_ISS }, - { {'~','>','>',0}, COND_IRHS }, - { {'~','<','>',0}, COND_INE }, - { {'~','>','=',0}, COND_IGE }, - { {'~','<','<',0}, COND_ILHS }, - { {'~','=',0}, COND_IEQ }, - { {'~','<',0}, COND_ILT }, - { {'~','>',0}, COND_IGT }, - { {'>','=',0}, COND_GE }, - { {'>','<',0}, COND_SS }, - { {'<','<',0}, COND_LHS }, - { {'<','>',0}, COND_NE }, - { {'<','=',0}, COND_LE }, - { {'>','>',0}, COND_RHS }, - { {'>',0}, COND_GT }, - { {'<',0}, COND_LT }, - { {0}, 0 } - }; - LPCWSTR p = &cond->str[cond->n]; - int i = 0, len; - - while ( 1 ) - { - len = lstrlenW( table[i].str ); - if ( !len || 0 == strncmpW( table[i].str, p, len ) ) - break; - i++; - } - cond->n += len; - return table[i].id; -} - -static int COND_GetOne( struct cond_str *str, COND_input *cond ) -{ - int rc, len = 1; - WCHAR ch; - - str->data = &cond->str[cond->n]; - - ch = str->data[0]; - - switch( ch ) - { - case 0: return 0; - case '(': rc = COND_LPAR; break; - case ')': rc = COND_RPAR; break; - case '&': rc = COND_AMPER; break; - case '!': rc = COND_EXCLAM; break; - case '$': rc = COND_DOLLARS; break; - case '?': rc = COND_QUESTION; break; - case '%': rc = COND_PERCENT; break; - case ' ': rc = COND_SPACE; break; - case '=': rc = COND_EQ; break; - - case '~': - case '<': - case '>': - rc = COND_GetOperator( cond ); - if (!rc) - rc = COND_ERROR; - return rc; - default: - rc = 0; - } - - if ( rc ) - { - cond->n += len; - return rc; - } - - if (ch == '"' ) - { - LPCWSTR p = strchrW( str->data + 1, '"' ); - if (!p) return COND_ERROR; - len = p - str->data + 1; - rc = COND_LITER; - } - else if( COND_IsAlpha( ch ) ) - { - static const WCHAR szNot[] = {'N','O','T',0}; - static const WCHAR szAnd[] = {'A','N','D',0}; - static const WCHAR szXor[] = {'X','O','R',0}; - static const WCHAR szEqv[] = {'E','Q','V',0}; - static const WCHAR szImp[] = {'I','M','P',0}; - static const WCHAR szOr[] = {'O','R',0}; - - while( COND_IsIdent( str->data[len] ) ) - len++; - rc = COND_IDENT; - - if ( len == 3 ) - { - if ( !strncmpiW( str->data, szNot, len ) ) - rc = COND_NOT; - else if( !strncmpiW( str->data, szAnd, len ) ) - rc = COND_AND; - else if( !strncmpiW( str->data, szXor, len ) ) - rc = COND_XOR; - else if( !strncmpiW( str->data, szEqv, len ) ) - rc = COND_EQV; - else if( !strncmpiW( str->data, szImp, len ) ) - rc = COND_IMP; - } - else if( (len == 2) && !strncmpiW( str->data, szOr, len ) ) - rc = COND_OR; - } - else if( COND_IsNumber( ch ) ) - { - while( COND_IsNumber( str->data[len] ) ) - len++; - rc = COND_NUMBER; - } - else - { - ERR("Got unknown character %c(%x)\n",ch,ch); - return COND_ERROR; - } - - cond->n += len; - str->len = len; - - return rc; -} - -static int cond_lex( void *COND_lval, COND_input *cond ) -{ - int rc; - struct cond_str *str = COND_lval; - - do { - rc = COND_GetOne( str, cond ); - } while (rc == COND_SPACE); - - return rc; -} - -static LPWSTR COND_GetString( COND_input *cond, const struct cond_str *str ) -{ - LPWSTR ret; - - ret = cond_alloc( cond, (str->len+1) * sizeof (WCHAR) ); - if( ret ) - { - memcpy( ret, str->data, str->len * sizeof(WCHAR)); - ret[str->len]=0; - } - TRACE("Got identifier %s\n",debugstr_w(ret)); - return ret; -} - -static LPWSTR COND_GetLiteral( COND_input *cond, const struct cond_str *str ) -{ - LPWSTR ret; - - ret = cond_alloc( cond, (str->len-1) * sizeof (WCHAR) ); - if( ret ) - { - memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) ); - ret[str->len - 2]=0; - } - TRACE("Got literal %s\n",debugstr_w(ret)); - return ret; -} - -static void *cond_alloc( COND_input *cond, unsigned int sz ) -{ - struct list *mem; - - mem = msi_alloc( sizeof (struct list) + sz ); - if( !mem ) - return NULL; - - list_add_head( &(cond->mem), mem ); - return mem + 1; -} - -static void *cond_track_mem( COND_input *cond, void *ptr, unsigned int sz ) -{ - void *new_ptr; - - if( !ptr ) - return ptr; - - new_ptr = cond_alloc( cond, sz ); - if( !new_ptr ) - { - msi_free( ptr ); - return NULL; - } - - memcpy( new_ptr, ptr, sz ); - msi_free( ptr ); - return new_ptr; -} - -static void cond_free( void *ptr ) -{ - struct list *mem = (struct list *)ptr - 1; - - if( ptr ) - { - list_remove( mem ); - msi_free( mem ); - } -} - -static int cond_error(const char *str) -{ - TRACE("%s\n", str ); - return 0; -} - -MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition ) -{ - COND_input cond; - MSICONDITION r; - struct list *mem, *safety; - - TRACE("%s\n", debugstr_w( szCondition ) ); - - if (szCondition == NULL) return MSICONDITION_NONE; - - cond.package = package; - cond.str = szCondition; - cond.n = 0; - cond.result = MSICONDITION_ERROR; - - list_init( &cond.mem ); - - if ( !cond_parse( &cond ) ) - r = cond.result; - else - r = MSICONDITION_ERROR; - - LIST_FOR_EACH_SAFE( mem, safety, &cond.mem ) - { - /* The tracked memory lives directly after the list struct */ - void *ptr = mem + 1; - if ( r != MSICONDITION_ERROR ) - WARN( "condition parser failed to free up some memory: %p\n", ptr ); - cond_free( ptr ); - } - - TRACE("%i <- %s\n", r, debugstr_w(szCondition)); - return r; -} - -MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition ) -{ - MSIPACKAGE *package; - UINT ret; - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); - if( !package ) - return ERROR_INVALID_HANDLE; - ret = MSI_EvaluateConditionW( package, szCondition ); - msiobj_release( &package->hdr ); - return ret; -} - -MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition ) -{ - LPWSTR szwCond = NULL; - MSICONDITION r; - - szwCond = strdupAtoW( szCondition ); - if( szCondition && !szwCond ) - return MSICONDITION_ERROR; - - r = MsiEvaluateConditionW( hInstall, szwCond ); - msi_free( szwCond ); - return r; -} diff --git a/libmsi/custom.c b/libmsi/custom.c deleted file mode 100644 index 43c86f3..0000000 --- a/libmsi/custom.c +++ /dev/null @@ -1,1311 +0,0 @@ -/* - * Custom Action processing for the Microsoft Installer (msi.dll) - * - * Copyright 2005 Aric Stewart for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "config.h" - -#define COBJMACROS - -#include <stdarg.h> -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "msidefs.h" -#include "wingdi.h" -#include "winuser.h" -#include "objbase.h" -#include "oleauto.h" - -#include "msipriv.h" -#include "msiserver.h" -#include "wine/debug.h" -#include "wine/unicode.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -#define CUSTOM_ACTION_TYPE_MASK 0x3F - -typedef struct tagMSIRUNNINGACTION -{ - struct list entry; - HANDLE handle; - BOOL process; - LPWSTR name; -} MSIRUNNINGACTION; - -typedef UINT (WINAPI *MsiCustomActionEntryPoint)( MSIHANDLE ); - -static CRITICAL_SECTION msi_custom_action_cs; -static CRITICAL_SECTION_DEBUG msi_custom_action_cs_debug = -{ - 0, 0, &msi_custom_action_cs, - { &msi_custom_action_cs_debug.ProcessLocksList, - &msi_custom_action_cs_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": msi_custom_action_cs") } -}; -static CRITICAL_SECTION msi_custom_action_cs = { &msi_custom_action_cs_debug, -1, 0, 0, 0, 0 }; - -static struct list msi_pending_custom_actions = LIST_INIT( msi_pending_custom_actions ); - -UINT msi_schedule_action( MSIPACKAGE *package, UINT script, const WCHAR *action ) -{ - UINT count; - WCHAR **newbuf = NULL; - - if (script >= SCRIPT_MAX) - { - FIXME("Unknown script requested %u\n", script); - return ERROR_FUNCTION_FAILED; - } - TRACE("Scheduling action %s in script %u\n", debugstr_w(action), script); - - count = package->script->ActionCount[script]; - package->script->ActionCount[script]++; - if (count != 0) newbuf = msi_realloc( package->script->Actions[script], - package->script->ActionCount[script] * sizeof(WCHAR *) ); - else newbuf = msi_alloc( sizeof(WCHAR *) ); - - newbuf[count] = strdupW( action ); - package->script->Actions[script] = newbuf; - return ERROR_SUCCESS; -} - -UINT msi_register_unique_action( MSIPACKAGE *package, const WCHAR *action ) -{ - UINT count; - WCHAR **newbuf = NULL; - - if (!package->script) return FALSE; - - TRACE("Registering %s as unique action\n", debugstr_w(action)); - - count = package->script->UniqueActionsCount; - package->script->UniqueActionsCount++; - if (count != 0) newbuf = msi_realloc( package->script->UniqueActions, - package->script->UniqueActionsCount * sizeof(WCHAR *) ); - else newbuf = msi_alloc( sizeof(WCHAR *) ); - - newbuf[count] = strdupW( action ); - package->script->UniqueActions = newbuf; - return ERROR_SUCCESS; -} - -BOOL msi_action_is_unique( const MSIPACKAGE *package, const WCHAR *action ) -{ - UINT i; - - if (!package->script) return FALSE; - - for (i = 0; i < package->script->UniqueActionsCount; i++) - { - if (!strcmpW( package->script->UniqueActions[i], action )) return TRUE; - } - return FALSE; -} - -static BOOL check_execution_scheduling_options(MSIPACKAGE *package, LPCWSTR action, UINT options) -{ - if (!package->script) - return TRUE; - - if ((options & msidbCustomActionTypeClientRepeat) == - msidbCustomActionTypeClientRepeat) - { - if (!(package->script->InWhatSequence & SEQUENCE_UI && - package->script->InWhatSequence & SEQUENCE_EXEC)) - { - TRACE("Skipping action due to dbCustomActionTypeClientRepeat option.\n"); - return FALSE; - } - } - else if (options & msidbCustomActionTypeFirstSequence) - { - if (package->script->InWhatSequence & SEQUENCE_UI && - package->script->InWhatSequence & SEQUENCE_EXEC ) - { - TRACE("Skipping action due to msidbCustomActionTypeFirstSequence option.\n"); - return FALSE; - } - } - else if (options & msidbCustomActionTypeOncePerProcess) - { - if (msi_action_is_unique(package, action)) - { - TRACE("Skipping action due to msidbCustomActionTypeOncePerProcess option.\n"); - return FALSE; - } - else - msi_register_unique_action(package, action); - } - - return TRUE; -} - -/* stores the following properties before the action: - * - * [CustomActionData<=>UserSID<=>ProductCode]Action - */ -static LPWSTR msi_get_deferred_action(LPCWSTR action, LPCWSTR actiondata, - LPCWSTR usersid, LPCWSTR prodcode) -{ - LPWSTR deferred; - DWORD len; - - static const WCHAR format[] = { - '[','%','s','<','=','>','%','s','<','=','>','%','s',']','%','s',0 - }; - - if (!actiondata) - return strdupW(action); - - len = lstrlenW(action) + lstrlenW(actiondata) + - lstrlenW(usersid) + lstrlenW(prodcode) + - lstrlenW(format) - 7; - deferred = msi_alloc(len * sizeof(WCHAR)); - - sprintfW(deferred, format, actiondata, usersid, prodcode, action); - return deferred; -} - -static void set_deferred_action_props(MSIPACKAGE *package, LPWSTR deferred_data) -{ - LPWSTR end, beg = deferred_data + 1; - - static const WCHAR sep[] = {'<','=','>',0}; - - end = strstrW(beg, sep); - *end = '\0'; - msi_set_property(package->db, szCustomActionData, beg); - beg = end + 3; - - end = strstrW(beg, sep); - *end = '\0'; - msi_set_property(package->db, szUserSID, beg); - beg = end + 3; - - end = strchrW(beg, ']'); - *end = '\0'; - msi_set_property(package->db, szProductCode, beg); -} - -static MSIBINARY *create_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL dll ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','B','i' ,'n','a','r','y','`',' ','W','H','E','R','E',' ', - '`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0}; - MSIRECORD *row; - MSIBINARY *binary; - HANDLE file; - CHAR buffer[1024]; - WCHAR fmt[MAX_PATH], tmpfile[MAX_PATH]; - DWORD sz = MAX_PATH, write; - UINT r; - - if (msi_get_property(package->db, szTempFolder, fmt, &sz) != ERROR_SUCCESS) - GetTempPathW(MAX_PATH, fmt); - - if (!GetTempFileNameW( fmt, szMsi, 0, tmpfile )) - { - TRACE("unable to create temp file %s (%u)\n", debugstr_w(tmpfile), GetLastError()); - return NULL; - } - - row = MSI_QueryGetRecord(package->db, query, source); - if (!row) - return NULL; - - if (!(binary = msi_alloc_zero( sizeof(MSIBINARY) ))) - { - msiobj_release( &row->hdr ); - return NULL; - } - file = CreateFileW( tmpfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); - if (file == INVALID_HANDLE_VALUE) - { - msiobj_release( &row->hdr ); - msi_free( binary ); - return NULL; - } - do - { - sz = sizeof(buffer); - r = MSI_RecordReadStream( row, 2, buffer, &sz ); - if (r != ERROR_SUCCESS) - { - ERR("Failed to get stream\n"); - break; - } - WriteFile( file, buffer, sz, &write, NULL ); - } while (sz == sizeof buffer); - - CloseHandle( file ); - msiobj_release( &row->hdr ); - if (r != ERROR_SUCCESS) - { - DeleteFileW( tmpfile ); - msi_free( binary ); - return NULL; - } - - /* keep a reference to prevent the dll from being unloaded */ - if (dll && !(binary->module = LoadLibraryW( tmpfile ))) - { - WARN( "failed to load dll %s (%u)\n", debugstr_w( tmpfile ), GetLastError() ); - } - binary->source = strdupW( source ); - binary->tmpfile = strdupW( tmpfile ); - list_add_tail( &package->binaries, &binary->entry ); - return binary; -} - -static MSIBINARY *get_temp_binary( MSIPACKAGE *package, LPCWSTR source, BOOL dll ) -{ - MSIBINARY *binary; - - LIST_FOR_EACH_ENTRY( binary, &package->binaries, MSIBINARY, entry ) - { - if (!strcmpW( binary->source, source )) - return binary; - } - - return create_temp_binary( package, source, dll ); -} - -static void file_running_action(MSIPACKAGE* package, HANDLE Handle, - BOOL process, LPCWSTR name) -{ - MSIRUNNINGACTION *action; - - action = msi_alloc( sizeof(MSIRUNNINGACTION) ); - - action->handle = Handle; - action->process = process; - action->name = strdupW(name); - - list_add_tail( &package->RunningActions, &action->entry ); -} - -static UINT custom_get_process_return( HANDLE process ) -{ - DWORD rc = 0; - - GetExitCodeProcess( process, &rc ); - TRACE("exit code is %u\n", rc); - if (rc != 0) - return ERROR_FUNCTION_FAILED; - return ERROR_SUCCESS; -} - -static UINT custom_get_thread_return( MSIPACKAGE *package, HANDLE thread ) -{ - DWORD rc = 0; - - GetExitCodeThread( thread, &rc ); - - switch (rc) - { - case ERROR_FUNCTION_NOT_CALLED: - case ERROR_SUCCESS: - case ERROR_INSTALL_USEREXIT: - case ERROR_INSTALL_FAILURE: - return rc; - case ERROR_NO_MORE_ITEMS: - return ERROR_SUCCESS; - case ERROR_INSTALL_SUSPEND: - ACTION_ForceReboot( package ); - return ERROR_SUCCESS; - default: - ERR("Invalid Return Code %d\n",rc); - return ERROR_INSTALL_FAILURE; - } -} - -static UINT wait_process_handle(MSIPACKAGE* package, UINT type, - HANDLE ProcessHandle, LPCWSTR name) -{ - UINT rc = ERROR_SUCCESS; - - if (!(type & msidbCustomActionTypeAsync)) - { - TRACE("waiting for %s\n", debugstr_w(name)); - - msi_dialog_check_messages(ProcessHandle); - - if (!(type & msidbCustomActionTypeContinue)) - rc = custom_get_process_return(ProcessHandle); - - CloseHandle(ProcessHandle); - } - else - { - TRACE("%s running in background\n", debugstr_w(name)); - - if (!(type & msidbCustomActionTypeContinue)) - file_running_action(package, ProcessHandle, TRUE, name); - else - CloseHandle(ProcessHandle); - } - - return rc; -} - -typedef struct _msi_custom_action_info { - struct list entry; - LONG refs; - MSIPACKAGE *package; - LPWSTR source; - LPWSTR target; - HANDLE handle; - LPWSTR action; - INT type; - GUID guid; -} msi_custom_action_info; - -static void release_custom_action_data( msi_custom_action_info *info ) -{ - EnterCriticalSection( &msi_custom_action_cs ); - - if (!--info->refs) - { - list_remove( &info->entry ); - if (info->handle) - CloseHandle( info->handle ); - msi_free( info->action ); - msi_free( info->source ); - msi_free( info->target ); - msiobj_release( &info->package->hdr ); - msi_free( info ); - } - - LeaveCriticalSection( &msi_custom_action_cs ); -} - -/* must be called inside msi_custom_action_cs if info is in the pending custom actions list */ -static void addref_custom_action_data( msi_custom_action_info *info ) -{ - info->refs++; - } - -static UINT wait_thread_handle( msi_custom_action_info *info ) -{ - UINT rc = ERROR_SUCCESS; - - if (!(info->type & msidbCustomActionTypeAsync)) - { - TRACE("waiting for %s\n", debugstr_w( info->action )); - - msi_dialog_check_messages( info->handle ); - - if (!(info->type & msidbCustomActionTypeContinue)) - rc = custom_get_thread_return( info->package, info->handle ); - - release_custom_action_data( info ); - } - else - { - TRACE("%s running in background\n", debugstr_w( info->action )); - } - - return rc; -} - -static msi_custom_action_info *find_action_by_guid( const GUID *guid ) -{ - msi_custom_action_info *info; - BOOL found = FALSE; - - EnterCriticalSection( &msi_custom_action_cs ); - - LIST_FOR_EACH_ENTRY( info, &msi_pending_custom_actions, msi_custom_action_info, entry ) - { - if (IsEqualGUID( &info->guid, guid )) - { - addref_custom_action_data( info ); - found = TRUE; - break; - } - } - - LeaveCriticalSection( &msi_custom_action_cs ); - - if (!found) - return NULL; - - return info; -} - -static void handle_msi_break( LPCWSTR target ) -{ - LPWSTR msg; - WCHAR val[MAX_PATH]; - - static const WCHAR MsiBreak[] = { 'M','s','i','B','r','e','a','k',0 }; - static const WCHAR WindowsInstaller[] = { - 'W','i','n','d','o','w','s',' ','I','n','s','t','a','l','l','e','r',0 - }; - - static const WCHAR format[] = { - 'T','o',' ','d','e','b','u','g',' ','y','o','u','r',' ', - 'c','u','s','t','o','m',' ','a','c','t','i','o','n',',',' ', - 'a','t','t','a','c','h',' ','y','o','u','r',' ','d','e','b','u','g','g','e','r',' ', - 't','o',' ','p','r','o','c','e','s','s',' ','%','i',' ','(','0','x','%','X',')',' ', - 'a','n','d',' ','p','r','e','s','s',' ','O','K',0 - }; - - if( !GetEnvironmentVariableW( MsiBreak, val, MAX_PATH )) - return; - - if( strcmpiW( val, target )) - return; - - msg = msi_alloc( (lstrlenW(format) + 10) * sizeof(WCHAR) ); - if (!msg) - return; - - wsprintfW( msg, format, GetCurrentProcessId(), GetCurrentProcessId()); - MessageBoxW( NULL, msg, WindowsInstaller, MB_OK); - msi_free(msg); - DebugBreak(); -} - -static inline UINT CUSTOMPROC_wrapper( MsiCustomActionEntryPoint proc, MSIHANDLE handle ) -{ - return proc(handle); -} - -static DWORD ACTION_CallDllFunction( const GUID *guid ) -{ - return ERROR_FUNCTION_FAILED; -} - -static DWORD WINAPI DllThread( LPVOID arg ) -{ - LPGUID guid = arg; - DWORD rc = 0; - - TRACE("custom action (%x) started\n", GetCurrentThreadId() ); - - rc = ACTION_CallDllFunction( guid ); - - TRACE("custom action (%x) returned %i\n", GetCurrentThreadId(), rc ); - - MsiCloseAllHandles(); - return rc; -} - -static DWORD ACTION_CAInstallPackage(const GUID *guid) -{ - msi_custom_action_info *info; - UINT r = ERROR_FUNCTION_FAILED; - INSTALLUILEVEL old_level; - - info = find_action_by_guid(guid); - if (!info) - { - ERR("failed to find action %s\n", debugstr_guid(guid)); - return r; - } - - old_level = MsiSetInternalUI(INSTALLUILEVEL_BASIC, NULL); - r = MsiInstallProductW(info->source, info->target); - MsiSetInternalUI(old_level, NULL); - - release_custom_action_data(info); - - return r; -} - -static DWORD WINAPI ConcurrentInstallThread(LPVOID arg) -{ - LPGUID guid = arg; - DWORD rc; - - TRACE("concurrent installation (%x) started\n", GetCurrentThreadId()); - - rc = ACTION_CAInstallPackage(guid); - - TRACE("concurrent installation (%x) returned %i\n", GetCurrentThreadId(), rc); - - MsiCloseAllHandles(); - return rc; -} - -static msi_custom_action_info *do_msidbCustomActionTypeDll( - MSIPACKAGE *package, INT type, LPCWSTR source, LPCWSTR target, LPCWSTR action ) -{ - msi_custom_action_info *info; - - info = msi_alloc( sizeof *info ); - if (!info) - return NULL; - - msiobj_addref( &package->hdr ); - info->refs = 2; /* 1 for our caller and 1 for thread we created */ - info->package = package; - info->type = type; - info->target = strdupW( target ); - info->source = strdupW( source ); - info->action = strdupW( action ); - CoCreateGuid( &info->guid ); - - EnterCriticalSection( &msi_custom_action_cs ); - list_add_tail( &msi_pending_custom_actions, &info->entry ); - LeaveCriticalSection( &msi_custom_action_cs ); - - info->handle = CreateThread( NULL, 0, DllThread, &info->guid, 0, NULL ); - if (!info->handle) - { - /* release both references */ - release_custom_action_data( info ); - release_custom_action_data( info ); - return NULL; - } - - return info; -} - -static msi_custom_action_info *do_msidbCAConcurrentInstall( - MSIPACKAGE *package, INT type, LPCWSTR source, LPCWSTR target, LPCWSTR action) -{ - msi_custom_action_info *info; - - info = msi_alloc( sizeof *info ); - if (!info) - return NULL; - - msiobj_addref( &package->hdr ); - info->refs = 2; /* 1 for our caller and 1 for thread we created */ - info->package = package; - info->type = type; - info->target = strdupW( target ); - info->source = strdupW( source ); - info->action = strdupW( action ); - CoCreateGuid( &info->guid ); - - EnterCriticalSection( &msi_custom_action_cs ); - list_add_tail( &msi_pending_custom_actions, &info->entry ); - LeaveCriticalSection( &msi_custom_action_cs ); - - info->handle = CreateThread( NULL, 0, ConcurrentInstallThread, &info->guid, 0, NULL ); - if (!info->handle) - { - /* release both references */ - release_custom_action_data( info ); - release_custom_action_data( info ); - return NULL; - } - - return info; -} - -static UINT HANDLE_CustomType23(MSIPACKAGE *package, LPCWSTR source, - LPCWSTR target, const INT type, LPCWSTR action) -{ - msi_custom_action_info *info; - WCHAR package_path[MAX_PATH]; - DWORD size; - - size = MAX_PATH; - msi_get_property(package->db, szSourceDir, package_path, &size); - lstrcatW(package_path, szBackSlash); - lstrcatW(package_path, source); - - TRACE("Installing package %s concurrently\n", debugstr_w(package_path)); - - info = do_msidbCAConcurrentInstall(package, type, package_path, target, action); - return wait_thread_handle(info); -} - -static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source, - LPCWSTR target, const INT type, LPCWSTR action) -{ - msi_custom_action_info *info; - MSIBINARY *binary; - - if (!(binary = get_temp_binary( package, source, TRUE ))) - return ERROR_FUNCTION_FAILED; - - TRACE("Calling function %s from %s\n", debugstr_w(target), debugstr_w(binary->tmpfile)); - - info = do_msidbCustomActionTypeDll( package, type, binary->tmpfile, target, action ); - return wait_thread_handle( info ); -} - -static HANDLE execute_command( const WCHAR *app, WCHAR *arg, const WCHAR *dir ) -{ - static const WCHAR dotexeW[] = {'.','e','x','e',0}; - STARTUPINFOW si; - PROCESS_INFORMATION info; - WCHAR *exe = NULL, *cmd = NULL, *p; - BOOL ret; - - if (app) - { - int len_arg = 0; - DWORD len_exe; - - if (!(exe = msi_alloc( MAX_PATH * sizeof(WCHAR) ))) return INVALID_HANDLE_VALUE; - len_exe = SearchPathW( NULL, app, dotexeW, MAX_PATH, exe, NULL ); - if (len_exe >= MAX_PATH) - { - msi_free( exe ); - if (!(exe = msi_alloc( len_exe * sizeof(WCHAR) ))) return INVALID_HANDLE_VALUE; - len_exe = SearchPathW( NULL, app, dotexeW, len_exe, exe, NULL ); - } - if (!len_exe) - { - WARN("can't find executable %u\n", GetLastError()); - msi_free( exe ); - return INVALID_HANDLE_VALUE; - } - - if (arg) len_arg = strlenW( arg ); - if (!(cmd = msi_alloc( (len_exe + len_arg + 4) * sizeof(WCHAR) ))) - { - msi_free( exe ); - return INVALID_HANDLE_VALUE; - } - p = cmd; - if (strchrW( exe, ' ' )) - { - *p++ = '\"'; - memcpy( p, exe, len_exe * sizeof(WCHAR) ); - p += len_exe; - *p++ = '\"'; - *p = 0; - } - else - { - strcpyW( p, exe ); - p += len_exe; - } - if (arg) - { - *p++ = ' '; - memcpy( p, arg, len_arg * sizeof(WCHAR) ); - p[len_arg] = 0; - } - } - memset( &si, 0, sizeof(STARTUPINFOW) ); - ret = CreateProcessW( exe, exe ? cmd : arg, NULL, NULL, FALSE, 0, NULL, dir, &si, &info ); - msi_free( cmd ); - msi_free( exe ); - if (!ret) - { - WARN("unable to execute command %u\n", GetLastError()); - return INVALID_HANDLE_VALUE; - } - CloseHandle( info.hThread ); - return info.hProcess; -} - -static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source, - LPCWSTR target, const INT type, LPCWSTR action) -{ - MSIBINARY *binary; - HANDLE handle; - WCHAR *arg; - - if (!(binary = get_temp_binary( package, source, FALSE ))) return ERROR_FUNCTION_FAILED; - - deformat_string( package, target, &arg ); - TRACE("exe %s arg %s\n", debugstr_w(binary->tmpfile), debugstr_w(arg)); - - handle = execute_command( binary->tmpfile, arg, szCRoot ); - msi_free( arg ); - if (handle == INVALID_HANDLE_VALUE) return ERROR_SUCCESS; - return wait_process_handle( package, type, handle, action ); -} - -static UINT HANDLE_CustomType17(MSIPACKAGE *package, LPCWSTR source, - LPCWSTR target, const INT type, LPCWSTR action) -{ - msi_custom_action_info *info; - MSIFILE *file; - - TRACE("%s %s\n", debugstr_w(source), debugstr_w(target)); - - file = msi_get_loaded_file( package, source ); - if (!file) - { - ERR("invalid file key %s\n", debugstr_w( source )); - return ERROR_FUNCTION_FAILED; - } - - info = do_msidbCustomActionTypeDll( package, type, file->TargetPath, target, action ); - return wait_thread_handle( info ); -} - -static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source, - LPCWSTR target, const INT type, LPCWSTR action) -{ - MSIFILE *file; - HANDLE handle; - WCHAR *arg; - - if (!(file = msi_get_loaded_file( package, source ))) return ERROR_FUNCTION_FAILED; - - deformat_string( package, target, &arg ); - TRACE("exe %s arg %s\n", debugstr_w(file->TargetPath), debugstr_w(arg)); - - handle = execute_command( file->TargetPath, arg, szCRoot ); - msi_free( arg ); - if (handle == INVALID_HANDLE_VALUE) return ERROR_SUCCESS; - return wait_process_handle( package, type, handle, action ); -} - -static UINT HANDLE_CustomType19(MSIPACKAGE *package, LPCWSTR source, - LPCWSTR target, const INT type, LPCWSTR action) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ', - 'F','R','O','M',' ','`','E','r','r','o','r','`',' ', - 'W','H','E','R','E',' ','`','E','r','r','o','r','`',' ','=',' ', - '%','s',0 - }; - MSIRECORD *row = 0; - LPWSTR deformated = NULL; - - deformat_string( package, target, &deformated ); - - /* first try treat the error as a number */ - row = MSI_QueryGetRecord( package->db, query, deformated ); - if( row ) - { - LPCWSTR error = MSI_RecordGetString( row, 1 ); - if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE) - MessageBoxW( NULL, error, NULL, MB_OK ); - msiobj_release( &row->hdr ); - } - else if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE) - MessageBoxW( NULL, deformated, NULL, MB_OK ); - - msi_free( deformated ); - - return ERROR_INSTALL_FAILURE; -} - -static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source, - LPCWSTR target, const INT type, LPCWSTR action) -{ - WCHAR *exe, *arg; - HANDLE handle; - - if (!(exe = msi_dup_property( package->db, source ))) return ERROR_SUCCESS; - - deformat_string( package, target, &arg ); - TRACE("exe %s arg %s\n", debugstr_w(exe), debugstr_w(arg)); - - handle = execute_command( exe, arg, szCRoot ); - msi_free( arg ); - if (handle == INVALID_HANDLE_VALUE) return ERROR_SUCCESS; - return wait_process_handle( package, type, handle, action ); -} - -static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source, - LPCWSTR target, const INT type, LPCWSTR action) -{ - const WCHAR *workingdir = NULL; - HANDLE handle; - WCHAR *cmd; - - if (source) - { - workingdir = msi_get_target_folder( package, source ); - if (!workingdir) return ERROR_FUNCTION_FAILED; - } - deformat_string( package, target, &cmd ); - if (!cmd) return ERROR_FUNCTION_FAILED; - - TRACE("cmd %s dir %s\n", debugstr_w(cmd), debugstr_w(workingdir)); - - handle = execute_command( NULL, cmd, workingdir ); - msi_free( cmd ); - if (handle == INVALID_HANDLE_VALUE) return ERROR_SUCCESS; - return wait_process_handle( package, type, handle, action ); -} - -static DWORD ACTION_CallScript( const GUID *guid ) -{ - msi_custom_action_info *info; - MSIHANDLE hPackage; - UINT r = ERROR_FUNCTION_FAILED; - - info = find_action_by_guid( guid ); - if (!info) - { - ERR("failed to find action %s\n", debugstr_guid( guid) ); - return ERROR_FUNCTION_FAILED; - } - - TRACE("function %s, script %s\n", debugstr_w( info->target ), debugstr_w( info->source ) ); - - hPackage = alloc_msihandle( &info->package->hdr ); - if (hPackage) - { - r = call_script( hPackage, info->type, info->source, info->target, info->action ); - TRACE("script returned %u\n", r); - MsiCloseHandle( hPackage ); - } - else - ERR("failed to create handle for %p\n", info->package ); - - release_custom_action_data( info ); - return r; -} - -static DWORD WINAPI ScriptThread( LPVOID arg ) -{ - LPGUID guid = arg; - DWORD rc; - - TRACE("custom action (%x) started\n", GetCurrentThreadId() ); - - rc = ACTION_CallScript( guid ); - - TRACE("custom action (%x) returned %i\n", GetCurrentThreadId(), rc ); - - MsiCloseAllHandles(); - return rc; -} - -static msi_custom_action_info *do_msidbCustomActionTypeScript( - MSIPACKAGE *package, INT type, LPCWSTR script, LPCWSTR function, LPCWSTR action ) -{ - msi_custom_action_info *info; - - info = msi_alloc( sizeof *info ); - if (!info) - return NULL; - - msiobj_addref( &package->hdr ); - info->refs = 2; /* 1 for our caller and 1 for thread we created */ - info->package = package; - info->type = type; - info->target = strdupW( function ); - info->source = strdupW( script ); - info->action = strdupW( action ); - CoCreateGuid( &info->guid ); - - EnterCriticalSection( &msi_custom_action_cs ); - list_add_tail( &msi_pending_custom_actions, &info->entry ); - LeaveCriticalSection( &msi_custom_action_cs ); - - info->handle = CreateThread( NULL, 0, ScriptThread, &info->guid, 0, NULL ); - if (!info->handle) - { - /* release both references */ - release_custom_action_data( info ); - release_custom_action_data( info ); - return NULL; - } - - return info; -} - -static UINT HANDLE_CustomType37_38(MSIPACKAGE *package, LPCWSTR source, - LPCWSTR target, const INT type, LPCWSTR action) -{ - msi_custom_action_info *info; - - TRACE("%s %s\n", debugstr_w(source), debugstr_w(target)); - - info = do_msidbCustomActionTypeScript( package, type, target, NULL, action ); - return wait_thread_handle( info ); -} - -static UINT HANDLE_CustomType5_6(MSIPACKAGE *package, LPCWSTR source, - LPCWSTR target, const INT type, LPCWSTR action) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','B','i' ,'n','a','r','y','`',' ','W','H','E','R','E',' ', - '`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0}; - MSIRECORD *row = 0; - msi_custom_action_info *info; - CHAR *buffer = NULL; - WCHAR *bufferw = NULL; - DWORD sz = 0; - UINT r; - - TRACE("%s %s\n", debugstr_w(source), debugstr_w(target)); - - row = MSI_QueryGetRecord(package->db, query, source); - if (!row) - return ERROR_FUNCTION_FAILED; - - r = MSI_RecordReadStream(row, 2, NULL, &sz); - if (r != ERROR_SUCCESS) return r; - - buffer = msi_alloc( sz + 1 ); - if (!buffer) return ERROR_FUNCTION_FAILED; - - r = MSI_RecordReadStream(row, 2, buffer, &sz); - if (r != ERROR_SUCCESS) - goto done; - - buffer[sz] = 0; - bufferw = strdupAtoW(buffer); - if (!bufferw) - { - r = ERROR_FUNCTION_FAILED; - goto done; - } - - info = do_msidbCustomActionTypeScript( package, type, bufferw, target, action ); - r = wait_thread_handle( info ); - -done: - msi_free(bufferw); - msi_free(buffer); - return r; -} - -static UINT HANDLE_CustomType21_22(MSIPACKAGE *package, LPCWSTR source, - LPCWSTR target, const INT type, LPCWSTR action) -{ - msi_custom_action_info *info; - MSIFILE *file; - HANDLE hFile; - DWORD sz, szHighWord = 0, read; - CHAR *buffer=NULL; - WCHAR *bufferw=NULL; - BOOL bRet; - UINT r; - - TRACE("%s %s\n", debugstr_w(source), debugstr_w(target)); - - file = msi_get_loaded_file(package, source); - if (!file) - { - ERR("invalid file key %s\n", debugstr_w(source)); - return ERROR_FUNCTION_FAILED; - } - - hFile = CreateFileW(file->TargetPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - if (hFile == INVALID_HANDLE_VALUE) return ERROR_FUNCTION_FAILED; - - sz = GetFileSize(hFile, &szHighWord); - if (sz == INVALID_FILE_SIZE || szHighWord != 0) - { - CloseHandle(hFile); - return ERROR_FUNCTION_FAILED; - } - buffer = msi_alloc( sz + 1 ); - if (!buffer) - { - CloseHandle(hFile); - return ERROR_FUNCTION_FAILED; - } - bRet = ReadFile(hFile, buffer, sz, &read, NULL); - CloseHandle(hFile); - if (!bRet) - { - r = ERROR_FUNCTION_FAILED; - goto done; - } - buffer[read] = 0; - bufferw = strdupAtoW(buffer); - if (!bufferw) - { - r = ERROR_FUNCTION_FAILED; - goto done; - } - info = do_msidbCustomActionTypeScript( package, type, bufferw, target, action ); - r = wait_thread_handle( info ); - -done: - msi_free(bufferw); - msi_free(buffer); - return r; -} - -static UINT HANDLE_CustomType53_54(MSIPACKAGE *package, LPCWSTR source, - LPCWSTR target, const INT type, LPCWSTR action) -{ - msi_custom_action_info *info; - WCHAR *prop; - - TRACE("%s %s\n", debugstr_w(source), debugstr_w(target)); - - prop = msi_dup_property( package->db, source ); - if (!prop) return ERROR_SUCCESS; - - info = do_msidbCustomActionTypeScript( package, type, prop, NULL, action ); - msi_free(prop); - return wait_thread_handle( info ); -} - -static BOOL action_type_matches_script( MSIPACKAGE *package, UINT type, UINT script ) -{ - switch (script) - { - case SCRIPT_NONE: - case SCRIPT_INSTALL: - return !(type & msidbCustomActionTypeCommit) && !(type & msidbCustomActionTypeRollback); - case SCRIPT_COMMIT: - return (type & msidbCustomActionTypeCommit); - case SCRIPT_ROLLBACK: - return (type & msidbCustomActionTypeRollback); - default: - ERR("unhandled script %u\n", script); - } - return FALSE; -} - -static UINT defer_custom_action( MSIPACKAGE *package, const WCHAR *action, UINT type ) -{ - WCHAR *actiondata = msi_dup_property( package->db, action ); - WCHAR *usersid = msi_dup_property( package->db, szUserSID ); - WCHAR *prodcode = msi_dup_property( package->db, szProductCode ); - WCHAR *deferred = msi_get_deferred_action( action, actiondata, usersid, prodcode ); - - if (!deferred) - { - msi_free( actiondata ); - msi_free( usersid ); - msi_free( prodcode ); - return ERROR_OUTOFMEMORY; - } - if (type & msidbCustomActionTypeCommit) - { - TRACE("deferring commit action\n"); - msi_schedule_action( package, SCRIPT_COMMIT, deferred ); - } - else if (type & msidbCustomActionTypeRollback) - { - TRACE("deferring rollback action\n"); - msi_schedule_action( package, SCRIPT_ROLLBACK, deferred ); - } - else - { - TRACE("deferring install action\n"); - msi_schedule_action( package, SCRIPT_INSTALL, deferred ); - } - - msi_free( actiondata ); - msi_free( usersid ); - msi_free( prodcode ); - msi_free( deferred ); - return ERROR_SUCCESS; -} - -UINT ACTION_CustomAction(MSIPACKAGE *package, LPCWSTR action, UINT script, BOOL execute) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','C','u','s','t','o','m','A','c','t','i','o','n','`',' ','W','H','E','R','E',' ', - '`','A','c','t','i' ,'o','n','`',' ','=',' ','\'','%','s','\'',0}; - UINT rc = ERROR_SUCCESS; - MSIRECORD *row; - UINT type; - LPCWSTR source, target; - LPWSTR ptr, deferred_data = NULL; - LPWSTR deformated = NULL, action_copy = strdupW(action); - - /* deferred action: [properties]Action */ - if ((ptr = strrchrW(action_copy, ']'))) - { - deferred_data = action_copy; - action = ptr + 1; - } - - row = MSI_QueryGetRecord( package->db, query, action ); - if (!row) - { - msi_free(action_copy); - return ERROR_CALL_NOT_IMPLEMENTED; - } - - type = MSI_RecordGetInteger(row,2); - source = MSI_RecordGetString(row,3); - target = MSI_RecordGetString(row,4); - - TRACE("Handling custom action %s (%x %s %s)\n",debugstr_w(action),type, - debugstr_w(source), debugstr_w(target)); - - /* handle some of the deferred actions */ - if (type & msidbCustomActionTypeTSAware) - FIXME("msidbCustomActionTypeTSAware not handled\n"); - - if (type & msidbCustomActionTypeInScript) - { - if (type & msidbCustomActionTypeNoImpersonate) - WARN("msidbCustomActionTypeNoImpersonate not handled\n"); - - if (!execute || !action_type_matches_script( package, type, script )) - { - rc = defer_custom_action( package, action, type ); - goto end; - } - else - { - LPWSTR actiondata = msi_dup_property( package->db, action ); - - if (type & msidbCustomActionTypeInScript) - package->scheduled_action_running = TRUE; - - if (type & msidbCustomActionTypeCommit) - package->commit_action_running = TRUE; - - if (type & msidbCustomActionTypeRollback) - package->rollback_action_running = TRUE; - - if (deferred_data) - set_deferred_action_props(package, deferred_data); - else if (actiondata) - msi_set_property(package->db, szCustomActionData, actiondata); - else - msi_set_property(package->db, szCustomActionData, szEmpty); - - msi_free(actiondata); - } - } - else if (!check_execution_scheduling_options(package,action,type)) - { - rc = ERROR_SUCCESS; - goto end; - } - - switch (type & CUSTOM_ACTION_TYPE_MASK) - { - case 1: /* DLL file stored in a Binary table stream */ - rc = HANDLE_CustomType1(package,source,target,type,action); - break; - case 2: /* EXE file stored in a Binary table stream */ - rc = HANDLE_CustomType2(package,source,target,type,action); - break; - case 18: /*EXE file installed with package */ - rc = HANDLE_CustomType18(package,source,target,type,action); - break; - case 19: /* Error that halts install */ - rc = HANDLE_CustomType19(package,source,target,type,action); - break; - case 17: - rc = HANDLE_CustomType17(package,source,target,type,action); - break; - case 23: /* installs another package in the source tree */ - deformat_string(package,target,&deformated); - rc = HANDLE_CustomType23(package,source,deformated,type,action); - msi_free(deformated); - break; - case 50: /*EXE file specified by a property value */ - rc = HANDLE_CustomType50(package,source,target,type,action); - break; - case 34: /*EXE to be run in specified directory */ - rc = HANDLE_CustomType34(package,source,target,type,action); - break; - case 35: /* Directory set with formatted text. */ - deformat_string(package,target,&deformated); - MSI_SetTargetPathW(package, source, deformated); - msi_free(deformated); - break; - case 51: /* Property set with formatted text. */ - if (!source) - break; - - deformat_string(package,target,&deformated); - rc = msi_set_property( package->db, source, deformated ); - if (rc == ERROR_SUCCESS && !strcmpW( source, szSourceDir )) - msi_reset_folders( package, TRUE ); - msi_free(deformated); - break; - case 37: /* JScript/VBScript text stored in target column. */ - case 38: - rc = HANDLE_CustomType37_38(package,source,target,type,action); - break; - case 5: - case 6: /* JScript/VBScript file stored in a Binary table stream. */ - rc = HANDLE_CustomType5_6(package,source,target,type,action); - break; - case 21: /* JScript/VBScript file installed with the product. */ - case 22: - rc = HANDLE_CustomType21_22(package,source,target,type,action); - break; - case 53: /* JScript/VBScript text specified by a property value. */ - case 54: - rc = HANDLE_CustomType53_54(package,source,target,type,action); - break; - default: - FIXME("unhandled action type %u (%s %s)\n", type & CUSTOM_ACTION_TYPE_MASK, - debugstr_w(source), debugstr_w(target)); - } - -end: - package->scheduled_action_running = FALSE; - package->commit_action_running = FALSE; - package->rollback_action_running = FALSE; - msi_free(action_copy); - msiobj_release(&row->hdr); - return rc; -} - -void ACTION_FinishCustomActions(const MSIPACKAGE* package) -{ - struct list *item; - HANDLE *wait_handles; - unsigned int handle_count, i; - msi_custom_action_info *info, *cursor; - - while ((item = list_head( &package->RunningActions ))) - { - MSIRUNNINGACTION *action = LIST_ENTRY( item, MSIRUNNINGACTION, entry ); - - list_remove( &action->entry ); - - TRACE("waiting for %s\n", debugstr_w( action->name ) ); - msi_dialog_check_messages( action->handle ); - - CloseHandle( action->handle ); - msi_free( action->name ); - msi_free( action ); - } - - EnterCriticalSection( &msi_custom_action_cs ); - - handle_count = list_count( &msi_pending_custom_actions ); - wait_handles = msi_alloc( handle_count * sizeof(HANDLE) ); - - handle_count = 0; - LIST_FOR_EACH_ENTRY_SAFE( info, cursor, &msi_pending_custom_actions, msi_custom_action_info, entry ) - { - if (info->package == package ) - { - if (DuplicateHandle(GetCurrentProcess(), info->handle, GetCurrentProcess(), &wait_handles[handle_count], SYNCHRONIZE, FALSE, 0)) - handle_count++; - } - } - - LeaveCriticalSection( &msi_custom_action_cs ); - - for (i = 0; i < handle_count; i++) - { - msi_dialog_check_messages( wait_handles[i] ); - CloseHandle( wait_handles[i] ); - } - msi_free( wait_handles ); - - EnterCriticalSection( &msi_custom_action_cs ); - LIST_FOR_EACH_ENTRY_SAFE( info, cursor, &msi_pending_custom_actions, msi_custom_action_info, entry ) - { - if (info->package == package) release_custom_action_data( info ); - } - LeaveCriticalSection( &msi_custom_action_cs ); -} diff --git a/libmsi/dialog.c b/libmsi/dialog.c deleted file mode 100644 index 61acc0f..0000000 --- a/libmsi/dialog.c +++ /dev/null @@ -1,4151 +0,0 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2005 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "msi.h" -#include "msipriv.h" -#include "msidefs.h" -#include "ocidl.h" -#include "olectl.h" -#include "richedit.h" -#include "commctrl.h" -#include "winreg.h" -#include "shlwapi.h" -#include "msiserver.h" - -#include "wine/debug.h" -#include "wine/unicode.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -extern HINSTANCE msi_hInstance; - -struct msi_control_tag; -typedef struct msi_control_tag msi_control; -typedef UINT (*msi_handler)( msi_dialog *, msi_control *, WPARAM ); -typedef void (*msi_update)( msi_dialog *, msi_control * ); - -struct msi_control_tag -{ - struct list entry; - HWND hwnd; - msi_handler handler; - msi_update update; - LPWSTR property; - LPWSTR value; - HBITMAP hBitmap; - HICON hIcon; - LPWSTR tabnext; - LPWSTR type; - HMODULE hDll; - float progress_current; - float progress_max; - BOOL progress_backwards; - DWORD attributes; - WCHAR name[1]; -}; - -typedef struct msi_font_tag -{ - struct list entry; - HFONT hfont; - COLORREF color; - WCHAR name[1]; -} msi_font; - -struct msi_dialog_tag -{ - MSIPACKAGE *package; - msi_dialog *parent; - msi_dialog_event_handler event_handler; - BOOL finished; - INT scale; - DWORD attributes; - SIZE size; - HWND hwnd; - LPWSTR default_font; - struct list fonts; - struct list controls; - HWND hWndFocus; - LPWSTR control_default; - LPWSTR control_cancel; - WCHAR name[1]; -}; - -typedef UINT (*msi_dialog_control_func)( msi_dialog *dialog, MSIRECORD *rec ); -struct control_handler -{ - LPCWSTR control_type; - msi_dialog_control_func func; -}; - -typedef struct -{ - msi_dialog* dialog; - msi_control *parent; - DWORD attributes; - LPWSTR propval; -} radio_button_group_descr; - -static const WCHAR szMsiDialogClass[] = { 'M','s','i','D','i','a','l','o','g','C','l','o','s','e','C','l','a','s','s',0 }; -static const WCHAR szMsiHiddenWindow[] = { 'M','s','i','H','i','d','d','e','n','W','i','n','d','o','w',0 }; -static const WCHAR szStatic[] = { 'S','t','a','t','i','c',0 }; -static const WCHAR szButton[] = { 'B','U','T','T','O','N', 0 }; -static const WCHAR szButtonData[] = { 'M','S','I','D','A','T','A',0 }; -static const WCHAR szProgress[] = { 'P','r','o','g','r','e','s','s',0 }; -static const WCHAR szText[] = { 'T','e','x','t',0 }; -static const WCHAR szPushButton[] = { 'P','u','s','h','B','u','t','t','o','n',0 }; -static const WCHAR szLine[] = { 'L','i','n','e',0 }; -static const WCHAR szBitmap[] = { 'B','i','t','m','a','p',0 }; -static const WCHAR szCheckBox[] = { 'C','h','e','c','k','B','o','x',0 }; -static const WCHAR szScrollableText[] = { 'S','c','r','o','l','l','a','b','l','e','T','e','x','t',0 }; -static const WCHAR szComboBox[] = { 'C','o','m','b','o','B','o','x',0 }; -static const WCHAR szEdit[] = { 'E','d','i','t',0 }; -static const WCHAR szMaskedEdit[] = { 'M','a','s','k','e','d','E','d','i','t',0 }; -static const WCHAR szPathEdit[] = { 'P','a','t','h','E','d','i','t',0 }; -static const WCHAR szProgressBar[] = { 'P','r','o','g','r','e','s','s','B','a','r',0 }; -static const WCHAR szSetProgress[] = { 'S','e','t','P','r','o','g','r','e','s','s',0 }; -static const WCHAR szRadioButtonGroup[] = { 'R','a','d','i','o','B','u','t','t','o','n','G','r','o','u','p',0 }; -static const WCHAR szIcon[] = { 'I','c','o','n',0 }; -static const WCHAR szSelectionTree[] = { 'S','e','l','e','c','t','i','o','n','T','r','e','e',0 }; -static const WCHAR szGroupBox[] = { 'G','r','o','u','p','B','o','x',0 }; -static const WCHAR szListBox[] = { 'L','i','s','t','B','o','x',0 }; -static const WCHAR szDirectoryCombo[] = { 'D','i','r','e','c','t','o','r','y','C','o','m','b','o',0 }; -static const WCHAR szDirectoryList[] = { 'D','i','r','e','c','t','o','r','y','L','i','s','t',0 }; -static const WCHAR szVolumeCostList[] = { 'V','o','l','u','m','e','C','o','s','t','L','i','s','t',0 }; -static const WCHAR szVolumeSelectCombo[] = { 'V','o','l','u','m','e','S','e','l','e','c','t','C','o','m','b','o',0 }; -static const WCHAR szSelectionDescription[] = {'S','e','l','e','c','t','i','o','n','D','e','s','c','r','i','p','t','i','o','n',0}; -static const WCHAR szSelectionPath[] = {'S','e','l','e','c','t','i','o','n','P','a','t','h',0}; -static const WCHAR szProperty[] = {'P','r','o','p','e','r','t','y',0}; - -/* dialog sequencing */ - -#define WM_MSI_DIALOG_CREATE (WM_USER+0x100) -#define WM_MSI_DIALOG_DESTROY (WM_USER+0x101) - -#define USER_INSTALLSTATE_ALL 0x1000 - -static DWORD uiThreadId; -static HWND hMsiHiddenWindow; - -static LPWSTR msi_get_window_text( HWND hwnd ) -{ - UINT sz, r; - LPWSTR buf; - - sz = 0x20; - buf = msi_alloc( sz*sizeof(WCHAR) ); - while ( buf ) - { - r = GetWindowTextW( hwnd, buf, sz ); - if ( r < (sz - 1) ) - break; - sz *= 2; - buf = msi_realloc( buf, sz*sizeof(WCHAR) ); - } - - return buf; -} - -static INT msi_dialog_scale_unit( msi_dialog *dialog, INT val ) -{ - return MulDiv( val, dialog->scale, 12 ); -} - -static msi_control *msi_dialog_find_control( msi_dialog *dialog, LPCWSTR name ) -{ - msi_control *control; - - if( !name ) - return NULL; - if( !dialog->hwnd ) - return NULL; - LIST_FOR_EACH_ENTRY( control, &dialog->controls, msi_control, entry ) - if( !strcmpW( control->name, name ) ) /* FIXME: case sensitive? */ - return control; - return NULL; -} - -static msi_control *msi_dialog_find_control_by_type( msi_dialog *dialog, LPCWSTR type ) -{ - msi_control *control; - - if( !type ) - return NULL; - if( !dialog->hwnd ) - return NULL; - LIST_FOR_EACH_ENTRY( control, &dialog->controls, msi_control, entry ) - if( !strcmpW( control->type, type ) ) /* FIXME: case sensitive? */ - return control; - return NULL; -} - -static msi_control *msi_dialog_find_control_by_hwnd( msi_dialog *dialog, HWND hwnd ) -{ - msi_control *control; - - if( !dialog->hwnd ) - return NULL; - LIST_FOR_EACH_ENTRY( control, &dialog->controls, msi_control, entry ) - if( hwnd == control->hwnd ) - return control; - return NULL; -} - -static LPWSTR msi_get_deformatted_field( MSIPACKAGE *package, MSIRECORD *rec, int field ) -{ - LPCWSTR str = MSI_RecordGetString( rec, field ); - LPWSTR ret = NULL; - - if (str) - deformat_string( package, str, &ret ); - return ret; -} - -static LPWSTR msi_dialog_dup_property( msi_dialog *dialog, LPCWSTR property, BOOL indirect ) -{ - LPWSTR prop = NULL; - - if (!property) - return NULL; - - if (indirect) - prop = msi_dup_property( dialog->package->db, property ); - - if (!prop) - prop = strdupW( property ); - - return prop; -} - -msi_dialog *msi_dialog_get_parent( msi_dialog *dialog ) -{ - return dialog->parent; -} - -LPWSTR msi_dialog_get_name( msi_dialog *dialog ) -{ - return dialog->name; -} - -/* - * msi_dialog_get_style - * - * Extract the {\style} string from the front of the text to display and - * update the pointer. Only the last style in a list is applied. - */ -static LPWSTR msi_dialog_get_style( LPCWSTR p, LPCWSTR *rest ) -{ - LPWSTR ret; - LPCWSTR q, i, first; - DWORD len; - - q = NULL; - *rest = p; - if( !p ) - return NULL; - - while ((first = strchrW( p, '{' )) && (q = strchrW( first + 1, '}' ))) - { - p = first + 1; - if( *p != '\\' && *p != '&' ) - return NULL; - - /* little bit of sanity checking to stop us getting confused with RTF */ - for( i=++p; i<q; i++ ) - if( *i == '}' || *i == '\\' ) - return NULL; - } - - if (!q) - return NULL; - - *rest = ++q; - len = q - p; - - ret = msi_alloc( len*sizeof(WCHAR) ); - if( !ret ) - return ret; - memcpy( ret, p, len*sizeof(WCHAR) ); - ret[len-1] = 0; - return ret; -} - -static UINT msi_dialog_add_font( MSIRECORD *rec, LPVOID param ) -{ - msi_dialog *dialog = param; - msi_font *font; - LPCWSTR face, name; - LOGFONTW lf; - INT style; - HDC hdc; - - /* create a font and add it to the list */ - name = MSI_RecordGetString( rec, 1 ); - font = msi_alloc( sizeof *font + strlenW( name )*sizeof (WCHAR) ); - strcpyW( font->name, name ); - list_add_head( &dialog->fonts, &font->entry ); - - font->color = MSI_RecordGetInteger( rec, 4 ); - - memset( &lf, 0, sizeof lf ); - face = MSI_RecordGetString( rec, 2 ); - lf.lfHeight = MSI_RecordGetInteger( rec, 3 ); - style = MSI_RecordGetInteger( rec, 5 ); - if( style & msidbTextStyleStyleBitsBold ) - lf.lfWeight = FW_BOLD; - if( style & msidbTextStyleStyleBitsItalic ) - lf.lfItalic = TRUE; - if( style & msidbTextStyleStyleBitsUnderline ) - lf.lfUnderline = TRUE; - if( style & msidbTextStyleStyleBitsStrike ) - lf.lfStrikeOut = TRUE; - lstrcpynW( lf.lfFaceName, face, LF_FACESIZE ); - - /* adjust the height */ - hdc = GetDC( dialog->hwnd ); - if (hdc) - { - lf.lfHeight = -MulDiv(lf.lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72); - ReleaseDC( dialog->hwnd, hdc ); - } - - font->hfont = CreateFontIndirectW( &lf ); - - TRACE("Adding font style %s\n", debugstr_w(font->name) ); - - return ERROR_SUCCESS; -} - -static msi_font *msi_dialog_find_font( msi_dialog *dialog, LPCWSTR name ) -{ - msi_font *font = NULL; - - LIST_FOR_EACH_ENTRY( font, &dialog->fonts, msi_font, entry ) - if( !strcmpW( font->name, name ) ) /* FIXME: case sensitive? */ - break; - - return font; -} - -static UINT msi_dialog_set_font( msi_dialog *dialog, HWND hwnd, LPCWSTR name ) -{ - msi_font *font; - - font = msi_dialog_find_font( dialog, name ); - if( font ) - SendMessageW( hwnd, WM_SETFONT, (WPARAM) font->hfont, TRUE ); - else - ERR("No font entry for %s\n", debugstr_w(name)); - return ERROR_SUCCESS; -} - -static UINT msi_dialog_build_font_list( msi_dialog *dialog ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','T','e','x','t','S','t','y','l','e','`',0}; - MSIQUERY *view; - UINT r; - - TRACE("dialog %p\n", dialog ); - - r = MSI_OpenQuery( dialog->package->db, &view, query ); - if( r != ERROR_SUCCESS ) - return r; - - r = MSI_IterateRecords( view, NULL, msi_dialog_add_font, dialog ); - msiobj_release( &view->hdr ); - return r; -} - -static void msi_destroy_control( msi_control *t ) -{ - list_remove( &t->entry ); - /* leave dialog->hwnd - destroying parent destroys child windows */ - msi_free( t->property ); - msi_free( t->value ); - if( t->hBitmap ) - DeleteObject( t->hBitmap ); - if( t->hIcon ) - DestroyIcon( t->hIcon ); - msi_free( t->tabnext ); - msi_free( t->type ); - if (t->hDll) - FreeLibrary( t->hDll ); - msi_free( t ); -} - -static msi_control *msi_dialog_create_window( msi_dialog *dialog, - MSIRECORD *rec, DWORD exstyle, LPCWSTR szCls, LPCWSTR name, LPCWSTR text, - DWORD style, HWND parent ) -{ - DWORD x, y, width, height; - LPWSTR font = NULL, title_font = NULL; - LPCWSTR title = NULL; - msi_control *control; - - style |= WS_CHILD; - - control = msi_alloc( sizeof *control + strlenW(name)*sizeof(WCHAR) ); - if (!control) - return NULL; - - strcpyW( control->name, name ); - list_add_tail( &dialog->controls, &control->entry ); - control->handler = NULL; - control->update = NULL; - control->property = NULL; - control->value = NULL; - control->hBitmap = NULL; - control->hIcon = NULL; - control->hDll = NULL; - control->tabnext = strdupW( MSI_RecordGetString( rec, 11) ); - control->type = strdupW( MSI_RecordGetString( rec, 3 ) ); - control->progress_current = 0; - control->progress_max = 100; - control->progress_backwards = FALSE; - - x = MSI_RecordGetInteger( rec, 4 ); - y = MSI_RecordGetInteger( rec, 5 ); - width = MSI_RecordGetInteger( rec, 6 ); - height = MSI_RecordGetInteger( rec, 7 ); - - x = msi_dialog_scale_unit( dialog, x ); - y = msi_dialog_scale_unit( dialog, y ); - width = msi_dialog_scale_unit( dialog, width ); - height = msi_dialog_scale_unit( dialog, height ); - - if( text ) - { - deformat_string( dialog->package, text, &title_font ); - font = msi_dialog_get_style( title_font, &title ); - } - - control->hwnd = CreateWindowExW( exstyle, szCls, title, style, - x, y, width, height, parent, NULL, NULL, NULL ); - - TRACE("Dialog %s control %s hwnd %p\n", - debugstr_w(dialog->name), debugstr_w(text), control->hwnd ); - - msi_dialog_set_font( dialog, control->hwnd, - font ? font : dialog->default_font ); - - msi_free( title_font ); - msi_free( font ); - - return control; -} - -static LPWSTR msi_dialog_get_uitext( msi_dialog *dialog, LPCWSTR key ) -{ - MSIRECORD *rec; - LPWSTR text; - - static const WCHAR query[] = { - 's','e','l','e','c','t',' ','*',' ', - 'f','r','o','m',' ','`','U','I','T','e','x','t','`',' ', - 'w','h','e','r','e',' ','`','K','e','y','`',' ','=',' ','\'','%','s','\'',0 - }; - - rec = MSI_QueryGetRecord( dialog->package->db, query, key ); - if (!rec) return NULL; - text = strdupW( MSI_RecordGetString( rec, 2 ) ); - msiobj_release( &rec->hdr ); - return text; -} - -static MSIRECORD *msi_get_binary_record( MSIDATABASE *db, LPCWSTR name ) -{ - static const WCHAR query[] = { - 's','e','l','e','c','t',' ','*',' ', - 'f','r','o','m',' ','B','i','n','a','r','y',' ', - 'w','h','e','r','e',' ', - '`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0 - }; - - return MSI_QueryGetRecord( db, query, name ); -} - -static LPWSTR msi_create_tmp_path(void) -{ - WCHAR tmp[MAX_PATH]; - LPWSTR path = NULL; - DWORD len, r; - - r = GetTempPathW( MAX_PATH, tmp ); - if( !r ) - return path; - len = lstrlenW( tmp ) + 20; - path = msi_alloc( len * sizeof (WCHAR) ); - if( path ) - { - r = GetTempFileNameW( tmp, szMsi, 0, path ); - if (!r) - { - msi_free( path ); - path = NULL; - } - } - return path; -} - -static HANDLE msi_load_image( MSIDATABASE *db, LPCWSTR name, UINT type, - UINT cx, UINT cy, UINT flags ) -{ - MSIRECORD *rec = NULL; - HANDLE himage = NULL; - LPWSTR tmp; - UINT r; - - TRACE("%p %s %u %u %08x\n", db, debugstr_w(name), cx, cy, flags); - - tmp = msi_create_tmp_path(); - if( !tmp ) - return himage; - - rec = msi_get_binary_record( db, name ); - if( rec ) - { - r = MSI_RecordStreamToFile( rec, 2, tmp ); - if( r == ERROR_SUCCESS ) - { - himage = LoadImageW( 0, tmp, type, cx, cy, flags ); - } - msiobj_release( &rec->hdr ); - } - DeleteFileW( tmp ); - - msi_free( tmp ); - return himage; -} - -static HICON msi_load_icon( MSIDATABASE *db, LPCWSTR text, UINT attributes ) -{ - DWORD cx = 0, cy = 0, flags; - - flags = LR_LOADFROMFILE | LR_DEFAULTSIZE; - if( attributes & msidbControlAttributesFixedSize ) - { - flags &= ~LR_DEFAULTSIZE; - if( attributes & msidbControlAttributesIconSize16 ) - { - cx += 16; - cy += 16; - } - if( attributes & msidbControlAttributesIconSize32 ) - { - cx += 32; - cy += 32; - } - /* msidbControlAttributesIconSize48 handled by above logic */ - } - return msi_load_image( db, text, IMAGE_ICON, cx, cy, flags ); -} - -static void msi_dialog_update_controls( msi_dialog *dialog, LPCWSTR property ) -{ - msi_control *control; - - LIST_FOR_EACH_ENTRY( control, &dialog->controls, msi_control, entry ) - { - if ( control->property && !strcmpW( control->property, property ) && control->update ) - control->update( dialog, control ); - } -} - -static void msi_dialog_set_property( MSIPACKAGE *package, LPCWSTR property, LPCWSTR value ) -{ - UINT r = msi_set_property( package->db, property, value ); - if (r == ERROR_SUCCESS && !strcmpW( property, szSourceDir )) - msi_reset_folders( package, TRUE ); -} - -static MSIFEATURE *msi_seltree_feature_from_item( HWND hwnd, HTREEITEM hItem ) -{ - TVITEMW tvi; - - /* get the feature from the item */ - memset( &tvi, 0, sizeof tvi ); - tvi.hItem = hItem; - tvi.mask = TVIF_PARAM | TVIF_HANDLE; - SendMessageW( hwnd, TVM_GETITEMW, 0, (LPARAM)&tvi ); - return (MSIFEATURE *)tvi.lParam; -} - -struct msi_selection_tree_info -{ - msi_dialog *dialog; - HWND hwnd; - WNDPROC oldproc; - HTREEITEM selected; -}; - -static MSIFEATURE *msi_seltree_get_selected_feature( msi_control *control ) -{ - struct msi_selection_tree_info *info = GetPropW( control->hwnd, szButtonData ); - return msi_seltree_feature_from_item( control->hwnd, info->selected ); -} - -/* called from the Control Event subscription code */ -void msi_dialog_handle_event( msi_dialog* dialog, LPCWSTR control, - LPCWSTR attribute, MSIRECORD *rec ) -{ - msi_control* ctrl; - LPCWSTR font_text, text = NULL; - LPWSTR font; - - ctrl = msi_dialog_find_control( dialog, control ); - if (!ctrl) - return; - if( !strcmpW( attribute, szText ) ) - { - font_text = MSI_RecordGetString( rec , 1 ); - font = msi_dialog_get_style( font_text, &text ); - if (!text) text = szEmpty; - SetWindowTextW( ctrl->hwnd, text ); - msi_free( font ); - msi_dialog_check_messages( NULL ); - } - else if( !strcmpW( attribute, szProgress ) ) - { - DWORD func, val1, val2, units; - - func = MSI_RecordGetInteger( rec, 1 ); - val1 = MSI_RecordGetInteger( rec, 2 ); - val2 = MSI_RecordGetInteger( rec, 3 ); - - TRACE("progress: func %u val1 %u val2 %u\n", func, val1, val2); - - units = val1 / 512; - switch (func) - { - case 0: /* init */ - SendMessageW( ctrl->hwnd, PBM_SETRANGE, 0, MAKELPARAM(0,100) ); - if (val2) - { - ctrl->progress_max = units ? units : 100; - ctrl->progress_current = units; - ctrl->progress_backwards = TRUE; - SendMessageW( ctrl->hwnd, PBM_SETPOS, 100, 0 ); - } - else - { - ctrl->progress_max = units ? units : 100; - ctrl->progress_current = 0; - ctrl->progress_backwards = FALSE; - SendMessageW( ctrl->hwnd, PBM_SETPOS, 0, 0 ); - } - break; - case 1: /* action data increment */ - if (val2) dialog->package->action_progress_increment = val1; - else dialog->package->action_progress_increment = 0; - break; - case 2: /* move */ - if (ctrl->progress_backwards) - { - if (units >= ctrl->progress_current) ctrl->progress_current -= units; - else ctrl->progress_current = 0; - } - else - { - if (ctrl->progress_current + units < ctrl->progress_max) ctrl->progress_current += units; - else ctrl->progress_current = ctrl->progress_max; - } - SendMessageW( ctrl->hwnd, PBM_SETPOS, MulDiv(100, ctrl->progress_current, ctrl->progress_max), 0 ); - break; - case 3: /* add */ - ctrl->progress_max += units; - break; - default: - FIXME("Unknown progress message %u\n", func); - break; - } - } - else if ( !strcmpW( attribute, szProperty ) ) - { - MSIFEATURE *feature = msi_seltree_get_selected_feature( ctrl ); - msi_dialog_set_property( dialog->package, ctrl->property, feature->Directory ); - } - else if ( !strcmpW( attribute, szSelectionPath ) ) - { - BOOL indirect = ctrl->attributes & msidbControlAttributesIndirect; - LPWSTR path = msi_dialog_dup_property( dialog, ctrl->property, indirect ); - if (!path) return; - SetWindowTextW( ctrl->hwnd, path ); - msi_free(path); - } - else - { - FIXME("Attribute %s not being set\n", debugstr_w(attribute)); - return; - } -} - -static void msi_dialog_map_events(msi_dialog* dialog, LPCWSTR control) -{ - static const WCHAR Query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','E','v','e','n','t','M','a','p','p','i','n','g','`',' ', - 'W','H','E','R','E',' ', - '`','D','i','a','l','o','g','_','`',' ','=',' ','\'','%','s','\'',' ', - 'A','N','D',' ', - '`','C','o','n','t','r','o','l','_','`',' ','=',' ','\'','%','s','\'',0 - }; - MSIRECORD *row; - LPCWSTR event, attribute; - - row = MSI_QueryGetRecord( dialog->package->db, Query, dialog->name, control ); - if (!row) - return; - - event = MSI_RecordGetString( row, 3 ); - attribute = MSI_RecordGetString( row, 4 ); - ControlEvent_SubscribeToEvent( dialog->package, dialog, event, control, attribute ); - msiobj_release( &row->hdr ); -} - -/* everything except radio buttons */ -static msi_control *msi_dialog_add_control( msi_dialog *dialog, - MSIRECORD *rec, LPCWSTR szCls, DWORD style ) -{ - DWORD attributes; - LPCWSTR text, name; - DWORD exstyle = 0; - - name = MSI_RecordGetString( rec, 2 ); - attributes = MSI_RecordGetInteger( rec, 8 ); - text = MSI_RecordGetString( rec, 10 ); - - TRACE("%s, %s, %08x, %s, %08x\n", debugstr_w(szCls), debugstr_w(name), - attributes, debugstr_w(text), style); - - if( attributes & msidbControlAttributesVisible ) - style |= WS_VISIBLE; - if( ~attributes & msidbControlAttributesEnabled ) - style |= WS_DISABLED; - if( attributes & msidbControlAttributesSunken ) - exstyle |= WS_EX_CLIENTEDGE; - - msi_dialog_map_events(dialog, name); - - return msi_dialog_create_window( dialog, rec, exstyle, szCls, name, - text, style, dialog->hwnd ); -} - -struct msi_text_info -{ - msi_font *font; - WNDPROC oldproc; - DWORD attributes; -}; - -/* - * we don't erase our own background, - * so we have to make sure that the parent window redraws first - */ -static void msi_text_on_settext( HWND hWnd ) -{ - HWND hParent; - RECT rc; - - hParent = GetParent( hWnd ); - GetWindowRect( hWnd, &rc ); - MapWindowPoints( NULL, hParent, (LPPOINT) &rc, 2 ); - InvalidateRect( hParent, &rc, TRUE ); -} - -static LRESULT WINAPI -MSIText_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - struct msi_text_info *info; - LRESULT r = 0; - - TRACE("%p %04x %08lx %08lx\n", hWnd, msg, wParam, lParam); - - info = GetPropW(hWnd, szButtonData); - - if( msg == WM_CTLCOLORSTATIC && - ( info->attributes & msidbControlAttributesTransparent ) ) - { - SetBkMode( (HDC)wParam, TRANSPARENT ); - return (LRESULT) GetStockObject(NULL_BRUSH); - } - - r = CallWindowProcW(info->oldproc, hWnd, msg, wParam, lParam); - if ( info->font ) - SetTextColor( (HDC)wParam, info->font->color ); - - switch( msg ) - { - case WM_SETTEXT: - msi_text_on_settext( hWnd ); - break; - case WM_NCDESTROY: - msi_free( info ); - RemovePropW( hWnd, szButtonData ); - break; - } - - return r; -} - -static UINT msi_dialog_text_control( msi_dialog *dialog, MSIRECORD *rec ) -{ - msi_control *control; - struct msi_text_info *info; - LPCWSTR text, ptr, prop, control_name; - LPWSTR font_name; - - TRACE("%p %p\n", dialog, rec); - - control = msi_dialog_add_control( dialog, rec, szStatic, SS_LEFT | WS_GROUP ); - if( !control ) - return ERROR_FUNCTION_FAILED; - - info = msi_alloc( sizeof *info ); - if( !info ) - return ERROR_SUCCESS; - - control_name = MSI_RecordGetString( rec, 2 ); - control->attributes = MSI_RecordGetInteger( rec, 8 ); - prop = MSI_RecordGetString( rec, 9 ); - control->property = msi_dialog_dup_property( dialog, prop, FALSE ); - - text = MSI_RecordGetString( rec, 10 ); - font_name = msi_dialog_get_style( text, &ptr ); - info->font = ( font_name ) ? msi_dialog_find_font( dialog, font_name ) : NULL; - msi_free( font_name ); - - info->attributes = MSI_RecordGetInteger( rec, 8 ); - if( info->attributes & msidbControlAttributesTransparent ) - SetWindowLongPtrW( control->hwnd, GWL_EXSTYLE, WS_EX_TRANSPARENT ); - - info->oldproc = (WNDPROC) SetWindowLongPtrW( control->hwnd, GWLP_WNDPROC, - (LONG_PTR)MSIText_WndProc ); - SetPropW( control->hwnd, szButtonData, info ); - - ControlEvent_SubscribeToEvent( dialog->package, dialog, - szSelectionPath, control_name, szSelectionPath ); - - return ERROR_SUCCESS; -} - -/* strip any leading text style label from text field */ -static WCHAR *msi_get_binary_name( MSIPACKAGE *package, MSIRECORD *rec ) -{ - WCHAR *p, *text; - - text = msi_get_deformatted_field( package, rec, 10 ); - if (!text) - return NULL; - - p = text; - while (*p && *p != '{') p++; - if (!*p++) return text; - - while (*p && *p != '}') p++; - if (!*p++) return text; - - p = strdupW( p ); - msi_free( text ); - return p; -} - -static UINT msi_dialog_set_property_event( msi_dialog *dialog, LPCWSTR event, LPCWSTR arg ) -{ - static const WCHAR szNullArg[] = {'{','}',0}; - LPWSTR p, prop, arg_fmt = NULL; - UINT len; - - len = strlenW( event ); - prop = msi_alloc( len * sizeof(WCHAR) ); - strcpyW( prop, &event[1] ); - p = strchrW( prop, ']' ); - if (p && (p[1] == 0 || p[1] == ' ')) - { - *p = 0; - if (strcmpW( szNullArg, arg )) - deformat_string( dialog->package, arg, &arg_fmt ); - msi_dialog_set_property( dialog->package, prop, arg_fmt ); - msi_dialog_update_controls( dialog, prop ); - msi_free( arg_fmt ); - } - else ERR("Badly formatted property string - what happens?\n"); - msi_free( prop ); - return ERROR_SUCCESS; -} - -static UINT msi_dialog_send_event( msi_dialog *dialog, LPCWSTR event, LPCWSTR arg ) -{ - LPWSTR event_fmt = NULL, arg_fmt = NULL; - - TRACE("Sending control event %s %s\n", debugstr_w(event), debugstr_w(arg)); - - deformat_string( dialog->package, event, &event_fmt ); - deformat_string( dialog->package, arg, &arg_fmt ); - - dialog->event_handler( dialog->package, event_fmt, arg_fmt, dialog ); - - msi_free( event_fmt ); - msi_free( arg_fmt ); - - return ERROR_SUCCESS; -} - -static UINT msi_dialog_control_event( MSIRECORD *rec, LPVOID param ) -{ - msi_dialog *dialog = param; - LPCWSTR condition, event, arg; - UINT r; - - condition = MSI_RecordGetString( rec, 5 ); - r = MSI_EvaluateConditionW( dialog->package, condition ); - if (r == MSICONDITION_TRUE || r == MSICONDITION_NONE) - { - event = MSI_RecordGetString( rec, 3 ); - arg = MSI_RecordGetString( rec, 4 ); - if (event[0] == '[') - msi_dialog_set_property_event( dialog, event, arg ); - else - msi_dialog_send_event( dialog, event, arg ); - } - return ERROR_SUCCESS; -} - -static UINT msi_dialog_button_handler( msi_dialog *dialog, msi_control *control, WPARAM param ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'C','o','n','t','r','o','l','E','v','e','n','t',' ','W','H','E','R','E',' ', - '`','D','i','a','l','o','g','_','`',' ','=',' ','\'','%','s','\'',' ','A','N','D',' ', - '`','C','o','n','t','r','o','l','_','`',' ','=',' ','\'','%','s','\'',' ', - 'O','R','D','E','R',' ','B','Y',' ','`','O','r','d','e','r','i','n','g','`',0}; - MSIQUERY *view; - UINT r; - - if (HIWORD(param) != BN_CLICKED) - return ERROR_SUCCESS; - - r = MSI_OpenQuery( dialog->package->db, &view, query, dialog->name, control->name ); - if (r != ERROR_SUCCESS) - { - ERR("query failed\n"); - return ERROR_SUCCESS; - } - r = MSI_IterateRecords( view, 0, msi_dialog_control_event, dialog ); - msiobj_release( &view->hdr ); - return r; -} - -static UINT msi_dialog_button_control( msi_dialog *dialog, MSIRECORD *rec ) -{ - msi_control *control; - UINT attributes, style; - - TRACE("%p %p\n", dialog, rec); - - style = WS_TABSTOP; - attributes = MSI_RecordGetInteger( rec, 8 ); - if( attributes & msidbControlAttributesIcon ) - style |= BS_ICON; - - control = msi_dialog_add_control( dialog, rec, szButton, style ); - if( !control ) - return ERROR_FUNCTION_FAILED; - - control->handler = msi_dialog_button_handler; - - if (attributes & msidbControlAttributesIcon) - { - /* set the icon */ - LPWSTR name = msi_get_binary_name( dialog->package, rec ); - control->hIcon = msi_load_icon( dialog->package->db, name, attributes ); - if (control->hIcon) - { - SendMessageW( control->hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM) control->hIcon ); - } - else - ERR("Failed to load icon %s\n", debugstr_w(name)); - msi_free( name ); - } - - return ERROR_SUCCESS; -} - -static LPWSTR msi_get_checkbox_value( msi_dialog *dialog, LPCWSTR prop ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ', - 'F','R','O','M',' ','`','C','h','e','c','k','B','o','x','`',' ', - 'W','H','E','R','E',' ', - '`','P','r','o','p','e','r','t','y','`',' ','=',' ', - '\'','%','s','\'',0 - }; - MSIRECORD *rec = NULL; - LPWSTR ret = NULL; - - /* find if there is a value associated with the checkbox */ - rec = MSI_QueryGetRecord( dialog->package->db, query, prop ); - if (!rec) - return ret; - - ret = msi_get_deformatted_field( dialog->package, rec, 2 ); - if( ret && !ret[0] ) - { - msi_free( ret ); - ret = NULL; - } - msiobj_release( &rec->hdr ); - if (ret) - return ret; - - ret = msi_dup_property( dialog->package->db, prop ); - if( ret && !ret[0] ) - { - msi_free( ret ); - ret = NULL; - } - - return ret; -} - -static UINT msi_dialog_get_checkbox_state( msi_dialog *dialog, msi_control *control ) -{ - WCHAR state[2] = {0}; - DWORD sz = 2; - - msi_get_property( dialog->package->db, control->property, state, &sz ); - return state[0] ? 1 : 0; -} - -static void msi_dialog_set_checkbox_state( msi_dialog *dialog, msi_control *control, UINT state ) -{ - static const WCHAR szState[] = {'1',0}; - LPCWSTR val; - - /* if uncheck then the property is set to NULL */ - if (!state) - { - msi_dialog_set_property( dialog->package, control->property, NULL ); - return; - } - - /* check for a custom state */ - if (control->value && control->value[0]) - val = control->value; - else - val = szState; - - msi_dialog_set_property( dialog->package, control->property, val ); -} - -static void msi_dialog_checkbox_sync_state( msi_dialog *dialog, msi_control *control ) -{ - UINT state = msi_dialog_get_checkbox_state( dialog, control ); - SendMessageW( control->hwnd, BM_SETCHECK, state ? BST_CHECKED : BST_UNCHECKED, 0 ); -} - -static UINT msi_dialog_checkbox_handler( msi_dialog *dialog, msi_control *control, WPARAM param ) -{ - UINT state; - - if (HIWORD(param) != BN_CLICKED) - return ERROR_SUCCESS; - - TRACE("clicked checkbox %s, set %s\n", debugstr_w(control->name), debugstr_w(control->property)); - - state = msi_dialog_get_checkbox_state( dialog, control ); - state = state ? 0 : 1; - msi_dialog_set_checkbox_state( dialog, control, state ); - msi_dialog_checkbox_sync_state( dialog, control ); - - return msi_dialog_button_handler( dialog, control, param ); -} - -static UINT msi_dialog_checkbox_control( msi_dialog *dialog, MSIRECORD *rec ) -{ - msi_control *control; - LPCWSTR prop; - - TRACE("%p %p\n", dialog, rec); - - control = msi_dialog_add_control( dialog, rec, szButton, BS_CHECKBOX | BS_MULTILINE | WS_TABSTOP ); - control->handler = msi_dialog_checkbox_handler; - control->update = msi_dialog_checkbox_sync_state; - prop = MSI_RecordGetString( rec, 9 ); - if (prop) - { - control->property = strdupW( prop ); - control->value = msi_get_checkbox_value( dialog, prop ); - TRACE("control %s value %s\n", debugstr_w(control->property), debugstr_w(control->value)); - } - msi_dialog_checkbox_sync_state( dialog, control ); - return ERROR_SUCCESS; -} - -static UINT msi_dialog_line_control( msi_dialog *dialog, MSIRECORD *rec ) -{ - DWORD attributes; - LPCWSTR name; - DWORD style, exstyle = 0; - DWORD x, y, width, height; - msi_control *control; - - TRACE("%p %p\n", dialog, rec); - - style = WS_CHILD | SS_ETCHEDHORZ | SS_SUNKEN; - - name = MSI_RecordGetString( rec, 2 ); - attributes = MSI_RecordGetInteger( rec, 8 ); - - if( attributes & msidbControlAttributesVisible ) - style |= WS_VISIBLE; - if( ~attributes & msidbControlAttributesEnabled ) - style |= WS_DISABLED; - if( attributes & msidbControlAttributesSunken ) - exstyle |= WS_EX_CLIENTEDGE; - - msi_dialog_map_events(dialog, name); - - control = msi_alloc( sizeof(*control) + strlenW(name) * sizeof(WCHAR) ); - if (!control) - return ERROR_OUTOFMEMORY; - - strcpyW( control->name, name ); - list_add_head( &dialog->controls, &control->entry ); - control->handler = NULL; - control->property = NULL; - control->value = NULL; - control->hBitmap = NULL; - control->hIcon = NULL; - control->hDll = NULL; - control->tabnext = strdupW( MSI_RecordGetString( rec, 11) ); - control->type = strdupW( MSI_RecordGetString( rec, 3 ) ); - control->progress_current = 0; - control->progress_max = 100; - control->progress_backwards = FALSE; - - x = MSI_RecordGetInteger( rec, 4 ); - y = MSI_RecordGetInteger( rec, 5 ); - width = MSI_RecordGetInteger( rec, 6 ); - - x = msi_dialog_scale_unit( dialog, x ); - y = msi_dialog_scale_unit( dialog, y ); - width = msi_dialog_scale_unit( dialog, width ); - height = 2; /* line is exactly 2 units in height */ - - control->hwnd = CreateWindowExW( exstyle, szStatic, NULL, style, - x, y, width, height, dialog->hwnd, NULL, NULL, NULL ); - - TRACE("Dialog %s control %s hwnd %p\n", - debugstr_w(dialog->name), debugstr_w(name), control->hwnd ); - - return ERROR_SUCCESS; -} - -/******************** Scroll Text ********************************************/ - -struct msi_scrolltext_info -{ - msi_dialog *dialog; - msi_control *control; - WNDPROC oldproc; -}; - -static LRESULT WINAPI -MSIScrollText_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - struct msi_scrolltext_info *info; - HRESULT r; - - TRACE("%p %04x %08lx %08lx\n", hWnd, msg, wParam, lParam); - - info = GetPropW( hWnd, szButtonData ); - - r = CallWindowProcW( info->oldproc, hWnd, msg, wParam, lParam ); - - switch( msg ) - { - case WM_GETDLGCODE: - return DLGC_WANTARROWS; - case WM_NCDESTROY: - msi_free( info ); - RemovePropW( hWnd, szButtonData ); - break; - case WM_PAINT: - /* native MSI sets a wait cursor here */ - msi_dialog_button_handler( info->dialog, info->control, BN_CLICKED ); - break; - } - return r; -} - -struct msi_streamin_info -{ - LPSTR string; - DWORD offset; - DWORD length; -}; - -static DWORD CALLBACK -msi_richedit_stream_in( DWORD_PTR arg, LPBYTE buffer, LONG count, LONG *pcb ) -{ - struct msi_streamin_info *info = (struct msi_streamin_info*) arg; - - if( (count + info->offset) > info->length ) - count = info->length - info->offset; - memcpy( buffer, &info->string[ info->offset ], count ); - *pcb = count; - info->offset += count; - - TRACE("%d/%d\n", info->offset, info->length); - - return 0; -} - -static void msi_scrolltext_add_text( msi_control *control, LPCWSTR text ) -{ - struct msi_streamin_info info; - EDITSTREAM es; - - info.string = strdupWtoA( text ); - info.offset = 0; - info.length = lstrlenA( info.string ) + 1; - - es.dwCookie = (DWORD_PTR) &info; - es.dwError = 0; - es.pfnCallback = msi_richedit_stream_in; - - SendMessageW( control->hwnd, EM_STREAMIN, SF_RTF, (LPARAM) &es ); - - msi_free( info.string ); -} - -static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec ) -{ - static const WCHAR szRichEdit20W[] = {'R','i','c','h','E','d','i','t','2','0','W',0}; - struct msi_scrolltext_info *info; - msi_control *control; - HMODULE hRichedit; - LPCWSTR text; - DWORD style; - - info = msi_alloc( sizeof *info ); - if (!info) - return ERROR_FUNCTION_FAILED; - - hRichedit = LoadLibraryA("riched20"); - - style = WS_BORDER | ES_MULTILINE | WS_VSCROLL | - ES_READONLY | ES_AUTOVSCROLL | WS_TABSTOP; - control = msi_dialog_add_control( dialog, rec, szRichEdit20W, style ); - if (!control) - { - FreeLibrary( hRichedit ); - msi_free( info ); - return ERROR_FUNCTION_FAILED; - } - - control->hDll = hRichedit; - - info->dialog = dialog; - info->control = control; - - /* subclass the static control */ - info->oldproc = (WNDPROC) SetWindowLongPtrW( control->hwnd, GWLP_WNDPROC, - (LONG_PTR)MSIScrollText_WndProc ); - SetPropW( control->hwnd, szButtonData, info ); - - /* add the text into the richedit */ - text = MSI_RecordGetString( rec, 10 ); - if (text) - msi_scrolltext_add_text( control, text ); - - return ERROR_SUCCESS; -} - -static HBITMAP msi_load_picture( MSIDATABASE *db, LPCWSTR name, - INT cx, INT cy, DWORD flags ) -{ - HBITMAP hOleBitmap = 0, hBitmap = 0, hOldSrcBitmap, hOldDestBitmap; - MSIRECORD *rec = NULL; - IStream *stm = NULL; - IPicture *pic = NULL; - HDC srcdc, destdc; - BITMAP bm; - UINT r; - - rec = msi_get_binary_record( db, name ); - if( !rec ) - goto end; - - r = MSI_RecordGetIStream( rec, 2, &stm ); - msiobj_release( &rec->hdr ); - if( r != ERROR_SUCCESS ) - goto end; - - r = OleLoadPicture( stm, 0, TRUE, &IID_IPicture, (LPVOID*) &pic ); - IStream_Release( stm ); - if( FAILED( r ) ) - { - ERR("failed to load picture\n"); - goto end; - } - - r = IPicture_get_Handle( pic, (OLE_HANDLE*) &hOleBitmap ); - if( FAILED( r ) ) - { - ERR("failed to get bitmap handle\n"); - goto end; - } - - /* make the bitmap the desired size */ - r = GetObjectW( hOleBitmap, sizeof bm, &bm ); - if (r != sizeof bm ) - { - ERR("failed to get bitmap size\n"); - goto end; - } - - if (flags & LR_DEFAULTSIZE) - { - cx = bm.bmWidth; - cy = bm.bmHeight; - } - - srcdc = CreateCompatibleDC( NULL ); - hOldSrcBitmap = SelectObject( srcdc, hOleBitmap ); - destdc = CreateCompatibleDC( NULL ); - hBitmap = CreateCompatibleBitmap( srcdc, cx, cy ); - hOldDestBitmap = SelectObject( destdc, hBitmap ); - StretchBlt( destdc, 0, 0, cx, cy, - srcdc, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); - SelectObject( srcdc, hOldSrcBitmap ); - SelectObject( destdc, hOldDestBitmap ); - DeleteDC( srcdc ); - DeleteDC( destdc ); - -end: - if ( pic ) - IPicture_Release( pic ); - return hBitmap; -} - -static UINT msi_dialog_bitmap_control( msi_dialog *dialog, MSIRECORD *rec ) -{ - UINT cx, cy, flags, style, attributes; - msi_control *control; - LPWSTR name; - - flags = LR_LOADFROMFILE; - style = SS_BITMAP | SS_LEFT | WS_GROUP; - - attributes = MSI_RecordGetInteger( rec, 8 ); - if( attributes & msidbControlAttributesFixedSize ) - { - flags |= LR_DEFAULTSIZE; - style |= SS_CENTERIMAGE; - } - - control = msi_dialog_add_control( dialog, rec, szStatic, style ); - cx = MSI_RecordGetInteger( rec, 6 ); - cy = MSI_RecordGetInteger( rec, 7 ); - cx = msi_dialog_scale_unit( dialog, cx ); - cy = msi_dialog_scale_unit( dialog, cy ); - - name = msi_get_binary_name( dialog->package, rec ); - control->hBitmap = msi_load_picture( dialog->package->db, name, cx, cy, flags ); - if( control->hBitmap ) - SendMessageW( control->hwnd, STM_SETIMAGE, - IMAGE_BITMAP, (LPARAM) control->hBitmap ); - else - ERR("Failed to load bitmap %s\n", debugstr_w(name)); - - msi_free( name ); - - return ERROR_SUCCESS; -} - -static UINT msi_dialog_icon_control( msi_dialog *dialog, MSIRECORD *rec ) -{ - msi_control *control; - DWORD attributes; - LPWSTR name; - - TRACE("\n"); - - control = msi_dialog_add_control( dialog, rec, szStatic, - SS_ICON | SS_CENTERIMAGE | WS_GROUP ); - - attributes = MSI_RecordGetInteger( rec, 8 ); - name = msi_get_binary_name( dialog->package, rec ); - control->hIcon = msi_load_icon( dialog->package->db, name, attributes ); - if( control->hIcon ) - SendMessageW( control->hwnd, STM_SETICON, (WPARAM) control->hIcon, 0 ); - else - ERR("Failed to load bitmap %s\n", debugstr_w(name)); - msi_free( name ); - return ERROR_SUCCESS; -} - -/******************** Combo Box ***************************************/ - -struct msi_combobox_info -{ - msi_dialog *dialog; - HWND hwnd; - WNDPROC oldproc; - DWORD num_items; - DWORD addpos_items; - LPWSTR *items; -}; - -static LRESULT WINAPI MSIComboBox_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - struct msi_combobox_info *info; - LRESULT r; - DWORD j; - - TRACE("%p %04x %08lx %08lx\n", hWnd, msg, wParam, lParam); - - info = GetPropW( hWnd, szButtonData ); - if (!info) - return 0; - - r = CallWindowProcW( info->oldproc, hWnd, msg, wParam, lParam ); - - switch (msg) - { - case WM_NCDESTROY: - for (j = 0; j < info->num_items; j++) - msi_free( info->items[j] ); - msi_free( info->items ); - msi_free( info ); - RemovePropW( hWnd, szButtonData ); - break; - } - - return r; -} - -static UINT msi_combobox_add_item( MSIRECORD *rec, LPVOID param ) -{ - struct msi_combobox_info *info = param; - LPCWSTR value, text; - int pos; - - value = MSI_RecordGetString( rec, 3 ); - text = MSI_RecordGetString( rec, 4 ); - - info->items[info->addpos_items] = strdupW( value ); - - pos = SendMessageW( info->hwnd, CB_ADDSTRING, 0, (LPARAM)text ); - SendMessageW( info->hwnd, CB_SETITEMDATA, pos, (LPARAM)info->items[info->addpos_items] ); - info->addpos_items++; - - return ERROR_SUCCESS; -} - -static UINT msi_combobox_add_items( struct msi_combobox_info *info, LPCWSTR property ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','C','o','m','b','o','B','o','x','`',' ','W','H','E','R','E',' ', - '`','P','r','o','p','e','r','t','y','`',' ','=',' ','\'','%','s','\'',' ', - 'O','R','D','E','R',' ','B','Y',' ','`','O','r','d','e','r','`',0}; - MSIQUERY *view; - DWORD count; - UINT r; - - r = MSI_OpenQuery( info->dialog->package->db, &view, query, property ); - if (r != ERROR_SUCCESS) - return r; - - /* just get the number of records */ - count = 0; - r = MSI_IterateRecords( view, &count, NULL, NULL ); - if (r != ERROR_SUCCESS) - { - msiobj_release( &view->hdr ); - return r; - } - info->num_items = count; - info->items = msi_alloc( sizeof(*info->items) * count ); - - r = MSI_IterateRecords( view, NULL, msi_combobox_add_item, info ); - msiobj_release( &view->hdr ); - return r; -} - -static UINT msi_dialog_set_control_condition( MSIRECORD *rec, LPVOID param ) -{ - static const WCHAR szHide[] = {'H','i','d','e',0}; - static const WCHAR szShow[] = {'S','h','o','w',0}; - static const WCHAR szDisable[] = {'D','i','s','a','b','l','e',0}; - static const WCHAR szEnable[] = {'E','n','a','b','l','e',0}; - static const WCHAR szDefault[] = {'D','e','f','a','u','l','t',0}; - msi_dialog *dialog = param; - msi_control *control; - LPCWSTR name, action, condition; - UINT r; - - name = MSI_RecordGetString( rec, 2 ); - action = MSI_RecordGetString( rec, 3 ); - condition = MSI_RecordGetString( rec, 4 ); - r = MSI_EvaluateConditionW( dialog->package, condition ); - control = msi_dialog_find_control( dialog, name ); - if (r == MSICONDITION_TRUE && control) - { - TRACE("%s control %s\n", debugstr_w(action), debugstr_w(name)); - - /* FIXME: case sensitive? */ - if (!strcmpW( action, szHide )) - ShowWindow(control->hwnd, SW_HIDE); - else if (!strcmpW( action, szShow )) - ShowWindow(control->hwnd, SW_SHOW); - else if (!strcmpW( action, szDisable )) - EnableWindow(control->hwnd, FALSE); - else if (!strcmpW( action, szEnable )) - EnableWindow(control->hwnd, TRUE); - else if (!strcmpW( action, szDefault )) - SetFocus(control->hwnd); - else - FIXME("Unhandled action %s\n", debugstr_w(action)); - } - return ERROR_SUCCESS; -} - -static UINT msi_dialog_evaluate_control_conditions( msi_dialog *dialog ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'C','o','n','t','r','o','l','C','o','n','d','i','t','i','o','n',' ', - 'W','H','E','R','E',' ','`','D','i','a','l','o','g','_','`',' ','=',' ','\'','%','s','\'',0}; - UINT r; - MSIQUERY *view; - MSIPACKAGE *package = dialog->package; - - TRACE("%p %s\n", dialog, debugstr_w(dialog->name)); - - /* query the Control table for all the elements of the control */ - r = MSI_OpenQuery( package->db, &view, query, dialog->name ); - if (r != ERROR_SUCCESS) - return ERROR_SUCCESS; - - r = MSI_IterateRecords( view, 0, msi_dialog_set_control_condition, dialog ); - msiobj_release( &view->hdr ); - return r; -} - -static UINT msi_dialog_combobox_handler( msi_dialog *dialog, msi_control *control, WPARAM param ) -{ - struct msi_combobox_info *info; - int index; - LPWSTR value; - - if (HIWORD(param) != CBN_SELCHANGE && HIWORD(param) != CBN_EDITCHANGE) - return ERROR_SUCCESS; - - info = GetPropW( control->hwnd, szButtonData ); - index = SendMessageW( control->hwnd, CB_GETCURSEL, 0, 0 ); - if (index == CB_ERR) - value = msi_get_window_text( control->hwnd ); - else - value = (LPWSTR) SendMessageW( control->hwnd, CB_GETITEMDATA, index, 0 ); - - msi_dialog_set_property( info->dialog->package, control->property, value ); - msi_dialog_evaluate_control_conditions( info->dialog ); - - if (index == CB_ERR) - msi_free( value ); - - return ERROR_SUCCESS; -} - -static void msi_dialog_combobox_update( msi_dialog *dialog, msi_control *control ) -{ - struct msi_combobox_info *info; - LPWSTR value, tmp; - DWORD j; - - info = GetPropW( control->hwnd, szButtonData ); - - value = msi_dup_property( dialog->package->db, control->property ); - if (!value) - { - SendMessageW( control->hwnd, CB_SETCURSEL, -1, 0 ); - return; - } - - for (j = 0; j < info->num_items; j++) - { - tmp = (LPWSTR) SendMessageW( control->hwnd, CB_GETITEMDATA, j, 0 ); - if (!strcmpW( value, tmp )) - break; - } - - if (j < info->num_items) - { - SendMessageW( control->hwnd, CB_SETCURSEL, j, 0 ); - } - else - { - SendMessageW( control->hwnd, CB_SETCURSEL, -1, 0 ); - SetWindowTextW( control->hwnd, value ); - } - - msi_free(value); -} - -static UINT msi_dialog_combo_control( msi_dialog *dialog, MSIRECORD *rec ) -{ - struct msi_combobox_info *info; - msi_control *control; - DWORD attributes, style; - LPCWSTR prop; - - info = msi_alloc( sizeof *info ); - if (!info) - return ERROR_FUNCTION_FAILED; - - style = CBS_AUTOHSCROLL | WS_TABSTOP | WS_GROUP | WS_CHILD; - attributes = MSI_RecordGetInteger( rec, 8 ); - if ( ~attributes & msidbControlAttributesSorted) - style |= CBS_SORT; - if ( attributes & msidbControlAttributesComboList) - style |= CBS_DROPDOWNLIST; - else - style |= CBS_DROPDOWN; - - control = msi_dialog_add_control( dialog, rec, WC_COMBOBOXW, style ); - if (!control) - { - msi_free( info ); - return ERROR_FUNCTION_FAILED; - } - - control->handler = msi_dialog_combobox_handler; - control->update = msi_dialog_combobox_update; - - prop = MSI_RecordGetString( rec, 9 ); - control->property = msi_dialog_dup_property( dialog, prop, FALSE ); - - /* subclass */ - info->dialog = dialog; - info->hwnd = control->hwnd; - info->items = NULL; - info->addpos_items = 0; - info->oldproc = (WNDPROC)SetWindowLongPtrW( control->hwnd, GWLP_WNDPROC, - (LONG_PTR)MSIComboBox_WndProc ); - SetPropW( control->hwnd, szButtonData, info ); - - if (control->property) - msi_combobox_add_items( info, control->property ); - - msi_dialog_combobox_update( dialog, control ); - - return ERROR_SUCCESS; -} - -static UINT msi_dialog_edit_handler( msi_dialog *dialog, msi_control *control, WPARAM param ) -{ - LPWSTR buf; - - if (HIWORD(param) != EN_CHANGE) - return ERROR_SUCCESS; - - TRACE("edit %s contents changed, set %s\n", debugstr_w(control->name), debugstr_w(control->property)); - - buf = msi_get_window_text( control->hwnd ); - msi_dialog_set_property( dialog->package, control->property, buf ); - msi_free( buf ); - - return ERROR_SUCCESS; -} - -/* length of 2^32 + 1 */ -#define MAX_NUM_DIGITS 11 - -static UINT msi_dialog_edit_control( msi_dialog *dialog, MSIRECORD *rec ) -{ - msi_control *control; - LPCWSTR prop, text; - LPWSTR val, begin, end; - WCHAR num[MAX_NUM_DIGITS]; - DWORD limit; - - control = msi_dialog_add_control( dialog, rec, szEdit, - WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL ); - control->handler = msi_dialog_edit_handler; - - text = MSI_RecordGetString( rec, 10 ); - if ( text ) - { - begin = strchrW( text, '{' ); - end = strchrW( text, '}' ); - - if ( begin && end && end > begin && - begin[0] >= '0' && begin[0] <= '9' && - end - begin < MAX_NUM_DIGITS) - { - lstrcpynW( num, begin + 1, end - begin ); - limit = atolW( num ); - - SendMessageW( control->hwnd, EM_SETLIMITTEXT, limit, 0 ); - } - } - - prop = MSI_RecordGetString( rec, 9 ); - if( prop ) - control->property = strdupW( prop ); - - val = msi_dup_property( dialog->package->db, control->property ); - SetWindowTextW( control->hwnd, val ); - msi_free( val ); - return ERROR_SUCCESS; -} - -/******************** Masked Edit ********************************************/ - -#define MASK_MAX_GROUPS 20 - -struct msi_mask_group -{ - UINT len; - UINT ofs; - WCHAR type; - HWND hwnd; -}; - -struct msi_maskedit_info -{ - msi_dialog *dialog; - WNDPROC oldproc; - HWND hwnd; - LPWSTR prop; - UINT num_chars; - UINT num_groups; - struct msi_mask_group group[MASK_MAX_GROUPS]; -}; - -static BOOL msi_mask_editable( WCHAR type ) -{ - switch (type) - { - case '%': - case '#': - case '&': - case '`': - case '?': - case '^': - return TRUE; - } - return FALSE; -} - -static void msi_mask_control_change( struct msi_maskedit_info *info ) -{ - LPWSTR val; - UINT i, n, r; - - val = msi_alloc( (info->num_chars+1)*sizeof(WCHAR) ); - for( i=0, n=0; i<info->num_groups; i++ ) - { - if( (info->group[i].len + n) > info->num_chars ) - { - ERR("can't fit control %d text into template\n",i); - break; - } - if (!msi_mask_editable(info->group[i].type)) - { - for(r=0; r<info->group[i].len; r++) - val[n+r] = info->group[i].type; - val[n+r] = 0; - } - else - { - r = GetWindowTextW( info->group[i].hwnd, &val[n], info->group[i].len+1 ); - if( r != info->group[i].len ) - break; - } - n += r; - } - - TRACE("%d/%d controls were good\n", i, info->num_groups); - - if( i == info->num_groups ) - { - TRACE("Set property %s to %s\n", debugstr_w(info->prop), debugstr_w(val)); - CharUpperBuffW( val, info->num_chars ); - msi_dialog_set_property( info->dialog->package, info->prop, val ); - msi_dialog_evaluate_control_conditions( info->dialog ); - } - msi_free( val ); -} - -/* now move to the next control if necessary */ -static VOID msi_mask_next_control( struct msi_maskedit_info *info, HWND hWnd ) -{ - HWND hWndNext; - UINT len, i; - - for( i=0; i<info->num_groups; i++ ) - if( info->group[i].hwnd == hWnd ) - break; - - /* don't move from the last control */ - if( i >= (info->num_groups-1) ) - return; - - len = SendMessageW( hWnd, WM_GETTEXTLENGTH, 0, 0 ); - if( len < info->group[i].len ) - return; - - hWndNext = GetNextDlgTabItem( GetParent( hWnd ), hWnd, FALSE ); - SetFocus( hWndNext ); -} - -static LRESULT WINAPI -MSIMaskedEdit_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - struct msi_maskedit_info *info; - HRESULT r; - - TRACE("%p %04x %08lx %08lx\n", hWnd, msg, wParam, lParam); - - info = GetPropW(hWnd, szButtonData); - - r = CallWindowProcW(info->oldproc, hWnd, msg, wParam, lParam); - - switch( msg ) - { - case WM_COMMAND: - if (HIWORD(wParam) == EN_CHANGE) - { - msi_mask_control_change( info ); - msi_mask_next_control( info, (HWND) lParam ); - } - break; - case WM_NCDESTROY: - msi_free( info->prop ); - msi_free( info ); - RemovePropW( hWnd, szButtonData ); - break; - } - - return r; -} - -/* fish the various bits of the property out and put them in the control */ -static void -msi_maskedit_set_text( struct msi_maskedit_info *info, LPCWSTR text ) -{ - LPCWSTR p; - UINT i; - - p = text; - for( i = 0; i < info->num_groups; i++ ) - { - if( info->group[i].len < strlenW( p ) ) - { - LPWSTR chunk = strdupW( p ); - chunk[ info->group[i].len ] = 0; - SetWindowTextW( info->group[i].hwnd, chunk ); - msi_free( chunk ); - } - else - { - SetWindowTextW( info->group[i].hwnd, p ); - break; - } - p += info->group[i].len; - } -} - -static struct msi_maskedit_info * msi_dialog_parse_groups( LPCWSTR mask ) -{ - struct msi_maskedit_info * info = NULL; - int i = 0, n = 0, total = 0; - LPCWSTR p; - - TRACE("masked control, template %s\n", debugstr_w(mask)); - - if( !mask ) - return info; - - info = msi_alloc_zero( sizeof *info ); - if( !info ) - return info; - - p = strchrW(mask, '<'); - if( p ) - p++; - else - p = mask; - - for( i=0; i<MASK_MAX_GROUPS; i++ ) - { - /* stop at the end of the string */ - if( p[0] == 0 || p[0] == '>' ) - break; - - /* count the number of the same identifier */ - for( n=0; p[n] == p[0]; n++ ) - ; - info->group[i].ofs = total; - info->group[i].type = p[0]; - if( p[n] == '=' ) - { - n++; - total++; /* an extra not part of the group */ - } - info->group[i].len = n; - total += n; - p += n; - } - - TRACE("%d characters in %d groups\n", total, i ); - if( i == MASK_MAX_GROUPS ) - ERR("too many groups in PIDTemplate %s\n", debugstr_w(mask)); - - info->num_chars = total; - info->num_groups = i; - - return info; -} - -static void -msi_maskedit_create_children( struct msi_maskedit_info *info, LPCWSTR font ) -{ - DWORD width, height, style, wx, ww; - RECT rect; - HWND hwnd; - UINT i; - - style = WS_CHILD | WS_BORDER | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL; - - GetClientRect( info->hwnd, &rect ); - - width = rect.right - rect.left; - height = rect.bottom - rect.top; - - for( i = 0; i < info->num_groups; i++ ) - { - if (!msi_mask_editable( info->group[i].type )) - continue; - wx = (info->group[i].ofs * width) / info->num_chars; - ww = (info->group[i].len * width) / info->num_chars; - - hwnd = CreateWindowW( szEdit, NULL, style, wx, 0, ww, height, - info->hwnd, NULL, NULL, NULL ); - if( !hwnd ) - { - ERR("failed to create mask edit sub window\n"); - break; - } - - SendMessageW( hwnd, EM_LIMITTEXT, info->group[i].len, 0 ); - - msi_dialog_set_font( info->dialog, hwnd, - font?font:info->dialog->default_font ); - info->group[i].hwnd = hwnd; - } -} - -/* - * office 2003 uses "73931<````=````=````=````=`````>@@@@@" - * delphi 7 uses "<????-??????-??????-????>" and "<???-???>" - * filemaker pro 7 uses "<^^^^=^^^^=^^^^=^^^^=^^^^=^^^^=^^^^^>" - */ -static UINT msi_dialog_maskedit_control( msi_dialog *dialog, MSIRECORD *rec ) -{ - LPWSTR font_mask, val = NULL, font; - struct msi_maskedit_info *info = NULL; - UINT ret = ERROR_SUCCESS; - msi_control *control; - LPCWSTR prop, mask; - - TRACE("\n"); - - font_mask = msi_get_deformatted_field( dialog->package, rec, 10 ); - font = msi_dialog_get_style( font_mask, &mask ); - if( !mask ) - { - WARN("mask template is empty\n"); - goto end; - } - - info = msi_dialog_parse_groups( mask ); - if( !info ) - { - ERR("template %s is invalid\n", debugstr_w(mask)); - goto end; - } - - info->dialog = dialog; - - control = msi_dialog_add_control( dialog, rec, szStatic, - SS_OWNERDRAW | WS_GROUP | WS_VISIBLE ); - if( !control ) - { - ERR("Failed to create maskedit container\n"); - ret = ERROR_FUNCTION_FAILED; - goto end; - } - SetWindowLongPtrW( control->hwnd, GWL_EXSTYLE, WS_EX_CONTROLPARENT ); - - info->hwnd = control->hwnd; - - /* subclass the static control */ - info->oldproc = (WNDPROC) SetWindowLongPtrW( info->hwnd, GWLP_WNDPROC, - (LONG_PTR)MSIMaskedEdit_WndProc ); - SetPropW( control->hwnd, szButtonData, info ); - - prop = MSI_RecordGetString( rec, 9 ); - if( prop ) - info->prop = strdupW( prop ); - - msi_maskedit_create_children( info, font ); - - if( prop ) - { - val = msi_dup_property( dialog->package->db, prop ); - if( val ) - { - msi_maskedit_set_text( info, val ); - msi_free( val ); - } - } - -end: - if( ret != ERROR_SUCCESS ) - msi_free( info ); - msi_free( font_mask ); - msi_free( font ); - return ret; -} - -/******************** Progress Bar *****************************************/ - -static UINT msi_dialog_progress_bar( msi_dialog *dialog, MSIRECORD *rec ) -{ - msi_control *control; - DWORD attributes, style; - - style = WS_VISIBLE; - attributes = MSI_RecordGetInteger( rec, 8 ); - if( !(attributes & msidbControlAttributesProgress95) ) - style |= PBS_SMOOTH; - - control = msi_dialog_add_control( dialog, rec, PROGRESS_CLASSW, style ); - if( !control ) - return ERROR_FUNCTION_FAILED; - - ControlEvent_SubscribeToEvent( dialog->package, dialog, - szSetProgress, control->name, szProgress ); - return ERROR_SUCCESS; -} - -/******************** Path Edit ********************************************/ - -struct msi_pathedit_info -{ - msi_dialog *dialog; - msi_control *control; - WNDPROC oldproc; -}; - -static void msi_dialog_update_pathedit( msi_dialog *dialog, msi_control *control ) -{ - LPWSTR prop, path; - BOOL indirect; - - if (!control && !(control = msi_dialog_find_control_by_type( dialog, szPathEdit ))) - return; - - indirect = control->attributes & msidbControlAttributesIndirect; - prop = msi_dialog_dup_property( dialog, control->property, indirect ); - path = msi_dialog_dup_property( dialog, prop, TRUE ); - - SetWindowTextW( control->hwnd, path ); - SendMessageW( control->hwnd, EM_SETSEL, 0, -1 ); - - msi_free( path ); - msi_free( prop ); -} - -/* FIXME: test when this should fail */ -static BOOL msi_dialog_verify_path( LPWSTR path ) -{ - if ( !lstrlenW( path ) ) - return FALSE; - - if ( PathIsRelativeW( path ) ) - return FALSE; - - return TRUE; -} - -/* returns TRUE if the path is valid, FALSE otherwise */ -static BOOL msi_dialog_onkillfocus( msi_dialog *dialog, msi_control *control ) -{ - LPWSTR buf, prop; - BOOL indirect; - BOOL valid; - - indirect = control->attributes & msidbControlAttributesIndirect; - prop = msi_dialog_dup_property( dialog, control->property, indirect ); - - buf = msi_get_window_text( control->hwnd ); - - if ( !msi_dialog_verify_path( buf ) ) - { - /* FIXME: display an error message box */ - ERR("Invalid path %s\n", debugstr_w( buf )); - valid = FALSE; - SetFocus( control->hwnd ); - } - else - { - valid = TRUE; - msi_dialog_set_property( dialog->package, prop, buf ); - } - - msi_dialog_update_pathedit( dialog, control ); - - TRACE("edit %s contents changed, set %s\n", debugstr_w(control->name), - debugstr_w(prop)); - - msi_free( buf ); - msi_free( prop ); - - return valid; -} - -static LRESULT WINAPI MSIPathEdit_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - struct msi_pathedit_info *info = GetPropW(hWnd, szButtonData); - LRESULT r = 0; - - TRACE("%p %04x %08lx %08lx\n", hWnd, msg, wParam, lParam); - - if ( msg == WM_KILLFOCUS ) - { - /* if the path is invalid, don't handle this message */ - if ( !msi_dialog_onkillfocus( info->dialog, info->control ) ) - return 0; - } - - r = CallWindowProcW(info->oldproc, hWnd, msg, wParam, lParam); - - if ( msg == WM_NCDESTROY ) - { - msi_free( info ); - RemovePropW( hWnd, szButtonData ); - } - - return r; -} - -static UINT msi_dialog_pathedit_control( msi_dialog *dialog, MSIRECORD *rec ) -{ - struct msi_pathedit_info *info; - msi_control *control; - LPCWSTR prop; - - info = msi_alloc( sizeof *info ); - if (!info) - return ERROR_FUNCTION_FAILED; - - control = msi_dialog_add_control( dialog, rec, szEdit, - WS_BORDER | WS_TABSTOP ); - control->attributes = MSI_RecordGetInteger( rec, 8 ); - prop = MSI_RecordGetString( rec, 9 ); - control->property = msi_dialog_dup_property( dialog, prop, FALSE ); - - info->dialog = dialog; - info->control = control; - info->oldproc = (WNDPROC) SetWindowLongPtrW( control->hwnd, GWLP_WNDPROC, - (LONG_PTR)MSIPathEdit_WndProc ); - SetPropW( control->hwnd, szButtonData, info ); - - msi_dialog_update_pathedit( dialog, control ); - - return ERROR_SUCCESS; -} - -static UINT msi_dialog_radiogroup_handler( msi_dialog *dialog, msi_control *control, WPARAM param ) -{ - if (HIWORD(param) != BN_CLICKED) - return ERROR_SUCCESS; - - TRACE("clicked radio button %s, set %s\n", debugstr_w(control->name), debugstr_w(control->property)); - - msi_dialog_set_property( dialog->package, control->property, control->name ); - - return msi_dialog_button_handler( dialog, control, param ); -} - -/* radio buttons are a bit different from normal controls */ -static UINT msi_dialog_create_radiobutton( MSIRECORD *rec, LPVOID param ) -{ - radio_button_group_descr *group = param; - msi_dialog *dialog = group->dialog; - msi_control *control; - LPCWSTR prop, text, name; - DWORD style, attributes = group->attributes; - - style = WS_CHILD | BS_AUTORADIOBUTTON | BS_MULTILINE | WS_TABSTOP; - name = MSI_RecordGetString( rec, 3 ); - text = MSI_RecordGetString( rec, 8 ); - if( attributes & msidbControlAttributesVisible ) - style |= WS_VISIBLE; - if( ~attributes & msidbControlAttributesEnabled ) - style |= WS_DISABLED; - - control = msi_dialog_create_window( dialog, rec, 0, szButton, name, text, - style, group->parent->hwnd ); - if (!control) - return ERROR_FUNCTION_FAILED; - control->handler = msi_dialog_radiogroup_handler; - - if (group->propval && !strcmpW( control->name, group->propval )) - SendMessageW(control->hwnd, BM_SETCHECK, BST_CHECKED, 0); - - prop = MSI_RecordGetString( rec, 1 ); - if( prop ) - control->property = strdupW( prop ); - - return ERROR_SUCCESS; -} - -static BOOL CALLBACK msi_radioground_child_enum( HWND hWnd, LPARAM lParam ) -{ - EnableWindow( hWnd, lParam ); - return TRUE; -} - -static LRESULT WINAPI MSIRadioGroup_WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) -{ - WNDPROC oldproc = (WNDPROC)GetPropW( hWnd, szButtonData ); - LRESULT r; - - TRACE("hWnd %p msg %04x wParam 0x%08lx lParam 0x%08lx\n", hWnd, msg, wParam, lParam); - - if (msg == WM_COMMAND) /* Forward notifications to dialog */ - SendMessageW( GetParent( hWnd ), msg, wParam, lParam ); - - r = CallWindowProcW( oldproc, hWnd, msg, wParam, lParam ); - - /* make sure the radio buttons show as disabled if the parent is disabled */ - if (msg == WM_ENABLE) - EnumChildWindows( hWnd, msi_radioground_child_enum, wParam ); - - return r; -} - -static UINT msi_dialog_radiogroup_control( msi_dialog *dialog, MSIRECORD *rec ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'R','a','d','i','o','B','u','t','t','o','n',' ','W','H','E','R','E',' ', - '`','P','r','o','p','e','r','t','y','`',' ','=',' ','\'','%','s','\'',0}; - UINT r; - LPCWSTR prop; - msi_control *control; - MSIQUERY *view; - radio_button_group_descr group; - MSIPACKAGE *package = dialog->package; - WNDPROC oldproc; - DWORD attr, style = WS_GROUP; - - prop = MSI_RecordGetString( rec, 9 ); - - TRACE("%p %p %s\n", dialog, rec, debugstr_w( prop )); - - attr = MSI_RecordGetInteger( rec, 8 ); - if (attr & msidbControlAttributesHasBorder) - style |= BS_GROUPBOX; - else - style |= BS_OWNERDRAW; - - /* Create parent group box to hold radio buttons */ - control = msi_dialog_add_control( dialog, rec, szButton, style ); - if( !control ) - return ERROR_FUNCTION_FAILED; - - oldproc = (WNDPROC) SetWindowLongPtrW( control->hwnd, GWLP_WNDPROC, - (LONG_PTR)MSIRadioGroup_WndProc ); - SetPropW(control->hwnd, szButtonData, oldproc); - SetWindowLongPtrW( control->hwnd, GWL_EXSTYLE, WS_EX_CONTROLPARENT ); - - if( prop ) - control->property = strdupW( prop ); - - /* query the Radio Button table for all control in this group */ - r = MSI_OpenQuery( package->db, &view, query, prop ); - if( r != ERROR_SUCCESS ) - { - ERR("query failed for dialog %s radio group %s\n", - debugstr_w(dialog->name), debugstr_w(prop)); - return ERROR_INVALID_PARAMETER; - } - - group.dialog = dialog; - group.parent = control; - group.attributes = MSI_RecordGetInteger( rec, 8 ); - group.propval = msi_dup_property( dialog->package->db, control->property ); - - r = MSI_IterateRecords( view, 0, msi_dialog_create_radiobutton, &group ); - msiobj_release( &view->hdr ); - msi_free( group.propval ); - return r; -} - -static void -msi_seltree_sync_item_state( HWND hwnd, MSIFEATURE *feature, HTREEITEM hItem ) -{ - TVITEMW tvi; - DWORD index = feature->ActionRequest; - - TRACE("Feature %s -> %d %d %d\n", debugstr_w(feature->Title), - feature->Installed, feature->Action, feature->ActionRequest); - - if (index == INSTALLSTATE_UNKNOWN) - index = INSTALLSTATE_ABSENT; - - tvi.mask = TVIF_STATE; - tvi.hItem = hItem; - tvi.state = INDEXTOSTATEIMAGEMASK( index ); - tvi.stateMask = TVIS_STATEIMAGEMASK; - - SendMessageW( hwnd, TVM_SETITEMW, 0, (LPARAM) &tvi ); -} - -static UINT -msi_seltree_popup_menu( HWND hwnd, INT x, INT y ) -{ - HMENU hMenu; - INT r; - - /* create a menu to display */ - hMenu = CreatePopupMenu(); - - /* FIXME: load strings from resources */ - AppendMenuA( hMenu, MF_ENABLED, INSTALLSTATE_LOCAL, "Install feature locally"); - AppendMenuA( hMenu, MF_ENABLED, USER_INSTALLSTATE_ALL, "Install entire feature"); - AppendMenuA( hMenu, MF_ENABLED, INSTALLSTATE_ADVERTISED, "Install on demand"); - AppendMenuA( hMenu, MF_ENABLED, INSTALLSTATE_ABSENT, "Don't install"); - r = TrackPopupMenu( hMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, - x, y, 0, hwnd, NULL ); - DestroyMenu( hMenu ); - return r; -} - -static void -msi_seltree_update_feature_installstate( HWND hwnd, HTREEITEM hItem, - MSIPACKAGE *package, MSIFEATURE *feature, INSTALLSTATE state ) -{ - feature->ActionRequest = state; - msi_seltree_sync_item_state( hwnd, feature, hItem ); - ACTION_UpdateComponentStates( package, feature ); -} - -static void -msi_seltree_update_siblings_and_children_installstate( HWND hwnd, HTREEITEM curr, - MSIPACKAGE *package, INSTALLSTATE state) -{ - /* update all siblings */ - do - { - MSIFEATURE *feature; - HTREEITEM child; - - feature = msi_seltree_feature_from_item( hwnd, curr ); - msi_seltree_update_feature_installstate( hwnd, curr, package, feature, state ); - - /* update this sibling's children */ - child = (HTREEITEM)SendMessageW( hwnd, TVM_GETNEXTITEM, (WPARAM)TVGN_CHILD, (LPARAM)curr ); - if (child) - msi_seltree_update_siblings_and_children_installstate( hwnd, child, - package, state ); - } - while ((curr = (HTREEITEM)SendMessageW( hwnd, TVM_GETNEXTITEM, (WPARAM)TVGN_NEXT, (LPARAM)curr ))); -} - -static LRESULT -msi_seltree_menu( HWND hwnd, HTREEITEM hItem ) -{ - struct msi_selection_tree_info *info; - MSIFEATURE *feature; - MSIPACKAGE *package; - union { - RECT rc; - POINT pt[2]; - HTREEITEM hItem; - } u; - UINT r; - - info = GetPropW(hwnd, szButtonData); - package = info->dialog->package; - - feature = msi_seltree_feature_from_item( hwnd, hItem ); - if (!feature) - { - ERR("item %p feature was NULL\n", hItem); - return 0; - } - - /* get the item's rectangle to put the menu just below it */ - u.hItem = hItem; - SendMessageW( hwnd, TVM_GETITEMRECT, 0, (LPARAM) &u.rc ); - MapWindowPoints( hwnd, NULL, u.pt, 2 ); - - r = msi_seltree_popup_menu( hwnd, u.rc.left, u.rc.top ); - - switch (r) - { - case USER_INSTALLSTATE_ALL: - r = INSTALLSTATE_LOCAL; - /* fall-through */ - case INSTALLSTATE_ADVERTISED: - case INSTALLSTATE_ABSENT: - { - HTREEITEM child; - child = (HTREEITEM)SendMessageW( hwnd, TVM_GETNEXTITEM, (WPARAM)TVGN_CHILD, (LPARAM)hItem ); - if (child) - msi_seltree_update_siblings_and_children_installstate( hwnd, child, package, r ); - } - /* fall-through */ - case INSTALLSTATE_LOCAL: - msi_seltree_update_feature_installstate( hwnd, hItem, package, feature, r ); - break; - } - - return 0; -} - -static LRESULT WINAPI -MSISelectionTree_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - struct msi_selection_tree_info *info; - TVHITTESTINFO tvhti; - HRESULT r; - - TRACE("%p %04x %08lx %08lx\n", hWnd, msg, wParam, lParam); - - info = GetPropW(hWnd, szButtonData); - - switch( msg ) - { - case WM_LBUTTONDOWN: - tvhti.pt.x = (short)LOWORD( lParam ); - tvhti.pt.y = (short)HIWORD( lParam ); - tvhti.flags = 0; - tvhti.hItem = 0; - CallWindowProcW(info->oldproc, hWnd, TVM_HITTEST, 0, (LPARAM) &tvhti ); - if (tvhti.flags & TVHT_ONITEMSTATEICON) - return msi_seltree_menu( hWnd, tvhti.hItem ); - break; - } - r = CallWindowProcW(info->oldproc, hWnd, msg, wParam, lParam); - - switch( msg ) - { - case WM_NCDESTROY: - msi_free( info ); - RemovePropW( hWnd, szButtonData ); - break; - } - return r; -} - -static void -msi_seltree_add_child_features( MSIPACKAGE *package, HWND hwnd, - LPCWSTR parent, HTREEITEM hParent ) -{ - struct msi_selection_tree_info *info = GetPropW( hwnd, szButtonData ); - MSIFEATURE *feature; - TVINSERTSTRUCTW tvis; - HTREEITEM hitem, hfirst = NULL; - - LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) - { - if ( parent && feature->Feature_Parent && strcmpW( parent, feature->Feature_Parent )) - continue; - else if ( parent && !feature->Feature_Parent ) - continue; - else if ( !parent && feature->Feature_Parent ) - continue; - - if ( !feature->Title ) - continue; - - if ( !feature->Display ) - continue; - - memset( &tvis, 0, sizeof tvis ); - tvis.hParent = hParent; - tvis.hInsertAfter = TVI_LAST; - tvis.u.item.mask = TVIF_TEXT | TVIF_PARAM; - tvis.u.item.pszText = feature->Title; - tvis.u.item.lParam = (LPARAM) feature; - - hitem = (HTREEITEM) SendMessageW( hwnd, TVM_INSERTITEMW, 0, (LPARAM) &tvis ); - if (!hitem) - continue; - - if (!hfirst) - hfirst = hitem; - - msi_seltree_sync_item_state( hwnd, feature, hitem ); - msi_seltree_add_child_features( package, hwnd, - feature->Feature, hitem ); - - /* the node is expanded if Display is odd */ - if ( feature->Display % 2 != 0 ) - SendMessageW( hwnd, TVM_EXPAND, TVE_EXPAND, (LPARAM) hitem ); - } - - /* select the first item */ - SendMessageW( hwnd, TVM_SELECTITEM, TVGN_CARET | TVGN_DROPHILITE, (LPARAM) hfirst ); - info->selected = hfirst; -} - -static void msi_seltree_create_imagelist( HWND hwnd ) -{ - const int bm_width = 32, bm_height = 16, bm_count = 3; - const int bm_resource = 0x1001; - HIMAGELIST himl; - int i; - HBITMAP hbmp; - - himl = ImageList_Create( bm_width, bm_height, FALSE, 4, 0 ); - if (!himl) - { - ERR("failed to create image list\n"); - return; - } - - for (i=0; i<bm_count; i++) - { - hbmp = LoadBitmapW( msi_hInstance, MAKEINTRESOURCEW(i+bm_resource) ); - if (!hbmp) - { - ERR("failed to load bitmap %d\n", i); - break; - } - - /* - * Add a dummy bitmap at offset zero because the treeview - * can't use it as a state mask (zero means no user state). - */ - if (!i) - ImageList_Add( himl, hbmp, NULL ); - - ImageList_Add( himl, hbmp, NULL ); - } - - SendMessageW( hwnd, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)himl ); -} - -static UINT msi_dialog_seltree_handler( msi_dialog *dialog, - msi_control *control, WPARAM param ) -{ - struct msi_selection_tree_info *info = GetPropW( control->hwnd, szButtonData ); - LPNMTREEVIEWW tv = (LPNMTREEVIEWW)param; - MSIRECORD *row, *rec; - MSIFOLDER *folder; - MSIFEATURE *feature; - LPCWSTR dir, title = NULL; - UINT r = ERROR_SUCCESS; - - static const WCHAR select[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','F','e','a','t','u','r','e','`',' ','W','H','E','R','E',' ', - '`','T','i','t','l','e','`',' ','=',' ','\'','%','s','\'',0 - }; - - if (tv->hdr.code != TVN_SELCHANGINGW) - return ERROR_SUCCESS; - - info->selected = tv->itemNew.hItem; - - if (!(tv->itemNew.mask & TVIF_TEXT)) - { - feature = msi_seltree_feature_from_item( control->hwnd, tv->itemNew.hItem ); - if (feature) - title = feature->Title; - } - else - title = tv->itemNew.pszText; - - row = MSI_QueryGetRecord( dialog->package->db, select, title ); - if (!row) - return ERROR_FUNCTION_FAILED; - - rec = MSI_CreateRecord( 1 ); - - MSI_RecordSetStringW( rec, 1, MSI_RecordGetString( row, 4 ) ); - ControlEvent_FireSubscribedEvent( dialog->package, szSelectionDescription, rec ); - - dir = MSI_RecordGetString( row, 7 ); - if (dir) - { - folder = msi_get_loaded_folder( dialog->package, dir ); - if (!folder) - { - r = ERROR_FUNCTION_FAILED; - goto done; - } - MSI_RecordSetStringW( rec, 1, folder->ResolvedTarget ); - } - else - MSI_RecordSetStringW( rec, 1, NULL ); - - ControlEvent_FireSubscribedEvent( dialog->package, szSelectionPath, rec ); - -done: - msiobj_release(&row->hdr); - msiobj_release(&rec->hdr); - - return r; -} - -static UINT msi_dialog_selection_tree( msi_dialog *dialog, MSIRECORD *rec ) -{ - msi_control *control; - LPCWSTR prop, control_name; - MSIPACKAGE *package = dialog->package; - DWORD style; - struct msi_selection_tree_info *info; - - info = msi_alloc( sizeof *info ); - if (!info) - return ERROR_FUNCTION_FAILED; - - /* create the treeview control */ - style = TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT; - style |= WS_GROUP | WS_VSCROLL; - control = msi_dialog_add_control( dialog, rec, WC_TREEVIEWW, style ); - if (!control) - { - msi_free(info); - return ERROR_FUNCTION_FAILED; - } - - control->handler = msi_dialog_seltree_handler; - control_name = MSI_RecordGetString( rec, 2 ); - control->attributes = MSI_RecordGetInteger( rec, 8 ); - prop = MSI_RecordGetString( rec, 9 ); - control->property = msi_dialog_dup_property( dialog, prop, FALSE ); - - /* subclass */ - info->dialog = dialog; - info->hwnd = control->hwnd; - info->oldproc = (WNDPROC) SetWindowLongPtrW( control->hwnd, GWLP_WNDPROC, - (LONG_PTR)MSISelectionTree_WndProc ); - SetPropW( control->hwnd, szButtonData, info ); - - ControlEvent_SubscribeToEvent( dialog->package, dialog, - szSelectionPath, control_name, szProperty ); - - /* initialize it */ - msi_seltree_create_imagelist( control->hwnd ); - msi_seltree_add_child_features( package, control->hwnd, NULL, NULL ); - - return ERROR_SUCCESS; -} - -/******************** Group Box ***************************************/ - -static UINT msi_dialog_group_box( msi_dialog *dialog, MSIRECORD *rec ) -{ - msi_control *control; - DWORD style; - - style = BS_GROUPBOX | WS_CHILD | WS_GROUP; - control = msi_dialog_add_control( dialog, rec, WC_BUTTONW, style ); - if (!control) - return ERROR_FUNCTION_FAILED; - - return ERROR_SUCCESS; -} - -/******************** List Box ***************************************/ - -struct msi_listbox_info -{ - msi_dialog *dialog; - HWND hwnd; - WNDPROC oldproc; - DWORD num_items; - DWORD addpos_items; - LPWSTR *items; -}; - -static LRESULT WINAPI MSIListBox_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - struct msi_listbox_info *info; - LRESULT r; - DWORD j; - - TRACE("%p %04x %08lx %08lx\n", hWnd, msg, wParam, lParam); - - info = GetPropW( hWnd, szButtonData ); - if (!info) - return 0; - - r = CallWindowProcW( info->oldproc, hWnd, msg, wParam, lParam ); - - switch( msg ) - { - case WM_NCDESTROY: - for (j = 0; j < info->num_items; j++) - msi_free( info->items[j] ); - msi_free( info->items ); - msi_free( info ); - RemovePropW( hWnd, szButtonData ); - break; - } - - return r; -} - -static UINT msi_listbox_add_item( MSIRECORD *rec, LPVOID param ) -{ - struct msi_listbox_info *info = param; - LPCWSTR value, text; - int pos; - - value = MSI_RecordGetString( rec, 3 ); - text = MSI_RecordGetString( rec, 4 ); - - info->items[info->addpos_items] = strdupW( value ); - - pos = SendMessageW( info->hwnd, LB_ADDSTRING, 0, (LPARAM)text ); - SendMessageW( info->hwnd, LB_SETITEMDATA, pos, (LPARAM)info->items[info->addpos_items] ); - info->addpos_items++; - return ERROR_SUCCESS; -} - -static UINT msi_listbox_add_items( struct msi_listbox_info *info, LPCWSTR property ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','L','i','s','t','B','o','x','`',' ','W','H','E','R','E',' ', - '`','P','r','o','p','e','r','t','y','`',' ','=',' ','\'','%','s','\'',' ', - 'O','R','D','E','R',' ','B','Y',' ','`','O','r','d','e','r','`',0}; - MSIQUERY *view; - DWORD count; - UINT r; - - r = MSI_OpenQuery( info->dialog->package->db, &view, query, property ); - if ( r != ERROR_SUCCESS ) - return r; - - /* just get the number of records */ - count = 0; - r = MSI_IterateRecords( view, &count, NULL, NULL ); - if (r != ERROR_SUCCESS) - { - msiobj_release( &view->hdr ); - return r; - } - info->num_items = count; - info->items = msi_alloc( sizeof(*info->items) * count ); - - r = MSI_IterateRecords( view, NULL, msi_listbox_add_item, info ); - msiobj_release( &view->hdr ); - return r; -} - -static UINT msi_dialog_listbox_handler( msi_dialog *dialog, - msi_control *control, WPARAM param ) -{ - struct msi_listbox_info *info; - int index; - LPCWSTR value; - - if( HIWORD(param) != LBN_SELCHANGE ) - return ERROR_SUCCESS; - - info = GetPropW( control->hwnd, szButtonData ); - index = SendMessageW( control->hwnd, LB_GETCURSEL, 0, 0 ); - value = (LPCWSTR) SendMessageW( control->hwnd, LB_GETITEMDATA, index, 0 ); - - msi_dialog_set_property( info->dialog->package, control->property, value ); - msi_dialog_evaluate_control_conditions( info->dialog ); - - return ERROR_SUCCESS; -} - -static UINT msi_dialog_list_box( msi_dialog *dialog, MSIRECORD *rec ) -{ - struct msi_listbox_info *info; - msi_control *control; - DWORD attributes, style; - LPCWSTR prop; - - info = msi_alloc( sizeof *info ); - if (!info) - return ERROR_FUNCTION_FAILED; - - style = WS_TABSTOP | WS_GROUP | WS_CHILD | LBS_NOTIFY | WS_VSCROLL | WS_BORDER; - attributes = MSI_RecordGetInteger( rec, 8 ); - if (~attributes & msidbControlAttributesSorted) - style |= LBS_SORT; - - control = msi_dialog_add_control( dialog, rec, WC_LISTBOXW, style ); - if (!control) - { - msi_free(info); - return ERROR_FUNCTION_FAILED; - } - - control->handler = msi_dialog_listbox_handler; - - prop = MSI_RecordGetString( rec, 9 ); - control->property = msi_dialog_dup_property( dialog, prop, FALSE ); - - /* subclass */ - info->dialog = dialog; - info->hwnd = control->hwnd; - info->items = NULL; - info->addpos_items = 0; - info->oldproc = (WNDPROC)SetWindowLongPtrW( control->hwnd, GWLP_WNDPROC, - (LONG_PTR)MSIListBox_WndProc ); - SetPropW( control->hwnd, szButtonData, info ); - - if ( control->property ) - msi_listbox_add_items( info, control->property ); - - return ERROR_SUCCESS; -} - -/******************** Directory Combo ***************************************/ - -static void msi_dialog_update_directory_combo( msi_dialog *dialog, msi_control *control ) -{ - LPWSTR prop, path; - BOOL indirect; - - if (!control && !(control = msi_dialog_find_control_by_type( dialog, szDirectoryCombo ))) - return; - - indirect = control->attributes & msidbControlAttributesIndirect; - prop = msi_dialog_dup_property( dialog, control->property, indirect ); - path = msi_dialog_dup_property( dialog, prop, TRUE ); - - PathStripPathW( path ); - PathRemoveBackslashW( path ); - - SendMessageW( control->hwnd, CB_INSERTSTRING, 0, (LPARAM)path ); - SendMessageW( control->hwnd, CB_SETCURSEL, 0, 0 ); - - msi_free( path ); - msi_free( prop ); -} - -static UINT msi_dialog_directory_combo( msi_dialog *dialog, MSIRECORD *rec ) -{ - msi_control *control; - LPCWSTR prop; - DWORD style; - - /* FIXME: use CBS_OWNERDRAWFIXED and add owner draw code */ - style = CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_CHILD | - WS_GROUP | WS_TABSTOP | WS_VSCROLL; - control = msi_dialog_add_control( dialog, rec, WC_COMBOBOXW, style ); - if (!control) - return ERROR_FUNCTION_FAILED; - - control->attributes = MSI_RecordGetInteger( rec, 8 ); - prop = MSI_RecordGetString( rec, 9 ); - control->property = msi_dialog_dup_property( dialog, prop, FALSE ); - - msi_dialog_update_directory_combo( dialog, control ); - - return ERROR_SUCCESS; -} - -/******************** Directory List ***************************************/ - -static void msi_dialog_update_directory_list( msi_dialog *dialog, msi_control *control ) -{ - WCHAR dir_spec[MAX_PATH]; - WIN32_FIND_DATAW wfd; - LPWSTR prop, path; - BOOL indirect; - LVITEMW item; - HANDLE file; - - static const WCHAR asterisk[] = {'*',0}; - - if (!control && !(control = msi_dialog_find_control_by_type( dialog, szDirectoryList ))) - return; - - /* clear the list-view */ - SendMessageW( control->hwnd, LVM_DELETEALLITEMS, 0, 0 ); - - indirect = control->attributes & msidbControlAttributesIndirect; - prop = msi_dialog_dup_property( dialog, control->property, indirect ); - path = msi_dialog_dup_property( dialog, prop, TRUE ); - - lstrcpyW( dir_spec, path ); - lstrcatW( dir_spec, asterisk ); - - file = FindFirstFileW( dir_spec, &wfd ); - if ( file == INVALID_HANDLE_VALUE ) - return; - - do - { - if ( wfd.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY ) - continue; - - if ( !strcmpW( wfd.cFileName, szDot ) || !strcmpW( wfd.cFileName, szDotDot ) ) - continue; - - item.mask = LVIF_TEXT; - item.cchTextMax = MAX_PATH; - item.iItem = 0; - item.iSubItem = 0; - item.pszText = wfd.cFileName; - - SendMessageW( control->hwnd, LVM_INSERTITEMW, 0, (LPARAM)&item ); - } while ( FindNextFileW( file, &wfd ) ); - - msi_free( prop ); - msi_free( path ); - FindClose( file ); -} - -UINT msi_dialog_directorylist_up( msi_dialog *dialog ) -{ - msi_control *control; - LPWSTR prop, path, ptr; - BOOL indirect; - - control = msi_dialog_find_control_by_type( dialog, szDirectoryList ); - indirect = control->attributes & msidbControlAttributesIndirect; - prop = msi_dialog_dup_property( dialog, control->property, indirect ); - path = msi_dialog_dup_property( dialog, prop, TRUE ); - - /* strip off the last directory */ - ptr = PathFindFileNameW( path ); - if (ptr != path) *(ptr - 1) = '\0'; - PathAddBackslashW( path ); - - msi_dialog_set_property( dialog->package, prop, path ); - - msi_dialog_update_directory_list( dialog, NULL ); - msi_dialog_update_directory_combo( dialog, NULL ); - msi_dialog_update_pathedit( dialog, NULL ); - - msi_free( path ); - msi_free( prop ); - - return ERROR_SUCCESS; -} - -static UINT msi_dialog_dirlist_handler( msi_dialog *dialog, - msi_control *control, WPARAM param ) -{ - LPNMHDR nmhdr = (LPNMHDR)param; - WCHAR new_path[MAX_PATH]; - WCHAR text[MAX_PATH]; - LPWSTR path, prop; - BOOL indirect; - LVITEMW item; - int index; - - if (nmhdr->code != LVN_ITEMACTIVATE) - return ERROR_SUCCESS; - - index = SendMessageW( control->hwnd, LVM_GETNEXTITEM, -1, LVNI_SELECTED ); - if ( index < 0 ) - { - ERR("No list-view item selected!\n"); - return ERROR_FUNCTION_FAILED; - } - - item.iSubItem = 0; - item.pszText = text; - item.cchTextMax = MAX_PATH; - SendMessageW( control->hwnd, LVM_GETITEMTEXTW, index, (LPARAM)&item ); - - indirect = control->attributes & msidbControlAttributesIndirect; - prop = msi_dialog_dup_property( dialog, control->property, indirect ); - path = msi_dialog_dup_property( dialog, prop, TRUE ); - - lstrcpyW( new_path, path ); - lstrcatW( new_path, text ); - lstrcatW( new_path, szBackSlash ); - - msi_dialog_set_property( dialog->package, prop, new_path ); - - msi_dialog_update_directory_list( dialog, NULL ); - msi_dialog_update_directory_combo( dialog, NULL ); - msi_dialog_update_pathedit( dialog, NULL ); - - msi_free( prop ); - msi_free( path ); - return ERROR_SUCCESS; -} - -static UINT msi_dialog_directory_list( msi_dialog *dialog, MSIRECORD *rec ) -{ - msi_control *control; - LPCWSTR prop; - DWORD style; - - style = LVS_LIST | WS_VSCROLL | LVS_SHAREIMAGELISTS | - LVS_AUTOARRANGE | LVS_SINGLESEL | WS_BORDER | - LVS_SORTASCENDING | WS_CHILD | WS_GROUP | WS_TABSTOP; - control = msi_dialog_add_control( dialog, rec, WC_LISTVIEWW, style ); - if (!control) - return ERROR_FUNCTION_FAILED; - - control->attributes = MSI_RecordGetInteger( rec, 8 ); - control->handler = msi_dialog_dirlist_handler; - prop = MSI_RecordGetString( rec, 9 ); - control->property = msi_dialog_dup_property( dialog, prop, FALSE ); - - /* double click to activate an item in the list */ - SendMessageW( control->hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, - 0, LVS_EX_TWOCLICKACTIVATE ); - - msi_dialog_update_directory_list( dialog, control ); - - return ERROR_SUCCESS; -} - -/******************** VolumeCost List ***************************************/ - -static BOOL str_is_number( LPCWSTR str ) -{ - int i; - - for (i = 0; i < lstrlenW( str ); i++) - if (!isdigitW(str[i])) - return FALSE; - - return TRUE; -} - -static const WCHAR column_keys[][80] = -{ - {'V','o','l','u','m','e','C','o','s','t','V','o','l','u','m','e',0}, - {'V','o','l','u','m','e','C','o','s','t','S','i','z','e',0}, - {'V','o','l','u','m','e','C','o','s','t','A','v','a','i','l','a','b','l','e',0}, - {'V','o','l','u','m','e','C','o','s','t','R','e','q','u','i','r','e','d',0}, - {'V','o','l','u','m','e','C','o','s','t','D','i','f','f','e','r','e','n','c','e',0} -}; - -static void msi_dialog_vcl_add_columns( msi_dialog *dialog, msi_control *control, MSIRECORD *rec ) -{ - LPCWSTR text = MSI_RecordGetString( rec, 10 ); - LPCWSTR begin = text, end; - WCHAR *num; - LVCOLUMNW lvc; - DWORD count = 0; - - static const WCHAR negative[] = {'-',0}; - - if (!text) return; - - while ((begin = strchrW( begin, '{' )) && count < 5) - { - if (!(end = strchrW( begin, '}' ))) - return; - - num = msi_alloc( (end-begin+1)*sizeof(WCHAR) ); - if (!num) - return; - - lstrcpynW( num, begin + 1, end - begin ); - begin += end - begin + 1; - - /* empty braces or '0' hides the column */ - if ( !num[0] || !strcmpW( num, szZero ) ) - { - count++; - msi_free( num ); - continue; - } - - /* the width must be a positive number - * if a width is invalid, all remaining columns are hidden - */ - if ( !strncmpW( num, negative, 1 ) || !str_is_number( num ) ) { - msi_free( num ); - return; - } - - ZeroMemory( &lvc, sizeof(lvc) ); - lvc.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; - lvc.cx = atolW( num ); - lvc.pszText = msi_dialog_get_uitext( dialog, column_keys[count] ); - - SendMessageW( control->hwnd, LVM_INSERTCOLUMNW, count++, (LPARAM)&lvc ); - msi_free( lvc.pszText ); - msi_free( num ); - } -} - -static LONGLONG msi_vcl_get_cost( msi_dialog *dialog ) -{ - MSIFEATURE *feature; - INT each_cost; - LONGLONG total_cost = 0; - - LIST_FOR_EACH_ENTRY( feature, &dialog->package->features, MSIFEATURE, entry ) - { - if (ERROR_SUCCESS == (MSI_GetFeatureCost(dialog->package, feature, - MSICOSTTREE_SELFONLY, INSTALLSTATE_LOCAL, &each_cost))) - { - /* each_cost is in 512-byte units */ - total_cost += each_cost * 512; - } - if (ERROR_SUCCESS == (MSI_GetFeatureCost(dialog->package, feature, - MSICOSTTREE_SELFONLY, INSTALLSTATE_ABSENT, &each_cost))) - { - /* each_cost is in 512-byte units */ - total_cost -= each_cost * 512; - } - } - return total_cost; -} - -static void msi_dialog_vcl_add_drives( msi_dialog *dialog, msi_control *control ) -{ - ULARGE_INTEGER total, free; - LONGLONG difference, cost; - WCHAR size_text[MAX_PATH]; - WCHAR cost_text[MAX_PATH]; - LPWSTR drives, ptr; - LVITEMW lvitem; - DWORD size; - int i = 0; - - cost = msi_vcl_get_cost(dialog); - StrFormatByteSizeW(cost, cost_text, MAX_PATH); - - size = GetLogicalDriveStringsW( 0, NULL ); - if ( !size ) return; - - drives = msi_alloc( (size + 1) * sizeof(WCHAR) ); - if ( !drives ) return; - - GetLogicalDriveStringsW( size, drives ); - - ptr = drives; - while (*ptr) - { - lvitem.mask = LVIF_TEXT; - lvitem.iItem = i; - lvitem.iSubItem = 0; - lvitem.pszText = ptr; - lvitem.cchTextMax = lstrlenW(ptr) + 1; - SendMessageW( control->hwnd, LVM_INSERTITEMW, 0, (LPARAM)&lvitem ); - - GetDiskFreeSpaceExW(ptr, &free, &total, NULL); - difference = free.QuadPart - cost; - - StrFormatByteSizeW(total.QuadPart, size_text, MAX_PATH); - lvitem.iSubItem = 1; - lvitem.pszText = size_text; - lvitem.cchTextMax = lstrlenW(size_text) + 1; - SendMessageW( control->hwnd, LVM_SETITEMW, 0, (LPARAM)&lvitem ); - - StrFormatByteSizeW(free.QuadPart, size_text, MAX_PATH); - lvitem.iSubItem = 2; - lvitem.pszText = size_text; - lvitem.cchTextMax = lstrlenW(size_text) + 1; - SendMessageW( control->hwnd, LVM_SETITEMW, 0, (LPARAM)&lvitem ); - - lvitem.iSubItem = 3; - lvitem.pszText = cost_text; - lvitem.cchTextMax = lstrlenW(cost_text) + 1; - SendMessageW( control->hwnd, LVM_SETITEMW, 0, (LPARAM)&lvitem ); - - StrFormatByteSizeW(difference, size_text, MAX_PATH); - lvitem.iSubItem = 4; - lvitem.pszText = size_text; - lvitem.cchTextMax = lstrlenW(size_text) + 1; - SendMessageW( control->hwnd, LVM_SETITEMW, 0, (LPARAM)&lvitem ); - - ptr += lstrlenW(ptr) + 1; - i++; - } - - msi_free( drives ); -} - -static UINT msi_dialog_volumecost_list( msi_dialog *dialog, MSIRECORD *rec ) -{ - msi_control *control; - DWORD style; - - style = LVS_REPORT | WS_VSCROLL | WS_HSCROLL | LVS_SHAREIMAGELISTS | - LVS_AUTOARRANGE | LVS_SINGLESEL | WS_BORDER | - WS_CHILD | WS_TABSTOP | WS_GROUP; - control = msi_dialog_add_control( dialog, rec, WC_LISTVIEWW, style ); - if (!control) - return ERROR_FUNCTION_FAILED; - - msi_dialog_vcl_add_columns( dialog, control, rec ); - msi_dialog_vcl_add_drives( dialog, control ); - - return ERROR_SUCCESS; -} - -/******************** VolumeSelect Combo ***************************************/ - -static UINT msi_dialog_volsel_handler( msi_dialog *dialog, - msi_control *control, WPARAM param ) -{ - WCHAR text[MAX_PATH]; - LPWSTR prop; - BOOL indirect; - int index; - - if (HIWORD(param) != CBN_SELCHANGE) - return ERROR_SUCCESS; - - index = SendMessageW( control->hwnd, CB_GETCURSEL, 0, 0 ); - if ( index == CB_ERR ) - { - ERR("No ComboBox item selected!\n"); - return ERROR_FUNCTION_FAILED; - } - - SendMessageW( control->hwnd, CB_GETLBTEXT, index, (LPARAM)text ); - - indirect = control->attributes & msidbControlAttributesIndirect; - prop = msi_dialog_dup_property( dialog, control->property, indirect ); - - msi_dialog_set_property( dialog->package, prop, text ); - - msi_free( prop ); - return ERROR_SUCCESS; -} - -static void msi_dialog_vsc_add_drives( msi_dialog *dialog, msi_control *control ) -{ - LPWSTR drives, ptr; - DWORD size; - - size = GetLogicalDriveStringsW( 0, NULL ); - if ( !size ) return; - - drives = msi_alloc( (size + 1) * sizeof(WCHAR) ); - if ( !drives ) return; - - GetLogicalDriveStringsW( size, drives ); - - ptr = drives; - while (*ptr) - { - SendMessageW( control->hwnd, CB_ADDSTRING, 0, (LPARAM)ptr ); - ptr += lstrlenW(ptr) + 1; - } - - msi_free( drives ); -} - -static UINT msi_dialog_volumeselect_combo( msi_dialog *dialog, MSIRECORD *rec ) -{ - msi_control *control; - LPCWSTR prop; - DWORD style; - - /* FIXME: CBS_OWNERDRAWFIXED */ - style = WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP | - CBS_DROPDOWNLIST | CBS_SORT | CBS_HASSTRINGS | - WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR; - control = msi_dialog_add_control( dialog, rec, WC_COMBOBOXW, style ); - if (!control) - return ERROR_FUNCTION_FAILED; - - control->attributes = MSI_RecordGetInteger( rec, 8 ); - control->handler = msi_dialog_volsel_handler; - prop = MSI_RecordGetString( rec, 9 ); - control->property = msi_dialog_dup_property( dialog, prop, FALSE ); - - msi_dialog_vsc_add_drives( dialog, control ); - - return ERROR_SUCCESS; -} - -static const struct control_handler msi_dialog_handler[] = -{ - { szText, msi_dialog_text_control }, - { szPushButton, msi_dialog_button_control }, - { szLine, msi_dialog_line_control }, - { szBitmap, msi_dialog_bitmap_control }, - { szCheckBox, msi_dialog_checkbox_control }, - { szScrollableText, msi_dialog_scrolltext_control }, - { szComboBox, msi_dialog_combo_control }, - { szEdit, msi_dialog_edit_control }, - { szMaskedEdit, msi_dialog_maskedit_control }, - { szPathEdit, msi_dialog_pathedit_control }, - { szProgressBar, msi_dialog_progress_bar }, - { szRadioButtonGroup, msi_dialog_radiogroup_control }, - { szIcon, msi_dialog_icon_control }, - { szSelectionTree, msi_dialog_selection_tree }, - { szGroupBox, msi_dialog_group_box }, - { szListBox, msi_dialog_list_box }, - { szDirectoryCombo, msi_dialog_directory_combo }, - { szDirectoryList, msi_dialog_directory_list }, - { szVolumeCostList, msi_dialog_volumecost_list }, - { szVolumeSelectCombo, msi_dialog_volumeselect_combo }, -}; - -#define NUM_CONTROL_TYPES (sizeof msi_dialog_handler/sizeof msi_dialog_handler[0]) - -static UINT msi_dialog_create_controls( MSIRECORD *rec, LPVOID param ) -{ - msi_dialog *dialog = param; - LPCWSTR control_type; - UINT i; - - /* find and call the function that can create this type of control */ - control_type = MSI_RecordGetString( rec, 3 ); - for( i=0; i<NUM_CONTROL_TYPES; i++ ) - if (!strcmpiW( msi_dialog_handler[i].control_type, control_type )) - break; - if( i != NUM_CONTROL_TYPES ) - msi_dialog_handler[i].func( dialog, rec ); - else - ERR("no handler for element type %s\n", debugstr_w(control_type)); - - return ERROR_SUCCESS; -} - -static UINT msi_dialog_fill_controls( msi_dialog *dialog ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - 'C','o','n','t','r','o','l',' ','W','H','E','R','E',' ', - '`','D','i','a','l','o','g','_','`',' ','=',' ','\'','%','s','\'',0}; - UINT r; - MSIQUERY *view; - MSIPACKAGE *package = dialog->package; - - TRACE("%p %s\n", dialog, debugstr_w(dialog->name) ); - - /* query the Control table for all the elements of the control */ - r = MSI_OpenQuery( package->db, &view, query, dialog->name ); - if( r != ERROR_SUCCESS ) - { - ERR("query failed for dialog %s\n", debugstr_w(dialog->name)); - return ERROR_INVALID_PARAMETER; - } - - r = MSI_IterateRecords( view, 0, msi_dialog_create_controls, dialog ); - msiobj_release( &view->hdr ); - return r; -} - -UINT msi_dialog_reset( msi_dialog *dialog ) -{ - /* FIXME: should restore the original values of any properties we changed */ - return msi_dialog_evaluate_control_conditions( dialog ); -} - -/* figure out the height of 10 point MS Sans Serif */ -static INT msi_dialog_get_sans_serif_height( HWND hwnd ) -{ - static const WCHAR szSansSerif[] = { - 'M','S',' ','S','a','n','s',' ','S','e','r','i','f',0 }; - LOGFONTW lf; - TEXTMETRICW tm; - BOOL r; - LONG height = 0; - HFONT hFont, hOldFont; - HDC hdc; - - hdc = GetDC( hwnd ); - if (hdc) - { - memset( &lf, 0, sizeof lf ); - lf.lfHeight = MulDiv(12, GetDeviceCaps(hdc, LOGPIXELSY), 72); - strcpyW( lf.lfFaceName, szSansSerif ); - hFont = CreateFontIndirectW(&lf); - if (hFont) - { - hOldFont = SelectObject( hdc, hFont ); - r = GetTextMetricsW( hdc, &tm ); - if (r) - height = tm.tmHeight; - SelectObject( hdc, hOldFont ); - DeleteObject( hFont ); - } - ReleaseDC( hwnd, hdc ); - } - return height; -} - -/* fetch the associated record from the Dialog table */ -static MSIRECORD *msi_get_dialog_record( msi_dialog *dialog ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ', - 'F','R','O','M',' ','D','i','a','l','o','g',' ', - 'W','H','E','R','E',' ', - '`','D','i','a','l','o','g','`',' ','=',' ','\'','%','s','\'',0}; - MSIPACKAGE *package = dialog->package; - MSIRECORD *rec = NULL; - - TRACE("%p %s\n", dialog, debugstr_w(dialog->name) ); - - rec = MSI_QueryGetRecord( package->db, query, dialog->name ); - if( !rec ) - WARN("query failed for dialog %s\n", debugstr_w(dialog->name)); - - return rec; -} - -static void msi_dialog_adjust_dialog_pos( msi_dialog *dialog, MSIRECORD *rec, LPRECT pos ) -{ - static const WCHAR szScreenX[] = {'S','c','r','e','e','n','X',0}; - static const WCHAR szScreenY[] = {'S','c','r','e','e','n','Y',0}; - - UINT xres, yres; - POINT center; - SIZE sz; - LONG style; - - center.x = MSI_RecordGetInteger( rec, 2 ); - center.y = MSI_RecordGetInteger( rec, 3 ); - - sz.cx = MSI_RecordGetInteger( rec, 4 ); - sz.cy = MSI_RecordGetInteger( rec, 5 ); - - sz.cx = msi_dialog_scale_unit( dialog, sz.cx ); - sz.cy = msi_dialog_scale_unit( dialog, sz.cy ); - - xres = msi_get_property_int( dialog->package->db, szScreenX, 0 ); - yres = msi_get_property_int( dialog->package->db, szScreenY, 0 ); - - center.x = MulDiv( center.x, xres, 100 ); - center.y = MulDiv( center.y, yres, 100 ); - - /* turn the client pos into the window rectangle */ - if (dialog->package->center_x && dialog->package->center_y) - { - pos->left = dialog->package->center_x - sz.cx / 2.0; - pos->right = pos->left + sz.cx; - pos->top = dialog->package->center_y - sz.cy / 2.0; - pos->bottom = pos->top + sz.cy; - } - else - { - pos->left = center.x - sz.cx/2; - pos->right = pos->left + sz.cx; - pos->top = center.y - sz.cy/2; - pos->bottom = pos->top + sz.cy; - - /* save the center */ - dialog->package->center_x = center.x; - dialog->package->center_y = center.y; - } - - dialog->size.cx = sz.cx; - dialog->size.cy = sz.cy; - - TRACE("%u %u %u %u\n", pos->left, pos->top, pos->right, pos->bottom); - - style = GetWindowLongPtrW( dialog->hwnd, GWL_STYLE ); - AdjustWindowRect( pos, style, FALSE ); -} - -static void msi_dialog_set_tab_order( msi_dialog *dialog, LPCWSTR first ) -{ - struct list tab_chain; - msi_control *control; - HWND prev = HWND_TOP; - - list_init( &tab_chain ); - if (!(control = msi_dialog_find_control( dialog, first ))) return; - - dialog->hWndFocus = control->hwnd; - while (control) - { - list_remove( &control->entry ); - list_add_tail( &tab_chain, &control->entry ); - if (!control->tabnext) break; - control = msi_dialog_find_control( dialog, control->tabnext ); - } - - LIST_FOR_EACH_ENTRY( control, &tab_chain, msi_control, entry ) - { - SetWindowPos( control->hwnd, prev, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOREDRAW | - SWP_NOREPOSITION | SWP_NOSENDCHANGING | SWP_NOSIZE ); - prev = control->hwnd; - } - - /* put them back on the main list */ - list_move_head( &dialog->controls, &tab_chain ); -} - -static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs ) -{ - static const WCHAR df[] = { - 'D','e','f','a','u','l','t','U','I','F','o','n','t',0 }; - static const WCHAR dfv[] = { - 'M','S',' ','S','h','e','l','l',' ','D','l','g',0 }; - msi_dialog *dialog = cs->lpCreateParams; - MSIRECORD *rec = NULL; - LPWSTR title = NULL; - RECT pos; - - TRACE("%p %p\n", dialog, dialog->package); - - dialog->hwnd = hwnd; - SetWindowLongPtrW( hwnd, GWLP_USERDATA, (LONG_PTR) dialog ); - - rec = msi_get_dialog_record( dialog ); - if( !rec ) - { - TRACE("No record found for dialog %s\n", debugstr_w(dialog->name)); - return -1; - } - - dialog->scale = msi_dialog_get_sans_serif_height(dialog->hwnd); - - msi_dialog_adjust_dialog_pos( dialog, rec, &pos ); - - dialog->attributes = MSI_RecordGetInteger( rec, 6 ); - - dialog->default_font = msi_dup_property( dialog->package->db, df ); - if (!dialog->default_font) - { - dialog->default_font = strdupW(dfv); - if (!dialog->default_font) return -1; - } - - title = msi_get_deformatted_field( dialog->package, rec, 7 ); - SetWindowTextW( hwnd, title ); - msi_free( title ); - - SetWindowPos( hwnd, 0, pos.left, pos.top, - pos.right - pos.left, pos.bottom - pos.top, - SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW ); - - msi_dialog_build_font_list( dialog ); - msi_dialog_fill_controls( dialog ); - msi_dialog_evaluate_control_conditions( dialog ); - msi_dialog_set_tab_order( dialog, MSI_RecordGetString( rec, 8 ) ); - msiobj_release( &rec->hdr ); - - return 0; -} - -static LRESULT msi_dialog_oncommand( msi_dialog *dialog, WPARAM param, HWND hwnd ) -{ - msi_control *control = NULL; - - TRACE("%p %p %08lx\n", dialog, hwnd, param); - - switch (param) - { - case 1: /* enter */ - control = msi_dialog_find_control( dialog, dialog->control_default ); - break; - case 2: /* escape */ - control = msi_dialog_find_control( dialog, dialog->control_cancel ); - break; - default: - control = msi_dialog_find_control_by_hwnd( dialog, hwnd ); - } - - if( control ) - { - if( control->handler ) - { - control->handler( dialog, control, param ); - msi_dialog_evaluate_control_conditions( dialog ); - } - } - - return 0; -} - -static LRESULT msi_dialog_onnotify( msi_dialog *dialog, LPARAM param ) -{ - LPNMHDR nmhdr = (LPNMHDR) param; - msi_control *control = msi_dialog_find_control_by_hwnd( dialog, nmhdr->hwndFrom ); - - TRACE("%p %p\n", dialog, nmhdr->hwndFrom); - - if ( control && control->handler ) - control->handler( dialog, control, param ); - - return 0; -} - -static void msi_dialog_setfocus( msi_dialog *dialog ) -{ - HWND hwnd = dialog->hWndFocus; - - hwnd = GetNextDlgTabItem( dialog->hwnd, hwnd, TRUE); - hwnd = GetNextDlgTabItem( dialog->hwnd, hwnd, FALSE); - SetFocus( hwnd ); - dialog->hWndFocus = hwnd; -} - -static LRESULT WINAPI MSIDialog_WndProc( HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam ) -{ - msi_dialog *dialog = (LPVOID) GetWindowLongPtrW( hwnd, GWLP_USERDATA ); - - TRACE("0x%04x\n", msg); - - switch (msg) - { - case WM_MOVE: - dialog->package->center_x = LOWORD(lParam) + dialog->size.cx / 2.0; - dialog->package->center_y = HIWORD(lParam) + dialog->size.cy / 2.0; - break; - - case WM_CREATE: - return msi_dialog_oncreate( hwnd, (LPCREATESTRUCTW)lParam ); - - case WM_COMMAND: - return msi_dialog_oncommand( dialog, wParam, (HWND)lParam ); - - case WM_ACTIVATE: - if( LOWORD(wParam) == WA_INACTIVE ) - dialog->hWndFocus = GetFocus(); - else - msi_dialog_setfocus( dialog ); - return 0; - - case WM_SETFOCUS: - msi_dialog_setfocus( dialog ); - return 0; - - /* bounce back to our subclassed static control */ - case WM_CTLCOLORSTATIC: - return SendMessageW( (HWND) lParam, WM_CTLCOLORSTATIC, wParam, lParam ); - - case WM_DESTROY: - dialog->hwnd = NULL; - return 0; - case WM_NOTIFY: - return msi_dialog_onnotify( dialog, lParam ); - } - return DefWindowProcW(hwnd, msg, wParam, lParam); -} - -static LRESULT WINAPI MSIHiddenWindowProc( HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam ) -{ - msi_dialog *dialog = (msi_dialog*) lParam; - - TRACE("%d %p\n", msg, dialog); - - switch (msg) - { - case WM_MSI_DIALOG_CREATE: - return msi_dialog_run_message_loop( dialog ); - case WM_MSI_DIALOG_DESTROY: - msi_dialog_destroy( dialog ); - return 0; - } - return DefWindowProcW( hwnd, msg, wParam, lParam ); -} - -static BOOL msi_dialog_register_class( void ) -{ - WNDCLASSW cls; - - ZeroMemory( &cls, sizeof cls ); - cls.lpfnWndProc = MSIDialog_WndProc; - cls.hInstance = NULL; - cls.hIcon = LoadIconW(0, (LPWSTR)IDI_APPLICATION); - cls.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); - cls.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); - cls.lpszMenuName = NULL; - cls.lpszClassName = szMsiDialogClass; - - if( !RegisterClassW( &cls ) ) - return FALSE; - - cls.lpfnWndProc = MSIHiddenWindowProc; - cls.lpszClassName = szMsiHiddenWindow; - - if( !RegisterClassW( &cls ) ) - return FALSE; - - uiThreadId = GetCurrentThreadId(); - - hMsiHiddenWindow = CreateWindowW( szMsiHiddenWindow, NULL, WS_OVERLAPPED, - 0, 0, 100, 100, NULL, NULL, NULL, NULL ); - if( !hMsiHiddenWindow ) - return FALSE; - - return TRUE; -} - -/* functions that interface to other modules within MSI */ - -msi_dialog *msi_dialog_create( MSIPACKAGE* package, - LPCWSTR szDialogName, msi_dialog *parent, - msi_dialog_event_handler event_handler ) -{ - MSIRECORD *rec = NULL; - msi_dialog *dialog; - - TRACE("%p %s\n", package, debugstr_w(szDialogName)); - - if (!hMsiHiddenWindow) - msi_dialog_register_class(); - - /* allocate the structure for the dialog to use */ - dialog = msi_alloc_zero( sizeof *dialog + sizeof(WCHAR)*strlenW(szDialogName) ); - if( !dialog ) - return NULL; - strcpyW( dialog->name, szDialogName ); - dialog->parent = parent; - msiobj_addref( &package->hdr ); - dialog->package = package; - dialog->event_handler = event_handler; - dialog->finished = 0; - list_init( &dialog->controls ); - list_init( &dialog->fonts ); - - /* verify that the dialog exists */ - rec = msi_get_dialog_record( dialog ); - if( !rec ) - { - msiobj_release( &package->hdr ); - msi_free( dialog ); - return NULL; - } - dialog->attributes = MSI_RecordGetInteger( rec, 6 ); - dialog->control_default = strdupW( MSI_RecordGetString( rec, 9 ) ); - dialog->control_cancel = strdupW( MSI_RecordGetString( rec, 10 ) ); - msiobj_release( &rec->hdr ); - - return dialog; -} - -static void msi_process_pending_messages( HWND hdlg ) -{ - MSG msg; - - while( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ) ) - { - if( hdlg && IsDialogMessageW( hdlg, &msg )) - continue; - TranslateMessage( &msg ); - DispatchMessageW( &msg ); - } -} - -void msi_dialog_end_dialog( msi_dialog *dialog ) -{ - TRACE("%p\n", dialog); - dialog->finished = 1; - PostMessageW(dialog->hwnd, WM_NULL, 0, 0); -} - -void msi_dialog_check_messages( HANDLE handle ) -{ - DWORD r; - - /* in threads other than the UI thread, block */ - if( uiThreadId != GetCurrentThreadId() ) - { - if (!handle) return; - while (MsgWaitForMultipleObjectsEx( 1, &handle, INFINITE, QS_ALLINPUT, 0 ) == WAIT_OBJECT_0 + 1) - { - MSG msg; - while (PeekMessageW( &msg, NULL, 0, 0, PM_REMOVE )) - { - TranslateMessage( &msg ); - DispatchMessageW( &msg ); - } - } - return; - } - - /* there's two choices for the UI thread */ - while (1) - { - msi_process_pending_messages( NULL ); - - if( !handle ) - break; - - /* - * block here until somebody creates a new dialog or - * the handle we're waiting on becomes ready - */ - r = MsgWaitForMultipleObjects( 1, &handle, 0, INFINITE, QS_ALLINPUT ); - if( r == WAIT_OBJECT_0 ) - break; - } -} - -UINT msi_dialog_run_message_loop( msi_dialog *dialog ) -{ - DWORD style; - HWND hwnd; - - if( uiThreadId != GetCurrentThreadId() ) - return SendMessageW( hMsiHiddenWindow, WM_MSI_DIALOG_CREATE, 0, (LPARAM) dialog ); - - /* create the dialog window, don't show it yet */ - style = WS_OVERLAPPED; - if( dialog->attributes & msidbDialogAttributesVisible ) - style |= WS_VISIBLE; - - hwnd = CreateWindowW( szMsiDialogClass, dialog->name, style, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - NULL, NULL, NULL, dialog ); - if( !hwnd ) - { - ERR("Failed to create dialog %s\n", debugstr_w( dialog->name )); - return ERROR_FUNCTION_FAILED; - } - - ShowWindow( hwnd, SW_SHOW ); - /* UpdateWindow( hwnd ); - and causes the transparent static controls not to paint */ - - if( dialog->attributes & msidbDialogAttributesModal ) - { - while( !dialog->finished ) - { - MsgWaitForMultipleObjects( 0, NULL, 0, INFINITE, QS_ALLINPUT ); - msi_process_pending_messages( dialog->hwnd ); - } - } - else - return ERROR_IO_PENDING; - - return ERROR_SUCCESS; -} - -static void msi_dialog_do_preview( msi_dialog *dialog ) -{ - TRACE("\n"); - dialog->attributes |= msidbDialogAttributesVisible; - dialog->attributes &= ~msidbDialogAttributesModal; - msi_dialog_run_message_loop( dialog ); -} - -void msi_dialog_destroy( msi_dialog *dialog ) -{ - msi_font *font, *next; - - if( uiThreadId != GetCurrentThreadId() ) - { - SendMessageW( hMsiHiddenWindow, WM_MSI_DIALOG_DESTROY, 0, (LPARAM) dialog ); - return; - } - - if( dialog->hwnd ) - ShowWindow( dialog->hwnd, SW_HIDE ); - - if( dialog->hwnd ) - DestroyWindow( dialog->hwnd ); - - /* unsubscribe events */ - ControlEvent_CleanupDialogSubscriptions(dialog->package, dialog->name); - - /* destroy the list of controls */ - while( !list_empty( &dialog->controls ) ) - { - msi_control *t; - - t = LIST_ENTRY( list_head( &dialog->controls ), - msi_control, entry ); - msi_destroy_control( t ); - } - - /* destroy the list of fonts */ - LIST_FOR_EACH_ENTRY_SAFE( font, next, &dialog->fonts, msi_font, entry ) - { - list_remove( &font->entry ); - DeleteObject( font->hfont ); - msi_free( font ); - } - msi_free( dialog->default_font ); - - msi_free( dialog->control_default ); - msi_free( dialog->control_cancel ); - msiobj_release( &dialog->package->hdr ); - dialog->package = NULL; - msi_free( dialog ); -} - -void msi_dialog_unregister_class( void ) -{ - DestroyWindow( hMsiHiddenWindow ); - hMsiHiddenWindow = NULL; - UnregisterClassW( szMsiDialogClass, NULL ); - UnregisterClassW( szMsiHiddenWindow, NULL ); - uiThreadId = 0; -} - -static UINT error_dialog_handler(MSIPACKAGE *package, LPCWSTR event, - LPCWSTR argument, msi_dialog* dialog) -{ - static const WCHAR end_dialog[] = {'E','n','d','D','i','a','l','o','g',0}; - static const WCHAR error_abort[] = {'E','r','r','o','r','A','b','o','r','t',0}; - static const WCHAR error_cancel[] = {'E','r','r','o','r','C','a','n','c','e','l',0}; - static const WCHAR error_no[] = {'E','r','r','o','r','N','o',0}; - static const WCHAR result_prop[] = { - 'M','S','I','E','r','r','o','r','D','i','a','l','o','g','R','e','s','u','l','t',0 - }; - - if ( strcmpW( event, end_dialog ) ) - return ERROR_SUCCESS; - - if ( !strcmpW( argument, error_abort ) || !strcmpW( argument, error_cancel ) || - !strcmpW( argument, error_no ) ) - { - msi_set_property( package->db, result_prop, error_abort ); - } - - ControlEvent_CleanupSubscriptions(package); - msi_dialog_end_dialog( dialog ); - - return ERROR_SUCCESS; -} - -static UINT msi_error_dialog_set_error( MSIPACKAGE *package, LPWSTR error_dialog, LPWSTR error ) -{ - MSIRECORD * row; - - static const WCHAR update[] = - {'U','P','D','A','T','E',' ','`','C','o','n','t','r','o','l','`',' ', - 'S','E','T',' ','`','T','e','x','t','`',' ','=',' ','\'','%','s','\'',' ', - 'W','H','E','R','E', ' ','`','D','i','a','l','o','g','_','`',' ','=',' ','\'','%','s','\'',' ', - 'A','N','D',' ','`','C','o','n','t','r','o','l','`',' ','=',' ', - '\'','E','r','r','o','r','T','e','x','t','\'',0}; - - row = MSI_QueryGetRecord( package->db, update, error, error_dialog ); - if (!row) - return ERROR_FUNCTION_FAILED; - - msiobj_release(&row->hdr); - return ERROR_SUCCESS; -} - -UINT msi_spawn_error_dialog( MSIPACKAGE *package, LPWSTR error_dialog, LPWSTR error ) -{ - msi_dialog *dialog; - WCHAR result[MAX_PATH]; - UINT r = ERROR_SUCCESS; - DWORD size = MAX_PATH; - int res; - - static const WCHAR pn_prop[] = {'P','r','o','d','u','c','t','N','a','m','e',0}; - static const WCHAR title_fmt[] = {'%','s',' ','W','a','r','n','i','n','g',0}; - static const WCHAR error_abort[] = {'E','r','r','o','r','A','b','o','r','t',0}; - static const WCHAR result_prop[] = { - 'M','S','I','E','r','r','o','r','D','i','a','l','o','g','R','e','s','u','l','t',0 - }; - - if ((package->ui_level & INSTALLUILEVEL_MASK) == INSTALLUILEVEL_NONE) return ERROR_SUCCESS; - - if ( !error_dialog ) - { - LPWSTR product_name = msi_dup_property( package->db, pn_prop ); - WCHAR title[MAX_PATH]; - - sprintfW( title, title_fmt, product_name ); - res = MessageBoxW( NULL, error, title, MB_OKCANCEL | MB_ICONWARNING ); - - msi_free( product_name ); - - if ( res == IDOK ) - return ERROR_SUCCESS; - else - return ERROR_FUNCTION_FAILED; - } - - r = msi_error_dialog_set_error( package, error_dialog, error ); - if ( r != ERROR_SUCCESS ) - return r; - - dialog = msi_dialog_create( package, error_dialog, package->dialog, - error_dialog_handler ); - if ( !dialog ) - return ERROR_FUNCTION_FAILED; - - dialog->finished = FALSE; - r = msi_dialog_run_message_loop( dialog ); - if ( r != ERROR_SUCCESS ) - goto done; - - r = msi_get_property( package->db, result_prop, result, &size ); - if ( r != ERROR_SUCCESS) - r = ERROR_SUCCESS; - - if ( !strcmpW( result, error_abort ) ) - r = ERROR_FUNCTION_FAILED; - -done: - msi_dialog_destroy( dialog ); - - return r; -} - -static void MSI_ClosePreview( MSIOBJECTHDR *arg ) -{ - MSIPREVIEW *preview = (MSIPREVIEW *)arg; - msiobj_release( &preview->package->hdr ); -} - -static MSIPREVIEW *MSI_EnableUIPreview( MSIDATABASE *db ) -{ - MSIPREVIEW *preview = NULL; - MSIPACKAGE *package; - - package = MSI_CreatePackage( db, NULL ); - if (package) - { - preview = alloc_msiobject( MSIHANDLETYPE_PREVIEW, sizeof(MSIPREVIEW), MSI_ClosePreview ); - if (preview) - { - preview->package = package; - msiobj_addref( &package->hdr ); - } - msiobj_release( &package->hdr ); - } - return preview; -} - -UINT WINAPI MsiEnableUIPreview( MSIHANDLE hdb, MSIHANDLE *phPreview ) -{ - MSIDATABASE *db; - MSIPREVIEW *preview; - UINT r = ERROR_FUNCTION_FAILED; - - TRACE("%d %p\n", hdb, phPreview); - - db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE ); - if (!db) - return ERROR_INVALID_HANDLE; - preview = MSI_EnableUIPreview( db ); - if (preview) - { - *phPreview = alloc_msihandle( &preview->hdr ); - msiobj_release( &preview->hdr ); - r = ERROR_SUCCESS; - if (!*phPreview) - r = ERROR_NOT_ENOUGH_MEMORY; - } - msiobj_release( &db->hdr ); - return r; -} - -static UINT preview_event_handler( MSIPACKAGE *package, LPCWSTR event, - LPCWSTR argument, msi_dialog *dialog ) -{ - MESSAGE("Preview dialog event '%s' (arg='%s')\n", debugstr_w(event), debugstr_w(argument)); - return ERROR_SUCCESS; -} - -static UINT MSI_PreviewDialogW( MSIPREVIEW *preview, LPCWSTR szDialogName ) -{ - msi_dialog *dialog = NULL; - UINT r = ERROR_SUCCESS; - - if (preview->dialog) - msi_dialog_destroy( preview->dialog ); - - /* an empty name means we should just destroy the current preview dialog */ - if (szDialogName) - { - dialog = msi_dialog_create( preview->package, szDialogName, NULL, preview_event_handler ); - if (dialog) - msi_dialog_do_preview( dialog ); - else - r = ERROR_FUNCTION_FAILED; - } - preview->dialog = dialog; - return r; -} - -UINT WINAPI MsiPreviewDialogW( MSIHANDLE hPreview, LPCWSTR szDialogName ) -{ - MSIPREVIEW *preview; - UINT r; - - TRACE("%d %s\n", hPreview, debugstr_w(szDialogName)); - - preview = msihandle2msiinfo( hPreview, MSIHANDLETYPE_PREVIEW ); - if (!preview) - return ERROR_INVALID_HANDLE; - - r = MSI_PreviewDialogW( preview, szDialogName ); - msiobj_release( &preview->hdr ); - return r; -} - -UINT WINAPI MsiPreviewDialogA( MSIHANDLE hPreview, LPCSTR szDialogName ) -{ - UINT r; - LPWSTR strW = NULL; - - TRACE("%d %s\n", hPreview, debugstr_a(szDialogName)); - - if (szDialogName) - { - strW = strdupAtoW( szDialogName ); - if (!strW) - return ERROR_OUTOFMEMORY; - } - r = MsiPreviewDialogW( hPreview, strW ); - msi_free( strW ); - return r; -} - -UINT WINAPI MsiPreviewBillboardW( MSIHANDLE hPreview, LPCWSTR szControlName, LPCWSTR szBillboard ) -{ - FIXME("%d %s %s\n", hPreview, debugstr_w(szControlName), debugstr_w(szBillboard)); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiPreviewBillboardA( MSIHANDLE hPreview, LPCSTR szControlName, LPCSTR szBillboard ) -{ - FIXME("%d %s %s\n", hPreview, debugstr_a(szControlName), debugstr_a(szBillboard)); - return ERROR_CALL_NOT_IMPLEMENTED; -} diff --git a/libmsi/events.c b/libmsi/events.c deleted file mode 100644 index d42ac5b..0000000 --- a/libmsi/events.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2005 Aric Stewart for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include <stdarg.h> -#include <stdio.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winreg.h" -#include "msi.h" -#include "msipriv.h" - -#include "wine/debug.h" -#include "wine/unicode.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -typedef UINT (*EVENTHANDLER)(MSIPACKAGE*,LPCWSTR,msi_dialog *); - -struct control_events -{ - const WCHAR *event; - EVENTHANDLER handler; -}; - -struct subscriber { - struct list entry; - msi_dialog *dialog; - LPWSTR event; - LPWSTR control; - LPWSTR attribute; -}; - -static UINT ControlEvent_HandleControlEvent(MSIPACKAGE *, LPCWSTR, LPCWSTR, msi_dialog*); - -/* - * Create a dialog box and run it if it's modal - */ -static UINT event_do_dialog( MSIPACKAGE *package, LPCWSTR name, msi_dialog *parent, BOOL destroy_modeless ) -{ - msi_dialog *dialog; - UINT r; - - /* create a new dialog */ - dialog = msi_dialog_create( package, name, parent, - ControlEvent_HandleControlEvent ); - if( dialog ) - { - /* kill the current modeless dialog */ - if( destroy_modeless && package->dialog ) - { - msi_dialog_destroy( package->dialog ); - package->dialog = NULL; - } - - /* modeless dialogs return an error message */ - r = msi_dialog_run_message_loop( dialog ); - if( r == ERROR_SUCCESS ) - msi_dialog_destroy( dialog ); - else - package->dialog = dialog; - } - else - r = ERROR_FUNCTION_FAILED; - - return r; -} - - -/* - * End a modal dialog box - */ -static UINT ControlEvent_EndDialog(MSIPACKAGE* package, LPCWSTR argument, - msi_dialog* dialog) -{ - static const WCHAR szExit[] = {'E','x','i','t',0}; - static const WCHAR szRetry[] = {'R','e','t','r','y',0}; - static const WCHAR szIgnore[] = {'I','g','n','o','r','e',0}; - static const WCHAR szReturn[] = {'R','e','t','u','r','n',0}; - - if (!strcmpW( argument, szExit )) - package->CurrentInstallState = ERROR_INSTALL_USEREXIT; - else if (!strcmpW( argument, szRetry )) - package->CurrentInstallState = ERROR_INSTALL_SUSPEND; - else if (!strcmpW( argument, szIgnore )) - package->CurrentInstallState = ERROR_SUCCESS; - else if (!strcmpW( argument, szReturn )) - { - msi_dialog *parent = msi_dialog_get_parent(dialog); - msi_free(package->next_dialog); - package->next_dialog = (parent) ? strdupW(msi_dialog_get_name(parent)) : NULL; - package->CurrentInstallState = ERROR_SUCCESS; - } - else - { - ERR("Unknown argument string %s\n",debugstr_w(argument)); - package->CurrentInstallState = ERROR_FUNCTION_FAILED; - } - - ControlEvent_CleanupDialogSubscriptions(package, msi_dialog_get_name( dialog )); - msi_dialog_end_dialog( dialog ); - return ERROR_SUCCESS; -} - -/* - * transition from one modal dialog to another modal dialog - */ -static UINT ControlEvent_NewDialog(MSIPACKAGE* package, LPCWSTR argument, - msi_dialog *dialog) -{ - /* store the name of the next dialog, and signal this one to end */ - package->next_dialog = strdupW(argument); - ControlEvent_CleanupSubscriptions(package); - msi_dialog_end_dialog( dialog ); - return ERROR_SUCCESS; -} - -/* - * Create a new child dialog of an existing modal dialog - */ -static UINT ControlEvent_SpawnDialog(MSIPACKAGE* package, LPCWSTR argument, - msi_dialog *dialog) -{ - /* don't destroy a modeless dialogs that might be our parent */ - event_do_dialog( package, argument, dialog, FALSE ); - if( package->CurrentInstallState != ERROR_SUCCESS ) - msi_dialog_end_dialog( dialog ); - return ERROR_SUCCESS; -} - -/* - * Creates a dialog that remains up for a period of time - * based on a condition - */ -static UINT ControlEvent_SpawnWaitDialog(MSIPACKAGE* package, LPCWSTR argument, - msi_dialog* dialog) -{ - FIXME("Doing Nothing\n"); - return ERROR_SUCCESS; -} - -static UINT ControlEvent_DoAction(MSIPACKAGE* package, LPCWSTR argument, - msi_dialog* dialog) -{ - ACTION_PerformAction(package, argument, SCRIPT_NONE); - return ERROR_SUCCESS; -} - -static UINT ControlEvent_AddLocal( MSIPACKAGE *package, LPCWSTR argument, msi_dialog *dialog ) -{ - MSIFEATURE *feature; - - LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) - { - if (!strcmpW( argument, feature->Feature ) || !strcmpW( argument, szAll )) - { - if (feature->ActionRequest != INSTALLSTATE_LOCAL) - msi_set_property( package->db, szPreselected, szOne ); - MSI_SetFeatureStateW( package, feature->Feature, INSTALLSTATE_LOCAL ); - } - } - return ERROR_SUCCESS; -} - -static UINT ControlEvent_Remove( MSIPACKAGE *package, LPCWSTR argument, msi_dialog *dialog ) -{ - MSIFEATURE *feature; - - LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) - { - if (!strcmpW( argument, feature->Feature ) || !strcmpW( argument, szAll )) - { - if (feature->ActionRequest != INSTALLSTATE_ABSENT) - msi_set_property( package->db, szPreselected, szOne ); - MSI_SetFeatureStateW( package, feature->Feature, INSTALLSTATE_ABSENT ); - } - } - return ERROR_SUCCESS; -} - -static UINT ControlEvent_AddSource( MSIPACKAGE *package, LPCWSTR argument, msi_dialog *dialog ) -{ - MSIFEATURE *feature; - - LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) - { - if (!strcmpW( argument, feature->Feature ) || !strcmpW( argument, szAll )) - { - if (feature->ActionRequest != INSTALLSTATE_SOURCE) - msi_set_property( package->db, szPreselected, szOne ); - MSI_SetFeatureStateW( package, feature->Feature, INSTALLSTATE_SOURCE ); - } - } - return ERROR_SUCCESS; -} - -static UINT ControlEvent_SetTargetPath(MSIPACKAGE* package, LPCWSTR argument, - msi_dialog* dialog) -{ - static const WCHAR szSelectionPath[] = {'S','e','l','e','c','t','i','o','n','P','a','t','h',0}; - LPWSTR path = msi_dup_property( package->db, argument ); - MSIRECORD *rec = MSI_CreateRecord( 1 ); - UINT r = ERROR_SUCCESS; - - MSI_RecordSetStringW( rec, 1, path ); - ControlEvent_FireSubscribedEvent( package, szSelectionPath, rec ); - if (path) - { - /* failure to set the path halts the executing of control events */ - r = MSI_SetTargetPathW(package, argument, path); - msi_free(path); - } - msi_free(&rec->hdr); - return r; -} - -static UINT ControlEvent_Reset(MSIPACKAGE* package, LPCWSTR argument, - msi_dialog* dialog) -{ - msi_dialog_reset(dialog); - return ERROR_SUCCESS; -} - -/* - * Subscribed events - */ -static void free_subscriber( struct subscriber *sub ) -{ - msi_free(sub->event); - msi_free(sub->control); - msi_free(sub->attribute); - msi_free(sub); -} - -VOID ControlEvent_SubscribeToEvent( MSIPACKAGE *package, msi_dialog *dialog, - LPCWSTR event, LPCWSTR control, LPCWSTR attribute ) -{ - struct subscriber *sub; - - TRACE("event %s control %s attribute %s\n", debugstr_w(event), debugstr_w(control), debugstr_w(attribute)); - - LIST_FOR_EACH_ENTRY( sub, &package->subscriptions, struct subscriber, entry ) - { - if (!strcmpiW( sub->event, event ) && - !strcmpiW( sub->control, control ) && - !strcmpiW( sub->attribute, attribute )) - { - TRACE("already subscribed\n"); - return; - }; - } - if (!(sub = msi_alloc( sizeof(*sub) ))) return; - sub->dialog = dialog; - sub->event = strdupW(event); - sub->control = strdupW(control); - sub->attribute = strdupW(attribute); - list_add_tail( &package->subscriptions, &sub->entry ); -} - -VOID ControlEvent_FireSubscribedEvent( MSIPACKAGE *package, LPCWSTR event, MSIRECORD *rec ) -{ - struct subscriber *sub; - - TRACE("Firing event %s\n", debugstr_w(event)); - - LIST_FOR_EACH_ENTRY( sub, &package->subscriptions, struct subscriber, entry ) - { - if (strcmpiW( sub->event, event )) continue; - msi_dialog_handle_event( sub->dialog, sub->control, sub->attribute, rec ); - } -} - -VOID ControlEvent_CleanupDialogSubscriptions(MSIPACKAGE *package, LPWSTR dialog) -{ - struct list *i, *t; - struct subscriber *sub; - - LIST_FOR_EACH_SAFE( i, t, &package->subscriptions ) - { - sub = LIST_ENTRY( i, struct subscriber, entry ); - - if (strcmpW( msi_dialog_get_name( sub->dialog ), dialog )) - continue; - - list_remove( &sub->entry ); - free_subscriber( sub ); - } -} - -VOID ControlEvent_CleanupSubscriptions(MSIPACKAGE *package) -{ - struct list *i, *t; - struct subscriber *sub; - - LIST_FOR_EACH_SAFE( i, t, &package->subscriptions ) - { - sub = LIST_ENTRY( i, struct subscriber, entry ); - - list_remove( &sub->entry ); - free_subscriber( sub ); - } -} - -/* - * ACTION_DialogBox() - * - * Return ERROR_SUCCESS if dialog is process and ERROR_FUNCTION_FAILED - * if the given parameter is not a dialog box - */ -UINT ACTION_DialogBox( MSIPACKAGE* package, LPCWSTR szDialogName ) -{ - UINT r = ERROR_SUCCESS; - - if( package->next_dialog ) - ERR("Already a next dialog... ignoring it\n"); - package->next_dialog = NULL; - - /* - * Dialogs are chained by filling in the next_dialog member - * of the package structure, then terminating the current dialog. - * The code below sees the next_dialog member set, and runs the - * next dialog. - * We fall out of the loop below if we come across a modeless - * dialog, as it returns ERROR_IO_PENDING when we try to run - * its message loop. - */ - r = event_do_dialog( package, szDialogName, NULL, TRUE ); - while( r == ERROR_SUCCESS && package->next_dialog ) - { - LPWSTR name = package->next_dialog; - - package->next_dialog = NULL; - r = event_do_dialog( package, name, NULL, TRUE ); - msi_free( name ); - } - - if( r == ERROR_IO_PENDING ) - r = ERROR_SUCCESS; - - return r; -} - -static UINT ControlEvent_SetInstallLevel(MSIPACKAGE* package, LPCWSTR argument, - msi_dialog* dialog) -{ - int iInstallLevel = atolW(argument); - - TRACE("Setting install level: %i\n", iInstallLevel); - - return MSI_SetInstallLevel( package, iInstallLevel ); -} - -static UINT ControlEvent_DirectoryListUp(MSIPACKAGE *package, LPCWSTR argument, - msi_dialog *dialog) -{ - return msi_dialog_directorylist_up( dialog ); -} - -static UINT ControlEvent_ReinstallMode(MSIPACKAGE *package, LPCWSTR argument, - msi_dialog *dialog) -{ - return msi_set_property( package->db, szReinstallMode, argument ); -} - -static UINT ControlEvent_Reinstall( MSIPACKAGE *package, LPCWSTR argument, - msi_dialog *dialog ) -{ - return msi_set_property( package->db, szReinstall, argument ); -} - -static UINT ControlEvent_ValidateProductID(MSIPACKAGE *package, LPCWSTR argument, - msi_dialog *dialog) -{ - return msi_validate_product_id( package ); -} - -static const WCHAR end_dialogW[] = {'E','n','d','D','i','a','l','o','g',0}; -static const WCHAR new_dialogW[] = {'N','e','w','D','i','a','l','o','g',0}; -static const WCHAR spawn_dialogW[] = {'S','p','a','w','n','D','i','a','l','o','g',0}; -static const WCHAR spawn_wait_dialogW[] = {'S','p','a','w','n','W','a','i','t','D','i','a','l','o','g',0}; -static const WCHAR do_actionW[] = {'D','o','A','c','t','i','o','n',0}; -static const WCHAR add_localW[] = {'A','d','d','L','o','c','a','l',0}; -static const WCHAR removeW[] = {'R','e','m','o','v','e',0}; -static const WCHAR add_sourceW[] = {'A','d','d','S','o','u','r','c','e',0}; -static const WCHAR set_target_pathW[] = {'S','e','t','T','a','r','g','e','t','P','a','t','h',0}; -static const WCHAR resetW[] = {'R','e','s','e','t',0}; -static const WCHAR set_install_levelW[] = {'S','e','t','I','n','s','t','a','l','l','L','e','v','e','l',0}; -static const WCHAR directory_list_upW[] = {'D','i','r','e','c','t','o','r','y','L','i','s','t','U','p',0}; -static const WCHAR selection_browseW[] = {'S','e','l','e','c','t','i','o','n','B','r','o','w','s','e',0}; -static const WCHAR reinstall_modeW[] = {'R','e','i','n','s','t','a','l','l','M','o','d','e',0}; -static const WCHAR reinstallW[] = {'R','e','i','n','s','t','a','l','l',0}; -static const WCHAR validate_product_idW[] = {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0}; - -static const struct control_events control_events[] = -{ - { end_dialogW, ControlEvent_EndDialog }, - { new_dialogW, ControlEvent_NewDialog }, - { spawn_dialogW, ControlEvent_SpawnDialog }, - { spawn_wait_dialogW, ControlEvent_SpawnWaitDialog }, - { do_actionW, ControlEvent_DoAction }, - { add_localW, ControlEvent_AddLocal }, - { removeW, ControlEvent_Remove }, - { add_sourceW, ControlEvent_AddSource }, - { set_target_pathW, ControlEvent_SetTargetPath }, - { resetW, ControlEvent_Reset }, - { set_install_levelW, ControlEvent_SetInstallLevel }, - { directory_list_upW, ControlEvent_DirectoryListUp }, - { selection_browseW, ControlEvent_SpawnDialog }, - { reinstall_modeW, ControlEvent_ReinstallMode }, - { reinstallW, ControlEvent_Reinstall }, - { validate_product_idW, ControlEvent_ValidateProductID }, - { NULL, NULL } -}; - -UINT ControlEvent_HandleControlEvent( MSIPACKAGE *package, LPCWSTR event, - LPCWSTR argument, msi_dialog *dialog ) -{ - unsigned int i; - - TRACE("handling control event %s\n", debugstr_w(event)); - - if (!event) return ERROR_SUCCESS; - - for (i = 0; control_events[i].event; i++) - { - if (!strcmpW( control_events[i].event, event )) - return control_events[i].handler( package, argument, dialog ); - } - FIXME("unhandled control event %s arg(%s)\n", debugstr_w(event), debugstr_w(argument)); - return ERROR_SUCCESS; -} diff --git a/libmsi/files.c b/libmsi/files.c deleted file mode 100644 index 99ed1cf..0000000 --- a/libmsi/files.c +++ /dev/null @@ -1,1330 +0,0 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2005 Aric Stewart for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - - -/* - * Actions dealing with files: - * - * InstallFiles - * DuplicateFiles - * MoveFiles - * PatchFiles - * RemoveDuplicateFiles - * RemoveFiles - */ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wine/debug.h" -#include "fdi.h" -#include "msi.h" -#include "msidefs.h" -#include "msipriv.h" -#include "wingdi.h" -#include "winuser.h" -#include "winreg.h" -#include "shlwapi.h" -#include "wine/unicode.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -static HMODULE hmspatcha; -static BOOL (WINAPI *ApplyPatchToFileW)(LPCWSTR, LPCWSTR, LPCWSTR, ULONG); - -static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f, const WCHAR *action ) -{ - MSIRECORD *uirow; - - uirow = MSI_CreateRecord( 9 ); - MSI_RecordSetStringW( uirow, 1, f->FileName ); - MSI_RecordSetStringW( uirow, 9, f->Component->Directory ); - MSI_RecordSetInteger( uirow, 6, f->FileSize ); - msi_ui_actiondata( package, action, uirow ); - msiobj_release( &uirow->hdr ); - msi_ui_progress( package, 2, f->FileSize, 0, 0 ); -} - -static msi_file_state calculate_install_state( MSIPACKAGE *package, MSIFILE *file ) -{ - MSICOMPONENT *comp = file->Component; - VS_FIXEDFILEINFO *file_version; - WCHAR *font_version; - msi_file_state state; - DWORD file_size; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_LOCAL || (comp->assembly && comp->assembly->installed)) - { - TRACE("file %s is not scheduled for install\n", debugstr_w(file->File)); - return msifs_skipped; - } - if ((comp->assembly && !comp->assembly->application && !comp->assembly->installed) || - GetFileAttributesW( file->TargetPath ) == INVALID_FILE_ATTRIBUTES) - { - TRACE("file %s is missing\n", debugstr_w(file->File)); - return msifs_missing; - } - if (file->Version) - { - if ((file_version = msi_get_disk_file_version( file->TargetPath ))) - { - TRACE("new %s old %u.%u.%u.%u\n", debugstr_w(file->Version), - HIWORD(file_version->dwFileVersionMS), - LOWORD(file_version->dwFileVersionMS), - HIWORD(file_version->dwFileVersionLS), - LOWORD(file_version->dwFileVersionLS)); - - if (msi_compare_file_versions( file_version, file->Version ) < 0) - state = msifs_overwrite; - else - { - TRACE("destination file version equal or greater, not overwriting\n"); - state = msifs_present; - } - msi_free( file_version ); - return state; - } - else if ((font_version = msi_font_version_from_file( file->TargetPath ))) - { - TRACE("new %s old %s\n", debugstr_w(file->Version), debugstr_w(font_version)); - - if (msi_compare_font_versions( font_version, file->Version ) < 0) - state = msifs_overwrite; - else - { - TRACE("destination file version equal or greater, not overwriting\n"); - state = msifs_present; - } - msi_free( font_version ); - return state; - } - } - if ((file_size = msi_get_disk_file_size( file->TargetPath )) != file->FileSize) - { - return msifs_overwrite; - } - if (file->hash.dwFileHashInfoSize) - { - if (msi_file_hash_matches( file )) - { - TRACE("file hashes match, not overwriting\n"); - return msifs_hashmatch; - } - else - { - TRACE("file hashes do not match, overwriting\n"); - return msifs_overwrite; - } - } - /* assume present */ - return msifs_present; -} - -static void schedule_install_files(MSIPACKAGE *package) -{ - MSIFILE *file; - - LIST_FOR_EACH_ENTRY(file, &package->files, MSIFILE, entry) - { - MSICOMPONENT *comp = file->Component; - - file->state = calculate_install_state( package, file ); - if (file->state == msifs_overwrite && (comp->Attributes & msidbComponentAttributesNeverOverwrite)) - { - TRACE("not overwriting %s\n", debugstr_w(file->TargetPath)); - file->state = msifs_skipped; - } - } -} - -static UINT copy_file(MSIFILE *file, LPWSTR source) -{ - BOOL ret; - - ret = CopyFileW(source, file->TargetPath, FALSE); - if (!ret) - return GetLastError(); - - SetFileAttributesW(file->TargetPath, FILE_ATTRIBUTE_NORMAL); - - file->state = msifs_installed; - return ERROR_SUCCESS; -} - -static UINT copy_install_file(MSIPACKAGE *package, MSIFILE *file, LPWSTR source) -{ - UINT gle; - - TRACE("Copying %s to %s\n", debugstr_w(source), debugstr_w(file->TargetPath)); - - gle = copy_file(file, source); - if (gle == ERROR_SUCCESS) - return gle; - - if (gle == ERROR_ALREADY_EXISTS && file->state == msifs_overwrite) - { - TRACE("overwriting existing file\n"); - return ERROR_SUCCESS; - } - else if (gle == ERROR_ACCESS_DENIED) - { - SetFileAttributesW(file->TargetPath, FILE_ATTRIBUTE_NORMAL); - - gle = copy_file(file, source); - TRACE("Overwriting existing file: %d\n", gle); - } - if (gle == ERROR_SHARING_VIOLATION || gle == ERROR_USER_MAPPED_FILE) - { - WCHAR *tmpfileW, *pathW, *p; - DWORD len; - - TRACE("file in use, scheduling rename operation\n"); - - if (!(pathW = strdupW( file->TargetPath ))) return ERROR_OUTOFMEMORY; - if ((p = strrchrW(pathW, '\\'))) *p = 0; - len = strlenW( pathW ) + 16; - if (!(tmpfileW = msi_alloc(len * sizeof(WCHAR)))) - { - msi_free( pathW ); - return ERROR_OUTOFMEMORY; - } - if (!GetTempFileNameW( pathW, szMsi, 0, tmpfileW )) tmpfileW[0] = 0; - msi_free( pathW ); - - if (CopyFileW(source, tmpfileW, FALSE) && - MoveFileExW(file->TargetPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT) && - MoveFileExW(tmpfileW, file->TargetPath, MOVEFILE_DELAY_UNTIL_REBOOT)) - { - file->state = msifs_installed; - package->need_reboot_at_end = 1; - gle = ERROR_SUCCESS; - } - else - { - gle = GetLastError(); - WARN("failed to schedule rename operation: %d)\n", gle); - DeleteFileW( tmpfileW ); - } - msi_free(tmpfileW); - } - - return gle; -} - -static UINT msi_create_directory( MSIPACKAGE *package, const WCHAR *dir ) -{ - MSIFOLDER *folder; - const WCHAR *install_path; - - install_path = msi_get_target_folder( package, dir ); - if (!install_path) return ERROR_FUNCTION_FAILED; - - folder = msi_get_loaded_folder( package, dir ); - if (folder->State == FOLDER_STATE_UNINITIALIZED) - { - msi_create_full_path( install_path ); - folder->State = FOLDER_STATE_CREATED; - } - return ERROR_SUCCESS; -} - -static MSIFILE *find_file( MSIPACKAGE *package, const WCHAR *filename ) -{ - MSIFILE *file; - - LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) - { - if (file->state != msifs_installed && !strcmpiW( filename, file->File )) return file; - } - return NULL; -} - -static BOOL installfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action, - LPWSTR *path, DWORD *attrs, PVOID user) -{ - static MSIFILE *f = NULL; - UINT_PTR disk_id = (UINT_PTR)user; - - if (action == MSICABEXTRACT_BEGINEXTRACT) - { - if (!(f = find_file( package, file ))) - { - TRACE("unknown file in cabinet (%s)\n", debugstr_w(file)); - return FALSE; - } - if (f->disk_id != disk_id || (f->state != msifs_missing && f->state != msifs_overwrite)) - return FALSE; - - if (!f->Component->assembly || f->Component->assembly->application) - { - msi_create_directory(package, f->Component->Directory); - } - *path = strdupW(f->TargetPath); - *attrs = f->Attributes; - } - else if (action == MSICABEXTRACT_FILEEXTRACTED) - { - f->state = msifs_installed; - f = NULL; - } - - return TRUE; -} - -WCHAR *msi_resolve_file_source( MSIPACKAGE *package, MSIFILE *file ) -{ - WCHAR *p, *path; - - TRACE("Working to resolve source of file %s\n", debugstr_w(file->File)); - - if (file->IsCompressed) return NULL; - - p = msi_resolve_source_folder( package, file->Component->Directory, NULL ); - path = msi_build_directory_name( 2, p, file->ShortName ); - - if (file->LongName && GetFileAttributesW( path ) == INVALID_FILE_ATTRIBUTES) - { - msi_free( path ); - path = msi_build_directory_name( 2, p, file->LongName ); - } - msi_free( p ); - TRACE("file %s source resolves to %s\n", debugstr_w(file->File), debugstr_w(path)); - return path; -} - -/* - * ACTION_InstallFiles() - * - * For efficiency, this is done in two passes: - * 1) Correct all the TargetPaths and determine what files are to be installed. - * 2) Extract Cabinets and copy files. - */ -UINT ACTION_InstallFiles(MSIPACKAGE *package) -{ - MSIMEDIAINFO *mi; - MSICOMPONENT *comp; - UINT rc = ERROR_SUCCESS; - MSIFILE *file; - - schedule_install_files(package); - mi = msi_alloc_zero( sizeof(MSIMEDIAINFO) ); - - LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) - { - msi_file_update_ui( package, file, szInstallFiles ); - - rc = msi_load_media_info( package, file->Sequence, mi ); - if (rc != ERROR_SUCCESS) - { - ERR("Unable to load media info for %s (%u)\n", debugstr_w(file->File), rc); - return ERROR_FUNCTION_FAILED; - } - if (!file->Component->Enabled) continue; - - if (file->state != msifs_hashmatch && - file->state != msifs_skipped && - (file->state != msifs_present || !msi_get_property_int( package->db, szInstalled, 0 )) && - (rc = ready_media( package, file->IsCompressed, mi ))) - { - ERR("Failed to ready media for %s\n", debugstr_w(file->File)); - goto done; - } - - if (file->state != msifs_missing && !mi->is_continuous && file->state != msifs_overwrite) - continue; - - if (file->Sequence > mi->last_sequence || mi->is_continuous || - (file->IsCompressed && !mi->is_extracted)) - { - MSICABDATA data; - - data.mi = mi; - data.package = package; - data.cb = installfiles_cb; - data.user = (PVOID)(UINT_PTR)mi->disk_id; - - if (file->IsCompressed && - !msi_cabextract(package, mi, &data)) - { - ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet)); - rc = ERROR_INSTALL_FAILURE; - goto done; - } - } - - if (!file->IsCompressed) - { - WCHAR *source = msi_resolve_file_source(package, file); - - TRACE("copying %s to %s\n", debugstr_w(source), debugstr_w(file->TargetPath)); - - if (!file->Component->assembly || file->Component->assembly->application) - { - msi_create_directory(package, file->Component->Directory); - } - rc = copy_install_file(package, file, source); - if (rc != ERROR_SUCCESS) - { - ERR("Failed to copy %s to %s (%d)\n", debugstr_w(source), - debugstr_w(file->TargetPath), rc); - rc = ERROR_INSTALL_FAILURE; - msi_free(source); - goto done; - } - msi_free(source); - } - else if (file->state != msifs_installed && !(file->Attributes & msidbFileAttributesPatchAdded)) - { - ERR("compressed file wasn't installed (%s)\n", debugstr_w(file->TargetPath)); - rc = ERROR_INSTALL_FAILURE; - goto done; - } - } - LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) - { - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action == INSTALLSTATE_LOCAL && comp->assembly && !comp->assembly->installed) - { - rc = msi_install_assembly( package, comp ); - if (rc != ERROR_SUCCESS) - { - ERR("Failed to install assembly\n"); - rc = ERROR_INSTALL_FAILURE; - break; - } - } - } - -done: - msi_free_media_info(mi); - return rc; -} - -static BOOL load_mspatcha(void) -{ - hmspatcha = LoadLibraryA("mspatcha.dll"); - if (!hmspatcha) - { - ERR("Failed to load mspatcha.dll: %d\n", GetLastError()); - return FALSE; - } - - ApplyPatchToFileW = (void*)GetProcAddress(hmspatcha, "ApplyPatchToFileW"); - if(!ApplyPatchToFileW) - { - ERR("GetProcAddress(ApplyPatchToFileW) failed: %d.\n", GetLastError()); - return FALSE; - } - - return TRUE; -} - -static void unload_mspatch(void) -{ - FreeLibrary(hmspatcha); -} - -static BOOL patchfiles_cb(MSIPACKAGE *package, LPCWSTR file, DWORD action, - LPWSTR *path, DWORD *attrs, PVOID user) -{ - static MSIFILEPATCH *p = NULL; - static WCHAR patch_path[MAX_PATH] = {0}; - static WCHAR temp_folder[MAX_PATH] = {0}; - - if (action == MSICABEXTRACT_BEGINEXTRACT) - { - if (temp_folder[0] == '\0') - GetTempPathW(MAX_PATH, temp_folder); - - p = msi_get_loaded_filepatch(package, file); - if (!p) - { - TRACE("unknown file in cabinet (%s)\n", debugstr_w(file)); - return FALSE; - } - GetTempFileNameW(temp_folder, NULL, 0, patch_path); - - *path = strdupW(patch_path); - *attrs = p->File->Attributes; - } - else if (action == MSICABEXTRACT_FILEEXTRACTED) - { - WCHAR patched_file[MAX_PATH]; - BOOL br; - - GetTempFileNameW(temp_folder, NULL, 0, patched_file); - - br = ApplyPatchToFileW(patch_path, p->File->TargetPath, patched_file, 0); - if (br) - { - /* FIXME: baseline cache */ - - DeleteFileW( p->File->TargetPath ); - MoveFileW( patched_file, p->File->TargetPath ); - - p->IsApplied = TRUE; - } - else - ERR("Failed patch %s: %d.\n", debugstr_w(p->File->TargetPath), GetLastError()); - - DeleteFileW(patch_path); - p = NULL; - } - - return TRUE; -} - -UINT ACTION_PatchFiles( MSIPACKAGE *package ) -{ - MSIFILEPATCH *patch; - MSIMEDIAINFO *mi; - UINT rc = ERROR_SUCCESS; - BOOL mspatcha_loaded = FALSE; - - TRACE("%p\n", package); - - mi = msi_alloc_zero( sizeof(MSIMEDIAINFO) ); - - LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry ) - { - MSIFILE *file = patch->File; - MSICOMPONENT *comp = file->Component; - - rc = msi_load_media_info( package, patch->Sequence, mi ); - if (rc != ERROR_SUCCESS) - { - ERR("Unable to load media info for %s (%u)\n", debugstr_w(file->File), rc); - return ERROR_FUNCTION_FAILED; - } - comp->Action = msi_get_component_action( package, comp ); - if (!comp->Enabled || comp->Action != INSTALLSTATE_LOCAL) continue; - - if (!patch->IsApplied) - { - MSICABDATA data; - - rc = ready_media( package, TRUE, mi ); - if (rc != ERROR_SUCCESS) - { - ERR("Failed to ready media for %s\n", debugstr_w(file->File)); - goto done; - } - - if (!mspatcha_loaded && !load_mspatcha()) - { - rc = ERROR_FUNCTION_FAILED; - goto done; - } - mspatcha_loaded = TRUE; - - data.mi = mi; - data.package = package; - data.cb = patchfiles_cb; - data.user = (PVOID)(UINT_PTR)mi->disk_id; - - if (!msi_cabextract(package, mi, &data)) - { - ERR("Failed to extract cabinet: %s\n", debugstr_w(mi->cabinet)); - rc = ERROR_INSTALL_FAILURE; - goto done; - } - } - - if (!patch->IsApplied && !(patch->Attributes & msidbPatchAttributesNonVital)) - { - ERR("Failed to apply patch to file: %s\n", debugstr_w(file->File)); - rc = ERROR_INSTALL_FAILURE; - goto done; - } - } - -done: - msi_free_media_info(mi); - if (mspatcha_loaded) - unload_mspatch(); - return rc; -} - -#define is_dot_dir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0)))) - -typedef struct -{ - struct list entry; - LPWSTR sourcename; - LPWSTR destname; - LPWSTR source; - LPWSTR dest; -} FILE_LIST; - -static BOOL msi_move_file(LPCWSTR source, LPCWSTR dest, int options) -{ - BOOL ret; - - if (GetFileAttributesW(source) == FILE_ATTRIBUTE_DIRECTORY || - GetFileAttributesW(dest) == FILE_ATTRIBUTE_DIRECTORY) - { - WARN("Source or dest is directory, not moving\n"); - return FALSE; - } - - if (options == msidbMoveFileOptionsMove) - { - TRACE("moving %s -> %s\n", debugstr_w(source), debugstr_w(dest)); - ret = MoveFileExW(source, dest, MOVEFILE_REPLACE_EXISTING); - if (!ret) - { - WARN("MoveFile failed: %d\n", GetLastError()); - return FALSE; - } - } - else - { - TRACE("copying %s -> %s\n", debugstr_w(source), debugstr_w(dest)); - ret = CopyFileW(source, dest, FALSE); - if (!ret) - { - WARN("CopyFile failed: %d\n", GetLastError()); - return FALSE; - } - } - - return TRUE; -} - -static LPWSTR wildcard_to_file(LPWSTR wildcard, LPWSTR filename) -{ - LPWSTR path, ptr; - DWORD dirlen, pathlen; - - ptr = strrchrW(wildcard, '\\'); - dirlen = ptr - wildcard + 1; - - pathlen = dirlen + lstrlenW(filename) + 1; - path = msi_alloc(pathlen * sizeof(WCHAR)); - - lstrcpynW(path, wildcard, dirlen + 1); - lstrcatW(path, filename); - - return path; -} - -static void free_file_entry(FILE_LIST *file) -{ - msi_free(file->source); - msi_free(file->dest); - msi_free(file); -} - -static void free_list(FILE_LIST *list) -{ - while (!list_empty(&list->entry)) - { - FILE_LIST *file = LIST_ENTRY(list_head(&list->entry), FILE_LIST, entry); - - list_remove(&file->entry); - free_file_entry(file); - } -} - -static BOOL add_wildcard(FILE_LIST *files, LPWSTR source, LPWSTR dest) -{ - FILE_LIST *new, *file; - LPWSTR ptr, filename; - DWORD size; - - new = msi_alloc_zero(sizeof(FILE_LIST)); - if (!new) - return FALSE; - - new->source = strdupW(source); - ptr = strrchrW(dest, '\\') + 1; - filename = strrchrW(new->source, '\\') + 1; - - new->sourcename = filename; - - if (*ptr) - new->destname = ptr; - else - new->destname = new->sourcename; - - size = (ptr - dest) + lstrlenW(filename) + 1; - new->dest = msi_alloc(size * sizeof(WCHAR)); - if (!new->dest) - { - free_file_entry(new); - return FALSE; - } - - lstrcpynW(new->dest, dest, ptr - dest + 1); - lstrcatW(new->dest, filename); - - if (list_empty(&files->entry)) - { - list_add_head(&files->entry, &new->entry); - return TRUE; - } - - LIST_FOR_EACH_ENTRY(file, &files->entry, FILE_LIST, entry) - { - if (strcmpW( source, file->source ) < 0) - { - list_add_before(&file->entry, &new->entry); - return TRUE; - } - } - - list_add_after(&file->entry, &new->entry); - return TRUE; -} - -static BOOL move_files_wildcard(LPWSTR source, LPWSTR dest, int options) -{ - WIN32_FIND_DATAW wfd; - HANDLE hfile; - LPWSTR path; - BOOL res; - FILE_LIST files, *file; - DWORD size; - - hfile = FindFirstFileW(source, &wfd); - if (hfile == INVALID_HANDLE_VALUE) return FALSE; - - list_init(&files.entry); - - for (res = TRUE; res; res = FindNextFileW(hfile, &wfd)) - { - if (is_dot_dir(wfd.cFileName)) continue; - - path = wildcard_to_file(source, wfd.cFileName); - if (!path) - { - res = FALSE; - goto done; - } - - add_wildcard(&files, path, dest); - msi_free(path); - } - - /* no files match the wildcard */ - if (list_empty(&files.entry)) - goto done; - - /* only the first wildcard match gets renamed to dest */ - file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry); - size = (strrchrW(file->dest, '\\') - file->dest) + lstrlenW(file->destname) + 2; - file->dest = msi_realloc(file->dest, size * sizeof(WCHAR)); - if (!file->dest) - { - res = FALSE; - goto done; - } - - /* file->dest may be shorter after the reallocation, so add a NULL - * terminator. This is needed for the call to strrchrW, as there will no - * longer be a NULL terminator within the bounds of the allocation in this case. - */ - file->dest[size - 1] = '\0'; - lstrcpyW(strrchrW(file->dest, '\\') + 1, file->destname); - - while (!list_empty(&files.entry)) - { - file = LIST_ENTRY(list_head(&files.entry), FILE_LIST, entry); - - msi_move_file(file->source, file->dest, options); - - list_remove(&file->entry); - free_file_entry(file); - } - - res = TRUE; - -done: - free_list(&files); - FindClose(hfile); - return res; -} - -void msi_reduce_to_long_filename( WCHAR *filename ) -{ - WCHAR *p = strchrW( filename, '|' ); - if (p) memmove( filename, p + 1, (strlenW( p + 1 ) + 1) * sizeof(WCHAR) ); -} - -static UINT ITERATE_MoveFiles( MSIRECORD *rec, LPVOID param ) -{ - MSIPACKAGE *package = param; - MSIRECORD *uirow; - MSICOMPONENT *comp; - LPCWSTR sourcename, component; - LPWSTR sourcedir, destname = NULL, destdir = NULL, source = NULL, dest = NULL; - int options; - DWORD size; - BOOL ret, wildcards; - - component = MSI_RecordGetString(rec, 2); - comp = msi_get_loaded_component(package, component); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_LOCAL) - { - TRACE("component not scheduled for installation %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - - sourcename = MSI_RecordGetString(rec, 3); - options = MSI_RecordGetInteger(rec, 7); - - sourcedir = msi_dup_property(package->db, MSI_RecordGetString(rec, 5)); - if (!sourcedir) - goto done; - - destdir = msi_dup_property(package->db, MSI_RecordGetString(rec, 6)); - if (!destdir) - goto done; - - if (!sourcename) - { - if (GetFileAttributesW(sourcedir) == INVALID_FILE_ATTRIBUTES) - goto done; - - source = strdupW(sourcedir); - if (!source) - goto done; - } - else - { - size = lstrlenW(sourcedir) + lstrlenW(sourcename) + 2; - source = msi_alloc(size * sizeof(WCHAR)); - if (!source) - goto done; - - lstrcpyW(source, sourcedir); - if (source[lstrlenW(source) - 1] != '\\') - lstrcatW(source, szBackSlash); - lstrcatW(source, sourcename); - } - - wildcards = strchrW(source, '*') || strchrW(source, '?'); - - if (MSI_RecordIsNull(rec, 4)) - { - if (!wildcards) - { - destname = strdupW(sourcename); - if (!destname) - goto done; - } - } - else - { - destname = strdupW(MSI_RecordGetString(rec, 4)); - if (destname) msi_reduce_to_long_filename(destname); - } - - size = 0; - if (destname) - size = lstrlenW(destname); - - size += lstrlenW(destdir) + 2; - dest = msi_alloc(size * sizeof(WCHAR)); - if (!dest) - goto done; - - lstrcpyW(dest, destdir); - if (dest[lstrlenW(dest) - 1] != '\\') - lstrcatW(dest, szBackSlash); - - if (destname) - lstrcatW(dest, destname); - - if (GetFileAttributesW(destdir) == INVALID_FILE_ATTRIBUTES) - { - if (!(ret = msi_create_full_path(destdir))) - { - WARN("failed to create directory %u\n", GetLastError()); - goto done; - } - } - - if (!wildcards) - msi_move_file(source, dest, options); - else - move_files_wildcard(source, dest, options); - -done: - uirow = MSI_CreateRecord( 9 ); - MSI_RecordSetStringW( uirow, 1, MSI_RecordGetString(rec, 1) ); - MSI_RecordSetInteger( uirow, 6, 1 ); /* FIXME */ - MSI_RecordSetStringW( uirow, 9, destdir ); - msi_ui_actiondata( package, szMoveFiles, uirow ); - msiobj_release( &uirow->hdr ); - - msi_free(sourcedir); - msi_free(destdir); - msi_free(destname); - msi_free(source); - msi_free(dest); - - return ERROR_SUCCESS; -} - -UINT ACTION_MoveFiles( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','M','o','v','e','F','i','l','e','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, ITERATE_MoveFiles, package); - msiobj_release(&view->hdr); - return rc; -} - -static WCHAR *get_duplicate_filename( MSIPACKAGE *package, MSIRECORD *row, const WCHAR *file_key, const WCHAR *src ) -{ - DWORD len; - WCHAR *dst_name, *dst_path, *dst; - - if (MSI_RecordIsNull( row, 4 )) - { - len = strlenW( src ) + 1; - if (!(dst_name = msi_alloc( len * sizeof(WCHAR)))) return NULL; - strcpyW( dst_name, strrchrW( src, '\\' ) + 1 ); - } - else - { - MSI_RecordGetStringW( row, 4, NULL, &len ); - if (!(dst_name = msi_alloc( ++len * sizeof(WCHAR) ))) return NULL; - MSI_RecordGetStringW( row, 4, dst_name, &len ); - msi_reduce_to_long_filename( dst_name ); - } - - if (MSI_RecordIsNull( row, 5 )) - { - WCHAR *p; - dst_path = strdupW( src ); - p = strrchrW( dst_path, '\\' ); - if (p) *p = 0; - } - else - { - const WCHAR *dst_key = MSI_RecordGetString( row, 5 ); - - dst_path = strdupW( msi_get_target_folder( package, dst_key ) ); - if (!dst_path) - { - /* try a property */ - dst_path = msi_dup_property( package->db, dst_key ); - if (!dst_path) - { - FIXME("Unable to get destination folder, try AppSearch properties\n"); - msi_free( dst_name ); - return NULL; - } - } - } - - dst = msi_build_directory_name( 2, dst_path, dst_name ); - msi_create_full_path( dst_path ); - - msi_free( dst_name ); - msi_free( dst_path ); - return dst; -} - -static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param) -{ - MSIPACKAGE *package = param; - LPWSTR dest; - LPCWSTR file_key, component; - MSICOMPONENT *comp; - MSIRECORD *uirow; - MSIFILE *file; - - component = MSI_RecordGetString(row,2); - comp = msi_get_loaded_component(package, component); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_LOCAL) - { - TRACE("component not scheduled for installation %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - - file_key = MSI_RecordGetString(row,3); - if (!file_key) - { - ERR("Unable to get file key\n"); - return ERROR_FUNCTION_FAILED; - } - - file = msi_get_loaded_file( package, file_key ); - if (!file) - { - ERR("Original file unknown %s\n", debugstr_w(file_key)); - return ERROR_SUCCESS; - } - - dest = get_duplicate_filename( package, row, file_key, file->TargetPath ); - if (!dest) - { - WARN("Unable to get duplicate filename\n"); - return ERROR_SUCCESS; - } - - TRACE("Duplicating file %s to %s\n", debugstr_w(file->TargetPath), debugstr_w(dest)); - - if (!CopyFileW( file->TargetPath, dest, TRUE )) - { - WARN("Failed to copy file %s -> %s (%u)\n", - debugstr_w(file->TargetPath), debugstr_w(dest), GetLastError()); - } - - FIXME("We should track these duplicate files as well\n"); - - uirow = MSI_CreateRecord( 9 ); - MSI_RecordSetStringW( uirow, 1, MSI_RecordGetString( row, 1 ) ); - MSI_RecordSetInteger( uirow, 6, file->FileSize ); - MSI_RecordSetStringW( uirow, 9, MSI_RecordGetString( row, 5 ) ); - msi_ui_actiondata( package, szDuplicateFiles, uirow ); - msiobj_release( &uirow->hdr ); - - msi_free(dest); - return ERROR_SUCCESS; -} - -UINT ACTION_DuplicateFiles(MSIPACKAGE *package) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, ITERATE_DuplicateFiles, package); - msiobj_release(&view->hdr); - return rc; -} - -static UINT ITERATE_RemoveDuplicateFiles( MSIRECORD *row, LPVOID param ) -{ - MSIPACKAGE *package = param; - LPWSTR dest; - LPCWSTR file_key, component; - MSICOMPONENT *comp; - MSIRECORD *uirow; - MSIFILE *file; - - component = MSI_RecordGetString( row, 2 ); - comp = msi_get_loaded_component( package, component ); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_ABSENT) - { - TRACE("component not scheduled for removal %s\n", debugstr_w(component)); - return ERROR_SUCCESS; - } - - file_key = MSI_RecordGetString( row, 3 ); - if (!file_key) - { - ERR("Unable to get file key\n"); - return ERROR_FUNCTION_FAILED; - } - - file = msi_get_loaded_file( package, file_key ); - if (!file) - { - ERR("Original file unknown %s\n", debugstr_w(file_key)); - return ERROR_SUCCESS; - } - - dest = get_duplicate_filename( package, row, file_key, file->TargetPath ); - if (!dest) - { - WARN("Unable to get duplicate filename\n"); - return ERROR_SUCCESS; - } - - TRACE("Removing duplicate %s of %s\n", debugstr_w(dest), debugstr_w(file->TargetPath)); - - if (!DeleteFileW( dest )) - { - WARN("Failed to delete duplicate file %s (%u)\n", debugstr_w(dest), GetLastError()); - } - - uirow = MSI_CreateRecord( 9 ); - MSI_RecordSetStringW( uirow, 1, MSI_RecordGetString( row, 1 ) ); - MSI_RecordSetStringW( uirow, 9, MSI_RecordGetString( row, 5 ) ); - msi_ui_actiondata( package, szRemoveDuplicateFiles, uirow ); - msiobj_release( &uirow->hdr ); - - msi_free(dest); - return ERROR_SUCCESS; -} - -UINT ACTION_RemoveDuplicateFiles( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveDuplicateFiles, package ); - msiobj_release( &view->hdr ); - return rc; -} - -static BOOL verify_comp_for_removal(MSICOMPONENT *comp, UINT install_mode) -{ - /* special case */ - if (comp->Action != INSTALLSTATE_SOURCE && - comp->Attributes & msidbComponentAttributesSourceOnly && - (install_mode == msidbRemoveFileInstallModeOnRemove || - install_mode == msidbRemoveFileInstallModeOnBoth)) return TRUE; - - switch (comp->Action) - { - case INSTALLSTATE_LOCAL: - case INSTALLSTATE_SOURCE: - if (install_mode == msidbRemoveFileInstallModeOnInstall || - install_mode == msidbRemoveFileInstallModeOnBoth) return TRUE; - break; - case INSTALLSTATE_ABSENT: - if (install_mode == msidbRemoveFileInstallModeOnRemove || - install_mode == msidbRemoveFileInstallModeOnBoth) return TRUE; - break; - default: break; - } - return FALSE; -} - -static UINT ITERATE_RemoveFiles(MSIRECORD *row, LPVOID param) -{ - MSIPACKAGE *package = param; - MSICOMPONENT *comp; - MSIRECORD *uirow; - LPCWSTR component, dirprop; - UINT install_mode; - LPWSTR dir = NULL, path = NULL, filename = NULL; - DWORD size; - UINT ret = ERROR_SUCCESS; - - component = MSI_RecordGetString(row, 2); - dirprop = MSI_RecordGetString(row, 4); - install_mode = MSI_RecordGetInteger(row, 5); - - comp = msi_get_loaded_component(package, component); - if (!comp) - return ERROR_SUCCESS; - - comp->Action = msi_get_component_action( package, comp ); - if (!verify_comp_for_removal(comp, install_mode)) - { - TRACE("Skipping removal due to install mode\n"); - return ERROR_SUCCESS; - } - if (comp->assembly && !comp->assembly->application) - { - return ERROR_SUCCESS; - } - if (comp->Attributes & msidbComponentAttributesPermanent) - { - TRACE("permanent component, not removing file\n"); - return ERROR_SUCCESS; - } - - dir = msi_dup_property(package->db, dirprop); - if (!dir) - { - WARN("directory property has no value\n"); - return ERROR_SUCCESS; - } - size = 0; - if ((filename = strdupW( MSI_RecordGetString(row, 3) ))) - { - msi_reduce_to_long_filename( filename ); - size = lstrlenW( filename ); - } - size += lstrlenW(dir) + 2; - path = msi_alloc(size * sizeof(WCHAR)); - if (!path) - { - ret = ERROR_OUTOFMEMORY; - goto done; - } - - if (filename) - { - lstrcpyW(path, dir); - PathAddBackslashW(path); - lstrcatW(path, filename); - - TRACE("Deleting misc file: %s\n", debugstr_w(path)); - DeleteFileW(path); - } - else - { - TRACE("Removing misc directory: %s\n", debugstr_w(dir)); - RemoveDirectoryW(dir); - } - -done: - uirow = MSI_CreateRecord( 9 ); - MSI_RecordSetStringW( uirow, 1, MSI_RecordGetString(row, 1) ); - MSI_RecordSetStringW( uirow, 9, dir ); - msi_ui_actiondata( package, szRemoveFiles, uirow ); - msiobj_release( &uirow->hdr ); - - msi_free(filename); - msi_free(path); - msi_free(dir); - return ret; -} - -static void remove_folder( MSIFOLDER *folder ) -{ - FolderList *fl; - - LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry ) - { - remove_folder( fl->folder ); - } - if (!folder->persistent && folder->State != FOLDER_STATE_REMOVED) - { - if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED; - } -} - -UINT ACTION_RemoveFiles( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','R','e','m','o','v','e','F','i','l','e','`',0}; - MSIQUERY *view; - MSICOMPONENT *comp; - MSIFILE *file; - UINT r; - - r = MSI_DatabaseOpenViewW(package->db, query, &view); - if (r == ERROR_SUCCESS) - { - r = MSI_IterateRecords(view, NULL, ITERATE_RemoveFiles, package); - msiobj_release(&view->hdr); - if (r != ERROR_SUCCESS) - return r; - } - - LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) - { - MSIRECORD *uirow; - VS_FIXEDFILEINFO *ver; - - comp = file->Component; - msi_file_update_ui( package, file, szRemoveFiles ); - - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_ABSENT || comp->Installed == INSTALLSTATE_SOURCE) - continue; - - if (comp->assembly && !comp->assembly->application) - continue; - - if (comp->Attributes & msidbComponentAttributesPermanent) - { - TRACE("permanent component, not removing file\n"); - continue; - } - - if (file->Version) - { - ver = msi_get_disk_file_version( file->TargetPath ); - if (ver && msi_compare_file_versions( ver, file->Version ) > 0) - { - TRACE("newer version detected, not removing file\n"); - msi_free( ver ); - continue; - } - msi_free( ver ); - } - - if (file->state == msifs_installed) - WARN("removing installed file %s\n", debugstr_w(file->TargetPath)); - - TRACE("removing %s\n", debugstr_w(file->File) ); - - SetFileAttributesW( file->TargetPath, FILE_ATTRIBUTE_NORMAL ); - if (!DeleteFileW( file->TargetPath )) - { - WARN("failed to delete %s (%u)\n", debugstr_w(file->TargetPath), GetLastError()); - } - file->state = msifs_missing; - - uirow = MSI_CreateRecord( 9 ); - MSI_RecordSetStringW( uirow, 1, file->FileName ); - MSI_RecordSetStringW( uirow, 9, comp->Directory ); - msi_ui_actiondata( package, szRemoveFiles, uirow ); - msiobj_release( &uirow->hdr ); - } - - LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) - { - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_ABSENT) continue; - - if (comp->Attributes & msidbComponentAttributesPermanent) - { - TRACE("permanent component, not removing directory\n"); - continue; - } - if (comp->assembly && !comp->assembly->application) - msi_uninstall_assembly( package, comp ); - else - { - MSIFOLDER *folder = msi_get_loaded_folder( package, comp->Directory ); - remove_folder( folder ); - } - } - return ERROR_SUCCESS; -} diff --git a/libmsi/font.c b/libmsi/font.c deleted file mode 100644 index 0b728a3..0000000 --- a/libmsi/font.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2004,2005 Aric Stewart for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include <stdarg.h> -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winreg.h" -#include "wine/debug.h" -#include "msipriv.h" -#include "wine/unicode.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -typedef struct _tagTT_OFFSET_TABLE { - USHORT uMajorVersion; - USHORT uMinorVersion; - USHORT uNumOfTables; - USHORT uSearchRange; - USHORT uEntrySelector; - USHORT uRangeShift; -} TT_OFFSET_TABLE; - -typedef struct _tagTT_TABLE_DIRECTORY { - char szTag[4]; /* table name */ - ULONG uCheckSum; /* Check sum */ - ULONG uOffset; /* Offset from beginning of file */ - ULONG uLength; /* length of the table in bytes */ -} TT_TABLE_DIRECTORY; - -typedef struct _tagTT_NAME_TABLE_HEADER { - USHORT uFSelector; /* format selector. Always 0 */ - USHORT uNRCount; /* Name Records count */ - USHORT uStorageOffset; /* Offset for strings storage, - * from start of the table */ -} TT_NAME_TABLE_HEADER; - -#define NAME_ID_FULL_FONT_NAME 4 -#define NAME_ID_VERSION 5 - -typedef struct _tagTT_NAME_RECORD { - USHORT uPlatformID; - USHORT uEncodingID; - USHORT uLanguageID; - USHORT uNameID; - USHORT uStringLength; - USHORT uStringOffset; /* from start of storage area */ -} TT_NAME_RECORD; - -#define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x)) -#define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x))) - -static const WCHAR regfont1[] = - {'S','o','f','t','w','a','r','e','\\', - 'M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s',' ','N','T','\\', - 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'F','o','n','t','s',0}; -static const WCHAR regfont2[] = - {'S','o','f','t','w','a','r','e','\\', - 'M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s','\\', - 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'F','o','n','t','s',0}; - -/* - * Code based off of code located here - * http://www.codeproject.com/gdi/fontnamefromfile.asp - */ -static WCHAR *load_ttf_name_id( const WCHAR *filename, DWORD id ) -{ - TT_TABLE_DIRECTORY tblDir; - BOOL bFound = FALSE; - TT_OFFSET_TABLE ttOffsetTable; - TT_NAME_TABLE_HEADER ttNTHeader; - TT_NAME_RECORD ttRecord; - DWORD dwRead; - HANDLE handle; - LPWSTR ret = NULL; - int i; - - handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, 0 ); - if (handle == INVALID_HANDLE_VALUE) - { - ERR("Unable to open font file %s\n", debugstr_w(filename)); - return NULL; - } - - if (!ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),&dwRead,NULL)) - goto end; - - ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables); - ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion); - ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion); - - if ((ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0) && - (ttOffsetTable.uMajorVersion != 0x4f54 || ttOffsetTable.uMinorVersion != 0x544f)) - goto end; - - for (i=0; i< ttOffsetTable.uNumOfTables; i++) - { - if (!ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),&dwRead,NULL)) - break; - if (memcmp(tblDir.szTag,"name",4)==0) - { - bFound = TRUE; - tblDir.uLength = SWAPLONG(tblDir.uLength); - tblDir.uOffset = SWAPLONG(tblDir.uOffset); - break; - } - } - - if (!bFound) - goto end; - - SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN); - if (!ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER), &dwRead,NULL)) - goto end; - - ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount); - ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset); - for(i=0; i<ttNTHeader.uNRCount; i++) - { - if (!ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),&dwRead,NULL)) - break; - - ttRecord.uNameID = SWAPWORD(ttRecord.uNameID); - ttRecord.uPlatformID = SWAPWORD(ttRecord.uPlatformID); - ttRecord.uEncodingID = SWAPWORD(ttRecord.uEncodingID); - if (ttRecord.uNameID == id && ttRecord.uPlatformID == 3 && - (ttRecord.uEncodingID == 0 || ttRecord.uEncodingID == 1)) - { - WCHAR *buf; - unsigned int i; - - ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength); - ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset); - SetFilePointer(handle, tblDir.uOffset + ttRecord.uStringOffset + ttNTHeader.uStorageOffset, - NULL, FILE_BEGIN); - if (!(buf = msi_alloc_zero( ttRecord.uStringLength + sizeof(WCHAR) ))) goto end; - dwRead = 0; - ReadFile(handle, buf, ttRecord.uStringLength, &dwRead, NULL); - if (dwRead % sizeof(WCHAR)) - { - msi_free(buf); - goto end; - } - for (i = 0; i < dwRead / sizeof(WCHAR); i++) buf[i] = SWAPWORD(buf[i]); - ret = strdupW(buf); - msi_free(buf); - break; - } - } - -end: - CloseHandle(handle); - TRACE("Returning %s\n", debugstr_w(ret)); - return ret; -} - -static WCHAR *font_name_from_file( const WCHAR *filename ) -{ - static const WCHAR truetypeW[] = {' ','(','T','r','u','e','T','y','p','e',')',0}; - WCHAR *name, *ret = NULL; - - if ((name = load_ttf_name_id( filename, NAME_ID_FULL_FONT_NAME ))) - { - if (!name[0]) - { - WARN("empty font name\n"); - msi_free( name ); - return NULL; - } - ret = msi_alloc( (strlenW( name ) + strlenW( truetypeW ) + 1 ) * sizeof(WCHAR) ); - strcpyW( ret, name ); - strcatW( ret, truetypeW ); - msi_free( name ); - } - return ret; -} - -WCHAR *msi_font_version_from_file( const WCHAR *filename ) -{ - static const WCHAR fmtW[] = {'%','u','.','%','u','.','0','.','0',0}; - WCHAR *version, *p, *q, *ret = NULL; - - if ((version = load_ttf_name_id( filename, NAME_ID_VERSION ))) - { - int len, major = 0, minor = 0; - if ((p = strchrW( version, ';' ))) *p = 0; - p = version; - while (*p && !isdigitW( *p )) p++; - if ((q = strchrW( p, '.' ))) - { - major = atoiW( p ); - p = ++q; - while (*q && isdigitW( *q )) q++; - if (!*q || *q == ' ') minor = atoiW( p ); - else major = 0; - } - len = strlenW( fmtW ) + 20; - ret = msi_alloc( len * sizeof(WCHAR) ); - sprintfW( ret, fmtW, major, minor ); - msi_free( version ); - } - return ret; -} - -static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param) -{ - MSIPACKAGE *package = param; - LPWSTR name; - LPCWSTR filename; - MSIFILE *file; - MSICOMPONENT *comp; - HKEY hkey1, hkey2; - MSIRECORD *uirow; - LPWSTR uipath, p; - - filename = MSI_RecordGetString( row, 1 ); - file = msi_get_loaded_file( package, filename ); - if (!file) - { - WARN("unable to find file %s\n", debugstr_w(filename)); - return ERROR_SUCCESS; - } - comp = msi_get_loaded_component( package, file->Component->Component ); - if (!comp) - { - WARN("unable to find component %s\n", debugstr_w(file->Component->Component)); - return ERROR_SUCCESS; - } - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_LOCAL) - { - TRACE("component not scheduled for installation %s\n", debugstr_w(comp->Component)); - return ERROR_SUCCESS; - } - - RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1); - RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2); - - if (MSI_RecordIsNull(row,2)) - name = font_name_from_file( file->TargetPath ); - else - name = msi_dup_record_field(row,2); - - if (name) - { - msi_reg_set_val_str( hkey1, name, file->TargetPath); - msi_reg_set_val_str( hkey2, name, file->TargetPath); - } - - msi_free(name); - RegCloseKey(hkey1); - RegCloseKey(hkey2); - - /* the UI chunk */ - uirow = MSI_CreateRecord( 1 ); - uipath = strdupW( file->TargetPath ); - p = strrchrW(uipath,'\\'); - if (p) p++; - else p = uipath; - MSI_RecordSetStringW( uirow, 1, p ); - msi_ui_actiondata( package, szRegisterFonts, uirow ); - msiobj_release( &uirow->hdr ); - msi_free( uipath ); - /* FIXME: call msi_ui_progress? */ - - return ERROR_SUCCESS; -} - -UINT ACTION_RegisterFonts(MSIPACKAGE *package) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','F','o','n','t','`',0}; - MSIQUERY *view; - UINT rc; - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package); - msiobj_release(&view->hdr); - return rc; -} - -static UINT ITERATE_UnregisterFonts( MSIRECORD *row, LPVOID param ) -{ - MSIPACKAGE *package = param; - LPWSTR name; - LPCWSTR filename; - MSIFILE *file; - MSICOMPONENT *comp; - HKEY hkey1, hkey2; - MSIRECORD *uirow; - LPWSTR uipath, p; - - filename = MSI_RecordGetString( row, 1 ); - file = msi_get_loaded_file( package, filename ); - if (!file) - { - WARN("unable to find file %s\n", debugstr_w(filename)); - return ERROR_SUCCESS; - } - comp = msi_get_loaded_component( package, file->Component->Component ); - if (!comp) - { - WARN("unable to find component %s\n", debugstr_w(file->Component->Component)); - return ERROR_SUCCESS; - } - comp->Action = msi_get_component_action( package, comp ); - if (comp->Action != INSTALLSTATE_ABSENT) - { - TRACE("component not scheduled for removal %s\n", debugstr_w(comp->Component)); - return ERROR_SUCCESS; - } - - RegCreateKeyW( HKEY_LOCAL_MACHINE, regfont1, &hkey1 ); - RegCreateKeyW( HKEY_LOCAL_MACHINE, regfont2, &hkey2 ); - - if (MSI_RecordIsNull( row, 2 )) - name = font_name_from_file( file->TargetPath ); - else - name = msi_dup_record_field( row, 2 ); - - if (name) - { - RegDeleteValueW( hkey1, name ); - RegDeleteValueW( hkey2, name ); - } - - msi_free( name ); - RegCloseKey( hkey1 ); - RegCloseKey( hkey2 ); - - /* the UI chunk */ - uirow = MSI_CreateRecord( 1 ); - uipath = strdupW( file->TargetPath ); - p = strrchrW( uipath,'\\' ); - if (p) p++; - else p = uipath; - MSI_RecordSetStringW( uirow, 1, p ); - msi_ui_actiondata( package, szUnregisterFonts, uirow ); - msiobj_release( &uirow->hdr ); - msi_free( uipath ); - /* FIXME: call msi_ui_progress? */ - - return ERROR_SUCCESS; -} - -UINT ACTION_UnregisterFonts( MSIPACKAGE *package ) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','F','o','n','t','`',0}; - MSIQUERY *view; - UINT r; - - r = MSI_DatabaseOpenViewW( package->db, query, &view ); - if (r != ERROR_SUCCESS) - return ERROR_SUCCESS; - - r = MSI_IterateRecords( view, NULL, ITERATE_UnregisterFonts, package ); - msiobj_release( &view->hdr ); - return r; -} diff --git a/libmsi/format.c b/libmsi/format.c deleted file mode 100644 index c61fbd7..0000000 --- a/libmsi/format.c +++ /dev/null @@ -1,1012 +0,0 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2005 Mike McCormack for CodeWeavers - * Copyright 2005 Aric Stewart for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include <stdarg.h> -#include <stdio.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wine/debug.h" -#include "msi.h" -#include "winnls.h" -#include "objbase.h" -#include "oleauto.h" - -#include "msipriv.h" -#include "msiserver.h" -#include "wine/unicode.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -/* types arranged by precedence */ -#define FORMAT_NULL 0x0001 -#define FORMAT_LITERAL 0x0002 -#define FORMAT_NUMBER 0x0004 -#define FORMAT_LBRACK 0x0010 -#define FORMAT_LBRACE 0x0020 -#define FORMAT_RBRACK 0x0011 -#define FORMAT_RBRACE 0x0021 -#define FORMAT_ESCAPE 0x0040 -#define FORMAT_PROPNULL 0x0080 -#define FORMAT_ERROR 0x1000 -#define FORMAT_FAIL 0x2000 - -#define left_type(x) (x & 0xF0) - -typedef struct _tagFORMAT -{ - MSIPACKAGE *package; - MSIRECORD *record; - LPWSTR deformatted; - int len; - int n; - BOOL propfailed; - BOOL groupfailed; - int groups; -} FORMAT; - -typedef struct _tagFORMSTR -{ - struct list entry; - int n; - int len; - int type; - BOOL propfound; - BOOL nonprop; -} FORMSTR; - -typedef struct _tagSTACK -{ - struct list items; -} STACK; - -static STACK *create_stack(void) -{ - STACK *stack = msi_alloc(sizeof(STACK)); - list_init(&stack->items); - return stack; -} - -static void free_stack(STACK *stack) -{ - while (!list_empty(&stack->items)) - { - FORMSTR *str = LIST_ENTRY(list_head(&stack->items), FORMSTR, entry); - list_remove(&str->entry); - msi_free(str); - } - - msi_free(stack); -} - -static void stack_push(STACK *stack, FORMSTR *str) -{ - list_add_head(&stack->items, &str->entry); -} - -static FORMSTR *stack_pop(STACK *stack) -{ - FORMSTR *ret; - - if (list_empty(&stack->items)) - return NULL; - - ret = LIST_ENTRY(list_head(&stack->items), FORMSTR, entry); - list_remove(&ret->entry); - return ret; -} - -static FORMSTR *stack_find(STACK *stack, int type) -{ - FORMSTR *str; - - LIST_FOR_EACH_ENTRY(str, &stack->items, FORMSTR, entry) - { - if (str->type == type) - return str; - } - - return NULL; -} - -static FORMSTR *stack_peek(STACK *stack) -{ - return LIST_ENTRY(list_head(&stack->items), FORMSTR, entry); -} - -static LPCWSTR get_formstr_data(FORMAT *format, FORMSTR *str) -{ - return &format->deformatted[str->n]; -} - -static LPWSTR dup_formstr(FORMAT *format, FORMSTR *str) -{ - LPWSTR val; - LPCWSTR data; - - if (str->len == 0) - return NULL; - - val = msi_alloc((str->len + 1) * sizeof(WCHAR)); - data = get_formstr_data(format, str); - lstrcpynW(val, data, str->len + 1); - - return val; -} - -static LPWSTR deformat_index(FORMAT *format, FORMSTR *str) -{ - LPWSTR val, ret; - - val = msi_alloc((str->len + 1) * sizeof(WCHAR)); - lstrcpynW(val, get_formstr_data(format, str), str->len + 1); - - ret = msi_dup_record_field(format->record, atoiW(val)); - - msi_free(val); - return ret; -} - -static LPWSTR deformat_property(FORMAT *format, FORMSTR *str) -{ - LPWSTR val, ret; - - val = msi_alloc((str->len + 1) * sizeof(WCHAR)); - lstrcpynW(val, get_formstr_data(format, str), str->len + 1); - - ret = msi_dup_property(format->package->db, val); - - msi_free(val); - return ret; -} - -static LPWSTR deformat_component(FORMAT *format, FORMSTR *str) -{ - LPWSTR key, ret = NULL; - MSICOMPONENT *comp; - - key = msi_alloc((str->len + 1) * sizeof(WCHAR)); - lstrcpynW(key, get_formstr_data(format, str), str->len + 1); - - comp = msi_get_loaded_component(format->package, key); - if (!comp) - goto done; - - if (comp->Action == INSTALLSTATE_SOURCE) - ret = msi_resolve_source_folder( format->package, comp->Directory, NULL ); - else - ret = strdupW( msi_get_target_folder( format->package, comp->Directory ) ); - -done: - msi_free(key); - return ret; -} - -static LPWSTR deformat_file(FORMAT *format, FORMSTR *str, BOOL shortname) -{ - LPWSTR key, ret = NULL; - MSIFILE *file; - DWORD size; - - key = msi_alloc((str->len + 1) * sizeof(WCHAR)); - lstrcpynW(key, get_formstr_data(format, str), str->len + 1); - - file = msi_get_loaded_file(format->package, key); - if (!file) - goto done; - - if (!shortname) - { - ret = strdupW(file->TargetPath); - goto done; - } - - size = GetShortPathNameW(file->TargetPath, NULL, 0); - if (size <= 0) - { - ret = strdupW(file->TargetPath); - goto done; - } - - size++; - ret = msi_alloc(size * sizeof(WCHAR)); - GetShortPathNameW(file->TargetPath, ret, size); - -done: - msi_free(key); - return ret; -} - -static LPWSTR deformat_environment(FORMAT *format, FORMSTR *str) -{ - LPWSTR key, ret = NULL; - DWORD sz; - - key = msi_alloc((str->len + 1) * sizeof(WCHAR)); - lstrcpynW(key, get_formstr_data(format, str), str->len + 1); - - sz = GetEnvironmentVariableW(key, NULL ,0); - if (sz <= 0) - goto done; - - sz++; - ret = msi_alloc(sz * sizeof(WCHAR)); - GetEnvironmentVariableW(key, ret, sz); - -done: - msi_free(key); - return ret; -} - -static LPWSTR deformat_literal(FORMAT *format, FORMSTR *str, BOOL *propfound, - BOOL *nonprop, int *type) -{ - LPCWSTR data = get_formstr_data(format, str); - LPWSTR replaced = NULL; - char ch = data[0]; - - if (ch == '\\') - { - str->n++; - if (str->len == 1) - { - str->len = 0; - replaced = NULL; - } - else - { - str->len = 1; - replaced = dup_formstr(format, str); - } - } - else if (ch == '~') - { - if (str->len != 1) - replaced = NULL; - else - { - replaced = msi_alloc(sizeof(WCHAR)); - *replaced = '\0'; - } - } - else if (ch == '%' || ch == '#' || ch == '!' || ch == '$') - { - str->n++; - str->len--; - - switch (ch) - { - case '%': - replaced = deformat_environment(format, str); break; - case '#': - replaced = deformat_file(format, str, FALSE); break; - case '!': - replaced = deformat_file(format, str, TRUE); break; - case '$': - replaced = deformat_component(format, str); break; - } - - *type = FORMAT_LITERAL; - } - else - { - replaced = deformat_property(format, str); - *type = FORMAT_LITERAL; - - if (replaced) - *propfound = TRUE; - else - format->propfailed = TRUE; - } - - return replaced; -} - -static LPWSTR build_default_format(const MSIRECORD* record) -{ - int i; - int count; - LPWSTR rc, buf; - static const WCHAR fmt[] = {'%','i',':',' ','%','s',' ',0}; - static const WCHAR fmt_null[] = {'%','i',':',' ',' ',0}; - static const WCHAR fmt_index[] = {'%','i',0}; - LPCWSTR str; - WCHAR index[10]; - DWORD size, max_len, len; - - count = MSI_RecordGetFieldCount(record); - - max_len = MAX_PATH; - buf = msi_alloc((max_len + 1) * sizeof(WCHAR)); - - rc = NULL; - size = 1; - for (i = 1; i <= count; i++) - { - sprintfW(index, fmt_index, i); - str = MSI_RecordGetString(record, i); - len = (str) ? lstrlenW(str) : 0; - len += (sizeof(fmt_null)/sizeof(fmt_null[0]) - 3) + lstrlenW(index); - size += len; - - if (len > max_len) - { - max_len = len; - buf = msi_realloc(buf, (max_len + 1) * sizeof(WCHAR)); - if (!buf) return NULL; - } - - if (str) - sprintfW(buf, fmt, i, str); - else - sprintfW(buf, fmt_null, i); - - if (!rc) - { - rc = msi_alloc(size * sizeof(WCHAR)); - lstrcpyW(rc, buf); - } - else - { - rc = msi_realloc(rc, size * sizeof(WCHAR)); - lstrcatW(rc, buf); - } - } - - msi_free(buf); - return rc; -} - -static BOOL format_is_number(WCHAR x) -{ - return ((x >= '0') && (x <= '9')); -} - -static BOOL format_str_is_number(LPWSTR str) -{ - LPWSTR ptr; - - for (ptr = str; *ptr; ptr++) - if (!format_is_number(*ptr)) - return FALSE; - - return TRUE; -} - -static BOOL format_is_alpha(WCHAR x) -{ - return (!format_is_number(x) && x != '\0' && - x != '[' && x != ']' && x != '{' && x != '}'); -} - -static BOOL format_is_literal(WCHAR x) -{ - return (format_is_alpha(x) || format_is_number(x)); -} - -static int format_lex(FORMAT *format, FORMSTR **out) -{ - int type, len = 1; - FORMSTR *str; - LPCWSTR data; - WCHAR ch; - - *out = NULL; - - if (!format->deformatted) - return FORMAT_NULL; - - *out = msi_alloc_zero(sizeof(FORMSTR)); - if (!*out) - return FORMAT_FAIL; - - str = *out; - str->n = format->n; - str->len = 1; - data = get_formstr_data(format, str); - - ch = data[0]; - switch (ch) - { - case '{': type = FORMAT_LBRACE; break; - case '}': type = FORMAT_RBRACE; break; - case '[': type = FORMAT_LBRACK; break; - case ']': type = FORMAT_RBRACK; break; - case '~': type = FORMAT_PROPNULL; break; - case '\0': type = FORMAT_NULL; break; - - default: - type = 0; - } - - if (type) - { - str->type = type; - format->n++; - return type; - } - - if (ch == '\\') - { - while (data[len] && data[len] != ']') - len++; - - type = FORMAT_ESCAPE; - } - else if (format_is_alpha(ch)) - { - while (format_is_literal(data[len])) - len++; - - type = FORMAT_LITERAL; - } - else if (format_is_number(ch)) - { - while (format_is_number(data[len])) - len++; - - type = FORMAT_NUMBER; - - if (data[len] != ']') - { - while (format_is_literal(data[len])) - len++; - - type = FORMAT_LITERAL; - } - } - else - { - ERR("Got unknown character %c(%x)\n", ch, ch); - return FORMAT_ERROR; - } - - format->n += len; - str->len = len; - str->type = type; - - return type; -} - -static FORMSTR *format_replace(FORMAT *format, BOOL propfound, BOOL nonprop, - int oldsize, int type, LPWSTR replace) -{ - FORMSTR *ret; - LPWSTR str, ptr; - DWORD size = 0; - int n; - - if (replace) - { - if (!*replace) - size = 1; - else - size = lstrlenW(replace); - } - - size -= oldsize; - size = format->len + size + 1; - - if (size <= 1) - { - msi_free(format->deformatted); - format->deformatted = NULL; - format->len = 0; - return NULL; - } - - str = msi_alloc(size * sizeof(WCHAR)); - if (!str) - return NULL; - - str[0] = '\0'; - memcpy(str, format->deformatted, format->n * sizeof(WCHAR)); - n = format->n; - - if (replace) - { - if (!*replace) - { - str[n] = '\0'; - n++; - } - else - { - lstrcpyW(&str[n], replace); - n += lstrlenW(replace); - } - } - - ptr = &format->deformatted[format->n + oldsize]; - memcpy(&str[n], ptr, (lstrlenW(ptr) + 1) * sizeof(WCHAR)); - - msi_free(format->deformatted); - format->deformatted = str; - format->len = size - 1; - - /* don't reformat the NULL */ - if (replace && !*replace) - format->n++; - - if (!replace) - return NULL; - - ret = msi_alloc_zero(sizeof(FORMSTR)); - if (!ret) - return NULL; - - ret->len = lstrlenW(replace); - ret->type = type; - ret->n = format->n; - ret->propfound = propfound; - ret->nonprop = nonprop; - - return ret; -} - -static LPWSTR replace_stack_group(FORMAT *format, STACK *values, - BOOL *propfound, BOOL *nonprop, - int *oldsize, int *type) -{ - LPWSTR replaced = NULL; - FORMSTR *content; - FORMSTR *node; - int n; - - *nonprop = FALSE; - *propfound = FALSE; - - node = stack_pop(values); - n = node->n; - *oldsize = node->len; - msi_free(node); - - while ((node = stack_pop(values))) - { - *oldsize += node->len; - - if (node->nonprop) - *nonprop = TRUE; - - if (node->propfound) - *propfound = TRUE; - - msi_free(node); - } - - content = msi_alloc_zero(sizeof(FORMSTR)); - content->n = n; - content->len = *oldsize; - content->type = FORMAT_LITERAL; - - if (!format->groupfailed && (*oldsize == 2 || - (format->propfailed && !*nonprop))) - { - msi_free(content); - return NULL; - } - else if (format->deformatted[content->n + 1] == '{' && - format->deformatted[content->n + content->len - 2] == '}') - { - format->groupfailed = FALSE; - content->len = 0; - } - else if (*propfound && !*nonprop && - !format->groupfailed && format->groups == 0) - { - content->n++; - content->len -= 2; - } - else - { - if (format->groups != 0) - format->groupfailed = TRUE; - - *nonprop = TRUE; - } - - replaced = dup_formstr(format, content); - *type = content->type; - msi_free(content); - - if (format->groups == 0) - format->propfailed = FALSE; - - return replaced; -} - -static LPWSTR replace_stack_prop(FORMAT *format, STACK *values, - BOOL *propfound, BOOL *nonprop, - int *oldsize, int *type) -{ - LPWSTR replaced = NULL; - FORMSTR *content; - FORMSTR *node; - int n; - - *propfound = FALSE; - *nonprop = FALSE; - - node = stack_pop(values); - n = node->n; - *oldsize = node->len; - *type = stack_peek(values)->type; - msi_free(node); - - while ((node = stack_pop(values))) - { - *oldsize += node->len; - - if (*type != FORMAT_ESCAPE && - stack_peek(values) && node->type != *type) - *type = FORMAT_LITERAL; - - msi_free(node); - } - - content = msi_alloc_zero(sizeof(FORMSTR)); - content->n = n + 1; - content->len = *oldsize - 2; - content->type = *type; - - if (*type == FORMAT_NUMBER) - { - replaced = deformat_index(format, content); - if (replaced) - *propfound = TRUE; - else - format->propfailed = TRUE; - - if (replaced) - *type = format_str_is_number(replaced) ? - FORMAT_NUMBER : FORMAT_LITERAL; - } - else if (format->package) - { - replaced = deformat_literal(format, content, propfound, nonprop, type); - } - else - { - *nonprop = TRUE; - content->n--; - content->len += 2; - replaced = dup_formstr(format, content); - } - - msi_free(content); - return replaced; -} - -static UINT replace_stack(FORMAT *format, STACK *stack, STACK *values) -{ - LPWSTR replaced = NULL; - FORMSTR *beg; - FORMSTR *top; - FORMSTR *node; - BOOL propfound = FALSE; - BOOL nonprop = FALSE; - BOOL group = FALSE; - int oldsize = 0; - int type, n; - - node = stack_peek(values); - type = node->type; - n = node->n; - - if (type == FORMAT_LBRACK) - replaced = replace_stack_prop(format, values, &propfound, - &nonprop, &oldsize, &type); - else if (type == FORMAT_LBRACE) - { - replaced = replace_stack_group(format, values, &propfound, - &nonprop, &oldsize, &type); - group = TRUE; - } - - format->n = n; - beg = format_replace(format, propfound, nonprop, oldsize, type, replaced); - if (!beg) - return ERROR_SUCCESS; - - msi_free(replaced); - format->n = beg->n + beg->len; - - top = stack_peek(stack); - if (top) - { - type = top->type; - - if ((type == FORMAT_LITERAL || type == FORMAT_NUMBER) && - type == beg->type) - { - top->len += beg->len; - - if (group) - top->nonprop = FALSE; - - if (type == FORMAT_LITERAL) - top->nonprop = beg->nonprop; - - if (beg->propfound) - top->propfound = TRUE; - - msi_free(beg); - return ERROR_SUCCESS; - } - } - - stack_push(stack, beg); - return ERROR_SUCCESS; -} - -static BOOL verify_format(LPWSTR data) -{ - int count = 0; - - while (*data) - { - if (*data == '[' && *(data - 1) != '\\') - count++; - else if (*data == ']') - count--; - - data++; - } - - if (count > 0) - return FALSE; - - return TRUE; -} - -static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, - WCHAR** data, DWORD *len, - MSIRECORD* record, INT* failcount) -{ - FORMAT format; - FORMSTR *str = NULL; - STACK *stack, *temp; - FORMSTR *node; - int type; - - if (!ptr) - { - *data = NULL; - *len = 0; - return ERROR_SUCCESS; - } - - *data = strdupW(ptr); - *len = lstrlenW(ptr); - - ZeroMemory(&format, sizeof(FORMAT)); - format.package = package; - format.record = record; - format.deformatted = *data; - format.len = *len; - - if (!verify_format(*data)) - return ERROR_SUCCESS; - - stack = create_stack(); - temp = create_stack(); - - while ((type = format_lex(&format, &str)) != FORMAT_NULL) - { - if (type == FORMAT_LBRACK || type == FORMAT_LBRACE || - type == FORMAT_LITERAL || type == FORMAT_NUMBER || - type == FORMAT_ESCAPE || type == FORMAT_PROPNULL) - { - if (type == FORMAT_LBRACE) - { - format.propfailed = FALSE; - format.groups++; - } - else if (type == FORMAT_ESCAPE && - !stack_find(stack, FORMAT_LBRACK)) - { - format.n -= str->len - 1; - str->len = 1; - } - - stack_push(stack, str); - } - else if (type == FORMAT_RBRACK || type == FORMAT_RBRACE) - { - if (type == FORMAT_RBRACE) - format.groups--; - - stack_push(stack, str); - - if (stack_find(stack, left_type(type))) - { - do - { - node = stack_pop(stack); - stack_push(temp, node); - } while (node->type != left_type(type)); - - replace_stack(&format, stack, temp); - } - } - } - - *data = format.deformatted; - *len = format.len; - - msi_free(str); - free_stack(stack); - free_stack(temp); - - return ERROR_SUCCESS; -} - -UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer, - LPDWORD size ) -{ - LPWSTR deformated; - LPWSTR rec; - DWORD len; - UINT rc = ERROR_INVALID_PARAMETER; - - TRACE("%p %p %p %p\n", package, record, buffer, size); - - rec = msi_dup_record_field(record,0); - if (!rec) - rec = build_default_format(record); - - TRACE("(%s)\n",debugstr_w(rec)); - - deformat_string_internal(package, rec, &deformated, &len, record, NULL); - if (buffer) - { - if (*size>len) - { - memcpy(buffer,deformated,len*sizeof(WCHAR)); - rc = ERROR_SUCCESS; - buffer[len] = 0; - } - else - { - if (*size > 0) - { - memcpy(buffer,deformated,(*size)*sizeof(WCHAR)); - buffer[(*size)-1] = 0; - } - rc = ERROR_MORE_DATA; - } - } - else - rc = ERROR_SUCCESS; - - *size = len; - - msi_free(rec); - msi_free(deformated); - return rc; -} - -UINT WINAPI MsiFormatRecordW( MSIHANDLE hInstall, MSIHANDLE hRecord, - LPWSTR szResult, LPDWORD sz ) -{ - UINT r = ERROR_INVALID_HANDLE; - MSIPACKAGE *package; - MSIRECORD *record; - - TRACE("%d %d %p %p\n", hInstall, hRecord, szResult, sz); - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); - if (!package) - return ERROR_INVALID_HANDLE; - record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD ); - - if (!record) - return ERROR_INVALID_HANDLE; - if (!sz) - { - msiobj_release( &record->hdr ); - if (szResult) - return ERROR_INVALID_PARAMETER; - else - return ERROR_SUCCESS; - } - - r = MSI_FormatRecordW( package, record, szResult, sz ); - msiobj_release( &record->hdr ); - if (package) - msiobj_release( &package->hdr ); - return r; -} - -UINT WINAPI MsiFormatRecordA( MSIHANDLE hInstall, MSIHANDLE hRecord, - LPSTR szResult, LPDWORD sz ) -{ - UINT r; - DWORD len, save; - LPWSTR value; - - TRACE("%d %d %p %p\n", hInstall, hRecord, szResult, sz); - - if (!hRecord) - return ERROR_INVALID_HANDLE; - - if (!sz) - { - if (szResult) - return ERROR_INVALID_PARAMETER; - else - return ERROR_SUCCESS; - } - - r = MsiFormatRecordW( hInstall, hRecord, NULL, &len ); - if (r != ERROR_SUCCESS) - return r; - - value = msi_alloc(++len * sizeof(WCHAR)); - if (!value) - return ERROR_OUTOFMEMORY; - - r = MsiFormatRecordW( hInstall, hRecord, value, &len ); - if (r != ERROR_SUCCESS) - goto done; - - save = len + 1; - len = WideCharToMultiByte(CP_ACP, 0, value, len + 1, NULL, 0, NULL, NULL); - WideCharToMultiByte(CP_ACP, 0, value, len, szResult, *sz, NULL, NULL); - - if (szResult && len > *sz) - { - if (*sz) szResult[*sz - 1] = '\0'; - r = ERROR_MORE_DATA; - } - - *sz = save - 1; - -done: - msi_free(value); - return r; -} - -/* wrapper to resist a need for a full rewrite right now */ -DWORD deformat_string( MSIPACKAGE *package, const WCHAR *ptr, WCHAR **data ) -{ - if (ptr) - { - DWORD size = 0; - MSIRECORD *rec = MSI_CreateRecord( 1 ); - - MSI_RecordSetStringW( rec, 0, ptr ); - MSI_FormatRecordW( package, rec, NULL, &size ); - - size++; - *data = msi_alloc( size * sizeof(WCHAR) ); - if (size > 1) MSI_FormatRecordW( package, rec, *data, &size ); - else *data[0] = 0; - - msiobj_release( &rec->hdr ); - return size * sizeof(WCHAR); - } - *data = NULL; - return 0; -} diff --git a/libmsi/instabsent.bmp b/libmsi/instabsent.bmp Binary files differdeleted file mode 100644 index 9347961..0000000 --- a/libmsi/instabsent.bmp +++ /dev/null diff --git a/libmsi/instadvert.bmp b/libmsi/instadvert.bmp Binary files differdeleted file mode 100644 index 77b5309..0000000 --- a/libmsi/instadvert.bmp +++ /dev/null diff --git a/libmsi/install.c b/libmsi/install.c deleted file mode 100644 index 0cf25a8..0000000 --- a/libmsi/install.c +++ /dev/null @@ -1,1307 +0,0 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2005 Aric Stewart for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/* Msi top level apis directly related to installs */ - -#define COBJMACROS - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wine/debug.h" -#include "msi.h" -#include "msidefs.h" -#include "objbase.h" -#include "oleauto.h" - -#include "msipriv.h" -#include "msiserver.h" -#include "wine/unicode.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -/*********************************************************************** - * MsiDoActionA (MSI.@) - */ -UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction ) -{ - LPWSTR szwAction; - UINT ret; - - TRACE("%s\n", debugstr_a(szAction)); - - szwAction = strdupAtoW(szAction); - if (szAction && !szwAction) - return ERROR_FUNCTION_FAILED; - - ret = MsiDoActionW( hInstall, szwAction ); - msi_free( szwAction ); - return ret; -} - -/*********************************************************************** - * MsiDoActionW (MSI.@) - */ -UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction ) -{ - MSIPACKAGE *package; - UINT ret; - - TRACE("%s\n",debugstr_w(szAction)); - - if (!szAction) - return ERROR_INVALID_PARAMETER; - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); - if (!package) - return ERROR_INVALID_HANDLE; - ret = ACTION_PerformUIAction( package, szAction, SCRIPT_NONE ); - msiobj_release( &package->hdr ); - - return ret; -} - -/*********************************************************************** - * MsiSequenceA (MSI.@) - */ -UINT WINAPI MsiSequenceA( MSIHANDLE hInstall, LPCSTR szTable, INT iSequenceMode ) -{ - LPWSTR szwTable; - UINT ret; - - TRACE("%s, %d\n", debugstr_a(szTable), iSequenceMode); - - szwTable = strdupAtoW(szTable); - if (szTable && !szwTable) - return ERROR_FUNCTION_FAILED; - - ret = MsiSequenceW( hInstall, szwTable, iSequenceMode ); - msi_free( szwTable ); - return ret; -} - -/*********************************************************************** - * MsiSequenceW (MSI.@) - */ -UINT WINAPI MsiSequenceW( MSIHANDLE hInstall, LPCWSTR szTable, INT iSequenceMode ) -{ - MSIPACKAGE *package; - UINT ret; - - TRACE("%s, %d\n", debugstr_w(szTable), iSequenceMode); - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); - if (!package) - return ERROR_INVALID_HANDLE; - ret = MSI_Sequence( package, szTable ); - msiobj_release( &package->hdr ); - return ret; -} - -UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz ) -{ - UINT len, r = ERROR_SUCCESS; - - if (awbuf->str.w && !sz ) - return ERROR_INVALID_PARAMETER; - - if (!sz) - return r; - - if (awbuf->unicode) - { - len = lstrlenW( str ); - if (awbuf->str.w) - lstrcpynW( awbuf->str.w, str, *sz ); - } - else - { - len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL ); - if (len) - len--; - WideCharToMultiByte( CP_ACP, 0, str, -1, awbuf->str.a, *sz, NULL, NULL ); - if ( awbuf->str.a && *sz && (len >= *sz) ) - awbuf->str.a[*sz - 1] = 0; - } - - if (awbuf->str.w && len >= *sz) - r = ERROR_MORE_DATA; - *sz = len; - return r; -} - -const WCHAR *msi_get_target_folder( MSIPACKAGE *package, const WCHAR *name ) -{ - MSIFOLDER *folder = msi_get_loaded_folder( package, name ); - - if (!folder) return NULL; - if (!folder->ResolvedTarget) - { - MSIFOLDER *parent = folder; - while (parent->Parent && strcmpW( parent->Parent, parent->Directory )) - { - parent = msi_get_loaded_folder( package, parent->Parent ); - } - msi_resolve_target_folder( package, parent->Directory, TRUE ); - } - return folder->ResolvedTarget; -} - -/*********************************************************************** - * MsiGetTargetPath (internal) - */ -static UINT MSI_GetTargetPath( MSIHANDLE hInstall, LPCWSTR szFolder, - awstring *szPathBuf, LPDWORD pcchPathBuf ) -{ - MSIPACKAGE *package; - const WCHAR *path; - UINT r = ERROR_FUNCTION_FAILED; - - if (!szFolder) - return ERROR_INVALID_PARAMETER; - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); - if (!package) - return ERROR_INVALID_HANDLE; - path = msi_get_target_folder( package, szFolder ); - msiobj_release( &package->hdr ); - - if (!path) - return ERROR_DIRECTORY; - - r = msi_strcpy_to_awstring( path, szPathBuf, pcchPathBuf ); - return r; -} - -/*********************************************************************** - * MsiGetTargetPathA (MSI.@) - */ -UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder, - LPSTR szPathBuf, LPDWORD pcchPathBuf ) -{ - LPWSTR szwFolder; - awstring path; - UINT r; - - TRACE("%s %p %p\n", debugstr_a(szFolder), szPathBuf, pcchPathBuf); - - szwFolder = strdupAtoW(szFolder); - if (szFolder && !szwFolder) - return ERROR_FUNCTION_FAILED; - - path.unicode = FALSE; - path.str.a = szPathBuf; - - r = MSI_GetTargetPath( hInstall, szwFolder, &path, pcchPathBuf ); - - msi_free( szwFolder ); - - return r; -} - -/*********************************************************************** - * MsiGetTargetPathW (MSI.@) - */ -UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, - LPWSTR szPathBuf, LPDWORD pcchPathBuf ) -{ - awstring path; - - TRACE("%s %p %p\n", debugstr_w(szFolder), szPathBuf, pcchPathBuf); - - path.unicode = TRUE; - path.str.w = szPathBuf; - - return MSI_GetTargetPath( hInstall, szFolder, &path, pcchPathBuf ); -} - -static WCHAR *get_source_root( MSIPACKAGE *package ) -{ - msi_set_sourcedir_props( package, FALSE ); - return msi_dup_property( package->db, szSourceDir ); -} - -WCHAR *msi_resolve_source_folder( MSIPACKAGE *package, const WCHAR *name, MSIFOLDER **folder ) -{ - MSIFOLDER *f; - LPWSTR p, path = NULL, parent; - - TRACE("working to resolve %s\n", debugstr_w(name)); - - if (!strcmpW( name, szSourceDir )) name = szTargetDir; - if (!(f = msi_get_loaded_folder( package, name ))) return NULL; - - /* special resolving for root dir */ - if (!strcmpW( name, szTargetDir ) && !f->ResolvedSource) - { - f->ResolvedSource = get_source_root( package ); - } - if (folder) *folder = f; - if (f->ResolvedSource) - { - path = strdupW( f->ResolvedSource ); - TRACE(" already resolved to %s\n", debugstr_w(path)); - return path; - } - if (!f->Parent) return path; - parent = f->Parent; - TRACE(" ! parent is %s\n", debugstr_w(parent)); - - p = msi_resolve_source_folder( package, parent, NULL ); - - if (package->WordCount & msidbSumInfoSourceTypeCompressed) - path = get_source_root( package ); - else if (package->WordCount & msidbSumInfoSourceTypeSFN) - path = msi_build_directory_name( 3, p, f->SourceShortPath, NULL ); - else - path = msi_build_directory_name( 3, p, f->SourceLongPath, NULL ); - - TRACE("-> %s\n", debugstr_w(path)); - f->ResolvedSource = strdupW( path ); - msi_free( p ); - - return path; -} - -/*********************************************************************** - * MSI_GetSourcePath (internal) - */ -static UINT MSI_GetSourcePath( MSIHANDLE hInstall, LPCWSTR szFolder, - awstring *szPathBuf, LPDWORD pcchPathBuf ) -{ - MSIPACKAGE *package; - LPWSTR path; - UINT r = ERROR_FUNCTION_FAILED; - - TRACE("%s %p %p\n", debugstr_w(szFolder), szPathBuf, pcchPathBuf ); - - if (!szFolder) - return ERROR_INVALID_PARAMETER; - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); - if (!package) - return ERROR_INVALID_HANDLE; - if (szPathBuf->str.w && !pcchPathBuf ) - { - msiobj_release( &package->hdr ); - return ERROR_INVALID_PARAMETER; - } - - path = msi_resolve_source_folder( package, szFolder, NULL ); - msiobj_release( &package->hdr ); - - TRACE("path = %s\n", debugstr_w(path)); - if (!path) - return ERROR_DIRECTORY; - - r = msi_strcpy_to_awstring( path, szPathBuf, pcchPathBuf ); - msi_free( path ); - return r; -} - -/*********************************************************************** - * MsiGetSourcePathA (MSI.@) - */ -UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder, - LPSTR szPathBuf, LPDWORD pcchPathBuf ) -{ - LPWSTR folder; - awstring str; - UINT r; - - TRACE("%s %p %p\n", debugstr_a(szFolder), szPathBuf, pcchPathBuf); - - str.unicode = FALSE; - str.str.a = szPathBuf; - - folder = strdupAtoW( szFolder ); - r = MSI_GetSourcePath( hInstall, folder, &str, pcchPathBuf ); - msi_free( folder ); - - return r; -} - -/*********************************************************************** - * MsiGetSourcePathW (MSI.@) - */ -UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, - LPWSTR szPathBuf, LPDWORD pcchPathBuf ) -{ - awstring str; - - TRACE("%s %p %p\n", debugstr_w(szFolder), szPathBuf, pcchPathBuf ); - - str.unicode = TRUE; - str.str.w = szPathBuf; - - return MSI_GetSourcePath( hInstall, szFolder, &str, pcchPathBuf ); -} - -/*********************************************************************** - * MsiSetTargetPathA (MSI.@) - */ -UINT WINAPI MsiSetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder, - LPCSTR szFolderPath ) -{ - LPWSTR szwFolder = NULL, szwFolderPath = NULL; - UINT rc = ERROR_OUTOFMEMORY; - - if ( !szFolder || !szFolderPath ) - return ERROR_INVALID_PARAMETER; - - szwFolder = strdupAtoW(szFolder); - szwFolderPath = strdupAtoW(szFolderPath); - if (!szwFolder || !szwFolderPath) - goto end; - - rc = MsiSetTargetPathW( hInstall, szwFolder, szwFolderPath ); - -end: - msi_free(szwFolder); - msi_free(szwFolderPath); - - return rc; -} - -static void set_target_path( MSIPACKAGE *package, MSIFOLDER *folder, const WCHAR *path ) -{ - FolderList *fl; - MSIFOLDER *child; - WCHAR *target_path; - - if (!(target_path = msi_normalize_path( path ))) return; - if (strcmpW( target_path, folder->ResolvedTarget )) - { - msi_free( folder->ResolvedTarget ); - folder->ResolvedTarget = target_path; - msi_set_property( package->db, folder->Directory, folder->ResolvedTarget ); - - LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry ) - { - child = fl->folder; - msi_resolve_target_folder( package, child->Directory, FALSE ); - } - } - else msi_free( target_path ); -} - -UINT MSI_SetTargetPathW( MSIPACKAGE *package, LPCWSTR szFolder, LPCWSTR szFolderPath ) -{ - DWORD attrib; - MSIFOLDER *folder; - MSIFILE *file; - - TRACE("%p %s %s\n", package, debugstr_w(szFolder), debugstr_w(szFolderPath)); - - attrib = GetFileAttributesW(szFolderPath); - /* native MSI tests writeability by making temporary files at each drive */ - if (attrib != INVALID_FILE_ATTRIBUTES && - (attrib & FILE_ATTRIBUTE_OFFLINE || attrib & FILE_ATTRIBUTE_READONLY)) - { - return ERROR_FUNCTION_FAILED; - } - if (!(folder = msi_get_loaded_folder( package, szFolder ))) return ERROR_DIRECTORY; - - set_target_path( package, folder, szFolderPath ); - - LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) - { - const WCHAR *dir; - MSICOMPONENT *comp = file->Component; - - if (!comp->Enabled || (comp->assembly && !comp->assembly->application)) continue; - - dir = msi_get_target_folder( package, comp->Directory ); - msi_free( file->TargetPath ); - file->TargetPath = msi_build_directory_name( 2, dir, file->FileName ); - } - return ERROR_SUCCESS; -} - -/*********************************************************************** - * MsiSetTargetPathW (MSI.@) - */ -UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, - LPCWSTR szFolderPath) -{ - MSIPACKAGE *package; - UINT ret; - - TRACE("%s %s\n",debugstr_w(szFolder),debugstr_w(szFolderPath)); - - if ( !szFolder || !szFolderPath ) - return ERROR_INVALID_PARAMETER; - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - ret = MSI_SetTargetPathW( package, szFolder, szFolderPath ); - msiobj_release( &package->hdr ); - return ret; -} - -/*********************************************************************** - * MsiGetMode (MSI.@) - * - * Returns an internal installer state (if it is running in a mode iRunMode) - * - * PARAMS - * hInstall [I] Handle to the installation - * hRunMode [I] Checking run mode - * MSIRUNMODE_ADMIN Administrative mode - * MSIRUNMODE_ADVERTISE Advertisement mode - * MSIRUNMODE_MAINTENANCE Maintenance mode - * MSIRUNMODE_ROLLBACKENABLED Rollback is enabled - * MSIRUNMODE_LOGENABLED Log file is writing - * MSIRUNMODE_OPERATIONS Operations in progress?? - * MSIRUNMODE_REBOOTATEND We need to reboot after installation completed - * MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation - * MSIRUNMODE_CABINET Files from cabinet are installed - * MSIRUNMODE_SOURCESHORTNAMES Long names in source files is suppressed - * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is suppressed - * MSIRUNMODE_RESERVED11 Reserved - * MSIRUNMODE_WINDOWS9X Running under Windows95/98 - * MSIRUNMODE_ZAWENABLED Demand installation is supported - * MSIRUNMODE_RESERVED14 Reserved - * MSIRUNMODE_RESERVED15 Reserved - * MSIRUNMODE_SCHEDULED called from install script - * MSIRUNMODE_ROLLBACK called from rollback script - * MSIRUNMODE_COMMIT called from commit script - * - * RETURNS - * In the state: TRUE - * Not in the state: FALSE - * - */ -BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode) -{ - MSIPACKAGE *package; - BOOL r = FALSE; - - TRACE("%d %d\n", hInstall, iRunMode); - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - - switch (iRunMode) - { - case MSIRUNMODE_ADMIN: - FIXME("no support for administrative installs\n"); - break; - - case MSIRUNMODE_ADVERTISE: - FIXME("no support for advertised installs\n"); - break; - - case MSIRUNMODE_WINDOWS9X: - if (GetVersion() & 0x80000000) - r = TRUE; - break; - - case MSIRUNMODE_OPERATIONS: - case MSIRUNMODE_RESERVED11: - case MSIRUNMODE_RESERVED14: - case MSIRUNMODE_RESERVED15: - break; - - case MSIRUNMODE_SCHEDULED: - r = package->scheduled_action_running; - break; - - case MSIRUNMODE_ROLLBACK: - r = package->rollback_action_running; - break; - - case MSIRUNMODE_COMMIT: - r = package->commit_action_running; - break; - - case MSIRUNMODE_MAINTENANCE: - r = msi_get_property_int( package->db, szInstalled, 0 ) != 0; - break; - - case MSIRUNMODE_ROLLBACKENABLED: - r = msi_get_property_int( package->db, szRollbackDisabled, 0 ) == 0; - break; - - case MSIRUNMODE_REBOOTATEND: - r = package->need_reboot_at_end; - break; - - case MSIRUNMODE_REBOOTNOW: - r = package->need_reboot_now; - break; - - case MSIRUNMODE_LOGENABLED: - r = (package->log_file != INVALID_HANDLE_VALUE); - break; - - default: - FIXME("unimplemented run mode: %d\n", iRunMode); - r = TRUE; - } - - msiobj_release( &package->hdr ); - return r; -} - -/*********************************************************************** - * MsiSetMode (MSI.@) - */ -UINT WINAPI MsiSetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode, BOOL fState) -{ - MSIPACKAGE *package; - UINT r; - - TRACE("%d %d %d\n", hInstall, iRunMode, fState); - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); - if (!package) - return ERROR_INVALID_HANDLE; - switch (iRunMode) - { - case MSIRUNMODE_REBOOTATEND: - package->need_reboot_at_end = (fState != 0); - r = ERROR_SUCCESS; - break; - - case MSIRUNMODE_REBOOTNOW: - package->need_reboot_now = (fState != 0); - r = ERROR_SUCCESS; - break; - - default: - r = ERROR_ACCESS_DENIED; - } - - msiobj_release( &package->hdr ); - return r; -} - -/*********************************************************************** - * MsiSetFeatureStateA (MSI.@) - * - * According to the docs, when this is called it immediately recalculates - * all the component states as well - */ -UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature, - INSTALLSTATE iState) -{ - LPWSTR szwFeature = NULL; - UINT rc; - - szwFeature = strdupAtoW(szFeature); - - if (!szwFeature) - return ERROR_FUNCTION_FAILED; - - rc = MsiSetFeatureStateW(hInstall,szwFeature, iState); - - msi_free(szwFeature); - - return rc; -} - -/* update component state based on a feature change */ -void ACTION_UpdateComponentStates( MSIPACKAGE *package, MSIFEATURE *feature ) -{ - INSTALLSTATE newstate; - ComponentList *cl; - - newstate = feature->ActionRequest; - if (newstate == INSTALLSTATE_ABSENT) newstate = INSTALLSTATE_UNKNOWN; - - LIST_FOR_EACH_ENTRY(cl, &feature->Components, ComponentList, entry) - { - MSICOMPONENT *component = cl->component; - - if (!component->Enabled) continue; - - TRACE("Modifying (%d): Component %s (Installed %d, Action %d, Request %d)\n", - newstate, debugstr_w(component->Component), component->Installed, - component->Action, component->ActionRequest); - - if (newstate == INSTALLSTATE_LOCAL) - { - component->Action = INSTALLSTATE_LOCAL; - component->ActionRequest = INSTALLSTATE_LOCAL; - } - else - { - ComponentList *clist; - MSIFEATURE *f; - - component->hasLocalFeature = FALSE; - - component->Action = newstate; - component->ActionRequest = newstate; - /* if any other feature wants it local we need to set it local */ - LIST_FOR_EACH_ENTRY(f, &package->features, MSIFEATURE, entry) - { - if ( f->ActionRequest != INSTALLSTATE_LOCAL && - f->ActionRequest != INSTALLSTATE_SOURCE ) - { - continue; - } - LIST_FOR_EACH_ENTRY(clist, &f->Components, ComponentList, entry) - { - if (clist->component == component && - (f->ActionRequest == INSTALLSTATE_LOCAL || - f->ActionRequest == INSTALLSTATE_SOURCE)) - { - TRACE("Saved by %s\n", debugstr_w(f->Feature)); - component->hasLocalFeature = TRUE; - - if (component->Attributes & msidbComponentAttributesOptional) - { - if (f->Attributes & msidbFeatureAttributesFavorSource) - { - component->Action = INSTALLSTATE_SOURCE; - component->ActionRequest = INSTALLSTATE_SOURCE; - } - else - { - component->Action = INSTALLSTATE_LOCAL; - component->ActionRequest = INSTALLSTATE_LOCAL; - } - } - else if (component->Attributes & msidbComponentAttributesSourceOnly) - { - component->Action = INSTALLSTATE_SOURCE; - component->ActionRequest = INSTALLSTATE_SOURCE; - } - else - { - component->Action = INSTALLSTATE_LOCAL; - component->ActionRequest = INSTALLSTATE_LOCAL; - } - } - } - } - } - TRACE("Result (%d): Component %s (Installed %d, Action %d, Request %d)\n", - newstate, debugstr_w(component->Component), component->Installed, - component->Action, component->ActionRequest); - } -} - -UINT MSI_SetFeatureStateW( MSIPACKAGE *package, LPCWSTR szFeature, INSTALLSTATE iState ) -{ - UINT rc = ERROR_SUCCESS; - MSIFEATURE *feature, *child; - - TRACE("%s %i\n", debugstr_w(szFeature), iState); - - feature = msi_get_loaded_feature( package, szFeature ); - if (!feature) - return ERROR_UNKNOWN_FEATURE; - - if (iState == INSTALLSTATE_ADVERTISED && - feature->Attributes & msidbFeatureAttributesDisallowAdvertise) - return ERROR_FUNCTION_FAILED; - - feature->ActionRequest = iState; - - ACTION_UpdateComponentStates( package, feature ); - - /* update all the features that are children of this feature */ - LIST_FOR_EACH_ENTRY( child, &package->features, MSIFEATURE, entry ) - { - if (child->Feature_Parent && !strcmpW( szFeature, child->Feature_Parent )) - MSI_SetFeatureStateW(package, child->Feature, iState); - } - - return rc; -} - -/*********************************************************************** - * MsiSetFeatureStateW (MSI.@) - */ -UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature, - INSTALLSTATE iState) -{ - MSIPACKAGE* package; - UINT rc = ERROR_SUCCESS; - - TRACE("%s %i\n",debugstr_w(szFeature), iState); - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - rc = MSI_SetFeatureStateW(package,szFeature,iState); - - msiobj_release( &package->hdr ); - return rc; -} - -/*********************************************************************** -* MsiSetFeatureAttributesA (MSI.@) -*/ -UINT WINAPI MsiSetFeatureAttributesA( MSIHANDLE handle, LPCSTR feature, DWORD attrs ) -{ - UINT r; - WCHAR *featureW = NULL; - - TRACE("%u, %s, 0x%08x\n", handle, debugstr_a(feature), attrs); - - if (feature && !(featureW = strdupAtoW( feature ))) return ERROR_OUTOFMEMORY; - - r = MsiSetFeatureAttributesW( handle, featureW, attrs ); - msi_free( featureW ); - return r; -} - -static DWORD unmap_feature_attributes( DWORD attrs ) -{ - DWORD ret = 0; - - if (attrs & INSTALLFEATUREATTRIBUTE_FAVORLOCAL) ret = msidbFeatureAttributesFavorLocal; - if (attrs & INSTALLFEATUREATTRIBUTE_FAVORSOURCE) ret |= msidbFeatureAttributesFavorSource; - if (attrs & INSTALLFEATUREATTRIBUTE_FOLLOWPARENT) ret |= msidbFeatureAttributesFollowParent; - if (attrs & INSTALLFEATUREATTRIBUTE_FAVORADVERTISE) ret |= msidbFeatureAttributesFavorAdvertise; - if (attrs & INSTALLFEATUREATTRIBUTE_DISALLOWADVERTISE) ret |= msidbFeatureAttributesDisallowAdvertise; - if (attrs & INSTALLFEATUREATTRIBUTE_NOUNSUPPORTEDADVERTISE) ret |= msidbFeatureAttributesNoUnsupportedAdvertise; - return ret; -} - -/*********************************************************************** -* MsiSetFeatureAttributesW (MSI.@) -*/ -UINT WINAPI MsiSetFeatureAttributesW( MSIHANDLE handle, LPCWSTR name, DWORD attrs ) -{ - MSIPACKAGE *package; - MSIFEATURE *feature; - WCHAR *costing; - - TRACE("%u, %s, 0x%08x\n", handle, debugstr_w(name), attrs); - - if (!name || !name[0]) return ERROR_UNKNOWN_FEATURE; - - if (!(package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE ))) - return ERROR_INVALID_HANDLE; - - costing = msi_dup_property( package->db, szCostingComplete ); - if (!costing || !strcmpW( costing, szOne )) - { - msi_free( costing ); - msiobj_release( &package->hdr ); - return ERROR_FUNCTION_FAILED; - } - msi_free( costing ); - if (!(feature = msi_get_loaded_feature( package, name ))) - { - msiobj_release( &package->hdr ); - return ERROR_UNKNOWN_FEATURE; - } - feature->Attributes = unmap_feature_attributes( attrs ); - msiobj_release( &package->hdr ); - return ERROR_SUCCESS; -} - -/*********************************************************************** -* MsiGetFeatureStateA (MSI.@) -*/ -UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature, - INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) -{ - LPWSTR szwFeature = NULL; - UINT rc; - - if (szFeature && !(szwFeature = strdupAtoW(szFeature))) return ERROR_OUTOFMEMORY; - - rc = MsiGetFeatureStateW(hInstall, szwFeature, piInstalled, piAction); - msi_free( szwFeature); - return rc; -} - -UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPCWSTR szFeature, - INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) -{ - MSIFEATURE *feature; - - feature = msi_get_loaded_feature(package,szFeature); - if (!feature) - return ERROR_UNKNOWN_FEATURE; - - if (piInstalled) - *piInstalled = feature->Installed; - - if (piAction) - *piAction = feature->ActionRequest; - - TRACE("returning %i %i\n", feature->Installed, feature->ActionRequest); - - return ERROR_SUCCESS; -} - -/*********************************************************************** -* MsiGetFeatureStateW (MSI.@) -*/ -UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature, - INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) -{ - MSIPACKAGE* package; - UINT ret; - - TRACE("%d %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled, piAction); - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction); - msiobj_release( &package->hdr ); - return ret; -} - -/*********************************************************************** -* MsiGetFeatureCostA (MSI.@) -*/ -UINT WINAPI MsiGetFeatureCostA(MSIHANDLE hInstall, LPCSTR szFeature, - MSICOSTTREE iCostTree, INSTALLSTATE iState, LPINT piCost) -{ - LPWSTR szwFeature = NULL; - UINT rc; - - szwFeature = strdupAtoW(szFeature); - - rc = MsiGetFeatureCostW(hInstall, szwFeature, iCostTree, iState, piCost); - - msi_free(szwFeature); - - return rc; -} - -static INT feature_cost( MSIFEATURE *feature ) -{ - INT cost = 0; - MSICOMPONENT *comp; - - LIST_FOR_EACH_ENTRY( comp, &feature->Components, MSICOMPONENT, entry ) - { - cost += comp->Cost; - } - return cost; -} - -UINT MSI_GetFeatureCost( MSIPACKAGE *package, MSIFEATURE *feature, MSICOSTTREE tree, - INSTALLSTATE state, LPINT cost ) -{ - TRACE("%s, %u, %d, %p\n", debugstr_w(feature->Feature), tree, state, cost); - - *cost = 0; - switch (tree) - { - case MSICOSTTREE_CHILDREN: - { - MSIFEATURE *child; - - LIST_FOR_EACH_ENTRY( child, &feature->Children, MSIFEATURE, entry ) - { - if (child->ActionRequest == state) - *cost += feature_cost( child ); - } - break; - } - case MSICOSTTREE_PARENTS: - { - const WCHAR *feature_parent = feature->Feature_Parent; - for (;;) - { - MSIFEATURE *parent = msi_get_loaded_feature( package, feature_parent ); - if (!parent) - break; - - if (parent->ActionRequest == state) - *cost += feature_cost( parent ); - - feature_parent = parent->Feature_Parent; - } - break; - } - case MSICOSTTREE_SELFONLY: - if (feature->ActionRequest == state) - *cost = feature_cost( feature ); - break; - - default: - WARN("unhandled cost tree %u\n", tree); - break; - } - - *cost /= 512; - return ERROR_SUCCESS; -} - -/*********************************************************************** -* MsiGetFeatureCostW (MSI.@) -*/ -UINT WINAPI MsiGetFeatureCostW(MSIHANDLE hInstall, LPCWSTR szFeature, - MSICOSTTREE iCostTree, INSTALLSTATE iState, LPINT piCost) -{ - MSIPACKAGE *package; - MSIFEATURE *feature; - UINT ret; - - TRACE("(%d %s %i %i %p)\n", hInstall, debugstr_w(szFeature), - iCostTree, iState, piCost); - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - feature = msi_get_loaded_feature(package, szFeature); - - if (feature) - ret = MSI_GetFeatureCost(package, feature, iCostTree, iState, piCost); - else - ret = ERROR_UNKNOWN_FEATURE; - - msiobj_release( &package->hdr ); - return ret; -} - -/*********************************************************************** -* MsiGetFeatureInfoA (MSI.@) -*/ -UINT WINAPI MsiGetFeatureInfoA( MSIHANDLE handle, LPCSTR feature, LPDWORD attrs, - LPSTR title, LPDWORD title_len, LPSTR help, LPDWORD help_len ) -{ - UINT r; - WCHAR *titleW = NULL, *helpW = NULL, *featureW = NULL; - - TRACE("%u, %s, %p, %p, %p, %p, %p\n", handle, debugstr_a(feature), attrs, title, - title_len, help, help_len); - - if (feature && !(featureW = strdupAtoW( feature ))) return ERROR_OUTOFMEMORY; - - if (title && title_len && !(titleW = msi_alloc( *title_len * sizeof(WCHAR) ))) - { - msi_free( featureW ); - return ERROR_OUTOFMEMORY; - } - if (help && help_len && !(helpW = msi_alloc( *help_len * sizeof(WCHAR) ))) - { - msi_free( featureW ); - msi_free( titleW ); - return ERROR_OUTOFMEMORY; - } - r = MsiGetFeatureInfoW( handle, featureW, attrs, titleW, title_len, helpW, help_len ); - if (r == ERROR_SUCCESS) - { - if (titleW) WideCharToMultiByte( CP_ACP, 0, titleW, -1, title, *title_len + 1, NULL, NULL ); - if (helpW) WideCharToMultiByte( CP_ACP, 0, helpW, -1, help, *help_len + 1, NULL, NULL ); - } - msi_free( titleW ); - msi_free( helpW ); - msi_free( featureW ); - return r; -} - -static DWORD map_feature_attributes( DWORD attrs ) -{ - DWORD ret = 0; - - if (attrs == msidbFeatureAttributesFavorLocal) ret |= INSTALLFEATUREATTRIBUTE_FAVORLOCAL; - if (attrs & msidbFeatureAttributesFavorSource) ret |= INSTALLFEATUREATTRIBUTE_FAVORSOURCE; - if (attrs & msidbFeatureAttributesFollowParent) ret |= INSTALLFEATUREATTRIBUTE_FOLLOWPARENT; - if (attrs & msidbFeatureAttributesFavorAdvertise) ret |= INSTALLFEATUREATTRIBUTE_FAVORADVERTISE; - if (attrs & msidbFeatureAttributesDisallowAdvertise) ret |= INSTALLFEATUREATTRIBUTE_DISALLOWADVERTISE; - if (attrs & msidbFeatureAttributesNoUnsupportedAdvertise) ret |= INSTALLFEATUREATTRIBUTE_NOUNSUPPORTEDADVERTISE; - return ret; -} - -static UINT MSI_GetFeatureInfo( MSIPACKAGE *package, LPCWSTR name, LPDWORD attrs, - LPWSTR title, LPDWORD title_len, LPWSTR help, LPDWORD help_len ) -{ - UINT r = ERROR_SUCCESS; - MSIFEATURE *feature = msi_get_loaded_feature( package, name ); - int len; - - if (!feature) return ERROR_UNKNOWN_FEATURE; - if (attrs) *attrs = map_feature_attributes( feature->Attributes ); - if (title_len) - { - if (feature->Title) len = strlenW( feature->Title ); - else len = 0; - if (*title_len <= len) - { - *title_len = len; - if (title) r = ERROR_MORE_DATA; - } - else if (title) - { - if (feature->Title) strcpyW( title, feature->Title ); - else *title = 0; - *title_len = len; - } - } - if (help_len) - { - if (feature->Description) len = strlenW( feature->Description ); - else len = 0; - if (*help_len <= len) - { - *help_len = len; - if (help) r = ERROR_MORE_DATA; - } - else if (help) - { - if (feature->Description) strcpyW( help, feature->Description ); - else *help = 0; - *help_len = len; - } - } - return r; -} - -/*********************************************************************** -* MsiGetFeatureInfoW (MSI.@) -*/ -UINT WINAPI MsiGetFeatureInfoW( MSIHANDLE handle, LPCWSTR feature, LPDWORD attrs, - LPWSTR title, LPDWORD title_len, LPWSTR help, LPDWORD help_len ) -{ - UINT r; - MSIPACKAGE *package; - - TRACE("%u, %s, %p, %p, %p, %p, %p\n", handle, debugstr_w(feature), attrs, title, - title_len, help, help_len); - - if (!feature) return ERROR_INVALID_PARAMETER; - - if (!(package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE ))) - return ERROR_INVALID_HANDLE; - - /* features may not have been loaded yet */ - msi_load_all_components( package ); - msi_load_all_features( package ); - - r = MSI_GetFeatureInfo( package, feature, attrs, title, title_len, help, help_len ); - msiobj_release( &package->hdr ); - return r; -} - -/*********************************************************************** - * MsiSetComponentStateA (MSI.@) - */ -UINT WINAPI MsiSetComponentStateA(MSIHANDLE hInstall, LPCSTR szComponent, - INSTALLSTATE iState) -{ - UINT rc; - LPWSTR szwComponent = strdupAtoW(szComponent); - - rc = MsiSetComponentStateW(hInstall, szwComponent, iState); - - msi_free(szwComponent); - - return rc; -} - -/*********************************************************************** - * MsiGetComponentStateA (MSI.@) - */ -UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPCSTR szComponent, - INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) -{ - LPWSTR szwComponent= NULL; - UINT rc; - - szwComponent= strdupAtoW(szComponent); - - rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction); - - msi_free( szwComponent); - - return rc; -} - -static UINT MSI_SetComponentStateW(MSIPACKAGE *package, LPCWSTR szComponent, - INSTALLSTATE iState) -{ - MSICOMPONENT *comp; - - TRACE("%p %s %d\n", package, debugstr_w(szComponent), iState); - - comp = msi_get_loaded_component(package, szComponent); - if (!comp) - return ERROR_UNKNOWN_COMPONENT; - - if (comp->Enabled) - comp->Action = iState; - - return ERROR_SUCCESS; -} - -UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPCWSTR szComponent, - INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) -{ - MSICOMPONENT *comp; - - TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), - piInstalled, piAction); - - comp = msi_get_loaded_component(package,szComponent); - if (!comp) - return ERROR_UNKNOWN_COMPONENT; - - if (piInstalled) - { - if (comp->Enabled) - *piInstalled = comp->Installed; - else - *piInstalled = INSTALLSTATE_UNKNOWN; - } - - if (piAction) - { - if (comp->Enabled) - *piAction = comp->Action; - else - *piAction = INSTALLSTATE_UNKNOWN; - } - - TRACE("states (%i, %i)\n", comp->Installed, comp->Action ); - return ERROR_SUCCESS; -} - -/*********************************************************************** - * MsiSetComponentStateW (MSI.@) - */ -UINT WINAPI MsiSetComponentStateW(MSIHANDLE hInstall, LPCWSTR szComponent, - INSTALLSTATE iState) -{ - MSIPACKAGE* package; - UINT ret; - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - ret = MSI_SetComponentStateW(package, szComponent, iState); - msiobj_release(&package->hdr); - return ret; -} - -/*********************************************************************** - * MsiGetComponentStateW (MSI.@) - */ -UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPCWSTR szComponent, - INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) -{ - MSIPACKAGE* package; - UINT ret; - - TRACE("%d %s %p %p\n", hInstall, debugstr_w(szComponent), - piInstalled, piAction); - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction); - msiobj_release( &package->hdr ); - return ret; -} - -/*********************************************************************** - * MsiGetLanguage (MSI.@) - */ -LANGID WINAPI MsiGetLanguage(MSIHANDLE hInstall) -{ - MSIPACKAGE* package; - LANGID langid; - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - langid = msi_get_property_int( package->db, szProductLanguage, 0 ); - msiobj_release( &package->hdr ); - return langid; -} - -UINT MSI_SetInstallLevel( MSIPACKAGE *package, int iInstallLevel ) -{ - static const WCHAR fmt[] = { '%','d',0 }; - WCHAR level[6]; - UINT r; - - TRACE("%p %i\n", package, iInstallLevel); - - if (iInstallLevel > 32767) - return ERROR_INVALID_PARAMETER; - - if (iInstallLevel < 1) - return MSI_SetFeatureStates( package ); - - sprintfW( level, fmt, iInstallLevel ); - r = msi_set_property( package->db, szInstallLevel, level ); - if ( r == ERROR_SUCCESS ) - r = MSI_SetFeatureStates( package ); - - return r; -} - -/*********************************************************************** - * MsiSetInstallLevel (MSI.@) - */ -UINT WINAPI MsiSetInstallLevel(MSIHANDLE hInstall, int iInstallLevel) -{ - MSIPACKAGE* package; - UINT r; - - TRACE("%d %i\n", hInstall, iInstallLevel); - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - r = MSI_SetInstallLevel( package, iInstallLevel ); - - msiobj_release( &package->hdr ); - - return r; -} - -/*********************************************************************** - * MsiGetFeatureValidStatesW (MSI.@) - */ -UINT WINAPI MsiGetFeatureValidStatesW(MSIHANDLE hInstall, LPCWSTR szFeature, - LPDWORD pInstallState) -{ - if(pInstallState) *pInstallState = 1<<INSTALLSTATE_LOCAL; - FIXME("%d %s %p stub returning %d\n", - hInstall, debugstr_w(szFeature), pInstallState, pInstallState ? *pInstallState : 0); - - return ERROR_SUCCESS; -} - -/*********************************************************************** - * MsiGetFeatureValidStatesA (MSI.@) - */ -UINT WINAPI MsiGetFeatureValidStatesA(MSIHANDLE hInstall, LPCSTR szFeature, - LPDWORD pInstallState) -{ - UINT ret; - LPWSTR szwFeature = strdupAtoW(szFeature); - - ret = MsiGetFeatureValidStatesW(hInstall, szwFeature, pInstallState); - - msi_free(szwFeature); - - return ret; -} diff --git a/libmsi/instlocal.bmp b/libmsi/instlocal.bmp Binary files differdeleted file mode 100644 index c9591ad..0000000 --- a/libmsi/instlocal.bmp +++ /dev/null diff --git a/libmsi/media.c b/libmsi/media.c index ccacdef..10d7fe8 100644 --- a/libmsi/media.c +++ b/libmsi/media.c @@ -53,68 +53,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); #define _O_TEXT 0x4000 #define _O_BINARY 0x8000 -static BOOL source_matches_volume(MSIMEDIAINFO *mi, LPCWSTR source_root) -{ - WCHAR volume_name[MAX_PATH + 1]; - WCHAR root[MAX_PATH + 1]; - - strcpyW(root, source_root); - PathStripToRootW(root); - PathAddBackslashW(root); - - if (!GetVolumeInformationW(root, volume_name, MAX_PATH + 1, NULL, NULL, NULL, NULL, 0)) - { - WARN("failed to get volume information for %s (%u)\n", debugstr_w(root), GetLastError()); - return FALSE; - } - return !strcmpiW( mi->volume_label, volume_name ); -} - -static UINT msi_change_media(MSIPACKAGE *package, MSIMEDIAINFO *mi) -{ - LPWSTR error, error_dialog; - LPWSTR source_dir; - UINT r = ERROR_SUCCESS; - - static const WCHAR error_prop[] = {'E','r','r','o','r','D','i','a','l','o','g',0}; - - if ((package->ui_level & INSTALLUILEVEL_MASK) == INSTALLUILEVEL_NONE && - !gUIHandlerA && !gUIHandlerW && !gUIHandlerRecord) return ERROR_SUCCESS; - - error = msi_build_error_string(package, 1302, 1, mi->disk_prompt); - error_dialog = msi_dup_property(package->db, error_prop); - source_dir = msi_dup_property(package->db, szSourceDir); - - while (r == ERROR_SUCCESS && !source_matches_volume(mi, source_dir)) - { - r = msi_spawn_error_dialog(package, error_dialog, error); - - if (gUIHandlerW) - { - gUIHandlerW(gUIContext, MB_RETRYCANCEL | INSTALLMESSAGE_ERROR, error); - } - else if (gUIHandlerA) - { - char *msg = strdupWtoA(error); - gUIHandlerA(gUIContext, MB_RETRYCANCEL | INSTALLMESSAGE_ERROR, msg); - msi_free(msg); - } - else if (gUIHandlerRecord) - { - MSIHANDLE rec = MsiCreateRecord(1); - MsiRecordSetStringW(rec, 0, error); - gUIHandlerRecord(gUIContext, MB_RETRYCANCEL | INSTALLMESSAGE_ERROR, rec); - MsiCloseHandle(rec); - } - } - - msi_free(error); - msi_free(error_dialog); - msi_free(source_dir); - - return r; -} - static MSICABINETSTREAM *msi_get_cabinet_stream( MSIPACKAGE *package, UINT disk_id ) { MSICABINETSTREAM *cab; @@ -370,10 +308,7 @@ static INT_PTR cabinet_next_cabinet(FDINOTIFICATIONTYPE fdint, res = 0; if (GetFileAttributesW(cabinet_file) == INVALID_FILE_ATTRIBUTES) - { - if (msi_change_media(data->package, mi) != ERROR_SUCCESS) - res = -1; - } + res = -1; done: msi_free(cab); @@ -653,260 +588,6 @@ BOOL msi_cabextract(MSIPACKAGE* package, MSIMEDIAINFO *mi, LPVOID data) return extract_cabinet( package, mi, data ); } -void msi_free_media_info(MSIMEDIAINFO *mi) -{ - msi_free(mi->disk_prompt); - msi_free(mi->cabinet); - msi_free(mi->volume_label); - msi_free(mi->first_volume); - msi_free(mi); -} - -static UINT get_drive_type(const WCHAR *path) -{ - WCHAR root[MAX_PATH + 1]; - - strcpyW(root, path); - PathStripToRootW(root); - PathAddBackslashW(root); - - return GetDriveTypeW(root); -} - -UINT msi_load_media_info(MSIPACKAGE *package, UINT Sequence, MSIMEDIAINFO *mi) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','M','e','d','i','a','`',' ', - 'W','H','E','R','E',' ','`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ', - '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ','`','D','i','s','k','I','d','`',0}; - MSIRECORD *row; - LPWSTR source_dir, source; - DWORD options; - - if (Sequence <= mi->last_sequence) /* already loaded */ - return ERROR_SUCCESS; - - row = MSI_QueryGetRecord(package->db, query, Sequence); - if (!row) - { - TRACE("Unable to query row\n"); - return ERROR_FUNCTION_FAILED; - } - - mi->is_extracted = FALSE; - mi->disk_id = MSI_RecordGetInteger(row, 1); - mi->last_sequence = MSI_RecordGetInteger(row, 2); - msi_free(mi->disk_prompt); - mi->disk_prompt = strdupW(MSI_RecordGetString(row, 3)); - msi_free(mi->cabinet); - mi->cabinet = strdupW(MSI_RecordGetString(row, 4)); - msi_free(mi->volume_label); - mi->volume_label = strdupW(MSI_RecordGetString(row, 5)); - msiobj_release(&row->hdr); - - if (!mi->first_volume) - mi->first_volume = strdupW(mi->volume_label); - - msi_set_sourcedir_props(package, FALSE); - source_dir = msi_dup_property(package->db, szSourceDir); - lstrcpyW(mi->sourcedir, source_dir); - PathAddBackslashW(mi->sourcedir); - mi->type = get_drive_type(source_dir); - - options = MSICODE_PRODUCT; - if (mi->type == DRIVE_CDROM || mi->type == DRIVE_REMOVABLE) - { - source = source_dir; - options |= MSISOURCETYPE_MEDIA; - } - else if (package->BaseURL && UrlIsW(package->BaseURL, URLIS_URL)) - { - source = package->BaseURL; - options |= MSISOURCETYPE_URL; - } - else - { - source = mi->sourcedir; - options |= MSISOURCETYPE_NETWORK; - } - - msi_package_add_media_disk(package, package->Context, - MSICODE_PRODUCT, mi->disk_id, - mi->volume_label, mi->disk_prompt); - - msi_package_add_info(package, package->Context, - options, INSTALLPROPERTY_LASTUSEDSOURCEW, source); - - msi_free(source_dir); - TRACE("sequence %u -> cabinet %s disk id %u\n", Sequence, debugstr_w(mi->cabinet), mi->disk_id); - return ERROR_SUCCESS; -} - -/* FIXME: search URL sources as well */ -static UINT find_published_source(MSIPACKAGE *package, MSIMEDIAINFO *mi) -{ - WCHAR source[MAX_PATH]; - WCHAR volume[MAX_PATH]; - WCHAR prompt[MAX_PATH]; - DWORD volumesz, promptsz; - DWORD index, size, id; - WCHAR last_type[2]; - UINT r; - - size = 2; - r = MsiSourceListGetInfoW(package->ProductCode, NULL, - package->Context, MSICODE_PRODUCT, - INSTALLPROPERTY_LASTUSEDTYPEW, last_type, &size); - if (r != ERROR_SUCCESS) - return r; - - size = MAX_PATH; - r = MsiSourceListGetInfoW(package->ProductCode, NULL, - package->Context, MSICODE_PRODUCT, - INSTALLPROPERTY_LASTUSEDSOURCEW, source, &size); - if (r != ERROR_SUCCESS) - return r; - - if (last_type[0] == 'n') - { - WCHAR cabinet_file[MAX_PATH]; - BOOL check_all = FALSE; - - while(TRUE) - { - index = 0; - volumesz = MAX_PATH; - while (MsiSourceListEnumSourcesW(package->ProductCode, NULL, - package->Context, - MSISOURCETYPE_NETWORK, index++, - volume, &volumesz) == ERROR_SUCCESS) - { - if (check_all || !strncmpiW(source, volume, strlenW(source))) - { - lstrcpyW(cabinet_file, volume); - PathAddBackslashW(cabinet_file); - lstrcatW(cabinet_file, mi->cabinet); - - if (GetFileAttributesW(cabinet_file) == INVALID_FILE_ATTRIBUTES) - { - volumesz = MAX_PATH; - if(!check_all) - break; - continue; - } - - lstrcpyW(mi->sourcedir, volume); - PathAddBackslashW(mi->sourcedir); - TRACE("Found network source %s\n", debugstr_w(mi->sourcedir)); - return ERROR_SUCCESS; - } - } - - if (!check_all) - check_all = TRUE; - else - break; - } - } - - index = 0; - volumesz = MAX_PATH; - promptsz = MAX_PATH; - while (MsiSourceListEnumMediaDisksW(package->ProductCode, NULL, - package->Context, - MSICODE_PRODUCT, index++, &id, - volume, &volumesz, prompt, &promptsz) == ERROR_SUCCESS) - { - mi->disk_id = id; - msi_free( mi->volume_label ); - if (!(mi->volume_label = msi_alloc( ++volumesz * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY; - strcpyW( mi->volume_label, volume ); - - msi_free( mi->disk_prompt ); - if (!(mi->disk_prompt = msi_alloc( ++promptsz * sizeof(WCHAR) ))) return ERROR_OUTOFMEMORY; - strcpyW( mi->disk_prompt, prompt ); - - if (source_matches_volume(mi, source)) - { - /* FIXME: what about SourceDir */ - lstrcpyW(mi->sourcedir, source); - PathAddBackslashW(mi->sourcedir); - TRACE("Found disk source %s\n", debugstr_w(mi->sourcedir)); - return ERROR_SUCCESS; - } - } - - return ERROR_FUNCTION_FAILED; -} - -UINT ready_media( MSIPACKAGE *package, BOOL compressed, MSIMEDIAINFO *mi ) -{ - UINT rc; - WCHAR *cabinet_file = NULL; - - /* media info for continuous cabinet is already loaded */ - if (mi->is_continuous) return ERROR_SUCCESS; - - if (mi->cabinet) - { - /* cabinet is internal, no checks needed */ - if (mi->cabinet[0] == '#') return ERROR_SUCCESS; - - if (!(cabinet_file = get_cabinet_filename( mi ))) return ERROR_OUTOFMEMORY; - - /* package should be downloaded */ - if (compressed && GetFileAttributesW( cabinet_file ) == INVALID_FILE_ATTRIBUTES && - package->BaseURL && UrlIsW( package->BaseURL, URLIS_URL )) - { - WCHAR temppath[MAX_PATH], *p; - - if ((rc = msi_download_file( cabinet_file, temppath )) != ERROR_SUCCESS) - { - ERR("failed to download %s (%u)\n", debugstr_w(cabinet_file), rc); - msi_free( cabinet_file ); - return rc; - } - if ((p = strrchrW( temppath, '\\' ))) *p = 0; - strcpyW( mi->sourcedir, temppath ); - PathAddBackslashW( mi->sourcedir ); - msi_free( mi->cabinet ); - mi->cabinet = strdupW( p + 1 ); - msi_free( cabinet_file ); - return ERROR_SUCCESS; - } - } - /* check volume matches, change media if not */ - if (mi->volume_label && mi->disk_id > 1 && strcmpW( mi->first_volume, mi->volume_label )) - { - WCHAR *source = msi_dup_property( package->db, szSourceDir ); - BOOL match = source_matches_volume( mi, source ); - msi_free( source ); - - if (!match && (mi->type == DRIVE_CDROM || mi->type == DRIVE_REMOVABLE)) - { - if ((rc = msi_change_media( package, mi )) != ERROR_SUCCESS) - { - msi_free( cabinet_file ); - return rc; - } - } - } - if (mi->cabinet) - { - if (compressed && GetFileAttributesW( cabinet_file ) == INVALID_FILE_ATTRIBUTES) - { - if ((rc = find_published_source( package, mi )) != ERROR_SUCCESS) - { - ERR("cabinet not found: %s\n", debugstr_w(cabinet_file)); - msi_free( cabinet_file ); - return ERROR_INSTALL_FAILURE; - } - } - } - msi_free( cabinet_file ); - return ERROR_SUCCESS; -} - UINT msi_add_cabinet_stream( MSIPACKAGE *package, UINT disk_id, IStorage *storage, const WCHAR *name ) { MSICABINETSTREAM *cab, *item; diff --git a/libmsi/msi.c b/libmsi/msi.c index 0d066ed..a8bbb25 100644 --- a/libmsi/msi.c +++ b/libmsi/msi.c @@ -203,111 +203,6 @@ UINT WINAPI MsiAdvertiseProductExW( LPCWSTR szPackagePath, LPCWSTR szScriptfileP return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine) -{ - LPWSTR szwPath = NULL, szwCommand = NULL; - UINT r = ERROR_OUTOFMEMORY; - - TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine)); - - if( szPackagePath ) - { - szwPath = strdupAtoW( szPackagePath ); - if( !szwPath ) - goto end; - } - - if( szCommandLine ) - { - szwCommand = strdupAtoW( szCommandLine ); - if( !szwCommand ) - goto end; - } - - r = MsiInstallProductW( szwPath, szwCommand ); - -end: - msi_free( szwPath ); - msi_free( szwCommand ); - - return r; -} - -UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine) -{ - MSIPACKAGE *package = NULL; - UINT r; - - TRACE("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine)); - - if (!szPackagePath) - return ERROR_INVALID_PARAMETER; - - if (!*szPackagePath) - return ERROR_PATH_NOT_FOUND; - - r = MSI_OpenPackageW( szPackagePath, &package ); - if (r == ERROR_SUCCESS) - { - r = MSI_InstallPackage( package, szPackagePath, szCommandLine ); - msiobj_release( &package->hdr ); - } - - return r; -} - -UINT WINAPI MsiReinstallProductA(LPCSTR szProduct, DWORD dwReinstallMode) -{ - LPWSTR wszProduct; - UINT rc; - - TRACE("%s %08x\n", debugstr_a(szProduct), dwReinstallMode); - - wszProduct = strdupAtoW(szProduct); - - rc = MsiReinstallProductW(wszProduct, dwReinstallMode); - - msi_free(wszProduct); - return rc; -} - -UINT WINAPI MsiReinstallProductW(LPCWSTR szProduct, DWORD dwReinstallMode) -{ - TRACE("%s %08x\n", debugstr_w(szProduct), dwReinstallMode); - - return MsiReinstallFeatureW(szProduct, szAll, dwReinstallMode); -} - -UINT WINAPI MsiApplyPatchA(LPCSTR szPatchPackage, LPCSTR szInstallPackage, - INSTALLTYPE eInstallType, LPCSTR szCommandLine) -{ - LPWSTR patch_package = NULL; - LPWSTR install_package = NULL; - LPWSTR command_line = NULL; - UINT r = ERROR_OUTOFMEMORY; - - TRACE("%s %s %d %s\n", debugstr_a(szPatchPackage), debugstr_a(szInstallPackage), - eInstallType, debugstr_a(szCommandLine)); - - if (szPatchPackage && !(patch_package = strdupAtoW(szPatchPackage))) - goto done; - - if (szInstallPackage && !(install_package = strdupAtoW(szInstallPackage))) - goto done; - - if (szCommandLine && !(command_line = strdupAtoW(szCommandLine))) - goto done; - - r = MsiApplyPatchW(patch_package, install_package, eInstallType, command_line); - -done: - msi_free(patch_package); - msi_free(install_package); - msi_free(command_line); - - return r; -} - static UINT get_patch_product_codes( LPCWSTR szPatchPackage, WCHAR ***product_codes ) { MSIHANDLE patch, info = 0; @@ -351,151 +246,6 @@ done: return r; } -static UINT MSI_ApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szProductCode, LPCWSTR szCommandLine) -{ - UINT i, r = ERROR_FUNCTION_FAILED; - DWORD size; - LPCWSTR cmd_ptr = szCommandLine; - LPWSTR cmd, *codes = NULL; - BOOL succeeded = FALSE; - - static const WCHAR fmt[] = {'%','s',' ','P','A','T','C','H','=','"','%','s','"',0}; - static WCHAR empty[] = {0}; - - if (!szPatchPackage || !szPatchPackage[0]) - return ERROR_INVALID_PARAMETER; - - if (!szProductCode && (r = get_patch_product_codes( szPatchPackage, &codes ))) - return r; - - if (!szCommandLine) - cmd_ptr = empty; - - size = strlenW(cmd_ptr) + strlenW(fmt) + strlenW(szPatchPackage) + 1; - cmd = msi_alloc(size * sizeof(WCHAR)); - if (!cmd) - { - msi_free(codes); - return ERROR_OUTOFMEMORY; - } - sprintfW(cmd, fmt, cmd_ptr, szPatchPackage); - - if (szProductCode) - r = MsiConfigureProductExW(szProductCode, INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd); - else - { - for (i = 0; codes[i]; i++) - { - r = MsiConfigureProductExW(codes[i], INSTALLLEVEL_DEFAULT, INSTALLSTATE_DEFAULT, cmd); - if (r == ERROR_SUCCESS) - { - TRACE("patch applied\n"); - succeeded = TRUE; - } - } - - if (succeeded) - r = ERROR_SUCCESS; - } - - msi_free(cmd); - msi_free(codes); - return r; -} - -UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage, - INSTALLTYPE eInstallType, LPCWSTR szCommandLine) -{ - TRACE("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage), - eInstallType, debugstr_w(szCommandLine)); - - if (szInstallPackage || eInstallType == INSTALLTYPE_NETWORK_IMAGE || - eInstallType == INSTALLTYPE_SINGLE_INSTANCE) - { - FIXME("Only reading target products from patch\n"); - return ERROR_CALL_NOT_IMPLEMENTED; - } - - return MSI_ApplyPatchW(szPatchPackage, NULL, szCommandLine); -} - -UINT WINAPI MsiApplyMultiplePatchesA(LPCSTR szPatchPackages, - LPCSTR szProductCode, LPCSTR szPropertiesList) -{ - LPWSTR patch_packages = NULL; - LPWSTR product_code = NULL; - LPWSTR properties_list = NULL; - UINT r = ERROR_OUTOFMEMORY; - - TRACE("%s %s %s\n", debugstr_a(szPatchPackages), debugstr_a(szProductCode), - debugstr_a(szPropertiesList)); - - if (!szPatchPackages || !szPatchPackages[0]) - return ERROR_INVALID_PARAMETER; - - if (!(patch_packages = strdupAtoW(szPatchPackages))) - return ERROR_OUTOFMEMORY; - - if (szProductCode && !(product_code = strdupAtoW(szProductCode))) - goto done; - - if (szPropertiesList && !(properties_list = strdupAtoW(szPropertiesList))) - goto done; - - r = MsiApplyMultiplePatchesW(patch_packages, product_code, properties_list); - -done: - msi_free(patch_packages); - msi_free(product_code); - msi_free(properties_list); - - return r; -} - -UINT WINAPI MsiApplyMultiplePatchesW(LPCWSTR szPatchPackages, - LPCWSTR szProductCode, LPCWSTR szPropertiesList) -{ - UINT r = ERROR_SUCCESS; - LPCWSTR beg, end; - - TRACE("%s %s %s\n", debugstr_w(szPatchPackages), debugstr_w(szProductCode), - debugstr_w(szPropertiesList)); - - if (!szPatchPackages || !szPatchPackages[0]) - return ERROR_INVALID_PARAMETER; - - beg = end = szPatchPackages; - while (*beg) - { - DWORD len; - LPWSTR patch; - - while (*beg == ' ') beg++; - while (*end && *end != ';') end++; - - len = end - beg; - while (len && beg[len - 1] == ' ') len--; - - if (!len) return ERROR_INVALID_NAME; - - patch = msi_alloc((len + 1) * sizeof(WCHAR)); - if (!patch) - return ERROR_OUTOFMEMORY; - - memcpy(patch, beg, len * sizeof(WCHAR)); - patch[len] = '\0'; - - r = MSI_ApplyPatchW(patch, szProductCode, szPropertiesList); - msi_free(patch); - - if (r != ERROR_SUCCESS) - break; - - beg = ++end; - } - return r; -} - static void free_patchinfo( DWORD count, MSIPATCHSEQUENCEINFOW *info ) { DWORD i; @@ -831,157 +581,6 @@ UINT WINAPI MsiDeterminePatchSequenceW( LPCWSTR product, LPCWSTR usersid, return r; } -UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel, - INSTALLSTATE eInstallState, LPCWSTR szCommandLine) -{ - MSIPACKAGE* package = NULL; - MSIINSTALLCONTEXT context; - UINT r; - DWORD sz; - WCHAR sourcepath[MAX_PATH], filename[MAX_PATH]; - LPWSTR commandline; - - static const WCHAR szInstalled[] = { - ' ','I','n','s','t','a','l','l','e','d','=','1',0}; - static const WCHAR szMaxInstallLevel[] = { - ' ','I','N','S','T','A','L','L','L','E','V','E','L','=','3','2','7','6','7',0}; - static const WCHAR szRemoveAll[] = { - ' ','R','E','M','O','V','E','=','A','L','L',0}; - static const WCHAR szMachine[] = { - ' ','A','L','L','U','S','E','R','S','=','1',0}; - - TRACE("%s %d %d %s\n",debugstr_w(szProduct), iInstallLevel, eInstallState, - debugstr_w(szCommandLine)); - - if (!szProduct || lstrlenW(szProduct) != GUID_SIZE - 1) - return ERROR_INVALID_PARAMETER; - - if (eInstallState == INSTALLSTATE_ADVERTISED || - eInstallState == INSTALLSTATE_SOURCE) - { - FIXME("State %d not implemented\n", eInstallState); - return ERROR_CALL_NOT_IMPLEMENTED; - } - - r = msi_locate_product(szProduct, &context); - if (r != ERROR_SUCCESS) - return r; - - r = open_package(szProduct, NULL, context, &package); - if (r != ERROR_SUCCESS) - return r; - - sz = lstrlenW(szInstalled) + 1; - - if (szCommandLine) - sz += lstrlenW(szCommandLine); - - if (eInstallState != INSTALLSTATE_DEFAULT) - sz += lstrlenW(szMaxInstallLevel); - - if (eInstallState == INSTALLSTATE_ABSENT) - sz += lstrlenW(szRemoveAll); - - if (context == MSIINSTALLCONTEXT_MACHINE) - sz += lstrlenW(szMachine); - - commandline = msi_alloc(sz * sizeof(WCHAR)); - if (!commandline) - { - r = ERROR_OUTOFMEMORY; - goto end; - } - - commandline[0] = 0; - if (szCommandLine) - lstrcpyW(commandline,szCommandLine); - - if (eInstallState != INSTALLSTATE_DEFAULT) - lstrcatW(commandline, szMaxInstallLevel); - - if (eInstallState == INSTALLSTATE_ABSENT) - lstrcatW(commandline, szRemoveAll); - - if (context == MSIINSTALLCONTEXT_MACHINE) - lstrcatW(commandline, szMachine); - - sz = sizeof(sourcepath); - MsiSourceListGetInfoW(szProduct, NULL, context, MSICODE_PRODUCT, - INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz); - - sz = sizeof(filename); - MsiSourceListGetInfoW(szProduct, NULL, context, MSICODE_PRODUCT, - INSTALLPROPERTY_PACKAGENAMEW, filename, &sz); - - strcatW(sourcepath, filename); - - r = MSI_InstallPackage( package, sourcepath, commandline ); - - msi_free(commandline); - -end: - msiobj_release( &package->hdr ); - - return r; -} - -UINT WINAPI MsiConfigureProductExA(LPCSTR szProduct, int iInstallLevel, - INSTALLSTATE eInstallState, LPCSTR szCommandLine) -{ - LPWSTR szwProduct = NULL; - LPWSTR szwCommandLine = NULL; - UINT r = ERROR_OUTOFMEMORY; - - if( szProduct ) - { - szwProduct = strdupAtoW( szProduct ); - if( !szwProduct ) - goto end; - } - - if( szCommandLine) - { - szwCommandLine = strdupAtoW( szCommandLine ); - if( !szwCommandLine) - goto end; - } - - r = MsiConfigureProductExW( szwProduct, iInstallLevel, eInstallState, - szwCommandLine ); -end: - msi_free( szwProduct ); - msi_free( szwCommandLine); - - return r; -} - -UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel, - INSTALLSTATE eInstallState) -{ - LPWSTR szwProduct = NULL; - UINT r; - - TRACE("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState); - - if( szProduct ) - { - szwProduct = strdupAtoW( szProduct ); - if( !szwProduct ) - return ERROR_OUTOFMEMORY; - } - - r = MsiConfigureProductW( szwProduct, iInstallLevel, eInstallState ); - msi_free( szwProduct ); - - return r; -} - -UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel, - INSTALLSTATE eInstallState) -{ - return MsiConfigureProductExW(szProduct, iInstallLevel, eInstallState, NULL); -} - UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer) { LPWSTR szwComponent = NULL; @@ -1099,6 +698,38 @@ static LPWSTR msi_reg_get_value(HKEY hkey, LPCWSTR name, DWORD *type) return strdupW(temp); } +UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz ) +{ + UINT len, r = ERROR_SUCCESS; + + if (awbuf->str.w && !sz ) + return ERROR_INVALID_PARAMETER; + + if (!sz) + return r; + + if (awbuf->unicode) + { + len = lstrlenW( str ); + if (awbuf->str.w) + lstrcpynW( awbuf->str.w, str, *sz ); + } + else + { + len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL ); + if (len) + len--; + WideCharToMultiByte( CP_ACP, 0, str, -1, awbuf->str.a, *sz, NULL, NULL ); + if ( awbuf->str.a && *sz && (len >= *sz) ) + awbuf->str.a[*sz - 1] = 0; + } + + if (awbuf->str.w && len >= *sz) + r = ERROR_MORE_DATA; + *sz = len; + return r; +} + static UINT MSI_GetProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, awstring *szValue, LPDWORD pcchValueBuf) { @@ -3057,155 +2688,6 @@ INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature) return r; } -/****************************************************************** - * MsiGetFileVersionA [MSI.@] - */ -UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf, - LPDWORD pcchVersionBuf, LPSTR lpLangBuf, LPDWORD pcchLangBuf) -{ - LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL; - UINT ret = ERROR_OUTOFMEMORY; - - if ((lpVersionBuf && !pcchVersionBuf) || - (lpLangBuf && !pcchLangBuf)) - return ERROR_INVALID_PARAMETER; - - if( szFilePath ) - { - szwFilePath = strdupAtoW( szFilePath ); - if( !szwFilePath ) - goto end; - } - - if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf ) - { - lpwVersionBuff = msi_alloc(*pcchVersionBuf*sizeof(WCHAR)); - if( !lpwVersionBuff ) - goto end; - } - - if( lpLangBuf && pcchLangBuf && *pcchLangBuf ) - { - lpwLangBuff = msi_alloc(*pcchLangBuf*sizeof(WCHAR)); - if( !lpwLangBuff ) - goto end; - } - - ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf, - lpwLangBuff, pcchLangBuf); - - if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwVersionBuff ) - WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1, - lpVersionBuf, *pcchVersionBuf + 1, NULL, NULL); - if( (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && lpwLangBuff ) - WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1, - lpLangBuf, *pcchLangBuf + 1, NULL, NULL); - -end: - msi_free(szwFilePath); - msi_free(lpwVersionBuff); - msi_free(lpwLangBuff); - - return ret; -} - -static UINT get_file_version( const WCHAR *path, WCHAR *verbuf, DWORD *verlen, - WCHAR *langbuf, DWORD *langlen ) -{ - static const WCHAR szVersionResource[] = {'\\',0}; - static const WCHAR szVersionFormat[] = {'%','d','.','%','d','.','%','d','.','%','d',0}; - static const WCHAR szLangFormat[] = {'%','d',0}; - UINT ret = ERROR_SUCCESS; - DWORD len, error; - LPVOID version; - VS_FIXEDFILEINFO *ffi; - USHORT *lang; - WCHAR tmp[32]; - - if (!(len = GetFileVersionInfoSizeW( path, NULL ))) - { - error = GetLastError(); - if (error == ERROR_BAD_PATHNAME) return ERROR_FILE_NOT_FOUND; - return error; - } - if (!(version = msi_alloc( len ))) return ERROR_OUTOFMEMORY; - if (!GetFileVersionInfoW( path, 0, len, version )) - { - msi_free( version ); - return GetLastError(); - } - if (verlen) - { - if (VerQueryValueW( version, szVersionResource, (LPVOID *)&ffi, &len ) && len > 0) - { - sprintfW( tmp, szVersionFormat, - HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS), - HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS) ); - if (verbuf) lstrcpynW( verbuf, tmp, *verlen ); - len = strlenW( tmp ); - if (len >= *verlen) ret = ERROR_MORE_DATA; - *verlen = len; - } - else - { - if (verbuf) *verbuf = 0; - *verlen = 0; - } - } - if (langlen) - { - if (VerQueryValueW( version, szLangResource, (LPVOID *)&lang, &len ) && len > 0) - { - sprintfW( tmp, szLangFormat, *lang ); - if (langbuf) lstrcpynW( langbuf, tmp, *langlen ); - len = strlenW( tmp ); - if (len >= *langlen) ret = ERROR_MORE_DATA; - *langlen = len; - } - else - { - if (langbuf) *langbuf = 0; - *langlen = 0; - } - } - msi_free( version ); - return ret; -} - - -/****************************************************************** - * MsiGetFileVersionW [MSI.@] - */ -UINT WINAPI MsiGetFileVersionW( LPCWSTR path, LPWSTR verbuf, LPDWORD verlen, - LPWSTR langbuf, LPDWORD langlen ) -{ - UINT ret; - - TRACE("%s %p %u %p %u\n", debugstr_w(path), verbuf, verlen ? *verlen : 0, - langbuf, langlen ? *langlen : 0); - - if ((verbuf && !verlen) || (langbuf && !langlen)) - return ERROR_INVALID_PARAMETER; - - ret = get_file_version( path, verbuf, verlen, langbuf, langlen ); - if (ret == ERROR_RESOURCE_DATA_NOT_FOUND && verlen) - { - int len; - WCHAR *version = msi_font_version_from_file( path ); - if (!version) return ERROR_FILE_INVALID; - len = strlenW( version ); - if (len >= *verlen) ret = ERROR_MORE_DATA; - else if (verbuf) - { - strcpyW( verbuf, version ); - ret = ERROR_SUCCESS; - } - *verlen = len; - msi_free( version ); - } - return ret; -} - /*********************************************************************** * MsiGetFeatureUsageW [MSI.@] */ @@ -3604,147 +3086,6 @@ USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct, return r; } -UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct) -{ - MSIHANDLE handle; - UINT rc; - MSIPACKAGE *package; - static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0}; - - TRACE("(%s)\n",debugstr_w(szProduct)); - - rc = MsiOpenProductW(szProduct,&handle); - if (rc != ERROR_SUCCESS) - return ERROR_INVALID_PARAMETER; - - /* MsiCollectUserInfo cannot be called from a custom action. */ - package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_CALL_NOT_IMPLEMENTED; - - rc = ACTION_PerformUIAction(package, szFirstRun, SCRIPT_NONE); - msiobj_release( &package->hdr ); - - MsiCloseHandle(handle); - - return rc; -} - -UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct) -{ - MSIHANDLE handle; - UINT rc; - MSIPACKAGE *package; - static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0}; - - TRACE("(%s)\n",debugstr_a(szProduct)); - - rc = MsiOpenProductA(szProduct,&handle); - if (rc != ERROR_SUCCESS) - return ERROR_INVALID_PARAMETER; - - /* MsiCollectUserInfo cannot be called from a custom action. */ - package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_CALL_NOT_IMPLEMENTED; - - rc = ACTION_PerformUIAction(package, szFirstRun, SCRIPT_NONE); - msiobj_release( &package->hdr ); - - MsiCloseHandle(handle); - - return rc; -} - -/*********************************************************************** - * MsiConfigureFeatureA [MSI.@] - */ -UINT WINAPI MsiConfigureFeatureA(LPCSTR szProduct, LPCSTR szFeature, INSTALLSTATE eInstallState) -{ - LPWSTR prod, feat = NULL; - UINT r = ERROR_OUTOFMEMORY; - - TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), eInstallState); - - prod = strdupAtoW( szProduct ); - if (szProduct && !prod) - goto end; - - feat = strdupAtoW( szFeature ); - if (szFeature && !feat) - goto end; - - r = MsiConfigureFeatureW(prod, feat, eInstallState); - -end: - msi_free(feat); - msi_free(prod); - - return r; -} - -/*********************************************************************** - * MsiConfigureFeatureW [MSI.@] - */ -UINT WINAPI MsiConfigureFeatureW(LPCWSTR szProduct, LPCWSTR szFeature, INSTALLSTATE eInstallState) -{ - MSIPACKAGE *package = NULL; - UINT r; - WCHAR sourcepath[MAX_PATH], filename[MAX_PATH]; - DWORD sz; - - TRACE("%s %s %i\n", debugstr_w(szProduct), debugstr_w(szFeature), eInstallState); - - if (!szProduct || !szFeature) - return ERROR_INVALID_PARAMETER; - - switch (eInstallState) - { - case INSTALLSTATE_DEFAULT: - /* FIXME: how do we figure out the default location? */ - eInstallState = INSTALLSTATE_LOCAL; - break; - case INSTALLSTATE_LOCAL: - case INSTALLSTATE_SOURCE: - case INSTALLSTATE_ABSENT: - case INSTALLSTATE_ADVERTISED: - break; - default: - return ERROR_INVALID_PARAMETER; - } - - r = MSI_OpenProductW( szProduct, &package ); - if (r != ERROR_SUCCESS) - return r; - - sz = sizeof(sourcepath); - MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT, INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz); - - sz = sizeof(filename); - MsiSourceListGetInfoW(szProduct, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, - MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, filename, &sz); - - lstrcatW( sourcepath, filename ); - - MsiSetInternalUI( INSTALLUILEVEL_BASIC, NULL ); - - r = ACTION_PerformUIAction( package, szCostInitialize, SCRIPT_NONE ); - if (r != ERROR_SUCCESS) - goto end; - - r = MSI_SetFeatureStateW( package, szFeature, eInstallState); - if (r != ERROR_SUCCESS) - goto end; - - r = MSI_InstallPackage( package, sourcepath, NULL ); - -end: - msiobj_release( &package->hdr ); - - return r; -} - /*********************************************************************** * MsiCreateAndVerifyInstallerDirectory [MSI.@] * @@ -3858,98 +3199,6 @@ UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget, return ERROR_FUNCTION_FAILED; } -UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature, DWORD dwReinstallMode ) -{ - static const WCHAR fmtW[] = {'%','s','=','%','s',' ','%','s','=','%','s',0}; - MSIPACKAGE *package; - MSIINSTALLCONTEXT context; - UINT r; - WCHAR sourcepath[MAX_PATH], filename[MAX_PATH], reinstallmode[11]; - WCHAR *ptr, *cmdline; - DWORD sz; - - TRACE("%s, %s, 0x%08x\n", debugstr_w(szProduct), debugstr_w(szFeature), dwReinstallMode); - - r = msi_locate_product( szProduct, &context ); - if (r != ERROR_SUCCESS) - return r; - - ptr = reinstallmode; - - if (dwReinstallMode & REINSTALLMODE_FILEMISSING) - *ptr++ = 'p'; - if (dwReinstallMode & REINSTALLMODE_FILEOLDERVERSION) - *ptr++ = 'o'; - if (dwReinstallMode & REINSTALLMODE_FILEEQUALVERSION) - *ptr++ = 'w'; - if (dwReinstallMode & REINSTALLMODE_FILEEXACT) - *ptr++ = 'd'; - if (dwReinstallMode & REINSTALLMODE_FILEVERIFY) - *ptr++ = 'c'; - if (dwReinstallMode & REINSTALLMODE_FILEREPLACE) - *ptr++ = 'a'; - if (dwReinstallMode & REINSTALLMODE_USERDATA) - *ptr++ = 'u'; - if (dwReinstallMode & REINSTALLMODE_MACHINEDATA) - *ptr++ = 'm'; - if (dwReinstallMode & REINSTALLMODE_SHORTCUT) - *ptr++ = 's'; - if (dwReinstallMode & REINSTALLMODE_PACKAGE) - *ptr++ = 'v'; - *ptr = 0; - - sz = sizeof(sourcepath); - MsiSourceListGetInfoW( szProduct, NULL, context, MSICODE_PRODUCT, - INSTALLPROPERTY_LASTUSEDSOURCEW, sourcepath, &sz ); - sz = sizeof(filename); - MsiSourceListGetInfoW( szProduct, NULL, context, MSICODE_PRODUCT, - INSTALLPROPERTY_PACKAGENAMEW, filename, &sz ); - strcatW( sourcepath, filename ); - - if (dwReinstallMode & REINSTALLMODE_PACKAGE) - r = MSI_OpenPackageW( sourcepath, &package ); - else - r = MSI_OpenProductW( szProduct, &package ); - - if (r != ERROR_SUCCESS) - return r; - - sz = (strlenW( fmtW ) + strlenW( szReinstallMode ) + strlenW( reinstallmode )) * sizeof(WCHAR); - sz += (strlenW( szReinstall ) + strlenW( szFeature )) * sizeof(WCHAR); - if (!(cmdline = msi_alloc( sz ))) - { - msiobj_release( &package->hdr ); - return ERROR_OUTOFMEMORY; - } - sprintfW( cmdline, fmtW, szReinstallMode, reinstallmode, szReinstall, szFeature ); - - r = MSI_InstallPackage( package, sourcepath, cmdline ); - msiobj_release( &package->hdr ); - msi_free( cmdline ); - - return r; -} - -UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature, - DWORD dwReinstallMode ) -{ - LPWSTR wszProduct; - LPWSTR wszFeature; - UINT rc; - - TRACE("%s %s %i\n", debugstr_a(szProduct), debugstr_a(szFeature), - dwReinstallMode); - - wszProduct = strdupAtoW(szProduct); - wszFeature = strdupAtoW(szFeature); - - rc = MsiReinstallFeatureW(wszProduct, wszFeature, dwReinstallMode); - - msi_free(wszProduct); - msi_free(wszFeature); - return rc; -} - typedef struct { unsigned int i[2]; diff --git a/libmsi/msi.rc b/libmsi/msi.rc index 67b679a..bc08cdb 100644 --- a/libmsi/msi.rc +++ b/libmsi/msi.rc @@ -63,15 +63,6 @@ STRINGTABLE LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL -/* @makedep: instadvert.bmp */ -0x1001 BITMAP instadvert.bmp - -/* @makedep: instabsent.bmp */ -0x1002 BITMAP instabsent.bmp - -/* @makedep: instlocal.bmp */ -0x1003 BITMAP instlocal.bmp - #define WINE_FILEDESCRIPTION_STR "Wine MSI dll" #define WINE_FILENAME_STR "msi.dll" #define WINE_FILEVERSION 4,5,6001,22299 diff --git a/libmsi/msi_main.c b/libmsi/msi_main.c index fb81546..bc0bea4 100644 --- a/libmsi/msi_main.c +++ b/libmsi/msi_main.c @@ -76,7 +76,6 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) IsWow64Process( GetCurrentProcess(), &is_wow64 ); break; case DLL_PROCESS_DETACH: - msi_dialog_unregister_class(); msi_free_handle_table(); msi_free( gszLogFile ); break; diff --git a/libmsi/msipriv.h b/libmsi/msipriv.h index 51e12d8..77939be 100644 --- a/libmsi/msipriv.h +++ b/libmsi/msipriv.h @@ -866,7 +866,6 @@ extern UINT msi_download_file( LPCWSTR szUrl, LPWSTR filename ) DECLSPEC_HIDDEN; extern UINT msi_package_add_info(MSIPACKAGE *, DWORD, DWORD, LPCWSTR, LPWSTR) DECLSPEC_HIDDEN; extern UINT msi_package_add_media_disk(MSIPACKAGE *, DWORD, DWORD, DWORD, LPWSTR, LPWSTR) DECLSPEC_HIDDEN; extern UINT msi_clone_properties(MSIPACKAGE *) DECLSPEC_HIDDEN; -extern UINT msi_set_context(MSIPACKAGE *) DECLSPEC_HIDDEN; extern void msi_adjust_privilege_properties(MSIPACKAGE *) DECLSPEC_HIDDEN; extern UINT MSI_GetFeatureCost(MSIPACKAGE *, MSIFEATURE *, MSICOSTTREE, INSTALLSTATE, LPINT) DECLSPEC_HIDDEN; diff --git a/libmsi/package.c b/libmsi/package.c index 62cccc0..3e3faad 100644 --- a/libmsi/package.c +++ b/libmsi/package.c @@ -50,6 +50,63 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); +MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component ) +{ + MSICOMPONENT *comp; + + LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) + { + if (!strcmpW( Component, comp->Component )) return comp; + } + return NULL; +} + +MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature ) +{ + MSIFEATURE *feature; + + LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) + { + if (!strcmpW( Feature, feature->Feature )) return feature; + } + return NULL; +} + +MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key ) +{ + MSIFILE *file; + + LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) + { + if (!strcmpW( key, file->File )) return file; + } + return NULL; +} + +MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key ) +{ + MSIFILEPATCH *patch; + + /* FIXME: There might be more than one patch */ + LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry ) + { + if (!strcmpW( key, patch->File->File )) return patch; + } + return NULL; +} + +MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir ) +{ + MSIFOLDER *folder; + + LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry ) + { + if (!strcmpW( dir, folder->Directory )) return folder; + } + return NULL; +} + + static void remove_tracked_tempfiles( MSIPACKAGE *package ) { struct list *item, *cursor; @@ -338,20 +395,12 @@ static void free_package_structures( MSIPACKAGE *package ) msi_free( package->langids ); remove_tracked_tempfiles(package); - - /* cleanup control event subscriptions */ - ControlEvent_CleanupSubscriptions( package ); } static void MSI_FreePackage( MSIOBJECTHDR *arg) { MSIPACKAGE *package = (MSIPACKAGE *)arg; - msi_destroy_assembly_caches( package ); - - if( package->dialog ) - msi_dialog_destroy( package->dialog ); - msiobj_release( &package->db->hdr ); free_package_structures(package); CloseHandle( package->log_file ); @@ -1121,6 +1170,7 @@ static MSIPACKAGE *msi_alloc_package( void ) static UINT msi_load_admin_properties(MSIPACKAGE *package) { +#if 0 BYTE *data; UINT r, sz; @@ -1134,6 +1184,7 @@ static UINT msi_load_admin_properties(MSIPACKAGE *package) msi_free(data); return r; +#endif } void msi_adjust_privilege_properties( MSIPACKAGE *package ) @@ -1508,6 +1559,20 @@ static UINT get_local_package( const WCHAR *filename, WCHAR *localfile ) return r; } +static UINT msi_set_context(MSIPACKAGE *package) +{ + UINT r = msi_locate_product( package->ProductCode, &package->Context ); + if (r != ERROR_SUCCESS) + { + int num = msi_get_property_int( package->db, szAllUsers, 0 ); + if (num == 1 || num == 2) + package->Context = MSIINSTALLCONTEXT_MACHINE; + else + package->Context = MSIINSTALLCONTEXT_USERUNMANAGED; + } + return ERROR_SUCCESS; +} + UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) { static const WCHAR dotmsi[] = {'.','m','s','i',0}; @@ -1722,212 +1787,6 @@ MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall) return handle; } -INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType, MSIRECORD *record ) -{ - static const WCHAR szActionData[] = {'A','c','t','i','o','n','D','a','t','a',0}; - static const WCHAR szSetProgress[] = {'S','e','t','P','r','o','g','r','e','s','s',0}; - static const WCHAR szActionText[] = {'A','c','t','i','o','n','T','e','x','t',0}; - MSIRECORD *uirow; - LPWSTR deformated, message; - DWORD i, len, total_len, log_type = 0; - INT rc = 0; - char *msg; - - TRACE("%x\n", eMessageType); - - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_FATALEXIT) - log_type |= INSTALLLOGMODE_FATALEXIT; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR) - log_type |= INSTALLLOGMODE_ERROR; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING) - log_type |= INSTALLLOGMODE_WARNING; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER) - log_type |= INSTALLLOGMODE_USER; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO) - log_type |= INSTALLLOGMODE_INFO; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_RESOLVESOURCE) - log_type |= INSTALLLOGMODE_RESOLVESOURCE; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_OUTOFDISKSPACE) - log_type |= INSTALLLOGMODE_OUTOFDISKSPACE; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA) - log_type |= INSTALLLOGMODE_COMMONDATA; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART) - log_type |= INSTALLLOGMODE_ACTIONSTART; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA) - log_type |= INSTALLLOGMODE_ACTIONDATA; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS) - log_type |= INSTALLLOGMODE_PROGRESS; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INITIALIZE) - log_type |= INSTALLLOGMODE_INITIALIZE; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_TERMINATE) - log_type |= INSTALLLOGMODE_TERMINATE; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_SHOWDIALOG) - log_type |= INSTALLLOGMODE_SHOWDIALOG; - - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART) - { - static const WCHAR template_s[]= - {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ',0}; - static const WCHAR format[] = - {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0}; - WCHAR timet[0x100]; - LPCWSTR action_text, action; - LPWSTR deformatted = NULL; - - GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100); - - action = MSI_RecordGetString(record, 1); - action_text = MSI_RecordGetString(record, 2); - - if (!action || !action_text) - return IDOK; - - deformat_string(package, action_text, &deformatted); - - len = strlenW(timet) + strlenW(action) + strlenW(template_s); - if (deformatted) - len += strlenW(deformatted); - message = msi_alloc(len*sizeof(WCHAR)); - sprintfW(message, template_s, timet, action); - if (deformatted) - strcatW(message, deformatted); - msi_free(deformatted); - } - else - { - static const WCHAR format[] = {'%','u',':',' ',0}; - UINT count = MSI_RecordGetFieldCount( record ); - WCHAR *p; - - total_len = 1; - for (i = 1; i <= count; i++) - { - len = 0; - MSI_RecordGetStringW( record, i, NULL, &len ); - total_len += len + 13; - } - p = message = msi_alloc( total_len * sizeof(WCHAR) ); - if (!p) return ERROR_OUTOFMEMORY; - - for (i = 1; i <= count; i++) - { - if (count > 1) - { - len = sprintfW( p, format, i ); - total_len -= len; - p += len; - } - len = total_len; - MSI_RecordGetStringW( record, i, p, &len ); - total_len -= len; - p += len; - if (count > 1 && total_len) - { - *p++ = ' '; - total_len--; - } - } - p[0] = 0; - } - - TRACE("%p %p %p %x %x %s\n", gUIHandlerA, gUIHandlerW, gUIHandlerRecord, - gUIFilter, log_type, debugstr_w(message)); - - /* convert it to ASCII */ - len = WideCharToMultiByte( CP_ACP, 0, message, -1, NULL, 0, NULL, NULL ); - msg = msi_alloc( len ); - WideCharToMultiByte( CP_ACP, 0, message, -1, msg, len, NULL, NULL ); - - if (gUIHandlerW && (gUIFilter & log_type)) - { - rc = gUIHandlerW( gUIContext, eMessageType, message ); - } - else if (gUIHandlerA && (gUIFilter & log_type)) - { - rc = gUIHandlerA( gUIContext, eMessageType, msg ); - } - else if (gUIHandlerRecord && (gUIFilter & log_type)) - { - MSIHANDLE rec = MsiCreateRecord( 1 ); - MsiRecordSetStringW( rec, 0, message ); - rc = gUIHandlerRecord( gUIContext, eMessageType, rec ); - MsiCloseHandle( rec ); - } - - if (!rc && package->log_file != INVALID_HANDLE_VALUE && - (eMessageType & 0xff000000) != INSTALLMESSAGE_PROGRESS) - { - DWORD written; - WriteFile( package->log_file, msg, len - 1, &written, NULL ); - WriteFile( package->log_file, "\n", 1, &written, NULL ); - } - msi_free( msg ); - msi_free( message ); - - switch (eMessageType & 0xff000000) - { - case INSTALLMESSAGE_ACTIONDATA: - deformat_string(package, MSI_RecordGetString(record, 2), &deformated); - uirow = MSI_CreateRecord(1); - MSI_RecordSetStringW(uirow, 1, deformated); - msi_free(deformated); - - ControlEvent_FireSubscribedEvent(package, szActionData, uirow); - msiobj_release(&uirow->hdr); - - if (package->action_progress_increment) - { - uirow = MSI_CreateRecord(2); - MSI_RecordSetInteger(uirow, 1, 2); - MSI_RecordSetInteger(uirow, 2, package->action_progress_increment); - ControlEvent_FireSubscribedEvent(package, szSetProgress, uirow); - msiobj_release(&uirow->hdr); - } - break; - - case INSTALLMESSAGE_ACTIONSTART: - deformat_string(package, MSI_RecordGetString(record, 2), &deformated); - uirow = MSI_CreateRecord(1); - MSI_RecordSetStringW(uirow, 1, deformated); - msi_free(deformated); - - ControlEvent_FireSubscribedEvent(package, szActionText, uirow); - - msiobj_release(&uirow->hdr); - break; - - case INSTALLMESSAGE_PROGRESS: - ControlEvent_FireSubscribedEvent(package, szSetProgress, record); - break; - } - - return ERROR_SUCCESS; -} - -INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType, - MSIHANDLE hRecord) -{ - UINT ret = ERROR_INVALID_HANDLE; - MSIPACKAGE *package = NULL; - MSIRECORD *record = NULL; - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); - if( !package ) - return ERROR_INVALID_HANDLE; - record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD ); - if( !record ) - goto out; - - ret = MSI_ProcessMessage( package, eMessageType, record ); - -out: - msiobj_release( &package->hdr ); - if( record ) - msiobj_release( &record->hdr ); - - return ret; -} - /* property code */ UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue ) diff --git a/libmsi/patch.c b/libmsi/patch.c index 4801872..9410bb7 100644 --- a/libmsi/patch.c +++ b/libmsi/patch.c @@ -32,6 +32,43 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); +WCHAR **msi_split_string( const WCHAR *str, WCHAR sep ) +{ + LPCWSTR pc; + LPWSTR p, *ret = NULL; + UINT count = 0; + + if (!str) + return ret; + + /* count the number of substrings */ + for ( pc = str, count = 0; pc; count++ ) + { + pc = strchrW( pc, sep ); + if (pc) + pc++; + } + + /* allocate space for an array of substring pointers and the substrings */ + ret = msi_alloc( (count+1) * sizeof (LPWSTR) + + (lstrlenW(str)+1) * sizeof(WCHAR) ); + if (!ret) + return ret; + + /* copy the string and set the pointers */ + p = (LPWSTR) &ret[count+1]; + lstrcpyW( p, str ); + for( count = 0; (ret[count] = p); count++ ) + { + p = strchrW( p, sep ); + if (p) + *p++ = 0; + } + + return ret; +} + + static BOOL match_language( MSIPACKAGE *package, LANGID langid ) { UINT i; diff --git a/libmsi/script.c b/libmsi/script.c deleted file mode 100644 index f15185a..0000000 --- a/libmsi/script.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Implementation of scripting for Microsoft Installer (msi.dll) - * - * Copyright 2007 Misha Koshelev - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define COBJMACROS - -#include <stdarg.h> -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wingdi.h" -#include "winuser.h" -#include "msidefs.h" -#include "msipriv.h" -#include "activscp.h" -#include "oleauto.h" -#include "wine/debug.h" -#include "wine/unicode.h" - -#include "msiserver.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -/* - * Call a script. - */ -DWORD call_script(MSIHANDLE hPackage, INT type, LPCWSTR script, LPCWSTR function, LPCWSTR action) -{ - return ERROR_INSTALL_FAILURE; -} diff --git a/libmsi/upgrade.c b/libmsi/upgrade.c deleted file mode 100644 index fb84229..0000000 --- a/libmsi/upgrade.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2005 Aric Stewart for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/* - * Actions focused on in this module - * - * FindRelatedProducts - * MigrateFeatureStates (TODO) - * RemoveExistingProducts (TODO) - */ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winreg.h" -#include "wine/debug.h" -#include "msidefs.h" -#include "msipriv.h" -#include "wingdi.h" -#include "winuser.h" -#include "wine/unicode.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -static BOOL check_language(DWORD lang1, LPCWSTR lang2, DWORD attributes) -{ - DWORD langdword; - - if (!lang2 || lang2[0]==0) - return TRUE; - - langdword = atoiW(lang2); - - if (attributes & msidbUpgradeAttributesLanguagesExclusive) - return (lang1 != langdword); - else - return (lang1 == langdword); -} - -static void append_productcode(MSIPACKAGE* package, LPCWSTR action_property, - LPCWSTR productid) -{ - LPWSTR prop; - LPWSTR newprop; - DWORD len; - UINT r; - - prop = msi_dup_property(package->db, action_property ); - if (prop) - len = strlenW(prop); - else - len = 0; - - /*separator*/ - len ++; - - len += strlenW(productid); - - /*null*/ - len++; - - newprop = msi_alloc( len*sizeof(WCHAR) ); - - if (prop) - { - strcpyW(newprop,prop); - strcatW(newprop,szSemiColon); - } - else - newprop[0] = 0; - strcatW(newprop,productid); - - r = msi_set_property( package->db, action_property, newprop ); - if (r == ERROR_SUCCESS && !strcmpW( action_property, szSourceDir )) - msi_reset_folders( package, TRUE ); - - TRACE("Found Related Product... %s now %s\n", - debugstr_w(action_property), debugstr_w(newprop)); - - msi_free( prop ); - msi_free( newprop ); -} - -static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param) -{ - MSIPACKAGE *package = param; - WCHAR product[GUID_SIZE]; - DWORD index = 0; - DWORD attributes = 0; - DWORD sz = GUID_SIZE; - LPCWSTR upgrade_code; - HKEY hkey = 0; - UINT rc = ERROR_SUCCESS; - MSIRECORD *uirow; - - upgrade_code = MSI_RecordGetString(rec,1); - - rc = MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey, FALSE); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - uirow = MSI_CreateRecord(1); - attributes = MSI_RecordGetInteger(rec,5); - - while (rc == ERROR_SUCCESS) - { - rc = RegEnumValueW(hkey, index, product, &sz, NULL, NULL, NULL, NULL); - if (rc == ERROR_SUCCESS) - { - WCHAR productid[GUID_SIZE]; - LPCWSTR ver, language, action_property; - DWORD check = 0, comp_ver, sz = 0x100; - HKEY hukey; - INT r; - - TRACE("Looking at index %u product %s\n", index, debugstr_w(product)); - - unsquash_guid(product, productid); - if (MSIREG_OpenProductKey(productid, NULL, MSIINSTALLCONTEXT_USERMANAGED, &hukey, FALSE) && - MSIREG_OpenProductKey(productid, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, &hukey, FALSE) && - MSIREG_OpenProductKey(productid, NULL, MSIINSTALLCONTEXT_MACHINE, &hukey, FALSE)) - { - TRACE("product key not found\n"); - rc = ERROR_SUCCESS; - index ++; - continue; - } - - sz = sizeof(DWORD); - RegQueryValueExW(hukey, INSTALLPROPERTY_VERSIONW, NULL, NULL, (LPBYTE)&check, &sz); - - /* check version minimum */ - ver = MSI_RecordGetString(rec,2); - if (ver) - { - comp_ver = msi_version_str_to_dword(ver); - r = check - comp_ver; - if (r < 0 || (r == 0 && !(attributes & msidbUpgradeAttributesVersionMinInclusive))) - { - TRACE("version below minimum\n"); - RegCloseKey(hukey); - index ++; - continue; - } - } - - /* check version maximum */ - ver = MSI_RecordGetString(rec,3); - if (ver) - { - comp_ver = msi_version_str_to_dword(ver); - r = check - comp_ver; - if (r > 0 || (r == 0 && !(attributes & msidbUpgradeAttributesVersionMaxInclusive))) - { - RegCloseKey(hukey); - index ++; - continue; - } - TRACE("version above maximum\n"); - } - - /* check language */ - sz = sizeof(DWORD); - RegQueryValueExW(hukey, INSTALLPROPERTY_LANGUAGEW, NULL, NULL, (LPBYTE)&check, &sz); - RegCloseKey(hukey); - language = MSI_RecordGetString(rec,4); - if (!check_language(check, language, attributes)) - { - index ++; - TRACE("language doesn't match\n"); - continue; - } - TRACE("found related product\n"); - - action_property = MSI_RecordGetString(rec, 7); - append_productcode(package, action_property, productid); - MSI_RecordSetStringW(uirow, 1, productid); - msi_ui_actiondata(package, szFindRelatedProducts, uirow); - } - index ++; - } - RegCloseKey(hkey); - msiobj_release( &uirow->hdr); - - return ERROR_SUCCESS; -} - -UINT ACTION_FindRelatedProducts(MSIPACKAGE *package) -{ - static const WCHAR query[] = { - 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','U','p','g','r','a','d','e','`',0}; - MSIQUERY *view; - UINT rc; - - if (msi_get_property_int(package->db, szInstalled, 0)) - { - TRACE("Skipping FindRelatedProducts action: product already installed\n"); - return ERROR_SUCCESS; - } - if (msi_action_is_unique(package, szFindRelatedProducts)) - { - TRACE("Skipping FindRelatedProducts action: already done in UI sequence\n"); - return ERROR_SUCCESS; - } - else - msi_register_unique_action(package, szFindRelatedProducts); - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_IterateRecords(view, NULL, ITERATE_FindRelatedProducts, package); - msiobj_release(&view->hdr); - return rc; -} |
