msi: action.c reorginizaion (BIG)
Aric Stewart
aric at codeweavers.com
Fri Jun 10 09:05:26 CDT 2005
Break action.c into a number of new modules, files.c classes.c install.c
and helper.c Halves the number of lines in action.c
Make use of MSI_IterateRecords in a number of actions.
let upgrade.c use the action data ui functions now that they are not
static inside of action.c
-------------- next part --------------
Index: dlls/msi/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/msi/Makefile.in,v
retrieving revision 1.28
diff -u -r1.28 Makefile.in
--- dlls/msi/Makefile.in 9 Jun 2005 12:05:27 -0000 1.28
+++ dlls/msi/Makefile.in 10 Jun 2005 13:39:58 -0000
@@ -10,6 +10,7 @@
C_SRCS = \
action.c \
appsearch.c \
+ classes.c \
create.c \
custom.c \
database.c \
@@ -17,9 +18,12 @@
dialog.c \
distinct.c \
events.c \
+ files.c \
format.c \
handle.c \
+ helpers.c \
insert.c \
+ install.c \
msi.c \
msiquery.c \
order.c \
Index: dlls/msi/action.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/action.c,v
retrieving revision 1.145
diff -u -r1.145 action.c
--- dlls/msi/action.c 9 Jun 2005 20:30:59 -0000 1.145
+++ dlls/msi/action.c 10 Jun 2005 13:39:59 -0000
@@ -1,7 +1,7 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
- * Copyright 2004 Aric Stewart for CodeWeavers
+ * Copyright 2004,2005 Aric Stewart for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -27,7 +27,6 @@
*/
#include <stdarg.h>
-#include <stdio.h>
#define COBJMACROS
@@ -36,15 +35,8 @@
#include "winerror.h"
#include "winreg.h"
#include "wine/debug.h"
-#include "fdi.h"
-#include "msi.h"
-#include "msiquery.h"
#include "msidefs.h"
-#include "msvcrt/fcntl.h"
-#include "objbase.h"
-#include "objidl.h"
#include "msipriv.h"
-#include "winnls.h"
#include "winuser.h"
#include "shlobj.h"
#include "wine/unicode.h"
@@ -62,8 +54,6 @@
static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
-static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name,
- LPWSTR *FilePath);
/*
* action handlers
@@ -75,17 +65,11 @@
static UINT ACTION_CreateFolders(MSIPACKAGE *package);
static UINT ACTION_CostFinalize(MSIPACKAGE *package);
static UINT ACTION_FileCost(MSIPACKAGE *package);
-static UINT ACTION_InstallFiles(MSIPACKAGE *package);
-static UINT ACTION_DuplicateFiles(MSIPACKAGE *package);
static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package);
static UINT ACTION_InstallInitialize(MSIPACKAGE *package);
static UINT ACTION_InstallValidate(MSIPACKAGE *package);
static UINT ACTION_ProcessComponents(MSIPACKAGE *package);
static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package);
-static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package);
-static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package);
-static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package);
-static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package);
static UINT ACTION_RegisterUser(MSIPACKAGE *package);
static UINT ACTION_CreateShortcuts(MSIPACKAGE *package);
static UINT ACTION_PublishProduct(MSIPACKAGE *package);
@@ -101,26 +85,18 @@
static UINT ACTION_RegisterFonts(MSIPACKAGE *package);
static UINT ACTION_PublishComponents(MSIPACKAGE *package);
-
/*
* consts and values used
*/
-static const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
-static const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
-static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};
-static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
-static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0};
static const WCHAR c_colon[] = {'C',':','\\',0};
-static const WCHAR szProductCode[]=
- {'P','r','o','d','u','c','t','C','o','d','e',0};
-static const WCHAR cszbs[]={'\\',0};
+
const static WCHAR szCreateFolders[] =
{'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
const static WCHAR szCostFinalize[] =
{'C','o','s','t','F','i','n','a','l','i','z','e',0};
-const static WCHAR szInstallFiles[] =
+const WCHAR szInstallFiles[] =
{'I','n','s','t','a','l','l','F','i','l','e','s',0};
-const static WCHAR szDuplicateFiles[] =
+const WCHAR szDuplicateFiles[] =
{'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
const static WCHAR szWriteRegistryValues[] =
{'W','r','i','t','e','R','e','g','i','s','t','r','y',
@@ -140,9 +116,9 @@
const static WCHAR szRegisterTypeLibraries[] =
{'R','e','g','i','s','t','e','r','T','y','p','e',
'L','i','b','r','a','r','i','e','s',0};
-const static WCHAR szRegisterClassInfo[] =
+const WCHAR szRegisterClassInfo[] =
{'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
-const static WCHAR szRegisterProgIdInfo[] =
+const WCHAR szRegisterProgIdInfo[] =
{'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
const static WCHAR szCreateShortcuts[] =
{'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
@@ -167,7 +143,7 @@
{'F','o','r','c','e','R','e','b','o','o','t',0};
const static WCHAR szResolveSource[] =
{'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
-const static WCHAR szAppSearch[] =
+const WCHAR szAppSearch[] =
{'A','p','p','S','e','a','r','c','h',0};
const static WCHAR szAllocateRegistrySpace[] =
{'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
@@ -182,7 +158,7 @@
{'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
const static WCHAR szExecuteAction[] =
{'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
-const static WCHAR szFindRelatedProducts[] =
+const WCHAR szFindRelatedProducts[] =
{'F','i','n','d','R','e','l','a','t','e','d',
'P','r','o','d','u','c','t','s',0};
const static WCHAR szInstallAdminPackage[] =
@@ -193,10 +169,10 @@
'F','i','l','e',0};
const static WCHAR szIsolateComponents[] =
{'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
-const static WCHAR szMigrateFeatureStates[] =
+const WCHAR szMigrateFeatureStates[] =
{'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
'S','t','a','t','e','s',0};
-const static WCHAR szMoveFiles[] =
+const WCHAR szMoveFiles[] =
{'M','o','v','e','F','i','l','e','s',0};
const static WCHAR szMsiPublishAssemblies[] =
{'M','s','i','P','u','b','l','i','s','h',
@@ -208,31 +184,31 @@
{'I','n','s','t','a','l','l','O','D','B','C',0};
const static WCHAR szInstallServices[] =
{'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
-const static WCHAR szPatchFiles[] =
+const WCHAR szPatchFiles[] =
{'P','a','t','c','h','F','i','l','e','s',0};
const static WCHAR szPublishComponents[] =
{'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
const static WCHAR szRegisterComPlus[] =
{'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
-const static WCHAR szRegisterExtensionInfo[] =
+const WCHAR szRegisterExtensionInfo[] =
{'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
'I','n','f','o',0};
const static WCHAR szRegisterFonts[] =
{'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
-const static WCHAR szRegisterMIMEInfo[] =
+const WCHAR szRegisterMIMEInfo[] =
{'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
const static WCHAR szRegisterUser[] =
{'R','e','g','i','s','t','e','r','U','s','e','r',0};
-const static WCHAR szRemoveDuplicateFiles[] =
+const WCHAR szRemoveDuplicateFiles[] =
{'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
'F','i','l','e','s',0};
const static WCHAR szRemoveEnvironmentStrings[] =
{'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
'S','t','r','i','n','g','s',0};
-const static WCHAR szRemoveExistingProducts[] =
+const WCHAR szRemoveExistingProducts[] =
{'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
'P','r','o','d','u','c','t','s',0};
-const static WCHAR szRemoveFiles[] =
+const WCHAR szRemoveFiles[] =
{'R','e','m','o','v','e','F','i','l','e','s',0};
const static WCHAR szRemoveFolders[] =
{'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
@@ -262,19 +238,19 @@
'C','o','m','p','o','n','e','n','t','s',0};
const static WCHAR szUnpublishFeatures[] =
{'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
-const static WCHAR szUnregisterClassInfo[] =
+const WCHAR szUnregisterClassInfo[] =
{'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
'I','n','f','o',0};
const static WCHAR szUnregisterComPlus[] =
{'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
-const static WCHAR szUnregisterExtensionInfo[] =
+const WCHAR szUnregisterExtensionInfo[] =
{'U','n','r','e','g','i','s','t','e','r',
'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
const static WCHAR szUnregisterFonts[] =
{'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
-const static WCHAR szUnregisterMIMEInfo[] =
+const WCHAR szUnregisterMIMEInfo[] =
{'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
-const static WCHAR szUnregisterProgIdInfo[] =
+const WCHAR szUnregisterProgIdInfo[] =
{'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
'I','n','f','o',0};
const static WCHAR szUnregisterTypeLibraries[] =
@@ -372,369 +348,8 @@
/********************************************************
- * helper functions to get around current HACKS and such
+ * helper functions
********************************************************/
-inline static void reduce_to_longfilename(WCHAR* filename)
-{
- LPWSTR p = strchrW(filename,'|');
- if (p)
- memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR));
-}
-
-inline static void reduce_to_shortfilename(WCHAR* filename)
-{
- LPWSTR p = strchrW(filename,'|');
- if (p)
- *p = 0;
-}
-
-WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
-{
- UINT rc;
- DWORD sz;
- LPWSTR ret;
-
- sz = 0;
- if (MSI_RecordIsNull(row,index))
- return NULL;
-
- rc = MSI_RecordGetStringW(row,index,NULL,&sz);
-
- /* having an empty string is different than NULL */
- if (sz == 0)
- {
- ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR));
- ret[0] = 0;
- return ret;
- }
-
- sz ++;
- ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR));
- rc = MSI_RecordGetStringW(row,index,ret,&sz);
- if (rc!=ERROR_SUCCESS)
- {
- ERR("Unable to load dynamic string\n");
- HeapFree(GetProcessHeap(), 0, ret);
- ret = NULL;
- }
- return ret;
-}
-
-LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc)
-{
- DWORD sz = 0;
- LPWSTR str;
- UINT r;
-
- r = MSI_GetPropertyW(package, prop, NULL, &sz);
- if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
- {
- if (rc)
- *rc = r;
- return NULL;
- }
- sz++;
- str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
- r = MSI_GetPropertyW(package, prop, str, &sz);
- if (r != ERROR_SUCCESS)
- {
- HeapFree(GetProcessHeap(),0,str);
- str = NULL;
- }
- if (rc)
- *rc = r;
- return str;
-}
-
-int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
-{
- int rc = -1;
- DWORD i;
-
- for (i = 0; i < package->loaded_components; i++)
- {
- if (strcmpW(Component,package->components[i].Component)==0)
- {
- rc = i;
- break;
- }
- }
- return rc;
-}
-
-int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
-{
- int rc = -1;
- DWORD i;
-
- for (i = 0; i < package->loaded_features; i++)
- {
- if (strcmpW(Feature,package->features[i].Feature)==0)
- {
- rc = i;
- break;
- }
- }
- return rc;
-}
-
-int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
-{
- int rc = -1;
- DWORD i;
-
- for (i = 0; i < package->loaded_files; i++)
- {
- if (strcmpW(file,package->files[i].File)==0)
- {
- rc = i;
- break;
- }
- }
- return rc;
-}
-
-int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
-{
- DWORD i;
- DWORD index;
-
- if (!package)
- return -2;
-
- for (i=0; i < package->loaded_files; i++)
- if (strcmpW(package->files[i].File,name)==0)
- return -1;
-
- index = package->loaded_files;
- package->loaded_files++;
- if (package->loaded_files== 1)
- package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
- else
- package->files = HeapReAlloc(GetProcessHeap(),0,
- package->files , package->loaded_files * sizeof(MSIFILE));
-
- memset(&package->files[index],0,sizeof(MSIFILE));
-
- package->files[index].File = strdupW(name);
- package->files[index].TargetPath = strdupW(path);
- package->files[index].Temporary = TRUE;
-
- TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File));
-
- return 0;
-}
-
-static void remove_tracked_tempfiles(MSIPACKAGE* package)
-{
- DWORD i;
-
- if (!package)
- return;
-
- for (i = 0; i < package->loaded_files; i++)
- {
- if (package->files[i].Temporary)
- {
- TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath));
- DeleteFileW(package->files[i].TargetPath);
- }
-
- }
-}
-
-/* wrapper to resist a need for a full rewrite right now */
-DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data )
-{
- if (ptr)
- {
- MSIRECORD *rec = MSI_CreateRecord(1);
- DWORD size = 0;
-
- MSI_RecordSetStringW(rec,0,ptr);
- MSI_FormatRecordW(package,rec,NULL,&size);
- if (size >= 0)
- {
- size++;
- *data = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
- if (size > 1)
- MSI_FormatRecordW(package,rec,*data,&size);
- else
- *data[0] = 0;
- msiobj_release( &rec->hdr );
- return sizeof(WCHAR)*size;
- }
- msiobj_release( &rec->hdr );
- }
-
- *data = NULL;
- return 0;
-}
-
-DWORD build_version_dword(LPCWSTR version_string)
-{
- SHORT major,minor;
- WORD build;
- DWORD rc = 0x00000000;
- LPCWSTR ptr1;
-
- ptr1 = version_string;
-
- if (!ptr1)
- return rc;
- else
- major = atoiW(ptr1);
-
-
- if(ptr1)
- ptr1 = strchrW(ptr1,'.');
- if (ptr1)
- {
- ptr1++;
- minor = atoiW(ptr1);
- }
- else
- minor = 0;
-
- if (ptr1)
- ptr1 = strchrW(ptr1,'.');
-
- if (ptr1)
- {
- ptr1++;
- build = atoiW(ptr1);
- }
- else
- build = 0;
-
- rc = MAKELONG(build,MAKEWORD(minor,major));
- TRACE("%s -> 0x%lx\n",debugstr_w(version_string),rc);
- return rc;
-}
-
-/* Called when the package is being closed */
-void ACTION_free_package_structures( MSIPACKAGE* package)
-{
- INT i;
-
- TRACE("Freeing package action data\n");
-
- remove_tracked_tempfiles(package);
-
- /* No dynamic buffers in features */
- if (package->features && package->loaded_features > 0)
- HeapFree(GetProcessHeap(),0,package->features);
-
- for (i = 0; i < package->loaded_folders; i++)
- {
- HeapFree(GetProcessHeap(),0,package->folders[i].Directory);
- HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault);
- HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault);
- HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
- HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource);
- HeapFree(GetProcessHeap(),0,package->folders[i].Property);
- }
- if (package->folders && package->loaded_folders > 0)
- HeapFree(GetProcessHeap(),0,package->folders);
-
- for (i = 0; i < package->loaded_components; i++)
- HeapFree(GetProcessHeap(),0,package->components[i].FullKeypath);
-
- if (package->components && package->loaded_components > 0)
- HeapFree(GetProcessHeap(),0,package->components);
-
- for (i = 0; i < package->loaded_files; i++)
- {
- HeapFree(GetProcessHeap(),0,package->files[i].File);
- HeapFree(GetProcessHeap(),0,package->files[i].FileName);
- HeapFree(GetProcessHeap(),0,package->files[i].ShortName);
- HeapFree(GetProcessHeap(),0,package->files[i].Version);
- HeapFree(GetProcessHeap(),0,package->files[i].Language);
- HeapFree(GetProcessHeap(),0,package->files[i].SourcePath);
- HeapFree(GetProcessHeap(),0,package->files[i].TargetPath);
- }
-
- if (package->files && package->loaded_files > 0)
- HeapFree(GetProcessHeap(),0,package->files);
-
- /* clean up extension, progid, class and verb structures */
- for (i = 0; i < package->loaded_classes; i++)
- {
- HeapFree(GetProcessHeap(),0,package->classes[i].Description);
- HeapFree(GetProcessHeap(),0,package->classes[i].FileTypeMask);
- HeapFree(GetProcessHeap(),0,package->classes[i].IconPath);
- HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler);
- HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler32);
- HeapFree(GetProcessHeap(),0,package->classes[i].Argument);
- HeapFree(GetProcessHeap(),0,package->classes[i].ProgIDText);
- }
-
- if (package->classes && package->loaded_classes > 0)
- HeapFree(GetProcessHeap(),0,package->classes);
-
- for (i = 0; i < package->loaded_extensions; i++)
- {
- HeapFree(GetProcessHeap(),0,package->extensions[i].ProgIDText);
- }
-
- if (package->extensions && package->loaded_extensions > 0)
- HeapFree(GetProcessHeap(),0,package->extensions);
-
- for (i = 0; i < package->loaded_progids; i++)
- {
- HeapFree(GetProcessHeap(),0,package->progids[i].ProgID);
- HeapFree(GetProcessHeap(),0,package->progids[i].Description);
- HeapFree(GetProcessHeap(),0,package->progids[i].IconPath);
- }
-
- if (package->progids && package->loaded_progids > 0)
- HeapFree(GetProcessHeap(),0,package->progids);
-
- for (i = 0; i < package->loaded_verbs; i++)
- {
- HeapFree(GetProcessHeap(),0,package->verbs[i].Verb);
- HeapFree(GetProcessHeap(),0,package->verbs[i].Command);
- HeapFree(GetProcessHeap(),0,package->verbs[i].Argument);
- }
-
- if (package->verbs && package->loaded_verbs > 0)
- HeapFree(GetProcessHeap(),0,package->verbs);
-
- for (i = 0; i < package->loaded_mimes; i++)
- HeapFree(GetProcessHeap(),0,package->mimes[i].ContentType);
-
- if (package->mimes && package->loaded_mimes > 0)
- HeapFree(GetProcessHeap(),0,package->mimes);
-
- for (i = 0; i < package->loaded_appids; i++)
- {
- HeapFree(GetProcessHeap(),0,package->appids[i].RemoteServerName);
- HeapFree(GetProcessHeap(),0,package->appids[i].LocalServer);
- HeapFree(GetProcessHeap(),0,package->appids[i].ServiceParameters);
- HeapFree(GetProcessHeap(),0,package->appids[i].DllSurrogate);
- }
-
- if (package->appids && package->loaded_appids > 0)
- HeapFree(GetProcessHeap(),0,package->appids);
-
- if (package->script)
- {
- for (i = 0; i < TOTAL_SCRIPTS; i++)
- {
- int j;
- for (j = 0; j < package->script->ActionCount[i]; j++)
- HeapFree(GetProcessHeap(),0,package->script->Actions[i][j]);
-
- HeapFree(GetProcessHeap(),0,package->script->Actions[i]);
- }
- HeapFree(GetProcessHeap(),0,package->script);
- }
-
- HeapFree(GetProcessHeap(),0,package->PackagePath);
-
- /* cleanup control event subscriptions */
- ControlEvent_CleanupSubscriptions(package);
-}
static void ce_actiontext(MSIPACKAGE* package, LPCWSTR action)
{
@@ -748,71 +363,6 @@
msiobj_release(&row->hdr);
}
-static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d )
-{
- MSIRECORD * row;
-
- row = MSI_CreateRecord(4);
- MSI_RecordSetInteger(row,1,a);
- MSI_RecordSetInteger(row,2,b);
- MSI_RecordSetInteger(row,3,c);
- MSI_RecordSetInteger(row,4,d);
- MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row);
- msiobj_release(&row->hdr);
-
- msi_dialog_check_messages(NULL);
-}
-
-static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
-{
- static const WCHAR Query_t[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
- 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',
- ' ','\'','%','s','\'',0};
- WCHAR message[1024];
- MSIRECORD * row = 0;
- DWORD size;
- static const WCHAR szActionData[] =
- {'A','c','t','i','o','n','D','a','t','a',0};
-
- if (!package->LastAction || strcmpW(package->LastAction,action))
- {
- row = MSI_QueryGetRecord(package->db, Query_t, action);
- if (!row)
- return;
-
- if (MSI_RecordIsNull(row,3))
- {
- msiobj_release(&row->hdr);
- return;
- }
-
- /* update the cached actionformat */
- HeapFree(GetProcessHeap(),0,package->ActionFormat);
- package->ActionFormat = load_dynamic_stringW(row,3);
-
- HeapFree(GetProcessHeap(),0,package->LastAction);
- package->LastAction = strdupW(action);
-
- msiobj_release(&row->hdr);
- }
-
- MSI_RecordSetStringW(record,0,package->ActionFormat);
- size = 1024;
- MSI_FormatRecordW(package,record,message,&size);
-
- row = MSI_CreateRecord(1);
- MSI_RecordSetStringW(row,1,message);
-
- MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
-
- ControlEvent_FireSubscribedEvent(package,szActionData, row);
-
- msiobj_release(&row->hdr);
-}
-
-
static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
{
static const WCHAR template_s[]=
@@ -877,82 +427,6 @@
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
*****************************************************/
@@ -1156,9 +630,54 @@
return rc;
}
-static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
-{
- MSIQUERY * view;
+typedef struct {
+ MSIPACKAGE* package;
+ BOOL UI;
+} iterate_action_param;
+
+static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
+{
+ iterate_action_param *iap= (iterate_action_param*)param;
+ UINT rc;
+ LPCWSTR cond, action;
+
+ action = MSI_RecordGetString(row,1);
+ if (!action)
+ {
+ ERR("Error is retrieving action name\n");
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ /* check conditions */
+ cond = MSI_RecordGetString(row,2);
+ if (cond)
+ {
+ /* this is a hack to skip errors in the condition code */
+ if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
+ {
+ TRACE("Skipping action: %s (condition is false)\n",
+ debugstr_w(action));
+ return ERROR_SUCCESS;
+ }
+ }
+
+ if (iap->UI)
+ rc = ACTION_PerformUIAction(iap->package,action);
+ else
+ rc = ACTION_PerformAction(iap->package,action,FALSE);
+
+ if (rc == ERROR_FUNCTION_NOT_CALLED)
+ rc = ERROR_SUCCESS;
+
+ if (rc != ERROR_SUCCESS)
+ ERR("Execution halted due to error (%i)\n",rc);
+
+ return rc;
+}
+
+static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
+{
+ MSIQUERY * view;
UINT rc;
static const WCHAR ExecSeqQuery[] =
{'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
@@ -1176,7 +695,10 @@
' ','\'', 'I','n','s','t','a','l','l',
'V','a','l','i','d','a','t','e','\'', 0};
INT seq = 0;
+ iterate_action_param iap;
+ iap.package = package;
+ iap.UI = FALSE;
if (package->script->ExecuteSequenceRun)
{
@@ -1199,75 +721,15 @@
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)
- {
- LPCWSTR cond, action;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- action = MSI_RecordGetString(row,1);
- if (!action)
- {
- ERR("Error in retrieving action name\n");
- rc = ERROR_FUNCTION_FAILED;
- msiobj_release(&row->hdr);
- break;
- }
-
- /* check conditions */
- cond = MSI_RecordGetString(row,2);
- if (cond)
- {
- /* this is a hack to skip errors in the condition code */
- if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
- {
- TRACE("Skipping action: %s (condition is false)\n",
- debugstr_w(action));
- msiobj_release(&row->hdr);
- continue;
- }
- }
-
- rc = ACTION_PerformAction(package,action,FALSE);
-
- if (rc == ERROR_FUNCTION_NOT_CALLED)
- rc = ERROR_SUCCESS;
-
- if (rc != ERROR_SUCCESS)
- {
- ERR("Execution halted due to error (%i)\n",rc);
- msiobj_release(&row->hdr);
- break;
- }
-
- msiobj_release(&row->hdr);
- }
-
- MSI_ViewClose(view);
+ rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
msiobj_release(&view->hdr);
}
-end:
return rc;
}
-
static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
{
MSIQUERY * view;
@@ -1280,77 +742,21 @@
'`','S','e','q','u','e','n','c','e','`',' ',
'>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
'`','S','e','q','u','e','n','c','e','`',0};
-
+ iterate_action_param iap;
+
+ iap.package = package;
+ iap.UI = TRUE;
+
rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
if (rc == ERROR_SUCCESS)
{
- rc = MSI_ViewExecute(view, 0);
-
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- goto end;
- }
-
TRACE("Running the actions \n");
- while (1)
- {
- LPCWSTR action, cond;
- MSIRECORD * row = 0;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- action = MSI_RecordGetString(row,1);
- if (!action)
- {
- ERR("failed to fetch action\n");
- rc = ERROR_FUNCTION_FAILED;
- msiobj_release(&row->hdr);
- break;
- }
-
- /* check conditions */
- cond = MSI_RecordGetString(row,2);
- if (cond)
- {
- /* this is a hack to skip errors in the condition code */
- if (MSI_EvaluateConditionW(package,cond) == MSICONDITION_FALSE)
- {
- TRACE("Skipping action: %s (condition is false)\n",
- debugstr_w(action));
- msiobj_release(&row->hdr);
- continue;
- }
- }
-
- rc = ACTION_PerformUIAction(package,action);
-
- if (rc == ERROR_FUNCTION_NOT_CALLED)
- rc = ERROR_SUCCESS;
-
- if (rc != ERROR_SUCCESS)
- {
- ERR("Execution halted due to error (%i)\n",rc);
- msiobj_release(&row->hdr);
- break;
- }
-
- msiobj_release(&row->hdr);
- }
-
- MSI_ViewClose(view);
+ rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
msiobj_release(&view->hdr);
}
-end:
return rc;
}
@@ -1493,60 +899,51 @@
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));
+/*
+ * Actual Action Handlers
+ */
- strcpyW(new_path, path);
+static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
+{
+ MSIPACKAGE *package = (MSIPACKAGE*)param;
+ LPCWSTR dir;
+ LPWSTR full_path;
+ MSIRECORD *uirow;
+ MSIFOLDER *folder;
- while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
- new_path[len - 1] = 0;
+ dir = MSI_RecordGetString(row,1);
+ if (!dir)
+ {
+ ERR("Unable to get folder id \n");
+ return ERROR_SUCCESS;
+ }
- while(!CreateDirectoryW(new_path, NULL))
+ full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
+ if (!full_path)
{
- WCHAR *slash;
- DWORD last_error = GetLastError();
- if(last_error == ERROR_ALREADY_EXISTS)
- break;
+ ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
+ return ERROR_SUCCESS;
+ }
- if(last_error != ERROR_PATH_NOT_FOUND)
- {
- ret = FALSE;
- break;
- }
+ TRACE("Folder is %s\n",debugstr_w(full_path));
- if(!(slash = strrchrW(new_path, '\\')))
- {
- ret = FALSE;
- break;
- }
+ /* UI stuff */
+ uirow = MSI_CreateRecord(1);
+ MSI_RecordSetStringW(uirow,1,full_path);
+ ui_actiondata(package,szCreateFolders,uirow);
+ msiobj_release( &uirow->hdr );
- len = slash - new_path;
- new_path[len] = 0;
- if(!create_full_pathW(new_path))
- {
- ret = FALSE;
- break;
- }
- new_path[len] = '\\';
- }
+ if (folder->State == 0)
+ create_full_pathW(full_path);
- HeapFree(GetProcessHeap(), 0, new_path);
- return ret;
+ folder->State = 3;
+
+ HeapFree(GetProcessHeap(),0,full_path);
+ return ERROR_SUCCESS;
}
+
/*
* Also we cannot enable/disable components either, so for now I am just going
* to do all the directories for all the components.
@@ -1560,66 +957,12 @@
'`','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)
- {
- LPCWSTR dir;
- LPWSTR full_path;
- MSIRECORD *row = NULL, *uirow;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- dir = MSI_RecordGetString(row,1);
- if (!dir)
- {
- ERR("Unable to get folder id \n");
- msiobj_release(&row->hdr);
- continue;
- }
-
- full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
- if (!full_path)
- {
- ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
- msiobj_release(&row->hdr);
- continue;
- }
-
- TRACE("Folder is %s\n",debugstr_w(full_path));
-
- /* UI stuff */
- uirow = MSI_CreateRecord(1);
- MSI_RecordSetStringW(uirow,1,full_path);
- ui_actiondata(package,szCreateFolders,uirow);
- msiobj_release( &uirow->hdr );
-
- if (folder->State == 0)
- create_full_pathW(full_path);
-
- folder->State = 3;
-
- msiobj_release(&row->hdr);
- HeapFree(GetProcessHeap(),0,full_path);
- }
- MSI_ViewClose(view);
+ rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
msiobj_release(&view->hdr);
return rc;
@@ -1673,8 +1016,68 @@
return index;
}
-static void load_feature(MSIPACKAGE* package, MSIRECORD * row)
+typedef struct {
+ MSIPACKAGE *package;
+ INT index;
+ INT cnt;
+} _ilfs;
+
+static UINT iterate_component_check(MSIRECORD *row, LPVOID param)
+{
+ _ilfs* ilfs= (_ilfs*)param;
+ INT c_indx;
+
+ c_indx = load_component(ilfs->package,row);
+
+ ilfs->package->features[ilfs->index].Components[ilfs->cnt] = c_indx;
+ ilfs->package->features[ilfs->index].ComponentCount ++;
+ TRACE("Loaded new component to index %i\n",c_indx);
+
+ return ERROR_SUCCESS;
+}
+
+static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
+{
+ _ilfs* ilfs= (_ilfs*)param;
+ LPCWSTR component;
+ DWORD rc;
+ INT c_indx;
+ INT cnt = ilfs->package->features[ilfs->index].ComponentCount;
+ MSIQUERY * view;
+ static const WCHAR Query[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
+ '`','C','o','m','p','o','n','e','n','t','`',' ',
+ 'W','H','E','R','E',' ',
+ '`','C','o','m','p','o','n','e','n','t','`',' ',
+ '=','\'','%','s','\'',0};
+
+ component = MSI_RecordGetString(row,1);
+
+ /* check to see if the component is already loaded */
+ c_indx = get_loaded_component(ilfs->package,component);
+ if (c_indx != -1)
+ {
+ TRACE("Component %s already loaded at %i\n", debugstr_w(component),
+ c_indx);
+ ilfs->package->features[ilfs->index].Components[cnt] = c_indx;
+ ilfs->package->features[ilfs->index].ComponentCount ++;
+ return ERROR_SUCCESS;
+ }
+
+ rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component);
+ if (rc != ERROR_SUCCESS)
+ return ERROR_SUCCESS;
+
+ ilfs->cnt = cnt;
+ rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs);
+ msiobj_release( &view->hdr );
+
+ return ERROR_SUCCESS;
+}
+
+static UINT load_feature(MSIRECORD * row, LPVOID param)
{
+ MSIPACKAGE* package = (MSIPACKAGE*)param;
int index = package->loaded_features;
DWORD sz;
static const WCHAR Query1[] =
@@ -1684,17 +1087,12 @@
'C','o','m','p','o','n','e','n','t','s','`',' ',
'W','H','E','R','E',' ',
'`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
- static const WCHAR Query2[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
- '`','C','o','m','p','o','n','e','n','t','`',' ',
- 'W','H','E','R','E',' ',
- '`','C','o','m','p','o','n','e','n','t','`',' ',
- '=','\'','%','s','\'',0};
MSIQUERY * view;
- MSIQUERY * view2;
- MSIRECORD * row2;
- MSIRECORD * row3;
UINT rc;
+ _ilfs ilfs;
+
+ ilfs.package = package;
+ ilfs.index = index;
/* fill in the data */
@@ -1741,79 +1139,20 @@
/* load feature components */
- rc = MSI_OpenQuery(package->db, &view, Query1, package->features[index].Feature);
- if (rc != ERROR_SUCCESS)
- return;
- rc = MSI_ViewExecute(view,0);
+ rc = MSI_OpenQuery(package->db, &view, Query1,
+ package->features[index].Feature);
if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return;
- }
- while (1)
- {
- LPCWSTR component;
- DWORD rc;
- INT c_indx;
- INT cnt = package->features[index].ComponentCount;
-
- rc = MSI_ViewFetch(view,&row2);
- if (rc != ERROR_SUCCESS)
- break;
-
- component = MSI_RecordGetString(row2,1);
-
- /* check to see if the component is already loaded */
- c_indx = get_loaded_component(package,component);
- if (c_indx != -1)
- {
- TRACE("Component %s already loaded at %i\n", debugstr_w(component),
- c_indx);
- package->features[index].Components[cnt] = c_indx;
- package->features[index].ComponentCount ++;
- msiobj_release( &row2->hdr );
- continue;
- }
-
- rc = MSI_OpenQuery(package->db, &view2, Query2, component);
- 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);
+ return ERROR_SUCCESS;
+
+ MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
msiobj_release(&view->hdr);
+
+ return ERROR_SUCCESS;
}
-static UINT load_file(MSIPACKAGE* package, MSIRECORD * row)
+static UINT load_file(MSIRECORD *row, LPVOID param)
{
+ MSIPACKAGE* package = (MSIPACKAGE*)param;
DWORD index = package->loaded_files;
LPCWSTR component;
@@ -1860,7 +1199,6 @@
static UINT load_all_files(MSIPACKAGE *package)
{
MSIQUERY * view;
- MSIRECORD * row;
UINT rc;
static const WCHAR Query[] =
{'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
@@ -1874,26 +1212,7 @@
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return ERROR_SUCCESS;
- }
-
- while (1)
- {
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
- load_file(package,row);
- msiobj_release(&row->hdr);
- }
- MSI_ViewClose(view);
+ rc = MSI_IterateRecords(view, NULL, load_file, package);
msiobj_release(&view->hdr);
return ERROR_SUCCESS;
@@ -1916,7 +1235,6 @@
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',' ',
@@ -1937,25 +1255,8 @@
rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
if (rc != ERROR_SUCCESS)
return rc;
- rc = MSI_ViewExecute(view,0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
- while (1)
- {
- DWORD rc;
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- break;
-
- load_feature(package,row);
- msiobj_release(&row->hdr);
- }
- MSI_ViewClose(view);
+ rc = MSI_IterateRecords(view, NULL, load_feature, package);
msiobj_release(&view->hdr);
load_all_files(package);
@@ -1963,32 +1264,6 @@
return ERROR_SUCCESS;
}
-UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action)
-{
- UINT count;
- LPWSTR *newbuf = NULL;
- if (script >= TOTAL_SCRIPTS)
- {
- FIXME("Unknown script requested %i\n",script);
- return ERROR_FUNCTION_FAILED;
- }
- TRACE("Scheduling Action %s in script %i\n",debugstr_w(action), script);
-
- count = package->script->ActionCount[script];
- package->script->ActionCount[script]++;
- if (count != 0)
- newbuf = HeapReAlloc(GetProcessHeap(),0,
- package->script->Actions[script],
- package->script->ActionCount[script]* sizeof(LPWSTR));
- else
- newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
-
- newbuf[count] = strdupW(action);
- package->script->Actions[script] = newbuf;
-
- return ERROR_SUCCESS;
-}
-
static UINT execute_script(MSIPACKAGE *package, UINT script )
{
int i;
@@ -2135,128 +1410,6 @@
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));
-
- if (!name)
- return NULL;
-
- /* special resolving for Target and Source root dir */
- if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
- {
- if (!source)
- {
- path = load_dynamic_property(package,cszTargetDir,NULL);
- if (!path)
- {
- path = load_dynamic_property(package,cszRootDrive,NULL);
- if (set_prop)
- MSI_SetPropertyW(package,cszTargetDir,path);
- }
- if (folder)
- {
- for (i = 0; i < package->loaded_folders; i++)
- {
- if (strcmpW(package->folders[i].Directory,name)==0)
- break;
- }
- *folder = &(package->folders[i]);
- }
- return path;
- }
- else
- {
- path = load_dynamic_property(package,cszSourceDir,NULL);
- if (!path)
- {
- path = load_dynamic_property(package,cszDatabase,NULL);
- if (path)
- {
- p = strrchrW(path,'\\');
- if (p)
- *(p+1) = 0;
- }
- }
- if (folder)
- {
- for (i = 0; i < package->loaded_folders; i++)
- {
- if (strcmpW(package->folders[i].Directory,name)==0)
- break;
- }
- *folder = &(package->folders[i]);
- }
- return path;
- }
- }
-
- for (i = 0; i < package->loaded_folders; i++)
- {
- if (strcmpW(package->folders[i].Directory,name)==0)
- break;
- }
-
- if (i >= package->loaded_folders)
- return NULL;
-
- if (folder)
- *folder = &(package->folders[i]);
-
- if (!source && package->folders[i].ResolvedTarget)
- {
- path = strdupW(package->folders[i].ResolvedTarget);
- TRACE(" already resolved to %s\n",debugstr_w(path));
- return path;
- }
- else if (source && package->folders[i].ResolvedSource)
- {
- path = strdupW(package->folders[i].ResolvedSource);
- TRACE(" (source)already resolved to %s\n",debugstr_w(path));
- return path;
- }
- else if (!source && package->folders[i].Property)
- {
- path = build_directory_name(2, package->folders[i].Property, NULL);
-
- TRACE(" internally set to %s\n",debugstr_w(path));
- if (set_prop)
- MSI_SetPropertyW(package,name,path);
- return path;
- }
-
- if (package->folders[i].ParentIndex >= 0)
- {
- LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory;
-
- TRACE(" ! Parent is %s\n", debugstr_w(parent));
-
- p = resolve_folder(package, parent, source, set_prop, NULL);
- if (!source)
- {
- TRACE(" TargetDefault = %s\n",debugstr_w(package->folders[i].TargetDefault));
- path = build_directory_name(3, p, package->folders[i].TargetDefault, NULL);
- package->folders[i].ResolvedTarget = strdupW(path);
- TRACE(" resolved into %s\n",debugstr_w(path));
- if (set_prop)
- MSI_SetPropertyW(package,name,path);
- }
- else
- {
- path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL);
- TRACE(" (source)resolved into %s\n",debugstr_w(path));
- package->folders[i].ResolvedSource = strdupW(path);
- }
- HeapFree(GetProcessHeap(),0,p);
- }
- return path;
-}
-
/* scan for and update current install states */
static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
{
@@ -2297,72 +1450,6 @@
}
}
-/* update compoennt state based on a feature change */
-void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
-{
- int i;
- INSTALLSTATE newstate;
- MSIFEATURE *feature;
-
- i = get_loaded_feature(package,szFeature);
- if (i < 0)
- return;
-
- feature = &package->features[i];
- newstate = feature->ActionRequest;
-
- for( i = 0; i < feature->ComponentCount; i++)
- {
- MSICOMPONENT* component = &package->components[feature->Components[i]];
-
- TRACE("MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)\n",
- newstate, debugstr_w(component->Component), component->Installed,
- component->Action, component->ActionRequest);
-
- if (!component->Enabled)
- continue;
- else
- {
- if (newstate == INSTALLSTATE_LOCAL)
- {
- component->ActionRequest = INSTALLSTATE_LOCAL;
- component->Action = INSTALLSTATE_LOCAL;
- }
- else
- {
- int j,k;
-
- component->ActionRequest = newstate;
- component->Action = newstate;
-
- /*if any other feature wants is local we need to set it local*/
- for (j = 0;
- j < package->loaded_features &&
- component->ActionRequest != INSTALLSTATE_LOCAL;
- j++)
- {
- for (k = 0; k < package->features[j].ComponentCount; k++)
- if ( package->features[j].Components[k] ==
- feature->Components[i] )
- {
- if (package->features[j].ActionRequest ==
- INSTALLSTATE_LOCAL)
- {
- TRACE("Saved by %s\n", debugstr_w(package->features[j].Feature));
- component->ActionRequest = INSTALLSTATE_LOCAL;
- component->Action = INSTALLSTATE_LOCAL;
- }
- break;
- }
- }
- }
- }
- TRACE("Result (%i): Component %s (Installed %i, Action %i, Request %i)\n",
- newstate, debugstr_w(component->Component), component->Installed,
- component->Action, component->ActionRequest);
- }
-}
-
static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property,
INSTALLSTATE state)
{
@@ -2579,6 +1666,52 @@
return ERROR_SUCCESS;
}
+static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
+{
+ MSIPACKAGE *package = (MSIPACKAGE*)param;
+ LPCWSTR name;
+ LPWSTR path;
+
+ name = MSI_RecordGetString(row,1);
+
+ /* This helper function now does ALL the work */
+ TRACE("Dir %s ...\n",debugstr_w(name));
+ load_folder(package,name);
+ path = resolve_folder(package,name,FALSE,TRUE,NULL);
+ TRACE("resolves to %s\n",debugstr_w(path));
+ HeapFree( GetProcessHeap(), 0, path);
+
+ return ERROR_SUCCESS;
+}
+
+static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
+{
+ MSIPACKAGE *package = (MSIPACKAGE*)param;
+ LPCWSTR Feature;
+ int feature_index;
+
+ Feature = MSI_RecordGetString(row,1);
+
+ feature_index = get_loaded_feature(package,Feature);
+ if (feature_index < 0)
+ ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature));
+ else
+ {
+ LPCWSTR Condition;
+ Condition = MSI_RecordGetString(row,3);
+
+ if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
+ {
+ int level = MSI_RecordGetInteger(row,2);
+ TRACE("Reseting feature %s to level %i\n", debugstr_w(Feature),
+ level);
+ package->features[feature_index].Level = level;
+ }
+ }
+ return ERROR_SUCCESS;
+}
+
+
/*
* A lot is done in this function aside from just the costing.
* The costing needs to be implemented at some point but for now I am going
@@ -2614,39 +1747,8 @@
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)
- {
- LPCWSTR name;
- LPWSTR path;
- MSIRECORD * row = 0;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- name = MSI_RecordGetString(row,1);
-
- /* This helper function now does ALL the work */
- TRACE("Dir %s ...\n",debugstr_w(name));
- load_folder(package,name);
- path = resolve_folder(package,name,FALSE,TRUE,NULL);
- TRACE("resolves to %s\n",debugstr_w(path));
- HeapFree( GetProcessHeap(), 0, path);
-
- msiobj_release(&row->hdr);
- }
- MSI_ViewClose(view);
+ rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
+ package);
msiobj_release(&view->hdr);
}
@@ -2739,51 +1841,8 @@
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)
- {
- LPCWSTR Feature;
- MSIRECORD * row = 0;
- int feature_index;
-
- rc = MSI_ViewFetch(view,&row);
-
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- Feature = MSI_RecordGetString(row,1);
-
- feature_index = get_loaded_feature(package,Feature);
- if (feature_index < 0)
- ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature));
- else
- {
- LPCWSTR Condition;
- Condition = MSI_RecordGetString(row,3);
-
- if (MSI_EvaluateConditionW(package,Condition) ==
- MSICONDITION_TRUE)
- {
- int level = MSI_RecordGetInteger(row,2);
- TRACE("Reseting feature %s to level %i\n",
- debugstr_w(Feature), level);
- package->features[feature_index].Level = level;
- }
- }
-
- msiobj_release(&row->hdr);
- }
- MSI_ViewClose(view);
+ rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
+ package);
msiobj_release(&view->hdr);
}
@@ -2815,526 +1874,329 @@
return SetFeatureStates(package);
}
-/*
- * This is a helper function for handling embedded cabinet media
- */
-static UINT writeout_cabinet_stream(MSIPACKAGE *package, LPCWSTR stream_name,
- WCHAR* source)
+/* OK this value is "interpreted" and then formatted based on the
+ first few characters */
+static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type,
+ DWORD *size)
{
- 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)
+ LPSTR data = NULL;
+ if (value[0]=='#' && value[1]!='#' && value[1]!='%')
{
- ERR("Unable to create file %s\n",debugstr_w(source));
- rc = ERROR_FUNCTION_FAILED;
- goto end;
- }
-
- WriteFile(the_file,data,size,&write,NULL);
- CloseHandle(the_file);
- TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
-end:
- HeapFree(GetProcessHeap(),0,data);
- return rc;
-}
-
-
-/* Support functions for FDI functions */
-typedef struct
-{
- MSIPACKAGE* package;
- LPCSTR cab_path;
- LPCSTR file_name;
-} CabData;
-
-static void * cabinet_alloc(ULONG cb)
-{
- return HeapAlloc(GetProcessHeap(), 0, cb);
-}
+ if (value[1]=='x')
+ {
+ LPWSTR ptr;
+ CHAR byte[5];
+ LPWSTR deformated = NULL;
+ int count;
-static void cabinet_free(void *pv)
-{
- HeapFree(GetProcessHeap(), 0, pv);
-}
+ deformat_string(package, &value[2], &deformated);
-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);
-}
+ /* binary value type */
+ ptr = deformated;
+ *type = REG_BINARY;
+ if (strlenW(ptr)%2)
+ *size = (strlenW(ptr)/2)+1;
+ else
+ *size = strlenW(ptr)/2;
-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;
-}
+ data = HeapAlloc(GetProcessHeap(),0,*size);
-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;
-}
+ byte[0] = '0';
+ byte[1] = 'x';
+ byte[4] = 0;
+ count = 0;
+ /* if uneven pad with a zero in front */
+ if (strlenW(ptr)%2)
+ {
+ byte[2]= '0';
+ byte[3]= *ptr;
+ ptr++;
+ data[count] = (BYTE)strtol(byte,NULL,0);
+ count ++;
+ TRACE("Uneven byte count\n");
+ }
+ while (*ptr)
+ {
+ byte[2]= *ptr;
+ ptr++;
+ byte[3]= *ptr;
+ ptr++;
+ data[count] = (BYTE)strtol(byte,NULL,0);
+ count ++;
+ }
+ HeapFree(GetProcessHeap(),0,deformated);
-static int cabinet_close(INT_PTR hf)
-{
- return CloseHandle((HANDLE)hf) ? 0 : -1;
-}
+ TRACE("Data %li bytes(%i)\n",*size,count);
+ }
+ else
+ {
+ LPWSTR deformated;
+ LPWSTR p;
+ DWORD d = 0;
+ deformat_string(package, &value[1], &deformated);
-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);
-}
+ *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);
-static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
-{
- /* FIXME: try to do more processing in this function */
- switch (fdint)
- {
- case fdintCOPY_FILE:
+ HeapFree(GetProcessHeap(),0,deformated);
+ }
+ }
+ else
{
- CabData *data = (CabData*) pfdin->pv;
- ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
- char *file;
-
- LPWSTR trackname;
- LPWSTR trackpath;
- LPWSTR tracknametmp;
- static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
-
- if (data->file_name && lstrcmpiA(data->file_name,pfdin->psz1))
- return 0;
-
- file = cabinet_alloc((len+1)*sizeof(char));
- strcpy(file, data->cab_path);
- strcat(file, pfdin->psz1);
-
- TRACE("file: %s\n", debugstr_a(file));
-
- /* track this file so it can be deleted if not installed */
- trackpath=strdupAtoW(file);
- tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
- trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) +
- strlenW(tmpprefix)+1) * sizeof(WCHAR));
-
- strcpyW(trackname,tmpprefix);
- strcatW(trackname,tracknametmp);
-
- track_tempfile(data->package, trackname, trackpath);
+ static const WCHAR szMulti[] = {'[','~',']',0};
+ LPCWSTR ptr;
+ *type=REG_SZ;
- HeapFree(GetProcessHeap(),0,trackpath);
- HeapFree(GetProcessHeap(),0,trackname);
- HeapFree(GetProcessHeap(),0,tracknametmp);
+ if (value[0]=='#')
+ {
+ if (value[1]=='%')
+ {
+ ptr = &value[2];
+ *type=REG_EXPAND_SZ;
+ }
+ else
+ ptr = &value[1];
+ }
+ else
+ ptr=value;
- 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;
+ if (strstrW(value,szMulti))
+ *type = REG_MULTI_SZ;
- cabinet_close(pfdin->hf);
- return 1;
- }
- default:
- return 0;
+ *size = deformat_string(package, ptr,(LPWSTR*)&data);
}
+ return data;
}
-/***********************************************************************
- * 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)
+static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
{
- 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;
- }
+ MSIPACKAGE *package = (MSIPACKAGE*)param;
+ static const WCHAR szHCR[] =
+ {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
+ 'R','O','O','T','\\',0};
+ static const WCHAR szHCU[] =
+ {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
+ 'U','S','E','R','\\',0};
+ static const WCHAR szHLM[] =
+ {'H','K','E','Y','_','L','O','C','A','L','_',
+ 'M','A','C','H','I','N','E','\\',0};
+ static const WCHAR szHU[] =
+ {'H','K','E','Y','_','U','S','E','R','S','\\',0};
- if (!(cabinet = strdupWtoA( source )))
- {
- FDIDestroy(hfdi);
- return FALSE;
- }
- if (!(cab_path = strdupWtoA( path )))
- {
- FDIDestroy(hfdi);
- HeapFree(GetProcessHeap(), 0, cabinet);
- return FALSE;
- }
+ LPSTR value_data = NULL;
+ HKEY root_key, hkey;
+ DWORD type,size;
+ LPWSTR deformated;
+ LPCWSTR szRoot, component, name, key, value;
+ INT component_index;
+ MSIRECORD * uirow;
+ LPWSTR uikey;
+ INT root;
+ BOOL check_first = FALSE;
+ UINT rc;
- data.package = package;
- data.cab_path = cab_path;
- if (file)
- file_name = strdupWtoA(file);
- else
- file_name = NULL;
- data.file_name = file_name;
+ ui_progress(package,2,0,0,0);
- ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
+ value = NULL;
+ key = NULL;
+ uikey = NULL;
+ name = NULL;
- if (!ret)
- ERR("FDICopy failed\n");
+ component = MSI_RecordGetString(row, 6);
+ component_index = get_loaded_component(package,component);
- FDIDestroy(hfdi);
+ if (!ACTION_VerifyComponentForAction(package, component_index,
+ INSTALLSTATE_LOCAL))
+ {
+ TRACE("Skipping write due to disabled component %s\n",
+ debugstr_w(component));
- HeapFree(GetProcessHeap(), 0, cabinet);
- HeapFree(GetProcessHeap(), 0, cab_path);
- HeapFree(GetProcessHeap(), 0, file_name);
+ package->components[component_index].Action =
+ package->components[component_index].Installed;
- return ret;
-}
+ return ERROR_SUCCESS;
+ }
-static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path,
- MSIFILE* file)
-{
- UINT rc = ERROR_SUCCESS;
- MSIRECORD * row = 0;
- static WCHAR source[MAX_PATH];
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
- '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
- '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',
- ' ','%', 'i',' ','O','R','D','E','R',' ','B','Y',' ',
- '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0};
- LPCWSTR cab;
- DWORD sz;
- INT seq;
- static UINT last_sequence = 0;
+ package->components[component_index].Action = INSTALLSTATE_LOCAL;
- if (file->Attributes & msidbFileAttributesNoncompressed)
+ name = MSI_RecordGetString(row, 4);
+ if( MSI_RecordIsNull(row,5) && name )
{
- TRACE("Uncompressed File, no media to ready.\n");
- return ERROR_SUCCESS;
+ /* null values can have special meanings */
+ if (name[0]=='-' && name[1] == 0)
+ return ERROR_SUCCESS;
+ else if ((name[0]=='+' && name[1] == 0) ||
+ (name[0] == '*' && name[1] == 0))
+ name = NULL;
+ check_first = TRUE;
}
- if (file->Sequence <= last_sequence)
+ root = MSI_RecordGetInteger(row,2);
+ key = MSI_RecordGetString(row, 3);
+
+ /* get the root key */
+ switch (root)
{
- TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence);
- /*extract_a_cabinet_file(package, source,path,file->File); */
- return ERROR_SUCCESS;
+ case 0: root_key = HKEY_CLASSES_ROOT;
+ szRoot = szHCR;
+ break;
+ case 1: root_key = HKEY_CURRENT_USER;
+ szRoot = szHCU;
+ break;
+ case 2: root_key = HKEY_LOCAL_MACHINE;
+ szRoot = szHLM;
+ break;
+ case 3: root_key = HKEY_USERS;
+ szRoot = szHU;
+ break;
+ default:
+ ERR("Unknown root %i\n",root);
+ root_key=NULL;
+ szRoot = NULL;
+ break;
}
+ if (!root_key)
+ return ERROR_SUCCESS;
- row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence);
- if (!row)
- return ERROR_FUNCTION_FAILED;
-
- seq = MSI_RecordGetInteger(row,2);
- last_sequence = seq;
+ deformat_string(package, key , &deformated);
+ size = strlenW(deformated) + strlenW(szRoot) + 1;
+ uikey = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
+ strcpyW(uikey,szRoot);
+ strcatW(uikey,deformated);
- cab = MSI_RecordGetString(row,4);
- if (cab)
+ if (RegCreateKeyW( root_key, deformated, &hkey))
{
- 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);
+ ERR("Could not create key %s\n",debugstr_w(deformated));
+ HeapFree(GetProcessHeap(),0,deformated);
+ HeapFree(GetProcessHeap(),0,uikey);
+ return ERROR_SUCCESS;
}
+ HeapFree(GetProcessHeap(),0,deformated);
+
+ value = MSI_RecordGetString(row,5);
+ if (value)
+ value_data = parse_value(package, value, &type, &size);
else
{
- sz = MAX_PATH;
- MSI_GetPropertyW(package,cszSourceDir,source,&sz);
- strcpyW(path,source);
+ static const WCHAR szEmpty[] = {0};
+ value_data = (LPSTR)strdupW(szEmpty);
+ size = 0;
+ type = REG_SZ;
}
- msiobj_release(&row->hdr);
- return rc;
-}
-inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)
-{
- UINT rc = ERROR_SUCCESS;
- MSIFOLDER *folder;
- LPWSTR install_path;
+ deformat_string(package, name, &deformated);
- install_path = resolve_folder(package, package->components[component].Directory,
- FALSE, FALSE, &folder);
- if (!install_path)
- return ERROR_FUNCTION_FAILED;
+ /* get the double nulls to terminate SZ_MULTI */
+ if (type == REG_MULTI_SZ)
+ size +=sizeof(WCHAR);
- /* create the path */
- if (folder->State == 0)
+ if (!check_first)
{
- create_full_pathW(install_path);
- folder->State = 2;
+ TRACE("Setting value %s of %s\n",debugstr_w(deformated),
+ debugstr_w(uikey));
+ RegSetValueExW(hkey, deformated, 0, type, value_data, size);
}
- 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++)
+ else
{
- WCHAR path_to_source[MAX_PATH];
- MSIFILE *file;
-
- file = &package->files[index];
-
- if (file->Temporary)
- continue;
-
-
- if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex,
- INSTALLSTATE_LOCAL))
+ DWORD sz = 0;
+ rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
+ if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
{
- ui_progress(package,2,file->FileSize,0,0);
- TRACE("File %s is not scheduled for install\n",
- debugstr_w(file->File));
-
- continue;
+ TRACE("value %s of %s checked already exists\n",
+ debugstr_w(deformated), debugstr_w(uikey));
}
-
- if ((file->State == 1) || (file->State == 2))
+ else
{
- LPWSTR p;
- MSICOMPONENT* comp = NULL;
-
- TRACE("Installing %s\n",debugstr_w(file->File));
- rc = ready_media_for_file(package, path_to_source, file);
- /*
- * WARNING!
- * our file table could change here because a new temp file
- * may have been created
- */
- file = &package->files[index];
- if (rc != ERROR_SUCCESS)
- {
- ERR("Unable to ready media\n");
- rc = ERROR_FUNCTION_FAILED;
- break;
- }
-
- create_component_directory( package, file->ComponentIndex);
+ TRACE("Checked and setting value %s of %s\n",
+ debugstr_w(deformated), debugstr_w(uikey));
+ if (deformated || size)
+ RegSetValueExW(hkey, deformated, 0, type, value_data, size);
+ }
+ }
+ RegCloseKey(hkey);
- /* recalculate file paths because things may have changed */
+ uirow = MSI_CreateRecord(3);
+ MSI_RecordSetStringW(uirow,2,deformated);
+ MSI_RecordSetStringW(uirow,1,uikey);
- if (file->ComponentIndex >= 0)
- comp = &package->components[file->ComponentIndex];
+ if (type == REG_SZ)
+ MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
+ else
+ MSI_RecordSetStringW(uirow,3,value);
- p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
- HeapFree(GetProcessHeap(),0,file->TargetPath);
+ ui_actiondata(package,szWriteRegistryValues,uirow);
+ msiobj_release( &uirow->hdr );
- file->TargetPath = build_directory_name(2, p, file->FileName);
- HeapFree(GetProcessHeap(),0,p);
+ HeapFree(GetProcessHeap(),0,value_data);
+ HeapFree(GetProcessHeap(),0,deformated);
+ HeapFree(GetProcessHeap(),0,uikey);
- if (file->Attributes & msidbFileAttributesNoncompressed)
- {
- p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
- file->SourcePath = build_directory_name(2, p, file->ShortName);
- HeapFree(GetProcessHeap(),0,p);
- }
- else
- file->SourcePath = build_directory_name(2, path_to_source,
- file->File);
+ return ERROR_SUCCESS;
+}
+static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
+{
+ UINT rc;
+ MSIQUERY * view;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','R','e','g','i','s','t','r','y','`',0 };
- TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
- debugstr_w(file->TargetPath));
+ if (!package)
+ return ERROR_INVALID_HANDLE;
- /* 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);
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return ERROR_SUCCESS;
-
- if (file->Attributes & msidbFileAttributesNoncompressed)
- rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
- else
- rc = MoveFileW(file->SourcePath, file->TargetPath);
+ /* increment progress bar each time action data is sent */
+ ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
- if (!rc)
- {
- rc = GetLastError();
- ERR("Unable to move/copy file (%s -> %s) (error %d)\n",
- debugstr_w(file->SourcePath), debugstr_w(file->TargetPath),
- rc);
- if (rc == ERROR_ALREADY_EXISTS && file->State == 2)
- {
- if (!CopyFileW(file->SourcePath,file->TargetPath,FALSE))
- ERR("Unable to copy file (%s -> %s) (error %ld)\n",
- debugstr_w(file->SourcePath),
- debugstr_w(file->TargetPath), GetLastError());
- if (!(file->Attributes & msidbFileAttributesNoncompressed))
- DeleteFileW(file->SourcePath);
- rc = 0;
- }
- else if (rc == ERROR_FILE_NOT_FOUND)
- {
- ERR("Source File Not Found! Continuing\n");
- rc = 0;
- }
- else if (file->Attributes & msidbFileAttributesVital)
- {
- ERR("Ignoring Error and continuing (nonvital file)...\n");
- rc = 0;
- }
- }
- else
- {
- file->State = 4;
- rc = ERROR_SUCCESS;
- }
- }
- }
+ rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
+ msiobj_release(&view->hdr);
return rc;
}
-inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
- LPWSTR* file_source)
+static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
{
- DWORD index;
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- for (index = 0; index < package->loaded_files; index ++)
- {
- if (strcmpW(file_key,package->files[index].File)==0)
- {
- if (package->files[index].State >= 2)
- {
- *file_source = strdupW(package->files[index].TargetPath);
- return ERROR_SUCCESS;
- }
- else
- return ERROR_FILE_NOT_FOUND;
- }
- }
+ package->script->CurrentlyScripting = TRUE;
- return ERROR_FUNCTION_FAILED;
+ return ERROR_SUCCESS;
}
-static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
+
+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;
- 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};
+ int i;
- if (!package)
- return ERROR_INVALID_HANDLE;
+ TRACE(" InstallValidate \n");
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
@@ -3345,4608 +2207,1870 @@
msiobj_release(&view->hdr);
return rc;
}
-
while (1)
{
- WCHAR *file_source = NULL;
- WCHAR dest_name[0x100];
- LPWSTR dest_path, dest;
- LPCWSTR file_key, component;
- INT component_index;
-
- DWORD sz;
-
rc = MSI_ViewFetch(view,&row);
if (rc != ERROR_SUCCESS)
{
rc = ERROR_SUCCESS;
break;
}
+ progress +=1;
- component = MSI_RecordGetString(row,2);
- component_index = get_loaded_component(package,component);
+ msiobj_release(&row->hdr);
+ }
+ MSI_ViewClose(view);
+ msiobj_release(&view->hdr);
- if (!ACTION_VerifyComponentForAction(package, component_index,
- INSTALLSTATE_LOCAL))
- {
- TRACE("Skipping copy due to disabled component %s\n",
- debugstr_w(component));
+ 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);
- /* the action taken was the same as the current install state */
- package->components[component_index].Action =
- package->components[component_index].Installed;
+ for(i = 0; i < package->loaded_features; i++)
+ {
+ MSIFEATURE* feature = &package->features[i];
+ TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
+ debugstr_w(feature->Feature), feature->Installed, feature->Action,
+ feature->ActionRequest);
+ }
+
+ return ERROR_SUCCESS;
+}
- msiobj_release(&row->hdr);
- continue;
- }
-
- package->components[component_index].Action = INSTALLSTATE_LOCAL;
+static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
+{
+ MSIPACKAGE* package = (MSIPACKAGE*)param;
+ LPCWSTR cond = NULL;
+ LPCWSTR message = NULL;
+ static const WCHAR title[]=
+ {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
- file_key = MSI_RecordGetString(row,3);
- if (!file_key)
- {
- ERR("Unable to get file key\n");
- msiobj_release(&row->hdr);
- break;
- }
+ cond = MSI_RecordGetString(row,1);
- rc = get_file_target(package,file_key,&file_source);
+ if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
+ {
+ LPWSTR deformated;
+ message = MSI_RecordGetString(row,2);
+ deformat_string(package,message,&deformated);
+ MessageBoxW(NULL,deformated,title,MB_OK);
+ HeapFree(GetProcessHeap(),0,deformated);
+ return ERROR_FUNCTION_FAILED;
+ }
- if (rc != ERROR_SUCCESS)
- {
- ERR("Original file unknown %s\n",debugstr_w(file_key));
- msiobj_release(&row->hdr);
- HeapFree(GetProcessHeap(),0,file_source);
- continue;
- }
+ return ERROR_SUCCESS;
+}
- if (MSI_RecordIsNull(row,4))
- {
- strcpyW(dest_name,strrchrW(file_source,'\\')+1);
- }
- else
- {
- sz=0x100;
- MSI_RecordGetStringW(row,4,dest_name,&sz);
- reduce_to_longfilename(dest_name);
- }
+static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
+{
+ UINT rc;
+ MSIQUERY * view = NULL;
+ 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};
- if (MSI_RecordIsNull(row,5))
- {
- LPWSTR p;
- dest_path = strdupW(file_source);
- p = strrchrW(dest_path,'\\');
- if (p)
- *p=0;
- }
- else
- {
- LPCWSTR destkey;
- destkey = MSI_RecordGetString(row,5);
- dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);
- if (!dest_path)
- {
- ERR("Unable to get destination folder\n");
- msiobj_release(&row->hdr);
- HeapFree(GetProcessHeap(),0,file_source);
- break;
- }
- }
+ TRACE("Checking launch conditions\n");
- 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());
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return ERROR_SUCCESS;
- 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);
+ rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
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, LPCWSTR value, DWORD *type,
- DWORD *size)
+static LPWSTR resolve_keypath( MSIPACKAGE* package, INT
+ component_index)
{
- LPSTR data = NULL;
- if (value[0]=='#' && value[1]!='#' && value[1]!='%')
+ MSICOMPONENT* cmp = &package->components[component_index];
+
+ if (cmp->KeyPath[0]==0)
{
- if (value[1]=='x')
- {
- LPWSTR ptr;
- CHAR byte[5];
- LPWSTR deformated = NULL;
- int count;
+ LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
+ return p;
+ }
+ if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
+ {
+ MSIRECORD * row = 0;
+ UINT root,len;
+ LPWSTR deformated,buffer,deformated_name;
+ LPCWSTR key,name;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','R','e','g','i','s','t','r','y','`',' ',
+ '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};
- deformat_string(package, &value[2], &deformated);
+ row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
+ if (!row)
+ return NULL;
- /* binary value type */
- ptr = deformated;
- *type = REG_BINARY;
- if (strlenW(ptr)%2)
- *size = (strlenW(ptr)/2)+1;
- else
- *size = strlenW(ptr)/2;
+ root = MSI_RecordGetInteger(row,2);
+ key = MSI_RecordGetString(row, 3);
+ name = MSI_RecordGetString(row, 4);
+ deformat_string(package, key , &deformated);
+ deformat_string(package, name, &deformated_name);
- data = HeapAlloc(GetProcessHeap(),0,*size);
+ len = strlenW(deformated) + 6;
+ if (deformated_name)
+ len+=strlenW(deformated_name);
- byte[0] = '0';
- byte[1] = 'x';
- byte[4] = 0;
- count = 0;
- /* if uneven pad with a zero in front */
- if (strlenW(ptr)%2)
- {
- byte[2]= '0';
- byte[3]= *ptr;
- ptr++;
- data[count] = (BYTE)strtol(byte,NULL,0);
- count ++;
- TRACE("Uneven byte count\n");
- }
- while (*ptr)
- {
- byte[2]= *ptr;
- ptr++;
- byte[3]= *ptr;
- ptr++;
- data[count] = (BYTE)strtol(byte,NULL,0);
- count ++;
- }
- HeapFree(GetProcessHeap(),0,deformated);
+ buffer = HeapAlloc(GetProcessHeap(),0, len *sizeof(WCHAR));
- TRACE("Data %li bytes(%i)\n",*size,count);
- }
+ if (deformated_name)
+ sprintfW(buffer,fmt2,root,deformated,deformated_name);
else
- {
- LPWSTR deformated;
- LPWSTR p;
- DWORD d = 0;
- deformat_string(package, &value[1], &deformated);
+ sprintfW(buffer,fmt,root,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);
+ HeapFree(GetProcessHeap(),0,deformated_name);
+ msiobj_release(&row->hdr);
- HeapFree(GetProcessHeap(),0,deformated);
- }
+ return buffer;
+ }
+ else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
+ {
+ FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
+ return NULL;
}
else
{
- static const WCHAR szMulti[] = {'[','~',']',0};
- LPCWSTR ptr;
- *type=REG_SZ;
+ int j;
+ j = get_loaded_file(package,cmp->KeyPath);
- if (value[0]=='#')
+ if (j>=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);
+ LPWSTR p = strdupW(package->files[j].TargetPath);
+ return p;
+ }
}
- return data;
+ return NULL;
}
-static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
+static HKEY openSharedDLLsKey()
{
- 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;
+ 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};
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
- if (rc != ERROR_SUCCESS)
- return ERROR_SUCCESS;
+ RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
+ return hkey;
+}
- rc = MSI_ViewExecute(view, 0);
+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)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
+ count = 0;
+ RegCloseKey(hkey);
+ return count;
+}
- /* increment progress bar each time action data is sent */
- ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
+static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
+{
+ HKEY hkey;
- 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 deformated;
- LPCWSTR szRoot, component, name, key, value;
- INT component_index;
- MSIRECORD * uirow;
- LPWSTR uikey;
- INT root;
- BOOL check_first = FALSE;
+ hkey = openSharedDLLsKey();
+ if (count > 0)
+ RegSetValueExW(hkey,path,0,REG_DWORD,
+ (LPBYTE)&count,sizeof(count));
+ else
+ RegDeleteValueW(hkey,path);
+ RegCloseKey(hkey);
+ return count;
+}
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
- ui_progress(package,2,0,0,0);
+/*
+ * 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;
- value = NULL;
- key = NULL;
- uikey = NULL;
- name = NULL;
-
- component = MSI_RecordGetString(row, 6);
- component_index = get_loaded_component(package,component);
-
- if (!ACTION_VerifyComponentForAction(package, component_index,
- INSTALLSTATE_LOCAL))
- {
- TRACE("Skipping write due to disabled component %s\n",
- debugstr_w(component));
- msiobj_release(&row->hdr);
+ /* 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);
- package->components[component_index].Action =
- package->components[component_index].Installed;
+ if (package->components[index].Attributes &
+ msidbComponentAttributesSharedDllRefCount)
+ write = TRUE;
+ }
- goto next;
- }
+ /* increment counts */
+ for (j = 0; j < package->loaded_features; j++)
+ {
+ int i;
- package->components[component_index].Action = INSTALLSTATE_LOCAL;
+ if (!ACTION_VerifyFeatureForAction(package,j,INSTALLSTATE_LOCAL))
+ continue;
- name = MSI_RecordGetString(row, 4);
- if( MSI_RecordIsNull(row,5) && name )
+ for (i = 0; i < package->features[j].ComponentCount; i++)
{
- /* 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))
- name = NULL;
- check_first = TRUE;
+ 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;
- root = MSI_RecordGetInteger(row,2);
- key = MSI_RecordGetString(row, 3);
-
- /* get the root key */
- switch (root)
+ for (i = 0; i < package->features[j].ComponentCount; i++)
{
- 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 (package->features[j].Components[i] == index)
+ count--;
}
- if (!root_key)
+ }
+
+ /* ref count all the files in the component */
+ if (write)
+ for (j = 0; j < package->loaded_files; j++)
{
- msiobj_release(&row->hdr);
- goto next;
+ 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;
- 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 (write)
+ ACTION_WriteSharedDLLsCount(package->components[index].FullKeypath,
+ package->components[index].RefCount);
+}
- 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);
+/*
+ * 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;
- value = MSI_RecordGetString(row,5);
- if (value)
- value_data = parse_value(package, value, &type, &size);
- else
+ 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)
{
- static const WCHAR szEmpty[] = {0};
- value_data = (LPSTR)strdupW(szEmpty);
- size = 0;
- type = REG_SZ;
- }
+ WCHAR *keypath = NULL;
+ MSIRECORD * uirow;
- deformat_string(package, name, &deformated);
+ squash_guid(package->components[i].ComponentId,squished_cc);
+
+ keypath = resolve_keypath(package,i);
+ package->components[i].FullKeypath = keypath;
- /* get the double nulls to terminate SZ_MULTI */
- if (type == REG_MULTI_SZ)
- size +=sizeof(WCHAR);
+ /* do the refcounting */
+ ACTION_RefCountComponent( package, i);
- if (!check_first)
- {
- TRACE("Setting value %s of %s\n",debugstr_w(deformated),
- debugstr_w(uikey));
- RegSetValueExW(hkey, deformated, 0, type, value_data, size);
- }
- else
- {
- DWORD sz = 0;
- rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
- if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
- {
- TRACE("value %s of %s checked already exists\n",
- debugstr_w(deformated), debugstr_w(uikey));
- }
- else
+ TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
+ debugstr_w(package->components[i].Component),
+ debugstr_w(squished_cc),
+ 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))
{
- TRACE("Checked and setting value %s of %s\n",
- debugstr_w(deformated), debugstr_w(uikey));
- if (deformated || size)
- RegSetValueExW(hkey, deformated, 0, type, value_data, size);
- }
- }
+ rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
+ if (rc != ERROR_SUCCESS)
+ continue;
- uirow = MSI_CreateRecord(3);
- MSI_RecordSetStringW(uirow,2,deformated);
- MSI_RecordSetStringW(uirow,1,uikey);
+ if (keypath)
+ {
+ RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath,
+ (strlenW(keypath)+1)*sizeof(WCHAR));
- if (type == REG_SZ)
- MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
- else
- MSI_RecordSetStringW(uirow,3,value);
+ 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;
- ui_actiondata(package,szWriteRegistryValues,uirow);
- msiobj_release( &uirow->hdr );
+ rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
+ if (rc != ERROR_SUCCESS)
+ continue;
- HeapFree(GetProcessHeap(),0,value_data);
- HeapFree(GetProcessHeap(),0,deformated);
+ RegDeleteValueW(hkey2,squished_pc);
- msiobj_release(&row->hdr);
- RegCloseKey(hkey);
-next:
- HeapFree(GetProcessHeap(),0,uikey);
- }
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
+ /* 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_InstallInitialize(MSIPACKAGE *package)
+typedef struct {
+ CLSID clsid;
+ LPWSTR source;
+
+ LPWSTR path;
+ ITypeLib *ptLib;
+} typelib_struct;
+
+static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
+ LPWSTR lpszName, LONG_PTR lParam)
{
- package->script->CurrentlyScripting = TRUE;
+ TLIBATTR *attr;
+ typelib_struct *tl_struct = (typelib_struct*) lParam;
+ static const WCHAR fmt[] = {'%','s','\\','%','i',0};
+ int sz;
+ HRESULT res;
- return ERROR_SUCCESS;
-}
+ if (!IS_INTRESOURCE(lpszName))
+ {
+ ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
+ return TRUE;
+ }
+ sz = strlenW(tl_struct->source)+4;
+ sz *= sizeof(WCHAR);
-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;
+ if ((INT)lpszName == 1)
+ tl_struct->path = strdupW(tl_struct->source);
+ else
+ {
+ tl_struct->path = HeapAlloc(GetProcessHeap(),0,sz);
+ sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
+ }
- TRACE(" InstallValidate \n");
+ TRACE("trying %s\n", debugstr_w(tl_struct->path));
+ res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
+ if (!SUCCEEDED(res))
+ {
+ HeapFree(GetProcessHeap(),0,tl_struct->path);
+ tl_struct->path = NULL;
- rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
- if (rc != ERROR_SUCCESS)
- return ERROR_SUCCESS;
+ return TRUE;
+ }
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
+ ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
+ if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
{
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
+ ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
+ return FALSE;
}
- while (1)
+
+ HeapFree(GetProcessHeap(),0,tl_struct->path);
+ tl_struct->path = NULL;
+
+ ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
+ ITypeLib_Release(tl_struct->ptLib);
+
+ return TRUE;
+}
+
+static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
+{
+ MSIPACKAGE* package = (MSIPACKAGE*)param;
+ LPCWSTR component;
+ INT index;
+ typelib_struct tl_struct;
+ HMODULE module;
+ static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
+
+ component = MSI_RecordGetString(row,3);
+ index = get_loaded_component(package,component);
+ if (index < 0)
+ return ERROR_SUCCESS;
+
+ if (!ACTION_VerifyComponentForAction(package, index, INSTALLSTATE_LOCAL))
{
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
- progress +=1;
+ TRACE("Skipping typelib reg due to disabled component\n");
- msiobj_release(&row->hdr);
+ package->components[index].Action =
+ package->components[index].Installed;
+
+ return ERROR_SUCCESS;
}
- 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);
+ package->components[index].Action = INSTALLSTATE_LOCAL;
- for(i = 0; i < package->loaded_features; i++)
- {
- MSIFEATURE* feature = &package->features[i];
- TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
- debugstr_w(feature->Feature), feature->Installed, feature->Action,
- feature->ActionRequest);
+ index = get_loaded_file(package,package->components[index].KeyPath);
+
+ if (index < 0)
+ return ERROR_SUCCESS;
+
+ module = LoadLibraryExW(package->files[index].TargetPath, NULL,
+ LOAD_LIBRARY_AS_DATAFILE);
+ if (module != NULL)
+ {
+ LPWSTR guid;
+ guid = load_dynamic_stringW(row,1);
+ CLSIDFromString(guid, &tl_struct.clsid);
+ HeapFree(GetProcessHeap(),0,guid);
+ tl_struct.source = strdupW(package->files[index].TargetPath);
+ tl_struct.path = NULL;
+
+ EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
+ (LONG_PTR)&tl_struct);
+
+ if (tl_struct.path != NULL)
+ {
+ LPWSTR help = NULL;
+ LPCWSTR helpid;
+ HRESULT res;
+
+ helpid = MSI_RecordGetString(row,6);
+
+ if (helpid)
+ help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
+ res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
+ HeapFree(GetProcessHeap(),0,help);
+
+ if (!SUCCEEDED(res))
+ ERR("Failed to register type library %s\n",
+ debugstr_w(tl_struct.path));
+ else
+ {
+ ui_actiondata(package,szRegisterTypeLibraries,row);
+
+ TRACE("Registered %s\n", debugstr_w(tl_struct.path));
+ }
+
+ ITypeLib_Release(tl_struct.ptLib);
+ HeapFree(GetProcessHeap(),0,tl_struct.path);
+ }
+ else
+ ERR("Failed to load type library %s\n",
+ debugstr_w(tl_struct.source));
+
+ FreeLibrary(module);
+ HeapFree(GetProcessHeap(),0,tl_struct.source);
}
-
+ else
+ ERR("Could not load file! %s\n",
+ debugstr_w(package->files[index].TargetPath));
+
return ERROR_SUCCESS;
}
-static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
+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 = NULL;
- MSIRECORD * row = 0;
- static const WCHAR ExecSeqQuery[] =
+ MSIQUERY * view;
+ static const WCHAR Query[] =
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
- static const WCHAR title[]=
- {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
+ '`','T','y','p','e','L','i','b','`',0};
- TRACE("Checking launch conditions\n");
+ if (!package)
+ return ERROR_INVALID_HANDLE;
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
+ rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
+ msiobj_release(&view->hdr);
+ return rc;
+}
+
+static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
+{
+ MSIPACKAGE *package = (MSIPACKAGE*)param;
+
+ LPWSTR target_file, target_folder;
+ LPCWSTR buffer;
+ WCHAR filename[0x100];
+ DWORD sz;
+ DWORD index;
+ static const WCHAR szlnk[]={'.','l','n','k',0};
+ IShellLinkW *sl;
+ IPersistFile *pf;
+ HRESULT res;
+
+ buffer = MSI_RecordGetString(row,4);
+ index = get_loaded_component(package,buffer);
+
+ if (index < 0)
+ return ERROR_SUCCESS;
+
+ if (!ACTION_VerifyComponentForAction(package, index, INSTALLSTATE_LOCAL))
{
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
+ TRACE("Skipping shortcut creation due to disabled component\n");
+
+ package->components[index].Action =
+ package->components[index].Installed;
+
+ return ERROR_SUCCESS;
}
- rc = ERROR_SUCCESS;
- while (rc == ERROR_SUCCESS)
- {
- LPCWSTR cond = NULL;
- LPCWSTR message = NULL;
+ package->components[index].Action = INSTALLSTATE_LOCAL;
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
+ ui_actiondata(package,szCreateShortcuts,row);
- cond = MSI_RecordGetString(row,1);
+ res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IShellLinkW, (LPVOID *) &sl );
- if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
- {
- LPWSTR deformated;
- message = MSI_RecordGetString(row,2);
- deformat_string(package,message,&deformated);
- MessageBoxW(NULL,deformated,title,MB_OK);
- HeapFree(GetProcessHeap(),0,deformated);
- rc = ERROR_FUNCTION_FAILED;
- }
- msiobj_release(&row->hdr);
+ if (FAILED(res))
+ {
+ ERR("Is IID_IShellLink\n");
+ return ERROR_SUCCESS;
}
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
-}
-static LPWSTR resolve_keypath( MSIPACKAGE* package, INT
- component_index)
-{
- MSICOMPONENT* cmp = &package->components[component_index];
+ res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
+ if( FAILED( res ) )
+ {
+ ERR("Is IID_IPersistFile\n");
+ return ERROR_SUCCESS;
+ }
- if (cmp->KeyPath[0]==0)
+ buffer = MSI_RecordGetString(row,2);
+ target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
+
+ /* may be needed because of a bug somehwere else */
+ create_full_pathW(target_folder);
+
+ sz = 0x100;
+ MSI_RecordGetStringW(row,3,filename,&sz);
+ reduce_to_longfilename(filename);
+ if (!strchrW(filename,'.') || strcmpiW(strchrW(filename,'.'),szlnk))
+ strcatW(filename,szlnk);
+ target_file = build_directory_name(2, target_folder, filename);
+ HeapFree(GetProcessHeap(),0,target_folder);
+
+ buffer = MSI_RecordGetString(row,5);
+ if (strchrW(buffer,'['))
{
- LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
- return p;
+ LPWSTR deformated;
+ deformat_string(package,buffer,&deformated);
+ IShellLinkW_SetPath(sl,deformated);
+ HeapFree(GetProcessHeap(),0,deformated);
}
- if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
+ else
{
- MSIRECORD * row = 0;
- UINT root,len;
- LPWSTR deformated,buffer,deformated_name;
- LPCWSTR key,name;
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','R','e','g','i','s','t','r','y','`',' ',
- '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};
+ LPWSTR keypath;
+ FIXME("poorly handled shortcut format, advertised shortcut\n");
+ keypath = strdupW(package->components[index].FullKeypath);
+ IShellLinkW_SetPath(sl,keypath);
+ HeapFree(GetProcessHeap(),0,keypath);
+ }
- row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
- if (!row)
- return NULL;
+ if (!MSI_RecordIsNull(row,6))
+ {
+ LPWSTR deformated;
+ buffer = MSI_RecordGetString(row,6);
+ deformat_string(package,buffer,&deformated);
+ IShellLinkW_SetArguments(sl,deformated);
+ HeapFree(GetProcessHeap(),0,deformated);
+ }
- root = MSI_RecordGetInteger(row,2);
- key = MSI_RecordGetString(row, 3);
- name = MSI_RecordGetString(row, 4);
- deformat_string(package, key , &deformated);
- deformat_string(package, name, &deformated_name);
+ if (!MSI_RecordIsNull(row,7))
+ {
+ buffer = MSI_RecordGetString(row,7);
+ IShellLinkW_SetDescription(sl,buffer);
+ }
- len = strlenW(deformated) + 6;
- if (deformated_name)
- len+=strlenW(deformated_name);
+ if (!MSI_RecordIsNull(row,8))
+ IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
- buffer = HeapAlloc(GetProcessHeap(),0, len *sizeof(WCHAR));
+ if (!MSI_RecordIsNull(row,9))
+ {
+ WCHAR *Path = NULL;
+ INT index;
- if (deformated_name)
- sprintfW(buffer,fmt2,root,deformated,deformated_name);
- else
- sprintfW(buffer,fmt,root,deformated);
+ buffer = MSI_RecordGetString(row,9);
- HeapFree(GetProcessHeap(),0,deformated);
- HeapFree(GetProcessHeap(),0,deformated_name);
- msiobj_release(&row->hdr);
+ build_icon_path(package,buffer,&Path);
+ index = MSI_RecordGetInteger(row,10);
- return buffer;
+ IShellLinkW_SetIconLocation(sl,Path,index);
+ HeapFree(GetProcessHeap(),0,Path);
}
- else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
+
+ if (!MSI_RecordIsNull(row,11))
+ IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
+
+ if (!MSI_RecordIsNull(row,12))
{
- FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
- return NULL;
+ LPWSTR Path;
+ buffer = MSI_RecordGetString(row,12);
+ Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
+ IShellLinkW_SetWorkingDirectory(sl,Path);
+ HeapFree(GetProcessHeap(), 0, Path);
}
- else
- {
- int j;
- j = get_loaded_file(package,cmp->KeyPath);
- if (j>=0)
- {
- LPWSTR p = strdupW(package->files[j].TargetPath);
- return p;
- }
- }
- return NULL;
+ TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
+ IPersistFile_Save(pf,target_file,FALSE);
+
+ HeapFree(GetProcessHeap(),0,target_file);
+
+ IPersistFile_Release( pf );
+ IShellLinkW_Release( sl );
+
+ return ERROR_SUCCESS;
}
-static HKEY openSharedDLLsKey()
+static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
{
- 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};
+ UINT rc;
+ HRESULT res;
+ MSIQUERY * view;
+ static const WCHAR Query[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','S','h','o','r','t','c','u','t','`',0};
- RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
- return hkey;
-}
+ if (!package)
+ return ERROR_INVALID_HANDLE;
-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);
+ rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
if (rc != ERROR_SUCCESS)
- count = 0;
- RegCloseKey(hkey);
- return count;
-}
+ return ERROR_SUCCESS;
-static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
-{
- HKEY hkey;
+ res = CoInitialize( NULL );
+ if (FAILED (res))
+ {
+ ERR("CoInitialize failed\n");
+ return ERROR_FUNCTION_FAILED;
+ }
- hkey = openSharedDLLsKey();
- if (count > 0)
- RegSetValueExW(hkey,path,0,REG_DWORD,
- (LPBYTE)&count,sizeof(count));
- else
- RegDeleteValueW(hkey,path);
- RegCloseKey(hkey);
- return count;
+ rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
+ msiobj_release(&view->hdr);
+
+ CoUninitialize();
+
+ return rc;
}
-/*
- * Return TRUE if the count should be written out and FALSE if not
- */
-static void ACTION_RefCountComponent( MSIPACKAGE* package, UINT index)
+static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
{
- INT count = 0;
- BOOL write = FALSE;
- INT j;
+ MSIPACKAGE* package = (MSIPACKAGE*)param;
+ HANDLE the_file;
+ LPWSTR FilePath=NULL;
+ LPCWSTR FileName=NULL;
+ CHAR buffer[1024];
+ DWORD sz;
+ UINT rc;
- /* only refcount DLLs */
- if (package->components[index].KeyPath[0]==0 ||
- package->components[index].Attributes &
- msidbComponentAttributesRegistryKeyPath ||
- package->components[index].Attributes &
- msidbComponentAttributesODBCDataSource)
- write = FALSE;
- else
+ FileName = MSI_RecordGetString(row,1);
+ if (!FileName)
{
- count = ACTION_GetSharedDLLsCount(package->components[index].
- FullKeypath);
- write = (count > 0);
-
- if (package->components[index].Attributes &
- msidbComponentAttributesSharedDllRefCount)
- write = TRUE;
+ ERR("Unable to get FileName\n");
+ return ERROR_SUCCESS;
}
- /* increment counts */
- for (j = 0; j < package->loaded_features; j++)
- {
- int i;
+ build_icon_path(package,FileName,&FilePath);
- if (!ACTION_VerifyFeatureForAction(package,j,INSTALLSTATE_LOCAL))
- continue;
+ TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
+
+ the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
- 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++)
+ if (the_file == INVALID_HANDLE_VALUE)
{
- 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--;
- }
+ ERR("Unable to create file %s\n",debugstr_w(FilePath));
+ HeapFree(GetProcessHeap(),0,FilePath);
+ return ERROR_SUCCESS;
}
- /* ref count all the files in the component */
- if (write)
- for (j = 0; j < package->loaded_files; j++)
+ do
+ {
+ DWORD write;
+ sz = 1024;
+ rc = MSI_RecordReadStream(row,2,buffer,&sz);
+ if (rc != ERROR_SUCCESS)
{
- if (package->files[j].Temporary)
- continue;
- if (package->files[j].ComponentIndex == index)
- ACTION_WriteSharedDLLsCount(package->files[j].TargetPath,count);
+ ERR("Failed to get stream\n");
+ CloseHandle(the_file);
+ DeleteFileW(FilePath);
+ break;
}
-
- /* add a count for permenent */
- if (package->components[index].Attributes &
- msidbComponentAttributesPermanent)
- count ++;
-
- package->components[index].RefCount = count;
+ WriteFile(the_file,buffer,sz,&write,NULL);
+ } while (sz == 1024);
- if (write)
- ACTION_WriteSharedDLLsCount(package->components[index].FullKeypath,
- package->components[index].RefCount);
+ HeapFree(GetProcessHeap(),0,FilePath);
+
+ CloseHandle(the_file);
+ return ERROR_SUCCESS;
}
/*
- * 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
+ * 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_ProcessComponents(MSIPACKAGE *package)
+static UINT ACTION_PublishProduct(MSIPACKAGE *package)
{
- LPWSTR productcode;
- WCHAR squished_pc[GUID_SIZE];
- WCHAR squished_cc[GUID_SIZE];
UINT rc;
- DWORD i;
- HKEY hkey=0,hkey2=0;
+ MSIQUERY * view;
+ static const WCHAR Query[]=
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','I','c','o','n','`',0};
+ /* 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};
+ static const WCHAR szLanguage[] =
+ {'L','a','n','g','u','a','g','e',0};
+ static const WCHAR szProductLanguage[] =
+ {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
+ static const WCHAR szProductIcon[] =
+ {'P','r','o','d','u','c','t','I','c','o','n',0};
+ static const WCHAR szARPProductIcon[] =
+ {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
+ static const WCHAR szProductVersion[] =
+ {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
+ static const WCHAR szVersion[] =
+ {'V','e','r','s','i','o','n',0};
+ DWORD langid;
+ LPWSTR buffer;
+ DWORD size;
+ MSIHANDLE hDb, hSumInfo;
if (!package)
return ERROR_INVALID_HANDLE;
- /* writes the Component and Features values to the registry */
+ /* write out icon files */
+
+ rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
+ if (rc == ERROR_SUCCESS)
+ {
+ MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
+ msiobj_release(&view->hdr);
+ }
+
+ /* 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_OpenComponents(&hkey);
+ rc = MSIREG_OpenProductsKey(productcode,&hkey,TRUE);
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);
-
- keypath = resolve_keypath(package,i);
- package->components[i].FullKeypath = keypath;
+ rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
+ if (rc != ERROR_SUCCESS)
+ goto end;
- /* do the refcounting */
- ACTION_RefCountComponent( package, i);
- TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
- debugstr_w(package->components[i].Component),
- debugstr_w(squished_cc),
- 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))
- {
- rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
- if (rc != ERROR_SUCCESS)
- continue;
+ buffer = load_dynamic_property(package,szProductName,NULL);
+ size = strlenW(buffer)*sizeof(WCHAR);
+ RegSetValueExW(hukey,szProductName,0,REG_SZ, (BYTE *)buffer,size);
+ HeapFree(GetProcessHeap(),0,buffer);
- if (keypath)
- {
- RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath,
- (strlenW(keypath)+1)*sizeof(WCHAR));
+ buffer = load_dynamic_property(package,szProductLanguage,NULL);
+ size = sizeof(DWORD);
+ langid = atoiW(buffer);
+ RegSetValueExW(hukey,szLanguage,0,REG_DWORD, (BYTE *)&langid,size);
+ HeapFree(GetProcessHeap(),0,buffer);
- 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};
+ buffer = load_dynamic_property(package,szARPProductIcon,NULL);
+ if (buffer)
+ {
+ LPWSTR path;
+ build_icon_path(package,buffer,&path);
+ size = strlenW(path) * sizeof(WCHAR);
+ RegSetValueExW(hukey,szProductIcon,0,REG_SZ, (BYTE *)path,size);
+ }
+ HeapFree(GetProcessHeap(),0,buffer);
- 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;
-
- rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
- if (rc != ERROR_SUCCESS)
- continue;
-
- 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 );
- }
+ buffer = load_dynamic_property(package,szProductVersion,NULL);
+ if (buffer)
+ {
+ DWORD verdword = build_version_dword(buffer);
+ size = sizeof(DWORD);
+ RegSetValueExW(hukey,szVersion,0,REG_DWORD, (BYTE *)&verdword,size);
+ }
+ HeapFree(GetProcessHeap(),0,buffer);
+
+ FIXME("Need to write more keys to the user registry\n");
+
+ hDb= alloc_msihandle( &package->db->hdr );
+ 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);
+
+ HeapFree(GetProcessHeap(),0,productcode);
RegCloseKey(hkey);
+ RegCloseKey(hukey);
+
return rc;
}
-typedef struct {
- CLSID clsid;
- LPWSTR source;
-
- LPWSTR path;
- ITypeLib *ptLib;
-} typelib_struct;
-
-static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
- LPWSTR lpszName, LONG_PTR lParam)
+static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
{
- TLIBATTR *attr;
- typelib_struct *tl_struct = (typelib_struct*) lParam;
- static const WCHAR fmt[] = {'%','s','\\','%','i',0};
- int sz;
- HRESULT res;
+ MSIPACKAGE *package = (MSIPACKAGE*)param;
+ LPCWSTR component,section,key,value,identifier,filename,dirproperty;
+ LPWSTR deformated_section, deformated_key, deformated_value;
+ LPWSTR folder, fullname = NULL;
+ MSIRECORD * uirow;
+ INT component_index,action;
+ static const WCHAR szWindowsFolder[] =
+ {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
+
+ component = MSI_RecordGetString(row, 8);
+ component_index = get_loaded_component(package,component);
- if (!IS_INTRESOURCE(lpszName))
+ if (!ACTION_VerifyComponentForAction(package, component_index,
+ INSTALLSTATE_LOCAL))
{
- ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
- return TRUE;
- }
+ TRACE("Skipping ini file due to disabled component %s\n",
+ debugstr_w(component));
- sz = strlenW(tl_struct->source)+4;
- sz *= sizeof(WCHAR);
+ package->components[component_index].Action =
+ package->components[component_index].Installed;
- if ((INT)lpszName == 1)
- tl_struct->path = strdupW(tl_struct->source);
- else
- {
- tl_struct->path = HeapAlloc(GetProcessHeap(),0,sz);
- sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
+ return ERROR_SUCCESS;
}
- TRACE("trying %s\n", debugstr_w(tl_struct->path));
- res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
- if (!SUCCEEDED(res))
- {
- HeapFree(GetProcessHeap(),0,tl_struct->path);
- tl_struct->path = NULL;
+ package->components[component_index].Action = INSTALLSTATE_LOCAL;
+
+ identifier = MSI_RecordGetString(row,1);
+ filename = MSI_RecordGetString(row,2);
+ dirproperty = MSI_RecordGetString(row,3);
+ section = MSI_RecordGetString(row,4);
+ key = MSI_RecordGetString(row,5);
+ value = MSI_RecordGetString(row,6);
+ action = MSI_RecordGetInteger(row,7);
+
+ deformat_string(package,section,&deformated_section);
+ deformat_string(package,key,&deformated_key);
+ deformat_string(package,value,&deformated_value);
- return TRUE;
+ 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);
- ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
- if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
+ if (!folder)
{
- ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
- return FALSE;
+ ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
+ goto cleanup;
}
- HeapFree(GetProcessHeap(),0,tl_struct->path);
- tl_struct->path = NULL;
+ fullname = build_directory_name(3, folder, filename, NULL);
- ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
- ITypeLib_Release(tl_struct->ptLib);
+ 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));
- return TRUE;
+ WritePrivateProfileStringW(deformated_section, deformated_key,
+ deformated_value, fullname);
+ }
+ }
+ else if (action == 3)
+ FIXME("Append to existing section not yet implemented\n");
+
+ uirow = MSI_CreateRecord(4);
+ MSI_RecordSetStringW(uirow,1,identifier);
+ MSI_RecordSetStringW(uirow,2,deformated_section);
+ MSI_RecordSetStringW(uirow,3,deformated_key);
+ MSI_RecordSetStringW(uirow,4,deformated_value);
+ ui_actiondata(package,szWriteIniValues,uirow);
+ msiobj_release( &uirow->hdr );
+cleanup:
+ HeapFree(GetProcessHeap(),0,fullname);
+ HeapFree(GetProcessHeap(),0,folder);
+ HeapFree(GetProcessHeap(),0,deformated_key);
+ HeapFree(GetProcessHeap(),0,deformated_value);
+ HeapFree(GetProcessHeap(),0,deformated_section);
+ return ERROR_SUCCESS;
}
-static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
+static UINT ACTION_WriteIniValues(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[] =
+ static const WCHAR ExecSeqQuery[] =
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','T','y','p','e','L','i','b','`',0};
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
- if (rc != ERROR_SUCCESS)
- return ERROR_SUCCESS;
+ '`','I','n','i','F','i','l','e','`',0};
- rc = MSI_ViewExecute(view, 0);
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
if (rc != ERROR_SUCCESS)
{
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
+ TRACE("no IniFile table\n");
+ return ERROR_SUCCESS;
}
- while (1)
- {
- LPCWSTR component;
- INT index;
- typelib_struct tl_struct;
- HMODULE module;
- static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- component = MSI_RecordGetString(row,3);
- 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;
- }
-
- module = LoadLibraryExW(package->files[index].TargetPath, NULL,
- LOAD_LIBRARY_AS_DATAFILE);
- if (module != NULL)
- {
- LPWSTR guid;
- guid = load_dynamic_stringW(row,1);
- CLSIDFromString(guid, &tl_struct.clsid);
- HeapFree(GetProcessHeap(),0,guid);
- tl_struct.source = strdupW(package->files[index].TargetPath);
- tl_struct.path = NULL;
-
- EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
- (LONG_PTR)&tl_struct);
-
- if (tl_struct.path != NULL)
- {
- LPWSTR help = NULL;
- LPCWSTR helpid;
- HRESULT res;
-
- helpid = MSI_RecordGetString(row,6);
-
- if (helpid)
- help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
- res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
- HeapFree(GetProcessHeap(),0,help);
-
- if (!SUCCEEDED(res))
- ERR("Failed to register type library %s\n",
- debugstr_w(tl_struct.path));
- else
- {
- ui_actiondata(package,szRegisterTypeLibraries,row);
-
- TRACE("Registered %s\n", debugstr_w(tl_struct.path));
- }
-
- ITypeLib_Release(tl_struct.ptLib);
- HeapFree(GetProcessHeap(),0,tl_struct.path);
- }
- else
- ERR("Failed to load type library %s\n",
- debugstr_w(tl_struct.source));
-
- FreeLibrary(module);
- HeapFree(GetProcessHeap(),0,tl_struct.source);
- }
- else
- ERR("Could not load file! %s\n",
- debugstr_w(package->files[index].TargetPath));
- msiobj_release(&row->hdr);
- }
- MSI_ViewClose(view);
+ rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
msiobj_release(&view->hdr);
return rc;
}
-static INT load_appid(MSIPACKAGE* package, MSIRECORD *row)
+static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
{
- DWORD index = package->loaded_appids;
- DWORD sz;
- LPCWSTR buffer;
+ MSIPACKAGE *package = (MSIPACKAGE*)param;
+ LPCWSTR filename;
+ LPWSTR FullName;
+ INT index;
+ DWORD len;
+ static const WCHAR ExeStr[] =
+ {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
+ static const WCHAR close[] = {'\"',0};
+ STARTUPINFOW si;
+ PROCESS_INFORMATION info;
+ BOOL brc;
- /* fill in the data */
+ memset(&si,0,sizeof(STARTUPINFOW));
- package->loaded_appids++;
- if (package->loaded_appids == 1)
- package->appids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIAPPID));
- else
- package->appids = HeapReAlloc(GetProcessHeap(),0,
- package->appids, package->loaded_appids * sizeof(MSIAPPID));
+ filename = MSI_RecordGetString(row,1);
+ index = get_loaded_file(package,filename);
- memset(&package->appids[index],0,sizeof(MSIAPPID));
-
- sz = IDENTIFIER_SIZE;
- MSI_RecordGetStringW(row, 1, package->appids[index].AppID, &sz);
- TRACE("loading appid %s\n",debugstr_w(package->appids[index].AppID));
+ if (index < 0)
+ {
+ ERR("Unable to find file id %s\n",debugstr_w(filename));
+ return ERROR_SUCCESS;
+ }
- buffer = MSI_RecordGetString(row,2);
- deformat_string(package,buffer,&package->appids[index].RemoteServerName);
+ len = strlenW(ExeStr);
+ len += strlenW(package->files[index].TargetPath);
+ len +=2;
- package->appids[index].LocalServer = load_dynamic_stringW(row,3);
- package->appids[index].ServiceParameters = load_dynamic_stringW(row,4);
- package->appids[index].DllSurrogate = load_dynamic_stringW(row,5);
+ FullName = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
+ strcpyW(FullName,ExeStr);
+ strcatW(FullName,package->files[index].TargetPath);
+ strcatW(FullName,close);
- package->appids[index].ActivateAtStorage = !MSI_RecordIsNull(row,6);
- package->appids[index].RunAsInteractiveUser = !MSI_RecordIsNull(row,7);
-
- return index;
+ TRACE("Registering %s\n",debugstr_w(FullName));
+ brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
+ &si, &info);
+
+ if (brc)
+ msi_dialog_check_messages(info.hProcess);
+
+ HeapFree(GetProcessHeap(),0,FullName);
+ return ERROR_SUCCESS;
}
-static INT load_given_appid(MSIPACKAGE *package, LPCWSTR appid)
+static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
{
- INT rc;
- MSIRECORD *row;
- INT i;
- static const WCHAR ExecSeqQuery[] =
+ UINT rc;
+ MSIQUERY * view;
+ 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};
+ '`','S','e','l','f','R','e','g','`',0};
- if (!appid)
- return -1;
-
- /* check for appids already loaded */
- for (i = 0; i < package->loaded_appids; i++)
- if (strcmpiW(package->appids[i].AppID,appid)==0)
- {
- TRACE("found appid %s at index %i\n",debugstr_w(appid),i);
- return i;
- }
-
- row = MSI_QueryGetRecord(package->db, ExecSeqQuery, appid);
- if (!row)
- return -1;
-
- rc = load_appid(package, row);
- msiobj_release(&row->hdr);
-
- return rc;
-}
-
-static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid);
-static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid);
-
-static INT load_progid(MSIPACKAGE* package, MSIRECORD *row)
-{
- DWORD index = package->loaded_progids;
- LPCWSTR buffer;
-
- /* fill in the data */
-
- package->loaded_progids++;
- if (package->loaded_progids == 1)
- package->progids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIPROGID));
- else
- package->progids = HeapReAlloc(GetProcessHeap(),0,
- package->progids , package->loaded_progids * sizeof(MSIPROGID));
-
- memset(&package->progids[index],0,sizeof(MSIPROGID));
-
- package->progids[index].ProgID = load_dynamic_stringW(row,1);
- TRACE("loading progid %s\n",debugstr_w(package->progids[index].ProgID));
-
- buffer = MSI_RecordGetString(row,2);
- package->progids[index].ParentIndex = load_given_progid(package,buffer);
- if (package->progids[index].ParentIndex < 0 && buffer)
- FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer));
-
- buffer = MSI_RecordGetString(row,3);
- package->progids[index].ClassIndex = load_given_class(package,buffer);
- if (package->progids[index].ClassIndex< 0 && buffer)
- FIXME("Unknown class %s\n",debugstr_w(buffer));
-
- package->progids[index].Description = load_dynamic_stringW(row,4);
-
- if (!MSI_RecordIsNull(row,6))
- {
- INT icon_index = MSI_RecordGetInteger(row,6);
- LPWSTR FileName = load_dynamic_stringW(row,5);
- LPWSTR FilePath;
- static const WCHAR fmt[] = {'%','s',',','%','i',0};
-
- build_icon_path(package,FileName,&FilePath);
-
- package->progids[index].IconPath =
- HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+10)*
- sizeof(WCHAR));
-
- sprintfW(package->progids[index].IconPath,fmt,FilePath,icon_index);
-
- HeapFree(GetProcessHeap(),0,FilePath);
- HeapFree(GetProcessHeap(),0,FileName);
- }
- else
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
{
- buffer = MSI_RecordGetString(row,5);
- if (buffer)
- build_icon_path(package,buffer,&(package->progids[index].IconPath));
+ TRACE("no SelfReg table\n");
+ return ERROR_SUCCESS;
}
- package->progids[index].CurVerIndex = -1;
- package->progids[index].VersionIndIndex = -1;
-
- /* if we have a parent then we may be that parents CurVer */
- if (package->progids[index].ParentIndex >= 0 &&
- package->progids[index].ParentIndex != index)
- {
- int pindex = package->progids[index].ParentIndex;
- while (package->progids[pindex].ParentIndex>= 0)
- pindex = package->progids[pindex].ParentIndex;
-
- FIXME("BAD BAD need to determing if we are really the CurVer\n");
+ MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
+ msiobj_release(&view->hdr);
- package->progids[index].CurVerIndex = pindex;
- package->progids[pindex].VersionIndIndex = index;
- }
-
- return index;
+ return ERROR_SUCCESS;
}
-static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid)
+static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
{
- INT rc;
- MSIRECORD *row;
- INT i;
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','P','r','o','g','I','d','`',' ','W','H','E','R','E',' ',
- '`','P','r','o','g','I','d','`',' ','=',' ','\'','%','s','\'',0};
-
- if (!progid)
- return -1;
-
- /* check for progids already loaded */
- for (i = 0; i < package->loaded_progids; i++)
- if (strcmpiW(package->progids[i].ProgID,progid)==0)
- {
- TRACE("found progid %s at index %i\n",debugstr_w(progid), i);
- return i;
- }
+ LPWSTR productcode;
+ UINT rc;
+ DWORD i;
+ HKEY hkey=0;
+ HKEY hukey=0;
- row = MSI_QueryGetRecord(package->db, ExecSeqQuery, progid);
- if(!row)
- return -1;
-
- rc = load_progid(package, row);
- msiobj_release(&row->hdr);
-
- return rc;
-}
-
-static INT load_class(MSIPACKAGE* package, MSIRECORD *row)
-{
- DWORD index = package->loaded_classes;
- DWORD sz,i;
- LPCWSTR buffer;
-
- /* fill in the data */
-
- package->loaded_classes++;
- if (package->loaded_classes== 1)
- package->classes = HeapAlloc(GetProcessHeap(),0,sizeof(MSICLASS));
- else
- package->classes = HeapReAlloc(GetProcessHeap(),0,
- package->classes, package->loaded_classes * sizeof(MSICLASS));
-
- memset(&package->classes[index],0,sizeof(MSICLASS));
-
- sz = IDENTIFIER_SIZE;
- MSI_RecordGetStringW(row, 1, package->classes[index].CLSID, &sz);
- TRACE("loading class %s\n",debugstr_w(package->classes[index].CLSID));
- sz = IDENTIFIER_SIZE;
- MSI_RecordGetStringW(row, 2, package->classes[index].Context, &sz);
- buffer = MSI_RecordGetString(row,3);
- package->classes[index].ComponentIndex = get_loaded_component(package,
- buffer);
-
- package->classes[index].ProgIDText = load_dynamic_stringW(row,4);
- package->classes[index].ProgIDIndex =
- load_given_progid(package, package->classes[index].ProgIDText);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
- package->classes[index].Description = load_dynamic_stringW(row,5);
+ productcode = load_dynamic_property(package,szProductCode,&rc);
+ if (!productcode)
+ return rc;
- buffer = MSI_RecordGetString(row,6);
- if (buffer)
- package->classes[index].AppIDIndex =
- load_given_appid(package, buffer);
- else
- package->classes[index].AppIDIndex = -1;
+ rc = MSIREG_OpenFeaturesKey(productcode,&hkey,TRUE);
+ if (rc != ERROR_SUCCESS)
+ goto end;
- package->classes[index].FileTypeMask = load_dynamic_stringW(row,7);
+ rc = MSIREG_OpenUserFeaturesKey(productcode,&hukey,TRUE);
+ if (rc != ERROR_SUCCESS)
+ goto end;
- if (!MSI_RecordIsNull(row,9))
+ /* here the guids are base 85 encoded */
+ for (i = 0; i < package->loaded_features; i++)
{
+ LPWSTR data = NULL;
+ GUID clsid;
+ int j;
+ INT size;
+ BOOL absent = FALSE;
- INT icon_index = MSI_RecordGetInteger(row,9);
- LPWSTR FileName = load_dynamic_stringW(row,8);
- LPWSTR FilePath;
- static const WCHAR fmt[] = {'%','s',',','%','i',0};
-
- build_icon_path(package,FileName,&FilePath);
-
- package->classes[index].IconPath =
- HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)*
- sizeof(WCHAR));
+ if (!ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_LOCAL) &&
+ !ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_SOURCE) &&
+ !ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_ADVERTISED))
+ absent = TRUE;
- sprintfW(package->classes[index].IconPath,fmt,FilePath,icon_index);
+ size = package->features[i].ComponentCount*21;
+ size +=1;
+ if (package->features[i].Feature_Parent[0])
+ size += strlenW(package->features[i].Feature_Parent)+2;
- HeapFree(GetProcessHeap(),0,FilePath);
- HeapFree(GetProcessHeap(),0,FileName);
- }
- else
- {
- buffer = MSI_RecordGetString(row,8);
- if (buffer)
- build_icon_path(package,buffer,&(package->classes[index].IconPath));
- }
+ data = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
- if (!MSI_RecordIsNull(row,10))
- {
- i = MSI_RecordGetInteger(row,10);
- if (i != MSI_NULL_INTEGER && i > 0 && i < 4)
+ data[0] = 0;
+ for (j = 0; j < package->features[i].ComponentCount; j++)
{
- 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)
+ WCHAR buf[21];
+ memset(buf,0,sizeof(buf));
+ if (package->components
+ [package->features[i].Components[j]].ComponentId[0]!=0)
{
- case 1:
- package->classes[index].DefInprocHandler = strdupW(ole2);
- break;
- case 2:
- package->classes[index].DefInprocHandler32 = strdupW(ole32);
- break;
- case 3:
- package->classes[index].DefInprocHandler = strdupW(ole2);
- package->classes[index].DefInprocHandler32 = strdupW(ole32);
- break;
+ 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);
}
}
- else
+ if (package->features[i].Feature_Parent[0])
{
- package->classes[index].DefInprocHandler32 = load_dynamic_stringW(
- row, 10);
- reduce_to_longfilename(package->classes[index].DefInprocHandler32);
+ static const WCHAR sep[] = {'\2',0};
+ strcatW(data,sep);
+ strcatW(data,package->features[i].Feature_Parent);
}
- }
- buffer = MSI_RecordGetString(row,11);
- deformat_string(package,buffer,&package->classes[index].Argument);
-
- buffer = MSI_RecordGetString(row,12);
- package->classes[index].FeatureIndex = get_loaded_feature(package,buffer);
-
- package->classes[index].Attributes = MSI_RecordGetInteger(row,13);
-
- return index;
-}
-
-/*
- * the Class table has 3 primary keys. Generally it is only
- * referenced through the first CLSID key. However when loading
- * all of the classes we need to make sure we do not ignore rows
- * with other Context and ComponentIndexs
- */
-static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid)
-{
- INT rc;
- MSIRECORD *row;
- INT i;
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','C','l','a','s','s','`',' ','W','H','E','R','E',' ',
- '`','C','L','S','I','D','`',' ','=',' ','\'','%','s','\'',0};
+ size = (strlenW(data)+1)*sizeof(WCHAR);
+ RegSetValueExW(hkey,package->features[i].Feature,0,REG_SZ,
+ (LPSTR)data,size);
+ HeapFree(GetProcessHeap(),0,data);
- if (!classid)
- return -1;
-
- /* check for classes already loaded */
- for (i = 0; i < package->loaded_classes; i++)
- if (strcmpiW(package->classes[i].CLSID,classid)==0)
+ if (!absent)
{
- TRACE("found class %s at index %i\n",debugstr_w(classid), i);
- return i;
+ 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);
}
-
- row = MSI_QueryGetRecord(package->db, ExecSeqQuery, classid);
- if (!row)
- return -1;
-
- rc = load_class(package, row);
- msiobj_release(&row->hdr);
-
- return rc;
-}
-
-static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension);
-
-static INT load_mime(MSIPACKAGE* package, MSIRECORD *row)
-{
- DWORD index = package->loaded_mimes;
- DWORD sz;
- LPCWSTR buffer;
-
- /* fill in the data */
-
- package->loaded_mimes++;
- if (package->loaded_mimes== 1)
- package->mimes= HeapAlloc(GetProcessHeap(),0,sizeof(MSIMIME));
- else
- package->mimes= HeapReAlloc(GetProcessHeap(),0,
- package->mimes, package->loaded_mimes*
- sizeof(MSIMIME));
-
- memset(&package->mimes[index],0,sizeof(MSIMIME));
-
- package->mimes[index].ContentType = load_dynamic_stringW(row,1);
- TRACE("loading mime %s\n",debugstr_w(package->mimes[index].ContentType));
-
- buffer = MSI_RecordGetString(row,2);
- package->mimes[index].ExtensionIndex = load_given_extension(package,
- buffer);
-
- sz = IDENTIFIER_SIZE;
- MSI_RecordGetStringW(row,3,package->mimes[index].CLSID,&sz);
- package->mimes[index].ClassIndex= load_given_class(package,
- package->mimes[index].CLSID);
-
- return index;
-}
-
-static INT load_given_mime(MSIPACKAGE *package, LPCWSTR mime)
-{
- INT rc;
- MSIRECORD *row;
- INT i;
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','M','I','M','E','`',' ','W','H','E','R','E',' ',
- '`','C','o','n','t','e','n','t','T','y','p','e','`',' ','=',' ',
- '\'','%','s','\'',0};
-
- if (!mime)
- return -1;
-
- /* check for mime already loaded */
- for (i = 0; i < package->loaded_mimes; i++)
- if (strcmpiW(package->mimes[i].ContentType,mime)==0)
+ else
{
- TRACE("found mime %s at index %i\n",debugstr_w(mime), i);
- return i;
+ size = (strlenW(package->features[i].Feature_Parent)+2)*
+ sizeof(WCHAR);
+ data = HeapAlloc(GetProcessHeap(),0,size);
+ data[0] = 0x6;
+ strcpyW(&data[1],package->features[i].Feature_Parent);
+ RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ,
+ (LPSTR)data,size);
+ HeapFree(GetProcessHeap(),0,data);
}
-
- row = MSI_QueryGetRecord(package->db, ExecSeqQuery, mime);
- if (!row)
- return -1;
-
- rc = load_mime(package, row);
- msiobj_release(&row->hdr);
+ }
+end:
+ RegCloseKey(hkey);
+ RegCloseKey(hukey);
+ HeapFree(GetProcessHeap(), 0, productcode);
return rc;
}
-static INT load_extension(MSIPACKAGE* package, MSIRECORD *row)
+static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
{
- DWORD index = package->loaded_extensions;
- DWORD sz;
- LPCWSTR buffer;
-
- /* fill in the data */
-
- package->loaded_extensions++;
- if (package->loaded_extensions == 1)
- package->extensions = HeapAlloc(GetProcessHeap(),0,sizeof(MSIEXTENSION));
- else
- package->extensions = HeapReAlloc(GetProcessHeap(),0,
- package->extensions, package->loaded_extensions*
- sizeof(MSIEXTENSION));
-
- memset(&package->extensions[index],0,sizeof(MSIEXTENSION));
-
- sz = 256;
- MSI_RecordGetStringW(row,1,package->extensions[index].Extension,&sz);
- TRACE("loading extension %s\n",
- debugstr_w(package->extensions[index].Extension));
-
- buffer = MSI_RecordGetString(row,2);
- package->extensions[index].ComponentIndex =
- get_loaded_component(package,buffer);
-
- package->extensions[index].ProgIDText = load_dynamic_stringW(row,3);
- package->extensions[index].ProgIDIndex = load_given_progid(package,
- package->extensions[index].ProgIDText);
-
- buffer = MSI_RecordGetString(row,4);
- package->extensions[index].MIMEIndex = load_given_mime(package,buffer);
-
- buffer = MSI_RecordGetString(row,5);
- package->extensions[index].FeatureIndex =
- get_loaded_feature(package,buffer);
-
- return index;
-}
-
-/*
- * While the extension table has 2 primary keys, this function is only looking
- * at the Extension key which is what is referenced as a forign key
- */
-static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension)
-{
- INT rc;
- MSIRECORD *row;
- INT i;
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','E','x','t','e','n','s','i','o','n','`',' ',
- 'W','H','E','R','E',' ',
- '`','E','x','t','e','n','s','i','o','n','`',' ','=',' ',
- '\'','%','s','\'',0};
-
- if (!extension)
- return -1;
-
- /* check for extensions already loaded */
- for (i = 0; i < package->loaded_extensions; i++)
- if (strcmpiW(package->extensions[i].Extension,extension)==0)
- {
- TRACE("extension %s already loaded at %i\n",debugstr_w(extension),
- i);
- return i;
- }
-
- row = MSI_QueryGetRecord(package->db, ExecSeqQuery, extension);
- if (!row)
- return -1;
-
- rc = load_extension(package, row);
- msiobj_release(&row->hdr);
-
- return rc;
-}
-
-static UINT iterate_load_verb(MSIRECORD *row, LPVOID param)
-{
- MSIPACKAGE* package = (MSIPACKAGE*)param;
- DWORD index = package->loaded_verbs;
- LPCWSTR buffer;
-
- /* fill in the data */
-
- package->loaded_verbs++;
- if (package->loaded_verbs == 1)
- package->verbs = HeapAlloc(GetProcessHeap(),0,sizeof(MSIVERB));
- else
- package->verbs = HeapReAlloc(GetProcessHeap(),0,
- package->verbs , package->loaded_verbs * sizeof(MSIVERB));
-
- memset(&package->verbs[index],0,sizeof(MSIVERB));
-
- buffer = MSI_RecordGetString(row,1);
- package->verbs[index].ExtensionIndex = load_given_extension(package,buffer);
- if (package->verbs[index].ExtensionIndex < 0 && buffer)
- ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer));
-
- package->verbs[index].Verb = load_dynamic_stringW(row,2);
- TRACE("loading verb %s\n",debugstr_w(package->verbs[index].Verb));
- package->verbs[index].Sequence = MSI_RecordGetInteger(row,3);
-
- buffer = MSI_RecordGetString(row,4);
- deformat_string(package,buffer,&package->verbs[index].Command);
-
- buffer = MSI_RecordGetString(row,5);
- deformat_string(package,buffer,&package->verbs[index].Argument);
-
- /* assosiate the verb with the correct extension */
- if (package->verbs[index].ExtensionIndex >= 0)
- {
- MSIEXTENSION* extension = &package->extensions[package->verbs[index].
- ExtensionIndex];
- int count = extension->VerbCount;
-
- if (count >= 99)
- FIXME("Exceeding max verb count! Increase that limit!!!\n");
- else
- {
- extension->VerbCount++;
- extension->Verbs[count] = index;
- }
- }
-
- return ERROR_SUCCESS;
-}
-
-static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param)
-{
- LPCWSTR clsid;
- LPCWSTR context;
- LPCWSTR buffer;
- INT component_index;
- MSIPACKAGE* package =(MSIPACKAGE*)param;
- INT i;
- BOOL match = FALSE;
-
- clsid = MSI_RecordGetString(rec,1);
- context = MSI_RecordGetString(rec,2);
- buffer = MSI_RecordGetString(rec,3);
- component_index = get_loaded_component(package,buffer);
-
- for (i = 0; i < package->loaded_classes; i++)
- {
- if (strcmpiW(clsid,package->classes[i].CLSID))
- continue;
- if (strcmpW(context,package->classes[i].Context))
- continue;
- if (component_index == package->classes[i].ComponentIndex)
- {
- match = TRUE;
- break;
- }
- }
-
- if (!match)
- load_class(package, rec);
-
- return ERROR_SUCCESS;
-}
-
-static VOID load_all_classes(MSIPACKAGE *package)
-{
- UINT rc = ERROR_SUCCESS;
- MSIQUERY *view;
-
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
- '`','C','l','a','s','s','`',0};
-
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
- if (rc != ERROR_SUCCESS)
- return;
-
- rc = MSI_IterateRecords(view, NULL, iterate_all_classes, package);
- msiobj_release(&view->hdr);
-}
-
-static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param)
-{
- LPCWSTR buffer;
- LPCWSTR extension;
- INT component_index;
- MSIPACKAGE* package =(MSIPACKAGE*)param;
- BOOL match = FALSE;
- INT i;
-
- extension = MSI_RecordGetString(rec,1);
- buffer = MSI_RecordGetString(rec,2);
- component_index = get_loaded_component(package,buffer);
-
- for (i = 0; i < package->loaded_extensions; i++)
- {
- if (strcmpiW(extension,package->extensions[i].Extension))
- continue;
- if (component_index == package->extensions[i].ComponentIndex)
- {
- match = TRUE;
- break;
- }
- }
-
- if (!match)
- load_extension(package, rec);
-
- return ERROR_SUCCESS;
-}
-
-static VOID load_all_extensions(MSIPACKAGE *package)
-{
- UINT rc = ERROR_SUCCESS;
- MSIQUERY *view;
-
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','E','x','t','e','n','s','i','o','n','`',0};
-
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
- if (rc != ERROR_SUCCESS)
- return;
-
- rc = MSI_IterateRecords(view, NULL, iterate_all_extensions, package);
- msiobj_release(&view->hdr);
-}
-
-static UINT iterate_all_progids(MSIRECORD *rec, LPVOID param)
-{
- LPCWSTR buffer;
- MSIPACKAGE* package =(MSIPACKAGE*)param;
-
- buffer = MSI_RecordGetString(rec,1);
- load_given_progid(package,buffer);
- return ERROR_SUCCESS;
-}
-
-static VOID load_all_progids(MSIPACKAGE *package)
-{
- UINT rc = ERROR_SUCCESS;
- MSIQUERY *view;
-
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ',
- 'F','R','O','M',' ', '`','P','r','o','g','I','d','`',0};
-
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
- if (rc != ERROR_SUCCESS)
- return;
-
- rc = MSI_IterateRecords(view, NULL, iterate_all_progids, package);
- msiobj_release(&view->hdr);
-}
-
-static VOID load_all_verbs(MSIPACKAGE *package)
-{
- UINT rc = ERROR_SUCCESS;
- MSIQUERY *view;
-
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','V','e','r','b','`',0};
-
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
- if (rc != ERROR_SUCCESS)
- return;
-
- rc = MSI_IterateRecords(view, NULL, iterate_load_verb, package);
- msiobj_release(&view->hdr);
-}
-
-static UINT iterate_all_mimes(MSIRECORD *rec, LPVOID param)
-{
- LPCWSTR buffer;
- MSIPACKAGE* package =(MSIPACKAGE*)param;
-
- buffer = MSI_RecordGetString(rec,1);
- load_given_mime(package,buffer);
- return ERROR_SUCCESS;
-}
-
-static VOID load_all_mimes(MSIPACKAGE *package)
-{
- UINT rc = ERROR_SUCCESS;
- MSIQUERY *view;
-
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ',
- '`','C','o','n','t','e','n','t','T','y','p','e','`',
- ' ','F','R','O','M',' ',
- '`','M','I','M','E','`',0};
-
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
- if (rc != ERROR_SUCCESS)
- return;
-
- rc = MSI_IterateRecords(view, NULL, iterate_all_mimes, package);
- msiobj_release(&view->hdr);
-}
-
-static void load_classes_and_such(MSIPACKAGE *package)
-{
- TRACE("Loading all the class info and related tables\n");
-
- /* check if already loaded */
- if (package->classes || package->extensions || package->progids ||
- package->verbs || package->mimes)
- return;
-
- load_all_classes(package);
- load_all_extensions(package);
- load_all_progids(package);
- /* these loads must come after the other loads */
- load_all_verbs(package);
- load_all_mimes(package);
-}
-
-static void mark_progid_for_install(MSIPACKAGE* package, INT index)
-{
- MSIPROGID* progid;
- int i;
-
- if (index < 0 || index >= package->loaded_progids)
- return;
-
- progid = &package->progids[index];
-
- if (progid->InstallMe == TRUE)
- return;
-
- progid->InstallMe = TRUE;
-
- /* all children if this is a parent also install */
- for (i = 0; i < package->loaded_progids; i++)
- if (package->progids[i].ParentIndex == index)
- mark_progid_for_install(package,i);
-}
-
-static void mark_mime_for_install(MSIPACKAGE* package, INT index)
-{
- MSIMIME* mime;
-
- if (index < 0 || index >= package->loaded_mimes)
- return;
-
- mime = &package->mimes[index];
-
- if (mime->InstallMe == TRUE)
- return;
-
- mime->InstallMe = TRUE;
-}
-
-static UINT register_appid(MSIPACKAGE *package, int appidIndex, LPCWSTR app )
-{
- static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
- HKEY hkey2,hkey3;
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
- RegCreateKeyW(hkey2,package->appids[appidIndex].AppID,&hkey3);
- RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
- (strlenW(app)+1)*sizeof(WCHAR));
-
- if (package->appids[appidIndex].RemoteServerName)
- {
- UINT size;
- static const WCHAR szRemoteServerName[] =
- {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',
- 0};
-
- size = (strlenW(package->appids[appidIndex].RemoteServerName)+1) *
- sizeof(WCHAR);
-
- RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,
- (LPVOID)package->appids[appidIndex].RemoteServerName,
- size);
- }
-
- if (package->appids[appidIndex].LocalServer)
- {
- static const WCHAR szLocalService[] =
- {'L','o','c','a','l','S','e','r','v','i','c','e',0};
- UINT size;
- size = (strlenW(package->appids[appidIndex].LocalServer)+1) *
- sizeof(WCHAR);
-
- RegSetValueExW(hkey3,szLocalService,0,REG_SZ,
- (LPVOID)package->appids[appidIndex].LocalServer,size);
- }
-
- if (package->appids[appidIndex].ServiceParameters)
- {
- static const WCHAR szService[] =
- {'S','e','r','v','i','c','e',
- 'P','a','r','a','m','e','t','e','r','s',0};
- UINT size;
- size = (strlenW(package->appids[appidIndex].ServiceParameters)+1) *
- sizeof(WCHAR);
- RegSetValueExW(hkey3,szService,0,REG_SZ,
- (LPVOID)package->appids[appidIndex].ServiceParameters,
- size);
- }
-
- if (package->appids[appidIndex].DllSurrogate)
- {
- static const WCHAR szDLL[] =
- {'D','l','l','S','u','r','r','o','g','a','t','e',0};
- UINT size;
- size = (strlenW(package->appids[appidIndex].DllSurrogate)+1) *
- sizeof(WCHAR);
- RegSetValueExW(hkey3,szDLL,0,REG_SZ,
- (LPVOID)package->appids[appidIndex].DllSurrogate,size);
- }
-
- if (package->appids[appidIndex].ActivateAtStorage)
- {
- static const WCHAR szActivate[] =
- {'A','c','t','i','v','a','t','e','A','s',
- 'S','t','o','r','a','g','e',0};
- static const WCHAR szY[] = {'Y',0};
-
- RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
- }
-
- if (package->appids[appidIndex].RunAsInteractiveUser)
- {
- static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
- static const WCHAR szUser[] =
- {'I','n','t','e','r','a','c','t','i','v','e',' ',
- 'U','s','e','r',0};
-
- RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,sizeof(szUser));
- }
-
- RegCloseKey(hkey3);
- RegCloseKey(hkey2);
- return ERROR_SUCCESS;
-}
-
-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
- */
-
- UINT rc;
- MSIRECORD *uirow;
- static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
- static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
- static const WCHAR szVIProgID[] = { 'V','e','r','s','i','o','n','I','n','d','e','p','e','n','d','e','n','t','P','r','o','g','I','D',0 };
- static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
- static const WCHAR szSpace[] = {' ',0};
- static const WCHAR szInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
- static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0};
- HKEY hkey,hkey2,hkey3;
- BOOL install_on_demand = FALSE;
- int i;
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- load_classes_and_such(package);
- rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
- if (rc != ERROR_SUCCESS)
- return ERROR_FUNCTION_FAILED;
-
- /* install_on_demand should be set if OLE supports install on demand OLE
- * servers. For now i am defaulting to FALSE because i do not know how to
- * check, and i am told our builtin OLE does not support it
- */
-
- for (i = 0; i < package->loaded_classes; i++)
- {
- INT index,f_index;
- DWORD size, sz;
- LPWSTR argument;
-
- if (package->classes[i].ComponentIndex < 0)
- {
- continue;
- }
-
- index = package->classes[i].ComponentIndex;
- f_index = package->classes[i].FeatureIndex;
-
- /*
- * yes. MSDN says that these are based on _Feature_ not on
- * Component. So verify the feature is to be installed
- */
- if ((!ACTION_VerifyFeatureForAction(package, f_index,
- INSTALLSTATE_LOCAL)) &&
- !(install_on_demand && ACTION_VerifyFeatureForAction(package,
- f_index, INSTALLSTATE_ADVERTISED)))
- {
- TRACE("Skipping class %s reg due to disabled feature %s\n",
- debugstr_w(package->classes[i].CLSID),
- debugstr_w(package->features[f_index].Feature));
-
- continue;
- }
-
- TRACE("Registering index %i class %s\n",i,
- debugstr_w(package->classes[i].CLSID));
-
- package->classes[i].Installed = TRUE;
- if (package->classes[i].ProgIDIndex >= 0)
- mark_progid_for_install(package, package->classes[i].ProgIDIndex);
-
- RegCreateKeyW(hkey,package->classes[i].CLSID,&hkey2);
-
- if (package->classes[i].Description)
- RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)package->classes[i].
- Description, (strlenW(package->classes[i].
- Description)+1)*sizeof(WCHAR));
-
- RegCreateKeyW(hkey2,package->classes[i].Context,&hkey3);
- index = get_loaded_file(package,package->components[index].KeyPath);
-
-
- /* the context server is a short path name
- * except for if it is InprocServer32...
- */
- if (strcmpiW(package->classes[i].Context,szInprocServer32)!=0)
- {
- sz = 0;
- sz = GetShortPathNameW(package->files[index].TargetPath, NULL, 0);
- if (sz == 0)
- {
- ERR("Unable to find short path for CLSID COM Server\n");
- argument = NULL;
- }
- else
- {
- size = sz * sizeof(WCHAR);
-
- if (package->classes[i].Argument)
- {
- size += strlenW(package->classes[i].Argument) *
- sizeof(WCHAR);
- size += sizeof(WCHAR);
- }
-
- argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
- GetShortPathNameW(package->files[index].TargetPath, argument,
- sz);
-
- if (package->classes[i].Argument)
- {
- strcatW(argument,szSpace);
- strcatW(argument,package->classes[i].Argument);
- }
- }
- }
- else
- {
- size = lstrlenW(package->files[index].TargetPath) * sizeof(WCHAR);
-
- if (package->classes[i].Argument)
- {
- size += strlenW(package->classes[i].Argument) * sizeof(WCHAR);
- size += sizeof(WCHAR);
- }
-
- argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
- strcpyW(argument, package->files[index].TargetPath);
-
- if (package->classes[i].Argument)
- {
- strcatW(argument,szSpace);
- strcatW(argument,package->classes[i].Argument);
- }
- }
-
- if (argument)
- {
- RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size);
- HeapFree(GetProcessHeap(),0,argument);
- }
-
- RegCloseKey(hkey3);
-
- if (package->classes[i].ProgIDIndex >= 0 ||
- package->classes[i].ProgIDText)
- {
- LPCWSTR progid;
-
- if (package->classes[i].ProgIDIndex >= 0)
- progid = package->progids[
- package->classes[i].ProgIDIndex].ProgID;
- else
- progid = package->classes[i].ProgIDText;
-
- RegCreateKeyW(hkey2,szProgID,&hkey3);
- RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)progid,
- (strlenW(progid)+1) *sizeof(WCHAR));
- RegCloseKey(hkey3);
-
- if (package->classes[i].ProgIDIndex >= 0 &&
- package->progids[package->classes[i].ProgIDIndex].
- VersionIndIndex >= 0)
- {
- LPWSTR viprogid = strdupW(package->progids[package->progids[
- package->classes[i].ProgIDIndex].VersionIndIndex].
- ProgID);
- RegCreateKeyW(hkey2,szVIProgID,&hkey3);
- RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)viprogid,
- (strlenW(viprogid)+1) *sizeof(WCHAR));
- RegCloseKey(hkey3);
- HeapFree(GetProcessHeap(), 0, viprogid);
- }
- }
-
- if (package->classes[i].AppIDIndex >= 0)
- {
- RegSetValueExW(hkey2,szAppID,0,REG_SZ,
- (LPVOID)package->appids[package->classes[i].AppIDIndex].AppID,
- (strlenW(package->appids[package->classes[i].AppIDIndex].AppID)+1)
- *sizeof(WCHAR));
-
- register_appid(package,package->classes[i].AppIDIndex,
- package->classes[i].Description);
- }
-
- if (package->classes[i].IconPath)
- {
- static const WCHAR szDefaultIcon[] =
- {'D','e','f','a','u','l','t','I','c','o','n',0};
-
- RegCreateKeyW(hkey2,szDefaultIcon,&hkey3);
-
- RegSetValueExW(hkey3,NULL,0,REG_SZ,
- (LPVOID)package->classes[i].IconPath,
- (strlenW(package->classes[i].IconPath)+1) *
- sizeof(WCHAR));
-
- RegCloseKey(hkey3);
- }
-
- if (package->classes[i].DefInprocHandler)
- {
- static const WCHAR szInproc[] =
- {'I','n','p','r','o','c','H','a','n','d','l','e','r',0};
-
- size = (strlenW(package->classes[i].DefInprocHandler) + 1) *
- sizeof(WCHAR);
- RegCreateKeyW(hkey2,szInproc,&hkey3);
- RegSetValueExW(hkey3,NULL,0,REG_SZ,
- (LPVOID)package->classes[i].DefInprocHandler, size);
- RegCloseKey(hkey3);
- }
-
- if (package->classes[i].DefInprocHandler32)
- {
- static const WCHAR szInproc32[] =
- {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',
- 0};
- size = (strlenW(package->classes[i].DefInprocHandler32) + 1) *
- sizeof(WCHAR);
-
- RegCreateKeyW(hkey2,szInproc32,&hkey3);
- RegSetValueExW(hkey3,NULL,0,REG_SZ,
- (LPVOID)package->classes[i].DefInprocHandler32,size);
- RegCloseKey(hkey3);
- }
-
- RegCloseKey(hkey2);
-
- /* if there is a FileTypeMask, register the FileType */
- if (package->classes[i].FileTypeMask)
- {
- LPWSTR ptr, ptr2;
- LPWSTR keyname;
- INT index = 0;
- ptr = package->classes[i].FileTypeMask;
- while (ptr && *ptr)
- {
- ptr2 = strchrW(ptr,';');
- if (ptr2)
- *ptr2 = 0;
- keyname = HeapAlloc(GetProcessHeap(),0,(strlenW(szFileType_fmt)+
- strlenW(package->classes[i].CLSID) + 4)
- * sizeof(WCHAR));
- sprintfW(keyname,szFileType_fmt, package->classes[i].CLSID,
- index);
-
- RegCreateKeyW(HKEY_CLASSES_ROOT,keyname,&hkey2);
- RegSetValueExW(hkey2,NULL,0,REG_SZ, (LPVOID)ptr,
- strlenW(ptr)*sizeof(WCHAR));
- RegCloseKey(hkey2);
- HeapFree(GetProcessHeap(), 0, keyname);
-
- if (ptr2)
- ptr = ptr2+1;
- else
- ptr = NULL;
-
- index ++;
- }
- }
-
- uirow = MSI_CreateRecord(1);
-
- MSI_RecordSetStringW(uirow,1,package->classes[i].CLSID);
- ui_actiondata(package,szRegisterClassInfo,uirow);
- msiobj_release(&uirow->hdr);
- }
-
- RegCloseKey(hkey);
- return rc;
-}
-
-static UINT register_progid_base(MSIPACKAGE* package, MSIPROGID* progid,
- LPWSTR clsid)
-{
- static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
- static const WCHAR szDefaultIcon[] =
- {'D','e','f','a','u','l','t','I','c','o','n',0};
- HKEY hkey,hkey2;
-
- RegCreateKeyW(HKEY_CLASSES_ROOT,progid->ProgID,&hkey);
-
- if (progid->Description)
- {
- RegSetValueExW(hkey,NULL,0,REG_SZ,
- (LPVOID)progid->Description,
- (strlenW(progid->Description)+1) *
- sizeof(WCHAR));
- }
-
- if (progid->ClassIndex >= 0)
- {
- RegCreateKeyW(hkey,szCLSID,&hkey2);
- RegSetValueExW(hkey2,NULL,0,REG_SZ,
- (LPVOID)package->classes[progid->ClassIndex].CLSID,
- (strlenW(package->classes[progid->ClassIndex].CLSID)+1)
- * sizeof(WCHAR));
-
- if (clsid)
- strcpyW(clsid,package->classes[progid->ClassIndex].CLSID);
-
- RegCloseKey(hkey2);
- }
- else
- {
- FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
- }
-
- if (progid->IconPath)
- {
- RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
-
- RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath,
- (strlenW(progid->IconPath)+1) * sizeof(WCHAR));
- RegCloseKey(hkey2);
- }
- return ERROR_SUCCESS;
-}
-
-static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid,
- LPWSTR clsid)
-{
- UINT rc = ERROR_SUCCESS;
-
- if (progid->ParentIndex < 0)
- rc = register_progid_base(package, progid, clsid);
- else
- {
- DWORD disp;
- HKEY hkey,hkey2;
- static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
- static const WCHAR szDefaultIcon[] =
- {'D','e','f','a','u','l','t','I','c','o','n',0};
- static const WCHAR szCurVer[] =
- {'C','u','r','V','e','r',0};
-
- /* check if already registered */
- RegCreateKeyExW(HKEY_CLASSES_ROOT, progid->ProgID, 0, NULL, 0,
- KEY_ALL_ACCESS, NULL, &hkey, &disp );
- if (disp == REG_OPENED_EXISTING_KEY)
- {
- TRACE("Key already registered\n");
- RegCloseKey(hkey);
- return rc;
- }
-
- TRACE("Registering Parent %s index %i\n",
- debugstr_w(package->progids[progid->ParentIndex].ProgID),
- progid->ParentIndex);
- rc = register_progid(package,&package->progids[progid->ParentIndex],
- clsid);
-
- /* clsid is same as parent */
- RegCreateKeyW(hkey,szCLSID,&hkey2);
- RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
- sizeof(WCHAR));
-
- RegCloseKey(hkey2);
-
-
- if (progid->Description)
- {
- RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid->Description,
- (strlenW(progid->Description)+1) * sizeof(WCHAR));
- }
-
- if (progid->IconPath)
- {
- RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
- RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath,
- (strlenW(progid->IconPath)+1) * sizeof(WCHAR));
- RegCloseKey(hkey2);
- }
-
- /* write out the current version */
- if (progid->CurVerIndex >= 0)
- {
- RegCreateKeyW(hkey,szCurVer,&hkey2);
- RegSetValueExW(hkey2,NULL,0,REG_SZ,
- (LPVOID)package->progids[progid->CurVerIndex].ProgID,
- (strlenW(package->progids[progid->CurVerIndex].ProgID)+1) *
- sizeof(WCHAR));
- RegCloseKey(hkey2);
- }
-
- RegCloseKey(hkey);
- }
- return rc;
-}
-
-static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
-{
- INT i;
- MSIRECORD *uirow;
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- load_classes_and_such(package);
-
- for (i = 0; i < package->loaded_progids; i++)
- {
- WCHAR clsid[0x1000];
-
- /* check if this progid is to be installed */
- package->progids[i].InstallMe = ((package->progids[i].InstallMe) ||
- (package->progids[i].ClassIndex >= 0 &&
- package->classes[package->progids[i].ClassIndex].Installed));
-
- if (!package->progids[i].InstallMe)
- {
- TRACE("progid %s not scheduled to be installed\n",
- debugstr_w(package->progids[i].ProgID));
- continue;
- }
-
- TRACE("Registering progid %s index %i\n",
- debugstr_w(package->progids[i].ProgID), i);
-
- register_progid(package,&package->progids[i],clsid);
-
- uirow = MSI_CreateRecord(1);
- MSI_RecordSetStringW(uirow,1,package->progids[i].ProgID);
- ui_actiondata(package,szRegisterProgIdInfo,uirow);
- msiobj_release(&uirow->hdr);
- }
-
- return ERROR_SUCCESS;
-}
-
-static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name,
- LPWSTR *FilePath)
-{
- LPWSTR ProductCode;
- LPWSTR SystemFolder;
- LPWSTR dest;
- UINT rc;
-
- static const WCHAR szInstaller[] =
- {'M','i','c','r','o','s','o','f','t','\\',
- 'I','n','s','t','a','l','l','e','r','\\',0};
- static const WCHAR szFolder[] =
- {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
-
- ProductCode = load_dynamic_property(package,szProductCode,&rc);
- if (!ProductCode)
- return rc;
-
- SystemFolder = load_dynamic_property(package,szFolder,NULL);
-
- dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode);
-
- create_full_pathW(dest);
-
- *FilePath = build_directory_name(2, dest, icon_name);
-
- HeapFree(GetProcessHeap(),0,SystemFolder);
- HeapFree(GetProcessHeap(),0,ProductCode);
- HeapFree(GetProcessHeap(),0,dest);
- return ERROR_SUCCESS;
-}
-
-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;
- LPCWSTR buffer;
- WCHAR filename[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;
- }
-
- buffer = MSI_RecordGetString(row,4);
- 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;
- }
-
- buffer = MSI_RecordGetString(row,2);
- target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
-
- /* may be needed because of a bug somehwere else */
- create_full_pathW(target_folder);
-
- sz = 0x100;
- MSI_RecordGetStringW(row,3,filename,&sz);
- reduce_to_longfilename(filename);
- if (!strchrW(filename,'.') || strcmpiW(strchrW(filename,'.'),szlnk))
- strcatW(filename,szlnk);
- target_file = build_directory_name(2, target_folder, filename);
- HeapFree(GetProcessHeap(),0,target_folder);
-
- buffer = MSI_RecordGetString(row,5);
- if (strchrW(buffer,'['))
- {
- LPWSTR deformated;
- deformat_string(package,buffer,&deformated);
- IShellLinkW_SetPath(sl,deformated);
- HeapFree(GetProcessHeap(),0,deformated);
- }
- else
- {
- LPWSTR keypath;
- FIXME("poorly handled shortcut format, advertised shortcut\n");
- keypath = strdupW(package->components[index].FullKeypath);
- IShellLinkW_SetPath(sl,keypath);
- HeapFree(GetProcessHeap(),0,keypath);
- }
-
- if (!MSI_RecordIsNull(row,6))
- {
- LPWSTR deformated;
- buffer = MSI_RecordGetString(row,6);
- deformat_string(package,buffer,&deformated);
- IShellLinkW_SetArguments(sl,deformated);
- HeapFree(GetProcessHeap(),0,deformated);
- }
-
- if (!MSI_RecordIsNull(row,7))
- {
- buffer = MSI_RecordGetString(row,7);
- IShellLinkW_SetDescription(sl,buffer);
- }
-
- if (!MSI_RecordIsNull(row,8))
- IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
-
- if (!MSI_RecordIsNull(row,9))
- {
- WCHAR *Path = NULL;
- INT index;
-
- buffer = MSI_RecordGetString(row,9);
-
- build_icon_path(package,buffer,&Path);
- index = MSI_RecordGetInteger(row,10);
-
- IShellLinkW_SetIconLocation(sl,Path,index);
- HeapFree(GetProcessHeap(),0,Path);
- }
-
- if (!MSI_RecordIsNull(row,11))
- IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
-
- if (!MSI_RecordIsNull(row,12))
- {
- LPWSTR Path;
- buffer = MSI_RecordGetString(row,12);
- Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
- IShellLinkW_SetWorkingDirectory(sl,Path);
- HeapFree(GetProcessHeap(), 0, Path);
- }
-
- TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
- IPersistFile_Save(pf,target_file,FALSE);
-
- HeapFree(GetProcessHeap(),0,target_file);
-
- IPersistFile_Release( pf );
- IShellLinkW_Release( sl );
-
- 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};
- static const WCHAR szLanguage[] =
- {'L','a','n','g','u','a','g','e',0};
- static const WCHAR szProductLanguage[] =
- {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
- static const WCHAR szProductIcon[] =
- {'P','r','o','d','u','c','t','I','c','o','n',0};
- static const WCHAR szARPProductIcon[] =
- {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
- static const WCHAR szProductVersion[] =
- {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
- static const WCHAR szVersion[] =
- {'V','e','r','s','i','o','n',0};
- DWORD langid;
- LPWSTR buffer;
- DWORD size;
- MSIHANDLE hDb, hSumInfo;
-
- 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;
- LPWSTR FilePath=NULL;
- LPCWSTR FileName=NULL;
- CHAR buffer[1024];
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- FileName = MSI_RecordGetString(row,1);
- if (!FileName)
- {
- ERR("Unable to get FileName\n");
- msiobj_release(&row->hdr);
- continue;
- }
-
- build_icon_path(package,FileName,&FilePath);
-
- TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
-
- the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (the_file == INVALID_HANDLE_VALUE)
- {
- ERR("Unable to create file %s\n",debugstr_w(FilePath));
- 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, (BYTE *)buffer,size);
- HeapFree(GetProcessHeap(),0,buffer);
-
- buffer = load_dynamic_property(package,szProductLanguage,NULL);
- size = sizeof(DWORD);
- langid = atoiW(buffer);
- RegSetValueExW(hukey,szLanguage,0,REG_DWORD, (BYTE *)&langid,size);
- HeapFree(GetProcessHeap(),0,buffer);
-
- buffer = load_dynamic_property(package,szARPProductIcon,NULL);
- if (buffer)
- {
- LPWSTR path;
- build_icon_path(package,buffer,&path);
- size = strlenW(path) * sizeof(WCHAR);
- RegSetValueExW(hukey,szProductIcon,0,REG_SZ, (BYTE *)path,size);
- }
- HeapFree(GetProcessHeap(),0,buffer);
-
- buffer = load_dynamic_property(package,szProductVersion,NULL);
- if (buffer)
- {
- DWORD verdword = build_version_dword(buffer);
- size = sizeof(DWORD);
- RegSetValueExW(hukey,szVersion,0,REG_DWORD, (BYTE *)&verdword,size);
- }
- HeapFree(GetProcessHeap(),0,buffer);
-
- FIXME("Need to write more keys to the user registry\n");
-
- hDb= alloc_msihandle( &package->db->hdr );
- 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)
- {
- LPCWSTR component,section,key,value,identifier,filename,dirproperty;
- LPWSTR deformated_section, deformated_key, deformated_value;
- LPWSTR folder, fullname = NULL;
- MSIRECORD * uirow;
- INT component_index,action;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- component = MSI_RecordGetString(row, 8);
- component_index = get_loaded_component(package,component);
-
- if (!ACTION_VerifyComponentForAction(package, component_index,
- INSTALLSTATE_LOCAL))
- {
- TRACE("Skipping ini file due to disabled component %s\n",
- debugstr_w(component));
- msiobj_release(&row->hdr);
-
- package->components[component_index].Action =
- package->components[component_index].Installed;
-
- continue;
- }
-
- package->components[component_index].Action = INSTALLSTATE_LOCAL;
-
- identifier = MSI_RecordGetString(row,1);
- filename = MSI_RecordGetString(row,2);
- dirproperty = MSI_RecordGetString(row,3);
- section = MSI_RecordGetString(row,4);
- key = MSI_RecordGetString(row,5);
- value = MSI_RecordGetString(row,6);
- action = MSI_RecordGetInteger(row,7);
-
- deformat_string(package,section,&deformated_section);
- deformat_string(package,key,&deformated_key);
- deformat_string(package,value,&deformated_value);
-
- if (dirproperty)
- {
- folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
- if (!folder)
- folder = load_dynamic_property(package,dirproperty,NULL);
- }
- else
- folder = load_dynamic_property(package, szWindowsFolder, NULL);
-
- if (!folder)
- {
- ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
- goto cleanup;
- }
-
- fullname = build_directory_name(3, folder, filename, NULL);
-
- if (action == 0)
- {
- TRACE("Adding value %s to section %s in %s\n",
- debugstr_w(deformated_key), debugstr_w(deformated_section),
- debugstr_w(fullname));
- WritePrivateProfileStringW(deformated_section, deformated_key,
- deformated_value, fullname);
- }
- else if (action == 1)
- {
- WCHAR returned[10];
- GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
- returned, 10, fullname);
- if (returned[0] == 0)
- {
- TRACE("Adding value %s to section %s in %s\n",
- debugstr_w(deformated_key), debugstr_w(deformated_section),
- debugstr_w(fullname));
-
- WritePrivateProfileStringW(deformated_section, deformated_key,
- deformated_value, fullname);
- }
- }
- else if (action == 3)
- {
- FIXME("Append to existing section not yet implemented\n");
- }
-
- uirow = MSI_CreateRecord(4);
- MSI_RecordSetStringW(uirow,1,identifier);
- MSI_RecordSetStringW(uirow,2,deformated_section);
- MSI_RecordSetStringW(uirow,3,deformated_key);
- MSI_RecordSetStringW(uirow,4,deformated_value);
- ui_actiondata(package,szWriteIniValues,uirow);
- msiobj_release( &uirow->hdr );
-cleanup:
- HeapFree(GetProcessHeap(),0,fullname);
- HeapFree(GetProcessHeap(),0,folder);
- HeapFree(GetProcessHeap(),0,deformated_key);
- HeapFree(GetProcessHeap(),0,deformated_value);
- HeapFree(GetProcessHeap(),0,deformated_section);
- 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',' ','\"',0};
- static const WCHAR close[] = {'\"',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)
- {
- LPCWSTR filename;
- LPWSTR FullName;
- INT index;
- DWORD len;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- filename = MSI_RecordGetString(row,1);
- index = get_loaded_file(package,filename);
-
- if (index < 0)
- {
- ERR("Unable to find file id %s\n",debugstr_w(filename));
- msiobj_release(&row->hdr);
- continue;
- }
-
- len = strlenW(ExeStr);
- len += strlenW(package->files[index].TargetPath);
- len +=2;
-
- FullName = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
- strcpyW(FullName,ExeStr);
- strcatW(FullName,package->files[index].TargetPath);
- strcatW(FullName,close);
-
- TRACE("Registering %s\n",debugstr_w(FullName));
- brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL,
- c_colon, &si, &info);
-
- if (brc)
- msi_dialog_check_messages(info.hProcess);
-
- HeapFree(GetProcessHeap(),0,FullName);
- 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;
- BOOL absent = FALSE;
-
- if (!ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_LOCAL) &&
- !ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_SOURCE) &&
- !ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_ADVERTISED))
- absent = TRUE;
-
- 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));
- if (package->components
- [package->features[i].Components[j]].ComponentId[0]!=0)
- {
- 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);
-
- if (!absent)
- {
- 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);
- }
- else
- {
- size = (strlenW(package->features[i].Feature_Parent)+2)*
- sizeof(WCHAR);
- data = HeapAlloc(GetProcessHeap(),0,size);
- data[0] = 0x6;
- strcpyW(&data[1],package->features[i].Feature_Parent);
- RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ,
- (LPSTR)data,size);
- HeapFree(GetProcessHeap(),0,data);
- }
- }
-
-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};
- static const WCHAR szUpgradeCode[] =
- {'U','p','g','r','a','d','e','C','o','d','e',0};
- LPWSTR upgrade_code;
- 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));
- if (!CopyFileW(package->PackagePath,packagefile,FALSE))
- ERR("Unable to copy package (%s -> %s) (error %ld)\n",
- debugstr_w(package->PackagePath), debugstr_w(packagefile),
- GetLastError());
- size = strlenW(packagefile)*sizeof(WCHAR);
- RegSetValueExW(hkey,szLocalPackage,0,REG_SZ,(LPSTR)packagefile,size);
-
- /* Handle Upgrade Codes */
- upgrade_code = load_dynamic_property(package,szUpgradeCode, NULL);
- if (upgrade_code)
- {
- HKEY hkey2;
- WCHAR squashed[33];
- MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
- squash_guid(productcode,squashed);
- RegSetValueExW(hkey2, squashed, 0,REG_SZ,NULL,0);
- RegCloseKey(hkey2);
- MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
- squash_guid(productcode,squashed);
- RegSetValueExW(hkey2, squashed, 0,REG_SZ,NULL,0);
- RegCloseKey(hkey2);
-
- HeapFree(GetProcessHeap(),0,upgrade_code);
- }
-
-end:
- HeapFree(GetProcessHeap(),0,productcode);
- RegCloseKey(hkey);
-
- return ERROR_SUCCESS;
-}
-
-static UINT ACTION_InstallExecute(MSIPACKAGE *package)
-{
- UINT rc;
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- rc = execute_script(package,INSTALL_SCRIPT);
-
- return rc;
-}
-
-static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
-{
- UINT rc;
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- /* turn off scheduleing */
- package->script->CurrentlyScripting= FALSE;
-
- /* first do the same as an InstallExecute */
- rc = ACTION_InstallExecute(package);
- if (rc != ERROR_SUCCESS)
- return rc;
-
- /* then handle Commit Actions */
- rc = execute_script(package,COMMIT_SCRIPT);
-
- return rc;
-}
-
-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 LPWSTR create_component_advertise_string(MSIPACKAGE* package,
- MSICOMPONENT* component, LPCWSTR feature)
-{
- LPWSTR productid=NULL;
- GUID clsid;
- WCHAR productid_85[21];
- WCHAR component_85[21];
- /*
- * I have a fair bit of confusion as to when a < is used and when a > is
- * used. I do not think i have it right...
- *
- * Ok it appears that the > is used if there is a guid for the compoenent
- * and the < is used if not.
- */
- static WCHAR fmt1[] = {'%','s','%','s','<',0,0};
- static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0};
- LPWSTR output = NULL;
- DWORD sz = 0;
-
- memset(productid_85,0,sizeof(productid_85));
- memset(component_85,0,sizeof(component_85));
-
- productid = load_dynamic_property(package,szProductCode,NULL);
- CLSIDFromString(productid, &clsid);
-
- encode_base85_guid(&clsid,productid_85);
-
- CLSIDFromString(component->ComponentId, &clsid);
- encode_base85_guid(&clsid,component_85);
-
- TRACE("Doing something with this... %s %s %s\n",
- debugstr_w(productid_85), debugstr_w(feature),
- debugstr_w(component_85));
-
- sz = lstrlenW(productid_85) + lstrlenW(feature);
- if (component)
- sz += lstrlenW(component_85);
-
- sz+=3;
- sz *= sizeof(WCHAR);
-
- output = HeapAlloc(GetProcessHeap(),0,sz);
- memset(output,0,sz);
-
- if (component)
- sprintfW(output,fmt2,productid_85,feature,component_85);
- else
- sprintfW(output,fmt1,productid_85,feature);
-
- HeapFree(GetProcessHeap(),0,productid);
-
- return output;
-}
-
-static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid,
- MSICOMPONENT* component, MSIEXTENSION* extension,
- MSIVERB* verb, INT* Sequence )
-{
- LPWSTR keyname;
- HKEY key;
- static const WCHAR szShell[] = {'s','h','e','l','l',0};
- static const WCHAR szCommand[] = {'c','o','m','m','a','n','d',0};
- static const WCHAR fmt[] = {'\"','%','s','\"',' ','%','s',0};
- static const WCHAR fmt2[] = {'\"','%','s','\"',0};
- LPWSTR command;
- DWORD size;
- LPWSTR advertise;
-
- keyname = build_directory_name(4, progid, szShell, verb->Verb, szCommand);
-
- TRACE("Making Key %s\n",debugstr_w(keyname));
- RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
- size = strlenW(component->FullKeypath);
- if (verb->Argument)
- size += strlenW(verb->Argument);
- size += 4;
-
- command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
- if (verb->Argument)
- sprintfW(command, fmt, component->FullKeypath, verb->Argument);
- else
- sprintfW(command, fmt2, component->FullKeypath);
-
- RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)command, (strlenW(command)+1)*
- sizeof(WCHAR));
- HeapFree(GetProcessHeap(),0,command);
-
- advertise = create_component_advertise_string(package, component,
- package->features[extension->FeatureIndex].Feature);
-
- size = strlenW(advertise);
-
- if (verb->Argument)
- size += strlenW(verb->Argument);
- size += 4;
-
- command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
- memset(command,0,size*sizeof(WCHAR));
-
- strcpyW(command,advertise);
- if (verb->Argument)
- {
- static const WCHAR szSpace[] = {' ',0};
- strcatW(command,szSpace);
- strcatW(command,verb->Argument);
- }
-
- RegSetValueExW(key, szCommand, 0, REG_MULTI_SZ, (LPBYTE)command,
- (strlenW(command)+2)*sizeof(WCHAR));
-
- RegCloseKey(key);
- HeapFree(GetProcessHeap(),0,keyname);
- HeapFree(GetProcessHeap(),0,advertise);
- HeapFree(GetProcessHeap(),0,command);
-
- if (verb->Command)
- {
- keyname = build_directory_name(3, progid, szShell, verb->Verb);
- RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
- RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Command,
- (strlenW(verb->Command)+1) *sizeof(WCHAR));
- RegCloseKey(key);
- HeapFree(GetProcessHeap(),0,keyname);
- }
-
- if (verb->Sequence != MSI_NULL_INTEGER)
- {
- if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence)
- {
- *Sequence = verb->Sequence;
- keyname = build_directory_name(2, progid, szShell);
- RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
- RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Verb,
- (strlenW(verb->Verb)+1) *sizeof(WCHAR));
- RegCloseKey(key);
- HeapFree(GetProcessHeap(),0,keyname);
- }
- }
- return ERROR_SUCCESS;
-}
-
-static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
-{
- static const WCHAR szContentType[] =
- {'C','o','n','t','e','n','t',' ','T','y','p','e',0 };
- HKEY hkey;
- INT i;
- MSIRECORD *uirow;
- BOOL install_on_demand = TRUE;
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- load_classes_and_such(package);
-
- /* We need to set install_on_demand based on if the shell handles advertised
- * shortcuts and the like. Because Mike McCormack is working on this i am
- * going to default to TRUE
- */
-
- for (i = 0; i < package->loaded_extensions; i++)
- {
- WCHAR extension[257];
- INT index,f_index;
-
- index = package->extensions[i].ComponentIndex;
- f_index = package->extensions[i].FeatureIndex;
-
- if (index < 0)
- continue;
-
- /*
- * yes. MSDN says that these are based on _Feature_ not on
- * Component. So verify the feature is to be installed
- */
- if ((!ACTION_VerifyFeatureForAction(package, f_index,
- INSTALLSTATE_LOCAL)) &&
- !(install_on_demand && ACTION_VerifyFeatureForAction(package,
- f_index, INSTALLSTATE_ADVERTISED)))
- {
- TRACE("Skipping extension %s reg due to disabled feature %s\n",
- debugstr_w(package->extensions[i].Extension),
- debugstr_w(package->features[f_index].Feature));
-
- continue;
- }
-
- TRACE("Registering extension %s index %i\n",
- debugstr_w(package->extensions[i].Extension), i);
-
- package->extensions[i].Installed = TRUE;
-
- /* this is only registered if the extension has at least 1 verb
- * according to MSDN
- */
- if (package->extensions[i].ProgIDIndex >= 0 &&
- package->extensions[i].VerbCount > 0)
- mark_progid_for_install(package, package->extensions[i].ProgIDIndex);
-
- if (package->extensions[i].MIMEIndex >= 0)
- mark_mime_for_install(package, package->extensions[i].MIMEIndex);
-
- extension[0] = '.';
- extension[1] = 0;
- strcatW(extension,package->extensions[i].Extension);
-
- RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey);
-
- if (package->extensions[i].MIMEIndex >= 0)
- {
- RegSetValueExW(hkey,szContentType,0,REG_SZ,
- (LPVOID)package->mimes[package->extensions[i].
- MIMEIndex].ContentType,
- (strlenW(package->mimes[package->extensions[i].
- MIMEIndex].ContentType)+1)*sizeof(WCHAR));
- }
-
- if (package->extensions[i].ProgIDIndex >= 0 ||
- package->extensions[i].ProgIDText)
- {
- static const WCHAR szSN[] =
- {'\\','S','h','e','l','l','N','e','w',0};
- HKEY hkey2;
- LPWSTR newkey;
- LPCWSTR progid;
- INT v;
- INT Sequence = MSI_NULL_INTEGER;
-
- if (package->extensions[i].ProgIDIndex >= 0)
- progid = package->progids[package->extensions[i].
- ProgIDIndex].ProgID;
- else
- progid = package->extensions[i].ProgIDText;
-
- RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid,
- (strlenW(progid)+1)*sizeof(WCHAR));
-
- newkey = HeapAlloc(GetProcessHeap(),0,
- (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR));
-
- strcpyW(newkey,progid);
- strcatW(newkey,szSN);
- RegCreateKeyW(hkey,newkey,&hkey2);
- RegCloseKey(hkey2);
-
- HeapFree(GetProcessHeap(),0,newkey);
-
- /* do all the verbs */
- for (v = 0; v < package->extensions[i].VerbCount; v++)
- register_verb(package, progid,
- &package->components[index],
- &package->extensions[i],
- &package->verbs[package->extensions[i].Verbs[v]],
- &Sequence);
- }
-
- RegCloseKey(hkey);
-
- uirow = MSI_CreateRecord(1);
- MSI_RecordSetStringW(uirow,1,package->extensions[i].Extension);
- ui_actiondata(package,szRegisterExtensionInfo,uirow);
- msiobj_release(&uirow->hdr);
- }
-
- return ERROR_SUCCESS;
-}
-
-static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
-{
- static const WCHAR szExten[] =
- {'E','x','t','e','n','s','i','o','n',0 };
- HKEY hkey;
- INT i;
- MSIRECORD *uirow;
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- load_classes_and_such(package);
-
- for (i = 0; i < package->loaded_mimes; i++)
- {
- WCHAR extension[257];
- LPCWSTR exten;
- LPCWSTR mime;
- static const WCHAR fmt[] =
- {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\',
- 'C','o','n','t','e','n','t',' ','T','y','p','e','\\', '%','s',0};
- LPWSTR key;
-
- /*
- * check if the MIME is to be installed. Either as requesed by an
- * extension or Class
- */
- package->mimes[i].InstallMe = ((package->mimes[i].InstallMe) ||
- (package->mimes[i].ClassIndex >= 0 &&
- package->classes[package->mimes[i].ClassIndex].Installed) ||
- (package->mimes[i].ExtensionIndex >=0 &&
- package->extensions[package->mimes[i].ExtensionIndex].Installed));
-
- if (!package->mimes[i].InstallMe)
- {
- TRACE("MIME %s not scheduled to be installed\n",
- debugstr_w(package->mimes[i].ContentType));
- continue;
- }
-
- mime = package->mimes[i].ContentType;
- exten = package->extensions[package->mimes[i].ExtensionIndex].Extension;
- extension[0] = '.';
- extension[1] = 0;
- strcatW(extension,exten);
-
- key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) *
- sizeof(WCHAR));
- sprintfW(key,fmt,mime);
- RegCreateKeyW(HKEY_CLASSES_ROOT,key,&hkey);
- RegSetValueExW(hkey,szExten,0,REG_SZ,(LPVOID)extension,
- (strlenW(extension)+1)*sizeof(WCHAR));
-
- HeapFree(GetProcessHeap(),0,key);
-
- if (package->mimes[i].CLSID[0])
- {
- FIXME("Handle non null for field 3\n");
- }
-
- RegCloseKey(hkey);
-
- uirow = MSI_CreateRecord(2);
- MSI_RecordSetStringW(uirow,1,package->mimes[i].ContentType);
- MSI_RecordSetStringW(uirow,2,exten);
- ui_actiondata(package,szRegisterMIMEInfo,uirow);
- msiobj_release(&uirow->hdr);
- }
-
- return ERROR_SUCCESS;
-}
-
-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},
- };
+ 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] =
{
- {'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},
+{'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},
};
- 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);
- }
- else
- RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,NULL,0);
- 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,FALSE);
- 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 LPCSTR 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);
- }
- else
- ERR("Unable to open font file %s\n", debugstr_w(filename));
-
- TRACE("Returning fontname %s\n",debugstr_w(ret));
- return ret;
-}
+ 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};
+ static const WCHAR szUpgradeCode[] =
+ {'U','p','g','r','a','d','e','C','o','d','e',0};
+ LPWSTR upgrade_code;
+ WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
+ INT num,start;
-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;
+ if (!package)
+ return ERROR_INVALID_HANDLE;
- TRACE("%p\n", package);
+ productcode = load_dynamic_property(package,szProductCode,&rc);
+ if (!productcode)
+ return rc;
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);
if (rc != ERROR_SUCCESS)
- {
- TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
- return ERROR_SUCCESS;
- }
+ goto end;
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
+ /* dump all the info i can grab */
+ FIXME("Flesh out more information \n");
+
+ i = 0;
+ while (szPropKeys[i][0]!=0)
{
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- TRACE("MSI_ViewExecute returned %d\n", rc);
- return ERROR_SUCCESS;
+ 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++;
}
- RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
- RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
+ rc = 0x1;
+ size = sizeof(rc);
+ RegSetValueExW(hkey,szWindowsInstaler,0,REG_DWORD,(LPSTR)&rc,size);
- while (1)
+ /* 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
{
- LPWSTR name;
- LPCWSTR file;
- UINT index;
- DWORD size;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
+ HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
+ CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
+ if (handle != INVALID_HANDLE_VALUE)
{
- rc = ERROR_SUCCESS;
+ 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);
- file = MSI_RecordGetString(row,1);
- index = get_loaded_file(package,file);
- if (index < 0)
- {
- ERR("Unable to load file\n");
- continue;
- }
+ snprintfW(path,sizeof(path)/sizeof(path[0]),installerPathFmt,windir);
+ create_full_pathW(path);
+ TRACE("Copying to local package %s\n",debugstr_w(packagefile));
+ if (!CopyFileW(package->PackagePath,packagefile,FALSE))
+ ERR("Unable to copy package (%s -> %s) (error %ld)\n",
+ debugstr_w(package->PackagePath), debugstr_w(packagefile),
+ GetLastError());
+ size = strlenW(packagefile)*sizeof(WCHAR);
+ RegSetValueExW(hkey,szLocalPackage,0,REG_SZ,(LPSTR)packagefile,size);
- /* 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");
+ /* Handle Upgrade Codes */
+ upgrade_code = load_dynamic_property(package,szUpgradeCode, NULL);
+ if (upgrade_code)
+ {
+ HKEY hkey2;
+ WCHAR squashed[33];
+ MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
+ squash_guid(productcode,squashed);
+ RegSetValueExW(hkey2, squashed, 0,REG_SZ,NULL,0);
+ RegCloseKey(hkey2);
+ MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
+ squash_guid(productcode,squashed);
+ RegSetValueExW(hkey2, squashed, 0,REG_SZ,NULL,0);
+ RegCloseKey(hkey2);
- msiobj_release(&row->hdr);
+ HeapFree(GetProcessHeap(),0,upgrade_code);
+ }
+
+end:
+ HeapFree(GetProcessHeap(),0,productcode);
+ RegCloseKey(hkey);
- continue;
- }
+ return ERROR_SUCCESS;
+}
- if (MSI_RecordIsNull(row,2))
- name = load_ttfname_from(package->files[index].TargetPath);
- else
- name = load_dynamic_stringW(row,2);
+static UINT ACTION_InstallExecute(MSIPACKAGE *package)
+{
+ UINT rc;
- if (name)
- {
- size = strlenW(package->files[index].FileName) * sizeof(WCHAR);
- RegSetValueExW(hkey1,name,0,REG_SZ,
- (LPBYTE)package->files[index].FileName,size);
- RegSetValueExW(hkey2,name,0,REG_SZ,
- (LPBYTE)package->files[index].FileName,size);
- }
-
- HeapFree(GetProcessHeap(),0,name);
- msiobj_release(&row->hdr);
- }
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
- RegCloseKey(hkey1);
- RegCloseKey(hkey2);
+ rc = execute_script(package,INSTALL_SCRIPT);
- TRACE("returning %d\n", rc);
return rc;
}
-static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
+static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
{
- MSIPACKAGE *package = (MSIPACKAGE*)param;
- LPCWSTR compgroupid=NULL;
- LPCWSTR feature=NULL;
- LPCWSTR text = NULL;
- LPCWSTR qualifier = NULL;
- LPCWSTR component = NULL;
- LPWSTR advertise = NULL;
- LPWSTR output = NULL;
- HKEY hkey;
- UINT rc = ERROR_SUCCESS;
- UINT index;
- DWORD sz = 0;
-
- component = MSI_RecordGetString(rec,3);
- index = get_loaded_component(package,component);
-
- if (!ACTION_VerifyComponentForAction(package, index,
- INSTALLSTATE_LOCAL) &&
- !ACTION_VerifyComponentForAction(package, index,
- INSTALLSTATE_SOURCE) &&
- !ACTION_VerifyComponentForAction(package, index,
- INSTALLSTATE_ADVERTISED))
- {
- TRACE("Skipping: Component %s not scheduled for install\n",
- debugstr_w(component));
+ UINT rc;
- return ERROR_SUCCESS;
- }
+ if (!package)
+ return ERROR_INVALID_HANDLE;
- compgroupid = MSI_RecordGetString(rec,1);
+ /* turn off scheduleing */
+ package->script->CurrentlyScripting= FALSE;
- rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
+ /* first do the same as an InstallExecute */
+ rc = ACTION_InstallExecute(package);
if (rc != ERROR_SUCCESS)
- goto end;
-
- text = MSI_RecordGetString(rec,4);
- qualifier = MSI_RecordGetString(rec,2);
- feature = MSI_RecordGetString(rec,5);
-
- advertise = create_component_advertise_string(package,
- &package->components[index], feature);
-
- sz = strlenW(advertise);
-
- if (text)
- sz += lstrlenW(text);
-
- sz+=3;
- sz *= sizeof(WCHAR);
-
- output = HeapAlloc(GetProcessHeap(),0,sz);
- memset(output,0,sz);
- strcpyW(output,advertise);
+ return rc;
- if (text)
- strcatW(output,text);
+ /* then handle Commit Actions */
+ rc = execute_script(package,COMMIT_SCRIPT);
- sz = (lstrlenW(output)+2) * sizeof(WCHAR);
- RegSetValueExW(hkey, qualifier,0,REG_MULTI_SZ, (LPBYTE)output, sz);
-
-end:
- RegCloseKey(hkey);
- HeapFree(GetProcessHeap(),0,output);
-
return rc;
}
-/*
- * At present I am ignorning the advertised components part of this and only
- * focusing on the qualified component sets
- */
-static UINT ACTION_PublishComponents(MSIPACKAGE *package)
+static UINT ACTION_ForceReboot(MSIPACKAGE *package)
{
- UINT rc;
- MSIQUERY * view;
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','P','u','b','l','i','s','h',
- 'C','o','m','p','o','n','e','n','t','`',0};
-
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
- if (rc != ERROR_SUCCESS)
- return ERROR_SUCCESS;
+ 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};
- rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
- msiobj_release(&view->hdr);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
- return rc;
-}
+ productcode = load_dynamic_property(package,szProductCode,&rc);
+ if (!productcode)
+ return rc;
-/* Msi functions that seem appropriate here */
+ squash_guid(productcode,squished_pc);
-/***********************************************************************
- * MsiDoActionA (MSI.@)
- */
-UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
-{
- LPWSTR szwAction;
- UINT rc;
+ 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);
- TRACE(" exteral attempt at action %s\n",szAction);
+ size = strlenW(buffer)*sizeof(WCHAR);
+ RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
+ RegCloseKey(hkey);
- if (!szAction)
- return ERROR_FUNCTION_FAILED;
- if (hInstall == 0)
- return ERROR_FUNCTION_FAILED;
+ TRACE("Reboot command %s\n",debugstr_w(buffer));
- szwAction = strdupAtoW(szAction);
+ RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
+ sprintfW(buffer,install_fmt,productcode,squished_pc);
- if (!szwAction)
- return ERROR_FUNCTION_FAILED;
+ 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);
- rc = MsiDoActionW(hInstall, szwAction);
- HeapFree(GetProcessHeap(),0,szwAction);
- return rc;
+ 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;
}
-/***********************************************************************
- * MsiDoActionW (MSI.@)
- */
-UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
+UINT ACTION_ResolveSource(MSIPACKAGE* package)
{
- MSIPACKAGE *package;
- UINT ret = ERROR_INVALID_HANDLE;
+ /*
+ * 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;
+}
- TRACE(" external attempt at action %s \n",debugstr_w(szAction));
+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;
- package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
- if( package )
+ static const WCHAR szPropKeys[][80] =
{
- ret = ACTION_PerformUIAction(package,szAction);
- msiobj_release( &package->hdr );
- }
- return ret;
-}
+ {'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},
+ };
-UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
- LPSTR szPathBuf, DWORD* pcchPathBuf)
-{
- LPWSTR szwFolder;
- LPWSTR szwPathBuf;
- UINT rc;
+ 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},
+ };
- TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
- if (!szFolder)
- return ERROR_FUNCTION_FAILED;
- if (hInstall == 0)
- return ERROR_FUNCTION_FAILED;
+ productid = load_dynamic_property(package,szProductID,&rc);
+ if (!productid)
+ return ERROR_SUCCESS;
- szwFolder = strdupAtoW(szFolder);
+ productcode = load_dynamic_property(package,szProductCode,&rc);
+ if (!productcode)
+ return rc;
- if (!szwFolder)
- return ERROR_FUNCTION_FAILED;
+ rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);
+ if (rc != ERROR_SUCCESS)
+ goto end;
- szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
+ 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);
+ }
+ else
+ RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,NULL,0);
+ i++;
+ }
- rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
+end:
+ HeapFree(GetProcessHeap(),0,productcode);
+ HeapFree(GetProcessHeap(),0,productid);
+ RegCloseKey(hkey);
- WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
- *pcchPathBuf, NULL, NULL );
+ return ERROR_SUCCESS;
+}
- HeapFree(GetProcessHeap(),0,szwFolder);
- HeapFree(GetProcessHeap(),0,szwPathBuf);
+static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
+{
+ UINT rc;
+ rc = ACTION_ProcessExecSequence(package,FALSE);
return rc;
}
-UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
- szPathBuf, DWORD* pcchPathBuf)
+
+/*
+ * 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)
{
- LPWSTR path;
- UINT rc = ERROR_FUNCTION_FAILED;
- MSIPACKAGE *package;
+ HANDLE handle;
+ LPWSTR ret = NULL;
+ int i;
- TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
+ typedef struct _tagTT_OFFSET_TABLE{
+ USHORT uMajorVersion;
+ USHORT uMinorVersion;
+ USHORT uNumOfTables;
+ USHORT uSearchRange;
+ USHORT uEntrySelector;
+ USHORT uRangeShift;
+ }TT_OFFSET_TABLE;
- package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
- if (!package)
- return ERROR_INVALID_HANDLE;
- path = resolve_folder(package, szFolder, FALSE, FALSE, NULL);
- msiobj_release( &package->hdr );
+ 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;
- 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;
-}
+ 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)))
-UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder,
- LPSTR szPathBuf, DWORD* pcchPathBuf)
-{
- LPWSTR szwFolder;
- LPWSTR szwPathBuf;
- UINT rc;
+ 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;
- TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
+ 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;
- if (!szFolder)
- return ERROR_FUNCTION_FAILED;
- if (hInstall == 0)
- return ERROR_FUNCTION_FAILED;
+ 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;
+ }
+ }
- szwFolder = strdupAtoW(szFolder);
- if (!szwFolder)
- return ERROR_FUNCTION_FAILED;
+ if (bFound)
+ {
+ TT_NAME_TABLE_HEADER ttNTHeader;
+ TT_NAME_RECORD ttRecord;
- szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
+ SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
+ ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
+ NULL,NULL);
- rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
+ 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 LPCSTR tt = " (TrueType)";
- WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
- *pcchPathBuf, NULL, NULL );
+ 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,szwFolder);
- HeapFree(GetProcessHeap(),0,szwPathBuf);
+ HeapFree(GetProcessHeap(),0,buf);
+ SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
+ }
+ }
+ }
+ CloseHandle(handle);
+ }
+ else
+ ERR("Unable to open font file %s\n", debugstr_w(filename));
- return rc;
+ TRACE("Returning fontname %s\n",debugstr_w(ret));
+ return ret;
}
-UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
- szPathBuf, DWORD* pcchPathBuf)
+static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
{
- 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 );
+ MSIPACKAGE *package = (MSIPACKAGE*)param;
+ LPWSTR name;
+ LPCWSTR file;
+ UINT index;
+ DWORD size;
+ static const WCHAR regfont1[] =
+ {'S','o','f','t','w','a','r','e','\\',
+ 'M','i','c','r','o','s','o','f','t','\\',
+ '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;
- if (path && strlenW(path) > *pcchPathBuf)
- {
- *pcchPathBuf = strlenW(path)+1;
- rc = ERROR_MORE_DATA;
- }
- else if (path)
+ file = MSI_RecordGetString(row,1);
+ index = get_loaded_file(package,file);
+ if (index < 0)
{
- *pcchPathBuf = strlenW(path)+1;
- strcpyW(szPathBuf,path);
- TRACE("Returning Path %s\n",debugstr_w(path));
- rc = ERROR_SUCCESS;
+ ERR("Unable to load file\n");
+ return ERROR_SUCCESS;
}
- HeapFree(GetProcessHeap(),0,path);
-
- return rc;
-}
-
-
-/***********************************************************************
- * MsiSetTargetPathA (MSI.@)
- */
-UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder,
- LPCSTR szFolderPath)
-{
- LPWSTR szwFolder;
- LPWSTR szwFolderPath;
- UINT rc;
-
- if (!szFolder)
- return ERROR_FUNCTION_FAILED;
- if (hInstall == 0)
- return ERROR_FUNCTION_FAILED;
- szwFolder = strdupAtoW(szFolder);
- if (!szwFolder)
- return ERROR_FUNCTION_FAILED;
-
- szwFolderPath = strdupAtoW(szFolderPath);
- if (!szwFolderPath)
+ /* check to make sure that component is installed */
+ if (!ACTION_VerifyComponentForAction(package,
+ package->files[index].ComponentIndex, INSTALLSTATE_LOCAL))
{
- HeapFree(GetProcessHeap(),0,szwFolder);
- return ERROR_FUNCTION_FAILED;
+ TRACE("Skipping: Component not scheduled for install\n");
+ return ERROR_SUCCESS;
}
- 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);
+ RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
+ RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
- if (lstrcmpiW(path, folder->Property) == 0)
- {
- /*
- * Resolved Target has not really changed, so just
- * set this folder and do not recalculate everything.
- */
- HeapFree(GetProcessHeap(),0,folder->ResolvedTarget);
- folder->ResolvedTarget = NULL;
- path2 = resolve_folder(package,szFolder,FALSE,TRUE,NULL);
- HeapFree(GetProcessHeap(),0,path2);
- }
+ if (MSI_RecordIsNull(row,2))
+ name = load_ttfname_from(package->files[index].TargetPath);
else
- {
- for (i = 0; i < package->loaded_folders; i++)
- {
- HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
- package->folders[i].ResolvedTarget=NULL;
- }
+ name = load_dynamic_stringW(row,2);
- for (i = 0; i < package->loaded_folders; i++)
- {
- path2=resolve_folder(package, package->folders[i].Directory, FALSE,
- TRUE, NULL);
- HeapFree(GetProcessHeap(),0,path2);
- }
+ 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,path);
-
+
+ HeapFree(GetProcessHeap(),0,name);
+ RegCloseKey(hkey1);
+ RegCloseKey(hkey2);
return ERROR_SUCCESS;
}
-/***********************************************************************
- * MsiSetTargetPathW (MSI.@)
- */
-UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
- LPCWSTR szFolderPath)
-{
- MSIPACKAGE *package;
- UINT ret;
-
- TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
-
- package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
- ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
- msiobj_release( &package->hdr );
- return ret;
-}
-
-/***********************************************************************
- * MsiGetMode (MSI.@)
- *
- * Returns an internal installer state (if it is running in a mode iRunMode)
- *
- * PARAMS
- * hInstall [I] Handle to the installation
- * hRunMode [I] Checking run mode
- * MSIRUNMODE_ADMIN Administrative mode
- * MSIRUNMODE_ADVERTISE Advertisement mode
- * MSIRUNMODE_MAINTENANCE Maintenance mode
- * MSIRUNMODE_ROLLBACKENABLED Rollback is enabled
- * MSIRUNMODE_LOGENABLED Log file is writing
- * MSIRUNMODE_OPERATIONS Operations in progress??
- * MSIRUNMODE_REBOOTATEND We need to reboot after installation completed
- * MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation
- * MSIRUNMODE_CABINET Files from cabinet are installed
- * MSIRUNMODE_SOURCESHORTNAMES Long names in source files is suppressed
- * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is suppressed
- * MSIRUNMODE_RESERVED11 Reserved
- * MSIRUNMODE_WINDOWS9X Running under Windows95/98
- * MSIRUNMODE_ZAWENABLED Demand installation is supported
- * MSIRUNMODE_RESERVED14 Reserved
- * MSIRUNMODE_RESERVED15 Reserved
- * MSIRUNMODE_SCHEDULED called from install script
- * MSIRUNMODE_ROLLBACK called from rollback script
- * MSIRUNMODE_COMMIT called from commit script
- *
- * RETURNS
- * In the state: TRUE
- * Not in the state: FALSE
- *
- */
-
-BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
-{
- FIXME("STUB (iRunMode=%i)\n",iRunMode);
- return TRUE;
-}
-
-/***********************************************************************
- * MsiSetFeatureStateA (MSI.@)
- *
- * According to the docs, when this is called it immediately recalculates
- * all the component states as well
- */
-UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
- INSTALLSTATE iState)
+static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
{
- LPWSTR szwFeature = NULL;
UINT rc;
+ MSIQUERY * view;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','F','o','n','t','`',0};
- szwFeature = strdupAtoW(szFeature);
-
- if (!szwFeature)
- return ERROR_FUNCTION_FAILED;
-
- rc = MsiSetFeatureStateW(hInstall,szwFeature, iState);
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ {
+ TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
+ return ERROR_SUCCESS;
+ }
- HeapFree(GetProcessHeap(),0,szwFeature);
+ MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
+ msiobj_release(&view->hdr);
- return rc;
+ return ERROR_SUCCESS;
}
-
-
-UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
- INSTALLSTATE iState)
+static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
{
- INT index, i;
+ MSIPACKAGE *package = (MSIPACKAGE*)param;
+ LPCWSTR compgroupid=NULL;
+ LPCWSTR feature=NULL;
+ LPCWSTR text = NULL;
+ LPCWSTR qualifier = NULL;
+ LPCWSTR component = NULL;
+ LPWSTR advertise = NULL;
+ LPWSTR output = NULL;
+ HKEY hkey;
UINT rc = ERROR_SUCCESS;
+ UINT index;
+ DWORD sz = 0;
- TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
-
- index = get_loaded_feature(package,szFeature);
- if (index < 0)
- return ERROR_UNKNOWN_FEATURE;
+ component = MSI_RecordGetString(rec,3);
+ index = get_loaded_component(package,component);
- if (iState == INSTALLSTATE_ADVERTISED &&
- package->features[index].Attributes &
- msidbFeatureAttributesDisallowAdvertise)
- return ERROR_FUNCTION_FAILED;
+ if (!ACTION_VerifyComponentForAction(package, index,
+ INSTALLSTATE_LOCAL) &&
+ !ACTION_VerifyComponentForAction(package, index,
+ INSTALLSTATE_SOURCE) &&
+ !ACTION_VerifyComponentForAction(package, index,
+ INSTALLSTATE_ADVERTISED))
+ {
+ TRACE("Skipping: Component %s not scheduled for install\n",
+ debugstr_w(component));
- package->features[index].ActionRequest= iState;
- package->features[index].Action= iState;
+ return ERROR_SUCCESS;
+ }
- ACTION_UpdateComponentStates(package,szFeature);
+ compgroupid = MSI_RecordGetString(rec,1);
- /* update all the features that are children of this feature */
- for (i = 0; i < package->loaded_features; i++)
- {
- if (strcmpW(szFeature, package->features[i].Feature_Parent) == 0)
- MSI_SetFeatureStateW(package, package->features[i].Feature, iState);
- }
+ rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
+ if (rc != ERROR_SUCCESS)
+ goto end;
- return rc;
-}
-
-/***********************************************************************
- * MsiSetFeatureStateW (MSI.@)
- */
-UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
- INSTALLSTATE iState)
-{
- MSIPACKAGE* package;
- UINT rc = ERROR_SUCCESS;
+ text = MSI_RecordGetString(rec,4);
+ qualifier = MSI_RecordGetString(rec,2);
+ feature = MSI_RecordGetString(rec,5);
+
+ advertise = create_component_advertise_string(package,
+ &package->components[index], feature);
- TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
+ sz = strlenW(advertise);
- package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
- if (!package)
- return ERROR_INVALID_HANDLE;
+ if (text)
+ sz += lstrlenW(text);
- rc = MSI_SetFeatureStateW(package,szFeature,iState);
+ sz+=3;
+ sz *= sizeof(WCHAR);
+
+ output = HeapAlloc(GetProcessHeap(),0,sz);
+ memset(output,0,sz);
+ strcpyW(output,advertise);
- msiobj_release( &package->hdr );
- return rc;
-}
+ if (text)
+ strcatW(output,text);
-UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature,
- INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
-{
- LPWSTR szwFeature = NULL;
- UINT rc;
+ sz = (lstrlenW(output)+2) * sizeof(WCHAR);
+ RegSetValueExW(hkey, qualifier,0,REG_MULTI_SZ, (LPBYTE)output, sz);
+
+end:
+ RegCloseKey(hkey);
+ HeapFree(GetProcessHeap(),0,output);
- szwFeature = strdupAtoW(szFeature);
-
- rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
-
- HeapFree( GetProcessHeap(), 0 , szwFeature);
-
return rc;
}
-UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
- INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
-{
- INT index;
-
- index = get_loaded_feature(package,szFeature);
- if (index < 0)
- return ERROR_UNKNOWN_FEATURE;
-
- if (piInstalled)
- *piInstalled = package->features[index].Installed;
-
- if (piAction)
- *piAction = package->features[index].Action;
-
- TRACE("returning %i %i\n",*piInstalled,*piAction);
-
- return ERROR_SUCCESS;
-}
-
-UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature,
- INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
-{
- MSIPACKAGE* package;
- UINT ret;
-
- TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,
-piAction);
-
- package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
- if (!package)
- return ERROR_INVALID_HANDLE;
- ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
- msiobj_release( &package->hdr );
- return ret;
-}
-
-/***********************************************************************
- * MsiGetComponentStateA (MSI.@)
+/*
+ * At present I am ignorning the advertised components part of this and only
+ * focusing on the qualified component sets
*/
-UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent,
- INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
+static UINT ACTION_PublishComponents(MSIPACKAGE *package)
{
- LPWSTR szwComponent= NULL;
UINT rc;
+ MSIQUERY * view;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','P','u','b','l','i','s','h',
+ 'C','o','m','p','o','n','e','n','t','`',0};
- szwComponent= strdupAtoW(szComponent);
-
- rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return ERROR_SUCCESS;
- HeapFree( GetProcessHeap(), 0 , szwComponent);
+ rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
+ msiobj_release(&view->hdr);
return rc;
-}
-
-UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent,
- INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
-{
- INT index;
-
- TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled,
-piAction);
-
- index = get_loaded_component(package,szComponent);
- if (index < 0)
- return ERROR_UNKNOWN_COMPONENT;
-
- if (piInstalled)
- *piInstalled = package->components[index].Installed;
-
- if (piAction)
- *piAction = package->components[index].Action;
-
- TRACE("states (%i, %i)\n",
-(piInstalled)?*piInstalled:-1,(piAction)?*piAction:-1);
-
- return ERROR_SUCCESS;
-}
-
-/***********************************************************************
- * MsiGetComponentStateW (MSI.@)
- */
-UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent,
- INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
-{
- MSIPACKAGE* package;
- UINT ret;
-
- TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
- piInstalled, piAction);
-
- package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
- if (!package)
- return ERROR_INVALID_HANDLE;
- ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
- msiobj_release( &package->hdr );
- return ret;
}
Index: dlls/msi/action.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/action.h,v
retrieving revision 1.16
diff -u -r1.16 action.h
--- dlls/msi/action.h 9 Jun 2005 12:05:27 -0000 1.16
+++ dlls/msi/action.h 10 Jun 2005 13:39:59 -0000
@@ -201,10 +201,20 @@
UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action);
void ACTION_FinishCustomActions( MSIPACKAGE* package);
UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action, BOOL execute);
-void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature);
+
+/* actions in other modules */
UINT ACTION_AppSearch(MSIPACKAGE *package);
UINT ACTION_FindRelatedProducts(MSIPACKAGE *package);
+UINT ACTION_InstallFiles(MSIPACKAGE *package);
+UINT ACTION_DuplicateFiles(MSIPACKAGE *package);
+UINT ACTION_RegisterClassInfo(MSIPACKAGE *package);
+UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package);
+UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package);
+UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package);
+
+
+/* Helpers */
DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data );
WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index);
LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc);
@@ -215,6 +225,17 @@
int get_loaded_file(MSIPACKAGE* package, LPCWSTR file);
int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path);
UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action);
+UINT build_icon_path(MSIPACKAGE *, LPCWSTR, LPWSTR *);
+DWORD build_version_dword(LPCWSTR);
+LPWSTR build_directory_name(DWORD , ...);
+BOOL create_full_pathW(const WCHAR *path);
+BOOL ACTION_VerifyComponentForAction(MSIPACKAGE*, INT, INSTALLSTATE);
+BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE*, INT, INSTALLSTATE);
+void reduce_to_longfilename(WCHAR*);
+void reduce_to_shortfilename(WCHAR*);
+LPWSTR create_component_advertise_string(MSIPACKAGE*, MSICOMPONENT*, LPCWSTR);
+void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature);
+
/* control event stuff */
VOID ControlEvent_FireSubscribedEvent(MSIPACKAGE *package, LPCWSTR event,
@@ -225,5 +246,14 @@
VOID ControlEvent_UnSubscribeToEvent( MSIPACKAGE *package, LPCWSTR event,
LPCWSTR control, LPCWSTR attribute );
-/* version stuff for upgrades */
-DWORD build_version_dword(LPCWSTR version_string);
+/* User Interface messages from the actions */
+void ui_progress(MSIPACKAGE *, int, int, int, int);
+void ui_actiondata(MSIPACKAGE *, LPCWSTR, MSIRECORD *);
+
+
+/* string consts use a number of places and defined in helpers.c*/
+extern const WCHAR cszSourceDir[];
+extern const WCHAR szProductCode[];
+extern const WCHAR cszRootDrive[];
+extern const WCHAR cszbs[];
+
Index: dlls/msi/upgrade.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/upgrade.c,v
retrieving revision 1.1
diff -u -r1.1 upgrade.c
--- dlls/msi/upgrade.c 9 Jun 2005 12:05:27 -0000 1.1
+++ dlls/msi/upgrade.c 10 Jun 2005 13:39:59 -0000
@@ -27,27 +27,24 @@
*/
#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 "msi.h"
-#include "msiquery.h"
#include "msidefs.h"
#include "msipriv.h"
-#include "winnls.h"
#include "winuser.h"
-#include "winver.h"
#include "action.h"
#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
+extern const WCHAR szFindRelatedProducts[];
+extern const WCHAR szMigrateFeatureStates[];
+extern const WCHAR szRemoveExistingProducts[];
+
static BOOL check_language(DWORD lang1, LPCWSTR lang2, DWORD attributes)
{
DWORD langdword;
@@ -113,6 +110,7 @@
LPCWSTR upgrade_code;
HKEY hkey = 0;
UINT rc = ERROR_SUCCESS;
+ MSIRECORD *uirow;
upgrade_code = MSI_RecordGetString(rec,1);
@@ -120,6 +118,7 @@
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
+ uirow = MSI_CreateRecord(1);
attributes = MSI_RecordGetInteger(rec,5);
while (rc == ERROR_SUCCESS)
@@ -194,10 +193,12 @@
action_property = MSI_RecordGetString(rec,7);
append_productcode(package,action_property,productid);
+ ui_actiondata(package,szFindRelatedProducts,uirow);
}
index ++;
}
RegCloseKey(hkey);
+ msiobj_release( &uirow->hdr);
return ERROR_SUCCESS;
}
--- /dev//null 2005-03-17 08:20:53.000000000 -0600
+++ dlls/msi/classes.c 2005-06-10 08:04:29.000000000 -0500
@@ -0,0 +1,1603 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2005 Aric Stewart for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* actions handled in this module
+ * RegisterClassInfo
+ * RegisterProgIdInfo
+ * RegisterExtensionInfo
+ * RegisterMIMEInfo
+ * UnRegisterClassInfo (TODO)
+ * UnRegisterProgIdInfo (TODO)
+ * UnRegisterExtensionInfo (TODO)
+ * UnRegisterMIMEInfo (TODO)
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "winreg.h"
+#include "wine/debug.h"
+#include "msipriv.h"
+#include "winuser.h"
+#include "wine/unicode.h"
+#include "action.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+
+extern const WCHAR szRegisterClassInfo[];
+extern const WCHAR szRegisterProgIdInfo[];
+extern WCHAR szRegisterExtensionInfo[];
+extern const WCHAR szRegisterMIMEInfo[];
+
+extern const WCHAR szUnregisterClassInfo[];
+extern const WCHAR szUnregisterExtensionInfo[];
+extern const WCHAR szUnregisterMIMEInfo[];
+extern const WCHAR szUnregisterProgIdInfo[];
+
+static INT load_appid(MSIPACKAGE* package, MSIRECORD *row)
+{
+ DWORD index = package->loaded_appids;
+ DWORD sz;
+ LPCWSTR buffer;
+
+ /* fill in the data */
+
+ package->loaded_appids++;
+ if (package->loaded_appids == 1)
+ package->appids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIAPPID));
+ else
+ package->appids = HeapReAlloc(GetProcessHeap(),0,
+ package->appids, package->loaded_appids * sizeof(MSIAPPID));
+
+ memset(&package->appids[index],0,sizeof(MSIAPPID));
+
+ sz = IDENTIFIER_SIZE;
+ MSI_RecordGetStringW(row, 1, package->appids[index].AppID, &sz);
+ TRACE("loading appid %s\n",debugstr_w(package->appids[index].AppID));
+
+ buffer = MSI_RecordGetString(row,2);
+ deformat_string(package,buffer,&package->appids[index].RemoteServerName);
+
+ package->appids[index].LocalServer = load_dynamic_stringW(row,3);
+ package->appids[index].ServiceParameters = load_dynamic_stringW(row,4);
+ package->appids[index].DllSurrogate = load_dynamic_stringW(row,5);
+
+ package->appids[index].ActivateAtStorage = !MSI_RecordIsNull(row,6);
+ package->appids[index].RunAsInteractiveUser = !MSI_RecordIsNull(row,7);
+
+ return index;
+}
+
+static INT load_given_appid(MSIPACKAGE *package, LPCWSTR appid)
+{
+ INT rc;
+ MSIRECORD *row;
+ INT i;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','A','p','p','I','d','`',' ','W','H','E','R','E',' ',
+ '`','A','p','p','I','d','`',' ','=',' ','\'','%','s','\'',0};
+
+ if (!appid)
+ return -1;
+
+ /* check for appids already loaded */
+ for (i = 0; i < package->loaded_appids; i++)
+ if (strcmpiW(package->appids[i].AppID,appid)==0)
+ {
+ TRACE("found appid %s at index %i\n",debugstr_w(appid),i);
+ return i;
+ }
+
+ row = MSI_QueryGetRecord(package->db, ExecSeqQuery, appid);
+ if (!row)
+ return -1;
+
+ rc = load_appid(package, row);
+ msiobj_release(&row->hdr);
+
+ return rc;
+}
+
+static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid);
+static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid);
+
+static INT load_progid(MSIPACKAGE* package, MSIRECORD *row)
+{
+ DWORD index = package->loaded_progids;
+ LPCWSTR buffer;
+
+ /* fill in the data */
+
+ package->loaded_progids++;
+ if (package->loaded_progids == 1)
+ package->progids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIPROGID));
+ else
+ package->progids = HeapReAlloc(GetProcessHeap(),0,
+ package->progids , package->loaded_progids * sizeof(MSIPROGID));
+
+ memset(&package->progids[index],0,sizeof(MSIPROGID));
+
+ package->progids[index].ProgID = load_dynamic_stringW(row,1);
+ TRACE("loading progid %s\n",debugstr_w(package->progids[index].ProgID));
+
+ buffer = MSI_RecordGetString(row,2);
+ package->progids[index].ParentIndex = load_given_progid(package,buffer);
+ if (package->progids[index].ParentIndex < 0 && buffer)
+ FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer));
+
+ buffer = MSI_RecordGetString(row,3);
+ package->progids[index].ClassIndex = load_given_class(package,buffer);
+ if (package->progids[index].ClassIndex< 0 && buffer)
+ FIXME("Unknown class %s\n",debugstr_w(buffer));
+
+ package->progids[index].Description = load_dynamic_stringW(row,4);
+
+ if (!MSI_RecordIsNull(row,6))
+ {
+ INT icon_index = MSI_RecordGetInteger(row,6);
+ LPWSTR FileName = load_dynamic_stringW(row,5);
+ LPWSTR FilePath;
+ static const WCHAR fmt[] = {'%','s',',','%','i',0};
+
+ build_icon_path(package,FileName,&FilePath);
+
+ package->progids[index].IconPath =
+ HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+10)*
+ sizeof(WCHAR));
+
+ sprintfW(package->progids[index].IconPath,fmt,FilePath,icon_index);
+
+ HeapFree(GetProcessHeap(),0,FilePath);
+ HeapFree(GetProcessHeap(),0,FileName);
+ }
+ else
+ {
+ buffer = MSI_RecordGetString(row,5);
+ if (buffer)
+ build_icon_path(package,buffer,&(package->progids[index].IconPath));
+ }
+
+ package->progids[index].CurVerIndex = -1;
+ package->progids[index].VersionIndIndex = -1;
+
+ /* if we have a parent then we may be that parents CurVer */
+ if (package->progids[index].ParentIndex >= 0 &&
+ package->progids[index].ParentIndex != index)
+ {
+ int pindex = package->progids[index].ParentIndex;
+ while (package->progids[pindex].ParentIndex>= 0 &&
+ package->progids[pindex].ParentIndex != pindex)
+ pindex = package->progids[pindex].ParentIndex;
+
+ FIXME("BAD BAD need to determing if we are really the CurVer\n");
+
+ package->progids[index].CurVerIndex = pindex;
+ package->progids[pindex].VersionIndIndex = index;
+ }
+
+ return index;
+}
+
+static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid)
+{
+ INT rc;
+ MSIRECORD *row;
+ INT i;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','P','r','o','g','I','d','`',' ','W','H','E','R','E',' ',
+ '`','P','r','o','g','I','d','`',' ','=',' ','\'','%','s','\'',0};
+
+ if (!progid)
+ return -1;
+
+ /* check for progids already loaded */
+ for (i = 0; i < package->loaded_progids; i++)
+ if (strcmpiW(package->progids[i].ProgID,progid)==0)
+ {
+ TRACE("found progid %s at index %i\n",debugstr_w(progid), i);
+ return i;
+ }
+
+ row = MSI_QueryGetRecord(package->db, ExecSeqQuery, progid);
+ if(!row)
+ return -1;
+
+ rc = load_progid(package, row);
+ msiobj_release(&row->hdr);
+
+ return rc;
+}
+
+static INT load_class(MSIPACKAGE* package, MSIRECORD *row)
+{
+ DWORD index = package->loaded_classes;
+ DWORD sz,i;
+ LPCWSTR buffer;
+
+ /* fill in the data */
+
+ package->loaded_classes++;
+ if (package->loaded_classes== 1)
+ package->classes = HeapAlloc(GetProcessHeap(),0,sizeof(MSICLASS));
+ else
+ package->classes = HeapReAlloc(GetProcessHeap(),0,
+ package->classes, package->loaded_classes * sizeof(MSICLASS));
+
+ memset(&package->classes[index],0,sizeof(MSICLASS));
+
+ sz = IDENTIFIER_SIZE;
+ MSI_RecordGetStringW(row, 1, package->classes[index].CLSID, &sz);
+ TRACE("loading class %s\n",debugstr_w(package->classes[index].CLSID));
+ sz = IDENTIFIER_SIZE;
+ MSI_RecordGetStringW(row, 2, package->classes[index].Context, &sz);
+ buffer = MSI_RecordGetString(row,3);
+ package->classes[index].ComponentIndex = get_loaded_component(package,
+ buffer);
+
+ package->classes[index].ProgIDText = load_dynamic_stringW(row,4);
+ package->classes[index].ProgIDIndex =
+ load_given_progid(package, package->classes[index].ProgIDText);
+
+ package->classes[index].Description = load_dynamic_stringW(row,5);
+
+ buffer = MSI_RecordGetString(row,6);
+ if (buffer)
+ package->classes[index].AppIDIndex =
+ load_given_appid(package, buffer);
+ else
+ package->classes[index].AppIDIndex = -1;
+
+ package->classes[index].FileTypeMask = load_dynamic_stringW(row,7);
+
+ if (!MSI_RecordIsNull(row,9))
+ {
+
+ INT icon_index = MSI_RecordGetInteger(row,9);
+ LPWSTR FileName = load_dynamic_stringW(row,8);
+ LPWSTR FilePath;
+ static const WCHAR fmt[] = {'%','s',',','%','i',0};
+
+ build_icon_path(package,FileName,&FilePath);
+
+ package->classes[index].IconPath =
+ HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)*
+ sizeof(WCHAR));
+
+ sprintfW(package->classes[index].IconPath,fmt,FilePath,icon_index);
+
+ HeapFree(GetProcessHeap(),0,FilePath);
+ HeapFree(GetProcessHeap(),0,FileName);
+ }
+ else
+ {
+ buffer = MSI_RecordGetString(row,8);
+ if (buffer)
+ build_icon_path(package,buffer,&(package->classes[index].IconPath));
+ }
+
+ if (!MSI_RecordIsNull(row,10))
+ {
+ i = MSI_RecordGetInteger(row,10);
+ if (i != MSI_NULL_INTEGER && i > 0 && i < 4)
+ {
+ static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0};
+ static const WCHAR ole32[] = {'o','l','e','3','2','.','d','l','l',0};
+
+ switch(i)
+ {
+ case 1:
+ package->classes[index].DefInprocHandler = strdupW(ole2);
+ break;
+ case 2:
+ package->classes[index].DefInprocHandler32 = strdupW(ole32);
+ break;
+ case 3:
+ package->classes[index].DefInprocHandler = strdupW(ole2);
+ package->classes[index].DefInprocHandler32 = strdupW(ole32);
+ break;
+ }
+ }
+ else
+ {
+ package->classes[index].DefInprocHandler32 = load_dynamic_stringW(
+ row, 10);
+ reduce_to_longfilename(package->classes[index].DefInprocHandler32);
+ }
+ }
+ buffer = MSI_RecordGetString(row,11);
+ deformat_string(package,buffer,&package->classes[index].Argument);
+
+ buffer = MSI_RecordGetString(row,12);
+ package->classes[index].FeatureIndex = get_loaded_feature(package,buffer);
+
+ package->classes[index].Attributes = MSI_RecordGetInteger(row,13);
+
+ return index;
+}
+
+/*
+ * the Class table has 3 primary keys. Generally it is only
+ * referenced through the first CLSID key. However when loading
+ * all of the classes we need to make sure we do not ignore rows
+ * with other Context and ComponentIndexs
+ */
+static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid)
+{
+ INT rc;
+ MSIRECORD *row;
+ INT i;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','C','l','a','s','s','`',' ','W','H','E','R','E',' ',
+ '`','C','L','S','I','D','`',' ','=',' ','\'','%','s','\'',0};
+
+
+ if (!classid)
+ return -1;
+
+ /* check for classes already loaded */
+ for (i = 0; i < package->loaded_classes; i++)
+ if (strcmpiW(package->classes[i].CLSID,classid)==0)
+ {
+ TRACE("found class %s at index %i\n",debugstr_w(classid), i);
+ return i;
+ }
+
+ row = MSI_QueryGetRecord(package->db, ExecSeqQuery, classid);
+ if (!row)
+ return -1;
+
+ rc = load_class(package, row);
+ msiobj_release(&row->hdr);
+
+ return rc;
+}
+
+static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension);
+
+static INT load_mime(MSIPACKAGE* package, MSIRECORD *row)
+{
+ DWORD index = package->loaded_mimes;
+ DWORD sz;
+ LPCWSTR buffer;
+
+ /* fill in the data */
+
+ package->loaded_mimes++;
+ if (package->loaded_mimes== 1)
+ package->mimes= HeapAlloc(GetProcessHeap(),0,sizeof(MSIMIME));
+ else
+ package->mimes= HeapReAlloc(GetProcessHeap(),0,
+ package->mimes, package->loaded_mimes*
+ sizeof(MSIMIME));
+
+ memset(&package->mimes[index],0,sizeof(MSIMIME));
+
+ package->mimes[index].ContentType = load_dynamic_stringW(row,1);
+ TRACE("loading mime %s\n",debugstr_w(package->mimes[index].ContentType));
+
+ buffer = MSI_RecordGetString(row,2);
+ package->mimes[index].ExtensionIndex = load_given_extension(package,
+ buffer);
+
+ sz = IDENTIFIER_SIZE;
+ MSI_RecordGetStringW(row,3,package->mimes[index].CLSID,&sz);
+ package->mimes[index].ClassIndex= load_given_class(package,
+ package->mimes[index].CLSID);
+
+ return index;
+}
+
+static INT load_given_mime(MSIPACKAGE *package, LPCWSTR mime)
+{
+ INT rc;
+ MSIRECORD *row;
+ INT i;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','M','I','M','E','`',' ','W','H','E','R','E',' ',
+ '`','C','o','n','t','e','n','t','T','y','p','e','`',' ','=',' ',
+ '\'','%','s','\'',0};
+
+ if (!mime)
+ return -1;
+
+ /* check for mime already loaded */
+ for (i = 0; i < package->loaded_mimes; i++)
+ if (strcmpiW(package->mimes[i].ContentType,mime)==0)
+ {
+ TRACE("found mime %s at index %i\n",debugstr_w(mime), i);
+ return i;
+ }
+
+ row = MSI_QueryGetRecord(package->db, ExecSeqQuery, mime);
+ if (!row)
+ return -1;
+
+ rc = load_mime(package, row);
+ msiobj_release(&row->hdr);
+
+ return rc;
+}
+
+static INT load_extension(MSIPACKAGE* package, MSIRECORD *row)
+{
+ DWORD index = package->loaded_extensions;
+ DWORD sz;
+ LPCWSTR buffer;
+
+ /* fill in the data */
+
+ package->loaded_extensions++;
+ if (package->loaded_extensions == 1)
+ package->extensions = HeapAlloc(GetProcessHeap(),0,sizeof(MSIEXTENSION));
+ else
+ package->extensions = HeapReAlloc(GetProcessHeap(),0,
+ package->extensions, package->loaded_extensions*
+ sizeof(MSIEXTENSION));
+
+ memset(&package->extensions[index],0,sizeof(MSIEXTENSION));
+
+ sz = 256;
+ MSI_RecordGetStringW(row,1,package->extensions[index].Extension,&sz);
+ TRACE("loading extension %s\n",
+ debugstr_w(package->extensions[index].Extension));
+
+ buffer = MSI_RecordGetString(row,2);
+ package->extensions[index].ComponentIndex =
+ get_loaded_component(package,buffer);
+
+ package->extensions[index].ProgIDText = load_dynamic_stringW(row,3);
+ package->extensions[index].ProgIDIndex = load_given_progid(package,
+ package->extensions[index].ProgIDText);
+
+ buffer = MSI_RecordGetString(row,4);
+ package->extensions[index].MIMEIndex = load_given_mime(package,buffer);
+
+ buffer = MSI_RecordGetString(row,5);
+ package->extensions[index].FeatureIndex =
+ get_loaded_feature(package,buffer);
+
+ return index;
+}
+
+/*
+ * While the extension table has 2 primary keys, this function is only looking
+ * at the Extension key which is what is referenced as a forign key
+ */
+static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension)
+{
+ INT rc;
+ MSIRECORD *row;
+ INT i;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','E','x','t','e','n','s','i','o','n','`',' ',
+ 'W','H','E','R','E',' ',
+ '`','E','x','t','e','n','s','i','o','n','`',' ','=',' ',
+ '\'','%','s','\'',0};
+
+ if (!extension)
+ return -1;
+
+ /* check for extensions already loaded */
+ for (i = 0; i < package->loaded_extensions; i++)
+ if (strcmpiW(package->extensions[i].Extension,extension)==0)
+ {
+ TRACE("extension %s already loaded at %i\n",debugstr_w(extension),
+ i);
+ return i;
+ }
+
+ row = MSI_QueryGetRecord(package->db, ExecSeqQuery, extension);
+ if (!row)
+ return -1;
+
+ rc = load_extension(package, row);
+ msiobj_release(&row->hdr);
+
+ return rc;
+}
+
+static UINT iterate_load_verb(MSIRECORD *row, LPVOID param)
+{
+ MSIPACKAGE* package = (MSIPACKAGE*)param;
+ DWORD index = package->loaded_verbs;
+ LPCWSTR buffer;
+
+ /* fill in the data */
+
+ package->loaded_verbs++;
+ if (package->loaded_verbs == 1)
+ package->verbs = HeapAlloc(GetProcessHeap(),0,sizeof(MSIVERB));
+ else
+ package->verbs = HeapReAlloc(GetProcessHeap(),0,
+ package->verbs , package->loaded_verbs * sizeof(MSIVERB));
+
+ memset(&package->verbs[index],0,sizeof(MSIVERB));
+
+ buffer = MSI_RecordGetString(row,1);
+ package->verbs[index].ExtensionIndex = load_given_extension(package,buffer);
+ if (package->verbs[index].ExtensionIndex < 0 && buffer)
+ ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer));
+
+ package->verbs[index].Verb = load_dynamic_stringW(row,2);
+ TRACE("loading verb %s\n",debugstr_w(package->verbs[index].Verb));
+ package->verbs[index].Sequence = MSI_RecordGetInteger(row,3);
+
+ buffer = MSI_RecordGetString(row,4);
+ deformat_string(package,buffer,&package->verbs[index].Command);
+
+ buffer = MSI_RecordGetString(row,5);
+ deformat_string(package,buffer,&package->verbs[index].Argument);
+
+ /* assosiate the verb with the correct extension */
+ if (package->verbs[index].ExtensionIndex >= 0)
+ {
+ MSIEXTENSION* extension = &package->extensions[package->verbs[index].
+ ExtensionIndex];
+ int count = extension->VerbCount;
+
+ if (count >= 99)
+ FIXME("Exceeding max verb count! Increase that limit!!!\n");
+ else
+ {
+ extension->VerbCount++;
+ extension->Verbs[count] = index;
+ }
+ }
+
+ return ERROR_SUCCESS;
+}
+
+static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param)
+{
+ LPCWSTR clsid;
+ LPCWSTR context;
+ LPCWSTR buffer;
+ INT component_index;
+ MSIPACKAGE* package =(MSIPACKAGE*)param;
+ INT i;
+ BOOL match = FALSE;
+
+ clsid = MSI_RecordGetString(rec,1);
+ context = MSI_RecordGetString(rec,2);
+ buffer = MSI_RecordGetString(rec,3);
+ component_index = get_loaded_component(package,buffer);
+
+ for (i = 0; i < package->loaded_classes; i++)
+ {
+ if (strcmpiW(clsid,package->classes[i].CLSID))
+ continue;
+ if (strcmpW(context,package->classes[i].Context))
+ continue;
+ if (component_index == package->classes[i].ComponentIndex)
+ {
+ match = TRUE;
+ break;
+ }
+ }
+
+ if (!match)
+ load_class(package, rec);
+
+ return ERROR_SUCCESS;
+}
+
+static VOID load_all_classes(MSIPACKAGE *package)
+{
+ UINT rc = ERROR_SUCCESS;
+ MSIQUERY *view;
+
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
+ '`','C','l','a','s','s','`',0};
+
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return;
+
+ rc = MSI_IterateRecords(view, NULL, iterate_all_classes, package);
+ msiobj_release(&view->hdr);
+}
+
+static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param)
+{
+ LPCWSTR buffer;
+ LPCWSTR extension;
+ INT component_index;
+ MSIPACKAGE* package =(MSIPACKAGE*)param;
+ BOOL match = FALSE;
+ INT i;
+
+ extension = MSI_RecordGetString(rec,1);
+ buffer = MSI_RecordGetString(rec,2);
+ component_index = get_loaded_component(package,buffer);
+
+ for (i = 0; i < package->loaded_extensions; i++)
+ {
+ if (strcmpiW(extension,package->extensions[i].Extension))
+ continue;
+ if (component_index == package->extensions[i].ComponentIndex)
+ {
+ match = TRUE;
+ break;
+ }
+ }
+
+ if (!match)
+ load_extension(package, rec);
+
+ return ERROR_SUCCESS;
+}
+
+static VOID load_all_extensions(MSIPACKAGE *package)
+{
+ UINT rc = ERROR_SUCCESS;
+ MSIQUERY *view;
+
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','E','x','t','e','n','s','i','o','n','`',0};
+
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return;
+
+ rc = MSI_IterateRecords(view, NULL, iterate_all_extensions, package);
+ msiobj_release(&view->hdr);
+}
+
+static UINT iterate_all_progids(MSIRECORD *rec, LPVOID param)
+{
+ LPCWSTR buffer;
+ MSIPACKAGE* package =(MSIPACKAGE*)param;
+
+ buffer = MSI_RecordGetString(rec,1);
+ load_given_progid(package,buffer);
+ return ERROR_SUCCESS;
+}
+
+static VOID load_all_progids(MSIPACKAGE *package)
+{
+ UINT rc = ERROR_SUCCESS;
+ MSIQUERY *view;
+
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ',
+ 'F','R','O','M',' ', '`','P','r','o','g','I','d','`',0};
+
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return;
+
+ rc = MSI_IterateRecords(view, NULL, iterate_all_progids, package);
+ msiobj_release(&view->hdr);
+}
+
+static VOID load_all_verbs(MSIPACKAGE *package)
+{
+ UINT rc = ERROR_SUCCESS;
+ MSIQUERY *view;
+
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','V','e','r','b','`',0};
+
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return;
+
+ rc = MSI_IterateRecords(view, NULL, iterate_load_verb, package);
+ msiobj_release(&view->hdr);
+}
+
+static UINT iterate_all_mimes(MSIRECORD *rec, LPVOID param)
+{
+ LPCWSTR buffer;
+ MSIPACKAGE* package =(MSIPACKAGE*)param;
+
+ buffer = MSI_RecordGetString(rec,1);
+ load_given_mime(package,buffer);
+ return ERROR_SUCCESS;
+}
+
+static VOID load_all_mimes(MSIPACKAGE *package)
+{
+ UINT rc = ERROR_SUCCESS;
+ MSIQUERY *view;
+
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ',
+ '`','C','o','n','t','e','n','t','T','y','p','e','`',
+ ' ','F','R','O','M',' ',
+ '`','M','I','M','E','`',0};
+
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return;
+
+ rc = MSI_IterateRecords(view, NULL, iterate_all_mimes, package);
+ msiobj_release(&view->hdr);
+}
+
+static void load_classes_and_such(MSIPACKAGE *package)
+{
+ TRACE("Loading all the class info and related tables\n");
+
+ /* check if already loaded */
+ if (package->classes || package->extensions || package->progids ||
+ package->verbs || package->mimes)
+ return;
+
+ load_all_classes(package);
+ load_all_extensions(package);
+ load_all_progids(package);
+ /* these loads must come after the other loads */
+ load_all_verbs(package);
+ load_all_mimes(package);
+}
+
+static void mark_progid_for_install(MSIPACKAGE* package, INT index)
+{
+ MSIPROGID* progid;
+ int i;
+
+ if (index < 0 || index >= package->loaded_progids)
+ return;
+
+ progid = &package->progids[index];
+
+ if (progid->InstallMe == TRUE)
+ return;
+
+ progid->InstallMe = TRUE;
+
+ /* all children if this is a parent also install */
+ for (i = 0; i < package->loaded_progids; i++)
+ if (package->progids[i].ParentIndex == index)
+ mark_progid_for_install(package,i);
+}
+
+static void mark_mime_for_install(MSIPACKAGE* package, INT index)
+{
+ MSIMIME* mime;
+
+ if (index < 0 || index >= package->loaded_mimes)
+ return;
+
+ mime = &package->mimes[index];
+
+ if (mime->InstallMe == TRUE)
+ return;
+
+ mime->InstallMe = TRUE;
+}
+
+static UINT register_appid(MSIPACKAGE *package, int appidIndex, LPCWSTR app )
+{
+ static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
+ HKEY hkey2,hkey3;
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
+ RegCreateKeyW(hkey2,package->appids[appidIndex].AppID,&hkey3);
+ RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
+ (strlenW(app)+1)*sizeof(WCHAR));
+
+ if (package->appids[appidIndex].RemoteServerName)
+ {
+ UINT size;
+ static const WCHAR szRemoteServerName[] =
+ {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',
+ 0};
+
+ size = (strlenW(package->appids[appidIndex].RemoteServerName)+1) *
+ sizeof(WCHAR);
+
+ RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,
+ (LPVOID)package->appids[appidIndex].RemoteServerName,
+ size);
+ }
+
+ if (package->appids[appidIndex].LocalServer)
+ {
+ static const WCHAR szLocalService[] =
+ {'L','o','c','a','l','S','e','r','v','i','c','e',0};
+ UINT size;
+ size = (strlenW(package->appids[appidIndex].LocalServer)+1) *
+ sizeof(WCHAR);
+
+ RegSetValueExW(hkey3,szLocalService,0,REG_SZ,
+ (LPVOID)package->appids[appidIndex].LocalServer,size);
+ }
+
+ if (package->appids[appidIndex].ServiceParameters)
+ {
+ static const WCHAR szService[] =
+ {'S','e','r','v','i','c','e',
+ 'P','a','r','a','m','e','t','e','r','s',0};
+ UINT size;
+ size = (strlenW(package->appids[appidIndex].ServiceParameters)+1) *
+ sizeof(WCHAR);
+ RegSetValueExW(hkey3,szService,0,REG_SZ,
+ (LPVOID)package->appids[appidIndex].ServiceParameters,
+ size);
+ }
+
+ if (package->appids[appidIndex].DllSurrogate)
+ {
+ static const WCHAR szDLL[] =
+ {'D','l','l','S','u','r','r','o','g','a','t','e',0};
+ UINT size;
+ size = (strlenW(package->appids[appidIndex].DllSurrogate)+1) *
+ sizeof(WCHAR);
+ RegSetValueExW(hkey3,szDLL,0,REG_SZ,
+ (LPVOID)package->appids[appidIndex].DllSurrogate,size);
+ }
+
+ if (package->appids[appidIndex].ActivateAtStorage)
+ {
+ static const WCHAR szActivate[] =
+ {'A','c','t','i','v','a','t','e','A','s',
+ 'S','t','o','r','a','g','e',0};
+ static const WCHAR szY[] = {'Y',0};
+
+ RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
+ }
+
+ if (package->appids[appidIndex].RunAsInteractiveUser)
+ {
+ static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
+ static const WCHAR szUser[] =
+ {'I','n','t','e','r','a','c','t','i','v','e',' ',
+ 'U','s','e','r',0};
+
+ RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,sizeof(szUser));
+ }
+
+ RegCloseKey(hkey3);
+ RegCloseKey(hkey2);
+ return ERROR_SUCCESS;
+}
+
+UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
+{
+ /*
+ * Again I am assuming the words, "Whose key file represents" when referring
+ * to a Component as to meaning that Components KeyPath file
+ */
+
+ UINT rc;
+ MSIRECORD *uirow;
+ static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
+ static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
+ static const WCHAR szVIProgID[] = { 'V','e','r','s','i','o','n','I','n','d','e','p','e','n','d','e','n','t','P','r','o','g','I','D',0 };
+ static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
+ static const WCHAR szSpace[] = {' ',0};
+ static const WCHAR szInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
+ static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0};
+ HKEY hkey,hkey2,hkey3;
+ BOOL install_on_demand = FALSE;
+ int i;
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ load_classes_and_such(package);
+ rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
+ if (rc != ERROR_SUCCESS)
+ return ERROR_FUNCTION_FAILED;
+
+ /* install_on_demand should be set if OLE supports install on demand OLE
+ * servers. For now i am defaulting to FALSE because i do not know how to
+ * check, and i am told our builtin OLE does not support it
+ */
+
+ for (i = 0; i < package->loaded_classes; i++)
+ {
+ INT index,f_index;
+ DWORD size, sz;
+ LPWSTR argument;
+
+ if (package->classes[i].ComponentIndex < 0)
+ {
+ continue;
+ }
+
+ index = package->classes[i].ComponentIndex;
+ f_index = package->classes[i].FeatureIndex;
+
+ /*
+ * yes. MSDN says that these are based on _Feature_ not on
+ * Component. So verify the feature is to be installed
+ */
+ if ((!ACTION_VerifyFeatureForAction(package, f_index,
+ INSTALLSTATE_LOCAL)) &&
+ !(install_on_demand && ACTION_VerifyFeatureForAction(package,
+ f_index, INSTALLSTATE_ADVERTISED)))
+ {
+ TRACE("Skipping class %s reg due to disabled feature %s\n",
+ debugstr_w(package->classes[i].CLSID),
+ debugstr_w(package->features[f_index].Feature));
+
+ continue;
+ }
+
+ TRACE("Registering index %i class %s\n",i,
+ debugstr_w(package->classes[i].CLSID));
+
+ package->classes[i].Installed = TRUE;
+ if (package->classes[i].ProgIDIndex >= 0)
+ mark_progid_for_install(package, package->classes[i].ProgIDIndex);
+
+ RegCreateKeyW(hkey,package->classes[i].CLSID,&hkey2);
+
+ if (package->classes[i].Description)
+ RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)package->classes[i].
+ Description, (strlenW(package->classes[i].
+ Description)+1)*sizeof(WCHAR));
+
+ RegCreateKeyW(hkey2,package->classes[i].Context,&hkey3);
+ index = get_loaded_file(package,package->components[index].KeyPath);
+
+
+ /* the context server is a short path name
+ * except for if it is InprocServer32...
+ */
+ if (strcmpiW(package->classes[i].Context,szInprocServer32)!=0)
+ {
+ sz = 0;
+ sz = GetShortPathNameW(package->files[index].TargetPath, NULL, 0);
+ if (sz == 0)
+ {
+ ERR("Unable to find short path for CLSID COM Server\n");
+ argument = NULL;
+ }
+ else
+ {
+ size = sz * sizeof(WCHAR);
+
+ if (package->classes[i].Argument)
+ {
+ size += strlenW(package->classes[i].Argument) *
+ sizeof(WCHAR);
+ size += sizeof(WCHAR);
+ }
+
+ argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
+ GetShortPathNameW(package->files[index].TargetPath, argument,
+ sz);
+
+ if (package->classes[i].Argument)
+ {
+ strcatW(argument,szSpace);
+ strcatW(argument,package->classes[i].Argument);
+ }
+ }
+ }
+ else
+ {
+ size = lstrlenW(package->files[index].TargetPath) * sizeof(WCHAR);
+
+ if (package->classes[i].Argument)
+ {
+ size += strlenW(package->classes[i].Argument) * sizeof(WCHAR);
+ size += sizeof(WCHAR);
+ }
+
+ argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
+ strcpyW(argument, package->files[index].TargetPath);
+
+ if (package->classes[i].Argument)
+ {
+ strcatW(argument,szSpace);
+ strcatW(argument,package->classes[i].Argument);
+ }
+ }
+
+ if (argument)
+ {
+ RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size);
+ HeapFree(GetProcessHeap(),0,argument);
+ }
+
+ RegCloseKey(hkey3);
+
+ if (package->classes[i].ProgIDIndex >= 0 ||
+ package->classes[i].ProgIDText)
+ {
+ LPCWSTR progid;
+
+ if (package->classes[i].ProgIDIndex >= 0)
+ progid = package->progids[
+ package->classes[i].ProgIDIndex].ProgID;
+ else
+ progid = package->classes[i].ProgIDText;
+
+ RegCreateKeyW(hkey2,szProgID,&hkey3);
+ RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)progid,
+ (strlenW(progid)+1) *sizeof(WCHAR));
+ RegCloseKey(hkey3);
+
+ if (package->classes[i].ProgIDIndex >= 0 &&
+ package->progids[package->classes[i].ProgIDIndex].
+ VersionIndIndex >= 0)
+ {
+ LPWSTR viprogid = strdupW(package->progids[package->progids[
+ package->classes[i].ProgIDIndex].VersionIndIndex].
+ ProgID);
+ RegCreateKeyW(hkey2,szVIProgID,&hkey3);
+ RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)viprogid,
+ (strlenW(viprogid)+1) *sizeof(WCHAR));
+ RegCloseKey(hkey3);
+ HeapFree(GetProcessHeap(), 0, viprogid);
+ }
+ }
+
+ if (package->classes[i].AppIDIndex >= 0)
+ {
+ RegSetValueExW(hkey2,szAppID,0,REG_SZ,
+ (LPVOID)package->appids[package->classes[i].AppIDIndex].AppID,
+ (strlenW(package->appids[package->classes[i].AppIDIndex].AppID)+1)
+ *sizeof(WCHAR));
+
+ register_appid(package,package->classes[i].AppIDIndex,
+ package->classes[i].Description);
+ }
+
+ if (package->classes[i].IconPath)
+ {
+ static const WCHAR szDefaultIcon[] =
+ {'D','e','f','a','u','l','t','I','c','o','n',0};
+
+ RegCreateKeyW(hkey2,szDefaultIcon,&hkey3);
+
+ RegSetValueExW(hkey3,NULL,0,REG_SZ,
+ (LPVOID)package->classes[i].IconPath,
+ (strlenW(package->classes[i].IconPath)+1) *
+ sizeof(WCHAR));
+
+ RegCloseKey(hkey3);
+ }
+
+ if (package->classes[i].DefInprocHandler)
+ {
+ static const WCHAR szInproc[] =
+ {'I','n','p','r','o','c','H','a','n','d','l','e','r',0};
+
+ size = (strlenW(package->classes[i].DefInprocHandler) + 1) *
+ sizeof(WCHAR);
+ RegCreateKeyW(hkey2,szInproc,&hkey3);
+ RegSetValueExW(hkey3,NULL,0,REG_SZ,
+ (LPVOID)package->classes[i].DefInprocHandler, size);
+ RegCloseKey(hkey3);
+ }
+
+ if (package->classes[i].DefInprocHandler32)
+ {
+ static const WCHAR szInproc32[] =
+ {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',
+ 0};
+ size = (strlenW(package->classes[i].DefInprocHandler32) + 1) *
+ sizeof(WCHAR);
+
+ RegCreateKeyW(hkey2,szInproc32,&hkey3);
+ RegSetValueExW(hkey3,NULL,0,REG_SZ,
+ (LPVOID)package->classes[i].DefInprocHandler32,size);
+ RegCloseKey(hkey3);
+ }
+
+ RegCloseKey(hkey2);
+
+ /* if there is a FileTypeMask, register the FileType */
+ if (package->classes[i].FileTypeMask)
+ {
+ LPWSTR ptr, ptr2;
+ LPWSTR keyname;
+ INT index = 0;
+ ptr = package->classes[i].FileTypeMask;
+ while (ptr && *ptr)
+ {
+ ptr2 = strchrW(ptr,';');
+ if (ptr2)
+ *ptr2 = 0;
+ keyname = HeapAlloc(GetProcessHeap(),0,(strlenW(szFileType_fmt)+
+ strlenW(package->classes[i].CLSID) + 4)
+ * sizeof(WCHAR));
+ sprintfW(keyname,szFileType_fmt, package->classes[i].CLSID,
+ index);
+
+ RegCreateKeyW(HKEY_CLASSES_ROOT,keyname,&hkey2);
+ RegSetValueExW(hkey2,NULL,0,REG_SZ, (LPVOID)ptr,
+ strlenW(ptr)*sizeof(WCHAR));
+ RegCloseKey(hkey2);
+ HeapFree(GetProcessHeap(), 0, keyname);
+
+ if (ptr2)
+ ptr = ptr2+1;
+ else
+ ptr = NULL;
+
+ index ++;
+ }
+ }
+
+ uirow = MSI_CreateRecord(1);
+
+ MSI_RecordSetStringW(uirow,1,package->classes[i].CLSID);
+ ui_actiondata(package,szRegisterClassInfo,uirow);
+ msiobj_release(&uirow->hdr);
+ }
+
+ RegCloseKey(hkey);
+ return rc;
+}
+
+static UINT register_progid_base(MSIPACKAGE* package, MSIPROGID* progid,
+ LPWSTR clsid)
+{
+ static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
+ static const WCHAR szDefaultIcon[] =
+ {'D','e','f','a','u','l','t','I','c','o','n',0};
+ HKEY hkey,hkey2;
+
+ RegCreateKeyW(HKEY_CLASSES_ROOT,progid->ProgID,&hkey);
+
+ if (progid->Description)
+ {
+ RegSetValueExW(hkey,NULL,0,REG_SZ,
+ (LPVOID)progid->Description,
+ (strlenW(progid->Description)+1) *
+ sizeof(WCHAR));
+ }
+
+ if (progid->ClassIndex >= 0)
+ {
+ RegCreateKeyW(hkey,szCLSID,&hkey2);
+ RegSetValueExW(hkey2,NULL,0,REG_SZ,
+ (LPVOID)package->classes[progid->ClassIndex].CLSID,
+ (strlenW(package->classes[progid->ClassIndex].CLSID)+1)
+ * sizeof(WCHAR));
+
+ if (clsid)
+ strcpyW(clsid,package->classes[progid->ClassIndex].CLSID);
+
+ RegCloseKey(hkey2);
+ }
+ else
+ {
+ FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
+ }
+
+ if (progid->IconPath)
+ {
+ RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
+
+ RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath,
+ (strlenW(progid->IconPath)+1) * sizeof(WCHAR));
+ RegCloseKey(hkey2);
+ }
+ return ERROR_SUCCESS;
+}
+
+static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid,
+ LPWSTR clsid)
+{
+ UINT rc = ERROR_SUCCESS;
+
+ if (progid->ParentIndex < 0)
+ rc = register_progid_base(package, progid, clsid);
+ else
+ {
+ DWORD disp;
+ HKEY hkey,hkey2;
+ static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
+ static const WCHAR szDefaultIcon[] =
+ {'D','e','f','a','u','l','t','I','c','o','n',0};
+ static const WCHAR szCurVer[] =
+ {'C','u','r','V','e','r',0};
+
+ /* check if already registered */
+ RegCreateKeyExW(HKEY_CLASSES_ROOT, progid->ProgID, 0, NULL, 0,
+ KEY_ALL_ACCESS, NULL, &hkey, &disp );
+ if (disp == REG_OPENED_EXISTING_KEY)
+ {
+ TRACE("Key already registered\n");
+ RegCloseKey(hkey);
+ return rc;
+ }
+
+ TRACE("Registering Parent %s index %i\n",
+ debugstr_w(package->progids[progid->ParentIndex].ProgID),
+ progid->ParentIndex);
+ rc = register_progid(package,&package->progids[progid->ParentIndex],
+ clsid);
+
+ /* clsid is same as parent */
+ RegCreateKeyW(hkey,szCLSID,&hkey2);
+ RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
+ sizeof(WCHAR));
+
+ RegCloseKey(hkey2);
+
+
+ if (progid->Description)
+ {
+ RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid->Description,
+ (strlenW(progid->Description)+1) * sizeof(WCHAR));
+ }
+
+ if (progid->IconPath)
+ {
+ RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
+ RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath,
+ (strlenW(progid->IconPath)+1) * sizeof(WCHAR));
+ RegCloseKey(hkey2);
+ }
+
+ /* write out the current version */
+ if (progid->CurVerIndex >= 0)
+ {
+ RegCreateKeyW(hkey,szCurVer,&hkey2);
+ RegSetValueExW(hkey2,NULL,0,REG_SZ,
+ (LPVOID)package->progids[progid->CurVerIndex].ProgID,
+ (strlenW(package->progids[progid->CurVerIndex].ProgID)+1) *
+ sizeof(WCHAR));
+ RegCloseKey(hkey2);
+ }
+
+ RegCloseKey(hkey);
+ }
+ return rc;
+}
+
+UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
+{
+ INT i;
+ MSIRECORD *uirow;
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ load_classes_and_such(package);
+
+ for (i = 0; i < package->loaded_progids; i++)
+ {
+ WCHAR clsid[0x1000];
+
+ /* check if this progid is to be installed */
+ package->progids[i].InstallMe = ((package->progids[i].InstallMe) ||
+ (package->progids[i].ClassIndex >= 0 &&
+ package->classes[package->progids[i].ClassIndex].Installed));
+
+ if (!package->progids[i].InstallMe)
+ {
+ TRACE("progid %s not scheduled to be installed\n",
+ debugstr_w(package->progids[i].ProgID));
+ continue;
+ }
+
+ TRACE("Registering progid %s index %i\n",
+ debugstr_w(package->progids[i].ProgID), i);
+
+ register_progid(package,&package->progids[i],clsid);
+
+ uirow = MSI_CreateRecord(1);
+ MSI_RecordSetStringW(uirow,1,package->progids[i].ProgID);
+ ui_actiondata(package,szRegisterProgIdInfo,uirow);
+ msiobj_release(&uirow->hdr);
+ }
+
+ return ERROR_SUCCESS;
+}
+
+static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid,
+ MSICOMPONENT* component, MSIEXTENSION* extension,
+ MSIVERB* verb, INT* Sequence )
+{
+ LPWSTR keyname;
+ HKEY key;
+ static const WCHAR szShell[] = {'s','h','e','l','l',0};
+ static const WCHAR szCommand[] = {'c','o','m','m','a','n','d',0};
+ static const WCHAR fmt[] = {'\"','%','s','\"',' ','%','s',0};
+ static const WCHAR fmt2[] = {'\"','%','s','\"',0};
+ LPWSTR command;
+ DWORD size;
+ LPWSTR advertise;
+
+ keyname = build_directory_name(4, progid, szShell, verb->Verb, szCommand);
+
+ TRACE("Making Key %s\n",debugstr_w(keyname));
+ RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
+ size = strlenW(component->FullKeypath);
+ if (verb->Argument)
+ size += strlenW(verb->Argument);
+ size += 4;
+
+ command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
+ if (verb->Argument)
+ sprintfW(command, fmt, component->FullKeypath, verb->Argument);
+ else
+ sprintfW(command, fmt2, component->FullKeypath);
+
+ RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)command, (strlenW(command)+1)*
+ sizeof(WCHAR));
+ HeapFree(GetProcessHeap(),0,command);
+
+ advertise = create_component_advertise_string(package, component,
+ package->features[extension->FeatureIndex].Feature);
+
+ size = strlenW(advertise);
+
+ if (verb->Argument)
+ size += strlenW(verb->Argument);
+ size += 4;
+
+ command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
+ memset(command,0,size*sizeof(WCHAR));
+
+ strcpyW(command,advertise);
+ if (verb->Argument)
+ {
+ static const WCHAR szSpace[] = {' ',0};
+ strcatW(command,szSpace);
+ strcatW(command,verb->Argument);
+ }
+
+ RegSetValueExW(key, szCommand, 0, REG_MULTI_SZ, (LPBYTE)command,
+ (strlenW(command)+2)*sizeof(WCHAR));
+
+ RegCloseKey(key);
+ HeapFree(GetProcessHeap(),0,keyname);
+ HeapFree(GetProcessHeap(),0,advertise);
+ HeapFree(GetProcessHeap(),0,command);
+
+ if (verb->Command)
+ {
+ keyname = build_directory_name(3, progid, szShell, verb->Verb);
+ RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
+ RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Command,
+ (strlenW(verb->Command)+1) *sizeof(WCHAR));
+ RegCloseKey(key);
+ HeapFree(GetProcessHeap(),0,keyname);
+ }
+
+ if (verb->Sequence != MSI_NULL_INTEGER)
+ {
+ if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence)
+ {
+ *Sequence = verb->Sequence;
+ keyname = build_directory_name(2, progid, szShell);
+ RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
+ RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Verb,
+ (strlenW(verb->Verb)+1) *sizeof(WCHAR));
+ RegCloseKey(key);
+ HeapFree(GetProcessHeap(),0,keyname);
+ }
+ }
+ return ERROR_SUCCESS;
+}
+
+UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
+{
+ static const WCHAR szContentType[] =
+ {'C','o','n','t','e','n','t',' ','T','y','p','e',0 };
+ HKEY hkey;
+ INT i;
+ MSIRECORD *uirow;
+ BOOL install_on_demand = TRUE;
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ load_classes_and_such(package);
+
+ /* We need to set install_on_demand based on if the shell handles advertised
+ * shortcuts and the like. Because Mike McCormack is working on this i am
+ * going to default to TRUE
+ */
+
+ for (i = 0; i < package->loaded_extensions; i++)
+ {
+ WCHAR extension[257];
+ INT index,f_index;
+
+ index = package->extensions[i].ComponentIndex;
+ f_index = package->extensions[i].FeatureIndex;
+
+ if (index < 0)
+ continue;
+
+ /*
+ * yes. MSDN says that these are based on _Feature_ not on
+ * Component. So verify the feature is to be installed
+ */
+ if ((!ACTION_VerifyFeatureForAction(package, f_index,
+ INSTALLSTATE_LOCAL)) &&
+ !(install_on_demand && ACTION_VerifyFeatureForAction(package,
+ f_index, INSTALLSTATE_ADVERTISED)))
+ {
+ TRACE("Skipping extension %s reg due to disabled feature %s\n",
+ debugstr_w(package->extensions[i].Extension),
+ debugstr_w(package->features[f_index].Feature));
+
+ continue;
+ }
+
+ TRACE("Registering extension %s index %i\n",
+ debugstr_w(package->extensions[i].Extension), i);
+
+ package->extensions[i].Installed = TRUE;
+
+ /* this is only registered if the extension has at least 1 verb
+ * according to MSDN
+ */
+ if (package->extensions[i].ProgIDIndex >= 0 &&
+ package->extensions[i].VerbCount > 0)
+ mark_progid_for_install(package, package->extensions[i].ProgIDIndex);
+
+ if (package->extensions[i].MIMEIndex >= 0)
+ mark_mime_for_install(package, package->extensions[i].MIMEIndex);
+
+ extension[0] = '.';
+ extension[1] = 0;
+ strcatW(extension,package->extensions[i].Extension);
+
+ RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey);
+
+ if (package->extensions[i].MIMEIndex >= 0)
+ {
+ RegSetValueExW(hkey,szContentType,0,REG_SZ,
+ (LPVOID)package->mimes[package->extensions[i].
+ MIMEIndex].ContentType,
+ (strlenW(package->mimes[package->extensions[i].
+ MIMEIndex].ContentType)+1)*sizeof(WCHAR));
+ }
+
+ if (package->extensions[i].ProgIDIndex >= 0 ||
+ package->extensions[i].ProgIDText)
+ {
+ static const WCHAR szSN[] =
+ {'\\','S','h','e','l','l','N','e','w',0};
+ HKEY hkey2;
+ LPWSTR newkey;
+ LPCWSTR progid;
+ INT v;
+ INT Sequence = MSI_NULL_INTEGER;
+
+ if (package->extensions[i].ProgIDIndex >= 0)
+ progid = package->progids[package->extensions[i].
+ ProgIDIndex].ProgID;
+ else
+ progid = package->extensions[i].ProgIDText;
+
+ RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid,
+ (strlenW(progid)+1)*sizeof(WCHAR));
+
+ newkey = HeapAlloc(GetProcessHeap(),0,
+ (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR));
+
+ strcpyW(newkey,progid);
+ strcatW(newkey,szSN);
+ RegCreateKeyW(hkey,newkey,&hkey2);
+ RegCloseKey(hkey2);
+
+ HeapFree(GetProcessHeap(),0,newkey);
+
+ /* do all the verbs */
+ for (v = 0; v < package->extensions[i].VerbCount; v++)
+ register_verb(package, progid,
+ &package->components[index],
+ &package->extensions[i],
+ &package->verbs[package->extensions[i].Verbs[v]],
+ &Sequence);
+ }
+
+ RegCloseKey(hkey);
+
+ uirow = MSI_CreateRecord(1);
+ MSI_RecordSetStringW(uirow,1,package->extensions[i].Extension);
+ ui_actiondata(package,szRegisterExtensionInfo,uirow);
+ msiobj_release(&uirow->hdr);
+ }
+
+ return ERROR_SUCCESS;
+}
+
+UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
+{
+ static const WCHAR szExten[] =
+ {'E','x','t','e','n','s','i','o','n',0 };
+ HKEY hkey;
+ INT i;
+ MSIRECORD *uirow;
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ load_classes_and_such(package);
+
+ for (i = 0; i < package->loaded_mimes; i++)
+ {
+ WCHAR extension[257];
+ LPCWSTR exten;
+ LPCWSTR mime;
+ static const WCHAR fmt[] =
+ {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\',
+ 'C','o','n','t','e','n','t',' ','T','y','p','e','\\', '%','s',0};
+ LPWSTR key;
+
+ /*
+ * check if the MIME is to be installed. Either as requesed by an
+ * extension or Class
+ */
+ package->mimes[i].InstallMe = ((package->mimes[i].InstallMe) ||
+ (package->mimes[i].ClassIndex >= 0 &&
+ package->classes[package->mimes[i].ClassIndex].Installed) ||
+ (package->mimes[i].ExtensionIndex >=0 &&
+ package->extensions[package->mimes[i].ExtensionIndex].Installed));
+
+ if (!package->mimes[i].InstallMe)
+ {
+ TRACE("MIME %s not scheduled to be installed\n",
+ debugstr_w(package->mimes[i].ContentType));
+ continue;
+ }
+
+ mime = package->mimes[i].ContentType;
+ exten = package->extensions[package->mimes[i].ExtensionIndex].Extension;
+ extension[0] = '.';
+ extension[1] = 0;
+ strcatW(extension,exten);
+
+ key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) *
+ sizeof(WCHAR));
+ sprintfW(key,fmt,mime);
+ RegCreateKeyW(HKEY_CLASSES_ROOT,key,&hkey);
+ RegSetValueExW(hkey,szExten,0,REG_SZ,(LPVOID)extension,
+ (strlenW(extension)+1)*sizeof(WCHAR));
+
+ HeapFree(GetProcessHeap(),0,key);
+
+ if (package->mimes[i].CLSID[0])
+ {
+ FIXME("Handle non null for field 3\n");
+ }
+
+ RegCloseKey(hkey);
+
+ uirow = MSI_CreateRecord(2);
+ MSI_RecordSetStringW(uirow,1,package->mimes[i].ContentType);
+ MSI_RecordSetStringW(uirow,2,exten);
+ ui_actiondata(package,szRegisterMIMEInfo,uirow);
+ msiobj_release(&uirow->hdr);
+ }
+
+ return ERROR_SUCCESS;
+}
+
--- /dev//null 2005-03-17 08:20:53.000000000 -0600
+++ dlls/msi/files.c 2005-06-10 08:04:14.000000000 -0500
@@ -0,0 +1,684 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2005 Aric Stewart for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/*
+ * Actions dealing with files These are
+ *
+ * InstallFiles
+ * DuplicateFiles
+ * MoveFiles (TODO)
+ * PatchFiles (TODO)
+ * RemoveDuplicateFiles(TODO)
+ * RemoveFiles(TODO)
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "fdi.h"
+#include "msidefs.h"
+#include "msvcrt/fcntl.h"
+#include "msipriv.h"
+#include "winuser.h"
+#include "wine/unicode.h"
+#include "action.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+extern const WCHAR szInstallFiles[];
+extern const WCHAR szDuplicateFiles[];
+extern const WCHAR szMoveFiles[];
+extern const WCHAR szPatchFiles[];
+extern const WCHAR szRemoveDuplicateFiles[];
+extern const WCHAR szRemoveFiles[];
+
+static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
+
+inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)
+{
+ UINT rc = ERROR_SUCCESS;
+ MSIFOLDER *folder;
+ LPWSTR install_path;
+
+ install_path = resolve_folder(package, package->components[component].Directory,
+ FALSE, FALSE, &folder);
+ if (!install_path)
+ return ERROR_FUNCTION_FAILED;
+
+ /* create the path */
+ if (folder->State == 0)
+ {
+ create_full_pathW(install_path);
+ folder->State = 2;
+ }
+ HeapFree(GetProcessHeap(), 0, install_path);
+
+ return rc;
+}
+
+
+/*
+ * This is a helper function for handling embedded cabinet media
+ */
+static UINT writeout_cabinet_stream(MSIPACKAGE *package, LPCWSTR stream_name,
+ WCHAR* source)
+{
+ UINT rc;
+ USHORT* data;
+ UINT size;
+ DWORD write;
+ HANDLE the_file;
+ WCHAR tmp[MAX_PATH];
+
+ rc = read_raw_stream_data(package->db,stream_name,&data,&size);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ write = MAX_PATH;
+ if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))
+ GetTempPathW(MAX_PATH,tmp);
+
+ GetTempFileNameW(tmp,stream_name,0,source);
+
+ track_tempfile(package,strrchrW(source,'\\'), source);
+ the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (the_file == INVALID_HANDLE_VALUE)
+ {
+ ERR("Unable to create file %s\n",debugstr_w(source));
+ rc = ERROR_FUNCTION_FAILED;
+ goto end;
+ }
+
+ WriteFile(the_file,data,size,&write,NULL);
+ CloseHandle(the_file);
+ TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
+end:
+ HeapFree(GetProcessHeap(),0,data);
+ return rc;
+}
+
+
+/* Support functions for FDI functions */
+typedef struct
+{
+ MSIPACKAGE* package;
+ LPCSTR cab_path;
+ LPCSTR file_name;
+} CabData;
+
+static void * cabinet_alloc(ULONG cb)
+{
+ return HeapAlloc(GetProcessHeap(), 0, cb);
+}
+
+static void cabinet_free(void *pv)
+{
+ HeapFree(GetProcessHeap(), 0, pv);
+}
+
+static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
+{
+ DWORD dwAccess = 0;
+ DWORD dwShareMode = 0;
+ DWORD dwCreateDisposition = OPEN_EXISTING;
+ switch (oflag & _O_ACCMODE)
+ {
+ case _O_RDONLY:
+ dwAccess = GENERIC_READ;
+ dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
+ break;
+ case _O_WRONLY:
+ dwAccess = GENERIC_WRITE;
+ dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ break;
+ case _O_RDWR:
+ dwAccess = GENERIC_READ | GENERIC_WRITE;
+ dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ break;
+ }
+ if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
+ dwCreateDisposition = CREATE_NEW;
+ else if (oflag & _O_CREAT)
+ dwCreateDisposition = CREATE_ALWAYS;
+ return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
+ dwCreateDisposition, 0, NULL);
+}
+
+static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)
+{
+ DWORD dwRead;
+ if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL))
+ return dwRead;
+ return 0;
+}
+
+static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)
+{
+ DWORD dwWritten;
+ if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL))
+ return dwWritten;
+ return 0;
+}
+
+static int cabinet_close(INT_PTR hf)
+{
+ return CloseHandle((HANDLE)hf) ? 0 : -1;
+}
+
+static long cabinet_seek(INT_PTR hf, long dist, int seektype)
+{
+ /* flags are compatible and so are passed straight through */
+ return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
+}
+
+static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
+{
+ /* FIXME: try to do more processing in this function */
+ switch (fdint)
+ {
+ case fdintCOPY_FILE:
+ {
+ CabData *data = (CabData*) pfdin->pv;
+ ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
+ char *file;
+
+ LPWSTR trackname;
+ LPWSTR trackpath;
+ LPWSTR tracknametmp;
+ static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
+
+ if (data->file_name && lstrcmpiA(data->file_name,pfdin->psz1))
+ return 0;
+
+ file = cabinet_alloc((len+1)*sizeof(char));
+ strcpy(file, data->cab_path);
+ strcat(file, pfdin->psz1);
+
+ TRACE("file: %s\n", debugstr_a(file));
+
+ /* track this file so it can be deleted if not installed */
+ trackpath=strdupAtoW(file);
+ tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
+ trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) +
+ strlenW(tmpprefix)+1) * sizeof(WCHAR));
+
+ strcpyW(trackname,tmpprefix);
+ strcatW(trackname,tracknametmp);
+
+ track_tempfile(data->package, trackname, trackpath);
+
+ HeapFree(GetProcessHeap(),0,trackpath);
+ HeapFree(GetProcessHeap(),0,trackname);
+ HeapFree(GetProcessHeap(),0,tracknametmp);
+
+ return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
+ }
+ case fdintCLOSE_FILE_INFO:
+ {
+ FILETIME ft;
+ FILETIME ftLocal;
+ if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
+ return -1;
+ if (!LocalFileTimeToFileTime(&ft, &ftLocal))
+ return -1;
+ if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal))
+ return -1;
+
+ cabinet_close(pfdin->hf);
+ return 1;
+ }
+ default:
+ return 0;
+ }
+}
+
+/***********************************************************************
+ * extract_cabinet_file
+ *
+ * Extract files from a cab file.
+ */
+static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source,
+ const WCHAR* path, const WCHAR* file)
+{
+ HFDI hfdi;
+ ERF erf;
+ BOOL ret;
+ char *cabinet;
+ char *cab_path;
+ char *file_name;
+ CabData data;
+
+ TRACE("Extracting %s (%s) to %s\n",debugstr_w(source),
+ debugstr_w(file), debugstr_w(path));
+
+ hfdi = FDICreate(cabinet_alloc,
+ cabinet_free,
+ cabinet_open,
+ cabinet_read,
+ cabinet_write,
+ cabinet_close,
+ cabinet_seek,
+ 0,
+ &erf);
+ if (!hfdi)
+ {
+ ERR("FDICreate failed\n");
+ return FALSE;
+ }
+
+ if (!(cabinet = strdupWtoA( source )))
+ {
+ FDIDestroy(hfdi);
+ return FALSE;
+ }
+ if (!(cab_path = strdupWtoA( path )))
+ {
+ FDIDestroy(hfdi);
+ HeapFree(GetProcessHeap(), 0, cabinet);
+ return FALSE;
+ }
+
+ data.package = package;
+ data.cab_path = cab_path;
+ if (file)
+ file_name = strdupWtoA(file);
+ else
+ file_name = NULL;
+ data.file_name = file_name;
+
+ ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
+
+ if (!ret)
+ ERR("FDICopy failed\n");
+
+ FDIDestroy(hfdi);
+
+ HeapFree(GetProcessHeap(), 0, cabinet);
+ HeapFree(GetProcessHeap(), 0, cab_path);
+ HeapFree(GetProcessHeap(), 0, file_name);
+
+ return ret;
+}
+
+static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path,
+ MSIFILE* file)
+{
+ UINT rc = ERROR_SUCCESS;
+ MSIRECORD * row = 0;
+ static WCHAR source[MAX_PATH];
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
+ '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
+ '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',
+ ' ','%', 'i',' ','O','R','D','E','R',' ','B','Y',' ',
+ '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0};
+ LPCWSTR cab;
+ DWORD sz;
+ INT seq;
+ static UINT last_sequence = 0;
+
+ if (file->Attributes & msidbFileAttributesNoncompressed)
+ {
+ TRACE("Uncompressed File, no media to ready.\n");
+ return ERROR_SUCCESS;
+ }
+
+ if (file->Sequence <= last_sequence)
+ {
+ TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence);
+ /*extract_a_cabinet_file(package, source,path,file->File); */
+ return ERROR_SUCCESS;
+ }
+
+ row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence);
+ if (!row)
+ return ERROR_FUNCTION_FAILED;
+
+ seq = MSI_RecordGetInteger(row,2);
+ last_sequence = seq;
+
+ cab = MSI_RecordGetString(row,4);
+ if (cab)
+ {
+ TRACE("Source is CAB %s\n",debugstr_w(cab));
+ /* the stream does not contain the # character */
+ if (cab[0]=='#')
+ {
+ writeout_cabinet_stream(package,&cab[1],source);
+ 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);
+ return rc;
+}
+
+inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
+ LPWSTR* file_source)
+{
+ DWORD index;
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ for (index = 0; index < package->loaded_files; index ++)
+ {
+ if (strcmpW(file_key,package->files[index].File)==0)
+ {
+ if (package->files[index].State >= 2)
+ {
+ *file_source = strdupW(package->files[index].TargetPath);
+ return ERROR_SUCCESS;
+ }
+ else
+ return ERROR_FILE_NOT_FOUND;
+ }
+ }
+
+ return ERROR_FUNCTION_FAILED;
+}
+
+UINT ACTION_InstallFiles(MSIPACKAGE *package)
+{
+ UINT rc = ERROR_SUCCESS;
+ DWORD index;
+ MSIRECORD * uirow;
+ WCHAR uipath[MAX_PATH];
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ /* increment progress bar each time action data is sent */
+ ui_progress(package,1,1,0,0);
+
+ for (index = 0; index < package->loaded_files; index++)
+ {
+ WCHAR path_to_source[MAX_PATH];
+ MSIFILE *file;
+
+ file = &package->files[index];
+
+ if (file->Temporary)
+ continue;
+
+
+ if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex,
+ INSTALLSTATE_LOCAL))
+ {
+ ui_progress(package,2,file->FileSize,0,0);
+ TRACE("File %s is not scheduled for install\n",
+ debugstr_w(file->File));
+
+ continue;
+ }
+
+ if ((file->State == 1) || (file->State == 2))
+ {
+ LPWSTR p;
+ MSICOMPONENT* comp = NULL;
+
+ TRACE("Installing %s\n",debugstr_w(file->File));
+ rc = ready_media_for_file(package, path_to_source, file);
+ /*
+ * WARNING!
+ * our file table could change here because a new temp file
+ * may have been created
+ */
+ file = &package->files[index];
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Unable to ready media\n");
+ rc = ERROR_FUNCTION_FAILED;
+ break;
+ }
+
+ create_component_directory( package, file->ComponentIndex);
+
+ /* recalculate file paths because things may have changed */
+
+ if (file->ComponentIndex >= 0)
+ comp = &package->components[file->ComponentIndex];
+
+ p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
+ HeapFree(GetProcessHeap(),0,file->TargetPath);
+
+ file->TargetPath = build_directory_name(2, p, file->FileName);
+ HeapFree(GetProcessHeap(),0,p);
+
+ if (file->Attributes & msidbFileAttributesNoncompressed)
+ {
+ p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
+ file->SourcePath = build_directory_name(2, p, file->ShortName);
+ HeapFree(GetProcessHeap(),0,p);
+ }
+ else
+ file->SourcePath = build_directory_name(2, path_to_source,
+ file->File);
+
+
+ TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
+ debugstr_w(file->TargetPath));
+
+ /* the UI chunk */
+ uirow=MSI_CreateRecord(9);
+ MSI_RecordSetStringW(uirow,1,file->File);
+ strcpyW(uipath,file->TargetPath);
+ *(strrchrW(uipath,'\\')+1)=0;
+ MSI_RecordSetStringW(uirow,9,uipath);
+ MSI_RecordSetInteger(uirow,6,file->FileSize);
+ ui_actiondata(package,szInstallFiles,uirow);
+ msiobj_release( &uirow->hdr );
+ ui_progress(package,2,file->FileSize,0,0);
+
+
+ if (file->Attributes & msidbFileAttributesNoncompressed)
+ rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
+ else
+ rc = MoveFileW(file->SourcePath, file->TargetPath);
+
+ if (!rc)
+ {
+ rc = GetLastError();
+ ERR("Unable to move/copy file (%s -> %s) (error %d)\n",
+ debugstr_w(file->SourcePath), debugstr_w(file->TargetPath),
+ rc);
+ if (rc == ERROR_ALREADY_EXISTS && file->State == 2)
+ {
+ if (!CopyFileW(file->SourcePath,file->TargetPath,FALSE))
+ ERR("Unable to copy file (%s -> %s) (error %ld)\n",
+ debugstr_w(file->SourcePath),
+ debugstr_w(file->TargetPath), GetLastError());
+ if (!(file->Attributes & msidbFileAttributesNoncompressed))
+ DeleteFileW(file->SourcePath);
+ rc = 0;
+ }
+ else if (rc == ERROR_FILE_NOT_FOUND)
+ {
+ ERR("Source File Not Found! Continuing\n");
+ rc = 0;
+ }
+ else if (file->Attributes & msidbFileAttributesVital)
+ {
+ ERR("Ignoring Error and continuing (nonvital file)...\n");
+ rc = 0;
+ }
+ }
+ else
+ {
+ file->State = 4;
+ rc = ERROR_SUCCESS;
+ }
+ }
+ }
+
+ return rc;
+}
+
+static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
+{
+ MSIPACKAGE *package = (MSIPACKAGE*)param;
+ WCHAR *file_source = NULL;
+ WCHAR dest_name[0x100];
+ LPWSTR dest_path, dest;
+ LPCWSTR file_key, component;
+ INT component_index;
+ DWORD sz;
+ DWORD rc;
+
+ component = MSI_RecordGetString(row,2);
+ component_index = get_loaded_component(package,component);
+
+ if (!ACTION_VerifyComponentForAction(package, component_index,
+ INSTALLSTATE_LOCAL))
+ {
+ TRACE("Skipping copy due to disabled component %s\n",
+ debugstr_w(component));
+
+ /* the action taken was the same as the current install state */
+ package->components[component_index].Action =
+ package->components[component_index].Installed;
+
+ return ERROR_SUCCESS;
+ }
+
+ package->components[component_index].Action = INSTALLSTATE_LOCAL;
+
+ file_key = MSI_RecordGetString(row,3);
+ if (!file_key)
+ {
+ ERR("Unable to get file key\n");
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ rc = get_file_target(package,file_key,&file_source);
+
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Original file unknown %s\n",debugstr_w(file_key));
+ HeapFree(GetProcessHeap(),0,file_source);
+ return ERROR_SUCCESS;
+ }
+
+ if (MSI_RecordIsNull(row,4))
+ strcpyW(dest_name,strrchrW(file_source,'\\')+1);
+ else
+ {
+ sz=0x100;
+ MSI_RecordGetStringW(row,4,dest_name,&sz);
+ reduce_to_longfilename(dest_name);
+ }
+
+ if (MSI_RecordIsNull(row,5))
+ {
+ LPWSTR p;
+ dest_path = strdupW(file_source);
+ p = strrchrW(dest_path,'\\');
+ if (p)
+ *p=0;
+ }
+ else
+ {
+ LPCWSTR destkey;
+ destkey = MSI_RecordGetString(row,5);
+ dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);
+ if (!dest_path)
+ {
+ ERR("Unable to get destination folder\n");
+ HeapFree(GetProcessHeap(),0,file_source);
+ return ERROR_FUNCTION_FAILED;
+ }
+ }
+
+ dest = build_directory_name(2, dest_path, dest_name);
+
+ TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
+ debugstr_w(dest));
+
+ if (strcmpW(file_source,dest))
+ rc = !CopyFileW(file_source,dest,TRUE);
+ else
+ rc = ERROR_SUCCESS;
+
+ if (rc != ERROR_SUCCESS)
+ ERR("Failed to copy file %s -> %s, last error %ld\n",
+ debugstr_w(file_source), debugstr_w(dest_path), GetLastError());
+
+ FIXME("We should track these duplicate files as well\n");
+
+ HeapFree(GetProcessHeap(),0,dest_path);
+ HeapFree(GetProcessHeap(),0,dest);
+ HeapFree(GetProcessHeap(),0,file_source);
+
+ return ERROR_SUCCESS;
+}
+
+UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
+{
+ UINT rc;
+ MSIQUERY * view;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0};
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return ERROR_SUCCESS;
+
+ rc = MSI_IterateRecords(view, NULL, ITERATE_DuplicateFiles, package);
+ msiobj_release(&view->hdr);
+
+ return rc;
+}
+
--- /dev//null 2005-03-17 08:20:53.000000000 -0600
+++ dlls/msi/helpers.c 2005-06-10 08:07:48.000000000 -0500
@@ -0,0 +1,900 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2005 Aric Stewart for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Here are helper functions formally in action.c that are used by a variaty of
+ * actions and functions.
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "msipriv.h"
+#include "winuser.h"
+#include "wine/unicode.h"
+#include "action.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};
+static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0};
+
+const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
+const WCHAR szProductCode[]= {'P','r','o','d','u','c','t','C','o','d','e',0};
+const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
+const WCHAR cszbs[]={'\\',0};
+
+DWORD build_version_dword(LPCWSTR version_string)
+{
+ SHORT major,minor;
+ WORD build;
+ DWORD rc = 0x00000000;
+ LPCWSTR ptr1;
+
+ ptr1 = version_string;
+
+ if (!ptr1)
+ return rc;
+ else
+ major = atoiW(ptr1);
+
+
+ if(ptr1)
+ ptr1 = strchrW(ptr1,'.');
+ if (ptr1)
+ {
+ ptr1++;
+ minor = atoiW(ptr1);
+ }
+ else
+ minor = 0;
+
+ if (ptr1)
+ ptr1 = strchrW(ptr1,'.');
+
+ if (ptr1)
+ {
+ ptr1++;
+ build = atoiW(ptr1);
+ }
+ else
+ build = 0;
+
+ rc = MAKELONG(build,MAKEWORD(minor,major));
+ TRACE("%s -> 0x%lx\n",debugstr_w(version_string),rc);
+ return rc;
+}
+
+UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name,
+ LPWSTR *FilePath)
+{
+ LPWSTR ProductCode;
+ LPWSTR SystemFolder;
+ LPWSTR dest;
+ UINT rc;
+
+ static const WCHAR szInstaller[] =
+ {'M','i','c','r','o','s','o','f','t','\\',
+ 'I','n','s','t','a','l','l','e','r','\\',0};
+ static const WCHAR szFolder[] =
+ {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
+
+ ProductCode = load_dynamic_property(package,szProductCode,&rc);
+ if (!ProductCode)
+ return rc;
+
+ SystemFolder = load_dynamic_property(package,szFolder,NULL);
+
+ dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode);
+
+ create_full_pathW(dest);
+
+ *FilePath = build_directory_name(2, dest, icon_name);
+
+ HeapFree(GetProcessHeap(),0,SystemFolder);
+ HeapFree(GetProcessHeap(),0,ProductCode);
+ HeapFree(GetProcessHeap(),0,dest);
+ return ERROR_SUCCESS;
+}
+
+WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
+{
+ UINT rc;
+ DWORD sz;
+ LPWSTR ret;
+
+ sz = 0;
+ if (MSI_RecordIsNull(row,index))
+ return NULL;
+
+ rc = MSI_RecordGetStringW(row,index,NULL,&sz);
+
+ /* having an empty string is different than NULL */
+ if (sz == 0)
+ {
+ ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR));
+ ret[0] = 0;
+ return ret;
+ }
+
+ sz ++;
+ ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR));
+ rc = MSI_RecordGetStringW(row,index,ret,&sz);
+ if (rc!=ERROR_SUCCESS)
+ {
+ ERR("Unable to load dynamic string\n");
+ HeapFree(GetProcessHeap(), 0, ret);
+ ret = NULL;
+ }
+ return ret;
+}
+
+LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc)
+{
+ DWORD sz = 0;
+ LPWSTR str;
+ UINT r;
+
+ r = MSI_GetPropertyW(package, prop, NULL, &sz);
+ if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
+ {
+ if (rc)
+ *rc = r;
+ return NULL;
+ }
+ sz++;
+ str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
+ r = MSI_GetPropertyW(package, prop, str, &sz);
+ if (r != ERROR_SUCCESS)
+ {
+ HeapFree(GetProcessHeap(),0,str);
+ str = NULL;
+ }
+ if (rc)
+ *rc = r;
+ return str;
+}
+
+int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
+{
+ int rc = -1;
+ DWORD i;
+
+ for (i = 0; i < package->loaded_components; i++)
+ {
+ if (strcmpW(Component,package->components[i].Component)==0)
+ {
+ rc = i;
+ break;
+ }
+ }
+ return rc;
+}
+
+int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
+{
+ int rc = -1;
+ DWORD i;
+
+ for (i = 0; i < package->loaded_features; i++)
+ {
+ if (strcmpW(Feature,package->features[i].Feature)==0)
+ {
+ rc = i;
+ break;
+ }
+ }
+ return rc;
+}
+
+int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
+{
+ int rc = -1;
+ DWORD i;
+
+ for (i = 0; i < package->loaded_files; i++)
+ {
+ if (strcmpW(file,package->files[i].File)==0)
+ {
+ rc = i;
+ break;
+ }
+ }
+ return rc;
+}
+
+int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
+{
+ DWORD i;
+ DWORD index;
+
+ if (!package)
+ return -2;
+
+ for (i=0; i < package->loaded_files; i++)
+ if (strcmpW(package->files[i].File,name)==0)
+ return -1;
+
+ index = package->loaded_files;
+ package->loaded_files++;
+ if (package->loaded_files== 1)
+ package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
+ else
+ package->files = HeapReAlloc(GetProcessHeap(),0,
+ package->files , package->loaded_files * sizeof(MSIFILE));
+
+ memset(&package->files[index],0,sizeof(MSIFILE));
+
+ package->files[index].File = strdupW(name);
+ package->files[index].TargetPath = strdupW(path);
+ package->files[index].Temporary = TRUE;
+
+ TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File));
+
+ return 0;
+}
+
+LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
+ BOOL set_prop, MSIFOLDER **folder)
+{
+ DWORD i;
+ LPWSTR p, path = NULL;
+
+ TRACE("Working to resolve %s\n",debugstr_w(name));
+
+ if (!name)
+ return NULL;
+
+ /* special resolving for Target and Source root dir */
+ if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
+ {
+ if (!source)
+ {
+ path = load_dynamic_property(package,cszTargetDir,NULL);
+ if (!path)
+ {
+ path = load_dynamic_property(package,cszRootDrive,NULL);
+ if (set_prop)
+ MSI_SetPropertyW(package,cszTargetDir,path);
+ }
+ if (folder)
+ {
+ for (i = 0; i < package->loaded_folders; i++)
+ {
+ if (strcmpW(package->folders[i].Directory,name)==0)
+ break;
+ }
+ *folder = &(package->folders[i]);
+ }
+ return path;
+ }
+ else
+ {
+ path = load_dynamic_property(package,cszSourceDir,NULL);
+ if (!path)
+ {
+ path = load_dynamic_property(package,cszDatabase,NULL);
+ if (path)
+ {
+ p = strrchrW(path,'\\');
+ if (p)
+ *(p+1) = 0;
+ }
+ }
+ if (folder)
+ {
+ for (i = 0; i < package->loaded_folders; i++)
+ {
+ if (strcmpW(package->folders[i].Directory,name)==0)
+ break;
+ }
+ *folder = &(package->folders[i]);
+ }
+ return path;
+ }
+ }
+
+ for (i = 0; i < package->loaded_folders; i++)
+ {
+ if (strcmpW(package->folders[i].Directory,name)==0)
+ break;
+ }
+
+ if (i >= package->loaded_folders)
+ return NULL;
+
+ if (folder)
+ *folder = &(package->folders[i]);
+
+ if (!source && package->folders[i].ResolvedTarget)
+ {
+ path = strdupW(package->folders[i].ResolvedTarget);
+ TRACE(" already resolved to %s\n",debugstr_w(path));
+ return path;
+ }
+ else if (source && package->folders[i].ResolvedSource)
+ {
+ path = strdupW(package->folders[i].ResolvedSource);
+ TRACE(" (source)already resolved to %s\n",debugstr_w(path));
+ return path;
+ }
+ else if (!source && package->folders[i].Property)
+ {
+ path = build_directory_name(2, package->folders[i].Property, NULL);
+
+ TRACE(" internally set to %s\n",debugstr_w(path));
+ if (set_prop)
+ MSI_SetPropertyW(package,name,path);
+ return path;
+ }
+
+ if (package->folders[i].ParentIndex >= 0)
+ {
+ LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory;
+
+ TRACE(" ! Parent is %s\n", debugstr_w(parent));
+
+ p = resolve_folder(package, parent, source, set_prop, NULL);
+ if (!source)
+ {
+ TRACE(" TargetDefault = %s\n", debugstr_w(package->folders[i].TargetDefault));
+ path = build_directory_name(3, p, package->folders[i].TargetDefault, NULL);
+ package->folders[i].ResolvedTarget = strdupW(path);
+ TRACE(" resolved into %s\n",debugstr_w(path));
+ if (set_prop)
+ MSI_SetPropertyW(package,name,path);
+ }
+ else
+ {
+ path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL);
+ TRACE(" (source)resolved into %s\n",debugstr_w(path));
+ package->folders[i].ResolvedSource = strdupW(path);
+ }
+ HeapFree(GetProcessHeap(),0,p);
+ }
+ return path;
+}
+
+/* wrapper to resist a need for a full rewrite right now */
+DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data )
+{
+ if (ptr)
+ {
+ MSIRECORD *rec = MSI_CreateRecord(1);
+ DWORD size = 0;
+
+ MSI_RecordSetStringW(rec,0,ptr);
+ MSI_FormatRecordW(package,rec,NULL,&size);
+ if (size >= 0)
+ {
+ size++;
+ *data = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
+ if (size > 1)
+ MSI_FormatRecordW(package,rec,*data,&size);
+ else
+ *data[0] = 0;
+ msiobj_release( &rec->hdr );
+ return sizeof(WCHAR)*size;
+ }
+ msiobj_release( &rec->hdr );
+ }
+
+ *data = NULL;
+ return 0;
+}
+
+UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action)
+{
+ UINT count;
+ LPWSTR *newbuf = NULL;
+ if (script >= TOTAL_SCRIPTS)
+ {
+ FIXME("Unknown script requested %i\n",script);
+ return ERROR_FUNCTION_FAILED;
+ }
+ TRACE("Scheduling Action %s in script %i\n",debugstr_w(action), script);
+
+ count = package->script->ActionCount[script];
+ package->script->ActionCount[script]++;
+ if (count != 0)
+ newbuf = HeapReAlloc(GetProcessHeap(),0,
+ package->script->Actions[script],
+ package->script->ActionCount[script]* sizeof(LPWSTR));
+ else
+ newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
+
+ newbuf[count] = strdupW(action);
+ package->script->Actions[script] = newbuf;
+
+ return ERROR_SUCCESS;
+}
+
+static void remove_tracked_tempfiles(MSIPACKAGE* package)
+{
+ DWORD i;
+
+ if (!package)
+ return;
+
+ for (i = 0; i < package->loaded_files; i++)
+ {
+ if (package->files[i].Temporary)
+ {
+ TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath));
+ DeleteFileW(package->files[i].TargetPath);
+ }
+
+ }
+}
+
+/* Called when the package is being closed */
+void ACTION_free_package_structures( MSIPACKAGE* package)
+{
+ INT i;
+
+ TRACE("Freeing package action data\n");
+
+ remove_tracked_tempfiles(package);
+
+ /* No dynamic buffers in features */
+ if (package->features && package->loaded_features > 0)
+ HeapFree(GetProcessHeap(),0,package->features);
+
+ for (i = 0; i < package->loaded_folders; i++)
+ {
+ HeapFree(GetProcessHeap(),0,package->folders[i].Directory);
+ HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault);
+ HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault);
+ HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
+ HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource);
+ HeapFree(GetProcessHeap(),0,package->folders[i].Property);
+ }
+ if (package->folders && package->loaded_folders > 0)
+ HeapFree(GetProcessHeap(),0,package->folders);
+
+ for (i = 0; i < package->loaded_components; i++)
+ HeapFree(GetProcessHeap(),0,package->components[i].FullKeypath);
+
+ if (package->components && package->loaded_components > 0)
+ HeapFree(GetProcessHeap(),0,package->components);
+
+ for (i = 0; i < package->loaded_files; i++)
+ {
+ HeapFree(GetProcessHeap(),0,package->files[i].File);
+ HeapFree(GetProcessHeap(),0,package->files[i].FileName);
+ HeapFree(GetProcessHeap(),0,package->files[i].ShortName);
+ HeapFree(GetProcessHeap(),0,package->files[i].Version);
+ HeapFree(GetProcessHeap(),0,package->files[i].Language);
+ HeapFree(GetProcessHeap(),0,package->files[i].SourcePath);
+ HeapFree(GetProcessHeap(),0,package->files[i].TargetPath);
+ }
+
+ if (package->files && package->loaded_files > 0)
+ HeapFree(GetProcessHeap(),0,package->files);
+
+ /* clean up extension, progid, class and verb structures */
+ for (i = 0; i < package->loaded_classes; i++)
+ {
+ HeapFree(GetProcessHeap(),0,package->classes[i].Description);
+ HeapFree(GetProcessHeap(),0,package->classes[i].FileTypeMask);
+ HeapFree(GetProcessHeap(),0,package->classes[i].IconPath);
+ HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler);
+ HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler32);
+ HeapFree(GetProcessHeap(),0,package->classes[i].Argument);
+ HeapFree(GetProcessHeap(),0,package->classes[i].ProgIDText);
+ }
+
+ if (package->classes && package->loaded_classes > 0)
+ HeapFree(GetProcessHeap(),0,package->classes);
+
+ for (i = 0; i < package->loaded_extensions; i++)
+ {
+ HeapFree(GetProcessHeap(),0,package->extensions[i].ProgIDText);
+ }
+
+ if (package->extensions && package->loaded_extensions > 0)
+ HeapFree(GetProcessHeap(),0,package->extensions);
+
+ for (i = 0; i < package->loaded_progids; i++)
+ {
+ HeapFree(GetProcessHeap(),0,package->progids[i].ProgID);
+ HeapFree(GetProcessHeap(),0,package->progids[i].Description);
+ HeapFree(GetProcessHeap(),0,package->progids[i].IconPath);
+ }
+
+ if (package->progids && package->loaded_progids > 0)
+ HeapFree(GetProcessHeap(),0,package->progids);
+
+ for (i = 0; i < package->loaded_verbs; i++)
+ {
+ HeapFree(GetProcessHeap(),0,package->verbs[i].Verb);
+ HeapFree(GetProcessHeap(),0,package->verbs[i].Command);
+ HeapFree(GetProcessHeap(),0,package->verbs[i].Argument);
+ }
+
+ if (package->verbs && package->loaded_verbs > 0)
+ HeapFree(GetProcessHeap(),0,package->verbs);
+
+ for (i = 0; i < package->loaded_mimes; i++)
+ HeapFree(GetProcessHeap(),0,package->mimes[i].ContentType);
+
+ if (package->mimes && package->loaded_mimes > 0)
+ HeapFree(GetProcessHeap(),0,package->mimes);
+
+ for (i = 0; i < package->loaded_appids; i++)
+ {
+ HeapFree(GetProcessHeap(),0,package->appids[i].RemoteServerName);
+ HeapFree(GetProcessHeap(),0,package->appids[i].LocalServer);
+ HeapFree(GetProcessHeap(),0,package->appids[i].ServiceParameters);
+ HeapFree(GetProcessHeap(),0,package->appids[i].DllSurrogate);
+ }
+
+ if (package->appids && package->loaded_appids > 0)
+ HeapFree(GetProcessHeap(),0,package->appids);
+
+ if (package->script)
+ {
+ for (i = 0; i < TOTAL_SCRIPTS; i++)
+ {
+ int j;
+ for (j = 0; j < package->script->ActionCount[i]; j++)
+ HeapFree(GetProcessHeap(),0,package->script->Actions[i][j]);
+
+ HeapFree(GetProcessHeap(),0,package->script->Actions[i]);
+ }
+ HeapFree(GetProcessHeap(),0,package->script);
+ }
+
+ HeapFree(GetProcessHeap(),0,package->PackagePath);
+
+ /* cleanup control event subscriptions */
+ ControlEvent_CleanupSubscriptions(package);
+}
+
+/*
+ * build_directory_name()
+ *
+ * This function is to save messing round with directory names
+ * It handles adding backslashes between path segments,
+ * and can add \ at the end of the directory name if told to.
+ *
+ * It takes a variable number of arguments.
+ * It always allocates a new string for the result, so make sure
+ * to free the return value when finished with it.
+ *
+ * The first arg is the number of path segments that follow.
+ * The arguments following count are a list of path segments.
+ * A path segment may be NULL.
+ *
+ * Path segments will be added with a \ separating them.
+ * A \ will not be added after the last segment, however if the
+ * last segment is NULL, then the last character will be a \
+ *
+ */
+LPWSTR build_directory_name(DWORD count, ...)
+{
+ DWORD sz = 1, i;
+ LPWSTR dir;
+ va_list va;
+
+ va_start(va,count);
+ for(i=0; 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;
+}
+
+/***********************************************************************
+ * create_full_pathW
+ *
+ * Recursively create all directories in the path.
+ *
+ * shamelessly stolen from setupapi/queue.c
+ */
+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;
+}
+
+void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d )
+{
+ MSIRECORD * row;
+
+ row = MSI_CreateRecord(4);
+ MSI_RecordSetInteger(row,1,a);
+ MSI_RecordSetInteger(row,2,b);
+ MSI_RecordSetInteger(row,3,c);
+ MSI_RecordSetInteger(row,4,d);
+ MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row);
+ msiobj_release(&row->hdr);
+
+ msi_dialog_check_messages(NULL);
+}
+
+void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
+{
+ static const WCHAR Query_t[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
+ 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',
+ ' ','\'','%','s','\'',0};
+ WCHAR message[1024];
+ MSIRECORD * row = 0;
+ DWORD size;
+ static const WCHAR szActionData[] =
+ {'A','c','t','i','o','n','D','a','t','a',0};
+
+ if (!package->LastAction || strcmpW(package->LastAction,action))
+ {
+ row = MSI_QueryGetRecord(package->db, Query_t, action);
+ if (!row)
+ return;
+
+ if (MSI_RecordIsNull(row,3))
+ {
+ msiobj_release(&row->hdr);
+ return;
+ }
+
+ /* update the cached actionformat */
+ HeapFree(GetProcessHeap(),0,package->ActionFormat);
+ package->ActionFormat = load_dynamic_stringW(row,3);
+
+ HeapFree(GetProcessHeap(),0,package->LastAction);
+ package->LastAction = strdupW(action);
+
+ msiobj_release(&row->hdr);
+ }
+
+ MSI_RecordSetStringW(record,0,package->ActionFormat);
+ size = 1024;
+ MSI_FormatRecordW(package,record,message,&size);
+
+ row = MSI_CreateRecord(1);
+ MSI_RecordSetStringW(row,1,message);
+
+ MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
+
+ ControlEvent_FireSubscribedEvent(package,szActionData, row);
+
+ msiobj_release(&row->hdr);
+}
+
+BOOL ACTION_VerifyComponentForAction(MSIPACKAGE* package, INT index,
+ INSTALLSTATE check )
+{
+ if (package->components[index].Installed == check)
+ return FALSE;
+
+ if (package->components[index].ActionRequest == check)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE* package, INT index,
+ INSTALLSTATE check )
+{
+ if (package->features[index].Installed == check)
+ return FALSE;
+
+ if (package->features[index].ActionRequest == check)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+void reduce_to_longfilename(WCHAR* filename)
+{
+ LPWSTR p = strchrW(filename,'|');
+ if (p)
+ memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR));
+}
+
+void reduce_to_shortfilename(WCHAR* filename)
+{
+ LPWSTR p = strchrW(filename,'|');
+ if (p)
+ *p = 0;
+}
+
+LPWSTR create_component_advertise_string(MSIPACKAGE* package,
+ MSICOMPONENT* component, LPCWSTR feature)
+{
+ LPWSTR productid=NULL;
+ GUID clsid;
+ WCHAR productid_85[21];
+ WCHAR component_85[21];
+ /*
+ * I have a fair bit of confusion as to when a < is used and when a > is
+ * used. I do not think i have it right...
+ *
+ * Ok it appears that the > is used if there is a guid for the compoenent
+ * and the < is used if not.
+ */
+ static WCHAR fmt1[] = {'%','s','%','s','<',0,0};
+ static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0};
+ LPWSTR output = NULL;
+ DWORD sz = 0;
+
+ memset(productid_85,0,sizeof(productid_85));
+ memset(component_85,0,sizeof(component_85));
+
+ productid = load_dynamic_property(package,szProductCode,NULL);
+ CLSIDFromString(productid, &clsid);
+
+ encode_base85_guid(&clsid,productid_85);
+
+ CLSIDFromString(component->ComponentId, &clsid);
+ encode_base85_guid(&clsid,component_85);
+
+ TRACE("Doing something with this... %s %s %s\n",
+ debugstr_w(productid_85), debugstr_w(feature),
+ debugstr_w(component_85));
+
+ sz = lstrlenW(productid_85) + lstrlenW(feature);
+ if (component)
+ sz += lstrlenW(component_85);
+
+ sz+=3;
+ sz *= sizeof(WCHAR);
+
+ output = HeapAlloc(GetProcessHeap(),0,sz);
+ memset(output,0,sz);
+
+ if (component)
+ sprintfW(output,fmt2,productid_85,feature,component_85);
+ else
+ sprintfW(output,fmt1,productid_85,feature);
+
+ HeapFree(GetProcessHeap(),0,productid);
+
+ return output;
+}
+
+/* update compoennt state based on a feature change */
+void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
+{
+ int i;
+ INSTALLSTATE newstate;
+ MSIFEATURE *feature;
+
+ i = get_loaded_feature(package,szFeature);
+ if (i < 0)
+ return;
+
+ feature = &package->features[i];
+ newstate = feature->ActionRequest;
+
+ for( i = 0; i < feature->ComponentCount; i++)
+ {
+ MSICOMPONENT* component = &package->components[feature->Components[i]];
+
+ TRACE("MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)\n",
+ newstate, debugstr_w(component->Component), component->Installed,
+ component->Action, component->ActionRequest);
+
+ if (!component->Enabled)
+ continue;
+ else
+ {
+ if (newstate == INSTALLSTATE_LOCAL)
+ {
+ component->ActionRequest = INSTALLSTATE_LOCAL;
+ component->Action = INSTALLSTATE_LOCAL;
+ }
+ else
+ {
+ int j,k;
+
+ component->ActionRequest = newstate;
+ component->Action = newstate;
+
+ /*if any other feature wants is local we need to set it local*/
+ for (j = 0;
+ j < package->loaded_features &&
+ component->ActionRequest != INSTALLSTATE_LOCAL;
+ j++)
+ {
+ for (k = 0; k < package->features[j].ComponentCount; k++)
+ if ( package->features[j].Components[k] ==
+ feature->Components[i] )
+ {
+ if (package->features[j].ActionRequest ==
+ INSTALLSTATE_LOCAL)
+ {
+ TRACE("Saved by %s\n", debugstr_w(package->features[j].Feature));
+ component->ActionRequest = INSTALLSTATE_LOCAL;
+ component->Action = INSTALLSTATE_LOCAL;
+ }
+ break;
+ }
+ }
+ }
+ }
+ TRACE("Result (%i): Component %s (Installed %i, Action %i, Request %i)\n",
+ newstate, debugstr_w(component->Component), component->Installed,
+ component->Action, component->ActionRequest);
+ }
+}
+
--- /dev//null 2005-03-17 08:20:53.000000000 -0600
+++ dlls/msi/install.c 2005-06-10 08:04:19.000000000 -0500
@@ -0,0 +1,552 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2005 Aric Stewart for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* Msi top level apis directly related to installs */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "msi.h"
+#include "msidefs.h"
+#include "msipriv.h"
+#include "winuser.h"
+#include "wine/unicode.h"
+#include "action.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+/***********************************************************************
+ * MsiDoActionA (MSI.@)
+ */
+UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
+{
+ LPWSTR szwAction;
+ UINT rc;
+
+ TRACE(" exteral attempt at action %s\n",szAction);
+
+ if (!szAction)
+ return ERROR_FUNCTION_FAILED;
+ if (hInstall == 0)
+ return ERROR_FUNCTION_FAILED;
+
+ szwAction = strdupAtoW(szAction);
+
+ if (!szwAction)
+ return ERROR_FUNCTION_FAILED;
+
+
+ rc = MsiDoActionW(hInstall, szwAction);
+ HeapFree(GetProcessHeap(),0,szwAction);
+ return rc;
+}
+
+/***********************************************************************
+ * MsiDoActionW (MSI.@)
+ */
+UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
+{
+ MSIPACKAGE *package;
+ UINT ret = ERROR_INVALID_HANDLE;
+
+ TRACE(" external attempt at action %s \n",debugstr_w(szAction));
+
+ package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
+ if( package )
+ {
+ ret = ACTION_PerformUIAction(package,szAction);
+ msiobj_release( &package->hdr );
+ }
+ return ret;
+}
+
+UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
+ LPSTR szPathBuf, DWORD* pcchPathBuf)
+{
+ LPWSTR szwFolder;
+ LPWSTR szwPathBuf;
+ UINT rc;
+
+ TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
+
+ if (!szFolder)
+ return ERROR_FUNCTION_FAILED;
+ if (hInstall == 0)
+ return ERROR_FUNCTION_FAILED;
+
+ szwFolder = strdupAtoW(szFolder);
+
+ if (!szwFolder)
+ return ERROR_FUNCTION_FAILED;
+
+ szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
+
+ rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
+
+ WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
+ *pcchPathBuf, NULL, NULL );
+
+ HeapFree(GetProcessHeap(),0,szwFolder);
+ HeapFree(GetProcessHeap(),0,szwPathBuf);
+
+ return rc;
+}
+
+UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
+ szPathBuf, DWORD* pcchPathBuf)
+{
+ LPWSTR path;
+ UINT rc = ERROR_FUNCTION_FAILED;
+ MSIPACKAGE *package;
+
+ TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
+
+ package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+ path = resolve_folder(package, szFolder, FALSE, FALSE, NULL);
+ msiobj_release( &package->hdr );
+
+ if (path && (strlenW(path) > *pcchPathBuf))
+ {
+ *pcchPathBuf = strlenW(path)+1;
+ rc = ERROR_MORE_DATA;
+ }
+ else if (path)
+ {
+ *pcchPathBuf = strlenW(path)+1;
+ strcpyW(szPathBuf,path);
+ TRACE("Returning Path %s\n",debugstr_w(path));
+ rc = ERROR_SUCCESS;
+ }
+ HeapFree(GetProcessHeap(),0,path);
+
+ return rc;
+}
+
+
+UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder,
+ LPSTR szPathBuf, DWORD* pcchPathBuf)
+{
+ LPWSTR szwFolder;
+ LPWSTR szwPathBuf;
+ UINT rc;
+
+ TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
+
+ if (!szFolder)
+ return ERROR_FUNCTION_FAILED;
+ if (hInstall == 0)
+ return ERROR_FUNCTION_FAILED;
+
+ szwFolder = strdupAtoW(szFolder);
+ if (!szwFolder)
+ return ERROR_FUNCTION_FAILED;
+
+ szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
+
+ rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
+
+ WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
+ *pcchPathBuf, NULL, NULL );
+
+ HeapFree(GetProcessHeap(),0,szwFolder);
+ HeapFree(GetProcessHeap(),0,szwPathBuf);
+
+ return rc;
+}
+
+UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
+ szPathBuf, DWORD* pcchPathBuf)
+{
+ LPWSTR path;
+ UINT rc = ERROR_FUNCTION_FAILED;
+ MSIPACKAGE *package;
+
+ TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
+
+ package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
+ if( !package )
+ return ERROR_INVALID_HANDLE;
+ path = resolve_folder(package, szFolder, TRUE, FALSE, NULL);
+ msiobj_release( &package->hdr );
+
+ if (path && strlenW(path) > *pcchPathBuf)
+ {
+ *pcchPathBuf = strlenW(path)+1;
+ rc = ERROR_MORE_DATA;
+ }
+ else if (path)
+ {
+ *pcchPathBuf = strlenW(path)+1;
+ strcpyW(szPathBuf,path);
+ TRACE("Returning Path %s\n",debugstr_w(path));
+ rc = ERROR_SUCCESS;
+ }
+ HeapFree(GetProcessHeap(),0,path);
+
+ return rc;
+}
+
+
+/***********************************************************************
+ * MsiSetTargetPathA (MSI.@)
+ */
+UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder,
+ LPCSTR szFolderPath)
+{
+ LPWSTR szwFolder;
+ LPWSTR szwFolderPath;
+ UINT rc;
+
+ if (!szFolder)
+ return ERROR_FUNCTION_FAILED;
+ if (hInstall == 0)
+ return ERROR_FUNCTION_FAILED;
+
+ szwFolder = strdupAtoW(szFolder);
+ if (!szwFolder)
+ return ERROR_FUNCTION_FAILED;
+
+ szwFolderPath = strdupAtoW(szFolderPath);
+ if (!szwFolderPath)
+ {
+ HeapFree(GetProcessHeap(),0,szwFolder);
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);
+
+ HeapFree(GetProcessHeap(),0,szwFolder);
+ HeapFree(GetProcessHeap(),0,szwFolderPath);
+
+ return rc;
+}
+
+UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
+ LPCWSTR szFolderPath)
+{
+ DWORD i;
+ LPWSTR path = NULL;
+ LPWSTR path2 = NULL;
+ MSIFOLDER *folder;
+
+ TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
+
+ if (package==NULL)
+ return ERROR_INVALID_HANDLE;
+
+ if (szFolderPath[0]==0)
+ return ERROR_FUNCTION_FAILED;
+
+ if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES)
+ return ERROR_FUNCTION_FAILED;
+
+ path = resolve_folder(package,szFolder,FALSE,FALSE,&folder);
+
+ if (!path)
+ return ERROR_INVALID_PARAMETER;
+
+ HeapFree(GetProcessHeap(),0,folder->Property);
+ folder->Property = build_directory_name(2, szFolderPath, NULL);
+
+ if (lstrcmpiW(path, folder->Property) == 0)
+ {
+ /*
+ * Resolved Target has not really changed, so just
+ * set this folder and do not recalculate everything.
+ */
+ HeapFree(GetProcessHeap(),0,folder->ResolvedTarget);
+ folder->ResolvedTarget = NULL;
+ path2 = resolve_folder(package,szFolder,FALSE,TRUE,NULL);
+ HeapFree(GetProcessHeap(),0,path2);
+ }
+ else
+ {
+ for (i = 0; i < package->loaded_folders; i++)
+ {
+ HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
+ package->folders[i].ResolvedTarget=NULL;
+ }
+
+ for (i = 0; i < package->loaded_folders; i++)
+ {
+ path2=resolve_folder(package, package->folders[i].Directory, FALSE,
+ TRUE, NULL);
+ HeapFree(GetProcessHeap(),0,path2);
+ }
+ }
+ HeapFree(GetProcessHeap(),0,path);
+
+ return ERROR_SUCCESS;
+}
+
+/***********************************************************************
+ * MsiSetTargetPathW (MSI.@)
+ */
+UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
+ LPCWSTR szFolderPath)
+{
+ MSIPACKAGE *package;
+ UINT ret;
+
+ TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
+
+ package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
+ ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
+ msiobj_release( &package->hdr );
+ return ret;
+}
+
+/***********************************************************************
+ * MsiGetMode (MSI.@)
+ *
+ * Returns an internal installer state (if it is running in a mode iRunMode)
+ *
+ * PARAMS
+ * hInstall [I] Handle to the installation
+ * hRunMode [I] Checking run mode
+ * MSIRUNMODE_ADMIN Administrative mode
+ * MSIRUNMODE_ADVERTISE Advertisement mode
+ * MSIRUNMODE_MAINTENANCE Maintenance mode
+ * MSIRUNMODE_ROLLBACKENABLED Rollback is enabled
+ * MSIRUNMODE_LOGENABLED Log file is writing
+ * MSIRUNMODE_OPERATIONS Operations in progress??
+ * MSIRUNMODE_REBOOTATEND We need to reboot after installation completed
+ * MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation
+ * MSIRUNMODE_CABINET Files from cabinet are installed
+ * MSIRUNMODE_SOURCESHORTNAMES Long names in source files is suppressed
+ * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is suppressed
+ * MSIRUNMODE_RESERVED11 Reserved
+ * MSIRUNMODE_WINDOWS9X Running under Windows95/98
+ * MSIRUNMODE_ZAWENABLED Demand installation is supported
+ * MSIRUNMODE_RESERVED14 Reserved
+ * MSIRUNMODE_RESERVED15 Reserved
+ * MSIRUNMODE_SCHEDULED called from install script
+ * MSIRUNMODE_ROLLBACK called from rollback script
+ * MSIRUNMODE_COMMIT called from commit script
+ *
+ * RETURNS
+ * In the state: TRUE
+ * Not in the state: FALSE
+ *
+ */
+
+BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
+{
+ FIXME("STUB (iRunMode=%i)\n",iRunMode);
+ return TRUE;
+}
+
+/***********************************************************************
+ * MsiSetFeatureStateA (MSI.@)
+ *
+ * According to the docs, when this is called it immediately recalculates
+ * all the component states as well
+ */
+UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
+ INSTALLSTATE iState)
+{
+ LPWSTR szwFeature = NULL;
+ UINT rc;
+
+ szwFeature = strdupAtoW(szFeature);
+
+ if (!szwFeature)
+ return ERROR_FUNCTION_FAILED;
+
+ rc = MsiSetFeatureStateW(hInstall,szwFeature, iState);
+
+ HeapFree(GetProcessHeap(),0,szwFeature);
+
+ return rc;
+}
+
+
+
+UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
+ INSTALLSTATE iState)
+{
+ INT index, i;
+ UINT rc = ERROR_SUCCESS;
+
+ TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
+
+ index = get_loaded_feature(package,szFeature);
+ if (index < 0)
+ return ERROR_UNKNOWN_FEATURE;
+
+ if (iState == INSTALLSTATE_ADVERTISED &&
+ package->features[index].Attributes &
+ msidbFeatureAttributesDisallowAdvertise)
+ return ERROR_FUNCTION_FAILED;
+
+ package->features[index].ActionRequest= iState;
+ package->features[index].Action= iState;
+
+ ACTION_UpdateComponentStates(package,szFeature);
+
+ /* update all the features that are children of this feature */
+ for (i = 0; i < package->loaded_features; i++)
+ {
+ if (strcmpW(szFeature, package->features[i].Feature_Parent) == 0)
+ MSI_SetFeatureStateW(package, package->features[i].Feature, iState);
+ }
+
+ return rc;
+}
+
+/***********************************************************************
+ * MsiSetFeatureStateW (MSI.@)
+ */
+UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
+ INSTALLSTATE iState)
+{
+ MSIPACKAGE* package;
+ UINT rc = ERROR_SUCCESS;
+
+ TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
+
+ package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ rc = MSI_SetFeatureStateW(package,szFeature,iState);
+
+ msiobj_release( &package->hdr );
+ return rc;
+}
+
+UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature,
+ INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
+{
+ LPWSTR szwFeature = NULL;
+ UINT rc;
+
+ szwFeature = strdupAtoW(szFeature);
+
+ rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
+
+ HeapFree( GetProcessHeap(), 0 , szwFeature);
+
+ return rc;
+}
+
+UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
+ INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
+{
+ INT index;
+
+ index = get_loaded_feature(package,szFeature);
+ if (index < 0)
+ return ERROR_UNKNOWN_FEATURE;
+
+ if (piInstalled)
+ *piInstalled = package->features[index].Installed;
+
+ if (piAction)
+ *piAction = package->features[index].Action;
+
+ TRACE("returning %i %i\n",*piInstalled,*piAction);
+
+ return ERROR_SUCCESS;
+}
+
+UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature,
+ INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
+{
+ MSIPACKAGE* package;
+ UINT ret;
+
+ TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,
+piAction);
+
+ package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+ ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
+ msiobj_release( &package->hdr );
+ return ret;
+}
+
+/***********************************************************************
+ * MsiGetComponentStateA (MSI.@)
+ */
+UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent,
+ INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
+{
+ LPWSTR szwComponent= NULL;
+ UINT rc;
+
+ szwComponent= strdupAtoW(szComponent);
+
+ rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
+
+ HeapFree( GetProcessHeap(), 0 , szwComponent);
+
+ return rc;
+}
+
+UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent,
+ INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
+{
+ INT index;
+
+ TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled,
+piAction);
+
+ index = get_loaded_component(package,szComponent);
+ if (index < 0)
+ return ERROR_UNKNOWN_COMPONENT;
+
+ if (piInstalled)
+ *piInstalled = package->components[index].Installed;
+
+ if (piAction)
+ *piAction = package->components[index].Action;
+
+ TRACE("states (%i, %i)\n",
+(piInstalled)?*piInstalled:-1,(piAction)?*piAction:-1);
+
+ return ERROR_SUCCESS;
+}
+
+/***********************************************************************
+ * MsiGetComponentStateW (MSI.@)
+ */
+UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent,
+ INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
+{
+ MSIPACKAGE* package;
+ UINT ret;
+
+ TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
+ piInstalled, piAction);
+
+ package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+ ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
+ msiobj_release( &package->hdr );
+ return ret;
+}
More information about the wine-patches
mailing list