-/*\r
- * Implementation of the Microsoft Installer (msi.dll)\r
- *\r
- * Copyright 2004 Aric Stewart for CodeWeavers\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
- */\r
-\r
-/*\r
- * Pages I need\r
- *\r
-http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp\r
-\r
-http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp\r
- */\r
-\r
-#include <stdarg.h>\r
-#include <stdio.h>\r
-\r
-#include <fcntl.h>\r
-#define COBJMACROS\r
-\r
-#include "windef.h"\r
-#include "winbase.h"\r
-#include "winerror.h"\r
-#include "winreg.h"\r
-#include "wine/debug.h"\r
-#include "fdi.h"\r
-#include "msi.h"\r
-#include "msiquery.h"\r
-//#include "msvcrt/fcntl.h"\r
-#include "objbase.h"\r
-#include "objidl.h"\r
-#include "msipriv.h"\r
-#include "winnls.h"\r
-#include "winuser.h"\r
-#include "shlobj.h"\r
-#include "wine/unicode.h"\r
-#include "ver.h"\r
-#include "action.h"\r
-\r
-#define REG_PROGRESS_VALUE 13200\r
-#define COMPONENT_PROGRESS_VALUE 24000\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(msi);\r
-\r
-/*\r
- * Prototypes\r
- */\r
-static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);\r
-static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);\r
-static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq);\r
-static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, \r
- LPWSTR *FilePath);\r
-\r
-/* \r
- * action handlers\r
- */\r
-typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);\r
-\r
-static UINT ACTION_LaunchConditions(MSIPACKAGE *package);\r
-static UINT ACTION_CostInitialize(MSIPACKAGE *package);\r
-static UINT ACTION_CreateFolders(MSIPACKAGE *package);\r
-static UINT ACTION_CostFinalize(MSIPACKAGE *package);\r
-static UINT ACTION_FileCost(MSIPACKAGE *package);\r
-static UINT ACTION_InstallFiles(MSIPACKAGE *package);\r
-static UINT ACTION_DuplicateFiles(MSIPACKAGE *package);\r
-static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package);\r
-static UINT ACTION_InstallInitialize(MSIPACKAGE *package);\r
-static UINT ACTION_InstallValidate(MSIPACKAGE *package);\r
-static UINT ACTION_ProcessComponents(MSIPACKAGE *package);\r
-static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package);\r
-static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package);\r
-static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package);\r
-static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package);\r
-static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package);\r
-static UINT ACTION_RegisterUser(MSIPACKAGE *package);\r
-static UINT ACTION_CreateShortcuts(MSIPACKAGE *package);\r
-static UINT ACTION_PublishProduct(MSIPACKAGE *package);\r
-static UINT ACTION_WriteIniValues(MSIPACKAGE *package);\r
-static UINT ACTION_SelfRegModules(MSIPACKAGE *package);\r
-static UINT ACTION_PublishFeatures(MSIPACKAGE *package);\r
-static UINT ACTION_RegisterProduct(MSIPACKAGE *package);\r
-static UINT ACTION_InstallExecute(MSIPACKAGE *package);\r
-static UINT ACTION_InstallFinalize(MSIPACKAGE *package);\r
-static UINT ACTION_ForceReboot(MSIPACKAGE *package);\r
-static UINT ACTION_ResolveSource(MSIPACKAGE *package);\r
-\r
- \r
-/*\r
- * consts and values used\r
- */\r
-static const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};\r
-static const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};\r
-static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};\r
-static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};\r
-static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0};\r
-static const WCHAR c_collen[] = {'C',':','\\',0};\r
- \r
-static const WCHAR cszbs[]={'\\',0};\r
-\r
-const static WCHAR szCreateFolders[] =\r
-{'C','r','e','a','t','e','F','o','l','d','e','r','s',0};\r
-const static WCHAR szCostFinalize[] =\r
-{'C','o','s','t','F','i','n','a','l','i','z','e',0};\r
-const static WCHAR szInstallFiles[] =\r
-{'I','n','s','t','a','l','l','F','i','l','e','s',0};\r
-const static WCHAR szDuplicateFiles[] =\r
-{'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};\r
-const static WCHAR szWriteRegistryValues[] =\r
-{'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};\r
-const static WCHAR szCostInitialize[] =\r
-{'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};\r
-const static WCHAR szFileCost[] = \r
-{'F','i','l','e','C','o','s','t',0};\r
-const static WCHAR szInstallInitialize[] = \r
-{'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};\r
-const static WCHAR szInstallValidate[] = \r
-{'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};\r
-const static WCHAR szLaunchConditions[] = \r
-{'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};\r
-const static WCHAR szProcessComponents[] = \r
-{'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};\r
-const static WCHAR szRegisterTypeLibraries[] = \r
-{'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r',\r
-'i','e','s',0};\r
-const static WCHAR szRegisterClassInfo[] = \r
-{'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};\r
-const static WCHAR szRegisterProgIdInfo[] = \r
-{'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};\r
-const static WCHAR szCreateShortcuts[] = \r
-{'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};\r
-const static WCHAR szPublishProduct[] = \r
-{'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};\r
-const static WCHAR szWriteIniValues[] = \r
-{'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};\r
-const static WCHAR szSelfRegModules[] = \r
-{'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};\r
-const static WCHAR szPublishFeatures[] = \r
-{'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};\r
-const static WCHAR szRegisterProduct[] = \r
-{'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};\r
-const static WCHAR szInstallExecute[] = \r
-{'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};\r
-const static WCHAR szInstallExecuteAgain[] = \r
-{'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};\r
-const static WCHAR szInstallFinalize[] = \r
-{'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};\r
-const static WCHAR szForceReboot[] = \r
-{'F','o','r','c','e','R','e','b','o','o','t',0};\r
-const static WCHAR szResolveSource[] =\r
-{'R','e','s','o','l','v','e','S','o','u','r','c','e',0};\r
-const static WCHAR szAppSearch[] = \r
-{'A','p','p','S','e','a','r','c','h',0};\r
-const static WCHAR szAllocateRegistrySpace[] = \r
-{'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};\r
-const static WCHAR szBindImage[] = \r
-{'B','i','n','d','I','m','a','g','e',0};\r
-const static WCHAR szCCPSearch[] = \r
-{'C','C','P','S','e','a','r','c','h',0};\r
-const static WCHAR szDeleteServices[] = \r
-{'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};\r
-const static WCHAR szDisableRollback[] = \r
-{'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};\r
-const static WCHAR szExecuteAction[] = \r
-{'E','x','e','c','u','t','e','A','c','t','i','o','n',0};\r
-const static WCHAR szFindRelatedProducts[] = \r
-{'F','i','n','d','R','e','l','a','t','e','d','P','r','o','d','u','c','t','s',0};\r
-const static WCHAR szInstallAdminPackage[] = \r
-{'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};\r
-const static WCHAR szInstallSFPCatalogFile[] = \r
-{'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};\r
-const static WCHAR szIsolateComponents[] = \r
-{'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};\r
-const static WCHAR szMigrateFeatureStates[] = \r
-{'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};\r
-const static WCHAR szMoveFiles[] = \r
-{'M','o','v','e','F','i','l','e','s',0};\r
-const static WCHAR szMsiPublishAssemblies[] = \r
-{'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};\r
-const static WCHAR szMsiUnpublishAssemblies[] = \r
-{'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};\r
-const static WCHAR szInstallODBC[] = \r
-{'I','n','s','t','a','l','l','O','D','B','C',0};\r
-const static WCHAR szInstallServices[] = \r
-{'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};\r
-const static WCHAR szPatchFiles[] = \r
-{'P','a','t','c','h','F','i','l','e','s',0};\r
-const static WCHAR szPublishComponents[] = \r
-{'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};\r
-const static WCHAR szRegisterComPlus[] =\r
-{'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};\r
-const static WCHAR szRegisterExtensionInfo[] =\r
-{'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};\r
-const static WCHAR szRegisterFonts[] =\r
-{'R','e','g','i','s','t','e','r','F','o','n','t','s',0};\r
-const static WCHAR szRegisterMIMEInfo[] =\r
-{'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};\r
-const static WCHAR szRegisterUser[] =\r
-{'R','e','g','i','s','t','e','r','U','s','e','r',0};\r
-const static WCHAR szRemoveDuplicateFiles[] =\r
-{'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};\r
-const static WCHAR szRemoveEnvironmentStrings[] =\r
-{'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};\r
-const static WCHAR szRemoveExistingProducts[] =\r
-{'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};\r
-const static WCHAR szRemoveFiles[] =\r
-{'R','e','m','o','v','e','F','i','l','e','s',0};\r
-const static WCHAR szRemoveFolders[] =\r
-{'R','e','m','o','v','e','F','o','l','d','e','r','s',0};\r
-const static WCHAR szRemoveIniValues[] =\r
-{'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};\r
-const static WCHAR szRemoveODBC[] =\r
-{'R','e','m','o','v','e','O','D','B','C',0};\r
-const static WCHAR szRemoveRegistryValues[] =\r
-{'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};\r
-const static WCHAR szRemoveShortcuts[] =\r
-{'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};\r
-const static WCHAR szRMCCPSearch[] =\r
-{'R','M','C','C','P','S','e','a','r','c','h',0};\r
-const static WCHAR szScheduleReboot[] =\r
-{'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};\r
-const static WCHAR szSelfUnregModules[] =\r
-{'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};\r
-const static WCHAR szSetODBCFolders[] =\r
-{'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};\r
-const static WCHAR szStartServices[] =\r
-{'S','t','a','r','t','S','e','r','v','i','c','e','s',0};\r
-const static WCHAR szStopServices[] =\r
-{'S','t','o','p','S','e','r','v','i','c','e','s',0};\r
-const static WCHAR szUnpublishComponents[] =\r
-{'U','n','p','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};\r
-const static WCHAR szUnpublishFeatures[] =\r
-{'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};\r
-const static WCHAR szUnregisterClassInfo[] =\r
-{'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};\r
-const static WCHAR szUnregisterComPlus[] =\r
-{'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};\r
-const static WCHAR szUnregisterExtensionInfo[] =\r
-{'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};\r
-const static WCHAR szUnregisterFonts[] =\r
-{'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};\r
-const static WCHAR szUnregisterMIMEInfo[] =\r
-{'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};\r
-const static WCHAR szUnregisterProgIdInfo[] =\r
-{'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};\r
-const static WCHAR szUnregisterTypeLibraries[] =\r
-{'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};\r
-const static WCHAR szValidateProductID[] =\r
-{'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};\r
-const static WCHAR szWriteEnvironmentStrings[] =\r
-{'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};\r
-\r
-struct _actions {\r
- LPCWSTR action;\r
- STANDARDACTIONHANDLER handler;\r
-};\r
-\r
-struct _actions StandardActions[] = {\r
- { szAllocateRegistrySpace, NULL},\r
- { szAppSearch, ACTION_AppSearch },\r
- { szBindImage, NULL},\r
- { szCCPSearch, NULL},\r
- { szCostFinalize, ACTION_CostFinalize },\r
- { szCostInitialize, ACTION_CostInitialize },\r
- { szCreateFolders, ACTION_CreateFolders },\r
- { szCreateShortcuts, ACTION_CreateShortcuts },\r
- { szDeleteServices, NULL},\r
- { szDisableRollback, NULL},\r
- { szDuplicateFiles, ACTION_DuplicateFiles},\r
- { szExecuteAction, NULL},\r
- { szFileCost, ACTION_FileCost },\r
- { szFindRelatedProducts, NULL},\r
- { szForceReboot, ACTION_ForceReboot },\r
- { szInstallAdminPackage, NULL},\r
- { szInstallExecute, ACTION_InstallExecute },\r
- { szInstallExecuteAgain, ACTION_InstallExecute },\r
- { szInstallFiles, ACTION_InstallFiles},\r
- { szInstallFinalize, ACTION_InstallFinalize },\r
- { szInstallInitialize, ACTION_InstallInitialize },\r
- { szInstallSFPCatalogFile, NULL},\r
- { szInstallValidate, ACTION_InstallValidate },\r
- { szIsolateComponents, NULL},\r
- { szLaunchConditions, ACTION_LaunchConditions },\r
- { szMigrateFeatureStates, NULL},\r
- { szMoveFiles, NULL},\r
- { szMsiPublishAssemblies, NULL},\r
- { szMsiUnpublishAssemblies, NULL},\r
- { szInstallODBC, NULL},\r
- { szInstallServices, NULL},\r
- { szPatchFiles, NULL},\r
- { szProcessComponents, ACTION_ProcessComponents },\r
- { szPublishComponents, NULL},\r
- { szPublishFeatures, ACTION_PublishFeatures },\r
- { szPublishProduct, ACTION_PublishProduct },\r
- { szRegisterClassInfo, ACTION_RegisterClassInfo },\r
- { szRegisterComPlus, NULL},\r
- { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },\r
- { szRegisterFonts, NULL},\r
- { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },\r
- { szRegisterProduct, ACTION_RegisterProduct },\r
- { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },\r
- { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },\r
- { szRegisterUser, ACTION_RegisterUser},\r
- { szRemoveDuplicateFiles, NULL},\r
- { szRemoveEnvironmentStrings, NULL},\r
- { szRemoveExistingProducts, NULL},\r
- { szRemoveFiles, NULL},\r
- { szRemoveFolders, NULL},\r
- { szRemoveIniValues, NULL},\r
- { szRemoveODBC, NULL},\r
- { szRemoveRegistryValues, NULL},\r
- { szRemoveShortcuts, NULL},\r
- { szResolveSource, ACTION_ResolveSource},\r
- { szRMCCPSearch, NULL},\r
- { szScheduleReboot, NULL},\r
- { szSelfRegModules, ACTION_SelfRegModules },\r
- { szSelfUnregModules, NULL},\r
- { szSetODBCFolders, NULL},\r
- { szStartServices, NULL},\r
- { szStopServices, NULL},\r
- { szUnpublishComponents, NULL},\r
- { szUnpublishFeatures, NULL},\r
- { szUnregisterClassInfo, NULL},\r
- { szUnregisterComPlus, NULL},\r
- { szUnregisterExtensionInfo, NULL},\r
- { szUnregisterFonts, NULL},\r
- { szUnregisterMIMEInfo, NULL},\r
- { szUnregisterProgIdInfo, NULL},\r
- { szUnregisterTypeLibraries, NULL},\r
- { szValidateProductID, NULL},\r
- { szWriteEnvironmentStrings, NULL},\r
- { szWriteIniValues, ACTION_WriteIniValues },\r
- { szWriteRegistryValues, ACTION_WriteRegistryValues},\r
- { NULL, NULL},\r
-};\r
-\r
-\r
-/******************************************************** \r
- * helper functions to get around current HACKS and such\r
- ********************************************************/\r
-inline static void reduce_to_longfilename(WCHAR* filename)\r
-{\r
- LPWSTR p = strchrW(filename,'|');\r
- if (p)\r
- memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR));\r
-}\r
-\r
-WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)\r
-{\r
- UINT rc;\r
- DWORD sz;\r
- LPWSTR ret;\r
- \r
- sz = 0; \r
- if (MSI_RecordIsNull(row,index))\r
- return NULL;\r
-\r
- rc = MSI_RecordGetStringW(row,index,NULL,&sz);\r
-\r
- /* having an empty string is different than NULL */\r
- if (sz == 0)\r
- {\r
- ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR));\r
- ret[0] = 0;\r
- return ret;\r
- }\r
-\r
- sz ++;\r
- ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR));\r
- rc = MSI_RecordGetStringW(row,index,ret,&sz);\r
- if (rc!=ERROR_SUCCESS)\r
- {\r
- ERR("Unable to load dynamic string\n");\r
- HeapFree(GetProcessHeap(), 0, ret);\r
- ret = NULL;\r
- }\r
- return ret;\r
-}\r
-\r
-LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc)\r
-{\r
- DWORD sz = 0;\r
- LPWSTR str;\r
- UINT r;\r
-\r
- r = MSI_GetPropertyW(package, prop, NULL, &sz);\r
- if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)\r
- {\r
- if (rc)\r
- *rc = r;\r
- return NULL;\r
- }\r
- sz++;\r
- str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));\r
- r = MSI_GetPropertyW(package, prop, str, &sz);\r
- if (r != ERROR_SUCCESS)\r
- {\r
- HeapFree(GetProcessHeap(),0,str);\r
- str = NULL;\r
- }\r
- if (rc)\r
- *rc = r;\r
- return str;\r
-}\r
-\r
-int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )\r
-{\r
- int rc = -1;\r
- DWORD i;\r
-\r
- for (i = 0; i < package->loaded_components; i++)\r
- {\r
- if (strcmpW(Component,package->components[i].Component)==0)\r
- {\r
- rc = i;\r
- break;\r
- }\r
- }\r
- return rc;\r
-}\r
-\r
-int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )\r
-{\r
- int rc = -1;\r
- DWORD i;\r
-\r
- for (i = 0; i < package->loaded_features; i++)\r
- {\r
- if (strcmpW(Feature,package->features[i].Feature)==0)\r
- {\r
- rc = i;\r
- break;\r
- }\r
- }\r
- return rc;\r
-}\r
-\r
-int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)\r
-{\r
- int rc = -1;\r
- DWORD i;\r
-\r
- for (i = 0; i < package->loaded_files; i++)\r
- {\r
- if (strcmpW(file,package->files[i].File)==0)\r
- {\r
- rc = i;\r
- break;\r
- }\r
- }\r
- return rc;\r
-}\r
-\r
-int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)\r
-{\r
- DWORD i;\r
- DWORD index;\r
-\r
- if (!package)\r
- return -2;\r
-\r
- for (i=0; i < package->loaded_files; i++)\r
- if (strcmpW(package->files[i].File,name)==0)\r
- return -1;\r
-\r
- index = package->loaded_files;\r
- package->loaded_files++;\r
- if (package->loaded_files== 1)\r
- package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));\r
- else\r
- package->files = HeapReAlloc(GetProcessHeap(),0,\r
- package->files , package->loaded_files * sizeof(MSIFILE));\r
-\r
- memset(&package->files[index],0,sizeof(MSIFILE));\r
-\r
- package->files[index].File = dupstrW(name);\r
- package->files[index].TargetPath = dupstrW(path);\r
- package->files[index].Temporary = TRUE;\r
-\r
- TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File)); \r
-\r
- return 0;\r
-}\r
-\r
-static void remove_tracked_tempfiles(MSIPACKAGE* package)\r
-{\r
- DWORD i;\r
-\r
- if (!package)\r
- return;\r
-\r
- for (i = 0; i < package->loaded_files; i++)\r
- {\r
- if (package->files[i].Temporary)\r
- {\r
- TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath));\r
- DeleteFileW(package->files[i].TargetPath);\r
- }\r
-\r
- }\r
-}\r
-\r
-/* wrapper to resist a need for a full rewrite right now */\r
-DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data )\r
-{\r
- if (ptr)\r
- {\r
- MSIRECORD *rec = MSI_CreateRecord(1);\r
- DWORD size = 0;\r
-\r
- MSI_RecordSetStringW(rec,0,ptr);\r
- MSI_FormatRecordW(package,rec,NULL,&size);\r
- if (size >= 0)\r
- {\r
- size++;\r
- *data = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));\r
- if (size > 1)\r
- MSI_FormatRecordW(package,rec,*data,&size);\r
- else\r
- *data[0] = 0;\r
- msiobj_release( &rec->hdr );\r
- return sizeof(WCHAR)*size;\r
- }\r
- msiobj_release( &rec->hdr );\r
- }\r
-\r
- *data = NULL;\r
- return 0;\r
-}\r
-\r
-/* Called when the package is being closed */\r
-void ACTION_free_package_structures( MSIPACKAGE* package)\r
-{\r
- INT i;\r
- \r
- TRACE("Freeing package action data\n");\r
-\r
- remove_tracked_tempfiles(package);\r
-\r
- /* No dynamic buffers in features */\r
- if (package->features && package->loaded_features > 0)\r
- HeapFree(GetProcessHeap(),0,package->features);\r
-\r
- for (i = 0; i < package->loaded_folders; i++)\r
- {\r
- HeapFree(GetProcessHeap(),0,package->folders[i].Directory);\r
- HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault);\r
- HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault);\r
- HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);\r
- HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource);\r
- HeapFree(GetProcessHeap(),0,package->folders[i].Property);\r
- }\r
- if (package->folders && package->loaded_folders > 0)\r
- HeapFree(GetProcessHeap(),0,package->folders);\r
-\r
- /* no dynamic buffers in components */ \r
- if (package->components && package->loaded_components > 0)\r
- HeapFree(GetProcessHeap(),0,package->components);\r
-\r
- for (i = 0; i < package->loaded_files; i++)\r
- {\r
- HeapFree(GetProcessHeap(),0,package->files[i].File);\r
- HeapFree(GetProcessHeap(),0,package->files[i].FileName);\r
- HeapFree(GetProcessHeap(),0,package->files[i].Version);\r
- HeapFree(GetProcessHeap(),0,package->files[i].Language);\r
- HeapFree(GetProcessHeap(),0,package->files[i].SourcePath);\r
- HeapFree(GetProcessHeap(),0,package->files[i].TargetPath);\r
- }\r
-\r
- if (package->files && package->loaded_files > 0)\r
- HeapFree(GetProcessHeap(),0,package->files);\r
-\r
- for (i = 0; i < package->DeferredActionCount; i++)\r
- HeapFree(GetProcessHeap(),0,package->DeferredAction[i]);\r
- HeapFree(GetProcessHeap(),0,package->DeferredAction);\r
-\r
- for (i = 0; i < package->CommitActionCount; i++)\r
- HeapFree(GetProcessHeap(),0,package->CommitAction[i]);\r
- HeapFree(GetProcessHeap(),0,package->CommitAction);\r
-\r
- HeapFree(GetProcessHeap(),0,package->PackagePath);\r
-}\r
-\r
-static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d )\r
-{\r
- MSIRECORD * row;\r
-\r
- row = MSI_CreateRecord(4);\r
- MSI_RecordSetInteger(row,1,a);\r
- MSI_RecordSetInteger(row,2,b);\r
- MSI_RecordSetInteger(row,3,c);\r
- MSI_RecordSetInteger(row,4,d);\r
- MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row);\r
- msiobj_release(&row->hdr);\r
-\r
- msi_dialog_check_messages(package->dialog, NULL);\r
-}\r
-\r
-static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)\r
-{\r
- static const WCHAR Query_t[] = \r
-{'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',\r
-'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',\r
-' ','\'','%','s','\'',0};\r
- WCHAR message[1024];\r
- UINT rc;\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- DWORD size;\r
-\r
- if (!package->LastAction || strcmpW(package->LastAction,action))\r
- {\r
- rc = MSI_OpenQuery(package->db, &view, Query_t, action);\r
- if (rc != ERROR_SUCCESS)\r
- return;\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- return;\r
- }\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- return;\r
- }\r
-\r
- if (MSI_RecordIsNull(row,3))\r
- {\r
- msiobj_release(&row->hdr);\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return;\r
- }\r
-\r
- /* update the cached actionformat */\r
- HeapFree(GetProcessHeap(),0,package->ActionFormat);\r
- package->ActionFormat = load_dynamic_stringW(row,3);\r
-\r
- HeapFree(GetProcessHeap(),0,package->LastAction);\r
- package->LastAction = dupstrW(action);\r
-\r
- msiobj_release(&row->hdr);\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- }\r
-\r
- MSI_RecordSetStringW(record,0,package->ActionFormat);\r
- size = 1024;\r
- MSI_FormatRecordW(package,record,message,&size);\r
-\r
- row = MSI_CreateRecord(1);\r
- MSI_RecordSetStringW(row,1,message);\r
- \r
- MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);\r
- msiobj_release(&row->hdr);\r
-}\r
-\r
-\r
-static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)\r
-{\r
- static const WCHAR template_s[]=\r
-{'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ','%','s','.',0};\r
- static const WCHAR format[] = \r
-{'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};\r
- static const WCHAR Query_t[] = \r
-{'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','c','t','i','o',\r
-'n','T','e','x','t',' ','w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',\r
-' ','\'','%','s','\'',0};\r
- WCHAR message[1024];\r
- WCHAR timet[0x100];\r
- UINT rc;\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- WCHAR *ActionText=NULL;\r
-\r
- GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);\r
-\r
- rc = MSI_OpenQuery(package->db, &view, Query_t, action);\r
- if (rc != ERROR_SUCCESS)\r
- return;\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return;\r
- }\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return;\r
- }\r
-\r
- ActionText = load_dynamic_stringW(row,2);\r
- msiobj_release(&row->hdr);\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
-\r
- sprintfW(message,template_s,timet,action,ActionText);\r
-\r
- row = MSI_CreateRecord(1);\r
- MSI_RecordSetStringW(row,1,message);\r
- \r
- MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);\r
- msiobj_release(&row->hdr);\r
- HeapFree(GetProcessHeap(),0,ActionText);\r
-}\r
-\r
-static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, \r
- UINT rc)\r
-{\r
- MSIRECORD * row;\r
- static const WCHAR template_s[]=\r
-{'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ','%','s',\r
-'.',0};\r
- static const WCHAR template_e[]=\r
-{'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ','%','s',\r
-'.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ','%','i','.',0};\r
- static const WCHAR format[] = \r
-{'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};\r
- WCHAR message[1024];\r
- WCHAR timet[0x100];\r
-\r
- GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);\r
- if (start)\r
- sprintfW(message,template_s,timet,action);\r
- else\r
- sprintfW(message,template_e,timet,action,rc);\r
- \r
- row = MSI_CreateRecord(1);\r
- MSI_RecordSetStringW(row,1,message);\r
- \r
- MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);\r
- msiobj_release(&row->hdr);\r
-}\r
-\r
-/*\r
- * build_directory_name()\r
- *\r
- * This function is to save messing round with directory names\r
- * It handles adding backslashes between path segments, \r
- * and can add \ at the end of the directory name if told to.\r
- *\r
- * It takes a variable number of arguments.\r
- * It always allocates a new string for the result, so make sure\r
- * to free the return value when finished with it.\r
- *\r
- * The first arg is the number of path segments that follow.\r
- * The arguments following count are a list of path segments.\r
- * A path segment may be NULL.\r
- *\r
- * Path segments will be added with a \ separating them.\r
- * A \ will not be added after the last segment, however if the\r
- * last segment is NULL, then the last character will be a \\r
- * \r
- */\r
-static LPWSTR build_directory_name(DWORD count, ...)\r
-{\r
- DWORD sz = 1, i;\r
- LPWSTR dir;\r
- va_list va;\r
-\r
- va_start(va,count);\r
- for(i=0; i<count; i++)\r
- {\r
- LPCWSTR str = va_arg(va,LPCWSTR);\r
- if (str)\r
- sz += strlenW(str) + 1;\r
- }\r
- va_end(va);\r
-\r
- dir = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));\r
- dir[0]=0;\r
-\r
- va_start(va,count);\r
- for(i=0; i<count; i++)\r
- {\r
- LPCWSTR str = va_arg(va,LPCWSTR);\r
- if (!str)\r
- continue;\r
- strcatW(dir, str);\r
- if( ((i+1)!=count) && dir[strlenW(dir)-1]!='\\')\r
- strcatW(dir, cszbs);\r
- }\r
- return dir;\r
-}\r
-\r
-\r
-/****************************************************\r
- * TOP level entry points \r
- *****************************************************/\r
-\r
-UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath,\r
- LPCWSTR szCommandLine)\r
-{\r
- DWORD sz;\r
- WCHAR buffer[10];\r
- UINT rc;\r
- static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};\r
- static const WCHAR szAction[] = {'A','C','T','I','O','N',0};\r
- static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};\r
-\r
- MSI_SetPropertyW(package, szAction, szInstall);\r
-\r
- if (szPackagePath) \r
- {\r
- LPWSTR p, check, path;\r
- \r
- package->PackagePath = dupstrW(szPackagePath);\r
- path = dupstrW(szPackagePath);\r
- p = strrchrW(path,'\\'); \r
- if (p)\r
- {\r
- p++;\r
- *p=0;\r
- }\r
- else\r
- {\r
- HeapFree(GetProcessHeap(),0,path);\r
- path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR));\r
- GetCurrentDirectoryW(MAX_PATH,path);\r
- strcatW(path,cszbs);\r
- }\r
-\r
- check = load_dynamic_property(package, cszSourceDir,NULL);\r
- if (!check)\r
- MSI_SetPropertyW(package, cszSourceDir, path);\r
- else\r
- HeapFree(GetProcessHeap(), 0, check);\r
-\r
- HeapFree(GetProcessHeap(), 0, path);\r
- }\r
-\r
- if (szCommandLine)\r
- {\r
- LPWSTR ptr,ptr2;\r
- ptr = (LPWSTR)szCommandLine;\r
- \r
- while (*ptr)\r
- {\r
- WCHAR *prop = NULL;\r
- WCHAR *val = NULL;\r
-\r
- TRACE("Looking at %s\n",debugstr_w(ptr));\r
-\r
- ptr2 = strchrW(ptr,'=');\r
- if (ptr2)\r
- {\r
- BOOL quote=FALSE;\r
- DWORD len = 0;\r
-\r
- while (*ptr == ' ') ptr++;\r
- len = ptr2-ptr;\r
- prop = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));\r
- strncpyW(prop,ptr,len);\r
- prop[len]=0;\r
- ptr2++;\r
- \r
- len = 0; \r
- ptr = ptr2; \r
- while (*ptr && (quote || (!quote && *ptr!=' ')))\r
- {\r
- if (*ptr == '"')\r
- quote = !quote;\r
- ptr++;\r
- len++;\r
- }\r
- \r
- if (*ptr2=='"')\r
- {\r
- ptr2++;\r
- len -= 2;\r
- }\r
- val = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));\r
- strncpyW(val,ptr2,len);\r
- val[len] = 0;\r
-\r
- if (strlenW(prop) > 0)\r
- {\r
- TRACE("Found commandline property (%s) = (%s)\n", \r
- debugstr_w(prop), debugstr_w(val));\r
- MSI_SetPropertyW(package,prop,val);\r
- }\r
- HeapFree(GetProcessHeap(),0,val);\r
- HeapFree(GetProcessHeap(),0,prop);\r
- }\r
- ptr++;\r
- }\r
- }\r
- \r
- sz = 10; \r
- if (MSI_GetPropertyW(package,szUILevel,buffer,&sz) == ERROR_SUCCESS)\r
- {\r
- if (atoiW(buffer) >= INSTALLUILEVEL_REDUCED)\r
- {\r
- rc = ACTION_ProcessUISequence(package);\r
- if (rc == ERROR_SUCCESS)\r
- rc = ACTION_ProcessExecSequence(package,TRUE);\r
- }\r
- else\r
- rc = ACTION_ProcessExecSequence(package,FALSE);\r
- }\r
- else\r
- rc = ACTION_ProcessExecSequence(package,FALSE);\r
- \r
- if (rc == -1)\r
- {\r
- /* install was halted but should be considered a success */\r
- rc = ERROR_SUCCESS;\r
- }\r
-\r
- /* process the ending type action */\r
- if (rc == ERROR_SUCCESS)\r
- ACTION_PerformActionSequence(package,-1);\r
- else if (rc == ERROR_INSTALL_USEREXIT) \r
- ACTION_PerformActionSequence(package,-2);\r
- else if (rc == ERROR_FUNCTION_FAILED) \r
- ACTION_PerformActionSequence(package,-3);\r
- else if (rc == ERROR_INSTALL_SUSPEND) \r
- ACTION_PerformActionSequence(package,-4);\r
-\r
- /* finish up running custom actions */\r
- ACTION_FinishCustomActions(package);\r
- \r
- return rc;\r
-}\r
-\r
-static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)\r
-{\r
- MSIQUERY * view;\r
- UINT rc;\r
- WCHAR buffer[0x100];\r
- DWORD sz = 0x100;\r
- MSIRECORD * row = 0;\r
- static const WCHAR ExecSeqQuery[] = {\r
- 's','e','l','e','c','t',' ','*',' ',\r
- 'f','r','o','m',' ',\r
- 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',\r
- 'S','e','q','u','e','n','c','e',' ',\r
- 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',\r
- '=',' ','%','i',0};\r
-\r
- rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);\r
-\r
- if (rc == ERROR_SUCCESS)\r
- {\r
- rc = MSI_ViewExecute(view, 0);\r
-\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- goto end;\r
- }\r
- \r
- TRACE("Running the actions\n"); \r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- goto end;\r
- }\r
-\r
- /* check conditions */\r
- if (!MSI_RecordIsNull(row,2))\r
- {\r
- LPWSTR cond = NULL;\r
- cond = load_dynamic_stringW(row,2);\r
-\r
- if (cond)\r
- {\r
- /* this is a hack to skip errors in the condition code */\r
- if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)\r
- {\r
- HeapFree(GetProcessHeap(),0,cond);\r
- msiobj_release(&row->hdr);\r
- goto end;\r
- }\r
- else\r
- HeapFree(GetProcessHeap(),0,cond);\r
- }\r
- }\r
-\r
- sz=0x100;\r
- rc = MSI_RecordGetStringW(row,1,buffer,&sz);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- ERR("Error is %x\n",rc);\r
- msiobj_release(&row->hdr);\r
- goto end;\r
- }\r
-\r
- rc = ACTION_PerformAction(package,buffer);\r
- msiobj_release(&row->hdr);\r
-end:\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- }\r
- else\r
- rc = ERROR_SUCCESS;\r
-\r
- return rc;\r
-}\r
-\r
-static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)\r
-{\r
- MSIQUERY * view;\r
- UINT rc;\r
- static const WCHAR ExecSeqQuery[] = {\r
- 's','e','l','e','c','t',' ','*',' ',\r
- 'f','r','o','m',' ',\r
- 'I','n','s','t','a','l','l','E','x','e','c','u','t','e',\r
- 'S','e','q','u','e','n','c','e',' ',\r
- 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ',\r
- '>',' ','%','i',' ','o','r','d','e','r',' ',\r
- 'b','y',' ','S','e','q','u','e','n','c','e',0 };\r
- MSIRECORD * row = 0;\r
- static const WCHAR IVQuery[] = {\r
- 's','e','l','e','c','t',' ','S','e','q','u','e','n','c','e',' ',\r
- 'f','r','o','m',' ','I','n','s','t','a','l','l',\r
- 'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e',' ',\r
- 'w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',' ',\r
- '`','I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','`',\r
- 0};\r
- INT seq = 0;\r
-\r
- /* get the sequence number */\r
- if (UIran)\r
- {\r
- rc = MSI_DatabaseOpenViewW(package->db, IVQuery, &view);\r
- if (rc != ERROR_SUCCESS)\r
- return rc;\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
- seq = MSI_RecordGetInteger(row,1);\r
- msiobj_release(&row->hdr);\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- }\r
-\r
- rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);\r
- if (rc == ERROR_SUCCESS)\r
- {\r
- rc = MSI_ViewExecute(view, 0);\r
-\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- goto end;\r
- }\r
- \r
- TRACE("Running the actions\n"); \r
-\r
- while (1)\r
- {\r
- WCHAR buffer[0x100];\r
- DWORD sz = 0x100;\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
-\r
- /* check conditions */\r
- if (!MSI_RecordIsNull(row,2))\r
- {\r
- LPWSTR cond = NULL;\r
- cond = load_dynamic_stringW(row,2);\r
-\r
- if (cond)\r
- {\r
- /* this is a hack to skip errors in the condition code */\r
- if (MSI_EvaluateConditionW(package, cond) ==\r
- MSICONDITION_FALSE)\r
- {\r
- HeapFree(GetProcessHeap(),0,cond);\r
- msiobj_release(&row->hdr);\r
- continue; \r
- }\r
- else\r
- HeapFree(GetProcessHeap(),0,cond);\r
- }\r
- }\r
-\r
- sz=0x100;\r
- rc = MSI_RecordGetStringW(row,1,buffer,&sz);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- ERR("Error is %x\n",rc);\r
- msiobj_release(&row->hdr);\r
- break;\r
- }\r
-\r
- rc = ACTION_PerformAction(package,buffer);\r
-\r
- if (rc == ERROR_FUNCTION_NOT_CALLED)\r
- rc = ERROR_SUCCESS;\r
-\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- ERR("Execution halted due to error (%i)\n",rc);\r
- msiobj_release(&row->hdr);\r
- break;\r
- }\r
-\r
- msiobj_release(&row->hdr);\r
- }\r
-\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- }\r
-\r
-end:\r
- return rc;\r
-}\r
-\r
-\r
-static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)\r
-{\r
- MSIQUERY * view;\r
- UINT rc;\r
- static const WCHAR ExecSeqQuery [] = {\r
- 's','e','l','e','c','t',' ','*',' ',\r
- 'f','r','o','m',' ','I','n','s','t','a','l','l',\r
- 'U','I','S','e','q','u','e','n','c','e',' ',\r
- 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', '>',' ','0',' ',\r
- 'o','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e',0};\r
- \r
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);\r
- \r
- if (rc == ERROR_SUCCESS)\r
- {\r
- rc = MSI_ViewExecute(view, 0);\r
-\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- goto end;\r
- }\r
- \r
- TRACE("Running the actions \n"); \r
-\r
- while (1)\r
- {\r
- WCHAR buffer[0x100];\r
- DWORD sz = 0x100;\r
- MSIRECORD * row = 0;\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
-\r
- /* check conditions */\r
- if (!MSI_RecordIsNull(row,2))\r
- {\r
- LPWSTR cond = NULL;\r
- cond = load_dynamic_stringW(row,2);\r
-\r
- if (cond)\r
- {\r
- /* this is a hack to skip errors in the condition code */\r
- if (MSI_EvaluateConditionW(package, cond) ==\r
- MSICONDITION_FALSE)\r
- {\r
- HeapFree(GetProcessHeap(),0,cond);\r
- msiobj_release(&row->hdr);\r
- continue; \r
- }\r
- else\r
- HeapFree(GetProcessHeap(),0,cond);\r
- }\r
- }\r
-\r
- sz=0x100;\r
- rc = MSI_RecordGetStringW(row,1,buffer,&sz);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- ERR("Error is %x\n",rc);\r
- msiobj_release(&row->hdr);\r
- break;\r
- }\r
-\r
- rc = ACTION_PerformUIAction(package,buffer);\r
-\r
- if (rc == ERROR_FUNCTION_NOT_CALLED)\r
- rc = ERROR_SUCCESS;\r
-\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- ERR("Execution halted due to error (%i)\n",rc);\r
- msiobj_release(&row->hdr);\r
- break;\r
- }\r
-\r
- msiobj_release(&row->hdr);\r
- }\r
-\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- }\r
-\r
-end:\r
- return rc;\r
-}\r
-\r
-/********************************************************\r
- * ACTION helper functions and functions that perform the actions\r
- *******************************************************/\r
-BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, UINT* rc)\r
-{\r
- BOOL ret = FALSE; \r
-\r
- int i;\r
- i = 0;\r
- while (StandardActions[i].action != NULL)\r
- {\r
- if (strcmpW(StandardActions[i].action, action)==0)\r
- {\r
- ui_actioninfo(package, action, TRUE, 0);\r
- ui_actionstart(package, action);\r
- if (StandardActions[i].handler)\r
- {\r
- *rc = StandardActions[i].handler(package);\r
- }\r
- else\r
- {\r
- FIXME("UNHANDLED Standard Action %s\n",debugstr_w(action));\r
- *rc = ERROR_SUCCESS;\r
- }\r
- ui_actioninfo(package, action, FALSE, *rc);\r
- ret = TRUE;\r
- break;\r
- }\r
- i++;\r
- }\r
- return ret;\r
-}\r
-\r
-BOOL ACTION_HandleDialogBox(MSIPACKAGE *package, LPCWSTR dialog, UINT* rc)\r
-{\r
- BOOL ret = FALSE;\r
-\r
- /*\r
- * for the UI when we get that working\r
- *\r
- if (ACTION_DialogBox(package,dialog) == ERROR_SUCCESS)\r
- {\r
- *rc = package->CurrentInstallState;\r
- ret = TRUE;\r
- }\r
- */\r
- return ret;\r
-}\r
-\r
-BOOL ACTION_HandleCustomAction(MSIPACKAGE* package, LPCWSTR action, UINT* rc)\r
-{\r
- BOOL ret=FALSE;\r
- UINT arc;\r
-\r
- arc = ACTION_CustomAction(package,action,FALSE);\r
-\r
- if (arc != ERROR_CALL_NOT_IMPLEMENTED)\r
- {\r
- *rc = arc;\r
- ret = TRUE;\r
- }\r
- return ret;\r
-}\r
-\r
-/* \r
- * A lot of actions are really important even if they don't do anything\r
- * explicit... Lots of properties are set at the beginning of the installation\r
- * CostFinalize does a bunch of work to translate the directories and such\r
- * \r
- * But until I get write access to the database that is hard, so I am going to\r
- * hack it to see if I can get something to run.\r
- */\r
-UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action)\r
-{\r
- UINT rc = ERROR_SUCCESS; \r
- BOOL handled;\r
-\r
- TRACE("Performing action (%s)\n",debugstr_w(action));\r
-\r
- handled = ACTION_HandleStandardAction(package, action, &rc);\r
-\r
- if (!handled)\r
- handled = ACTION_HandleCustomAction(package, action, &rc);\r
-\r
- if (!handled)\r
- {\r
- FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));\r
- rc = ERROR_FUNCTION_NOT_CALLED;\r
- }\r
-\r
- package->CurrentInstallState = rc;\r
- return rc;\r
-}\r
-\r
-UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)\r
-{\r
- UINT rc = ERROR_SUCCESS;\r
- BOOL handled = FALSE;\r
-\r
- TRACE("Performing action (%s)\n",debugstr_w(action));\r
-\r
- handled = ACTION_HandleStandardAction(package, action, &rc);\r
-\r
- if (!handled)\r
- handled = ACTION_HandleCustomAction(package, action, &rc);\r
-\r
- if (!handled)\r
- handled = ACTION_HandleDialogBox(package, action, &rc);\r
-\r
- msi_dialog_check_messages( package->dialog, NULL );\r
-\r
- if (!handled)\r
- {\r
- FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));\r
- rc = ERROR_FUNCTION_NOT_CALLED;\r
- }\r
-\r
- package->CurrentInstallState = rc;\r
- return rc;\r
-}\r
-\r
-/***********************************************************************\r
- * create_full_pathW\r
- *\r
- * Recursively create all directories in the path.\r
- *\r
- * shamelessly stolen from setupapi/queue.c\r
- */\r
-static BOOL create_full_pathW(const WCHAR *path)\r
-{\r
- BOOL ret = TRUE;\r
- int len;\r
- WCHAR *new_path;\r
-\r
- new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) *\r
- sizeof(WCHAR));\r
-\r
- strcpyW(new_path, path);\r
-\r
- while((len = strlenW(new_path)) && new_path[len - 1] == '\\')\r
- new_path[len - 1] = 0;\r
-\r
- while(!CreateDirectoryW(new_path, NULL))\r
- {\r
- WCHAR *slash;\r
- DWORD last_error = GetLastError();\r
- if(last_error == ERROR_ALREADY_EXISTS)\r
- break;\r
-\r
- if(last_error != ERROR_PATH_NOT_FOUND)\r
- {\r
- ret = FALSE;\r
- break;\r
- }\r
-\r
- if(!(slash = strrchrW(new_path, '\\')))\r
- {\r
- ret = FALSE;\r
- break;\r
- }\r
-\r
- len = slash - new_path;\r
- new_path[len] = 0;\r
- if(!create_full_pathW(new_path))\r
- {\r
- ret = FALSE;\r
- break;\r
- }\r
- new_path[len] = '\\';\r
- }\r
-\r
- HeapFree(GetProcessHeap(), 0, new_path);\r
- return ret;\r
-}\r
-\r
-/*\r
- * Also we cannot enable/disable components either, so for now I am just going \r
- * to do all the directories for all the components.\r
- */\r
-static UINT ACTION_CreateFolders(MSIPACKAGE *package)\r
-{\r
- static const WCHAR ExecSeqQuery[] = {\r
- 's','e','l','e','c','t',' ','D','i','r','e','c','t','o','r','y','_',' ',\r
- 'f','r','o','m',' ','C','r','e','a','t','e','F','o','l','d','e','r',0 };\r
- UINT rc;\r
- MSIQUERY *view;\r
- MSIFOLDER *folder;\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );\r
- if (rc != ERROR_SUCCESS)\r
- return ERROR_SUCCESS;\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
- \r
- while (1)\r
- {\r
- WCHAR dir[0x100];\r
- LPWSTR full_path;\r
- DWORD sz;\r
- MSIRECORD *row = NULL, *uirow;\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
-\r
- sz=0x100;\r
- rc = MSI_RecordGetStringW(row,1,dir,&sz);\r
-\r
- if (rc!= ERROR_SUCCESS)\r
- {\r
- ERR("Unable to get folder id \n");\r
- msiobj_release(&row->hdr);\r
- continue;\r
- }\r
-\r
- sz = MAX_PATH;\r
- full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);\r
- if (!full_path)\r
- {\r
- ERR("Unable to resolve folder id %s\n",debugstr_w(dir));\r
- msiobj_release(&row->hdr);\r
- continue;\r
- }\r
-\r
- TRACE("Folder is %s\n",debugstr_w(full_path));\r
-\r
- /* UI stuff */\r
- uirow = MSI_CreateRecord(1);\r
- MSI_RecordSetStringW(uirow,1,full_path);\r
- ui_actiondata(package,szCreateFolders,uirow);\r
- msiobj_release( &uirow->hdr );\r
-\r
- if (folder->State == 0)\r
- create_full_pathW(full_path);\r
-\r
- folder->State = 3;\r
-\r
- msiobj_release(&row->hdr);\r
- HeapFree(GetProcessHeap(),0,full_path);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- \r
- return rc;\r
-}\r
-\r
-static int load_component(MSIPACKAGE* package, MSIRECORD * row)\r
-{\r
- int index = package->loaded_components;\r
- DWORD sz;\r
-\r
- /* fill in the data */\r
-\r
- package->loaded_components++;\r
- if (package->loaded_components == 1)\r
- package->components = HeapAlloc(GetProcessHeap(),0,\r
- sizeof(MSICOMPONENT));\r
- else\r
- package->components = HeapReAlloc(GetProcessHeap(),0,\r
- package->components, package->loaded_components * \r
- sizeof(MSICOMPONENT));\r
-\r
- memset(&package->components[index],0,sizeof(MSICOMPONENT));\r
-\r
- sz = 96; \r
- MSI_RecordGetStringW(row,1,package->components[index].Component,&sz);\r
-\r
- TRACE("Loading Component %s\n",\r
- debugstr_w(package->components[index].Component));\r
-\r
- sz = 0x100;\r
- if (!MSI_RecordIsNull(row,2))\r
- MSI_RecordGetStringW(row,2,package->components[index].ComponentId,&sz);\r
- \r
- sz = 96; \r
- MSI_RecordGetStringW(row,3,package->components[index].Directory,&sz);\r
-\r
- package->components[index].Attributes = MSI_RecordGetInteger(row,4);\r
-\r
- sz = 0x100; \r
- MSI_RecordGetStringW(row,5,package->components[index].Condition,&sz);\r
-\r
- sz = 96; \r
- MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz);\r
-\r
- package->components[index].Installed = INSTALLSTATE_ABSENT;\r
- package->components[index].Action = INSTALLSTATE_UNKNOWN;\r
- package->components[index].ActionRequest = INSTALLSTATE_UNKNOWN;\r
-\r
- package->components[index].Enabled = TRUE;\r
-\r
- return index;\r
-}\r
-\r
-static void load_feature(MSIPACKAGE* package, MSIRECORD * row)\r
-{\r
- int index = package->loaded_features;\r
- DWORD sz;\r
- static const WCHAR Query1[] = {'S','E','L','E','C','T',' ','C','o','m','p',\r
- 'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e',\r
- 'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e',\r
- 'a','t','u','r','e','_','=','\'','%','s','\'',0};\r
- static const WCHAR Query2[] = {'S','E','L','E','C','T',' ','*',' ','F','R',\r
- 'O','M',' ','C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ','C',\r
- 'o','m','p','o','n','e','n','t','=','\'','%','s','\'',0};\r
- MSIQUERY * view;\r
- MSIQUERY * view2;\r
- MSIRECORD * row2;\r
- MSIRECORD * row3;\r
- UINT rc;\r
-\r
- /* fill in the data */\r
-\r
- package->loaded_features ++;\r
- if (package->loaded_features == 1)\r
- package->features = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE));\r
- else\r
- package->features = HeapReAlloc(GetProcessHeap(),0,package->features,\r
- package->loaded_features * sizeof(MSIFEATURE));\r
-\r
- memset(&package->features[index],0,sizeof(MSIFEATURE));\r
- \r
- sz = 96; \r
- MSI_RecordGetStringW(row,1,package->features[index].Feature,&sz);\r
-\r
- TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature));\r
-\r
- sz = 96;\r
- if (!MSI_RecordIsNull(row,2))\r
- MSI_RecordGetStringW(row,2,package->features[index].Feature_Parent,&sz);\r
-\r
- sz = 0x100;\r
- if (!MSI_RecordIsNull(row,3))\r
- MSI_RecordGetStringW(row,3,package->features[index].Title,&sz);\r
-\r
- sz = 0x100;\r
- if (!MSI_RecordIsNull(row,4))\r
- MSI_RecordGetStringW(row,4,package->features[index].Description,&sz);\r
-\r
- if (!MSI_RecordIsNull(row,5))\r
- package->features[index].Display = MSI_RecordGetInteger(row,5);\r
- \r
- package->features[index].Level= MSI_RecordGetInteger(row,6);\r
-\r
- sz = 96;\r
- if (!MSI_RecordIsNull(row,7))\r
- MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz);\r
-\r
- package->features[index].Attributes= MSI_RecordGetInteger(row,8);\r
-\r
- package->features[index].Installed = INSTALLSTATE_ABSENT;\r
- package->features[index].Action = INSTALLSTATE_UNKNOWN;\r
- package->features[index].ActionRequest = INSTALLSTATE_UNKNOWN;\r
-\r
- /* load feature components */\r
-\r
- rc = MSI_OpenQuery(package->db, &view, Query1, package->features[index].Feature);\r
- if (rc != ERROR_SUCCESS)\r
- return;\r
- rc = MSI_ViewExecute(view,0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return;\r
- }\r
- while (1)\r
- {\r
- DWORD sz = 0x100;\r
- WCHAR buffer[0x100];\r
- DWORD rc;\r
- INT c_indx;\r
- INT cnt = package->features[index].ComponentCount;\r
-\r
- rc = MSI_ViewFetch(view,&row2);\r
- if (rc != ERROR_SUCCESS)\r
- break;\r
-\r
- sz = 0x100;\r
- MSI_RecordGetStringW(row2,1,buffer,&sz);\r
-\r
- /* check to see if the component is already loaded */\r
- c_indx = get_loaded_component(package,buffer);\r
- if (c_indx != -1)\r
- {\r
- TRACE("Component %s already loaded at %i\n", debugstr_w(buffer),\r
- c_indx);\r
- package->features[index].Components[cnt] = c_indx;\r
- package->features[index].ComponentCount ++;\r
- continue;\r
- }\r
-\r
- rc = MSI_OpenQuery(package->db, &view2, Query2, buffer);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- msiobj_release( &row2->hdr );\r
- continue;\r
- }\r
- rc = MSI_ViewExecute(view2,0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- msiobj_release( &row2->hdr );\r
- MSI_ViewClose(view2);\r
- msiobj_release( &view2->hdr ); \r
- continue;\r
- }\r
- while (1)\r
- {\r
- DWORD rc;\r
-\r
- rc = MSI_ViewFetch(view2,&row3);\r
- if (rc != ERROR_SUCCESS)\r
- break;\r
- c_indx = load_component(package,row3);\r
- msiobj_release( &row3->hdr );\r
-\r
- package->features[index].Components[cnt] = c_indx;\r
- package->features[index].ComponentCount ++;\r
- TRACE("Loaded new component to index %i\n",c_indx);\r
- }\r
- MSI_ViewClose(view2);\r
- msiobj_release( &view2->hdr );\r
- msiobj_release( &row2->hdr );\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
-}\r
-\r
-/*\r
- * I am not doing any of the costing functionality yet. \r
- * Mostly looking at doing the Component and Feature loading\r
- *\r
- * The native MSI does A LOT of modification to tables here. Mostly adding\r
- * a lot of temporary columns to the Feature and Component tables. \r
- *\r
- * note: Native msi also tracks the short filename. But I am only going to\r
- * track the long ones. Also looking at this directory table\r
- * it appears that the directory table does not get the parents\r
- * resolved base on property only based on their entries in the \r
- * directory table.\r
- */\r
-static UINT ACTION_CostInitialize(MSIPACKAGE *package)\r
-{\r
- MSIQUERY * view;\r
- MSIRECORD * row;\r
- UINT rc;\r
- static const WCHAR Query_all[] = {\r
- 'S','E','L','E','C','T',' ','*',' ',\r
- 'F','R','O','M',' ','F','e','a','t','u','r','e',0};\r
- static const WCHAR szCosting[] = {\r
- 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };\r
- static const WCHAR szZero[] = { '0', 0 };\r
-\r
- MSI_SetPropertyW(package, szCosting, szZero);\r
- MSI_SetPropertyW(package, cszRootDrive , c_collen);\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);\r
- if (rc != ERROR_SUCCESS)\r
- return rc;\r
- rc = MSI_ViewExecute(view,0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
- while (1)\r
- {\r
- DWORD rc;\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- break;\r
- \r
- load_feature(package,row); \r
- msiobj_release(&row->hdr);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
-\r
- return ERROR_SUCCESS;\r
-}\r
-\r
-static UINT load_file(MSIPACKAGE* package, MSIRECORD * row)\r
-{\r
- DWORD index = package->loaded_files;\r
- DWORD i;\r
- LPWSTR buffer;\r
-\r
- /* fill in the data */\r
-\r
- package->loaded_files++;\r
- if (package->loaded_files== 1)\r
- package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));\r
- else\r
- package->files = HeapReAlloc(GetProcessHeap(),0,\r
- package->files , package->loaded_files * sizeof(MSIFILE));\r
-\r
- memset(&package->files[index],0,sizeof(MSIFILE));\r
- \r
- package->files[index].File = load_dynamic_stringW(row, 1);\r
- buffer = load_dynamic_stringW(row, 2);\r
-\r
- package->files[index].ComponentIndex = -1;\r
- for (i = 0; i < package->loaded_components; i++)\r
- if (strcmpW(package->components[i].Component,buffer)==0)\r
- {\r
- package->files[index].ComponentIndex = i;\r
- break;\r
- }\r
- if (package->files[index].ComponentIndex == -1)\r
- ERR("Unfound Component %s\n",debugstr_w(buffer));\r
- HeapFree(GetProcessHeap(), 0, buffer);\r
-\r
- package->files[index].FileName = load_dynamic_stringW(row,3);\r
-\r
- reduce_to_longfilename(package->files[index].FileName);\r
- \r
- package->files[index].FileSize = MSI_RecordGetInteger(row,4);\r
- package->files[index].Version = load_dynamic_stringW(row, 5);\r
- package->files[index].Language = load_dynamic_stringW(row, 6);\r
- package->files[index].Attributes= MSI_RecordGetInteger(row,7);\r
- package->files[index].Sequence= MSI_RecordGetInteger(row,8);\r
-\r
- package->files[index].Temporary = FALSE;\r
- package->files[index].State = 0;\r
-\r
- TRACE("File Loaded (%s)\n",debugstr_w(package->files[index].File)); \r
- \r
- return ERROR_SUCCESS;\r
-}\r
-\r
-static UINT ACTION_FileCost(MSIPACKAGE *package)\r
-{\r
- MSIQUERY * view;\r
- MSIRECORD * row;\r
- UINT rc;\r
- static const WCHAR Query[] = {\r
- 'S','E','L','E','C','T',' ','*',' ',\r
- 'F','R','O','M',' ','F','i','l','e',' ',\r
- 'O','r','d','e','r',' ','b','y',' ','S','e','q','u','e','n','c','e', 0};\r
-\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, Query, &view);\r
- if (rc != ERROR_SUCCESS)\r
- return ERROR_SUCCESS;\r
- \r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return ERROR_SUCCESS;\r
- }\r
-\r
- while (1)\r
- {\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
- load_file(package,row);\r
- msiobj_release(&row->hdr);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
-\r
- return ERROR_SUCCESS;\r
-}\r
-\r
-static INT load_folder(MSIPACKAGE *package, const WCHAR* dir)\r
-\r
-{\r
- static const WCHAR Query[] =\r
- {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c',\r
- 't','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t',\r
- 'o','r','y','`',' ','=',' ','`','%','s','`',0};\r
- UINT rc;\r
- MSIQUERY * view;\r
- LPWSTR targetdir, parent, srcdir;\r
- MSIRECORD * row = 0;\r
- INT index = -1;\r
- DWORD i;\r
-\r
- TRACE("Looking for dir %s\n",debugstr_w(dir));\r
-\r
- for (i = 0; i < package->loaded_folders; i++)\r
- {\r
- if (strcmpW(package->folders[i].Directory,dir)==0)\r
- {\r
- TRACE(" %s retuning on index %lu\n",debugstr_w(dir),i);\r
- return i;\r
- }\r
- }\r
-\r
- TRACE("Working to load %s\n",debugstr_w(dir));\r
-\r
- index = package->loaded_folders++;\r
- if (package->loaded_folders==1)\r
- package->folders = HeapAlloc(GetProcessHeap(),0,\r
- sizeof(MSIFOLDER));\r
- else\r
- package->folders= HeapReAlloc(GetProcessHeap(),0,\r
- package->folders, package->loaded_folders* \r
- sizeof(MSIFOLDER));\r
-\r
- memset(&package->folders[index],0,sizeof(MSIFOLDER));\r
-\r
- package->folders[index].Directory = dupstrW(dir);\r
-\r
- rc = MSI_OpenQuery(package->db, &view, Query, dir);\r
- if (rc != ERROR_SUCCESS)\r
- return -1;\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return -1;\r
- }\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return -1;\r
- }\r
-\r
- targetdir = load_dynamic_stringW(row,3);\r
-\r
- /* split src and target dir */\r
- if (strchrW(targetdir,':'))\r
- {\r
- srcdir=strchrW(targetdir,':');\r
- *srcdir=0;\r
- srcdir ++;\r
- }\r
- else\r
- srcdir=NULL;\r
-\r
- /* for now only pick long filename versions */\r
- if (strchrW(targetdir,'|'))\r
- {\r
- targetdir = strchrW(targetdir,'|'); \r
- *targetdir = 0;\r
- targetdir ++;\r
- }\r
- if (srcdir && strchrW(srcdir,'|'))\r
- {\r
- srcdir= strchrW(srcdir,'|'); \r
- *srcdir= 0;\r
- srcdir ++;\r
- }\r
-\r
- /* now check for root dirs */\r
- if (targetdir[0] == '.' && targetdir[1] == 0)\r
- targetdir = NULL;\r
- \r
- if (srcdir && srcdir[0] == '.' && srcdir[1] == 0)\r
- srcdir = NULL;\r
-\r
- if (targetdir)\r
- {\r
- TRACE(" TargetDefault = %s\n",debugstr_w(targetdir));\r
- HeapFree(GetProcessHeap(),0, package->folders[index].TargetDefault);\r
- package->folders[index].TargetDefault = dupstrW(targetdir);\r
- }\r
-\r
- if (srcdir)\r
- package->folders[index].SourceDefault = dupstrW(srcdir);\r
- else if (targetdir)\r
- package->folders[index].SourceDefault = dupstrW(targetdir);\r
- HeapFree(GetProcessHeap(), 0, targetdir);\r
-\r
- parent = load_dynamic_stringW(row,2);\r
- if (parent) \r
- {\r
- i = load_folder(package,parent);\r
- package->folders[index].ParentIndex = i;\r
- TRACE("Parent is index %i... %s %s\n",\r
- package->folders[index].ParentIndex,\r
- debugstr_w(package->folders[package->folders[index].ParentIndex].Directory),\r
- debugstr_w(parent));\r
- }\r
- else\r
- package->folders[index].ParentIndex = -2;\r
- HeapFree(GetProcessHeap(), 0, parent);\r
-\r
- package->folders[index].Property = load_dynamic_property(package, dir,NULL);\r
-\r
- msiobj_release(&row->hdr);\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- TRACE(" %s retuning on index %i\n",debugstr_w(dir),index);\r
- return index;\r
-}\r
-\r
-\r
-LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, \r
- BOOL set_prop, MSIFOLDER **folder)\r
-{\r
- DWORD i;\r
- LPWSTR p, path = NULL;\r
-\r
- TRACE("Working to resolve %s\n",debugstr_w(name));\r
-\r
- /* special resolving for Target and Source root dir */\r
- if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)\r
- {\r
- if (!source)\r
- {\r
- path = load_dynamic_property(package,cszTargetDir,NULL);\r
- if (!path)\r
- {\r
- path = load_dynamic_property(package,cszRootDrive,NULL);\r
- if (set_prop)\r
- MSI_SetPropertyW(package,cszTargetDir,path);\r
- }\r
- if (folder)\r
- {\r
- for (i = 0; i < package->loaded_folders; i++)\r
- {\r
- if (strcmpW(package->folders[i].Directory,name)==0)\r
- break;\r
- }\r
- *folder = &(package->folders[i]);\r
- }\r
- return path;\r
- }\r
- else\r
- {\r
- path = load_dynamic_property(package,cszSourceDir,NULL);\r
- if (!path)\r
- {\r
- path = load_dynamic_property(package,cszDatabase,NULL);\r
- if (path)\r
- {\r
- p = strrchrW(path,'\\');\r
- if (p)\r
- *(p+1) = 0;\r
- }\r
- }\r
- if (folder)\r
- {\r
- for (i = 0; i < package->loaded_folders; i++)\r
- {\r
- if (strcmpW(package->folders[i].Directory,name)==0)\r
- break;\r
- }\r
- *folder = &(package->folders[i]);\r
- }\r
- return path;\r
- }\r
- }\r
-\r
- for (i = 0; i < package->loaded_folders; i++)\r
- {\r
- if (strcmpW(package->folders[i].Directory,name)==0)\r
- break;\r
- }\r
-\r
- if (i >= package->loaded_folders)\r
- return NULL;\r
-\r
- if (folder)\r
- *folder = &(package->folders[i]);\r
-\r
- if (!source && package->folders[i].ResolvedTarget)\r
- {\r
- path = dupstrW(package->folders[i].ResolvedTarget);\r
- TRACE(" already resolved to %s\n",debugstr_w(path));\r
- return path;\r
- }\r
- else if (source && package->folders[i].ResolvedSource)\r
- {\r
- path = dupstrW(package->folders[i].ResolvedSource);\r
- return path;\r
- }\r
- else if (!source && package->folders[i].Property)\r
- {\r
- path = build_directory_name(2, package->folders[i].Property, NULL);\r
- \r
- TRACE(" internally set to %s\n",debugstr_w(path));\r
- if (set_prop)\r
- MSI_SetPropertyW(package,name,path);\r
- return path;\r
- }\r
-\r
- if (package->folders[i].ParentIndex >= 0)\r
- {\r
- LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory;\r
-\r
- TRACE(" ! Parent is %s\n", debugstr_w(parent));\r
-\r
- p = resolve_folder(package, parent, source, set_prop, NULL);\r
- if (!source)\r
- {\r
- TRACE(" TargetDefault = %s\n",debugstr_w(package->folders[i].TargetDefault));\r
- path = build_directory_name(3, p, package->folders[i].TargetDefault, NULL);\r
- package->folders[i].ResolvedTarget = dupstrW(path);\r
- TRACE(" resolved into %s\n",debugstr_w(path));\r
- if (set_prop)\r
- MSI_SetPropertyW(package,name,path);\r
- }\r
- else \r
- {\r
- path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL);\r
- package->folders[i].ResolvedSource = dupstrW(path);\r
- }\r
- HeapFree(GetProcessHeap(),0,p);\r
- }\r
- return path;\r
-}\r
-\r
-/* update compoennt state based on a feature change */\r
-void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)\r
-{\r
- int i;\r
- INSTALLSTATE newstate;\r
- MSIFEATURE *feature;\r
-\r
- i = get_loaded_feature(package,szFeature);\r
- if (i < 0)\r
- return;\r
-\r
- feature = &package->features[i];\r
- newstate = feature->ActionRequest;\r
-\r
- for( i = 0; i < feature->ComponentCount; i++)\r
- {\r
- MSICOMPONENT* component = &package->components[feature->Components[i]];\r
-\r
- if (!component->Enabled)\r
- continue;\r
- else\r
- {\r
- if (newstate == INSTALLSTATE_LOCAL)\r
- component->ActionRequest = INSTALLSTATE_LOCAL;\r
- else \r
- {\r
- int j,k;\r
-\r
- component->ActionRequest = newstate;\r
-\r
- /*if any other feature wants is local we need to set it local*/\r
- for (j = 0; \r
- j < package->loaded_features &&\r
- component->ActionRequest != INSTALLSTATE_LOCAL; \r
- j++)\r
- {\r
- for (k = 0; k < package->features[j].ComponentCount; k++)\r
- if ( package->features[j].Components[k] ==\r
- feature->Components[i] )\r
- {\r
- if (package->features[j].ActionRequest == \r
- INSTALLSTATE_LOCAL)\r
- component->ActionRequest = INSTALLSTATE_LOCAL;\r
- break;\r
- }\r
- }\r
- }\r
- }\r
- } \r
-}\r
-\r
-static UINT SetFeatureStates(MSIPACKAGE *package)\r
-{\r
- LPWSTR level;\r
- INT install_level;\r
- DWORD i;\r
- INT j;\r
- LPWSTR override = NULL;\r
- static const WCHAR all[]={'A','L','L',0};\r
- static const WCHAR szlevel[] = {\r
- 'I','N','S','T','A','L','L','L','E','V','E','L',0};\r
- static const WCHAR szAddLocal[] = {\r
- 'A','D','D','L','O','C','A','L',0};\r
-\r
- /* I do not know if this is where it should happen.. but */\r
-\r
- TRACE("Checking Install Level\n");\r
-\r
- level = load_dynamic_property(package,szlevel,NULL);\r
- if (level)\r
- {\r
- install_level = atoiW(level);\r
- HeapFree(GetProcessHeap(), 0, level);\r
- }\r
- else\r
- install_level = 1;\r
-\r
- /* ok hereis the rub\r
- * ADDLOCAL and its friend OVERRIDE INSTALLLEVLE\r
- * I have confirmed this if ADDLOCALis stated then the INSTALLLEVEL is\r
- * itnored for all the features. seems strange, epsecially since it is not\r
- * documented anywhere, but it is how it works. \r
- */\r
- \r
- override = load_dynamic_property(package,szAddLocal,NULL);\r
- \r
- if (override)\r
- {\r
- for(i = 0; i < package->loaded_features; i++)\r
- {\r
- if (strcmpiW(override,all)==0)\r
- {\r
- package->features[i].ActionRequest= INSTALLSTATE_LOCAL;\r
- package->features[i].Action = INSTALLSTATE_LOCAL;\r
- }\r
- else\r
- {\r
- LPWSTR ptr = override;\r
- LPWSTR ptr2 = strchrW(override,',');\r
-\r
- while (ptr)\r
- {\r
- if ((ptr2 && \r
- strncmpW(ptr,package->features[i].Feature, ptr2-ptr)==0)\r
- || (!ptr2 &&\r
- strcmpW(ptr,package->features[i].Feature)==0))\r
- {\r
- package->features[i].ActionRequest= INSTALLSTATE_LOCAL;\r
- package->features[i].Action = INSTALLSTATE_LOCAL;\r
- break;\r
- }\r
- if (ptr2)\r
- {\r
- ptr=ptr2+1;\r
- ptr2 = strchrW(ptr,',');\r
- }\r
- else\r
- break;\r
- }\r
- }\r
- }\r
- HeapFree(GetProcessHeap(),0,override);\r
- } \r
- else\r
- {\r
- for(i = 0; i < package->loaded_features; i++)\r
- {\r
- BOOL feature_state= ((package->features[i].Level > 0) &&\r
- (package->features[i].Level <= install_level));\r
-\r
- if (feature_state)\r
- {\r
- package->features[i].ActionRequest= INSTALLSTATE_LOCAL;\r
- package->features[i].Action = INSTALLSTATE_LOCAL;\r
- }\r
- }\r
- }\r
-\r
- /*\r
- * now we want to enable or disable components base on feature \r
- */\r
-\r
- for(i = 0; i < package->loaded_features; i++)\r
- {\r
- MSIFEATURE* feature = &package->features[i];\r
- TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",\r
- debugstr_w(feature->Feature), feature->Installed, feature->Action,\r
- feature->ActionRequest);\r
-\r
- for( j = 0; j < feature->ComponentCount; j++)\r
- {\r
- MSICOMPONENT* component = &package->components[\r
- feature->Components[j]];\r
-\r
- if (!component->Enabled)\r
- {\r
- component->Action = INSTALLSTATE_ABSENT;\r
- component->ActionRequest = INSTALLSTATE_ABSENT;\r
- }\r
- else\r
- {\r
- if (feature->Action == INSTALLSTATE_LOCAL)\r
- component->Action = INSTALLSTATE_LOCAL;\r
- if (feature->ActionRequest == INSTALLSTATE_LOCAL)\r
- component->ActionRequest = INSTALLSTATE_LOCAL;\r
- }\r
- }\r
- } \r
-\r
- for(i = 0; i < package->loaded_components; i++)\r
- {\r
- MSICOMPONENT* component= &package->components[i];\r
-\r
- TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",\r
- debugstr_w(component->Component), component->Installed, \r
- component->Action, component->ActionRequest);\r
- }\r
-\r
-\r
- return ERROR_SUCCESS;\r
-}\r
-\r
-/* \r
- * A lot is done in this function aside from just the costing.\r
- * The costing needs to be implemented at some point but for now I am going\r
- * to focus on the directory building\r
- *\r
- */\r
-static UINT ACTION_CostFinalize(MSIPACKAGE *package)\r
-{\r
- static const WCHAR ExecSeqQuery[] = {\r
- 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',\r
- 'D','i','r','e','c','t','o','r','y',0};\r
- static const WCHAR ConditionQuery[] = {\r
- 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',\r
- 'C','o','n','d','i','t','i','o','n',0};\r
- static const WCHAR szCosting[] = {\r
- 'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };\r
- static const WCHAR szlevel[] = {\r
- 'I','N','S','T','A','L','L','L','E','V','E','L',0};\r
- static const WCHAR szOne[] = { '1', 0 };\r
- UINT rc;\r
- MSIQUERY * view;\r
- DWORD i;\r
- LPWSTR level;\r
-\r
- TRACE("Building Directory properties\n");\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);\r
- if (rc == ERROR_SUCCESS)\r
- {\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
-\r
- while (1)\r
- {\r
- WCHAR name[0x100];\r
- LPWSTR path;\r
- MSIRECORD * row = 0;\r
- DWORD sz;\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
-\r
- sz=0x100;\r
- MSI_RecordGetStringW(row,1,name,&sz);\r
-\r
- /* This helper function now does ALL the work */\r
- TRACE("Dir %s ...\n",debugstr_w(name));\r
- load_folder(package,name);\r
- path = resolve_folder(package,name,FALSE,TRUE,NULL);\r
- TRACE("resolves to %s\n",debugstr_w(path));\r
- HeapFree( GetProcessHeap(), 0, path);\r
-\r
- msiobj_release(&row->hdr);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- }\r
-\r
- TRACE("File calculations %i files\n",package->loaded_files);\r
-\r
- for (i = 0; i < package->loaded_files; i++)\r
- {\r
- MSICOMPONENT* comp = NULL;\r
- MSIFILE* file= NULL;\r
-\r
- file = &package->files[i];\r
- if (file->ComponentIndex >= 0)\r
- comp = &package->components[file->ComponentIndex];\r
-\r
- if (file->Temporary == TRUE)\r
- continue;\r
-\r
- if (comp)\r
- {\r
- LPWSTR p;\r
-\r
- /* calculate target */\r
- p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);\r
-\r
- HeapFree(GetProcessHeap(),0,file->TargetPath);\r
-\r
- TRACE("file %s is named %s\n",\r
- debugstr_w(file->File),debugstr_w(file->FileName)); \r
-\r
- file->TargetPath = build_directory_name(2, p, file->FileName);\r
-\r
- HeapFree(GetProcessHeap(),0,p);\r
-\r
- TRACE("file %s resolves to %s\n",\r
- debugstr_w(file->File),debugstr_w(file->TargetPath)); \r
-\r
- if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)\r
- {\r
- file->State = 1;\r
- comp->Cost += file->FileSize;\r
- }\r
- else\r
- {\r
- if (file->Version)\r
- {\r
- DWORD handle;\r
- DWORD versize;\r
- UINT sz;\r
- LPVOID version;\r
- static const WCHAR name[] = \r
- {'\\',0};\r
- static const WCHAR name_fmt[] = \r
- {'%','u','.','%','u','.','%','u','.','%','u',0};\r
- WCHAR filever[0x100];\r
- VS_FIXEDFILEINFO *lpVer;\r
-\r
- TRACE("Version comparison.. \n");\r
- versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);\r
- version = HeapAlloc(GetProcessHeap(),0,versize);\r
- GetFileVersionInfoW(file->TargetPath, 0, versize, version);\r
-\r
- VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);\r
-\r
- sprintfW(filever,name_fmt,\r
- HIWORD(lpVer->dwFileVersionMS),\r
- LOWORD(lpVer->dwFileVersionMS),\r
- HIWORD(lpVer->dwFileVersionLS),\r
- LOWORD(lpVer->dwFileVersionLS));\r
-\r
- TRACE("new %s old %s\n", debugstr_w(file->Version),\r
- debugstr_w(filever));\r
- if (strcmpiW(filever,file->Version)<0)\r
- {\r
- file->State = 2;\r
- FIXME("cost should be diff in size\n");\r
- comp->Cost += file->FileSize;\r
- }\r
- else\r
- file->State = 3;\r
- HeapFree(GetProcessHeap(),0,version);\r
- }\r
- else\r
- file->State = 3;\r
- }\r
- } \r
- }\r
-\r
- TRACE("Evaluating Condition Table\n");\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);\r
- if (rc == ERROR_SUCCESS)\r
- {\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
- \r
- while (1)\r
- {\r
- WCHAR Feature[0x100];\r
- MSIRECORD * row = 0;\r
- DWORD sz;\r
- int feature_index;\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
-\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
-\r
- sz = 0x100;\r
- MSI_RecordGetStringW(row,1,Feature,&sz);\r
-\r
- feature_index = get_loaded_feature(package,Feature);\r
- if (feature_index < 0)\r
- ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature));\r
- else\r
- {\r
- LPWSTR Condition;\r
- Condition = load_dynamic_stringW(row,3);\r
-\r
- if (MSI_EvaluateConditionW(package,Condition) == \r
- MSICONDITION_TRUE)\r
- {\r
- int level = MSI_RecordGetInteger(row,2);\r
- TRACE("Reseting feature %s to level %i\n",\r
- debugstr_w(Feature), level);\r
- package->features[feature_index].Level = level;\r
- }\r
- HeapFree(GetProcessHeap(),0,Condition);\r
- }\r
-\r
- msiobj_release(&row->hdr);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- }\r
-\r
- TRACE("Enabling or Disabling Components\n");\r
- for (i = 0; i < package->loaded_components; i++)\r
- {\r
- if (package->components[i].Condition[0])\r
- {\r
- if (MSI_EvaluateConditionW(package,\r
- package->components[i].Condition) == MSICONDITION_FALSE)\r
- {\r
- TRACE("Disabling component %s\n",\r
- debugstr_w(package->components[i].Component));\r
- package->components[i].Enabled = FALSE;\r
- }\r
- }\r
- }\r
-\r
- MSI_SetPropertyW(package,szCosting,szOne);\r
- /* set default run level if not set */\r
- level = load_dynamic_property(package,szlevel,NULL);\r
- if (!level)\r
- MSI_SetPropertyW(package,szlevel, szOne);\r
- else\r
- HeapFree(GetProcessHeap(),0,level);\r
-\r
- return SetFeatureStates(package);\r
-\r
-}\r
-\r
-/*\r
- * This is a helper function for handling embedded cabinet media\r
- */\r
-static UINT writeout_cabinet_stream(MSIPACKAGE *package, WCHAR* stream_name,\r
- WCHAR* source)\r
-{\r
- UINT rc;\r
- USHORT* data;\r
- UINT size;\r
- DWORD write;\r
- HANDLE the_file;\r
- WCHAR tmp[MAX_PATH];\r
-\r
- rc = read_raw_stream_data(package->db,stream_name,&data,&size); \r
- if (rc != ERROR_SUCCESS)\r
- return rc;\r
-\r
- write = MAX_PATH;\r
- if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))\r
- GetTempPathW(MAX_PATH,tmp);\r
-\r
- GetTempFileNameW(tmp,stream_name,0,source);\r
-\r
- track_tempfile(package,strrchrW(source,'\\'), source);\r
- the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,\r
- FILE_ATTRIBUTE_NORMAL, NULL);\r
-\r
- if (the_file == INVALID_HANDLE_VALUE)\r
- {\r
- rc = ERROR_FUNCTION_FAILED;\r
- goto end;\r
- }\r
-\r
- WriteFile(the_file,data,size,&write,NULL);\r
- CloseHandle(the_file);\r
- TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));\r
-end:\r
- HeapFree(GetProcessHeap(),0,data);\r
- return rc;\r
-}\r
-\r
-\r
-/* Support functions for FDI functions */\r
-typedef struct\r
-{\r
- MSIPACKAGE* package;\r
- LPCSTR cab_path;\r
- LPCSTR file_name;\r
-} CabData;\r
-\r
-static void * cabinet_alloc(ULONG cb)\r
-{\r
- return HeapAlloc(GetProcessHeap(), 0, cb);\r
-}\r
-\r
-static void cabinet_free(void *pv)\r
-{\r
- HeapFree(GetProcessHeap(), 0, pv);\r
-}\r
-\r
-static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)\r
-{\r
- DWORD dwAccess = 0;\r
- DWORD dwShareMode = 0;\r
- DWORD dwCreateDisposition = OPEN_EXISTING;\r
- switch (oflag & _O_ACCMODE)\r
- {\r
- case _O_RDONLY:\r
- dwAccess = GENERIC_READ;\r
- dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;\r
- break;\r
- case _O_WRONLY:\r
- dwAccess = GENERIC_WRITE;\r
- dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;\r
- break;\r
- case _O_RDWR:\r
- dwAccess = GENERIC_READ | GENERIC_WRITE;\r
- dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;\r
- break;\r
- }\r
- if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))\r
- dwCreateDisposition = CREATE_NEW;\r
- else if (oflag & _O_CREAT)\r
- dwCreateDisposition = CREATE_ALWAYS;\r
- return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL, dwCreateDisposition, 0, NULL);\r
-}\r
-\r
-static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)\r
-{\r
- DWORD dwRead;\r
- if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL))\r
- return dwRead;\r
- return 0;\r
-}\r
-\r
-static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)\r
-{\r
- DWORD dwWritten;\r
- if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL))\r
- return dwWritten;\r
- return 0;\r
-}\r
-\r
-static int cabinet_close(INT_PTR hf)\r
-{\r
- return CloseHandle((HANDLE)hf) ? 0 : -1;\r
-}\r
-\r
-static long cabinet_seek(INT_PTR hf, long dist, int seektype)\r
-{\r
- /* flags are compatible and so are passed straight through */\r
- return SetFilePointer((HANDLE)hf, dist, NULL, seektype);\r
-}\r
-\r
-static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)\r
-{\r
- /* FIXME: try to do more processing in this function */\r
- switch (fdint)\r
- {\r
- case fdintCOPY_FILE:\r
- {\r
- CabData *data = (CabData*) pfdin->pv;\r
- ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);\r
- char *file;\r
-\r
- LPWSTR trackname;\r
- LPWSTR trackpath;\r
- LPWSTR tracknametmp;\r
- static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};\r
- \r
- if (data->file_name && strcmp(data->file_name,pfdin->psz1))\r
- return 0;\r
- \r
- file = cabinet_alloc((len+1)*sizeof(char));\r
- strcpy(file, data->cab_path);\r
- strcat(file, pfdin->psz1);\r
-\r
- TRACE("file: %s\n", debugstr_a(file));\r
-\r
- /* track this file so it can be deleted if not installed */\r
- trackpath=strdupAtoW(file);\r
- tracknametmp=strdupAtoW(strrchr(file,'\\')+1);\r
- trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) + \r
- strlenW(tmpprefix)+1) * sizeof(WCHAR));\r
-\r
- strcpyW(trackname,tmpprefix);\r
- strcatW(trackname,tracknametmp);\r
-\r
- track_tempfile(data->package, trackname, trackpath);\r
-\r
- HeapFree(GetProcessHeap(),0,trackpath);\r
- HeapFree(GetProcessHeap(),0,trackname);\r
- HeapFree(GetProcessHeap(),0,tracknametmp);\r
-\r
- return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);\r
- }\r
- case fdintCLOSE_FILE_INFO:\r
- {\r
- FILETIME ft;\r
- FILETIME ftLocal;\r
- if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))\r
- return -1;\r
- if (!LocalFileTimeToFileTime(&ft, &ftLocal))\r
- return -1;\r
- if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal))\r
- return -1;\r
-\r
- cabinet_close(pfdin->hf);\r
- return 1;\r
- }\r
- default:\r
- return 0;\r
- }\r
-}\r
-\r
-/***********************************************************************\r
- * extract_cabinet_file\r
- *\r
- * Extract files from a cab file.\r
- */\r
-static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source, \r
- const WCHAR* path, const WCHAR* file)\r
-{\r
- HFDI hfdi;\r
- ERF erf;\r
- BOOL ret;\r
- char *cabinet;\r
- char *cab_path;\r
- char *file_name;\r
- CabData data;\r
-\r
- TRACE("Extracting %s (%s) to %s\n",debugstr_w(source), \r
- debugstr_w(file), debugstr_w(path));\r
-\r
- hfdi = FDICreate(cabinet_alloc,\r
- cabinet_free,\r
- cabinet_open,\r
- cabinet_read,\r
- cabinet_write,\r
- cabinet_close,\r
- cabinet_seek,\r
- 0,\r
- &erf);\r
- if (!hfdi)\r
- {\r
- ERR("FDICreate failed\n");\r
- return FALSE;\r
- }\r
-\r
- if (!(cabinet = strdupWtoA( source )))\r
- {\r
- FDIDestroy(hfdi);\r
- return FALSE;\r
- }\r
- if (!(cab_path = strdupWtoA( path )))\r
- {\r
- FDIDestroy(hfdi);\r
- HeapFree(GetProcessHeap(), 0, cabinet);\r
- return FALSE;\r
- }\r
-\r
- data.package = package;\r
- data.cab_path = cab_path;\r
- if (file)\r
- file_name = strdupWtoA(file);\r
- else\r
- file_name = NULL;\r
- data.file_name = file_name;\r
-\r
- ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);\r
-\r
- if (!ret)\r
- ERR("FDICopy failed\n");\r
-\r
- FDIDestroy(hfdi);\r
-\r
- HeapFree(GetProcessHeap(), 0, cabinet);\r
- HeapFree(GetProcessHeap(), 0, cab_path);\r
- HeapFree(GetProcessHeap(), 0, file_name);\r
-\r
- return ret;\r
-}\r
-\r
-static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence, \r
- WCHAR* path, WCHAR* file)\r
-{\r
- UINT rc;\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- static WCHAR source[MAX_PATH];\r
- static const WCHAR ExecSeqQuery[] = {\r
- 's','e','l','e','c','t',' ','*',' ',\r
- 'f','r','o','m',' ','M','e','d','i','a',' ',\r
- 'w','h','e','r','e',' ','L','a','s','t','S','e','q','u','e','n','c','e',' ','>','=',' ','%','i',' ',\r
- 'o','r','d','e','r',' ','b','y',' ','L','a','s','t','S','e','q','u','e','n','c','e',0};\r
- WCHAR Query[1024];\r
- WCHAR cab[0x100];\r
- DWORD sz=0x100;\r
- INT seq;\r
- static UINT last_sequence = 0; \r
-\r
- if (sequence <= last_sequence)\r
- {\r
- TRACE("Media already ready (%u, %u)\n",sequence,last_sequence);\r
- /*extract_a_cabinet_file(package, source,path,file); */\r
- return ERROR_SUCCESS;\r
- }\r
-\r
- sprintfW(Query,ExecSeqQuery,sequence);\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, Query, &view);\r
- if (rc != ERROR_SUCCESS)\r
- return rc;\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
- seq = MSI_RecordGetInteger(row,2);\r
- last_sequence = seq;\r
-\r
- if (!MSI_RecordIsNull(row,4))\r
- {\r
- sz=0x100;\r
- MSI_RecordGetStringW(row,4,cab,&sz);\r
- TRACE("Source is CAB %s\n",debugstr_w(cab));\r
- /* the stream does not contain the # character */\r
- if (cab[0]=='#')\r
- {\r
- writeout_cabinet_stream(package,&cab[1],source);\r
- strcpyW(path,source);\r
- *(strrchrW(path,'\\')+1)=0;\r
- }\r
- else\r
- {\r
- sz = MAX_PATH;\r
- if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))\r
- {\r
- ERR("No Source dir defined \n");\r
- rc = ERROR_FUNCTION_FAILED;\r
- }\r
- else\r
- {\r
- strcpyW(path,source);\r
- strcatW(source,cab);\r
- /* extract the cab file into a folder in the temp folder */\r
- sz = MAX_PATH;\r
- if (MSI_GetPropertyW(package, cszTempFolder,path, &sz) \r
- != ERROR_SUCCESS)\r
- GetTempPathW(MAX_PATH,path);\r
- }\r
- }\r
- rc = !extract_a_cabinet_file(package, source,path,NULL);\r
- }\r
- else\r
- {\r
- sz = MAX_PATH;\r
- MSI_GetPropertyW(package,cszSourceDir,source,&sz);\r
- strcpyW(path,source);\r
- }\r
- msiobj_release(&row->hdr);\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
-}\r
-\r
-inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)\r
-{\r
- UINT rc = ERROR_SUCCESS;\r
- MSIFOLDER *folder;\r
- LPWSTR install_path;\r
-\r
- install_path = resolve_folder(package, package->components[component].Directory,\r
- FALSE, FALSE, &folder);\r
- if (!install_path)\r
- return ERROR_FUNCTION_FAILED; \r
-\r
- /* create the path */\r
- if (folder->State == 0)\r
- {\r
- create_full_pathW(install_path);\r
- folder->State = 2;\r
- }\r
- HeapFree(GetProcessHeap(), 0, install_path);\r
-\r
- return rc;\r
-}\r
-\r
-static UINT ACTION_InstallFiles(MSIPACKAGE *package)\r
-{\r
- UINT rc = ERROR_SUCCESS;\r
- DWORD index;\r
- MSIRECORD * uirow;\r
- WCHAR uipath[MAX_PATH];\r
-\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- /* increment progress bar each time action data is sent */\r
- ui_progress(package,1,1,0,0);\r
-\r
- for (index = 0; index < package->loaded_files; index++)\r
- {\r
- WCHAR path_to_source[MAX_PATH];\r
- MSIFILE *file;\r
- \r
- file = &package->files[index];\r
-\r
- if (file->Temporary)\r
- continue;\r
-\r
- if (package->components[file->ComponentIndex].ActionRequest != \r
- INSTALLSTATE_LOCAL)\r
- {\r
- ui_progress(package,2,file->FileSize,0,0);\r
- TRACE("File %s is not scheduled for install\n",\r
- debugstr_w(file->File));\r
-\r
- continue;\r
- }\r
-\r
- if ((file->State == 1) || (file->State == 2))\r
- {\r
- LPWSTR p;\r
- INT len;\r
- MSICOMPONENT* comp = NULL;\r
-\r
- TRACE("Installing %s\n",debugstr_w(file->File));\r
- rc = ready_media_for_file(package,file->Sequence,path_to_source,\r
- file->File);\r
- /* \r
- * WARNING!\r
- * our file table could change here because a new temp file\r
- * may have been created\r
- */\r
- file = &package->files[index];\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- ERR("Unable to ready media\n");\r
- rc = ERROR_FUNCTION_FAILED;\r
- break;\r
- }\r
-\r
- create_component_directory( package, file->ComponentIndex);\r
-\r
- /* recalculate file paths because things may have changed */\r
-\r
- if (file->ComponentIndex >= 0)\r
- comp = &package->components[file->ComponentIndex];\r
-\r
- p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);\r
- HeapFree(GetProcessHeap(),0,file->TargetPath);\r
-\r
- file->TargetPath = build_directory_name(2, p, file->FileName);\r
-\r
- len = strlenW(path_to_source) + strlenW(file->File) + 2;\r
- file->SourcePath = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));\r
- strcpyW(file->SourcePath, path_to_source);\r
- strcatW(file->SourcePath, file->File);\r
-\r
- TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),\r
- debugstr_w(file->TargetPath));\r
-\r
- /* the UI chunk */\r
- uirow=MSI_CreateRecord(9);\r
- MSI_RecordSetStringW(uirow,1,file->File);\r
- strcpyW(uipath,file->TargetPath);\r
- *(strrchrW(uipath,'\\')+1)=0;\r
- MSI_RecordSetStringW(uirow,9,uipath);\r
- MSI_RecordSetInteger(uirow,6,file->FileSize);\r
- ui_actiondata(package,szInstallFiles,uirow);\r
- msiobj_release( &uirow->hdr );\r
- ui_progress(package,2,file->FileSize,0,0);\r
-\r
- if (!MoveFileW(file->SourcePath,file->TargetPath))\r
- {\r
- rc = GetLastError();\r
- ERR("Unable to move file (%s -> %s) (error %d)\n",\r
- debugstr_w(file->SourcePath), debugstr_w(file->TargetPath),\r
- rc);\r
- if (rc == ERROR_ALREADY_EXISTS && file->State == 2)\r
- {\r
- CopyFileW(file->SourcePath,file->TargetPath,FALSE);\r
- DeleteFileW(file->SourcePath);\r
- rc = 0;\r
- }\r
- else if (rc == ERROR_FILE_NOT_FOUND)\r
- {\r
- ERR("Source File Not Found! Continueing\n");\r
- rc = 0;\r
- }\r
- else\r
- {\r
- ERR("Ignoring Error and continuing...\n");\r
- rc = 0;\r
- }\r
- }\r
- else\r
- file->State = 4;\r
- }\r
- }\r
-\r
- return rc;\r
-}\r
-\r
-inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, \r
- LPWSTR* file_source)\r
-{\r
- DWORD index;\r
-\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- for (index = 0; index < package->loaded_files; index ++)\r
- {\r
- if (strcmpW(file_key,package->files[index].File)==0)\r
- {\r
- if (package->files[index].State >= 2)\r
- {\r
- *file_source = dupstrW(package->files[index].TargetPath);\r
- return ERROR_SUCCESS;\r
- }\r
- else\r
- return ERROR_FILE_NOT_FOUND;\r
- }\r
- }\r
-\r
- return ERROR_FUNCTION_FAILED;\r
-}\r
-\r
-static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)\r
-{\r
- UINT rc;\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- static const WCHAR ExecSeqQuery[] = {\r
- 's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ',\r
- 'D','u','p','l','i','c','a','t','e','F','i','l','e',0};\r
-\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);\r
- if (rc != ERROR_SUCCESS)\r
- return ERROR_SUCCESS;\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
-\r
- while (1)\r
- {\r
- WCHAR file_key[0x100];\r
- WCHAR *file_source = NULL;\r
- WCHAR dest_name[0x100];\r
- LPWSTR dest_path, dest;\r
- WCHAR component[0x100];\r
- INT component_index;\r
-\r
- DWORD sz=0x100;\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
-\r
- sz=0x100;\r
- rc = MSI_RecordGetStringW(row,2,component,&sz);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- ERR("Unable to get component\n");\r
- msiobj_release(&row->hdr);\r
- break;\r
- }\r
-\r
- component_index = get_loaded_component(package,component);\r
- if (package->components[component_index].ActionRequest != \r
- INSTALLSTATE_LOCAL)\r
- {\r
- TRACE("Skipping copy due to disabled component\n");\r
-\r
- /* the action taken was the same as the current install state */ \r
- package->components[component_index].Action =\r
- package->components[component_index].Installed;\r
-\r
- msiobj_release(&row->hdr);\r
- continue;\r
- }\r
-\r
- package->components[component_index].Action = INSTALLSTATE_LOCAL;\r
- package->components[component_index].Installed = INSTALLSTATE_LOCAL;\r
-\r
- sz=0x100;\r
- rc = MSI_RecordGetStringW(row,3,file_key,&sz);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- ERR("Unable to get file key\n");\r
- msiobj_release(&row->hdr);\r
- break;\r
- }\r
-\r
- rc = get_file_target(package,file_key,&file_source);\r
-\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- ERR("Original file unknown %s\n",debugstr_w(file_key));\r
- msiobj_release(&row->hdr);\r
- HeapFree(GetProcessHeap(),0,file_source);\r
- continue;\r
- }\r
-\r
- if (MSI_RecordIsNull(row,4))\r
- {\r
- strcpyW(dest_name,strrchrW(file_source,'\\')+1);\r
- }\r
- else\r
- {\r
- sz=0x100;\r
- MSI_RecordGetStringW(row,4,dest_name,&sz);\r
- reduce_to_longfilename(dest_name);\r
- }\r
-\r
- if (MSI_RecordIsNull(row,5))\r
- {\r
- LPWSTR p;\r
- dest_path = dupstrW(file_source);\r
- p = strrchrW(dest_path,'\\');\r
- if (p)\r
- *p=0;\r
- }\r
- else\r
- {\r
- WCHAR destkey[0x100];\r
- sz=0x100;\r
- MSI_RecordGetStringW(row,5,destkey,&sz);\r
- sz = 0x100;\r
- dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);\r
- if (!dest_path)\r
- {\r
- ERR("Unable to get destination folder\n");\r
- msiobj_release(&row->hdr);\r
- HeapFree(GetProcessHeap(),0,file_source);\r
- break;\r
- }\r
- }\r
-\r
- dest = build_directory_name(2, dest_path, dest_name);\r
- HeapFree(GetProcessHeap(), 0, dest_path);\r
- \r
- TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),\r
- debugstr_w(dest)); \r
- \r
- if (strcmpW(file_source,dest))\r
- rc = !CopyFileW(file_source,dest,TRUE);\r
- else\r
- rc = ERROR_SUCCESS;\r
- \r
- if (rc != ERROR_SUCCESS)\r
- ERR("Failed to copy file\n");\r
-\r
- FIXME("We should track these duplicate files as well\n"); \r
- \r
- msiobj_release(&row->hdr);\r
- HeapFree(GetProcessHeap(),0,dest);\r
- HeapFree(GetProcessHeap(),0,file_source);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
-}\r
-\r
-\r
-/* OK this value is "interpreted" and then formatted based on the \r
- first few characters */\r
-static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type, \r
- DWORD *size)\r
-{\r
- LPSTR data = NULL;\r
- if (value[0]=='#' && value[1]!='#' && value[1]!='%')\r
- {\r
- if (value[1]=='x')\r
- {\r
- LPWSTR ptr;\r
- CHAR byte[5];\r
- LPWSTR deformated;\r
- int count;\r
-\r
- deformat_string(package, &value[2], &deformated);\r
-\r
- /* binary value type */\r
- ptr = deformated; \r
- *type=REG_BINARY;\r
- *size = strlenW(ptr)/2;\r
- data = HeapAlloc(GetProcessHeap(),0,*size);\r
- \r
- byte[0] = '0'; \r
- byte[1] = 'x'; \r
- byte[4] = 0; \r
- count = 0;\r
- while (*ptr)\r
- {\r
- byte[2]= *ptr;\r
- ptr++;\r
- byte[3]= *ptr;\r
- ptr++;\r
- data[count] = (BYTE)strtol(byte,NULL,0);\r
- count ++;\r
- }\r
- HeapFree(GetProcessHeap(),0,deformated);\r
-\r
- TRACE("Data %li bytes(%i)\n",*size,count);\r
- }\r
- else\r
- {\r
- LPWSTR deformated;\r
- deformat_string(package, &value[1], &deformated);\r
-\r
- *type=REG_DWORD; \r
- *size = sizeof(DWORD);\r
- data = HeapAlloc(GetProcessHeap(),0,*size);\r
- *(LPDWORD)data = atoiW(deformated); \r
- TRACE("DWORD %i\n",*data);\r
-\r
- HeapFree(GetProcessHeap(),0,deformated);\r
- }\r
- }\r
- else\r
- {\r
- static const WCHAR szMulti[] = {'[','~',']',0};\r
- WCHAR *ptr;\r
- *type=REG_SZ;\r
-\r
- if (value[0]=='#')\r
- {\r
- if (value[1]=='%')\r
- {\r
- ptr = &value[2];\r
- *type=REG_EXPAND_SZ;\r
- }\r
- else\r
- ptr = &value[1];\r
- }\r
- else\r
- ptr=value;\r
-\r
- if (strstrW(value,szMulti))\r
- *type = REG_MULTI_SZ;\r
-\r
- *size = deformat_string(package, ptr,(LPWSTR*)&data);\r
- }\r
- return data;\r
-}\r
-\r
-static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)\r
-{\r
- UINT rc;\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- static const WCHAR ExecSeqQuery[] = {\r
- 's','e','l','e','c','t',' ','*',' ',\r
- 'f','r','o','m',' ','R','e','g','i','s','t','r','y',0 };\r
-\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);\r
- if (rc != ERROR_SUCCESS)\r
- return ERROR_SUCCESS;\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
-\r
- /* increment progress bar each time action data is sent */\r
- ui_progress(package,1,REG_PROGRESS_VALUE,1,0);\r
-\r
- while (1)\r
- {\r
- static const WCHAR szHCR[] = \r
-{'H','K','E','Y','_','C','L','A','S','S','E','S','_','R','O','O','T','\\',0};\r
- static const WCHAR szHCU[] =\r
-{'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R','\\',0};\r
- static const WCHAR szHLM[] =\r
-{'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E',\r
-'\\',0};\r
- static const WCHAR szHU[] =\r
-{'H','K','E','Y','_','U','S','E','R','S','\\',0};\r
-\r
- LPSTR value_data = NULL;\r
- HKEY root_key, hkey;\r
- DWORD type,size;\r
- LPWSTR value, key, name, component, deformated;\r
- LPCWSTR szRoot;\r
- INT component_index;\r
- MSIRECORD * uirow;\r
- LPWSTR uikey;\r
- INT root;\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
- ui_progress(package,2,0,0,0);\r
-\r
- value = NULL;\r
- key = NULL;\r
- uikey = NULL;\r
- name = NULL;\r
-\r
- component = load_dynamic_stringW(row, 6);\r
- component_index = get_loaded_component(package,component);\r
-\r
- if (package->components[component_index].ActionRequest != \r
- INSTALLSTATE_LOCAL)\r
- {\r
- TRACE("Skipping write due to disabled component\n");\r
- msiobj_release(&row->hdr);\r
-\r
- package->components[component_index].Action =\r
- package->components[component_index].Installed;\r
-\r
- goto next;\r
- }\r
-\r
- package->components[component_index].Action = INSTALLSTATE_LOCAL;\r
- package->components[component_index].Installed = INSTALLSTATE_LOCAL;\r
-\r
- /* null values have special meanings during uninstalls and such */\r
- \r
- if(MSI_RecordIsNull(row,5))\r
- {\r
- msiobj_release(&row->hdr);\r
- goto next;\r
- }\r
-\r
- root = MSI_RecordGetInteger(row,2);\r
- key = load_dynamic_stringW(row, 3);\r
- \r
- name = load_dynamic_stringW(row, 4);\r
- \r
- /* get the root key */\r
- switch (root)\r
- {\r
- case 0: root_key = HKEY_CLASSES_ROOT; \r
- szRoot = szHCR;\r
- break;\r
- case 1: root_key = HKEY_CURRENT_USER;\r
- szRoot = szHCU;\r
- break;\r
- case 2: root_key = HKEY_LOCAL_MACHINE;\r
- szRoot = szHLM;\r
- break;\r
- case 3: root_key = HKEY_USERS; \r
- szRoot = szHU;\r
- break;\r
- default:\r
- ERR("Unknown root %i\n",root);\r
- root_key=NULL;\r
- szRoot = NULL;\r
- break;\r
- }\r
- if (!root_key)\r
- {\r
- msiobj_release(&row->hdr);\r
- goto next;\r
- }\r
-\r
- deformat_string(package, key , &deformated);\r
- size = strlenW(deformated) + strlenW(szRoot) + 1;\r
- uikey = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));\r
- strcpyW(uikey,szRoot);\r
- strcatW(uikey,deformated);\r
-\r
- if (RegCreateKeyW( root_key, deformated, &hkey))\r
- {\r
- ERR("Could not create key %s\n",debugstr_w(deformated));\r
- msiobj_release(&row->hdr);\r
- HeapFree(GetProcessHeap(),0,deformated);\r
- goto next;\r
- }\r
- HeapFree(GetProcessHeap(),0,deformated);\r
-\r
- value = load_dynamic_stringW(row,5);\r
- value_data = parse_value(package, value, &type, &size); \r
-\r
- deformat_string(package, name, &deformated);\r
-\r
- if (value_data)\r
- {\r
- TRACE("Setting value %s\n",debugstr_w(deformated));\r
- RegSetValueExW(hkey, deformated, 0, type, value_data, size);\r
-\r
- uirow = MSI_CreateRecord(3);\r
- MSI_RecordSetStringW(uirow,2,deformated);\r
- MSI_RecordSetStringW(uirow,1,uikey);\r
-\r
- if (type == REG_SZ)\r
- MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);\r
- else\r
- MSI_RecordSetStringW(uirow,3,value);\r
-\r
- ui_actiondata(package,szWriteRegistryValues,uirow);\r
- msiobj_release( &uirow->hdr );\r
-\r
- HeapFree(GetProcessHeap(),0,value_data);\r
- }\r
- HeapFree(GetProcessHeap(),0,value);\r
- HeapFree(GetProcessHeap(),0,deformated);\r
-\r
- msiobj_release(&row->hdr);\r
- RegCloseKey(hkey);\r
-next:\r
- HeapFree(GetProcessHeap(),0,uikey);\r
- HeapFree(GetProcessHeap(),0,key);\r
- HeapFree(GetProcessHeap(),0,name);\r
- HeapFree(GetProcessHeap(),0,component);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
-}\r
-\r
-static UINT ACTION_InstallInitialize(MSIPACKAGE *package)\r
-{\r
- return ERROR_SUCCESS;\r
-}\r
-\r
-\r
-static UINT ACTION_InstallValidate(MSIPACKAGE *package)\r
-{\r
- DWORD progress = 0;\r
- DWORD total = 0;\r
- static const WCHAR q1[]={\r
- 'S','E','L','E','C','T',' ','*',' ',\r
- 'F','R','O','M',' ','R','e','g','i','s','t','r','y',0};\r
- UINT rc;\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- int i;\r
-\r
- TRACE(" InstallValidate \n");\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, q1, &view);\r
- if (rc != ERROR_SUCCESS)\r
- return ERROR_SUCCESS;\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
- while (1)\r
- {\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
- progress +=1;\r
-\r
- msiobj_release(&row->hdr);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
-\r
- total = total + progress * REG_PROGRESS_VALUE;\r
- total = total + package->loaded_components * COMPONENT_PROGRESS_VALUE;\r
- for (i=0; i < package->loaded_files; i++)\r
- total += package->files[i].FileSize;\r
- ui_progress(package,0,total,0,0);\r
-\r
- return ERROR_SUCCESS;\r
-}\r
-\r
-static UINT ACTION_LaunchConditions(MSIPACKAGE *package)\r
-{\r
- UINT rc;\r
- MSIQUERY * view = NULL;\r
- MSIRECORD * row = 0;\r
- static const WCHAR ExecSeqQuery[] = {\r
- 'S','E','L','E','C','T',' ','*',' ',\r
- 'f','r','o','m',' ','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n',0};\r
- static const WCHAR title[]=\r
- {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};\r
-\r
- TRACE("Checking launch conditions\n");\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);\r
- if (rc != ERROR_SUCCESS)\r
- return ERROR_SUCCESS;\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
-\r
- rc = ERROR_SUCCESS;\r
- while (rc == ERROR_SUCCESS)\r
- {\r
- LPWSTR cond = NULL; \r
- LPWSTR message = NULL;\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
-\r
- cond = load_dynamic_stringW(row,1);\r
-\r
- if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)\r
- {\r
- LPWSTR deformated;\r
- message = load_dynamic_stringW(row,2);\r
- deformat_string(package,message,&deformated); \r
- MessageBoxW(NULL,deformated,title,MB_OK);\r
- HeapFree(GetProcessHeap(),0,message);\r
- HeapFree(GetProcessHeap(),0,deformated);\r
- rc = ERROR_FUNCTION_FAILED;\r
- }\r
- HeapFree(GetProcessHeap(),0,cond);\r
- msiobj_release(&row->hdr);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
-}\r
-\r
-static LPWSTR resolve_keypath( MSIPACKAGE* package, INT\r
- component_index)\r
-{\r
- MSICOMPONENT* cmp = &package->components[component_index];\r
-\r
- if (cmp->KeyPath[0]==0)\r
- {\r
- LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);\r
- return p;\r
- }\r
- if (cmp->Attributes & 0x4)\r
- {\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- UINT rc,root,len;\r
- LPWSTR key,deformated,buffer,name,deformated_name;\r
- static const WCHAR ExecSeqQuery[] = {\r
- 's','e','l','e','c','t',' ','*',' ',\r
- 'f','r','o','m',' ','R','e','g','i','s','t','r','y',' ',\r
-'w','h','e','r','e',' ','R','e','g','i','s','t','r','y',' ','=',' '\r
-,'`','%','s','`',0 };\r
- static const WCHAR fmt[]={'%','0','2','i',':','%','s',0};\r
- static const WCHAR fmt2[]={'%','0','2','i',':','%','s','\\','%','s',0};\r
-\r
- rc = MSI_OpenQuery(package->db,&view,ExecSeqQuery,cmp->KeyPath);\r
-\r
- if (rc!=ERROR_SUCCESS)\r
- return NULL;\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return NULL;\r
- }\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return NULL;\r
- }\r
-\r
- root = MSI_RecordGetInteger(row,2);\r
- key = load_dynamic_stringW(row, 3);\r
- name = load_dynamic_stringW(row, 4);\r
- deformat_string(package, key , &deformated);\r
- deformat_string(package, name, &deformated_name);\r
-\r
- len = strlenW(deformated) + 5;\r
- if (deformated_name)\r
- len+=strlenW(deformated_name);\r
-\r
- buffer = HeapAlloc(GetProcessHeap(),0, len *sizeof(WCHAR));\r
-\r
- if (deformated_name)\r
- sprintfW(buffer,fmt2,root,deformated,deformated_name);\r
- else\r
- sprintfW(buffer,fmt,root,deformated);\r
-\r
- HeapFree(GetProcessHeap(),0,key);\r
- HeapFree(GetProcessHeap(),0,deformated);\r
- HeapFree(GetProcessHeap(),0,name);\r
- HeapFree(GetProcessHeap(),0,deformated_name);\r
- msiobj_release(&row->hdr);\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
-\r
- return buffer;\r
- }\r
- else if (cmp->Attributes & 0x20)\r
- {\r
- FIXME("UNIMPLEMENTED keypath as ODBC Source\n");\r
- return NULL;\r
- }\r
- else\r
- {\r
- int j;\r
- j = get_loaded_file(package,cmp->KeyPath);\r
-\r
- if (j>=0)\r
- {\r
- LPWSTR p = dupstrW(package->files[j].TargetPath);\r
- return p;\r
- }\r
- }\r
- return NULL;\r
-}\r
-\r
-/*\r
- * Ok further analysis makes me think that this work is\r
- * actually done in the PublishComponents and PublishFeatures\r
- * step, and not here. It appears like the keypath and all that is\r
- * resolved in this step, however actually written in the Publish steps.\r
- * But we will leave it here for now because it is unclear\r
- */\r
-static UINT ACTION_ProcessComponents(MSIPACKAGE *package)\r
-{\r
- LPWSTR productcode;\r
- WCHAR squished_pc[GUID_SIZE];\r
- WCHAR squished_cc[GUID_SIZE];\r
- UINT rc;\r
- DWORD i;\r
- HKEY hkey=0,hkey2=0;\r
- static const WCHAR szProductCode[]=\r
- {'P','r','o','d','u','c','t','C','o','d','e',0};\r
-\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- /* writes the Component and Features values to the registry */\r
- productcode = load_dynamic_property(package,szProductCode,&rc);\r
- if (!productcode)\r
- return rc;\r
-\r
- rc = MSIREG_OpenComponents(&hkey);\r
- if (rc != ERROR_SUCCESS)\r
- goto end;\r
- \r
- squash_guid(productcode,squished_pc);\r
- ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);\r
- for (i = 0; i < package->loaded_components; i++)\r
- {\r
- ui_progress(package,2,0,0,0);\r
- if (package->components[i].ComponentId[0]!=0)\r
- {\r
- WCHAR *keypath = NULL;\r
- MSIRECORD * uirow;\r
-\r
- squash_guid(package->components[i].ComponentId,squished_cc);\r
- rc = RegCreateKeyW(hkey,squished_cc,&hkey2);\r
- if (rc != ERROR_SUCCESS)\r
- continue;\r
- \r
- keypath = resolve_keypath(package,i);\r
- if (keypath)\r
- {\r
- RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath,\r
- (strlenW(keypath)+1)*sizeof(WCHAR));\r
- RegCloseKey(hkey2);\r
- \r
- /* UI stuff */\r
- uirow = MSI_CreateRecord(3);\r
- MSI_RecordSetStringW(uirow,1,productcode);\r
- MSI_RecordSetStringW(uirow,2,package->components[i].\r
- ComponentId);\r
- MSI_RecordSetStringW(uirow,3,keypath);\r
- ui_actiondata(package,szProcessComponents,uirow);\r
- msiobj_release( &uirow->hdr );\r
- HeapFree(GetProcessHeap(),0,keypath);\r
- }\r
- }\r
- } \r
-end:\r
- HeapFree(GetProcessHeap(), 0, productcode);\r
- RegCloseKey(hkey);\r
- return rc;\r
-}\r
-\r
-static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)\r
-{\r
- /* \r
- * OK this is a bit confusing.. I am given a _Component key and I believe\r
- * that the file that is being registered as a type library is the "key file\r
- * of that component" which I interpret to mean "The file in the KeyPath of\r
- * that component".\r
- */\r
- UINT rc;\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- static const WCHAR Query[] = {\r
- 'S','E','L','E','C','T',' ','*',' ',\r
- 'f','r','o','m',' ','T','y','p','e','L','i','b',0};\r
- ITypeLib *ptLib;\r
- HRESULT res;\r
-\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, Query, &view);\r
- if (rc != ERROR_SUCCESS)\r
- return ERROR_SUCCESS;\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
-\r
- while (1)\r
- { \r
- WCHAR component[0x100];\r
- DWORD sz;\r
- INT index;\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
-\r
- sz = 0x100;\r
- MSI_RecordGetStringW(row,3,component,&sz);\r
-\r
- index = get_loaded_component(package,component);\r
- if (index < 0)\r
- {\r
- msiobj_release(&row->hdr);\r
- continue;\r
- }\r
-\r
- if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)\r
- {\r
- TRACE("Skipping typelib reg due to disabled component\n");\r
- msiobj_release(&row->hdr);\r
-\r
- package->components[index].Action =\r
- package->components[index].Installed;\r
-\r
- continue;\r
- }\r
-\r
- package->components[index].Action = INSTALLSTATE_LOCAL;\r
- package->components[index].Installed = INSTALLSTATE_LOCAL;\r
-\r
- index = get_loaded_file(package,package->components[index].KeyPath); \r
- \r
- if (index < 0)\r
- {\r
- msiobj_release(&row->hdr);\r
- continue;\r
- }\r
-\r
- res = LoadTypeLib(package->files[index].TargetPath,&ptLib);\r
- if (SUCCEEDED(res))\r
- {\r
- LPWSTR help;\r
- WCHAR helpid[0x100];\r
-\r
- sz = 0x100;\r
- MSI_RecordGetStringW(row,6,helpid,&sz);\r
-\r
- help = resolve_folder(package,helpid,FALSE,FALSE,NULL);\r
- res = RegisterTypeLib(ptLib,package->files[index].TargetPath,help);\r
- HeapFree(GetProcessHeap(),0,help);\r
-\r
- if (!SUCCEEDED(res))\r
- ERR("Failed to register type library %s\n",\r
- debugstr_w(package->files[index].TargetPath));\r
- else\r
- {\r
- /* Yes the row has more fields than I need, but #1 is \r
- correct and the only one I need. Why make a new row? */\r
-\r
- ui_actiondata(package,szRegisterTypeLibraries,row);\r
- \r
- TRACE("Registered %s\n",\r
- debugstr_w(package->files[index].TargetPath));\r
- }\r
-\r
- if (ptLib)\r
- ITypeLib_Release(ptLib);\r
- }\r
- else\r
- ERR("Failed to load type library %s\n",\r
- debugstr_w(package->files[index].TargetPath));\r
- \r
- msiobj_release(&row->hdr);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- \r
-}\r
-\r
-static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app )\r
-{\r
- static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };\r
- UINT rc;\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- static const WCHAR ExecSeqQuery[] = \r
- {'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ','A','p','p','I'\r
- ,'d',' ','w','h','e','r','e',' ','A','p','p','I','d','=','`','%','s','`',0};\r
- HKEY hkey2,hkey3;\r
- LPWSTR buffer=0;\r
-\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, clsid);\r
- if (rc != ERROR_SUCCESS)\r
- return rc;\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
-\r
- RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);\r
- RegCreateKeyW(hkey2,clsid,&hkey3);\r
- RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,\r
- (strlenW(app)+1)*sizeof(WCHAR));\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
-\r
- if (!MSI_RecordIsNull(row,2)) \r
- {\r
- LPWSTR deformated=0;\r
- UINT size; \r
- static const WCHAR szRemoteServerName[] =\r
- {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',0};\r
- buffer = load_dynamic_stringW(row,2);\r
- size = deformat_string(package,buffer,&deformated);\r
- RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,(LPVOID)deformated,\r
- size);\r
- HeapFree(GetProcessHeap(),0,deformated);\r
- HeapFree(GetProcessHeap(),0,buffer);\r
- }\r
-\r
- if (!MSI_RecordIsNull(row,3)) \r
- {\r
- static const WCHAR szLocalService[] =\r
- {'L','o','c','a','l','S','e','r','v','i','c','e',0};\r
- UINT size;\r
- buffer = load_dynamic_stringW(row,3);\r
- size = (strlenW(buffer)+1) * sizeof(WCHAR);\r
- RegSetValueExW(hkey3,szLocalService,0,REG_SZ,(LPVOID)buffer,size);\r
- HeapFree(GetProcessHeap(),0,buffer);\r
- }\r
-\r
- if (!MSI_RecordIsNull(row,4)) \r
- {\r
- static const WCHAR szService[] =\r
- {'S','e','r','v','i','c','e','P','a','r','a','m','e','t','e','r','s',0};\r
- UINT size;\r
- buffer = load_dynamic_stringW(row,4);\r
- size = (strlenW(buffer)+1) * sizeof(WCHAR);\r
- RegSetValueExW(hkey3,szService,0,REG_SZ,(LPVOID)buffer,size);\r
- HeapFree(GetProcessHeap(),0,buffer);\r
- }\r
-\r
- if (!MSI_RecordIsNull(row,5)) \r
- {\r
- static const WCHAR szDLL[] =\r
- {'D','l','l','S','u','r','r','o','g','a','t','e',0};\r
- UINT size;\r
- buffer = load_dynamic_stringW(row,5);\r
- size = (strlenW(buffer)+1) * sizeof(WCHAR);\r
- RegSetValueExW(hkey3,szDLL,0,REG_SZ,(LPVOID)buffer,size);\r
- HeapFree(GetProcessHeap(),0,buffer);\r
- }\r
-\r
- if (!MSI_RecordIsNull(row,6)) \r
- {\r
- static const WCHAR szActivate[] =\r
- {'A','c','t','i','v','a','t','e','A','s','S','t','o','r','a','g','e',0};\r
- static const WCHAR szY[] = {'Y',0};\r
-\r
- if (MSI_RecordGetInteger(row,6))\r
- RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);\r
- }\r
-\r
- if (!MSI_RecordIsNull(row,7)) \r
- {\r
- static const WCHAR szRunAs[] = {'R','u','n','A','s',0};\r
- static const WCHAR szUser[] = \r
- {'I','n','t','e','r','a','c','t','i','v','e',' ','U','s','e','r',0};\r
-\r
- if (MSI_RecordGetInteger(row,7))\r
- RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,34);\r
- }\r
-\r
- msiobj_release(&row->hdr);\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- RegCloseKey(hkey3);\r
- RegCloseKey(hkey2);\r
- return rc;\r
-}\r
-\r
-static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)\r
-{\r
- /* \r
- * Again I am assuming the words, "Whose key file represents" when referring\r
- * to a Component as to meaning that Components KeyPath file\r
- *\r
- * Also there is a very strong connection between ClassInfo and ProgID\r
- * that I am mostly glossing over. \r
- * What would be more propper is to load the ClassInfo and the ProgID info\r
- * into memory data structures and then be able to enable and disable them\r
- * based on component. \r
- */\r
- \r
- UINT rc;\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- static const WCHAR ExecSeqQuery[] = {\r
- 'S','E','L','E','C','T',' ','*',' ',\r
- 'f','r','o','m',' ','C','l','a','s','s',0};\r
- static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };\r
- static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };\r
- static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };\r
- static const WCHAR szSpace[] = {' ',0};\r
- HKEY hkey,hkey2,hkey3;\r
- LPWSTR argument,deformated;\r
-\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);\r
- if (rc != ERROR_SUCCESS)\r
- return ERROR_FUNCTION_FAILED;\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- goto end;\r
- }\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- goto end;\r
- }\r
-\r
- while (1)\r
- {\r
- WCHAR clsid[0x100];\r
- WCHAR buffer[0x100];\r
- WCHAR desc[0x100];\r
- DWORD sz;\r
- INT index;\r
- DWORD size;\r
- \r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
-\r
- sz=0x100;\r
- MSI_RecordGetStringW(row,3,buffer,&sz);\r
-\r
- index = get_loaded_component(package,buffer);\r
-\r
- if (index < 0)\r
- {\r
- msiobj_release(&row->hdr);\r
- continue;\r
- }\r
-\r
- if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)\r
- {\r
- TRACE("Skipping class reg due to disabled component\n");\r
- msiobj_release(&row->hdr);\r
-\r
- package->components[index].Action =\r
- package->components[index].Installed;\r
-\r
- continue;\r
- }\r
-\r
- package->components[index].Action = INSTALLSTATE_LOCAL;\r
- package->components[index].Installed = INSTALLSTATE_LOCAL;\r
-\r
- sz=0x100;\r
- MSI_RecordGetStringW(row,1,clsid,&sz);\r
- RegCreateKeyW(hkey,clsid,&hkey2);\r
-\r
- if (!MSI_RecordIsNull(row,5))\r
- {\r
- sz=0x100;\r
- MSI_RecordGetStringW(row,5,desc,&sz);\r
-\r
- RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)desc,\r
- (strlenW(desc)+1)*sizeof(WCHAR));\r
- }\r
- else\r
- desc[0]=0;\r
-\r
- sz=0x100;\r
- MSI_RecordGetStringW(row,2,buffer,&sz);\r
-\r
- RegCreateKeyW(hkey2,buffer,&hkey3);\r
-\r
- index = get_loaded_file(package,package->components[index].KeyPath);\r
-\r
- argument = load_dynamic_stringW(row,11); \r
- size = deformat_string(package,argument,&deformated);\r
- if (deformated)\r
- size+=sizeof(WCHAR);\r
- HeapFree(GetProcessHeap(),0,argument);\r
- size += (strlenW(package->files[index].TargetPath))*sizeof(WCHAR);\r
-\r
- argument = (LPWSTR)HeapAlloc(GetProcessHeap(),0,size+sizeof(WCHAR));\r
- strcpyW(argument,package->files[index].TargetPath);\r
- if (deformated)\r
- {\r
- strcatW(argument,szSpace);\r
- strcatW(argument,deformated);\r
- }\r
-\r
- RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size);\r
- HeapFree(GetProcessHeap(),0,deformated);\r
- HeapFree(GetProcessHeap(),0,argument);\r
-\r
- RegCloseKey(hkey3);\r
-\r
- if (!MSI_RecordIsNull(row,4))\r
- {\r
- sz=0x100;\r
- MSI_RecordGetStringW(row,4,buffer,&sz);\r
-\r
- RegCreateKeyW(hkey2,szProgID,&hkey3);\r
- \r
- RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)buffer,\r
- (strlenW(buffer)+1)*sizeof(WCHAR));\r
-\r
- RegCloseKey(hkey3);\r
- }\r
-\r
- if (!MSI_RecordIsNull(row,6))\r
- { \r
- sz=0x100;\r
- MSI_RecordGetStringW(row,6,buffer,&sz);\r
-\r
- RegSetValueExW(hkey2,szAppID,0,REG_SZ,(LPVOID)buffer,\r
- (strlenW(buffer)+1)*sizeof(WCHAR));\r
-\r
- register_appid(package,buffer,desc);\r
- }\r
-\r
-\r
- if (!MSI_RecordIsNull(row,7))\r
- {\r
- FIXME("Process field 7\n");\r
- }\r
-\r
- if (!MSI_RecordIsNull(row,8))\r
- {\r
- static const WCHAR szDefaultIcon[] = \r
- {'D','e','f','a','u','l','t','I','c','o','n',0};\r
-\r
- LPWSTR FileName = load_dynamic_stringW(row,8);\r
- LPWSTR FilePath;\r
- INT index;\r
-\r
- RegCreateKeyW(hkey2,szDefaultIcon,&hkey3);\r
- build_icon_path(package,FileName,&FilePath);\r
- if (!MSI_RecordIsNull(row,9))\r
- {\r
- static const WCHAR index_fmt[] = {',','%','i',0};\r
- WCHAR index_buf[20];\r
- index = MSI_RecordGetInteger(row,9);\r
- sprintfW(index_buf,index_fmt,index);\r
- size = strlenW(FilePath)+strlenW(index_buf)+1;\r
- size *= sizeof(WCHAR);\r
- HeapReAlloc(GetProcessHeap(),0,FilePath,size);\r
- }\r
- RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)FilePath,\r
- (strlenW(FilePath)+1) * sizeof(WCHAR));\r
- HeapFree(GetProcessHeap(),0,FilePath);\r
- HeapFree(GetProcessHeap(),0,FileName);\r
- RegCloseKey(hkey3);\r
- }\r
-\r
- if (!MSI_RecordIsNull(row,10))\r
- {\r
- static const WCHAR szInproc32[] = {\r
- 'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};\r
- static const WCHAR szInproc[] = {\r
- 'I','n','p','r','o','c','H','a','n','d','l','e','r',0};\r
- INT i = MSI_RecordGetInteger(row,10);\r
- if (i != MSI_NULL_INTEGER && i > 0 && i < 4)\r
- {\r
- static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0};\r
- static const WCHAR ole32[] = {\r
- 'o','l','e','3','2','.','d','l','l',0};\r
- switch(i)\r
- {\r
- case 1:\r
- size = strlenW(ole2) * sizeof(WCHAR);\r
- RegCreateKeyW(hkey2,szInproc,&hkey3);\r
- RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole2, size);\r
- RegCloseKey(hkey3);\r
- break;\r
- case 2:\r
- size = strlenW(ole32) * sizeof(WCHAR);\r
- RegCreateKeyW(hkey2,szInproc32,&hkey3);\r
- RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole32,size);\r
- RegCloseKey(hkey3);\r
- break;\r
- case 3:\r
- size = strlenW(ole2) * sizeof(WCHAR);\r
- RegCreateKeyW(hkey2,szInproc,&hkey3);\r
- RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole2, size);\r
- RegCloseKey(hkey3);\r
- size = strlenW(ole32) * sizeof(WCHAR);\r
- RegCreateKeyW(hkey2,szInproc32,&hkey3);\r
- RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole32,size);\r
- RegCloseKey(hkey3);\r
- break;\r
- }\r
- \r
- }\r
- else\r
- {\r
- RegCreateKeyW(hkey2,szInproc32,&hkey3);\r
- argument = load_dynamic_stringW(row,10);\r
- reduce_to_longfilename(argument);\r
- size = strlenW(argument)*sizeof(WCHAR);\r
-\r
- RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size);\r
- HeapFree(GetProcessHeap(),0,argument);\r
-\r
- RegCloseKey(hkey3);\r
- }\r
- }\r
-\r
- RegCloseKey(hkey2);\r
-\r
- ui_actiondata(package,szRegisterClassInfo,row);\r
-\r
- msiobj_release(&row->hdr);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
-\r
-end:\r
- RegCloseKey(hkey);\r
- return rc;\r
-}\r
-\r
-static UINT register_progid_base(MSIPACKAGE* package, MSIRECORD * row, \r
- LPWSTR clsid)\r
-{\r
- static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };\r
- static const WCHAR szDefaultIcon[] = {\r
- 'D','e','f','a','u','l','t','I','c','o','n',0};\r
- HKEY hkey,hkey2;\r
- WCHAR buffer[0x100];\r
- DWORD sz;\r
-\r
-\r
- sz = 0x100;\r
- MSI_RecordGetStringW(row,1,buffer,&sz);\r
- RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey);\r
-\r
- if (!MSI_RecordIsNull(row,4))\r
- {\r
- sz = 0x100;\r
- MSI_RecordGetStringW(row,4,buffer,&sz);\r
- RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *\r
- sizeof(WCHAR));\r
- }\r
-\r
- if (!MSI_RecordIsNull(row,3))\r
- { \r
- sz = 0x100;\r
- \r
- MSI_RecordGetStringW(row,3,buffer,&sz);\r
- RegCreateKeyW(hkey,szCLSID,&hkey2);\r
- RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *\r
- sizeof(WCHAR));\r
-\r
- if (clsid)\r
- strcpyW(clsid,buffer);\r
-\r
- RegCloseKey(hkey2);\r
- }\r
- else\r
- {\r
- FIXME("UNHANDLED case, Parent progid but classid is NULL\n");\r
- return ERROR_FUNCTION_FAILED;\r
- }\r
- if (!MSI_RecordIsNull(row,5))\r
- {\r
- INT index = MSI_RecordGetInteger(row,6); \r
- LPWSTR FileName = load_dynamic_stringW(row,5);\r
- LPWSTR FilePath,IconPath;\r
- static const WCHAR fmt[] = {'%','s',',','%','i',0};\r
-\r
- RegCreateKeyW(hkey,szDefaultIcon,&hkey2);\r
- build_icon_path(package,FileName,&FilePath);\r
- \r
- IconPath = HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)*\r
- sizeof(WCHAR));\r
-\r
- sprintfW(IconPath,fmt,FilePath,index);\r
- RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)IconPath,\r
- (strlenW(IconPath)+1) * sizeof(WCHAR));\r
- HeapFree(GetProcessHeap(),0,FilePath);\r
- HeapFree(GetProcessHeap(),0,FileName);\r
- RegCloseKey(hkey2);\r
- }\r
- return ERROR_SUCCESS;\r
-}\r
-\r
-static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid);\r
-\r
-static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent, \r
- LPWSTR clsid)\r
-{\r
- UINT rc;\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- static const WCHAR Query_t[] = \r
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','P','r','o','g'\r
- ,'I','d',' ','w','h','e','r','e',' ','P','r','o','g','I','d',' ','=',' ','`'\r
- ,'%','s','`',0};\r
-\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- rc = MSI_OpenQuery(package->db, &view, Query_t, parent);\r
- if (rc != ERROR_SUCCESS)\r
- return rc;\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
-\r
- register_progid(package,row,clsid);\r
-\r
- msiobj_release(&row->hdr);\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
-}\r
-\r
-static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid)\r
-{\r
- UINT rc = ERROR_SUCCESS; \r
-\r
- if (MSI_RecordIsNull(row,2))\r
- rc = register_progid_base(package,row,clsid);\r
- else\r
- {\r
- WCHAR buffer[0x1000];\r
- DWORD sz, disp;\r
- HKEY hkey,hkey2;\r
- static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };\r
- static const WCHAR szDefaultIcon[] = {\r
- 'D','e','f','a','u','l','t','I','c','o','n',0};\r
-\r
- /* check if already registered */\r
- sz = 0x100;\r
- MSI_RecordGetStringW(row,1,buffer,&sz);\r
- RegCreateKeyExW(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0,\r
- KEY_ALL_ACCESS, NULL, &hkey, &disp );\r
- if (disp == REG_OPENED_EXISTING_KEY)\r
- {\r
- TRACE("Key already registered\n");\r
- RegCloseKey(hkey);\r
- return rc;\r
- }\r
-\r
- sz = 0x100;\r
- MSI_RecordGetStringW(row,2,buffer,&sz);\r
- rc = register_parent_progid(package,buffer,clsid);\r
-\r
- /* clsid is same as parent */\r
- RegCreateKeyW(hkey,szCLSID,&hkey2);\r
- RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *\r
- sizeof(WCHAR));\r
-\r
- RegCloseKey(hkey2);\r
-\r
-\r
- if (!MSI_RecordIsNull(row,4))\r
- {\r
- sz = 0x100;\r
- MSI_RecordGetStringW(row,4,buffer,&sz);\r
- RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer,\r
- (strlenW(buffer)+1) * sizeof(WCHAR));\r
- }\r
-\r
- if (!MSI_RecordIsNull(row,5))\r
- {\r
- LPWSTR FileName = load_dynamic_stringW(row,5);\r
- LPWSTR FilePath;\r
- RegCreateKeyW(hkey,szDefaultIcon,&hkey2);\r
- build_icon_path(package,FileName,&FilePath);\r
- RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)FilePath,\r
- (strlenW(FilePath)+1) * sizeof(WCHAR));\r
- HeapFree(GetProcessHeap(),0,FilePath);\r
- HeapFree(GetProcessHeap(),0,FileName);\r
- RegCloseKey(hkey2);\r
- }\r
-\r
- RegCloseKey(hkey);\r
- }\r
- return rc;\r
-}\r
-\r
-static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)\r
-{\r
- /* \r
- * Sigh, here I am just brute force registering all progids\r
- * this needs to be linked to the Classes that have been registered\r
- * but the easiest way to do that is to load all these stuff into\r
- * memory for easy checking.\r
- *\r
- * Gives me something to continue to work toward.\r
- */\r
- UINT rc;\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- static const WCHAR Query[] = {\r
- 'S','E','L','E','C','T',' ','*',' ',\r
- 'F','R','O','M',' ','P','r','o','g','I','d',0};\r
-\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, Query, &view);\r
- if (rc != ERROR_SUCCESS)\r
- return ERROR_SUCCESS;\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
-\r
- while (1)\r
- {\r
- WCHAR clsid[0x1000];\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
- \r
- register_progid(package,row,clsid);\r
- ui_actiondata(package,szRegisterProgIdInfo,row);\r
-\r
- msiobj_release(&row->hdr);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
-}\r
-\r
-static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, \r
- LPWSTR *FilePath)\r
-{\r
- LPWSTR ProductCode;\r
- LPWSTR SystemFolder;\r
- LPWSTR dest;\r
- UINT rc;\r
-\r
- static const WCHAR szInstaller[] = \r
- {'I','n','s','t','a','l','l','e','r','\\',0};\r
- static const WCHAR szProductCode[] =\r
- {'P','r','o','d','u','c','t','C','o','d','e',0};\r
- static const WCHAR szFolder[] =\r
- {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};\r
-\r
- ProductCode = load_dynamic_property(package,szProductCode,&rc);\r
- if (!ProductCode)\r
- return rc;\r
-\r
- SystemFolder = load_dynamic_property(package,szFolder,NULL);\r
-\r
- dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode);\r
-\r
- create_full_pathW(dest);\r
-\r
- *FilePath = build_directory_name(2, dest, icon_name);\r
-\r
- HeapFree(GetProcessHeap(),0,SystemFolder);\r
- HeapFree(GetProcessHeap(),0,ProductCode);\r
- HeapFree(GetProcessHeap(),0,dest);\r
- return ERROR_SUCCESS;\r
-}\r
-\r
-static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)\r
-{\r
- UINT rc;\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- static const WCHAR Query[] = {\r
- 'S','E','L','E','C','T',' ','*',' ','f','r','o','m',' ',\r
- 'S','h','o','r','t','c','u','t',0};\r
- IShellLinkW *sl;\r
- IPersistFile *pf;\r
- HRESULT res;\r
-\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- res = CoInitialize( NULL );\r
- if (FAILED (res))\r
- {\r
- ERR("CoInitialize failed\n");\r
- return ERROR_FUNCTION_FAILED;\r
- }\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, Query, &view);\r
- if (rc != ERROR_SUCCESS)\r
- return ERROR_SUCCESS;\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
-\r
- while (1)\r
- {\r
- LPWSTR target_file, target_folder;\r
- WCHAR buffer[0x100];\r
- DWORD sz;\r
- DWORD index;\r
- static const WCHAR szlnk[]={'.','l','n','k',0};\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
- \r
- sz = 0x100;\r
- MSI_RecordGetStringW(row,4,buffer,&sz);\r
-\r
- index = get_loaded_component(package,buffer);\r
-\r
- if (index < 0)\r
- {\r
- msiobj_release(&row->hdr);\r
- continue;\r
- }\r
-\r
- if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)\r
- {\r
- TRACE("Skipping shortcut creation due to disabled component\n");\r
- msiobj_release(&row->hdr);\r
-\r
- package->components[index].Action =\r
- package->components[index].Installed;\r
-\r
- continue;\r
- }\r
-\r
- package->components[index].Action = INSTALLSTATE_LOCAL;\r
- package->components[index].Installed = INSTALLSTATE_LOCAL;\r
-\r
- ui_actiondata(package,szCreateShortcuts,row);\r
-\r
- res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,\r
- &IID_IShellLinkW, (LPVOID *) &sl );\r
-\r
- if (FAILED(res))\r
- {\r
- ERR("Is IID_IShellLink\n");\r
- msiobj_release(&row->hdr);\r
- continue;\r
- }\r
-\r
- res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );\r
- if( FAILED( res ) )\r
- {\r
- ERR("Is IID_IPersistFile\n");\r
- msiobj_release(&row->hdr);\r
- continue;\r
- }\r
-\r
- sz = 0x100;\r
- MSI_RecordGetStringW(row,2,buffer,&sz);\r
- target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);\r
-\r
- /* may be needed because of a bug somehwere else */\r
- create_full_pathW(target_folder);\r
-\r
- sz = 0x100;\r
- MSI_RecordGetStringW(row,3,buffer,&sz);\r
- reduce_to_longfilename(buffer);\r
- if (!strchrW(buffer,'.') || strcmpiW(strchrW(buffer,'.'),szlnk))\r
- strcatW(buffer,szlnk);\r
- target_file = build_directory_name(2, target_folder, buffer);\r
- HeapFree(GetProcessHeap(),0,target_folder);\r
-\r
- sz = 0x100;\r
- MSI_RecordGetStringW(row,5,buffer,&sz);\r
- if (strchrW(buffer,'['))\r
- {\r
- LPWSTR deformated;\r
- deformat_string(package,buffer,&deformated);\r
- IShellLinkW_SetPath(sl,deformated);\r
- HeapFree(GetProcessHeap(),0,deformated);\r
- }\r
- else\r
- {\r
- FIXME("UNHANDLED shortcut format, advertised shortcut\n");\r
- IPersistFile_Release( pf );\r
- IShellLinkW_Release( sl );\r
- msiobj_release(&row->hdr);\r
- continue;\r
- }\r
-\r
- if (!MSI_RecordIsNull(row,6))\r
- {\r
- LPWSTR deformated;\r
- sz = 0x100;\r
- MSI_RecordGetStringW(row,6,buffer,&sz);\r
- deformat_string(package,buffer,&deformated);\r
- IShellLinkW_SetArguments(sl,deformated);\r
- HeapFree(GetProcessHeap(),0,deformated);\r
- }\r
-\r
- if (!MSI_RecordIsNull(row,7))\r
- {\r
- LPWSTR deformated;\r
- deformated = load_dynamic_stringW(row,7);\r
- IShellLinkW_SetDescription(sl,deformated);\r
- HeapFree(GetProcessHeap(),0,deformated);\r
- }\r
-\r
- if (!MSI_RecordIsNull(row,8))\r
- IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));\r
-\r
- if (!MSI_RecordIsNull(row,9))\r
- {\r
- WCHAR *Path = NULL;\r
- INT index; \r
-\r
- sz = 0x100;\r
- MSI_RecordGetStringW(row,9,buffer,&sz);\r
-\r
- build_icon_path(package,buffer,&Path);\r
- index = MSI_RecordGetInteger(row,10);\r
-\r
- IShellLinkW_SetIconLocation(sl,Path,index);\r
- HeapFree(GetProcessHeap(),0,Path);\r
- }\r
-\r
- if (!MSI_RecordIsNull(row,11))\r
- IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));\r
-\r
- if (!MSI_RecordIsNull(row,12))\r
- {\r
- LPWSTR Path;\r
- sz = 0x100;\r
- MSI_RecordGetStringW(row,12,buffer,&sz);\r
- Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);\r
- IShellLinkW_SetWorkingDirectory(sl,Path);\r
- HeapFree(GetProcessHeap(), 0, Path);\r
- }\r
-\r
- TRACE("Writing shortcut to %s\n",debugstr_w(target_file));\r
- IPersistFile_Save(pf,target_file,FALSE);\r
- \r
- HeapFree(GetProcessHeap(),0,target_file); \r
-\r
- IPersistFile_Release( pf );\r
- IShellLinkW_Release( sl );\r
-\r
- msiobj_release(&row->hdr);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
-\r
-\r
- CoUninitialize();\r
-\r
- return rc;\r
-}\r
-\r
-\r
-/*\r
- * 99% of the work done here is only done for \r
- * advertised installs. However this is where the\r
- * Icon table is processed and written out\r
- * so that is what I am going to do here.\r
- */\r
-static UINT ACTION_PublishProduct(MSIPACKAGE *package)\r
-{\r
- UINT rc;\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- static const WCHAR Query[]={\r
- 'S','E','L','E','C','T',' ','*',' ',\r
- 'f','r','o','m',' ','I','c','o','n',0};\r
- DWORD sz;\r
- /* for registry stuff */\r
- LPWSTR productcode;\r
- HKEY hkey=0;\r
- HKEY hukey=0;\r
- static const WCHAR szProductCode[]=\r
- {'P','r','o','d','u','c','t','C','o','d','e',0};\r
- static const WCHAR szProductName[] = {\r
- 'P','r','o','d','u','c','t','N','a','m','e',0};\r
- static const WCHAR szPackageCode[] = {\r
- 'P','a','c','k','a','g','e','C','o','d','e',0};\r
- LPWSTR buffer;\r
- DWORD size;\r
- MSIHANDLE hDb, hSumInfo;\r
-\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, Query, &view);\r
- if (rc != ERROR_SUCCESS)\r
- goto next;\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- goto next;\r
- }\r
-\r
- while (1)\r
- {\r
- HANDLE the_file;\r
- WCHAR *FilePath=NULL;\r
- WCHAR *FileName=NULL;\r
- CHAR buffer[1024];\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
- \r
- FileName = load_dynamic_stringW(row,1);\r
- if (!FileName)\r
- {\r
- ERR("Unable to get FileName\n");\r
- msiobj_release(&row->hdr);\r
- continue;\r
- }\r
-\r
- build_icon_path(package,FileName,&FilePath);\r
-\r
- HeapFree(GetProcessHeap(),0,FileName);\r
-\r
- TRACE("Creating icon file at %s\n",debugstr_w(FilePath));\r
- \r
- the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,\r
- FILE_ATTRIBUTE_NORMAL, NULL);\r
-\r
- if (the_file == INVALID_HANDLE_VALUE)\r
- {\r
- ERR("Unable to create file %s\n",debugstr_w(FilePath));\r
- msiobj_release(&row->hdr);\r
- HeapFree(GetProcessHeap(),0,FilePath);\r
- continue;\r
- }\r
-\r
- do \r
- {\r
- DWORD write;\r
- sz = 1024;\r
- rc = MSI_RecordReadStream(row,2,buffer,&sz);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- ERR("Failed to get stream\n");\r
- CloseHandle(the_file); \r
- DeleteFileW(FilePath);\r
- break;\r
- }\r
- WriteFile(the_file,buffer,sz,&write,NULL);\r
- } while (sz == 1024);\r
-\r
- HeapFree(GetProcessHeap(),0,FilePath);\r
-\r
- CloseHandle(the_file);\r
- msiobj_release(&row->hdr);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
-\r
-next:\r
- /* ok there is a lot more done here but i need to figure out what */\r
- productcode = load_dynamic_property(package,szProductCode,&rc);\r
- if (!productcode)\r
- return rc;\r
-\r
- rc = MSIREG_OpenProductsKey(productcode,&hkey,TRUE);\r
- if (rc != ERROR_SUCCESS)\r
- goto end;\r
-\r
- rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);\r
- if (rc != ERROR_SUCCESS)\r
- goto end;\r
-\r
-\r
- buffer = load_dynamic_property(package,szProductName,NULL);\r
- size = strlenW(buffer)*sizeof(WCHAR);\r
- RegSetValueExW(hukey,szProductName,0,REG_SZ, (LPSTR)buffer,size);\r
- HeapFree(GetProcessHeap(),0,buffer);\r
- FIXME("Need to write more keys to the user registry\n");\r
- \r
- hDb= msiobj_findhandle( &package->db->hdr );\r
- rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo); \r
- if (rc == ERROR_SUCCESS)\r
- {\r
- WCHAR guidbuffer[0x200];\r
- size = 0x200;\r
- rc = MsiSummaryInfoGetPropertyW(hSumInfo, 8, NULL, NULL, NULL,\r
- guidbuffer, &size);\r
- if (rc == ERROR_SUCCESS)\r
- {\r
- WCHAR squashed[GUID_SIZE];\r
- /* for now we only care about the first guid */\r
- LPWSTR ptr = strchrW(guidbuffer,';');\r
- if (ptr) *ptr = 0;\r
- squash_guid(guidbuffer,squashed);\r
- size = strlenW(guidbuffer)*sizeof(WCHAR);\r
- RegSetValueExW(hukey,szPackageCode,0,REG_SZ, (LPSTR)guidbuffer,\r
- size);\r
- \r
- }\r
- else\r
- {\r
- ERR("Unable to query Revision_Number... \n");\r
- rc = ERROR_SUCCESS;\r
- }\r
- MsiCloseHandle(hSumInfo);\r
- }\r
- else\r
- {\r
- ERR("Unable to open Summary Information\n");\r
- rc = ERROR_SUCCESS;\r
- }\r
-\r
-end:\r
-\r
- HeapFree(GetProcessHeap(),0,productcode); \r
- RegCloseKey(hkey);\r
- RegCloseKey(hukey);\r
-\r
- return rc;\r
-}\r
-\r
-static UINT ACTION_WriteIniValues(MSIPACKAGE *package)\r
-{\r
- UINT rc;\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- static const WCHAR ExecSeqQuery[] = {'S','e','l','e','c','t',' ','*',\r
- ' ','f','r','o','m',' ','I','n','i','F','i','l','e',0};\r
- static const WCHAR szWindowsFolder[] =\r
- {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- TRACE("no IniFile table\n");\r
- return ERROR_SUCCESS;\r
- }\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
-\r
- while (1)\r
- {\r
- LPWSTR component,filename,dirproperty,section,key,value,identifier;\r
- LPWSTR deformated_section, deformated_key, deformated_value;\r
- LPWSTR folder, fullname = NULL;\r
- MSIRECORD * uirow;\r
- INT component_index,action;\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
-\r
- component = load_dynamic_stringW(row, 8);\r
- component_index = get_loaded_component(package,component);\r
- HeapFree(GetProcessHeap(),0,component);\r
-\r
- if (package->components[component_index].ActionRequest != \r
- INSTALLSTATE_LOCAL)\r
- {\r
- TRACE("Skipping ini file due to disabled component\n");\r
- msiobj_release(&row->hdr);\r
-\r
- package->components[component_index].Action =\r
- package->components[component_index].Installed;\r
-\r
- continue;\r
- }\r
-\r
- package->components[component_index].Action = INSTALLSTATE_LOCAL;\r
- package->components[component_index].Installed = INSTALLSTATE_LOCAL;\r
- \r
- identifier = load_dynamic_stringW(row,1); \r
- filename = load_dynamic_stringW(row,2);\r
- dirproperty = load_dynamic_stringW(row,3);\r
- section = load_dynamic_stringW(row,4);\r
- key = load_dynamic_stringW(row,5);\r
- value = load_dynamic_stringW(row,6);\r
- action = MSI_RecordGetInteger(row,7);\r
-\r
- deformat_string(package,section,&deformated_section);\r
- deformat_string(package,key,&deformated_key);\r
- deformat_string(package,value,&deformated_value);\r
-\r
- if (dirproperty)\r
- {\r
- folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);\r
- if (!folder)\r
- folder = load_dynamic_property(package,dirproperty,NULL);\r
- }\r
- else\r
- folder = load_dynamic_property(package, szWindowsFolder, NULL);\r
-\r
- if (!folder)\r
- {\r
- ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));\r
- goto cleanup;\r
- }\r
-\r
- fullname = build_directory_name(3, folder, filename, NULL);\r
-\r
- if (action == 0)\r
- {\r
- TRACE("Adding value %s to section %s in %s\n",\r
- debugstr_w(deformated_key), debugstr_w(deformated_section),\r
- debugstr_w(fullname));\r
- WritePrivateProfileStringW(deformated_section, deformated_key,\r
- deformated_value, fullname);\r
- }\r
- else if (action == 1)\r
- {\r
- WCHAR returned[10];\r
- GetPrivateProfileStringW(deformated_section, deformated_key, NULL,\r
- returned, 10, fullname);\r
- if (returned[0] == 0)\r
- {\r
- TRACE("Adding value %s to section %s in %s\n",\r
- debugstr_w(deformated_key), debugstr_w(deformated_section),\r
- debugstr_w(fullname));\r
-\r
- WritePrivateProfileStringW(deformated_section, deformated_key,\r
- deformated_value, fullname);\r
- }\r
- }\r
- else if (action == 3)\r
- {\r
- FIXME("Append to existing section not yet implemented\n");\r
- }\r
- \r
- uirow = MSI_CreateRecord(4);\r
- MSI_RecordSetStringW(uirow,1,identifier);\r
- MSI_RecordSetStringW(uirow,2,deformated_section);\r
- MSI_RecordSetStringW(uirow,3,deformated_key);\r
- MSI_RecordSetStringW(uirow,4,deformated_value);\r
- ui_actiondata(package,szWriteIniValues,uirow);\r
- msiobj_release( &uirow->hdr );\r
-cleanup:\r
- HeapFree(GetProcessHeap(),0,identifier);\r
- HeapFree(GetProcessHeap(),0,fullname);\r
- HeapFree(GetProcessHeap(),0,filename);\r
- HeapFree(GetProcessHeap(),0,key);\r
- HeapFree(GetProcessHeap(),0,value);\r
- HeapFree(GetProcessHeap(),0,section);\r
- HeapFree(GetProcessHeap(),0,dirproperty);\r
- HeapFree(GetProcessHeap(),0,folder);\r
- HeapFree(GetProcessHeap(),0,deformated_key);\r
- HeapFree(GetProcessHeap(),0,deformated_value);\r
- HeapFree(GetProcessHeap(),0,deformated_section);\r
- msiobj_release(&row->hdr);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
-}\r
-\r
-static UINT ACTION_SelfRegModules(MSIPACKAGE *package)\r
-{\r
- UINT rc;\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- static const WCHAR ExecSeqQuery[] = {'S','e','l','e','c','t',' ','*',' ',\r
-'f','r','o','m',' ','S','e','l','f','R','e','g',0};\r
-\r
- static const WCHAR ExeStr[] = {\r
-'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','s',' ',0};\r
- STARTUPINFOW si;\r
- PROCESS_INFORMATION info;\r
- BOOL brc;\r
-\r
- memset(&si,0,sizeof(STARTUPINFOW));\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- TRACE("no SelfReg table\n");\r
- return ERROR_SUCCESS;\r
- }\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
-\r
- while (1)\r
- {\r
- LPWSTR filename;\r
- INT index;\r
- DWORD len;\r
-\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
-\r
- filename = load_dynamic_stringW(row,1);\r
- index = get_loaded_file(package,filename);\r
-\r
- if (index < 0)\r
- {\r
- ERR("Unable to find file id %s\n",debugstr_w(filename));\r
- HeapFree(GetProcessHeap(),0,filename);\r
- msiobj_release(&row->hdr);\r
- continue;\r
- }\r
- HeapFree(GetProcessHeap(),0,filename);\r
-\r
- len = strlenW(ExeStr);\r
- len += strlenW(package->files[index].TargetPath);\r
- len +=2;\r
-\r
- filename = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));\r
- strcpyW(filename,ExeStr);\r
- strcatW(filename,package->files[index].TargetPath);\r
-\r
- TRACE("Registering %s\n",debugstr_w(filename));\r
- brc = CreateProcessW(NULL, filename, NULL, NULL, FALSE, 0, NULL,\r
- c_collen, &si, &info);\r
-\r
- if (brc)\r
- msi_dialog_check_messages(package->dialog, info.hProcess);\r
- \r
- HeapFree(GetProcessHeap(),0,filename);\r
- msiobj_release(&row->hdr);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
-}\r
-\r
-static UINT ACTION_PublishFeatures(MSIPACKAGE *package)\r
-{\r
- LPWSTR productcode;\r
- UINT rc;\r
- DWORD i;\r
- HKEY hkey=0;\r
- HKEY hukey=0;\r
- static const WCHAR szProductCode[]=\r
- {'P','r','o','d','u','c','t','C','o','d','e',0};\r
- \r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- productcode = load_dynamic_property(package,szProductCode,&rc);\r
- if (!productcode)\r
- return rc;\r
-\r
- rc = MSIREG_OpenFeaturesKey(productcode,&hkey,TRUE);\r
- if (rc != ERROR_SUCCESS)\r
- goto end;\r
-\r
- rc = MSIREG_OpenUserFeaturesKey(productcode,&hukey,TRUE);\r
- if (rc != ERROR_SUCCESS)\r
- goto end;\r
-\r
- /* here the guids are base 85 encoded */\r
- for (i = 0; i < package->loaded_features; i++)\r
- {\r
- LPWSTR data = NULL;\r
- GUID clsid;\r
- int j;\r
- INT size;\r
-\r
- size = package->features[i].ComponentCount*21;\r
- size +=1;\r
- if (package->features[i].Feature_Parent[0])\r
- size += strlenW(package->features[i].Feature_Parent)+2;\r
-\r
- data = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));\r
-\r
- data[0] = 0;\r
- for (j = 0; j < package->features[i].ComponentCount; j++)\r
- {\r
- WCHAR buf[21];\r
- memset(buf,0,sizeof(buf));\r
- TRACE("From %s\n",debugstr_w(package->components\r
- [package->features[i].Components[j]].ComponentId));\r
- CLSIDFromString(package->components\r
- [package->features[i].Components[j]].ComponentId,\r
- &clsid);\r
- encode_base85_guid(&clsid,buf);\r
- TRACE("to %s\n",debugstr_w(buf));\r
- strcatW(data,buf);\r
- }\r
- if (package->features[i].Feature_Parent[0])\r
- {\r
- static const WCHAR sep[] = {'\2',0};\r
- strcatW(data,sep);\r
- strcatW(data,package->features[i].Feature_Parent);\r
- }\r
-\r
- size = (strlenW(data)+1)*sizeof(WCHAR);\r
- RegSetValueExW(hkey,package->features[i].Feature,0,REG_SZ,\r
- (LPSTR)data,size);\r
- HeapFree(GetProcessHeap(),0,data);\r
-\r
- size = strlenW(package->features[i].Feature_Parent)*sizeof(WCHAR);\r
- RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ,\r
- (LPSTR)package->features[i].Feature_Parent,size);\r
- }\r
-\r
-end:\r
- RegCloseKey(hkey);\r
- RegCloseKey(hukey);\r
- HeapFree(GetProcessHeap(), 0, productcode);\r
- return rc;\r
-}\r
-\r
-static UINT ACTION_RegisterProduct(MSIPACKAGE *package)\r
-{\r
- static const WCHAR szProductCode[]=\r
- {'P','r','o','d','u','c','t','C','o','d','e',0};\r
- HKEY hkey=0;\r
- LPWSTR buffer;\r
- LPWSTR productcode;\r
- UINT rc,i;\r
- DWORD size;\r
- static WCHAR szNONE[] = {0};\r
- static const WCHAR szWindowsInstaler[] = \r
- {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};\r
- static const WCHAR szPropKeys[][80] = \r
- {\r
-{'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0},\r
-{'A','R','P','C','O','N','T','A','C','T'},\r
-{'A','R','P','C','O','M','M','E','N','T','S',0},\r
-{'P','r','o','d','u','c','t','N','a','m','e',0},\r
-{'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0},\r
-{'A','R','P','H','E','L','P','L','I','N','K',0},\r
-{'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0},\r
-{'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0},\r
-{'S','O','U','R','C','E','D','I','R',0},\r
-{'M','a','n','u','f','a','c','t','u','r','e','r',0},\r
-{'A','R','P','R','E','A','D','M','E',0},\r
-{'A','R','P','S','I','Z','E',0},\r
-{'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0},\r
-{'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0},\r
-{0},\r
- };\r
-\r
- static const WCHAR szRegKeys[][80] = \r
- {\r
-{'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0},\r
-{'C','o','n','t','a','c','t',0},\r
-{'C','o','m','m','e','n','t','s',0},\r
-{'D','i','s','p','l','a','y','N','a','m','e',0},\r
-{'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0},\r
-{'H','e','l','p','L','i','n','k',0},\r
-{'H','e','l','p','T','e','l','e','p','h','o','n','e',0},\r
-{'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0},\r
-{'I','n','s','t','a','l','l','S','o','u','r','c','e',0},\r
-{'P','u','b','l','i','s','h','e','r',0},\r
-{'R','e','a','d','m','e',0},\r
-{'S','i','z','e',0},\r
-{'U','R','L','I','n','f','o','A','b','o','u','t',0},\r
-{'U','R','L','U','p','d','a','t','e','I','n','f','o',0},\r
-{0},\r
- };\r
-\r
- static const WCHAR path[] = {\r
- 'C',':','\\','W','i','n','d','o','w','s','\\',\r
- 'I','n','s','t','a','l','l','e','r','\\'};\r
- static const WCHAR fmt[] = {\r
- 'C',':','\\','W','i','n','d','o','w','s','\\',\r
- 'I','n','s','t','a','l','l','e','r','\\',\r
- '%','x','.','m','s','i',0};\r
- static const WCHAR szLocalPackage[]=\r
- {'L','o','c','a','l','P','a','c','k','a','g','e',0};\r
- WCHAR packagefile[MAX_PATH];\r
- INT num,start;\r
-\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- productcode = load_dynamic_property(package,szProductCode,&rc);\r
- if (!productcode)\r
- return rc;\r
-\r
- rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);\r
- if (rc != ERROR_SUCCESS)\r
- goto end;\r
-\r
- /* dump all the info i can grab */\r
- FIXME("Flesh out more information \n");\r
-\r
- i = 0;\r
- while (szPropKeys[i][0]!=0)\r
- {\r
- buffer = load_dynamic_property(package,szPropKeys[i],&rc);\r
- if (rc != ERROR_SUCCESS)\r
- buffer = szNONE;\r
- size = strlenW(buffer)*sizeof(WCHAR);\r
- RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size);\r
- i++;\r
- }\r
-\r
- rc = 0x1;\r
- size = sizeof(rc);\r
- RegSetValueExW(hkey,szWindowsInstaler,0,REG_DWORD,(LPSTR)&rc,size);\r
- \r
- /* copy the package locally */\r
- num = GetTickCount() & 0xffff;\r
- if (!num) \r
- num = 1;\r
- start = num;\r
- sprintfW(packagefile,fmt,num);\r
- do \r
- {\r
- HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,\r
- CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );\r
- if (handle != INVALID_HANDLE_VALUE)\r
- {\r
- CloseHandle(handle);\r
- break;\r
- }\r
- if (GetLastError() != ERROR_FILE_EXISTS &&\r
- GetLastError() != ERROR_SHARING_VIOLATION)\r
- break;\r
- if (!(++num & 0xffff)) num = 1;\r
- sprintfW(packagefile,fmt,num);\r
- } while (num != start);\r
-\r
- create_full_pathW(path);\r
- TRACE("Copying to local package %s\n",debugstr_w(packagefile));\r
- CopyFileW(package->PackagePath,packagefile,FALSE);\r
- size = strlenW(packagefile)*sizeof(WCHAR);\r
- RegSetValueExW(hkey,szLocalPackage,0,REG_SZ,(LPSTR)packagefile,size);\r
- \r
-end:\r
- HeapFree(GetProcessHeap(),0,productcode);\r
- RegCloseKey(hkey);\r
-\r
- return ERROR_SUCCESS;\r
-}\r
-\r
-static UINT ACTION_InstallExecute(MSIPACKAGE *package)\r
-{\r
- int i;\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- for (i = 0; i < package->DeferredActionCount; i++)\r
- {\r
- LPWSTR action;\r
- action = package->DeferredAction[i];\r
- ui_actionstart(package, action);\r
- TRACE("Executing Action (%s)\n",debugstr_w(action));\r
- ACTION_CustomAction(package,action,TRUE);\r
- HeapFree(GetProcessHeap(),0,package->DeferredAction[i]);\r
- }\r
- HeapFree(GetProcessHeap(),0,package->DeferredAction);\r
-\r
- package->DeferredActionCount = 0;\r
- package->DeferredAction = NULL;\r
-\r
- return ERROR_SUCCESS;\r
-}\r
-\r
-static UINT ACTION_InstallFinalize(MSIPACKAGE *package)\r
-{\r
- int i;\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- /* first do the same as an InstallExecute */\r
- ACTION_InstallExecute(package);\r
-\r
- /* then handle Commit Actions */\r
- for (i = 0; i < package->CommitActionCount; i++)\r
- {\r
- LPWSTR action;\r
- action = package->CommitAction[i];\r
- ui_actionstart(package, action);\r
- TRACE("Executing Commit Action (%s)\n",debugstr_w(action));\r
- ACTION_CustomAction(package,action,TRUE);\r
- HeapFree(GetProcessHeap(),0,package->CommitAction[i]);\r
- }\r
- HeapFree(GetProcessHeap(),0,package->CommitAction);\r
-\r
- package->CommitActionCount = 0;\r
- package->CommitAction = NULL;\r
-\r
- return ERROR_SUCCESS;\r
-}\r
-\r
-static UINT ACTION_ForceReboot(MSIPACKAGE *package)\r
-{\r
- static const WCHAR RunOnce[] = {\r
- 'S','o','f','t','w','a','r','e','\\',\r
- 'M','i','c','r','o','s','o','f','t','\\',\r
- 'W','i','n','d','o','w','s','\\',\r
- 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',\r
- 'R','u','n','O','n','c','e'};\r
- static const WCHAR InstallRunOnce[] = {\r
- 'S','o','f','t','w','a','r','e','\\',\r
- 'M','i','c','r','o','s','o','f','t','\\',\r
- 'W','i','n','d','o','w','s','\\',\r
- 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',\r
- 'I','n','s','t','a','l','l','e','r','\\',\r
- 'R','u','n','O','n','c','e','E','n','t','r','i','e','s'};\r
-\r
- static const WCHAR msiexec_fmt[] = {\r
- 'C',':','\\','W','i','n','d','o','w','s','\\','S','y','s','t','e','m',\r
- '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',\r
- '\"','%','s','\"',0};\r
- static const WCHAR install_fmt[] = {\r
- '/','I',' ','\"','%','s','\"',' ',\r
- 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',\r
- 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};\r
- WCHAR buffer[256];\r
- HKEY hkey,hukey;\r
- LPWSTR productcode;\r
- WCHAR squished_pc[100];\r
- INT rc;\r
- DWORD size;\r
- static const WCHAR szProductCode[]=\r
- {'P','r','o','d','u','c','t','C','o','d','e',0};\r
- static const WCHAR szLUS[] = {\r
- 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0};\r
- static const WCHAR szSourceList[] = {\r
- 'S','o','u','r','c','e','L','i','s','t',0};\r
- static const WCHAR szPackageName[] = { \r
- 'P','a','c','k','a','g','e','N','a','m','e',0};\r
-\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- productcode = load_dynamic_property(package,szProductCode,&rc);\r
- if (!productcode)\r
- return rc;\r
-\r
- squash_guid(productcode,squished_pc);\r
-\r
- RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);\r
- sprintfW(buffer,msiexec_fmt,squished_pc);\r
-\r
- size = strlenW(buffer)*sizeof(WCHAR);\r
- RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);\r
- RegCloseKey(hkey);\r
-\r
- TRACE("Reboot command %s\n",debugstr_w(buffer));\r
-\r
- RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);\r
- sprintfW(buffer,install_fmt,productcode,squished_pc);\r
- RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);\r
- RegCloseKey(hkey);\r
-\r
- rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);\r
- if (rc == ERROR_SUCCESS)\r
- {\r
- HKEY hukey2;\r
- LPWSTR buf;\r
- RegCreateKeyW(hukey, szSourceList, &hukey2);\r
- buf = load_dynamic_property(package,cszSourceDir,NULL);\r
- size = strlenW(buf)*sizeof(WCHAR);\r
- RegSetValueExW(hukey2,szLUS,0,REG_SZ,(LPSTR)buf,size);\r
- HeapFree(GetProcessHeap(),0,buf); \r
-\r
- buf = strrchrW(package->PackagePath,'\\');\r
- if (buf)\r
- {\r
- buf++;\r
- size = strlenW(buf)*sizeof(WCHAR);\r
- RegSetValueExW(hukey2,szPackageName,0,REG_SZ,(LPSTR)buf,size);\r
- }\r
-\r
- RegCloseKey(hukey2);\r
- }\r
- HeapFree(GetProcessHeap(),0,productcode);\r
-\r
- return ERROR_INSTALL_SUSPEND;\r
-}\r
-\r
-UINT ACTION_ResolveSource(MSIPACKAGE* package)\r
-{\r
- /*\r
- * we are currently doing what should be done here in the top level Install\r
- * however for Adminastrative and uninstalls this step will be needed\r
- */\r
- return ERROR_SUCCESS;\r
-}\r
-\r
-\r
-static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)\r
-{\r
- UINT rc;\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- static const WCHAR ExecSeqQuery[] = {\r
- 'S','E','L','E','C','T',' ','*',' ',\r
- 'f','r','o','m',' ','E','x','t','e','n','s','i','o','n',0};\r
- static const WCHAR szContentType[] = \r
-{ 'C','o','n','t','e','n','t',' ','T','y','p','e',0 };\r
- HKEY hkey;\r
-\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- goto end;\r
- }\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- goto end;\r
- }\r
-\r
- while (1)\r
- {\r
- WCHAR buffer[0x100];\r
- WCHAR extension[257];\r
- LPWSTR exten;\r
- DWORD sz;\r
- INT index;\r
- \r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
-\r
- sz=0x100;\r
- MSI_RecordGetStringW(row,2,buffer,&sz);\r
-\r
- index = get_loaded_component(package,buffer);\r
-\r
- if (index < 0)\r
- {\r
- msiobj_release(&row->hdr);\r
- continue;\r
- }\r
-\r
- if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL)\r
- {\r
- TRACE("Skipping extension reg due to disabled component\n");\r
- msiobj_release(&row->hdr);\r
-\r
- package->components[index].Action =\r
- package->components[index].Installed;\r
-\r
- continue;\r
- }\r
-\r
- package->components[index].Action = INSTALLSTATE_LOCAL;\r
- package->components[index].Installed = INSTALLSTATE_LOCAL;\r
-\r
- exten = load_dynamic_stringW(row,1);\r
- extension[0] = '.';\r
- extension[1] = 0;\r
- strcatW(extension,exten);\r
- HeapFree(GetProcessHeap(),0,exten);\r
-\r
- RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey);\r
-\r
- if (!MSI_RecordIsNull(row,4))\r
- {\r
- LPWSTR mime = load_dynamic_stringW(row,4);\r
- RegSetValueExW(hkey,szContentType,0,REG_SZ,(LPVOID)mime,\r
- (strlenW(mime)+1)*sizeof(WCHAR));\r
- HeapFree(GetProcessHeap(),0,mime);\r
- }\r
-\r
- if (!MSI_RecordIsNull(row,3))\r
- {\r
- static const WCHAR szSN[] = \r
- {'\\','S','h','e','l','l','N','e','w',0};\r
- HKEY hkey2;\r
- LPWSTR newkey;\r
- LPWSTR progid= load_dynamic_stringW(row,3);\r
-\r
- RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid,\r
- (strlenW(progid)+1)*sizeof(WCHAR));\r
-\r
- newkey = HeapAlloc(GetProcessHeap(),0,\r
- (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR)); \r
-\r
- strcpyW(newkey,progid);\r
- strcatW(newkey,szSN);\r
- RegCreateKeyW(hkey,newkey,&hkey2);\r
- RegCloseKey(hkey2);\r
-\r
- HeapFree(GetProcessHeap(),0,progid);\r
- HeapFree(GetProcessHeap(),0,newkey);\r
- }\r
-\r
-\r
- RegCloseKey(hkey);\r
-\r
- ui_actiondata(package,szRegisterExtensionInfo,row);\r
-\r
- msiobj_release(&row->hdr);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
-\r
-end:\r
- return rc;\r
-}\r
-\r
-static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)\r
-{\r
- UINT rc;\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- static const WCHAR ExecSeqQuery[] = {\r
- 'S','E','L','E','C','T',' ','*',' ',\r
- 'f','r','o','m',' ','M','I','M','E',0};\r
- static const WCHAR szExten[] = \r
-{ 'E','x','t','e','n','s','i','o','n',0 };\r
- HKEY hkey;\r
-\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- goto end;\r
- }\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- goto end;\r
- }\r
-\r
- while (1)\r
- {\r
- WCHAR extension[257];\r
- LPWSTR exten;\r
- LPWSTR mime;\r
- static const WCHAR fmt[] = \r
-{'M','I','M','E','\\',\r
-'D','a','t','a','b','a','s','e','\\',\r
-'C','o','n','t','e','n','t',' ','T','y','p','e','\\',\r
-'%','s',0};\r
- LPWSTR key;\r
- \r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
-\r
- mime = load_dynamic_stringW(row,1);\r
- exten = load_dynamic_stringW(row,2);\r
- extension[0] = '.';\r
- extension[1] = 0;\r
- strcatW(extension,exten);\r
- HeapFree(GetProcessHeap(),0,exten);\r
-\r
- key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) *\r
- sizeof(WCHAR));\r
- sprintfW(key,fmt,mime);\r
- RegCreateKeyW(HKEY_CLASSES_ROOT,key,&hkey);\r
- RegSetValueExW(hkey,szExten,0,REG_SZ,(LPVOID)extension,\r
- (strlenW(extension)+1)*sizeof(WCHAR));\r
-\r
- HeapFree(GetProcessHeap(),0,mime);\r
- HeapFree(GetProcessHeap(),0,key);\r
-\r
- if (!MSI_RecordIsNull(row,3))\r
- {\r
- FIXME("Handle non null for field 3\n");\r
- }\r
-\r
- RegCloseKey(hkey);\r
-\r
- ui_actiondata(package,szRegisterMIMEInfo,row);\r
-\r
- msiobj_release(&row->hdr);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
-\r
-end:\r
- return rc;\r
-}\r
-\r
-static UINT ACTION_RegisterUser(MSIPACKAGE *package)\r
-{\r
- static const WCHAR szProductCode[]=\r
- {'P','r','o','d','u','c','t','C','o','d','e',0};\r
- static const WCHAR szProductID[]=\r
- {'P','r','o','d','u','c','t','I','D',0};\r
- HKEY hkey=0;\r
- LPWSTR buffer;\r
- LPWSTR productcode;\r
- LPWSTR productid;\r
- UINT rc,i;\r
- DWORD size;\r
-\r
- static const WCHAR szPropKeys[][80] = \r
- {\r
-{'P','r','o','d','u','c','t','I','D',0},\r
-{'U','S','E','R','N','A','M','E',0},\r
-{'C','O','M','P','A','N','Y','N','A','M','E',0},\r
-{0},\r
- };\r
-\r
- static const WCHAR szRegKeys[][80] = \r
- {\r
-{'P','r','o','d','u','c','t','I','D',0},\r
-{'R','e','g','O','w','n','e','r',0},\r
-{'R','e','g','C','o','m','p','a','n','y',0},\r
-{0},\r
- };\r
-\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- productid = load_dynamic_property(package,szProductID,&rc);\r
- if (!productid)\r
- return ERROR_SUCCESS;\r
-\r
- productcode = load_dynamic_property(package,szProductCode,&rc);\r
- if (!productcode)\r
- return rc;\r
-\r
- rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);\r
- if (rc != ERROR_SUCCESS)\r
- goto end;\r
-\r
- i = 0;\r
- while (szPropKeys[i][0]!=0)\r
- {\r
- buffer = load_dynamic_property(package,szPropKeys[i],&rc);\r
- if (rc == ERROR_SUCCESS)\r
- {\r
- size = strlenW(buffer)*sizeof(WCHAR);\r
- RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size);\r
- }\r
- i++;\r
- }\r
-\r
-end:\r
- HeapFree(GetProcessHeap(),0,productcode);\r
- HeapFree(GetProcessHeap(),0,productid);\r
- RegCloseKey(hkey);\r
-\r
- return ERROR_SUCCESS;\r
-}\r
-\r
-/* Msi functions that seem appropriate here */\r
-UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )\r
-{\r
- LPWSTR szwAction;\r
- UINT rc;\r
-\r
- TRACE(" exteral attempt at action %s\n",szAction);\r
-\r
- if (!szAction)\r
- return ERROR_FUNCTION_FAILED;\r
- if (hInstall == 0)\r
- return ERROR_FUNCTION_FAILED;\r
-\r
- szwAction = strdupAtoW(szAction);\r
-\r
- if (!szwAction)\r
- return ERROR_FUNCTION_FAILED; \r
-\r
-\r
- rc = MsiDoActionW(hInstall, szwAction);\r
- HeapFree(GetProcessHeap(),0,szwAction);\r
- return rc;\r
-}\r
-\r
-UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )\r
-{\r
- MSIPACKAGE *package;\r
- UINT ret = ERROR_INVALID_HANDLE;\r
-\r
- TRACE(" external attempt at action %s \n",debugstr_w(szAction));\r
-\r
- package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);\r
- if( package )\r
- {\r
- ret = ACTION_PerformAction(package,szAction);\r
- msiobj_release( &package->hdr );\r
- }\r
- return ret;\r
-}\r
-\r
-UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder, \r
- LPSTR szPathBuf, DWORD* pcchPathBuf) \r
-{\r
- LPWSTR szwFolder;\r
- LPWSTR szwPathBuf;\r
- UINT rc;\r
-\r
- TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);\r
-\r
- if (!szFolder)\r
- return ERROR_FUNCTION_FAILED;\r
- if (hInstall == 0)\r
- return ERROR_FUNCTION_FAILED;\r
-\r
- szwFolder = strdupAtoW(szFolder);\r
-\r
- if (!szwFolder)\r
- return ERROR_FUNCTION_FAILED; \r
-\r
- szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));\r
-\r
- rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);\r
-\r
- WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,\r
- *pcchPathBuf, NULL, NULL );\r
-\r
- HeapFree(GetProcessHeap(),0,szwFolder);\r
- HeapFree(GetProcessHeap(),0,szwPathBuf);\r
-\r
- return rc;\r
-}\r
-\r
-UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR\r
- szPathBuf, DWORD* pcchPathBuf) \r
-{\r
- LPWSTR path;\r
- UINT rc = ERROR_FUNCTION_FAILED;\r
- MSIPACKAGE *package;\r
-\r
- TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);\r
-\r
- package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
- path = resolve_folder(package, szFolder, FALSE, FALSE, NULL);\r
- msiobj_release( &package->hdr );\r
-\r
- if (path && (strlenW(path) > *pcchPathBuf))\r
- {\r
- *pcchPathBuf = strlenW(path)+1;\r
- rc = ERROR_MORE_DATA;\r
- }\r
- else if (path)\r
- {\r
- *pcchPathBuf = strlenW(path)+1;\r
- strcpyW(szPathBuf,path);\r
- TRACE("Returning Path %s\n",debugstr_w(path));\r
- rc = ERROR_SUCCESS;\r
- }\r
- HeapFree(GetProcessHeap(),0,path);\r
- \r
- return rc;\r
-}\r
-\r
-\r
-UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder, \r
- LPSTR szPathBuf, DWORD* pcchPathBuf) \r
-{\r
- LPWSTR szwFolder;\r
- LPWSTR szwPathBuf;\r
- UINT rc;\r
-\r
- TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);\r
-\r
- if (!szFolder)\r
- return ERROR_FUNCTION_FAILED;\r
- if (hInstall == 0)\r
- return ERROR_FUNCTION_FAILED;\r
-\r
- szwFolder = strdupAtoW(szFolder);\r
- if (!szwFolder)\r
- return ERROR_FUNCTION_FAILED; \r
-\r
- szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));\r
-\r
- rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);\r
-\r
- WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,\r
- *pcchPathBuf, NULL, NULL );\r
-\r
- HeapFree(GetProcessHeap(),0,szwFolder);\r
- HeapFree(GetProcessHeap(),0,szwPathBuf);\r
-\r
- return rc;\r
-}\r
-\r
-UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR\r
- szPathBuf, DWORD* pcchPathBuf) \r
-{\r
- LPWSTR path;\r
- UINT rc = ERROR_FUNCTION_FAILED;\r
- MSIPACKAGE *package;\r
-\r
- TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);\r
-\r
- package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);\r
- if( !package )\r
- return ERROR_INVALID_HANDLE;\r
- path = resolve_folder(package, szFolder, TRUE, FALSE, NULL);\r
- msiobj_release( &package->hdr );\r
-\r
- if (path && strlenW(path) > *pcchPathBuf)\r
- {\r
- *pcchPathBuf = strlenW(path)+1;\r
- rc = ERROR_MORE_DATA;\r
- }\r
- else if (path)\r
- {\r
- *pcchPathBuf = strlenW(path)+1;\r
- strcpyW(szPathBuf,path);\r
- TRACE("Returning Path %s\n",debugstr_w(path));\r
- rc = ERROR_SUCCESS;\r
- }\r
- HeapFree(GetProcessHeap(),0,path);\r
- \r
- return rc;\r
-}\r
-\r
-\r
-UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder, \r
- LPCSTR szFolderPath)\r
-{\r
- LPWSTR szwFolder;\r
- LPWSTR szwFolderPath;\r
- UINT rc;\r
-\r
- if (!szFolder)\r
- return ERROR_FUNCTION_FAILED;\r
- if (hInstall == 0)\r
- return ERROR_FUNCTION_FAILED;\r
-\r
- szwFolder = strdupAtoW(szFolder);\r
- if (!szwFolder)\r
- return ERROR_FUNCTION_FAILED; \r
-\r
- szwFolderPath = strdupAtoW(szFolderPath);\r
- if (!szwFolderPath)\r
- {\r
- HeapFree(GetProcessHeap(),0,szwFolder);\r
- return ERROR_FUNCTION_FAILED; \r
- }\r
-\r
- rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);\r
-\r
- HeapFree(GetProcessHeap(),0,szwFolder);\r
- HeapFree(GetProcessHeap(),0,szwFolderPath);\r
-\r
- return rc;\r
-}\r
-\r
-UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, \r
- LPCWSTR szFolderPath)\r
-{\r
- DWORD i;\r
- LPWSTR path = NULL;\r
- LPWSTR path2 = NULL;\r
- MSIFOLDER *folder;\r
-\r
- TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));\r
-\r
- if (package==NULL)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- if (szFolderPath[0]==0)\r
- return ERROR_FUNCTION_FAILED;\r
-\r
- if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES)\r
- return ERROR_FUNCTION_FAILED;\r
-\r
- path = resolve_folder(package,szFolder,FALSE,FALSE,&folder);\r
-\r
- if (!path)\r
- return ERROR_INVALID_PARAMETER;\r
-\r
- HeapFree(GetProcessHeap(),0,folder->Property);\r
- folder->Property = build_directory_name(2, szFolderPath, NULL);\r
-\r
- if (strcmpiW(path, folder->Property) == 0)\r
- {\r
- /*\r
- * Resolved Target has not really changed, so just \r
- * set this folder and do not recalculate everything.\r
- */\r
- HeapFree(GetProcessHeap(),0,folder->ResolvedTarget);\r
- folder->ResolvedTarget = NULL;\r
- path2 = resolve_folder(package,szFolder,FALSE,TRUE,NULL);\r
- HeapFree(GetProcessHeap(),0,path2);\r
- }\r
- else\r
- {\r
- for (i = 0; i < package->loaded_folders; i++)\r
- {\r
- HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);\r
- package->folders[i].ResolvedTarget=NULL;\r
- }\r
-\r
- for (i = 0; i < package->loaded_folders; i++)\r
- {\r
- path2=resolve_folder(package, package->folders[i].Directory, FALSE,\r
- TRUE, NULL);\r
- HeapFree(GetProcessHeap(),0,path2);\r
- }\r
- }\r
- HeapFree(GetProcessHeap(),0,path);\r
-\r
- return ERROR_SUCCESS;\r
-}\r
-\r
-UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, \r
- LPCWSTR szFolderPath)\r
-{\r
- MSIPACKAGE *package;\r
- UINT ret;\r
-\r
- TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));\r
-\r
- package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);\r
- ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );\r
- msiobj_release( &package->hdr );\r
- return ret;\r
-}\r
-\r
-/***********************************************************************\r
- * MsiGetMode (MSI.@)\r
- *\r
- * Returns an internal installer state (if it is running in a mode iRunMode)\r
- *\r
- * PARAMS\r
- * hInstall [I] Handle to the installation\r
- * hRunMode [I] Checking run mode\r
- * MSIRUNMODE_ADMIN Administrative mode\r
- * MSIRUNMODE_ADVERTISE Advertisement mode\r
- * MSIRUNMODE_MAINTENANCE Maintenance mode\r
- * MSIRUNMODE_ROLLBACKENABLED Rollback is enabled\r
- * MSIRUNMODE_LOGENABLED Log file is writing\r
- * MSIRUNMODE_OPERATIONS Operations in progress??\r
- * MSIRUNMODE_REBOOTATEND We need to reboot after installation completed\r
- * MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation\r
- * MSIRUNMODE_CABINET Files from cabinet are installed\r
- * MSIRUNMODE_SOURCESHORTNAMES Long names in source files is suppressed\r
- * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is suppressed\r
- * MSIRUNMODE_RESERVED11 Reserved\r
- * MSIRUNMODE_WINDOWS9X Running under Windows95/98\r
- * MSIRUNMODE_ZAWENABLED Demand installation is supported\r
- * MSIRUNMODE_RESERVED14 Reserved\r
- * MSIRUNMODE_RESERVED15 Reserved\r
- * MSIRUNMODE_SCHEDULED called from install script\r
- * MSIRUNMODE_ROLLBACK called from rollback script\r
- * MSIRUNMODE_COMMIT called from commit script\r
- *\r
- * RETURNS\r
- * In the state: TRUE\r
- * Not in the state: FALSE\r
- *\r
- */\r
-\r
-BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)\r
-{\r
- FIXME("STUB (iRunMode=%i)\n",iRunMode);\r
- return TRUE;\r
-}\r
-\r
-/*\r
- * According to the docs, when this is called it immediately recalculates\r
- * all the component states as well\r
- */\r
-UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,\r
- INSTALLSTATE iState)\r
-{\r
- LPWSTR szwFeature = NULL;\r
- UINT rc;\r
-\r
- szwFeature = strdupAtoW(szFeature);\r
-\r
- if (!szwFeature)\r
- return ERROR_FUNCTION_FAILED;\r
- \r
- rc = MsiSetFeatureStateW(hInstall,szwFeature, iState); \r
-\r
- HeapFree(GetProcessHeap(),0,szwFeature);\r
-\r
- return rc;\r
-}\r
-\r
-UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,\r
- INSTALLSTATE iState)\r
-{\r
- MSIPACKAGE* package;\r
- INT index;\r
-\r
- TRACE(" %s to %i\n",debugstr_w(szFeature), iState);\r
-\r
- package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
-\r
- index = get_loaded_feature(package,szFeature);\r
- if (index < 0)\r
- return ERROR_UNKNOWN_FEATURE;\r
-\r
- package->features[index].ActionRequest= iState;\r
- ACTION_UpdateComponentStates(package,szFeature);\r
-\r
- return ERROR_SUCCESS;\r
-}\r
-\r
-UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature,\r
- INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)\r
-{\r
- LPWSTR szwFeature = NULL;\r
- UINT rc;\r
- \r
- szwFeature = strdupAtoW(szFeature);\r
-\r
- rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);\r
-\r
- HeapFree( GetProcessHeap(), 0 , szwFeature);\r
-\r
- return rc;\r
-}\r
-\r
-UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,\r
- INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)\r
-{\r
- INT index;\r
-\r
- index = get_loaded_feature(package,szFeature);\r
- if (index < 0)\r
- return ERROR_UNKNOWN_FEATURE;\r
-\r
- if (piInstalled)\r
- *piInstalled = package->features[index].Installed;\r
-\r
- if (piAction)\r
- *piAction = package->features[index].Action;\r
-\r
- TRACE("returning %i %i\n",*piInstalled,*piAction);\r
-\r
- return ERROR_SUCCESS;\r
-}\r
-\r
-UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature,\r
- INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)\r
-{\r
- MSIPACKAGE* package;\r
- UINT ret;\r
-\r
- TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,\r
-piAction);\r
-\r
- package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
- ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);\r
- msiobj_release( &package->hdr );\r
- return ret;\r
-}\r
-\r
-UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent,\r
- INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)\r
-{\r
- LPWSTR szwComponent= NULL;\r
- UINT rc;\r
- \r
- szwComponent= strdupAtoW(szComponent);\r
-\r
- rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);\r
-\r
- HeapFree( GetProcessHeap(), 0 , szwComponent);\r
-\r
- return rc;\r
-}\r
-\r
-UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent,\r
- INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)\r
-{\r
- INT index;\r
-\r
- TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled,\r
-piAction);\r
-\r
- index = get_loaded_component(package,szComponent);\r
- if (index < 0)\r
- return ERROR_UNKNOWN_COMPONENT;\r
-\r
- if (piInstalled)\r
- *piInstalled = package->components[index].Installed;\r
-\r
- if (piAction)\r
- *piAction = package->components[index].Action;\r
-\r
- TRACE("states (%i, %i)\n",\r
-(piInstalled)?*piInstalled:-1,(piAction)?*piAction:-1);\r
-\r
- return ERROR_SUCCESS;\r
-}\r
-\r
-UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent,\r
- INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)\r
-{\r
- MSIPACKAGE* package;\r
- UINT ret;\r
-\r
- TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),\r
- piInstalled, piAction);\r
-\r
- package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);\r
- if (!package)\r
- return ERROR_INVALID_HANDLE;\r
- ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);\r
- msiobj_release( &package->hdr );\r
- return ret;\r
-}\r
-\r
-#if 0\r
-static UINT ACTION_Template(MSIPACKAGE *package)\r
-{\r
- UINT rc;\r
- MSIQUERY * view;\r
- MSIRECORD * row = 0;\r
- static const WCHAR ExecSeqQuery[] = {0};\r
-\r
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);\r
- if (rc != ERROR_SUCCESS)\r
- return rc;\r
-\r
- rc = MSI_ViewExecute(view, 0);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
- }\r
-\r
- while (1)\r
- {\r
- rc = MSI_ViewFetch(view,&row);\r
- if (rc != ERROR_SUCCESS)\r
- {\r
- rc = ERROR_SUCCESS;\r
- break;\r
- }\r
-\r
- msiobj_release(&row->hdr);\r
- }\r
- MSI_ViewClose(view);\r
- msiobj_release(&view->hdr);\r
- return rc;\r
-}\r
-#endif\r
+/*
+ * 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 <stdarg.h>
+#include <stdio.h>
+
+#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; i<count; i++)
+ {
+ LPCWSTR str = va_arg(va,LPCWSTR);
+ if (str)
+ sz += strlenW(str) + 1;
+ }
+ va_end(va);
+
+ dir = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));
+ dir[0]=0;
+
+ va_start(va,count);
+ for(i=0; i<count; i++)
+ {
+ LPCWSTR str = va_arg(va,LPCWSTR);
+ if (!str)
+ continue;
+ strcatW(dir, str);
+ if( ((i+1)!=count) && dir[strlenW(dir)-1]!='\\')
+ strcatW(dir, cszbs);
+ }
+ return dir;
+}
+
+static BOOL ACTION_VerifyComponentForAction(MSIPACKAGE* package, INT index,
+ INSTALLSTATE check )
+{
+ if (package->components[index].Installed == check)
+ return FALSE;
+
+ if (package->components[index].ActionRequest == check)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+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<ttNTHeader.uNRCount; i++)
+ {
+ ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),NULL,NULL);
+ ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
+ /* 4 is the Full Font Name */
+ if(ttRecord.uNameID == 4)
+ {
+ int nPos;
+ LPSTR buf;
+ static const LPSTR tt = " (TrueType)";
+
+ ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
+ ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
+ nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
+ SetFilePointer(handle, tblDir.uOffset +
+ ttRecord.uStringOffset +
+ ttNTHeader.uStorageOffset,
+ NULL, FILE_BEGIN);
+ buf = HeapAlloc(GetProcessHeap(), 0,
+ ttRecord.uStringLength + 1 + strlen(tt));
+ memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
+ ReadFile(handle, buf, ttRecord.uStringLength, NULL, NULL);
+ if (strlen(buf) > 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