From 4e23c74418bfb93144d77e51002b521af0382d5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9=20van=20Geldorp?= Date: Wed, 3 Aug 2005 22:12:15 +0000 Subject: [PATCH] Sync to Wine-20050628: Mike McCormack - Repaint the area behind the "transparent" text control when it changes. - Implement transparency in the text control. - Make the MSI icon control work. - Make tabs work in msi dialogs. - Added support for the MSI MaskEdit control. - Use a richedit control for license text. - Fix radio button groups. Don't add the WS_GROUP style to every window. - Use standard lists in the event subscription code. - Take the dialog frame into account when calculating the dialog size. - Use MSI_QueryGetRecord in one more place. - Create a helper function to fetch a single record from a query. - More -Wmissing-declarations and -Wwrite-strings warning fixes. - Get rid of some redundant parser types. - Use the new helper function MSI_QueryGetRecord. - Use MSI_RecordGetString in more actions. - Use MSI_RecordGetString where possible. - Fixes for -Wmissing-declarations and -Wwrite-strings warnings. - Remove some unused code. - Add and correct some function declarations. - Improve number parsing and avoid unicode.h. - avoid unicode.h - add a missing function prototype - Create a stub implementation for MsiViewGetError. - Remove more types from the parser. - Test and fix the size of stream fields in a record. - Clean up headers and make some functions static. Marcus Meissner - Use a simpler expression for the "RichEdit20W" string to workaround compiler bug. - Remove cszbs from msi/action.h. Aric Stewart Mike McCormack - Allow dialog controls to subscribe to installer events. - Fix handling of checkbox properties. - Implement dialog events and hook up the dialog code. Aric Stewart - Break out all the file related actions and helper functions into files.c - Break out all the top level apis into install.c. - Break out all the class registration actions into classes.c. This includes RegisterClassInfo, RegisterProgIds, RegisterExtensions and RegisterMIMETypes. - Break out all the helper functions into helpers.c. - Added module upgrade.c and implemented FindRelatedProducts. - A long overdue fix to MSI_SetTargetPath. This should fix an error with some installers that where unable to change the target path. - Add functions to add the User UpgradeCodes. - A simple cleanup to only track the temp file if we need to have it laying around because the action is going on asynchronously. Otherwise clean up the temp file as the action finishes. - Introduce really basic scripting of actions. This is primarily to get the order of execution of the action correct since some custom actions can be scripted and others are run during the script building phase. - Perform ExecuteAction at UILevel 2. - Rework CreateShortcuts to use MSI_IterateRecords. - Properly handle -1 as a registry key root. - Rework SelfRegModules to use MSI_IterateRecords. - Rework component, feature and file loading to use MSI_IterateRecords. - Rework RegisterFonts to use MSI_IterateRecords. - Rework WriteIniValues to use MSI_IterateRecords. - Rework PublishProduct to use MSI_IterateRecords. - Rework RegisterTypeLibraries to use MSI_IterateR - Rework LaunchConditions to use MSI_IterateRecord - Rework CostFinalize to use MSI_IterateRecords. - Rework WriteRegistryValues to use MSI_IterateRecords. - Rework CreateFolders to use MSI_IterateRecords. - Use MSI_IterateRecords for processing actions. Some whitespace cleanup and replace a comment block I did not want to remove. - Flesh out the remaining keys in RegisterProduct. - Extending upon Mike McCormack's cleanup to use MSI_RecordGetString. - Register the Product Version also. Also help plug some memory leaks pointed out by Mike McCormack. - Avoid a loop where a parent's parent refers to itself as its parent. - Added module upgrade.c and implemented FindRelatedProducts. - Set the Preselected property if appropriate (relevant to MigrateFeatureStates when implemented). - Write out Product Language and Product Icon to the registry. - Write out UpgradeCodes to the registry to allow for future upgrades. - Don't get caught in loops on parent progids. - Since multiple progids can refer to 1 class we need to check if that class is isntalled instead of just relying on having it set the InstallMe variable. - Add install_on_demand for Extension servers also. currently defaulting to TRUE. - Extension need to have 1 verb to mark the given progid to be installed. - Do not loop if a ProgId's Parent Index it itself. - Add a VersionIndIndex for tracking version independent fields for the ProgIds properly. - Print a message for skipped actions in ProcessExecSequence like in the UISequence. - Do not change a features state to Advertise if it explicitly disallows it. - For typelibs index 1 do not add \\1 to the path. This cleans up registry diffs with native MSI. - Register the FileType and correct short vs long path problems with InprocServer32. Also add install_on_demand boolean for future expansion. - First pass at writing out CurVer keys for ProgIds. Also print a message for the actions we skip. Lines up with native MSI output logs for ease of comparison. - A big rewrite of the whole RegisterClass, RegisterProgId, RegisterExtension and RegisterMIME actions. We now handle verbs properly, handle dependancies and such properly and keep track of what we need to register and what we do not properly. - Allow control events to return codes to halt the processing of event. Needed for the SetTargetPath Event. - Fix situations where TARGETDIR is set to a non \ terminated path. Fixes a few installers. - Redo how we extract files from a cabinet in order to dramatically improve performance, especially if picking and choosing files out of the cabinet. - Duplicate files should not fail if unable to get Destination Directory. - Use MSI_IterateRecords for DuplicateFiles. - Add UI messages to FindRelatedProducts. - Reduce unneeded includes. - A "1" is returned not a 1 for AssignmentType. Also as a bit more to the FIXME message. - Add Language to the values we can query with MsiGetProductInfo. - Correct a crash if the length buffer is NULL. - Locate where a buffer size is not being set and correctly handle the buffer size conversion from W to A (with help from Robert Shearman). - Make sure the TRACE statements do not spew garbage by using debugstr_wn. - Restrict deformating of nested index keys [[1]]. - Introduce the beginning of group deformating {}. - Implement the [!file] format to produce the short filename. Stefan Huehner - Fix more -Wstrict-prototypes warnings. Francois Gouget - Assorted spelling fixes. Dmitry Timoshkov - Make more of the OLE interface vtables const. svn path=/trunk/; revision=17034 --- reactos/include/wine/msvcrt/fcntl.h | 10 + reactos/lib/msi/Makefile.in | 8 +- reactos/lib/msi/action.c | 5514 ++++++--------------------- reactos/lib/msi/action.h | 158 +- reactos/lib/msi/classes.c | 1602 ++++++++ reactos/lib/msi/cond.tab.c | 4 +- reactos/lib/msi/cond.tab.h | 115 +- reactos/lib/msi/cond.y | 4 +- reactos/lib/msi/create.c | 10 +- reactos/lib/msi/custom.c | 144 +- reactos/lib/msi/database.c | 8 +- reactos/lib/msi/dialog.c | 819 +++- reactos/lib/msi/events.c | 396 ++ reactos/lib/msi/files.c | 759 ++++ reactos/lib/msi/format.c | 224 +- reactos/lib/msi/helpers.c | 913 +++++ reactos/lib/msi/insert.c | 6 +- reactos/lib/msi/install.c | 587 +++ reactos/lib/msi/msi.c | 52 +- reactos/lib/msi/msi.spec | 4 +- reactos/lib/msi/msi.xml | 7 + reactos/lib/msi/msipriv.h | 68 +- reactos/lib/msi/msiquery.c | 81 +- reactos/lib/msi/order.c | 6 +- reactos/lib/msi/package.c | 3 +- reactos/lib/msi/preview.c | 3 +- reactos/lib/msi/query.h | 45 +- reactos/lib/msi/record.c | 75 +- reactos/lib/msi/registry.c | 35 + reactos/lib/msi/select.c | 6 +- reactos/lib/msi/sql.tab.c | 633 ++- reactos/lib/msi/sql.tab.h | 490 +-- reactos/lib/msi/sql.y | 194 +- reactos/lib/msi/suminfo.c | 18 +- reactos/lib/msi/table.c | 12 +- reactos/lib/msi/tokenize.c | 2 +- reactos/lib/msi/update.c | 8 +- reactos/lib/msi/upgrade.c | 228 ++ reactos/lib/msi/where.c | 3 +- reactos/w32api/include/msi.h | 46 +- reactos/w32api/include/msidefs.h | 54 + reactos/w32api/include/msiquery.h | 84 +- 42 files changed, 7931 insertions(+), 5507 deletions(-) create mode 100644 reactos/include/wine/msvcrt/fcntl.h create mode 100644 reactos/lib/msi/classes.c create mode 100644 reactos/lib/msi/events.c create mode 100644 reactos/lib/msi/files.c create mode 100644 reactos/lib/msi/helpers.c create mode 100644 reactos/lib/msi/install.c create mode 100644 reactos/lib/msi/upgrade.c diff --git a/reactos/include/wine/msvcrt/fcntl.h b/reactos/include/wine/msvcrt/fcntl.h new file mode 100644 index 00000000000..f914f088840 --- /dev/null +++ b/reactos/include/wine/msvcrt/fcntl.h @@ -0,0 +1,10 @@ +#ifndef __WINE_MSVCRT_FCNTL_H +#define __WINE_MSVCRT_FCNTL_H + +/* + * Compatibility header + */ + +#include + +#endif /* __WINE_MSVCRT_FCNTL_H */ diff --git a/reactos/lib/msi/Makefile.in b/reactos/lib/msi/Makefile.in index 12f85fdf719..38098fab66f 100644 --- a/reactos/lib/msi/Makefile.in +++ b/reactos/lib/msi/Makefile.in @@ -4,21 +4,26 @@ SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = msi.dll IMPORTLIB = libmsi.$(IMPLIBEXT) -IMPORTS = shell32 cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32 +IMPORTS = shell32 shlwapi cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32 EXTRALIBS = -luuid $(LIBUNICODE) C_SRCS = \ action.c \ appsearch.c \ + classes.c \ create.c \ custom.c \ database.c \ delete.c \ dialog.c \ distinct.c \ + events.c \ + files.c \ format.c \ handle.c \ + helpers.c \ insert.c \ + install.c \ msi.c \ msiquery.c \ order.c \ @@ -33,6 +38,7 @@ C_SRCS = \ table.c \ tokenize.c \ update.c \ + upgrade.c \ where.c RC_SRCS = msi.rc diff --git a/reactos/lib/msi/action.c b/reactos/lib/msi/action.c index 336a4a863c1..6f6ca2e12c9 100644 --- a/reactos/lib/msi/action.c +++ b/reactos/lib/msi/action.c @@ -1,7 +1,7 @@ /* * Implementation of the Microsoft Installer (msi.dll) * - * Copyright 2004 Aric Stewart for CodeWeavers + * 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 @@ -27,7 +27,6 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/stand */ #include -#include #define COBJMACROS @@ -36,15 +35,8 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/stand #include "winerror.h" #include "winreg.h" #include "wine/debug.h" -#include "fdi.h" -#include "msi.h" -#include "msiquery.h" #include "msidefs.h" -#include "fcntl.h" -#include "objbase.h" -#include "objidl.h" #include "msipriv.h" -#include "winnls.h" #include "winuser.h" #include "shlobj.h" #include "wine/unicode.h" @@ -62,8 +54,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran); static UINT ACTION_ProcessUISequence(MSIPACKAGE *package); static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI); -static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, - LPWSTR *FilePath); /* * action handlers @@ -75,17 +65,11 @@ static UINT ACTION_CostInitialize(MSIPACKAGE *package); static UINT ACTION_CreateFolders(MSIPACKAGE *package); static UINT ACTION_CostFinalize(MSIPACKAGE *package); static UINT ACTION_FileCost(MSIPACKAGE *package); -static UINT ACTION_InstallFiles(MSIPACKAGE *package); -static UINT ACTION_DuplicateFiles(MSIPACKAGE *package); static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package); static UINT ACTION_InstallInitialize(MSIPACKAGE *package); static UINT ACTION_InstallValidate(MSIPACKAGE *package); static UINT ACTION_ProcessComponents(MSIPACKAGE *package); static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package); -static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package); -static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package); -static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package); -static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package); static UINT ACTION_RegisterUser(MSIPACKAGE *package); static UINT ACTION_CreateShortcuts(MSIPACKAGE *package); static UINT ACTION_PublishProduct(MSIPACKAGE *package); @@ -101,26 +85,18 @@ static UINT ACTION_ExecuteAction(MSIPACKAGE *package); static UINT ACTION_RegisterFonts(MSIPACKAGE *package); static UINT ACTION_PublishComponents(MSIPACKAGE *package); - /* * consts and values used */ -static const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0}; -static const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0}; -static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0}; -static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0}; -static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0}; static const WCHAR c_colon[] = {'C',':','\\',0}; -static const WCHAR szProductCode[]= - {'P','r','o','d','u','c','t','C','o','d','e',0}; -static const WCHAR cszbs[]={'\\',0}; + const static WCHAR szCreateFolders[] = {'C','r','e','a','t','e','F','o','l','d','e','r','s',0}; const static WCHAR szCostFinalize[] = {'C','o','s','t','F','i','n','a','l','i','z','e',0}; -const static WCHAR szInstallFiles[] = +const WCHAR szInstallFiles[] = {'I','n','s','t','a','l','l','F','i','l','e','s',0}; -const static WCHAR szDuplicateFiles[] = +const WCHAR szDuplicateFiles[] = {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0}; const static WCHAR szWriteRegistryValues[] = {'W','r','i','t','e','R','e','g','i','s','t','r','y', @@ -140,9 +116,9 @@ const static WCHAR szProcessComponents[] = const static WCHAR szRegisterTypeLibraries[] = {'R','e','g','i','s','t','e','r','T','y','p','e', 'L','i','b','r','a','r','i','e','s',0}; -const static WCHAR szRegisterClassInfo[] = +const WCHAR szRegisterClassInfo[] = {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0}; -const static WCHAR szRegisterProgIdInfo[] = +const WCHAR szRegisterProgIdInfo[] = {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0}; const static WCHAR szCreateShortcuts[] = {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0}; @@ -167,7 +143,7 @@ const static WCHAR szForceReboot[] = {'F','o','r','c','e','R','e','b','o','o','t',0}; const static WCHAR szResolveSource[] = {'R','e','s','o','l','v','e','S','o','u','r','c','e',0}; -const static WCHAR szAppSearch[] = +const WCHAR szAppSearch[] = {'A','p','p','S','e','a','r','c','h',0}; const static WCHAR szAllocateRegistrySpace[] = {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y', @@ -182,7 +158,7 @@ const static WCHAR szDisableRollback[] = {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0}; const static WCHAR szExecuteAction[] = {'E','x','e','c','u','t','e','A','c','t','i','o','n',0}; -const static WCHAR szFindRelatedProducts[] = +const WCHAR szFindRelatedProducts[] = {'F','i','n','d','R','e','l','a','t','e','d', 'P','r','o','d','u','c','t','s',0}; const static WCHAR szInstallAdminPackage[] = @@ -193,10 +169,10 @@ const static WCHAR szInstallSFPCatalogFile[] = 'F','i','l','e',0}; const static WCHAR szIsolateComponents[] = {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0}; -const static WCHAR szMigrateFeatureStates[] = +const WCHAR szMigrateFeatureStates[] = {'M','i','g','r','a','t','e','F','e','a','t','u','r','e', 'S','t','a','t','e','s',0}; -const static WCHAR szMoveFiles[] = +const WCHAR szMoveFiles[] = {'M','o','v','e','F','i','l','e','s',0}; const static WCHAR szMsiPublishAssemblies[] = {'M','s','i','P','u','b','l','i','s','h', @@ -208,31 +184,31 @@ const static WCHAR szInstallODBC[] = {'I','n','s','t','a','l','l','O','D','B','C',0}; const static WCHAR szInstallServices[] = {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0}; -const static WCHAR szPatchFiles[] = +const WCHAR szPatchFiles[] = {'P','a','t','c','h','F','i','l','e','s',0}; const static WCHAR szPublishComponents[] = {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0}; const static WCHAR szRegisterComPlus[] = {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0}; -const static WCHAR szRegisterExtensionInfo[] = +const WCHAR szRegisterExtensionInfo[] = {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n', 'I','n','f','o',0}; const static WCHAR szRegisterFonts[] = {'R','e','g','i','s','t','e','r','F','o','n','t','s',0}; -const static WCHAR szRegisterMIMEInfo[] = +const WCHAR szRegisterMIMEInfo[] = {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0}; const static WCHAR szRegisterUser[] = {'R','e','g','i','s','t','e','r','U','s','e','r',0}; -const static WCHAR szRemoveDuplicateFiles[] = +const WCHAR szRemoveDuplicateFiles[] = {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e', 'F','i','l','e','s',0}; const static 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}; -const static WCHAR szRemoveExistingProducts[] = +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}; -const static WCHAR szRemoveFiles[] = +const WCHAR szRemoveFiles[] = {'R','e','m','o','v','e','F','i','l','e','s',0}; const static WCHAR szRemoveFolders[] = {'R','e','m','o','v','e','F','o','l','d','e','r','s',0}; @@ -262,19 +238,19 @@ const static WCHAR szUnpublishComponents[] = 'C','o','m','p','o','n','e','n','t','s',0}; const static WCHAR szUnpublishFeatures[] = {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0}; -const static WCHAR szUnregisterClassInfo[] = +const WCHAR szUnregisterClassInfo[] = {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s', 'I','n','f','o',0}; const static WCHAR szUnregisterComPlus[] = {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0}; -const static WCHAR szUnregisterExtensionInfo[] = +const WCHAR szUnregisterExtensionInfo[] = {'U','n','r','e','g','i','s','t','e','r', 'E','x','t','e','n','s','i','o','n','I','n','f','o',0}; const static WCHAR szUnregisterFonts[] = {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0}; -const static WCHAR szUnregisterMIMEInfo[] = +const WCHAR szUnregisterMIMEInfo[] = {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0}; -const static WCHAR szUnregisterProgIdInfo[] = +const WCHAR szUnregisterProgIdInfo[] = {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d', 'I','n','f','o',0}; const static WCHAR szUnregisterTypeLibraries[] = @@ -305,7 +281,7 @@ static struct _actions StandardActions[] = { { szDuplicateFiles, ACTION_DuplicateFiles }, { szExecuteAction, ACTION_ExecuteAction }, { szFileCost, ACTION_FileCost }, - { szFindRelatedProducts, NULL}, + { szFindRelatedProducts, ACTION_FindRelatedProducts }, { szForceReboot, ACTION_ForceReboot }, { szInstallAdminPackage, NULL}, { szInstallExecute, ACTION_InstallExecute }, @@ -371,343 +347,22 @@ static struct _actions StandardActions[] = { }; -/******************************************************** - * helper functions to get around current HACKS and such +/******************************************************** + * helper functions ********************************************************/ -inline static void reduce_to_longfilename(WCHAR* filename) + +static void ce_actiontext(MSIPACKAGE* package, LPCWSTR action) { - LPWSTR p = strchrW(filename,'|'); - if (p) - memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR)); -} - -inline static void reduce_to_shortfilename(WCHAR* filename) -{ - LPWSTR p = strchrW(filename,'|'); - if (p) - *p = 0; -} - -WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index) -{ - UINT rc; - DWORD sz; - LPWSTR ret; - - sz = 0; - if (MSI_RecordIsNull(row,index)) - return NULL; - - rc = MSI_RecordGetStringW(row,index,NULL,&sz); - - /* having an empty string is different than NULL */ - if (sz == 0) - { - ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)); - ret[0] = 0; - return ret; - } - - sz ++; - ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR)); - rc = MSI_RecordGetStringW(row,index,ret,&sz); - if (rc!=ERROR_SUCCESS) - { - ERR("Unable to load dynamic string\n"); - HeapFree(GetProcessHeap(), 0, ret); - ret = NULL; - } - return ret; -} - -LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc) -{ - DWORD sz = 0; - LPWSTR str; - UINT r; - - r = MSI_GetPropertyW(package, prop, NULL, &sz); - if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA) - { - if (rc) - *rc = r; - return NULL; - } - sz++; - str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR)); - r = MSI_GetPropertyW(package, prop, str, &sz); - if (r != ERROR_SUCCESS) - { - HeapFree(GetProcessHeap(),0,str); - str = NULL; - } - if (rc) - *rc = r; - return str; -} - -int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component ) -{ - int rc = -1; - DWORD i; - - for (i = 0; i < package->loaded_components; i++) - { - if (strcmpW(Component,package->components[i].Component)==0) - { - rc = i; - break; - } - } - return rc; -} - -int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature ) -{ - int rc = -1; - DWORD i; - - for (i = 0; i < package->loaded_features; i++) - { - if (strcmpW(Feature,package->features[i].Feature)==0) - { - rc = i; - break; - } - } - return rc; -} - -int get_loaded_file(MSIPACKAGE* package, LPCWSTR file) -{ - int rc = -1; - DWORD i; - - for (i = 0; i < package->loaded_files; i++) - { - if (strcmpW(file,package->files[i].File)==0) - { - rc = i; - break; - } - } - return rc; -} - -int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path) -{ - DWORD i; - DWORD index; - - if (!package) - return -2; - - for (i=0; i < package->loaded_files; i++) - if (strcmpW(package->files[i].File,name)==0) - return -1; - - index = package->loaded_files; - package->loaded_files++; - if (package->loaded_files== 1) - package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE)); - else - package->files = HeapReAlloc(GetProcessHeap(),0, - package->files , package->loaded_files * sizeof(MSIFILE)); - - memset(&package->files[index],0,sizeof(MSIFILE)); - - package->files[index].File = strdupW(name); - package->files[index].TargetPath = strdupW(path); - package->files[index].Temporary = TRUE; - - TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File)); - - return 0; -} - -static void remove_tracked_tempfiles(MSIPACKAGE* package) -{ - DWORD i; - - if (!package) - return; - - for (i = 0; i < package->loaded_files; i++) - { - if (package->files[i].Temporary) - { - TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath)); - DeleteFileW(package->files[i].TargetPath); - } - - } -} - -/* wrapper to resist a need for a full rewrite right now */ -DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data ) -{ - if (ptr) - { - MSIRECORD *rec = MSI_CreateRecord(1); - DWORD size = 0; - - MSI_RecordSetStringW(rec,0,ptr); - MSI_FormatRecordW(package,rec,NULL,&size); - if (size >= 0) - { - size++; - *data = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR)); - if (size > 1) - MSI_FormatRecordW(package,rec,*data,&size); - else - *data[0] = 0; - msiobj_release( &rec->hdr ); - return sizeof(WCHAR)*size; - } - msiobj_release( &rec->hdr ); - } - - *data = NULL; - return 0; -} - -/* Called when the package is being closed */ -void ACTION_free_package_structures( MSIPACKAGE* package) -{ - INT i; - - TRACE("Freeing package action data\n"); - - remove_tracked_tempfiles(package); - - /* No dynamic buffers in features */ - if (package->features && package->loaded_features > 0) - HeapFree(GetProcessHeap(),0,package->features); - - for (i = 0; i < package->loaded_folders; i++) - { - HeapFree(GetProcessHeap(),0,package->folders[i].Directory); - HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault); - HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault); - HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget); - HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource); - HeapFree(GetProcessHeap(),0,package->folders[i].Property); - } - if (package->folders && package->loaded_folders > 0) - HeapFree(GetProcessHeap(),0,package->folders); - - for (i = 0; i < package->loaded_components; i++) - HeapFree(GetProcessHeap(),0,package->components[i].FullKeypath); - - if (package->components && package->loaded_components > 0) - HeapFree(GetProcessHeap(),0,package->components); - - for (i = 0; i < package->loaded_files; i++) - { - HeapFree(GetProcessHeap(),0,package->files[i].File); - HeapFree(GetProcessHeap(),0,package->files[i].FileName); - HeapFree(GetProcessHeap(),0,package->files[i].ShortName); - HeapFree(GetProcessHeap(),0,package->files[i].Version); - HeapFree(GetProcessHeap(),0,package->files[i].Language); - HeapFree(GetProcessHeap(),0,package->files[i].SourcePath); - HeapFree(GetProcessHeap(),0,package->files[i].TargetPath); - } - - if (package->files && package->loaded_files > 0) - HeapFree(GetProcessHeap(),0,package->files); - - for (i = 0; i < package->DeferredActionCount; i++) - HeapFree(GetProcessHeap(),0,package->DeferredAction[i]); - HeapFree(GetProcessHeap(),0,package->DeferredAction); - - for (i = 0; i < package->CommitActionCount; i++) - HeapFree(GetProcessHeap(),0,package->CommitAction[i]); - HeapFree(GetProcessHeap(),0,package->CommitAction); - - HeapFree(GetProcessHeap(),0,package->PackagePath); -} - -static void 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); -} - -static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record) -{ - 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}; - WCHAR message[1024]; - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - DWORD size; - - if (!package->LastAction || strcmpW(package->LastAction,action)) - { - rc = MSI_OpenQuery(package->db, &view, Query_t, action); - if (rc != ERROR_SUCCESS) - return; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return; - } - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return; - } - - if (MSI_RecordIsNull(row,3)) - { - msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return; - } - - /* update the cached actionformat */ - HeapFree(GetProcessHeap(),0,package->ActionFormat); - package->ActionFormat = load_dynamic_stringW(row,3); - - HeapFree(GetProcessHeap(),0,package->LastAction); - package->LastAction = strdupW(action); - - msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); - } - - MSI_RecordSetStringW(record,0,package->ActionFormat); - size = 1024; - MSI_FormatRecordW(package,record,message,&size); + static const WCHAR szActionText[] = + {'A','c','t','i','o','n','T','e','x','t',0}; + MSIRECORD *row; row = MSI_CreateRecord(1); - MSI_RecordSetStringW(row,1,message); - - MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row); + MSI_RecordSetStringW(row,1,action); + ControlEvent_FireSubscribedEvent(package,szActionText, row); msiobj_release(&row->hdr); } - static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action) { static const WCHAR template_s[]= @@ -722,44 +377,25 @@ static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action) ' ','\'','%','s','\'',0}; WCHAR message[1024]; WCHAR timet[0x100]; - UINT rc; - MSIQUERY * view; MSIRECORD * row = 0; - WCHAR *ActionText=NULL; + LPCWSTR ActionText; GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100); - rc = MSI_OpenQuery(package->db, &view, Query_t, action); - if (rc != ERROR_SUCCESS) + row = MSI_QueryGetRecord( package->db, Query_t, action ); + if (!row) return; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return; - } - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return; - } - ActionText = load_dynamic_stringW(row,2); - msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); + ActionText = MSI_RecordGetString(row,2); sprintfW(message,template_s,timet,action,ActionText); + msiobj_release(&row->hdr); row = MSI_CreateRecord(1); MSI_RecordSetStringW(row,1,message); MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row); msiobj_release(&row->hdr); - HeapFree(GetProcessHeap(),0,ActionText); } static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, @@ -791,82 +427,6 @@ static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, msiobj_release(&row->hdr); } -/* - * 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 \ - * - */ -static LPWSTR build_directory_name(DWORD count, ...) -{ - DWORD sz = 1, i; - LPWSTR dir; - va_list va; - - va_start(va,count); - for(i=0; icomponents[index].Installed == check) - return FALSE; - - if (package->components[index].ActionRequest == check) - return TRUE; - else - return FALSE; -} - -static BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE* package, INT index, - INSTALLSTATE check ) -{ - if (package->features[index].Installed == check) - return FALSE; - - if (package->features[index].ActionRequest == check) - return TRUE; - else - return FALSE; -} - - /**************************************************** * TOP level entry points *****************************************************/ @@ -883,7 +443,9 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath, static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0}; MSI_SetPropertyW(package, szAction, szInstall); - package->ExecuteSequenceRun = FALSE; + + package->script = HeapAlloc(GetProcessHeap(),0,sizeof(MSISCRIPT)); + memset(package->script,0,sizeof(MSISCRIPT)); if (szPackagePath) { @@ -993,15 +555,17 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath, rc = ERROR_SUCCESS; } + package->script->CurrentlyScripting= FALSE; + /* process the ending type action */ if (rc == ERROR_SUCCESS) ACTION_PerformActionSequence(package,-1,ui); else if (rc == ERROR_INSTALL_USEREXIT) ACTION_PerformActionSequence(package,-2,ui); - else if (rc == ERROR_FUNCTION_FAILED) - ACTION_PerformActionSequence(package,-3,ui); else if (rc == ERROR_INSTALL_SUSPEND) ACTION_PerformActionSequence(package,-4,ui); + else /* failed */ + ACTION_PerformActionSequence(package,-3,ui); /* finish up running custom actions */ ACTION_FinishCustomActions(package); @@ -1011,10 +575,7 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath, static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI) { - MSIQUERY * view; - UINT rc; - WCHAR buffer[0x100]; - DWORD sz = 0x100; + UINT rc = ERROR_SUCCESS; MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', @@ -1029,67 +590,39 @@ static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI) ' ', '=',' ','%','i',0}; if (UI) - rc = MSI_OpenQuery(package->db, &view, UISeqQuery, seq); + row = MSI_QueryGetRecord(package->db, UISeqQuery, seq); else - rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq); + row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq); - if (rc == ERROR_SUCCESS) + if (row) { - rc = MSI_ViewExecute(view, 0); + LPCWSTR action, cond; - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - goto end; - } - TRACE("Running the actions\n"); - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - goto end; - } - /* check conditions */ - if (!MSI_RecordIsNull(row,2)) + cond = MSI_RecordGetString(row,2); + if (cond) { - LPWSTR cond = NULL; - cond = load_dynamic_stringW(row,2); - - if (cond) - { - /* this is a hack to skip errors in the condition code */ - if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE) - { - HeapFree(GetProcessHeap(),0,cond); - msiobj_release(&row->hdr); - goto end; - } - else - HeapFree(GetProcessHeap(),0,cond); - } + /* this is a hack to skip errors in the condition code */ + if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE) + goto end; } - sz=0x100; - rc = MSI_RecordGetStringW(row,1,buffer,&sz); - if (rc != ERROR_SUCCESS) + action = MSI_RecordGetString(row,1); + if (!action) { - ERR("Error is %x\n",rc); - msiobj_release(&row->hdr); + ERR("failed to fetch action\n"); + rc = ERROR_FUNCTION_FAILED; goto end; } if (UI) - rc = ACTION_PerformUIAction(package,buffer); + rc = ACTION_PerformUIAction(package,action); else - rc = ACTION_PerformAction(package,buffer); - msiobj_release(&row->hdr); + rc = ACTION_PerformAction(package,action,FALSE); end: - MSI_ViewClose(view); - msiobj_release(&view->hdr); + msiobj_release(&row->hdr); } else rc = ERROR_SUCCESS; @@ -1097,6 +630,51 @@ end: return rc; } +typedef struct { + MSIPACKAGE* package; + BOOL UI; +} iterate_action_param; + +static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param) +{ + iterate_action_param *iap= (iterate_action_param*)param; + UINT rc; + LPCWSTR cond, action; + + 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); + if (cond) + { + /* this is a hack to skip errors in the condition code */ + if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE) + { + TRACE("Skipping action: %s (condition is false)\n", + debugstr_w(action)); + return ERROR_SUCCESS; + } + } + + if (iap->UI) + rc = ACTION_PerformUIAction(iap->package,action); + else + rc = ACTION_PerformAction(iap->package,action,FALSE); + + if (rc == ERROR_FUNCTION_NOT_CALLED) + rc = ERROR_SUCCESS; + + if (rc != ERROR_SUCCESS) + ERR("Execution halted due to error (%i)\n",rc); + + return rc; +} + static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran) { MSIQUERY * view; @@ -1117,122 +695,41 @@ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran) ' ','\'', 'I','n','s','t','a','l','l', 'V','a','l','i','d','a','t','e','\'', 0}; INT seq = 0; + iterate_action_param iap; + iap.package = package; + iap.UI = FALSE; - if (package->ExecuteSequenceRun) + if (package->script->ExecuteSequenceRun) { TRACE("Execute Sequence already Run\n"); return ERROR_SUCCESS; } - package->ExecuteSequenceRun = TRUE; - + package->script->ExecuteSequenceRun = TRUE; + /* get the sequence number */ if (UIran) { - rc = MSI_DatabaseOpenViewW(package->db, IVQuery, &view); - if (rc != ERROR_SUCCESS) - return rc; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } + row = MSI_QueryGetRecord(package->db, IVQuery); + if( !row ) + return ERROR_FUNCTION_FAILED; seq = MSI_RecordGetInteger(row,1); msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); } rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq); if (rc == ERROR_SUCCESS) { - rc = MSI_ViewExecute(view, 0); + TRACE("Running the actions\n"); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - goto end; - } - - TRACE("Running the actions\n"); - - while (1) - { - WCHAR buffer[0x100]; - DWORD sz = 0x100; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - /* check conditions */ - if (!MSI_RecordIsNull(row,2)) - { - LPWSTR cond = NULL; - cond = load_dynamic_stringW(row,2); - - if (cond) - { - /* this is a hack to skip errors in the condition code */ - if (MSI_EvaluateConditionW(package, cond) == - MSICONDITION_FALSE) - { - HeapFree(GetProcessHeap(),0,cond); - msiobj_release(&row->hdr); - continue; - } - else - HeapFree(GetProcessHeap(),0,cond); - } - } - - sz=0x100; - rc = MSI_RecordGetStringW(row,1,buffer,&sz); - if (rc != ERROR_SUCCESS) - { - ERR("Error is %x\n",rc); - msiobj_release(&row->hdr); - break; - } - - rc = ACTION_PerformAction(package,buffer); - - if (rc == ERROR_FUNCTION_NOT_CALLED) - rc = ERROR_SUCCESS; - - if (rc != ERROR_SUCCESS) - { - ERR("Execution halted due to error (%i)\n",rc); - msiobj_release(&row->hdr); - break; - } - - msiobj_release(&row->hdr); - } - - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap); msiobj_release(&view->hdr); } -end: return rc; } - static UINT ACTION_ProcessUISequence(MSIPACKAGE *package) { MSIQUERY * view; @@ -1245,113 +742,70 @@ static UINT ACTION_ProcessUISequence(MSIPACKAGE *package) '`','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}; - + iterate_action_param iap; + + iap.package = package; + iap.UI = TRUE; + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); if (rc == ERROR_SUCCESS) { - rc = MSI_ViewExecute(view, 0); - - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - goto end; - } - TRACE("Running the actions \n"); - while (1) - { - WCHAR buffer[0x100]; - DWORD sz = 0x100; - MSIRECORD * row = 0; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - /* check conditions */ - if (!MSI_RecordIsNull(row,2)) - { - LPWSTR cond = NULL; - cond = load_dynamic_stringW(row,2); - - if (cond) - { - /* this is a hack to skip errors in the condition code */ - if (MSI_EvaluateConditionW(package, cond) == - MSICONDITION_FALSE) - { - HeapFree(GetProcessHeap(),0,cond); - msiobj_release(&row->hdr); - continue; - } - else - HeapFree(GetProcessHeap(),0,cond); - } - } - - sz=0x100; - rc = MSI_RecordGetStringW(row,1,buffer,&sz); - if (rc != ERROR_SUCCESS) - { - ERR("Error is %x\n",rc); - msiobj_release(&row->hdr); - break; - } - - rc = ACTION_PerformUIAction(package,buffer); - - if (rc == ERROR_FUNCTION_NOT_CALLED) - rc = ERROR_SUCCESS; - - if (rc != ERROR_SUCCESS) - { - ERR("Execution halted due to error (%i)\n",rc); - msiobj_release(&row->hdr); - break; - } - - msiobj_release(&row->hdr); - } - - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap); msiobj_release(&view->hdr); } -end: return rc; } /******************************************************** * ACTION helper functions and functions that perform the actions *******************************************************/ -BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, UINT* rc) +static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, + UINT* rc, BOOL force ) { BOOL ret = FALSE; - + BOOL run = force; int i; + + if (!run && !package->script->CurrentlyScripting) + run = TRUE; + + if (!run) + { + if (strcmpW(action,szInstallFinalize) == 0 || + strcmpW(action,szInstallExecute) == 0 || + strcmpW(action,szInstallExecuteAgain) == 0) + run = TRUE; + } + i = 0; while (StandardActions[i].action != NULL) { if (strcmpW(StandardActions[i].action, action)==0) { - ui_actioninfo(package, action, TRUE, 0); - ui_actionstart(package, action); - if (StandardActions[i].handler) + ce_actiontext(package, action); + if (!run) { - *rc = StandardActions[i].handler(package); + ui_actioninfo(package, action, TRUE, 0); + *rc = schedule_action(package,INSTALL_SCRIPT,action); + ui_actioninfo(package, action, FALSE, *rc); } else { - FIXME("UNHANDLED Standard Action %s\n",debugstr_w(action)); - *rc = ERROR_SUCCESS; + ui_actionstart(package, action); + if (StandardActions[i].handler) + { + *rc = StandardActions[i].handler(package); + } + else + { + FIXME("UNHANDLED Standard Action %s\n",debugstr_w(action)); + *rc = ERROR_SUCCESS; + } } - ui_actioninfo(package, action, FALSE, *rc); ret = TRUE; break; } @@ -1360,28 +814,25 @@ BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, UINT* rc) return ret; } -BOOL ACTION_HandleDialogBox(MSIPACKAGE *package, LPCWSTR dialog, UINT* rc) +static BOOL ACTION_HandleDialogBox( MSIPACKAGE *package, LPCWSTR dialog, UINT* rc ) { BOOL ret = FALSE; - /* - * for the UI when we get that working - * if (ACTION_DialogBox(package,dialog) == ERROR_SUCCESS) { *rc = package->CurrentInstallState; ret = TRUE; } - */ return ret; } -BOOL ACTION_HandleCustomAction(MSIPACKAGE* package, LPCWSTR action, UINT* rc) +static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action, + UINT* rc, BOOL force ) { BOOL ret=FALSE; UINT arc; - arc = ACTION_CustomAction(package,action,FALSE); + arc = ACTION_CustomAction(package,action, force); if (arc != ERROR_CALL_NOT_IMPLEMENTED) { @@ -1399,17 +850,17 @@ BOOL ACTION_HandleCustomAction(MSIPACKAGE* package, LPCWSTR action, UINT* rc) * But until I get write access to the database that is hard, so I am going to * hack it to see if I can get something to run. */ -UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action) +UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force) { UINT rc = ERROR_SUCCESS; BOOL handled; TRACE("Performing action (%s)\n",debugstr_w(action)); - handled = ACTION_HandleStandardAction(package, action, &rc); + handled = ACTION_HandleStandardAction(package, action, &rc, force); if (!handled) - handled = ACTION_HandleCustomAction(package, action, &rc); + handled = ACTION_HandleCustomAction(package, action, &rc, force); if (!handled) { @@ -1428,10 +879,10 @@ UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action) TRACE("Performing action (%s)\n",debugstr_w(action)); - handled = ACTION_HandleStandardAction(package, action, &rc); + handled = ACTION_HandleStandardAction(package, action, &rc,TRUE); if (!handled) - handled = ACTION_HandleCustomAction(package, action, &rc); + handled = ACTION_HandleCustomAction(package, action, &rc, FALSE); if (!handled) handled = ACTION_HandleDialogBox(package, action, &rc); @@ -1448,60 +899,51 @@ UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action) return rc; } -/*********************************************************************** - * create_full_pathW - * - * Recursively create all directories in the path. - * - * shamelessly stolen from setupapi/queue.c + +/* + * Actual Action Handlers */ -static BOOL create_full_pathW(const WCHAR *path) + +static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param) { - BOOL ret = TRUE; - int len; - WCHAR *new_path; + MSIPACKAGE *package = (MSIPACKAGE*)param; + LPCWSTR dir; + LPWSTR full_path; + MSIRECORD *uirow; + MSIFOLDER *folder; - new_path = HeapAlloc(GetProcessHeap(), 0, (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)) + dir = MSI_RecordGetString(row,1); + if (!dir) { - 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(!create_full_pathW(new_path)) - { - ret = FALSE; - break; - } - new_path[len] = '\\'; + ERR("Unable to get folder id \n"); + return ERROR_SUCCESS; } - HeapFree(GetProcessHeap(), 0, new_path); - return ret; + full_path = resolve_folder(package,dir,FALSE,FALSE,&folder); + if (!full_path) + { + ERR("Unable to resolve folder id %s\n",debugstr_w(dir)); + return ERROR_SUCCESS; + } + + TRACE("Folder is %s\n",debugstr_w(full_path)); + + /* UI stuff */ + uirow = MSI_CreateRecord(1); + MSI_RecordSetStringW(uirow,1,full_path); + ui_actiondata(package,szCreateFolders,uirow); + msiobj_release( &uirow->hdr ); + + if (folder->State == 0) + create_full_pathW(full_path); + + folder->State = 3; + + HeapFree(GetProcessHeap(),0,full_path); + return ERROR_SUCCESS; } + /* * Also we cannot enable/disable components either, so for now I am just going * to do all the directories for all the components. @@ -1515,70 +957,12 @@ static UINT ACTION_CreateFolders(MSIPACKAGE *package) '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 }; UINT rc; MSIQUERY *view; - MSIFOLDER *folder; rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view ); if (rc != ERROR_SUCCESS) return ERROR_SUCCESS; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - WCHAR dir[0x100]; - LPWSTR full_path; - DWORD sz; - MSIRECORD *row = NULL, *uirow; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - sz=0x100; - rc = MSI_RecordGetStringW(row,1,dir,&sz); - - if (rc!= ERROR_SUCCESS) - { - ERR("Unable to get folder id \n"); - msiobj_release(&row->hdr); - continue; - } - - sz = MAX_PATH; - full_path = resolve_folder(package,dir,FALSE,FALSE,&folder); - if (!full_path) - { - ERR("Unable to resolve folder id %s\n",debugstr_w(dir)); - msiobj_release(&row->hdr); - continue; - } - - TRACE("Folder is %s\n",debugstr_w(full_path)); - - /* UI stuff */ - uirow = MSI_CreateRecord(1); - MSI_RecordSetStringW(uirow,1,full_path); - ui_actiondata(package,szCreateFolders,uirow); - msiobj_release( &uirow->hdr ); - - if (folder->State == 0) - create_full_pathW(full_path); - - folder->State = 3; - - msiobj_release(&row->hdr); - HeapFree(GetProcessHeap(),0,full_path); - } - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package); msiobj_release(&view->hdr); return rc; @@ -1602,7 +986,7 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row) memset(&package->components[index],0,sizeof(MSICOMPONENT)); - sz = 96; + sz = IDENTIFIER_SIZE; MSI_RecordGetStringW(row,1,package->components[index].Component,&sz); TRACE("Loading Component %s\n", @@ -1612,7 +996,7 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row) if (!MSI_RecordIsNull(row,2)) MSI_RecordGetStringW(row,2,package->components[index].ComponentId,&sz); - sz = 96; + sz = IDENTIFIER_SIZE; MSI_RecordGetStringW(row,3,package->components[index].Directory,&sz); package->components[index].Attributes = MSI_RecordGetInteger(row,4); @@ -1620,7 +1004,7 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row) sz = 0x100; MSI_RecordGetStringW(row,5,package->components[index].Condition,&sz); - sz = 96; + sz = IDENTIFIER_SIZE; MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz); package->components[index].Installed = INSTALLSTATE_ABSENT; @@ -1632,8 +1016,68 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row) return index; } -static void load_feature(MSIPACKAGE* package, MSIRECORD * row) +typedef struct { + MSIPACKAGE *package; + INT index; + INT cnt; +} _ilfs; + +static UINT iterate_component_check(MSIRECORD *row, LPVOID param) { + _ilfs* ilfs= (_ilfs*)param; + INT c_indx; + + c_indx = load_component(ilfs->package,row); + + ilfs->package->features[ilfs->index].Components[ilfs->cnt] = c_indx; + ilfs->package->features[ilfs->index].ComponentCount ++; + TRACE("Loaded new component to index %i\n",c_indx); + + return ERROR_SUCCESS; +} + +static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param) +{ + _ilfs* ilfs= (_ilfs*)param; + LPCWSTR component; + DWORD rc; + INT c_indx; + INT cnt = ilfs->package->features[ilfs->index].ComponentCount; + MSIQUERY * view; + 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}; + + component = MSI_RecordGetString(row,1); + + /* check to see if the component is already loaded */ + c_indx = get_loaded_component(ilfs->package,component); + if (c_indx != -1) + { + TRACE("Component %s already loaded at %i\n", debugstr_w(component), + c_indx); + ilfs->package->features[ilfs->index].Components[cnt] = c_indx; + ilfs->package->features[ilfs->index].ComponentCount ++; + return ERROR_SUCCESS; + } + + rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + ilfs->cnt = cnt; + rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs); + msiobj_release( &view->hdr ); + + return ERROR_SUCCESS; +} + +static UINT load_feature(MSIRECORD * row, LPVOID param) +{ + MSIPACKAGE* package = (MSIPACKAGE*)param; int index = package->loaded_features; DWORD sz; static const WCHAR Query1[] = @@ -1643,17 +1087,12 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) 'C','o','m','p','o','n','e','n','t','s','`',' ', 'W','H','E','R','E',' ', '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0}; - static const WCHAR Query2[] = - {'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}; MSIQUERY * view; - MSIQUERY * view2; - MSIRECORD * row2; - MSIRECORD * row3; UINT rc; + _ilfs ilfs; + + ilfs.package = package; + ilfs.index = index; /* fill in the data */ @@ -1666,12 +1105,12 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) memset(&package->features[index],0,sizeof(MSIFEATURE)); - sz = 96; + sz = IDENTIFIER_SIZE; MSI_RecordGetStringW(row,1,package->features[index].Feature,&sz); TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature)); - sz = 96; + sz = IDENTIFIER_SIZE; if (!MSI_RecordIsNull(row,2)) MSI_RecordGetStringW(row,2,package->features[index].Feature_Parent,&sz); @@ -1688,7 +1127,7 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) package->features[index].Level= MSI_RecordGetInteger(row,6); - sz = 96; + sz = IDENTIFIER_SIZE; if (!MSI_RecordIsNull(row,7)) MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz); @@ -1700,84 +1139,22 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) /* load feature components */ - rc = MSI_OpenQuery(package->db, &view, Query1, package->features[index].Feature); + rc = MSI_OpenQuery(package->db, &view, Query1, + package->features[index].Feature); if (rc != ERROR_SUCCESS) - return; - rc = MSI_ViewExecute(view,0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return; - } - while (1) - { - DWORD sz = 0x100; - WCHAR buffer[0x100]; - DWORD rc; - INT c_indx; - INT cnt = package->features[index].ComponentCount; + return ERROR_SUCCESS; - rc = MSI_ViewFetch(view,&row2); - if (rc != ERROR_SUCCESS) - break; - - sz = 0x100; - MSI_RecordGetStringW(row2,1,buffer,&sz); - - /* check to see if the component is already loaded */ - c_indx = get_loaded_component(package,buffer); - if (c_indx != -1) - { - TRACE("Component %s already loaded at %i\n", debugstr_w(buffer), - c_indx); - package->features[index].Components[cnt] = c_indx; - package->features[index].ComponentCount ++; - msiobj_release( &row2->hdr ); - continue; - } - - rc = MSI_OpenQuery(package->db, &view2, Query2, buffer); - if (rc != ERROR_SUCCESS) - { - msiobj_release( &row2->hdr ); - continue; - } - rc = MSI_ViewExecute(view2,0); - if (rc != ERROR_SUCCESS) - { - msiobj_release( &row2->hdr ); - MSI_ViewClose(view2); - msiobj_release( &view2->hdr ); - continue; - } - while (1) - { - DWORD rc; - - rc = MSI_ViewFetch(view2,&row3); - if (rc != ERROR_SUCCESS) - break; - c_indx = load_component(package,row3); - msiobj_release( &row3->hdr ); - - package->features[index].Components[cnt] = c_indx; - package->features[index].ComponentCount ++; - TRACE("Loaded new component to index %i\n",c_indx); - } - MSI_ViewClose(view2); - msiobj_release( &view2->hdr ); - msiobj_release( &row2->hdr ); - } - MSI_ViewClose(view); + MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs); msiobj_release(&view->hdr); + + return ERROR_SUCCESS; } -static UINT load_file(MSIPACKAGE* package, MSIRECORD * row) +static UINT load_file(MSIRECORD *row, LPVOID param) { + MSIPACKAGE* package = (MSIPACKAGE*)param; DWORD index = package->loaded_files; - DWORD i; - LPWSTR buffer; + LPCWSTR component; /* fill in the data */ @@ -1791,18 +1168,13 @@ static UINT load_file(MSIPACKAGE* package, MSIRECORD * row) memset(&package->files[index],0,sizeof(MSIFILE)); package->files[index].File = load_dynamic_stringW(row, 1); - buffer = load_dynamic_stringW(row, 2); - package->files[index].ComponentIndex = -1; - for (i = 0; i < package->loaded_components; i++) - if (strcmpW(package->components[i].Component,buffer)==0) - { - package->files[index].ComponentIndex = i; - break; - } + component = MSI_RecordGetString(row, 2); + package->files[index].ComponentIndex = get_loaded_component(package, + component); + if (package->files[index].ComponentIndex == -1) - ERR("Unfound Component %s\n",debugstr_w(buffer)); - HeapFree(GetProcessHeap(), 0, buffer); + ERR("Unfound Component %s\n",debugstr_w(component)); package->files[index].FileName = load_dynamic_stringW(row,3); reduce_to_longfilename(package->files[index].FileName); @@ -1827,7 +1199,6 @@ static UINT load_file(MSIPACKAGE* package, MSIRECORD * row) static UINT load_all_files(MSIPACKAGE *package) { MSIQUERY * view; - MSIRECORD * row; UINT rc; static const WCHAR Query[] = {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', @@ -1840,27 +1211,8 @@ static UINT load_all_files(MSIPACKAGE *package) rc = MSI_DatabaseOpenViewW(package->db, Query, &view); if (rc != ERROR_SUCCESS) return ERROR_SUCCESS; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return ERROR_SUCCESS; - } - while (1) - { - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - load_file(package,row); - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, load_file, package); msiobj_release(&view->hdr); return ERROR_SUCCESS; @@ -1883,7 +1235,6 @@ static UINT load_all_files(MSIPACKAGE *package) static UINT ACTION_CostInitialize(MSIPACKAGE *package) { MSIQUERY * view; - MSIRECORD * row; UINT rc; static const WCHAR Query_all[] = {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', @@ -1904,25 +1255,8 @@ static UINT ACTION_CostInitialize(MSIPACKAGE *package) rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view); if (rc != ERROR_SUCCESS) return rc; - rc = MSI_ViewExecute(view,0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - while (1) - { - DWORD rc; - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - break; - - load_feature(package,row); - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, load_feature, package); msiobj_release(&view->hdr); load_all_files(package); @@ -1930,6 +1264,31 @@ static UINT ACTION_CostInitialize(MSIPACKAGE *package) return ERROR_SUCCESS; } +static UINT execute_script(MSIPACKAGE *package, UINT script ) +{ + int i; + UINT rc = ERROR_SUCCESS; + + TRACE("Executing Script %i\n",script); + + for (i = 0; i < package->script->ActionCount[script]; i++) + { + LPWSTR action; + action = package->script->Actions[script][i]; + ui_actionstart(package, action); + TRACE("Executing Action (%s)\n",debugstr_w(action)); + rc = ACTION_PerformAction(package, action, TRUE); + HeapFree(GetProcessHeap(),0,package->script->Actions[script][i]); + if (rc != ERROR_SUCCESS) + break; + } + HeapFree(GetProcessHeap(),0,package->script->Actions[script]); + + package->script->ActionCount[script] = 0; + package->script->Actions[script] = NULL; + return rc; +} + static UINT ACTION_FileCost(MSIPACKAGE *package) { return ERROR_SUCCESS; @@ -1944,9 +1303,8 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`', ' ','=',' ','\'','%','s','\'', 0}; - UINT rc; - MSIQUERY * view; - LPWSTR ptargetdir, targetdir, parent, srcdir; + LPWSTR ptargetdir, targetdir, srcdir; + LPCWSTR parent; LPWSTR shortname = NULL; MSIRECORD * row = 0; INT index = -1; @@ -1978,26 +1336,10 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) package->folders[index].Directory = strdupW(dir); - rc = MSI_OpenQuery(package->db, &view, Query, dir); - if (rc != ERROR_SUCCESS) + row = MSI_QueryGetRecord(package->db, Query, dir); + if (!row) return -1; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return -1; - } - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return -1; - } - ptargetdir = targetdir = load_dynamic_stringW(row,3); /* split src and target dir */ @@ -2048,7 +1390,7 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) HeapFree(GetProcessHeap(), 0, ptargetdir); TRACE(" SourceDefault = %s\n",debugstr_w(package->folders[index].SourceDefault)); - parent = load_dynamic_stringW(row,2); + parent = MSI_RecordGetString(row,2); if (parent) { i = load_folder(package,parent); @@ -2060,138 +1402,16 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) } else package->folders[index].ParentIndex = -2; - HeapFree(GetProcessHeap(), 0, parent); package->folders[index].Property = load_dynamic_property(package, dir,NULL); msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); TRACE(" %s retuning on index %i\n",debugstr_w(dir),index); return index; } - -LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, - BOOL set_prop, MSIFOLDER **folder) -{ - DWORD i; - LPWSTR p, path = NULL; - - TRACE("Working to resolve %s\n",debugstr_w(name)); - - /* special resolving for Target and Source root dir */ - if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0) - { - if (!source) - { - path = load_dynamic_property(package,cszTargetDir,NULL); - if (!path) - { - path = load_dynamic_property(package,cszRootDrive,NULL); - if (set_prop) - MSI_SetPropertyW(package,cszTargetDir,path); - } - if (folder) - { - for (i = 0; i < package->loaded_folders; i++) - { - if (strcmpW(package->folders[i].Directory,name)==0) - break; - } - *folder = &(package->folders[i]); - } - return path; - } - else - { - path = load_dynamic_property(package,cszSourceDir,NULL); - if (!path) - { - path = load_dynamic_property(package,cszDatabase,NULL); - if (path) - { - p = strrchrW(path,'\\'); - if (p) - *(p+1) = 0; - } - } - if (folder) - { - for (i = 0; i < package->loaded_folders; i++) - { - if (strcmpW(package->folders[i].Directory,name)==0) - break; - } - *folder = &(package->folders[i]); - } - return path; - } - } - - for (i = 0; i < package->loaded_folders; i++) - { - if (strcmpW(package->folders[i].Directory,name)==0) - break; - } - - if (i >= package->loaded_folders) - return NULL; - - if (folder) - *folder = &(package->folders[i]); - - if (!source && package->folders[i].ResolvedTarget) - { - path = strdupW(package->folders[i].ResolvedTarget); - TRACE(" already resolved to %s\n",debugstr_w(path)); - return path; - } - else if (source && package->folders[i].ResolvedSource) - { - path = strdupW(package->folders[i].ResolvedSource); - TRACE(" (source)already resolved to %s\n",debugstr_w(path)); - return path; - } - else if (!source && package->folders[i].Property) - { - path = build_directory_name(2, package->folders[i].Property, NULL); - - TRACE(" internally set to %s\n",debugstr_w(path)); - if (set_prop) - MSI_SetPropertyW(package,name,path); - return path; - } - - if (package->folders[i].ParentIndex >= 0) - { - LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory; - - TRACE(" ! Parent is %s\n", debugstr_w(parent)); - - p = resolve_folder(package, parent, source, set_prop, NULL); - if (!source) - { - TRACE(" TargetDefault = %s\n",debugstr_w(package->folders[i].TargetDefault)); - path = build_directory_name(3, p, package->folders[i].TargetDefault, NULL); - package->folders[i].ResolvedTarget = strdupW(path); - TRACE(" resolved into %s\n",debugstr_w(path)); - if (set_prop) - MSI_SetPropertyW(package,name,path); - } - else - { - path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL); - TRACE(" (source)resolved into %s\n",debugstr_w(path)); - package->folders[i].ResolvedSource = strdupW(path); - } - HeapFree(GetProcessHeap(),0,p); - } - return path; -} - /* scan for and update current install states */ -void ACTION_UpdateInstallStates(MSIPACKAGE *package) +static void ACTION_UpdateInstallStates(MSIPACKAGE *package) { int i; LPWSTR productcode; @@ -2230,72 +1450,6 @@ void ACTION_UpdateInstallStates(MSIPACKAGE *package) } } -/* update compoennt state based on a feature change */ -void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature) -{ - int i; - INSTALLSTATE newstate; - MSIFEATURE *feature; - - i = get_loaded_feature(package,szFeature); - if (i < 0) - return; - - feature = &package->features[i]; - newstate = feature->ActionRequest; - - for( i = 0; i < feature->ComponentCount; i++) - { - MSICOMPONENT* component = &package->components[feature->Components[i]]; - - TRACE("MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)\n", - newstate, debugstr_w(component->Component), component->Installed, - component->Action, component->ActionRequest); - - if (!component->Enabled) - continue; - else - { - if (newstate == INSTALLSTATE_LOCAL) - { - component->ActionRequest = INSTALLSTATE_LOCAL; - component->Action = INSTALLSTATE_LOCAL; - } - else - { - int j,k; - - component->ActionRequest = newstate; - component->Action = newstate; - - /*if any other feature wants is local we need to set it local*/ - for (j = 0; - j < package->loaded_features && - component->ActionRequest != INSTALLSTATE_LOCAL; - j++) - { - for (k = 0; k < package->features[j].ComponentCount; k++) - if ( package->features[j].Components[k] == - feature->Components[i] ) - { - if (package->features[j].ActionRequest == - INSTALLSTATE_LOCAL) - { - TRACE("Saved by %s\n", debugstr_w(package->features[j].Feature)); - component->ActionRequest = INSTALLSTATE_LOCAL; - component->Action = INSTALLSTATE_LOCAL; - } - break; - } - } - } - } - TRACE("Result (%i): Component %s (Installed %i, Action %i, Request %i)\n", - newstate, debugstr_w(component->Component), component->Installed, - component->Action, component->ActionRequest); - } -} - static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property, INSTALLSTATE state) { @@ -2429,6 +1583,14 @@ static UINT SetFeatureStates(MSIPACKAGE *package) } } } + else + { + /* set the Preselected Property */ + static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0}; + static const WCHAR szOne[] = { '1', 0 }; + + MSI_SetPropertyW(package,szPreselected,szOne); + } /* * now we want to enable or disable components base on feature @@ -2504,6 +1666,52 @@ static UINT SetFeatureStates(MSIPACKAGE *package) return ERROR_SUCCESS; } +static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE *package = (MSIPACKAGE*)param; + LPCWSTR name; + LPWSTR path; + + name = MSI_RecordGetString(row,1); + + /* This helper function now does ALL the work */ + TRACE("Dir %s ...\n",debugstr_w(name)); + load_folder(package,name); + path = resolve_folder(package,name,FALSE,TRUE,NULL); + TRACE("resolves to %s\n",debugstr_w(path)); + HeapFree( GetProcessHeap(), 0, path); + + return ERROR_SUCCESS; +} + +static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE *package = (MSIPACKAGE*)param; + LPCWSTR Feature; + int feature_index; + + Feature = MSI_RecordGetString(row,1); + + feature_index = get_loaded_feature(package,Feature); + if (feature_index < 0) + ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature)); + else + { + LPCWSTR Condition; + Condition = MSI_RecordGetString(row,3); + + if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE) + { + int level = MSI_RecordGetInteger(row,2); + TRACE("Reseting feature %s to level %i\n", debugstr_w(Feature), + level); + package->features[feature_index].Level = level; + } + } + return ERROR_SUCCESS; +} + + /* * A lot is done in this function aside from just the costing. * The costing needs to be implemented at some point but for now I am going @@ -2539,41 +1747,8 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); if (rc == ERROR_SUCCESS) { - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - WCHAR name[0x100]; - LPWSTR path; - MSIRECORD * row = 0; - DWORD sz; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - sz=0x100; - MSI_RecordGetStringW(row,1,name,&sz); - - /* This helper function now does ALL the work */ - TRACE("Dir %s ...\n",debugstr_w(name)); - load_folder(package,name); - path = resolve_folder(package,name,FALSE,TRUE,NULL); - TRACE("resolves to %s\n",debugstr_w(path)); - HeapFree( GetProcessHeap(), 0, path); - - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories, + package); msiobj_release(&view->hdr); } @@ -2666,54 +1841,8 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view); if (rc == ERROR_SUCCESS) { - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - WCHAR Feature[0x100]; - MSIRECORD * row = 0; - DWORD sz; - int feature_index; - - rc = MSI_ViewFetch(view,&row); - - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - sz = 0x100; - MSI_RecordGetStringW(row,1,Feature,&sz); - - feature_index = get_loaded_feature(package,Feature); - if (feature_index < 0) - ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature)); - else - { - LPWSTR Condition; - Condition = load_dynamic_stringW(row,3); - - if (MSI_EvaluateConditionW(package,Condition) == - MSICONDITION_TRUE) - { - int level = MSI_RecordGetInteger(row,2); - TRACE("Reseting feature %s to level %i\n", - debugstr_w(Feature), level); - package->features[feature_index].Level = level; - } - HeapFree(GetProcessHeap(),0,Condition); - } - - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions, + package); msiobj_release(&view->hdr); } @@ -2745,686 +1874,9 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) return SetFeatureStates(package); } -/* - * This is a helper function for handling embedded cabinet media - */ -static UINT writeout_cabinet_stream(MSIPACKAGE *package, WCHAR* stream_name, - WCHAR* source) -{ - UINT rc; - USHORT* data; - UINT size; - DWORD write; - HANDLE the_file; - WCHAR tmp[MAX_PATH]; - - rc = read_raw_stream_data(package->db,stream_name,&data,&size); - if (rc != ERROR_SUCCESS) - return rc; - - write = MAX_PATH; - if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write)) - GetTempPathW(MAX_PATH,tmp); - - GetTempFileNameW(tmp,stream_name,0,source); - - track_tempfile(package,strrchrW(source,'\\'), source); - the_file = CreateFileW(source, 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(source)); - rc = ERROR_FUNCTION_FAILED; - goto end; - } - - WriteFile(the_file,data,size,&write,NULL); - CloseHandle(the_file); - TRACE("wrote %li bytes to %s\n",write,debugstr_w(source)); -end: - HeapFree(GetProcessHeap(),0,data); - return rc; -} - - -/* Support functions for FDI functions */ -typedef struct -{ - MSIPACKAGE* package; - LPCSTR cab_path; - LPCSTR file_name; -} CabData; - -static void * cabinet_alloc(ULONG cb) -{ - return HeapAlloc(GetProcessHeap(), 0, cb); -} - -static void cabinet_free(void *pv) -{ - HeapFree(GetProcessHeap(), 0, pv); -} - -static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode) -{ - DWORD dwAccess = 0; - DWORD dwShareMode = 0; - DWORD dwCreateDisposition = OPEN_EXISTING; - switch (oflag & _O_ACCMODE) - { - case _O_RDONLY: - dwAccess = GENERIC_READ; - dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE; - break; - case _O_WRONLY: - dwAccess = GENERIC_WRITE; - dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - break; - case _O_RDWR: - dwAccess = GENERIC_READ | GENERIC_WRITE; - dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - break; - } - if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL)) - dwCreateDisposition = CREATE_NEW; - else if (oflag & _O_CREAT) - dwCreateDisposition = CREATE_ALWAYS; - return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL, - dwCreateDisposition, 0, NULL); -} - -static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb) -{ - DWORD dwRead; - if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL)) - return dwRead; - return 0; -} - -static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb) -{ - DWORD dwWritten; - if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL)) - return dwWritten; - return 0; -} - -static int cabinet_close(INT_PTR hf) -{ - return CloseHandle((HANDLE)hf) ? 0 : -1; -} - -static long cabinet_seek(INT_PTR hf, long dist, int seektype) -{ - /* flags are compatible and so are passed straight through */ - return SetFilePointer((HANDLE)hf, dist, NULL, seektype); -} - -static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) -{ - /* FIXME: try to do more processing in this function */ - switch (fdint) - { - case fdintCOPY_FILE: - { - CabData *data = (CabData*) pfdin->pv; - ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1); - char *file; - - LPWSTR trackname; - LPWSTR trackpath; - LPWSTR tracknametmp; - static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0}; - - if (data->file_name && lstrcmpiA(data->file_name,pfdin->psz1)) - return 0; - - file = cabinet_alloc((len+1)*sizeof(char)); - strcpy(file, data->cab_path); - strcat(file, pfdin->psz1); - - TRACE("file: %s\n", debugstr_a(file)); - - /* track this file so it can be deleted if not installed */ - trackpath=strdupAtoW(file); - tracknametmp=strdupAtoW(strrchr(file,'\\')+1); - trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) + - strlenW(tmpprefix)+1) * sizeof(WCHAR)); - - strcpyW(trackname,tmpprefix); - strcatW(trackname,tracknametmp); - - track_tempfile(data->package, trackname, trackpath); - - HeapFree(GetProcessHeap(),0,trackpath); - HeapFree(GetProcessHeap(),0,trackname); - HeapFree(GetProcessHeap(),0,tracknametmp); - - return cabinet_open(file, _O_WRONLY | _O_CREAT, 0); - } - case fdintCLOSE_FILE_INFO: - { - FILETIME ft; - FILETIME ftLocal; - if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft)) - return -1; - if (!LocalFileTimeToFileTime(&ft, &ftLocal)) - return -1; - if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal)) - return -1; - - cabinet_close(pfdin->hf); - return 1; - } - default: - return 0; - } -} - -/*********************************************************************** - * extract_cabinet_file - * - * Extract files from a cab file. - */ -static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source, - const WCHAR* path, const WCHAR* file) -{ - HFDI hfdi; - ERF erf; - BOOL ret; - char *cabinet; - char *cab_path; - char *file_name; - CabData data; - - TRACE("Extracting %s (%s) to %s\n",debugstr_w(source), - debugstr_w(file), debugstr_w(path)); - - hfdi = FDICreate(cabinet_alloc, - cabinet_free, - cabinet_open, - cabinet_read, - cabinet_write, - cabinet_close, - cabinet_seek, - 0, - &erf); - if (!hfdi) - { - ERR("FDICreate failed\n"); - return FALSE; - } - - if (!(cabinet = strdupWtoA( source ))) - { - FDIDestroy(hfdi); - return FALSE; - } - if (!(cab_path = strdupWtoA( path ))) - { - FDIDestroy(hfdi); - HeapFree(GetProcessHeap(), 0, cabinet); - return FALSE; - } - - data.package = package; - data.cab_path = cab_path; - if (file) - file_name = strdupWtoA(file); - else - file_name = NULL; - data.file_name = file_name; - - ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data); - - if (!ret) - ERR("FDICopy failed\n"); - - FDIDestroy(hfdi); - - HeapFree(GetProcessHeap(), 0, cabinet); - HeapFree(GetProcessHeap(), 0, cab_path); - HeapFree(GetProcessHeap(), 0, file_name); - - return ret; -} - -static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path, - MSIFILE* file) -{ - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static WCHAR source[MAX_PATH]; - static const WCHAR ExecSeqQuery[] = - {'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',' ', - '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0}; - WCHAR Query[1024]; - WCHAR cab[0x100]; - DWORD sz=0x100; - INT seq; - static UINT last_sequence = 0; - - if (file->Attributes & msidbFileAttributesNoncompressed) - { - TRACE("Uncompressed File, no media to ready.\n"); - return ERROR_SUCCESS; - } - - if (file->Sequence <= last_sequence) - { - TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence); - /*extract_a_cabinet_file(package, source,path,file->File); */ - return ERROR_SUCCESS; - } - - sprintfW(Query,ExecSeqQuery,file->Sequence); - - rc = MSI_DatabaseOpenViewW(package->db, Query, &view); - if (rc != ERROR_SUCCESS) - return rc; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - seq = MSI_RecordGetInteger(row,2); - last_sequence = seq; - - if (!MSI_RecordIsNull(row,4)) - { - sz=0x100; - MSI_RecordGetStringW(row,4,cab,&sz); - TRACE("Source is CAB %s\n",debugstr_w(cab)); - /* the stream does not contain the # character */ - if (cab[0]=='#') - { - writeout_cabinet_stream(package,&cab[1],source); - strcpyW(path,source); - *(strrchrW(path,'\\')+1)=0; - } - else - { - sz = MAX_PATH; - if (MSI_GetPropertyW(package, cszSourceDir, source, &sz)) - { - ERR("No Source dir defined \n"); - rc = ERROR_FUNCTION_FAILED; - } - else - { - strcpyW(path,source); - strcatW(source,cab); - /* extract the cab file into a folder in the temp folder */ - sz = MAX_PATH; - if (MSI_GetPropertyW(package, cszTempFolder,path, &sz) - != ERROR_SUCCESS) - GetTempPathW(MAX_PATH,path); - } - } - rc = !extract_a_cabinet_file(package, source,path,NULL); - } - else - { - sz = MAX_PATH; - MSI_GetPropertyW(package,cszSourceDir,source,&sz); - strcpyW(path,source); - } - msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; -} - -inline static UINT create_component_directory ( MSIPACKAGE* package, INT component) -{ - UINT rc = ERROR_SUCCESS; - MSIFOLDER *folder; - LPWSTR install_path; - - install_path = resolve_folder(package, package->components[component].Directory, - FALSE, FALSE, &folder); - if (!install_path) - return ERROR_FUNCTION_FAILED; - - /* create the path */ - if (folder->State == 0) - { - create_full_pathW(install_path); - folder->State = 2; - } - HeapFree(GetProcessHeap(), 0, install_path); - - return rc; -} - -static UINT ACTION_InstallFiles(MSIPACKAGE *package) -{ - UINT rc = ERROR_SUCCESS; - DWORD index; - MSIRECORD * uirow; - WCHAR uipath[MAX_PATH]; - - if (!package) - return ERROR_INVALID_HANDLE; - - /* increment progress bar each time action data is sent */ - ui_progress(package,1,1,0,0); - - for (index = 0; index < package->loaded_files; index++) - { - WCHAR path_to_source[MAX_PATH]; - MSIFILE *file; - - file = &package->files[index]; - - if (file->Temporary) - continue; - - - if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex, - INSTALLSTATE_LOCAL)) - { - ui_progress(package,2,file->FileSize,0,0); - TRACE("File %s is not scheduled for install\n", - debugstr_w(file->File)); - - continue; - } - - if ((file->State == 1) || (file->State == 2)) - { - LPWSTR p; - MSICOMPONENT* comp = NULL; - - TRACE("Installing %s\n",debugstr_w(file->File)); - rc = ready_media_for_file(package, path_to_source, file); - /* - * WARNING! - * our file table could change here because a new temp file - * may have been created - */ - file = &package->files[index]; - if (rc != ERROR_SUCCESS) - { - ERR("Unable to ready media\n"); - rc = ERROR_FUNCTION_FAILED; - break; - } - - create_component_directory( package, file->ComponentIndex); - - /* recalculate file paths because things may have changed */ - - if (file->ComponentIndex >= 0) - comp = &package->components[file->ComponentIndex]; - - p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL); - HeapFree(GetProcessHeap(),0,file->TargetPath); - - file->TargetPath = build_directory_name(2, p, file->FileName); - HeapFree(GetProcessHeap(),0,p); - - if (file->Attributes & msidbFileAttributesNoncompressed) - { - p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL); - file->SourcePath = build_directory_name(2, p, file->ShortName); - HeapFree(GetProcessHeap(),0,p); - } - else - file->SourcePath = build_directory_name(2, path_to_source, - file->File); - - - TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath), - debugstr_w(file->TargetPath)); - - /* the UI chunk */ - uirow=MSI_CreateRecord(9); - MSI_RecordSetStringW(uirow,1,file->File); - strcpyW(uipath,file->TargetPath); - *(strrchrW(uipath,'\\')+1)=0; - MSI_RecordSetStringW(uirow,9,uipath); - MSI_RecordSetInteger(uirow,6,file->FileSize); - ui_actiondata(package,szInstallFiles,uirow); - msiobj_release( &uirow->hdr ); - ui_progress(package,2,file->FileSize,0,0); - - - if (file->Attributes & msidbFileAttributesNoncompressed) - rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE); - else - rc = MoveFileW(file->SourcePath, file->TargetPath); - - if (!rc) - { - rc = GetLastError(); - ERR("Unable to move/copy file (%s -> %s) (error %d)\n", - debugstr_w(file->SourcePath), debugstr_w(file->TargetPath), - rc); - if (rc == ERROR_ALREADY_EXISTS && file->State == 2) - { - if (!CopyFileW(file->SourcePath,file->TargetPath,FALSE)) - ERR("Unable to copy file (%s -> %s) (error %ld)\n", - debugstr_w(file->SourcePath), - debugstr_w(file->TargetPath), GetLastError()); - if (!(file->Attributes & msidbFileAttributesNoncompressed)) - DeleteFileW(file->SourcePath); - rc = 0; - } - else if (rc == ERROR_FILE_NOT_FOUND) - { - ERR("Source File Not Found! Continuing\n"); - rc = 0; - } - else if (file->Attributes & msidbFileAttributesVital) - { - ERR("Ignoring Error and continuing (nonvital file)...\n"); - rc = 0; - } - } - else - { - file->State = 4; - rc = ERROR_SUCCESS; - } - } - } - - return rc; -} - -inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, - LPWSTR* file_source) -{ - DWORD index; - - if (!package) - return ERROR_INVALID_HANDLE; - - for (index = 0; index < package->loaded_files; index ++) - { - if (strcmpW(file_key,package->files[index].File)==0) - { - if (package->files[index].State >= 2) - { - *file_source = strdupW(package->files[index].TargetPath); - return ERROR_SUCCESS; - } - else - return ERROR_FILE_NOT_FOUND; - } - } - - return ERROR_FUNCTION_FAILED; -} - -static UINT ACTION_DuplicateFiles(MSIPACKAGE *package) -{ - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0}; - - if (!package) - return ERROR_INVALID_HANDLE; - - rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - WCHAR file_key[0x100]; - WCHAR *file_source = NULL; - WCHAR dest_name[0x100]; - LPWSTR dest_path, dest; - WCHAR component[0x100]; - INT component_index; - - DWORD sz=0x100; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - sz=0x100; - rc = MSI_RecordGetStringW(row,2,component,&sz); - if (rc != ERROR_SUCCESS) - { - ERR("Unable to get component\n"); - msiobj_release(&row->hdr); - break; - } - - component_index = get_loaded_component(package,component); - - if (!ACTION_VerifyComponentForAction(package, component_index, - INSTALLSTATE_LOCAL)) - { - TRACE("Skipping copy due to disabled component\n"); - - /* the action taken was the same as the current install state */ - package->components[component_index].Action = - package->components[component_index].Installed; - - msiobj_release(&row->hdr); - continue; - } - - package->components[component_index].Action = INSTALLSTATE_LOCAL; - - sz=0x100; - rc = MSI_RecordGetStringW(row,3,file_key,&sz); - if (rc != ERROR_SUCCESS) - { - ERR("Unable to get file key\n"); - msiobj_release(&row->hdr); - break; - } - - rc = get_file_target(package,file_key,&file_source); - - if (rc != ERROR_SUCCESS) - { - ERR("Original file unknown %s\n",debugstr_w(file_key)); - msiobj_release(&row->hdr); - HeapFree(GetProcessHeap(),0,file_source); - continue; - } - - if (MSI_RecordIsNull(row,4)) - { - strcpyW(dest_name,strrchrW(file_source,'\\')+1); - } - else - { - sz=0x100; - MSI_RecordGetStringW(row,4,dest_name,&sz); - reduce_to_longfilename(dest_name); - } - - if (MSI_RecordIsNull(row,5)) - { - LPWSTR p; - dest_path = strdupW(file_source); - p = strrchrW(dest_path,'\\'); - if (p) - *p=0; - } - else - { - WCHAR destkey[0x100]; - sz=0x100; - MSI_RecordGetStringW(row,5,destkey,&sz); - sz = 0x100; - dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL); - if (!dest_path) - { - ERR("Unable to get destination folder\n"); - msiobj_release(&row->hdr); - HeapFree(GetProcessHeap(),0,file_source); - break; - } - } - - dest = build_directory_name(2, dest_path, dest_name); - - TRACE("Duplicating file %s to %s\n",debugstr_w(file_source), - debugstr_w(dest)); - - if (strcmpW(file_source,dest)) - rc = !CopyFileW(file_source,dest,TRUE); - else - rc = ERROR_SUCCESS; - - if (rc != ERROR_SUCCESS) - ERR("Failed to copy file %s -> %s, last error %ld\n", debugstr_w(file_source), debugstr_w(dest_path), GetLastError()); - - FIXME("We should track these duplicate files as well\n"); - - msiobj_release(&row->hdr); - HeapFree(GetProcessHeap(),0,dest_path); - HeapFree(GetProcessHeap(),0,dest); - HeapFree(GetProcessHeap(),0,file_source); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; -} - - /* OK this value is "interpreted" and then formatted based on the first few characters */ -static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type, +static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type, DWORD *size) { LPSTR data = NULL; @@ -3508,7 +1960,7 @@ static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type, else { static const WCHAR szMulti[] = {'[','~',']',0}; - WCHAR *ptr; + LPCWSTR ptr; *type=REG_SZ; if (value[0]=='#') @@ -3532,11 +1984,193 @@ static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type, return data; } +static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE *package = (MSIPACKAGE*)param; + static const WCHAR szHCR[] = + {'H','K','E','Y','_','C','L','A','S','S','E','S','_', + 'R','O','O','T','\\',0}; + static const WCHAR szHCU[] = + {'H','K','E','Y','_','C','U','R','R','E','N','T','_', + 'U','S','E','R','\\',0}; + static const WCHAR szHLM[] = + {'H','K','E','Y','_','L','O','C','A','L','_', + 'M','A','C','H','I','N','E','\\',0}; + static const WCHAR szHU[] = + {'H','K','E','Y','_','U','S','E','R','S','\\',0}; + + LPSTR value_data = NULL; + HKEY root_key, hkey; + DWORD type,size; + LPWSTR deformated; + LPCWSTR szRoot, component, name, key, value; + INT component_index; + MSIRECORD * uirow; + LPWSTR uikey; + INT root; + BOOL check_first = FALSE; + UINT rc; + + ui_progress(package,2,0,0,0); + + value = NULL; + key = NULL; + uikey = NULL; + name = NULL; + + component = MSI_RecordGetString(row, 6); + component_index = get_loaded_component(package,component); + + if (!ACTION_VerifyComponentForAction(package, component_index, + INSTALLSTATE_LOCAL)) + { + TRACE("Skipping write due to disabled component %s\n", + debugstr_w(component)); + + package->components[component_index].Action = + package->components[component_index].Installed; + + return ERROR_SUCCESS; + } + + package->components[component_index].Action = INSTALLSTATE_LOCAL; + + 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; + else if ((name[0]=='+' && name[1] == 0) || + (name[0] == '*' && name[1] == 0)) + name = NULL; + check_first = TRUE; + } + + root = MSI_RecordGetInteger(row,2); + key = MSI_RecordGetString(row, 3); + + /* get the root key */ + switch (root) + { + case -1: + { + static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0}; + LPWSTR all_users = load_dynamic_property(package, szALLUSER, NULL); + if (all_users && all_users[0] == '1') + { + root_key = HKEY_LOCAL_MACHINE; + szRoot = szHLM; + } + else + { + root_key = HKEY_CURRENT_USER; + szRoot = szHCU; + } + HeapFree(GetProcessHeap(),0,all_users); + } + break; + case 0: root_key = HKEY_CLASSES_ROOT; + szRoot = szHCR; + break; + case 1: root_key = HKEY_CURRENT_USER; + szRoot = szHCU; + break; + case 2: root_key = HKEY_LOCAL_MACHINE; + szRoot = szHLM; + break; + case 3: root_key = HKEY_USERS; + szRoot = szHU; + break; + default: + ERR("Unknown root %i\n",root); + root_key=NULL; + szRoot = NULL; + break; + } + if (!root_key) + return ERROR_SUCCESS; + + deformat_string(package, key , &deformated); + size = strlenW(deformated) + strlenW(szRoot) + 1; + uikey = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR)); + strcpyW(uikey,szRoot); + strcatW(uikey,deformated); + + if (RegCreateKeyW( root_key, deformated, &hkey)) + { + ERR("Could not create key %s\n",debugstr_w(deformated)); + HeapFree(GetProcessHeap(),0,deformated); + HeapFree(GetProcessHeap(),0,uikey); + return ERROR_SUCCESS; + } + HeapFree(GetProcessHeap(),0,deformated); + + value = MSI_RecordGetString(row,5); + if (value) + value_data = parse_value(package, value, &type, &size); + else + { + static const WCHAR szEmpty[] = {0}; + value_data = (LPSTR)strdupW(szEmpty); + size = 0; + type = REG_SZ; + } + + deformat_string(package, name, &deformated); + + /* get the double nulls to terminate SZ_MULTI */ + if (type == REG_MULTI_SZ) + size +=sizeof(WCHAR); + + if (!check_first) + { + TRACE("Setting value %s of %s\n",debugstr_w(deformated), + debugstr_w(uikey)); + RegSetValueExW(hkey, deformated, 0, type, value_data, 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, value_data, size); + } + } + RegCloseKey(hkey); + + uirow = MSI_CreateRecord(3); + MSI_RecordSetStringW(uirow,2,deformated); + MSI_RecordSetStringW(uirow,1,uikey); + + if (type == REG_SZ) + MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data); + else + MSI_RecordSetStringW(uirow,3,value); + + ui_actiondata(package,szWriteRegistryValues,uirow); + msiobj_release( &uirow->hdr ); + + HeapFree(GetProcessHeap(),0,value_data); + HeapFree(GetProcessHeap(),0,deformated); + HeapFree(GetProcessHeap(),0,uikey); + + return ERROR_SUCCESS; +} + static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) { UINT rc; MSIQUERY * view; - MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', '`','R','e','g','i','s','t','r','y','`',0 }; @@ -3548,207 +2182,19 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) if (rc != ERROR_SUCCESS) return ERROR_SUCCESS; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - /* increment progress bar each time action data is sent */ ui_progress(package,1,REG_PROGRESS_VALUE,1,0); - while (1) - { - static const WCHAR szHCR[] = - {'H','K','E','Y','_','C','L','A','S','S','E','S','_', - 'R','O','O','T','\\',0}; - static const WCHAR szHCU[] = - {'H','K','E','Y','_','C','U','R','R','E','N','T','_', - 'U','S','E','R','\\',0}; - static const WCHAR szHLM[] = - {'H','K','E','Y','_','L','O','C','A','L','_', - 'M','A','C','H','I','N','E','\\',0}; - static const WCHAR szHU[] = - {'H','K','E','Y','_','U','S','E','R','S','\\',0}; + rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package); - LPSTR value_data = NULL; - HKEY root_key, hkey; - DWORD type,size; - LPWSTR value, key, name, component, deformated; - LPCWSTR szRoot; - INT component_index; - MSIRECORD * uirow; - LPWSTR uikey; - INT root; - BOOL check_first = FALSE; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - ui_progress(package,2,0,0,0); - - value = NULL; - key = NULL; - uikey = NULL; - name = NULL; - - component = load_dynamic_stringW(row, 6); - component_index = get_loaded_component(package,component); - - if (!ACTION_VerifyComponentForAction(package, component_index, - INSTALLSTATE_LOCAL)) - { - TRACE("Skipping write due to disabled component\n"); - msiobj_release(&row->hdr); - - package->components[component_index].Action = - package->components[component_index].Installed; - - goto next; - } - - package->components[component_index].Action = INSTALLSTATE_LOCAL; - - name = load_dynamic_stringW(row, 4); - if( MSI_RecordIsNull(row,5) && name ) - { - /* null values can have special meanings */ - if (name[0]=='-' && name[1] == 0) - { - msiobj_release(&row->hdr); - goto next; - } - else if ((name[0]=='+' && name[1] == 0) || - (name[0] == '*' && name[1] == 0)) - { - HeapFree(GetProcessHeap(),0,name); - name = NULL; - check_first = TRUE; - } - } - - root = MSI_RecordGetInteger(row,2); - key = load_dynamic_stringW(row, 3); - - - /* get the root key */ - switch (root) - { - case 0: root_key = HKEY_CLASSES_ROOT; - szRoot = szHCR; - break; - case 1: root_key = HKEY_CURRENT_USER; - szRoot = szHCU; - break; - case 2: root_key = HKEY_LOCAL_MACHINE; - szRoot = szHLM; - break; - case 3: root_key = HKEY_USERS; - szRoot = szHU; - break; - default: - ERR("Unknown root %i\n",root); - root_key=NULL; - szRoot = NULL; - break; - } - if (!root_key) - { - msiobj_release(&row->hdr); - goto next; - } - - deformat_string(package, key , &deformated); - size = strlenW(deformated) + strlenW(szRoot) + 1; - uikey = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR)); - strcpyW(uikey,szRoot); - strcatW(uikey,deformated); - - if (RegCreateKeyW( root_key, deformated, &hkey)) - { - ERR("Could not create key %s\n",debugstr_w(deformated)); - msiobj_release(&row->hdr); - HeapFree(GetProcessHeap(),0,deformated); - goto next; - } - HeapFree(GetProcessHeap(),0,deformated); - - value = load_dynamic_stringW(row,5); - if (value) - value_data = parse_value(package, value, &type, &size); - else - { - static const WCHAR szEmpty[] = {0}; - value_data = (LPSTR)strdupW(szEmpty); - size = 0; - type = REG_SZ; - } - - deformat_string(package, name, &deformated); - - /* get the double nulls to terminate SZ_MULTI */ - if (type == REG_MULTI_SZ) - size +=sizeof(WCHAR); - - if (!check_first) - { - TRACE("Setting value %s of %s\n",debugstr_w(deformated), - debugstr_w(uikey)); - RegSetValueExW(hkey, deformated, 0, type, value_data, 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)); - RegSetValueExW(hkey, deformated, 0, type, value_data, size); - } - } - - uirow = MSI_CreateRecord(3); - MSI_RecordSetStringW(uirow,2,deformated); - MSI_RecordSetStringW(uirow,1,uikey); - - if (type == REG_SZ) - MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data); - else - MSI_RecordSetStringW(uirow,3,value); - - ui_actiondata(package,szWriteRegistryValues,uirow); - msiobj_release( &uirow->hdr ); - - HeapFree(GetProcessHeap(),0,value_data); - HeapFree(GetProcessHeap(),0,value); - HeapFree(GetProcessHeap(),0,deformated); - - msiobj_release(&row->hdr); - RegCloseKey(hkey); -next: - HeapFree(GetProcessHeap(),0,uikey); - HeapFree(GetProcessHeap(),0,key); - HeapFree(GetProcessHeap(),0,name); - HeapFree(GetProcessHeap(),0,component); - } - MSI_ViewClose(view); msiobj_release(&view->hdr); return rc; } static UINT ACTION_InstallInitialize(MSIPACKAGE *package) { + package->script->CurrentlyScripting = TRUE; + return ERROR_SUCCESS; } @@ -3810,16 +2256,36 @@ static UINT ACTION_InstallValidate(MSIPACKAGE *package) return ERROR_SUCCESS; } +static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE* package = (MSIPACKAGE*)param; + LPCWSTR cond = NULL; + LPCWSTR message = NULL; + static const WCHAR title[]= + {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0}; + + cond = MSI_RecordGetString(row,1); + + if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE) + { + LPWSTR deformated; + message = MSI_RecordGetString(row,2); + deformat_string(package,message,&deformated); + MessageBoxW(NULL,deformated,title,MB_OK); + HeapFree(GetProcessHeap(),0,deformated); + return ERROR_FUNCTION_FAILED; + } + + return ERROR_SUCCESS; +} + static UINT ACTION_LaunchConditions(MSIPACKAGE *package) { UINT rc; MSIQUERY * view = NULL; - MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'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}; - static const WCHAR title[]= - {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0}; TRACE("Checking launch conditions\n"); @@ -3827,44 +2293,9 @@ static UINT ACTION_LaunchConditions(MSIPACKAGE *package) if (rc != ERROR_SUCCESS) return ERROR_SUCCESS; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - rc = ERROR_SUCCESS; - while (rc == ERROR_SUCCESS) - { - LPWSTR cond = NULL; - LPWSTR message = NULL; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - cond = load_dynamic_stringW(row,1); - - if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE) - { - LPWSTR deformated; - message = load_dynamic_stringW(row,2); - deformat_string(package,message,&deformated); - MessageBoxW(NULL,deformated,title,MB_OK); - HeapFree(GetProcessHeap(),0,message); - HeapFree(GetProcessHeap(),0,deformated); - rc = ERROR_FUNCTION_FAILED; - } - HeapFree(GetProcessHeap(),0,cond); - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package); msiobj_release(&view->hdr); + return rc; } @@ -3880,10 +2311,10 @@ static LPWSTR resolve_keypath( MSIPACKAGE* package, INT } if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath) { - MSIQUERY * view; MSIRECORD * row = 0; - UINT rc,root,len; - LPWSTR key,deformated,buffer,name,deformated_name; + UINT root,len; + LPWSTR deformated,buffer,deformated_name; + LPCWSTR key,name; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', '`','R','e','g','i','s','t','r','y','`',' ', @@ -3893,30 +2324,13 @@ static LPWSTR resolve_keypath( MSIPACKAGE* package, INT static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0}; - rc = MSI_OpenQuery(package->db,&view,ExecSeqQuery,cmp->KeyPath); - - if (rc!=ERROR_SUCCESS) + row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath); + if (!row) return NULL; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return NULL; - } - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return NULL; - } - root = MSI_RecordGetInteger(row,2); - key = load_dynamic_stringW(row, 3); - name = load_dynamic_stringW(row, 4); + key = MSI_RecordGetString(row, 3); + name = MSI_RecordGetString(row, 4); deformat_string(package, key , &deformated); deformat_string(package, name, &deformated_name); @@ -3931,13 +2345,9 @@ static LPWSTR resolve_keypath( MSIPACKAGE* package, INT else sprintfW(buffer,fmt,root,deformated); - HeapFree(GetProcessHeap(),0,key); HeapFree(GetProcessHeap(),0,deformated); - HeapFree(GetProcessHeap(),0,name); HeapFree(GetProcessHeap(),0,deformated_name); msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); return buffer; } @@ -3960,7 +2370,7 @@ static LPWSTR resolve_keypath( MSIPACKAGE* package, INT return NULL; } -static HKEY openSharedDLLsKey() +static HKEY openSharedDLLsKey(void) { HKEY hkey=0; static const WCHAR path[] = @@ -4214,7 +2624,7 @@ typedef struct { ITypeLib *ptLib; } typelib_struct; -BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, +static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam) { TLIBATTR *attr; @@ -4232,8 +2642,13 @@ BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, sz = strlenW(tl_struct->source)+4; sz *= sizeof(WCHAR); - tl_struct->path = HeapAlloc(GetProcessHeap(),0,sz); - sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName); + if ((INT)lpszName == 1) + tl_struct->path = strdupW(tl_struct->source); + else + { + tl_struct->path = HeapAlloc(GetProcessHeap(),0,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); @@ -4261,6 +2676,91 @@ BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, return TRUE; } +static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE* package = (MSIPACKAGE*)param; + LPCWSTR component; + INT index; + typelib_struct tl_struct; + HMODULE module; + static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0}; + + component = MSI_RecordGetString(row,3); + index = get_loaded_component(package,component); + if (index < 0) + return ERROR_SUCCESS; + + if (!ACTION_VerifyComponentForAction(package, index, INSTALLSTATE_LOCAL)) + { + TRACE("Skipping typelib reg due to disabled component\n"); + + package->components[index].Action = + package->components[index].Installed; + + return ERROR_SUCCESS; + } + + package->components[index].Action = INSTALLSTATE_LOCAL; + + index = get_loaded_file(package,package->components[index].KeyPath); + + if (index < 0) + return ERROR_SUCCESS; + + module = LoadLibraryExW(package->files[index].TargetPath, NULL, + LOAD_LIBRARY_AS_DATAFILE); + if (module != NULL) + { + LPWSTR guid; + guid = load_dynamic_stringW(row,1); + CLSIDFromString(guid, &tl_struct.clsid); + HeapFree(GetProcessHeap(),0,guid); + tl_struct.source = strdupW(package->files[index].TargetPath); + tl_struct.path = NULL; + + EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc, + (LONG_PTR)&tl_struct); + + if (tl_struct.path != NULL) + { + LPWSTR help = NULL; + LPCWSTR helpid; + HRESULT res; + + helpid = MSI_RecordGetString(row,6); + + if (helpid) + help = resolve_folder(package,helpid,FALSE,FALSE,NULL); + res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help); + HeapFree(GetProcessHeap(),0,help); + + if (!SUCCEEDED(res)) + ERR("Failed to register type library %s\n", + debugstr_w(tl_struct.path)); + else + { + ui_actiondata(package,szRegisterTypeLibraries,row); + + TRACE("Registered %s\n", debugstr_w(tl_struct.path)); + } + + ITypeLib_Release(tl_struct.ptLib); + HeapFree(GetProcessHeap(),0,tl_struct.path); + } + else + ERR("Failed to load type library %s\n", + debugstr_w(tl_struct.source)); + + FreeLibrary(module); + HeapFree(GetProcessHeap(),0,tl_struct.source); + } + else + ERR("Could not load file! %s\n", + debugstr_w(package->files[index].TargetPath)); + + return ERROR_SUCCESS; +} + static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) { /* @@ -4271,7 +2771,6 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) */ UINT rc; MSIQUERY * view; - MSIRECORD * row = 0; static const WCHAR Query[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', '`','T','y','p','e','L','i','b','`',0}; @@ -4283,688 +2782,154 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) if (rc != ERROR_SUCCESS) return ERROR_SUCCESS; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - WCHAR component[0x100]; - DWORD sz; - INT index; - LPWSTR guid; - typelib_struct tl_struct; - HMODULE module; - static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0}; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - sz = 0x100; - MSI_RecordGetStringW(row,3,component,&sz); - - index = get_loaded_component(package,component); - if (index < 0) - { - msiobj_release(&row->hdr); - continue; - } - - if (!ACTION_VerifyComponentForAction(package, index, - INSTALLSTATE_LOCAL)) - { - TRACE("Skipping typelib reg due to disabled component\n"); - msiobj_release(&row->hdr); - - package->components[index].Action = - package->components[index].Installed; - - continue; - } - - package->components[index].Action = INSTALLSTATE_LOCAL; - - index = get_loaded_file(package,package->components[index].KeyPath); - - if (index < 0) - { - msiobj_release(&row->hdr); - continue; - } - - guid = load_dynamic_stringW(row,1); - module = LoadLibraryExW(package->files[index].TargetPath, NULL, - LOAD_LIBRARY_AS_DATAFILE); - if (module != NULL) - { - CLSIDFromString(guid, &tl_struct.clsid); - tl_struct.source = strdupW(package->files[index].TargetPath); - tl_struct.path = NULL; - - EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc, - (LONG_PTR)&tl_struct); - - if (tl_struct.path != NULL) - { - LPWSTR help; - WCHAR helpid[0x100]; - HRESULT res; - - sz = 0x100; - MSI_RecordGetStringW(row,6,helpid,&sz); - - help = resolve_folder(package,helpid,FALSE,FALSE,NULL); - res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help); - HeapFree(GetProcessHeap(),0,help); - - if (!SUCCEEDED(res)) - ERR("Failed to register type library %s\n", - debugstr_w(tl_struct.path)); - else - { - ui_actiondata(package,szRegisterTypeLibraries,row); - - TRACE("Registered %s\n", debugstr_w(tl_struct.path)); - } - - ITypeLib_Release(tl_struct.ptLib); - HeapFree(GetProcessHeap(),0,tl_struct.path); - } - else - ERR("Failed to load type library %s\n", - debugstr_w(tl_struct.source)); - - FreeLibrary(module); - HeapFree(GetProcessHeap(),0,tl_struct.source); - } - else - ERR("Could not load file! %s\n", - debugstr_w(package->files[index].TargetPath)); - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package); msiobj_release(&view->hdr); return rc; } -static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app ) +static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param) { - static const WCHAR szAppID[] = { 'A','p','p','I','D',0 }; - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = - {'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}; - HKEY hkey2,hkey3; - LPWSTR buffer=0; - - if (!package) - return ERROR_INVALID_HANDLE; - - rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, clsid); - if (rc != ERROR_SUCCESS) - return rc; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2); - RegCreateKeyW(hkey2,clsid,&hkey3); - RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app, - (strlenW(app)+1)*sizeof(WCHAR)); - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - if (!MSI_RecordIsNull(row,2)) - { - LPWSTR deformated=0; - UINT size; - static const WCHAR szRemoteServerName[] = - {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e', - 0}; - buffer = load_dynamic_stringW(row,2); - size = deformat_string(package,buffer,&deformated); - RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,(LPVOID)deformated, - size); - HeapFree(GetProcessHeap(),0,deformated); - HeapFree(GetProcessHeap(),0,buffer); - } - - if (!MSI_RecordIsNull(row,3)) - { - static const WCHAR szLocalService[] = - {'L','o','c','a','l','S','e','r','v','i','c','e',0}; - UINT size; - buffer = load_dynamic_stringW(row,3); - size = (strlenW(buffer)+1) * sizeof(WCHAR); - RegSetValueExW(hkey3,szLocalService,0,REG_SZ,(LPVOID)buffer,size); - HeapFree(GetProcessHeap(),0,buffer); - } - - if (!MSI_RecordIsNull(row,4)) - { - static const WCHAR szService[] = - {'S','e','r','v','i','c','e', - 'P','a','r','a','m','e','t','e','r','s',0}; - UINT size; - buffer = load_dynamic_stringW(row,4); - size = (strlenW(buffer)+1) * sizeof(WCHAR); - RegSetValueExW(hkey3,szService,0,REG_SZ,(LPVOID)buffer,size); - HeapFree(GetProcessHeap(),0,buffer); - } - - if (!MSI_RecordIsNull(row,5)) - { - static const WCHAR szDLL[] = - {'D','l','l','S','u','r','r','o','g','a','t','e',0}; - UINT size; - buffer = load_dynamic_stringW(row,5); - size = (strlenW(buffer)+1) * sizeof(WCHAR); - RegSetValueExW(hkey3,szDLL,0,REG_SZ,(LPVOID)buffer,size); - HeapFree(GetProcessHeap(),0,buffer); - } - - if (!MSI_RecordIsNull(row,6)) - { - 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}; - - if (MSI_RecordGetInteger(row,6)) - RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4); - } - - if (!MSI_RecordIsNull(row,7)) - { - 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}; - - if (MSI_RecordGetInteger(row,7)) - RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,34); - } - - msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); - RegCloseKey(hkey3); - RegCloseKey(hkey2); - return rc; -} - -static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) -{ - /* - * Again I am assuming the words, "Whose key file represents" when referring - * to a Component as to meaning that Components KeyPath file - * - * Also there is a very strong connection between ClassInfo and ProgID - * that I am mostly glossing over. - * What would be more propper is to load the ClassInfo and the ProgID info - * into memory data structures and then be able to enable and disable them - * based on component. - */ - - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','C','l','a','s','s','`',0}; - static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; - static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 }; - static const WCHAR szAppID[] = { 'A','p','p','I','D',0 }; - static const WCHAR szSpace[] = {' ',0}; - HKEY hkey,hkey2,hkey3; - LPWSTR argument,deformated; - - if (!package) - return ERROR_INVALID_HANDLE; - - rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey); - if (rc != ERROR_SUCCESS) - return ERROR_FUNCTION_FAILED; - - rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - goto end; - } - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - goto end; - } - - while (1) - { - WCHAR clsid[0x100]; - WCHAR buffer[0x100]; - WCHAR desc[0x100]; - DWORD sz; - INT index; - DWORD size; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - sz=0x100; - MSI_RecordGetStringW(row,3,buffer,&sz); - - index = get_loaded_component(package,buffer); - - if (index < 0) - { - msiobj_release(&row->hdr); - continue; - } - - if ((!ACTION_VerifyComponentForAction(package, index, - INSTALLSTATE_LOCAL)) && - (!ACTION_VerifyComponentForAction(package, index, - INSTALLSTATE_ADVERTISED))) - { - TRACE("Skipping class reg due to disabled component\n"); - msiobj_release(&row->hdr); - - package->components[index].Action = - package->components[index].Installed; - - continue; - } - - package->components[index].Action = INSTALLSTATE_LOCAL; - - sz=0x100; - MSI_RecordGetStringW(row,1,clsid,&sz); - RegCreateKeyW(hkey,clsid,&hkey2); - - if (!MSI_RecordIsNull(row,5)) - { - sz=0x100; - MSI_RecordGetStringW(row,5,desc,&sz); - - RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)desc, - (strlenW(desc)+1)*sizeof(WCHAR)); - } - else - desc[0]=0; - - sz=0x100; - MSI_RecordGetStringW(row,2,buffer,&sz); - - RegCreateKeyW(hkey2,buffer,&hkey3); - - index = get_loaded_file(package,package->components[index].KeyPath); - - argument = load_dynamic_stringW(row,11); - size = deformat_string(package,argument,&deformated); - if (deformated) - size+=sizeof(WCHAR); - HeapFree(GetProcessHeap(),0,argument); - size += (strlenW(package->files[index].TargetPath))*sizeof(WCHAR); - - argument = HeapAlloc(GetProcessHeap(),0,size+sizeof(WCHAR)); - strcpyW(argument,package->files[index].TargetPath); - if (deformated) - { - strcatW(argument,szSpace); - strcatW(argument,deformated); - } - - RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size); - HeapFree(GetProcessHeap(),0,deformated); - HeapFree(GetProcessHeap(),0,argument); - - RegCloseKey(hkey3); - - if (!MSI_RecordIsNull(row,4)) - { - sz=0x100; - MSI_RecordGetStringW(row,4,buffer,&sz); - - RegCreateKeyW(hkey2,szProgID,&hkey3); - - RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)buffer, - (strlenW(buffer)+1)*sizeof(WCHAR)); - - RegCloseKey(hkey3); - } - - if (!MSI_RecordIsNull(row,6)) - { - sz=0x100; - MSI_RecordGetStringW(row,6,buffer,&sz); - - RegSetValueExW(hkey2,szAppID,0,REG_SZ,(LPVOID)buffer, - (strlenW(buffer)+1)*sizeof(WCHAR)); - - register_appid(package,buffer,desc); - } - - - if (!MSI_RecordIsNull(row,7)) - { - FIXME("Process field 7\n"); - } - - if (!MSI_RecordIsNull(row,8)) - { - static const WCHAR szDefaultIcon[] = - {'D','e','f','a','u','l','t','I','c','o','n',0}; - - LPWSTR FileName = load_dynamic_stringW(row,8); - LPWSTR FilePath; - INT index; - - RegCreateKeyW(hkey2,szDefaultIcon,&hkey3); - build_icon_path(package,FileName,&FilePath); - if (!MSI_RecordIsNull(row,9)) - { - static const WCHAR index_fmt[] = {',','%','i',0}; - WCHAR index_buf[20]; - index = MSI_RecordGetInteger(row,9); - sprintfW(index_buf,index_fmt,index); - size = strlenW(FilePath)+strlenW(index_buf)+1; - size *= sizeof(WCHAR); - HeapReAlloc(GetProcessHeap(),0,FilePath,size); - } - RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)FilePath, - (strlenW(FilePath)+1) * sizeof(WCHAR)); - HeapFree(GetProcessHeap(),0,FilePath); - HeapFree(GetProcessHeap(),0,FileName); - RegCloseKey(hkey3); - } - - if (!MSI_RecordIsNull(row,10)) - { - static const WCHAR szInproc32[] = - {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2', - 0}; - static const WCHAR szInproc[] = - {'I','n','p','r','o','c','H','a','n','d','l','e','r',0}; - INT 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: - size = strlenW(ole2) * sizeof(WCHAR); - RegCreateKeyW(hkey2,szInproc,&hkey3); - RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole2, size); - RegCloseKey(hkey3); - break; - case 2: - size = strlenW(ole32) * sizeof(WCHAR); - RegCreateKeyW(hkey2,szInproc32,&hkey3); - RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole32,size); - RegCloseKey(hkey3); - break; - case 3: - size = strlenW(ole2) * sizeof(WCHAR); - RegCreateKeyW(hkey2,szInproc,&hkey3); - RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole2, size); - RegCloseKey(hkey3); - size = strlenW(ole32) * sizeof(WCHAR); - RegCreateKeyW(hkey2,szInproc32,&hkey3); - RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole32,size); - RegCloseKey(hkey3); - break; - } - - } - else - { - RegCreateKeyW(hkey2,szInproc32,&hkey3); - argument = load_dynamic_stringW(row,10); - reduce_to_longfilename(argument); - size = strlenW(argument)*sizeof(WCHAR); - - RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size); - HeapFree(GetProcessHeap(),0,argument); - - RegCloseKey(hkey3); - } - } - - RegCloseKey(hkey2); - - ui_actiondata(package,szRegisterClassInfo,row); - - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - -end: - RegCloseKey(hkey); - return rc; -} - -static UINT register_progid_base(MSIPACKAGE* package, MSIRECORD * row, - LPWSTR clsid) -{ - static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; - static const WCHAR szDefaultIcon[] = - {'D','e','f','a','u','l','t','I','c','o','n',0}; - HKEY hkey,hkey2; - WCHAR buffer[0x100]; + MSIPACKAGE *package = (MSIPACKAGE*)param; + LPWSTR target_file, target_folder; + LPCWSTR buffer; + WCHAR filename[0x100]; DWORD sz; + DWORD index; + static const WCHAR szlnk[]={'.','l','n','k',0}; + IShellLinkW *sl; + IPersistFile *pf; + HRESULT res; + buffer = MSI_RecordGetString(row,4); + index = get_loaded_component(package,buffer); + + if (index < 0) + return ERROR_SUCCESS; + + if (!ACTION_VerifyComponentForAction(package, index, INSTALLSTATE_LOCAL)) + { + TRACE("Skipping shortcut creation due to disabled component\n"); + + package->components[index].Action = + package->components[index].Installed; + + return ERROR_SUCCESS; + } + + package->components[index].Action = INSTALLSTATE_LOCAL; + + ui_actiondata(package,szCreateShortcuts,row); + + res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, + &IID_IShellLinkW, (LPVOID *) &sl ); + + if (FAILED(res)) + { + ERR("Is IID_IShellLink\n"); + return ERROR_SUCCESS; + } + + res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf ); + if( FAILED( res ) ) + { + ERR("Is IID_IPersistFile\n"); + return ERROR_SUCCESS; + } + + buffer = MSI_RecordGetString(row,2); + target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL); + + /* may be needed because of a bug somehwere else */ + create_full_pathW(target_folder); sz = 0x100; - MSI_RecordGetStringW(row,1,buffer,&sz); - RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey); + MSI_RecordGetStringW(row,3,filename,&sz); + reduce_to_longfilename(filename); + if (!strchrW(filename,'.') || strcmpiW(strchrW(filename,'.'),szlnk)) + strcatW(filename,szlnk); + target_file = build_directory_name(2, target_folder, filename); + HeapFree(GetProcessHeap(),0,target_folder); - if (!MSI_RecordIsNull(row,4)) + buffer = MSI_RecordGetString(row,5); + if (strchrW(buffer,'[')) { - sz = 0x100; - MSI_RecordGetStringW(row,4,buffer,&sz); - RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) * - sizeof(WCHAR)); - } - - if (!MSI_RecordIsNull(row,3)) - { - sz = 0x100; - - MSI_RecordGetStringW(row,3,buffer,&sz); - RegCreateKeyW(hkey,szCLSID,&hkey2); - RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) * - sizeof(WCHAR)); - - if (clsid) - strcpyW(clsid,buffer); - - RegCloseKey(hkey2); + LPWSTR deformated; + deformat_string(package,buffer,&deformated); + IShellLinkW_SetPath(sl,deformated); + HeapFree(GetProcessHeap(),0,deformated); } else { - FIXME("UNHANDLED case, Parent progid but classid is NULL\n"); - return ERROR_FUNCTION_FAILED; + LPWSTR keypath; + FIXME("poorly handled shortcut format, advertised shortcut\n"); + keypath = strdupW(package->components[index].FullKeypath); + IShellLinkW_SetPath(sl,keypath); + HeapFree(GetProcessHeap(),0,keypath); } - if (!MSI_RecordIsNull(row,5)) + + if (!MSI_RecordIsNull(row,6)) { - INT index = MSI_RecordGetInteger(row,6); - LPWSTR FileName = load_dynamic_stringW(row,5); - LPWSTR FilePath,IconPath; - static const WCHAR fmt[] = {'%','s',',','%','i',0}; - - RegCreateKeyW(hkey,szDefaultIcon,&hkey2); - build_icon_path(package,FileName,&FilePath); - - IconPath = HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)* - sizeof(WCHAR)); - - sprintfW(IconPath,fmt,FilePath,index); - RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)IconPath, - (strlenW(IconPath)+1) * sizeof(WCHAR)); - HeapFree(GetProcessHeap(),0,FilePath); - HeapFree(GetProcessHeap(),0,FileName); - RegCloseKey(hkey2); + LPWSTR deformated; + buffer = MSI_RecordGetString(row,6); + deformat_string(package,buffer,&deformated); + IShellLinkW_SetArguments(sl,deformated); + HeapFree(GetProcessHeap(),0,deformated); } + + if (!MSI_RecordIsNull(row,7)) + { + buffer = MSI_RecordGetString(row,7); + IShellLinkW_SetDescription(sl,buffer); + } + + if (!MSI_RecordIsNull(row,8)) + IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8)); + + if (!MSI_RecordIsNull(row,9)) + { + WCHAR *Path = NULL; + INT index; + + buffer = MSI_RecordGetString(row,9); + + build_icon_path(package,buffer,&Path); + index = MSI_RecordGetInteger(row,10); + + IShellLinkW_SetIconLocation(sl,Path,index); + HeapFree(GetProcessHeap(),0,Path); + } + + if (!MSI_RecordIsNull(row,11)) + IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11)); + + if (!MSI_RecordIsNull(row,12)) + { + LPWSTR Path; + buffer = MSI_RecordGetString(row,12); + Path = resolve_folder(package, buffer, FALSE, FALSE, NULL); + IShellLinkW_SetWorkingDirectory(sl,Path); + HeapFree(GetProcessHeap(), 0, Path); + } + + TRACE("Writing shortcut to %s\n",debugstr_w(target_file)); + IPersistFile_Save(pf,target_file,FALSE); + + HeapFree(GetProcessHeap(),0,target_file); + + IPersistFile_Release( pf ); + IShellLinkW_Release( sl ); + return ERROR_SUCCESS; } -static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid); - -static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent, - LPWSTR clsid) +static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) { UINT rc; + HRESULT res; MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR Query_t[] = - {'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}; - - if (!package) - return ERROR_INVALID_HANDLE; - - rc = MSI_OpenQuery(package->db, &view, Query_t, parent); - if (rc != ERROR_SUCCESS) - return rc; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - register_progid(package,row,clsid); - - msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; -} - -static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid) -{ - UINT rc = ERROR_SUCCESS; - - if (MSI_RecordIsNull(row,2)) - rc = register_progid_base(package,row,clsid); - else - { - WCHAR buffer[0x1000]; - DWORD sz, disp; - HKEY hkey,hkey2; - static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; - static const WCHAR szDefaultIcon[] = - {'D','e','f','a','u','l','t','I','c','o','n',0}; - - /* check if already registered */ - sz = 0x100; - MSI_RecordGetStringW(row,1,buffer,&sz); - RegCreateKeyExW(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0, - KEY_ALL_ACCESS, NULL, &hkey, &disp ); - if (disp == REG_OPENED_EXISTING_KEY) - { - TRACE("Key already registered\n"); - RegCloseKey(hkey); - return rc; - } - - sz = 0x100; - MSI_RecordGetStringW(row,2,buffer,&sz); - rc = register_parent_progid(package,buffer,clsid); - - /* clsid is same as parent */ - RegCreateKeyW(hkey,szCLSID,&hkey2); - RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) * - sizeof(WCHAR)); - - RegCloseKey(hkey2); - - - if (!MSI_RecordIsNull(row,4)) - { - sz = 0x100; - MSI_RecordGetStringW(row,4,buffer,&sz); - RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, - (strlenW(buffer)+1) * sizeof(WCHAR)); - } - - if (!MSI_RecordIsNull(row,5)) - { - LPWSTR FileName = load_dynamic_stringW(row,5); - LPWSTR FilePath; - RegCreateKeyW(hkey,szDefaultIcon,&hkey2); - build_icon_path(package,FileName,&FilePath); - RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)FilePath, - (strlenW(FilePath)+1) * sizeof(WCHAR)); - HeapFree(GetProcessHeap(),0,FilePath); - HeapFree(GetProcessHeap(),0,FileName); - RegCloseKey(hkey2); - } - - RegCloseKey(hkey); - } - return rc; -} - -static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package) -{ - /* - * Sigh, here I am just brute force registering all progids - * this needs to be linked to the Classes that have been registered - * but the easiest way to do that is to load all these stuff into - * memory for easy checking. - * - * Gives me something to continue to work toward. - */ - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; static const WCHAR Query[] = - {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', - '`','P','r','o','g','I','d','`',0}; + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','S','h','o','r','t','c','u','t','`',0}; if (!package) return ERROR_INVALID_HANDLE; @@ -4973,81 +2938,6 @@ static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package) if (rc != ERROR_SUCCESS) return ERROR_SUCCESS; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - WCHAR clsid[0x1000]; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - register_progid(package,row,clsid); - ui_actiondata(package,szRegisterProgIdInfo,row); - - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; -} - -static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, - LPWSTR *FilePath) -{ - LPWSTR ProductCode; - LPWSTR SystemFolder; - LPWSTR dest; - UINT rc; - - static const WCHAR szInstaller[] = - {'I','n','s','t','a','l','l','e','r','\\',0}; - static const WCHAR szFolder[] = - {'W','i','n','d','o','w','s','F','o','l','d','e','r',0}; - - ProductCode = load_dynamic_property(package,szProductCode,&rc); - if (!ProductCode) - return rc; - - SystemFolder = load_dynamic_property(package,szFolder,NULL); - - dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode); - - create_full_pathW(dest); - - *FilePath = build_directory_name(2, dest, icon_name); - - HeapFree(GetProcessHeap(),0,SystemFolder); - HeapFree(GetProcessHeap(),0,ProductCode); - HeapFree(GetProcessHeap(),0,dest); - return ERROR_SUCCESS; -} - -static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) -{ - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR Query[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','S','h','o','r','t','c','u','t','`',0}; - IShellLinkW *sl; - IPersistFile *pf; - HRESULT res; - - if (!package) - return ERROR_INVALID_HANDLE; - res = CoInitialize( NULL ); if (FAILED (res)) { @@ -5055,179 +2945,65 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) return ERROR_FUNCTION_FAILED; } - rc = MSI_DatabaseOpenViewW(package->db, Query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - LPWSTR target_file, target_folder; - WCHAR buffer[0x100]; - DWORD sz; - DWORD index; - static const WCHAR szlnk[]={'.','l','n','k',0}; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - sz = 0x100; - MSI_RecordGetStringW(row,4,buffer,&sz); - - index = get_loaded_component(package,buffer); - - if (index < 0) - { - msiobj_release(&row->hdr); - continue; - } - - if (!ACTION_VerifyComponentForAction(package, index, - INSTALLSTATE_LOCAL)) - { - TRACE("Skipping shortcut creation due to disabled component\n"); - msiobj_release(&row->hdr); - - package->components[index].Action = - package->components[index].Installed; - - continue; - } - - package->components[index].Action = INSTALLSTATE_LOCAL; - - ui_actiondata(package,szCreateShortcuts,row); - - res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, - &IID_IShellLinkW, (LPVOID *) &sl ); - - if (FAILED(res)) - { - ERR("Is IID_IShellLink\n"); - msiobj_release(&row->hdr); - continue; - } - - res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf ); - if( FAILED( res ) ) - { - ERR("Is IID_IPersistFile\n"); - msiobj_release(&row->hdr); - continue; - } - - sz = 0x100; - MSI_RecordGetStringW(row,2,buffer,&sz); - target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL); - - /* may be needed because of a bug somehwere else */ - create_full_pathW(target_folder); - - sz = 0x100; - MSI_RecordGetStringW(row,3,buffer,&sz); - reduce_to_longfilename(buffer); - if (!strchrW(buffer,'.') || strcmpiW(strchrW(buffer,'.'),szlnk)) - strcatW(buffer,szlnk); - target_file = build_directory_name(2, target_folder, buffer); - HeapFree(GetProcessHeap(),0,target_folder); - - sz = 0x100; - MSI_RecordGetStringW(row,5,buffer,&sz); - if (strchrW(buffer,'[')) - { - LPWSTR deformated; - deformat_string(package,buffer,&deformated); - IShellLinkW_SetPath(sl,deformated); - HeapFree(GetProcessHeap(),0,deformated); - } - else - { - LPWSTR keypath; - FIXME("poorly handled shortcut format, advertised shortcut\n"); - keypath = strdupW(package->components[index].FullKeypath); - IShellLinkW_SetPath(sl,keypath); - HeapFree(GetProcessHeap(),0,keypath); - } - - if (!MSI_RecordIsNull(row,6)) - { - LPWSTR deformated; - sz = 0x100; - MSI_RecordGetStringW(row,6,buffer,&sz); - deformat_string(package,buffer,&deformated); - IShellLinkW_SetArguments(sl,deformated); - HeapFree(GetProcessHeap(),0,deformated); - } - - if (!MSI_RecordIsNull(row,7)) - { - LPWSTR deformated; - deformated = load_dynamic_stringW(row,7); - IShellLinkW_SetDescription(sl,deformated); - HeapFree(GetProcessHeap(),0,deformated); - } - - if (!MSI_RecordIsNull(row,8)) - IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8)); - - if (!MSI_RecordIsNull(row,9)) - { - WCHAR *Path = NULL; - INT index; - - sz = 0x100; - MSI_RecordGetStringW(row,9,buffer,&sz); - - build_icon_path(package,buffer,&Path); - index = MSI_RecordGetInteger(row,10); - - IShellLinkW_SetIconLocation(sl,Path,index); - HeapFree(GetProcessHeap(),0,Path); - } - - if (!MSI_RecordIsNull(row,11)) - IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11)); - - if (!MSI_RecordIsNull(row,12)) - { - LPWSTR Path; - sz = 0x100; - MSI_RecordGetStringW(row,12,buffer,&sz); - Path = resolve_folder(package, buffer, FALSE, FALSE, NULL); - IShellLinkW_SetWorkingDirectory(sl,Path); - HeapFree(GetProcessHeap(), 0, Path); - } - - TRACE("Writing shortcut to %s\n",debugstr_w(target_file)); - IPersistFile_Save(pf,target_file,FALSE); - - HeapFree(GetProcessHeap(),0,target_file); - - IPersistFile_Release( pf ); - IShellLinkW_Release( sl ); - - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package); msiobj_release(&view->hdr); - CoUninitialize(); return rc; } +static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE* package = (MSIPACKAGE*)param; + HANDLE the_file; + LPWSTR FilePath=NULL; + LPCWSTR FileName=NULL; + CHAR buffer[1024]; + DWORD sz; + UINT rc; + + FileName = MSI_RecordGetString(row,1); + if (!FileName) + { + ERR("Unable to get FileName\n"); + return ERROR_SUCCESS; + } + + build_icon_path(package,FileName,&FilePath); + + 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)); + HeapFree(GetProcessHeap(),0,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); + + HeapFree(GetProcessHeap(),0,FilePath); + + CloseHandle(the_file); + return ERROR_SUCCESS; +} /* * 99% of the work done here is only done for @@ -5239,11 +3015,9 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) { UINT rc; MSIQUERY * view; - MSIRECORD * row = 0; static const WCHAR Query[]= {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', '`','I','c','o','n','`',0}; - DWORD sz; /* for registry stuff */ LPWSTR productcode; HKEY hkey=0; @@ -5252,6 +3026,19 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) {'P','r','o','d','u','c','t','N','a','m','e',0}; static const WCHAR szPackageCode[] = {'P','a','c','k','a','g','e','C','o','d','e',0}; + static const WCHAR szLanguage[] = + {'L','a','n','g','u','a','g','e',0}; + static const WCHAR szProductLanguage[] = + {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0}; + static const WCHAR szProductIcon[] = + {'P','r','o','d','u','c','t','I','c','o','n',0}; + static const WCHAR szARPProductIcon[] = + {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0}; + static const WCHAR szProductVersion[] = + {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0}; + static const WCHAR szVersion[] = + {'V','e','r','s','i','o','n',0}; + DWORD langid; LPWSTR buffer; DWORD size; MSIHANDLE hDb, hSumInfo; @@ -5259,82 +3046,17 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) if (!package) return ERROR_INVALID_HANDLE; + /* write out icon files */ + rc = MSI_DatabaseOpenViewW(package->db, Query, &view); - if (rc != ERROR_SUCCESS) - goto next; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) + if (rc == ERROR_SUCCESS) { - MSI_ViewClose(view); + MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package); msiobj_release(&view->hdr); - goto next; } - while (1) - { - HANDLE the_file; - WCHAR *FilePath=NULL; - WCHAR *FileName=NULL; - CHAR buffer[1024]; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - FileName = load_dynamic_stringW(row,1); - if (!FileName) - { - ERR("Unable to get FileName\n"); - msiobj_release(&row->hdr); - continue; - } - - build_icon_path(package,FileName,&FilePath); - - HeapFree(GetProcessHeap(),0,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)); - msiobj_release(&row->hdr); - HeapFree(GetProcessHeap(),0,FilePath); - continue; - } - - 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); - - HeapFree(GetProcessHeap(),0,FilePath); - - CloseHandle(the_file); - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - -next: /* ok there is a lot more done here but i need to figure out what */ + productcode = load_dynamic_property(package,szProductCode,&rc); if (!productcode) return rc; @@ -5350,8 +3072,34 @@ next: buffer = load_dynamic_property(package,szProductName,NULL); size = strlenW(buffer)*sizeof(WCHAR); - RegSetValueExW(hukey,szProductName,0,REG_SZ, (LPSTR)buffer,size); + RegSetValueExW(hukey,szProductName,0,REG_SZ, (BYTE *)buffer,size); HeapFree(GetProcessHeap(),0,buffer); + + buffer = load_dynamic_property(package,szProductLanguage,NULL); + size = sizeof(DWORD); + langid = atoiW(buffer); + RegSetValueExW(hukey,szLanguage,0,REG_DWORD, (BYTE *)&langid,size); + HeapFree(GetProcessHeap(),0,buffer); + + buffer = load_dynamic_property(package,szARPProductIcon,NULL); + if (buffer) + { + LPWSTR path; + build_icon_path(package,buffer,&path); + size = strlenW(path) * sizeof(WCHAR); + RegSetValueExW(hukey,szProductIcon,0,REG_SZ, (BYTE *)path,size); + } + HeapFree(GetProcessHeap(),0,buffer); + + buffer = load_dynamic_property(package,szProductVersion,NULL); + if (buffer) + { + DWORD verdword = build_version_dword(buffer); + size = sizeof(DWORD); + RegSetValueExW(hukey,szVersion,0,REG_DWORD, (BYTE *)&verdword,size); + } + HeapFree(GetProcessHeap(),0,buffer); + FIXME("Need to write more keys to the user registry\n"); hDb= alloc_msihandle( &package->db->hdr ); @@ -5396,16 +3144,112 @@ end: return rc; } +static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE *package = (MSIPACKAGE*)param; + LPCWSTR component,section,key,value,identifier,filename,dirproperty; + LPWSTR deformated_section, deformated_key, deformated_value; + LPWSTR folder, fullname = NULL; + MSIRECORD * uirow; + INT component_index,action; + static const WCHAR szWindowsFolder[] = + {'W','i','n','d','o','w','s','F','o','l','d','e','r',0}; + + component = MSI_RecordGetString(row, 8); + component_index = get_loaded_component(package,component); + + if (!ACTION_VerifyComponentForAction(package, component_index, + INSTALLSTATE_LOCAL)) + { + TRACE("Skipping ini file due to disabled component %s\n", + debugstr_w(component)); + + package->components[component_index].Action = + package->components[component_index].Installed; + + return ERROR_SUCCESS; + } + + package->components[component_index].Action = INSTALLSTATE_LOCAL; + + identifier = MSI_RecordGetString(row,1); + filename = MSI_RecordGetString(row,2); + dirproperty = MSI_RecordGetString(row,3); + 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 (dirproperty) + { + folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL); + if (!folder) + folder = load_dynamic_property(package,dirproperty,NULL); + } + else + folder = load_dynamic_property(package, szWindowsFolder, NULL); + + if (!folder) + { + ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty)); + goto cleanup; + } + + fullname = build_directory_name(3, folder, filename, NULL); + + 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); + ui_actiondata(package,szWriteIniValues,uirow); + msiobj_release( &uirow->hdr ); +cleanup: + HeapFree(GetProcessHeap(),0,fullname); + HeapFree(GetProcessHeap(),0,folder); + HeapFree(GetProcessHeap(),0,deformated_key); + HeapFree(GetProcessHeap(),0,deformated_value); + HeapFree(GetProcessHeap(),0,deformated_section); + return ERROR_SUCCESS; +} + static UINT ACTION_WriteIniValues(MSIPACKAGE *package) { UINT rc; MSIQUERY * view; - MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', '`','I','n','i','F','i','l','e','`',0}; - static const WCHAR szWindowsFolder[] = - {'W','i','n','d','o','w','s','F','o','l','d','e','r',0}; rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); if (rc != ERROR_SUCCESS) @@ -5414,139 +3258,18 @@ static UINT ACTION_WriteIniValues(MSIPACKAGE *package) return ERROR_SUCCESS; } - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - LPWSTR component,filename,dirproperty,section,key,value,identifier; - LPWSTR deformated_section, deformated_key, deformated_value; - LPWSTR folder, fullname = NULL; - MSIRECORD * uirow; - INT component_index,action; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - component = load_dynamic_stringW(row, 8); - component_index = get_loaded_component(package,component); - HeapFree(GetProcessHeap(),0,component); - - if (!ACTION_VerifyComponentForAction(package, component_index, - INSTALLSTATE_LOCAL)) - { - TRACE("Skipping ini file due to disabled component\n"); - msiobj_release(&row->hdr); - - package->components[component_index].Action = - package->components[component_index].Installed; - - continue; - } - - package->components[component_index].Action = INSTALLSTATE_LOCAL; - - identifier = load_dynamic_stringW(row,1); - filename = load_dynamic_stringW(row,2); - dirproperty = load_dynamic_stringW(row,3); - section = load_dynamic_stringW(row,4); - key = load_dynamic_stringW(row,5); - value = load_dynamic_stringW(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 (dirproperty) - { - folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL); - if (!folder) - folder = load_dynamic_property(package,dirproperty,NULL); - } - else - folder = load_dynamic_property(package, szWindowsFolder, NULL); - - if (!folder) - { - ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty)); - goto cleanup; - } - - fullname = build_directory_name(3, folder, filename, NULL); - - 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); - ui_actiondata(package,szWriteIniValues,uirow); - msiobj_release( &uirow->hdr ); -cleanup: - HeapFree(GetProcessHeap(),0,identifier); - HeapFree(GetProcessHeap(),0,fullname); - HeapFree(GetProcessHeap(),0,filename); - HeapFree(GetProcessHeap(),0,key); - HeapFree(GetProcessHeap(),0,value); - HeapFree(GetProcessHeap(),0,section); - HeapFree(GetProcessHeap(),0,dirproperty); - HeapFree(GetProcessHeap(),0,folder); - HeapFree(GetProcessHeap(),0,deformated_key); - HeapFree(GetProcessHeap(),0,deformated_value); - HeapFree(GetProcessHeap(),0,deformated_section); - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package); msiobj_release(&view->hdr); return rc; } -static UINT ACTION_SelfRegModules(MSIPACKAGE *package) +static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param) { - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','S','e','l','f','R','e','g','`',0}; - + MSIPACKAGE *package = (MSIPACKAGE*)param; + LPCWSTR filename; + LPWSTR FullName; + INT index; + DWORD len; static const WCHAR ExeStr[] = {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0}; static const WCHAR close[] = {'\"',0}; @@ -5556,6 +3279,43 @@ static UINT ACTION_SelfRegModules(MSIPACKAGE *package) memset(&si,0,sizeof(STARTUPINFOW)); + filename = MSI_RecordGetString(row,1); + index = get_loaded_file(package,filename); + + if (index < 0) + { + ERR("Unable to find file id %s\n",debugstr_w(filename)); + return ERROR_SUCCESS; + } + + len = strlenW(ExeStr); + len += strlenW(package->files[index].TargetPath); + len +=2; + + FullName = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); + strcpyW(FullName,ExeStr); + strcatW(FullName,package->files[index].TargetPath); + strcatW(FullName,close); + + TRACE("Registering %s\n",debugstr_w(FullName)); + brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon, + &si, &info); + + if (brc) + msi_dialog_check_messages(info.hProcess); + + HeapFree(GetProcessHeap(),0,FullName); + return ERROR_SUCCESS; +} + +static UINT ACTION_SelfRegModules(MSIPACKAGE *package) +{ + UINT rc; + MSIQUERY * view; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','S','e','l','f','R','e','g','`',0}; + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); if (rc != ERROR_SUCCESS) { @@ -5563,61 +3323,10 @@ static UINT ACTION_SelfRegModules(MSIPACKAGE *package) return ERROR_SUCCESS; } - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - LPWSTR filename; - INT index; - DWORD len; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - filename = load_dynamic_stringW(row,1); - index = get_loaded_file(package,filename); - - if (index < 0) - { - ERR("Unable to find file id %s\n",debugstr_w(filename)); - HeapFree(GetProcessHeap(),0,filename); - msiobj_release(&row->hdr); - continue; - } - HeapFree(GetProcessHeap(),0,filename); - - len = strlenW(ExeStr); - len += strlenW(package->files[index].TargetPath); - len +=2; - - filename = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); - strcpyW(filename,ExeStr); - strcatW(filename,package->files[index].TargetPath); - strcatW(filename,close); - - TRACE("Registering %s\n",debugstr_w(filename)); - brc = CreateProcessW(NULL, filename, NULL, NULL, FALSE, 0, NULL, - c_colon, &si, &info); - - if (brc) - msi_dialog_check_messages(info.hProcess); - - HeapFree(GetProcessHeap(),0,filename); - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package); msiobj_release(&view->hdr); - return rc; + + return ERROR_SUCCESS; } static UINT ACTION_PublishFeatures(MSIPACKAGE *package) @@ -5723,7 +3432,7 @@ end: static UINT ACTION_RegisterProduct(MSIPACKAGE *package) { HKEY hkey=0; - LPWSTR buffer; + LPWSTR buffer = NULL; LPWSTR productcode; UINT rc,i; DWORD size; @@ -5777,6 +3486,34 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) '%','x','.','m','s','i',0}; static const WCHAR szLocalPackage[]= {'L','o','c','a','l','P','a','c','k','a','g','e',0}; + static const WCHAR szUpgradeCode[] = + {'U','p','g','r','a','d','e','C','o','d','e',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 szInstallDate[] = + {'I','n','s','t','a','l','l','D','a','t','e',0}; + static const WCHAR szLanguage[] = + {'L','a','n','g','u','a','g','e',0}; + static const WCHAR szProductLanguage[] = + {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0}; + static const WCHAR szProductVersion[] = + {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0}; + static const WCHAR szVersion[] = + {'V','e','r','s','i','o','n',0}; + static const WCHAR szVersionMajor[] = + {'V','e','r','s','i','o','n','M','a','j','o','r',0}; + static const WCHAR szVersionMinor[] = + {'V','e','r','s','i','o','n','M','i','n','o','r',0}; + + SYSTEMTIME systime; + static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0}; + LPWSTR upgrade_code; WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH]; INT num,start; @@ -5802,6 +3539,7 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) buffer = szNONE; size = strlenW(buffer)*sizeof(WCHAR); RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size); + HeapFree(GetProcessHeap(),0,buffer); i++; } @@ -5842,6 +3580,60 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) GetLastError()); size = strlenW(packagefile)*sizeof(WCHAR); RegSetValueExW(hkey,szLocalPackage,0,REG_SZ,(LPSTR)packagefile,size); + + /* do ModifyPath and UninstallString */ + size = deformat_string(package,modpath_fmt,&buffer); + RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPSTR)buffer,size); + RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPSTR)buffer,size); + HeapFree(GetProcessHeap(),0,buffer); + + FIXME("Write real Estimated Size when we have it\n"); + size = 0; + RegSetValueExW(hkey,szEstimatedSize,0,REG_DWORD,(LPSTR)&size,sizeof(DWORD)); + + GetLocalTime(&systime); + size = 9*sizeof(WCHAR); + buffer= HeapAlloc(GetProcessHeap(),0,size); + sprintfW(buffer,date_fmt,systime.wYear,systime.wMonth,systime.wDay); + size = strlenW(buffer)*sizeof(WCHAR); + RegSetValueExW(hkey,szInstallDate,0,REG_SZ,(LPSTR)buffer,size); + HeapFree(GetProcessHeap(),0,buffer); + + buffer = load_dynamic_property(package,szProductLanguage,NULL); + size = atoiW(buffer); + RegSetValueExW(hkey,szLanguage,0,REG_DWORD, (LPSTR)&size,sizeof(DWORD)); + HeapFree(GetProcessHeap(),1,buffer); + + buffer = load_dynamic_property(package,szProductVersion,NULL); + if (buffer) + { + DWORD verdword = build_version_dword(buffer); + DWORD vermajor = verdword>>24; + DWORD verminor = (verdword>>16)&0x00FF; + size = sizeof(DWORD); + RegSetValueExW(hkey,szVersion,0,REG_DWORD,(LPSTR)&verdword,size); + RegSetValueExW(hkey,szVersionMajor,0,REG_DWORD,(LPSTR)&vermajor,size); + RegSetValueExW(hkey,szVersionMinor,0,REG_DWORD,(LPSTR)&verminor,size); + } + HeapFree(GetProcessHeap(),0,buffer); + + /* Handle Upgrade Codes */ + upgrade_code = load_dynamic_property(package,szUpgradeCode, NULL); + if (upgrade_code) + { + HKEY hkey2; + WCHAR squashed[33]; + MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE); + squash_guid(productcode,squashed); + RegSetValueExW(hkey2, squashed, 0,REG_SZ,NULL,0); + RegCloseKey(hkey2); + MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE); + squash_guid(productcode,squashed); + RegSetValueExW(hkey2, squashed, 0,REG_SZ,NULL,0); + RegCloseKey(hkey2); + + HeapFree(GetProcessHeap(),0,upgrade_code); + } end: HeapFree(GetProcessHeap(),0,productcode); @@ -5852,52 +3644,35 @@ end: static UINT ACTION_InstallExecute(MSIPACKAGE *package) { - int i; + UINT rc; + if (!package) return ERROR_INVALID_HANDLE; - for (i = 0; i < package->DeferredActionCount; i++) - { - LPWSTR action; - action = package->DeferredAction[i]; - ui_actionstart(package, action); - TRACE("Executing Action (%s)\n",debugstr_w(action)); - ACTION_CustomAction(package,action,TRUE); - HeapFree(GetProcessHeap(),0,package->DeferredAction[i]); - } - HeapFree(GetProcessHeap(),0,package->DeferredAction); + rc = execute_script(package,INSTALL_SCRIPT); - package->DeferredActionCount = 0; - package->DeferredAction = NULL; - - return ERROR_SUCCESS; + return rc; } static UINT ACTION_InstallFinalize(MSIPACKAGE *package) { - int i; + UINT rc; + if (!package) return ERROR_INVALID_HANDLE; + /* turn off scheduleing */ + package->script->CurrentlyScripting= FALSE; + /* first do the same as an InstallExecute */ - ACTION_InstallExecute(package); + rc = ACTION_InstallExecute(package); + if (rc != ERROR_SUCCESS) + return rc; /* then handle Commit Actions */ - for (i = 0; i < package->CommitActionCount; i++) - { - LPWSTR action; - action = package->CommitAction[i]; - ui_actionstart(package, action); - TRACE("Executing Commit Action (%s)\n",debugstr_w(action)); - ACTION_CustomAction(package,action,TRUE); - HeapFree(GetProcessHeap(),0,package->CommitAction[i]); - } - HeapFree(GetProcessHeap(),0,package->CommitAction); + rc = execute_script(package,COMMIT_SCRIPT); - package->CommitActionCount = 0; - package->CommitAction = NULL; - - return ERROR_SUCCESS; + return rc; } static UINT ACTION_ForceReboot(MSIPACKAGE *package) @@ -5999,214 +3774,6 @@ UINT ACTION_ResolveSource(MSIPACKAGE* package) return ERROR_SUCCESS; } - -static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package) -{ - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','E','x','t','e','n','s','i','o','n','`',0}; - static const WCHAR szContentType[] = - {'C','o','n','t','e','n','t',' ','T','y','p','e',0 }; - HKEY hkey; - - if (!package) - return ERROR_INVALID_HANDLE; - - rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - goto end; - } - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - goto end; - } - - while (1) - { - WCHAR buffer[0x100]; - WCHAR extension[257]; - LPWSTR exten; - DWORD sz; - INT index; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - sz=0x100; - MSI_RecordGetStringW(row,2,buffer,&sz); - - index = get_loaded_component(package,buffer); - - if (index < 0) - { - msiobj_release(&row->hdr); - continue; - } - - if ((!ACTION_VerifyComponentForAction(package, index, - INSTALLSTATE_LOCAL)) && - (!ACTION_VerifyComponentForAction(package, index, - INSTALLSTATE_ADVERTISED))) - { - TRACE("Skipping extension reg due to disabled component\n"); - msiobj_release(&row->hdr); - - package->components[index].Action = - package->components[index].Installed; - - continue; - } - - package->components[index].Action = INSTALLSTATE_LOCAL; - - exten = load_dynamic_stringW(row,1); - extension[0] = '.'; - extension[1] = 0; - strcatW(extension,exten); - HeapFree(GetProcessHeap(),0,exten); - - RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey); - - if (!MSI_RecordIsNull(row,4)) - { - LPWSTR mime = load_dynamic_stringW(row,4); - RegSetValueExW(hkey,szContentType,0,REG_SZ,(LPVOID)mime, - (strlenW(mime)+1)*sizeof(WCHAR)); - HeapFree(GetProcessHeap(),0,mime); - } - - if (!MSI_RecordIsNull(row,3)) - { - static const WCHAR szSN[] = - {'\\','S','h','e','l','l','N','e','w',0}; - HKEY hkey2; - LPWSTR newkey; - LPWSTR progid= load_dynamic_stringW(row,3); - - RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid, - (strlenW(progid)+1)*sizeof(WCHAR)); - - newkey = HeapAlloc(GetProcessHeap(),0, - (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR)); - - strcpyW(newkey,progid); - strcatW(newkey,szSN); - RegCreateKeyW(hkey,newkey,&hkey2); - RegCloseKey(hkey2); - - HeapFree(GetProcessHeap(),0,progid); - HeapFree(GetProcessHeap(),0,newkey); - } - - - RegCloseKey(hkey); - - ui_actiondata(package,szRegisterExtensionInfo,row); - - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - -end: - return rc; -} - -static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package) -{ - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','M','I','M','E','`',0}; - static const WCHAR szExten[] = - {'E','x','t','e','n','s','i','o','n',0 }; - HKEY hkey; - - if (!package) - return ERROR_INVALID_HANDLE; - - rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - goto end; - } - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - goto end; - } - - while (1) - { - WCHAR extension[257]; - LPWSTR exten; - LPWSTR mime; - static const WCHAR fmt[] = - {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\', - 'C','o','n','t','e','n','t',' ','T','y','p','e','\\', '%','s',0}; - LPWSTR key; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - mime = load_dynamic_stringW(row,1); - exten = load_dynamic_stringW(row,2); - extension[0] = '.'; - extension[1] = 0; - strcatW(extension,exten); - HeapFree(GetProcessHeap(),0,exten); - - key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) * - sizeof(WCHAR)); - sprintfW(key,fmt,mime); - RegCreateKeyW(HKEY_CLASSES_ROOT,key,&hkey); - RegSetValueExW(hkey,szExten,0,REG_SZ,(LPVOID)extension, - (strlenW(extension)+1)*sizeof(WCHAR)); - - HeapFree(GetProcessHeap(),0,mime); - HeapFree(GetProcessHeap(),0,key); - - if (!MSI_RecordIsNull(row,3)) - { - FIXME("Handle non null for field 3\n"); - } - - RegCloseKey(hkey); - - ui_actiondata(package,szRegisterMIMEInfo,row); - - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - -end: - return rc; -} - static UINT ACTION_RegisterUser(MSIPACKAGE *package) { static const WCHAR szProductID[]= @@ -6274,8 +3841,16 @@ end: static UINT ACTION_ExecuteAction(MSIPACKAGE *package) { + static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0}; + static const WCHAR szTwo[] = {'2',0}; UINT rc; + LPWSTR level; + level = load_dynamic_property(package,szUILevel,NULL); + + MSI_SetPropertyW(package,szUILevel,szTwo); rc = ACTION_ProcessExecSequence(package,FALSE); + MSI_SetPropertyW(package,szUILevel,level); + HeapFree(GetProcessHeap(),0,level); return rc; } @@ -6377,7 +3952,7 @@ static LPWSTR load_ttfname_from(LPCWSTR filename) { int nPos; LPSTR buf; - static const LPSTR tt = " (TrueType)"; + static LPCSTR tt = " (TrueType)"; ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength); ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset); @@ -6412,14 +3987,13 @@ static LPWSTR load_ttfname_from(LPCWSTR filename) return ret; } -static UINT ACTION_RegisterFonts(MSIPACKAGE *package) +static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param) { - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','F','o','n','t','`',0}; + MSIPACKAGE *package = (MSIPACKAGE*)param; + LPWSTR name; + LPCWSTR file; + UINT index; + DWORD size; static const WCHAR regfont1[] = {'S','o','f','t','w','a','r','e','\\', 'M','i','c','r','o','s','o','f','t','\\', @@ -6435,7 +4009,52 @@ static UINT ACTION_RegisterFonts(MSIPACKAGE *package) HKEY hkey1; HKEY hkey2; - TRACE("%p\n", package); + file = MSI_RecordGetString(row,1); + index = get_loaded_file(package,file); + if (index < 0) + { + ERR("Unable to load file\n"); + return ERROR_SUCCESS; + } + + /* check to make sure that component is installed */ + if (!ACTION_VerifyComponentForAction(package, + package->files[index].ComponentIndex, INSTALLSTATE_LOCAL)) + { + TRACE("Skipping: Component not scheduled for install\n"); + return ERROR_SUCCESS; + } + + RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1); + RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2); + + if (MSI_RecordIsNull(row,2)) + name = load_ttfname_from(package->files[index].TargetPath); + else + name = load_dynamic_stringW(row,2); + + if (name) + { + size = strlenW(package->files[index].FileName) * sizeof(WCHAR); + RegSetValueExW(hkey1,name,0,REG_SZ, + (LPBYTE)package->files[index].FileName,size); + RegSetValueExW(hkey2,name,0,REG_SZ, + (LPBYTE)package->files[index].FileName,size); + } + + HeapFree(GetProcessHeap(),0,name); + RegCloseKey(hkey1); + RegCloseKey(hkey2); + return ERROR_SUCCESS; +} + +static UINT ACTION_RegisterFonts(MSIPACKAGE *package) +{ + UINT rc; + MSIQUERY * view; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','F','o','n','t','`',0}; rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); if (rc != ERROR_SUCCESS) @@ -6444,182 +4063,77 @@ static UINT ACTION_RegisterFonts(MSIPACKAGE *package) return ERROR_SUCCESS; } - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - TRACE("MSI_ViewExecute returned %d\n", rc); - return ERROR_SUCCESS; - } - - RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1); - RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2); - - while (1) - { - LPWSTR name; - LPWSTR file; - UINT index; - DWORD size; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - file = load_dynamic_stringW(row,1); - index = get_loaded_file(package,file); - if (index < 0) - { - ERR("Unable to load file\n"); - HeapFree(GetProcessHeap(),0,file); - continue; - } - - /* check to make sure that component is installed */ - if (!ACTION_VerifyComponentForAction(package, - package->files[index].ComponentIndex, INSTALLSTATE_LOCAL)) - { - TRACE("Skipping: Component not scheduled for install\n"); - HeapFree(GetProcessHeap(),0,file); - - msiobj_release(&row->hdr); - - continue; - } - - if (MSI_RecordIsNull(row,2)) - name = load_ttfname_from(package->files[index].TargetPath); - else - name = load_dynamic_stringW(row,2); - - if (name) - { - size = strlenW(package->files[index].FileName) * sizeof(WCHAR); - RegSetValueExW(hkey1,name,0,REG_SZ, - (LPBYTE)package->files[index].FileName,size); - RegSetValueExW(hkey2,name,0,REG_SZ, - (LPBYTE)package->files[index].FileName,size); - } - - HeapFree(GetProcessHeap(),0,file); - HeapFree(GetProcessHeap(),0,name); - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package); msiobj_release(&view->hdr); - RegCloseKey(hkey1); - RegCloseKey(hkey2); - - TRACE("returning %d\n", rc); - return rc; + return ERROR_SUCCESS; } static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param) { MSIPACKAGE *package = (MSIPACKAGE*)param; - LPWSTR productid=NULL, compgroupid=NULL; - LPWSTR feature=NULL; - LPWSTR text = NULL; - LPWSTR qualifier = NULL; - LPWSTR component = NULL; - GUID clsid; - WCHAR productid_85[21]; - WCHAR component_85[21]; + LPCWSTR compgroupid=NULL; + LPCWSTR feature=NULL; + LPCWSTR text = NULL; + LPCWSTR qualifier = NULL; + LPCWSTR component = NULL; + LPWSTR advertise = NULL; + LPWSTR output = NULL; HKEY hkey; UINT rc = ERROR_SUCCESS; UINT index; - /* - * I have a fair bit of confusion as to when a < is used and when a > is - * used. I do not think i have it right... - * - * Ok it appears that the > is used if there is a guid for the compoenent - * and the < is used if not. - */ - static WCHAR fmt1[] = {'%','s','%','s','<',0,0}; - static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0}; - LPWSTR output = NULL; DWORD sz = 0; - INT component_index; - component = load_dynamic_stringW(rec,3); - component_index = get_loaded_component(package,component); + component = MSI_RecordGetString(rec,3); + index = get_loaded_component(package,component); - if (!ACTION_VerifyComponentForAction(package, component_index, + if (!ACTION_VerifyComponentForAction(package, index, INSTALLSTATE_LOCAL) && - !ACTION_VerifyComponentForAction(package, component_index, + !ACTION_VerifyComponentForAction(package, index, INSTALLSTATE_SOURCE) && - !ACTION_VerifyComponentForAction(package, component_index, + !ACTION_VerifyComponentForAction(package, index, INSTALLSTATE_ADVERTISED)) { TRACE("Skipping: Component %s not scheduled for install\n", debugstr_w(component)); - HeapFree(GetProcessHeap(),0,component); + return ERROR_SUCCESS; } - memset(productid_85,0,sizeof(productid_85)); - memset(component_85,0,sizeof(component_85)); - compgroupid = load_dynamic_stringW(rec,1); + compgroupid = MSI_RecordGetString(rec,1); rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE); if (rc != ERROR_SUCCESS) goto end; - productid = load_dynamic_property(package,szProductCode,NULL); - CLSIDFromString(productid, &clsid); - - encode_base85_guid(&clsid,productid_85); - - text = load_dynamic_stringW(rec,4); - qualifier = load_dynamic_stringW(rec,2); - - feature = load_dynamic_stringW(rec,5); + text = MSI_RecordGetString(rec,4); + qualifier = MSI_RecordGetString(rec,2); + feature = MSI_RecordGetString(rec,5); - index = get_loaded_component(package, component); - CLSIDFromString(package->components[index].ComponentId, &clsid); - encode_base85_guid(&clsid,component_85); + advertise = create_component_advertise_string(package, + &package->components[index], feature); + + sz = strlenW(advertise); - TRACE("Doing something with this... %s = %s %s %s %s\n", - debugstr_w(qualifier), debugstr_w(productid_85), - debugstr_w(feature), debugstr_w(text), debugstr_w(component_85)); - - sz = lstrlenW(productid_85) + lstrlenW(feature); if (text) sz += lstrlenW(text); - if (component && index >= 0) - sz += lstrlenW(component_85); sz+=3; sz *= sizeof(WCHAR); output = HeapAlloc(GetProcessHeap(),0,sz); memset(output,0,sz); - - if (component && index >= 0) - sprintfW(output,fmt2,productid_85,feature,component_85); - else - sprintfW(output,fmt1,productid_85,feature); + strcpyW(output,advertise); if (text) strcatW(output,text); sz = (lstrlenW(output)+2) * sizeof(WCHAR); - RegSetValueExW(hkey, qualifier,0,REG_MULTI_SZ, (LPBYTE)output, sz); + RegSetValueExW(hkey, qualifier,0,REG_MULTI_SZ, (LPBYTE)output, sz); end: RegCloseKey(hkey); HeapFree(GetProcessHeap(),0,output); - HeapFree(GetProcessHeap(),0,compgroupid); - HeapFree(GetProcessHeap(),0,component); - HeapFree(GetProcessHeap(),0,productid); - HeapFree(GetProcessHeap(),0,feature); - HeapFree(GetProcessHeap(),0,text); - HeapFree(GetProcessHeap(),0,qualifier); return rc; } @@ -6646,553 +4160,3 @@ static UINT ACTION_PublishComponents(MSIPACKAGE *package) return rc; } - -/* Msi functions that seem appropriate here */ - -/*********************************************************************** - * MsiDoActionA (MSI.@) - */ -UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction ) -{ - LPWSTR szwAction; - UINT rc; - - TRACE(" exteral attempt at action %s\n",szAction); - - if (!szAction) - return ERROR_FUNCTION_FAILED; - if (hInstall == 0) - return ERROR_FUNCTION_FAILED; - - szwAction = strdupAtoW(szAction); - - if (!szwAction) - return ERROR_FUNCTION_FAILED; - - - rc = MsiDoActionW(hInstall, szwAction); - HeapFree(GetProcessHeap(),0,szwAction); - return rc; -} - -/*********************************************************************** - * MsiDoActionW (MSI.@) - */ -UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction ) -{ - MSIPACKAGE *package; - UINT ret = ERROR_INVALID_HANDLE; - - TRACE(" external attempt at action %s \n",debugstr_w(szAction)); - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if( package ) - { - ret = ACTION_PerformUIAction(package,szAction); - msiobj_release( &package->hdr ); - } - return ret; -} - -UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder, - LPSTR szPathBuf, DWORD* pcchPathBuf) -{ - LPWSTR szwFolder; - LPWSTR szwPathBuf; - UINT rc; - - TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf); - - if (!szFolder) - return ERROR_FUNCTION_FAILED; - if (hInstall == 0) - return ERROR_FUNCTION_FAILED; - - szwFolder = strdupAtoW(szFolder); - - if (!szwFolder) - return ERROR_FUNCTION_FAILED; - - szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR)); - - rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf); - - WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf, - *pcchPathBuf, NULL, NULL ); - - HeapFree(GetProcessHeap(),0,szwFolder); - HeapFree(GetProcessHeap(),0,szwPathBuf); - - return rc; -} - -UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR - szPathBuf, DWORD* pcchPathBuf) -{ - LPWSTR path; - UINT rc = ERROR_FUNCTION_FAILED; - MSIPACKAGE *package; - - TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf); - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - path = resolve_folder(package, szFolder, FALSE, FALSE, NULL); - msiobj_release( &package->hdr ); - - if (path && (strlenW(path) > *pcchPathBuf)) - { - *pcchPathBuf = strlenW(path)+1; - rc = ERROR_MORE_DATA; - } - else if (path) - { - *pcchPathBuf = strlenW(path)+1; - strcpyW(szPathBuf,path); - TRACE("Returning Path %s\n",debugstr_w(path)); - rc = ERROR_SUCCESS; - } - HeapFree(GetProcessHeap(),0,path); - - return rc; -} - - -UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder, - LPSTR szPathBuf, DWORD* pcchPathBuf) -{ - LPWSTR szwFolder; - LPWSTR szwPathBuf; - UINT rc; - - TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf); - - if (!szFolder) - return ERROR_FUNCTION_FAILED; - if (hInstall == 0) - return ERROR_FUNCTION_FAILED; - - szwFolder = strdupAtoW(szFolder); - if (!szwFolder) - return ERROR_FUNCTION_FAILED; - - szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR)); - - rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf); - - WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf, - *pcchPathBuf, NULL, NULL ); - - HeapFree(GetProcessHeap(),0,szwFolder); - HeapFree(GetProcessHeap(),0,szwPathBuf); - - return rc; -} - -UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR - szPathBuf, DWORD* pcchPathBuf) -{ - LPWSTR path; - UINT rc = ERROR_FUNCTION_FAILED; - MSIPACKAGE *package; - - TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf); - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if( !package ) - return ERROR_INVALID_HANDLE; - path = resolve_folder(package, szFolder, TRUE, FALSE, NULL); - msiobj_release( &package->hdr ); - - if (path && strlenW(path) > *pcchPathBuf) - { - *pcchPathBuf = strlenW(path)+1; - rc = ERROR_MORE_DATA; - } - else if (path) - { - *pcchPathBuf = strlenW(path)+1; - strcpyW(szPathBuf,path); - TRACE("Returning Path %s\n",debugstr_w(path)); - rc = ERROR_SUCCESS; - } - HeapFree(GetProcessHeap(),0,path); - - return rc; -} - - -/*********************************************************************** - * MsiSetTargetPathA (MSI.@) - */ -UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder, - LPCSTR szFolderPath) -{ - LPWSTR szwFolder; - LPWSTR szwFolderPath; - UINT rc; - - if (!szFolder) - return ERROR_FUNCTION_FAILED; - if (hInstall == 0) - return ERROR_FUNCTION_FAILED; - - szwFolder = strdupAtoW(szFolder); - if (!szwFolder) - return ERROR_FUNCTION_FAILED; - - szwFolderPath = strdupAtoW(szFolderPath); - if (!szwFolderPath) - { - HeapFree(GetProcessHeap(),0,szwFolder); - return ERROR_FUNCTION_FAILED; - } - - rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath); - - HeapFree(GetProcessHeap(),0,szwFolder); - HeapFree(GetProcessHeap(),0,szwFolderPath); - - return rc; -} - -UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, - LPCWSTR szFolderPath) -{ - DWORD i; - LPWSTR path = NULL; - LPWSTR path2 = NULL; - MSIFOLDER *folder; - - TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath)); - - if (package==NULL) - return ERROR_INVALID_HANDLE; - - if (szFolderPath[0]==0) - return ERROR_FUNCTION_FAILED; - - if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES) - return ERROR_FUNCTION_FAILED; - - path = resolve_folder(package,szFolder,FALSE,FALSE,&folder); - - if (!path) - return ERROR_INVALID_PARAMETER; - - HeapFree(GetProcessHeap(),0,folder->Property); - folder->Property = build_directory_name(2, szFolderPath, NULL); - - if (lstrcmpiW(path, folder->Property) == 0) - { - /* - * Resolved Target has not really changed, so just - * set this folder and do not recalculate everything. - */ - HeapFree(GetProcessHeap(),0,folder->ResolvedTarget); - folder->ResolvedTarget = NULL; - path2 = resolve_folder(package,szFolder,FALSE,TRUE,NULL); - HeapFree(GetProcessHeap(),0,path2); - } - else - { - for (i = 0; i < package->loaded_folders; i++) - { - HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget); - package->folders[i].ResolvedTarget=NULL; - } - - for (i = 0; i < package->loaded_folders; i++) - { - path2=resolve_folder(package, package->folders[i].Directory, FALSE, - TRUE, NULL); - HeapFree(GetProcessHeap(),0,path2); - } - } - HeapFree(GetProcessHeap(),0,path); - - 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)); - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - 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) -{ - FIXME("STUB (iRunMode=%i)\n",iRunMode); - return TRUE; -} - -/*********************************************************************** - * 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); - - HeapFree(GetProcessHeap(),0,szwFeature); - - return rc; -} - - - -UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature, - INSTALLSTATE iState) -{ - INT index, i; - UINT rc = ERROR_SUCCESS; - - TRACE(" %s to %i\n",debugstr_w(szFeature), iState); - - index = get_loaded_feature(package,szFeature); - if (index < 0) - return ERROR_UNKNOWN_FEATURE; - - package->features[index].ActionRequest= iState; - package->features[index].Action= iState; - - ACTION_UpdateComponentStates(package,szFeature); - - /* update all the features that are children of this feature */ - for (i = 0; i < package->loaded_features; i++) - { - if (strcmpW(szFeature, package->features[i].Feature_Parent) == 0) - MSI_SetFeatureStateW(package, package->features[i].Feature, iState); - } - - return rc; -} - -/*********************************************************************** - * MsiSetFeatureStateW (MSI.@) - */ -UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature, - INSTALLSTATE iState) -{ - MSIPACKAGE* package; - UINT rc = ERROR_SUCCESS; - - TRACE(" %s to %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; -} - -UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature, - INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) -{ - LPWSTR szwFeature = NULL; - UINT rc; - - szwFeature = strdupAtoW(szFeature); - - rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction); - - HeapFree( GetProcessHeap(), 0 , szwFeature); - - return rc; -} - -UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature, - INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) -{ - INT index; - - index = get_loaded_feature(package,szFeature); - if (index < 0) - return ERROR_UNKNOWN_FEATURE; - - if (piInstalled) - *piInstalled = package->features[index].Installed; - - if (piAction) - *piAction = package->features[index].Action; - - TRACE("returning %i %i\n",*piInstalled,*piAction); - - return ERROR_SUCCESS; -} - -UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature, - INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) -{ - MSIPACKAGE* package; - UINT ret; - - TRACE("%ld %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; -} - -/*********************************************************************** - * MsiGetComponentStateA (MSI.@) - */ -UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent, - INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) -{ - LPWSTR szwComponent= NULL; - UINT rc; - - szwComponent= strdupAtoW(szComponent); - - rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction); - - HeapFree( GetProcessHeap(), 0 , szwComponent); - - return rc; -} - -UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent, - INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) -{ - INT index; - - TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled, -piAction); - - index = get_loaded_component(package,szComponent); - if (index < 0) - return ERROR_UNKNOWN_COMPONENT; - - if (piInstalled) - *piInstalled = package->components[index].Installed; - - if (piAction) - *piAction = package->components[index].Action; - - TRACE("states (%i, %i)\n", -(piInstalled)?*piInstalled:-1,(piAction)?*piAction:-1); - - return ERROR_SUCCESS; -} - -/*********************************************************************** - * MsiGetComponentStateW (MSI.@) - */ -UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent, - INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) -{ - MSIPACKAGE* package; - UINT ret; - - TRACE("%ld %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; -} - -#if 0 -static UINT ACTION_Template(MSIPACKAGE *package) -{ - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = {0}; - - rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); - if (rc != ERROR_SUCCESS) - return rc; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; -} -#endif diff --git a/reactos/lib/msi/action.h b/reactos/lib/msi/action.h index a88a07f5e15..9c472a53f15 100644 --- a/reactos/lib/msi/action.h +++ b/reactos/lib/msi/action.h @@ -18,15 +18,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define IDENTIFIER_SIZE 96 + typedef struct tagMSIFEATURE { - WCHAR Feature[96]; - WCHAR Feature_Parent[96]; + WCHAR Feature[IDENTIFIER_SIZE]; + WCHAR Feature_Parent[IDENTIFIER_SIZE]; WCHAR Title[0x100]; WCHAR Description[0x100]; INT Display; INT Level; - WCHAR Directory[96]; + WCHAR Directory[IDENTIFIER_SIZE]; INT Attributes; INSTALLSTATE Installed; @@ -40,12 +42,12 @@ typedef struct tagMSIFEATURE typedef struct tagMSICOMPONENT { - WCHAR Component[96]; - WCHAR ComponentId[96]; - WCHAR Directory[96]; + WCHAR Component[IDENTIFIER_SIZE]; + WCHAR ComponentId[IDENTIFIER_SIZE]; + WCHAR Directory[IDENTIFIER_SIZE]; INT Attributes; WCHAR Condition[0x100]; - WCHAR KeyPath[96]; + WCHAR KeyPath[IDENTIFIER_SIZE]; INSTALLSTATE Installed; INSTALLSTATE ActionRequest; @@ -56,6 +58,7 @@ typedef struct tagMSICOMPONENT INT RefCount; LPWSTR FullKeypath; + LPWSTR AdvertiseString; } MSICOMPONENT; typedef struct tagMSIFOLDER @@ -100,14 +103,117 @@ typedef struct tagMSIFILE BOOL Temporary; }MSIFILE; +typedef struct tagMSICLASS +{ + WCHAR CLSID[IDENTIFIER_SIZE]; /* Primary Key */ + WCHAR Context[IDENTIFIER_SIZE]; /* Primary Key */ + INT ComponentIndex; /* Primary Key */ + INT ProgIDIndex; + LPWSTR ProgIDText; + LPWSTR Description; + INT AppIDIndex; + LPWSTR FileTypeMask; + LPWSTR IconPath; + LPWSTR DefInprocHandler; + LPWSTR DefInprocHandler32; + LPWSTR Argument; + INT FeatureIndex; + INT Attributes; + /* not in the table, set during installation */ + BOOL Installed; +} MSICLASS; -UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action); +typedef struct tagMSIEXTENSION +{ + WCHAR Extension[256]; /* Primary Key */ + INT ComponentIndex; /* Primary Key */ + INT ProgIDIndex; + LPWSTR ProgIDText; + INT MIMEIndex; + INT FeatureIndex; + /* not in the table, set during installation */ + BOOL Installed; + INT VerbCount; + INT Verbs[100]; /* yes hard coded limit, but realistically 100 verbs??? */ +} MSIEXTENSION; + +typedef struct tagMSIPROGID +{ + LPWSTR ProgID; /* Primary Key */ + INT ParentIndex; + INT ClassIndex; + LPWSTR Description; + LPWSTR IconPath; + /* not in the table, set during installation */ + BOOL InstallMe; + INT CurVerIndex; + INT VersionIndIndex; +} MSIPROGID; + +typedef struct tagMSIVERB +{ + INT ExtensionIndex; + LPWSTR Verb; + INT Sequence; + LPWSTR Command; + LPWSTR Argument; +} MSIVERB; + +typedef struct tagMSIMIME +{ + LPWSTR ContentType; /* Primary Key */ + INT ExtensionIndex; + WCHAR CLSID[IDENTIFIER_SIZE]; + INT ClassIndex; + /* not in the table, set during installation */ + BOOL InstallMe; +} MSIMIME; + +typedef struct tagMSIAPPID +{ + WCHAR AppID[IDENTIFIER_SIZE]; /* Primary key */ + LPWSTR RemoteServerName; + LPWSTR LocalServer; + LPWSTR ServiceParameters; + LPWSTR DllSurrogate; + BOOL ActivateAtStorage; + BOOL RunAsInteractiveUser; +} MSIAPPID; + +enum SCRIPTS { + INSTALL_SCRIPT = 0, + COMMIT_SCRIPT = 1, + ROLLBACK_SCRIPT = 2, + TOTAL_SCRIPTS = 3 +}; + +typedef struct tagMSISCRIPT +{ + LPWSTR *Actions[TOTAL_SCRIPTS]; + UINT ActionCount[TOTAL_SCRIPTS]; + BOOL ExecuteSequenceRun; + BOOL FindRelatedProductsRun; + BOOL CurrentlyScripting; +}MSISCRIPT; + + +UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force); UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action); void ACTION_FinishCustomActions( MSIPACKAGE* package); UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action, BOOL execute); -void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature); -UINT ACTION_AppSearch(MSIPACKAGE *package); +/* actions in other modules */ +UINT ACTION_AppSearch(MSIPACKAGE *package); +UINT ACTION_FindRelatedProducts(MSIPACKAGE *package); +UINT ACTION_InstallFiles(MSIPACKAGE *package); +UINT ACTION_DuplicateFiles(MSIPACKAGE *package); +UINT ACTION_RegisterClassInfo(MSIPACKAGE *package); +UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package); +UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package); +UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package); + + +/* Helpers */ DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data ); WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index); LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc); @@ -117,3 +223,35 @@ int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component ); int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature ); int get_loaded_file(MSIPACKAGE* package, LPCWSTR file); int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path); +UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action); +UINT build_icon_path(MSIPACKAGE *, LPCWSTR, LPWSTR *); +DWORD build_version_dword(LPCWSTR); +LPWSTR build_directory_name(DWORD , ...); +BOOL create_full_pathW(const WCHAR *path); +BOOL ACTION_VerifyComponentForAction(MSIPACKAGE*, INT, INSTALLSTATE); +BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE*, INT, INSTALLSTATE); +void reduce_to_longfilename(WCHAR*); +void reduce_to_shortfilename(WCHAR*); +LPWSTR create_component_advertise_string(MSIPACKAGE*, MSICOMPONENT*, LPCWSTR); +void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature); + + +/* control event stuff */ +VOID ControlEvent_FireSubscribedEvent(MSIPACKAGE *package, LPCWSTR event, + MSIRECORD *data); +VOID ControlEvent_CleanupSubscriptions(MSIPACKAGE *package); +VOID ControlEvent_SubscribeToEvent(MSIPACKAGE *package, LPCWSTR event, + LPCWSTR control, LPCWSTR attribute); +VOID ControlEvent_UnSubscribeToEvent( MSIPACKAGE *package, LPCWSTR event, + LPCWSTR control, LPCWSTR attribute ); + +/* User Interface messages from the actions */ +void ui_progress(MSIPACKAGE *, int, int, int, int); +void ui_actiondata(MSIPACKAGE *, LPCWSTR, MSIRECORD *); + + +/* string consts use a number of places and defined in helpers.c*/ +extern const WCHAR cszSourceDir[]; +extern const WCHAR szProductCode[]; +extern const WCHAR cszRootDrive[]; +extern const WCHAR cszbs[]; diff --git a/reactos/lib/msi/classes.c b/reactos/lib/msi/classes.c new file mode 100644 index 00000000000..ed0f550994c --- /dev/null +++ b/reactos/lib/msi/classes.c @@ -0,0 +1,1602 @@ +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* actions handled in this module + * RegisterClassInfo + * RegisterProgIdInfo + * RegisterExtensionInfo + * RegisterMIMEInfo + * UnRegisterClassInfo (TODO) + * UnRegisterProgIdInfo (TODO) + * UnRegisterExtensionInfo (TODO) + * UnRegisterMIMEInfo (TODO) + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" +#include "wine/debug.h" +#include "msipriv.h" +#include "winuser.h" +#include "wine/unicode.h" +#include "action.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + + +extern const WCHAR szRegisterClassInfo[]; +extern const WCHAR szRegisterProgIdInfo[]; +extern const WCHAR szRegisterExtensionInfo[]; +extern const WCHAR szRegisterMIMEInfo[]; + +extern const WCHAR szUnregisterClassInfo[]; +extern const WCHAR szUnregisterExtensionInfo[]; +extern const WCHAR szUnregisterMIMEInfo[]; +extern const WCHAR szUnregisterProgIdInfo[]; + +static INT load_appid(MSIPACKAGE* package, MSIRECORD *row) +{ + DWORD index = package->loaded_appids; + DWORD sz; + LPCWSTR buffer; + + /* fill in the data */ + + package->loaded_appids++; + if (package->loaded_appids == 1) + package->appids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIAPPID)); + else + package->appids = HeapReAlloc(GetProcessHeap(),0, + package->appids, package->loaded_appids * sizeof(MSIAPPID)); + + memset(&package->appids[index],0,sizeof(MSIAPPID)); + + sz = IDENTIFIER_SIZE; + MSI_RecordGetStringW(row, 1, package->appids[index].AppID, &sz); + TRACE("loading appid %s\n",debugstr_w(package->appids[index].AppID)); + + buffer = MSI_RecordGetString(row,2); + deformat_string(package,buffer,&package->appids[index].RemoteServerName); + + package->appids[index].LocalServer = load_dynamic_stringW(row,3); + package->appids[index].ServiceParameters = load_dynamic_stringW(row,4); + package->appids[index].DllSurrogate = load_dynamic_stringW(row,5); + + package->appids[index].ActivateAtStorage = !MSI_RecordIsNull(row,6); + package->appids[index].RunAsInteractiveUser = !MSI_RecordIsNull(row,7); + + return index; +} + +static INT load_given_appid(MSIPACKAGE *package, LPCWSTR appid) +{ + INT rc; + MSIRECORD *row; + INT i; + static const WCHAR ExecSeqQuery[] = + {'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}; + + if (!appid) + return -1; + + /* check for appids already loaded */ + for (i = 0; i < package->loaded_appids; i++) + if (strcmpiW(package->appids[i].AppID,appid)==0) + { + TRACE("found appid %s at index %i\n",debugstr_w(appid),i); + return i; + } + + row = MSI_QueryGetRecord(package->db, ExecSeqQuery, appid); + if (!row) + return -1; + + rc = load_appid(package, row); + msiobj_release(&row->hdr); + + return rc; +} + +static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid); +static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid); + +static INT load_progid(MSIPACKAGE* package, MSIRECORD *row) +{ + DWORD index = package->loaded_progids; + LPCWSTR buffer; + + /* fill in the data */ + + package->loaded_progids++; + if (package->loaded_progids == 1) + package->progids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIPROGID)); + else + package->progids = HeapReAlloc(GetProcessHeap(),0, + package->progids , package->loaded_progids * sizeof(MSIPROGID)); + + memset(&package->progids[index],0,sizeof(MSIPROGID)); + + package->progids[index].ProgID = load_dynamic_stringW(row,1); + TRACE("loading progid %s\n",debugstr_w(package->progids[index].ProgID)); + + buffer = MSI_RecordGetString(row,2); + package->progids[index].ParentIndex = load_given_progid(package,buffer); + if (package->progids[index].ParentIndex < 0 && buffer) + FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer)); + + buffer = MSI_RecordGetString(row,3); + package->progids[index].ClassIndex = load_given_class(package,buffer); + if (package->progids[index].ClassIndex< 0 && buffer) + FIXME("Unknown class %s\n",debugstr_w(buffer)); + + package->progids[index].Description = load_dynamic_stringW(row,4); + + if (!MSI_RecordIsNull(row,6)) + { + INT icon_index = MSI_RecordGetInteger(row,6); + LPWSTR FileName = load_dynamic_stringW(row,5); + LPWSTR FilePath; + static const WCHAR fmt[] = {'%','s',',','%','i',0}; + + build_icon_path(package,FileName,&FilePath); + + package->progids[index].IconPath = + HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+10)* + sizeof(WCHAR)); + + sprintfW(package->progids[index].IconPath,fmt,FilePath,icon_index); + + HeapFree(GetProcessHeap(),0,FilePath); + HeapFree(GetProcessHeap(),0,FileName); + } + else + { + buffer = MSI_RecordGetString(row,5); + if (buffer) + build_icon_path(package,buffer,&(package->progids[index].IconPath)); + } + + package->progids[index].CurVerIndex = -1; + package->progids[index].VersionIndIndex = -1; + + /* if we have a parent then we may be that parents CurVer */ + if (package->progids[index].ParentIndex >= 0 && + package->progids[index].ParentIndex != index) + { + int pindex = package->progids[index].ParentIndex; + while (package->progids[pindex].ParentIndex>= 0 && + package->progids[pindex].ParentIndex != pindex) + pindex = package->progids[pindex].ParentIndex; + + FIXME("BAD BAD need to determing if we are really the CurVer\n"); + + package->progids[index].CurVerIndex = pindex; + package->progids[pindex].VersionIndIndex = index; + } + + return index; +} + +static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid) +{ + INT rc; + MSIRECORD *row; + INT i; + static const WCHAR ExecSeqQuery[] = + {'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}; + + if (!progid) + return -1; + + /* check for progids already loaded */ + for (i = 0; i < package->loaded_progids; i++) + if (strcmpiW(package->progids[i].ProgID,progid)==0) + { + TRACE("found progid %s at index %i\n",debugstr_w(progid), i); + return i; + } + + row = MSI_QueryGetRecord(package->db, ExecSeqQuery, progid); + if(!row) + return -1; + + rc = load_progid(package, row); + msiobj_release(&row->hdr); + + return rc; +} + +static INT load_class(MSIPACKAGE* package, MSIRECORD *row) +{ + DWORD index = package->loaded_classes; + DWORD sz,i; + LPCWSTR buffer; + + /* fill in the data */ + + package->loaded_classes++; + if (package->loaded_classes== 1) + package->classes = HeapAlloc(GetProcessHeap(),0,sizeof(MSICLASS)); + else + package->classes = HeapReAlloc(GetProcessHeap(),0, + package->classes, package->loaded_classes * sizeof(MSICLASS)); + + memset(&package->classes[index],0,sizeof(MSICLASS)); + + sz = IDENTIFIER_SIZE; + MSI_RecordGetStringW(row, 1, package->classes[index].CLSID, &sz); + TRACE("loading class %s\n",debugstr_w(package->classes[index].CLSID)); + sz = IDENTIFIER_SIZE; + MSI_RecordGetStringW(row, 2, package->classes[index].Context, &sz); + buffer = MSI_RecordGetString(row,3); + package->classes[index].ComponentIndex = get_loaded_component(package, + buffer); + + package->classes[index].ProgIDText = load_dynamic_stringW(row,4); + package->classes[index].ProgIDIndex = + load_given_progid(package, package->classes[index].ProgIDText); + + package->classes[index].Description = load_dynamic_stringW(row,5); + + buffer = MSI_RecordGetString(row,6); + if (buffer) + package->classes[index].AppIDIndex = + load_given_appid(package, buffer); + else + package->classes[index].AppIDIndex = -1; + + package->classes[index].FileTypeMask = load_dynamic_stringW(row,7); + + if (!MSI_RecordIsNull(row,9)) + { + + INT icon_index = MSI_RecordGetInteger(row,9); + LPWSTR FileName = load_dynamic_stringW(row,8); + LPWSTR FilePath; + static const WCHAR fmt[] = {'%','s',',','%','i',0}; + + build_icon_path(package,FileName,&FilePath); + + package->classes[index].IconPath = + HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)* + sizeof(WCHAR)); + + sprintfW(package->classes[index].IconPath,fmt,FilePath,icon_index); + + HeapFree(GetProcessHeap(),0,FilePath); + HeapFree(GetProcessHeap(),0,FileName); + } + else + { + buffer = MSI_RecordGetString(row,8); + if (buffer) + build_icon_path(package,buffer,&(package->classes[index].IconPath)); + } + + 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: + package->classes[index].DefInprocHandler = strdupW(ole2); + break; + case 2: + package->classes[index].DefInprocHandler32 = strdupW(ole32); + break; + case 3: + package->classes[index].DefInprocHandler = strdupW(ole2); + package->classes[index].DefInprocHandler32 = strdupW(ole32); + break; + } + } + else + { + package->classes[index].DefInprocHandler32 = load_dynamic_stringW( + row, 10); + reduce_to_longfilename(package->classes[index].DefInprocHandler32); + } + } + buffer = MSI_RecordGetString(row,11); + deformat_string(package,buffer,&package->classes[index].Argument); + + buffer = MSI_RecordGetString(row,12); + package->classes[index].FeatureIndex = get_loaded_feature(package,buffer); + + package->classes[index].Attributes = MSI_RecordGetInteger(row,13); + + return index; +} + +/* + * 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 INT load_given_class(MSIPACKAGE *package, LPCWSTR classid) +{ + INT rc; + MSIRECORD *row; + INT i; + static const WCHAR ExecSeqQuery[] = + {'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}; + + + if (!classid) + return -1; + + /* check for classes already loaded */ + for (i = 0; i < package->loaded_classes; i++) + if (strcmpiW(package->classes[i].CLSID,classid)==0) + { + TRACE("found class %s at index %i\n",debugstr_w(classid), i); + return i; + } + + row = MSI_QueryGetRecord(package->db, ExecSeqQuery, classid); + if (!row) + return -1; + + rc = load_class(package, row); + msiobj_release(&row->hdr); + + return rc; +} + +static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension); + +static INT load_mime(MSIPACKAGE* package, MSIRECORD *row) +{ + DWORD index = package->loaded_mimes; + DWORD sz; + LPCWSTR buffer; + + /* fill in the data */ + + package->loaded_mimes++; + if (package->loaded_mimes== 1) + package->mimes= HeapAlloc(GetProcessHeap(),0,sizeof(MSIMIME)); + else + package->mimes= HeapReAlloc(GetProcessHeap(),0, + package->mimes, package->loaded_mimes* + sizeof(MSIMIME)); + + memset(&package->mimes[index],0,sizeof(MSIMIME)); + + package->mimes[index].ContentType = load_dynamic_stringW(row,1); + TRACE("loading mime %s\n",debugstr_w(package->mimes[index].ContentType)); + + buffer = MSI_RecordGetString(row,2); + package->mimes[index].ExtensionIndex = load_given_extension(package, + buffer); + + sz = IDENTIFIER_SIZE; + MSI_RecordGetStringW(row,3,package->mimes[index].CLSID,&sz); + package->mimes[index].ClassIndex= load_given_class(package, + package->mimes[index].CLSID); + + return index; +} + +static INT load_given_mime(MSIPACKAGE *package, LPCWSTR mime) +{ + INT rc; + MSIRECORD *row; + INT i; + static const WCHAR ExecSeqQuery[] = + {'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}; + + if (!mime) + return -1; + + /* check for mime already loaded */ + for (i = 0; i < package->loaded_mimes; i++) + if (strcmpiW(package->mimes[i].ContentType,mime)==0) + { + TRACE("found mime %s at index %i\n",debugstr_w(mime), i); + return i; + } + + row = MSI_QueryGetRecord(package->db, ExecSeqQuery, mime); + if (!row) + return -1; + + rc = load_mime(package, row); + msiobj_release(&row->hdr); + + return rc; +} + +static INT load_extension(MSIPACKAGE* package, MSIRECORD *row) +{ + DWORD index = package->loaded_extensions; + DWORD sz; + LPCWSTR buffer; + + /* fill in the data */ + + package->loaded_extensions++; + if (package->loaded_extensions == 1) + package->extensions = HeapAlloc(GetProcessHeap(),0,sizeof(MSIEXTENSION)); + else + package->extensions = HeapReAlloc(GetProcessHeap(),0, + package->extensions, package->loaded_extensions* + sizeof(MSIEXTENSION)); + + memset(&package->extensions[index],0,sizeof(MSIEXTENSION)); + + sz = 256; + MSI_RecordGetStringW(row,1,package->extensions[index].Extension,&sz); + TRACE("loading extension %s\n", + debugstr_w(package->extensions[index].Extension)); + + buffer = MSI_RecordGetString(row,2); + package->extensions[index].ComponentIndex = + get_loaded_component(package,buffer); + + package->extensions[index].ProgIDText = load_dynamic_stringW(row,3); + package->extensions[index].ProgIDIndex = load_given_progid(package, + package->extensions[index].ProgIDText); + + buffer = MSI_RecordGetString(row,4); + package->extensions[index].MIMEIndex = load_given_mime(package,buffer); + + buffer = MSI_RecordGetString(row,5); + package->extensions[index].FeatureIndex = + get_loaded_feature(package,buffer); + + return index; +} + +/* + * While the extension table has 2 primary keys, this function is only looking + * at the Extension key which is what is referenced as a forign key + */ +static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension) +{ + INT rc; + MSIRECORD *row; + INT i; + static const WCHAR ExecSeqQuery[] = + {'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}; + + if (!extension) + return -1; + + /* check for extensions already loaded */ + for (i = 0; i < package->loaded_extensions; i++) + if (strcmpiW(package->extensions[i].Extension,extension)==0) + { + TRACE("extension %s already loaded at %i\n",debugstr_w(extension), + i); + return i; + } + + row = MSI_QueryGetRecord(package->db, ExecSeqQuery, extension); + if (!row) + return -1; + + rc = load_extension(package, row); + msiobj_release(&row->hdr); + + return rc; +} + +static UINT iterate_load_verb(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE* package = (MSIPACKAGE*)param; + DWORD index = package->loaded_verbs; + LPCWSTR buffer; + + /* fill in the data */ + + package->loaded_verbs++; + if (package->loaded_verbs == 1) + package->verbs = HeapAlloc(GetProcessHeap(),0,sizeof(MSIVERB)); + else + package->verbs = HeapReAlloc(GetProcessHeap(),0, + package->verbs , package->loaded_verbs * sizeof(MSIVERB)); + + memset(&package->verbs[index],0,sizeof(MSIVERB)); + + buffer = MSI_RecordGetString(row,1); + package->verbs[index].ExtensionIndex = load_given_extension(package,buffer); + if (package->verbs[index].ExtensionIndex < 0 && buffer) + ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer)); + + package->verbs[index].Verb = load_dynamic_stringW(row,2); + TRACE("loading verb %s\n",debugstr_w(package->verbs[index].Verb)); + package->verbs[index].Sequence = MSI_RecordGetInteger(row,3); + + buffer = MSI_RecordGetString(row,4); + deformat_string(package,buffer,&package->verbs[index].Command); + + buffer = MSI_RecordGetString(row,5); + deformat_string(package,buffer,&package->verbs[index].Argument); + + /* assosiate the verb with the correct extension */ + if (package->verbs[index].ExtensionIndex >= 0) + { + MSIEXTENSION* extension = &package->extensions[package->verbs[index]. + ExtensionIndex]; + int count = extension->VerbCount; + + if (count >= 99) + FIXME("Exceeding max verb count! Increase that limit!!!\n"); + else + { + extension->VerbCount++; + extension->Verbs[count] = index; + } + } + + return ERROR_SUCCESS; +} + +static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param) +{ + LPCWSTR clsid; + LPCWSTR context; + LPCWSTR buffer; + INT component_index; + MSIPACKAGE* package =(MSIPACKAGE*)param; + INT i; + BOOL match = FALSE; + + clsid = MSI_RecordGetString(rec,1); + context = MSI_RecordGetString(rec,2); + buffer = MSI_RecordGetString(rec,3); + component_index = get_loaded_component(package,buffer); + + for (i = 0; i < package->loaded_classes; i++) + { + if (strcmpiW(clsid,package->classes[i].CLSID)) + continue; + if (strcmpW(context,package->classes[i].Context)) + continue; + if (component_index == package->classes[i].ComponentIndex) + { + match = TRUE; + break; + } + } + + if (!match) + load_class(package, rec); + + return ERROR_SUCCESS; +} + +static VOID load_all_classes(MSIPACKAGE *package) +{ + UINT rc = ERROR_SUCCESS; + MSIQUERY *view; + + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', + '`','C','l','a','s','s','`',0}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return; + + rc = MSI_IterateRecords(view, NULL, iterate_all_classes, package); + msiobj_release(&view->hdr); +} + +static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param) +{ + LPCWSTR buffer; + LPCWSTR extension; + INT component_index; + MSIPACKAGE* package =(MSIPACKAGE*)param; + BOOL match = FALSE; + INT i; + + extension = MSI_RecordGetString(rec,1); + buffer = MSI_RecordGetString(rec,2); + component_index = get_loaded_component(package,buffer); + + for (i = 0; i < package->loaded_extensions; i++) + { + if (strcmpiW(extension,package->extensions[i].Extension)) + continue; + if (component_index == package->extensions[i].ComponentIndex) + { + match = TRUE; + break; + } + } + + if (!match) + load_extension(package, rec); + + return ERROR_SUCCESS; +} + +static VOID load_all_extensions(MSIPACKAGE *package) +{ + UINT rc = ERROR_SUCCESS; + MSIQUERY *view; + + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','E','x','t','e','n','s','i','o','n','`',0}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return; + + rc = MSI_IterateRecords(view, NULL, iterate_all_extensions, package); + msiobj_release(&view->hdr); +} + +static UINT iterate_all_progids(MSIRECORD *rec, LPVOID param) +{ + LPCWSTR buffer; + MSIPACKAGE* package =(MSIPACKAGE*)param; + + buffer = MSI_RecordGetString(rec,1); + load_given_progid(package,buffer); + return ERROR_SUCCESS; +} + +static VOID load_all_progids(MSIPACKAGE *package) +{ + UINT rc = ERROR_SUCCESS; + MSIQUERY *view; + + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ', + 'F','R','O','M',' ', '`','P','r','o','g','I','d','`',0}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return; + + rc = MSI_IterateRecords(view, NULL, iterate_all_progids, package); + msiobj_release(&view->hdr); +} + +static VOID load_all_verbs(MSIPACKAGE *package) +{ + UINT rc = ERROR_SUCCESS; + MSIQUERY *view; + + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','V','e','r','b','`',0}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return; + + rc = MSI_IterateRecords(view, NULL, iterate_load_verb, package); + msiobj_release(&view->hdr); +} + +static UINT iterate_all_mimes(MSIRECORD *rec, LPVOID param) +{ + LPCWSTR buffer; + MSIPACKAGE* package =(MSIPACKAGE*)param; + + buffer = MSI_RecordGetString(rec,1); + load_given_mime(package,buffer); + return ERROR_SUCCESS; +} + +static VOID load_all_mimes(MSIPACKAGE *package) +{ + UINT rc = ERROR_SUCCESS; + MSIQUERY *view; + + static const WCHAR ExecSeqQuery[] = + {'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}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return; + + rc = MSI_IterateRecords(view, NULL, iterate_all_mimes, package); + msiobj_release(&view->hdr); +} + +static void load_classes_and_such(MSIPACKAGE *package) +{ + TRACE("Loading all the class info and related tables\n"); + + /* check if already loaded */ + if (package->classes || package->extensions || package->progids || + package->verbs || package->mimes) + return; + + load_all_classes(package); + load_all_extensions(package); + load_all_progids(package); + /* these loads must come after the other loads */ + load_all_verbs(package); + load_all_mimes(package); +} + +static void mark_progid_for_install(MSIPACKAGE* package, INT index) +{ + MSIPROGID* progid; + int i; + + if (index < 0 || index >= package->loaded_progids) + return; + + progid = &package->progids[index]; + + if (progid->InstallMe == TRUE) + return; + + progid->InstallMe = TRUE; + + /* all children if this is a parent also install */ + for (i = 0; i < package->loaded_progids; i++) + if (package->progids[i].ParentIndex == index) + mark_progid_for_install(package,i); +} + +static void mark_mime_for_install(MSIPACKAGE* package, INT index) +{ + MSIMIME* mime; + + if (index < 0 || index >= package->loaded_mimes) + return; + + mime = &package->mimes[index]; + + if (mime->InstallMe == TRUE) + return; + + mime->InstallMe = TRUE; +} + +static UINT register_appid(MSIPACKAGE *package, int appidIndex, LPCWSTR app ) +{ + static const WCHAR szAppID[] = { 'A','p','p','I','D',0 }; + HKEY hkey2,hkey3; + + if (!package) + return ERROR_INVALID_HANDLE; + + RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2); + RegCreateKeyW(hkey2,package->appids[appidIndex].AppID,&hkey3); + RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app, + (strlenW(app)+1)*sizeof(WCHAR)); + + if (package->appids[appidIndex].RemoteServerName) + { + UINT size; + static const WCHAR szRemoteServerName[] = + {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e', + 0}; + + size = (strlenW(package->appids[appidIndex].RemoteServerName)+1) * + sizeof(WCHAR); + + RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ, + (LPVOID)package->appids[appidIndex].RemoteServerName, + size); + } + + if (package->appids[appidIndex].LocalServer) + { + static const WCHAR szLocalService[] = + {'L','o','c','a','l','S','e','r','v','i','c','e',0}; + UINT size; + size = (strlenW(package->appids[appidIndex].LocalServer)+1) * + sizeof(WCHAR); + + RegSetValueExW(hkey3,szLocalService,0,REG_SZ, + (LPVOID)package->appids[appidIndex].LocalServer,size); + } + + if (package->appids[appidIndex].ServiceParameters) + { + static const WCHAR szService[] = + {'S','e','r','v','i','c','e', + 'P','a','r','a','m','e','t','e','r','s',0}; + UINT size; + size = (strlenW(package->appids[appidIndex].ServiceParameters)+1) * + sizeof(WCHAR); + RegSetValueExW(hkey3,szService,0,REG_SZ, + (LPVOID)package->appids[appidIndex].ServiceParameters, + size); + } + + if (package->appids[appidIndex].DllSurrogate) + { + static const WCHAR szDLL[] = + {'D','l','l','S','u','r','r','o','g','a','t','e',0}; + UINT size; + size = (strlenW(package->appids[appidIndex].DllSurrogate)+1) * + sizeof(WCHAR); + RegSetValueExW(hkey3,szDLL,0,REG_SZ, + (LPVOID)package->appids[appidIndex].DllSurrogate,size); + } + + if (package->appids[appidIndex].ActivateAtStorage) + { + 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}; + + RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4); + } + + if (package->appids[appidIndex].RunAsInteractiveUser) + { + 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}; + + RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,sizeof(szUser)); + } + + RegCloseKey(hkey3); + RegCloseKey(hkey2); + return ERROR_SUCCESS; +} + +UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) +{ + /* + * Again I am assuming the words, "Whose key file represents" when referring + * to a Component as to meaning that Components KeyPath file + */ + + UINT rc; + MSIRECORD *uirow; + static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; + static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 }; + static const WCHAR szVIProgID[] = { 'V','e','r','s','i','o','n','I','n','d','e','p','e','n','d','e','n','t','P','r','o','g','I','D',0 }; + static const WCHAR szAppID[] = { 'A','p','p','I','D',0 }; + static const WCHAR szSpace[] = {' ',0}; + static const WCHAR szInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0}; + static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0}; + HKEY hkey,hkey2,hkey3; + BOOL install_on_demand = FALSE; + int i; + + if (!package) + return ERROR_INVALID_HANDLE; + + load_classes_and_such(package); + rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey); + if (rc != ERROR_SUCCESS) + return ERROR_FUNCTION_FAILED; + + /* install_on_demand should be set if OLE supports install on demand OLE + * servers. For now i am defaulting to FALSE because i do not know how to + * check, and i am told our builtin OLE does not support it + */ + + for (i = 0; i < package->loaded_classes; i++) + { + INT index,f_index; + DWORD size, sz; + LPWSTR argument; + + if (package->classes[i].ComponentIndex < 0) + { + continue; + } + + index = package->classes[i].ComponentIndex; + f_index = package->classes[i].FeatureIndex; + + /* + * yes. MSDN says that these are based on _Feature_ not on + * Component. So verify the feature is to be installed + */ + if ((!ACTION_VerifyFeatureForAction(package, f_index, + INSTALLSTATE_LOCAL)) && + !(install_on_demand && ACTION_VerifyFeatureForAction(package, + f_index, INSTALLSTATE_ADVERTISED))) + { + TRACE("Skipping class %s reg due to disabled feature %s\n", + debugstr_w(package->classes[i].CLSID), + debugstr_w(package->features[f_index].Feature)); + + continue; + } + + TRACE("Registering index %i class %s\n",i, + debugstr_w(package->classes[i].CLSID)); + + package->classes[i].Installed = TRUE; + if (package->classes[i].ProgIDIndex >= 0) + mark_progid_for_install(package, package->classes[i].ProgIDIndex); + + RegCreateKeyW(hkey,package->classes[i].CLSID,&hkey2); + + if (package->classes[i].Description) + RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)package->classes[i]. + Description, (strlenW(package->classes[i]. + Description)+1)*sizeof(WCHAR)); + + RegCreateKeyW(hkey2,package->classes[i].Context,&hkey3); + index = get_loaded_file(package,package->components[index].KeyPath); + + + /* the context server is a short path name + * except for if it is InprocServer32... + */ + if (strcmpiW(package->classes[i].Context,szInprocServer32)!=0) + { + sz = 0; + sz = GetShortPathNameW(package->files[index].TargetPath, NULL, 0); + if (sz == 0) + { + ERR("Unable to find short path for CLSID COM Server\n"); + argument = NULL; + } + else + { + size = sz * sizeof(WCHAR); + + if (package->classes[i].Argument) + { + size += strlenW(package->classes[i].Argument) * + sizeof(WCHAR); + size += sizeof(WCHAR); + } + + argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR)); + GetShortPathNameW(package->files[index].TargetPath, argument, + sz); + + if (package->classes[i].Argument) + { + strcatW(argument,szSpace); + strcatW(argument,package->classes[i].Argument); + } + } + } + else + { + size = lstrlenW(package->files[index].TargetPath) * sizeof(WCHAR); + + if (package->classes[i].Argument) + { + size += strlenW(package->classes[i].Argument) * sizeof(WCHAR); + size += sizeof(WCHAR); + } + + argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR)); + strcpyW(argument, package->files[index].TargetPath); + + if (package->classes[i].Argument) + { + strcatW(argument,szSpace); + strcatW(argument,package->classes[i].Argument); + } + } + + if (argument) + { + RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size); + HeapFree(GetProcessHeap(),0,argument); + } + + RegCloseKey(hkey3); + + if (package->classes[i].ProgIDIndex >= 0 || + package->classes[i].ProgIDText) + { + LPCWSTR progid; + + if (package->classes[i].ProgIDIndex >= 0) + progid = package->progids[ + package->classes[i].ProgIDIndex].ProgID; + else + progid = package->classes[i].ProgIDText; + + RegCreateKeyW(hkey2,szProgID,&hkey3); + RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)progid, + (strlenW(progid)+1) *sizeof(WCHAR)); + RegCloseKey(hkey3); + + if (package->classes[i].ProgIDIndex >= 0 && + package->progids[package->classes[i].ProgIDIndex]. + VersionIndIndex >= 0) + { + LPWSTR viprogid = strdupW(package->progids[package->progids[ + package->classes[i].ProgIDIndex].VersionIndIndex]. + ProgID); + RegCreateKeyW(hkey2,szVIProgID,&hkey3); + RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)viprogid, + (strlenW(viprogid)+1) *sizeof(WCHAR)); + RegCloseKey(hkey3); + HeapFree(GetProcessHeap(), 0, viprogid); + } + } + + if (package->classes[i].AppIDIndex >= 0) + { + RegSetValueExW(hkey2,szAppID,0,REG_SZ, + (LPVOID)package->appids[package->classes[i].AppIDIndex].AppID, + (strlenW(package->appids[package->classes[i].AppIDIndex].AppID)+1) + *sizeof(WCHAR)); + + register_appid(package,package->classes[i].AppIDIndex, + package->classes[i].Description); + } + + if (package->classes[i].IconPath) + { + static const WCHAR szDefaultIcon[] = + {'D','e','f','a','u','l','t','I','c','o','n',0}; + + RegCreateKeyW(hkey2,szDefaultIcon,&hkey3); + + RegSetValueExW(hkey3,NULL,0,REG_SZ, + (LPVOID)package->classes[i].IconPath, + (strlenW(package->classes[i].IconPath)+1) * + sizeof(WCHAR)); + + RegCloseKey(hkey3); + } + + if (package->classes[i].DefInprocHandler) + { + static const WCHAR szInproc[] = + {'I','n','p','r','o','c','H','a','n','d','l','e','r',0}; + + size = (strlenW(package->classes[i].DefInprocHandler) + 1) * + sizeof(WCHAR); + RegCreateKeyW(hkey2,szInproc,&hkey3); + RegSetValueExW(hkey3,NULL,0,REG_SZ, + (LPVOID)package->classes[i].DefInprocHandler, size); + RegCloseKey(hkey3); + } + + if (package->classes[i].DefInprocHandler32) + { + static const WCHAR szInproc32[] = + {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2', + 0}; + size = (strlenW(package->classes[i].DefInprocHandler32) + 1) * + sizeof(WCHAR); + + RegCreateKeyW(hkey2,szInproc32,&hkey3); + RegSetValueExW(hkey3,NULL,0,REG_SZ, + (LPVOID)package->classes[i].DefInprocHandler32,size); + RegCloseKey(hkey3); + } + + RegCloseKey(hkey2); + + /* if there is a FileTypeMask, register the FileType */ + if (package->classes[i].FileTypeMask) + { + LPWSTR ptr, ptr2; + LPWSTR keyname; + INT index = 0; + ptr = package->classes[i].FileTypeMask; + while (ptr && *ptr) + { + ptr2 = strchrW(ptr,';'); + if (ptr2) + *ptr2 = 0; + keyname = HeapAlloc(GetProcessHeap(),0,(strlenW(szFileType_fmt)+ + strlenW(package->classes[i].CLSID) + 4) + * sizeof(WCHAR)); + sprintfW(keyname,szFileType_fmt, package->classes[i].CLSID, + index); + + RegCreateKeyW(HKEY_CLASSES_ROOT,keyname,&hkey2); + RegSetValueExW(hkey2,NULL,0,REG_SZ, (LPVOID)ptr, + strlenW(ptr)*sizeof(WCHAR)); + RegCloseKey(hkey2); + HeapFree(GetProcessHeap(), 0, keyname); + + if (ptr2) + ptr = ptr2+1; + else + ptr = NULL; + + index ++; + } + } + + uirow = MSI_CreateRecord(1); + + MSI_RecordSetStringW(uirow,1,package->classes[i].CLSID); + ui_actiondata(package,szRegisterClassInfo,uirow); + msiobj_release(&uirow->hdr); + } + + RegCloseKey(hkey); + return rc; +} + +static UINT register_progid_base(MSIPACKAGE* package, MSIPROGID* progid, + LPWSTR clsid) +{ + static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; + static const WCHAR szDefaultIcon[] = + {'D','e','f','a','u','l','t','I','c','o','n',0}; + HKEY hkey,hkey2; + + RegCreateKeyW(HKEY_CLASSES_ROOT,progid->ProgID,&hkey); + + if (progid->Description) + { + RegSetValueExW(hkey,NULL,0,REG_SZ, + (LPVOID)progid->Description, + (strlenW(progid->Description)+1) * + sizeof(WCHAR)); + } + + if (progid->ClassIndex >= 0) + { + RegCreateKeyW(hkey,szCLSID,&hkey2); + RegSetValueExW(hkey2,NULL,0,REG_SZ, + (LPVOID)package->classes[progid->ClassIndex].CLSID, + (strlenW(package->classes[progid->ClassIndex].CLSID)+1) + * sizeof(WCHAR)); + + if (clsid) + strcpyW(clsid,package->classes[progid->ClassIndex].CLSID); + + RegCloseKey(hkey2); + } + else + { + FIXME("UNHANDLED case, Parent progid but classid is NULL\n"); + } + + if (progid->IconPath) + { + RegCreateKeyW(hkey,szDefaultIcon,&hkey2); + + RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath, + (strlenW(progid->IconPath)+1) * sizeof(WCHAR)); + RegCloseKey(hkey2); + } + return ERROR_SUCCESS; +} + +static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid, + LPWSTR clsid) +{ + UINT rc = ERROR_SUCCESS; + + if (progid->ParentIndex < 0) + rc = register_progid_base(package, progid, clsid); + else + { + DWORD disp; + HKEY hkey,hkey2; + static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; + static const WCHAR szDefaultIcon[] = + {'D','e','f','a','u','l','t','I','c','o','n',0}; + static const WCHAR szCurVer[] = + {'C','u','r','V','e','r',0}; + + /* check if already registered */ + RegCreateKeyExW(HKEY_CLASSES_ROOT, progid->ProgID, 0, NULL, 0, + KEY_ALL_ACCESS, NULL, &hkey, &disp ); + if (disp == REG_OPENED_EXISTING_KEY) + { + TRACE("Key already registered\n"); + RegCloseKey(hkey); + return rc; + } + + TRACE("Registering Parent %s index %i\n", + debugstr_w(package->progids[progid->ParentIndex].ProgID), + progid->ParentIndex); + rc = register_progid(package,&package->progids[progid->ParentIndex], + clsid); + + /* clsid is same as parent */ + RegCreateKeyW(hkey,szCLSID,&hkey2); + RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) * + sizeof(WCHAR)); + + RegCloseKey(hkey2); + + + if (progid->Description) + { + RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid->Description, + (strlenW(progid->Description)+1) * sizeof(WCHAR)); + } + + if (progid->IconPath) + { + RegCreateKeyW(hkey,szDefaultIcon,&hkey2); + RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath, + (strlenW(progid->IconPath)+1) * sizeof(WCHAR)); + RegCloseKey(hkey2); + } + + /* write out the current version */ + if (progid->CurVerIndex >= 0) + { + RegCreateKeyW(hkey,szCurVer,&hkey2); + RegSetValueExW(hkey2,NULL,0,REG_SZ, + (LPVOID)package->progids[progid->CurVerIndex].ProgID, + (strlenW(package->progids[progid->CurVerIndex].ProgID)+1) * + sizeof(WCHAR)); + RegCloseKey(hkey2); + } + + RegCloseKey(hkey); + } + return rc; +} + +UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package) +{ + INT i; + MSIRECORD *uirow; + + if (!package) + return ERROR_INVALID_HANDLE; + + load_classes_and_such(package); + + for (i = 0; i < package->loaded_progids; i++) + { + WCHAR clsid[0x1000]; + + /* check if this progid is to be installed */ + package->progids[i].InstallMe = ((package->progids[i].InstallMe) || + (package->progids[i].ClassIndex >= 0 && + package->classes[package->progids[i].ClassIndex].Installed)); + + if (!package->progids[i].InstallMe) + { + TRACE("progid %s not scheduled to be installed\n", + debugstr_w(package->progids[i].ProgID)); + continue; + } + + TRACE("Registering progid %s index %i\n", + debugstr_w(package->progids[i].ProgID), i); + + register_progid(package,&package->progids[i],clsid); + + uirow = MSI_CreateRecord(1); + MSI_RecordSetStringW(uirow,1,package->progids[i].ProgID); + ui_actiondata(package,szRegisterProgIdInfo,uirow); + msiobj_release(&uirow->hdr); + } + + return ERROR_SUCCESS; +} + +static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid, + MSICOMPONENT* component, 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 = 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 = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR)); + if (verb->Argument) + sprintfW(command, fmt, component->FullKeypath, verb->Argument); + else + sprintfW(command, fmt2, component->FullKeypath); + + RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)command, (strlenW(command)+1)* + sizeof(WCHAR)); + HeapFree(GetProcessHeap(),0,command); + + advertise = create_component_advertise_string(package, component, + package->features[extension->FeatureIndex].Feature); + + size = strlenW(advertise); + + if (verb->Argument) + size += strlenW(verb->Argument); + size += 4; + + command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR)); + memset(command,0,size*sizeof(WCHAR)); + + strcpyW(command,advertise); + if (verb->Argument) + { + static const WCHAR szSpace[] = {' ',0}; + strcatW(command,szSpace); + strcatW(command,verb->Argument); + } + + RegSetValueExW(key, szCommand, 0, REG_MULTI_SZ, (LPBYTE)command, + (strlenW(command)+2)*sizeof(WCHAR)); + + RegCloseKey(key); + HeapFree(GetProcessHeap(),0,keyname); + HeapFree(GetProcessHeap(),0,advertise); + HeapFree(GetProcessHeap(),0,command); + + if (verb->Command) + { + keyname = build_directory_name(3, progid, szShell, verb->Verb); + RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key); + RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Command, + (strlenW(verb->Command)+1) *sizeof(WCHAR)); + RegCloseKey(key); + HeapFree(GetProcessHeap(),0,keyname); + } + + if (verb->Sequence != MSI_NULL_INTEGER) + { + if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence) + { + *Sequence = verb->Sequence; + keyname = build_directory_name(2, progid, szShell); + RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key); + RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Verb, + (strlenW(verb->Verb)+1) *sizeof(WCHAR)); + RegCloseKey(key); + HeapFree(GetProcessHeap(),0,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; + INT i; + MSIRECORD *uirow; + BOOL install_on_demand = TRUE; + + if (!package) + return ERROR_INVALID_HANDLE; + + load_classes_and_such(package); + + /* 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 + */ + + for (i = 0; i < package->loaded_extensions; i++) + { + WCHAR extension[257]; + INT index,f_index; + + index = package->extensions[i].ComponentIndex; + f_index = package->extensions[i].FeatureIndex; + + if (index < 0) + continue; + + /* + * yes. MSDN says that these are based on _Feature_ not on + * Component. So verify the feature is to be installed + */ + if ((!ACTION_VerifyFeatureForAction(package, f_index, + INSTALLSTATE_LOCAL)) && + !(install_on_demand && ACTION_VerifyFeatureForAction(package, + f_index, INSTALLSTATE_ADVERTISED))) + { + TRACE("Skipping extension %s reg due to disabled feature %s\n", + debugstr_w(package->extensions[i].Extension), + debugstr_w(package->features[f_index].Feature)); + + continue; + } + + TRACE("Registering extension %s index %i\n", + debugstr_w(package->extensions[i].Extension), i); + + package->extensions[i].Installed = TRUE; + + /* this is only registered if the extension has at least 1 verb + * according to MSDN + */ + if (package->extensions[i].ProgIDIndex >= 0 && + package->extensions[i].VerbCount > 0) + mark_progid_for_install(package, package->extensions[i].ProgIDIndex); + + if (package->extensions[i].MIMEIndex >= 0) + mark_mime_for_install(package, package->extensions[i].MIMEIndex); + + extension[0] = '.'; + extension[1] = 0; + strcatW(extension,package->extensions[i].Extension); + + RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey); + + if (package->extensions[i].MIMEIndex >= 0) + { + RegSetValueExW(hkey,szContentType,0,REG_SZ, + (LPVOID)package->mimes[package->extensions[i]. + MIMEIndex].ContentType, + (strlenW(package->mimes[package->extensions[i]. + MIMEIndex].ContentType)+1)*sizeof(WCHAR)); + } + + if (package->extensions[i].ProgIDIndex >= 0 || + package->extensions[i].ProgIDText) + { + static const WCHAR szSN[] = + {'\\','S','h','e','l','l','N','e','w',0}; + HKEY hkey2; + LPWSTR newkey; + LPCWSTR progid; + INT v; + INT Sequence = MSI_NULL_INTEGER; + + if (package->extensions[i].ProgIDIndex >= 0) + progid = package->progids[package->extensions[i]. + ProgIDIndex].ProgID; + else + progid = package->extensions[i].ProgIDText; + + RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid, + (strlenW(progid)+1)*sizeof(WCHAR)); + + newkey = HeapAlloc(GetProcessHeap(),0, + (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR)); + + strcpyW(newkey,progid); + strcatW(newkey,szSN); + RegCreateKeyW(hkey,newkey,&hkey2); + RegCloseKey(hkey2); + + HeapFree(GetProcessHeap(),0,newkey); + + /* do all the verbs */ + for (v = 0; v < package->extensions[i].VerbCount; v++) + register_verb(package, progid, + &package->components[index], + &package->extensions[i], + &package->verbs[package->extensions[i].Verbs[v]], + &Sequence); + } + + RegCloseKey(hkey); + + uirow = MSI_CreateRecord(1); + MSI_RecordSetStringW(uirow,1,package->extensions[i].Extension); + ui_actiondata(package,szRegisterExtensionInfo,uirow); + msiobj_release(&uirow->hdr); + } + + return ERROR_SUCCESS; +} + +UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package) +{ + static const WCHAR szExten[] = + {'E','x','t','e','n','s','i','o','n',0 }; + HKEY hkey; + INT i; + MSIRECORD *uirow; + + if (!package) + return ERROR_INVALID_HANDLE; + + load_classes_and_such(package); + + for (i = 0; i < package->loaded_mimes; i++) + { + WCHAR extension[257]; + LPCWSTR exten; + LPCWSTR mime; + static const WCHAR fmt[] = + {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\', + 'C','o','n','t','e','n','t',' ','T','y','p','e','\\', '%','s',0}; + LPWSTR key; + + /* + * check if the MIME is to be installed. Either as requesed by an + * extension or Class + */ + package->mimes[i].InstallMe = ((package->mimes[i].InstallMe) || + (package->mimes[i].ClassIndex >= 0 && + package->classes[package->mimes[i].ClassIndex].Installed) || + (package->mimes[i].ExtensionIndex >=0 && + package->extensions[package->mimes[i].ExtensionIndex].Installed)); + + if (!package->mimes[i].InstallMe) + { + TRACE("MIME %s not scheduled to be installed\n", + debugstr_w(package->mimes[i].ContentType)); + continue; + } + + mime = package->mimes[i].ContentType; + exten = package->extensions[package->mimes[i].ExtensionIndex].Extension; + extension[0] = '.'; + extension[1] = 0; + strcatW(extension,exten); + + key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) * + sizeof(WCHAR)); + sprintfW(key,fmt,mime); + RegCreateKeyW(HKEY_CLASSES_ROOT,key,&hkey); + RegSetValueExW(hkey,szExten,0,REG_SZ,(LPVOID)extension, + (strlenW(extension)+1)*sizeof(WCHAR)); + + HeapFree(GetProcessHeap(),0,key); + + if (package->mimes[i].CLSID[0]) + { + FIXME("Handle non null for field 3\n"); + } + + RegCloseKey(hkey); + + uirow = MSI_CreateRecord(2); + MSI_RecordSetStringW(uirow,1,package->mimes[i].ContentType); + MSI_RecordSetStringW(uirow,2,exten); + ui_actiondata(package,szRegisterMIMEInfo,uirow); + msiobj_release(&uirow->hdr); + } + + return ERROR_SUCCESS; +} diff --git a/reactos/lib/msi/cond.tab.c b/reactos/lib/msi/cond.tab.c index d025c24df54..ae49cc09d5a 100644 --- a/reactos/lib/msi/cond.tab.c +++ b/reactos/lib/msi/cond.tab.c @@ -72,7 +72,7 @@ #define YYLEX_PARAM info #define YYPARSE_PARAM info -static int COND_error(char *str); +static int COND_error(const char *str); WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -1970,7 +1970,7 @@ static LPWSTR COND_GetLiteral( struct cond_str *str ) return ret; } -static int COND_error(char *str) +static int COND_error(const char *str) { return 0; } diff --git a/reactos/lib/msi/cond.tab.h b/reactos/lib/msi/cond.tab.h index f37273b3993..d6099930466 100644 --- a/reactos/lib/msi/cond.tab.h +++ b/reactos/lib/msi/cond.tab.h @@ -1,83 +1,9 @@ -/* A Bison parser, made by GNU Bison 1.875c. */ +#ifndef BISON_COND_TAB_H +# define BISON_COND_TAB_H -/* Skeleton parser for Yacc-like parsing with Bison, - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* As a special exception, when this file is copied by Bison into a - Bison output file, you may use that output file without restriction. - This special exception was added by the Free Software Foundation - in version 1.24 of Bison. */ - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - COND_SPACE = 258, - COND_EOF = 259, - COND_OR = 260, - COND_AND = 261, - COND_NOT = 262, - COND_LT = 263, - COND_GT = 264, - COND_EQ = 265, - COND_LPAR = 266, - COND_RPAR = 267, - COND_TILDA = 268, - COND_PERCENT = 269, - COND_DOLLARS = 270, - COND_QUESTION = 271, - COND_AMPER = 272, - COND_EXCLAM = 273, - COND_IDENT = 274, - COND_NUMBER = 275, - COND_LITER = 276, - COND_ERROR = 277 - }; -#endif -#define COND_SPACE 258 -#define COND_EOF 259 -#define COND_OR 260 -#define COND_AND 261 -#define COND_NOT 262 -#define COND_LT 263 -#define COND_GT 264 -#define COND_EQ 265 -#define COND_LPAR 266 -#define COND_RPAR 267 -#define COND_TILDA 268 -#define COND_PERCENT 269 -#define COND_DOLLARS 270 -#define COND_QUESTION 271 -#define COND_AMPER 272 -#define COND_EXCLAM 273 -#define COND_IDENT 274 -#define COND_NUMBER 275 -#define COND_LITER 276 -#define COND_ERROR 277 - - - - -#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) -#line 106 "./cond.y" -typedef union YYSTYPE { +#ifndef YYSTYPE +typedef union +{ struct cond_str str; LPWSTR string; INT value; @@ -85,15 +11,30 @@ typedef union YYSTYPE { comp_str fn_comp_str; comp_m1 fn_comp_m1; comp_m2 fn_comp_m2; -} YYSTYPE; -/* Line 1275 of yacc.c. */ -#line 91 "cond.tab.h" -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 +} yystype; +# define YYSTYPE yystype # define YYSTYPE_IS_TRIVIAL 1 #endif +# define COND_SPACE 257 +# define COND_EOF 258 +# define COND_OR 259 +# define COND_AND 260 +# define COND_NOT 261 +# define COND_LT 262 +# define COND_GT 263 +# define COND_EQ 264 +# define COND_LPAR 265 +# define COND_RPAR 266 +# define COND_TILDA 267 +# define COND_PERCENT 268 +# define COND_DOLLARS 269 +# define COND_QUESTION 270 +# define COND_AMPER 271 +# define COND_EXCLAM 272 +# define COND_IDENT 273 +# define COND_NUMBER 274 +# define COND_LITER 275 +# define COND_ERROR 276 - - - +#endif /* not BISON_COND_TAB_H */ diff --git a/reactos/lib/msi/cond.y b/reactos/lib/msi/cond.y index fd995b8cb38..5cb921bfe37 100644 --- a/reactos/lib/msi/cond.y +++ b/reactos/lib/msi/cond.y @@ -38,7 +38,7 @@ #define YYLEX_PARAM info #define YYPARSE_PARAM info -static int COND_error(char *str); +static int COND_error(const char *str); WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -722,7 +722,7 @@ static LPWSTR COND_GetLiteral( struct cond_str *str ) return ret; } -static int COND_error(char *str) +static int COND_error(const char *str) { return 0; } diff --git a/reactos/lib/msi/create.c b/reactos/lib/msi/create.c index 51d316e6b50..2d92db1f1f6 100644 --- a/reactos/lib/msi/create.c +++ b/reactos/lib/msi/create.c @@ -44,7 +44,7 @@ typedef struct tagMSICREATEVIEW MSIDATABASE *db; LPWSTR name; BOOL bIsTemp; - create_col_info *col_info; + column_info *col_info; } MSICREATEVIEW; static UINT CREATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) @@ -59,7 +59,7 @@ static UINT CREATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT static UINT CREATE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) { MSICREATEVIEW *cv = (MSICREATEVIEW*)view; - create_col_info *col; + column_info *col; UINT r, nField, row, table_val, column_val; static const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 }; static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 }; @@ -122,8 +122,8 @@ static UINT CREATE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) if( r ) goto err; - column_val = msi_addstringW( cv->db->strings, 0, col->colname, -1, 1 ); - TRACE("New string %s -> %d\n", debugstr_w( col->colname ), column_val ); + column_val = msi_addstringW( cv->db->strings, 0, col->column, -1, 1 ); + TRACE("New string %s -> %d\n", debugstr_w( col->column ), column_val ); if( column_val < 0 ) break; @@ -226,7 +226,7 @@ MSIVIEWOPS create_ops = }; UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, - create_col_info *col_info, BOOL temp ) + column_info *col_info, BOOL temp ) { MSICREATEVIEW *cv = NULL; diff --git a/reactos/lib/msi/custom.c b/reactos/lib/msi/custom.c index 4465fc2ebf2..17645e999cc 100644 --- a/reactos/lib/msi/custom.c +++ b/reactos/lib/msi/custom.c @@ -77,7 +77,6 @@ static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source, UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute) { UINT rc = ERROR_SUCCESS; - MSIQUERY * view; MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', @@ -89,25 +88,9 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute) LPWSTR target; WCHAR *deformated=NULL; - rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, action); - if (rc != ERROR_SUCCESS) - return rc; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); + row = MSI_QueryGetRecord( package->db, ExecSeqQuery, action ); + if (!row) return ERROR_CALL_NOT_IMPLEMENTED; - } type = MSI_RecordGetInteger(row,2); @@ -123,53 +106,28 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute) if (type & 0x100) { FIXME("Rollback only action... rollbacks not supported yet\n"); + schedule_action(package, ROLLBACK_SCRIPT, action); HeapFree(GetProcessHeap(),0,source); HeapFree(GetProcessHeap(),0,target); msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); return ERROR_SUCCESS; } if (!execute) { - LPWSTR *newbuf = NULL; - INT count; if (type & 0x200) { TRACE("Deferring Commit Action!\n"); - count = package->CommitActionCount; - package->CommitActionCount++; - if (count != 0) - newbuf = HeapReAlloc(GetProcessHeap(),0, - package->CommitAction, - package->CommitActionCount * sizeof(LPWSTR)); - else - newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR)); - - newbuf[count] = strdupW(action); - package->CommitAction = newbuf; + schedule_action(package, COMMIT_SCRIPT, action); } else { TRACE("Deferring Action!\n"); - count = package->DeferredActionCount; - package->DeferredActionCount++; - if (count != 0) - newbuf = HeapReAlloc(GetProcessHeap(),0, - package->DeferredAction, - package->DeferredActionCount * sizeof(LPWSTR)); - else - newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR)); - - newbuf[count] = strdupW(action); - package->DeferredAction = newbuf; + schedule_action(package, INSTALL_SCRIPT, action); } HeapFree(GetProcessHeap(),0,source); HeapFree(GetProcessHeap(),0,target); msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); return ERROR_SUCCESS; } else @@ -223,8 +181,6 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute) HeapFree(GetProcessHeap(),0,source); HeapFree(GetProcessHeap(),0,target); msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); return rc; } @@ -249,7 +205,6 @@ static UINT store_binary_to_temp(MSIPACKAGE *package, LPCWSTR source, { /* write out the file */ UINT rc; - MSIQUERY * view; MSIRECORD * row = 0; static const WCHAR fmt[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', @@ -258,34 +213,15 @@ static UINT store_binary_to_temp(MSIPACKAGE *package, LPCWSTR source, HANDLE the_file; CHAR buffer[1024]; - if (track_tempfile(package, tmp_file, tmp_file)!=0) - FIXME("File Name in temp tracking collision\n"); - the_file = CreateFileW(tmp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (the_file == INVALID_HANDLE_VALUE) return ERROR_FUNCTION_FAILED; - rc = MSI_OpenQuery(package->db, &view, fmt, source); - if (rc != ERROR_SUCCESS) - return rc; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } + row = MSI_QueryGetRecord(package->db, fmt, source); + if (!row) + return ERROR_FUNCTION_FAILED; do { @@ -305,8 +241,6 @@ static UINT store_binary_to_temp(MSIPACKAGE *package, LPCWSTR source, CloseHandle(the_file); msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); } return ERROR_SUCCESS; @@ -366,7 +300,7 @@ static UINT process_action_return_value(UINT type, HANDLE ThreadHandle) static UINT process_handle(MSIPACKAGE* package, UINT type, HANDLE ThreadHandle, HANDLE ProcessHandle, - LPCWSTR Name) + LPCWSTR Name, BOOL *finished) { UINT rc = ERROR_SUCCESS; @@ -390,6 +324,8 @@ static UINT process_handle(MSIPACKAGE* package, UINT type, CloseHandle(ThreadHandle); if (ProcessHandle); CloseHandle(ProcessHandle); + if (finished) + *finished = TRUE; } else { @@ -411,6 +347,8 @@ static UINT process_handle(MSIPACKAGE* package, UINT type, if (ProcessHandle); CloseHandle(ProcessHandle); } + if (finished) + *finished = FALSE; } return rc; @@ -496,6 +434,7 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source, DWORD ThreadId; HANDLE ThreadHandle; UINT rc = ERROR_SUCCESS; + BOOL finished = FALSE; store_binary_to_temp(package, source, tmp_file); @@ -516,7 +455,12 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source, ThreadHandle = CreateThread(NULL,0,DllThread,(LPVOID)info,0,&ThreadId); - rc = process_handle(package, type, ThreadHandle, NULL, action); + rc = process_handle(package, type, ThreadHandle, NULL, action, &finished ); + + if (!finished) + track_tempfile(package, tmp_file, tmp_file); + else + DeleteFileW(tmp_file); return rc; } @@ -533,6 +477,7 @@ static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source, WCHAR *cmd; static const WCHAR spc[] = {' ',0}; UINT prc = ERROR_SUCCESS; + BOOL finished = FALSE; memset(&si,0,sizeof(STARTUPINFOW)); @@ -569,8 +514,14 @@ static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source, return ERROR_SUCCESS; } - prc = process_handle(package, type, info.hThread, info.hProcess, action); + prc = process_handle(package, type, info.hThread, info.hProcess, action, + &finished); + if (!finished) + track_tempfile(package, tmp_file, tmp_file); + else + DeleteFileW(tmp_file); + return prc; } @@ -622,7 +573,8 @@ static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source, return ERROR_SUCCESS; } - prc = process_handle(package, type, info.hThread, info.hProcess, action); + prc = process_handle(package, type, info.hThread, info.hProcess, action, + NULL); return prc; } @@ -636,37 +588,23 @@ static UINT HANDLE_CustomType19(MSIPACKAGE *package, LPCWSTR source, 'W','H','E','R','E',' ','`','E','r','r','o','r','`',' ','=',' ', '\'','%','s','\'',0 }; - MSIQUERY *view = NULL; MSIRECORD *row = 0; - UINT r; LPWSTR deformated = NULL; deformat_string( package, target, &deformated ); /* first try treat the error as a number */ - r = MSI_OpenQuery( package->db, &view, query, deformated ); - if( r == ERROR_SUCCESS ) + row = MSI_QueryGetRecord( package->db, query, deformated ); + if( row ) { - r = MSI_ViewExecute( view, 0 ); - if( r == ERROR_SUCCESS ) - { - r = MSI_ViewFetch( view, &row ); - if( r == ERROR_SUCCESS ) - { - LPCWSTR error = MSI_RecordGetString( row, 1 ); - MessageBoxW( NULL, error, NULL, MB_OK ); - msiobj_release( &row->hdr ); - } - } - MSI_ViewClose( view ); - msiobj_release( &view->hdr ); + LPCWSTR error = MSI_RecordGetString( row, 1 ); + MessageBoxW( NULL, error, NULL, MB_OK ); + msiobj_release( &row->hdr ); } - - if (r != ERROR_SUCCESS ) - { + else MessageBoxW( NULL, deformated, NULL, MB_OK ); - HeapFree( GetProcessHeap(), 0, deformated ); - } + + HeapFree( GetProcessHeap(), 0, deformated ); return ERROR_FUNCTION_FAILED; } @@ -720,7 +658,8 @@ static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source, return ERROR_SUCCESS; } - prc = process_handle(package, type, info.hThread, info.hProcess, action); + prc = process_handle(package, type, info.hThread, info.hProcess, action, + NULL); return prc; } @@ -761,7 +700,8 @@ static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source, return ERROR_SUCCESS; } - prc = process_handle(package, type, info.hThread, info.hProcess, action); + prc = process_handle(package, type, info.hThread, info.hProcess, action, + NULL); return prc; } diff --git a/reactos/lib/msi/database.c b/reactos/lib/msi/database.c index 800b1db2f57..aa94a232638 100644 --- a/reactos/lib/msi/database.c +++ b/reactos/lib/msi/database.c @@ -59,7 +59,7 @@ DEFINE_GUID( CLSID_MsiDatabase, 0x000c1084, 0x0000, 0x0000, * Any binary data in a table is a reference to a stream. */ -VOID MSI_CloseDatabase( MSIOBJECTHDR *arg ) +static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg ) { MSIDATABASE *db = (MSIDATABASE *) arg; DWORD r; @@ -77,7 +77,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb) HRESULT r; MSIDATABASE *db = NULL; UINT ret = ERROR_FUNCTION_FAILED; - LPWSTR szMode; + LPCWSTR szMode; STATSTG stat; TRACE("%s %s\n",debugstr_w(szDBPath),debugstr_w(szPersist) ); @@ -85,7 +85,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb) if( !pdb ) return ERROR_INVALID_PARAMETER; - szMode = (LPWSTR) szPersist; + szMode = szPersist; if( HIWORD( szPersist ) ) { /* UINT len = lstrlenW( szPerist ) + 1; */ @@ -209,7 +209,7 @@ UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB) goto end; } else - szwPersist = (LPWSTR) szPersist; + szwPersist = (LPWSTR)(DWORD)szPersist; r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB ); diff --git a/reactos/lib/msi/dialog.c b/reactos/lib/msi/dialog.c index 4977329f471..69e2b1e6fd7 100644 --- a/reactos/lib/msi/dialog.c +++ b/reactos/lib/msi/dialog.c @@ -32,6 +32,7 @@ #include "msidefs.h" #include "ocidl.h" #include "olectl.h" +#include "richedit.h" #include "wine/debug.h" #include "wine/unicode.h" @@ -41,17 +42,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); -const WCHAR szMsiDialogClass[] = { - 'M','s','i','D','i','a','l','o','g','C','l','o','s','e','C','l','a','s','s',0 -}; -const WCHAR szMsiHiddenWindow[] = { - 'M','s','i','H','i','d','d','e','n','W','i','n','d','o','w',0 -}; -const static WCHAR szStatic[] = { 'S','t','a','t','i','c',0 }; -const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 }; - -const static WCHAR szButtonData[] = { 'M','S','I','D','A','T','A',0 }; - struct msi_control_tag; typedef struct msi_control_tag msi_control; typedef UINT (*msi_handler)( msi_dialog *, msi_control *, WPARAM ); @@ -62,7 +52,9 @@ struct msi_control_tag HWND hwnd; msi_handler handler; LPWSTR property; + LPWSTR value; IPicture *pic; + HICON hIcon; WCHAR name[1]; }; @@ -101,11 +93,35 @@ typedef struct DWORD attributes; } radio_button_group_descr; +const WCHAR szMsiDialogClass[] = { + 'M','s','i','D','i','a','l','o','g','C','l','o','s','e','C','l','a','s','s',0 +}; +const WCHAR szMsiHiddenWindow[] = { + 'M','s','i','H','i','d','d','e','n','W','i','n','d','o','w',0 }; +const static WCHAR szStatic[] = { 'S','t','a','t','i','c',0 }; +const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 }; +const static WCHAR szButtonData[] = { 'M','S','I','D','A','T','A',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 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 UINT msi_dialog_checkbox_handler( msi_dialog *, msi_control *, WPARAM ); static void msi_dialog_checkbox_sync_state( msi_dialog *, msi_control * ); static UINT msi_dialog_button_handler( msi_dialog *, msi_control *, WPARAM ); static UINT msi_dialog_edit_handler( msi_dialog *, msi_control *, WPARAM ); static UINT msi_dialog_radiogroup_handler( msi_dialog *, msi_control *, WPARAM param ); +static UINT msi_dialog_evaluate_control_conditions( msi_dialog *dialog ); static LRESULT WINAPI MSIRadioGroup_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); @@ -116,12 +132,33 @@ static LRESULT WINAPI MSIRadioGroup_WndProc(HWND hWnd, UINT msg, WPARAM wParam, static DWORD uiThreadId; static HWND hMsiHiddenWindow; +static HMODULE hRichedit; -INT msi_dialog_scale_unit( msi_dialog *dialog, INT val ) +static INT msi_dialog_scale_unit( msi_dialog *dialog, INT val ) { return (dialog->scale * val + 5) / 10; } +static msi_control *msi_dialog_find_control( msi_dialog *dialog, LPCWSTR name ) +{ + msi_control *control; + + for( control = dialog->control_list; control; control = control->next ) + if( !strcmpW( control->name, name ) ) /* FIXME: case sensitive? */ + break; + return control; +} + +static msi_control *msi_dialog_find_control_by_hwnd( msi_dialog *dialog, HWND hwnd ) +{ + msi_control *control; + + for( control = dialog->control_list; control; control = control->next ) + if( hwnd == control->hwnd ) + break; + return control; +} + /* * msi_dialog_get_style * @@ -250,7 +287,7 @@ static msi_control *msi_dialog_create_window( msi_dialog *dialog, LPWSTR font = NULL, title = NULL; msi_control *control; - style |= WS_CHILD | WS_GROUP; + style |= WS_CHILD; control = HeapAlloc( GetProcessHeap(), 0, sizeof *control + strlenW(name)*sizeof(WCHAR) ); @@ -259,7 +296,9 @@ static msi_control *msi_dialog_create_window( msi_dialog *dialog, dialog->control_list = control; control->handler = NULL; control->property = NULL; + control->value = NULL; control->pic = NULL; + control->hIcon = NULL; x = MSI_RecordGetInteger( rec, 4 ); y = MSI_RecordGetInteger( rec, 5 ); @@ -292,6 +331,46 @@ static msi_control *msi_dialog_create_window( msi_dialog *dialog, return control; } +/* 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 text; + + ctrl = msi_dialog_find_control( dialog, control ); + if (!ctrl) + return; + if( lstrcmpW(attribute, szText) ) + return; + text = MSI_RecordGetString( rec , 1 ); + SetWindowTextW( ctrl->hwnd, text ); + msi_dialog_check_messages( NULL ); +} + +static void msi_dialog_map_events(msi_dialog* dialog, LPCWSTR control) +{ + static 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, 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 ) @@ -302,19 +381,94 @@ static msi_control *msi_dialog_add_control( msi_dialog *dialog, name = MSI_RecordGetString( rec, 2 ); attributes = MSI_RecordGetInteger( rec, 8 ); text = MSI_RecordGetString( rec, 10 ); - if( attributes & 1 ) + if( attributes & msidbControlAttributesVisible ) style |= WS_VISIBLE; - if( ~attributes & 2 ) + if( ~attributes & msidbControlAttributesEnabled ) style |= WS_DISABLED; + + msi_dialog_map_events(dialog, name); + return msi_dialog_create_window( dialog, rec, szCls, name, text, style, dialog->hwnd ); } +struct msi_text_info +{ + 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 %08x %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); + + switch( msg ) + { + case WM_SETTEXT: + msi_text_on_settext( hWnd ); + break; + case WM_NCDESTROY: + HeapFree( GetProcessHeap(), 0, 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; + TRACE("%p %p\n", dialog, rec); - msi_dialog_add_control( dialog, rec, szStatic, 0 ); + control = msi_dialog_add_control( dialog, rec, szStatic, SS_LEFT | WS_GROUP ); + if( !control ) + return ERROR_FUNCTION_FAILED; + + info = HeapAlloc( GetProcessHeap(), 0, sizeof *info ); + if( !info ) + return ERROR_SUCCESS; + + 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 ); + return ERROR_SUCCESS; } @@ -324,12 +478,54 @@ static UINT msi_dialog_button_control( msi_dialog *dialog, MSIRECORD *rec ) TRACE("%p %p\n", dialog, rec); - control = msi_dialog_add_control( dialog, rec, szButton, 0 ); + control = msi_dialog_add_control( dialog, rec, szButton, WS_TABSTOP ); control->handler = msi_dialog_button_handler; return ERROR_SUCCESS; } +static LPWSTR msi_get_checkbox_value( msi_dialog *dialog, LPCWSTR prop ) +{ + const static 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; + LPCWSTR val = 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; + + val = MSI_RecordGetString( rec, 2 ); + if (val) + { + deformat_string( dialog->package, val, &ret ); + if( ret && !ret[0] ) + { + HeapFree( GetProcessHeap(), 0, ret ); + ret = NULL; + } + } + msiobj_release( &rec->hdr ); + if (ret) + return ret; + + ret = load_dynamic_property(dialog->package, prop, NULL); + if( ret && !ret[0] ) + { + HeapFree( GetProcessHeap(), 0, ret ); + ret = NULL; + } + + return ret; +} + static UINT msi_dialog_checkbox_control( msi_dialog *dialog, MSIRECORD *rec ) { msi_control *control; @@ -338,11 +534,16 @@ static UINT msi_dialog_checkbox_control( msi_dialog *dialog, MSIRECORD *rec ) TRACE("%p %p\n", dialog, rec); control = msi_dialog_add_control( dialog, rec, szButton, - BS_CHECKBOX | BS_MULTILINE ); + BS_CHECKBOX | BS_MULTILINE | WS_TABSTOP ); control->handler = msi_dialog_checkbox_handler; 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; @@ -356,19 +557,61 @@ static UINT msi_dialog_line_control( msi_dialog *dialog, MSIRECORD *rec ) return ERROR_SUCCESS; } +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("%ld/%ld\n", info->offset, info->length); + + return 0; +} + static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec ) { - const static WCHAR szEdit[] = { 'E','D','I','T',0 }; + const static WCHAR szRichEdit20W[] = { + 'R','i','c','h','E','d','i','t','2','0','W',0 + }; + struct msi_streamin_info info; + msi_control *control; + LPCWSTR text; + EDITSTREAM es; + DWORD style; - FIXME("%p %p\n", dialog, rec); + style = WS_BORDER | ES_MULTILINE | WS_VSCROLL | + ES_READONLY | ES_AUTOVSCROLL | WS_TABSTOP; + control = msi_dialog_add_control( dialog, rec, szRichEdit20W, style ); - msi_dialog_add_control( dialog, rec, szEdit, WS_BORDER | - ES_MULTILINE | WS_VSCROLL | ES_READONLY | ES_AUTOVSCROLL ); + text = MSI_RecordGetString( rec, 10 ); + 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 ); + + HeapFree( GetProcessHeap(), 0, info.string ); return ERROR_SUCCESS; } -static UINT msi_load_bitmap( MSIDATABASE *db, LPCWSTR name, IPicture **pic ) +static MSIRECORD *msi_get_binary_record( MSIDATABASE *db, LPCWSTR name ) { const static WCHAR query[] = { 's','e','l','e','c','t',' ','*',' ', @@ -376,20 +619,17 @@ static UINT msi_load_bitmap( MSIDATABASE *db, LPCWSTR name, IPicture **pic ) 'w','h','e','r','e',' ', '`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0 }; - MSIQUERY *view = NULL; + + return MSI_QueryGetRecord( db, query, name ); +} + +static UINT msi_load_bitmap( MSIDATABASE *db, LPCWSTR name, IPicture **pic ) +{ MSIRECORD *rec = NULL; IStream *stm = NULL; UINT r; - r = MSI_OpenQuery( db, &view, query, name ); - if( r != ERROR_SUCCESS ) - return r; - - MSI_ViewExecute( view, NULL ); - MSI_ViewFetch( view, &rec ); - MSI_ViewClose( view ); - msiobj_release( &view->hdr ); - + rec = msi_get_binary_record( db, name ); if( !rec ) return ERROR_FUNCTION_FAILED; @@ -429,6 +669,108 @@ static UINT msi_dialog_bitmap_control( msi_dialog *dialog, MSIRECORD *rec ) return ERROR_SUCCESS; } +static LPWSTR msi_create_tmp_path(void) +{ + WCHAR tmp[MAX_PATH]; + LPWSTR path = NULL; + static const WCHAR prefix[] = { 'm','s','i',0 }; + DWORD len, r; + + r = GetTempPathW( MAX_PATH, tmp ); + if( !r ) + return path; + len = lstrlenW( tmp ) + 20; + path = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); + if( path ) + { + r = GetTempFileNameW( tmp, prefix, 0, path ); + if (!r) + { + HeapFree( GetProcessHeap(), 0, path ); + path = NULL; + } + } + return path; +} + +static UINT +msi_load_icon( MSIDATABASE *db, LPCWSTR name, DWORD attributes, HICON *picon ) +{ + UINT r = ERROR_FUNCTION_FAILED; + LPWSTR tmp; + MSIRECORD *rec; + HICON hicon = 0; + + TRACE("loading %s\n", debugstr_w( name ) ); + + tmp = msi_create_tmp_path(); + if( !tmp ) + return r; + + rec = msi_get_binary_record( db, name ); + if( rec ) + { + r = MSI_RecordStreamToFile( rec, 2, tmp ); + if( r == ERROR_SUCCESS ) + { + DWORD cx = 0, cy = 0, 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 */ + } + + hicon = LoadImageW( 0, tmp, IMAGE_ICON, cx, cy, flags ); + if( hicon ) + *picon = hicon; + else + ERR("failed to load icon from %s\n", debugstr_w( tmp )); + DeleteFileW( tmp ); + } + msiobj_release( &rec->hdr ); + } + + HeapFree( GetProcessHeap(), 0, tmp ); + + return r; +} + +static UINT msi_dialog_icon_control( msi_dialog *dialog, MSIRECORD *rec ) +{ + msi_control *control; + DWORD attributes; + HICON hIcon = 0; + LPCWSTR text; + UINT r; + + TRACE("\n"); + + control = msi_dialog_add_control( dialog, rec, szStatic, + SS_ICON | SS_CENTERIMAGE | WS_GROUP ); + text = MSI_RecordGetString( rec, 10 ); + attributes = MSI_RecordGetInteger( rec, 8 ); + r = msi_load_icon( dialog->package->db, text, attributes, &hIcon ); + if( r == ERROR_SUCCESS ) + { + r = SendMessageW( control->hwnd, STM_SETICON, (WPARAM) hIcon, 0 ); + control->hIcon = hIcon; + } + else + ERR("Failed to load bitmap %s\n", debugstr_w(text)); + return ERROR_SUCCESS; +} + static UINT msi_dialog_combo_control( msi_dialog *dialog, MSIRECORD *rec ) { static const WCHAR szCombo[] = { 'C','O','M','B','O','B','O','X',0 }; @@ -440,12 +782,12 @@ static UINT msi_dialog_combo_control( msi_dialog *dialog, MSIRECORD *rec ) static UINT msi_dialog_edit_control( msi_dialog *dialog, MSIRECORD *rec ) { - const static WCHAR szEdit[] = { 'E','D','I','T',0 }; msi_control *control; LPCWSTR prop; LPWSTR val; - control = msi_dialog_add_control( dialog, rec, szEdit, WS_BORDER ); + control = msi_dialog_add_control( dialog, rec, szEdit, + WS_BORDER | WS_TABSTOP ); control->handler = msi_dialog_edit_handler; prop = MSI_RecordGetString( rec, 9 ); if( prop ) @@ -456,6 +798,275 @@ static UINT msi_dialog_edit_control( msi_dialog *dialog, MSIRECORD *rec ) return ERROR_SUCCESS; } +/******************** Masked Edit ********************************************/ + +#define MASK_MAX_GROUPS 10 + +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 void msi_mask_control_change( struct msi_maskedit_info *info ) +{ + LPWSTR val; + UINT i, n, r; + + val = HeapAlloc( GetProcessHeap(), 0, (info->num_chars+1)*sizeof(WCHAR) ); + for( i=0, n=0; inum_groups; i++ ) + { + if( (info->group[i].len + n) > info->num_chars ) + { + ERR("can't fit control %d text into template\n",i); + break; + } + 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_SetPropertyW( info->dialog->package, info->prop, val ); + msi_dialog_evaluate_control_conditions( info->dialog ); + } + HeapFree( GetProcessHeap(), 0, val ); +} + +static LRESULT WINAPI +MSIMaskedEdit_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + struct msi_maskedit_info *info; + HRESULT r; + + TRACE("%p %04x %08x %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 ); + break; + case WM_NCDESTROY: + HeapFree( GetProcessHeap(), 0, info->prop ); + HeapFree( GetProcessHeap(), 0, 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 < lstrlenW( p ) ) + { + LPWSTR chunk = strdupW( p ); + chunk[ info->group[i].len ] = 0; + SetWindowTextW( info->group[i].hwnd, chunk ); + HeapFree( GetProcessHeap(), 0, 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; + + p = strchrW(mask, '<'); + if( !p ) + return info; + + info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *info ); + if( !info ) + return info; + + p++; + for( i=0; i' ) + 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, info->num_groups ); + 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 ) +{ + DWORD width, height, style, wx, ww; + LPCWSTR text, font = NULL; + RECT rect; + HWND hwnd; + UINT i; + + style = WS_CHILD | WS_BORDER | WS_VISIBLE | WS_TABSTOP; + + GetClientRect( info->hwnd, &rect ); + + width = rect.right - rect.left; + height = rect.bottom - rect.top; + + if( text ) + font = msi_dialog_get_style( &text ); + + for( i = 0; i < info->num_groups; i++ ) + { + 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<````=````=````=````=`````>@@@@@" */ +static UINT msi_dialog_maskedit_control( msi_dialog *dialog, MSIRECORD *rec ) +{ + const static WCHAR pidt[] = {'P','I','D','T','e','m','p','l','a','t','e',0}; + LPWSTR mask = NULL, title = NULL, val = NULL; + struct msi_maskedit_info *info = NULL; + UINT ret = ERROR_SUCCESS; + msi_control *control; + LPCWSTR prop; + + mask = load_dynamic_property( dialog->package, pidt, NULL ); + if( !mask ) + { + ERR("PIDTemplate 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 ); + + if( prop ) + { + val = load_dynamic_property( dialog->package, prop, NULL ); + if( val ) + { + msi_maskedit_set_text( info, val ); + HeapFree( GetProcessHeap(), 0, val ); + } + } + +end: + if( ret != ERROR_SUCCESS ) + HeapFree( GetProcessHeap(), 0, info ); + HeapFree( GetProcessHeap(), 0, title ); + HeapFree( GetProcessHeap(), 0, mask ); + return ret; +} + +/******************** Path Edit ********************************************/ + static UINT msi_dialog_pathedit_control( msi_dialog *dialog, MSIRECORD *rec ) { FIXME("not implemented properly\n"); @@ -472,7 +1083,7 @@ static UINT msi_dialog_create_radiobutton( MSIRECORD *rec, LPVOID param ) DWORD style; DWORD attributes = group->attributes; - style = WS_CHILD | BS_AUTORADIOBUTTON | BS_MULTILINE; + style = WS_CHILD | BS_AUTORADIOBUTTON | BS_MULTILINE | WS_TABSTOP; name = MSI_RecordGetString( rec, 3 ); text = MSI_RecordGetString( rec, 8 ); if( attributes & 1 ) @@ -504,20 +1115,21 @@ static UINT msi_dialog_radiogroup_control( msi_dialog *dialog, MSIRECORD *rec ) MSIQUERY *view = NULL; radio_button_group_descr group; MSIPACKAGE *package = dialog->package; + WNDPROC oldproc; prop = MSI_RecordGetString( rec, 9 ); TRACE("%p %p %s\n", dialog, rec, debugstr_w( prop )); /* Create parent group box to hold radio buttons */ - control = msi_dialog_add_control( dialog, rec, szButton, BS_OWNERDRAW ); + control = msi_dialog_add_control( dialog, rec, szButton, BS_OWNERDRAW|WS_GROUP ); + if( !control ) + return ERROR_FUNCTION_FAILED; - if (control->hwnd) - { - WNDPROC oldproc = (WNDPROC) SetWindowLongPtrW(control->hwnd, GWLP_WNDPROC, - (LONG_PTR)MSIRadioGroup_WndProc); - SetPropW(control->hwnd, szButtonData, oldproc); - } + 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 ); @@ -541,20 +1153,6 @@ static UINT msi_dialog_radiogroup_control( msi_dialog *dialog, MSIRECORD *rec ) return r; } -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 szRadioButtonGroup[] = { - 'R','a','d','i','o','B','u','t','t','o','n','G','r','o','u','p',0 }; - struct control_handler msi_dialog_handler[] = { { szText, msi_dialog_text_control }, @@ -565,9 +1163,10 @@ struct control_handler msi_dialog_handler[] = { szScrollableText, msi_dialog_scrolltext_control }, { szComboBox, msi_dialog_combo_control }, { szEdit, msi_dialog_edit_control }, - { szMaskedEdit, msi_dialog_edit_control }, + { szMaskedEdit, msi_dialog_maskedit_control }, { szPathEdit, msi_dialog_pathedit_control }, { szRadioButtonGroup, msi_dialog_radiogroup_control }, + { szIcon, msi_dialog_icon_control }, }; #define NUM_CONTROL_TYPES (sizeof msi_dialog_handler/sizeof msi_dialog_handler[0]) @@ -618,26 +1217,6 @@ static UINT msi_dialog_fill_controls( msi_dialog *dialog ) return r; } -static msi_control *msi_dialog_find_control( msi_dialog *dialog, LPCWSTR name ) -{ - msi_control *control; - - for( control = dialog->control_list; control; control = control->next ) - if( !strcmpW( control->name, name ) ) /* FIXME: case sensitive? */ - break; - return control; -} - -static msi_control *msi_dialog_find_control_by_hwnd( msi_dialog *dialog, HWND hwnd ) -{ - msi_control *control; - - for( control = dialog->control_list; control; control = control->next ) - if( hwnd == control->hwnd ) - break; - return control; -} - static UINT msi_dialog_set_control_condition( MSIRECORD *rec, LPVOID param ) { static const WCHAR szHide[] = { 'H','i','d','e',0 }; @@ -659,7 +1238,7 @@ static UINT msi_dialog_set_control_condition( MSIRECORD *rec, LPVOID param ) TRACE("%s control %s\n", debugstr_w(action), debugstr_w(name)); /* FIXME: case sensitive? */ - if(!strcmpW(action, szHide)) + if(!lstrcmpW(action, szHide)) ShowWindow(control->hwnd, SW_HIDE); else if(!strcmpW(action, szShow)) ShowWindow(control->hwnd, SW_SHOW); @@ -745,35 +1324,42 @@ static MSIRECORD *msi_get_dialog_record( msi_dialog *dialog ) 'W','H','E','R','E',' ', '`','D','i','a','l','o','g','`',' ','=',' ','\'','%','s','\'',0}; MSIPACKAGE *package = dialog->package; - MSIQUERY *view = NULL; MSIRECORD *rec = NULL; - UINT r; TRACE("%p %s\n", dialog, debugstr_w(dialog->name) ); - r = MSI_OpenQuery( package->db, &view, query, dialog->name ); - if( r != ERROR_SUCCESS ) - { + rec = MSI_QueryGetRecord( package->db, query, dialog->name ); + if( !rec ) ERR("query failed for dialog %s\n", debugstr_w(dialog->name)); - return NULL; - } - MSI_ViewExecute( view, NULL ); - MSI_ViewFetch( view, &rec ); - MSI_ViewClose( view ); - msiobj_release( &view->hdr ); return rec; } +static void msi_dialog_adjust_dialog_size( msi_dialog *dialog, LPSIZE sz ) +{ + RECT rect; + LONG style; + + /* turn the client size into the window rectangle */ + rect.left = 0; + rect.top = 0; + rect.right = msi_dialog_scale_unit( dialog, sz->cx ); + rect.bottom = msi_dialog_scale_unit( dialog, sz->cy ); + style = GetWindowLongPtrW( dialog->hwnd, GWL_STYLE ); + AdjustWindowRect( &rect, style, FALSE ); + sz->cx = rect.right - rect.left; + sz->cy = rect.bottom - rect.top; +} + 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 }; msi_dialog *dialog = (msi_dialog*) cs->lpCreateParams; MSIRECORD *rec = NULL; - DWORD width, height; LPCWSTR text; LPWSTR title = NULL; + SIZE size; TRACE("%p %p\n", dialog, dialog->package); @@ -789,19 +1375,18 @@ static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs ) dialog->scale = msi_dialog_get_sans_serif_height(dialog->hwnd); - width = MSI_RecordGetInteger( rec, 4 ); - height = MSI_RecordGetInteger( rec, 5 ); + size.cx = MSI_RecordGetInteger( rec, 4 ); + size.cy = MSI_RecordGetInteger( rec, 5 ); + msi_dialog_adjust_dialog_size( dialog, &size ); + dialog->attributes = MSI_RecordGetInteger( rec, 6 ); text = MSI_RecordGetString( rec, 7 ); - width = msi_dialog_scale_unit( dialog, width ); - height = msi_dialog_scale_unit( dialog, height ) + 25; /* FIXME */ - dialog->default_font = load_dynamic_property( dialog->package, df, NULL ); deformat_string( dialog->package, text, &title ); SetWindowTextW( hwnd, title ); - SetWindowPos( hwnd, 0, 0, 0, width, height, + SetWindowPos( hwnd, 0, 0, 0, size.cx, size.cy, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW ); HeapFree( GetProcessHeap(), 0, title ); @@ -914,17 +1499,29 @@ static UINT msi_dialog_get_checkbox_state( msi_dialog *dialog, DWORD sz = 2; MSI_GetPropertyW( dialog->package, control->property, state, &sz ); - return atoiW( state ) ? 1 : 0; + return state[0] ? 1 : 0; } static void msi_dialog_set_checkbox_state( msi_dialog *dialog, msi_control *control, UINT state ) { - WCHAR szState[2] = { '0', 0 }; + static const WCHAR szState[] = { '1', 0 }; + LPCWSTR val; - if( state ) - szState[0]++; - MSI_SetPropertyW( dialog->package, control->property, szState ); + /* if uncheck then the property is set to NULL */ + if (!state) + { + MSI_SetPropertyW( dialog->package, control->property, NULL ); + return; + } + + /* check for a custom state */ + if (control->value && control->value[0]) + val = control->value; + else + val = szState; + + MSI_SetPropertyW( dialog->package, control->property, val ); } static void msi_dialog_checkbox_sync_state( msi_dialog *dialog, @@ -1035,6 +1632,10 @@ static LRESULT WINAPI MSIDialog_WndProc( HWND hwnd, UINT msg, case WM_COMMAND: return msi_dialog_oncommand( dialog, wParam, (HWND)lParam ); + /* 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; @@ -1106,12 +1707,14 @@ msi_dialog *msi_dialog_create( MSIPACKAGE* package, LPCWSTR szDialogName, return dialog; } -static void msi_process_pending_messages(void) +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 ); } @@ -1139,7 +1742,7 @@ void msi_dialog_check_messages( HANDLE handle ) /* there's two choices for the UI thread */ while (1) { - msi_process_pending_messages(); + msi_process_pending_messages( NULL ); if( !handle ) break; @@ -1182,7 +1785,7 @@ UINT msi_dialog_run_message_loop( msi_dialog *dialog ) while( !dialog->finished ) { MsgWaitForMultipleObjects( 0, NULL, 0, INFINITE, QS_ALLEVENTS ); - msi_process_pending_messages(); + msi_process_pending_messages( dialog->hwnd ); } } else @@ -1217,8 +1820,11 @@ void msi_dialog_destroy( msi_dialog *dialog ) dialog->control_list = t->next; /* leave dialog->hwnd - destroying parent destroys child windows */ HeapFree( GetProcessHeap(), 0, t->property ); + HeapFree( GetProcessHeap(), 0, t->value ); if( t->pic ) IPicture_Release( t->pic ); + if( t->hIcon ) + DestroyIcon( t->hIcon ); HeapFree( GetProcessHeap(), 0, t ); } @@ -1269,6 +1875,8 @@ BOOL msi_dialog_register_class( void ) if( !hMsiHiddenWindow ) return FALSE; + hRichedit = LoadLibraryA("riched20"); + return TRUE; } @@ -1277,4 +1885,5 @@ void msi_dialog_unregister_class( void ) DestroyWindow( hMsiHiddenWindow ); UnregisterClassW( szMsiDialogClass, NULL ); uiThreadId = 0; + FreeLibrary( hRichedit ); } diff --git a/reactos/lib/msi/events.c b/reactos/lib/msi/events.c new file mode 100644 index 00000000000..6d6682bb91f --- /dev/null +++ b/reactos/lib/msi/events.c @@ -0,0 +1,396 @@ +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* +http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/controlevent_overview.asp +*/ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" +#include "msi.h" +#include "msipriv.h" +#include "action.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +typedef UINT (*EVENTHANDLER)(MSIPACKAGE*,LPCWSTR,msi_dialog *); + +struct _events { + LPCSTR event; + EVENTHANDLER handler; +}; + +struct subscriber { + struct list entry; + LPWSTR event; + LPWSTR control; + LPWSTR attribute; +}; + +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 *dialog; + UINT r; + + /* kill the current modeless dialog */ + if( package->dialog ) + msi_dialog_destroy( package->dialog ); + package->dialog = NULL; + + /* create a new dialog */ + dialog = msi_dialog_create( package, name, + ControlEvent_HandleControlEvent ); + if( dialog ) + { + /* 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 (lstrcmpW(argument,szExit)==0) + package->CurrentInstallState = ERROR_INSTALL_USEREXIT; + else if (lstrcmpW(argument, szRetry) == 0) + package->CurrentInstallState = ERROR_INSTALL_SUSPEND; + else if (lstrcmpW(argument, szIgnore) == 0) + package->CurrentInstallState = -1; + else if (lstrcmpW(argument, szReturn) == 0) + package->CurrentInstallState = ERROR_SUCCESS; + else + { + ERR("Unknown argument string %s\n",debugstr_w(argument)); + package->CurrentInstallState = ERROR_FUNCTION_FAILED; + } + + ControlEvent_CleanupSubscriptions(package); + 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) +{ + event_do_dialog( package, argument ); + 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,TRUE); + return ERROR_SUCCESS; +} + +static UINT ControlEvent_AddLocal(MSIPACKAGE* package, LPCWSTR argument, + msi_dialog* dialog) +{ + static const WCHAR szAll[] = {'A','L','L',0}; + int i; + + if (lstrcmpW(szAll,argument)) + { + MSI_SetFeatureStateW(package,argument,INSTALLSTATE_LOCAL); + } + else + { + for (i = 0; i < package->loaded_features; i++) + { + package->features[i].ActionRequest = INSTALLSTATE_LOCAL; + package->features[i].Action = INSTALLSTATE_LOCAL; + } + ACTION_UpdateComponentStates(package,argument); + } + return ERROR_SUCCESS; +} + +static UINT ControlEvent_Remove(MSIPACKAGE* package, LPCWSTR argument, + msi_dialog* dialog) +{ + static const WCHAR szAll[] = {'A','L','L',0}; + int i; + + if (lstrcmpW(szAll,argument)) + { + MSI_SetFeatureStateW(package,argument,INSTALLSTATE_ABSENT); + } + else + { + for (i = 0; i < package->loaded_features; i++) + { + package->features[i].ActionRequest = INSTALLSTATE_ABSENT; + package->features[i].Action= INSTALLSTATE_ABSENT; + } + ACTION_UpdateComponentStates(package,argument); + } + return ERROR_SUCCESS; +} + +static UINT ControlEvent_AddSource(MSIPACKAGE* package, LPCWSTR argument, + msi_dialog* dialog) +{ + static const WCHAR szAll[] = {'A','L','L',0}; + int i; + + if (lstrcmpW(szAll,argument)) + { + MSI_SetFeatureStateW(package,argument,INSTALLSTATE_SOURCE); + } + else + { + for (i = 0; i < package->loaded_features; i++) + { + package->features[i].ActionRequest = INSTALLSTATE_SOURCE; + package->features[i].Action = INSTALLSTATE_SOURCE; + } + ACTION_UpdateComponentStates(package,argument); + } + return ERROR_SUCCESS; +} + +static UINT ControlEvent_SetTargetPath(MSIPACKAGE* package, LPCWSTR argument, + msi_dialog* dialog) +{ + LPWSTR path = load_dynamic_property(package,argument, NULL); + /* failure to set the path halts the executing of control events */ + return MSI_SetTargetPathW(package, argument, path); +} + +/* + * Subscribed events + */ +static void free_subscriber( struct subscriber *sub ) +{ + HeapFree(GetProcessHeap(),0,sub->event); + HeapFree(GetProcessHeap(),0,sub->control); + HeapFree(GetProcessHeap(),0,sub->attribute); + HeapFree(GetProcessHeap(),0,sub); +} + +VOID ControlEvent_SubscribeToEvent( MSIPACKAGE *package, LPCWSTR event, + LPCWSTR control, LPCWSTR attribute ) +{ + struct subscriber *sub; + + sub = HeapAlloc(GetProcessHeap(),0,sizeof (*sub)); + if( !sub ) + return; + sub->event = strdupW(event); + sub->control = strdupW(control); + sub->attribute = strdupW(attribute); + list_add_tail( &package->subscriptions, &sub->entry ); +} + +VOID ControlEvent_UnSubscribeToEvent( MSIPACKAGE *package, LPCWSTR event, + LPCWSTR control, LPCWSTR attribute ) +{ + struct list *i, *t; + struct subscriber *sub; + + LIST_FOR_EACH_SAFE( i, t, &package->subscriptions ) + { + sub = LIST_ENTRY( i, struct subscriber, entry ); + + if( lstrcmpiW(sub->control,control) ) + continue; + if( lstrcmpiW(sub->attribute,attribute) ) + continue; + if( lstrcmpiW(sub->event,event) ) + continue; + list_remove( &sub->entry ); + free_subscriber( sub ); + } +} + +VOID ControlEvent_FireSubscribedEvent( MSIPACKAGE *package, LPCWSTR event, + MSIRECORD *rec ) +{ + struct subscriber *sub; + + TRACE("Firing Event %s\n",debugstr_w(event)); + + if (!package->dialog) + return; + + LIST_FOR_EACH_ENTRY( sub, &package->subscriptions, struct subscriber, entry ) + { + if (lstrcmpiW(sub->event, event)) + continue; + msi_dialog_handle_event( package->dialog, sub->control, + sub->attribute, rec ); + } +} + +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 ); + while( r == ERROR_SUCCESS && package->next_dialog ) + { + LPWSTR name = package->next_dialog; + + package->next_dialog = NULL; + r = event_do_dialog( package, name ); + HeapFree( GetProcessHeap(), 0, name ); + } + + if( r == ERROR_IO_PENDING ) + r = ERROR_SUCCESS; + + return r; +} + +struct _events Events[] = { + { "EndDialog",ControlEvent_EndDialog }, + { "NewDialog",ControlEvent_NewDialog }, + { "SpawnDialog",ControlEvent_SpawnDialog }, + { "SpawnWaitDialog",ControlEvent_SpawnWaitDialog }, + { "DoAction",ControlEvent_DoAction }, + { "AddLocal",ControlEvent_AddLocal }, + { "Remove",ControlEvent_Remove }, + { "AddSource",ControlEvent_AddSource }, + { "SetTargetPath",ControlEvent_SetTargetPath }, + { NULL,NULL }, +}; + +UINT ControlEvent_HandleControlEvent(MSIPACKAGE *package, LPCWSTR event, + LPCWSTR argument, msi_dialog* dialog) +{ + int i = 0; + UINT rc = ERROR_SUCCESS; + + TRACE("Handling Control Event %s\n",debugstr_w(event)); + if (!event) + return rc; + + while( Events[i].event != NULL) + { + LPWSTR wevent = strdupAtoW(Events[i].event); + if (lstrcmpW(wevent,event)==0) + { + HeapFree(GetProcessHeap(),0,wevent); + rc = Events[i].handler(package,argument,dialog); + return rc; + } + HeapFree(GetProcessHeap(),0,wevent); + i++; + } + FIXME("unhandled control event %s arg(%s)\n", + debugstr_w(event), debugstr_w(argument)); + return rc; +} diff --git a/reactos/lib/msi/files.c b/reactos/lib/msi/files.c new file mode 100644 index 00000000000..a4fd40e493d --- /dev/null +++ b/reactos/lib/msi/files.c @@ -0,0 +1,759 @@ +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* + * Actions dealing with files These are + * + * InstallFiles + * DuplicateFiles + * MoveFiles (TODO) + * PatchFiles (TODO) + * RemoveDuplicateFiles(TODO) + * RemoveFiles(TODO) + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "fdi.h" +#include "msidefs.h" +#include "msvcrt/fcntl.h" +#include "msipriv.h" +#include "winuser.h" +#include "wine/unicode.h" +#include "action.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +extern const WCHAR szInstallFiles[]; +extern const WCHAR szDuplicateFiles[]; +extern const WCHAR szMoveFiles[]; +extern const WCHAR szPatchFiles[]; +extern const WCHAR szRemoveDuplicateFiles[]; +extern const WCHAR szRemoveFiles[]; + +static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0}; + +inline static UINT create_component_directory ( MSIPACKAGE* package, INT component) +{ + UINT rc = ERROR_SUCCESS; + MSIFOLDER *folder; + LPWSTR install_path; + + install_path = resolve_folder(package, package->components[component].Directory, + FALSE, FALSE, &folder); + if (!install_path) + return ERROR_FUNCTION_FAILED; + + /* create the path */ + if (folder->State == 0) + { + create_full_pathW(install_path); + folder->State = 2; + } + HeapFree(GetProcessHeap(), 0, install_path); + + return rc; +} + +/* + * This is a helper function for handling embedded cabinet media + */ +static UINT writeout_cabinet_stream(MSIPACKAGE *package, LPCWSTR stream_name, + WCHAR* source) +{ + UINT rc; + USHORT* data; + UINT size; + DWORD write; + HANDLE the_file; + WCHAR tmp[MAX_PATH]; + + rc = read_raw_stream_data(package->db,stream_name,&data,&size); + if (rc != ERROR_SUCCESS) + return rc; + + write = MAX_PATH; + if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write)) + GetTempPathW(MAX_PATH,tmp); + + GetTempFileNameW(tmp,stream_name,0,source); + + track_tempfile(package,strrchrW(source,'\\'), source); + the_file = CreateFileW(source, 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(source)); + rc = ERROR_FUNCTION_FAILED; + goto end; + } + + WriteFile(the_file,data,size,&write,NULL); + CloseHandle(the_file); + TRACE("wrote %li bytes to %s\n",write,debugstr_w(source)); +end: + HeapFree(GetProcessHeap(),0,data); + return rc; +} + + +/* Support functions for FDI functions */ +typedef struct +{ + MSIPACKAGE* package; + LPCSTR cab_path; +} CabData; + +static void * cabinet_alloc(ULONG cb) +{ + return HeapAlloc(GetProcessHeap(), 0, cb); +} + +static void cabinet_free(void *pv) +{ + HeapFree(GetProcessHeap(), 0, pv); +} + +static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode) +{ + DWORD dwAccess = 0; + DWORD dwShareMode = 0; + DWORD dwCreateDisposition = OPEN_EXISTING; + switch (oflag & _O_ACCMODE) + { + case _O_RDONLY: + dwAccess = GENERIC_READ; + dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE; + break; + case _O_WRONLY: + dwAccess = GENERIC_WRITE; + dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + break; + case _O_RDWR: + dwAccess = GENERIC_READ | GENERIC_WRITE; + dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + break; + } + if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL)) + dwCreateDisposition = CREATE_NEW; + else if (oflag & _O_CREAT) + dwCreateDisposition = CREATE_ALWAYS; + return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL, + dwCreateDisposition, 0, NULL); +} + +static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb) +{ + DWORD dwRead; + if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL)) + return dwRead; + return 0; +} + +static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb) +{ + DWORD dwWritten; + if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL)) + return dwWritten; + return 0; +} + +static int cabinet_close(INT_PTR hf) +{ + return CloseHandle((HANDLE)hf) ? 0 : -1; +} + +static long cabinet_seek(INT_PTR hf, long dist, int seektype) +{ + /* flags are compatible and so are passed straight through */ + return SetFilePointer((HANDLE)hf, dist, NULL, seektype); +} + +static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) +{ + switch (fdint) + { + case fdintCOPY_FILE: + { + CabData *data = (CabData*) pfdin->pv; + ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1); + char *file; + + LPWSTR trackname; + LPWSTR trackpath; + LPWSTR tracknametmp; + static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0}; + LPWSTR given_file; + INT index; + + MSIRECORD * uirow; + LPWSTR uipath; + + given_file = strdupAtoW(pfdin->psz1); + index = get_loaded_file(data->package, given_file); + + if (index < 0) + { + ERR("Unknown File in Cabinent (%s)\n",debugstr_w(given_file)); + HeapFree(GetProcessHeap(),0,given_file); + return 0; + } + + if (!((data->package->files[index].State == 1 || + data->package->files[index].State == 2))) + { + TRACE("Skipping extraction of %s\n",debugstr_w(given_file)); + HeapFree(GetProcessHeap(),0,given_file); + return 0; + } + + file = cabinet_alloc((len+1)*sizeof(char)); + strcpy(file, data->cab_path); + strcat(file, pfdin->psz1); + + TRACE("file: %s\n", debugstr_a(file)); + + /* track this file so it can be deleted if not installed */ + trackpath=strdupAtoW(file); + tracknametmp=strdupAtoW(strrchr(file,'\\')+1); + trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) + + strlenW(tmpprefix)+1) * sizeof(WCHAR)); + + strcpyW(trackname,tmpprefix); + strcatW(trackname,tracknametmp); + + track_tempfile(data->package, trackname, trackpath); + + HeapFree(GetProcessHeap(),0,trackpath); + HeapFree(GetProcessHeap(),0,trackname); + HeapFree(GetProcessHeap(),0,tracknametmp); + + /* the UI chunk */ + uirow=MSI_CreateRecord(9); + MSI_RecordSetStringW(uirow,1,data->package->files[index].File); + uipath = strdupW(data->package->files[index].TargetPath); + *(strrchrW(uipath,'\\')+1)=0; + MSI_RecordSetStringW(uirow,9,uipath); + MSI_RecordSetInteger(uirow,6,data->package->files[index].FileSize); + ui_actiondata(data->package,szInstallFiles,uirow); + msiobj_release( &uirow->hdr ); + HeapFree(GetProcessHeap(),0,uipath); + + ui_progress(data->package,2,data->package->files[index].FileSize,0,0); + + return cabinet_open(file, _O_WRONLY | _O_CREAT, 0); + } + case fdintCLOSE_FILE_INFO: + { + FILETIME ft; + FILETIME ftLocal; + if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft)) + return -1; + if (!LocalFileTimeToFileTime(&ft, &ftLocal)) + return -1; + if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal)) + return -1; + + cabinet_close(pfdin->hf); + return 1; + } + default: + return 0; + } +} + +/*********************************************************************** + * extract_cabinet_file + * + * Extract files from a cab file. + */ +static BOOL extract_cabinet_file(MSIPACKAGE* package, LPCWSTR source, + LPCWSTR path) +{ + HFDI hfdi; + ERF erf; + BOOL ret; + char *cabinet; + char *cab_path; + CabData data; + + TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path)); + + hfdi = FDICreate(cabinet_alloc, + cabinet_free, + cabinet_open, + cabinet_read, + cabinet_write, + cabinet_close, + cabinet_seek, + 0, + &erf); + if (!hfdi) + { + ERR("FDICreate failed\n"); + return FALSE; + } + + if (!(cabinet = strdupWtoA( source ))) + { + FDIDestroy(hfdi); + return FALSE; + } + if (!(cab_path = strdupWtoA( path ))) + { + FDIDestroy(hfdi); + HeapFree(GetProcessHeap(), 0, cabinet); + return FALSE; + } + + data.package = package; + data.cab_path = cab_path; + + ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data); + + if (!ret) + ERR("FDICopy failed\n"); + + FDIDestroy(hfdi); + + HeapFree(GetProcessHeap(), 0, cabinet); + HeapFree(GetProcessHeap(), 0, cab_path); + + return ret; +} + +static VOID set_file_source(MSIPACKAGE* package, MSIFILE* file, MSICOMPONENT* + comp, LPCWSTR path) +{ + if (file->Attributes & msidbFileAttributesNoncompressed) + { + LPWSTR p; + p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL); + file->SourcePath = build_directory_name(2, p, file->ShortName); + HeapFree(GetProcessHeap(),0,p); + } + else + file->SourcePath = build_directory_name(2, path, file->File); +} + +static UINT ready_media_for_file(MSIPACKAGE *package, int fileindex, + MSICOMPONENT* comp) +{ + UINT rc = ERROR_SUCCESS; + MSIRECORD * row = 0; + static WCHAR source[MAX_PATH]; + static const WCHAR ExecSeqQuery[] = + {'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',' ', + '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0}; + LPCWSTR cab; + DWORD sz; + INT seq; + static UINT last_sequence = 0; + static LPWSTR last_path = NULL; + MSIFILE* file = NULL; + + /* cleanup signal */ + if (!package) + { + HeapFree(GetProcessHeap(),0,last_path); + return ERROR_SUCCESS; + } + + file = &package->files[fileindex]; + + if (file->Sequence <= last_sequence) + { + set_file_source(package,file,comp,last_path); + TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence); + return ERROR_SUCCESS; + } + + row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence); + if (!row) + { + TRACE("Unable to query row\n"); + return ERROR_FUNCTION_FAILED; + } + + seq = MSI_RecordGetInteger(row,2); + last_sequence = seq; + + HeapFree(GetProcessHeap(),0,last_path); + last_path = NULL; + + if (file->Attributes & msidbFileAttributesNoncompressed) + { + last_path = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL); + set_file_source(package,file,comp,last_path); + msiobj_release(&row->hdr); + return rc; + } + + cab = MSI_RecordGetString(row,4); + if (cab) + { + TRACE("Source is CAB %s\n",debugstr_w(cab)); + /* the stream does not contain the # character */ + if (cab[0]=='#') + { + writeout_cabinet_stream(package,&cab[1],source); + last_path = strdupW(source); + *(strrchrW(last_path,'\\')+1)=0; + } + else + { + sz = MAX_PATH; + last_path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR)); + if (MSI_GetPropertyW(package, cszSourceDir, source, &sz)) + { + ERR("No Source dir defined \n"); + rc = ERROR_FUNCTION_FAILED; + } + else + { + strcpyW(last_path,source); + strcatW(source,cab); + /* extract the cab file into a folder in the temp folder */ + sz = MAX_PATH; + if (MSI_GetPropertyW(package, cszTempFolder,last_path, &sz) + != ERROR_SUCCESS) + GetTempPathW(MAX_PATH,last_path); + } + } + rc = !extract_cabinet_file(package, source, last_path); + /* reaquire file ptr */ + file = &package->files[fileindex]; + } + else + { + sz = MAX_PATH; + last_path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR)); + MSI_GetPropertyW(package,cszSourceDir,source,&sz); + strcpyW(last_path,source); + } + set_file_source(package, file, comp, last_path); + msiobj_release(&row->hdr); + + return rc; +} + +inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, + LPWSTR* file_source) +{ + DWORD index; + + if (!package) + return ERROR_INVALID_HANDLE; + + for (index = 0; index < package->loaded_files; index ++) + { + if (strcmpW(file_key,package->files[index].File)==0) + { + if (package->files[index].State >= 2) + { + *file_source = strdupW(package->files[index].TargetPath); + return ERROR_SUCCESS; + } + else + return ERROR_FILE_NOT_FOUND; + } + } + + return ERROR_FUNCTION_FAILED; +} + +/* + * In order to make this work more effeciencly I am going to do this in 2 + * passes. + * Pass 1) Correct all the TargetPaths and determin what files are to be + * installed. + * Pass 2) Extract Cabinents and copy files. + */ +UINT ACTION_InstallFiles(MSIPACKAGE *package) +{ + UINT rc = ERROR_SUCCESS; + DWORD index; + + if (!package) + return ERROR_INVALID_HANDLE; + + /* increment progress bar each time action data is sent */ + ui_progress(package,1,1,0,0); + + /* Pass 1 */ + for (index = 0; index < package->loaded_files; index++) + { + MSIFILE *file; + MSICOMPONENT* comp = NULL; + + file = &package->files[index]; + + if (file->Temporary) + continue; + + if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex, + INSTALLSTATE_LOCAL)) + { + ui_progress(package,2,file->FileSize,0,0); + TRACE("File %s is not scheduled for install\n", + debugstr_w(file->File)); + + file->State = 5; + continue; + } + + if ((file->State == 1) || (file->State == 2)) + { + LPWSTR p = NULL; + + TRACE("Pass 1: %s\n",debugstr_w(file->File)); + + create_component_directory( package, file->ComponentIndex); + + /* recalculate file paths because things may have changed */ + + if (file->ComponentIndex >= 0) + comp = &package->components[file->ComponentIndex]; + else + { + ERR("No Component for file\n"); + continue; + } + + p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL); + HeapFree(GetProcessHeap(),0,file->TargetPath); + + file->TargetPath = build_directory_name(2, p, file->FileName); + HeapFree(GetProcessHeap(),0,p); + } + } + + /* Pass 2 */ + for (index = 0; index < package->loaded_files; index++) + { + MSIFILE *file; + MSICOMPONENT* comp = NULL; + + file = &package->files[index]; + + if (file->Temporary) + continue; + + if ((file->State == 1) || (file->State == 2)) + { + TRACE("Pass 2: %s\n",debugstr_w(file->File)); + + if (file->ComponentIndex >= 0) + comp = &package->components[file->ComponentIndex]; + + rc = ready_media_for_file(package, index, comp); + if (rc != ERROR_SUCCESS) + { + ERR("Unable to ready media\n"); + rc = ERROR_FUNCTION_FAILED; + break; + } + + /* + * WARNING! + * our file table could change here because a new temp file + * may have been created. So reaquire our ptr. + */ + file = &package->files[index]; + + TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath), + debugstr_w(file->TargetPath)); + + if (file->Attributes & msidbFileAttributesNoncompressed) + rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE); + else + rc = MoveFileW(file->SourcePath, file->TargetPath); + + if (!rc) + { + rc = GetLastError(); + ERR("Unable to move/copy file (%s -> %s) (error %d)\n", + debugstr_w(file->SourcePath), debugstr_w(file->TargetPath), + rc); + if (rc == ERROR_ALREADY_EXISTS && file->State == 2) + { + if (!CopyFileW(file->SourcePath,file->TargetPath,FALSE)) + ERR("Unable to copy file (%s -> %s) (error %ld)\n", + debugstr_w(file->SourcePath), + debugstr_w(file->TargetPath), GetLastError()); + if (!(file->Attributes & msidbFileAttributesNoncompressed)) + DeleteFileW(file->SourcePath); + rc = 0; + } + else if (rc == ERROR_FILE_NOT_FOUND) + { + ERR("Source File Not Found! Continuing\n"); + rc = 0; + } + else if (file->Attributes & msidbFileAttributesVital) + { + ERR("Ignoring Error and continuing (nonvital file)...\n"); + rc = 0; + } + } + else + { + file->State = 4; + rc = ERROR_SUCCESS; + } + } + } + + /* cleanup */ + ready_media_for_file(NULL, 0, NULL); + return rc; +} + +static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE *package = (MSIPACKAGE*)param; + WCHAR *file_source = NULL; + WCHAR dest_name[0x100]; + LPWSTR dest_path, dest; + LPCWSTR file_key, component; + INT component_index; + DWORD sz; + DWORD rc; + + component = MSI_RecordGetString(row,2); + component_index = get_loaded_component(package,component); + + if (!ACTION_VerifyComponentForAction(package, component_index, + INSTALLSTATE_LOCAL)) + { + TRACE("Skipping copy due to disabled component %s\n", + debugstr_w(component)); + + /* the action taken was the same as the current install state */ + package->components[component_index].Action = + package->components[component_index].Installed; + + return ERROR_SUCCESS; + } + + package->components[component_index].Action = INSTALLSTATE_LOCAL; + + file_key = MSI_RecordGetString(row,3); + if (!file_key) + { + ERR("Unable to get file key\n"); + return ERROR_FUNCTION_FAILED; + } + + rc = get_file_target(package,file_key,&file_source); + + if (rc != ERROR_SUCCESS) + { + ERR("Original file unknown %s\n",debugstr_w(file_key)); + HeapFree(GetProcessHeap(),0,file_source); + return ERROR_SUCCESS; + } + + if (MSI_RecordIsNull(row,4)) + strcpyW(dest_name,strrchrW(file_source,'\\')+1); + else + { + sz=0x100; + MSI_RecordGetStringW(row,4,dest_name,&sz); + reduce_to_longfilename(dest_name); + } + + if (MSI_RecordIsNull(row,5)) + { + LPWSTR p; + dest_path = strdupW(file_source); + p = strrchrW(dest_path,'\\'); + if (p) + *p=0; + } + else + { + LPCWSTR destkey; + destkey = MSI_RecordGetString(row,5); + dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL); + if (!dest_path) + { + /* try a Property */ + dest_path = load_dynamic_property(package, destkey, NULL); + if (!dest_path) + { + FIXME("Unable to get destination folder, try AppSearch properties\n"); + HeapFree(GetProcessHeap(),0,file_source); + return ERROR_SUCCESS; + } + } + } + + dest = build_directory_name(2, dest_path, dest_name); + + TRACE("Duplicating file %s to %s\n",debugstr_w(file_source), + debugstr_w(dest)); + + if (strcmpW(file_source,dest)) + rc = !CopyFileW(file_source,dest,TRUE); + else + rc = ERROR_SUCCESS; + + if (rc != ERROR_SUCCESS) + ERR("Failed to copy file %s -> %s, last error %ld\n", debugstr_w(file_source), debugstr_w(dest_path), GetLastError()); + + FIXME("We should track these duplicate files as well\n"); + + HeapFree(GetProcessHeap(),0,dest_path); + HeapFree(GetProcessHeap(),0,dest); + HeapFree(GetProcessHeap(),0,file_source); + + return ERROR_SUCCESS; +} + +UINT ACTION_DuplicateFiles(MSIPACKAGE *package) +{ + UINT rc; + MSIQUERY * view; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0}; + + if (!package) + return ERROR_INVALID_HANDLE; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + rc = MSI_IterateRecords(view, NULL, ITERATE_DuplicateFiles, package); + msiobj_release(&view->hdr); + + return rc; +} diff --git a/reactos/lib/msi/format.c b/reactos/lib/msi/format.c index d85fd27c58b..4bd8f98a9e8 100644 --- a/reactos/lib/msi/format.c +++ b/reactos/lib/msi/format.c @@ -31,26 +31,22 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msifo #include "windef.h" #include "winbase.h" #include "winerror.h" -#include "winreg.h" #include "wine/debug.h" -#include "fdi.h" #include "msi.h" -#include "msiquery.h" -#include "fcntl.h" -#include "objbase.h" -#include "objidl.h" #include "msipriv.h" #include "winnls.h" -#include "winuser.h" -#include "shlobj.h" #include "wine/unicode.h" -#include "winver.h" #include "action.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); -LPWSTR build_default_format(MSIRECORD* record) +static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, + WCHAR** data, DWORD len, MSIRECORD* record, + BOOL* in_group); + + +static LPWSTR build_default_format(MSIRECORD* record) { int i; int count; @@ -101,7 +97,8 @@ static LPWSTR deformat_component(MSIPACKAGE* package, LPCWSTR key, DWORD* sz) return value; } -static LPWSTR deformat_file(MSIPACKAGE* package, LPCWSTR key, DWORD* sz) +static LPWSTR deformat_file(MSIPACKAGE* package, LPCWSTR key, DWORD* sz, + BOOL shortname) { LPWSTR value = NULL; INT index; @@ -114,8 +111,32 @@ static LPWSTR deformat_file(MSIPACKAGE* package, LPCWSTR key, DWORD* sz) index = get_loaded_file(package,key); if (index >=0) { - value = strdupW(package->files[index].TargetPath); - *sz = (strlenW(value)) * sizeof(WCHAR); + if (!shortname) + { + value = strdupW(package->files[index].TargetPath); + *sz = (strlenW(value)) * sizeof(WCHAR); + } + else + { + DWORD size = 0; + size = GetShortPathNameW(package->files[index].TargetPath, NULL, 0); + + if (size > 0) + { + *sz = (size-1) * sizeof (WCHAR); + size ++; + value = HeapAlloc(GetProcessHeap(),0,size * sizeof(WCHAR)); + GetShortPathNameW(package->files[index].TargetPath, value, + size); + } + else + { + ERR("Unable to get ShortPath size (%s)\n", + debugstr_w(package->files[index].TargetPath)); + value = NULL; + *sz = 0; + } + } } return value; @@ -214,6 +235,45 @@ static LPWSTR deformat_property(MSIPACKAGE* package, LPCWSTR key, DWORD* chunk) return value; } +/* + * Groups cannot be nested. They are just treated as from { to next } + */ +static BOOL find_next_group(LPCWSTR source, DWORD len_remaining, + LPWSTR *group, LPCWSTR *mark, + LPCWSTR* mark2) +{ + int i; + BOOL found = FALSE; + + *mark = scanW(source,'{',len_remaining); + if (!*mark) + return FALSE; + + for (i = 1; (*mark - source) + i < len_remaining; i++) + { + if ((*mark)[i] == '}') + { + found = TRUE; + break; + } + } + if (! found) + return FALSE; + + *mark2 = &(*mark)[i]; + + i = *mark2 - *mark; + *group = HeapAlloc(GetProcessHeap(),0,i*sizeof(WCHAR)); + + i -= 1; + memcpy(*group,&(*mark)[1],i*sizeof(WCHAR)); + (*group)[i] = 0; + + TRACE("Found group %s\n",debugstr_w(*group)); + return TRUE; +} + + static BOOL find_next_outermost_key(LPCWSTR source, DWORD len_remaining, LPWSTR *key, LPCWSTR *mark, LPCWSTR* mark2, BOOL *nested) @@ -259,13 +319,71 @@ static BOOL find_next_outermost_key(LPCWSTR source, DWORD len_remaining, return TRUE; } +static LPWSTR deformat_group(MSIPACKAGE* package, LPWSTR group, DWORD len, + MSIRECORD* record, DWORD* size) +{ + LPWSTR value; + LPCWSTR mark, mark2; + LPWSTR key; + BOOL nested; + INT failcount; + static const WCHAR fmt[] = {'{','%','s','}',0}; + UINT sz; + + if (!group || group[0] == 0) + { + *size = 0; + return NULL; + } + /* if no [] then group is returned as is */ + + if (!find_next_outermost_key(group, len, &key, &mark, &mark2, &nested)) + { + *size = (len+2)*sizeof(WCHAR); + value = HeapAlloc(GetProcessHeap(),0,*size); + sprintfW(value,fmt,group); + /* do not return size of the null at the end */ + *size = (len+1)*sizeof(WCHAR); + return value; + } + + HeapFree(GetProcessHeap(),0,key); + failcount = 0; + sz = deformat_string_internal(package, group, &value, strlenW(group), + record, &failcount); + if (failcount==0) + { + *size = sz * sizeof(WCHAR); + return value; + } + else if (failcount < 0) + { + LPWSTR v2; + + v2 = HeapAlloc(GetProcessHeap(),0,(sz+2)*sizeof(WCHAR)); + v2[0] = '{'; + memcpy(&v2[1],value,sz*sizeof(WCHAR)); + v2[sz+1]='}'; + HeapFree(GetProcessHeap(),0,value); + + *size = (sz+2)*sizeof(WCHAR); + return v2; + } + else + { + *size = 0; + return NULL; + } +} + /* * len is in WCHARs * return is also in WCHARs */ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, - WCHAR** data, DWORD len, MSIRECORD* record) + WCHAR** data, DWORD len, MSIRECORD* record, + INT* failcount) { LPCWSTR mark = NULL; LPCWSTR mark2 = NULL; @@ -285,15 +403,16 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, return 0; } - TRACE("Starting with %s\n",debugstr_w(ptr)); + TRACE("Starting with %s\n",debugstr_wn(ptr,len)); /* scan for special characters... fast exit */ - if (!scanW(ptr,'[',len) || (scanW(ptr,'[',len) && !scanW(ptr,']',len))) + if ((!scanW(ptr,'[',len) || (scanW(ptr,'[',len) && !scanW(ptr,']',len))) && + (scanW(ptr,'{',len) && !scanW(ptr,'}',len))) { /* not formatted */ *data = HeapAlloc(GetProcessHeap(),0,(len*sizeof(WCHAR))); memcpy(*data,ptr,len*sizeof(WCHAR)); - TRACE("Returning %s\n",debugstr_w(*data)); + TRACE("Returning %s\n",debugstr_wn(*data,len)); return len; } @@ -301,14 +420,23 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, while (progress - ptr < len) { + /* seek out first group if existing */ + if (find_next_group(progress, len - (progress - ptr), &key, + &mark, &mark2)) + { + value = deformat_group(package, key, strlenW(key)+1, record, + &chunk); + key = NULL; + nested = FALSE; + } /* formatted string located */ - if (!find_next_outermost_key(progress, len - (progress - ptr), &key, - &mark, &mark2, &nested)) + else if (!find_next_outermost_key(progress, len - (progress - ptr), + &key, &mark, &mark2, &nested)) { LPBYTE nd2; - TRACE("after value %s .. %s\n",debugstr_w((LPWSTR)newdata), - debugstr_w(mark)); + TRACE("after value %s \n",debugstr_wn((LPWSTR)newdata, + size/sizeof(WCHAR))); chunk = (len - (progress - ptr)) * sizeof(WCHAR); TRACE("after chunk is %li + %li\n",size,chunk); if (size) @@ -343,33 +471,43 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, { TRACE("Nested key... %s\n",debugstr_w(key)); deformat_string_internal(package, key, &value, strlenW(key)+1, - record); + record, failcount); HeapFree(GetProcessHeap(),0,key); key = value; } - TRACE("Current %s .. %s\n",debugstr_w((LPWSTR)newdata),debugstr_w(key)); + TRACE("Current %s .. %s\n",debugstr_wn((LPWSTR)newdata, + size/sizeof(WCHAR)),debugstr_w(key)); if (!package) { /* only deformat number indexs */ - if (is_key_number(key)) + if (key && is_key_number(key)) + { value = deformat_index(record,key,&chunk); + if (!chunk && failcount && *failcount >= 0) + (*failcount)++; + } else { - DWORD keylen = strlenW(key); - chunk = (keylen + 2)*sizeof(WCHAR); - value = HeapAlloc(GetProcessHeap(),0,chunk); - value[0] = '['; - memcpy(&value[1],key,keylen*sizeof(WCHAR)); - value[1+keylen] = ']'; + if (failcount) + *failcount = -1; + if(key) + { + DWORD keylen = strlenW(key); + chunk = (keylen + 2)*sizeof(WCHAR); + value = HeapAlloc(GetProcessHeap(),0,chunk); + value[0] = '['; + memcpy(&value[1],key,keylen*sizeof(WCHAR)); + value[1+keylen] = ']'; + } } } else { sz = 0; - switch (key[0]) + if (key) switch (key[0]) { case '~': value = deformat_NULL(&chunk); @@ -378,8 +516,10 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, value = deformat_component(package,&key[1],&chunk); break; case '#': + value = deformat_file(package,&key[1], &chunk, FALSE); + break; case '!': /* should be short path */ - value = deformat_file(package,&key[1], &chunk); + value = deformat_file(package,&key[1], &chunk, TRUE); break; case '\\': value = deformat_escape(&key[1],&chunk); @@ -388,8 +528,17 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, value = deformat_environment(package,&key[1],&chunk); break; default: + /* index keys cannot be nested */ if (is_key_number(key)) - value = deformat_index(record,key,&chunk); + if (!nested) + value = deformat_index(record,key,&chunk); + else + { + static const WCHAR fmt[] = {'[','%','s',']',0}; + value = HeapAlloc(GetProcessHeap(),0,10); + sprintfW(value,fmt,key); + chunk = strlenW(value)*sizeof(WCHAR); + } else value = deformat_property(package,key,&chunk); break; @@ -412,11 +561,14 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, size+=chunk; HeapFree(GetProcessHeap(),0,value); } + else if (failcount && *failcount >=0 ) + (*failcount)++; progress = mark2+1; } - TRACE("after everything %s\n",debugstr_w((LPWSTR)newdata)); + TRACE("after everything %s\n",debugstr_wn((LPWSTR)newdata, + size/sizeof(WCHAR))); *data = (LPWSTR)newdata; return size / sizeof(WCHAR); @@ -440,7 +592,7 @@ UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer, TRACE("(%s)\n",debugstr_w(rec)); len = deformat_string_internal(package,rec,&deformated,strlenW(rec), - record); + record, NULL); if (buffer) { @@ -487,7 +639,7 @@ UINT MSI_FormatRecordA( MSIPACKAGE* package, MSIRECORD* record, LPSTR buffer, TRACE("(%s)\n",debugstr_w(rec)); len = deformat_string_internal(package,rec,&deformated,strlenW(rec), - record); + record, NULL); lenA = WideCharToMultiByte(CP_ACP,0,deformated,len,NULL,0,NULL,NULL); if (buffer) diff --git a/reactos/lib/msi/helpers.c b/reactos/lib/msi/helpers.c new file mode 100644 index 00000000000..e9e12f12214 --- /dev/null +++ b/reactos/lib/msi/helpers.c @@ -0,0 +1,913 @@ +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Here are helper functions formally in action.c that are used by a variaty of + * actions and functions. + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "msipriv.h" +#include "winuser.h" +#include "wine/unicode.h" +#include "action.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0}; +static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0}; + +const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0}; +const WCHAR szProductCode[]= {'P','r','o','d','u','c','t','C','o','d','e',0}; +const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0}; +const WCHAR cszbs[]={'\\',0}; + +DWORD build_version_dword(LPCWSTR version_string) +{ + SHORT major,minor; + WORD build; + DWORD rc = 0x00000000; + LPCWSTR ptr1; + + ptr1 = version_string; + + if (!ptr1) + return rc; + else + major = atoiW(ptr1); + + + if(ptr1) + ptr1 = strchrW(ptr1,'.'); + if (ptr1) + { + ptr1++; + minor = atoiW(ptr1); + } + else + minor = 0; + + if (ptr1) + ptr1 = strchrW(ptr1,'.'); + + if (ptr1) + { + ptr1++; + build = atoiW(ptr1); + } + else + build = 0; + + rc = MAKELONG(build,MAKEWORD(minor,major)); + TRACE("%s -> 0x%lx\n",debugstr_w(version_string),rc); + return rc; +} + +UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, + LPWSTR *FilePath) +{ + LPWSTR ProductCode; + LPWSTR SystemFolder; + LPWSTR dest; + UINT rc; + + static const WCHAR szInstaller[] = + {'M','i','c','r','o','s','o','f','t','\\', + 'I','n','s','t','a','l','l','e','r','\\',0}; + static const WCHAR szFolder[] = + {'A','p','p','D','a','t','a','F','o','l','d','e','r',0}; + + ProductCode = load_dynamic_property(package,szProductCode,&rc); + if (!ProductCode) + return rc; + + SystemFolder = load_dynamic_property(package,szFolder,NULL); + + dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode); + + create_full_pathW(dest); + + *FilePath = build_directory_name(2, dest, icon_name); + + HeapFree(GetProcessHeap(),0,SystemFolder); + HeapFree(GetProcessHeap(),0,ProductCode); + HeapFree(GetProcessHeap(),0,dest); + return ERROR_SUCCESS; +} + +WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index) +{ + UINT rc; + DWORD sz; + LPWSTR ret; + + sz = 0; + if (MSI_RecordIsNull(row,index)) + return NULL; + + rc = MSI_RecordGetStringW(row,index,NULL,&sz); + + /* having an empty string is different than NULL */ + if (sz == 0) + { + ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)); + ret[0] = 0; + return ret; + } + + sz ++; + ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR)); + rc = MSI_RecordGetStringW(row,index,ret,&sz); + if (rc!=ERROR_SUCCESS) + { + ERR("Unable to load dynamic string\n"); + HeapFree(GetProcessHeap(), 0, ret); + ret = NULL; + } + return ret; +} + +LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc) +{ + DWORD sz = 0; + LPWSTR str; + UINT r; + + r = MSI_GetPropertyW(package, prop, NULL, &sz); + if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA) + { + if (rc) + *rc = r; + return NULL; + } + sz++; + str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR)); + r = MSI_GetPropertyW(package, prop, str, &sz); + if (r != ERROR_SUCCESS) + { + HeapFree(GetProcessHeap(),0,str); + str = NULL; + } + if (rc) + *rc = r; + return str; +} + +int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component ) +{ + int rc = -1; + DWORD i; + + for (i = 0; i < package->loaded_components; i++) + { + if (strcmpW(Component,package->components[i].Component)==0) + { + rc = i; + break; + } + } + return rc; +} + +int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature ) +{ + int rc = -1; + DWORD i; + + for (i = 0; i < package->loaded_features; i++) + { + if (strcmpW(Feature,package->features[i].Feature)==0) + { + rc = i; + break; + } + } + return rc; +} + +int get_loaded_file(MSIPACKAGE* package, LPCWSTR file) +{ + int rc = -1; + DWORD i; + + for (i = 0; i < package->loaded_files; i++) + { + if (strcmpW(file,package->files[i].File)==0) + { + rc = i; + break; + } + } + return rc; +} + +int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path) +{ + DWORD i; + DWORD index; + + if (!package) + return -2; + + for (i=0; i < package->loaded_files; i++) + if (strcmpW(package->files[i].File,name)==0) + return -1; + + index = package->loaded_files; + package->loaded_files++; + if (package->loaded_files== 1) + package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE)); + else + package->files = HeapReAlloc(GetProcessHeap(),0, + package->files , package->loaded_files * sizeof(MSIFILE)); + + memset(&package->files[index],0,sizeof(MSIFILE)); + + package->files[index].File = strdupW(name); + package->files[index].TargetPath = strdupW(path); + package->files[index].Temporary = TRUE; + + TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File)); + + return 0; +} + +LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, + BOOL set_prop, MSIFOLDER **folder) +{ + DWORD i; + LPWSTR p, path = NULL; + + TRACE("Working to resolve %s\n",debugstr_w(name)); + + if (!name) + return NULL; + + /* special resolving for Target and Source root dir */ + if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0) + { + if (!source) + { + LPWSTR check_path; + check_path = load_dynamic_property(package,cszTargetDir,NULL); + if (!check_path) + { + check_path = load_dynamic_property(package,cszRootDrive,NULL); + if (set_prop) + MSI_SetPropertyW(package,cszTargetDir,check_path); + } + + /* correct misbuilt target dir */ + path = build_directory_name(2, check_path, NULL); + if (strcmpiW(path,check_path)!=0) + MSI_SetPropertyW(package,cszTargetDir,path); + + if (folder) + { + for (i = 0; i < package->loaded_folders; i++) + { + if (strcmpW(package->folders[i].Directory,name)==0) + break; + } + *folder = &(package->folders[i]); + } + return path; + } + else + { + path = load_dynamic_property(package,cszSourceDir,NULL); + if (!path) + { + path = load_dynamic_property(package,cszDatabase,NULL); + if (path) + { + p = strrchrW(path,'\\'); + if (p) + *(p+1) = 0; + } + } + if (folder) + { + for (i = 0; i < package->loaded_folders; i++) + { + if (strcmpW(package->folders[i].Directory,name)==0) + break; + } + *folder = &(package->folders[i]); + } + return path; + } + } + + for (i = 0; i < package->loaded_folders; i++) + { + if (strcmpW(package->folders[i].Directory,name)==0) + break; + } + + if (i >= package->loaded_folders) + return NULL; + + if (folder) + *folder = &(package->folders[i]); + + if (!source && package->folders[i].ResolvedTarget) + { + path = strdupW(package->folders[i].ResolvedTarget); + TRACE(" already resolved to %s\n",debugstr_w(path)); + return path; + } + else if (source && package->folders[i].ResolvedSource) + { + path = strdupW(package->folders[i].ResolvedSource); + TRACE(" (source)already resolved to %s\n",debugstr_w(path)); + return path; + } + else if (!source && package->folders[i].Property) + { + path = build_directory_name(2, package->folders[i].Property, NULL); + + TRACE(" internally set to %s\n",debugstr_w(path)); + if (set_prop) + MSI_SetPropertyW(package,name,path); + return path; + } + + if (package->folders[i].ParentIndex >= 0) + { + LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory; + + TRACE(" ! Parent is %s\n", debugstr_w(parent)); + + p = resolve_folder(package, parent, source, set_prop, NULL); + if (!source) + { + TRACE(" TargetDefault = %s\n", + debugstr_w(package->folders[i].TargetDefault)); + + path = build_directory_name(3, p, + package->folders[i].TargetDefault, NULL); + package->folders[i].ResolvedTarget = strdupW(path); + TRACE(" resolved into %s\n",debugstr_w(path)); + if (set_prop) + MSI_SetPropertyW(package,name,path); + } + else + { + if (package->folders[i].SourceDefault && + package->folders[i].SourceDefault[0]!='.') + path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL); + else + path = strdupW(p); + TRACE(" (source)resolved into %s\n",debugstr_w(path)); + package->folders[i].ResolvedSource = strdupW(path); + } + HeapFree(GetProcessHeap(),0,p); + } + return path; +} + +/* wrapper to resist a need for a full rewrite right now */ +DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data ) +{ + if (ptr) + { + MSIRECORD *rec = MSI_CreateRecord(1); + DWORD size = 0; + + MSI_RecordSetStringW(rec,0,ptr); + MSI_FormatRecordW(package,rec,NULL,&size); + if (size >= 0) + { + size++; + *data = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR)); + if (size > 1) + MSI_FormatRecordW(package,rec,*data,&size); + else + *data[0] = 0; + msiobj_release( &rec->hdr ); + return sizeof(WCHAR)*size; + } + msiobj_release( &rec->hdr ); + } + + *data = NULL; + return 0; +} + +UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action) +{ + UINT count; + LPWSTR *newbuf = NULL; + if (script >= TOTAL_SCRIPTS) + { + FIXME("Unknown script requested %i\n",script); + return ERROR_FUNCTION_FAILED; + } + TRACE("Scheduling Action %s in script %i\n",debugstr_w(action), script); + + count = package->script->ActionCount[script]; + package->script->ActionCount[script]++; + if (count != 0) + newbuf = HeapReAlloc(GetProcessHeap(),0, + package->script->Actions[script], + package->script->ActionCount[script]* sizeof(LPWSTR)); + else + newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR)); + + newbuf[count] = strdupW(action); + package->script->Actions[script] = newbuf; + + return ERROR_SUCCESS; +} + +static void remove_tracked_tempfiles(MSIPACKAGE* package) +{ + DWORD i; + + if (!package) + return; + + for (i = 0; i < package->loaded_files; i++) + { + if (package->files[i].Temporary) + { + TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath)); + DeleteFileW(package->files[i].TargetPath); + } + + } +} + +/* Called when the package is being closed */ +void ACTION_free_package_structures( MSIPACKAGE* package) +{ + INT i; + + TRACE("Freeing package action data\n"); + + remove_tracked_tempfiles(package); + + /* No dynamic buffers in features */ + if (package->features && package->loaded_features > 0) + HeapFree(GetProcessHeap(),0,package->features); + + for (i = 0; i < package->loaded_folders; i++) + { + HeapFree(GetProcessHeap(),0,package->folders[i].Directory); + HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault); + HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault); + HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget); + HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource); + HeapFree(GetProcessHeap(),0,package->folders[i].Property); + } + if (package->folders && package->loaded_folders > 0) + HeapFree(GetProcessHeap(),0,package->folders); + + for (i = 0; i < package->loaded_components; i++) + HeapFree(GetProcessHeap(),0,package->components[i].FullKeypath); + + if (package->components && package->loaded_components > 0) + HeapFree(GetProcessHeap(),0,package->components); + + for (i = 0; i < package->loaded_files; i++) + { + HeapFree(GetProcessHeap(),0,package->files[i].File); + HeapFree(GetProcessHeap(),0,package->files[i].FileName); + HeapFree(GetProcessHeap(),0,package->files[i].ShortName); + HeapFree(GetProcessHeap(),0,package->files[i].Version); + HeapFree(GetProcessHeap(),0,package->files[i].Language); + HeapFree(GetProcessHeap(),0,package->files[i].SourcePath); + HeapFree(GetProcessHeap(),0,package->files[i].TargetPath); + } + + if (package->files && package->loaded_files > 0) + HeapFree(GetProcessHeap(),0,package->files); + + /* clean up extension, progid, class and verb structures */ + for (i = 0; i < package->loaded_classes; i++) + { + HeapFree(GetProcessHeap(),0,package->classes[i].Description); + HeapFree(GetProcessHeap(),0,package->classes[i].FileTypeMask); + HeapFree(GetProcessHeap(),0,package->classes[i].IconPath); + HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler); + HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler32); + HeapFree(GetProcessHeap(),0,package->classes[i].Argument); + HeapFree(GetProcessHeap(),0,package->classes[i].ProgIDText); + } + + if (package->classes && package->loaded_classes > 0) + HeapFree(GetProcessHeap(),0,package->classes); + + for (i = 0; i < package->loaded_extensions; i++) + { + HeapFree(GetProcessHeap(),0,package->extensions[i].ProgIDText); + } + + if (package->extensions && package->loaded_extensions > 0) + HeapFree(GetProcessHeap(),0,package->extensions); + + for (i = 0; i < package->loaded_progids; i++) + { + HeapFree(GetProcessHeap(),0,package->progids[i].ProgID); + HeapFree(GetProcessHeap(),0,package->progids[i].Description); + HeapFree(GetProcessHeap(),0,package->progids[i].IconPath); + } + + if (package->progids && package->loaded_progids > 0) + HeapFree(GetProcessHeap(),0,package->progids); + + for (i = 0; i < package->loaded_verbs; i++) + { + HeapFree(GetProcessHeap(),0,package->verbs[i].Verb); + HeapFree(GetProcessHeap(),0,package->verbs[i].Command); + HeapFree(GetProcessHeap(),0,package->verbs[i].Argument); + } + + if (package->verbs && package->loaded_verbs > 0) + HeapFree(GetProcessHeap(),0,package->verbs); + + for (i = 0; i < package->loaded_mimes; i++) + HeapFree(GetProcessHeap(),0,package->mimes[i].ContentType); + + if (package->mimes && package->loaded_mimes > 0) + HeapFree(GetProcessHeap(),0,package->mimes); + + for (i = 0; i < package->loaded_appids; i++) + { + HeapFree(GetProcessHeap(),0,package->appids[i].RemoteServerName); + HeapFree(GetProcessHeap(),0,package->appids[i].LocalServer); + HeapFree(GetProcessHeap(),0,package->appids[i].ServiceParameters); + HeapFree(GetProcessHeap(),0,package->appids[i].DllSurrogate); + } + + if (package->appids && package->loaded_appids > 0) + HeapFree(GetProcessHeap(),0,package->appids); + + if (package->script) + { + for (i = 0; i < TOTAL_SCRIPTS; i++) + { + int j; + for (j = 0; j < package->script->ActionCount[i]; j++) + HeapFree(GetProcessHeap(),0,package->script->Actions[i][j]); + + HeapFree(GetProcessHeap(),0,package->script->Actions[i]); + } + HeapFree(GetProcessHeap(),0,package->script); + } + + HeapFree(GetProcessHeap(),0,package->PackagePath); + + /* cleanup control event subscriptions */ + ControlEvent_CleanupSubscriptions(package); +} + +/* + * 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 \ + * + */ +LPWSTR build_directory_name(DWORD count, ...) +{ + DWORD sz = 1, i; + LPWSTR dir; + va_list va; + + va_start(va,count); + for(i=0; ihdr); + + msi_dialog_check_messages(NULL); +} + +void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record) +{ + 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}; + WCHAR message[1024]; + MSIRECORD * row = 0; + DWORD size; + static const WCHAR szActionData[] = + {'A','c','t','i','o','n','D','a','t','a',0}; + + if (!package->LastAction || strcmpW(package->LastAction,action)) + { + row = MSI_QueryGetRecord(package->db, Query_t, action); + if (!row) + return; + + if (MSI_RecordIsNull(row,3)) + { + msiobj_release(&row->hdr); + return; + } + + /* update the cached actionformat */ + HeapFree(GetProcessHeap(),0,package->ActionFormat); + package->ActionFormat = load_dynamic_stringW(row,3); + + HeapFree(GetProcessHeap(),0,package->LastAction); + package->LastAction = strdupW(action); + + msiobj_release(&row->hdr); + } + + MSI_RecordSetStringW(record,0,package->ActionFormat); + size = 1024; + MSI_FormatRecordW(package,record,message,&size); + + row = MSI_CreateRecord(1); + MSI_RecordSetStringW(row,1,message); + + MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row); + + ControlEvent_FireSubscribedEvent(package,szActionData, row); + + msiobj_release(&row->hdr); +} + +BOOL ACTION_VerifyComponentForAction(MSIPACKAGE* package, INT index, + INSTALLSTATE check ) +{ + if (package->components[index].Installed == check) + return FALSE; + + if (package->components[index].ActionRequest == check) + return TRUE; + else + return FALSE; +} + +BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE* package, INT index, + INSTALLSTATE check ) +{ + if (package->features[index].Installed == check) + return FALSE; + + if (package->features[index].ActionRequest == check) + return TRUE; + else + return FALSE; +} + +void reduce_to_longfilename(WCHAR* filename) +{ + LPWSTR p = strchrW(filename,'|'); + if (p) + memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR)); +} + +void reduce_to_shortfilename(WCHAR* filename) +{ + LPWSTR p = strchrW(filename,'|'); + if (p) + *p = 0; +} + +LPWSTR create_component_advertise_string(MSIPACKAGE* package, + MSICOMPONENT* component, LPCWSTR feature) +{ + LPWSTR productid=NULL; + GUID clsid; + WCHAR productid_85[21]; + WCHAR component_85[21]; + /* + * I have a fair bit of confusion as to when a < is used and when a > is + * used. I do not think i have it right... + * + * Ok it appears that the > is used if there is a guid for the compoenent + * and the < is used if not. + */ + static WCHAR fmt1[] = {'%','s','%','s','<',0,0}; + static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0}; + LPWSTR output = NULL; + DWORD sz = 0; + + memset(productid_85,0,sizeof(productid_85)); + memset(component_85,0,sizeof(component_85)); + + productid = load_dynamic_property(package,szProductCode,NULL); + CLSIDFromString(productid, &clsid); + + encode_base85_guid(&clsid,productid_85); + + CLSIDFromString(component->ComponentId, &clsid); + encode_base85_guid(&clsid,component_85); + + TRACE("Doing something with this... %s %s %s\n", + debugstr_w(productid_85), debugstr_w(feature), + debugstr_w(component_85)); + + sz = lstrlenW(productid_85) + lstrlenW(feature); + if (component) + sz += lstrlenW(component_85); + + sz+=3; + sz *= sizeof(WCHAR); + + output = HeapAlloc(GetProcessHeap(),0,sz); + memset(output,0,sz); + + if (component) + sprintfW(output,fmt2,productid_85,feature,component_85); + else + sprintfW(output,fmt1,productid_85,feature); + + HeapFree(GetProcessHeap(),0,productid); + + return output; +} + +/* update compoennt state based on a feature change */ +void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature) +{ + int i; + INSTALLSTATE newstate; + MSIFEATURE *feature; + + i = get_loaded_feature(package,szFeature); + if (i < 0) + return; + + feature = &package->features[i]; + newstate = feature->ActionRequest; + + for( i = 0; i < feature->ComponentCount; i++) + { + MSICOMPONENT* component = &package->components[feature->Components[i]]; + + TRACE("MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)\n", + newstate, debugstr_w(component->Component), component->Installed, + component->Action, component->ActionRequest); + + if (!component->Enabled) + continue; + else + { + if (newstate == INSTALLSTATE_LOCAL) + { + component->ActionRequest = INSTALLSTATE_LOCAL; + component->Action = INSTALLSTATE_LOCAL; + } + else + { + int j,k; + + component->ActionRequest = newstate; + component->Action = newstate; + + /*if any other feature wants is local we need to set it local*/ + for (j = 0; + j < package->loaded_features && + component->ActionRequest != INSTALLSTATE_LOCAL; + j++) + { + for (k = 0; k < package->features[j].ComponentCount; k++) + if ( package->features[j].Components[k] == + feature->Components[i] ) + { + if (package->features[j].ActionRequest == + INSTALLSTATE_LOCAL) + { + TRACE("Saved by %s\n", debugstr_w(package->features[j].Feature)); + component->ActionRequest = INSTALLSTATE_LOCAL; + component->Action = INSTALLSTATE_LOCAL; + } + break; + } + } + } + } + TRACE("Result (%i): Component %s (Installed %i, Action %i, Request %i)\n", + newstate, debugstr_w(component->Component), component->Installed, + component->Action, component->ActionRequest); + } +} diff --git a/reactos/lib/msi/insert.c b/reactos/lib/msi/insert.c index 1ec84bf3523..c3932907a15 100644 --- a/reactos/lib/msi/insert.c +++ b/reactos/lib/msi/insert.c @@ -44,7 +44,7 @@ typedef struct tagMSIINSERTVIEW MSIDATABASE *db; BOOL bIsTemp; MSIVIEW *sv; - value_list *vals; + column_info *vals; } MSIINSERTVIEW; static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) @@ -62,7 +62,7 @@ static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT * Merge a value_list and a record to create a second record. * Replace wildcard entries in the valuelist with values from the record */ -static MSIRECORD *INSERT_merge_record( UINT fields, value_list *vl, MSIRECORD *rec ) +static MSIRECORD *INSERT_merge_record( UINT fields, column_info *vl, MSIRECORD *rec ) { MSIRECORD *merged; DWORD wildcard_count = 1, i; @@ -255,7 +255,7 @@ MSIVIEWOPS insert_ops = }; UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, - string_list *columns, value_list *values, BOOL temp ) + column_info *columns, column_info *values, BOOL temp ) { MSIINSERTVIEW *iv = NULL; UINT r; diff --git a/reactos/lib/msi/install.c b/reactos/lib/msi/install.c new file mode 100644 index 00000000000..9b9ea41dcf7 --- /dev/null +++ b/reactos/lib/msi/install.c @@ -0,0 +1,587 @@ +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Msi top level apis directly related to installs */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "msi.h" +#include "msidefs.h" +#include "msipriv.h" +#include "winuser.h" +#include "wine/unicode.h" +#include "action.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +/*********************************************************************** + * MsiDoActionA (MSI.@) + */ +UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction ) +{ + LPWSTR szwAction; + UINT rc; + + TRACE(" exteral attempt at action %s\n",szAction); + + if (!szAction) + return ERROR_FUNCTION_FAILED; + if (hInstall == 0) + return ERROR_FUNCTION_FAILED; + + szwAction = strdupAtoW(szAction); + + if (!szwAction) + return ERROR_FUNCTION_FAILED; + + + rc = MsiDoActionW(hInstall, szwAction); + HeapFree(GetProcessHeap(),0,szwAction); + return rc; +} + +/*********************************************************************** + * MsiDoActionW (MSI.@) + */ +UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction ) +{ + MSIPACKAGE *package; + UINT ret = ERROR_INVALID_HANDLE; + + TRACE(" external attempt at action %s \n",debugstr_w(szAction)); + + package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); + if( package ) + { + ret = ACTION_PerformUIAction(package,szAction); + msiobj_release( &package->hdr ); + } + return ret; +} + +/*********************************************************************** + * MsiGetTargetPathA (MSI.@) + */ +UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder, + LPSTR szPathBuf, DWORD* pcchPathBuf) +{ + LPWSTR szwFolder; + LPWSTR szwPathBuf; + UINT rc; + + TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf); + + if (!szFolder) + return ERROR_FUNCTION_FAILED; + if (hInstall == 0) + return ERROR_FUNCTION_FAILED; + + szwFolder = strdupAtoW(szFolder); + + if (!szwFolder) + return ERROR_FUNCTION_FAILED; + + szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR)); + + rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf); + + WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf, + *pcchPathBuf, NULL, NULL ); + + HeapFree(GetProcessHeap(),0,szwFolder); + HeapFree(GetProcessHeap(),0,szwPathBuf); + + return rc; +} + +/*********************************************************************** +* MsiGetTargetPathW (MSI.@) +*/ +UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR + szPathBuf, DWORD* pcchPathBuf) +{ + LPWSTR path; + UINT rc = ERROR_FUNCTION_FAILED; + MSIPACKAGE *package; + + TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf); + + package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); + if (!package) + return ERROR_INVALID_HANDLE; + path = resolve_folder(package, szFolder, FALSE, FALSE, NULL); + msiobj_release( &package->hdr ); + + if (path && (strlenW(path) > *pcchPathBuf)) + { + *pcchPathBuf = strlenW(path)+1; + rc = ERROR_MORE_DATA; + } + else if (path) + { + *pcchPathBuf = strlenW(path)+1; + strcpyW(szPathBuf,path); + TRACE("Returning Path %s\n",debugstr_w(path)); + rc = ERROR_SUCCESS; + } + HeapFree(GetProcessHeap(),0,path); + + return rc; +} + + +/*********************************************************************** +* MsiGetSourcePathA (MSI.@) +*/ +UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder, + LPSTR szPathBuf, DWORD* pcchPathBuf) +{ + LPWSTR szwFolder; + LPWSTR szwPathBuf; + UINT rc; + + TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf); + + if (!szFolder) + return ERROR_FUNCTION_FAILED; + if (hInstall == 0) + return ERROR_FUNCTION_FAILED; + + szwFolder = strdupAtoW(szFolder); + if (!szwFolder) + return ERROR_FUNCTION_FAILED; + + szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR)); + + rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf); + + WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf, + *pcchPathBuf, NULL, NULL ); + + HeapFree(GetProcessHeap(),0,szwFolder); + HeapFree(GetProcessHeap(),0,szwPathBuf); + + return rc; +} + +/*********************************************************************** +* MsiGetSourcePathW (MSI.@) +*/ +UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR + szPathBuf, DWORD* pcchPathBuf) +{ + LPWSTR path; + UINT rc = ERROR_FUNCTION_FAILED; + MSIPACKAGE *package; + + TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf); + + package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); + if( !package ) + return ERROR_INVALID_HANDLE; + path = resolve_folder(package, szFolder, TRUE, FALSE, NULL); + msiobj_release( &package->hdr ); + + if (path && strlenW(path) > *pcchPathBuf) + { + *pcchPathBuf = strlenW(path)+1; + rc = ERROR_MORE_DATA; + } + else if (path) + { + *pcchPathBuf = strlenW(path)+1; + strcpyW(szPathBuf,path); + TRACE("Returning Path %s\n",debugstr_w(path)); + rc = ERROR_SUCCESS; + } + HeapFree(GetProcessHeap(),0,path); + + return rc; +} + + +/*********************************************************************** + * MsiSetTargetPathA (MSI.@) + */ +UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder, + LPCSTR szFolderPath) +{ + LPWSTR szwFolder; + LPWSTR szwFolderPath; + UINT rc; + + if (!szFolder) + return ERROR_FUNCTION_FAILED; + if (hInstall == 0) + return ERROR_FUNCTION_FAILED; + + szwFolder = strdupAtoW(szFolder); + if (!szwFolder) + return ERROR_FUNCTION_FAILED; + + szwFolderPath = strdupAtoW(szFolderPath); + if (!szwFolderPath) + { + HeapFree(GetProcessHeap(),0,szwFolder); + return ERROR_FUNCTION_FAILED; + } + + rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath); + + HeapFree(GetProcessHeap(),0,szwFolder); + HeapFree(GetProcessHeap(),0,szwFolderPath); + + return rc; +} + +/* + * Ok my original interpretation of this was wrong. And it looks like msdn has + * changed a bit also. The given folder path does not have to actually already + * exist, it just cannot be read only and must be a legal folder path. + */ +UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, + LPCWSTR szFolderPath) +{ + DWORD i; + DWORD attrib; + LPWSTR path = NULL; + LPWSTR path2 = NULL; + MSIFOLDER *folder; + + TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath)); + + if (package==NULL) + return ERROR_INVALID_HANDLE; + + if (szFolderPath[0]==0) + return ERROR_FUNCTION_FAILED; + + attrib = GetFileAttributesW(szFolderPath); + if ( attrib != INVALID_FILE_ATTRIBUTES && + (!(attrib & FILE_ATTRIBUTE_DIRECTORY) || + attrib & FILE_ATTRIBUTE_OFFLINE || + attrib & FILE_ATTRIBUTE_READONLY)) + return ERROR_FUNCTION_FAILED; + + path = resolve_folder(package,szFolder,FALSE,FALSE,&folder); + + if (!path) + return ERROR_INVALID_PARAMETER; + + if (attrib == INVALID_FILE_ATTRIBUTES) + { + if (!CreateDirectoryW(szFolderPath,NULL)) + return ERROR_FUNCTION_FAILED; + RemoveDirectoryW(szFolderPath); + } + + HeapFree(GetProcessHeap(),0,folder->Property); + folder->Property = build_directory_name(2, szFolderPath, NULL); + + if (lstrcmpiW(path, folder->Property) == 0) + { + /* + * Resolved Target has not really changed, so just + * set this folder and do not recalculate everything. + */ + HeapFree(GetProcessHeap(),0,folder->ResolvedTarget); + folder->ResolvedTarget = NULL; + path2 = resolve_folder(package,szFolder,FALSE,TRUE,NULL); + HeapFree(GetProcessHeap(),0,path2); + } + else + { + for (i = 0; i < package->loaded_folders; i++) + { + HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget); + package->folders[i].ResolvedTarget=NULL; + } + + for (i = 0; i < package->loaded_folders; i++) + { + path2=resolve_folder(package, package->folders[i].Directory, FALSE, + TRUE, NULL); + HeapFree(GetProcessHeap(),0,path2); + } + } + HeapFree(GetProcessHeap(),0,path); + + 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)); + + package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); + 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) +{ + FIXME("STUB (iRunMode=%i)\n",iRunMode); + return TRUE; +} + +/*********************************************************************** + * 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); + + HeapFree(GetProcessHeap(),0,szwFeature); + + return rc; +} + + + +UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature, + INSTALLSTATE iState) +{ + INT index, i; + UINT rc = ERROR_SUCCESS; + + TRACE(" %s to %i\n",debugstr_w(szFeature), iState); + + index = get_loaded_feature(package,szFeature); + if (index < 0) + return ERROR_UNKNOWN_FEATURE; + + if (iState == INSTALLSTATE_ADVERTISED && + package->features[index].Attributes & + msidbFeatureAttributesDisallowAdvertise) + return ERROR_FUNCTION_FAILED; + + package->features[index].ActionRequest= iState; + package->features[index].Action= iState; + + ACTION_UpdateComponentStates(package,szFeature); + + /* update all the features that are children of this feature */ + for (i = 0; i < package->loaded_features; i++) + { + if (strcmpW(szFeature, package->features[i].Feature_Parent) == 0) + MSI_SetFeatureStateW(package, package->features[i].Feature, iState); + } + + return rc; +} + +/*********************************************************************** + * MsiSetFeatureStateW (MSI.@) + */ +UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature, + INSTALLSTATE iState) +{ + MSIPACKAGE* package; + UINT rc = ERROR_SUCCESS; + + TRACE(" %s to %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; +} + +/*********************************************************************** +* MsiGetFeatureStateA (MSI.@) +*/ +UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature, + INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) +{ + LPWSTR szwFeature = NULL; + UINT rc; + + szwFeature = strdupAtoW(szFeature); + + rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction); + + HeapFree( GetProcessHeap(), 0 , szwFeature); + + return rc; +} + +UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature, + INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) +{ + INT index; + + index = get_loaded_feature(package,szFeature); + if (index < 0) + return ERROR_UNKNOWN_FEATURE; + + if (piInstalled) + *piInstalled = package->features[index].Installed; + + if (piAction) + *piAction = package->features[index].Action; + + TRACE("returning %i %i\n",*piInstalled,*piAction); + + return ERROR_SUCCESS; +} + +/*********************************************************************** +* MsiGetFeatureStateW (MSI.@) +*/ +UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature, + INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) +{ + MSIPACKAGE* package; + UINT ret; + + TRACE("%ld %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; +} + +/*********************************************************************** + * MsiGetComponentStateA (MSI.@) + */ +UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent, + INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) +{ + LPWSTR szwComponent= NULL; + UINT rc; + + szwComponent= strdupAtoW(szComponent); + + rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction); + + HeapFree( GetProcessHeap(), 0 , szwComponent); + + return rc; +} + +UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent, + INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) +{ + INT index; + + TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled, +piAction); + + index = get_loaded_component(package,szComponent); + if (index < 0) + return ERROR_UNKNOWN_COMPONENT; + + if (piInstalled) + *piInstalled = package->components[index].Installed; + + if (piAction) + *piAction = package->components[index].Action; + + TRACE("states (%i, %i)\n", +(piInstalled)?*piInstalled:-1,(piAction)?*piAction:-1); + + return ERROR_SUCCESS; +} + +/*********************************************************************** + * MsiGetComponentStateW (MSI.@) + */ +UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent, + INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) +{ + MSIPACKAGE* package; + UINT ret; + + TRACE("%ld %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; +} diff --git a/reactos/lib/msi/msi.c b/reactos/lib/msi/msi.c index e7d1fa1a094..bec3ccbf05a 100644 --- a/reactos/lib/msi/msi.c +++ b/reactos/lib/msi/msi.c @@ -38,9 +38,6 @@ #include "wine/unicode.h" #include "action.h" -UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf); - - WINE_DEFAULT_DEBUG_CHANNEL(msi); /* @@ -465,6 +462,7 @@ UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, { LPWSTR szwProduct = NULL, szwAttribute = NULL, szwBuffer = NULL; UINT r = ERROR_OUTOFMEMORY; + DWORD pcchwValueBuf = 0; TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute), szBuffer, pcchValueBuf); @@ -486,14 +484,17 @@ UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, if( szBuffer ) { szwBuffer = HeapAlloc( GetProcessHeap(), 0, (*pcchValueBuf) * sizeof(WCHAR) ); + pcchwValueBuf = *pcchValueBuf; if( !szwBuffer ) goto end; } - r = MsiGetProductInfoW( szwProduct, szwAttribute, szwBuffer, pcchValueBuf ); + r = MsiGetProductInfoW( szwProduct, szwAttribute, szwBuffer, + &pcchwValueBuf ); if( ERROR_SUCCESS == r ) - WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, *pcchValueBuf, NULL, NULL); + *pcchValueBuf = WideCharToMultiByte(CP_ACP, 0, szwBuffer, pcchwValueBuf, + szBuffer, *pcchValueBuf, NULL, NULL); end: HeapFree( GetProcessHeap(), 0, szwProduct ); @@ -516,6 +517,10 @@ UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0}; static const WCHAR szAssignmentType[] = {'A','s','s','i','g','n','m','e','n','t','T','y','p','e',0}; + static const WCHAR szLanguage[] = + {'L','a','n','g','u','a','g','e',0}; + static const WCHAR szProductLanguage[] = + {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0}; FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute), szBuffer, pcchValueBuf); @@ -569,11 +574,25 @@ UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, } else if (strcmpW(szAttribute, szAssignmentType)==0) { - FIXME("0 (zero) if advertised, 1(one) if per machine.\n"); + FIXME("0 (zero) if advertised or per user , 1(one) if per machine.\n"); if (szBuffer) - szBuffer[0] = 1; + { + szBuffer[0] = '1'; + szBuffer[1] = 0; + } + if (pcchValueBuf) + *pcchValueBuf = 1; r = ERROR_SUCCESS; } + else if (strcmpW(szAttribute, szLanguage)==0) + { + r = MsiOpenProductW(szProduct, &hProduct); + if (ERROR_SUCCESS != r) + return r; + + r = MsiGetPropertyW(hProduct, szProductLanguage, szBuffer, pcchValueBuf); + MsiCloseHandle(hProduct); + } else { r = MsiOpenProductW(szProduct, &hProduct); @@ -820,7 +839,7 @@ INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf, return INSTALLSTATE_UNKNOWN; } -INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPSTR lpPathBuf, +INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf, DWORD *pcchBuf) { FIXME("%s %p %08lx\n", debugstr_w(szComponent), lpPathBuf, *pcchBuf); @@ -968,11 +987,16 @@ INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent, } if( pcchBuf && *pcchBuf > 0 ) + { lpwPathBuf = HeapAlloc( GetProcessHeap(), 0, *pcchBuf * sizeof(WCHAR)); + incoming_len = *pcchBuf; + } else + { lpwPathBuf = NULL; + incoming_len = 0; + } - incoming_len = *pcchBuf; rc = MsiGetComponentPathW(szwProduct, szwComponent, lpwPathBuf, pcchBuf); HeapFree( GetProcessHeap(), 0, szwProduct); @@ -1195,7 +1219,7 @@ UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0, lpLangBuf, pcchLangBuf?*pcchLangBuf:0); - dwVerLen = GetFileVersionInfoSizeW((LPWSTR)szFilePath, NULL); + dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL); if( !dwVerLen ) return GetLastError(); @@ -1206,14 +1230,14 @@ UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, goto end; } - if( !GetFileVersionInfoW((LPWSTR)szFilePath, 0, dwVerLen, lpVer) ) + if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) ) { ret = GetLastError(); goto end; } if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf ) { - if( VerQueryValueW(lpVer, (LPWSTR)szVersionResource, (LPVOID*)&ffi, &puLen) && + if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) && (puLen > 0) ) { wsprintfW(tmp, szVersionFormat, @@ -1267,7 +1291,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) typedef struct tagIClassFactoryImpl { - IClassFactoryVtbl *lpVtbl; + const IClassFactoryVtbl *lpVtbl; } IClassFactoryImpl; static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface, @@ -1305,7 +1329,7 @@ static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface, BOOL dolock) return S_OK; } -static IClassFactoryVtbl MsiCF_Vtbl = +static const IClassFactoryVtbl MsiCF_Vtbl = { MsiCF_QueryInterface, MsiCF_AddRef, diff --git a/reactos/lib/msi/msi.spec b/reactos/lib/msi/msi.spec index 91464064b0d..ecb7621ff39 100644 --- a/reactos/lib/msi/msi.spec +++ b/reactos/lib/msi/msi.spec @@ -158,8 +158,8 @@ 158 stdcall MsiViewClose(long) 159 stdcall MsiViewExecute(long long) 160 stdcall MsiViewFetch(long ptr) -161 stub MsiViewGetErrorA -162 stub MsiViewGetErrorW +161 stdcall MsiViewGetErrorA(long ptr ptr) +162 stdcall MsiViewGetErrorW(long ptr ptr) 163 stdcall MsiViewModify(long long long) 164 stdcall MsiDatabaseIsTablePersistentA(long str) 165 stdcall MsiDatabaseIsTablePersistentW(long wstr) diff --git a/reactos/lib/msi/msi.xml b/reactos/lib/msi/msi.xml index 221c50fa42a..81bb068d370 100644 --- a/reactos/lib/msi/msi.xml +++ b/reactos/lib/msi/msi.xml @@ -15,6 +15,7 @@ gdi32 advapi32 shell32 + shlwapi winmm cabinet ole32 @@ -22,6 +23,7 @@ version action.c appsearch.c + classes.c cond.tab.c create.c custom.c @@ -29,9 +31,13 @@ delete.c dialog.c distinct.c + events.c + files.c format.c handle.c + helpers.c insert.c + install.c msi.c msiquery.c order.c @@ -47,6 +53,7 @@ table.c tokenize.c update.c + upgrade.c where.c msi.spec msi.rc diff --git a/reactos/lib/msi/msipriv.h b/reactos/lib/msi/msipriv.h index 8aa931a198b..dde612992fe 100644 --- a/reactos/lib/msi/msipriv.h +++ b/reactos/lib/msi/msipriv.h @@ -29,7 +29,7 @@ #include "msiquery.h" #include "objbase.h" #include "objidl.h" -#include "wine/unicode.h" +#include "winnls.h" #include "wine/list.h" #define MSI_DATASIZEMASK 0x00ff @@ -66,7 +66,7 @@ typedef struct tagMSIDATABASE MSIOBJECTHDR hdr; IStorage *storage; string_table *strings; - LPWSTR mode; + LPCWSTR mode; MSITABLE *first_table, *last_table; } MSIDATABASE; @@ -197,11 +197,20 @@ typedef struct tagMSIPACKAGE LPWSTR ActionFormat; LPWSTR LastAction; - LPWSTR *DeferredAction; - UINT DeferredActionCount; - - LPWSTR *CommitAction; - UINT CommitActionCount; + struct tagMSICLASS *classes; + UINT loaded_classes; + struct tagMSIEXTENSION *extensions; + UINT loaded_extensions; + struct tagMSIPROGID *progids; + UINT loaded_progids; + struct tagMSIVERB *verbs; + UINT loaded_verbs; + struct tagMSIMIME *mimes; + UINT loaded_mimes; + struct tagMSIAPPID *appids; + UINT loaded_appids; + + struct tagMSISCRIPT *script; struct tagMSIRUNNINGACTION *RunningAction; UINT RunningActionCount; @@ -211,8 +220,8 @@ typedef struct tagMSIPACKAGE UINT CurrentInstallState; msi_dialog *dialog; LPWSTR next_dialog; - - BOOL ExecuteSequenceRun; + + struct list subscriptions; } MSIPACKAGE; typedef struct tagMSIPREVIEW @@ -309,12 +318,17 @@ extern const WCHAR *MSI_RecordGetString( MSIRECORD *, unsigned int ); extern MSIRECORD *MSI_CreateRecord( unsigned int ); extern UINT MSI_RecordSetInteger( MSIRECORD *, unsigned int, int ); extern UINT MSI_RecordSetStringW( MSIRECORD *, unsigned int, LPCWSTR ); +extern UINT MSI_RecordSetStringA( MSIRECORD *, unsigned int, LPCSTR ); extern BOOL MSI_RecordIsNull( MSIRECORD *, unsigned int ); extern UINT MSI_RecordGetStringW( MSIRECORD * , unsigned int, LPWSTR, DWORD *); extern UINT MSI_RecordGetStringA( MSIRECORD *, unsigned int, LPSTR, DWORD *); extern int MSI_RecordGetInteger( MSIRECORD *, unsigned int ); extern UINT MSI_RecordReadStream( MSIRECORD *, unsigned int, char *, DWORD *); extern unsigned int MSI_RecordGetFieldCount( MSIRECORD *rec ); +extern UINT MSI_RecordSetStreamW( MSIRECORD *, unsigned int, LPCWSTR ); +extern UINT MSI_RecordSetStreamA( MSIRECORD *, unsigned int, LPCSTR ); +extern UINT MSI_RecordDataSize( MSIRECORD *, unsigned int ); +extern UINT MSI_RecordStreamToFile( MSIRECORD *, unsigned int, LPCWSTR ); /* stream internals */ extern UINT get_raw_stream( MSIHANDLE hdb, LPCWSTR stname, IStream **stm ); @@ -325,8 +339,12 @@ extern void enum_stream_names( IStorage *stg ); extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** ); extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** ); extern UINT MSI_OpenQuery( MSIDATABASE *, MSIQUERY **, LPCWSTR, ... ); -typedef UINT (*record_func)( MSIRECORD *rec, LPVOID param ); +typedef UINT (*record_func)( MSIRECORD *, LPVOID ); extern UINT MSI_IterateRecords( MSIQUERY *, DWORD *, record_func, LPVOID ); +extern MSIRECORD *MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR query, ... ); +extern UINT MSI_DatabaseImport( MSIDATABASE *, LPCWSTR, LPCWSTR ); +extern UINT MSI_DatabaseExport( MSIDATABASE *, LPCWSTR, LPCWSTR, LPCWSTR ); +extern UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *, LPCWSTR, MSIRECORD ** ); /* view internals */ extern UINT MSI_ViewExecute( MSIQUERY*, MSIRECORD * ); @@ -340,6 +358,7 @@ extern UINT MSI_SetTargetPathW( MSIPACKAGE *, LPCWSTR, LPCWSTR ); extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR ); extern INT MSI_ProcessMessage( MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD * ); extern UINT MSI_GetPropertyW( MSIPACKAGE *, LPCWSTR, LPWSTR, DWORD * ); +extern UINT MSI_GetPropertyA(MSIPACKAGE *, LPCSTR, LPSTR, DWORD* ); extern MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *, LPCWSTR ); extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR ); extern UINT MSI_GetComponentStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE * ); @@ -347,8 +366,8 @@ extern UINT MSI_GetFeatureStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLS extern UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE*, LPCWSTR, INSTALLSTATE ); /* for deformating */ -extern UINT MSI_FormatRecordW(MSIPACKAGE* package, MSIRECORD* record, - LPWSTR buffer, DWORD *size); +extern UINT MSI_FormatRecordW( MSIPACKAGE *, MSIRECORD *, LPWSTR, DWORD * ); +extern UINT MSI_FormatRecordA( MSIPACKAGE *, MSIRECORD *, LPSTR, DWORD * ); /* registry data encoding/decoding functions */ extern BOOL unsquash_guid(LPCWSTR in, LPWSTR out); @@ -364,10 +383,12 @@ extern UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL cr extern UINT MSIREG_OpenComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create); extern UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create); extern UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create); +extern UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create); extern UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create); +extern UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create); /* msi dialog interface */ -typedef VOID (*msi_dialog_event_handler)( MSIPACKAGE*, LPCWSTR, LPCWSTR, msi_dialog* ); +typedef UINT (*msi_dialog_event_handler)( MSIPACKAGE*, LPCWSTR, LPCWSTR, msi_dialog* ); extern msi_dialog *msi_dialog_create( MSIPACKAGE*, LPCWSTR, msi_dialog_event_handler ); extern UINT msi_dialog_run_message_loop( msi_dialog* ); extern void msi_dialog_end_dialog( msi_dialog* ); @@ -376,6 +397,23 @@ extern void msi_dialog_do_preview( msi_dialog* ); extern void msi_dialog_destroy( msi_dialog* ); extern BOOL msi_dialog_register_class( void ); extern void msi_dialog_unregister_class( void ); +extern void msi_dialog_handle_event( msi_dialog*, LPCWSTR, LPCWSTR, MSIRECORD * ); + +/* preview */ +extern MSIPREVIEW *MSI_EnableUIPreview( MSIDATABASE * ); +extern UINT MSI_PreviewDialogW( MSIPREVIEW *, LPCWSTR ); + +/* undocumented functions */ +UINT WINAPI MsiCreateAndVerifyInstallerDirectory( DWORD ); +UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR, LPWSTR, LPWSTR, LPWSTR, DWORD * ); +UINT WINAPI MsiDecomposeDescriptorA( LPCSTR, LPSTR, LPSTR, LPSTR, DWORD * ); +LANGID WINAPI MsiLoadStringW( MSIHANDLE, UINT, LPWSTR, int, LANGID ); +LANGID WINAPI MsiLoadStringA( MSIHANDLE, UINT, LPSTR, int, LANGID ); + +HRESULT WINAPI MSI_DllGetClassObject( REFCLSID, REFIID, LPVOID * ); +HRESULT WINAPI MSI_DllRegisterServer( void ); +HRESULT WINAPI MSI_DllUnregisterServer( void ); +BOOL WINAPI MSI_DllCanUnloadNow( void ); /* UI globals */ extern INSTALLUILEVEL gUILevel; @@ -415,8 +453,8 @@ inline static LPWSTR strdupW( LPCWSTR src ) { LPWSTR dest; if (!src) return NULL; - dest = HeapAlloc(GetProcessHeap(), 0, (strlenW(src)+1)*sizeof(WCHAR)); - strcpyW(dest, src); + dest = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(src)+1)*sizeof(WCHAR)); + lstrcpyW(dest, src); return dest; } diff --git a/reactos/lib/msi/msiquery.c b/reactos/lib/msi/msiquery.c index f833847c840..49fd3e9ad4e 100644 --- a/reactos/lib/msi/msiquery.c +++ b/reactos/lib/msi/msiquery.c @@ -38,7 +38,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); -void MSI_CloseView( MSIOBJECTHDR *arg ) +static void MSI_CloseView( MSIOBJECTHDR *arg ) { MSIQUERY *query = (MSIQUERY*) arg; struct list *ptr, *t; @@ -139,7 +139,8 @@ UINT MSI_DatabaseOpenViewW(MSIDATABASE *db, return r; } -UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) +static UINT MSI_OpenQueryV( MSIDATABASE *db, MSIQUERY **view, + LPCWSTR fmt, va_list args ) { LPWSTR szQuery; LPCWSTR p; @@ -147,7 +148,7 @@ UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) va_list va; /* figure out how much space we need to allocate */ - va_start(va, fmt); + va = args; sz = lstrlenW(fmt) + 1; p = fmt; while (*p) @@ -173,13 +174,11 @@ UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) } p++; } - va_end(va); /* construct the string */ szQuery = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR)); - va_start(va, fmt); + va = args; vsnprintfW(szQuery, sz, fmt, va); - va_end(va); /* perform the query */ rc = MSI_DatabaseOpenViewW(db, szQuery, view); @@ -187,6 +186,18 @@ UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) return rc; } +UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) +{ + UINT r; + va_list va; + + va_start(va, fmt); + r = MSI_OpenQueryV( db, view, fmt, va ); + va_end(va); + + return r; +} + UINT MSI_IterateRecords( MSIQUERY *view, DWORD *count, record_func func, LPVOID param ) { @@ -223,6 +234,28 @@ UINT MSI_IterateRecords( MSIQUERY *view, DWORD *count, return r; } +/* return a single record from a query */ +MSIRECORD *MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR fmt, ... ) +{ + MSIRECORD *rec = NULL; + MSIQUERY *view = NULL; + UINT r; + va_list va; + + va_start(va, fmt); + r = MSI_OpenQueryV( db, &view, fmt, va ); + va_end(va); + + if( r == ERROR_SUCCESS ) + { + MSI_ViewExecute( view, NULL ); + MSI_ViewFetch( view, &rec ); + MSI_ViewClose( view ); + msiobj_release( &view->hdr ); + } + return rec; +} + UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb, LPCWSTR szQuery, MSIHANDLE *phView) { @@ -530,6 +563,42 @@ out: return r; } +UINT WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR szColumnNameBuffer, + DWORD *pcchBuf ) +{ + MSIQUERY *query = NULL; + + FIXME("%ld %p %p\n", handle, szColumnNameBuffer, pcchBuf ); + + if( !pcchBuf ) + return MSIDBERROR_INVALIDARG; + + query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW ); + if( !query ) + return MSIDBERROR_INVALIDARG; + + msiobj_release( &query->hdr ); + return MSIDBERROR_NOERROR; +} + +UINT WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR szColumnNameBuffer, + DWORD *pcchBuf ) +{ + MSIQUERY *query = NULL; + + FIXME("%ld %p %p\n", handle, szColumnNameBuffer, pcchBuf ); + + if( !pcchBuf ) + return MSIDBERROR_INVALIDARG; + + query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW ); + if( !query ) + return MSIDBERROR_INVALIDARG; + + msiobj_release( &query->hdr ); + return MSIDBERROR_NOERROR; +} + UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb, LPCSTR szTransformFile, int iErrorCond) { diff --git a/reactos/lib/msi/order.c b/reactos/lib/msi/order.c index 0e3b98fa84e..2a03bab63b8 100644 --- a/reactos/lib/msi/order.c +++ b/reactos/lib/msi/order.c @@ -302,11 +302,11 @@ static UINT ORDER_AddColumn( MSIORDERVIEW *ov, LPCWSTR name ) } UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, - string_list *columns ) + column_info *columns ) { MSIORDERVIEW *ov = NULL; UINT count = 0, r; - string_list *x; + column_info *x; TRACE("%p\n", ov ); @@ -332,7 +332,7 @@ UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, *view = (MSIVIEW*) ov; for( x = columns; x ; x = x->next ) - ORDER_AddColumn( ov, x->string ); + ORDER_AddColumn( ov, x->column ); return ERROR_SUCCESS; } diff --git a/reactos/lib/msi/package.c b/reactos/lib/msi/package.c index 53808ab0679..54a692452eb 100644 --- a/reactos/lib/msi/package.c +++ b/reactos/lib/msi/package.c @@ -49,7 +49,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); */ #define LPCTSTR LPCWSTR -void MSI_FreePackage( MSIOBJECTHDR *arg) +static void MSI_FreePackage( MSIOBJECTHDR *arg) { MSIPACKAGE *package= (MSIPACKAGE*) arg; @@ -389,6 +389,7 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db ) package->LastAction = NULL; package->dialog = NULL; package->next_dialog = NULL; + list_init( &package->subscriptions ); /* OK, here is where we do a slew of things to the database to * prep for all that is to come as a package */ diff --git a/reactos/lib/msi/preview.c b/reactos/lib/msi/preview.c index 540d65174b6..5c596fbc85a 100644 --- a/reactos/lib/msi/preview.c +++ b/reactos/lib/msi/preview.c @@ -82,11 +82,12 @@ UINT WINAPI MsiEnableUIPreview( MSIHANDLE hdb, MSIHANDLE* phPreview ) return r; } -static VOID preview_event_handler( MSIPACKAGE *package, LPCWSTR event, +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; } UINT MSI_PreviewDialogW( MSIPREVIEW *preview, LPCWSTR szDialogName ) diff --git a/reactos/lib/msi/query.h b/reactos/lib/msi/query.h index 28f74b515e4..e1fa104e603 100644 --- a/reactos/lib/msi/query.h +++ b/reactos/lib/msi/query.h @@ -59,11 +59,14 @@ struct sql_str { INT len; }; -typedef struct _string_list +typedef struct _column_info { - LPWSTR string; - struct _string_list *next; -} string_list; + LPCWSTR table; + LPCWSTR column; + UINT type; + struct expr *val; + struct _column_info *next; +} column_info; struct complex_expr { @@ -80,56 +83,36 @@ struct expr struct complex_expr expr; INT ival; UINT uval; - LPWSTR sval; - LPWSTR column; + LPCWSTR sval; + LPCWSTR column; UINT col_number; } u; }; -typedef struct _create_col_info -{ - LPWSTR colname; - UINT type; - struct _create_col_info *next; -} create_col_info; - -typedef struct _value_list -{ - struct expr *val; - struct _value_list *next; -} value_list; - -typedef struct _column_assignment -{ - string_list *col_list; - value_list *val_list; -} column_assignment; - - UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview, struct list *mem ); UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view ); UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, - string_list *columns ); + column_info *columns ); UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table ); UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, - string_list *columns ); + column_info *columns ); UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, struct expr *cond ); UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, - create_col_info *col_info, BOOL temp ); + column_info *col_info, BOOL temp ); UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, - string_list *columns, value_list *values, BOOL temp ); + column_info *columns, column_info *values, BOOL temp ); UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **, LPWSTR table, - column_assignment *list, struct expr *expr ); + column_info *list, struct expr *expr ); UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table ); diff --git a/reactos/lib/msi/record.c b/reactos/lib/msi/record.c index 57a1d71279a..8bdc3c4cf47 100644 --- a/reactos/lib/msi/record.c +++ b/reactos/lib/msi/record.c @@ -34,6 +34,9 @@ #include "winnls.h" #include "ole2.h" +#include "winreg.h" +#include "shlwapi.h" + #include "query.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -44,7 +47,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); #define MSIFIELD_WSTR 3 #define MSIFIELD_STREAM 4 -void MSI_FreeField( MSIFIELD *field ) +static void MSI_FreeField( MSIFIELD *field ) { switch( field->type ) { @@ -62,7 +65,7 @@ void MSI_FreeField( MSIFIELD *field ) } } -void MSI_CloseRecord( MSIOBJECTHDR *arg ) +static void MSI_CloseRecord( MSIOBJECTHDR *arg ) { MSIRECORD *rec = (MSIRECORD *) arg; UINT i; @@ -410,6 +413,17 @@ UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, unsigned int iField, return ret; } +static UINT msi_get_stream_size( IStream *stm ) +{ + STATSTG stat; + HRESULT r; + + r = IStream_Stat( stm, &stat, STATFLAG_NONAME ); + if( FAILED(r) ) + return 0; + return stat.cbSize.QuadPart; +} + UINT MSI_RecordDataSize(MSIRECORD *rec, unsigned int iField) { TRACE("%p %d\n", rec, iField); @@ -425,6 +439,8 @@ UINT MSI_RecordDataSize(MSIRECORD *rec, unsigned int iField) return lstrlenW( rec->fields[iField].u.szwVal ); case MSIFIELD_NULL: break; + case MSIFIELD_STREAM: + return msi_get_stream_size( rec->fields[iField].u.stream ); } return 0; } @@ -533,7 +549,7 @@ UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, unsigned int iField, LPCWSTR } /* read the data in a file into an IStream */ -UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm) +static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm) { DWORD sz, szHighWord = 0, read; HANDLE handle; @@ -761,3 +777,56 @@ UINT MSI_RecordGetIStream( MSIRECORD *rec, unsigned int iField, IStream **pstm) return ERROR_SUCCESS; } + +static UINT msi_dump_stream_to_file( IStream *stm, LPCWSTR name ) +{ + ULARGE_INTEGER size; + LARGE_INTEGER pos; + IStream *out; + DWORD stgm; + HRESULT r; + + stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE; + r = SHCreateStreamOnFileW( name, stgm, &out ); + if( FAILED( r ) ) + return ERROR_FUNCTION_FAILED; + + pos.QuadPart = 0; + r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size ); + if( FAILED( r ) ) + goto end; + + pos.QuadPart = 0; + r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL ); + if( FAILED( r ) ) + goto end; + + r = IStream_CopyTo( stm, out, size, NULL, NULL ); + +end: + IStream_Release( out ); + if( FAILED( r ) ) + return ERROR_FUNCTION_FAILED; + return ERROR_SUCCESS; +} + +UINT MSI_RecordStreamToFile( MSIRECORD *rec, unsigned int iField, LPCWSTR name ) +{ + IStream *stm = NULL; + UINT r; + + TRACE("%p %u %s\n", rec, iField, debugstr_w(name)); + + msiobj_lock( &rec->hdr ); + + r = MSI_RecordGetIStream( rec, iField, &stm ); + if( r == ERROR_SUCCESS ) + { + r = msi_dump_stream_to_file( stm, name ); + IStream_Release( stm ); + } + + msiobj_unlock( &rec->hdr ); + + return r; +} diff --git a/reactos/lib/msi/registry.c b/reactos/lib/msi/registry.c index 15e91090dc5..012986115c2 100644 --- a/reactos/lib/msi/registry.c +++ b/reactos/lib/msi/registry.c @@ -141,6 +141,20 @@ static const WCHAR szInstaller_UpgradeCodes_fmt[] = { 'U','p','g','r','a','d','e','C','o','d','e','s','\\', '%','s',0}; +static const WCHAR szInstaller_UserUpgradeCodes[] = { +'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','\\', +'U','p','g','r','a','d','e','C','o','d','e','s',0}; + +static const WCHAR szInstaller_UserUpgradeCodes_fmt[] = { +'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','\\', +'U','p','g','r','a','d','e','C','o','d','e','s','\\', +'%','s',0}; + + #define SQUISH_GUID_SIZE 33 BOOL unsquash_guid(LPCWSTR in, LPWSTR out) @@ -455,6 +469,27 @@ UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create) return rc; } +UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create) +{ + UINT rc; + WCHAR squished_pc[GUID_SIZE]; + WCHAR keypath[0x200]; + + TRACE("%s\n",debugstr_w(szUpgradeCode)); + squash_guid(szUpgradeCode,squished_pc); + TRACE("squished (%s)\n", debugstr_w(squished_pc)); + + sprintfW(keypath,szInstaller_UserUpgradeCodes_fmt,squished_pc); + + if (create) + rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key); + else + rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key); + + return rc; +} + + /************************************************************************* * MsiDecomposeDescriptorW [MSI.@] * diff --git a/reactos/lib/msi/select.c b/reactos/lib/msi/select.c index 6118966d072..9378676f719 100644 --- a/reactos/lib/msi/select.c +++ b/reactos/lib/msi/select.c @@ -210,7 +210,7 @@ MSIVIEWOPS select_ops = SELECT_delete }; -static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPWSTR name ) +static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name ) { UINT r, n=0; MSIVIEW *table; @@ -245,7 +245,7 @@ static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPWSTR name ) } UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, - string_list *columns ) + column_info *columns ) { MSISELECTVIEW *sv = NULL; UINT count = 0, r; @@ -273,7 +273,7 @@ UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, while( columns ) { - r = SELECT_AddColumn( sv, columns->string ); + r = SELECT_AddColumn( sv, columns->column ); if( r ) break; columns = columns->next; diff --git a/reactos/lib/msi/sql.tab.c b/reactos/lib/msi/sql.tab.c index 6ead0d2e7c0..39dc0f0e955 100644 --- a/reactos/lib/msi/sql.tab.c +++ b/reactos/lib/msi/sql.tab.c @@ -189,7 +189,6 @@ #include "query.h" #include "wine/list.h" #include "wine/debug.h" -#include "wine/unicode.h" #define YYLEX_PARAM info #define YYPARSE_PARAM info @@ -212,12 +211,13 @@ static INT SQL_getint( void *info ); static int SQL_lex( void *SQL_lval, SQL_input *info ); static void *parser_alloc( void *info, unsigned int sz ); +static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column ); -static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys); +static BOOL SQL_MarkPrimaryKeys( column_info *cols, column_info *keys); static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r ); -static struct expr * EXPR_column( void *info, LPWSTR column ); -static struct expr * EXPR_ival( void *info, struct sql_str *, int sign ); +static struct expr * EXPR_column( void *info, column_info *column ); +static struct expr * EXPR_ival( void *info, int val ); static struct expr * EXPR_sval( void *info, struct sql_str * ); static struct expr * EXPR_wildcard( void *info ); @@ -228,13 +228,11 @@ typedef union { struct sql_str str; LPWSTR string; - string_list *column_list; - value_list *val_list; + column_info *column_list; MSIVIEW *query; struct expr *expr; USHORT column_type; - create_col_info *column_info; - column_assignment update_col_info; + int integer; } yystype; # define YYSTYPE yystype # define YYSTYPE_IS_TRIVIAL 1 @@ -245,12 +243,12 @@ typedef union -#define YYFINAL 126 +#define YYFINAL 127 #define YYFLAG -32768 #define YYNTBASE 147 /* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ -#define YYTRANSLATE(x) ((unsigned)(x) <= 400 ? yytranslate[x] : 175) +#define YYTRANSLATE(x) ((unsigned)(x) <= 400 ? yytranslate[x] : 177) /* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ static const short yytranslate[] = @@ -302,38 +300,38 @@ static const short yytranslate[] = static const short yyprhs[] = { 0, 0, 2, 4, 6, 8, 10, 12, 23, 35, - 42, 50, 57, 60, 65, 70, 73, 75, 78, 80, - 84, 86, 91, 93, 95, 97, 99, 101, 103, 108, - 110, 113, 117, 120, 122, 126, 128, 130, 134, 137, - 141, 145, 149, 153, 157, 161, 165, 169, 173, 177, - 181, 186, 188, 190, 192, 196, 198, 202, 206, 208, - 211, 213, 215, 217, 221, 223, 225 + 42, 50, 57, 60, 65, 69, 71, 74, 76, 79, + 81, 85, 87, 92, 94, 96, 98, 100, 102, 104, + 109, 111, 114, 118, 121, 123, 127, 129, 131, 135, + 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, + 178, 182, 187, 189, 191, 193, 197, 199, 203, 207, + 209, 212, 214, 216, 218, 222, 224, 226, 228 }; static const short yyrhs[] = { - 148, 0, 159, 0, 150, 0, 149, 0, 151, 0, - 152, 0, 67, 72, 173, 83, 162, 110, 134, 83, - 167, 110, 0, 67, 72, 173, 83, 162, 110, 134, - 83, 167, 110, 122, 0, 31, 121, 173, 83, 153, - 110, 0, 31, 121, 173, 83, 153, 110, 59, 0, - 130, 173, 114, 168, 137, 165, 0, 35, 163, 0, - 154, 102, 77, 162, 0, 154, 24, 172, 155, 0, - 172, 155, 0, 156, 0, 156, 86, 0, 157, 0, - 157, 90, 92, 0, 19, 0, 19, 83, 158, 110, - 0, 82, 0, 115, 0, 69, 0, 81, 0, 93, - 0, 70, 0, 160, 99, 16, 162, 0, 160, 0, - 112, 161, 0, 112, 38, 161, 0, 162, 163, 0, - 172, 0, 172, 24, 162, 0, 118, 0, 164, 0, - 164, 137, 165, 0, 52, 173, 0, 83, 165, 110, - 0, 171, 45, 171, 0, 165, 7, 165, 0, 165, - 97, 165, 0, 171, 45, 166, 0, 171, 57, 166, - 0, 171, 85, 166, 0, 171, 78, 166, 0, 171, - 54, 166, 0, 171, 89, 166, 0, 171, 73, 92, - 0, 171, 73, 90, 92, 0, 171, 0, 170, 0, - 170, 0, 170, 24, 167, 0, 169, 0, 169, 24, - 168, 0, 172, 45, 170, 0, 70, 0, 88, 70, - 0, 120, 0, 138, 0, 172, 0, 173, 39, 174, - 0, 174, 0, 174, 0, 66, 0 + 148, 0, 160, 0, 150, 0, 149, 0, 151, 0, + 152, 0, 67, 72, 174, 83, 163, 110, 134, 83, + 168, 110, 0, 67, 72, 174, 83, 163, 110, 134, + 83, 168, 110, 122, 0, 31, 121, 174, 83, 153, + 110, 0, 31, 121, 174, 83, 153, 110, 59, 0, + 130, 174, 114, 169, 137, 166, 0, 35, 164, 0, + 154, 102, 77, 163, 0, 154, 24, 155, 0, 155, + 0, 173, 156, 0, 157, 0, 157, 86, 0, 158, + 0, 158, 90, 92, 0, 19, 0, 19, 83, 159, + 110, 0, 82, 0, 115, 0, 69, 0, 81, 0, + 93, 0, 176, 0, 161, 99, 16, 163, 0, 161, + 0, 112, 162, 0, 112, 38, 162, 0, 163, 164, + 0, 173, 0, 173, 24, 163, 0, 118, 0, 165, + 0, 165, 137, 166, 0, 52, 174, 0, 83, 166, + 110, 0, 172, 45, 172, 0, 166, 7, 166, 0, + 166, 97, 166, 0, 172, 45, 167, 0, 172, 57, + 167, 0, 172, 85, 167, 0, 172, 78, 167, 0, + 172, 54, 167, 0, 172, 89, 167, 0, 172, 73, + 92, 0, 172, 73, 90, 92, 0, 172, 0, 171, + 0, 171, 0, 171, 24, 168, 0, 170, 0, 170, + 24, 169, 0, 173, 45, 171, 0, 176, 0, 88, + 176, 0, 120, 0, 138, 0, 173, 0, 174, 39, + 175, 0, 175, 0, 175, 0, 66, 0, 70, 0 }; #endif @@ -342,13 +340,13 @@ static const short yyrhs[] = /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const short yyrline[] = { - 0, 140, 148, 150, 151, 152, 153, 156, 168, 180, - 193, 207, 220, 233, 243, 263, 274, 279, 286, 291, - 297, 302, 306, 310, 314, 318, 322, 328, 339, 352, - 355, 360, 371, 387, 401, 414, 420, 422, 434, 447, - 454, 460, 466, 472, 478, 484, 490, 496, 502, 508, - 514, 522, 524, 527, 539, 552, 554, 562, 578, 585, - 591, 597, 605, 614, 619, 625, 632 + 0, 137, 145, 147, 148, 149, 150, 153, 165, 177, + 190, 204, 217, 230, 240, 251, 257, 265, 270, 277, + 282, 288, 293, 297, 301, 305, 309, 313, 319, 328, + 341, 344, 349, 360, 376, 378, 382, 388, 390, 402, + 415, 422, 428, 434, 440, 446, 452, 458, 464, 470, + 476, 482, 490, 492, 495, 503, 513, 515, 522, 530, + 537, 543, 549, 557, 566, 573, 581, 588, 597 }; #endif @@ -387,10 +385,11 @@ static const char *const yytname[] = "TK_WILDCARD", "END_OF_FILE", "ILLEGAL", "SPACE", "UNCLOSED_STRING", "COMMENT", "FUNCTION", "COLUMN", "AGG_FUNCTION.", "query", "onequery", "oneinsert", "onecreate", "oneupdate", "onedelete", "table_def", - "column_def", "column_type", "data_type_l", "data_type", "data_count", - "oneselect", "unorderedsel", "selectfrom", "selcollist", "from", - "fromtable", "expr", "val", "constlist", "update_assign_list", - "column_assignment", "const_val", "column_val", "column", "table", "id", 0 + "column_def", "column_and_type", "column_type", "data_type_l", + "data_type", "data_count", "oneselect", "unorderedsel", "selectfrom", + "selcollist", "from", "fromtable", "expr", "val", "constlist", + "update_assign_list", "column_assignment", "const_val", "column_val", + "column", "table", "id", "number", 0 }; #endif @@ -398,24 +397,24 @@ static const char *const yytname[] = static const short yyr1[] = { 0, 147, 148, 148, 148, 148, 148, 149, 149, 150, - 150, 151, 152, 153, 154, 154, 155, 155, 156, 156, - 157, 157, 157, 157, 157, 157, 157, 158, 159, 159, - 160, 160, 161, 162, 162, 162, 163, 163, 164, 165, - 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, - 165, 166, 166, 167, 167, 168, 168, 169, 170, 170, - 170, 170, 171, 172, 172, 173, 174 + 150, 151, 152, 153, 154, 154, 155, 156, 156, 157, + 157, 158, 158, 158, 158, 158, 158, 158, 159, 160, + 160, 161, 161, 162, 163, 163, 163, 164, 164, 165, + 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, + 166, 166, 167, 167, 168, 168, 169, 169, 170, 171, + 171, 171, 171, 172, 173, 173, 174, 175, 176 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const short yyr2[] = { 0, 1, 1, 1, 1, 1, 1, 10, 11, 6, - 7, 6, 2, 4, 4, 2, 1, 2, 1, 3, - 1, 4, 1, 1, 1, 1, 1, 1, 4, 1, - 2, 3, 2, 1, 3, 1, 1, 3, 2, 3, + 7, 6, 2, 4, 3, 1, 2, 1, 2, 1, + 3, 1, 4, 1, 1, 1, 1, 1, 1, 4, + 1, 2, 3, 2, 1, 3, 1, 1, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 1, 1, 1, 3, 1, 3, 3, 1, 2, - 1, 1, 1, 3, 1, 1, 1 + 3, 4, 1, 1, 1, 3, 1, 3, 3, 1, + 2, 1, 1, 1, 3, 1, 1, 1, 1 }; /* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE @@ -424,49 +423,49 @@ static const short yyr2[] = static const short yydefact[] = { 0, 0, 0, 0, 0, 0, 1, 4, 3, 5, - 6, 2, 29, 0, 0, 12, 36, 0, 0, 66, - 35, 30, 0, 33, 0, 64, 0, 65, 0, 0, - 38, 0, 0, 31, 32, 0, 0, 0, 0, 0, - 0, 37, 0, 62, 0, 34, 63, 0, 55, 0, - 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, - 0, 20, 24, 25, 22, 26, 23, 15, 16, 18, - 39, 41, 42, 58, 0, 60, 61, 43, 52, 40, - 47, 51, 44, 0, 49, 46, 45, 48, 0, 11, - 56, 57, 10, 0, 0, 0, 17, 0, 59, 50, - 0, 14, 13, 27, 0, 19, 0, 21, 0, 53, - 7, 0, 8, 54, 0, 0, 0 + 6, 2, 30, 0, 0, 12, 37, 0, 0, 67, + 36, 31, 0, 34, 0, 65, 0, 66, 0, 0, + 39, 0, 0, 32, 33, 0, 0, 0, 0, 0, + 0, 38, 0, 63, 0, 35, 64, 0, 56, 0, + 29, 0, 0, 15, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 0, 0, 21, 25, 26, 23, 27, 24, 16, 17, + 19, 40, 42, 43, 68, 0, 61, 62, 44, 53, + 41, 59, 48, 52, 45, 0, 50, 47, 46, 49, + 0, 11, 57, 58, 10, 14, 0, 0, 18, 0, + 60, 51, 0, 13, 0, 28, 20, 0, 22, 0, + 54, 7, 0, 8, 55, 0, 0, 0 }; static const short yydefgoto[] = { - 124, 6, 7, 8, 9, 10, 51, 52, 77, 78, - 79, 114, 11, 12, 21, 22, 15, 16, 41, 87, - 118, 47, 48, 88, 42, 43, 24, 25 + 125, 6, 7, 8, 9, 10, 51, 52, 53, 78, + 79, 80, 114, 11, 12, 21, 22, 15, 16, 41, + 88, 119, 47, 48, 89, 42, 43, 24, 25, 91 }; static const short yypact[] = { - -28, -102, -32, -48, -29, -39,-32768,-32768,-32768,-32768, - -32768,-32768, -61, -39, -39,-32768, -97, -39, -50,-32768, - -32768,-32768, -32, 19, 6, 9, -65,-32768, 34, -30, - -32768, -37, -26,-32768,-32768, -50, -39, -39, -50, -39, - -37, -2, -31,-32768, -50,-32768,-32768, -86, 32, 10, - -32768, -51, -20, -17, -7, -37, -37, -60, -60, -60, - -59, -60, -60, -60, -36, -37, -39, -58, 16, -39, - 2, 0,-32768,-32768,-32768,-32768,-32768,-32768, -5, 1, - -32768, -2, -2,-32768, 15,-32768,-32768,-32768,-32768,-32768, - -32768,-32768,-32768, -4,-32768,-32768,-32768,-32768, -42, -2, - -32768,-32768,-32768, -17, -50, 23,-32768, 5,-32768,-32768, - 11,-32768,-32768,-32768, -11,-32768, -58,-32768, -10, 83, - -9, -58,-32768,-32768, 117, 118,-32768 + -28, -106, -27, -52, -32, -42,-32768,-32768,-32768,-32768, + -32768,-32768, -70, -42, -42,-32768, -97, -42, -48,-32768, + -32768,-32768, -27, 7, 2, 5, -62,-32768, 40, -23, + -32768, -55, -22,-32768,-32768, -48, -42, -42, -48, -42, + -55, -3, 0,-32768, -48,-32768,-32768, -65, 43, 29, + -32768, -34, -19,-32768, -18, -7, -55, -55, -58, -58, + -58, -37, -58, -58, -58, -31, -55, -42, -61, 23, + -42, 10, 8,-32768,-32768,-32768,-32768,-32768,-32768, 6, + 3,-32768, -3, -3,-32768, 18,-32768,-32768,-32768,-32768, + -32768,-32768,-32768,-32768,-32768, 16,-32768,-32768,-32768,-32768, + -33, -3,-32768,-32768,-32768,-32768, -48, 18,-32768, 20, + -32768,-32768, 30,-32768, 4,-32768,-32768, -61,-32768, 11, + 91, -6, -61,-32768,-32768, 117, 118,-32768 }; static const short yypgoto[] = { - -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 17,-32768, - -32768,-32768,-32768,-32768, 101, -27, 99,-32768, 31, 53, - 3, 57,-32768, -49, 47, -3, 56, 8 + -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 49,-32768, + -32768,-32768,-32768,-32768,-32768, 102, -25, 100,-32768, -8, + 36, 1, 57,-32768, -51, 47, -2, 9, 33, -64 }; @@ -475,36 +474,36 @@ static const short yypgoto[] = static const short yytable[] = { - 55, 23, 71, 1, 69, 55, 19, 2, 45, 18, - 83, 50, 83, 27, 57, 23, 19, 64, 101, 13, - 14, 27, 27, 58, 17, 27, 59, 19, 84, 19, - 84, 93, 23, 94, 49, 23, 53, 19, 28, 3, - 31, 23, 60, 35, 46, 36, 40, 61, -65, 37, - 38, 65, 72, 39, 62, 67, 66, 44, 63, 68, - 85, 26, 85, 49, 73, 74, 103, 119, 20, 29, - 30, 54, 119, 32, 98, 102, 75, 112, 86, 104, - 86, 106, 70, 105, 4, 108, 81, 82, 109, 20, - 56, 107, 110, 113, 116, 56, 99, 115, 76, 117, - 120, 23, 5, 80, 89, 91, 91, 121, 91, 91, - 91, 90, 92, 122, 95, 96, 97, 125, 126, 33, - 111, 34, 0, 100, 123 + 56, 72, 23, 1, 56, 70, 18, 2, 19, 84, + 45, 19, 84, 50, 26, 13, 23, 103, 19, 65, + 17, 110, 29, 30, 19, 14, 32, 85, 40, 28, + 85, 35, 55, 23, 19, 49, 23, 54, 27, 3, + 31, 36, 23, 115, -66, 58, 27, 27, 82, 83, + 27, 73, 37, 95, 59, 96, 38, 60, 101, 86, + 39, 44, 86, 74, 75, 49, 120, 67, 54, 46, + 20, 120, 66, 61, 68, 76, 69, 87, 62, 100, + 87, 113, 104, 71, 4, 63, 20, 106, 84, 64, + 57, 107, 108, 109, 57, 92, 94, 77, 97, 98, + 99, 112, 5, 81, 23, 90, 93, 93, 111, 93, + 93, 93, 116, 117, 118, 122, 123, 126, 127, 105, + 33, 121, 34, 124, 102 }; static const short yycheck[] = { - 7, 4, 19, 31, 24, 7, 66, 35, 35, 38, - 70, 38, 70, 5, 45, 18, 66, 44, 67, 121, - 52, 13, 14, 54, 72, 17, 57, 66, 88, 66, - 88, 90, 35, 92, 37, 38, 39, 66, 99, 67, - 137, 44, 73, 24, 36, 39, 83, 78, 39, 114, - 16, 137, 69, 83, 85, 45, 24, 83, 89, 110, - 120, 5, 120, 66, 81, 82, 69, 116, 118, 13, - 14, 40, 121, 17, 110, 59, 93, 104, 138, 77, - 138, 86, 102, 83, 112, 70, 55, 56, 92, 118, - 97, 90, 134, 70, 83, 97, 65, 92, 115, 110, - 110, 104, 130, 110, 57, 58, 59, 24, 61, 62, - 63, 58, 59, 122, 61, 62, 63, 0, 0, 18, - 103, 22, -1, 66, 121 + 7, 19, 4, 31, 7, 24, 38, 35, 66, 70, + 35, 66, 70, 38, 5, 121, 18, 68, 66, 44, + 72, 85, 13, 14, 66, 52, 17, 88, 83, 99, + 88, 24, 40, 35, 66, 37, 38, 39, 5, 67, + 137, 39, 44, 107, 39, 45, 13, 14, 56, 57, + 17, 69, 114, 90, 54, 92, 16, 57, 66, 120, + 83, 83, 120, 81, 82, 67, 117, 24, 70, 36, + 118, 122, 137, 73, 45, 93, 110, 138, 78, 110, + 138, 106, 59, 102, 112, 85, 118, 77, 70, 89, + 97, 83, 86, 90, 97, 59, 60, 115, 62, 63, + 64, 134, 130, 110, 106, 58, 59, 60, 92, 62, + 63, 64, 92, 83, 110, 24, 122, 0, 0, 70, + 18, 110, 22, 122, 67 }; #define YYPURE 1 @@ -1216,79 +1215,79 @@ yyreduce: switch (yyn) { case 1: -#line 142 "./sql.y" +#line 139 "./sql.y" { SQL_input* sql = (SQL_input*) info; *sql->view = yyvsp[0].query; ; break;} case 7: -#line 158 "./sql.y" +#line 155 "./sql.y" { SQL_input *sql = (SQL_input*) info; MSIVIEW *insert = NULL; UINT r; - r = INSERT_CreateView( sql->db, &insert, yyvsp[-7].string, yyvsp[-5].column_list, yyvsp[-1].val_list, FALSE ); + r = INSERT_CreateView( sql->db, &insert, yyvsp[-7].string, yyvsp[-5].column_list, yyvsp[-1].column_list, FALSE ); if( !insert ) YYABORT; yyval.query = insert; ; break;} case 8: -#line 169 "./sql.y" +#line 166 "./sql.y" { SQL_input *sql = (SQL_input*) info; MSIVIEW *insert = NULL; - INSERT_CreateView( sql->db, &insert, yyvsp[-8].string, yyvsp[-6].column_list, yyvsp[-2].val_list, TRUE ); + INSERT_CreateView( sql->db, &insert, yyvsp[-8].string, yyvsp[-6].column_list, yyvsp[-2].column_list, TRUE ); if( !insert ) YYABORT; yyval.query = insert; ; break;} case 9: -#line 182 "./sql.y" +#line 179 "./sql.y" { SQL_input* sql = (SQL_input*) info; MSIVIEW *create = NULL; - if( !yyvsp[-1].column_info ) + if( !yyvsp[-1].column_list ) YYABORT; - CREATE_CreateView( sql->db, &create, yyvsp[-3].string, yyvsp[-1].column_info, FALSE ); + CREATE_CreateView( sql->db, &create, yyvsp[-3].string, yyvsp[-1].column_list, FALSE ); if( !create ) YYABORT; yyval.query = create; ; break;} case 10: -#line 194 "./sql.y" +#line 191 "./sql.y" { SQL_input* sql = (SQL_input*) info; MSIVIEW *create = NULL; - if( !yyvsp[-2].column_info ) + if( !yyvsp[-2].column_list ) YYABORT; - CREATE_CreateView( sql->db, &create, yyvsp[-4].string, yyvsp[-2].column_info, TRUE ); + CREATE_CreateView( sql->db, &create, yyvsp[-4].string, yyvsp[-2].column_list, TRUE ); if( !create ) YYABORT; yyval.query = create; ; break;} case 11: -#line 209 "./sql.y" +#line 206 "./sql.y" { SQL_input* sql = (SQL_input*) info; MSIVIEW *update = NULL; - UPDATE_CreateView( sql->db, &update, yyvsp[-4].string, &yyvsp[-2].update_col_info, yyvsp[0].expr ); + UPDATE_CreateView( sql->db, &update, yyvsp[-4].string, yyvsp[-2].column_list, yyvsp[0].expr ); if( !update ) YYABORT; yyval.query = update; ; break;} case 12: -#line 222 "./sql.y" +#line 219 "./sql.y" { SQL_input* sql = (SQL_input*) info; MSIVIEW *delete = NULL; @@ -1300,125 +1299,116 @@ case 12: ; break;} case 13: -#line 235 "./sql.y" +#line 232 "./sql.y" { - if( SQL_MarkPrimaryKeys( yyvsp[-3].column_info, yyvsp[0].column_list ) ) - yyval.column_info = yyvsp[-3].column_info; + if( SQL_MarkPrimaryKeys( yyvsp[-3].column_list, yyvsp[0].column_list ) ) + yyval.column_list = yyvsp[-3].column_list; else - yyval.column_info = NULL; + yyval.column_list = NULL; ; break;} case 14: -#line 245 "./sql.y" +#line 242 "./sql.y" { - create_col_info *ci; + column_info *ci; - for( ci = yyvsp[-3].column_info; ci->next; ci = ci->next ) + for( ci = yyvsp[-2].column_list; ci->next; ci = ci->next ) ; - ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info ); - if( !ci->next ) - { - /* FIXME: free $1 */ - YYABORT; - } - ci->next->colname = yyvsp[-1].string; - ci->next->type = yyvsp[0].column_type; - ci->next->next = NULL; - - yyval.column_info = yyvsp[-3].column_info; + ci->next = yyvsp[0].column_list; + yyval.column_list = yyvsp[-2].column_list; ; break;} case 15: -#line 264 "./sql.y" +#line 252 "./sql.y" { - yyval.column_info = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info ); - if( ! yyval.column_info ) - YYABORT; - yyval.column_info->colname = yyvsp[-1].string; - yyval.column_info->type = yyvsp[0].column_type; - yyval.column_info->next = NULL; + yyval.column_list = yyvsp[0].column_list; ; break;} case 16: -#line 276 "./sql.y" +#line 259 "./sql.y" +{ + yyval.column_list = yyvsp[-1].column_list; + yyval.column_list->type = yyvsp[0].column_type; + ; + break;} +case 17: +#line 267 "./sql.y" { yyval.column_type = yyvsp[0].column_type | MSITYPE_VALID; ; break;} -case 17: -#line 280 "./sql.y" +case 18: +#line 271 "./sql.y" { FIXME("LOCALIZABLE ignored\n"); yyval.column_type = yyvsp[-1].column_type | MSITYPE_VALID; ; break;} -case 18: -#line 288 "./sql.y" +case 19: +#line 279 "./sql.y" { yyval.column_type |= MSITYPE_NULLABLE; ; break;} -case 19: -#line 292 "./sql.y" +case 20: +#line 283 "./sql.y" { yyval.column_type = yyvsp[-2].column_type; ; break;} -case 20: -#line 299 "./sql.y" +case 21: +#line 290 "./sql.y" { yyval.column_type = MSITYPE_STRING | 1; ; break;} -case 21: -#line 303 "./sql.y" +case 22: +#line 294 "./sql.y" { yyval.column_type = MSITYPE_STRING | 0x400 | yyvsp[-1].column_type; ; break;} -case 22: -#line 307 "./sql.y" -{ - yyval.column_type = 2; - ; - break;} case 23: -#line 311 "./sql.y" +#line 298 "./sql.y" { yyval.column_type = 2; ; break;} case 24: -#line 315 "./sql.y" +#line 302 "./sql.y" { yyval.column_type = 2; ; break;} case 25: -#line 319 "./sql.y" +#line 306 "./sql.y" +{ + yyval.column_type = 2; + ; + break;} +case 26: +#line 310 "./sql.y" { yyval.column_type = 4; ; break;} -case 26: -#line 323 "./sql.y" +case 27: +#line 314 "./sql.y" { yyval.column_type = 0; ; break;} -case 27: -#line 330 "./sql.y" +case 28: +#line 321 "./sql.y" { - SQL_input* sql = (SQL_input*) info; - int val = SQL_getint(sql); - if( ( val > 255 ) || ( val < 0 ) ) + if( ( yyvsp[0].integer > 255 ) || ( yyvsp[0].integer < 0 ) ) YYABORT; - yyval.column_type = val; + yyval.column_type = yyvsp[0].integer; ; break;} -case 28: -#line 341 "./sql.y" +case 29: +#line 330 "./sql.y" { SQL_input* sql = (SQL_input*) info; @@ -1431,14 +1421,14 @@ case 28: YYABORT; ; break;} -case 30: -#line 357 "./sql.y" +case 31: +#line 346 "./sql.y" { yyval.query = yyvsp[0].query; ; break;} -case 31: -#line 361 "./sql.y" +case 32: +#line 350 "./sql.y" { SQL_input* sql = (SQL_input*) info; @@ -1448,8 +1438,8 @@ case 31: YYABORT; ; break;} -case 32: -#line 373 "./sql.y" +case 33: +#line 362 "./sql.y" { SQL_input* sql = (SQL_input*) info; @@ -1463,44 +1453,20 @@ case 32: YYABORT; ; break;} -case 33: -#line 389 "./sql.y" -{ - string_list *list; - - list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); - if( !list ) - YYABORT; - list->string = yyvsp[0].string; - list->next = NULL; - - yyval.column_list = list; - TRACE("Collist %s\n",debugstr_w(yyval.column_list->string)); - ; - break;} -case 34: -#line 402 "./sql.y" -{ - string_list *list; - - list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); - if( !list ) - YYABORT; - list->string = yyvsp[-2].string; - list->next = yyvsp[0].column_list; - - yyval.column_list = list; - TRACE("From table: %s\n",debugstr_w(yyval.column_list->string)); - ; - break;} case 35: -#line 415 "./sql.y" +#line 379 "./sql.y" +{ + yyvsp[-2].column_list->next = yyvsp[0].column_list; + ; + break;} +case 36: +#line 383 "./sql.y" { yyval.column_list = NULL; ; break;} -case 37: -#line 423 "./sql.y" +case 38: +#line 391 "./sql.y" { SQL_input* sql = (SQL_input*) info; UINT r; @@ -1511,8 +1477,8 @@ case 37: YYABORT; ; break;} -case 38: -#line 436 "./sql.y" +case 39: +#line 404 "./sql.y" { SQL_input* sql = (SQL_input*) info; UINT r; @@ -1523,217 +1489,211 @@ case 38: YYABORT; ; break;} -case 39: -#line 449 "./sql.y" +case 40: +#line 417 "./sql.y" { yyval.expr = yyvsp[-1].expr; if( !yyval.expr ) YYABORT; ; break;} -case 40: -#line 455 "./sql.y" +case 41: +#line 423 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_EQ, yyvsp[0].expr ); if( !yyval.expr ) YYABORT; ; break;} -case 41: -#line 461 "./sql.y" +case 42: +#line 429 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_AND, yyvsp[0].expr ); if( !yyval.expr ) YYABORT; ; break;} -case 42: -#line 467 "./sql.y" +case 43: +#line 435 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_OR, yyvsp[0].expr ); if( !yyval.expr ) YYABORT; ; break;} -case 43: -#line 473 "./sql.y" +case 44: +#line 441 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_EQ, yyvsp[0].expr ); if( !yyval.expr ) YYABORT; ; break;} -case 44: -#line 479 "./sql.y" +case 45: +#line 447 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_GT, yyvsp[0].expr ); if( !yyval.expr ) YYABORT; ; break;} -case 45: -#line 485 "./sql.y" +case 46: +#line 453 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_LT, yyvsp[0].expr ); if( !yyval.expr ) YYABORT; ; break;} -case 46: -#line 491 "./sql.y" +case 47: +#line 459 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_LE, yyvsp[0].expr ); if( !yyval.expr ) YYABORT; ; break;} -case 47: -#line 497 "./sql.y" +case 48: +#line 465 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_GE, yyvsp[0].expr ); if( !yyval.expr ) YYABORT; ; break;} -case 48: -#line 503 "./sql.y" +case 49: +#line 471 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_NE, yyvsp[0].expr ); if( !yyval.expr ) YYABORT; ; break;} -case 49: -#line 509 "./sql.y" +case 50: +#line 477 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_ISNULL, NULL ); if( !yyval.expr ) YYABORT; ; break;} -case 50: -#line 515 "./sql.y" +case 51: +#line 483 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-3].expr, OP_NOTNULL, NULL ); if( !yyval.expr ) YYABORT; ; break;} -case 53: -#line 529 "./sql.y" -{ - value_list *vals; - - vals = parser_alloc( info, sizeof *vals ); - if( !vals ) - YYABORT; - vals->val = yyvsp[0].expr; - vals->next = NULL; - yyval.val_list = vals; - ; - break;} case 54: -#line 540 "./sql.y" +#line 497 "./sql.y" { - value_list *vals; - - vals = parser_alloc( info, sizeof *vals ); - if( !vals ) + yyval.column_list = parser_alloc_column( info, NULL, NULL ); + if( !yyval.column_list ) YYABORT; - vals->val = yyvsp[-2].expr; - vals->next = yyvsp[0].val_list; - yyval.val_list = vals; + yyval.column_list->val = yyvsp[0].expr; ; break;} -case 56: -#line 555 "./sql.y" +case 55: +#line 504 "./sql.y" { - yyvsp[-2].update_col_info.col_list->next = yyvsp[0].update_col_info.col_list; - yyvsp[-2].update_col_info.val_list->next = yyvsp[0].update_col_info.val_list; - yyval.update_col_info = yyvsp[-2].update_col_info; + yyval.column_list = parser_alloc_column( info, NULL, NULL ); + if( !yyval.column_list ) + YYABORT; + yyval.column_list->val = yyvsp[-2].expr; + yyval.column_list->next = yyvsp[0].column_list; ; break;} case 57: -#line 564 "./sql.y" +#line 516 "./sql.y" { - yyval.update_col_info.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.col_list ); - if( !yyval.update_col_info.col_list ) - YYABORT; - yyval.update_col_info.col_list->string = yyvsp[-2].string; - yyval.update_col_info.col_list->next = NULL; - yyval.update_col_info.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.val_list ); - if( !yyval.update_col_info.val_list ) - YYABORT; - yyval.update_col_info.val_list->val = yyvsp[0].expr; - yyval.update_col_info.val_list->next = 0; + yyval.column_list = yyvsp[-2].column_list; + yyval.column_list->next = yyvsp[0].column_list; ; break;} case 58: -#line 580 "./sql.y" +#line 524 "./sql.y" { - yyval.expr = EXPR_ival( info, &yyvsp[0].str, 1 ); - if( !yyval.expr ) - YYABORT; + yyval.column_list = yyvsp[-2].column_list; + yyval.column_list->val = yyvsp[0].expr; ; break;} case 59: -#line 586 "./sql.y" +#line 532 "./sql.y" { - yyval.expr = EXPR_ival( info, &yyvsp[0].str, -1 ); + yyval.expr = EXPR_ival( info, yyvsp[0].integer ); if( !yyval.expr ) YYABORT; ; break;} case 60: -#line 592 "./sql.y" +#line 538 "./sql.y" +{ + yyval.expr = EXPR_ival( info, -yyvsp[0].integer ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 61: +#line 544 "./sql.y" { yyval.expr = EXPR_sval( info, &yyvsp[0].str ); if( !yyval.expr ) YYABORT; ; break;} -case 61: -#line 598 "./sql.y" +case 62: +#line 550 "./sql.y" { yyval.expr = EXPR_wildcard( info ); if( !yyval.expr ) YYABORT; ; break;} -case 62: -#line 607 "./sql.y" +case 63: +#line 559 "./sql.y" { - yyval.expr = EXPR_column( info, yyvsp[0].string ); + yyval.expr = EXPR_column( info, yyvsp[0].column_list ); if( !yyval.expr ) YYABORT; ; break;} -case 63: -#line 616 "./sql.y" -{ - yyval.string = yyvsp[0].string; /* FIXME */ - ; - break;} case 64: -#line 620 "./sql.y" +#line 568 "./sql.y" { - yyval.string = yyvsp[0].string; + yyval.column_list = parser_alloc_column( info, yyvsp[-2].string, yyvsp[0].string ); + if( !yyval.column_list ) + YYABORT; ; break;} case 65: -#line 627 "./sql.y" +#line 574 "./sql.y" +{ + yyval.column_list = parser_alloc_column( info, NULL, yyvsp[0].string ); + if( !yyval.column_list ) + YYABORT; + ; + break;} +case 66: +#line 583 "./sql.y" { yyval.string = yyvsp[0].string; ; break;} -case 66: -#line 634 "./sql.y" +case 67: +#line 590 "./sql.y" { yyval.string = SQL_getstring( info, &yyvsp[0].str ); if( !yyval.string ) YYABORT; ; break;} +case 68: +#line 599 "./sql.y" +{ + yyval.integer = SQL_getint( info ); + ; + break;} } #line 705 "/usr/share/bison/bison.simple" @@ -1967,7 +1927,7 @@ yyreturn: #endif return yyresult; } -#line 641 "./sql.y" +#line 604 "./sql.y" static void *parser_alloc( void *info, unsigned int sz ) @@ -1980,6 +1940,23 @@ static void *parser_alloc( void *info, unsigned int sz ) return &mem[1]; } +static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column ) +{ + column_info *col; + + col = parser_alloc( info, sizeof (*col) ); + if( col ) + { + col->table = table; + col->column = column; + col->val = NULL; + col->type = 0; + col->next = NULL; + } + + return col; +} + int SQL_lex( void *SQL_lval, SQL_input *sql ) { int token; @@ -2031,8 +2008,19 @@ INT SQL_getint( void *info ) { SQL_input* sql = (SQL_input*) info; LPCWSTR p = &sql->command[sql->n]; + INT i, r = 0; - return atoiW( p ); + for( i=0; ilen; i++ ) + { + if( '0' > p[i] || '9' < p[i] ) + { + ERR("should only be numbers here!\n"); + break; + } + r = (p[i]-'0') + r*10; + } + + return r; } int SQL_error( const char *str ) @@ -2063,24 +2051,24 @@ static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct e return e; } -static struct expr * EXPR_column( void *info, LPWSTR column ) +static struct expr * EXPR_column( void *info, column_info *column ) { struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { e->type = EXPR_COLUMN; - e->u.sval = column; + e->u.sval = column->column; } return e; } -static struct expr * EXPR_ival( void *info, struct sql_str *str, int sign ) +static struct expr * EXPR_ival( void *info, int val ) { struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { e->type = EXPR_IVAL; - e->u.ival = atoiW( str->data ) * sign; + e->u.ival = val; } return e; } @@ -2096,19 +2084,20 @@ static struct expr * EXPR_sval( void *info, struct sql_str *str ) return e; } -static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys) +static BOOL SQL_MarkPrimaryKeys( column_info *cols, + column_info *keys ) { - string_list *k; + column_info *k; BOOL found = TRUE; for( k = keys; k && found; k = k->next ) { - create_col_info *c; + column_info *c; found = FALSE; for( c = cols; c && !found; c = c->next ) { - if( lstrcmpW( k->string, c->colname ) ) + if( lstrcmpW( k->column, c->column ) ) continue; c->type |= MSITYPE_KEY; found = TRUE; diff --git a/reactos/lib/msi/sql.tab.h b/reactos/lib/msi/sql.tab.h index bfc66b3f050..f49301be8b1 100644 --- a/reactos/lib/msi/sql.tab.h +++ b/reactos/lib/msi/sql.tab.h @@ -1,347 +1,163 @@ -/* A Bison parser, made by GNU Bison 1.875b. */ +#ifndef BISON_SQL_TAB_H +# define BISON_SQL_TAB_H -/* Skeleton parser for Yacc-like parsing with Bison, - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* As a special exception, when this file is copied by Bison into a - Bison output file, you may use that output file without restriction. - This special exception was added by the Free Software Foundation - in version 1.24 of Bison. */ - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - TK_ABORT = 258, - TK_AFTER = 259, - TK_AGG_FUNCTION = 260, - TK_ALL = 261, - TK_AND = 262, - TK_AS = 263, - TK_ASC = 264, - TK_BEFORE = 265, - TK_BEGIN = 266, - TK_BETWEEN = 267, - TK_BITAND = 268, - TK_BITNOT = 269, - TK_BITOR = 270, - TK_BY = 271, - TK_CASCADE = 272, - TK_CASE = 273, - TK_CHAR = 274, - TK_CHECK = 275, - TK_CLUSTER = 276, - TK_COLLATE = 277, - TK_COLUMN = 278, - TK_COMMA = 279, - TK_COMMENT = 280, - TK_COMMIT = 281, - TK_CONCAT = 282, - TK_CONFLICT = 283, - TK_CONSTRAINT = 284, - TK_COPY = 285, - TK_CREATE = 286, - TK_DEFAULT = 287, - TK_DEFERRABLE = 288, - TK_DEFERRED = 289, - TK_DELETE = 290, - TK_DELIMITERS = 291, - TK_DESC = 292, - TK_DISTINCT = 293, - TK_DOT = 294, - TK_DROP = 295, - TK_EACH = 296, - TK_ELSE = 297, - TK_END = 298, - TK_END_OF_FILE = 299, - TK_EQ = 300, - TK_EXCEPT = 301, - TK_EXPLAIN = 302, - TK_FAIL = 303, - TK_FLOAT = 304, - TK_FOR = 305, - TK_FOREIGN = 306, - TK_FROM = 307, - TK_FUNCTION = 308, - TK_GE = 309, - TK_GLOB = 310, - TK_GROUP = 311, - TK_GT = 312, - TK_HAVING = 313, - TK_HOLD = 314, - TK_IGNORE = 315, - TK_ILLEGAL = 316, - TK_IMMEDIATE = 317, - TK_IN = 318, - TK_INDEX = 319, - TK_INITIALLY = 320, - TK_ID = 321, - TK_INSERT = 322, - TK_INSTEAD = 323, - TK_INT = 324, - TK_INTEGER = 325, - TK_INTERSECT = 326, - TK_INTO = 327, - TK_IS = 328, - TK_ISNULL = 329, - TK_JOIN = 330, - TK_JOIN_KW = 331, - TK_KEY = 332, - TK_LE = 333, - TK_LIKE = 334, - TK_LIMIT = 335, - TK_LONG = 336, - TK_LONGCHAR = 337, - TK_LP = 338, - TK_LSHIFT = 339, - TK_LT = 340, - TK_LOCALIZABLE = 341, - TK_MATCH = 342, - TK_MINUS = 343, - TK_NE = 344, - TK_NOT = 345, - TK_NOTNULL = 346, - TK_NULL = 347, - TK_OBJECT = 348, - TK_OF = 349, - TK_OFFSET = 350, - TK_ON = 351, - TK_OR = 352, - TK_ORACLE_OUTER_JOIN = 353, - TK_ORDER = 354, - TK_PLUS = 355, - TK_PRAGMA = 356, - TK_PRIMARY = 357, - TK_RAISE = 358, - TK_REFERENCES = 359, - TK_REM = 360, - TK_REPLACE = 361, - TK_RESTRICT = 362, - TK_ROLLBACK = 363, - TK_ROW = 364, - TK_RP = 365, - TK_RSHIFT = 366, - TK_SELECT = 367, - TK_SEMI = 368, - TK_SET = 369, - TK_SHORT = 370, - TK_SLASH = 371, - TK_SPACE = 372, - TK_STAR = 373, - TK_STATEMENT = 374, - TK_STRING = 375, - TK_TABLE = 376, - TK_TEMP = 377, - TK_THEN = 378, - TK_TRANSACTION = 379, - TK_TRIGGER = 380, - TK_UMINUS = 381, - TK_UNCLOSED_STRING = 382, - TK_UNION = 383, - TK_UNIQUE = 384, - TK_UPDATE = 385, - TK_UPLUS = 386, - TK_USING = 387, - TK_VACUUM = 388, - TK_VALUES = 389, - TK_VIEW = 390, - TK_WHEN = 391, - TK_WHERE = 392, - TK_WILDCARD = 393, - COLUMN = 395, - FUNCTION = 396, - COMMENT = 397, - UNCLOSED_STRING = 398, - SPACE = 399, - ILLEGAL = 400, - END_OF_FILE = 401 - }; -#endif -#define TK_ABORT 258 -#define TK_AFTER 259 -#define TK_AGG_FUNCTION 260 -#define TK_ALL 261 -#define TK_AND 262 -#define TK_AS 263 -#define TK_ASC 264 -#define TK_BEFORE 265 -#define TK_BEGIN 266 -#define TK_BETWEEN 267 -#define TK_BITAND 268 -#define TK_BITNOT 269 -#define TK_BITOR 270 -#define TK_BY 271 -#define TK_CASCADE 272 -#define TK_CASE 273 -#define TK_CHAR 274 -#define TK_CHECK 275 -#define TK_CLUSTER 276 -#define TK_COLLATE 277 -#define TK_COLUMN 278 -#define TK_COMMA 279 -#define TK_COMMENT 280 -#define TK_COMMIT 281 -#define TK_CONCAT 282 -#define TK_CONFLICT 283 -#define TK_CONSTRAINT 284 -#define TK_COPY 285 -#define TK_CREATE 286 -#define TK_DEFAULT 287 -#define TK_DEFERRABLE 288 -#define TK_DEFERRED 289 -#define TK_DELETE 290 -#define TK_DELIMITERS 291 -#define TK_DESC 292 -#define TK_DISTINCT 293 -#define TK_DOT 294 -#define TK_DROP 295 -#define TK_EACH 296 -#define TK_ELSE 297 -#define TK_END 298 -#define TK_END_OF_FILE 299 -#define TK_EQ 300 -#define TK_EXCEPT 301 -#define TK_EXPLAIN 302 -#define TK_FAIL 303 -#define TK_FLOAT 304 -#define TK_FOR 305 -#define TK_FOREIGN 306 -#define TK_FROM 307 -#define TK_FUNCTION 308 -#define TK_GE 309 -#define TK_GLOB 310 -#define TK_GROUP 311 -#define TK_GT 312 -#define TK_HAVING 313 -#define TK_HOLD 314 -#define TK_IGNORE 315 -#define TK_ILLEGAL 316 -#define TK_IMMEDIATE 317 -#define TK_IN 318 -#define TK_INDEX 319 -#define TK_INITIALLY 320 -#define TK_ID 321 -#define TK_INSERT 322 -#define TK_INSTEAD 323 -#define TK_INT 324 -#define TK_INTEGER 325 -#define TK_INTERSECT 326 -#define TK_INTO 327 -#define TK_IS 328 -#define TK_ISNULL 329 -#define TK_JOIN 330 -#define TK_JOIN_KW 331 -#define TK_KEY 332 -#define TK_LE 333 -#define TK_LIKE 334 -#define TK_LIMIT 335 -#define TK_LONG 336 -#define TK_LONGCHAR 337 -#define TK_LP 338 -#define TK_LSHIFT 339 -#define TK_LT 340 -#define TK_LOCALIZABLE 341 -#define TK_MATCH 342 -#define TK_MINUS 343 -#define TK_NE 344 -#define TK_NOT 345 -#define TK_NOTNULL 346 -#define TK_NULL 347 -#define TK_OBJECT 348 -#define TK_OF 349 -#define TK_OFFSET 350 -#define TK_ON 351 -#define TK_OR 352 -#define TK_ORACLE_OUTER_JOIN 353 -#define TK_ORDER 354 -#define TK_PLUS 355 -#define TK_PRAGMA 356 -#define TK_PRIMARY 357 -#define TK_RAISE 358 -#define TK_REFERENCES 359 -#define TK_REM 360 -#define TK_REPLACE 361 -#define TK_RESTRICT 362 -#define TK_ROLLBACK 363 -#define TK_ROW 364 -#define TK_RP 365 -#define TK_RSHIFT 366 -#define TK_SELECT 367 -#define TK_SEMI 368 -#define TK_SET 369 -#define TK_SHORT 370 -#define TK_SLASH 371 -#define TK_SPACE 372 -#define TK_STAR 373 -#define TK_STATEMENT 374 -#define TK_STRING 375 -#define TK_TABLE 376 -#define TK_TEMP 377 -#define TK_THEN 378 -#define TK_TRANSACTION 379 -#define TK_TRIGGER 380 -#define TK_UMINUS 381 -#define TK_UNCLOSED_STRING 382 -#define TK_UNION 383 -#define TK_UNIQUE 384 -#define TK_UPDATE 385 -#define TK_UPLUS 386 -#define TK_USING 387 -#define TK_VACUUM 388 -#define TK_VALUES 389 -#define TK_VIEW 390 -#define TK_WHEN 391 -#define TK_WHERE 392 -#define TK_WILDCARD 393 -#define COLUMN 395 -#define FUNCTION 396 -#define COMMENT 397 -#define UNCLOSED_STRING 398 -#define SPACE 399 -#define ILLEGAL 400 -#define END_OF_FILE 401 - - - - -#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) -#line 74 "./sql.y" -typedef union YYSTYPE { +#ifndef YYSTYPE +typedef union +{ struct sql_str str; LPWSTR string; - string_list *column_list; - value_list *val_list; + column_info *column_list; MSIVIEW *query; struct expr *expr; USHORT column_type; - create_col_info *column_info; - column_assignment update_col_info; -} YYSTYPE; -/* Line 1252 of yacc.c. */ -#line 339 "sql.tab.h" -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 + int integer; +} yystype; +# define YYSTYPE yystype # define YYSTYPE_IS_TRIVIAL 1 #endif +# define TK_ABORT 257 +# define TK_AFTER 258 +# define TK_AGG_FUNCTION 259 +# define TK_ALL 260 +# define TK_AND 261 +# define TK_AS 262 +# define TK_ASC 263 +# define TK_BEFORE 264 +# define TK_BEGIN 265 +# define TK_BETWEEN 266 +# define TK_BITAND 267 +# define TK_BITNOT 268 +# define TK_BITOR 269 +# define TK_BY 270 +# define TK_CASCADE 271 +# define TK_CASE 272 +# define TK_CHAR 273 +# define TK_CHECK 274 +# define TK_CLUSTER 275 +# define TK_COLLATE 276 +# define TK_COLUMN 277 +# define TK_COMMA 278 +# define TK_COMMENT 279 +# define TK_COMMIT 280 +# define TK_CONCAT 281 +# define TK_CONFLICT 282 +# define TK_CONSTRAINT 283 +# define TK_COPY 284 +# define TK_CREATE 285 +# define TK_DEFAULT 286 +# define TK_DEFERRABLE 287 +# define TK_DEFERRED 288 +# define TK_DELETE 289 +# define TK_DELIMITERS 290 +# define TK_DESC 291 +# define TK_DISTINCT 292 +# define TK_DOT 293 +# define TK_DROP 294 +# define TK_EACH 295 +# define TK_ELSE 296 +# define TK_END 297 +# define TK_END_OF_FILE 298 +# define TK_EQ 299 +# define TK_EXCEPT 300 +# define TK_EXPLAIN 301 +# define TK_FAIL 302 +# define TK_FLOAT 303 +# define TK_FOR 304 +# define TK_FOREIGN 305 +# define TK_FROM 306 +# define TK_FUNCTION 307 +# define TK_GE 308 +# define TK_GLOB 309 +# define TK_GROUP 310 +# define TK_GT 311 +# define TK_HAVING 312 +# define TK_HOLD 313 +# define TK_IGNORE 314 +# define TK_ILLEGAL 315 +# define TK_IMMEDIATE 316 +# define TK_IN 317 +# define TK_INDEX 318 +# define TK_INITIALLY 319 +# define TK_ID 320 +# define TK_INSERT 321 +# define TK_INSTEAD 322 +# define TK_INT 323 +# define TK_INTEGER 324 +# define TK_INTERSECT 325 +# define TK_INTO 326 +# define TK_IS 327 +# define TK_ISNULL 328 +# define TK_JOIN 329 +# define TK_JOIN_KW 330 +# define TK_KEY 331 +# define TK_LE 332 +# define TK_LIKE 333 +# define TK_LIMIT 334 +# define TK_LONG 335 +# define TK_LONGCHAR 336 +# define TK_LP 337 +# define TK_LSHIFT 338 +# define TK_LT 339 +# define TK_LOCALIZABLE 340 +# define TK_MATCH 341 +# define TK_MINUS 342 +# define TK_NE 343 +# define TK_NOT 344 +# define TK_NOTNULL 345 +# define TK_NULL 346 +# define TK_OBJECT 347 +# define TK_OF 348 +# define TK_OFFSET 349 +# define TK_ON 350 +# define TK_OR 351 +# define TK_ORACLE_OUTER_JOIN 352 +# define TK_ORDER 353 +# define TK_PLUS 354 +# define TK_PRAGMA 355 +# define TK_PRIMARY 356 +# define TK_RAISE 357 +# define TK_REFERENCES 358 +# define TK_REM 359 +# define TK_REPLACE 360 +# define TK_RESTRICT 361 +# define TK_ROLLBACK 362 +# define TK_ROW 363 +# define TK_RP 364 +# define TK_RSHIFT 365 +# define TK_SELECT 366 +# define TK_SEMI 367 +# define TK_SET 368 +# define TK_SHORT 369 +# define TK_SLASH 370 +# define TK_SPACE 371 +# define TK_STAR 372 +# define TK_STATEMENT 373 +# define TK_STRING 374 +# define TK_TABLE 375 +# define TK_TEMP 376 +# define TK_THEN 377 +# define TK_TRANSACTION 378 +# define TK_TRIGGER 379 +# define TK_UMINUS 380 +# define TK_UNCLOSED_STRING 381 +# define TK_UNION 382 +# define TK_UNIQUE 383 +# define TK_UPDATE 384 +# define TK_UPLUS 385 +# define TK_USING 386 +# define TK_VACUUM 387 +# define TK_VALUES 388 +# define TK_VIEW 389 +# define TK_WHEN 390 +# define TK_WHERE 391 +# define TK_WILDCARD 392 +# define END_OF_FILE 393 +# define ILLEGAL 394 +# define SPACE 395 +# define UNCLOSED_STRING 396 +# define COMMENT 397 +# define FUNCTION 398 +# define COLUMN 399 - - - +#endif /* not BISON_SQL_TAB_H */ diff --git a/reactos/lib/msi/sql.y b/reactos/lib/msi/sql.y index 7a0edd9f6ab..a311d6aa886 100644 --- a/reactos/lib/msi/sql.y +++ b/reactos/lib/msi/sql.y @@ -32,7 +32,6 @@ #include "query.h" #include "wine/list.h" #include "wine/debug.h" -#include "wine/unicode.h" #define YYLEX_PARAM info #define YYPARSE_PARAM info @@ -55,12 +54,13 @@ static INT SQL_getint( void *info ); static int SQL_lex( void *SQL_lval, SQL_input *info ); static void *parser_alloc( void *info, unsigned int sz ); +static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column ); -static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys); +static BOOL SQL_MarkPrimaryKeys( column_info *cols, column_info *keys); static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r ); -static struct expr * EXPR_column( void *info, LPWSTR column ); -static struct expr * EXPR_ival( void *info, struct sql_str *, int sign ); +static struct expr * EXPR_column( void *info, column_info *column ); +static struct expr * EXPR_ival( void *info, int val ); static struct expr * EXPR_sval( void *info, struct sql_str * ); static struct expr * EXPR_wildcard( void *info ); @@ -72,13 +72,11 @@ static struct expr * EXPR_wildcard( void *info ); { struct sql_str str; LPWSTR string; - string_list *column_list; - value_list *val_list; + column_info *column_list; MSIVIEW *query; struct expr *expr; USHORT column_type; - create_col_info *column_info; - column_assignment update_col_info; + int integer; } %token TK_ABORT TK_AFTER TK_AGG_FUNCTION TK_ALL TK_AND TK_AS TK_ASC @@ -125,15 +123,14 @@ static struct expr * EXPR_wildcard( void *info ); %nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION COLUMN AGG_FUNCTION. -%type column table id -%type selcollist -%type query from fromtable unorderedsel selectfrom +%type table id +%type selcollist column column_and_type column_def table_def +%type column_assignment update_assign_list constlist +%type query from fromtable selectfrom unorderedsel %type oneupdate onedelete oneselect onequery onecreate oneinsert %type expr val column_val const_val %type column_type data_type data_type_l data_count -%type column_def table_def -%type constlist -%type column_assignment update_assign_list +%type number %% @@ -210,7 +207,7 @@ oneupdate: SQL_input* sql = (SQL_input*) info; MSIVIEW *update = NULL; - UPDATE_CreateView( sql->db, &update, $2, &$4, $6 ); + UPDATE_CreateView( sql->db, &update, $2, $4, $6 ); if( !update ) YYABORT; $$ = update; @@ -241,33 +238,27 @@ table_def: ; column_def: - column_def TK_COMMA column column_type + column_def TK_COMMA column_and_type { - create_col_info *ci; + column_info *ci; for( ci = $1; ci->next; ci = ci->next ) ; - ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ ); - if( !ci->next ) - { - /* FIXME: free $1 */ - YYABORT; - } - ci->next->colname = $3; - ci->next->type = $4; - ci->next->next = NULL; - + ci->next = $3; $$ = $1; } - | column column_type + | column_and_type { - $$ = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ ); - if( ! $$ ) - YYABORT; - $$->colname = $1; + $$ = $1; + } + ; + +column_and_type: + column column_type + { + $$ = $1; $$->type = $2; - $$->next = NULL; } ; @@ -326,13 +317,11 @@ data_type: ; data_count: - TK_INTEGER + number { - SQL_input* sql = (SQL_input*) info; - int val = SQL_getint(sql); - if( ( val > 255 ) || ( val < 0 ) ) + if( ( $1 > 255 ) || ( $1 < 0 ) ) YYABORT; - $$ = val; + $$ = $1; } ; @@ -386,30 +375,9 @@ selectfrom: selcollist: column - { - string_list *list; - - list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); - if( !list ) - YYABORT; - list->string = $1; - list->next = NULL; - - $$ = list; - TRACE("Collist %s\n",debugstr_w($$->string)); - } | column TK_COMMA selcollist { - string_list *list; - - list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); - if( !list ) - YYABORT; - list->string = $1; - list->next = $3; - - $$ = list; - TRACE("From table: %s\n",debugstr_w($$->string)); + $1->next = $3; } | TK_STAR { @@ -527,25 +495,18 @@ val: constlist: const_val { - value_list *vals; - - vals = parser_alloc( info, sizeof *vals ); - if( !vals ) + $$ = parser_alloc_column( info, NULL, NULL ); + if( !$$ ) YYABORT; - vals->val = $1; - vals->next = NULL; - $$ = vals; + $$->val = $1; } | const_val TK_COMMA constlist { - value_list *vals; - - vals = parser_alloc( info, sizeof *vals ); - if( !vals ) + $$ = parser_alloc_column( info, NULL, NULL ); + if( !$$ ) YYABORT; - vals->val = $1; - vals->next = $3; - $$ = vals; + $$->val = $1; + $$->next = $3; } ; @@ -553,38 +514,29 @@ update_assign_list: column_assignment | column_assignment TK_COMMA update_assign_list { - $1.col_list->next = $3.col_list; - $1.val_list->next = $3.val_list; $$ = $1; + $$->next = $3; } ; column_assignment: column TK_EQ const_val { - $$.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.col_list ); - if( !$$.col_list ) - YYABORT; - $$.col_list->string = $1; - $$.col_list->next = NULL; - $$.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.val_list ); - if( !$$.val_list ) - YYABORT; - $$.val_list->val = $3; - $$.val_list->next = 0; + $$ = $1; + $$->val = $3; } ; const_val: - TK_INTEGER + number { - $$ = EXPR_ival( info, &$1, 1 ); + $$ = EXPR_ival( info, $1 ); if( !$$ ) YYABORT; } - | TK_MINUS TK_INTEGER + | TK_MINUS number { - $$ = EXPR_ival( info, &$2, -1 ); + $$ = EXPR_ival( info, -$2 ); if( !$$ ) YYABORT; } @@ -614,11 +566,15 @@ column_val: column: table TK_DOT id { - $$ = $3; /* FIXME */ + $$ = parser_alloc_column( info, $1, $3 ); + if( !$$ ) + YYABORT; } | id { - $$ = $1; + $$ = parser_alloc_column( info, NULL, $1 ); + if( !$$ ) + YYABORT; } ; @@ -638,6 +594,13 @@ id: } ; +number: + TK_INTEGER + { + $$ = SQL_getint( info ); + } + ; + %% static void *parser_alloc( void *info, unsigned int sz ) @@ -650,6 +613,23 @@ static void *parser_alloc( void *info, unsigned int sz ) return &mem[1]; } +static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column ) +{ + column_info *col; + + col = parser_alloc( info, sizeof (*col) ); + if( col ) + { + col->table = table; + col->column = column; + col->val = NULL; + col->type = 0; + col->next = NULL; + } + + return col; +} + int SQL_lex( void *SQL_lval, SQL_input *sql ) { int token; @@ -701,8 +681,19 @@ INT SQL_getint( void *info ) { SQL_input* sql = (SQL_input*) info; LPCWSTR p = &sql->command[sql->n]; + INT i, r = 0; - return atoiW( p ); + for( i=0; ilen; i++ ) + { + if( '0' > p[i] || '9' < p[i] ) + { + ERR("should only be numbers here!\n"); + break; + } + r = (p[i]-'0') + r*10; + } + + return r; } int SQL_error( const char *str ) @@ -733,24 +724,24 @@ static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct e return e; } -static struct expr * EXPR_column( void *info, LPWSTR column ) +static struct expr * EXPR_column( void *info, column_info *column ) { struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { e->type = EXPR_COLUMN; - e->u.sval = column; + e->u.sval = column->column; } return e; } -static struct expr * EXPR_ival( void *info, struct sql_str *str, int sign ) +static struct expr * EXPR_ival( void *info, int val ) { struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { e->type = EXPR_IVAL; - e->u.ival = atoiW( str->data ) * sign; + e->u.ival = val; } return e; } @@ -766,19 +757,20 @@ static struct expr * EXPR_sval( void *info, struct sql_str *str ) return e; } -static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys) +static BOOL SQL_MarkPrimaryKeys( column_info *cols, + column_info *keys ) { - string_list *k; + column_info *k; BOOL found = TRUE; for( k = keys; k && found; k = k->next ) { - create_col_info *c; + column_info *c; found = FALSE; for( c = cols; c && !found; c = c->next ) { - if( lstrcmpW( k->string, c->colname ) ) + if( lstrcmpW( k->column, c->column ) ) continue; c->type |= MSITYPE_KEY; found = TRUE; diff --git a/reactos/lib/msi/suminfo.c b/reactos/lib/msi/suminfo.c index 744898d3379..cd507f2c082 100644 --- a/reactos/lib/msi/suminfo.c +++ b/reactos/lib/msi/suminfo.c @@ -91,6 +91,14 @@ typedef struct { } str; } awstring; +typedef struct { + BOOL unicode; + union { + LPCSTR a; + LPCWSTR w; + } str; +} awcstring; + typedef struct tagMSISUMMARYINFO { MSIOBJECTHDR hdr; @@ -627,7 +635,7 @@ UINT WINAPI MsiSummaryInfoGetPropertyW( } static UINT set_prop( MSIHANDLE handle, UINT uiProperty, UINT uiDataType, - INT iValue, FILETIME* pftValue, awstring *str ) + INT iValue, FILETIME* pftValue, awcstring *str ) { MSISUMMARYINFO *si; PROPVARIANT *prop; @@ -701,9 +709,9 @@ end: } UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty, - UINT uiDataType, INT iValue, FILETIME* pftValue, LPWSTR szValue ) + UINT uiDataType, INT iValue, FILETIME* pftValue, LPCWSTR szValue ) { - awstring str; + awcstring str; TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType, iValue, pftValue, debugstr_w(szValue) ); @@ -714,9 +722,9 @@ UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty, } UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty, - UINT uiDataType, INT iValue, FILETIME* pftValue, LPSTR szValue ) + UINT uiDataType, INT iValue, FILETIME* pftValue, LPCSTR szValue ) { - awstring str; + awcstring str; TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType, iValue, pftValue, debugstr_a(szValue) ); diff --git a/reactos/lib/msi/table.c b/reactos/lib/msi/table.c index 29f19117a66..60fd269be4c 100644 --- a/reactos/lib/msi/table.c +++ b/reactos/lib/msi/table.c @@ -397,7 +397,7 @@ end: return ret; } -UINT read_table_from_storage( MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable) +static UINT read_table_from_storage( MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable) { MSITABLE *t; USHORT *rawdata = NULL; @@ -507,7 +507,7 @@ void remove_table( MSIDATABASE *db, MSITABLE *table ) table->prev = NULL; } -void release_table( MSIDATABASE *db, MSITABLE *table ) +static void release_table( MSIDATABASE *db, MSITABLE *table ) { if( !table->ref_count ) ERR("Trying to destroy table with refcount 0\n"); @@ -610,7 +610,7 @@ UINT get_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable) return ERROR_SUCCESS; } -UINT save_table( MSIDATABASE *db, MSITABLE *t ) +static UINT save_table( MSIDATABASE *db, MSITABLE *t ) { USHORT *rawdata = NULL, *p; UINT rawsize, r, i, j, row_size, num_cols = 0; @@ -751,7 +751,7 @@ end: return ret; } -UINT save_string_table( MSIDATABASE *db ) +static UINT save_string_table( MSIDATABASE *db ) { UINT i, count, datasize, poolsize, sz, used, r, codepage; UINT ret = ERROR_FUNCTION_FAILED; @@ -858,7 +858,7 @@ struct standard_table { #define STANDARD_TABLE_COUNT \ (sizeof(MSI_standard_tables)/sizeof(struct standard_table)) -UINT get_defaulttablecolumns( LPCWSTR szTable, MSICOLUMNINFO *colinfo, UINT *sz) +static UINT get_defaulttablecolumns( LPCWSTR szTable, MSICOLUMNINFO *colinfo, UINT *sz) { DWORD i, n=0; @@ -1167,7 +1167,7 @@ static UINT TABLE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val return ERROR_SUCCESS; } -UINT TABLE_insert_row( struct tagMSIVIEW *view, UINT *num ) +static UINT TABLE_insert_row( struct tagMSIVIEW *view, UINT *num ) { MSITABLEVIEW *tv = (MSITABLEVIEW*)view; USHORT **p, *row; diff --git a/reactos/lib/msi/tokenize.c b/reactos/lib/msi/tokenize.c index 315bac9a670..05c3cda38e2 100644 --- a/reactos/lib/msi/tokenize.c +++ b/reactos/lib/msi/tokenize.c @@ -158,7 +158,7 @@ static const Keyword aKeywordTable[] = { ** keyword. If it is a keyword, the token code of that keyword is ** returned. If the input is not a keyword, TK_ID is returned. */ -int sqliteKeywordCode(const WCHAR *z, int n){ +static int sqliteKeywordCode(const WCHAR *z, int n){ UINT i, len; char buffer[0x10]; diff --git a/reactos/lib/msi/update.c b/reactos/lib/msi/update.c index 3ab38603a10..0af29e07b17 100644 --- a/reactos/lib/msi/update.c +++ b/reactos/lib/msi/update.c @@ -43,7 +43,7 @@ typedef struct tagMSIUPDATEVIEW MSIVIEW view; MSIDATABASE *db; MSIVIEW *wv; - value_list *vals; + column_info *vals; } MSIUPDATEVIEW; static UINT UPDATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) @@ -193,7 +193,7 @@ static MSIVIEWOPS update_ops = }; UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, - column_assignment *list, struct expr *expr ) + column_info *columns, struct expr *expr ) { MSIUPDATEVIEW *uv = NULL; UINT r; @@ -215,7 +215,7 @@ UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, } /* then select the columns we want */ - r = SELECT_CreateView( db, &sv, wv, list->col_list ); + r = SELECT_CreateView( db, &sv, wv, columns ); if( r != ERROR_SUCCESS ) { if( tv ) @@ -231,7 +231,7 @@ UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, uv->view.ops = &update_ops; msiobj_addref( &db->hdr ); uv->db = db; - uv->vals = list->val_list; + uv->vals = columns; uv->wv = sv; *view = (MSIVIEW*) uv; diff --git a/reactos/lib/msi/upgrade.c b/reactos/lib/msi/upgrade.c new file mode 100644 index 00000000000..7a066ca621a --- /dev/null +++ b/reactos/lib/msi/upgrade.c @@ -0,0 +1,228 @@ +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Actions focused on in this module + * + * FindRelatedProducts + * MigrateFeatureStates (TODO) + * RemoveExistingProducts (TODO) + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" +#include "wine/debug.h" +#include "msidefs.h" +#include "msipriv.h" +#include "winuser.h" +#include "action.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +extern const WCHAR szFindRelatedProducts[]; +extern const WCHAR szMigrateFeatureStates[]; +extern const WCHAR szRemoveExistingProducts[]; + +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; + static const WCHAR separator[] = {';',0}; + + prop = load_dynamic_property(package, action_property, NULL); + if (prop) + len = strlenW(prop); + else + len = 0; + + /*separator*/ + len ++; + + len += strlenW(productid); + + /*null*/ + len++; + + newprop = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); + + if (prop) + { + strcpyW(newprop,prop); + strcatW(newprop,separator); + } + else + newprop[0] = 0; + strcatW(newprop,productid); + + MSI_SetPropertyW(package, action_property, newprop); + TRACE("Found Related Product... %s now %s\n",debugstr_w(action_property), + debugstr_w(newprop)); + HeapFree(GetProcessHeap(),0,prop); + HeapFree(GetProcessHeap(),0,newprop); +} + +static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param) +{ + MSIPACKAGE *package = (MSIPACKAGE*)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); + TRACE("Looking at (%li) %s\n",index,debugstr_w(product)); + if (rc == ERROR_SUCCESS) + { + WCHAR productid[GUID_SIZE]; + LPCWSTR ver; + LPCWSTR language; + LPCWSTR action_property; + DWORD check = 0x00000000; + DWORD comp_ver = 0x00000000; + DWORD sz = 0x100; + HKEY hukey; + INT r; + static const WCHAR szVersion[] = + {'V','e','r','s','i','o','n',0}; + static const WCHAR szLanguage[] = + {'L','a','n','g','u','a','g','e',0}; + + unsquash_guid(product,productid); + rc = MSIREG_OpenUserProductsKey(productid, &hukey, FALSE); + if (rc != ERROR_SUCCESS) + { + rc = ERROR_SUCCESS; + index ++; + continue; + } + + sz = sizeof(DWORD); + RegQueryValueExW(hukey, szVersion, NULL, NULL, (LPBYTE)&check, + &sz); + /* check min */ + ver = MSI_RecordGetString(rec,2); + comp_ver = build_version_dword(ver); + r = check - comp_ver; + if (r < 0 || (r == 0 && !(attributes & + msidbUpgradeAttributesVersionMinInclusive))) + { + RegCloseKey(hukey); + index ++; + continue; + } + + /* check max */ + ver = MSI_RecordGetString(rec,3); + comp_ver = build_version_dword(ver); + r = check - comp_ver; + if (r > 0 || (r == 0 && !(attributes & + msidbUpgradeAttributesVersionMaxInclusive))) + { + RegCloseKey(hukey); + index ++; + continue; + } + + /* check language*/ + sz = sizeof(DWORD); + RegQueryValueExW(hukey, szLanguage, NULL, NULL, (LPBYTE)&check, + &sz); + RegCloseKey(hukey); + language = MSI_RecordGetString(rec,4); + TRACE("Checking languages 0x%lx and %s\n", check, + debugstr_w(language)); + if (!check_language(check, language, attributes)) + { + index ++; + continue; + } + + action_property = MSI_RecordGetString(rec,7); + append_productcode(package,action_property,productid); + 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}; + UINT rc = ERROR_SUCCESS; + MSIQUERY *view; + + if (package->script && package->script->FindRelatedProductsRun) + return ERROR_SUCCESS; + + if (package->script) + package->script->FindRelatedProductsRun = TRUE; + + 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; +} diff --git a/reactos/lib/msi/where.c b/reactos/lib/msi/where.c index e43e3c48984..9bad7b54c8d 100644 --- a/reactos/lib/msi/where.c +++ b/reactos/lib/msi/where.c @@ -24,7 +24,6 @@ #include "winbase.h" #include "winerror.h" #include "wine/debug.h" -#include "wine/unicode.h" #include "msi.h" #include "msiquery.h" #include "objbase.h" @@ -171,7 +170,7 @@ static UINT STRCMP_Evaluate( string_table *st, MSIVIEW *table, UINT row, else if( r_str && ! l_str ) sr = -1; else - sr = strcmpW( l_str, r_str ); + sr = lstrcmpW( l_str, r_str ); *val = ( cond->u.expr.op == OP_EQ && ( sr == 0 ) ) || ( cond->u.expr.op == OP_LT && ( sr < 0 ) ) || diff --git a/reactos/w32api/include/msi.h b/reactos/w32api/include/msi.h index 9ae0f6c2a2d..1c1278272c4 100644 --- a/reactos/w32api/include/msi.h +++ b/reactos/w32api/include/msi.h @@ -23,6 +23,10 @@ extern "C" { #endif +#ifndef _MSI_NO_CRYPTO +#include "wincrypt.h" +#endif + typedef unsigned long MSIHANDLE; typedef enum tagINSTALLSTATE @@ -201,20 +205,6 @@ UINT WINAPI MsiOpenProductA(LPCSTR, MSIHANDLE*); UINT WINAPI MsiOpenProductW(LPCWSTR, MSIHANDLE*); #define MsiOpenProduct WINELIB_NAME_AW(MsiOpenProduct) -UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE, LPCSTR, UINT, MSIHANDLE *); -UINT WINAPI MsiGetSummaryInformationW(MSIHANDLE, LPCWSTR, UINT, MSIHANDLE *); -#define MsiGetSummaryInformation WINELIB_NAME_AW(MsiGetSummaryInformation) - -UINT WINAPI MsiSummaryInfoGetPropertyA(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPSTR,DWORD*); -UINT WINAPI MsiSummaryInfoGetPropertyW(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPWSTR,DWORD*); -#define MsiSummaryInfoGetProperty WINELIB_NAME_AW(MsiSummaryInfoGetProperty) - -UINT WINAPI MsiSummaryInfoPersist(MSIHANDLE); - -UINT WINAPI MsiSummaryInfoSetPropertyA(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPSTR); -UINT WINAPI MsiSummaryInfoSetPropertyW(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPWSTR); -#define MsiSummaryInfoSetProperty WINELIB_NAME_AW(MsiSummaryInfoSetProperty) - UINT WINAPI MsiProvideComponentFromDescriptorA(LPCSTR,LPSTR,DWORD*,DWORD*); UINT WINAPI MsiProvideComponentFromDescriptorW(LPCWSTR,LPWSTR,DWORD*,DWORD*); #define MsiProvideComponentFromDescriptor WINELIB_NAME_AW(MsiProvideComponentFromDescriptor) @@ -303,10 +293,34 @@ USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR, LPSTR, DWORD*, LPSTR, DWORD*, LPSTR USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR, LPWSTR, DWORD*, LPWSTR, DWORD*, LPWSTR, DWORD*); #define MsiGetUserInfo WINELIB_NAME_AW(MsiGetUserInfo) -UINT WINAPI MsiCollectUserInfoA( LPCSTR ); -UINT WINAPI MsiCollectUserInfoW( LPCWSTR ); +UINT WINAPI MsiCollectUserInfoA(LPCSTR); +UINT WINAPI MsiCollectUserInfoW(LPCWSTR); #define MsiCollectUserInfo WINELIB_NAME_AW(MsiCollectUserInfo) +UINT WINAPI MsiReinstallFeatureA(LPCSTR, LPCSTR, DWORD); +UINT WINAPI MsiReinstallFeatureW(LPCWSTR, LPCWSTR, DWORD); +#define MsiReinstallFeature WINELIB_NAME_AW(MsiReinstallFeature) + +UINT WINAPI MsiGetShortcutTargetA(LPCSTR, LPSTR, LPSTR, LPSTR); +UINT WINAPI MsiGetShortcutTargetW(LPCWSTR, LPWSTR, LPWSTR, LPWSTR); +#define MsiGetShortcutTarget WINELIB_NAME_AW(MsiGetShortcutTarget) + +INSTALLSTATE WINAPI MsiUseFeatureW(LPCWSTR, LPCWSTR); +INSTALLSTATE WINAPI MsiUseFeatureA(LPCSTR, LPCSTR); +#define MsiUseFeature WINELIB_NAME_AW(MsiUseFeature) + +INSTALLSTATE WINAPI MsiUseFeatureExW(LPCWSTR, LPCWSTR, DWORD, DWORD); +INSTALLSTATE WINAPI MsiUseFeatureExA(LPCSTR, LPCSTR, DWORD, DWORD); +#define MsiUseFeatureEx WINELIB_NAME_AW(MsiUseFeatureEx) + +HRESULT WINAPI MsiGetFileSignatureInformationA(LPCSTR, DWORD, PCCERT_CONTEXT*, BYTE*, DWORD*); +HRESULT WINAPI MsiGetFileSignatureInformationW(LPCWSTR, DWORD, PCCERT_CONTEXT*, BYTE*, DWORD*); +#define MsiGetFileSignatureInformation WINELIB_NAME_AW(MsiGetFileSignatureInformation) + +INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR, LPSTR, DWORD *); +INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR, LPWSTR, DWORD *); +#define MsiLocateComponent WINELIB_NAME_AW(MsiLocateComponent) + /* Non Unicode */ UINT WINAPI MsiCloseHandle(MSIHANDLE); UINT WINAPI MsiCloseAllHandles(void); diff --git a/reactos/w32api/include/msidefs.h b/reactos/w32api/include/msidefs.h index 71b054b80ca..9d06d6da508 100644 --- a/reactos/w32api/include/msidefs.h +++ b/reactos/w32api/include/msidefs.h @@ -23,6 +23,15 @@ extern "C" { #endif +enum msidbUpgradeAttributes { + msidbUpgradeAttributesMigrateFeatures = 0x0000001, + msidbUpgradeAttributesOnlyDetect = 0x00000002, + msidbUpgradeAttributesIgnoreRemoveFailure = 0x00000004, + msidbUpgradeAttributesVersionMinInclusive = 0x00000100, + msidbUpgradeAttributesVersionMaxInclusive = 0x00000200, + msidbUpgradeAttributesLanguagesExclusive = 0x00000400 +}; + enum msidbFileAttributes { msidbFileAttributesReadOnly = 0x00000001, msidbFileAttributesHidden = 0x00000002, @@ -49,6 +58,51 @@ enum msidbDialogAttributes { msidbDialogAttributesError = 0x00010000 }; +enum msidbControlAttributes { + msidbControlAttributesVisible = 0x00000001, + msidbControlAttributesEnabled = 0x00000002, + msidbControlAttributesSunken = 0x00000004, + msidbControlAttributesIndirect = 0x00000008, + msidbControlAttributesInteger = 0x00000010, + msidbControlAttributesRTLRO = 0x00000020, + msidbControlAttributesRightAligned = 0x00000040, + msidbControlAttributesLeftScroll = 0x00000080, + msidbControlAttributesBiDi = 0x000000c0, + + msidbControlAttributesTransparent = 0x00010000, + msidbControlAttributesNoPrefix = 0x00020000, + msidbControlAttributesNoWrap = 0x00040000, + msidbControlAttributesFormatSize = 0x00080000, + msidbControlAttributesUsersLanguage = 0x00100000, + + msidbControlAttributesMultiline = 0x00010000, + msidbControlAttributesPasswordInput = 0x00200000, + + msidbControlAttributesProgress95 = 0x00010000, + + msidbControlAttributesRemovableVolume = 0x00010000, + msidbControlAttributesFixedVolume = 0x00020000, + msidbControlAttributesRemoteVolume = 0x00040000, + msidbControlAttributesCDROMVolume = 0x00080000, + msidbControlAttributesRAMdiskVolume = 0x00100000, + msidbControlAttributesFloppyVolume = 0x00200000, + msidbControlShowRollbackCost = 0x00400000, + + msidbControlAttributesSorted = 0x00010000, + msidbControlAttributesComboList = 0x00020000, + + msidbControlAttributesImageHandle = 0x00010000, + msidbControlAttributesPushLike = 0x00020000, + msidbControlAttributesBitmap = 0x00040000, + msidbControlAttributesIcon = 0x00080000, + msidbControlAttributesFixedSize = 0x00100000, + msidbControlAttributesIconSize16 = 0x00200000, + msidbControlAttributesIconSize32 = 0x00400000, + msidbControlAttributesIconSize48 = 0x00600000, + + msidbControlAttributesHasBorder = 0x01000000, +}; + enum msidbTextStyleStyleBits { msidbTextStyleStyleBitsBold = 0x00000001, diff --git a/reactos/w32api/include/msiquery.h b/reactos/w32api/include/msiquery.h index 9b61ae6acd4..a836f630464 100644 --- a/reactos/w32api/include/msiquery.h +++ b/reactos/w32api/include/msiquery.h @@ -53,8 +53,6 @@ typedef enum tagMSIMODIFY MSIMODIFY_VALIDATE_DELETE = 11 } MSIMODIFY; -#define MSI_NULL_INTEGER 0x80000000 - #define MSIDBOPEN_READONLY (LPCTSTR)0 #define MSIDBOPEN_TRANSACT (LPCTSTR)1 #define MSIDBOPEN_DIRECT (LPCTSTR)2 @@ -84,6 +82,43 @@ typedef enum tagMSIRUNMODE MSIRUNMODE_COMMIT = 18 } MSIRUNMODE; +typedef enum tagMSIDBERROR +{ + MSIDBERROR_INVALIDARG = -3, + MSIDBERROR_MOREDATA = -2, + MSIDBERROR_FUNCTIONERROR = -1, + MSIDBERROR_NOERROR = 0, + MSIDBERROR_DUPLICATEKEY = 1, + MSIDBERROR_REQUIRED = 2, + MSIDBERROR_BADLINK = 3, + MSIDBERROR_OVERFLOW = 4, + MSIDBERROR_UNDERFLOW = 5, + MSIDBERROR_NOTINSET = 6, + MSIDBERROR_BADVERSION = 7, + MSIDBERROR_BADCASE = 8, + MSIDBERROR_BADGUID = 9, + MSIDBERROR_BADWILDCARD = 10, + MSIDBERROR_BADIDENTIFIER = 11, + MSIDBERROR_BADLANGUAGE = 12, + MSIDBERROR_BADFILENAME = 13, + MSIDBERROR_BADPATH = 14, + MSIDBERROR_BADCONDITION = 15, + MSIDBERROR_BADFORMATTED = 16, + MSIDBERROR_BADTEMPLATE = 17, + MSIDBERROR_BADDEFAULTDIR = 18, + MSIDBERROR_BADREGPATH = 19, + MSIDBERROR_BADCUSTOMSOURCE = 20, + MSIDBERROR_BADPROPERTY = 21, + MSIDBERROR_MISSINGDATA = 22, + MSIDBERROR_BADCATEGORY = 23, + MSIDBERROR_BADKEYTABLE = 24, + MSIDBERROR_BADMAXMINVALUES = 25, + MSIDBERROR_BADCABINET = 26, + MSIDBERROR_BADSHORTCUT= 27, + MSIDBERROR_STRINGOVERFLOW = 28, + MSIDBERROR_BADLOCALIZEATTRIB = 29 +} MSIDBERROR; + /* view manipulation */ UINT WINAPI MsiViewFetch(MSIHANDLE,MSIHANDLE*); UINT WINAPI MsiViewExecute(MSIHANDLE,MSIHANDLE); @@ -91,6 +126,9 @@ UINT WINAPI MsiViewClose(MSIHANDLE); UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE,LPCSTR,MSIHANDLE*); UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE,LPCWSTR,MSIHANDLE*); #define MsiDatabaseOpenView WINELIB_NAME_AW(MsiDatabaseOpenView) +UINT WINAPI MsiViewGetErrorA(MSIHANDLE,LPSTR,DWORD*); +UINT WINAPI MsiViewGetErrorW(MSIHANDLE,LPWSTR,DWORD*); +#define MsiViewGetError WINELIB_NAME_AW(MsiViewGetError) /* record manipulation */ MSIHANDLE WINAPI MsiCreateRecord(unsigned int); @@ -175,6 +213,48 @@ UINT WINAPI MsiSetFeatureStateA(MSIHANDLE, LPCSTR, INSTALLSTATE); UINT WINAPI MsiSetFeatureStateW(MSIHANDLE, LPCWSTR, INSTALLSTATE); #define MsiSetFeatureState WINELIB_NAME_AW(MsiSetFeatureState) +UINT WINAPI MsiPreviewDialogA(MSIHANDLE, LPCSTR); +UINT WINAPI MsiPreviewDialogW(MSIHANDLE, LPCWSTR); +#define MsiPreviewDialog WINELIB_NAME_AW(MsiPreviewDialog) + +UINT WINAPI MsiPreviewBillboardA(MSIHANDLE, LPCSTR, LPCSTR); +UINT WINAPI MsiPreviewBillboardW(MSIHANDLE, LPCWSTR, LPCWSTR); +#define MsiPreviewBillboard WINELIB_NAME_AW(MsiPreviewBillboard) + +UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE, LPCSTR, UINT, MSIHANDLE *); +UINT WINAPI MsiGetSummaryInformationW(MSIHANDLE, LPCWSTR, UINT, MSIHANDLE *); +#define MsiGetSummaryInformation WINELIB_NAME_AW(MsiGetSummaryInformation) + +UINT WINAPI MsiSummaryInfoGetPropertyA(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPSTR,DWORD*); +UINT WINAPI MsiSummaryInfoGetPropertyW(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPWSTR,DWORD*); +#define MsiSummaryInfoGetProperty WINELIB_NAME_AW(MsiSummaryInfoGetProperty) + +UINT WINAPI MsiSummaryInfoSetPropertyA(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPCSTR); +UINT WINAPI MsiSummaryInfoSetPropertyW(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPCWSTR); +#define MsiSummaryInfoSetProperty WINELIB_NAME_AW(MsiSummaryInfoSetProperty) + +UINT WINAPI MsiDatabaseExportA(MSIHANDLE, LPCSTR, LPCSTR, LPCSTR); +UINT WINAPI MsiDatabaseExportW(MSIHANDLE, LPCWSTR, LPCWSTR, LPCWSTR); +#define MsiDatabaseExport WINELIB_NAME_AW(MsiDatabaseExport) + +UINT WINAPI MsiDatabaseImportA(MSIHANDLE, LPCSTR, LPCSTR); +UINT WINAPI MsiDatabaseImportW(MSIHANDLE, LPCWSTR, LPCWSTR); +#define MsiDatabaseImport WINELIB_NAME_AW(MsiDatabaseImport) + +UINT WINAPI MsiOpenDatabaseW(LPCWSTR, LPCWSTR, MSIHANDLE*); +UINT WINAPI MsiOpenDatabaseA(LPCSTR, LPCSTR, MSIHANDLE*); +#define MsiOpenDatabase WINELIB_NAME_AW(MsiOpenDatabase) + +UINT WINAPI MsiDatabaseIsTablePersistentA(MSIHANDLE, LPSTR); +UINT WINAPI MsiDatabaseIsTablePersistentW(MSIHANDLE, LPWSTR); +#define MsiDatabaseIsTablePersistent WINELIB_NAME_AW(MsiDatabaseIsTablePersistent) + +UINT WINAPI MsiSummaryInfoPersist(MSIHANDLE); +UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE,UINT*); + +UINT WINAPI MsiEnableUIPreview(MSIHANDLE, MSIHANDLE*); BOOL WINAPI MsiGetMode(MSIHANDLE, MSIRUNMODE); +UINT WINAPI MsiViewModify(MSIHANDLE, MSIMODIFY, MSIHANDLE); + #endif /* __WINE_MSIQUERY_H */