From 5df62c8577ab9e9a5877ab5928ba4251b6008d76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9=20van=20Geldorp?= Date: Mon, 14 Mar 2005 22:54:57 +0000 Subject: [PATCH] Sync to Wine-20050310: Ulrich Czekalla - Add support for radio buttons. - Allocate space for terminating null. - Fix a memory leak. - Prevent accessing freed memory in failure case. Mike McCormack - Add a border to the edit control, add some more controls. - Implement SQL delete query. - Move product, feature and component enumeration functions to registry.c. - Make sure strings are null terminated. - Fix up the summary information code a little. - Allow MsiViewExecute to be called twice on the same query. - Implement MsiDatabaseGetPrimaryKeys. - MsiGetComponentPath should allow null pointers for pcchBuf and lpPathBuf. - Remove const declaration from non-const function. Jose Manuel Ferrer Ortiz - Added MSI Spanish resources. Juan Lang - Implement MsiEnumRelatedProducts. - make sure msihandle2msiinfo is correctly matched with msiobj_release - don't do redundant NULL checks - Don't hardcode windows or system directories, correct a typo. - Fix a regression in AppSearch. Jonathan Ernst - Add French resources. Henning Gerhardt - Add/updated German resources. Marcelo Duarte - Update the resources for Portuguese. Francois Gouget - Assorted spelling fixes. Alexandre Julliard - Avoid spaces before preprocessor directives, that's not portable. Aric Stewart - Text reformatting patch to clean up all the static strings. - Implement the action RegisterFonts. - Add the ExecuteAction handler. - Store the keypath, and do refcounting and registration of SharedDLLs. - Fix a bug with handing dword values in the registry. - Fix bugs with writing registry keys where value == NULL. - Make use of msidefs.h. - Lay some groundwork for uninstalls. - Update the installed state for components during CostFinalize. Laying groundwork to be able to start processing uninstall logic as well. - Fixed problems with my code for finding the PackageCode. - Stubs for MsiUseFeature. - Do some basic work with registry component paths. - Make sure formats like [\\]] and [\\[] work properly. Steven Edwards - Correct typo. Marcus Meissner - Output some more informations. - Mark one global variable static. svn path=/trunk/; revision=14081 --- reactos/lib/msi/Makefile.in | 1 + reactos/lib/msi/action.c | 12842 ++++++++++++++++++---------------- reactos/lib/msi/action.h | 3 + reactos/lib/msi/appsearch.c | 4 +- reactos/lib/msi/delete.c | 218 + reactos/lib/msi/dialog.c | 171 +- reactos/lib/msi/format.c | 18 +- reactos/lib/msi/msi.c | 359 +- reactos/lib/msi/msi.rc | 4 + reactos/lib/msi/msi.spec | 10 +- reactos/lib/msi/msi_De.rc | 33 + reactos/lib/msi/msi_Es.rc | 33 + reactos/lib/msi/msi_Fr.rc | 33 + reactos/lib/msi/msi_Pt.rc | 33 + reactos/lib/msi/msipriv.h | 3 + reactos/lib/msi/msiquery.c | 133 +- reactos/lib/msi/package.c | 7 +- reactos/lib/msi/preview.c | 1 + reactos/lib/msi/query.h | 2 + reactos/lib/msi/record.c | 1 + reactos/lib/msi/registry.c | 315 + reactos/lib/msi/sql.tab.c | 547 +- reactos/lib/msi/sql.y | 19 +- reactos/lib/msi/suminfo.c | 42 +- reactos/lib/msi/table.c | 5 +- reactos/lib/msi/where.c | 1 + 26 files changed, 8137 insertions(+), 6701 deletions(-) create mode 100644 reactos/lib/msi/delete.c create mode 100644 reactos/lib/msi/msi_De.rc create mode 100644 reactos/lib/msi/msi_Es.rc create mode 100644 reactos/lib/msi/msi_Fr.rc create mode 100644 reactos/lib/msi/msi_Pt.rc diff --git a/reactos/lib/msi/Makefile.in b/reactos/lib/msi/Makefile.in index 27ce824fa1c..14ad0ed4a12 100644 --- a/reactos/lib/msi/Makefile.in +++ b/reactos/lib/msi/Makefile.in @@ -11,6 +11,7 @@ C_SRCS = \ appsearch.c \ create.c \ custom.c \ + delete.c \ dialog.c \ distinct.c \ format.c \ diff --git a/reactos/lib/msi/action.c b/reactos/lib/msi/action.c index 5b4c8e117c7..f03ccc6324c 100644 --- a/reactos/lib/msi/action.c +++ b/reactos/lib/msi/action.c @@ -1,6127 +1,6715 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2004 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 - */ - -/* - * Pages I need - * -http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp - -http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp - */ - -#include -#include - -#include -#define COBJMACROS - -#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 "msvcrt/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 "ver.h" -#include "action.h" - -#define REG_PROGRESS_VALUE 13200 -#define COMPONENT_PROGRESS_VALUE 24000 - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -/* - * Prototypes - */ -static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran); -static UINT ACTION_ProcessUISequence(MSIPACKAGE *package); -static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq); -static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, - LPWSTR *FilePath); - -/* - * action handlers - */ -typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*); - -static UINT ACTION_LaunchConditions(MSIPACKAGE *package); -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); -static UINT ACTION_WriteIniValues(MSIPACKAGE *package); -static UINT ACTION_SelfRegModules(MSIPACKAGE *package); -static UINT ACTION_PublishFeatures(MSIPACKAGE *package); -static UINT ACTION_RegisterProduct(MSIPACKAGE *package); -static UINT ACTION_InstallExecute(MSIPACKAGE *package); -static UINT ACTION_InstallFinalize(MSIPACKAGE *package); -static UINT ACTION_ForceReboot(MSIPACKAGE *package); -static UINT ACTION_ResolveSource(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_collen[] = {'C',':','\\',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[] = -{'I','n','s','t','a','l','l','F','i','l','e','s',0}; -const static 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','V','a','l','u','e','s',0}; -const static WCHAR szCostInitialize[] = -{'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0}; -const static WCHAR szFileCost[] = -{'F','i','l','e','C','o','s','t',0}; -const static WCHAR szInstallInitialize[] = -{'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0}; -const static WCHAR szInstallValidate[] = -{'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0}; -const static WCHAR szLaunchConditions[] = -{'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0}; -const static WCHAR szProcessComponents[] = -{'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0}; -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[] = -{'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0}; -const static 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}; -const static WCHAR szPublishProduct[] = -{'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0}; -const static WCHAR szWriteIniValues[] = -{'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0}; -const static WCHAR szSelfRegModules[] = -{'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0}; -const static WCHAR szPublishFeatures[] = -{'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0}; -const static WCHAR szRegisterProduct[] = -{'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0}; -const static WCHAR szInstallExecute[] = -{'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0}; -const static WCHAR szInstallExecuteAgain[] = -{'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0}; -const static WCHAR szInstallFinalize[] = -{'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0}; -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[] = -{'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','S','p','a','c','e',0}; -const static WCHAR szBindImage[] = -{'B','i','n','d','I','m','a','g','e',0}; -const static WCHAR szCCPSearch[] = -{'C','C','P','S','e','a','r','c','h',0}; -const static WCHAR szDeleteServices[] = -{'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0}; -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[] = -{'F','i','n','d','R','e','l','a','t','e','d','P','r','o','d','u','c','t','s',0}; -const static WCHAR szInstallAdminPackage[] = -{'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0}; -const static WCHAR szInstallSFPCatalogFile[] = -{'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','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[] = -{'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[] = -{'M','o','v','e','F','i','l','e','s',0}; -const static WCHAR szMsiPublishAssemblies[] = -{'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0}; -const static WCHAR szMsiUnpublishAssemblies[] = -{'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0}; -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[] = -{'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[] = -{'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[] = -{'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[] = -{'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[] = -{'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[] = -{'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}; -const static WCHAR szRemoveIniValues[] = -{'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0}; -const static WCHAR szRemoveODBC[] = -{'R','e','m','o','v','e','O','D','B','C',0}; -const static WCHAR szRemoveRegistryValues[] = -{'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0}; -const static WCHAR szRemoveShortcuts[] = -{'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0}; -const static WCHAR szRMCCPSearch[] = -{'R','M','C','C','P','S','e','a','r','c','h',0}; -const static WCHAR szScheduleReboot[] = -{'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0}; -const static WCHAR szSelfUnregModules[] = -{'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0}; -const static WCHAR szSetODBCFolders[] = -{'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0}; -const static WCHAR szStartServices[] = -{'S','t','a','r','t','S','e','r','v','i','c','e','s',0}; -const static WCHAR szStopServices[] = -{'S','t','o','p','S','e','r','v','i','c','e','s',0}; -const static WCHAR szUnpublishComponents[] = -{'U','n','p','u','b','l','i','s','h','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[] = -{'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[] = -{'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[] = -{'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0}; -const static 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[] = -{'U','n','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 szValidateProductID[] = -{'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0}; -const static WCHAR szWriteEnvironmentStrings[] = -{'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0}; - -struct _actions { - LPCWSTR action; - STANDARDACTIONHANDLER handler; -}; - -struct _actions StandardActions[] = { - { szAllocateRegistrySpace, NULL}, - { szAppSearch, ACTION_AppSearch }, - { szBindImage, NULL}, - { szCCPSearch, NULL}, - { szCostFinalize, ACTION_CostFinalize }, - { szCostInitialize, ACTION_CostInitialize }, - { szCreateFolders, ACTION_CreateFolders }, - { szCreateShortcuts, ACTION_CreateShortcuts }, - { szDeleteServices, NULL}, - { szDisableRollback, NULL}, - { szDuplicateFiles, ACTION_DuplicateFiles}, - { szExecuteAction, NULL}, - { szFileCost, ACTION_FileCost }, - { szFindRelatedProducts, NULL}, - { szForceReboot, ACTION_ForceReboot }, - { szInstallAdminPackage, NULL}, - { szInstallExecute, ACTION_InstallExecute }, - { szInstallExecuteAgain, ACTION_InstallExecute }, - { szInstallFiles, ACTION_InstallFiles}, - { szInstallFinalize, ACTION_InstallFinalize }, - { szInstallInitialize, ACTION_InstallInitialize }, - { szInstallSFPCatalogFile, NULL}, - { szInstallValidate, ACTION_InstallValidate }, - { szIsolateComponents, NULL}, - { szLaunchConditions, ACTION_LaunchConditions }, - { szMigrateFeatureStates, NULL}, - { szMoveFiles, NULL}, - { szMsiPublishAssemblies, NULL}, - { szMsiUnpublishAssemblies, NULL}, - { szInstallODBC, NULL}, - { szInstallServices, NULL}, - { szPatchFiles, NULL}, - { szProcessComponents, ACTION_ProcessComponents }, - { szPublishComponents, NULL}, - { szPublishFeatures, ACTION_PublishFeatures }, - { szPublishProduct, ACTION_PublishProduct }, - { szRegisterClassInfo, ACTION_RegisterClassInfo }, - { szRegisterComPlus, NULL}, - { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo }, - { szRegisterFonts, NULL}, - { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo }, - { szRegisterProduct, ACTION_RegisterProduct }, - { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo }, - { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries }, - { szRegisterUser, ACTION_RegisterUser}, - { szRemoveDuplicateFiles, NULL}, - { szRemoveEnvironmentStrings, NULL}, - { szRemoveExistingProducts, NULL}, - { szRemoveFiles, NULL}, - { szRemoveFolders, NULL}, - { szRemoveIniValues, NULL}, - { szRemoveODBC, NULL}, - { szRemoveRegistryValues, NULL}, - { szRemoveShortcuts, NULL}, - { szResolveSource, ACTION_ResolveSource}, - { szRMCCPSearch, NULL}, - { szScheduleReboot, NULL}, - { szSelfRegModules, ACTION_SelfRegModules }, - { szSelfUnregModules, NULL}, - { szSetODBCFolders, NULL}, - { szStartServices, NULL}, - { szStopServices, NULL}, - { szUnpublishComponents, NULL}, - { szUnpublishFeatures, NULL}, - { szUnregisterClassInfo, NULL}, - { szUnregisterComPlus, NULL}, - { szUnregisterExtensionInfo, NULL}, - { szUnregisterFonts, NULL}, - { szUnregisterMIMEInfo, NULL}, - { szUnregisterProgIdInfo, NULL}, - { szUnregisterTypeLibraries, NULL}, - { szValidateProductID, NULL}, - { szWriteEnvironmentStrings, NULL}, - { szWriteIniValues, ACTION_WriteIniValues }, - { szWriteRegistryValues, ACTION_WriteRegistryValues}, - { NULL, NULL}, -}; - - -/******************************************************** - * helper functions to get around current HACKS and such - ********************************************************/ -inline static void reduce_to_longfilename(WCHAR* filename) -{ - LPWSTR p = strchrW(filename,'|'); - if (p) - memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR)); -} - -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 = dupstrW(name); - package->files[index].TargetPath = dupstrW(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); - - /* no dynamic buffers in components */ - 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].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(package->dialog, 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); - return; - } - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - 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 = dupstrW(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); - - row = MSI_CreateRecord(1); - MSI_RecordSetStringW(row,1,message); - - MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row); - msiobj_release(&row->hdr); -} - - -static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action) -{ - static const WCHAR template_s[]= -{'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ','%','s','.',0}; - static const WCHAR format[] = -{'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0}; - 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]; - WCHAR timet[0x100]; - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - WCHAR *ActionText=NULL; - - GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100); - - 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; - } - - ActionText = load_dynamic_stringW(row,2); - msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); - - sprintfW(message,template_s,timet,action,ActionText); - - 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, - UINT rc) -{ - MSIRECORD * row; - static const WCHAR template_s[]= -{'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ','%','s', -'.',0}; - static const WCHAR template_e[]= -{'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ','%','s', -'.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ','%','i','.',0}; - static const WCHAR format[] = -{'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0}; - WCHAR message[1024]; - WCHAR timet[0x100]; - - GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100); - if (start) - sprintfW(message,template_s,timet,action); - else - sprintfW(message,template_e,timet,action,rc); - - row = MSI_CreateRecord(1); - MSI_RecordSetStringW(row,1,message); - - MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row); - msiobj_release(&row->hdr); -} - -/* - * 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; iPackagePath = dupstrW(szPackagePath); - path = dupstrW(szPackagePath); - p = strrchrW(path,'\\'); - if (p) - { - p++; - *p=0; - } - else - { - HeapFree(GetProcessHeap(),0,path); - path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR)); - GetCurrentDirectoryW(MAX_PATH,path); - strcatW(path,cszbs); - } - - check = load_dynamic_property(package, cszSourceDir,NULL); - if (!check) - MSI_SetPropertyW(package, cszSourceDir, path); - else - HeapFree(GetProcessHeap(), 0, check); - - HeapFree(GetProcessHeap(), 0, path); - } - - if (szCommandLine) - { - LPWSTR ptr,ptr2; - ptr = (LPWSTR)szCommandLine; - - while (*ptr) - { - WCHAR *prop = NULL; - WCHAR *val = NULL; - - TRACE("Looking at %s\n",debugstr_w(ptr)); - - ptr2 = strchrW(ptr,'='); - if (ptr2) - { - BOOL quote=FALSE; - DWORD len = 0; - - while (*ptr == ' ') ptr++; - len = ptr2-ptr; - prop = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR)); - strncpyW(prop,ptr,len); - prop[len]=0; - ptr2++; - - len = 0; - ptr = ptr2; - while (*ptr && (quote || (!quote && *ptr!=' '))) - { - if (*ptr == '"') - quote = !quote; - ptr++; - len++; - } - - if (*ptr2=='"') - { - ptr2++; - len -= 2; - } - val = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR)); - strncpyW(val,ptr2,len); - val[len] = 0; - - if (strlenW(prop) > 0) - { - TRACE("Found commandline property (%s) = (%s)\n", - debugstr_w(prop), debugstr_w(val)); - MSI_SetPropertyW(package,prop,val); - } - HeapFree(GetProcessHeap(),0,val); - HeapFree(GetProcessHeap(),0,prop); - } - ptr++; - } - } - - sz = 10; - if (MSI_GetPropertyW(package,szUILevel,buffer,&sz) == ERROR_SUCCESS) - { - if (atoiW(buffer) >= INSTALLUILEVEL_REDUCED) - { - rc = ACTION_ProcessUISequence(package); - if (rc == ERROR_SUCCESS) - rc = ACTION_ProcessExecSequence(package,TRUE); - } - else - rc = ACTION_ProcessExecSequence(package,FALSE); - } - else - rc = ACTION_ProcessExecSequence(package,FALSE); - - if (rc == -1) - { - /* install was halted but should be considered a success */ - rc = ERROR_SUCCESS; - } - - /* process the ending type action */ - if (rc == ERROR_SUCCESS) - ACTION_PerformActionSequence(package,-1); - else if (rc == ERROR_INSTALL_USEREXIT) - ACTION_PerformActionSequence(package,-2); - else if (rc == ERROR_FUNCTION_FAILED) - ACTION_PerformActionSequence(package,-3); - else if (rc == ERROR_INSTALL_SUSPEND) - ACTION_PerformActionSequence(package,-4); - - /* finish up running custom actions */ - ACTION_FinishCustomActions(package); - - return rc; -} - -static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq) -{ - MSIQUERY * view; - UINT rc; - WCHAR buffer[0x100]; - DWORD sz = 0x100; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = { - 's','e','l','e','c','t',' ','*',' ', - 'f','r','o','m',' ', - 'I','n','s','t','a','l','l','E','x','e','c','u','t','e', - 'S','e','q','u','e','n','c','e',' ', - 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', - '=',' ','%','i',0}; - - rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq); - - 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"); - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - goto end; - } - - /* 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); - goto end; - } - 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); - goto end; - } - - rc = ACTION_PerformAction(package,buffer); - msiobj_release(&row->hdr); -end: - MSI_ViewClose(view); - msiobj_release(&view->hdr); - } - else - rc = ERROR_SUCCESS; - - return rc; -} - -static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran) -{ - MSIQUERY * view; - UINT rc; - static const WCHAR ExecSeqQuery[] = { - 's','e','l','e','c','t',' ','*',' ', - 'f','r','o','m',' ', - 'I','n','s','t','a','l','l','E','x','e','c','u','t','e', - 'S','e','q','u','e','n','c','e',' ', - 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', - '>',' ','%','i',' ','o','r','d','e','r',' ', - 'b','y',' ','S','e','q','u','e','n','c','e',0 }; - MSIRECORD * row = 0; - static const WCHAR IVQuery[] = { - 's','e','l','e','c','t',' ','S','e','q','u','e','n','c','e',' ', - 'f','r','o','m',' ','I','n','s','t','a','l','l', - 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e',' ', - 'w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',' ', - '`','I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','`', - 0}; - INT seq = 0; - - /* 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; - } - 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); - - 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); - msiobj_release(&view->hdr); - } - -end: - return rc; -} - - -static UINT ACTION_ProcessUISequence(MSIPACKAGE *package) -{ - MSIQUERY * view; - UINT rc; - static const WCHAR ExecSeqQuery [] = { - 's','e','l','e','c','t',' ','*',' ', - 'f','r','o','m',' ','I','n','s','t','a','l','l', - 'U','I','S','e','q','u','e','n','c','e',' ', - 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', '>',' ','0',' ', - 'o','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e',0}; - - 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); - 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) -{ - BOOL ret = FALSE; - - int i; - 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) - { - *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; - } - i++; - } - return ret; -} - -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) -{ - BOOL ret=FALSE; - UINT arc; - - arc = ACTION_CustomAction(package,action,FALSE); - - if (arc != ERROR_CALL_NOT_IMPLEMENTED) - { - *rc = arc; - ret = TRUE; - } - return ret; -} - -/* - * A lot of actions are really important even if they don't do anything - * explicit... Lots of properties are set at the beginning of the installation - * CostFinalize does a bunch of work to translate the directories and such - * - * 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 rc = ERROR_SUCCESS; - BOOL handled; - - TRACE("Performing action (%s)\n",debugstr_w(action)); - - handled = ACTION_HandleStandardAction(package, action, &rc); - - if (!handled) - handled = ACTION_HandleCustomAction(package, action, &rc); - - if (!handled) - { - FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action)); - rc = ERROR_FUNCTION_NOT_CALLED; - } - - package->CurrentInstallState = rc; - return rc; -} - -UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action) -{ - UINT rc = ERROR_SUCCESS; - BOOL handled = FALSE; - - TRACE("Performing action (%s)\n",debugstr_w(action)); - - handled = ACTION_HandleStandardAction(package, action, &rc); - - if (!handled) - handled = ACTION_HandleCustomAction(package, action, &rc); - - if (!handled) - handled = ACTION_HandleDialogBox(package, action, &rc); - - msi_dialog_check_messages( package->dialog, NULL ); - - if (!handled) - { - FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action)); - rc = ERROR_FUNCTION_NOT_CALLED; - } - - package->CurrentInstallState = rc; - return rc; -} - -/*********************************************************************** - * create_full_pathW - * - * Recursively create all directories in the path. - * - * shamelessly stolen from setupapi/queue.c - */ -static BOOL create_full_pathW(const WCHAR *path) -{ - BOOL ret = TRUE; - int len; - WCHAR *new_path; - - 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)) - { - 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] = '\\'; - } - - HeapFree(GetProcessHeap(), 0, new_path); - return ret; -} - -/* - * Also we cannot enable/disable components either, so for now I am just going - * to do all the directories for all the components. - */ -static UINT ACTION_CreateFolders(MSIPACKAGE *package) -{ - static const WCHAR ExecSeqQuery[] = { - 's','e','l','e','c','t',' ','D','i','r','e','c','t','o','r','y','_',' ', - 'f','r','o','m',' ','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); - msiobj_release(&view->hdr); - - return rc; -} - -static int load_component(MSIPACKAGE* package, MSIRECORD * row) -{ - int index = package->loaded_components; - DWORD sz; - - /* fill in the data */ - - package->loaded_components++; - if (package->loaded_components == 1) - package->components = HeapAlloc(GetProcessHeap(),0, - sizeof(MSICOMPONENT)); - else - package->components = HeapReAlloc(GetProcessHeap(),0, - package->components, package->loaded_components * - sizeof(MSICOMPONENT)); - - memset(&package->components[index],0,sizeof(MSICOMPONENT)); - - sz = 96; - MSI_RecordGetStringW(row,1,package->components[index].Component,&sz); - - TRACE("Loading Component %s\n", - debugstr_w(package->components[index].Component)); - - sz = 0x100; - if (!MSI_RecordIsNull(row,2)) - MSI_RecordGetStringW(row,2,package->components[index].ComponentId,&sz); - - sz = 96; - MSI_RecordGetStringW(row,3,package->components[index].Directory,&sz); - - package->components[index].Attributes = MSI_RecordGetInteger(row,4); - - sz = 0x100; - MSI_RecordGetStringW(row,5,package->components[index].Condition,&sz); - - sz = 96; - MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz); - - package->components[index].Installed = INSTALLSTATE_ABSENT; - package->components[index].Action = INSTALLSTATE_UNKNOWN; - package->components[index].ActionRequest = INSTALLSTATE_UNKNOWN; - - package->components[index].Enabled = TRUE; - - return index; -} - -static void load_feature(MSIPACKAGE* package, MSIRECORD * row) -{ - int index = package->loaded_features; - DWORD sz; - static const WCHAR Query1[] = {'S','E','L','E','C','T',' ','C','o','m','p', - 'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e', - 'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e', - 'a','t','u','r','e','_','=','\'','%','s','\'',0}; - 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; - - /* fill in the data */ - - package->loaded_features ++; - if (package->loaded_features == 1) - package->features = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE)); - else - package->features = HeapReAlloc(GetProcessHeap(),0,package->features, - package->loaded_features * sizeof(MSIFEATURE)); - - memset(&package->features[index],0,sizeof(MSIFEATURE)); - - sz = 96; - MSI_RecordGetStringW(row,1,package->features[index].Feature,&sz); - - TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature)); - - sz = 96; - if (!MSI_RecordIsNull(row,2)) - MSI_RecordGetStringW(row,2,package->features[index].Feature_Parent,&sz); - - sz = 0x100; - if (!MSI_RecordIsNull(row,3)) - MSI_RecordGetStringW(row,3,package->features[index].Title,&sz); - - sz = 0x100; - if (!MSI_RecordIsNull(row,4)) - MSI_RecordGetStringW(row,4,package->features[index].Description,&sz); - - if (!MSI_RecordIsNull(row,5)) - package->features[index].Display = MSI_RecordGetInteger(row,5); - - package->features[index].Level= MSI_RecordGetInteger(row,6); - - sz = 96; - if (!MSI_RecordIsNull(row,7)) - MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz); - - package->features[index].Attributes= MSI_RecordGetInteger(row,8); - - package->features[index].Installed = INSTALLSTATE_ABSENT; - package->features[index].Action = INSTALLSTATE_UNKNOWN; - package->features[index].ActionRequest = INSTALLSTATE_UNKNOWN; - - /* load feature components */ - - 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; - - 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 ++; - 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); - msiobj_release(&view->hdr); -} - -/* - * I am not doing any of the costing functionality yet. - * Mostly looking at doing the Component and Feature loading - * - * The native MSI does A LOT of modification to tables here. Mostly adding - * a lot of temporary columns to the Feature and Component tables. - * - * note: Native msi also tracks the short filename. But I am only going to - * track the long ones. Also looking at this directory table - * it appears that the directory table does not get the parents - * resolved base on property only based on their entries in the - * directory table. - */ -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',' ','F','e','a','t','u','r','e',0}; - static const WCHAR szCosting[] = { - 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 }; - static const WCHAR szZero[] = { '0', 0 }; - - MSI_SetPropertyW(package, szCosting, szZero); - MSI_SetPropertyW(package, cszRootDrive , c_collen); - - 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); - msiobj_release(&view->hdr); - - return ERROR_SUCCESS; -} - -static UINT load_file(MSIPACKAGE* package, MSIRECORD * row) -{ - DWORD index = package->loaded_files; - DWORD i; - LPWSTR buffer; - - /* fill in the data */ - - 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 = 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; - } - if (package->files[index].ComponentIndex == -1) - ERR("Unfound Component %s\n",debugstr_w(buffer)); - HeapFree(GetProcessHeap(), 0, buffer); - - package->files[index].FileName = load_dynamic_stringW(row,3); - - reduce_to_longfilename(package->files[index].FileName); - - package->files[index].FileSize = MSI_RecordGetInteger(row,4); - package->files[index].Version = load_dynamic_stringW(row, 5); - package->files[index].Language = load_dynamic_stringW(row, 6); - package->files[index].Attributes= MSI_RecordGetInteger(row,7); - package->files[index].Sequence= MSI_RecordGetInteger(row,8); - - package->files[index].Temporary = FALSE; - package->files[index].State = 0; - - TRACE("File Loaded (%s)\n",debugstr_w(package->files[index].File)); - - return ERROR_SUCCESS; -} - -static UINT ACTION_FileCost(MSIPACKAGE *package) -{ - MSIQUERY * view; - MSIRECORD * row; - UINT rc; - static const WCHAR Query[] = { - 'S','E','L','E','C','T',' ','*',' ', - 'F','R','O','M',' ','F','i','l','e',' ', - 'O','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e', 0}; - - if (!package) - return ERROR_INVALID_HANDLE; - - 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); - msiobj_release(&view->hdr); - - return ERROR_SUCCESS; -} - -static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) - -{ - static const WCHAR Query[] = - {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c', - 't','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t', - 'o','r','y','`',' ','=',' ','`','%','s','`',0}; - UINT rc; - MSIQUERY * view; - LPWSTR targetdir, parent, srcdir; - MSIRECORD * row = 0; - INT index = -1; - DWORD i; - - TRACE("Looking for dir %s\n",debugstr_w(dir)); - - for (i = 0; i < package->loaded_folders; i++) - { - if (strcmpW(package->folders[i].Directory,dir)==0) - { - TRACE(" %s retuning on index %lu\n",debugstr_w(dir),i); - return i; - } - } - - TRACE("Working to load %s\n",debugstr_w(dir)); - - index = package->loaded_folders++; - if (package->loaded_folders==1) - package->folders = HeapAlloc(GetProcessHeap(),0, - sizeof(MSIFOLDER)); - else - package->folders= HeapReAlloc(GetProcessHeap(),0, - package->folders, package->loaded_folders* - sizeof(MSIFOLDER)); - - memset(&package->folders[index],0,sizeof(MSIFOLDER)); - - package->folders[index].Directory = dupstrW(dir); - - rc = MSI_OpenQuery(package->db, &view, Query, dir); - if (rc != ERROR_SUCCESS) - 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; - } - - targetdir = load_dynamic_stringW(row,3); - - /* split src and target dir */ - if (strchrW(targetdir,':')) - { - srcdir=strchrW(targetdir,':'); - *srcdir=0; - srcdir ++; - } - else - srcdir=NULL; - - /* for now only pick long filename versions */ - if (strchrW(targetdir,'|')) - { - targetdir = strchrW(targetdir,'|'); - *targetdir = 0; - targetdir ++; - } - if (srcdir && strchrW(srcdir,'|')) - { - srcdir= strchrW(srcdir,'|'); - *srcdir= 0; - srcdir ++; - } - - /* now check for root dirs */ - if (targetdir[0] == '.' && targetdir[1] == 0) - targetdir = NULL; - - if (srcdir && srcdir[0] == '.' && srcdir[1] == 0) - srcdir = NULL; - - if (targetdir) - { - TRACE(" TargetDefault = %s\n",debugstr_w(targetdir)); - HeapFree(GetProcessHeap(),0, package->folders[index].TargetDefault); - package->folders[index].TargetDefault = dupstrW(targetdir); - } - - if (srcdir) - package->folders[index].SourceDefault = dupstrW(srcdir); - else if (targetdir) - package->folders[index].SourceDefault = dupstrW(targetdir); - HeapFree(GetProcessHeap(), 0, targetdir); - - parent = load_dynamic_stringW(row,2); - if (parent) - { - i = load_folder(package,parent); - package->folders[index].ParentIndex = i; - TRACE("Parent is index %i... %s %s\n", - package->folders[index].ParentIndex, - debugstr_w(package->folders[package->folders[index].ParentIndex].Directory), - debugstr_w(parent)); - } - 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 = dupstrW(package->folders[i].ResolvedTarget); - TRACE(" already resolved to %s\n",debugstr_w(path)); - return path; - } - else if (source && package->folders[i].ResolvedSource) - { - path = dupstrW(package->folders[i].ResolvedSource); - 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 = dupstrW(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); - package->folders[i].ResolvedSource = dupstrW(path); - } - HeapFree(GetProcessHeap(),0,p); - } - return path; -} - -/* 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]]; - - if (!component->Enabled) - continue; - else - { - if (newstate == INSTALLSTATE_LOCAL) - component->ActionRequest = INSTALLSTATE_LOCAL; - else - { - int j,k; - - component->ActionRequest = 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) - component->ActionRequest = INSTALLSTATE_LOCAL; - break; - } - } - } - } - } -} - -static UINT SetFeatureStates(MSIPACKAGE *package) -{ - LPWSTR level; - INT install_level; - DWORD i; - INT j; - LPWSTR override = NULL; - static const WCHAR all[]={'A','L','L',0}; - static const WCHAR szlevel[] = { - 'I','N','S','T','A','L','L','L','E','V','E','L',0}; - static const WCHAR szAddLocal[] = { - 'A','D','D','L','O','C','A','L',0}; - - /* I do not know if this is where it should happen.. but */ - - TRACE("Checking Install Level\n"); - - level = load_dynamic_property(package,szlevel,NULL); - if (level) - { - install_level = atoiW(level); - HeapFree(GetProcessHeap(), 0, level); - } - else - install_level = 1; - - /* ok hereis the rub - * ADDLOCAL and its friend OVERRIDE INSTALLLEVLE - * I have confirmed this if ADDLOCALis stated then the INSTALLLEVEL is - * itnored for all the features. seems strange, epsecially since it is not - * documented anywhere, but it is how it works. - */ - - override = load_dynamic_property(package,szAddLocal,NULL); - - if (override) - { - for(i = 0; i < package->loaded_features; i++) - { - if (strcmpiW(override,all)==0) - { - package->features[i].ActionRequest= INSTALLSTATE_LOCAL; - package->features[i].Action = INSTALLSTATE_LOCAL; - } - else - { - LPWSTR ptr = override; - LPWSTR ptr2 = strchrW(override,','); - - while (ptr) - { - if ((ptr2 && - strncmpW(ptr,package->features[i].Feature, ptr2-ptr)==0) - || (!ptr2 && - strcmpW(ptr,package->features[i].Feature)==0)) - { - package->features[i].ActionRequest= INSTALLSTATE_LOCAL; - package->features[i].Action = INSTALLSTATE_LOCAL; - break; - } - if (ptr2) - { - ptr=ptr2+1; - ptr2 = strchrW(ptr,','); - } - else - break; - } - } - } - HeapFree(GetProcessHeap(),0,override); - } - else - { - for(i = 0; i < package->loaded_features; i++) - { - BOOL feature_state= ((package->features[i].Level > 0) && - (package->features[i].Level <= install_level)); - - if (feature_state) - { - package->features[i].ActionRequest= INSTALLSTATE_LOCAL; - package->features[i].Action = INSTALLSTATE_LOCAL; - } - } - } - - /* - * now we want to enable or disable components base on feature - */ - - for(i = 0; i < package->loaded_features; i++) - { - MSIFEATURE* feature = &package->features[i]; - TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n", - debugstr_w(feature->Feature), feature->Installed, feature->Action, - feature->ActionRequest); - - for( j = 0; j < feature->ComponentCount; j++) - { - MSICOMPONENT* component = &package->components[ - feature->Components[j]]; - - if (!component->Enabled) - { - component->Action = INSTALLSTATE_ABSENT; - component->ActionRequest = INSTALLSTATE_ABSENT; - } - else - { - if (feature->Action == INSTALLSTATE_LOCAL) - component->Action = INSTALLSTATE_LOCAL; - if (feature->ActionRequest == INSTALLSTATE_LOCAL) - component->ActionRequest = INSTALLSTATE_LOCAL; - } - } - } - - for(i = 0; i < package->loaded_components; i++) - { - MSICOMPONENT* component= &package->components[i]; - - TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n", - debugstr_w(component->Component), component->Installed, - component->Action, component->ActionRequest); - } - - - 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 - * to focus on the directory building - * - */ -static UINT ACTION_CostFinalize(MSIPACKAGE *package) -{ - static const WCHAR ExecSeqQuery[] = { - 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ', - 'D','i','r','e','c','t','o','r','y',0}; - static const WCHAR ConditionQuery[] = { - 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ', - 'C','o','n','d','i','t','i','o','n',0}; - static const WCHAR szCosting[] = { - 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 }; - static const WCHAR szlevel[] = { - 'I','N','S','T','A','L','L','L','E','V','E','L',0}; - static const WCHAR szOne[] = { '1', 0 }; - UINT rc; - MSIQUERY * view; - DWORD i; - LPWSTR level; - - TRACE("Building Directory properties\n"); - - 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); - msiobj_release(&view->hdr); - } - - TRACE("File calculations %i files\n",package->loaded_files); - - for (i = 0; i < package->loaded_files; i++) - { - MSICOMPONENT* comp = NULL; - MSIFILE* file= NULL; - - file = &package->files[i]; - if (file->ComponentIndex >= 0) - comp = &package->components[file->ComponentIndex]; - - if (file->Temporary == TRUE) - continue; - - if (comp) - { - LPWSTR p; - - /* calculate target */ - p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL); - - HeapFree(GetProcessHeap(),0,file->TargetPath); - - TRACE("file %s is named %s\n", - debugstr_w(file->File),debugstr_w(file->FileName)); - - file->TargetPath = build_directory_name(2, p, file->FileName); - - HeapFree(GetProcessHeap(),0,p); - - TRACE("file %s resolves to %s\n", - debugstr_w(file->File),debugstr_w(file->TargetPath)); - - if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES) - { - file->State = 1; - comp->Cost += file->FileSize; - } - else - { - if (file->Version) - { - DWORD handle; - DWORD versize; - UINT sz; - LPVOID version; - static const WCHAR name[] = - {'\\',0}; - static const WCHAR name_fmt[] = - {'%','u','.','%','u','.','%','u','.','%','u',0}; - WCHAR filever[0x100]; - VS_FIXEDFILEINFO *lpVer; - - TRACE("Version comparison.. \n"); - versize = GetFileVersionInfoSizeW(file->TargetPath,&handle); - version = HeapAlloc(GetProcessHeap(),0,versize); - GetFileVersionInfoW(file->TargetPath, 0, versize, version); - - VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz); - - sprintfW(filever,name_fmt, - HIWORD(lpVer->dwFileVersionMS), - LOWORD(lpVer->dwFileVersionMS), - HIWORD(lpVer->dwFileVersionLS), - LOWORD(lpVer->dwFileVersionLS)); - - TRACE("new %s old %s\n", debugstr_w(file->Version), - debugstr_w(filever)); - if (strcmpiW(filever,file->Version)<0) - { - file->State = 2; - FIXME("cost should be diff in size\n"); - comp->Cost += file->FileSize; - } - else - file->State = 3; - HeapFree(GetProcessHeap(),0,version); - } - else - file->State = 3; - } - } - } - - TRACE("Evaluating Condition Table\n"); - - 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); - msiobj_release(&view->hdr); - } - - TRACE("Enabling or Disabling Components\n"); - for (i = 0; i < package->loaded_components; i++) - { - if (package->components[i].Condition[0]) - { - if (MSI_EvaluateConditionW(package, - package->components[i].Condition) == MSICONDITION_FALSE) - { - TRACE("Disabling component %s\n", - debugstr_w(package->components[i].Component)); - package->components[i].Enabled = FALSE; - } - } - } - - MSI_SetPropertyW(package,szCosting,szOne); - /* set default run level if not set */ - level = load_dynamic_property(package,szlevel,NULL); - if (!level) - MSI_SetPropertyW(package,szlevel, szOne); - else - HeapFree(GetProcessHeap(),0,level); - - 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) - { - 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 && strcmp(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, UINT sequence, - WCHAR* path, WCHAR* 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 (sequence <= last_sequence) - { - TRACE("Media already ready (%u, %u)\n",sequence,last_sequence); - /*extract_a_cabinet_file(package, source,path,file); */ - return ERROR_SUCCESS; - } - - sprintfW(Query,ExecSeqQuery,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 (package->components[file->ComponentIndex].ActionRequest != - 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; - INT len; - MSICOMPONENT* comp = NULL; - - TRACE("Installing %s\n",debugstr_w(file->File)); - rc = ready_media_for_file(package,file->Sequence,path_to_source, - file->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); - - len = strlenW(path_to_source) + strlenW(file->File) + 2; - file->SourcePath = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); - strcpyW(file->SourcePath, path_to_source); - strcatW(file->SourcePath, 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 (!MoveFileW(file->SourcePath,file->TargetPath)) - { - rc = GetLastError(); - ERR("Unable to move file (%s -> %s) (error %d)\n", - debugstr_w(file->SourcePath), debugstr_w(file->TargetPath), - rc); - if (rc == ERROR_ALREADY_EXISTS && file->State == 2) - { - CopyFileW(file->SourcePath,file->TargetPath,FALSE); - DeleteFileW(file->SourcePath); - rc = 0; - } - else if (rc == ERROR_FILE_NOT_FOUND) - { - ERR("Source File Not Found! Continueing\n"); - rc = 0; - } - else - { - ERR("Ignoring Error and continuing...\n"); - rc = 0; - } - } - else - file->State = 4; - } - } - - 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 = dupstrW(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 (package->components[component_index].ActionRequest != - 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; - package->components[component_index].Installed = 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 = dupstrW(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); - HeapFree(GetProcessHeap(), 0, dest_path); - - 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\n"); - - FIXME("We should track these duplicate files as well\n"); - - msiobj_release(&row->hdr); - 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, - DWORD *size) -{ - LPSTR data = NULL; - if (value[0]=='#' && value[1]!='#' && value[1]!='%') - { - if (value[1]=='x') - { - LPWSTR ptr; - CHAR byte[5]; - LPWSTR deformated; - int count; - - deformat_string(package, &value[2], &deformated); - - /* binary value type */ - ptr = deformated; - *type=REG_BINARY; - *size = strlenW(ptr)/2; - data = HeapAlloc(GetProcessHeap(),0,*size); - - byte[0] = '0'; - byte[1] = 'x'; - byte[4] = 0; - count = 0; - while (*ptr) - { - byte[2]= *ptr; - ptr++; - byte[3]= *ptr; - ptr++; - data[count] = (BYTE)strtol(byte,NULL,0); - count ++; - } - HeapFree(GetProcessHeap(),0,deformated); - - TRACE("Data %li bytes(%i)\n",*size,count); - } - else - { - LPWSTR deformated; - deformat_string(package, &value[1], &deformated); - - *type=REG_DWORD; - *size = sizeof(DWORD); - data = HeapAlloc(GetProcessHeap(),0,*size); - *(LPDWORD)data = atoiW(deformated); - TRACE("DWORD %i\n",*data); - - HeapFree(GetProcessHeap(),0,deformated); - } - } - else - { - static const WCHAR szMulti[] = {'[','~',']',0}; - WCHAR *ptr; - *type=REG_SZ; - - if (value[0]=='#') - { - if (value[1]=='%') - { - ptr = &value[2]; - *type=REG_EXPAND_SZ; - } - else - ptr = &value[1]; - } - else - ptr=value; - - if (strstrW(value,szMulti)) - *type = REG_MULTI_SZ; - - *size = deformat_string(package, ptr,(LPWSTR*)&data); - } - return data; -} - -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 }; - - 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; - } - - /* 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}; - - 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; - - 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 (package->components[component_index].ActionRequest != - 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; - package->components[component_index].Installed = INSTALLSTATE_LOCAL; - - /* null values have special meanings during uninstalls and such */ - - if(MSI_RecordIsNull(row,5)) - { - msiobj_release(&row->hdr); - goto next; - } - - root = MSI_RecordGetInteger(row,2); - key = load_dynamic_stringW(row, 3); - - name = load_dynamic_stringW(row, 4); - - /* 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); - value_data = parse_value(package, value, &type, &size); - - deformat_string(package, name, &deformated); - - if (value_data) - { - TRACE("Setting value %s\n",debugstr_w(deformated)); - 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) -{ - return ERROR_SUCCESS; -} - - -static UINT ACTION_InstallValidate(MSIPACKAGE *package) -{ - DWORD progress = 0; - DWORD total = 0; - static const WCHAR q1[]={ - 'S','E','L','E','C','T',' ','*',' ', - 'F','R','O','M',' ','R','e','g','i','s','t','r','y',0}; - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - int i; - - TRACE(" InstallValidate \n"); - - rc = MSI_DatabaseOpenViewW(package->db, q1, &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) - { - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - progress +=1; - - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - - total = total + progress * REG_PROGRESS_VALUE; - total = total + package->loaded_components * COMPONENT_PROGRESS_VALUE; - for (i=0; i < package->loaded_files; i++) - total += package->files[i].FileSize; - ui_progress(package,0,total,0,0); - - 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"); - - 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; - } - - 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); - msiobj_release(&view->hdr); - return rc; -} - -static LPWSTR resolve_keypath( MSIPACKAGE* package, INT - component_index) -{ - MSICOMPONENT* cmp = &package->components[component_index]; - - if (cmp->KeyPath[0]==0) - { - LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL); - return p; - } - if (cmp->Attributes & 0x4) - { - MSIQUERY * view; - MSIRECORD * row = 0; - UINT rc,root,len; - LPWSTR key,deformated,buffer,name,deformated_name; - static const WCHAR ExecSeqQuery[] = { - 's','e','l','e','c','t',' ','*',' ', - 'f','r','o','m',' ','R','e','g','i','s','t','r','y',' ', -'w','h','e','r','e',' ','R','e','g','i','s','t','r','y',' ','=',' ' -,'`','%','s','`',0 }; - static const WCHAR fmt[]={'%','0','2','i',':','%','s',0}; - static const WCHAR fmt2[]={'%','0','2','i',':','%','s','\\','%','s',0}; - - rc = MSI_OpenQuery(package->db,&view,ExecSeqQuery,cmp->KeyPath); - - if (rc!=ERROR_SUCCESS) - 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); - deformat_string(package, key , &deformated); - deformat_string(package, name, &deformated_name); - - len = strlenW(deformated) + 5; - if (deformated_name) - len+=strlenW(deformated_name); - - buffer = HeapAlloc(GetProcessHeap(),0, len *sizeof(WCHAR)); - - if (deformated_name) - sprintfW(buffer,fmt2,root,deformated,deformated_name); - 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; - } - else if (cmp->Attributes & 0x20) - { - FIXME("UNIMPLEMENTED keypath as ODBC Source\n"); - return NULL; - } - else - { - int j; - j = get_loaded_file(package,cmp->KeyPath); - - if (j>=0) - { - LPWSTR p = dupstrW(package->files[j].TargetPath); - return p; - } - } - return NULL; -} - -/* - * Ok further analysis makes me think that this work is - * actually done in the PublishComponents and PublishFeatures - * step, and not here. It appears like the keypath and all that is - * resolved in this step, however actually written in the Publish steps. - * But we will leave it here for now because it is unclear - */ -static UINT ACTION_ProcessComponents(MSIPACKAGE *package) -{ - LPWSTR productcode; - WCHAR squished_pc[GUID_SIZE]; - WCHAR squished_cc[GUID_SIZE]; - UINT rc; - DWORD i; - HKEY hkey=0,hkey2=0; - static const WCHAR szProductCode[]= - {'P','r','o','d','u','c','t','C','o','d','e',0}; - - if (!package) - return ERROR_INVALID_HANDLE; - - /* writes the Component and Features values to the registry */ - productcode = load_dynamic_property(package,szProductCode,&rc); - if (!productcode) - return rc; - - rc = MSIREG_OpenComponents(&hkey); - if (rc != ERROR_SUCCESS) - goto end; - - squash_guid(productcode,squished_pc); - ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0); - for (i = 0; i < package->loaded_components; i++) - { - ui_progress(package,2,0,0,0); - if (package->components[i].ComponentId[0]!=0) - { - WCHAR *keypath = NULL; - MSIRECORD * uirow; - - squash_guid(package->components[i].ComponentId,squished_cc); - rc = RegCreateKeyW(hkey,squished_cc,&hkey2); - if (rc != ERROR_SUCCESS) - continue; - - keypath = resolve_keypath(package,i); - if (keypath) - { - RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath, - (strlenW(keypath)+1)*sizeof(WCHAR)); - RegCloseKey(hkey2); - - /* UI stuff */ - uirow = MSI_CreateRecord(3); - MSI_RecordSetStringW(uirow,1,productcode); - MSI_RecordSetStringW(uirow,2,package->components[i]. - ComponentId); - MSI_RecordSetStringW(uirow,3,keypath); - ui_actiondata(package,szProcessComponents,uirow); - msiobj_release( &uirow->hdr ); - HeapFree(GetProcessHeap(),0,keypath); - } - } - } -end: - HeapFree(GetProcessHeap(), 0, productcode); - RegCloseKey(hkey); - return rc; -} - -static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) -{ - /* - * OK this is a bit confusing.. I am given a _Component key and I believe - * that the file that is being registered as a type library is the "key file - * of that component" which I interpret to mean "The file in the KeyPath of - * that component". - */ - 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}; - ITypeLib *ptLib; - HRESULT res; - - if (!package) - return ERROR_INVALID_HANDLE; - - 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) - { - WCHAR component[0x100]; - DWORD sz; - INT index; - - 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 (package->components[index].ActionRequest != 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; - package->components[index].Installed = INSTALLSTATE_LOCAL; - - index = get_loaded_file(package,package->components[index].KeyPath); - - if (index < 0) - { - msiobj_release(&row->hdr); - continue; - } - - res = LoadTypeLib(package->files[index].TargetPath,&ptLib); - if (SUCCEEDED(res)) - { - LPWSTR help; - WCHAR helpid[0x100]; - - sz = 0x100; - MSI_RecordGetStringW(row,6,helpid,&sz); - - help = resolve_folder(package,helpid,FALSE,FALSE,NULL); - res = RegisterTypeLib(ptLib,package->files[index].TargetPath,help); - HeapFree(GetProcessHeap(),0,help); - - if (!SUCCEEDED(res)) - ERR("Failed to register type library %s\n", - debugstr_w(package->files[index].TargetPath)); - else - { - /* Yes the row has more fields than I need, but #1 is - correct and the only one I need. Why make a new row? */ - - ui_actiondata(package,szRegisterTypeLibraries,row); - - TRACE("Registered %s\n", - debugstr_w(package->files[index].TargetPath)); - } - - if (ptLib) - ITypeLib_Release(ptLib); - } - else - ERR("Failed to load type library %s\n", - debugstr_w(package->files[index].TargetPath)); - - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - -} - -static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app ) -{ - 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 (package->components[index].ActionRequest != INSTALLSTATE_LOCAL) - { - 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; - package->components[index].Installed = 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 = (LPWSTR)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]; - DWORD sz; - - - sz = 0x100; - MSI_RecordGetStringW(row,1,buffer,&sz); - RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey); - - 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,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); - } - else - { - FIXME("UNHANDLED case, Parent progid but classid is NULL\n"); - return ERROR_FUNCTION_FAILED; - } - if (!MSI_RecordIsNull(row,5)) - { - 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); - } - return ERROR_SUCCESS; -} - -static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid); - -static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent, - LPWSTR clsid) -{ - UINT rc; - 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}; - - if (!package) - return ERROR_INVALID_HANDLE; - - 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) - { - 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 szProductCode[] = - {'P','r','o','d','u','c','t','C','o','d','e',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)) - { - ERR("CoInitialize failed\n"); - 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 (package->components[index].ActionRequest != 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; - package->components[index].Installed = 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 - { - FIXME("UNHANDLED shortcut format, advertised shortcut\n"); - IPersistFile_Release( pf ); - IShellLinkW_Release( sl ); - msiobj_release(&row->hdr); - continue; - } - - 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); - msiobj_release(&view->hdr); - - - CoUninitialize(); - - return rc; -} - - -/* - * 99% of the work done here is only done for - * advertised installs. However this is where the - * Icon table is processed and written out - * so that is what I am going to do here. - */ -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; - HKEY hukey=0; - static const WCHAR szProductCode[]= - {'P','r','o','d','u','c','t','C','o','d','e',0}; - static const WCHAR szProductName[] = { - '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}; - LPWSTR buffer; - DWORD size; - MSIHANDLE hDb, hSumInfo; - - if (!package) - return ERROR_INVALID_HANDLE; - - rc = MSI_DatabaseOpenViewW(package->db, Query, &view); - if (rc != ERROR_SUCCESS) - goto next; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - 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; - - rc = MSIREG_OpenProductsKey(productcode,&hkey,TRUE); - if (rc != ERROR_SUCCESS) - goto end; - - rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE); - if (rc != ERROR_SUCCESS) - goto end; - - - buffer = load_dynamic_property(package,szProductName,NULL); - size = strlenW(buffer)*sizeof(WCHAR); - RegSetValueExW(hukey,szProductName,0,REG_SZ, (LPSTR)buffer,size); - HeapFree(GetProcessHeap(),0,buffer); - FIXME("Need to write more keys to the user registry\n"); - - hDb= msiobj_findhandle( &package->db->hdr ); - rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo); - if (rc == ERROR_SUCCESS) - { - WCHAR guidbuffer[0x200]; - size = 0x200; - rc = MsiSummaryInfoGetPropertyW(hSumInfo, 8, NULL, NULL, NULL, - guidbuffer, &size); - if (rc == ERROR_SUCCESS) - { - WCHAR squashed[GUID_SIZE]; - /* for now we only care about the first guid */ - LPWSTR ptr = strchrW(guidbuffer,';'); - if (ptr) *ptr = 0; - squash_guid(guidbuffer,squashed); - size = strlenW(guidbuffer)*sizeof(WCHAR); - RegSetValueExW(hukey,szPackageCode,0,REG_SZ, (LPSTR)guidbuffer, - size); - - } - else - { - ERR("Unable to query Revision_Number... \n"); - rc = ERROR_SUCCESS; - } - MsiCloseHandle(hSumInfo); - } - else - { - ERR("Unable to open Summary Information\n"); - rc = ERROR_SUCCESS; - } - -end: - - HeapFree(GetProcessHeap(),0,productcode); - RegCloseKey(hkey); - RegCloseKey(hukey); - - return rc; -} - -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) - { - TRACE("no IniFile table\n"); - 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 (package->components[component_index].ActionRequest != - 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; - package->components[component_index].Installed = 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); - msiobj_release(&view->hdr); - return rc; -} - -static UINT ACTION_SelfRegModules(MSIPACKAGE *package) -{ - 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}; - - static const WCHAR ExeStr[] = { -'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','s',' ',0}; - STARTUPINFOW si; - PROCESS_INFORMATION info; - BOOL brc; - - memset(&si,0,sizeof(STARTUPINFOW)); - - rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); - if (rc != ERROR_SUCCESS) - { - TRACE("no SelfReg table\n"); - 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); - - TRACE("Registering %s\n",debugstr_w(filename)); - brc = CreateProcessW(NULL, filename, NULL, NULL, FALSE, 0, NULL, - c_collen, &si, &info); - - if (brc) - msi_dialog_check_messages(package->dialog, info.hProcess); - - HeapFree(GetProcessHeap(),0,filename); - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; -} - -static UINT ACTION_PublishFeatures(MSIPACKAGE *package) -{ - LPWSTR productcode; - UINT rc; - DWORD i; - HKEY hkey=0; - HKEY hukey=0; - static const WCHAR szProductCode[]= - {'P','r','o','d','u','c','t','C','o','d','e',0}; - - if (!package) - return ERROR_INVALID_HANDLE; - - productcode = load_dynamic_property(package,szProductCode,&rc); - if (!productcode) - return rc; - - rc = MSIREG_OpenFeaturesKey(productcode,&hkey,TRUE); - if (rc != ERROR_SUCCESS) - goto end; - - rc = MSIREG_OpenUserFeaturesKey(productcode,&hukey,TRUE); - if (rc != ERROR_SUCCESS) - goto end; - - /* here the guids are base 85 encoded */ - for (i = 0; i < package->loaded_features; i++) - { - LPWSTR data = NULL; - GUID clsid; - int j; - INT size; - - size = package->features[i].ComponentCount*21; - size +=1; - if (package->features[i].Feature_Parent[0]) - size += strlenW(package->features[i].Feature_Parent)+2; - - data = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); - - data[0] = 0; - for (j = 0; j < package->features[i].ComponentCount; j++) - { - WCHAR buf[21]; - memset(buf,0,sizeof(buf)); - TRACE("From %s\n",debugstr_w(package->components - [package->features[i].Components[j]].ComponentId)); - CLSIDFromString(package->components - [package->features[i].Components[j]].ComponentId, - &clsid); - encode_base85_guid(&clsid,buf); - TRACE("to %s\n",debugstr_w(buf)); - strcatW(data,buf); - } - if (package->features[i].Feature_Parent[0]) - { - static const WCHAR sep[] = {'\2',0}; - strcatW(data,sep); - strcatW(data,package->features[i].Feature_Parent); - } - - size = (strlenW(data)+1)*sizeof(WCHAR); - RegSetValueExW(hkey,package->features[i].Feature,0,REG_SZ, - (LPSTR)data,size); - HeapFree(GetProcessHeap(),0,data); - - size = strlenW(package->features[i].Feature_Parent)*sizeof(WCHAR); - RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ, - (LPSTR)package->features[i].Feature_Parent,size); - } - -end: - RegCloseKey(hkey); - RegCloseKey(hukey); - HeapFree(GetProcessHeap(), 0, productcode); - return rc; -} - -static UINT ACTION_RegisterProduct(MSIPACKAGE *package) -{ - static const WCHAR szProductCode[]= - {'P','r','o','d','u','c','t','C','o','d','e',0}; - HKEY hkey=0; - LPWSTR buffer; - LPWSTR productcode; - UINT rc,i; - DWORD size; - static WCHAR szNONE[] = {0}; - static const WCHAR szWindowsInstaler[] = - {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0}; - static const WCHAR szPropKeys[][80] = - { -{'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0}, -{'A','R','P','C','O','N','T','A','C','T'}, -{'A','R','P','C','O','M','M','E','N','T','S',0}, -{'P','r','o','d','u','c','t','N','a','m','e',0}, -{'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0}, -{'A','R','P','H','E','L','P','L','I','N','K',0}, -{'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0}, -{'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0}, -{'S','O','U','R','C','E','D','I','R',0}, -{'M','a','n','u','f','a','c','t','u','r','e','r',0}, -{'A','R','P','R','E','A','D','M','E',0}, -{'A','R','P','S','I','Z','E',0}, -{'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0}, -{'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0}, -{0}, - }; - - static const WCHAR szRegKeys[][80] = - { -{'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0}, -{'C','o','n','t','a','c','t',0}, -{'C','o','m','m','e','n','t','s',0}, -{'D','i','s','p','l','a','y','N','a','m','e',0}, -{'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0}, -{'H','e','l','p','L','i','n','k',0}, -{'H','e','l','p','T','e','l','e','p','h','o','n','e',0}, -{'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0}, -{'I','n','s','t','a','l','l','S','o','u','r','c','e',0}, -{'P','u','b','l','i','s','h','e','r',0}, -{'R','e','a','d','m','e',0}, -{'S','i','z','e',0}, -{'U','R','L','I','n','f','o','A','b','o','u','t',0}, -{'U','R','L','U','p','d','a','t','e','I','n','f','o',0}, -{0}, - }; - - static const WCHAR path[] = { - 'C',':','\\','W','i','n','d','o','w','s','\\', - 'I','n','s','t','a','l','l','e','r','\\'}; - static const WCHAR fmt[] = { - 'C',':','\\','W','i','n','d','o','w','s','\\', - 'I','n','s','t','a','l','l','e','r','\\', - '%','x','.','m','s','i',0}; - static const WCHAR szLocalPackage[]= - {'L','o','c','a','l','P','a','c','k','a','g','e',0}; - WCHAR packagefile[MAX_PATH]; - INT num,start; - - if (!package) - return ERROR_INVALID_HANDLE; - - productcode = load_dynamic_property(package,szProductCode,&rc); - if (!productcode) - return rc; - - rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE); - if (rc != ERROR_SUCCESS) - goto end; - - /* dump all the info i can grab */ - FIXME("Flesh out more information \n"); - - i = 0; - while (szPropKeys[i][0]!=0) - { - buffer = load_dynamic_property(package,szPropKeys[i],&rc); - if (rc != ERROR_SUCCESS) - buffer = szNONE; - size = strlenW(buffer)*sizeof(WCHAR); - RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size); - i++; - } - - rc = 0x1; - size = sizeof(rc); - RegSetValueExW(hkey,szWindowsInstaler,0,REG_DWORD,(LPSTR)&rc,size); - - /* copy the package locally */ - num = GetTickCount() & 0xffff; - if (!num) - num = 1; - start = num; - sprintfW(packagefile,fmt,num); - do - { - HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL, - CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 ); - if (handle != INVALID_HANDLE_VALUE) - { - CloseHandle(handle); - break; - } - if (GetLastError() != ERROR_FILE_EXISTS && - GetLastError() != ERROR_SHARING_VIOLATION) - break; - if (!(++num & 0xffff)) num = 1; - sprintfW(packagefile,fmt,num); - } while (num != start); - - create_full_pathW(path); - TRACE("Copying to local package %s\n",debugstr_w(packagefile)); - CopyFileW(package->PackagePath,packagefile,FALSE); - size = strlenW(packagefile)*sizeof(WCHAR); - RegSetValueExW(hkey,szLocalPackage,0,REG_SZ,(LPSTR)packagefile,size); - -end: - HeapFree(GetProcessHeap(),0,productcode); - RegCloseKey(hkey); - - return ERROR_SUCCESS; -} - -static UINT ACTION_InstallExecute(MSIPACKAGE *package) -{ - int i; - 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); - - package->DeferredActionCount = 0; - package->DeferredAction = NULL; - - return ERROR_SUCCESS; -} - -static UINT ACTION_InstallFinalize(MSIPACKAGE *package) -{ - int i; - if (!package) - return ERROR_INVALID_HANDLE; - - /* first do the same as an InstallExecute */ - ACTION_InstallExecute(package); - - /* 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); - - package->CommitActionCount = 0; - package->CommitAction = NULL; - - return ERROR_SUCCESS; -} - -static UINT ACTION_ForceReboot(MSIPACKAGE *package) -{ - static const WCHAR RunOnce[] = { - 'S','o','f','t','w','a','r','e','\\', - 'M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s','\\', - 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'R','u','n','O','n','c','e'}; - static const WCHAR InstallRunOnce[] = { - 'S','o','f','t','w','a','r','e','\\', - 'M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s','\\', - 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'I','n','s','t','a','l','l','e','r','\\', - 'R','u','n','O','n','c','e','E','n','t','r','i','e','s'}; - - static const WCHAR msiexec_fmt[] = { - 'C',':','\\','W','i','n','d','o','w','s','\\','S','y','s','t','e','m', - '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ', - '\"','%','s','\"',0}; - static const WCHAR install_fmt[] = { - '/','I',' ','\"','%','s','\"',' ', - 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ', - 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0}; - WCHAR buffer[256]; - HKEY hkey,hukey; - LPWSTR productcode; - WCHAR squished_pc[100]; - INT rc; - DWORD size; - static const WCHAR szProductCode[]= - {'P','r','o','d','u','c','t','C','o','d','e',0}; - static const WCHAR szLUS[] = { - 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0}; - static const WCHAR szSourceList[] = { - 'S','o','u','r','c','e','L','i','s','t',0}; - static const WCHAR szPackageName[] = { - 'P','a','c','k','a','g','e','N','a','m','e',0}; - - if (!package) - return ERROR_INVALID_HANDLE; - - productcode = load_dynamic_property(package,szProductCode,&rc); - if (!productcode) - return rc; - - squash_guid(productcode,squished_pc); - - RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey); - sprintfW(buffer,msiexec_fmt,squished_pc); - - size = strlenW(buffer)*sizeof(WCHAR); - RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size); - RegCloseKey(hkey); - - TRACE("Reboot command %s\n",debugstr_w(buffer)); - - RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey); - sprintfW(buffer,install_fmt,productcode,squished_pc); - RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size); - RegCloseKey(hkey); - - rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE); - if (rc == ERROR_SUCCESS) - { - HKEY hukey2; - LPWSTR buf; - RegCreateKeyW(hukey, szSourceList, &hukey2); - buf = load_dynamic_property(package,cszSourceDir,NULL); - size = strlenW(buf)*sizeof(WCHAR); - RegSetValueExW(hukey2,szLUS,0,REG_SZ,(LPSTR)buf,size); - HeapFree(GetProcessHeap(),0,buf); - - buf = strrchrW(package->PackagePath,'\\'); - if (buf) - { - buf++; - size = strlenW(buf)*sizeof(WCHAR); - RegSetValueExW(hukey2,szPackageName,0,REG_SZ,(LPSTR)buf,size); - } - - RegCloseKey(hukey2); - } - HeapFree(GetProcessHeap(),0,productcode); - - return ERROR_INSTALL_SUSPEND; -} - -UINT ACTION_ResolveSource(MSIPACKAGE* package) -{ - /* - * we are currently doing what should be done here in the top level Install - * however for Adminastrative and uninstalls this step will be needed - */ - 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 (package->components[index].ActionRequest != INSTALLSTATE_LOCAL) - { - 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; - package->components[index].Installed = 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 szProductCode[]= - {'P','r','o','d','u','c','t','C','o','d','e',0}; - static const WCHAR szProductID[]= - {'P','r','o','d','u','c','t','I','D',0}; - HKEY hkey=0; - LPWSTR buffer; - LPWSTR productcode; - LPWSTR productid; - UINT rc,i; - DWORD size; - - static const WCHAR szPropKeys[][80] = - { -{'P','r','o','d','u','c','t','I','D',0}, -{'U','S','E','R','N','A','M','E',0}, -{'C','O','M','P','A','N','Y','N','A','M','E',0}, -{0}, - }; - - static const WCHAR szRegKeys[][80] = - { -{'P','r','o','d','u','c','t','I','D',0}, -{'R','e','g','O','w','n','e','r',0}, -{'R','e','g','C','o','m','p','a','n','y',0}, -{0}, - }; - - if (!package) - return ERROR_INVALID_HANDLE; - - productid = load_dynamic_property(package,szProductID,&rc); - if (!productid) - return ERROR_SUCCESS; - - productcode = load_dynamic_property(package,szProductCode,&rc); - if (!productcode) - return rc; - - rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE); - if (rc != ERROR_SUCCESS) - goto end; - - i = 0; - while (szPropKeys[i][0]!=0) - { - buffer = load_dynamic_property(package,szPropKeys[i],&rc); - if (rc == ERROR_SUCCESS) - { - size = strlenW(buffer)*sizeof(WCHAR); - RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size); - } - i++; - } - -end: - HeapFree(GetProcessHeap(),0,productcode); - HeapFree(GetProcessHeap(),0,productid); - RegCloseKey(hkey); - - return ERROR_SUCCESS; -} - -/* Msi functions that seem appropriate here */ -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; -} - -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_PerformAction(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; -} - - -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 (strcmpiW(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; -} - -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; -} - -/* - * 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 MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature, - INSTALLSTATE iState) -{ - MSIPACKAGE* package; - INT index; - - TRACE(" %s to %i\n",debugstr_w(szFeature), iState); - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - - index = get_loaded_feature(package,szFeature); - if (index < 0) - return ERROR_UNKNOWN_FEATURE; - - package->features[index].ActionRequest= iState; - ACTION_UpdateComponentStates(package,szFeature); - - return ERROR_SUCCESS; -} - -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; -} - -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; -} - -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 +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2004 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 + */ + +/* + * Pages I need + * +http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp + +http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp + */ + +#include +#include + +#define COBJMACROS + +#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 "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" +#include "ver.h" +#include "action.h" + +#define REG_PROGRESS_VALUE 13200 +#define COMPONENT_PROGRESS_VALUE 24000 + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +/* + * Prototypes + */ +static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran); +static UINT ACTION_ProcessUISequence(MSIPACKAGE *package); +static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq); +static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, + LPWSTR *FilePath); + +/* + * action handlers + */ +typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*); + +static UINT ACTION_LaunchConditions(MSIPACKAGE *package); +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); +static UINT ACTION_WriteIniValues(MSIPACKAGE *package); +static UINT ACTION_SelfRegModules(MSIPACKAGE *package); +static UINT ACTION_PublishFeatures(MSIPACKAGE *package); +static UINT ACTION_RegisterProduct(MSIPACKAGE *package); +static UINT ACTION_InstallExecute(MSIPACKAGE *package); +static UINT ACTION_InstallFinalize(MSIPACKAGE *package); +static UINT ACTION_ForceReboot(MSIPACKAGE *package); +static UINT ACTION_ResolveSource(MSIPACKAGE *package); +static UINT ACTION_ExecuteAction(MSIPACKAGE *package); +static UINT ACTION_RegisterFonts(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[] = + {'I','n','s','t','a','l','l','F','i','l','e','s',0}; +const static 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', + 'V','a','l','u','e','s',0}; +const static WCHAR szCostInitialize[] = + {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0}; +const static WCHAR szFileCost[] = + {'F','i','l','e','C','o','s','t',0}; +const static WCHAR szInstallInitialize[] = + {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0}; +const static WCHAR szInstallValidate[] = + {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0}; +const static WCHAR szLaunchConditions[] = + {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0}; +const static WCHAR szProcessComponents[] = + {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0}; +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[] = + {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0}; +const static 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}; +const static WCHAR szPublishProduct[] = + {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0}; +const static WCHAR szWriteIniValues[] = + {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0}; +const static WCHAR szSelfRegModules[] = + {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0}; +const static WCHAR szPublishFeatures[] = + {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0}; +const static WCHAR szRegisterProduct[] = + {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0}; +const static WCHAR szInstallExecute[] = + {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0}; +const static WCHAR szInstallExecuteAgain[] = + {'I','n','s','t','a','l','l','E','x','e','c','u','t','e', + 'A','g','a','i','n',0}; +const static WCHAR szInstallFinalize[] = + {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0}; +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[] = + {'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', + 'S','p','a','c','e',0}; +const static WCHAR szBindImage[] = + {'B','i','n','d','I','m','a','g','e',0}; +const static WCHAR szCCPSearch[] = + {'C','C','P','S','e','a','r','c','h',0}; +const static WCHAR szDeleteServices[] = + {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0}; +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[] = + {'F','i','n','d','R','e','l','a','t','e','d', + 'P','r','o','d','u','c','t','s',0}; +const static WCHAR szInstallAdminPackage[] = + {'I','n','s','t','a','l','l','A','d','m','i','n', + 'P','a','c','k','a','g','e',0}; +const static WCHAR szInstallSFPCatalogFile[] = + {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g', + '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[] = + {'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[] = + {'M','o','v','e','F','i','l','e','s',0}; +const static WCHAR szMsiPublishAssemblies[] = + {'M','s','i','P','u','b','l','i','s','h', + 'A','s','s','e','m','b','l','i','e','s',0}; +const static WCHAR szMsiUnpublishAssemblies[] = + {'M','s','i','U','n','p','u','b','l','i','s','h', + 'A','s','s','e','m','b','l','i','e','s',0}; +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[] = + {'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[] = + {'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[] = + {'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[] = + {'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[] = + {'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[] = + {'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}; +const static WCHAR szRemoveIniValues[] = + {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0}; +const static WCHAR szRemoveODBC[] = + {'R','e','m','o','v','e','O','D','B','C',0}; +const static WCHAR szRemoveRegistryValues[] = + {'R','e','m','o','v','e','R','e','g','i','s','t','r','y', + 'V','a','l','u','e','s',0}; +const static WCHAR szRemoveShortcuts[] = + {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0}; +const static WCHAR szRMCCPSearch[] = + {'R','M','C','C','P','S','e','a','r','c','h',0}; +const static WCHAR szScheduleReboot[] = + {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0}; +const static WCHAR szSelfUnregModules[] = + {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0}; +const static WCHAR szSetODBCFolders[] = + {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0}; +const static WCHAR szStartServices[] = + {'S','t','a','r','t','S','e','r','v','i','c','e','s',0}; +const static WCHAR szStopServices[] = + {'S','t','o','p','S','e','r','v','i','c','e','s',0}; +const static WCHAR szUnpublishComponents[] = + {'U','n','p','u','b','l','i','s','h', + '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[] = + {'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[] = + {'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[] = + {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0}; +const static 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[] = + {'U','n','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 szValidateProductID[] = + {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0}; +const static WCHAR szWriteEnvironmentStrings[] = + {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t', + 'S','t','r','i','n','g','s',0}; + +struct _actions { + LPCWSTR action; + STANDARDACTIONHANDLER handler; +}; + +static struct _actions StandardActions[] = { + { szAllocateRegistrySpace, NULL}, + { szAppSearch, ACTION_AppSearch }, + { szBindImage, NULL}, + { szCCPSearch, NULL}, + { szCostFinalize, ACTION_CostFinalize }, + { szCostInitialize, ACTION_CostInitialize }, + { szCreateFolders, ACTION_CreateFolders }, + { szCreateShortcuts, ACTION_CreateShortcuts }, + { szDeleteServices, NULL}, + { szDisableRollback, NULL}, + { szDuplicateFiles, ACTION_DuplicateFiles }, + { szExecuteAction, ACTION_ExecuteAction }, + { szFileCost, ACTION_FileCost }, + { szFindRelatedProducts, NULL}, + { szForceReboot, ACTION_ForceReboot }, + { szInstallAdminPackage, NULL}, + { szInstallExecute, ACTION_InstallExecute }, + { szInstallExecuteAgain, ACTION_InstallExecute }, + { szInstallFiles, ACTION_InstallFiles}, + { szInstallFinalize, ACTION_InstallFinalize }, + { szInstallInitialize, ACTION_InstallInitialize }, + { szInstallSFPCatalogFile, NULL}, + { szInstallValidate, ACTION_InstallValidate }, + { szIsolateComponents, NULL}, + { szLaunchConditions, ACTION_LaunchConditions }, + { szMigrateFeatureStates, NULL}, + { szMoveFiles, NULL}, + { szMsiPublishAssemblies, NULL}, + { szMsiUnpublishAssemblies, NULL}, + { szInstallODBC, NULL}, + { szInstallServices, NULL}, + { szPatchFiles, NULL}, + { szProcessComponents, ACTION_ProcessComponents }, + { szPublishComponents, NULL}, + { szPublishFeatures, ACTION_PublishFeatures }, + { szPublishProduct, ACTION_PublishProduct }, + { szRegisterClassInfo, ACTION_RegisterClassInfo }, + { szRegisterComPlus, NULL}, + { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo }, + { szRegisterFonts, ACTION_RegisterFonts }, + { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo }, + { szRegisterProduct, ACTION_RegisterProduct }, + { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo }, + { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries }, + { szRegisterUser, ACTION_RegisterUser}, + { szRemoveDuplicateFiles, NULL}, + { szRemoveEnvironmentStrings, NULL}, + { szRemoveExistingProducts, NULL}, + { szRemoveFiles, NULL}, + { szRemoveFolders, NULL}, + { szRemoveIniValues, NULL}, + { szRemoveODBC, NULL}, + { szRemoveRegistryValues, NULL}, + { szRemoveShortcuts, NULL}, + { szResolveSource, ACTION_ResolveSource}, + { szRMCCPSearch, NULL}, + { szScheduleReboot, NULL}, + { szSelfRegModules, ACTION_SelfRegModules }, + { szSelfUnregModules, NULL}, + { szSetODBCFolders, NULL}, + { szStartServices, NULL}, + { szStopServices, NULL}, + { szUnpublishComponents, NULL}, + { szUnpublishFeatures, NULL}, + { szUnregisterClassInfo, NULL}, + { szUnregisterComPlus, NULL}, + { szUnregisterExtensionInfo, NULL}, + { szUnregisterFonts, NULL}, + { szUnregisterMIMEInfo, NULL}, + { szUnregisterProgIdInfo, NULL}, + { szUnregisterTypeLibraries, NULL}, + { szValidateProductID, NULL}, + { szWriteEnvironmentStrings, NULL}, + { szWriteIniValues, ACTION_WriteIniValues }, + { szWriteRegistryValues, ACTION_WriteRegistryValues}, + { NULL, NULL}, +}; + + +/******************************************************** + * helper functions to get around current HACKS and such + ********************************************************/ +inline static void reduce_to_longfilename(WCHAR* filename) +{ + LPWSTR p = strchrW(filename,'|'); + if (p) + memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR)); +} + +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 = dupstrW(name); + package->files[index].TargetPath = dupstrW(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].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(package->dialog, 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); + return; + } + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + 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 = dupstrW(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); + + row = MSI_CreateRecord(1); + MSI_RecordSetStringW(row,1,message); + + MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row); + msiobj_release(&row->hdr); +} + + +static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action) +{ + static const WCHAR template_s[]= + {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ', '%','s', + '.',0}; + static const WCHAR format[] = + {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0}; + 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]; + WCHAR timet[0x100]; + UINT rc; + MSIQUERY * view; + MSIRECORD * row = 0; + WCHAR *ActionText=NULL; + + GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100); + + 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; + } + + ActionText = load_dynamic_stringW(row,2); + msiobj_release(&row->hdr); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + + sprintfW(message,template_s,timet,action,ActionText); + + 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, + UINT rc) +{ + MSIRECORD * row; + static const WCHAR template_s[]= + {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ', + '%','s', '.',0}; + static const WCHAR template_e[]= + {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ', + '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ', + '%','i','.',0}; + static const WCHAR format[] = + {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0}; + WCHAR message[1024]; + WCHAR timet[0x100]; + + GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100); + if (start) + sprintfW(message,template_s,timet,action); + else + sprintfW(message,template_e,timet,action,rc); + + row = MSI_CreateRecord(1); + MSI_RecordSetStringW(row,1,message); + + MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row); + msiobj_release(&row->hdr); +} + +/* + * 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 + *****************************************************/ + +UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath, + LPCWSTR szCommandLine) +{ + DWORD sz; + WCHAR buffer[10]; + UINT rc; + static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0}; + static const WCHAR szAction[] = {'A','C','T','I','O','N',0}; + static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0}; + + MSI_SetPropertyW(package, szAction, szInstall); + package->ExecuteSequenceRun = FALSE; + + if (szPackagePath) + { + LPWSTR p, check, path; + + package->PackagePath = dupstrW(szPackagePath); + path = dupstrW(szPackagePath); + p = strrchrW(path,'\\'); + if (p) + { + p++; + *p=0; + } + else + { + HeapFree(GetProcessHeap(),0,path); + path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR)); + GetCurrentDirectoryW(MAX_PATH,path); + strcatW(path,cszbs); + } + + check = load_dynamic_property(package, cszSourceDir,NULL); + if (!check) + MSI_SetPropertyW(package, cszSourceDir, path); + else + HeapFree(GetProcessHeap(), 0, check); + + HeapFree(GetProcessHeap(), 0, path); + } + + if (szCommandLine) + { + LPWSTR ptr,ptr2; + ptr = (LPWSTR)szCommandLine; + + while (*ptr) + { + WCHAR *prop = NULL; + WCHAR *val = NULL; + + TRACE("Looking at %s\n",debugstr_w(ptr)); + + ptr2 = strchrW(ptr,'='); + if (ptr2) + { + BOOL quote=FALSE; + DWORD len = 0; + + while (*ptr == ' ') ptr++; + len = ptr2-ptr; + prop = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR)); + strncpyW(prop,ptr,len); + prop[len]=0; + ptr2++; + + len = 0; + ptr = ptr2; + while (*ptr && (quote || (!quote && *ptr!=' '))) + { + if (*ptr == '"') + quote = !quote; + ptr++; + len++; + } + + if (*ptr2=='"') + { + ptr2++; + len -= 2; + } + val = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR)); + strncpyW(val,ptr2,len); + val[len] = 0; + + if (strlenW(prop) > 0) + { + TRACE("Found commandline property (%s) = (%s)\n", + debugstr_w(prop), debugstr_w(val)); + MSI_SetPropertyW(package,prop,val); + } + HeapFree(GetProcessHeap(),0,val); + HeapFree(GetProcessHeap(),0,prop); + } + ptr++; + } + } + + sz = 10; + if (MSI_GetPropertyW(package,szUILevel,buffer,&sz) == ERROR_SUCCESS) + { + if (atoiW(buffer) >= INSTALLUILEVEL_REDUCED) + { + rc = ACTION_ProcessUISequence(package); + if (rc == ERROR_SUCCESS) + rc = ACTION_ProcessExecSequence(package,TRUE); + } + else + rc = ACTION_ProcessExecSequence(package,FALSE); + } + else + rc = ACTION_ProcessExecSequence(package,FALSE); + + if (rc == -1) + { + /* install was halted but should be considered a success */ + rc = ERROR_SUCCESS; + } + + /* process the ending type action */ + if (rc == ERROR_SUCCESS) + ACTION_PerformActionSequence(package,-1); + else if (rc == ERROR_INSTALL_USEREXIT) + ACTION_PerformActionSequence(package,-2); + else if (rc == ERROR_FUNCTION_FAILED) + ACTION_PerformActionSequence(package,-3); + else if (rc == ERROR_INSTALL_SUSPEND) + ACTION_PerformActionSequence(package,-4); + + /* finish up running custom actions */ + ACTION_FinishCustomActions(package); + + return rc; +} + +static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq) +{ + MSIQUERY * view; + UINT rc; + WCHAR buffer[0x100]; + DWORD sz = 0x100; + MSIRECORD * row = 0; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + 'I','n','s','t','a','l','l','E','x','e','c','u','t','e', + 'S','e','q','u','e','n','c','e',' ', 'W','H','E','R','E',' ', + 'S','e','q','u','e','n','c','e',' ', '=',' ','%','i',0}; + + rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq); + + 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"); + + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + rc = ERROR_SUCCESS; + goto end; + } + + /* 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); + goto end; + } + 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); + goto end; + } + + rc = ACTION_PerformAction(package,buffer); + msiobj_release(&row->hdr); +end: + MSI_ViewClose(view); + msiobj_release(&view->hdr); + } + else + rc = ERROR_SUCCESS; + + return rc; +} + +static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran) +{ + MSIQUERY * view; + UINT rc; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', + 'I','n','s','t','a','l','l','E','x','e','c','u','t','e', + 'S','e','q','u','e','n','c','e',' ', 'W','H','E','R','E',' ', + 'S','e','q','u','e','n','c','e',' ', '>',' ','%','i',' ', + 'O','R','D','E','R',' ', 'B','Y',' ', + 'S','e','q','u','e','n','c','e',0 }; + MSIRECORD * row = 0; + static const WCHAR IVQuery[] = + {'S','E','L','E','C','T',' ','S','e','q','u','e','n','c','e',' ', + 'F','R','O','M',' ','I','n','s','t','a','l','l', + 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e',' ', + 'W','H','E','R','E',' ','A','c','t','i','o','n',' ','=',' ','`', + 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','`', 0}; + INT seq = 0; + + + if (package->ExecuteSequenceRun) + { + TRACE("Execute Sequence already Run\n"); + return ERROR_SUCCESS; + } + + package->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; + } + 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); + + 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); + msiobj_release(&view->hdr); + } + +end: + return rc; +} + + +static UINT ACTION_ProcessUISequence(MSIPACKAGE *package) +{ + MSIQUERY * view; + UINT rc; + static const WCHAR ExecSeqQuery [] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + 'I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e', + ' ','W','H','E','R','E',' ', 'S','e','q','u','e','n','c','e',' ', + '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ', + 'S','e','q','u','e','n','c','e',0}; + + 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); + 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) +{ + BOOL ret = FALSE; + + int i; + 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) + { + *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; + } + i++; + } + return ret; +} + +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) +{ + BOOL ret=FALSE; + UINT arc; + + arc = ACTION_CustomAction(package,action,FALSE); + + if (arc != ERROR_CALL_NOT_IMPLEMENTED) + { + *rc = arc; + ret = TRUE; + } + return ret; +} + +/* + * A lot of actions are really important even if they don't do anything + * explicit... Lots of properties are set at the beginning of the installation + * CostFinalize does a bunch of work to translate the directories and such + * + * 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 rc = ERROR_SUCCESS; + BOOL handled; + + TRACE("Performing action (%s)\n",debugstr_w(action)); + + handled = ACTION_HandleStandardAction(package, action, &rc); + + if (!handled) + handled = ACTION_HandleCustomAction(package, action, &rc); + + if (!handled) + { + FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action)); + rc = ERROR_FUNCTION_NOT_CALLED; + } + + package->CurrentInstallState = rc; + return rc; +} + +UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action) +{ + UINT rc = ERROR_SUCCESS; + BOOL handled = FALSE; + + TRACE("Performing action (%s)\n",debugstr_w(action)); + + handled = ACTION_HandleStandardAction(package, action, &rc); + + if (!handled) + handled = ACTION_HandleCustomAction(package, action, &rc); + + if (!handled) + handled = ACTION_HandleDialogBox(package, action, &rc); + + msi_dialog_check_messages( package->dialog, NULL ); + + if (!handled) + { + FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action)); + rc = ERROR_FUNCTION_NOT_CALLED; + } + + package->CurrentInstallState = rc; + return rc; +} + +/*********************************************************************** + * create_full_pathW + * + * Recursively create all directories in the path. + * + * shamelessly stolen from setupapi/queue.c + */ +static BOOL create_full_pathW(const WCHAR *path) +{ + BOOL ret = TRUE; + int len; + WCHAR *new_path; + + 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)) + { + 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] = '\\'; + } + + HeapFree(GetProcessHeap(), 0, new_path); + return ret; +} + +/* + * Also we cannot enable/disable components either, so for now I am just going + * to do all the directories for all the components. + */ +static UINT ACTION_CreateFolders(MSIPACKAGE *package) +{ + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','D','i','r','e','c','t','o','r','y','_', + ' ','F','R','O','M',' ', + '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); + msiobj_release(&view->hdr); + + return rc; +} + +static int load_component(MSIPACKAGE* package, MSIRECORD * row) +{ + int index = package->loaded_components; + DWORD sz; + + /* fill in the data */ + + package->loaded_components++; + if (package->loaded_components == 1) + package->components = HeapAlloc(GetProcessHeap(),0, + sizeof(MSICOMPONENT)); + else + package->components = HeapReAlloc(GetProcessHeap(),0, + package->components, package->loaded_components * + sizeof(MSICOMPONENT)); + + memset(&package->components[index],0,sizeof(MSICOMPONENT)); + + sz = 96; + MSI_RecordGetStringW(row,1,package->components[index].Component,&sz); + + TRACE("Loading Component %s\n", + debugstr_w(package->components[index].Component)); + + sz = 0x100; + if (!MSI_RecordIsNull(row,2)) + MSI_RecordGetStringW(row,2,package->components[index].ComponentId,&sz); + + sz = 96; + MSI_RecordGetStringW(row,3,package->components[index].Directory,&sz); + + package->components[index].Attributes = MSI_RecordGetInteger(row,4); + + sz = 0x100; + MSI_RecordGetStringW(row,5,package->components[index].Condition,&sz); + + sz = 96; + MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz); + + package->components[index].Installed = INSTALLSTATE_UNKNOWN; + package->components[index].Action = INSTALLSTATE_UNKNOWN; + package->components[index].ActionRequest = INSTALLSTATE_UNKNOWN; + + package->components[index].Enabled = TRUE; + + return index; +} + +static void load_feature(MSIPACKAGE* package, MSIRECORD * row) +{ + int index = package->loaded_features; + DWORD sz; + static const WCHAR Query1[] = + {'S','E','L','E','C','T',' ','C','o','m','p','o','n','e','n','t','_', + ' ','F','R','O','M',' ','F','e','a','t','u','r','e', + 'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ', + 'F','e', 'a','t','u','r','e','_','=','\'','%','s','\'',0}; + 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; + + /* fill in the data */ + + package->loaded_features ++; + if (package->loaded_features == 1) + package->features = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE)); + else + package->features = HeapReAlloc(GetProcessHeap(),0,package->features, + package->loaded_features * sizeof(MSIFEATURE)); + + memset(&package->features[index],0,sizeof(MSIFEATURE)); + + sz = 96; + MSI_RecordGetStringW(row,1,package->features[index].Feature,&sz); + + TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature)); + + sz = 96; + if (!MSI_RecordIsNull(row,2)) + MSI_RecordGetStringW(row,2,package->features[index].Feature_Parent,&sz); + + sz = 0x100; + if (!MSI_RecordIsNull(row,3)) + MSI_RecordGetStringW(row,3,package->features[index].Title,&sz); + + sz = 0x100; + if (!MSI_RecordIsNull(row,4)) + MSI_RecordGetStringW(row,4,package->features[index].Description,&sz); + + if (!MSI_RecordIsNull(row,5)) + package->features[index].Display = MSI_RecordGetInteger(row,5); + + package->features[index].Level= MSI_RecordGetInteger(row,6); + + sz = 96; + if (!MSI_RecordIsNull(row,7)) + MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz); + + package->features[index].Attributes= MSI_RecordGetInteger(row,8); + + package->features[index].Installed = INSTALLSTATE_UNKNOWN; + package->features[index].Action = INSTALLSTATE_UNKNOWN; + package->features[index].ActionRequest = INSTALLSTATE_UNKNOWN; + + /* load feature components */ + + 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; + + 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 ++; + 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); + msiobj_release(&view->hdr); +} + +/* + * I am not doing any of the costing functionality yet. + * Mostly looking at doing the Component and Feature loading + * + * The native MSI does A LOT of modification to tables here. Mostly adding + * a lot of temporary columns to the Feature and Component tables. + * + * note: Native msi also tracks the short filename. But I am only going to + * track the long ones. Also looking at this directory table + * it appears that the directory table does not get the parents + * resolved base on property only based on their entries in the + * directory table. + */ +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',' ', + 'F','e','a','t','u','r','e',0}; + static const WCHAR szCosting[] = + {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 }; + static const WCHAR szZero[] = { '0', 0 }; + + MSI_SetPropertyW(package, szCosting, szZero); + MSI_SetPropertyW(package, cszRootDrive , c_colon); + + 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); + msiobj_release(&view->hdr); + + return ERROR_SUCCESS; +} + +static UINT load_file(MSIPACKAGE* package, MSIRECORD * row) +{ + DWORD index = package->loaded_files; + DWORD i; + LPWSTR buffer; + + /* fill in the data */ + + 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 = 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; + } + if (package->files[index].ComponentIndex == -1) + ERR("Unfound Component %s\n",debugstr_w(buffer)); + HeapFree(GetProcessHeap(), 0, buffer); + + package->files[index].FileName = load_dynamic_stringW(row,3); + + reduce_to_longfilename(package->files[index].FileName); + + package->files[index].FileSize = MSI_RecordGetInteger(row,4); + package->files[index].Version = load_dynamic_stringW(row, 5); + package->files[index].Language = load_dynamic_stringW(row, 6); + package->files[index].Attributes= MSI_RecordGetInteger(row,7); + package->files[index].Sequence= MSI_RecordGetInteger(row,8); + + package->files[index].Temporary = FALSE; + package->files[index].State = 0; + + TRACE("File Loaded (%s)\n",debugstr_w(package->files[index].File)); + + return ERROR_SUCCESS; +} + +static UINT ACTION_FileCost(MSIPACKAGE *package) +{ + MSIQUERY * view; + MSIRECORD * row; + UINT rc; + static const WCHAR Query[] = + {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', + 'F','i','l','e',' ', 'O','R','D','E','R',' ','B','Y',' ', + 'S','e','q','u','e','n','c','e', 0}; + + if (!package) + return ERROR_INVALID_HANDLE; + + 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); + msiobj_release(&view->hdr); + + return ERROR_SUCCESS; +} + +static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) +{ + static const WCHAR Query[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + 'D','i','r','e','c', 't','o','r','y',' ','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; + MSIRECORD * row = 0; + INT index = -1; + DWORD i; + + TRACE("Looking for dir %s\n",debugstr_w(dir)); + + for (i = 0; i < package->loaded_folders; i++) + { + if (strcmpW(package->folders[i].Directory,dir)==0) + { + TRACE(" %s retuning on index %lu\n",debugstr_w(dir),i); + return i; + } + } + + TRACE("Working to load %s\n",debugstr_w(dir)); + + index = package->loaded_folders++; + if (package->loaded_folders==1) + package->folders = HeapAlloc(GetProcessHeap(),0, + sizeof(MSIFOLDER)); + else + package->folders= HeapReAlloc(GetProcessHeap(),0, + package->folders, package->loaded_folders* + sizeof(MSIFOLDER)); + + memset(&package->folders[index],0,sizeof(MSIFOLDER)); + + package->folders[index].Directory = dupstrW(dir); + + rc = MSI_OpenQuery(package->db, &view, Query, dir); + if (rc != ERROR_SUCCESS) + 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 */ + if (strchrW(targetdir,':')) + { + srcdir=strchrW(targetdir,':'); + *srcdir=0; + srcdir ++; + } + else + srcdir=NULL; + + /* for now only pick long filename versions */ + if (strchrW(targetdir,'|')) + { + targetdir = strchrW(targetdir,'|'); + *targetdir = 0; + targetdir ++; + } + if (srcdir && strchrW(srcdir,'|')) + { + srcdir= strchrW(srcdir,'|'); + *srcdir= 0; + srcdir ++; + } + + /* now check for root dirs */ + if (targetdir[0] == '.' && targetdir[1] == 0) + targetdir = NULL; + + if (srcdir && srcdir[0] == '.' && srcdir[1] == 0) + srcdir = NULL; + + if (targetdir) + { + TRACE(" TargetDefault = %s\n",debugstr_w(targetdir)); + HeapFree(GetProcessHeap(),0, package->folders[index].TargetDefault); + package->folders[index].TargetDefault = dupstrW(targetdir); + } + + if (srcdir) + package->folders[index].SourceDefault = dupstrW(srcdir); + else if (targetdir) + package->folders[index].SourceDefault = dupstrW(targetdir); + HeapFree(GetProcessHeap(), 0, ptargetdir); + + parent = load_dynamic_stringW(row,2); + if (parent) + { + i = load_folder(package,parent); + package->folders[index].ParentIndex = i; + TRACE("Parent is index %i... %s %s\n", + package->folders[index].ParentIndex, + debugstr_w(package->folders[package->folders[index].ParentIndex].Directory), + debugstr_w(parent)); + } + 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 = dupstrW(package->folders[i].ResolvedTarget); + TRACE(" already resolved to %s\n",debugstr_w(path)); + return path; + } + else if (source && package->folders[i].ResolvedSource) + { + path = dupstrW(package->folders[i].ResolvedSource); + 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 = dupstrW(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); + package->folders[i].ResolvedSource = dupstrW(path); + } + HeapFree(GetProcessHeap(),0,p); + } + return path; +} + +/* scan for and update current install states */ +void ACTION_UpdateInstallStates(MSIPACKAGE *package) +{ + int i; + LPWSTR productcode; + + productcode = load_dynamic_property(package,szProductCode,NULL); + + for (i = 0; i < package->loaded_components; i++) + { + INSTALLSTATE res; + res = MsiGetComponentPathW(productcode, + package->components[i].ComponentId , NULL, NULL); + if (res < 0) + res = INSTALLSTATE_ABSENT; + package->components[i].Installed = res; + } + + for (i = 0; i < package->loaded_features; i++) + { + INSTALLSTATE res = -10; + int j; + for (j = 0; j < package->features[i].ComponentCount; j++) + { + MSICOMPONENT* component = &package->components[package->features[i]. + Components[j]]; + if (res == -10) + res = component->Installed; + else + { + if (res == component->Installed) + continue; + + if (res != component->Installed) + res = INSTALLSTATE_INCOMPLETE; + } + } + } +} + +/* 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]]; + + if (!component->Enabled) + continue; + else + { + if (newstate == INSTALLSTATE_LOCAL) + component->ActionRequest = INSTALLSTATE_LOCAL; + else + { + int j,k; + + component->ActionRequest = 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) + component->ActionRequest = INSTALLSTATE_LOCAL; + break; + } + } + } + } + } +} + +static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property, + INSTALLSTATE state) +{ + static const WCHAR all[]={'A','L','L',0}; + LPWSTR override = NULL; + INT i; + BOOL rc = FALSE; + + override = load_dynamic_property(package, property, NULL); + if (override) + { + rc = TRUE; + for(i = 0; i < package->loaded_features; i++) + { + if (strcmpiW(override,all)==0) + { + package->features[i].ActionRequest= state; + package->features[i].Action = state; + } + else + { + LPWSTR ptr = override; + LPWSTR ptr2 = strchrW(override,','); + + while (ptr) + { + if ((ptr2 && + strncmpW(ptr,package->features[i].Feature, ptr2-ptr)==0) + || (!ptr2 && + strcmpW(ptr,package->features[i].Feature)==0)) + { + package->features[i].ActionRequest= state; + package->features[i].Action = state; + break; + } + if (ptr2) + { + ptr=ptr2+1; + ptr2 = strchrW(ptr,','); + } + else + break; + } + } + } + HeapFree(GetProcessHeap(),0,override); + } + + return rc; +} + +static UINT SetFeatureStates(MSIPACKAGE *package) +{ + LPWSTR level; + INT install_level; + DWORD i; + INT j; + static const WCHAR szlevel[] = + {'I','N','S','T','A','L','L','L','E','V','E','L',0}; + static const WCHAR szAddLocal[] = + {'A','D','D','L','O','C','A','L',0}; + static const WCHAR szRemove[] = + {'R','E','M','O','V','E',0}; + BOOL override = FALSE; + + /* I do not know if this is where it should happen.. but */ + + TRACE("Checking Install Level\n"); + + level = load_dynamic_property(package,szlevel,NULL); + if (level) + { + install_level = atoiW(level); + HeapFree(GetProcessHeap(), 0, level); + } + else + install_level = 1; + + /* ok hereis the _real_ rub + * all these activation/deactivation things happen in order and things + * later on the list override things earlier on the list. + * 1) INSTALLLEVEL processing + * 2) ADDLOCAL + * 3) REMOVE + * 4) ADDSOURCE + * 5) ADDDEFAULT + * 6) REINSTALL + * 7) COMPADDLOCAL + * 8) COMPADDSOURCE + * 9) FILEADDLOCAL + * 10) FILEADDSOURCE + * 11) FILEADDDEFAULT + * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is + * ignored for all the features. seems strange, especially since it is not + * documented anywhere, but it is how it works. + * + * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and + * REMOVE are the big ones, since we don't handle administrative installs + * yet anyway. + */ + override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL); + override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT); + + if (!override) + { + for(i = 0; i < package->loaded_features; i++) + { + BOOL feature_state = ((package->features[i].Level > 0) && + (package->features[i].Level <= install_level)); + + if (feature_state) + { + package->features[i].ActionRequest = INSTALLSTATE_LOCAL; + package->features[i].Action = INSTALLSTATE_LOCAL; + } + } + } + + /* + * now we want to enable or disable components base on feature + */ + + for(i = 0; i < package->loaded_features; i++) + { + MSIFEATURE* feature = &package->features[i]; + TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n", + debugstr_w(feature->Feature), feature->Installed, feature->Action, + feature->ActionRequest); + + for( j = 0; j < feature->ComponentCount; j++) + { + MSICOMPONENT* component = &package->components[ + feature->Components[j]]; + + if (!component->Enabled) + { + component->Action = INSTALLSTATE_UNKNOWN; + component->ActionRequest = INSTALLSTATE_UNKNOWN; + } + else + { + if (feature->Action == INSTALLSTATE_LOCAL) + { + component->Action = INSTALLSTATE_LOCAL; + component->ActionRequest = INSTALLSTATE_LOCAL; + } + else if (feature->ActionRequest == INSTALLSTATE_ABSENT) + { + if (component->Action == INSTALLSTATE_UNKNOWN) + { + component->Action = INSTALLSTATE_ABSENT; + component->ActionRequest = INSTALLSTATE_ABSENT; + } + } + } + } + } + + for(i = 0; i < package->loaded_components; i++) + { + MSICOMPONENT* component= &package->components[i]; + + TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n", + debugstr_w(component->Component), component->Installed, + component->Action, component->ActionRequest); + } + + + 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 + * to focus on the directory building + * + */ +static UINT ACTION_CostFinalize(MSIPACKAGE *package) +{ + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + 'D','i','r','e','c','t','o','r','y',0}; + static const WCHAR ConditionQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + 'C','o','n','d','i','t','i','o','n',0}; + static const WCHAR szCosting[] = + {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 }; + static const WCHAR szlevel[] = + {'I','N','S','T','A','L','L','L','E','V','E','L',0}; + static const WCHAR szOne[] = { '1', 0 }; + UINT rc; + MSIQUERY * view; + DWORD i; + LPWSTR level; + + TRACE("Building Directory properties\n"); + + 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); + msiobj_release(&view->hdr); + } + + TRACE("File calculations %i files\n",package->loaded_files); + + for (i = 0; i < package->loaded_files; i++) + { + MSICOMPONENT* comp = NULL; + MSIFILE* file= NULL; + + file = &package->files[i]; + if (file->ComponentIndex >= 0) + comp = &package->components[file->ComponentIndex]; + + if (file->Temporary == TRUE) + continue; + + if (comp) + { + LPWSTR p; + + /* calculate target */ + p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL); + + HeapFree(GetProcessHeap(),0,file->TargetPath); + + TRACE("file %s is named %s\n", + debugstr_w(file->File),debugstr_w(file->FileName)); + + file->TargetPath = build_directory_name(2, p, file->FileName); + + HeapFree(GetProcessHeap(),0,p); + + TRACE("file %s resolves to %s\n", + debugstr_w(file->File),debugstr_w(file->TargetPath)); + + if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES) + { + file->State = 1; + comp->Cost += file->FileSize; + } + else + { + if (file->Version) + { + DWORD handle; + DWORD versize; + UINT sz; + LPVOID version; + static const WCHAR name[] = + {'\\',0}; + static const WCHAR name_fmt[] = + {'%','u','.','%','u','.','%','u','.','%','u',0}; + WCHAR filever[0x100]; + VS_FIXEDFILEINFO *lpVer; + + TRACE("Version comparison.. \n"); + versize = GetFileVersionInfoSizeW(file->TargetPath,&handle); + version = HeapAlloc(GetProcessHeap(),0,versize); + GetFileVersionInfoW(file->TargetPath, 0, versize, version); + + VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz); + + sprintfW(filever,name_fmt, + HIWORD(lpVer->dwFileVersionMS), + LOWORD(lpVer->dwFileVersionMS), + HIWORD(lpVer->dwFileVersionLS), + LOWORD(lpVer->dwFileVersionLS)); + + TRACE("new %s old %s\n", debugstr_w(file->Version), + debugstr_w(filever)); + if (strcmpiW(filever,file->Version)<0) + { + file->State = 2; + FIXME("cost should be diff in size\n"); + comp->Cost += file->FileSize; + } + else + file->State = 3; + HeapFree(GetProcessHeap(),0,version); + } + else + file->State = 3; + } + } + } + + TRACE("Evaluating Condition Table\n"); + + 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); + msiobj_release(&view->hdr); + } + + TRACE("Enabling or Disabling Components\n"); + for (i = 0; i < package->loaded_components; i++) + { + if (package->components[i].Condition[0]) + { + if (MSI_EvaluateConditionW(package, + package->components[i].Condition) == MSICONDITION_FALSE) + { + TRACE("Disabling component %s\n", + debugstr_w(package->components[i].Component)); + package->components[i].Enabled = FALSE; + } + } + } + + MSI_SetPropertyW(package,szCosting,szOne); + /* set default run level if not set */ + level = load_dynamic_property(package,szlevel,NULL); + if (!level) + MSI_SetPropertyW(package,szlevel, szOne); + else + HeapFree(GetProcessHeap(),0,level); + + ACTION_UpdateInstallStates(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) + { + 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 && strcmp(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, UINT sequence, + WCHAR* path, WCHAR* 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 (sequence <= last_sequence) + { + TRACE("Media already ready (%u, %u)\n",sequence,last_sequence); + /*extract_a_cabinet_file(package, source,path,file); */ + return ERROR_SUCCESS; + } + + sprintfW(Query,ExecSeqQuery,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; + INT len; + MSICOMPONENT* comp = NULL; + + TRACE("Installing %s\n",debugstr_w(file->File)); + rc = ready_media_for_file(package,file->Sequence,path_to_source, + file->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); + + len = strlenW(path_to_source) + strlenW(file->File) + 2; + file->SourcePath = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); + strcpyW(file->SourcePath, path_to_source); + strcatW(file->SourcePath, 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 (!MoveFileW(file->SourcePath,file->TargetPath)) + { + rc = GetLastError(); + ERR("Unable to move file (%s -> %s) (error %d)\n", + debugstr_w(file->SourcePath), debugstr_w(file->TargetPath), + rc); + if (rc == ERROR_ALREADY_EXISTS && file->State == 2) + { + CopyFileW(file->SourcePath,file->TargetPath,FALSE); + DeleteFileW(file->SourcePath); + rc = 0; + } + else if (rc == ERROR_FILE_NOT_FOUND) + { + ERR("Source File Not Found! Continuing\n"); + rc = 0; + } + else + { + ERR("Ignoring Error and continuing...\n"); + rc = 0; + } + } + else + file->State = 4; + } + } + + 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 = dupstrW(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 = dupstrW(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, + DWORD *size) +{ + LPSTR data = NULL; + if (value[0]=='#' && value[1]!='#' && value[1]!='%') + { + if (value[1]=='x') + { + LPWSTR ptr; + CHAR byte[5]; + LPWSTR deformated; + int count; + + deformat_string(package, &value[2], &deformated); + + /* binary value type */ + ptr = deformated; + *type=REG_BINARY; + *size = strlenW(ptr)/2; + data = HeapAlloc(GetProcessHeap(),0,*size); + + byte[0] = '0'; + byte[1] = 'x'; + byte[4] = 0; + count = 0; + while (*ptr) + { + byte[2]= *ptr; + ptr++; + byte[3]= *ptr; + ptr++; + data[count] = (BYTE)strtol(byte,NULL,0); + count ++; + } + HeapFree(GetProcessHeap(),0,deformated); + + TRACE("Data %li bytes(%i)\n",*size,count); + } + else + { + LPWSTR deformated; + LPWSTR p; + DWORD d = 0; + deformat_string(package, &value[1], &deformated); + + *type=REG_DWORD; + *size = sizeof(DWORD); + data = HeapAlloc(GetProcessHeap(),0,*size); + p = deformated; + if (*p == '-') + p++; + while (*p) + { + if ( (*p < '0') || (*p > '9') ) + break; + d *= 10; + d += (*p - '0'); + p++; + } + if (deformated[0] == '-') + d = -d; + *(LPDWORD)data = d; + TRACE("DWORD %li\n",*(LPDWORD)data); + + HeapFree(GetProcessHeap(),0,deformated); + } + } + else + { + static const WCHAR szMulti[] = {'[','~',']',0}; + WCHAR *ptr; + *type=REG_SZ; + + if (value[0]=='#') + { + if (value[1]=='%') + { + ptr = &value[2]; + *type=REG_EXPAND_SZ; + } + else + ptr = &value[1]; + } + else + ptr=value; + + if (strstrW(value,szMulti)) + *type = REG_MULTI_SZ; + + *size = deformat_string(package, ptr,(LPWSTR*)&data); + } + return data; +} + +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 }; + + 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; + } + + /* 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}; + + 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; + + 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; + } + } + + 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 + { + value_data = NULL; + size = 0; + type = REG_SZ; + } + + deformat_string(package, name, &deformated); + + TRACE("Setting value %s\n",debugstr_w(deformated)); + 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) +{ + return ERROR_SUCCESS; +} + + +static UINT ACTION_InstallValidate(MSIPACKAGE *package) +{ + DWORD progress = 0; + DWORD total = 0; + static const WCHAR q1[]= + {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', + 'R','e','g','i','s','t','r','y',0}; + UINT rc; + MSIQUERY * view; + MSIRECORD * row = 0; + int i; + + TRACE(" InstallValidate \n"); + + rc = MSI_DatabaseOpenViewW(package->db, q1, &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) + { + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + rc = ERROR_SUCCESS; + break; + } + progress +=1; + + msiobj_release(&row->hdr); + } + MSI_ViewClose(view); + msiobj_release(&view->hdr); + + total = total + progress * REG_PROGRESS_VALUE; + total = total + package->loaded_components * COMPONENT_PROGRESS_VALUE; + for (i=0; i < package->loaded_files; i++) + total += package->files[i].FileSize; + ui_progress(package,0,total,0,0); + + 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"); + + 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; + } + + 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); + msiobj_release(&view->hdr); + return rc; +} + +static LPWSTR resolve_keypath( MSIPACKAGE* package, INT + component_index) +{ + MSICOMPONENT* cmp = &package->components[component_index]; + + if (cmp->KeyPath[0]==0) + { + LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL); + return p; + } + if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath) + { + MSIQUERY * view; + MSIRECORD * row = 0; + UINT rc,root,len; + LPWSTR key,deformated,buffer,name,deformated_name; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + 'R','e','g','i','s','t','r','y',' ','W','H','E','R','E',' ', + 'R','e','g','i','s','t','r','y',' ','=',' ' ,'`','%','s','`',0 }; + static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0}; + static const WCHAR fmt2[]= + {'%','0','2','i',':','\\','%','s','\\','%','s',0}; + + rc = MSI_OpenQuery(package->db,&view,ExecSeqQuery,cmp->KeyPath); + + if (rc!=ERROR_SUCCESS) + 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); + deformat_string(package, key , &deformated); + deformat_string(package, name, &deformated_name); + + len = strlenW(deformated) + 6; + if (deformated_name) + len+=strlenW(deformated_name); + + buffer = HeapAlloc(GetProcessHeap(),0, len *sizeof(WCHAR)); + + if (deformated_name) + sprintfW(buffer,fmt2,root,deformated,deformated_name); + 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; + } + else if (cmp->Attributes & msidbComponentAttributesODBCDataSource) + { + FIXME("UNIMPLEMENTED keypath as ODBC Source\n"); + return NULL; + } + else + { + int j; + j = get_loaded_file(package,cmp->KeyPath); + + if (j>=0) + { + LPWSTR p = dupstrW(package->files[j].TargetPath); + return p; + } + } + return NULL; +} + +static HKEY openSharedDLLsKey() +{ + HKEY hkey=0; + static const WCHAR path[] = + {'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'S','h','a','r','e','d','D','L','L','s',0}; + + RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey); + return hkey; +} + +static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll) +{ + HKEY hkey; + DWORD count=0; + DWORD type; + DWORD sz = sizeof(count); + DWORD rc; + + hkey = openSharedDLLsKey(); + rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz); + if (rc != ERROR_SUCCESS) + count = 0; + RegCloseKey(hkey); + return count; +} + +static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count) +{ + HKEY hkey; + + hkey = openSharedDLLsKey(); + if (count > 0) + RegSetValueExW(hkey,path,0,REG_DWORD, + (LPBYTE)&count,sizeof(count)); + else + RegDeleteValueW(hkey,path); + RegCloseKey(hkey); + return count; +} + +/* + * Return TRUE if the count should be written out and FALSE if not + */ +static void ACTION_RefCountComponent( MSIPACKAGE* package, UINT index) +{ + INT count = 0; + BOOL write = FALSE; + INT j; + + /* only refcount DLLs */ + if (package->components[index].KeyPath[0]==0 || + package->components[index].Attributes & + msidbComponentAttributesRegistryKeyPath || + package->components[index].Attributes & + msidbComponentAttributesODBCDataSource) + write = FALSE; + else + { + count = ACTION_GetSharedDLLsCount(package->components[index]. + FullKeypath); + write = (count > 0); + + if (package->components[index].Attributes & + msidbComponentAttributesSharedDllRefCount) + write = TRUE; + } + + /* increment counts */ + for (j = 0; j < package->loaded_features; j++) + { + int i; + + if (!ACTION_VerifyFeatureForAction(package,j,INSTALLSTATE_LOCAL)) + continue; + + for (i = 0; i < package->features[j].ComponentCount; i++) + { + if (package->features[j].Components[i] == index) + count++; + } + } + /* decrement counts */ + for (j = 0; j < package->loaded_features; j++) + { + int i; + if (!ACTION_VerifyFeatureForAction(package,j,INSTALLSTATE_ABSENT)) + continue; + + for (i = 0; i < package->features[j].ComponentCount; i++) + { + if (package->features[j].Components[i] == index) + count--; + } + } + + /* ref count all the files in the component */ + if (write) + for (j = 0; j < package->loaded_files; j++) + { + if (package->files[j].Temporary) + continue; + if (package->files[j].ComponentIndex == index) + ACTION_WriteSharedDLLsCount(package->files[j].TargetPath,count); + } + + /* add a count for permenent */ + if (package->components[index].Attributes & + msidbComponentAttributesPermanent) + count ++; + + package->components[index].RefCount = count; + + if (write) + ACTION_WriteSharedDLLsCount(package->components[index].FullKeypath, + package->components[index].RefCount); +} + +/* + * Ok further analysis makes me think that this work is + * actually done in the PublishComponents and PublishFeatures + * step, and not here. It appears like the keypath and all that is + * resolved in this step, however actually written in the Publish steps. + * But we will leave it here for now because it is unclear + */ +static UINT ACTION_ProcessComponents(MSIPACKAGE *package) +{ + LPWSTR productcode; + WCHAR squished_pc[GUID_SIZE]; + WCHAR squished_cc[GUID_SIZE]; + UINT rc; + DWORD i; + HKEY hkey=0,hkey2=0; + + if (!package) + return ERROR_INVALID_HANDLE; + + /* writes the Component and Features values to the registry */ + productcode = load_dynamic_property(package,szProductCode,&rc); + if (!productcode) + return rc; + + rc = MSIREG_OpenComponents(&hkey); + if (rc != ERROR_SUCCESS) + goto end; + + squash_guid(productcode,squished_pc); + ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0); + for (i = 0; i < package->loaded_components; i++) + { + ui_progress(package,2,0,0,0); + if (package->components[i].ComponentId[0]!=0) + { + WCHAR *keypath = NULL; + MSIRECORD * uirow; + + squash_guid(package->components[i].ComponentId,squished_cc); + rc = RegCreateKeyW(hkey,squished_cc,&hkey2); + if (rc != ERROR_SUCCESS) + continue; + + keypath = resolve_keypath(package,i); + package->components[i].FullKeypath = keypath; + + /* do the refcounting */ + ACTION_RefCountComponent( package, i); + + TRACE("Component %s, Keypath=%s, RefCount=%i\n", + debugstr_w(package->components[i].Component), + debugstr_w(package->components[i].FullKeypath), + package->components[i].RefCount); + /* + * Write the keypath out if the component is to be registered + * and delete the key if the component is to be deregistered + */ + if (ACTION_VerifyComponentForAction(package, i, + INSTALLSTATE_LOCAL)) + { + if (keypath) + { + RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath, + (strlenW(keypath)+1)*sizeof(WCHAR)); + + if (package->components[i].Attributes & + msidbComponentAttributesPermanent) + { + static const WCHAR szPermKey[] = + { '0','0','0','0','0','0','0','0','0','0','0','0', + '0','0','0','0','0','0','0', '0','0','0','0','0', + '0','0','0','0','0','0','0','0',0}; + + RegSetValueExW(hkey2,szPermKey,0,REG_SZ, + (LPVOID)keypath, + (strlenW(keypath)+1)*sizeof(WCHAR)); + } + + RegCloseKey(hkey2); + + /* UI stuff */ + uirow = MSI_CreateRecord(3); + MSI_RecordSetStringW(uirow,1,productcode); + MSI_RecordSetStringW(uirow,2,package->components[i]. + ComponentId); + MSI_RecordSetStringW(uirow,3,keypath); + ui_actiondata(package,szProcessComponents,uirow); + msiobj_release( &uirow->hdr ); + } + } + else if (ACTION_VerifyComponentForAction(package, i, + INSTALLSTATE_ABSENT)) + { + DWORD res; + RegDeleteValueW(hkey2,squished_pc); + + /* if the key is empty delete it */ + res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL); + RegCloseKey(hkey2); + if (res == ERROR_NO_MORE_ITEMS) + RegDeleteKeyW(hkey,squished_cc); + + /* UI stuff */ + uirow = MSI_CreateRecord(2); + MSI_RecordSetStringW(uirow,1,productcode); + MSI_RecordSetStringW(uirow,2,package->components[i]. + ComponentId); + ui_actiondata(package,szProcessComponents,uirow); + msiobj_release( &uirow->hdr ); + } + } + } +end: + HeapFree(GetProcessHeap(), 0, productcode); + RegCloseKey(hkey); + return rc; +} + +static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) +{ + /* + * OK this is a bit confusing.. I am given a _Component key and I believe + * that the file that is being registered as a type library is the "key file + * of that component" which I interpret to mean "The file in the KeyPath of + * that component". + */ + 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}; + ITypeLib *ptLib; + HRESULT res; + + if (!package) + return ERROR_INVALID_HANDLE; + + 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) + { + WCHAR component[0x100]; + DWORD sz; + INT index; + + 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; + } + + res = LoadTypeLib(package->files[index].TargetPath,&ptLib); + if (SUCCEEDED(res)) + { + LPWSTR help; + WCHAR helpid[0x100]; + + sz = 0x100; + MSI_RecordGetStringW(row,6,helpid,&sz); + + help = resolve_folder(package,helpid,FALSE,FALSE,NULL); + res = RegisterTypeLib(ptLib,package->files[index].TargetPath,help); + HeapFree(GetProcessHeap(),0,help); + + if (!SUCCEEDED(res)) + ERR("Failed to register type library %s\n", + debugstr_w(package->files[index].TargetPath)); + else + { + /* Yes the row has more fields than I need, but #1 is + correct and the only one I need. Why make a new row? */ + + ui_actiondata(package,szRegisterTypeLibraries,row); + + TRACE("Registered %s\n", + debugstr_w(package->files[index].TargetPath)); + } + + if (ptLib) + ITypeLib_Release(ptLib); + } + else + ERR("Failed to load type library %s\n", + debugstr_w(package->files[index].TargetPath)); + + msiobj_release(&row->hdr); + } + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return rc; + +} + +static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app ) +{ + 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)) + { + 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 = (LPWSTR)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]; + DWORD sz; + + + sz = 0x100; + MSI_RecordGetStringW(row,1,buffer,&sz); + RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey); + + 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,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); + } + else + { + FIXME("UNHANDLED case, Parent progid but classid is NULL\n"); + return ERROR_FUNCTION_FAILED; + } + if (!MSI_RecordIsNull(row,5)) + { + 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); + } + return ERROR_SUCCESS; +} + +static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid); + +static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent, + LPWSTR clsid) +{ + UINT rc; + 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}; + + if (!package) + return ERROR_INVALID_HANDLE; + + 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) + { + 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)) + { + ERR("CoInitialize failed\n"); + 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 = dupstrW(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); + msiobj_release(&view->hdr); + + + CoUninitialize(); + + return rc; +} + + +/* + * 99% of the work done here is only done for + * advertised installs. However this is where the + * Icon table is processed and written out + * so that is what I am going to do here. + */ +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; + HKEY hukey=0; + static const WCHAR szProductName[] = + {'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}; + LPWSTR buffer; + DWORD size; + MSIHANDLE hDb, hSumInfo; + + if (!package) + return ERROR_INVALID_HANDLE; + + rc = MSI_DatabaseOpenViewW(package->db, Query, &view); + if (rc != ERROR_SUCCESS) + goto next; + + rc = MSI_ViewExecute(view, 0); + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + 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; + + rc = MSIREG_OpenProductsKey(productcode,&hkey,TRUE); + if (rc != ERROR_SUCCESS) + goto end; + + rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE); + if (rc != ERROR_SUCCESS) + goto end; + + + buffer = load_dynamic_property(package,szProductName,NULL); + size = strlenW(buffer)*sizeof(WCHAR); + RegSetValueExW(hukey,szProductName,0,REG_SZ, (LPSTR)buffer,size); + HeapFree(GetProcessHeap(),0,buffer); + FIXME("Need to write more keys to the user registry\n"); + + hDb= alloc_msihandle( &package->db->hdr ); + rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo); + MsiCloseHandle(hDb); + if (rc == ERROR_SUCCESS) + { + WCHAR guidbuffer[0x200]; + size = 0x200; + rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL, + guidbuffer, &size); + if (rc == ERROR_SUCCESS) + { + WCHAR squashed[GUID_SIZE]; + /* for now we only care about the first guid */ + LPWSTR ptr = strchrW(guidbuffer,';'); + if (ptr) *ptr = 0; + squash_guid(guidbuffer,squashed); + size = strlenW(squashed)*sizeof(WCHAR); + RegSetValueExW(hukey,szPackageCode,0,REG_SZ, (LPSTR)squashed, + size); + } + else + { + ERR("Unable to query Revision_Number... \n"); + rc = ERROR_SUCCESS; + } + MsiCloseHandle(hSumInfo); + } + else + { + ERR("Unable to open Summary Information\n"); + rc = ERROR_SUCCESS; + } + +end: + + HeapFree(GetProcessHeap(),0,productcode); + RegCloseKey(hkey); + RegCloseKey(hukey); + + return rc; +} + +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) + { + TRACE("no IniFile table\n"); + 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); + msiobj_release(&view->hdr); + return rc; +} + +static UINT ACTION_SelfRegModules(MSIPACKAGE *package) +{ + 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}; + + static const WCHAR ExeStr[] = + {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','s',' ',0}; + STARTUPINFOW si; + PROCESS_INFORMATION info; + BOOL brc; + + memset(&si,0,sizeof(STARTUPINFOW)); + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + { + TRACE("no SelfReg table\n"); + 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); + + 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(package->dialog, info.hProcess); + + HeapFree(GetProcessHeap(),0,filename); + msiobj_release(&row->hdr); + } + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return rc; +} + +static UINT ACTION_PublishFeatures(MSIPACKAGE *package) +{ + LPWSTR productcode; + UINT rc; + DWORD i; + HKEY hkey=0; + HKEY hukey=0; + + if (!package) + return ERROR_INVALID_HANDLE; + + productcode = load_dynamic_property(package,szProductCode,&rc); + if (!productcode) + return rc; + + rc = MSIREG_OpenFeaturesKey(productcode,&hkey,TRUE); + if (rc != ERROR_SUCCESS) + goto end; + + rc = MSIREG_OpenUserFeaturesKey(productcode,&hukey,TRUE); + if (rc != ERROR_SUCCESS) + goto end; + + /* here the guids are base 85 encoded */ + for (i = 0; i < package->loaded_features; i++) + { + LPWSTR data = NULL; + GUID clsid; + int j; + INT size; + + if (!ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_LOCAL)) + continue; + + size = package->features[i].ComponentCount*21; + size +=1; + if (package->features[i].Feature_Parent[0]) + size += strlenW(package->features[i].Feature_Parent)+2; + + data = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); + + data[0] = 0; + for (j = 0; j < package->features[i].ComponentCount; j++) + { + WCHAR buf[21]; + memset(buf,0,sizeof(buf)); + TRACE("From %s\n",debugstr_w(package->components + [package->features[i].Components[j]].ComponentId)); + CLSIDFromString(package->components + [package->features[i].Components[j]].ComponentId, + &clsid); + encode_base85_guid(&clsid,buf); + TRACE("to %s\n",debugstr_w(buf)); + strcatW(data,buf); + } + if (package->features[i].Feature_Parent[0]) + { + static const WCHAR sep[] = {'\2',0}; + strcatW(data,sep); + strcatW(data,package->features[i].Feature_Parent); + } + + size = (strlenW(data)+1)*sizeof(WCHAR); + RegSetValueExW(hkey,package->features[i].Feature,0,REG_SZ, + (LPSTR)data,size); + HeapFree(GetProcessHeap(),0,data); + + size = strlenW(package->features[i].Feature_Parent)*sizeof(WCHAR); + RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ, + (LPSTR)package->features[i].Feature_Parent,size); + } + +end: + RegCloseKey(hkey); + RegCloseKey(hukey); + HeapFree(GetProcessHeap(), 0, productcode); + return rc; +} + +static UINT ACTION_RegisterProduct(MSIPACKAGE *package) +{ + HKEY hkey=0; + LPWSTR buffer; + LPWSTR productcode; + UINT rc,i; + DWORD size; + static WCHAR szNONE[] = {0}; + static const WCHAR szWindowsInstaler[] = + {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0}; + static const WCHAR szPropKeys[][80] = + { +{'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0}, +{'A','R','P','C','O','N','T','A','C','T',0}, +{'A','R','P','C','O','M','M','E','N','T','S',0}, +{'P','r','o','d','u','c','t','N','a','m','e',0}, +{'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0}, +{'A','R','P','H','E','L','P','L','I','N','K',0}, +{'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0}, +{'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0}, +{'S','o','u','r','c','e','D','i','r',0}, +{'M','a','n','u','f','a','c','t','u','r','e','r',0}, +{'A','R','P','R','E','A','D','M','E',0}, +{'A','R','P','S','I','Z','E',0}, +{'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0}, +{'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0}, +{0}, + }; + + static const WCHAR szRegKeys[][80] = + { +{'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0}, +{'C','o','n','t','a','c','t',0}, +{'C','o','m','m','e','n','t','s',0}, +{'D','i','s','p','l','a','y','N','a','m','e',0}, +{'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0}, +{'H','e','l','p','L','i','n','k',0}, +{'H','e','l','p','T','e','l','e','p','h','o','n','e',0}, +{'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0}, +{'I','n','s','t','a','l','l','S','o','u','r','c','e',0}, +{'P','u','b','l','i','s','h','e','r',0}, +{'R','e','a','d','m','e',0}, +{'S','i','z','e',0}, +{'U','R','L','I','n','f','o','A','b','o','u','t',0}, +{'U','R','L','U','p','d','a','t','e','I','n','f','o',0}, +{0}, + }; + + static const WCHAR installerPathFmt[] = { + '%','s','\\', + 'I','n','s','t','a','l','l','e','r','\\',0}; + static const WCHAR fmt[] = { + '%','s','\\', + 'I','n','s','t','a','l','l','e','r','\\', + '%','x','.','m','s','i',0}; + static const WCHAR szLocalPackage[]= + {'L','o','c','a','l','P','a','c','k','a','g','e',0}; + WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH]; + INT num,start; + + if (!package) + return ERROR_INVALID_HANDLE; + + productcode = load_dynamic_property(package,szProductCode,&rc); + if (!productcode) + return rc; + + rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE); + if (rc != ERROR_SUCCESS) + goto end; + + /* dump all the info i can grab */ + FIXME("Flesh out more information \n"); + + i = 0; + while (szPropKeys[i][0]!=0) + { + buffer = load_dynamic_property(package,szPropKeys[i],&rc); + if (rc != ERROR_SUCCESS) + buffer = szNONE; + size = strlenW(buffer)*sizeof(WCHAR); + RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size); + i++; + } + + rc = 0x1; + size = sizeof(rc); + RegSetValueExW(hkey,szWindowsInstaler,0,REG_DWORD,(LPSTR)&rc,size); + + /* copy the package locally */ + num = GetTickCount() & 0xffff; + if (!num) + num = 1; + start = num; + GetWindowsDirectoryW(windir, sizeof(windir) / sizeof(windir[0])); + snprintfW(packagefile,sizeof(packagefile)/sizeof(packagefile[0]),fmt, + windir,num); + do + { + HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL, + CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 ); + if (handle != INVALID_HANDLE_VALUE) + { + CloseHandle(handle); + break; + } + if (GetLastError() != ERROR_FILE_EXISTS && + GetLastError() != ERROR_SHARING_VIOLATION) + break; + if (!(++num & 0xffff)) num = 1; + sprintfW(packagefile,fmt,num); + } while (num != start); + + snprintfW(path,sizeof(path)/sizeof(path[0]),installerPathFmt,windir); + create_full_pathW(path); + TRACE("Copying to local package %s\n",debugstr_w(packagefile)); + CopyFileW(package->PackagePath,packagefile,FALSE); + size = strlenW(packagefile)*sizeof(WCHAR); + RegSetValueExW(hkey,szLocalPackage,0,REG_SZ,(LPSTR)packagefile,size); + +end: + HeapFree(GetProcessHeap(),0,productcode); + RegCloseKey(hkey); + + return ERROR_SUCCESS; +} + +static UINT ACTION_InstallExecute(MSIPACKAGE *package) +{ + int i; + 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); + + package->DeferredActionCount = 0; + package->DeferredAction = NULL; + + return ERROR_SUCCESS; +} + +static UINT ACTION_InstallFinalize(MSIPACKAGE *package) +{ + int i; + if (!package) + return ERROR_INVALID_HANDLE; + + /* first do the same as an InstallExecute */ + ACTION_InstallExecute(package); + + /* 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); + + package->CommitActionCount = 0; + package->CommitAction = NULL; + + return ERROR_SUCCESS; +} + +static UINT ACTION_ForceReboot(MSIPACKAGE *package) +{ + static const WCHAR RunOnce[] = { + 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'R','u','n','O','n','c','e',0}; + static const WCHAR InstallRunOnce[] = { + 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'I','n','s','t','a','l','l','e','r','\\', + 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0}; + + static const WCHAR msiexec_fmt[] = { + '%','s', + '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ', + '\"','%','s','\"',0}; + static const WCHAR install_fmt[] = { + '/','I',' ','\"','%','s','\"',' ', + 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ', + 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0}; + WCHAR buffer[256], sysdir[MAX_PATH]; + HKEY hkey,hukey; + LPWSTR productcode; + WCHAR squished_pc[100]; + INT rc; + DWORD size; + static const WCHAR szLUS[] = { + 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0}; + static const WCHAR szSourceList[] = { + 'S','o','u','r','c','e','L','i','s','t',0}; + static const WCHAR szPackageName[] = { + 'P','a','c','k','a','g','e','N','a','m','e',0}; + + if (!package) + return ERROR_INVALID_HANDLE; + + productcode = load_dynamic_property(package,szProductCode,&rc); + if (!productcode) + return rc; + + squash_guid(productcode,squished_pc); + + GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0])); + RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey); + snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir, + squished_pc); + + size = strlenW(buffer)*sizeof(WCHAR); + RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size); + RegCloseKey(hkey); + + TRACE("Reboot command %s\n",debugstr_w(buffer)); + + RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey); + sprintfW(buffer,install_fmt,productcode,squished_pc); + + size = strlenW(buffer)*sizeof(WCHAR); + RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size); + RegCloseKey(hkey); + + rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE); + if (rc == ERROR_SUCCESS) + { + HKEY hukey2; + LPWSTR buf; + RegCreateKeyW(hukey, szSourceList, &hukey2); + buf = load_dynamic_property(package,cszSourceDir,NULL); + size = strlenW(buf)*sizeof(WCHAR); + RegSetValueExW(hukey2,szLUS,0,REG_SZ,(LPSTR)buf,size); + HeapFree(GetProcessHeap(),0,buf); + + buf = strrchrW(package->PackagePath,'\\'); + if (buf) + { + buf++; + size = strlenW(buf)*sizeof(WCHAR); + RegSetValueExW(hukey2,szPackageName,0,REG_SZ,(LPSTR)buf,size); + } + + RegCloseKey(hukey2); + } + HeapFree(GetProcessHeap(),0,productcode); + + return ERROR_INSTALL_SUSPEND; +} + +UINT ACTION_ResolveSource(MSIPACKAGE* package) +{ + /* + * we are currently doing what should be done here in the top level Install + * however for Adminastrative and uninstalls this step will be needed + */ + 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)) + { + 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[]= + {'P','r','o','d','u','c','t','I','D',0}; + HKEY hkey=0; + LPWSTR buffer; + LPWSTR productcode; + LPWSTR productid; + UINT rc,i; + DWORD size; + + static const WCHAR szPropKeys[][80] = + { + {'P','r','o','d','u','c','t','I','D',0}, + {'U','S','E','R','N','A','M','E',0}, + {'C','O','M','P','A','N','Y','N','A','M','E',0}, + {0}, + }; + + static const WCHAR szRegKeys[][80] = + { + {'P','r','o','d','u','c','t','I','D',0}, + {'R','e','g','O','w','n','e','r',0}, + {'R','e','g','C','o','m','p','a','n','y',0}, + {0}, + }; + + if (!package) + return ERROR_INVALID_HANDLE; + + productid = load_dynamic_property(package,szProductID,&rc); + if (!productid) + return ERROR_SUCCESS; + + productcode = load_dynamic_property(package,szProductCode,&rc); + if (!productcode) + return rc; + + rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE); + if (rc != ERROR_SUCCESS) + goto end; + + i = 0; + while (szPropKeys[i][0]!=0) + { + buffer = load_dynamic_property(package,szPropKeys[i],&rc); + if (rc == ERROR_SUCCESS) + { + size = strlenW(buffer)*sizeof(WCHAR); + RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size); + } + i++; + } + +end: + HeapFree(GetProcessHeap(),0,productcode); + HeapFree(GetProcessHeap(),0,productid); + RegCloseKey(hkey); + + return ERROR_SUCCESS; +} + + +static UINT ACTION_ExecuteAction(MSIPACKAGE *package) +{ + UINT rc; + rc = ACTION_ProcessExecSequence(package,TRUE); + return rc; +} + + +/* + * Code based off of code located here + * http://www.codeproject.com/gdi/fontnamefromfile.asp + * + * Using string index 4 (full font name) instead of 1 (family name) + */ +static LPWSTR load_ttfname_from(LPCWSTR filename) +{ + HANDLE handle; + LPWSTR ret = NULL; + int i; + + typedef struct _tagTT_OFFSET_TABLE{ + USHORT uMajorVersion; + USHORT uMinorVersion; + USHORT uNumOfTables; + USHORT uSearchRange; + USHORT uEntrySelector; + USHORT uRangeShift; + }TT_OFFSET_TABLE; + + typedef struct _tagTT_TABLE_DIRECTORY{ + char szTag[4]; /* table name */ + ULONG uCheckSum; /* Check sum */ + ULONG uOffset; /* Offset from beginning of file */ + ULONG uLength; /* length of the table in bytes */ + }TT_TABLE_DIRECTORY; + + typedef struct _tagTT_NAME_TABLE_HEADER{ + USHORT uFSelector; /* format selector. Always 0 */ + USHORT uNRCount; /* Name Records count */ + USHORT uStorageOffset; /* Offset for strings storage, + * from start of the table */ + }TT_NAME_TABLE_HEADER; + + typedef struct _tagTT_NAME_RECORD{ + USHORT uPlatformID; + USHORT uEncodingID; + USHORT uLanguageID; + USHORT uNameID; + USHORT uStringLength; + USHORT uStringOffset; /* from start of storage area */ + }TT_NAME_RECORD; + +#define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x)) +#define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x))) + + handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, 0 ); + if (handle != INVALID_HANDLE_VALUE) + { + TT_TABLE_DIRECTORY tblDir; + BOOL bFound = FALSE; + TT_OFFSET_TABLE ttOffsetTable; + + ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),NULL,NULL); + ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables); + ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion); + ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion); + + if (ttOffsetTable.uMajorVersion != 1 || + ttOffsetTable.uMinorVersion != 0) + return NULL; + + for (i=0; i< ttOffsetTable.uNumOfTables; i++) + { + ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),NULL,NULL); + if (strncmp(tblDir.szTag,"name",4)==0) + { + bFound = TRUE; + tblDir.uLength = SWAPLONG(tblDir.uLength); + tblDir.uOffset = SWAPLONG(tblDir.uOffset); + break; + } + } + + if (bFound) + { + TT_NAME_TABLE_HEADER ttNTHeader; + TT_NAME_RECORD ttRecord; + + SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN); + ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER), + NULL,NULL); + + ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount); + ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset); + bFound = FALSE; + for(i=0; i 0) + { + strcat(buf,tt); + ret = strdupAtoW(buf); + HeapFree(GetProcessHeap(),0,buf); + break; + } + + HeapFree(GetProcessHeap(),0,buf); + SetFilePointer(handle,nPos, NULL, FILE_BEGIN); + } + } + } + CloseHandle(handle); + } + + TRACE("Returning fontname %s\n",debugstr_w(ret)); + return ret; +} + +static UINT ACTION_RegisterFonts(MSIPACKAGE *package) +{ + 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}; + static const WCHAR regfont1[] = + {'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s',' ','N','T','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'F','o','n','t','s',0}; + static const WCHAR regfont2[] = + {'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'F','o','n','t','s',0}; + HKEY hkey1; + HKEY hkey2; + + 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; + } + + 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); + msiobj_release(&view->hdr); + + RegCloseKey(hkey1); + RegCloseKey(hkey2); + + return rc; +} + +/* Msi functions that seem appropriate here */ +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; +} + +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; +} + + +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 (strcmpiW(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; +} + +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; +} + +/* + * 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 MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature, + INSTALLSTATE iState) +{ + MSIPACKAGE* package; + INT index; + UINT rc = ERROR_SUCCESS; + + TRACE(" %s to %i\n",debugstr_w(szFeature), iState); + + package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); + if (!package) + return ERROR_INVALID_HANDLE; + + index = get_loaded_feature(package,szFeature); + if (index < 0) + { + rc = ERROR_UNKNOWN_FEATURE; + goto end; + } + + package->features[index].ActionRequest= iState; + ACTION_UpdateComponentStates(package,szFeature); + +end: + 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; +} + +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; +} + +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 221e2a22275..1ac1430c32e 100644 --- a/reactos/lib/msi/action.h +++ b/reactos/lib/msi/action.h @@ -53,6 +53,9 @@ typedef struct tagMSICOMPONENT BOOL Enabled; INT Cost; + INT RefCount; + + LPWSTR FullKeypath; } MSICOMPONENT; typedef struct tagMSIFOLDER diff --git a/reactos/lib/msi/appsearch.c b/reactos/lib/msi/appsearch.c index 60059b6429b..8918d7f4588 100644 --- a/reactos/lib/msi/appsearch.c +++ b/reactos/lib/msi/appsearch.c @@ -629,7 +629,7 @@ static BOOL ACTION_IsFullPath(LPCWSTR path) WCHAR first = toupperW(path[0]); BOOL ret; - if (first >= 'A' && first <= 'A' && path[1] == ':') + if (first >= 'A' && first <= 'Z' && path[1] == ':') ret = TRUE; else if (path[0] == '\\' && path[1] == '\\') ret = TRUE; @@ -644,6 +644,7 @@ static UINT ACTION_SearchDirectory(MSIPACKAGE *package, MSISIGNATURE *sig, UINT rc; BOOL found; + TRACE("%p, %p, %s, %d\n", package, sig, debugstr_w(expanded), depth); if (ACTION_IsFullPath(expanded)) { if (sig->File) @@ -681,6 +682,7 @@ static UINT ACTION_SearchDirectory(MSIPACKAGE *package, MSISIGNATURE *sig, } } } + TRACE("returning %d\n", rc); return rc; } diff --git a/reactos/lib/msi/delete.c b/reactos/lib/msi/delete.c new file mode 100644 index 00000000000..fdb1c00c4fd --- /dev/null +++ b/reactos/lib/msi/delete.c @@ -0,0 +1,218 @@ +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002-2005 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "msi.h" +#include "msiquery.h" +#include "objbase.h" +#include "objidl.h" +#include "msipriv.h" +#include "winnls.h" + +#include "query.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + + +/* + * Code to delete rows from a table. + * + * We delete rows by blanking them out rather than trying to remove the row. + * This appears to be what the native MSI does (or tries to do). For the query: + * + * delete from Property + * + * some non-zero entries are left in the table by native MSI. I'm not sure if + * that's a bug in the way I'm running the query, or a just a bug. + */ + +typedef struct tagMSIDELETEVIEW +{ + MSIVIEW view; + MSIDATABASE *db; + MSIVIEW *table; +} MSIDELETEVIEW; + +static UINT DELETE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) +{ + MSIDELETEVIEW *dv = (MSIDELETEVIEW*)view; + + TRACE("%p %d %d %p\n", dv, row, col, val ); + + return ERROR_FUNCTION_FAILED; +} + +static UINT DELETE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm) +{ + MSIDELETEVIEW *dv = (MSIDELETEVIEW*)view; + + TRACE("%p %d %d %p\n", dv, row, col, stm ); + + return ERROR_FUNCTION_FAILED; +} + +static UINT DELETE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val ) +{ + MSIDELETEVIEW *dv = (MSIDELETEVIEW*)view; + + TRACE("%p %d %d %04x\n", dv, row, col, val ); + + return ERROR_FUNCTION_FAILED; +} + +static UINT DELETE_insert_row( struct tagMSIVIEW *view, UINT *num ) +{ + MSIDELETEVIEW *dv = (MSIDELETEVIEW*)view; + + TRACE("%p %p\n", dv, num ); + + return ERROR_FUNCTION_FAILED; +} + +static UINT DELETE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) +{ + MSIDELETEVIEW *dv = (MSIDELETEVIEW*)view; + UINT r, i, j, rows = 0, cols = 0; + + TRACE("%p %p\n", dv, record); + + if( !dv->table ) + return ERROR_FUNCTION_FAILED; + + r = dv->table->ops->execute( dv->table, record ); + if( r != ERROR_SUCCESS ) + return r; + + r = dv->table->ops->get_dimensions( dv->table, &rows, &cols ); + if( r != ERROR_SUCCESS ) + return r; + + TRACE("blanking %d rows\n", rows); + + /* blank out all the rows that match */ + for( i=0; itable->ops->set_int( dv->table, i, j, 0 ); + + return ERROR_SUCCESS; +} + +static UINT DELETE_close( struct tagMSIVIEW *view ) +{ + MSIDELETEVIEW *dv = (MSIDELETEVIEW*)view; + + TRACE("%p\n", dv ); + + if( !dv->table ) + return ERROR_FUNCTION_FAILED; + + return dv->table->ops->close( dv->table ); +} + +static UINT DELETE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) +{ + MSIDELETEVIEW *dv = (MSIDELETEVIEW*)view; + + TRACE("%p %p %p\n", dv, rows, cols ); + + if( !dv->table ) + return ERROR_FUNCTION_FAILED; + + *rows = 0; + + return dv->table->ops->get_dimensions( dv->table, NULL, cols ); +} + +static UINT DELETE_get_column_info( struct tagMSIVIEW *view, + UINT n, LPWSTR *name, UINT *type ) +{ + MSIDELETEVIEW *dv = (MSIDELETEVIEW*)view; + + TRACE("%p %d %p %p\n", dv, n, name, type ); + + if( !dv->table ) + return ERROR_FUNCTION_FAILED; + + return dv->table->ops->get_column_info( dv->table, n, name, type ); +} + +static UINT DELETE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, + MSIRECORD *rec ) +{ + MSIDELETEVIEW *dv = (MSIDELETEVIEW*)view; + + TRACE("%p %d %p\n", dv, eModifyMode, rec ); + + return ERROR_FUNCTION_FAILED; +} + +static UINT DELETE_delete( struct tagMSIVIEW *view ) +{ + MSIDELETEVIEW *dv = (MSIDELETEVIEW*)view; + + TRACE("%p\n", dv ); + + if( dv->table ) + dv->table->ops->delete( dv->table ); + + HeapFree( GetProcessHeap(), 0, dv ); + + return ERROR_SUCCESS; +} + + +MSIVIEWOPS delete_ops = +{ + DELETE_fetch_int, + DELETE_fetch_stream, + DELETE_set_int, + DELETE_insert_row, + DELETE_execute, + DELETE_close, + DELETE_get_dimensions, + DELETE_get_column_info, + DELETE_modify, + DELETE_delete +}; + +UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table ) +{ + MSIDELETEVIEW *dv = NULL; + + TRACE("%p\n", dv ); + + dv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *dv ); + if( !dv ) + return ERROR_FUNCTION_FAILED; + + /* fill the structure */ + dv->view.ops = &delete_ops; + dv->db = db; + dv->table = table; + + *view = &dv->view; + + return ERROR_SUCCESS; +} diff --git a/reactos/lib/msi/dialog.c b/reactos/lib/msi/dialog.c index db8328f14d1..ccd01a43c1c 100644 --- a/reactos/lib/msi/dialog.c +++ b/reactos/lib/msi/dialog.c @@ -41,6 +41,9 @@ const WCHAR szMsiDialogClass[] = { 'M','s','i','D','i','a','l','o','g','C','l','o','s','e','C','l','a','s','s',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; @@ -83,10 +86,19 @@ struct control_handler msi_dialog_control_func func; }; +typedef struct +{ + msi_dialog* dialog; + msi_control *parent; + DWORD attributes; +} radio_button_group_descr; + 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 LRESULT WINAPI MSIRadioGroup_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); INT msi_dialog_scale_unit( msi_dialog *dialog, INT val ) @@ -275,7 +287,6 @@ static UINT msi_dialog_text_control( msi_dialog *dialog, MSIRECORD *rec ) static UINT msi_dialog_button_control( msi_dialog *dialog, MSIRECORD *rec ) { - const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 }; msi_control *control; TRACE("%p %p\n", dialog, rec); @@ -288,7 +299,6 @@ static UINT msi_dialog_button_control( msi_dialog *dialog, MSIRECORD *rec ) static UINT msi_dialog_checkbox_control( msi_dialog *dialog, MSIRECORD *rec ) { - const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 }; msi_control *control; LPCWSTR prop; @@ -319,7 +329,7 @@ static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec ) TRACE("%p %p\n", dialog, rec); - msi_dialog_add_control( dialog, rec, szEdit, + msi_dialog_add_control( dialog, rec, szEdit, WS_BORDER | ES_MULTILINE | WS_VSCROLL | ES_READONLY | ES_AUTOVSCROLL ); return ERROR_SUCCESS; @@ -350,7 +360,7 @@ static UINT msi_dialog_edit_control( msi_dialog *dialog, MSIRECORD *rec ) LPCWSTR prop; LPWSTR val; - control = msi_dialog_add_control( dialog, rec, szEdit, 0 ); + control = msi_dialog_add_control( dialog, rec, szEdit, WS_BORDER ); control->handler = msi_dialog_edit_handler; prop = MSI_RecordGetString( rec, 9 ); if( prop ) @@ -361,8 +371,125 @@ static UINT msi_dialog_edit_control( msi_dialog *dialog, MSIRECORD *rec ) return ERROR_SUCCESS; } +static UINT msi_dialog_pathedit_control( msi_dialog *dialog, MSIRECORD *rec ) +{ + FIXME("not implemented properly\n"); + return msi_dialog_edit_control( dialog, rec ); +} + +static UINT msi_dialog_create_radiobutton( MSIRECORD *rec, LPVOID param ) +{ + radio_button_group_descr *group = (radio_button_group_descr *)param; + msi_dialog *dialog = group->dialog; + msi_control *control; + LPCWSTR prop; + DWORD x, y, width, height, style; + DWORD attributes = group->attributes; + LPCWSTR text, name; + LPWSTR font = NULL, title = NULL; + + style = WS_CHILD | BS_AUTORADIOBUTTON | BS_MULTILINE; + name = MSI_RecordGetString( rec, 3 ); + control = HeapAlloc( GetProcessHeap(), 0, + sizeof *control + strlenW(name)*sizeof(WCHAR) ); + strcpyW( control->name, name ); + control->next = dialog->control_list; + dialog->control_list = control; + + x = MSI_RecordGetInteger( rec, 4 ); + y = MSI_RecordGetInteger( rec, 5 ); + width = MSI_RecordGetInteger( rec, 6 ); + height = MSI_RecordGetInteger( rec, 7 ); + text = MSI_RecordGetString( rec, 8 ); + + x = msi_dialog_scale_unit( dialog, x ); + y = msi_dialog_scale_unit( dialog, y ); + width = msi_dialog_scale_unit( dialog, width ); + height = msi_dialog_scale_unit( dialog, height ); + + if( attributes & 1 ) + style |= WS_VISIBLE; + if( ~attributes & 2 ) + style |= WS_DISABLED; + + if( text ) + { + font = msi_dialog_get_style( &text ); + deformat_string( dialog->package, text, &title ); + } + + control->hwnd = CreateWindowW( szButton, title, style, x, y, width, height, + group->parent->hwnd, NULL, NULL, NULL ); + + TRACE("Dialog %s control %s hwnd %p\n", debugstr_w(dialog->name), debugstr_w(text), control->hwnd); + + msi_dialog_set_font( dialog, control->hwnd, + font ? font : dialog->default_font ); + + HeapFree( GetProcessHeap(), 0, font ); + HeapFree( GetProcessHeap(), 0, title ); + + control->handler = msi_dialog_radiogroup_handler; + + prop = MSI_RecordGetString( rec, 1 ); + if( prop ) + control->property = dupstrW( prop ); + + return ERROR_SUCCESS; +} + +static UINT msi_dialog_radiogroup_control( msi_dialog *dialog, MSIRECORD *rec ) +{ + static const WCHAR query[] = { + 'S','E','L','E','C','T',' ','*',' ', + 'F','R','O','M',' ','R','a','d','i','o','B','u','t','t','o','n',' ', + 'W','H','E','R','E',' ', + '`','P','r','o','p','e','r','t','y','`',' ','=',' ','\'','%','s','\'',0}; + UINT r; + LPCWSTR prop; + msi_control *control; + MSIQUERY *view = NULL; + radio_button_group_descr group; + MSIPACKAGE *package = dialog->package; + + 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 ); + + if (control->hwnd) + { + WNDPROC oldproc = (WNDPROC) SetWindowLongPtrW(control->hwnd, GWLP_WNDPROC, + (LONG_PTR)MSIRadioGroup_WndProc); + SetPropW(control->hwnd, szButtonData, oldproc); + } + + if( prop ) + control->property = dupstrW( prop ); + + /* query the Radio Button table for all control in this group */ + r = MSI_OpenQuery( package->db, &view, query, prop ); + if( r != ERROR_SUCCESS ) + { + ERR("query failed for dialog %s radio group %s\n", + debugstr_w(dialog->name), debugstr_w(prop)); + return ERROR_INVALID_PARAMETER; + } + + group.dialog = dialog; + group.parent = control; + group.attributes = MSI_RecordGetInteger( rec, 8 ); + + r = MSI_IterateRecords( view, 0, msi_dialog_create_radiobutton, &group ); + msiobj_release( &view->hdr ); + + return r; +} + static const WCHAR szText[] = { 'T','e','x','t',0 }; -static const WCHAR szButton[] = { 'P','u','s','h','B','u','t','t','o','n',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 }; @@ -371,11 +498,14 @@ static const WCHAR szScrollableText[] = { 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 }, - { szButton, msi_dialog_button_control }, + { szPushButton, msi_dialog_button_control }, { szLine, msi_dialog_line_control }, { szBitmap, msi_dialog_bitmap_control }, { szCheckBox, msi_dialog_checkbox_control }, @@ -383,6 +513,8 @@ struct control_handler msi_dialog_handler[] = { szComboBox, msi_dialog_combo_control }, { szEdit, msi_dialog_edit_control }, { szMaskedEdit, msi_dialog_edit_control }, + { szPathEdit, msi_dialog_pathedit_control }, + { szRadioButtonGroup, msi_dialog_radiogroup_control }, }; #define NUM_CONTROL_TYPES (sizeof msi_dialog_handler/sizeof msi_dialog_handler[0]) @@ -791,6 +923,20 @@ static UINT msi_dialog_edit_handler( msi_dialog *dialog, return ERROR_SUCCESS; } +static UINT msi_dialog_radiogroup_handler( msi_dialog *dialog, + msi_control *control, WPARAM param ) +{ + if( HIWORD(param) != BN_CLICKED ) + return ERROR_SUCCESS; + + TRACE("clicked radio button %s, set %s\n", debugstr_w(control->name), + debugstr_w(control->property)); + + MSI_SetPropertyW( dialog->package, control->property, control->name ); + + return msi_dialog_button_handler( dialog, control, param ); +} + static LRESULT msi_dialog_oncommand( msi_dialog *dialog, WPARAM param, HWND hwnd ) { msi_control *control; @@ -816,6 +962,7 @@ static LRESULT WINAPI MSIDialog_WndProc( HWND hwnd, UINT msg, { msi_dialog *dialog = (LPVOID) GetWindowLongPtrW( hwnd, GWLP_USERDATA ); + TRACE(" 0x%04x\n", msg); switch (msg) { case WM_CREATE: @@ -971,3 +1118,15 @@ void msi_dialog_unregister_class( void ) { UnregisterClassW( szMsiDialogClass, NULL ); } + +static LRESULT WINAPI MSIRadioGroup_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + WNDPROC oldproc = (WNDPROC) GetPropW(hWnd, szButtonData); + + TRACE("hWnd %p msg %04x wParam 0x%08x lParam 0x%08lx\n", hWnd, msg, wParam, lParam); + + if (msg == WM_COMMAND) /* Forward notifications to dialog */ + SendMessageW(GetParent(hWnd), msg, wParam, lParam); + + return CallWindowProcW(oldproc, hWnd, msg, wParam, lParam); +} diff --git a/reactos/lib/msi/format.c b/reactos/lib/msi/format.c index a5a9d2b778b..22f11dcc08b 100644 --- a/reactos/lib/msi/format.c +++ b/reactos/lib/msi/format.c @@ -231,13 +231,13 @@ static BOOL find_next_outermost_key(LPCWSTR source, DWORD len_remaining, *nested = FALSE; for (i = 1; (*mark - source) + i < len_remaining && count > 0; i++) { - if ((*mark)[i] == '[') + if ((*mark)[i] == '[' && (*mark)[i-1] != '\\') { count ++; total_count ++; *nested = TRUE; } - else if ((*mark)[i] == ']') + else if ((*mark)[i] == ']' && (*mark)[i-1] != '\\') { count --; } @@ -538,11 +538,8 @@ UINT WINAPI MsiFormatRecordW( MSIHANDLE hInstall, MSIHANDLE hRecord, package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); - if( record ) - { - r = MSI_FormatRecordW( package, record, szResult, sz ); - msiobj_release( &record->hdr ); - } + r = MSI_FormatRecordW( package, record, szResult, sz ); + msiobj_release( &record->hdr ); if (package) msiobj_release( &package->hdr ); return r; @@ -572,11 +569,8 @@ UINT WINAPI MsiFormatRecordA( MSIHANDLE hInstall, MSIHANDLE hRecord, package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); - if( record ) - { - r = MSI_FormatRecordA( package, record, szResult, sz ); - msiobj_release( &record->hdr ); - } + r = MSI_FormatRecordA( package, record, szResult, sz ); + msiobj_release( &record->hdr ); if (package) msiobj_release( &package->hdr ); return r; diff --git a/reactos/lib/msi/msi.c b/reactos/lib/msi/msi.c index 78f8ce7750a..7534f04f6d2 100644 --- a/reactos/lib/msi/msi.c +++ b/reactos/lib/msi/msi.c @@ -487,6 +487,11 @@ UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel, goto end; package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE); + if (!package) + { + rc = ERROR_INVALID_HANDLE; + goto end; + } sz = strlenW(szInstalled); @@ -865,7 +870,7 @@ INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler, * id [I] id of the string to be loaded * lpBuffer [O] buffer for the string to be written to * nBufferMax [I] maximum size of the buffer in characters - * lang [I] the prefered language for the string + * lang [I] the preferred language for the string * * RETURNS * @@ -973,219 +978,6 @@ UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uT return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid) -{ - DWORD r; - WCHAR szwGuid[GUID_SIZE]; - - TRACE("%ld %p\n",index,lpguid); - - if (NULL == lpguid) { - return ERROR_INVALID_PARAMETER; - } - r = MsiEnumProductsW(index, szwGuid); - if( r == ERROR_SUCCESS ) - WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL); - - return r; -} - -UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid) -{ - HKEY hkeyFeatures = 0; - DWORD r; - WCHAR szKeyName[33]; - - TRACE("%ld %p\n",index,lpguid); - - if (NULL == lpguid) - return ERROR_INVALID_PARAMETER; - - r = MSIREG_OpenFeatures(&hkeyFeatures); - if( r != ERROR_SUCCESS ) - goto end; - - r = RegEnumKeyW(hkeyFeatures, index, szKeyName, GUID_SIZE); - - unsquash_guid(szKeyName, lpguid); - -end: - - if( hkeyFeatures ) - RegCloseKey(hkeyFeatures); - - return r; -} - -UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index, - LPSTR szFeature, LPSTR szParent) -{ - DWORD r; - WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE]; - LPWSTR szwProduct = NULL; - - TRACE("%s %ld %p %p\n",debugstr_a(szProduct),index,szFeature,szParent); - - if( szProduct ) - { - UINT len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 ); - szwProduct = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); - if( szwProduct ) - MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len ); - else - return ERROR_FUNCTION_FAILED; - } - - r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent); - if( r == ERROR_SUCCESS ) - { - WideCharToMultiByte(CP_ACP, 0, szwFeature, -1, - szFeature, GUID_SIZE, NULL, NULL); - WideCharToMultiByte(CP_ACP, 0, szwParent, -1, - szParent, GUID_SIZE, NULL, NULL); - } - - HeapFree( GetProcessHeap(), 0, szwProduct); - - return r; -} - -UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index, - LPWSTR szFeature, LPWSTR szParent) -{ - HKEY hkeyProduct = 0; - DWORD r, sz; - - TRACE("%s %ld %p %p\n",debugstr_w(szProduct),index,szFeature,szParent); - - r = MSIREG_OpenFeaturesKey(szProduct,&hkeyProduct,FALSE); - if( r != ERROR_SUCCESS ) - goto end; - - sz = GUID_SIZE; - r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL); - -end: - if( hkeyProduct ) - RegCloseKey(hkeyProduct); - - return r; -} - -UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid) -{ - DWORD r; - WCHAR szwGuid[GUID_SIZE]; - - TRACE("%ld %p\n",index,lpguid); - - r = MsiEnumComponentsW(index, szwGuid); - if( r == ERROR_SUCCESS ) - WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL); - - return r; -} - -UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid) -{ - HKEY hkeyComponents = 0; - DWORD r; - WCHAR szKeyName[33]; - - TRACE("%ld %p\n",index,lpguid); - - r = MSIREG_OpenComponents(&hkeyComponents); - if( r != ERROR_SUCCESS ) - goto end; - - r = RegEnumKeyW(hkeyComponents, index, szKeyName, GUID_SIZE); - - unsquash_guid(szKeyName, lpguid); - -end: - - if( hkeyComponents ) - RegCloseKey(hkeyComponents); - - return r; -} - -UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct) -{ - DWORD r; - WCHAR szwProduct[GUID_SIZE]; - LPWSTR szwComponent = NULL; - - TRACE("%s %ld %p\n",debugstr_a(szComponent),index,szProduct); - - if( szComponent ) - { - UINT len = MultiByteToWideChar( CP_ACP, 0, szComponent, -1, NULL, 0 ); - szwComponent = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); - if( szwComponent ) - MultiByteToWideChar( CP_ACP, 0, szComponent, -1, szwComponent, len ); - else - return ERROR_FUNCTION_FAILED; - } - - r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct); - if( r == ERROR_SUCCESS ) - { - WideCharToMultiByte(CP_ACP, 0, szwProduct, -1, - szProduct, GUID_SIZE, NULL, NULL); - } - - HeapFree( GetProcessHeap(), 0, szwComponent); - - return r; -} - -UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct) -{ - HKEY hkeyComp = 0; - DWORD r, sz; - WCHAR szValName[GUID_SIZE]; - - TRACE("%s %ld %p\n",debugstr_w(szComponent),index,szProduct); - - r = MSIREG_OpenComponentsKey(szComponent,&hkeyComp,FALSE); - if( r != ERROR_SUCCESS ) - goto end; - - sz = GUID_SIZE; - r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL); - if( r != ERROR_SUCCESS ) - goto end; - - unsquash_guid(szValName, szProduct); - -end: - if( hkeyComp ) - RegCloseKey(hkeyComp); - - return r; -} - -UINT WINAPI MsiEnumComponentQualifiersA( LPSTR szComponent, DWORD iIndex, - LPSTR lpQualifierBuf, DWORD* pcchQualifierBuf, - LPSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf) -{ - FIXME("%s %08lx %p %p %p %p\n", debugstr_a(szComponent), iIndex, - lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, - pcchApplicationDataBuf); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiEnumComponentQualifiersW( LPWSTR szComponent, DWORD iIndex, - LPWSTR lpQualifierBuf, DWORD* pcchQualifierBuf, - LPWSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf ) -{ - FIXME("%s %08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex, - lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, - pcchApplicationDataBuf); - return ERROR_CALL_NOT_IMPLEMENTED; -} - UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext, DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf, DWORD* pcchPathBuf ) @@ -1343,41 +1135,72 @@ INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent, WCHAR squished_pc[GUID_SIZE]; UINT rc; INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN; - HKEY hkey=0; + HKEY hkey = 0; + LPWSTR path = NULL; + DWORD sz, type; TRACE("%s %s %p %p\n", debugstr_w(szProduct), debugstr_w(szComponent), lpPathBuf, pcchBuf); + if( lpPathBuf && !pcchBuf ) + return INSTALLSTATE_INVALIDARG; + squash_guid(szProduct,squished_pc); - rc = MSIREG_OpenProductsKey(szProduct,&hkey,FALSE); - if (rc != ERROR_SUCCESS) + rc = MSIREG_OpenProductsKey( szProduct, &hkey, FALSE); + if( rc != ERROR_SUCCESS ) goto end; RegCloseKey(hkey); - rc = MSIREG_OpenComponentsKey(szComponent,&hkey,FALSE); - if (rc != ERROR_SUCCESS) + rc = MSIREG_OpenComponentsKey( szComponent, &hkey, FALSE); + if( rc != ERROR_SUCCESS ) goto end; - *pcchBuf *= sizeof(WCHAR); - rc = RegQueryValueExW(hkey,squished_pc,NULL,NULL,(LPVOID)lpPathBuf, - pcchBuf); - *pcchBuf /= sizeof(WCHAR); + sz = 0; + type = 0; + rc = RegQueryValueExW( hkey, squished_pc, NULL, &type, NULL, &sz ); + if( rc != ERROR_SUCCESS ) + goto end; + if( type != REG_SZ ) + goto end; - if (rc!= ERROR_SUCCESS) + sz += sizeof(WCHAR); + path = HeapAlloc( GetProcessHeap(), 0, sz ); + if( !path ) + goto end; + + rc = RegQueryValueExW( hkey, squished_pc, NULL, NULL, (LPVOID) path, &sz ); + if( rc != ERROR_SUCCESS ) goto end; TRACE("found path of (%s:%s)(%s)\n", debugstr_w(szComponent), - debugstr_w(szProduct), debugstr_w(lpPathBuf)); + debugstr_w(szProduct), debugstr_w(path)); - FIXME("Only working for installed files, not registry keys\n"); - if (GetFileAttributesW(lpPathBuf) != INVALID_FILE_ATTRIBUTES) - rrc = INSTALLSTATE_LOCAL; + if (path[0]=='0') + { + FIXME("Registry entry.. check entry\n"); + rrc = INSTALLSTATE_LOCAL; + } else - rrc = INSTALLSTATE_ABSENT; + { + /* PROBABLY a file */ + if ( GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES ) + rrc = INSTALLSTATE_LOCAL; + else + rrc = INSTALLSTATE_ABSENT; + } + + if( pcchBuf ) + { + sz = sz / sizeof(WCHAR); + if( *pcchBuf >= sz ) + strcpyW( lpPathBuf, path ); + *pcchBuf = sz; + } end: + HeapFree(GetProcessHeap(), 0, path ); RegCloseKey(hkey); return rrc; } @@ -1421,7 +1244,10 @@ INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature) INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature) { FIXME("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature)); - return INSTALLSTATE_UNKNOWN; + /* + * Iterates all the features components and the features parents components + */ + return INSTALLSTATE_LOCAL; } UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf, @@ -1655,22 +1481,6 @@ BOOL WINAPI MSI_DllCanUnloadNow(void) return S_FALSE; } -UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved, - DWORD iProductIndex, LPWSTR lpProductBuf) -{ - FIXME("%s %lu %lu %p\n", debugstr_w(szUpgradeCode), dwReserved, - iProductIndex, lpProductBuf); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved, - DWORD iProductIndex, LPSTR lpProductBuf) -{ - FIXME("%s %lu %lu %p\n", debugstr_a(szUpgradeCode), dwReserved, - iProductIndex, lpProductBuf); - return ERROR_CALL_NOT_IMPLEMENTED; -} - UINT WINAPI MsiGetFeatureUsageW(LPCWSTR szProduct, LPCWSTR szFeature, DWORD* pdwUseCount, WORD* pwDateUsed) { @@ -1687,11 +1497,42 @@ UINT WINAPI MsiGetFeatureUsageA(LPCSTR szProduct, LPCSTR szFeature, return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiUseFeatureExW(LPCWSTR szProduct, LPCWSTR szFeature, +INSTALLSTATE WINAPI MsiUseFeatureExW(LPCWSTR szProduct, LPCWSTR szFeature, DWORD dwInstallMode, DWORD dwReserved) { FIXME("%s %s %li %li\n", debugstr_w(szProduct), debugstr_w(szFeature), dwInstallMode, dwReserved); + + /* + * Polls all the components of the feature to find install state and then + * writes: + * Software\\Microsoft\\Windows\\CurrentVersion\\ + * Installer\\Products\\\\ + * "Usage"=dword:........ + */ + + return INSTALLSTATE_LOCAL; +} + +INSTALLSTATE WINAPI MsiUseFeatureExA(LPCSTR szProduct, LPCSTR szFeature, + DWORD dwInstallMode, DWORD dwReserved) +{ + FIXME("%s %s %li %li\n", debugstr_a(szProduct), debugstr_a(szFeature), + dwInstallMode, dwReserved); + + return INSTALLSTATE_LOCAL; +} + +INSTALLSTATE WINAPI MsiUseFeatureW(LPCWSTR szProduct, LPCWSTR szFeature) +{ + FIXME("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature)); + + return INSTALLSTATE_LOCAL; +} + +INSTALLSTATE WINAPI MsiUseFeatureA(LPCSTR szProduct, LPCSTR szFeature) +{ + FIXME("%s %s\n", debugstr_a(szProduct), debugstr_a(szFeature)); return INSTALLSTATE_LOCAL; } @@ -1749,17 +1590,33 @@ UINT WINAPI MsiCreateAndVerifyInstallerDirectory(void) } UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget, - LPSTR szProductCode, LPSTR szFeatureId, - LPSTR szComponentCode) + LPSTR szProductCode, LPSTR szFeatureId, + LPSTR szComponentCode ) { FIXME("\n"); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget, - LPWSTR szProductCode, LPWSTR szFeatureId, - LPWSTR szComponentCode) + LPWSTR szProductCode, LPWSTR szFeatureId, + LPWSTR szComponentCode ) { FIXME("\n"); return ERROR_CALL_NOT_IMPLEMENTED; } + +UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature, + DWORD dwReinstallMode ) +{ + FIXME("%s %s %li\n", debugstr_w(szProduct), debugstr_w(szFeature), + dwReinstallMode); + return ERROR_SUCCESS; +} + +UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature, + DWORD dwReinstallMode ) +{ + FIXME("%s %s %li\n", debugstr_a(szProduct), debugstr_a(szFeature), + dwReinstallMode); + return ERROR_SUCCESS; +} diff --git a/reactos/lib/msi/msi.rc b/reactos/lib/msi/msi.rc index adf5138d0e3..af6906c8883 100644 --- a/reactos/lib/msi/msi.rc +++ b/reactos/lib/msi/msi.rc @@ -27,4 +27,8 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL #include "version.rc" +#include "msi_De.rc" #include "msi_En.rc" +#include "msi_Es.rc" +#include "msi_Fr.rc" +#include "msi_Pt.rc" diff --git a/reactos/lib/msi/msi.spec b/reactos/lib/msi/msi.spec index ad1cd0d0840..a5a7d44068b 100644 --- a/reactos/lib/msi/msi.spec +++ b/reactos/lib/msi/msi.spec @@ -123,10 +123,10 @@ 123 stdcall MsiRecordSetStreamW(long long wstr) 124 stdcall MsiRecordSetStringA(long long str) 125 stdcall MsiRecordSetStringW(long long wstr) -126 stub MsiReinstallFeatureA +126 stdcall MsiReinstallFeatureA(str str long) 127 stub MsiReinstallFeatureFromDescriptorA 128 stub MsiReinstallFeatureFromDescriptorW -129 stub MsiReinstallFeatureW +129 stdcall MsiReinstallFeatureW(wstr wstr long) 130 stdcall MsiReinstallProductA(str long) 131 stdcall MsiReinstallProductW(wstr long) 132 stub MsiSequenceA @@ -151,8 +151,8 @@ 151 stdcall MsiSummaryInfoPersist(long) 152 stdcall MsiSummaryInfoSetPropertyA(long long long long ptr str) 153 stdcall MsiSummaryInfoSetPropertyW(long long long long ptr wstr) -154 stub MsiUseFeatureA -155 stub MsiUseFeatureW +154 stdcall MsiUseFeatureA(str str) +155 stdcall MsiUseFeatureW(wstr wstr) 156 stdcall MsiVerifyPackageA(str) 157 stdcall MsiVerifyPackageW(wstr) 158 stdcall MsiViewClose(long) @@ -189,7 +189,7 @@ 189 stdcall MsiConfigureProductExA(str long long str) 190 stdcall MsiConfigureProductExW(wstr long long wstr) 191 stub MsiInvalidateFeatureCache -192 stub MsiUseFeatureExA +192 stdcall MsiUseFeatureExA(str str long long) 193 stdcall MsiUseFeatureExW(wstr wstr long long) 194 stdcall MsiGetFileVersionA(str str ptr str ptr) 195 stdcall MsiGetFileVersionW(wstr wstr ptr wstr ptr) diff --git a/reactos/lib/msi/msi_De.rc b/reactos/lib/msi/msi_De.rc new file mode 100644 index 00000000000..0b15276eca8 --- /dev/null +++ b/reactos/lib/msi/msi_De.rc @@ -0,0 +1,33 @@ +/* + * German resources for MSI + * + * Copyright 2005 Henning Gerhardt + * + * 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 + */ + +LANGUAGE LANG_GERMAN, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + 5 "Der Pfad %s wurde nicht gefunden." + 9 "Bitte Disk %s einlegen." + 10 "schlechte Parameter" + 11 "Geben Sie das Verzeichnis ein, dass %s enthält." + 12 "Die Installationsquelle für das Feature fehlt." + 13 "Das Netzwerklaufwerk für das Feature fehlt." + 14 "Feature von:" + 15 "Wählen Sie das Verzeichnis aus, dass %s enthält." +} diff --git a/reactos/lib/msi/msi_Es.rc b/reactos/lib/msi/msi_Es.rc new file mode 100644 index 00000000000..3270f479eea --- /dev/null +++ b/reactos/lib/msi/msi_Es.rc @@ -0,0 +1,33 @@ +/* + * Spanish resources for MSI + * + * Copyright 2005 José Manuel Ferrer Ortiz + * + * 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 + */ + +LANGUAGE LANG_SPANISH, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + 5 "ruta %s no encontrada" + 9 "inserte el disco %s" + 10 "parámetros incorrectos" + 11 "introduzca qué carpeta contiene %s" + 12 "instalar fuente para característica ausente" + 13 "unidad de red para característica ausente" + 14 "característica de:" + 15 "elija qué carpeta contiene %s" +} diff --git a/reactos/lib/msi/msi_Fr.rc b/reactos/lib/msi/msi_Fr.rc new file mode 100644 index 00000000000..d1551aba270 --- /dev/null +++ b/reactos/lib/msi/msi_Fr.rc @@ -0,0 +1,33 @@ +/* + * French resources for MSI + * + * Copyright 2005 Jonathan Ernst + * + * 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 + */ + +LANGUAGE LANG_FRENCH, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + 5 "Le chemin %s est introuvable" + 9 "insérez le disque %s" + 10 "mauvais paramètres" + 11 "saisissez le nom du dossier contenant %s" + 12 "source d'installation pour la fonctionnalité manquante" + 13 "lecteur réseau pour la fonctionnalité manquant" + 14 "fonctionnalité depuis:" + 15 "sélectionnez le dossier contenant %s" +} diff --git a/reactos/lib/msi/msi_Pt.rc b/reactos/lib/msi/msi_Pt.rc new file mode 100644 index 00000000000..aa87ad2fb8e --- /dev/null +++ b/reactos/lib/msi/msi_Pt.rc @@ -0,0 +1,33 @@ +/* + * Portuguese resources for MSI + * + * Copyright 2005 Marcelo Duarte + * + * 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 + */ + +LANGUAGE LANG_PORTUGUESE, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + 5 "caminho %s não encontrado" + 9 "insira disco %s" + 10 "parâmetros inválidos" + 11 "entre qual pasta contém %s" + 12 "instalar fonte para característica faltando" + 13 "drive de rede para característica faltando" + 14 "característica de:" + 15 "escolha qual pasta contém %s" +} diff --git a/reactos/lib/msi/msipriv.h b/reactos/lib/msi/msipriv.h index 98e735056fa..eed3e545517 100644 --- a/reactos/lib/msi/msipriv.h +++ b/reactos/lib/msi/msipriv.h @@ -214,6 +214,8 @@ typedef struct tagMSIPACKAGE UINT CurrentInstallState; msi_dialog *dialog; LPWSTR next_dialog; + + BOOL ExecuteSequenceRun; } MSIPACKAGE; typedef struct tagMSIPREVIEW @@ -362,6 +364,7 @@ extern UINT MSIREG_OpenComponents(HKEY* key); 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_OpenUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create); /* msi dialog interface */ typedef VOID (*msi_dialog_event_handler)( MSIPACKAGE*, LPCWSTR, LPCWSTR, msi_dialog* ); diff --git a/reactos/lib/msi/msiquery.c b/reactos/lib/msi/msiquery.c index 29665bd6fa3..cfe1ecfab64 100644 --- a/reactos/lib/msi/msiquery.c +++ b/reactos/lib/msi/msiquery.c @@ -1,7 +1,7 @@ /* * Implementation of the Microsoft Installer (msi.dll) * - * Copyright 2002-2004 Mike McCormack for CodeWeavers + * Copyright 2002-2005 Mike McCormack for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -212,6 +212,9 @@ UINT MSI_IterateRecords( MSIQUERY *view, DWORD *count, if( count ) *count = n; + if( r == ERROR_NO_MORE_ITEMS ) + r = ERROR_SUCCESS; + return r; } @@ -420,8 +423,7 @@ UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec) msiobj_unlock( &rec->hdr ); out: - if( query ) - msiobj_release( &query->hdr ); + msiobj_release( &query->hdr ); if( rec ) msiobj_release( &rec->hdr ); @@ -460,7 +462,10 @@ UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hR rec = MSI_CreateRecord( count ); if( !rec ) - return ERROR_FUNCTION_FAILED; + { + r = ERROR_FUNCTION_FAILED; + goto out; + } for( i=0; ihdr ); out: - if( query ) - msiobj_release( &query->hdr ); + msiobj_release( &query->hdr ); if( rec ) msiobj_release( &rec->hdr ); @@ -514,8 +518,7 @@ UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode, r = view->ops->modify( view, eModifyMode, rec ); out: - if( query ) - msiobj_release( &query->hdr ); + msiobj_release( &query->hdr ); if( rec ) msiobj_release( &rec->hdr ); @@ -574,18 +577,116 @@ UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb ) return r; } -UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb, - LPCSTR table, MSIHANDLE* rec) +struct msi_primary_key_record_info { - FIXME("%ld %s %p\n", hdb, debugstr_a(table), rec); - return ERROR_CALL_NOT_IMPLEMENTED; + DWORD n; + MSIRECORD *rec; +}; + +static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param ) +{ + struct msi_primary_key_record_info *info = param; + LPCWSTR name; + DWORD type; + + type = MSI_RecordGetInteger( rec, 4 ); + if( type & MSITYPE_KEY ) + { + info->n++; + if( info->rec ) + { + name = MSI_RecordGetString( rec, 3 ); + MSI_RecordSetStringW( info->rec, info->n, name ); + } + } + + return ERROR_SUCCESS; } -UINT WINAPI MsiDatabaseGetPrimaryKeysW(MSIHANDLE hdb, - LPCWSTR table, MSIHANDLE* rec) +UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db, + LPCWSTR table, MSIRECORD **prec ) { - FIXME("%ld %s %p\n", hdb, debugstr_w(table), rec); - return ERROR_CALL_NOT_IMPLEMENTED; + static const WCHAR sql[] = { + 's','e','l','e','c','t',' ','*',' ', + 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ', + 'w','h','e','r','e',' ', + '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 }; + struct msi_primary_key_record_info info; + MSIQUERY *query = NULL; + MSIVIEW *view; + UINT r; + + r = MSI_OpenQuery( db, &query, sql, table ); + if( r != ERROR_SUCCESS ) + return r; + + view = query->view; + + /* count the number of primary key records */ + info.n = 0; + info.rec = 0; + r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info ); + if( r == ERROR_SUCCESS ) + { + TRACE("Found %ld primary keys\n", info.n ); + + /* allocate a record and fill in the names of the tables */ + info.rec = MSI_CreateRecord( info.n ); + info.n = 0; + r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info ); + if( r == ERROR_SUCCESS ) + *prec = info.rec; + else + msiobj_release( &info.rec->hdr ); + } + msiobj_release( &query->hdr ); + + return r; +} + +UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb, + LPCWSTR table, MSIHANDLE* phRec ) +{ + MSIRECORD *rec = NULL; + MSIDATABASE *db; + UINT r; + + TRACE("%ld %s %p\n", hdb, debugstr_w(table), phRec); + + db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE ); + if( !db ) + return ERROR_INVALID_HANDLE; + + r = MSI_DatabaseGetPrimaryKeys( db, table, &rec ); + if( r == ERROR_SUCCESS ) + { + *phRec = alloc_msihandle( &rec->hdr ); + msiobj_release( &rec->hdr ); + } + msiobj_release( &db->hdr ); + + return r; +} + +UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb, + LPCSTR table, MSIHANDLE* phRec) +{ + LPWSTR szwTable = NULL; + DWORD len; + UINT r; + + TRACE("%ld %s %p\n", hdb, debugstr_a(table), phRec); + + if( table ) + { + len = MultiByteToWideChar( CP_ACP, 0, table, -1, NULL, 0 ); + szwTable = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, table, -1, szwTable, len ); + } + r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec ); + HeapFree( GetProcessHeap(), 0, szwTable ); + + return r; } UINT WINAPI MsiDatabaseIsTablePersistentA( diff --git a/reactos/lib/msi/package.c b/reactos/lib/msi/package.c index 72d1a8deda4..60f939e6472 100644 --- a/reactos/lib/msi/package.c +++ b/reactos/lib/msi/package.c @@ -60,7 +60,7 @@ void MSI_FreePackage( MSIOBJECTHDR *arg) msiobj_release( &package->db->hdr ); } -static const UINT clone_properties(MSIDATABASE *db) +static UINT clone_properties(MSIDATABASE *db) { MSIQUERY * view = NULL; UINT rc; @@ -617,7 +617,7 @@ INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType, package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); if( !package ) - goto out; + return ERROR_INVALID_HANDLE; record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD ); if( !record ) @@ -626,8 +626,7 @@ INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType, ret = MSI_ProcessMessage( package, eMessageType, record ); out: - if( package ) - msiobj_release( &package->hdr ); + msiobj_release( &package->hdr ); if( record ) msiobj_release( &record->hdr ); diff --git a/reactos/lib/msi/preview.c b/reactos/lib/msi/preview.c index 03c7436ddd2..5df8ef0e796 100644 --- a/reactos/lib/msi/preview.c +++ b/reactos/lib/msi/preview.c @@ -77,6 +77,7 @@ UINT WINAPI MsiEnableUIPreview( MSIHANDLE hdb, MSIHANDLE* phPreview ) msiobj_release( &preview->hdr ); r = ERROR_SUCCESS; } + msiobj_release( &db->hdr ); return r; } diff --git a/reactos/lib/msi/query.h b/reactos/lib/msi/query.h index dfe5816936d..b66cc589df4 100644 --- a/reactos/lib/msi/query.h +++ b/reactos/lib/msi/query.h @@ -131,6 +131,8 @@ UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **, LPWSTR table, column_assignment *list, struct expr *expr ); +UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table ); + void delete_expr( struct expr *e ); void delete_string_list( string_list *sl ); void delete_value_list( value_list *vl ); diff --git a/reactos/lib/msi/record.c b/reactos/lib/msi/record.c index 967017cd5cc..99722e347c1 100644 --- a/reactos/lib/msi/record.c +++ b/reactos/lib/msi/record.c @@ -210,6 +210,7 @@ UINT WINAPI MsiRecordClearData( MSIHANDLE handle ) rec->fields[i].u.iVal = 0; } msiobj_unlock( &rec->hdr ); + msiobj_release( &rec->hdr ); return ERROR_SUCCESS; } diff --git a/reactos/lib/msi/registry.c b/reactos/lib/msi/registry.c index 61c03c63e5c..ad3fa1c7985 100644 --- a/reactos/lib/msi/registry.c +++ b/reactos/lib/msi/registry.c @@ -117,6 +117,23 @@ static const WCHAR szInstaller_Products_fmt[] = { 'P','r','o','d','u','c','t','s','\\', '%','s',0}; +static const WCHAR szInstaller_UpgradeCodes[] = { +'S','o','f','t','w','a','r','e','\\', +'M','i','c','r','o','s','o','f','t','\\', +'W','i','n','d','o','w','s','\\', +'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', +'I','n','s','t','a','l','l','e','r','\\', +'U','p','g','r','a','d','e','C','o','d','e','s',0}; + +static const WCHAR szInstaller_UpgradeCodes_fmt[] = { +'S','o','f','t','w','a','r','e','\\', +'M','i','c','r','o','s','o','f','t','\\', +'W','i','n','d','o','w','s','\\', +'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', +'I','n','s','t','a','l','l','e','r','\\', +'U','p','g','r','a','d','e','C','o','d','e','s','\\', +'%','s',0}; + BOOL unsquash_guid(LPCWSTR in, LPWSTR out) { DWORD i,n=0; @@ -389,6 +406,26 @@ UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create) return rc; } +UINT MSIREG_OpenUpgradeCodesKey(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_UpgradeCodes_fmt,squished_pc); + + if (create) + rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key); + else + rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key); + + return rc; +} + /************************************************************************* * MsiDecomposeDescriptorW [MSI.@] * @@ -484,3 +521,281 @@ UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct, return r; } + +UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid) +{ + DWORD r; + WCHAR szwGuid[GUID_SIZE]; + + TRACE("%ld %p\n",index,lpguid); + + if (NULL == lpguid) + return ERROR_INVALID_PARAMETER; + r = MsiEnumProductsW(index, szwGuid); + if( r == ERROR_SUCCESS ) + WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL); + + return r; +} + +UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid) +{ + HKEY hkeyFeatures = 0; + DWORD r; + WCHAR szKeyName[33]; + + TRACE("%ld %p\n",index,lpguid); + + if (NULL == lpguid) + return ERROR_INVALID_PARAMETER; + + r = MSIREG_OpenFeatures(&hkeyFeatures); + if( r != ERROR_SUCCESS ) + goto end; + + r = RegEnumKeyW(hkeyFeatures, index, szKeyName, GUID_SIZE); + + unsquash_guid(szKeyName, lpguid); + +end: + + if( hkeyFeatures ) + RegCloseKey(hkeyFeatures); + + return r; +} + +UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index, + LPSTR szFeature, LPSTR szParent) +{ + DWORD r; + WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE]; + LPWSTR szwProduct = NULL; + + TRACE("%s %ld %p %p\n",debugstr_a(szProduct),index,szFeature,szParent); + + if( szProduct ) + { + UINT len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 ); + szwProduct = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); + if( szwProduct ) + MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len ); + else + return ERROR_FUNCTION_FAILED; + } + + r = MsiEnumFeaturesW(szwProduct, index, szwFeature, szwParent); + if( r == ERROR_SUCCESS ) + { + WideCharToMultiByte(CP_ACP, 0, szwFeature, -1, + szFeature, GUID_SIZE, NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, szwParent, -1, + szParent, GUID_SIZE, NULL, NULL); + } + + HeapFree( GetProcessHeap(), 0, szwProduct); + + return r; +} + +UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index, + LPWSTR szFeature, LPWSTR szParent) +{ + HKEY hkeyProduct = 0; + DWORD r, sz; + + TRACE("%s %ld %p %p\n",debugstr_w(szProduct),index,szFeature,szParent); + + r = MSIREG_OpenFeaturesKey(szProduct,&hkeyProduct,FALSE); + if( r != ERROR_SUCCESS ) + goto end; + + sz = GUID_SIZE; + r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL); + +end: + if( hkeyProduct ) + RegCloseKey(hkeyProduct); + + return r; +} + +UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid) +{ + DWORD r; + WCHAR szwGuid[GUID_SIZE]; + + TRACE("%ld %p\n",index,lpguid); + + r = MsiEnumComponentsW(index, szwGuid); + if( r == ERROR_SUCCESS ) + WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL); + + return r; +} + +UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid) +{ + HKEY hkeyComponents = 0; + DWORD r; + WCHAR szKeyName[33]; + + TRACE("%ld %p\n",index,lpguid); + + r = MSIREG_OpenComponents(&hkeyComponents); + if( r != ERROR_SUCCESS ) + goto end; + + r = RegEnumKeyW(hkeyComponents, index, szKeyName, GUID_SIZE); + + unsquash_guid(szKeyName, lpguid); + +end: + + if( hkeyComponents ) + RegCloseKey(hkeyComponents); + + return r; +} + +UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct) +{ + DWORD r; + WCHAR szwProduct[GUID_SIZE]; + LPWSTR szwComponent = NULL; + + TRACE("%s %ld %p\n",debugstr_a(szComponent),index,szProduct); + + if( szComponent ) + { + UINT len = MultiByteToWideChar( CP_ACP, 0, szComponent, -1, NULL, 0 ); + szwComponent = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); + if( szwComponent ) + MultiByteToWideChar( CP_ACP, 0, szComponent, -1, szwComponent, len ); + else + return ERROR_FUNCTION_FAILED; + } + + r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct); + if( r == ERROR_SUCCESS ) + { + WideCharToMultiByte(CP_ACP, 0, szwProduct, -1, + szProduct, GUID_SIZE, NULL, NULL); + } + + HeapFree( GetProcessHeap(), 0, szwComponent); + + return r; +} + +UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct) +{ + HKEY hkeyComp = 0; + DWORD r, sz; + WCHAR szValName[GUID_SIZE]; + + TRACE("%s %ld %p\n",debugstr_w(szComponent),index,szProduct); + + r = MSIREG_OpenComponentsKey(szComponent,&hkeyComp,FALSE); + if( r != ERROR_SUCCESS ) + goto end; + + sz = GUID_SIZE; + r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL); + if( r != ERROR_SUCCESS ) + goto end; + + unsquash_guid(szValName, szProduct); + +end: + if( hkeyComp ) + RegCloseKey(hkeyComp); + + return r; +} + +UINT WINAPI MsiEnumComponentQualifiersA( LPSTR szComponent, DWORD iIndex, + LPSTR lpQualifierBuf, DWORD* pcchQualifierBuf, + LPSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf) +{ + FIXME("%s %08lx %p %p %p %p\n", debugstr_a(szComponent), iIndex, + lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, + pcchApplicationDataBuf); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiEnumComponentQualifiersW( LPWSTR szComponent, DWORD iIndex, + LPWSTR lpQualifierBuf, DWORD* pcchQualifierBuf, + LPWSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf ) +{ + FIXME("%s %08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex, + lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, + pcchApplicationDataBuf); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved, + DWORD iProductIndex, LPWSTR lpProductBuf) +{ + UINT rc; + HKEY hkey; + WCHAR szKeyName[33]; + + TRACE("%s %lu %lu %p\n", debugstr_w(szUpgradeCode), dwReserved, + iProductIndex, lpProductBuf); + + if (NULL == szUpgradeCode) + return ERROR_INVALID_PARAMETER; + if (NULL == lpProductBuf) + return ERROR_INVALID_PARAMETER; + rc = MSIREG_OpenUpgradeCodesKey(szUpgradeCode, &hkey, FALSE); + if (rc != ERROR_SUCCESS) + { + rc = ERROR_NO_MORE_ITEMS; + goto end; + } + + rc = RegEnumKeyW(hkey, iProductIndex, szKeyName, + sizeof(szKeyName) / sizeof(szKeyName[0])); + + unsquash_guid(szKeyName, lpProductBuf); + RegCloseKey(hkey); + +end: + return rc; +} + +UINT WINAPI MsiEnumRelatedProductsA(LPCSTR szUpgradeCode, DWORD dwReserved, + DWORD iProductIndex, LPSTR lpProductBuf) +{ + UINT rc; + int len; + LPWSTR szUpgradeCodeW = NULL; + + TRACE("%s %lu %lu %p\n", debugstr_a(szUpgradeCode), dwReserved, + iProductIndex, lpProductBuf); + if (!szUpgradeCode) + return ERROR_INVALID_PARAMETER; + len = MultiByteToWideChar(CP_ACP, 0, szUpgradeCode, -1, NULL, 0); + szUpgradeCodeW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, + len * sizeof(WCHAR)); + if (szUpgradeCodeW) + { + WCHAR productW[39]; + + MultiByteToWideChar(CP_ACP, 0, szUpgradeCode, -1, szUpgradeCodeW, len); + rc = MsiEnumRelatedProductsW(szUpgradeCodeW, dwReserved, + iProductIndex, productW); + if (rc == ERROR_SUCCESS) + { + LPWSTR ptr; + + for (ptr = productW; *ptr; ) + *lpProductBuf++ = *ptr++; + } + HeapFree(GetProcessHeap(), 0, szUpgradeCodeW); + } + else + rc = ERROR_OUTOFMEMORY; + return rc; +} diff --git a/reactos/lib/msi/sql.tab.c b/reactos/lib/msi/sql.tab.c index 478856d6737..874691c4c28 100644 --- a/reactos/lib/msi/sql.tab.c +++ b/reactos/lib/msi/sql.tab.c @@ -562,18 +562,18 @@ union yyalloc #endif /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 23 +#define YYFINAL 27 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 126 +#define YYLAST 128 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 147 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 25 +#define YYNNTS 26 /* YYNRULES -- Number of rules. */ -#define YYNRULES 63 +#define YYNRULES 65 /* YYNRULES -- Number of states. */ -#define YYNSTATES 123 +#define YYNSTATES 126 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 @@ -633,53 +633,53 @@ static const unsigned char yytranslate[] = YYRHS. */ static const unsigned char yyprhs[] = { - 0, 0, 3, 5, 7, 9, 11, 22, 34, 41, - 49, 56, 61, 66, 69, 71, 74, 76, 80, 82, - 87, 89, 91, 93, 95, 97, 99, 104, 106, 110, - 115, 117, 121, 123, 126, 131, 135, 139, 143, 147, - 151, 155, 159, 163, 167, 171, 175, 180, 182, 184, - 186, 190, 192, 196, 200, 202, 205, 207, 209, 211, - 215, 217, 219, 221 + 0, 0, 3, 5, 7, 9, 11, 13, 24, 36, + 43, 51, 58, 61, 66, 71, 74, 76, 79, 81, + 85, 87, 92, 94, 96, 98, 100, 102, 104, 109, + 111, 115, 120, 122, 126, 128, 131, 136, 140, 144, + 148, 152, 156, 160, 164, 168, 172, 176, 180, 185, + 187, 189, 191, 195, 197, 201, 205, 207, 210, 212, + 214, 216, 220, 222, 224, 226 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const short yyrhs[] = { - 148, 0, -1, 158, -1, 150, -1, 149, -1, 151, - -1, 67, 72, 170, 83, 160, 110, 134, 83, 164, - 110, -1, 67, 72, 170, 83, 160, 110, 134, 83, - 164, 110, 122, -1, 31, 121, 170, 83, 152, 110, - -1, 31, 121, 170, 83, 152, 110, 59, -1, 130, - 170, 114, 165, 137, 162, -1, 153, 102, 77, 160, - -1, 153, 24, 169, 154, -1, 169, 154, -1, 155, - -1, 155, 86, -1, 156, -1, 156, 90, 92, -1, - 19, -1, 19, 83, 157, 110, -1, 82, -1, 115, - -1, 69, -1, 81, -1, 93, -1, 70, -1, 159, - 99, 16, 160, -1, 159, -1, 112, 160, 161, -1, - 112, 38, 160, 161, -1, 169, -1, 169, 24, 160, - -1, 118, -1, 52, 170, -1, 52, 170, 137, 162, - -1, 83, 162, 110, -1, 168, 45, 168, -1, 162, - 7, 162, -1, 162, 97, 162, -1, 168, 45, 163, - -1, 168, 57, 163, -1, 168, 85, 163, -1, 168, - 78, 163, -1, 168, 54, 163, -1, 168, 89, 163, - -1, 168, 73, 92, -1, 168, 73, 90, 92, -1, - 168, -1, 167, -1, 167, -1, 167, 24, 164, -1, - 166, -1, 166, 24, 165, -1, 169, 45, 167, -1, - 70, -1, 88, 70, -1, 120, -1, 138, -1, 169, - -1, 170, 39, 171, -1, 171, -1, 171, -1, 66, - -1, 120, -1 + 148, 0, -1, 159, -1, 150, -1, 149, -1, 151, + -1, 152, -1, 67, 72, 171, 83, 161, 110, 134, + 83, 165, 110, -1, 67, 72, 171, 83, 161, 110, + 134, 83, 165, 110, 122, -1, 31, 121, 171, 83, + 153, 110, -1, 31, 121, 171, 83, 153, 110, 59, + -1, 130, 171, 114, 166, 137, 163, -1, 35, 162, + -1, 154, 102, 77, 161, -1, 154, 24, 170, 155, + -1, 170, 155, -1, 156, -1, 156, 86, -1, 157, + -1, 157, 90, 92, -1, 19, -1, 19, 83, 158, + 110, -1, 82, -1, 115, -1, 69, -1, 81, -1, + 93, -1, 70, -1, 160, 99, 16, 161, -1, 160, + -1, 112, 161, 162, -1, 112, 38, 161, 162, -1, + 170, -1, 170, 24, 161, -1, 118, -1, 52, 171, + -1, 52, 171, 137, 163, -1, 83, 163, 110, -1, + 169, 45, 169, -1, 163, 7, 163, -1, 163, 97, + 163, -1, 169, 45, 164, -1, 169, 57, 164, -1, + 169, 85, 164, -1, 169, 78, 164, -1, 169, 54, + 164, -1, 169, 89, 164, -1, 169, 73, 92, -1, + 169, 73, 90, 92, -1, 169, -1, 168, -1, 168, + -1, 168, 24, 165, -1, 167, -1, 167, 24, 166, + -1, 170, 45, 168, -1, 70, -1, 88, 70, -1, + 120, -1, 138, -1, 170, -1, 171, 39, 172, -1, + 172, -1, 172, -1, 66, -1, 120, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const unsigned short yyrline[] = { - 0, 142, 142, 147, 152, 157, 165, 173, 184, 194, - 207, 218, 228, 247, 259, 263, 271, 275, 282, 286, - 290, 294, 298, 302, 306, 313, 324, 335, 339, 353, - 371, 384, 397, 404, 415, 434, 438, 442, 446, 450, - 454, 458, 462, 466, 470, 474, 478, 485, 486, 490, - 502, 517, 518, 527, 543, 547, 551, 555, 562, 569, - 573, 580, 587, 591 + 0, 143, 143, 148, 153, 158, 163, 171, 179, 190, + 200, 213, 224, 235, 245, 264, 276, 280, 288, 292, + 299, 303, 307, 311, 315, 319, 323, 330, 341, 352, + 356, 370, 388, 401, 414, 421, 432, 451, 455, 459, + 463, 467, 471, 475, 479, 483, 487, 491, 495, 502, + 503, 507, 519, 534, 535, 544, 560, 564, 568, 572, + 579, 586, 590, 597, 604, 608 }; #endif @@ -716,11 +716,11 @@ static const char *const yytname[] = "TK_USING", "TK_VACUUM", "TK_VALUES", "TK_VIEW", "TK_WHEN", "TK_WHERE", "TK_WILDCARD", "AGG_FUNCTION.", "COLUMN", "FUNCTION", "COMMENT", "UNCLOSED_STRING", "SPACE", "ILLEGAL", "END_OF_FILE", "$accept", - "onequery", "oneinsert", "onecreate", "oneupdate", "table_def", - "column_def", "column_type", "data_type_l", "data_type", "data_count", - "oneselect", "unorderedsel", "selcollist", "from", "expr", "val", - "constlist", "update_assign_list", "column_assignment", "const_val", - "column_val", "column", "table", "string_or_id", 0 + "onequery", "oneinsert", "onecreate", "oneupdate", "onedelete", + "table_def", "column_def", "column_type", "data_type_l", "data_type", + "data_count", "oneselect", "unorderedsel", "selcollist", "from", "expr", + "val", "constlist", "update_assign_list", "column_assignment", + "const_val", "column_val", "column", "table", "string_or_id", 0 }; #endif @@ -750,25 +750,25 @@ static const unsigned short yytoknum[] = /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const unsigned char yyr1[] = { - 0, 147, 148, 148, 148, 148, 149, 149, 150, 150, - 151, 152, 153, 153, 154, 154, 155, 155, 156, 156, - 156, 156, 156, 156, 156, 157, 158, 158, 159, 159, - 160, 160, 160, 161, 161, 162, 162, 162, 162, 162, - 162, 162, 162, 162, 162, 162, 162, 163, 163, 164, - 164, 165, 165, 166, 167, 167, 167, 167, 168, 169, - 169, 170, 171, 171 + 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, 161, 161, 162, 162, 163, 163, 163, + 163, 163, 163, 163, 163, 163, 163, 163, 163, 164, + 164, 165, 165, 166, 166, 167, 168, 168, 168, 168, + 169, 170, 170, 171, 172, 172 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const unsigned char yyr2[] = { - 0, 2, 1, 1, 1, 1, 10, 11, 6, 7, - 6, 4, 4, 2, 1, 2, 1, 3, 1, 4, - 1, 1, 1, 1, 1, 1, 4, 1, 3, 4, - 1, 3, 1, 2, 4, 3, 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, 1 + 0, 2, 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, + 3, 4, 1, 3, 1, 2, 4, 3, 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, 1 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state @@ -776,113 +776,113 @@ static const unsigned char yyr2[] = means the default is an error. */ static const unsigned char yydefact[] = { - 0, 0, 0, 0, 0, 0, 4, 3, 5, 2, - 27, 0, 0, 0, 62, 32, 63, 0, 30, 0, - 60, 0, 61, 1, 0, 0, 0, 0, 0, 28, - 0, 0, 0, 0, 0, 0, 29, 33, 31, 59, - 0, 51, 0, 26, 0, 0, 0, 0, 0, 0, - 0, 0, 8, 0, 0, 18, 22, 23, 20, 24, - 21, 13, 14, 16, 0, 0, 34, 0, 58, 10, - 52, 54, 0, 56, 57, 53, 9, 0, 0, 0, - 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 55, 12, 11, 25, 0, 17, 0, - 35, 37, 38, 56, 39, 48, 36, 43, 47, 40, - 0, 45, 42, 41, 44, 19, 0, 49, 46, 6, - 0, 7, 50 + 0, 0, 0, 0, 0, 0, 0, 4, 3, 5, + 6, 2, 29, 0, 0, 12, 0, 0, 64, 34, + 65, 0, 32, 0, 62, 0, 63, 1, 0, 0, + 35, 0, 0, 30, 0, 0, 0, 0, 0, 0, + 0, 31, 33, 61, 0, 53, 0, 28, 0, 0, + 0, 0, 36, 0, 60, 0, 0, 0, 0, 9, + 0, 0, 20, 24, 25, 22, 26, 23, 15, 16, + 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 11, 54, 56, 0, 58, 59, 55, 10, + 0, 0, 0, 17, 0, 37, 39, 40, 58, 41, + 50, 38, 45, 49, 42, 0, 47, 44, 43, 46, + 0, 57, 14, 13, 27, 0, 19, 48, 0, 21, + 0, 51, 7, 0, 8, 52 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yysigned_char yydefgoto[] = { - -1, 5, 6, 7, 8, 44, 45, 61, 62, 63, - 97, 9, 10, 17, 29, 66, 104, 116, 40, 41, - 105, 67, 68, 19, 20 + -1, 6, 7, 8, 9, 10, 48, 49, 68, 69, + 70, 115, 11, 12, 21, 15, 52, 99, 120, 44, + 45, 100, 53, 54, 23, 24 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -104 +#define YYPACT_NINF -106 static const yysigned_char yypact[] = { - -30, -103, -52, -34, -51, 21, -104, -104, -104, -104, - -70, -51, -51, -57, -104, -104, -104, -26, 11, -6, - -1, -69, -104, -104, 32, -25, -15, -26, -51, -104, - -57, -51, -51, -57, -51, -57, -104, -71, -104, -104, - -67, 47, 27, -104, -36, -19, -17, -29, -53, -53, - -51, -63, 26, -51, 17, -10, -104, -104, -104, -104, - -104, -104, 5, 7, -35, -53, -4, 35, -104, -4, - -104, -104, 37, -104, -104, -104, -104, -17, -57, 39, - -104, 18, 28, -7, -53, -53, -60, -60, -60, -73, - -60, -60, -60, -104, -104, -104, -104, 4, -104, -63, - -104, -4, -4, 77, -104, -104, -104, -104, -104, -104, - 25, -104, -104, -104, -104, -104, 8, 95, -104, 0, - -63, -104, -104 + -30, -105, -33, -54, -34, -51, 22, -106, -106, -106, + -106, -106, -79, -51, -51, -106, -51, -60, -106, -106, + -106, -33, 17, 10, 11, -63, -106, -106, 41, -24, + -75, -13, -33, -106, -60, -51, -51, -60, -51, -45, + -60, -106, -106, -106, -65, 50, 32, -106, -32, -15, + -17, -45, -4, 26, -106, -22, -45, -51, -59, 30, + -51, 24, 19, -106, -106, -106, -106, -106, -106, 21, + 15, -7, -45, -45, -53, -53, -53, -78, -53, -53, + -53, -28, -4, -106, -106, 46, -106, -106, -106, -106, + -17, -60, 47, -106, 27, -106, -4, -4, 79, -106, + -106, -106, -106, -106, -106, 28, -106, -106, -106, -106, + 38, -106, -106, -106, -106, 12, -106, -106, -59, -106, + 13, 100, 3, -59, -106, -106 }; /* YYPGOTO[NTERM-NUM]. */ static const yysigned_char yypgoto[] = { - -104, -104, -104, -104, -104, -104, -104, 44, -104, -104, - -104, -104, -104, 1, 96, -38, 14, 6, 75, -104, - -43, -37, 9, 12, 84 + -106, -106, -106, -106, -106, -106, -106, -106, 36, -106, + -106, -106, -106, -106, -10, 7, -25, 16, 4, 71, + -106, -50, 34, 6, 40, 20 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -64 +#define YYTABLE_NINF -66 static const yysigned_char yytable[] = { - 84, 1, 55, 84, 13, 53, 14, 71, 75, 14, - 71, 69, 18, 14, 27, 14, 21, 110, 11, 111, - 12, 23, 18, 25, 26, 72, 28, 83, 72, 24, - 65, 38, 14, 31, 43, 30, 47, 2, -61, 18, - 37, 42, 18, 46, 18, 32, 101, 102, 33, 106, - 108, 108, 56, 108, 108, 108, 117, 73, 34, 42, - 103, 15, 77, 16, 57, 58, 48, 16, 35, 16, - 49, 50, 51, 79, 52, 74, 59, 117, 74, 95, - 86, 64, 3, 54, 15, 76, 16, 18, 22, 87, - 85, 80, 88, 85, 78, 22, 22, 81, 60, 82, - 4, 107, 109, 100, 112, 113, 114, 93, 89, 96, - 98, 99, 22, 90, 115, 39, -63, 118, 119, 120, - 91, 94, 121, 36, 92, 70, 122 + 72, 1, 62, 72, 17, 2, 18, 32, 88, 60, + 22, 84, 105, 18, 106, 18, 13, 84, 16, 14, + 28, 18, 27, 22, 42, 26, 71, 47, 33, 85, + 55, 82, 18, 26, 26, 85, 26, 3, 51, 41, + 22, 34, 46, 22, 50, 25, 22, 96, 97, 35, + -63, 36, 63, 29, 30, 43, 31, 37, 19, 38, + 20, 86, 39, 46, 64, 65, 90, 98, 121, 20, + 40, 74, 56, 121, 57, 20, 66, 58, 59, 87, + 75, 113, 4, 76, 19, 87, 20, 61, 81, 89, + 73, 102, 104, 73, 107, 108, 109, 22, 67, 77, + 5, 91, 92, 95, 78, 94, 110, 93, 101, 103, + 103, 79, 103, 103, 103, 80, 111, 114, -65, 116, + 117, 118, 119, 122, 123, 124, 112, 125, 83 }; static const unsigned char yycheck[] = { - 7, 31, 19, 7, 38, 24, 66, 70, 51, 66, - 70, 49, 3, 66, 13, 66, 4, 90, 121, 92, - 72, 0, 13, 11, 12, 88, 52, 65, 88, 99, - 83, 30, 66, 39, 33, 24, 35, 67, 39, 30, - 28, 32, 33, 34, 35, 114, 84, 85, 16, 86, - 87, 88, 69, 90, 91, 92, 99, 120, 83, 50, - 120, 118, 53, 120, 81, 82, 137, 120, 83, 120, - 137, 24, 45, 83, 110, 138, 93, 120, 138, 78, - 45, 110, 112, 102, 118, 59, 120, 78, 4, 54, - 97, 86, 57, 97, 77, 11, 12, 90, 115, 134, - 130, 87, 88, 110, 90, 91, 92, 70, 73, 70, - 92, 83, 28, 78, 110, 31, 39, 92, 110, 24, - 85, 77, 122, 27, 89, 50, 120 + 7, 31, 19, 7, 38, 35, 66, 17, 58, 24, + 4, 70, 90, 66, 92, 66, 121, 70, 72, 52, + 99, 66, 0, 17, 34, 5, 51, 37, 21, 88, + 40, 56, 66, 13, 14, 88, 16, 67, 83, 32, + 34, 24, 36, 37, 38, 5, 40, 72, 73, 39, + 39, 114, 69, 13, 14, 35, 16, 16, 118, 83, + 120, 120, 137, 57, 81, 82, 60, 120, 118, 120, + 83, 45, 137, 123, 24, 120, 93, 45, 110, 138, + 54, 91, 112, 57, 118, 138, 120, 102, 110, 59, + 97, 75, 76, 97, 78, 79, 80, 91, 115, 73, + 130, 77, 83, 110, 78, 90, 134, 86, 74, 75, + 76, 85, 78, 79, 80, 89, 70, 70, 39, 92, + 92, 83, 110, 110, 24, 122, 90, 123, 57 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const unsigned char yystos[] = { - 0, 31, 67, 112, 130, 148, 149, 150, 151, 158, - 159, 121, 72, 38, 66, 118, 120, 160, 169, 170, - 171, 170, 171, 0, 99, 170, 170, 160, 52, 161, - 24, 39, 114, 16, 83, 83, 161, 170, 160, 171, - 165, 166, 169, 160, 152, 153, 169, 160, 137, 137, - 24, 45, 110, 24, 102, 19, 69, 81, 82, 93, - 115, 154, 155, 156, 110, 83, 162, 168, 169, 162, - 165, 70, 88, 120, 138, 167, 59, 169, 77, 83, - 86, 90, 134, 162, 7, 97, 45, 54, 57, 73, - 78, 85, 89, 70, 154, 160, 70, 157, 92, 83, - 110, 162, 162, 120, 163, 167, 168, 163, 168, 163, - 90, 92, 163, 163, 163, 110, 164, 167, 92, 110, - 24, 122, 164 + 0, 31, 35, 67, 112, 130, 148, 149, 150, 151, + 152, 159, 160, 121, 52, 162, 72, 38, 66, 118, + 120, 161, 170, 171, 172, 171, 172, 0, 99, 171, + 171, 171, 161, 162, 24, 39, 114, 16, 83, 137, + 83, 162, 161, 172, 166, 167, 170, 161, 153, 154, + 170, 83, 163, 169, 170, 161, 137, 24, 45, 110, + 24, 102, 19, 69, 81, 82, 93, 115, 155, 156, + 157, 163, 7, 97, 45, 54, 57, 73, 78, 85, + 89, 110, 163, 166, 70, 88, 120, 138, 168, 59, + 170, 77, 83, 86, 90, 110, 163, 163, 120, 164, + 168, 169, 164, 169, 164, 90, 92, 164, 164, 164, + 134, 70, 155, 161, 70, 158, 92, 92, 83, 110, + 165, 168, 110, 24, 122, 165 }; #if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) @@ -1493,7 +1493,7 @@ yyreduce: switch (yyn) { case 2: -#line 143 "./sql.y" +#line 144 "./sql.y" { SQL_input* sql = (SQL_input*) info; *sql->view = yyvsp[0].query; @@ -1501,7 +1501,7 @@ yyreduce: break; case 3: -#line 148 "./sql.y" +#line 149 "./sql.y" { SQL_input* sql = (SQL_input*) info; *sql->view = yyvsp[0].query; @@ -1509,7 +1509,7 @@ yyreduce: break; case 4: -#line 153 "./sql.y" +#line 154 "./sql.y" { SQL_input* sql = (SQL_input*) info; *sql->view = yyvsp[0].query; @@ -1517,7 +1517,7 @@ yyreduce: break; case 5: -#line 158 "./sql.y" +#line 159 "./sql.y" { SQL_input* sql = (SQL_input*) info; *sql->view = yyvsp[0].query; @@ -1525,7 +1525,15 @@ yyreduce: break; case 6: -#line 166 "./sql.y" +#line 164 "./sql.y" + { + SQL_input* sql = (SQL_input*) info; + *sql->view = yyvsp[0].query; + ;} + break; + + case 7: +#line 172 "./sql.y" { SQL_input *sql = (SQL_input*) info; MSIVIEW *insert = NULL; @@ -1535,8 +1543,8 @@ yyreduce: ;} break; - case 7: -#line 174 "./sql.y" + case 8: +#line 180 "./sql.y" { SQL_input *sql = (SQL_input*) info; MSIVIEW *insert = NULL; @@ -1546,8 +1554,8 @@ yyreduce: ;} break; - case 8: -#line 185 "./sql.y" + case 9: +#line 191 "./sql.y" { SQL_input* sql = (SQL_input*) info; MSIVIEW *create = NULL; @@ -1559,8 +1567,8 @@ yyreduce: ;} break; - case 9: -#line 195 "./sql.y" + case 10: +#line 201 "./sql.y" { SQL_input* sql = (SQL_input*) info; MSIVIEW *create = NULL; @@ -1572,8 +1580,8 @@ yyreduce: ;} break; - case 10: -#line 208 "./sql.y" + case 11: +#line 214 "./sql.y" { SQL_input* sql = (SQL_input*) info; MSIVIEW *update = NULL; @@ -1583,8 +1591,19 @@ yyreduce: ;} break; - case 11: -#line 219 "./sql.y" + case 12: +#line 225 "./sql.y" + { + SQL_input* sql = (SQL_input*) info; + MSIVIEW *delete = NULL; + + DELETE_CreateView( sql->db, &delete, yyvsp[0].query ); + yyval.query = delete; + ;} + break; + + case 13: +#line 236 "./sql.y" { if( SQL_MarkPrimaryKeys( yyvsp[-3].column_info, yyvsp[0].column_list ) ) yyval.column_info = yyvsp[-3].column_info; @@ -1593,8 +1612,8 @@ yyreduce: ;} break; - case 12: -#line 229 "./sql.y" + case 14: +#line 246 "./sql.y" { create_col_info *ci; @@ -1615,8 +1634,8 @@ yyreduce: ;} break; - case 13: -#line 248 "./sql.y" + case 15: +#line 265 "./sql.y" { yyval.column_info = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info ); if( ! yyval.column_info ) @@ -1627,86 +1646,86 @@ yyreduce: ;} break; - case 14: -#line 260 "./sql.y" + case 16: +#line 277 "./sql.y" { yyval.column_type = yyvsp[0].column_type | MSITYPE_VALID; ;} break; - case 15: -#line 264 "./sql.y" + case 17: +#line 281 "./sql.y" { FIXME("LOCALIZABLE ignored\n"); yyval.column_type = yyvsp[-1].column_type | MSITYPE_VALID; ;} break; - case 16: -#line 272 "./sql.y" + case 18: +#line 289 "./sql.y" { yyval.column_type |= MSITYPE_NULLABLE; ;} break; - case 17: -#line 276 "./sql.y" + case 19: +#line 293 "./sql.y" { yyval.column_type = yyvsp[-2].column_type; ;} break; - case 18: -#line 283 "./sql.y" + case 20: +#line 300 "./sql.y" { yyval.column_type = MSITYPE_STRING | 1; ;} break; - case 19: -#line 287 "./sql.y" + case 21: +#line 304 "./sql.y" { yyval.column_type = MSITYPE_STRING | 0x400 | yyvsp[-1].column_type; ;} break; - case 20: -#line 291 "./sql.y" - { - yyval.column_type = 2; - ;} - break; - - case 21: -#line 295 "./sql.y" - { - yyval.column_type = 2; - ;} - break; - case 22: -#line 299 "./sql.y" +#line 308 "./sql.y" { yyval.column_type = 2; ;} break; case 23: -#line 303 "./sql.y" +#line 312 "./sql.y" + { + yyval.column_type = 2; + ;} + break; + + case 24: +#line 316 "./sql.y" + { + yyval.column_type = 2; + ;} + break; + + case 25: +#line 320 "./sql.y" { yyval.column_type = 4; ;} break; - case 24: -#line 307 "./sql.y" + case 26: +#line 324 "./sql.y" { yyval.column_type = 0; ;} break; - case 25: -#line 314 "./sql.y" + case 27: +#line 331 "./sql.y" { SQL_input* sql = (SQL_input*) info; int val = SQL_getint(sql); @@ -1716,8 +1735,8 @@ yyreduce: ;} break; - case 26: -#line 325 "./sql.y" + case 28: +#line 342 "./sql.y" { SQL_input* sql = (SQL_input*) info; @@ -1730,8 +1749,8 @@ yyreduce: ;} break; - case 28: -#line 340 "./sql.y" + case 30: +#line 357 "./sql.y" { SQL_input* sql = (SQL_input*) info; if( !yyvsp[0].query ) @@ -1747,8 +1766,8 @@ yyreduce: ;} break; - case 29: -#line 354 "./sql.y" + case 31: +#line 371 "./sql.y" { SQL_input* sql = (SQL_input*) info; MSIVIEW *view = yyvsp[0].query; @@ -1765,8 +1784,8 @@ yyreduce: ;} break; - case 30: -#line 372 "./sql.y" + case 32: +#line 389 "./sql.y" { string_list *list; @@ -1781,8 +1800,8 @@ yyreduce: ;} break; - case 31: -#line 385 "./sql.y" + case 33: +#line 402 "./sql.y" { string_list *list; @@ -1797,15 +1816,15 @@ yyreduce: ;} break; - case 32: -#line 398 "./sql.y" + case 34: +#line 415 "./sql.y" { yyval.column_list = NULL; ;} break; - case 33: -#line 405 "./sql.y" + case 35: +#line 422 "./sql.y" { SQL_input* sql = (SQL_input*) info; UINT r; @@ -1818,8 +1837,8 @@ yyreduce: ;} break; - case 34: -#line 416 "./sql.y" + case 36: +#line 433 "./sql.y" { SQL_input* sql = (SQL_input*) info; MSIVIEW *view = NULL; @@ -1837,92 +1856,92 @@ yyreduce: ;} break; - case 35: -#line 435 "./sql.y" + case 37: +#line 452 "./sql.y" { yyval.expr = yyvsp[-1].expr; ;} break; - case 36: -#line 439 "./sql.y" + case 38: +#line 456 "./sql.y" { yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_EQ, yyvsp[0].expr ); ;} break; - case 37: -#line 443 "./sql.y" + case 39: +#line 460 "./sql.y" { yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_AND, yyvsp[0].expr ); ;} break; - case 38: -#line 447 "./sql.y" + case 40: +#line 464 "./sql.y" { yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_OR, yyvsp[0].expr ); ;} break; - case 39: -#line 451 "./sql.y" + case 41: +#line 468 "./sql.y" { yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_EQ, yyvsp[0].expr ); ;} break; - case 40: -#line 455 "./sql.y" + case 42: +#line 472 "./sql.y" { yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_GT, yyvsp[0].expr ); ;} break; - case 41: -#line 459 "./sql.y" + case 43: +#line 476 "./sql.y" { yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_LT, yyvsp[0].expr ); ;} break; - case 42: -#line 463 "./sql.y" + case 44: +#line 480 "./sql.y" { yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_LE, yyvsp[0].expr ); ;} break; - case 43: -#line 467 "./sql.y" + case 45: +#line 484 "./sql.y" { yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_GE, yyvsp[0].expr ); ;} break; - case 44: -#line 471 "./sql.y" + case 46: +#line 488 "./sql.y" { yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_NE, yyvsp[0].expr ); ;} break; - case 45: -#line 475 "./sql.y" + case 47: +#line 492 "./sql.y" { yyval.expr = EXPR_complex( yyvsp[-2].expr, OP_ISNULL, NULL ); ;} break; - case 46: -#line 479 "./sql.y" + case 48: +#line 496 "./sql.y" { yyval.expr = EXPR_complex( yyvsp[-3].expr, OP_NOTNULL, NULL ); ;} break; - case 49: -#line 491 "./sql.y" + case 51: +#line 508 "./sql.y" { value_list *vals; @@ -1936,8 +1955,8 @@ yyreduce: ;} break; - case 50: -#line 503 "./sql.y" + case 52: +#line 520 "./sql.y" { value_list *vals; @@ -1951,8 +1970,8 @@ yyreduce: ;} break; - case 52: -#line 519 "./sql.y" + case 54: +#line 536 "./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; @@ -1960,8 +1979,8 @@ yyreduce: ;} break; - case 53: -#line 528 "./sql.y" + case 55: +#line 545 "./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 ) @@ -1976,71 +1995,71 @@ yyreduce: ;} break; - case 54: -#line 544 "./sql.y" + case 56: +#line 561 "./sql.y" { yyval.expr = EXPR_ival( &yyvsp[0].str, 1 ); ;} break; - case 55: -#line 548 "./sql.y" + case 57: +#line 565 "./sql.y" { yyval.expr = EXPR_ival( &yyvsp[0].str, -1 ); ;} break; - case 56: -#line 552 "./sql.y" + case 58: +#line 569 "./sql.y" { yyval.expr = EXPR_sval( &yyvsp[0].str ); ;} break; - case 57: -#line 556 "./sql.y" + case 59: +#line 573 "./sql.y" { yyval.expr = EXPR_wildcard(); ;} break; - case 58: -#line 563 "./sql.y" + case 60: +#line 580 "./sql.y" { yyval.expr = EXPR_column( yyvsp[0].string ); ;} break; - case 59: -#line 570 "./sql.y" + case 61: +#line 587 "./sql.y" { yyval.string = yyvsp[0].string; /* FIXME */ ;} break; - case 60: -#line 574 "./sql.y" - { - yyval.string = yyvsp[0].string; - ;} - break; - - case 61: -#line 581 "./sql.y" - { - yyval.string = yyvsp[0].string; - ;} - break; - case 62: -#line 588 "./sql.y" +#line 591 "./sql.y" + { + yyval.string = yyvsp[0].string; + ;} + break; + + case 63: +#line 598 "./sql.y" + { + yyval.string = yyvsp[0].string; + ;} + break; + + case 64: +#line 605 "./sql.y" { yyval.string = SQL_getstring( &yyvsp[0].str ); ;} break; - case 63: -#line 592 "./sql.y" + case 65: +#line 609 "./sql.y" { yyval.string = SQL_getstring( &yyvsp[0].str ); ;} @@ -2050,7 +2069,7 @@ yyreduce: } /* Line 999 of yacc.c. */ -#line 2054 "sql.tab.c" +#line 2073 "sql.tab.c" yyvsp -= yylen; yyssp -= yylen; @@ -2256,7 +2275,7 @@ yyreturn: } -#line 597 "./sql.y" +#line 614 "./sql.y" int SQL_lex( void *SQL_lval, SQL_input *sql) diff --git a/reactos/lib/msi/sql.y b/reactos/lib/msi/sql.y index ca918500245..5bd2c7dffd7 100644 --- a/reactos/lib/msi/sql.y +++ b/reactos/lib/msi/sql.y @@ -129,7 +129,8 @@ static struct expr * EXPR_wildcard(); %type column table string_or_id %type selcollist -%type from unorderedsel oneselect onequery onecreate oneinsert oneupdate +%type from unorderedsel oneselect onequery onecreate oneinsert +%type oneupdate onedelete %type expr val column_val const_val %type column_type data_type data_type_l data_count %type column_def table_def @@ -159,6 +160,11 @@ onequery: SQL_input* sql = (SQL_input*) info; *sql->view = $1; } + | onedelete + { + SQL_input* sql = (SQL_input*) info; + *sql->view = $1; + } ; oneinsert: @@ -214,6 +220,17 @@ oneupdate: } ; +onedelete: + TK_DELETE from + { + SQL_input* sql = (SQL_input*) info; + MSIVIEW *delete = NULL; + + DELETE_CreateView( sql->db, &delete, $2 ); + $$ = delete; + } + ; + table_def: column_def TK_PRIMARY TK_KEY selcollist { diff --git a/reactos/lib/msi/suminfo.c b/reactos/lib/msi/suminfo.c index fbc39d0f598..16e4516b9ae 100644 --- a/reactos/lib/msi/suminfo.c +++ b/reactos/lib/msi/suminfo.c @@ -110,11 +110,9 @@ UINT WINAPI MsiGetSummaryInformationW(MSIHANDLE hDatabase, if( FAILED( r ) ) { ERR("IStorage -> IPropertySetStorage failed\n"); - if (db) - msiobj_release(&db->hdr); - return ERROR_FUNCTION_FAILED; + ret = ERROR_FUNCTION_FAILED; + goto end; } - ERR("storage = %p propertysetstorage = %p\n", db->storage, psstg); grfMode = STGM_READ | STGM_SHARE_EXCLUSIVE; r = IPropertySetStorage_Open( psstg, &FMTID_SummaryInformation, grfMode, &ps ); @@ -137,7 +135,7 @@ UINT WINAPI MsiGetSummaryInformationW(MSIHANDLE hDatabase, suminfo->propstg = ps; handle = alloc_msihandle( &suminfo->hdr ); if( handle ) - *phSummaryInfo = handle; + *phSummaryInfo = handle; else ret = ERROR_FUNCTION_FAILED; msiobj_release( &suminfo->hdr ); @@ -147,7 +145,7 @@ end: IPropertyStorage_Release(ps); if( psstg ) IPropertySetStorage_Release(psstg); - if (db) + if( db ) msiobj_release(&db->hdr); return ret; @@ -163,6 +161,7 @@ UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, UINT *pCount) if( !suminfo ) return ERROR_INVALID_HANDLE; + msiobj_release( &suminfo->hdr ); return ERROR_CALL_NOT_IMPLEMENTED; } @@ -174,6 +173,7 @@ UINT WINAPI MsiSummaryInfoGetPropertyA( HRESULT r; PROPSPEC spec; PROPVARIANT var; + UINT rc = ERROR_SUCCESS; TRACE("%ld %d %p %p %p %p %p\n", hSummaryInfo, uiProperty, puiDataType, piValue, @@ -188,7 +188,10 @@ UINT WINAPI MsiSummaryInfoGetPropertyA( r = IPropertyStorage_ReadMultiple( suminfo->propstg, 1, &spec, &var); if( FAILED(r) ) - return ERROR_FUNCTION_FAILED; + { + rc = ERROR_FUNCTION_FAILED; + goto end; + } if( puiDataType ) *puiDataType = var.vt; @@ -217,7 +220,9 @@ UINT WINAPI MsiSummaryInfoGetPropertyA( break; } - return ERROR_SUCCESS; +end: + msiobj_release( &suminfo->hdr ); + return rc; } UINT WINAPI MsiSummaryInfoGetPropertyW( @@ -228,6 +233,7 @@ UINT WINAPI MsiSummaryInfoGetPropertyW( HRESULT r; PROPSPEC spec; PROPVARIANT var; + UINT rc = ERROR_SUCCESS; TRACE("%ld %d %p %p %p %p %p\n", hSummaryInfo, uiProperty, puiDataType, piValue, @@ -242,7 +248,10 @@ UINT WINAPI MsiSummaryInfoGetPropertyW( r = IPropertyStorage_ReadMultiple( suminfo->propstg, 1, &spec, &var); if( FAILED(r) ) - return ERROR_FUNCTION_FAILED; + { + rc = ERROR_FUNCTION_FAILED; + goto end; + } if( puiDataType ) *puiDataType = var.vt; @@ -272,24 +281,31 @@ UINT WINAPI MsiSummaryInfoGetPropertyW( break; } - return ERROR_SUCCESS; +end: + msiobj_release( &suminfo->hdr ); + return rc; } UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE hSummaryInfo, UINT uiProperty, UINT uiDataType, INT iValue, - FILETIME* pftValue, LPSTR szValue) + FILETIME* pftValue, LPSTR szValue ) { + FIXME("%ld %u %u %i %p %s\n", hSummaryInfo, uiProperty, + uiDataType, iValue, pftValue, debugstr_a(szValue) ); return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE hSummaryInfo, UINT uiProperty, UINT uiDataType, INT iValue, - FILETIME* pftValue, LPWSTR szValue) + FILETIME* pftValue, LPWSTR szValue ) { + FIXME("%ld %u %u %i %p %s\n", hSummaryInfo, uiProperty, + uiDataType, iValue, pftValue, debugstr_w(szValue) ); return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiSummaryInfoPersist(MSIHANDLE hSummaryInfo) +UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE hSummaryInfo ) { + FIXME("%ld\n", hSummaryInfo ); return ERROR_CALL_NOT_IMPLEMENTED; } diff --git a/reactos/lib/msi/table.c b/reactos/lib/msi/table.c index 5e1891b04fd..63ee0db24ac 100644 --- a/reactos/lib/msi/table.c +++ b/reactos/lib/msi/table.c @@ -1220,7 +1220,10 @@ static UINT TABLE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) TRACE("%p %p\n", tv, record); if( tv->table ) - return ERROR_FUNCTION_FAILED; + { + release_table( tv->db, tv->table ); + tv->table = NULL; + } r = get_table( tv->db, tv->name, &tv->table ); if( r != ERROR_SUCCESS ) diff --git a/reactos/lib/msi/where.c b/reactos/lib/msi/where.c index 2754f996b5b..8b84d3aafab 100644 --- a/reactos/lib/msi/where.c +++ b/reactos/lib/msi/where.c @@ -247,6 +247,7 @@ static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) if( !wv->reorder ) return ERROR_FUNCTION_FAILED; + wv->row_count = 0; for( i=0; i