summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2012-10-22 12:13:38 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2012-12-06 20:25:48 +0100
commit849e863a16e216100a711bb0fe0da33ab64ec577 (patch)
treea25456396769472110093b61ebffbdda8f9c5e1f
parent722565ce6f7bb2361207c43769f27c76864fdae1 (diff)
downloadmsitools-849e863a16e216100a711bb0fe0da33ab64ec577.tar.gz
msitools-849e863a16e216100a711bb0fe0da33ab64ec577.tar.xz
msitools-849e863a16e216100a711bb0fe0da33ab64ec577.zip
remove most of the run-time processing
-rw-r--r--libmsi/Makefile.am19
-rw-r--r--libmsi/action.c7683
-rw-r--r--libmsi/appsearch.c1189
-rw-r--r--libmsi/assembly.c694
-rw-r--r--libmsi/classes.c1565
-rw-r--r--libmsi/cond-parser.y869
-rw-r--r--libmsi/custom.c1311
-rw-r--r--libmsi/dialog.c4151
-rw-r--r--libmsi/events.c449
-rw-r--r--libmsi/files.c1330
-rw-r--r--libmsi/font.c385
-rw-r--r--libmsi/format.c1012
-rw-r--r--libmsi/instabsent.bmpbin374 -> 0 bytes
-rw-r--r--libmsi/instadvert.bmpbin374 -> 0 bytes
-rw-r--r--libmsi/install.c1307
-rw-r--r--libmsi/instlocal.bmpbin374 -> 0 bytes
-rw-r--r--libmsi/media.c321
-rw-r--r--libmsi/msi.c815
-rw-r--r--libmsi/msi.rc9
-rw-r--r--libmsi/msi_main.c1
-rw-r--r--libmsi/msipriv.h1
-rw-r--r--libmsi/package.c287
-rw-r--r--libmsi/patch.c37
-rw-r--r--libmsi/script.c46
-rw-r--r--libmsi/upgrade.c235
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, &regType, 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
deleted file mode 100644
index 9347961..0000000
--- a/libmsi/instabsent.bmp
+++ /dev/null
Binary files differ
diff --git a/libmsi/instadvert.bmp b/libmsi/instadvert.bmp
deleted file mode 100644
index 77b5309..0000000
--- a/libmsi/instadvert.bmp
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index c9591ad..0000000
--- a/libmsi/instlocal.bmp
+++ /dev/null
Binary files differ
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;
-}