--- /dev/null
+#ifndef __WINE_MSVCRT_FCNTL_H
+#define __WINE_MSVCRT_FCNTL_H
+
+/*
+ * Compatibility header
+ */
+
+#include <fcntl.h>
+
+#endif /* __WINE_MSVCRT_FCNTL_H */
VPATH = @srcdir@\r
MODULE = msi.dll\r
IMPORTLIB = libmsi.$(IMPLIBEXT)\r
-IMPORTS = shell32 cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32\r
+IMPORTS = shell32 shlwapi cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32\r
EXTRALIBS = -luuid $(LIBUNICODE)\r
\r
C_SRCS = \\r
action.c \\r
appsearch.c \\r
+ classes.c \\r
create.c \\r
custom.c \\r
database.c \\r
delete.c \\r
dialog.c \\r
distinct.c \\r
+ events.c \\r
+ files.c \\r
format.c \\r
handle.c \\r
+ helpers.c \\r
insert.c \\r
+ install.c \\r
msi.c \\r
msiquery.c \\r
order.c \\r
table.c \\r
tokenize.c \\r
update.c \\r
+ upgrade.c \\r
where.c\r
\r
RC_SRCS = msi.rc\r
/*
* 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
*/
#include <stdarg.h>
-#include <stdio.h>
#define COBJMACROS
#include "winerror.h"
#include "winreg.h"
#include "wine/debug.h"
-#include "fdi.h"
-#include "msi.h"
-#include "msiquery.h"
#include "msidefs.h"
-#include "fcntl.h"
-#include "objbase.h"
-#include "objidl.h"
#include "msipriv.h"
-#include "winnls.h"
#include "winuser.h"
#include "shlobj.h"
#include "wine/unicode.h"
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
static UINT ACTION_CreateFolders(MSIPACKAGE *package);
static UINT ACTION_CostFinalize(MSIPACKAGE *package);
static UINT ACTION_FileCost(MSIPACKAGE *package);
-static UINT ACTION_InstallFiles(MSIPACKAGE *package);
-static UINT ACTION_DuplicateFiles(MSIPACKAGE *package);
static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package);
static UINT ACTION_InstallInitialize(MSIPACKAGE *package);
static UINT ACTION_InstallValidate(MSIPACKAGE *package);
static UINT ACTION_ProcessComponents(MSIPACKAGE *package);
static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package);
-static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package);
-static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package);
-static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package);
-static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package);
static UINT ACTION_RegisterUser(MSIPACKAGE *package);
static UINT ACTION_CreateShortcuts(MSIPACKAGE *package);
static UINT ACTION_PublishProduct(MSIPACKAGE *package);
static UINT ACTION_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',
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};
{'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',
{'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[] =
'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',
{'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};
'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[] =
{ szDuplicateFiles, ACTION_DuplicateFiles },
{ szExecuteAction, ACTION_ExecuteAction },
{ szFileCost, ACTION_FileCost },
- { szFindRelatedProducts, NULL},
+ { szFindRelatedProducts, ACTION_FindRelatedProducts },
{ szForceReboot, ACTION_ForceReboot },
{ szInstallAdminPackage, NULL},
{ szInstallExecute, ACTION_InstallExecute },
};
-/********************************************************
- * 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;
-}
-
-/* Called when the package is being closed */
-void ACTION_free_package_structures( MSIPACKAGE* package)
-{
- INT i;
-
- TRACE("Freeing package action data\n");
-
- remove_tracked_tempfiles(package);
-
- /* No dynamic buffers in features */
- if (package->features && package->loaded_features > 0)
- HeapFree(GetProcessHeap(),0,package->features);
-
- for (i = 0; i < package->loaded_folders; i++)
- {
- HeapFree(GetProcessHeap(),0,package->folders[i].Directory);
- HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault);
- HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault);
- HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
- HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource);
- HeapFree(GetProcessHeap(),0,package->folders[i].Property);
- }
- if (package->folders && package->loaded_folders > 0)
- HeapFree(GetProcessHeap(),0,package->folders);
-
- for (i = 0; i < package->loaded_components; i++)
- HeapFree(GetProcessHeap(),0,package->components[i].FullKeypath);
-
- if (package->components && package->loaded_components > 0)
- HeapFree(GetProcessHeap(),0,package->components);
- for (i = 0; i < package->loaded_files; i++)
- {
- HeapFree(GetProcessHeap(),0,package->files[i].File);
- HeapFree(GetProcessHeap(),0,package->files[i].FileName);
- HeapFree(GetProcessHeap(),0,package->files[i].ShortName);
- HeapFree(GetProcessHeap(),0,package->files[i].Version);
- HeapFree(GetProcessHeap(),0,package->files[i].Language);
- HeapFree(GetProcessHeap(),0,package->files[i].SourcePath);
- HeapFree(GetProcessHeap(),0,package->files[i].TargetPath);
- }
-
- if (package->files && package->loaded_files > 0)
- HeapFree(GetProcessHeap(),0,package->files);
-
- for (i = 0; i < package->DeferredActionCount; i++)
- HeapFree(GetProcessHeap(),0,package->DeferredAction[i]);
- HeapFree(GetProcessHeap(),0,package->DeferredAction);
-
- for (i = 0; i < package->CommitActionCount; i++)
- HeapFree(GetProcessHeap(),0,package->CommitAction[i]);
- HeapFree(GetProcessHeap(),0,package->CommitAction);
-
- HeapFree(GetProcessHeap(),0,package->PackagePath);
-}
-
-static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d )
-{
- MSIRECORD * row;
-
- row = MSI_CreateRecord(4);
- MSI_RecordSetInteger(row,1,a);
- MSI_RecordSetInteger(row,2,b);
- MSI_RecordSetInteger(row,3,c);
- MSI_RecordSetInteger(row,4,d);
- MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row);
- msiobj_release(&row->hdr);
-
- msi_dialog_check_messages(NULL);
-}
-
-static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
+static void ce_actiontext(MSIPACKAGE* package, LPCWSTR action)
{
- static const WCHAR Query_t[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
- 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',
- ' ','\'','%','s','\'',0};
- WCHAR message[1024];
- UINT rc;
- MSIQUERY * view;
- MSIRECORD * row = 0;
- DWORD size;
-
- if (!package->LastAction || strcmpW(package->LastAction,action))
- {
- rc = MSI_OpenQuery(package->db, &view, Query_t, action);
- if (rc != ERROR_SUCCESS)
- return;
-
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return;
- }
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return;
- }
-
- if (MSI_RecordIsNull(row,3))
- {
- msiobj_release(&row->hdr);
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return;
- }
-
- /* update the cached actionformat */
- HeapFree(GetProcessHeap(),0,package->ActionFormat);
- package->ActionFormat = load_dynamic_stringW(row,3);
-
- HeapFree(GetProcessHeap(),0,package->LastAction);
- package->LastAction = strdupW(action);
-
- msiobj_release(&row->hdr);
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- }
-
- MSI_RecordSetStringW(record,0,package->ActionFormat);
- size = 1024;
- MSI_FormatRecordW(package,record,message,&size);
+ static const WCHAR szActionText[] =
+ {'A','c','t','i','o','n','T','e','x','t',0};
+ MSIRECORD *row;
row = MSI_CreateRecord(1);
- MSI_RecordSetStringW(row,1,message);
-
- MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
+ MSI_RecordSetStringW(row,1,action);
+ ControlEvent_FireSubscribedEvent(package,szActionText, row);
msiobj_release(&row->hdr);
}
-
static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
{
static const WCHAR template_s[]=
' ','\'','%','s','\'',0};
WCHAR message[1024];
WCHAR timet[0x100];
- UINT rc;
- MSIQUERY * view;
MSIRECORD * row = 0;
- WCHAR *ActionText=NULL;
+ LPCWSTR ActionText;
GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
- rc = MSI_OpenQuery(package->db, &view, Query_t, action);
- if (rc != ERROR_SUCCESS)
- return;
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return;
- }
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
+ row = MSI_QueryGetRecord( package->db, Query_t, action );
+ if (!row)
return;
- }
- ActionText = load_dynamic_stringW(row,2);
- msiobj_release(&row->hdr);
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
+ ActionText = MSI_RecordGetString(row,2);
sprintfW(message,template_s,timet,action,ActionText);
+ msiobj_release(&row->hdr);
row = MSI_CreateRecord(1);
MSI_RecordSetStringW(row,1,message);
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
msiobj_release(&row->hdr);
- HeapFree(GetProcessHeap(),0,ActionText);
}
static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
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
*****************************************************/
static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
MSI_SetPropertyW(package, szAction, szInstall);
- package->ExecuteSequenceRun = FALSE;
+
+ package->script = HeapAlloc(GetProcessHeap(),0,sizeof(MSISCRIPT));
+ memset(package->script,0,sizeof(MSISCRIPT));
if (szPackagePath)
{
rc = ERROR_SUCCESS;
}
+ package->script->CurrentlyScripting= FALSE;
+
/* process the ending type action */
if (rc == ERROR_SUCCESS)
ACTION_PerformActionSequence(package,-1,ui);
else if (rc == ERROR_INSTALL_USEREXIT)
ACTION_PerformActionSequence(package,-2,ui);
- else if (rc == ERROR_FUNCTION_FAILED)
- ACTION_PerformActionSequence(package,-3,ui);
else if (rc == ERROR_INSTALL_SUSPEND)
ACTION_PerformActionSequence(package,-4,ui);
+ else /* failed */
+ ACTION_PerformActionSequence(package,-3,ui);
/* finish up running custom actions */
ACTION_FinishCustomActions(package);
static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
{
- MSIQUERY * view;
- UINT rc;
- WCHAR buffer[0x100];
- DWORD sz = 0x100;
+ UINT rc = ERROR_SUCCESS;
MSIRECORD * row = 0;
static const WCHAR ExecSeqQuery[] =
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
' ', '=',' ','%','i',0};
if (UI)
- rc = MSI_OpenQuery(package->db, &view, UISeqQuery, seq);
+ row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
else
- rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
+ row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
- if (rc == ERROR_SUCCESS)
+ if (row)
{
- rc = MSI_ViewExecute(view, 0);
+ LPCWSTR action, cond;
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- goto end;
- }
-
TRACE("Running the actions\n");
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
+ /* check conditions */
+ cond = MSI_RecordGetString(row,2);
+ if (cond)
{
- rc = ERROR_SUCCESS;
- goto end;
+ /* this is a hack to skip errors in the condition code */
+ if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
+ goto end;
}
- /* check conditions */
- if (!MSI_RecordIsNull(row,2))
+ action = MSI_RecordGetString(row,1);
+ if (!action)
{
- LPWSTR cond = NULL;
- cond = load_dynamic_stringW(row,2);
-
- if (cond)
- {
- /* this is a hack to skip errors in the condition code */
- if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
- {
- HeapFree(GetProcessHeap(),0,cond);
- msiobj_release(&row->hdr);
- goto end;
- }
- else
- HeapFree(GetProcessHeap(),0,cond);
- }
- }
-
- sz=0x100;
- rc = MSI_RecordGetStringW(row,1,buffer,&sz);
- if (rc != ERROR_SUCCESS)
- {
- ERR("Error is %x\n",rc);
- msiobj_release(&row->hdr);
- goto end;
- }
+ ERR("failed to fetch action\n");
+ rc = ERROR_FUNCTION_FAILED;
+ goto end;
+ }
if (UI)
- rc = ACTION_PerformUIAction(package,buffer);
+ rc = ACTION_PerformUIAction(package,action);
else
- rc = ACTION_PerformAction(package,buffer);
- msiobj_release(&row->hdr);
+ rc = ACTION_PerformAction(package,action,FALSE);
end:
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
+ msiobj_release(&row->hdr);
+ }
+ else
+ rc = ERROR_SUCCESS;
+
+ return rc;
+}
+
+typedef struct {
+ MSIPACKAGE* package;
+ BOOL UI;
+} iterate_action_param;
+
+static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
+{
+ iterate_action_param *iap= (iterate_action_param*)param;
+ UINT rc;
+ LPCWSTR cond, action;
+
+ action = MSI_RecordGetString(row,1);
+ if (!action)
+ {
+ ERR("Error is retrieving action name\n");
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ /* check conditions */
+ cond = MSI_RecordGetString(row,2);
+ if (cond)
+ {
+ /* this is a hack to skip errors in the condition code */
+ if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
+ {
+ TRACE("Skipping action: %s (condition is false)\n",
+ debugstr_w(action));
+ return ERROR_SUCCESS;
+ }
}
+
+ if (iap->UI)
+ rc = ACTION_PerformUIAction(iap->package,action);
else
+ rc = ACTION_PerformAction(iap->package,action,FALSE);
+
+ if (rc == ERROR_FUNCTION_NOT_CALLED)
rc = ERROR_SUCCESS;
+ if (rc != ERROR_SUCCESS)
+ ERR("Execution halted due to error (%i)\n",rc);
+
return rc;
}
' ','\'', 'I','n','s','t','a','l','l',
'V','a','l','i','d','a','t','e','\'', 0};
INT seq = 0;
+ iterate_action_param iap;
+ iap.package = package;
+ iap.UI = FALSE;
- if (package->ExecuteSequenceRun)
+ if (package->script->ExecuteSequenceRun)
{
TRACE("Execute Sequence already Run\n");
return ERROR_SUCCESS;
}
- package->ExecuteSequenceRun = TRUE;
-
+ package->script->ExecuteSequenceRun = TRUE;
+
/* get the sequence number */
if (UIran)
{
- rc = MSI_DatabaseOpenViewW(package->db, IVQuery, &view);
- if (rc != ERROR_SUCCESS)
- return rc;
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
+ row = MSI_QueryGetRecord(package->db, IVQuery);
+ if( !row )
+ return ERROR_FUNCTION_FAILED;
seq = MSI_RecordGetInteger(row,1);
msiobj_release(&row->hdr);
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
}
rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
if (rc == ERROR_SUCCESS)
{
- rc = MSI_ViewExecute(view, 0);
-
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- goto end;
- }
-
- TRACE("Running the actions\n");
-
- while (1)
- {
- WCHAR buffer[0x100];
- DWORD sz = 0x100;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- /* check conditions */
- if (!MSI_RecordIsNull(row,2))
- {
- LPWSTR cond = NULL;
- cond = load_dynamic_stringW(row,2);
-
- if (cond)
- {
- /* this is a hack to skip errors in the condition code */
- if (MSI_EvaluateConditionW(package, cond) ==
- MSICONDITION_FALSE)
- {
- HeapFree(GetProcessHeap(),0,cond);
- msiobj_release(&row->hdr);
- continue;
- }
- else
- HeapFree(GetProcessHeap(),0,cond);
- }
- }
-
- sz=0x100;
- rc = MSI_RecordGetStringW(row,1,buffer,&sz);
- if (rc != ERROR_SUCCESS)
- {
- ERR("Error is %x\n",rc);
- msiobj_release(&row->hdr);
- break;
- }
-
- rc = ACTION_PerformAction(package,buffer);
-
- if (rc == ERROR_FUNCTION_NOT_CALLED)
- rc = ERROR_SUCCESS;
-
- if (rc != ERROR_SUCCESS)
- {
- ERR("Execution halted due to error (%i)\n",rc);
- msiobj_release(&row->hdr);
- break;
- }
-
- msiobj_release(&row->hdr);
- }
+ TRACE("Running the actions\n");
- 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;
'`','S','e','q','u','e','n','c','e','`',' ',
'>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
'`','S','e','q','u','e','n','c','e','`',0};
-
+ iterate_action_param iap;
+
+ iap.package = package;
+ iap.UI = TRUE;
+
rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
if (rc == ERROR_SUCCESS)
{
- rc = MSI_ViewExecute(view, 0);
-
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- goto end;
- }
-
TRACE("Running the actions \n");
- while (1)
- {
- WCHAR buffer[0x100];
- DWORD sz = 0x100;
- MSIRECORD * row = 0;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- /* check conditions */
- if (!MSI_RecordIsNull(row,2))
- {
- LPWSTR cond = NULL;
- cond = load_dynamic_stringW(row,2);
-
- if (cond)
- {
- /* this is a hack to skip errors in the condition code */
- if (MSI_EvaluateConditionW(package, cond) ==
- MSICONDITION_FALSE)
- {
- HeapFree(GetProcessHeap(),0,cond);
- msiobj_release(&row->hdr);
- continue;
- }
- else
- HeapFree(GetProcessHeap(),0,cond);
- }
- }
-
- sz=0x100;
- rc = MSI_RecordGetStringW(row,1,buffer,&sz);
- if (rc != ERROR_SUCCESS)
- {
- ERR("Error is %x\n",rc);
- msiobj_release(&row->hdr);
- break;
- }
-
- rc = ACTION_PerformUIAction(package,buffer);
-
- if (rc == ERROR_FUNCTION_NOT_CALLED)
- rc = ERROR_SUCCESS;
-
- if (rc != ERROR_SUCCESS)
- {
- ERR("Execution halted due to error (%i)\n",rc);
- msiobj_release(&row->hdr);
- break;
- }
-
- msiobj_release(&row->hdr);
- }
-
- MSI_ViewClose(view);
+ rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
msiobj_release(&view->hdr);
}
-end:
return rc;
}
/********************************************************
* ACTION helper functions and functions that perform the actions
*******************************************************/
-BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, UINT* rc)
+static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action,
+ UINT* rc, BOOL force )
{
BOOL ret = FALSE;
-
+ BOOL run = force;
int i;
+
+ if (!run && !package->script->CurrentlyScripting)
+ run = TRUE;
+
+ if (!run)
+ {
+ if (strcmpW(action,szInstallFinalize) == 0 ||
+ strcmpW(action,szInstallExecute) == 0 ||
+ strcmpW(action,szInstallExecuteAgain) == 0)
+ run = TRUE;
+ }
+
i = 0;
while (StandardActions[i].action != NULL)
{
if (strcmpW(StandardActions[i].action, action)==0)
{
- ui_actioninfo(package, action, TRUE, 0);
- ui_actionstart(package, action);
- if (StandardActions[i].handler)
+ ce_actiontext(package, action);
+ if (!run)
{
- *rc = StandardActions[i].handler(package);
+ ui_actioninfo(package, action, TRUE, 0);
+ *rc = schedule_action(package,INSTALL_SCRIPT,action);
+ ui_actioninfo(package, action, FALSE, *rc);
}
else
{
- FIXME("UNHANDLED Standard Action %s\n",debugstr_w(action));
- *rc = ERROR_SUCCESS;
+ ui_actionstart(package, action);
+ if (StandardActions[i].handler)
+ {
+ *rc = StandardActions[i].handler(package);
+ }
+ else
+ {
+ FIXME("UNHANDLED Standard Action %s\n",debugstr_w(action));
+ *rc = ERROR_SUCCESS;
+ }
}
- ui_actioninfo(package, action, FALSE, *rc);
ret = TRUE;
break;
}
return ret;
}
-BOOL ACTION_HandleDialogBox(MSIPACKAGE *package, LPCWSTR dialog, UINT* rc)
+static BOOL ACTION_HandleDialogBox( MSIPACKAGE *package, LPCWSTR dialog, UINT* rc )
{
BOOL ret = FALSE;
- /*
- * for the UI when we get that working
- *
if (ACTION_DialogBox(package,dialog) == ERROR_SUCCESS)
{
*rc = package->CurrentInstallState;
ret = TRUE;
}
- */
return ret;
}
-BOOL ACTION_HandleCustomAction(MSIPACKAGE* package, LPCWSTR action, UINT* rc)
+static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
+ UINT* rc, BOOL force )
{
BOOL ret=FALSE;
UINT arc;
- arc = ACTION_CustomAction(package,action,FALSE);
+ arc = ACTION_CustomAction(package,action, force);
if (arc != ERROR_CALL_NOT_IMPLEMENTED)
{
* But until I get write access to the database that is hard, so I am going to
* hack it to see if I can get something to run.
*/
-UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action)
+UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
{
UINT rc = ERROR_SUCCESS;
BOOL handled;
TRACE("Performing action (%s)\n",debugstr_w(action));
- handled = ACTION_HandleStandardAction(package, action, &rc);
+ handled = ACTION_HandleStandardAction(package, action, &rc, force);
if (!handled)
- handled = ACTION_HandleCustomAction(package, action, &rc);
+ handled = ACTION_HandleCustomAction(package, action, &rc, force);
if (!handled)
{
TRACE("Performing action (%s)\n",debugstr_w(action));
- handled = ACTION_HandleStandardAction(package, action, &rc);
+ handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
if (!handled)
- handled = ACTION_HandleCustomAction(package, action, &rc);
+ handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
if (!handled)
handled = ACTION_HandleDialogBox(package, action, &rc);
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.
'`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
UINT rc;
MSIQUERY *view;
- MSIFOLDER *folder;
rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
-
- while (1)
- {
- WCHAR dir[0x100];
- LPWSTR full_path;
- DWORD sz;
- MSIRECORD *row = NULL, *uirow;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- sz=0x100;
- rc = MSI_RecordGetStringW(row,1,dir,&sz);
-
- if (rc!= ERROR_SUCCESS)
- {
- ERR("Unable to get folder id \n");
- msiobj_release(&row->hdr);
- continue;
- }
-
- sz = MAX_PATH;
- full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
- if (!full_path)
- {
- ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
- msiobj_release(&row->hdr);
- continue;
- }
-
- TRACE("Folder is %s\n",debugstr_w(full_path));
-
- /* UI stuff */
- uirow = MSI_CreateRecord(1);
- MSI_RecordSetStringW(uirow,1,full_path);
- ui_actiondata(package,szCreateFolders,uirow);
- msiobj_release( &uirow->hdr );
-
- if (folder->State == 0)
- create_full_pathW(full_path);
-
- folder->State = 3;
-
- msiobj_release(&row->hdr);
- HeapFree(GetProcessHeap(),0,full_path);
- }
- MSI_ViewClose(view);
+ rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
msiobj_release(&view->hdr);
return rc;
memset(&package->components[index],0,sizeof(MSICOMPONENT));
- sz = 96;
+ sz = IDENTIFIER_SIZE;
MSI_RecordGetStringW(row,1,package->components[index].Component,&sz);
TRACE("Loading Component %s\n",
if (!MSI_RecordIsNull(row,2))
MSI_RecordGetStringW(row,2,package->components[index].ComponentId,&sz);
- sz = 96;
+ sz = IDENTIFIER_SIZE;
MSI_RecordGetStringW(row,3,package->components[index].Directory,&sz);
package->components[index].Attributes = MSI_RecordGetInteger(row,4);
sz = 0x100;
MSI_RecordGetStringW(row,5,package->components[index].Condition,&sz);
- sz = 96;
+ sz = IDENTIFIER_SIZE;
MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz);
package->components[index].Installed = INSTALLSTATE_ABSENT;
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[] =
'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 */
memset(&package->features[index],0,sizeof(MSIFEATURE));
- sz = 96;
+ sz = IDENTIFIER_SIZE;
MSI_RecordGetStringW(row,1,package->features[index].Feature,&sz);
TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature));
- sz = 96;
+ sz = IDENTIFIER_SIZE;
if (!MSI_RecordIsNull(row,2))
MSI_RecordGetStringW(row,2,package->features[index].Feature_Parent,&sz);
package->features[index].Level= MSI_RecordGetInteger(row,6);
- sz = 96;
+ sz = IDENTIFIER_SIZE;
if (!MSI_RecordIsNull(row,7))
MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz);
/* 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)
- {
- DWORD sz = 0x100;
- WCHAR buffer[0x100];
- DWORD rc;
- INT c_indx;
- INT cnt = package->features[index].ComponentCount;
-
- rc = MSI_ViewFetch(view,&row2);
- if (rc != ERROR_SUCCESS)
- break;
+ return ERROR_SUCCESS;
- sz = 0x100;
- MSI_RecordGetStringW(row2,1,buffer,&sz);
+ MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
+ msiobj_release(&view->hdr);
- /* check to see if the component is already loaded */
- c_indx = get_loaded_component(package,buffer);
- if (c_indx != -1)
- {
- TRACE("Component %s already loaded at %i\n", debugstr_w(buffer),
- c_indx);
- package->features[index].Components[cnt] = c_indx;
- package->features[index].ComponentCount ++;
- msiobj_release( &row2->hdr );
- continue;
- }
-
- rc = MSI_OpenQuery(package->db, &view2, Query2, buffer);
- if (rc != ERROR_SUCCESS)
- {
- msiobj_release( &row2->hdr );
- continue;
- }
- rc = MSI_ViewExecute(view2,0);
- if (rc != ERROR_SUCCESS)
- {
- msiobj_release( &row2->hdr );
- MSI_ViewClose(view2);
- msiobj_release( &view2->hdr );
- continue;
- }
- while (1)
- {
- DWORD rc;
-
- rc = MSI_ViewFetch(view2,&row3);
- if (rc != ERROR_SUCCESS)
- break;
- c_indx = load_component(package,row3);
- msiobj_release( &row3->hdr );
-
- package->features[index].Components[cnt] = c_indx;
- package->features[index].ComponentCount ++;
- TRACE("Loaded new component to index %i\n",c_indx);
- }
- MSI_ViewClose(view2);
- msiobj_release( &view2->hdr );
- msiobj_release( &row2->hdr );
- }
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
+ return ERROR_SUCCESS;
}
-static UINT load_file(MSIPACKAGE* package, MSIRECORD * row)
+static UINT load_file(MSIRECORD *row, LPVOID param)
{
+ MSIPACKAGE* package = (MSIPACKAGE*)param;
DWORD index = package->loaded_files;
- DWORD i;
- LPWSTR buffer;
+ LPCWSTR component;
/* fill in the data */
memset(&package->files[index],0,sizeof(MSIFILE));
package->files[index].File = load_dynamic_stringW(row, 1);
- buffer = load_dynamic_stringW(row, 2);
- package->files[index].ComponentIndex = -1;
- for (i = 0; i < package->loaded_components; i++)
- if (strcmpW(package->components[i].Component,buffer)==0)
- {
- package->files[index].ComponentIndex = i;
- break;
- }
+ component = MSI_RecordGetString(row, 2);
+ package->files[index].ComponentIndex = get_loaded_component(package,
+ component);
+
if (package->files[index].ComponentIndex == -1)
- ERR("Unfound Component %s\n",debugstr_w(buffer));
- HeapFree(GetProcessHeap(), 0, buffer);
+ ERR("Unfound Component %s\n",debugstr_w(component));
package->files[index].FileName = load_dynamic_stringW(row,3);
reduce_to_longfilename(package->files[index].FileName);
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',' ',
rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
-
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return ERROR_SUCCESS;
- }
- while (1)
- {
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
- load_file(package,row);
- msiobj_release(&row->hdr);
- }
- MSI_ViewClose(view);
+ rc = MSI_IterateRecords(view, NULL, load_file, package);
msiobj_release(&view->hdr);
return ERROR_SUCCESS;
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',' ',
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);
return ERROR_SUCCESS;
}
+static UINT execute_script(MSIPACKAGE *package, UINT script )
+{
+ int i;
+ UINT rc = ERROR_SUCCESS;
+
+ TRACE("Executing Script %i\n",script);
+
+ for (i = 0; i < package->script->ActionCount[script]; i++)
+ {
+ LPWSTR action;
+ action = package->script->Actions[script][i];
+ ui_actionstart(package, action);
+ TRACE("Executing Action (%s)\n",debugstr_w(action));
+ rc = ACTION_PerformAction(package, action, TRUE);
+ HeapFree(GetProcessHeap(),0,package->script->Actions[script][i]);
+ if (rc != ERROR_SUCCESS)
+ break;
+ }
+ HeapFree(GetProcessHeap(),0,package->script->Actions[script]);
+
+ package->script->ActionCount[script] = 0;
+ package->script->Actions[script] = NULL;
+ return rc;
+}
+
static UINT ACTION_FileCost(MSIPACKAGE *package)
{
return ERROR_SUCCESS;
'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
' ','=',' ','\'','%','s','\'',
0};
- UINT rc;
- MSIQUERY * view;
- LPWSTR ptargetdir, targetdir, parent, srcdir;
+ LPWSTR ptargetdir, targetdir, srcdir;
+ LPCWSTR parent;
LPWSTR shortname = NULL;
MSIRECORD * row = 0;
INT index = -1;
package->folders[index].Directory = strdupW(dir);
- rc = MSI_OpenQuery(package->db, &view, Query, dir);
- if (rc != ERROR_SUCCESS)
- return -1;
-
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return -1;
- }
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
+ row = MSI_QueryGetRecord(package->db, Query, dir);
+ if (!row)
return -1;
- }
ptargetdir = targetdir = load_dynamic_stringW(row,3);
HeapFree(GetProcessHeap(), 0, ptargetdir);
TRACE(" SourceDefault = %s\n",debugstr_w(package->folders[index].SourceDefault));
- parent = load_dynamic_stringW(row,2);
+ parent = MSI_RecordGetString(row,2);
if (parent)
{
i = load_folder(package,parent);
}
else
package->folders[index].ParentIndex = -2;
- HeapFree(GetProcessHeap(), 0, parent);
package->folders[index].Property = load_dynamic_property(package, dir,NULL);
msiobj_release(&row->hdr);
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
TRACE(" %s retuning on index %i\n",debugstr_w(dir),index);
return index;
}
-
-LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
- BOOL set_prop, MSIFOLDER **folder)
-{
- DWORD i;
- LPWSTR p, path = NULL;
-
- TRACE("Working to resolve %s\n",debugstr_w(name));
-
- /* special resolving for Target and Source root dir */
- if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
- {
- if (!source)
- {
- path = load_dynamic_property(package,cszTargetDir,NULL);
- if (!path)
- {
- path = load_dynamic_property(package,cszRootDrive,NULL);
- if (set_prop)
- MSI_SetPropertyW(package,cszTargetDir,path);
- }
- if (folder)
- {
- for (i = 0; i < package->loaded_folders; i++)
- {
- if (strcmpW(package->folders[i].Directory,name)==0)
- break;
- }
- *folder = &(package->folders[i]);
- }
- return path;
- }
- else
- {
- path = load_dynamic_property(package,cszSourceDir,NULL);
- if (!path)
- {
- path = load_dynamic_property(package,cszDatabase,NULL);
- if (path)
- {
- p = strrchrW(path,'\\');
- if (p)
- *(p+1) = 0;
- }
- }
- if (folder)
- {
- for (i = 0; i < package->loaded_folders; i++)
- {
- if (strcmpW(package->folders[i].Directory,name)==0)
- break;
- }
- *folder = &(package->folders[i]);
- }
- return path;
- }
- }
-
- for (i = 0; i < package->loaded_folders; i++)
- {
- if (strcmpW(package->folders[i].Directory,name)==0)
- break;
- }
-
- if (i >= package->loaded_folders)
- return NULL;
-
- if (folder)
- *folder = &(package->folders[i]);
-
- if (!source && package->folders[i].ResolvedTarget)
- {
- path = strdupW(package->folders[i].ResolvedTarget);
- TRACE(" already resolved to %s\n",debugstr_w(path));
- return path;
- }
- else if (source && package->folders[i].ResolvedSource)
- {
- path = strdupW(package->folders[i].ResolvedSource);
- TRACE(" (source)already resolved to %s\n",debugstr_w(path));
- return path;
- }
- else if (!source && package->folders[i].Property)
- {
- path = build_directory_name(2, package->folders[i].Property, NULL);
-
- TRACE(" internally set to %s\n",debugstr_w(path));
- if (set_prop)
- MSI_SetPropertyW(package,name,path);
- return path;
- }
-
- if (package->folders[i].ParentIndex >= 0)
- {
- LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory;
-
- TRACE(" ! Parent is %s\n", debugstr_w(parent));
-
- p = resolve_folder(package, parent, source, set_prop, NULL);
- if (!source)
- {
- TRACE(" TargetDefault = %s\n",debugstr_w(package->folders[i].TargetDefault));
- path = build_directory_name(3, p, package->folders[i].TargetDefault, NULL);
- package->folders[i].ResolvedTarget = strdupW(path);
- TRACE(" resolved into %s\n",debugstr_w(path));
- if (set_prop)
- MSI_SetPropertyW(package,name,path);
- }
- else
- {
- path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL);
- TRACE(" (source)resolved into %s\n",debugstr_w(path));
- package->folders[i].ResolvedSource = strdupW(path);
- }
- HeapFree(GetProcessHeap(),0,p);
- }
- return path;
-}
-
/* scan for and update current install states */
-void ACTION_UpdateInstallStates(MSIPACKAGE *package)
+static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
{
int i;
LPWSTR productcode;
}
}
-/* 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)
{
}
}
}
+ else
+ {
+ /* set the Preselected Property */
+ static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
+ static const WCHAR szOne[] = { '1', 0 };
+
+ MSI_SetPropertyW(package,szPreselected,szOne);
+ }
/*
* now we want to enable or disable components base on feature
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
rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
if (rc == ERROR_SUCCESS)
{
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
-
- while (1)
- {
- WCHAR name[0x100];
- LPWSTR path;
- MSIRECORD * row = 0;
- DWORD sz;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- sz=0x100;
- MSI_RecordGetStringW(row,1,name,&sz);
-
- /* This helper function now does ALL the work */
- TRACE("Dir %s ...\n",debugstr_w(name));
- load_folder(package,name);
- path = resolve_folder(package,name,FALSE,TRUE,NULL);
- TRACE("resolves to %s\n",debugstr_w(path));
- HeapFree( GetProcessHeap(), 0, path);
-
- msiobj_release(&row->hdr);
- }
- MSI_ViewClose(view);
+ rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
+ package);
msiobj_release(&view->hdr);
}
rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
if (rc == ERROR_SUCCESS)
{
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
-
- while (1)
- {
- WCHAR Feature[0x100];
- MSIRECORD * row = 0;
- DWORD sz;
- int feature_index;
-
- rc = MSI_ViewFetch(view,&row);
-
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- sz = 0x100;
- MSI_RecordGetStringW(row,1,Feature,&sz);
-
- feature_index = get_loaded_feature(package,Feature);
- if (feature_index < 0)
- ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature));
- else
- {
- LPWSTR Condition;
- Condition = load_dynamic_stringW(row,3);
-
- if (MSI_EvaluateConditionW(package,Condition) ==
- MSICONDITION_TRUE)
- {
- int level = MSI_RecordGetInteger(row,2);
- TRACE("Reseting feature %s to level %i\n",
- debugstr_w(Feature), level);
- package->features[feature_index].Level = level;
- }
- HeapFree(GetProcessHeap(),0,Condition);
- }
-
- msiobj_release(&row->hdr);
- }
- MSI_ViewClose(view);
+ rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
+ package);
msiobj_release(&view->hdr);
}
return SetFeatureStates(package);
}
-/*
- * This is a helper function for handling embedded cabinet media
- */
-static UINT writeout_cabinet_stream(MSIPACKAGE *package, WCHAR* stream_name,
- WCHAR* source)
+/* 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;
- }
+ if (value[1]=='x')
+ {
+ LPWSTR ptr;
+ CHAR byte[5];
+ LPWSTR deformated = NULL;
+ int count;
- 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;
-}
+ deformat_string(package, &value[2], &deformated);
+ /* binary value type */
+ ptr = deformated;
+ *type = REG_BINARY;
+ if (strlenW(ptr)%2)
+ *size = (strlenW(ptr)/2)+1;
+ else
+ *size = strlenW(ptr)/2;
-/* Support functions for FDI functions */
-typedef struct
-{
- MSIPACKAGE* package;
- LPCSTR cab_path;
- LPCSTR file_name;
-} CabData;
+ data = HeapAlloc(GetProcessHeap(),0,*size);
-static void * cabinet_alloc(ULONG cb)
-{
- return HeapAlloc(GetProcessHeap(), 0, cb);
-}
+ 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 void cabinet_free(void *pv)
-{
- HeapFree(GetProcessHeap(), 0, pv);
-}
+ TRACE("Data %li bytes(%i)\n",*size,count);
+ }
+ else
+ {
+ LPWSTR deformated;
+ LPWSTR p;
+ DWORD d = 0;
+ deformat_string(package, &value[1], &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);
-}
+ *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 UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)
-{
- DWORD dwRead;
- if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL))
- return dwRead;
- return 0;
-}
+ HeapFree(GetProcessHeap(),0,deformated);
+ }
+ }
+ else
+ {
+ static const WCHAR szMulti[] = {'[','~',']',0};
+ LPCWSTR ptr;
+ *type=REG_SZ;
-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;
-}
+ if (value[0]=='#')
+ {
+ if (value[1]=='%')
+ {
+ ptr = &value[2];
+ *type=REG_EXPAND_SZ;
+ }
+ else
+ ptr = &value[1];
+ }
+ else
+ ptr=value;
-static int cabinet_close(INT_PTR hf)
-{
- return CloseHandle((HANDLE)hf) ? 0 : -1;
-}
+ if (strstrW(value,szMulti))
+ *type = REG_MULTI_SZ;
-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);
+ *size = deformat_string(package, ptr,(LPWSTR*)&data);
+ }
+ return data;
}
-static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
+static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
{
- /* 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);
+ MSIPACKAGE *package = (MSIPACKAGE*)param;
+ static const WCHAR szHCR[] =
+ {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
+ 'R','O','O','T','\\',0};
+ static const WCHAR szHCU[] =
+ {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
+ 'U','S','E','R','\\',0};
+ static const WCHAR szHLM[] =
+ {'H','K','E','Y','_','L','O','C','A','L','_',
+ 'M','A','C','H','I','N','E','\\',0};
+ static const WCHAR szHU[] =
+ {'H','K','E','Y','_','U','S','E','R','S','\\',0};
+
+ LPSTR value_data = NULL;
+ HKEY root_key, hkey;
+ DWORD type,size;
+ LPWSTR deformated;
+ LPCWSTR szRoot, component, name, key, value;
+ INT component_index;
+ MSIRECORD * uirow;
+ LPWSTR uikey;
+ INT root;
+ BOOL check_first = FALSE;
+ UINT rc;
- TRACE("file: %s\n", debugstr_a(file));
+ ui_progress(package,2,0,0,0);
- /* 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));
+ value = NULL;
+ key = NULL;
+ uikey = NULL;
+ name = NULL;
- strcpyW(trackname,tmpprefix);
- strcatW(trackname,tracknametmp);
+ component = MSI_RecordGetString(row, 6);
+ component_index = get_loaded_component(package,component);
- track_tempfile(data->package, trackname, trackpath);
+ if (!ACTION_VerifyComponentForAction(package, component_index,
+ INSTALLSTATE_LOCAL))
+ {
+ TRACE("Skipping write due to disabled component %s\n",
+ debugstr_w(component));
- HeapFree(GetProcessHeap(),0,trackpath);
- HeapFree(GetProcessHeap(),0,trackname);
- HeapFree(GetProcessHeap(),0,tracknametmp);
+ package->components[component_index].Action =
+ package->components[component_index].Installed;
- 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;
+ return ERROR_SUCCESS;
}
-}
-/***********************************************************************
- * 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;
- }
+ package->components[component_index].Action = INSTALLSTATE_LOCAL;
- if (!(cabinet = strdupWtoA( source )))
- {
- FDIDestroy(hfdi);
- return FALSE;
- }
- if (!(cab_path = strdupWtoA( path )))
+ name = MSI_RecordGetString(row, 4);
+ if( MSI_RecordIsNull(row,5) && name )
{
- FDIDestroy(hfdi);
- HeapFree(GetProcessHeap(), 0, cabinet);
- return FALSE;
+ /* 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;
}
- 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");
+ root = MSI_RecordGetInteger(row,2);
+ key = MSI_RecordGetString(row, 3);
- FDIDestroy(hfdi);
-
- HeapFree(GetProcessHeap(), 0, cabinet);
- HeapFree(GetProcessHeap(), 0, cab_path);
- HeapFree(GetProcessHeap(), 0, file_name);
+ /* get the root key */
+ switch (root)
+ {
+ case -1:
+ {
+ static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
+ LPWSTR all_users = load_dynamic_property(package, szALLUSER, NULL);
+ if (all_users && all_users[0] == '1')
+ {
+ root_key = HKEY_LOCAL_MACHINE;
+ szRoot = szHLM;
+ }
+ else
+ {
+ root_key = HKEY_CURRENT_USER;
+ szRoot = szHCU;
+ }
+ HeapFree(GetProcessHeap(),0,all_users);
+ }
+ break;
+ case 0: root_key = HKEY_CLASSES_ROOT;
+ szRoot = szHCR;
+ break;
+ case 1: root_key = HKEY_CURRENT_USER;
+ szRoot = szHCU;
+ break;
+ case 2: root_key = HKEY_LOCAL_MACHINE;
+ szRoot = szHLM;
+ break;
+ case 3: root_key = HKEY_USERS;
+ szRoot = szHU;
+ break;
+ default:
+ ERR("Unknown root %i\n",root);
+ root_key=NULL;
+ szRoot = NULL;
+ break;
+ }
+ if (!root_key)
+ return ERROR_SUCCESS;
- return ret;
-}
+ deformat_string(package, key , &deformated);
+ size = strlenW(deformated) + strlenW(szRoot) + 1;
+ uikey = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
+ strcpyW(uikey,szRoot);
+ strcatW(uikey,deformated);
-static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path,
- MSIFILE* file)
-{
- UINT rc;
- MSIQUERY * view;
- MSIRECORD * row = 0;
- static WCHAR source[MAX_PATH];
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
- '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
- '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',
- ' ','%', 'i',' ','O','R','D','E','R',' ','B','Y',' ',
- '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0};
- WCHAR Query[1024];
- WCHAR cab[0x100];
- DWORD sz=0x100;
- INT seq;
- static UINT last_sequence = 0;
-
- if (file->Attributes & msidbFileAttributesNoncompressed)
+ if (RegCreateKeyW( root_key, deformated, &hkey))
{
- TRACE("Uncompressed File, no media to ready.\n");
+ 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);
- if (file->Sequence <= last_sequence)
+ value = MSI_RecordGetString(row,5);
+ if (value)
+ value_data = parse_value(package, value, &type, &size);
+ else
{
- TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence);
- /*extract_a_cabinet_file(package, source,path,file->File); */
- return ERROR_SUCCESS;
+ static const WCHAR szEmpty[] = {0};
+ value_data = (LPSTR)strdupW(szEmpty);
+ size = 0;
+ type = REG_SZ;
}
- sprintfW(Query,ExecSeqQuery,file->Sequence);
-
- rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
- if (rc != ERROR_SUCCESS)
- return rc;
+ deformat_string(package, name, &deformated);
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
+ /* get the double nulls to terminate SZ_MULTI */
+ if (type == REG_MULTI_SZ)
+ size +=sizeof(WCHAR);
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
+ if (!check_first)
{
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
+ TRACE("Setting value %s of %s\n",debugstr_w(deformated),
+ debugstr_w(uikey));
+ RegSetValueExW(hkey, deformated, 0, type, value_data, size);
}
- seq = MSI_RecordGetInteger(row,2);
- last_sequence = seq;
-
- if (!MSI_RecordIsNull(row,4))
+ else
{
- sz=0x100;
- MSI_RecordGetStringW(row,4,cab,&sz);
- TRACE("Source is CAB %s\n",debugstr_w(cab));
- /* the stream does not contain the # character */
- if (cab[0]=='#')
+ DWORD sz = 0;
+ rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
+ if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
{
- writeout_cabinet_stream(package,&cab[1],source);
- strcpyW(path,source);
- *(strrchrW(path,'\\')+1)=0;
+ TRACE("value %s of %s checked already exists\n",
+ debugstr_w(deformated), debugstr_w(uikey));
}
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);
- }
+ 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 = !extract_a_cabinet_file(package, source,path,NULL);
- }
- else
- {
- sz = MAX_PATH;
- MSI_GetPropertyW(package,cszSourceDir,source,&sz);
- strcpyW(path,source);
}
- msiobj_release(&row->hdr);
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
-}
+ RegCloseKey(hkey);
-inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)
-{
- UINT rc = ERROR_SUCCESS;
- MSIFOLDER *folder;
- LPWSTR install_path;
+ uirow = MSI_CreateRecord(3);
+ MSI_RecordSetStringW(uirow,2,deformated);
+ MSI_RecordSetStringW(uirow,1,uikey);
+
+ if (type == REG_SZ)
+ MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
+ else
+ MSI_RecordSetStringW(uirow,3,value);
- install_path = resolve_folder(package, package->components[component].Directory,
- FALSE, FALSE, &folder);
- if (!install_path)
- return ERROR_FUNCTION_FAILED;
+ ui_actiondata(package,szWriteRegistryValues,uirow);
+ msiobj_release( &uirow->hdr );
- /* create the path */
- if (folder->State == 0)
- {
- create_full_pathW(install_path);
- folder->State = 2;
- }
- HeapFree(GetProcessHeap(), 0, install_path);
+ HeapFree(GetProcessHeap(),0,value_data);
+ HeapFree(GetProcessHeap(),0,deformated);
+ HeapFree(GetProcessHeap(),0,uikey);
- return rc;
+ return ERROR_SUCCESS;
}
-static UINT ACTION_InstallFiles(MSIPACKAGE *package)
+static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
{
- UINT rc = ERROR_SUCCESS;
- DWORD index;
- MSIRECORD * uirow;
- WCHAR uipath[MAX_PATH];
+ 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 };
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];
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return ERROR_SUCCESS;
- if (file->Temporary)
- continue;
+ /* increment progress bar each time action data is sent */
+ ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
+ rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
- 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));
+ msiobj_release(&view->hdr);
+ return rc;
+}
- continue;
- }
+static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
+{
+ package->script->CurrentlyScripting = TRUE;
- 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;
- }
+ return ERROR_SUCCESS;
+}
- create_component_directory( package, file->ComponentIndex);
- /* recalculate file paths because things may have changed */
-
- if (file->ComponentIndex >= 0)
- comp = &package->components[file->ComponentIndex];
-
- p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
- HeapFree(GetProcessHeap(),0,file->TargetPath);
-
- file->TargetPath = build_directory_name(2, p, file->FileName);
- HeapFree(GetProcessHeap(),0,p);
-
- if (file->Attributes & msidbFileAttributesNoncompressed)
- {
- p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
- file->SourcePath = build_directory_name(2, p, file->ShortName);
- HeapFree(GetProcessHeap(),0,p);
- }
- else
- file->SourcePath = build_directory_name(2, path_to_source,
- file->File);
-
-
- TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
- debugstr_w(file->TargetPath));
-
- /* the UI chunk */
- uirow=MSI_CreateRecord(9);
- MSI_RecordSetStringW(uirow,1,file->File);
- strcpyW(uipath,file->TargetPath);
- *(strrchrW(uipath,'\\')+1)=0;
- MSI_RecordSetStringW(uirow,9,uipath);
- MSI_RecordSetInteger(uirow,6,file->FileSize);
- ui_actiondata(package,szInstallFiles,uirow);
- msiobj_release( &uirow->hdr );
- ui_progress(package,2,file->FileSize,0,0);
-
-
- if (file->Attributes & msidbFileAttributesNoncompressed)
- rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
- else
- rc = MoveFileW(file->SourcePath, file->TargetPath);
-
- if (!rc)
- {
- rc = GetLastError();
- ERR("Unable to move/copy file (%s -> %s) (error %d)\n",
- debugstr_w(file->SourcePath), debugstr_w(file->TargetPath),
- rc);
- if (rc == ERROR_ALREADY_EXISTS && file->State == 2)
- {
- if (!CopyFileW(file->SourcePath,file->TargetPath,FALSE))
- ERR("Unable to copy file (%s -> %s) (error %ld)\n",
- debugstr_w(file->SourcePath),
- debugstr_w(file->TargetPath), GetLastError());
- if (!(file->Attributes & msidbFileAttributesNoncompressed))
- DeleteFileW(file->SourcePath);
- rc = 0;
- }
- else if (rc == ERROR_FILE_NOT_FOUND)
- {
- ERR("Source File Not Found! Continuing\n");
- rc = 0;
- }
- else if (file->Attributes & msidbFileAttributesVital)
- {
- ERR("Ignoring Error and continuing (nonvital file)...\n");
- rc = 0;
- }
- }
- else
- {
- file->State = 4;
- rc = ERROR_SUCCESS;
- }
- }
- }
-
- return rc;
-}
-
-inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
- LPWSTR* file_source)
-{
- DWORD index;
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- for (index = 0; index < package->loaded_files; index ++)
- {
- if (strcmpW(file_key,package->files[index].File)==0)
- {
- if (package->files[index].State >= 2)
- {
- *file_source = strdupW(package->files[index].TargetPath);
- return ERROR_SUCCESS;
- }
- else
- return ERROR_FILE_NOT_FOUND;
- }
- }
-
- return ERROR_FUNCTION_FAILED;
-}
-
-static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
+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;
msiobj_release(&view->hdr);
return rc;
}
-
while (1)
{
- WCHAR file_key[0x100];
- WCHAR *file_source = NULL;
- WCHAR dest_name[0x100];
- LPWSTR dest_path, dest;
- WCHAR component[0x100];
- INT component_index;
-
- DWORD sz=0x100;
-
rc = MSI_ViewFetch(view,&row);
if (rc != ERROR_SUCCESS)
{
rc = ERROR_SUCCESS;
break;
}
+ progress +=1;
- sz=0x100;
- rc = MSI_RecordGetStringW(row,2,component,&sz);
- if (rc != ERROR_SUCCESS)
- {
- ERR("Unable to get component\n");
- msiobj_release(&row->hdr);
- break;
- }
-
- component_index = get_loaded_component(package,component);
-
- if (!ACTION_VerifyComponentForAction(package, component_index,
- INSTALLSTATE_LOCAL))
- {
- TRACE("Skipping copy due to disabled component\n");
-
- /* the action taken was the same as the current install state */
- package->components[component_index].Action =
- package->components[component_index].Installed;
-
- msiobj_release(&row->hdr);
- continue;
- }
-
- package->components[component_index].Action = INSTALLSTATE_LOCAL;
-
- sz=0x100;
- rc = MSI_RecordGetStringW(row,3,file_key,&sz);
- if (rc != ERROR_SUCCESS)
- {
- ERR("Unable to get file key\n");
- msiobj_release(&row->hdr);
- break;
- }
-
- rc = get_file_target(package,file_key,&file_source);
-
- if (rc != ERROR_SUCCESS)
- {
- ERR("Original file unknown %s\n",debugstr_w(file_key));
- msiobj_release(&row->hdr);
- HeapFree(GetProcessHeap(),0,file_source);
- continue;
- }
-
- if (MSI_RecordIsNull(row,4))
- {
- strcpyW(dest_name,strrchrW(file_source,'\\')+1);
- }
- else
- {
- sz=0x100;
- MSI_RecordGetStringW(row,4,dest_name,&sz);
- reduce_to_longfilename(dest_name);
- }
-
- if (MSI_RecordIsNull(row,5))
- {
- LPWSTR p;
- dest_path = strdupW(file_source);
- p = strrchrW(dest_path,'\\');
- if (p)
- *p=0;
- }
- else
- {
- WCHAR destkey[0x100];
- sz=0x100;
- MSI_RecordGetStringW(row,5,destkey,&sz);
- sz = 0x100;
- dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);
- if (!dest_path)
- {
- ERR("Unable to get destination folder\n");
- msiobj_release(&row->hdr);
- HeapFree(GetProcessHeap(),0,file_source);
- break;
- }
- }
-
- dest = build_directory_name(2, dest_path, dest_name);
-
- TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
- debugstr_w(dest));
-
- if (strcmpW(file_source,dest))
- rc = !CopyFileW(file_source,dest,TRUE);
- else
- rc = ERROR_SUCCESS;
-
- if (rc != ERROR_SUCCESS)
- ERR("Failed to copy file %s -> %s, last error %ld\n", debugstr_w(file_source), debugstr_w(dest_path), GetLastError());
-
- FIXME("We should track these duplicate files as well\n");
-
msiobj_release(&row->hdr);
- HeapFree(GetProcessHeap(),0,dest_path);
- HeapFree(GetProcessHeap(),0,dest);
- HeapFree(GetProcessHeap(),0,file_source);
}
MSI_ViewClose(view);
msiobj_release(&view->hdr);
- return rc;
-}
+ 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);
-/* OK this value is "interpreted" and then formatted based on the
- first few characters */
-static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type,
- DWORD *size)
-{
- LPSTR data = NULL;
- if (value[0]=='#' && value[1]!='#' && value[1]!='%')
+ for(i = 0; i < package->loaded_features; i++)
{
- if (value[1]=='x')
- {
- LPWSTR ptr;
- CHAR byte[5];
- LPWSTR deformated = NULL;
- int count;
-
- deformat_string(package, &value[2], &deformated);
-
- /* binary value type */
- ptr = deformated;
- *type = REG_BINARY;
- if (strlenW(ptr)%2)
- *size = (strlenW(ptr)/2)+1;
- else
- *size = strlenW(ptr)/2;
-
- data = HeapAlloc(GetProcessHeap(),0,*size);
-
- byte[0] = '0';
- byte[1] = 'x';
- byte[4] = 0;
- count = 0;
- /* if uneven pad with a zero in front */
- if (strlenW(ptr)%2)
- {
- byte[2]= '0';
- byte[3]= *ptr;
- ptr++;
- data[count] = (BYTE)strtol(byte,NULL,0);
- count ++;
- TRACE("Uneven byte count\n");
- }
- while (*ptr)
- {
- byte[2]= *ptr;
- ptr++;
- byte[3]= *ptr;
- ptr++;
- data[count] = (BYTE)strtol(byte,NULL,0);
- count ++;
- }
- HeapFree(GetProcessHeap(),0,deformated);
-
- TRACE("Data %li bytes(%i)\n",*size,count);
- }
- else
- {
- LPWSTR deformated;
- LPWSTR p;
- DWORD d = 0;
- deformat_string(package, &value[1], &deformated);
-
- *type=REG_DWORD;
- *size = sizeof(DWORD);
- data = HeapAlloc(GetProcessHeap(),0,*size);
- p = deformated;
- if (*p == '-')
- p++;
- while (*p)
- {
- if ( (*p < '0') || (*p > '9') )
- break;
- d *= 10;
- d += (*p - '0');
- p++;
- }
- if (deformated[0] == '-')
- d = -d;
- *(LPDWORD)data = d;
- TRACE("DWORD %li\n",*(LPDWORD)data);
-
- HeapFree(GetProcessHeap(),0,deformated);
- }
+ 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);
}
- else
- {
- static const WCHAR szMulti[] = {'[','~',']',0};
- WCHAR *ptr;
- *type=REG_SZ;
+
+ return ERROR_SUCCESS;
+}
- if (value[0]=='#')
- {
- if (value[1]=='%')
- {
- ptr = &value[2];
- *type=REG_EXPAND_SZ;
- }
- else
- ptr = &value[1];
- }
- else
- ptr=value;
+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};
- if (strstrW(value,szMulti))
- *type = REG_MULTI_SZ;
+ cond = MSI_RecordGetString(row,1);
- *size = deformat_string(package, ptr,(LPWSTR*)&data);
+ if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
+ {
+ LPWSTR deformated;
+ message = MSI_RecordGetString(row,2);
+ deformat_string(package,message,&deformated);
+ MessageBoxW(NULL,deformated,title,MB_OK);
+ HeapFree(GetProcessHeap(),0,deformated);
+ return ERROR_FUNCTION_FAILED;
}
- return data;
+
+ return ERROR_SUCCESS;
}
-static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
+static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
{
UINT rc;
- MSIQUERY * view;
- MSIRECORD * row = 0;
+ MSIQUERY * view = NULL;
static const WCHAR ExecSeqQuery[] =
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','R','e','g','i','s','t','r','y','`',0 };
+ '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
- if (!package)
- return ERROR_INVALID_HANDLE;
+ TRACE("Checking launch conditions\n");
rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
-
- /* increment progress bar each time action data is sent */
- ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
-
- while (1)
- {
- static const WCHAR szHCR[] =
- {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
- 'R','O','O','T','\\',0};
- static const WCHAR szHCU[] =
- {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
- 'U','S','E','R','\\',0};
- static const WCHAR szHLM[] =
- {'H','K','E','Y','_','L','O','C','A','L','_',
- 'M','A','C','H','I','N','E','\\',0};
- static const WCHAR szHU[] =
- {'H','K','E','Y','_','U','S','E','R','S','\\',0};
-
- LPSTR value_data = NULL;
- HKEY root_key, hkey;
- DWORD type,size;
- LPWSTR value, key, name, component, deformated;
- LPCWSTR szRoot;
- INT component_index;
- MSIRECORD * uirow;
- LPWSTR uikey;
- INT root;
- BOOL check_first = FALSE;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
- ui_progress(package,2,0,0,0);
-
- value = NULL;
- key = NULL;
- uikey = NULL;
- name = NULL;
-
- component = load_dynamic_stringW(row, 6);
- component_index = get_loaded_component(package,component);
-
- if (!ACTION_VerifyComponentForAction(package, component_index,
- INSTALLSTATE_LOCAL))
- {
- TRACE("Skipping write due to disabled component\n");
- msiobj_release(&row->hdr);
-
- package->components[component_index].Action =
- package->components[component_index].Installed;
-
- goto next;
- }
-
- package->components[component_index].Action = INSTALLSTATE_LOCAL;
-
- name = load_dynamic_stringW(row, 4);
- if( MSI_RecordIsNull(row,5) && name )
- {
- /* null values can have special meanings */
- if (name[0]=='-' && name[1] == 0)
- {
- msiobj_release(&row->hdr);
- goto next;
- }
- else if ((name[0]=='+' && name[1] == 0) ||
- (name[0] == '*' && name[1] == 0))
- {
- HeapFree(GetProcessHeap(),0,name);
- name = NULL;
- check_first = TRUE;
- }
- }
-
- root = MSI_RecordGetInteger(row,2);
- key = load_dynamic_stringW(row, 3);
-
-
- /* get the root key */
- switch (root)
- {
- case 0: root_key = HKEY_CLASSES_ROOT;
- szRoot = szHCR;
- break;
- case 1: root_key = HKEY_CURRENT_USER;
- szRoot = szHCU;
- break;
- case 2: root_key = HKEY_LOCAL_MACHINE;
- szRoot = szHLM;
- break;
- case 3: root_key = HKEY_USERS;
- szRoot = szHU;
- break;
- default:
- ERR("Unknown root %i\n",root);
- root_key=NULL;
- szRoot = NULL;
- break;
- }
- if (!root_key)
- {
- msiobj_release(&row->hdr);
- goto next;
- }
-
- deformat_string(package, key , &deformated);
- size = strlenW(deformated) + strlenW(szRoot) + 1;
- uikey = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
- strcpyW(uikey,szRoot);
- strcatW(uikey,deformated);
-
- if (RegCreateKeyW( root_key, deformated, &hkey))
- {
- ERR("Could not create key %s\n",debugstr_w(deformated));
- msiobj_release(&row->hdr);
- HeapFree(GetProcessHeap(),0,deformated);
- goto next;
- }
- HeapFree(GetProcessHeap(),0,deformated);
-
- value = load_dynamic_stringW(row,5);
- if (value)
- value_data = parse_value(package, value, &type, &size);
- else
- {
- static const WCHAR szEmpty[] = {0};
- value_data = (LPSTR)strdupW(szEmpty);
- size = 0;
- type = REG_SZ;
- }
-
- deformat_string(package, name, &deformated);
-
- /* get the double nulls to terminate SZ_MULTI */
- if (type == REG_MULTI_SZ)
- size +=sizeof(WCHAR);
-
- if (!check_first)
- {
- TRACE("Setting value %s of %s\n",debugstr_w(deformated),
- debugstr_w(uikey));
- RegSetValueExW(hkey, deformated, 0, type, value_data, size);
- }
- else
- {
- DWORD sz = 0;
- rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
- if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
- {
- TRACE("value %s of %s checked already exists\n",
- debugstr_w(deformated), debugstr_w(uikey));
- }
- else
- {
- TRACE("Checked and setting value %s of %s\n",
- debugstr_w(deformated), debugstr_w(uikey));
- RegSetValueExW(hkey, deformated, 0, type, value_data, size);
- }
- }
-
- uirow = MSI_CreateRecord(3);
- MSI_RecordSetStringW(uirow,2,deformated);
- MSI_RecordSetStringW(uirow,1,uikey);
-
- if (type == REG_SZ)
- MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
- else
- MSI_RecordSetStringW(uirow,3,value);
-
- ui_actiondata(package,szWriteRegistryValues,uirow);
- msiobj_release( &uirow->hdr );
-
- HeapFree(GetProcessHeap(),0,value_data);
- HeapFree(GetProcessHeap(),0,value);
- HeapFree(GetProcessHeap(),0,deformated);
-
- msiobj_release(&row->hdr);
- RegCloseKey(hkey);
-next:
- HeapFree(GetProcessHeap(),0,uikey);
- HeapFree(GetProcessHeap(),0,key);
- HeapFree(GetProcessHeap(),0,name);
- HeapFree(GetProcessHeap(),0,component);
- }
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
-}
-
-static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
-{
- return ERROR_SUCCESS;
-}
-
-
-static UINT ACTION_InstallValidate(MSIPACKAGE *package)
-{
- DWORD progress = 0;
- DWORD total = 0;
- static const WCHAR q1[]=
- {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
- '`','R','e','g','i','s','t','r','y','`',0};
- UINT rc;
- MSIQUERY * view;
- MSIRECORD * row = 0;
- int i;
-
- TRACE(" InstallValidate \n");
-
- rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
- if (rc != ERROR_SUCCESS)
- return ERROR_SUCCESS;
-
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
- while (1)
- {
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
- progress +=1;
-
- msiobj_release(&row->hdr);
- }
- MSI_ViewClose(view);
+ rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
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);
-
- 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;
-}
-
-static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
-{
- UINT rc;
- MSIQUERY * view = NULL;
- MSIRECORD * row = 0;
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
- static const WCHAR title[]=
- {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
-
- TRACE("Checking launch conditions\n");
-
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
- if (rc != ERROR_SUCCESS)
- return ERROR_SUCCESS;
-
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
-
- rc = ERROR_SUCCESS;
- while (rc == ERROR_SUCCESS)
- {
- LPWSTR cond = NULL;
- LPWSTR message = NULL;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- cond = load_dynamic_stringW(row,1);
-
- if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
- {
- LPWSTR deformated;
- message = load_dynamic_stringW(row,2);
- deformat_string(package,message,&deformated);
- MessageBoxW(NULL,deformated,title,MB_OK);
- HeapFree(GetProcessHeap(),0,message);
- HeapFree(GetProcessHeap(),0,deformated);
- rc = ERROR_FUNCTION_FAILED;
- }
- HeapFree(GetProcessHeap(),0,cond);
- msiobj_release(&row->hdr);
- }
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
return rc;
}
}
if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
{
- MSIQUERY * view;
MSIRECORD * row = 0;
- UINT rc,root,len;
- LPWSTR key,deformated,buffer,name,deformated_name;
+ UINT root,len;
+ LPWSTR deformated,buffer,deformated_name;
+ LPCWSTR key,name;
static const WCHAR ExecSeqQuery[] =
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
'`','R','e','g','i','s','t','r','y','`',' ',
static const WCHAR fmt2[]=
{'%','0','2','i',':','\\','%','s','\\','%','s',0};
- rc = MSI_OpenQuery(package->db,&view,ExecSeqQuery,cmp->KeyPath);
-
- if (rc!=ERROR_SUCCESS)
+ row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
+ if (!row)
return NULL;
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return NULL;
- }
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return NULL;
- }
-
root = MSI_RecordGetInteger(row,2);
- key = load_dynamic_stringW(row, 3);
- name = load_dynamic_stringW(row, 4);
+ key = MSI_RecordGetString(row, 3);
+ name = MSI_RecordGetString(row, 4);
deformat_string(package, key , &deformated);
deformat_string(package, name, &deformated_name);
else
sprintfW(buffer,fmt,root,deformated);
- HeapFree(GetProcessHeap(),0,key);
HeapFree(GetProcessHeap(),0,deformated);
- HeapFree(GetProcessHeap(),0,name);
HeapFree(GetProcessHeap(),0,deformated_name);
msiobj_release(&row->hdr);
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
return buffer;
}
return NULL;
}
-static HKEY openSharedDLLsKey()
+static HKEY openSharedDLLsKey(void)
{
HKEY hkey=0;
static const WCHAR path[] =
ITypeLib *ptLib;
} typelib_struct;
-BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
+static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
LPWSTR lpszName, LONG_PTR lParam)
{
TLIBATTR *attr;
sz = strlenW(tl_struct->source)+4;
sz *= sizeof(WCHAR);
- tl_struct->path = HeapAlloc(GetProcessHeap(),0,sz);
- sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
+ if ((INT)lpszName == 1)
+ tl_struct->path = strdupW(tl_struct->source);
+ else
+ {
+ tl_struct->path = HeapAlloc(GetProcessHeap(),0,sz);
+ sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
+ }
TRACE("trying %s\n", debugstr_w(tl_struct->path));
res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
return TRUE;
}
+static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
+{
+ MSIPACKAGE* package = (MSIPACKAGE*)param;
+ LPCWSTR component;
+ INT index;
+ typelib_struct tl_struct;
+ HMODULE module;
+ static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
+
+ component = MSI_RecordGetString(row,3);
+ index = get_loaded_component(package,component);
+ if (index < 0)
+ return ERROR_SUCCESS;
+
+ if (!ACTION_VerifyComponentForAction(package, index, INSTALLSTATE_LOCAL))
+ {
+ TRACE("Skipping typelib reg due to disabled component\n");
+
+ package->components[index].Action =
+ package->components[index].Installed;
+
+ return ERROR_SUCCESS;
+ }
+
+ package->components[index].Action = INSTALLSTATE_LOCAL;
+
+ index = get_loaded_file(package,package->components[index].KeyPath);
+
+ if (index < 0)
+ return ERROR_SUCCESS;
+
+ module = LoadLibraryExW(package->files[index].TargetPath, NULL,
+ LOAD_LIBRARY_AS_DATAFILE);
+ if (module != NULL)
+ {
+ LPWSTR guid;
+ guid = load_dynamic_stringW(row,1);
+ CLSIDFromString(guid, &tl_struct.clsid);
+ HeapFree(GetProcessHeap(),0,guid);
+ tl_struct.source = strdupW(package->files[index].TargetPath);
+ tl_struct.path = NULL;
+
+ EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
+ (LONG_PTR)&tl_struct);
+
+ if (tl_struct.path != NULL)
+ {
+ LPWSTR help = NULL;
+ LPCWSTR helpid;
+ HRESULT res;
+
+ helpid = MSI_RecordGetString(row,6);
+
+ if (helpid)
+ help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
+ res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
+ HeapFree(GetProcessHeap(),0,help);
+
+ if (!SUCCEEDED(res))
+ ERR("Failed to register type library %s\n",
+ debugstr_w(tl_struct.path));
+ else
+ {
+ ui_actiondata(package,szRegisterTypeLibraries,row);
+
+ TRACE("Registered %s\n", debugstr_w(tl_struct.path));
+ }
+
+ ITypeLib_Release(tl_struct.ptLib);
+ HeapFree(GetProcessHeap(),0,tl_struct.path);
+ }
+ else
+ ERR("Failed to load type library %s\n",
+ debugstr_w(tl_struct.source));
+
+ FreeLibrary(module);
+ HeapFree(GetProcessHeap(),0,tl_struct.source);
+ }
+ else
+ ERR("Could not load file! %s\n",
+ debugstr_w(package->files[index].TargetPath));
+
+ return ERROR_SUCCESS;
+}
+
static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
{
/*
*/
UINT rc;
MSIQUERY * view;
- MSIRECORD * row = 0;
static const WCHAR Query[] =
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
'`','T','y','p','e','L','i','b','`',0};
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
-
- while (1)
- {
- WCHAR component[0x100];
- DWORD sz;
- INT index;
- LPWSTR guid;
- typelib_struct tl_struct;
- HMODULE module;
- static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
+ rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
+ msiobj_release(&view->hdr);
+ return rc;
+}
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
+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;
- sz = 0x100;
- MSI_RecordGetStringW(row,3,component,&sz);
+ buffer = MSI_RecordGetString(row,4);
+ index = get_loaded_component(package,buffer);
- index = get_loaded_component(package,component);
- if (index < 0)
- {
- msiobj_release(&row->hdr);
- continue;
- }
+ if (index < 0)
+ return ERROR_SUCCESS;
- if (!ACTION_VerifyComponentForAction(package, index,
- INSTALLSTATE_LOCAL))
- {
- TRACE("Skipping typelib reg due to disabled component\n");
- msiobj_release(&row->hdr);
+ if (!ACTION_VerifyComponentForAction(package, index, INSTALLSTATE_LOCAL))
+ {
+ TRACE("Skipping shortcut creation due to disabled component\n");
- package->components[index].Action =
+ package->components[index].Action =
package->components[index].Installed;
- continue;
- }
-
- package->components[index].Action = INSTALLSTATE_LOCAL;
-
- index = get_loaded_file(package,package->components[index].KeyPath);
-
- if (index < 0)
- {
- msiobj_release(&row->hdr);
- continue;
- }
-
- guid = load_dynamic_stringW(row,1);
- module = LoadLibraryExW(package->files[index].TargetPath, NULL,
- LOAD_LIBRARY_AS_DATAFILE);
- if (module != NULL)
- {
- CLSIDFromString(guid, &tl_struct.clsid);
- tl_struct.source = strdupW(package->files[index].TargetPath);
- tl_struct.path = NULL;
-
- EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
- (LONG_PTR)&tl_struct);
-
- if (tl_struct.path != NULL)
- {
- LPWSTR help;
- WCHAR helpid[0x100];
- HRESULT res;
-
- sz = 0x100;
- MSI_RecordGetStringW(row,6,helpid,&sz);
-
- help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
- res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
- HeapFree(GetProcessHeap(),0,help);
-
- if (!SUCCEEDED(res))
- ERR("Failed to register type library %s\n",
- debugstr_w(tl_struct.path));
- else
- {
- ui_actiondata(package,szRegisterTypeLibraries,row);
-
- TRACE("Registered %s\n", debugstr_w(tl_struct.path));
- }
-
- ITypeLib_Release(tl_struct.ptLib);
- HeapFree(GetProcessHeap(),0,tl_struct.path);
- }
- else
- ERR("Failed to load type library %s\n",
- debugstr_w(tl_struct.source));
-
- FreeLibrary(module);
- HeapFree(GetProcessHeap(),0,tl_struct.source);
- }
- else
- ERR("Could not load file! %s\n",
- debugstr_w(package->files[index].TargetPath));
- msiobj_release(&row->hdr);
+ return ERROR_SUCCESS;
}
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
-}
-static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app )
-{
- static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
- UINT rc;
- MSIQUERY * view;
- MSIRECORD * row = 0;
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','A','p','p','I' ,'d','`',' ','W','H','E','R','E',' ',
- '`','A','p','p','I','d','`',' ','=','\'','%','s','\'',0};
- HKEY hkey2,hkey3;
- LPWSTR buffer=0;
+ package->components[index].Action = INSTALLSTATE_LOCAL;
- if (!package)
- return ERROR_INVALID_HANDLE;
+ ui_actiondata(package,szCreateShortcuts,row);
- rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, clsid);
- if (rc != ERROR_SUCCESS)
- return rc;
+ res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IShellLinkW, (LPVOID *) &sl );
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
+ if (FAILED(res))
{
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
+ ERR("Is IID_IShellLink\n");
+ return ERROR_SUCCESS;
}
- RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
- RegCreateKeyW(hkey2,clsid,&hkey3);
- RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
- (strlenW(app)+1)*sizeof(WCHAR));
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
+ res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
+ if( FAILED( res ) )
{
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
+ ERR("Is IID_IPersistFile\n");
+ return ERROR_SUCCESS;
}
- if (!MSI_RecordIsNull(row,2))
- {
- LPWSTR deformated=0;
- UINT size;
- static const WCHAR szRemoteServerName[] =
- {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',
- 0};
- buffer = load_dynamic_stringW(row,2);
- size = deformat_string(package,buffer,&deformated);
- RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,(LPVOID)deformated,
- size);
+ 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);
- HeapFree(GetProcessHeap(),0,buffer);
}
-
- if (!MSI_RecordIsNull(row,3))
+ else
{
- static const WCHAR szLocalService[] =
- {'L','o','c','a','l','S','e','r','v','i','c','e',0};
- UINT size;
- buffer = load_dynamic_stringW(row,3);
- size = (strlenW(buffer)+1) * sizeof(WCHAR);
- RegSetValueExW(hkey3,szLocalService,0,REG_SZ,(LPVOID)buffer,size);
- HeapFree(GetProcessHeap(),0,buffer);
+ 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,4))
+ if (!MSI_RecordIsNull(row,6))
{
- static const WCHAR szService[] =
- {'S','e','r','v','i','c','e',
- 'P','a','r','a','m','e','t','e','r','s',0};
- UINT size;
- buffer = load_dynamic_stringW(row,4);
- size = (strlenW(buffer)+1) * sizeof(WCHAR);
- RegSetValueExW(hkey3,szService,0,REG_SZ,(LPVOID)buffer,size);
- HeapFree(GetProcessHeap(),0,buffer);
+ LPWSTR deformated;
+ buffer = MSI_RecordGetString(row,6);
+ deformat_string(package,buffer,&deformated);
+ IShellLinkW_SetArguments(sl,deformated);
+ HeapFree(GetProcessHeap(),0,deformated);
}
- if (!MSI_RecordIsNull(row,5))
+ if (!MSI_RecordIsNull(row,7))
{
- static const WCHAR szDLL[] =
- {'D','l','l','S','u','r','r','o','g','a','t','e',0};
- UINT size;
- buffer = load_dynamic_stringW(row,5);
- size = (strlenW(buffer)+1) * sizeof(WCHAR);
- RegSetValueExW(hkey3,szDLL,0,REG_SZ,(LPVOID)buffer,size);
- HeapFree(GetProcessHeap(),0,buffer);
+ buffer = MSI_RecordGetString(row,7);
+ IShellLinkW_SetDescription(sl,buffer);
}
- if (!MSI_RecordIsNull(row,6))
+ if (!MSI_RecordIsNull(row,8))
+ IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
+
+ if (!MSI_RecordIsNull(row,9))
{
- 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};
+ WCHAR *Path = NULL;
+ INT index;
- if (MSI_RecordGetInteger(row,6))
- RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
+ 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,7))
- {
- static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
- static const WCHAR szUser[] =
- {'I','n','t','e','r','a','c','t','i','v','e',' ',
- 'U','s','e','r',0};
+ if (!MSI_RecordIsNull(row,11))
+ IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
- if (MSI_RecordGetInteger(row,7))
- RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,34);
+ 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);
}
- msiobj_release(&row->hdr);
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- RegCloseKey(hkey3);
- RegCloseKey(hkey2);
- return rc;
+ TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
+ IPersistFile_Save(pf,target_file,FALSE);
+
+ HeapFree(GetProcessHeap(),0,target_file);
+
+ IPersistFile_Release( pf );
+ IShellLinkW_Release( sl );
+
+ return ERROR_SUCCESS;
}
-static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
+static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
{
- /*
- * Again I am assuming the words, "Whose key file represents" when referring
- * to a Component as to meaning that Components KeyPath file
- *
- * Also there is a very strong connection between ClassInfo and ProgID
- * that I am mostly glossing over.
- * What would be more propper is to load the ClassInfo and the ProgID info
- * into memory data structures and then be able to enable and disable them
- * based on component.
- */
-
UINT rc;
+ HRESULT res;
MSIQUERY * view;
- MSIRECORD * row = 0;
- static const WCHAR ExecSeqQuery[] =
+ static const WCHAR Query[] =
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','C','l','a','s','s','`',0};
- static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
- static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
- static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
- static const WCHAR szSpace[] = {' ',0};
- HKEY hkey,hkey2,hkey3;
- LPWSTR argument,deformated;
+ '`','S','h','o','r','t','c','u','t','`',0};
if (!package)
return ERROR_INVALID_HANDLE;
- rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
- if (rc != ERROR_SUCCESS)
- return ERROR_FUNCTION_FAILED;
-
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- goto end;
- }
+ return ERROR_SUCCESS;
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
+ res = CoInitialize( NULL );
+ if (FAILED (res))
{
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- goto end;
+ ERR("CoInitialize failed\n");
+ return ERROR_FUNCTION_FAILED;
}
- while (1)
- {
- WCHAR clsid[0x100];
- WCHAR buffer[0x100];
- WCHAR desc[0x100];
- DWORD sz;
- INT index;
- DWORD size;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
+ rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
+ msiobj_release(&view->hdr);
- sz=0x100;
- MSI_RecordGetStringW(row,3,buffer,&sz);
+ CoUninitialize();
- index = get_loaded_component(package,buffer);
+ return rc;
+}
- if (index < 0)
- {
- msiobj_release(&row->hdr);
- continue;
- }
+static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
+{
+ MSIPACKAGE* package = (MSIPACKAGE*)param;
+ HANDLE the_file;
+ LPWSTR FilePath=NULL;
+ LPCWSTR FileName=NULL;
+ CHAR buffer[1024];
+ DWORD sz;
+ UINT rc;
- if ((!ACTION_VerifyComponentForAction(package, index,
- INSTALLSTATE_LOCAL)) &&
- (!ACTION_VerifyComponentForAction(package, index,
- INSTALLSTATE_ADVERTISED)))
- {
- TRACE("Skipping class reg due to disabled component\n");
- msiobj_release(&row->hdr);
+ FileName = MSI_RecordGetString(row,1);
+ if (!FileName)
+ {
+ ERR("Unable to get FileName\n");
+ return ERROR_SUCCESS;
+ }
- package->components[index].Action =
- package->components[index].Installed;
+ build_icon_path(package,FileName,&FilePath);
- continue;
- }
+ TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
- package->components[index].Action = INSTALLSTATE_LOCAL;
+ the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
- sz=0x100;
- MSI_RecordGetStringW(row,1,clsid,&sz);
- RegCreateKeyW(hkey,clsid,&hkey2);
+ if (the_file == INVALID_HANDLE_VALUE)
+ {
+ ERR("Unable to create file %s\n",debugstr_w(FilePath));
+ HeapFree(GetProcessHeap(),0,FilePath);
+ return ERROR_SUCCESS;
+ }
- if (!MSI_RecordIsNull(row,5))
+ do
+ {
+ DWORD write;
+ sz = 1024;
+ rc = MSI_RecordReadStream(row,2,buffer,&sz);
+ if (rc != ERROR_SUCCESS)
{
- sz=0x100;
- MSI_RecordGetStringW(row,5,desc,&sz);
-
- RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)desc,
- (strlenW(desc)+1)*sizeof(WCHAR));
+ ERR("Failed to get stream\n");
+ CloseHandle(the_file);
+ DeleteFileW(FilePath);
+ break;
}
- else
- desc[0]=0;
+ WriteFile(the_file,buffer,sz,&write,NULL);
+ } while (sz == 1024);
- sz=0x100;
- MSI_RecordGetStringW(row,2,buffer,&sz);
+ HeapFree(GetProcessHeap(),0,FilePath);
- RegCreateKeyW(hkey2,buffer,&hkey3);
+ CloseHandle(the_file);
+ return ERROR_SUCCESS;
+}
- index = get_loaded_file(package,package->components[index].KeyPath);
+/*
+ * 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;
+ 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;
- argument = load_dynamic_stringW(row,11);
- size = deformat_string(package,argument,&deformated);
- if (deformated)
- size+=sizeof(WCHAR);
- HeapFree(GetProcessHeap(),0,argument);
- size += (strlenW(package->files[index].TargetPath))*sizeof(WCHAR);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
- argument = HeapAlloc(GetProcessHeap(),0,size+sizeof(WCHAR));
- strcpyW(argument,package->files[index].TargetPath);
- if (deformated)
- {
- strcatW(argument,szSpace);
- strcatW(argument,deformated);
- }
+ /* write out icon files */
- RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size);
- HeapFree(GetProcessHeap(),0,deformated);
- HeapFree(GetProcessHeap(),0,argument);
+ rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
+ if (rc == ERROR_SUCCESS)
+ {
+ MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
+ msiobj_release(&view->hdr);
+ }
- RegCloseKey(hkey3);
+ /* ok there is a lot more done here but i need to figure out what */
- if (!MSI_RecordIsNull(row,4))
- {
- sz=0x100;
- MSI_RecordGetStringW(row,4,buffer,&sz);
+ productcode = load_dynamic_property(package,szProductCode,&rc);
+ if (!productcode)
+ return rc;
- RegCreateKeyW(hkey2,szProgID,&hkey3);
-
- RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)buffer,
- (strlenW(buffer)+1)*sizeof(WCHAR));
+ rc = MSIREG_OpenProductsKey(productcode,&hkey,TRUE);
+ if (rc != ERROR_SUCCESS)
+ goto end;
- RegCloseKey(hkey3);
- }
+ rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
+ if (rc != ERROR_SUCCESS)
+ goto end;
- if (!MSI_RecordIsNull(row,6))
- {
- sz=0x100;
- MSI_RecordGetStringW(row,6,buffer,&sz);
- RegSetValueExW(hkey2,szAppID,0,REG_SZ,(LPVOID)buffer,
- (strlenW(buffer)+1)*sizeof(WCHAR));
+ 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);
- register_appid(package,buffer,desc);
- }
+ 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);
- if (!MSI_RecordIsNull(row,7))
+ 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)
{
- FIXME("Process field 7\n");
+ 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);
}
-
- if (!MSI_RecordIsNull(row,8))
- {
- static const WCHAR szDefaultIcon[] =
- {'D','e','f','a','u','l','t','I','c','o','n',0};
-
- LPWSTR FileName = load_dynamic_stringW(row,8);
- LPWSTR FilePath;
- INT index;
-
- RegCreateKeyW(hkey2,szDefaultIcon,&hkey3);
- build_icon_path(package,FileName,&FilePath);
- if (!MSI_RecordIsNull(row,9))
- {
- static const WCHAR index_fmt[] = {',','%','i',0};
- WCHAR index_buf[20];
- index = MSI_RecordGetInteger(row,9);
- sprintfW(index_buf,index_fmt,index);
- size = strlenW(FilePath)+strlenW(index_buf)+1;
- size *= sizeof(WCHAR);
- HeapReAlloc(GetProcessHeap(),0,FilePath,size);
- }
- RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)FilePath,
- (strlenW(FilePath)+1) * sizeof(WCHAR));
- HeapFree(GetProcessHeap(),0,FilePath);
- HeapFree(GetProcessHeap(),0,FileName);
- RegCloseKey(hkey3);
- }
-
- if (!MSI_RecordIsNull(row,10))
+ else
{
- static const WCHAR szInproc32[] =
- {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',
- 0};
- static const WCHAR szInproc[] =
- {'I','n','p','r','o','c','H','a','n','d','l','e','r',0};
- INT i = MSI_RecordGetInteger(row,10);
- if (i != MSI_NULL_INTEGER && i > 0 && i < 4)
- {
- static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0};
- static const WCHAR ole32[] =
- {'o','l','e','3','2','.','d','l','l',0};
- switch(i)
- {
- case 1:
- size = strlenW(ole2) * sizeof(WCHAR);
- RegCreateKeyW(hkey2,szInproc,&hkey3);
- RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole2, size);
- RegCloseKey(hkey3);
- break;
- case 2:
- size = strlenW(ole32) * sizeof(WCHAR);
- RegCreateKeyW(hkey2,szInproc32,&hkey3);
- RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole32,size);
- RegCloseKey(hkey3);
- break;
- case 3:
- size = strlenW(ole2) * sizeof(WCHAR);
- RegCreateKeyW(hkey2,szInproc,&hkey3);
- RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole2, size);
- RegCloseKey(hkey3);
- size = strlenW(ole32) * sizeof(WCHAR);
- RegCreateKeyW(hkey2,szInproc32,&hkey3);
- RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole32,size);
- RegCloseKey(hkey3);
- break;
- }
-
- }
- else
- {
- RegCreateKeyW(hkey2,szInproc32,&hkey3);
- argument = load_dynamic_stringW(row,10);
- reduce_to_longfilename(argument);
- size = strlenW(argument)*sizeof(WCHAR);
-
- RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size);
- HeapFree(GetProcessHeap(),0,argument);
-
- RegCloseKey(hkey3);
- }
+ ERR("Unable to query Revision_Number... \n");
+ rc = ERROR_SUCCESS;
}
-
- RegCloseKey(hkey2);
-
- ui_actiondata(package,szRegisterClassInfo,row);
-
- msiobj_release(&row->hdr);
+ MsiCloseHandle(hSumInfo);
+ }
+ else
+ {
+ ERR("Unable to open Summary Information\n");
+ rc = ERROR_SUCCESS;
}
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
end:
+
+ HeapFree(GetProcessHeap(),0,productcode);
RegCloseKey(hkey);
+ RegCloseKey(hukey);
+
return rc;
}
-static UINT register_progid_base(MSIPACKAGE* package, MSIRECORD * row,
- LPWSTR clsid)
+static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
{
- static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
- static const WCHAR szDefaultIcon[] =
- {'D','e','f','a','u','l','t','I','c','o','n',0};
- HKEY hkey,hkey2;
- WCHAR buffer[0x100];
- DWORD sz;
-
+ 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};
- sz = 0x100;
- MSI_RecordGetStringW(row,1,buffer,&sz);
- RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey);
+ component = MSI_RecordGetString(row, 8);
+ component_index = get_loaded_component(package,component);
- if (!MSI_RecordIsNull(row,4))
+ if (!ACTION_VerifyComponentForAction(package, component_index,
+ INSTALLSTATE_LOCAL))
{
- sz = 0x100;
- MSI_RecordGetStringW(row,4,buffer,&sz);
- RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
- sizeof(WCHAR));
+ TRACE("Skipping ini file due to disabled component %s\n",
+ debugstr_w(component));
+
+ package->components[component_index].Action =
+ package->components[component_index].Installed;
+
+ return ERROR_SUCCESS;
}
- if (!MSI_RecordIsNull(row,3))
- {
- sz = 0x100;
-
- MSI_RecordGetStringW(row,3,buffer,&sz);
- RegCreateKeyW(hkey,szCLSID,&hkey2);
- RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) *
- sizeof(WCHAR));
+ package->components[component_index].Action = INSTALLSTATE_LOCAL;
- if (clsid)
- strcpyW(clsid,buffer);
+ 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);
- RegCloseKey(hkey2);
+ 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)
{
- FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
- return ERROR_FUNCTION_FAILED;
+ ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
+ goto cleanup;
}
- if (!MSI_RecordIsNull(row,5))
- {
- INT index = MSI_RecordGetInteger(row,6);
- LPWSTR FileName = load_dynamic_stringW(row,5);
- LPWSTR FilePath,IconPath;
- static const WCHAR fmt[] = {'%','s',',','%','i',0};
- RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
- build_icon_path(package,FileName,&FilePath);
-
- IconPath = HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)*
- sizeof(WCHAR));
+ fullname = build_directory_name(3, folder, filename, NULL);
- sprintfW(IconPath,fmt,FilePath,index);
- RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)IconPath,
- (strlenW(IconPath)+1) * sizeof(WCHAR));
- HeapFree(GetProcessHeap(),0,FilePath);
- HeapFree(GetProcessHeap(),0,FileName);
- RegCloseKey(hkey2);
+ if (action == 0)
+ {
+ TRACE("Adding value %s to section %s in %s\n",
+ debugstr_w(deformated_key), debugstr_w(deformated_section),
+ debugstr_w(fullname));
+ WritePrivateProfileStringW(deformated_section, deformated_key,
+ deformated_value, fullname);
+ }
+ else if (action == 1)
+ {
+ WCHAR returned[10];
+ GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
+ returned, 10, fullname);
+ if (returned[0] == 0)
+ {
+ TRACE("Adding value %s to section %s in %s\n",
+ debugstr_w(deformated_key), debugstr_w(deformated_section),
+ debugstr_w(fullname));
+
+ WritePrivateProfileStringW(deformated_section, deformated_key,
+ deformated_value, fullname);
+ }
}
+ else if (action == 3)
+ FIXME("Append to existing section not yet implemented\n");
+
+ uirow = MSI_CreateRecord(4);
+ MSI_RecordSetStringW(uirow,1,identifier);
+ MSI_RecordSetStringW(uirow,2,deformated_section);
+ MSI_RecordSetStringW(uirow,3,deformated_key);
+ MSI_RecordSetStringW(uirow,4,deformated_value);
+ ui_actiondata(package,szWriteIniValues,uirow);
+ msiobj_release( &uirow->hdr );
+cleanup:
+ HeapFree(GetProcessHeap(),0,fullname);
+ HeapFree(GetProcessHeap(),0,folder);
+ HeapFree(GetProcessHeap(),0,deformated_key);
+ HeapFree(GetProcessHeap(),0,deformated_value);
+ HeapFree(GetProcessHeap(),0,deformated_section);
return ERROR_SUCCESS;
}
-static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid);
-
-static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent,
- LPWSTR clsid)
+static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
{
UINT rc;
MSIQUERY * view;
- MSIRECORD * row = 0;
- static const WCHAR Query_t[] =
+ 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 (!package)
- return ERROR_INVALID_HANDLE;
-
- rc = MSI_OpenQuery(package->db, &view, Query_t, parent);
- if (rc != ERROR_SUCCESS)
- return rc;
-
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
+ '`','I','n','i','F','i','l','e','`',0};
- rc = MSI_ViewFetch(view,&row);
+ 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;
}
- register_progid(package,row,clsid);
-
- msiobj_release(&row->hdr);
- MSI_ViewClose(view);
+ rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
msiobj_release(&view->hdr);
return rc;
}
-static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid)
+static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
{
- UINT rc = ERROR_SUCCESS;
+ 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;
- if (MSI_RecordIsNull(row,2))
- rc = register_progid_base(package,row,clsid);
- else
- {
- WCHAR buffer[0x1000];
- DWORD sz, disp;
- HKEY hkey,hkey2;
- static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
- static const WCHAR szDefaultIcon[] =
- {'D','e','f','a','u','l','t','I','c','o','n',0};
-
- /* check if already registered */
- sz = 0x100;
- MSI_RecordGetStringW(row,1,buffer,&sz);
- RegCreateKeyExW(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0,
- KEY_ALL_ACCESS, NULL, &hkey, &disp );
- if (disp == REG_OPENED_EXISTING_KEY)
- {
- TRACE("Key already registered\n");
- RegCloseKey(hkey);
- return rc;
- }
+ memset(&si,0,sizeof(STARTUPINFOW));
- sz = 0x100;
- MSI_RecordGetStringW(row,2,buffer,&sz);
- rc = register_parent_progid(package,buffer,clsid);
+ filename = MSI_RecordGetString(row,1);
+ index = get_loaded_file(package,filename);
- /* clsid is same as parent */
- RegCreateKeyW(hkey,szCLSID,&hkey2);
- RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
- sizeof(WCHAR));
+ if (index < 0)
+ {
+ ERR("Unable to find file id %s\n",debugstr_w(filename));
+ return ERROR_SUCCESS;
+ }
- RegCloseKey(hkey2);
+ 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);
- if (!MSI_RecordIsNull(row,4))
- {
- sz = 0x100;
- MSI_RecordGetStringW(row,4,buffer,&sz);
- RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer,
- (strlenW(buffer)+1) * sizeof(WCHAR));
- }
+ TRACE("Registering %s\n",debugstr_w(FullName));
+ brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
+ &si, &info);
- if (!MSI_RecordIsNull(row,5))
- {
- LPWSTR FileName = load_dynamic_stringW(row,5);
- LPWSTR FilePath;
- RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
- build_icon_path(package,FileName,&FilePath);
- RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)FilePath,
- (strlenW(FilePath)+1) * sizeof(WCHAR));
- HeapFree(GetProcessHeap(),0,FilePath);
- HeapFree(GetProcessHeap(),0,FileName);
- RegCloseKey(hkey2);
- }
+ if (brc)
+ msi_dialog_check_messages(info.hProcess);
- RegCloseKey(hkey);
- }
- return rc;
+ HeapFree(GetProcessHeap(),0,FullName);
+ return ERROR_SUCCESS;
}
-static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
+static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
{
- /*
- * Sigh, here I am just brute force registering all progids
- * this needs to be linked to the Classes that have been registered
- * but the easiest way to do that is to load all these stuff into
- * memory for easy checking.
- *
- * Gives me something to continue to work toward.
- */
UINT rc;
MSIQUERY * view;
- MSIRECORD * row = 0;
- static const WCHAR Query[] =
- {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
- '`','P','r','o','g','I','d','`',0};
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
- if (rc != ERROR_SUCCESS)
- return ERROR_SUCCESS;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','S','e','l','f','R','e','g','`',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 SelfReg table\n");
+ return ERROR_SUCCESS;
}
- while (1)
- {
- WCHAR clsid[0x1000];
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- register_progid(package,row,clsid);
- ui_actiondata(package,szRegisterProgIdInfo,row);
-
- msiobj_release(&row->hdr);
- }
- MSI_ViewClose(view);
+ MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
msiobj_release(&view->hdr);
- return rc;
-}
-static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name,
- LPWSTR *FilePath)
-{
- LPWSTR ProductCode;
- LPWSTR SystemFolder;
- LPWSTR dest;
- UINT rc;
-
- static const WCHAR szInstaller[] =
- {'I','n','s','t','a','l','l','e','r','\\',0};
- static const WCHAR szFolder[] =
- {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
-
- ProductCode = load_dynamic_property(package,szProductCode,&rc);
- if (!ProductCode)
- return rc;
-
- SystemFolder = load_dynamic_property(package,szFolder,NULL);
-
- dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode);
-
- create_full_pathW(dest);
-
- *FilePath = build_directory_name(2, dest, icon_name);
-
- HeapFree(GetProcessHeap(),0,SystemFolder);
- HeapFree(GetProcessHeap(),0,ProductCode);
- HeapFree(GetProcessHeap(),0,dest);
return ERROR_SUCCESS;
}
-static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
+static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
{
+ LPWSTR productcode;
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;
-
+ DWORD i;
+ HKEY hkey=0;
+ HKEY hukey=0;
+
if (!package)
return ERROR_INVALID_HANDLE;
- res = CoInitialize( NULL );
- if (FAILED (res))
- {
- ERR("CoInitialize failed\n");
- return ERROR_FUNCTION_FAILED;
- }
+ productcode = load_dynamic_property(package,szProductCode,&rc);
+ if (!productcode)
+ return rc;
- rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
+ rc = MSIREG_OpenFeaturesKey(productcode,&hkey,TRUE);
if (rc != ERROR_SUCCESS)
- return ERROR_SUCCESS;
+ goto end;
- rc = MSI_ViewExecute(view, 0);
+ rc = MSIREG_OpenUserFeaturesKey(productcode,&hukey,TRUE);
if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
+ goto end;
- while (1)
+ /* here the guids are base 85 encoded */
+ for (i = 0; i < package->loaded_features; i++)
{
- LPWSTR target_file, target_folder;
- WCHAR buffer[0x100];
- DWORD sz;
- DWORD index;
- static const WCHAR szlnk[]={'.','l','n','k',0};
+ LPWSTR data = NULL;
+ GUID clsid;
+ int j;
+ INT size;
+ BOOL absent = FALSE;
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- sz = 0x100;
- MSI_RecordGetStringW(row,4,buffer,&sz);
+ if (!ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_LOCAL) &&
+ !ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_SOURCE) &&
+ !ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_ADVERTISED))
+ absent = TRUE;
- index = get_loaded_component(package,buffer);
+ size = package->features[i].ComponentCount*21;
+ size +=1;
+ if (package->features[i].Feature_Parent[0])
+ size += strlenW(package->features[i].Feature_Parent)+2;
- if (index < 0)
- {
- msiobj_release(&row->hdr);
- continue;
- }
+ data = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
- if (!ACTION_VerifyComponentForAction(package, index,
- INSTALLSTATE_LOCAL))
+ data[0] = 0;
+ for (j = 0; j < package->features[i].ComponentCount; j++)
{
- 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;
+ 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);
+ }
}
-
- res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
- if( FAILED( res ) )
+ if (package->features[i].Feature_Parent[0])
{
- ERR("Is IID_IPersistFile\n");
- msiobj_release(&row->hdr);
- continue;
+ static const WCHAR sep[] = {'\2',0};
+ strcatW(data,sep);
+ strcatW(data,package->features[i].Feature_Parent);
}
- sz = 0x100;
- MSI_RecordGetStringW(row,2,buffer,&sz);
- target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
-
- /* may be needed because of a bug somehwere else */
- create_full_pathW(target_folder);
-
- sz = 0x100;
- MSI_RecordGetStringW(row,3,buffer,&sz);
- reduce_to_longfilename(buffer);
- if (!strchrW(buffer,'.') || strcmpiW(strchrW(buffer,'.'),szlnk))
- strcatW(buffer,szlnk);
- target_file = build_directory_name(2, target_folder, buffer);
- HeapFree(GetProcessHeap(),0,target_folder);
+ size = (strlenW(data)+1)*sizeof(WCHAR);
+ RegSetValueExW(hkey,package->features[i].Feature,0,REG_SZ,
+ (LPSTR)data,size);
+ HeapFree(GetProcessHeap(),0,data);
- sz = 0x100;
- MSI_RecordGetStringW(row,5,buffer,&sz);
- if (strchrW(buffer,'['))
+ if (!absent)
{
- LPWSTR deformated;
- deformat_string(package,buffer,&deformated);
- IShellLinkW_SetPath(sl,deformated);
- HeapFree(GetProcessHeap(),0,deformated);
+ 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
{
- LPWSTR keypath;
- FIXME("poorly handled shortcut format, advertised shortcut\n");
- keypath = strdupW(package->components[index].FullKeypath);
- IShellLinkW_SetPath(sl,keypath);
- HeapFree(GetProcessHeap(),0,keypath);
- }
-
- if (!MSI_RecordIsNull(row,6))
- {
- LPWSTR deformated;
- sz = 0x100;
- MSI_RecordGetStringW(row,6,buffer,&sz);
- deformat_string(package,buffer,&deformated);
- IShellLinkW_SetArguments(sl,deformated);
- HeapFree(GetProcessHeap(),0,deformated);
- }
-
- if (!MSI_RecordIsNull(row,7))
- {
- LPWSTR deformated;
- deformated = load_dynamic_stringW(row,7);
- IShellLinkW_SetDescription(sl,deformated);
- HeapFree(GetProcessHeap(),0,deformated);
- }
-
- if (!MSI_RecordIsNull(row,8))
- IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
-
- if (!MSI_RecordIsNull(row,9))
- {
- WCHAR *Path = NULL;
- INT index;
-
- sz = 0x100;
- MSI_RecordGetStringW(row,9,buffer,&sz);
-
- build_icon_path(package,buffer,&Path);
- index = MSI_RecordGetInteger(row,10);
-
- IShellLinkW_SetIconLocation(sl,Path,index);
- HeapFree(GetProcessHeap(),0,Path);
- }
-
- if (!MSI_RecordIsNull(row,11))
- IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
-
- if (!MSI_RecordIsNull(row,12))
- {
- LPWSTR Path;
- sz = 0x100;
- MSI_RecordGetStringW(row,12,buffer,&sz);
- Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
- IShellLinkW_SetWorkingDirectory(sl,Path);
- HeapFree(GetProcessHeap(), 0, Path);
+ 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);
}
-
- 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();
+end:
+ RegCloseKey(hkey);
+ RegCloseKey(hukey);
+ HeapFree(GetProcessHeap(), 0, productcode);
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)
+static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
{
- UINT rc;
- MSIQUERY * view;
- MSIRECORD * row = 0;
- static const WCHAR Query[]=
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','I','c','o','n','`',0};
- DWORD sz;
- /* for registry stuff */
- LPWSTR productcode;
HKEY hkey=0;
- HKEY hukey=0;
- static const WCHAR szProductName[] =
- {'P','r','o','d','u','c','t','N','a','m','e',0};
- static const WCHAR szPackageCode[] =
- {'P','a','c','k','a','g','e','C','o','d','e',0};
- LPWSTR buffer;
+ LPWSTR buffer = NULL;
+ LPWSTR productcode;
+ UINT rc,i;
DWORD size;
- MSIHANDLE hDb, hSumInfo;
+ 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};
+ static const WCHAR modpath_fmt[] =
+ {'M','s','i','E','x','e','c','.','e','x','e',' ','/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
+ static const WCHAR szModifyPath[] =
+ {'M','o','d','i','f','y','P','a','t','h',0};
+ static const WCHAR szUninstallString[] =
+ {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
+ static const WCHAR szEstimatedSize[] =
+ {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
+ static const WCHAR szInstallDate[] =
+ {'I','n','s','t','a','l','l','D','a','t','e',0};
+ static const WCHAR szLanguage[] =
+ {'L','a','n','g','u','a','g','e',0};
+ static const WCHAR szProductLanguage[] =
+ {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
+ static const WCHAR szProductVersion[] =
+ {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
+ static const WCHAR szVersion[] =
+ {'V','e','r','s','i','o','n',0};
+ static const WCHAR szVersionMajor[] =
+ {'V','e','r','s','i','o','n','M','a','j','o','r',0};
+ static const WCHAR szVersionMinor[] =
+ {'V','e','r','s','i','o','n','M','i','n','o','r',0};
+
+ SYSTEMTIME systime;
+ static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
+ LPWSTR upgrade_code;
+ WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
+ INT num,start;
if (!package)
return ERROR_INVALID_HANDLE;
- rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
- if (rc != ERROR_SUCCESS)
- goto next;
+ productcode = load_dynamic_property(package,szProductCode,&rc);
+ if (!productcode)
+ return rc;
- rc = MSI_ViewExecute(view, 0);
+ 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)
{
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- goto next;
+ 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);
+ HeapFree(GetProcessHeap(),0,buffer);
+ i++;
}
- while (1)
+ 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 the_file;
- WCHAR *FilePath=NULL;
- WCHAR *FileName=NULL;
- CHAR buffer[1024];
-
- 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;
}
-
- FileName = load_dynamic_stringW(row,1);
- if (!FileName)
- {
- ERR("Unable to get FileName\n");
- msiobj_release(&row->hdr);
- continue;
- }
-
- build_icon_path(package,FileName,&FilePath);
-
- HeapFree(GetProcessHeap(),0,FileName);
-
- TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
-
- the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (the_file == INVALID_HANDLE_VALUE)
- {
- ERR("Unable to create file %s\n",debugstr_w(FilePath));
- msiobj_release(&row->hdr);
- HeapFree(GetProcessHeap(),0,FilePath);
- continue;
- }
+ if (GetLastError() != ERROR_FILE_EXISTS &&
+ GetLastError() != ERROR_SHARING_VIOLATION)
+ break;
+ if (!(++num & 0xffff)) num = 1;
+ sprintfW(packagefile,fmt,num);
+ } while (num != start);
- 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);
+ 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);
- HeapFree(GetProcessHeap(),0,FilePath);
+ /* do ModifyPath and UninstallString */
+ size = deformat_string(package,modpath_fmt,&buffer);
+ RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPSTR)buffer,size);
+ RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPSTR)buffer,size);
+ HeapFree(GetProcessHeap(),0,buffer);
- CloseHandle(the_file);
- msiobj_release(&row->hdr);
+ FIXME("Write real Estimated Size when we have it\n");
+ size = 0;
+ RegSetValueExW(hkey,szEstimatedSize,0,REG_DWORD,(LPSTR)&size,sizeof(DWORD));
+
+ GetLocalTime(&systime);
+ size = 9*sizeof(WCHAR);
+ buffer= HeapAlloc(GetProcessHeap(),0,size);
+ sprintfW(buffer,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
+ size = strlenW(buffer)*sizeof(WCHAR);
+ RegSetValueExW(hkey,szInstallDate,0,REG_SZ,(LPSTR)buffer,size);
+ HeapFree(GetProcessHeap(),0,buffer);
+
+ buffer = load_dynamic_property(package,szProductLanguage,NULL);
+ size = atoiW(buffer);
+ RegSetValueExW(hkey,szLanguage,0,REG_DWORD, (LPSTR)&size,sizeof(DWORD));
+ HeapFree(GetProcessHeap(),1,buffer);
+
+ buffer = load_dynamic_property(package,szProductVersion,NULL);
+ if (buffer)
+ {
+ DWORD verdword = build_version_dword(buffer);
+ DWORD vermajor = verdword>>24;
+ DWORD verminor = (verdword>>16)&0x00FF;
+ size = sizeof(DWORD);
+ RegSetValueExW(hkey,szVersion,0,REG_DWORD,(LPSTR)&verdword,size);
+ RegSetValueExW(hkey,szVersionMajor,0,REG_DWORD,(LPSTR)&vermajor,size);
+ RegSetValueExW(hkey,szVersionMinor,0,REG_DWORD,(LPSTR)&verminor,size);
}
- 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;
+ HeapFree(GetProcessHeap(),0,buffer);
+
+ /* Handle Upgrade Codes */
+ upgrade_code = load_dynamic_property(package,szUpgradeCode, NULL);
+ if (upgrade_code)
+ {
+ HKEY hkey2;
+ WCHAR squashed[33];
+ MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
+ squash_guid(productcode,squashed);
+ RegSetValueExW(hkey2, squashed, 0,REG_SZ,NULL,0);
+ RegCloseKey(hkey2);
+ MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
+ squash_guid(productcode,squashed);
+ RegSetValueExW(hkey2, squashed, 0,REG_SZ,NULL,0);
+ RegCloseKey(hkey2);
- rc = MSIREG_OpenProductsKey(productcode,&hkey,TRUE);
- if (rc != ERROR_SUCCESS)
- goto end;
-
- rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
- if (rc != ERROR_SUCCESS)
- goto end;
-
-
- buffer = load_dynamic_property(package,szProductName,NULL);
- size = strlenW(buffer)*sizeof(WCHAR);
- RegSetValueExW(hukey,szProductName,0,REG_SZ, (LPSTR)buffer,size);
- HeapFree(GetProcessHeap(),0,buffer);
- FIXME("Need to write more keys to the user registry\n");
-
- hDb= alloc_msihandle( &package->db->hdr );
- rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
- MsiCloseHandle(hDb);
- if (rc == ERROR_SUCCESS)
- {
- WCHAR guidbuffer[0x200];
- size = 0x200;
- rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
- guidbuffer, &size);
- if (rc == ERROR_SUCCESS)
- {
- WCHAR squashed[GUID_SIZE];
- /* for now we only care about the first guid */
- LPWSTR ptr = strchrW(guidbuffer,';');
- if (ptr) *ptr = 0;
- squash_guid(guidbuffer,squashed);
- size = strlenW(squashed)*sizeof(WCHAR);
- RegSetValueExW(hukey,szPackageCode,0,REG_SZ, (LPSTR)squashed,
- size);
- }
- else
- {
- ERR("Unable to query Revision_Number... \n");
- rc = ERROR_SUCCESS;
- }
- MsiCloseHandle(hSumInfo);
- }
- else
- {
- ERR("Unable to open Summary Information\n");
- rc = ERROR_SUCCESS;
- }
-
-end:
-
- HeapFree(GetProcessHeap(),0,productcode);
- RegCloseKey(hkey);
- RegCloseKey(hukey);
-
- return rc;
-}
-
-static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
-{
- UINT rc;
- MSIQUERY * view;
- MSIRECORD * row = 0;
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','I','n','i','F','i','l','e','`',0};
- static const WCHAR szWindowsFolder[] =
- {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
-
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
- if (rc != ERROR_SUCCESS)
- {
- TRACE("no IniFile table\n");
- return ERROR_SUCCESS;
- }
-
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
-
- while (1)
- {
- LPWSTR component,filename,dirproperty,section,key,value,identifier;
- LPWSTR deformated_section, deformated_key, deformated_value;
- LPWSTR folder, fullname = NULL;
- MSIRECORD * uirow;
- INT component_index,action;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- component = load_dynamic_stringW(row, 8);
- component_index = get_loaded_component(package,component);
- HeapFree(GetProcessHeap(),0,component);
-
- if (!ACTION_VerifyComponentForAction(package, component_index,
- INSTALLSTATE_LOCAL))
- {
- TRACE("Skipping ini file due to disabled component\n");
- msiobj_release(&row->hdr);
-
- package->components[component_index].Action =
- package->components[component_index].Installed;
-
- continue;
- }
-
- package->components[component_index].Action = INSTALLSTATE_LOCAL;
-
- identifier = load_dynamic_stringW(row,1);
- filename = load_dynamic_stringW(row,2);
- dirproperty = load_dynamic_stringW(row,3);
- section = load_dynamic_stringW(row,4);
- key = load_dynamic_stringW(row,5);
- value = load_dynamic_stringW(row,6);
- action = MSI_RecordGetInteger(row,7);
-
- deformat_string(package,section,&deformated_section);
- deformat_string(package,key,&deformated_key);
- deformat_string(package,value,&deformated_value);
-
- if (dirproperty)
- {
- folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
- if (!folder)
- folder = load_dynamic_property(package,dirproperty,NULL);
- }
- else
- folder = load_dynamic_property(package, szWindowsFolder, NULL);
-
- if (!folder)
- {
- ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
- goto cleanup;
- }
-
- fullname = build_directory_name(3, folder, filename, NULL);
-
- if (action == 0)
- {
- TRACE("Adding value %s to section %s in %s\n",
- debugstr_w(deformated_key), debugstr_w(deformated_section),
- debugstr_w(fullname));
- WritePrivateProfileStringW(deformated_section, deformated_key,
- deformated_value, fullname);
- }
- else if (action == 1)
- {
- WCHAR returned[10];
- GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
- returned, 10, fullname);
- if (returned[0] == 0)
- {
- TRACE("Adding value %s to section %s in %s\n",
- debugstr_w(deformated_key), debugstr_w(deformated_section),
- debugstr_w(fullname));
-
- WritePrivateProfileStringW(deformated_section, deformated_key,
- deformated_value, fullname);
- }
- }
- else if (action == 3)
- {
- FIXME("Append to existing section not yet implemented\n");
- }
-
- uirow = MSI_CreateRecord(4);
- MSI_RecordSetStringW(uirow,1,identifier);
- MSI_RecordSetStringW(uirow,2,deformated_section);
- MSI_RecordSetStringW(uirow,3,deformated_key);
- MSI_RecordSetStringW(uirow,4,deformated_value);
- ui_actiondata(package,szWriteIniValues,uirow);
- msiobj_release( &uirow->hdr );
-cleanup:
- HeapFree(GetProcessHeap(),0,identifier);
- HeapFree(GetProcessHeap(),0,fullname);
- HeapFree(GetProcessHeap(),0,filename);
- HeapFree(GetProcessHeap(),0,key);
- HeapFree(GetProcessHeap(),0,value);
- HeapFree(GetProcessHeap(),0,section);
- HeapFree(GetProcessHeap(),0,dirproperty);
- HeapFree(GetProcessHeap(),0,folder);
- HeapFree(GetProcessHeap(),0,deformated_key);
- HeapFree(GetProcessHeap(),0,deformated_value);
- HeapFree(GetProcessHeap(),0,deformated_section);
- msiobj_release(&row->hdr);
- }
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
-}
-
-static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
-{
- UINT rc;
- MSIQUERY * view;
- MSIRECORD * row = 0;
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','S','e','l','f','R','e','g','`',0};
-
- static const WCHAR ExeStr[] =
- {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',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)
- {
- LPWSTR filename;
- INT index;
- DWORD len;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- filename = load_dynamic_stringW(row,1);
- index = get_loaded_file(package,filename);
-
- if (index < 0)
- {
- ERR("Unable to find file id %s\n",debugstr_w(filename));
- HeapFree(GetProcessHeap(),0,filename);
- msiobj_release(&row->hdr);
- continue;
- }
- HeapFree(GetProcessHeap(),0,filename);
-
- len = strlenW(ExeStr);
- len += strlenW(package->files[index].TargetPath);
- len +=2;
-
- filename = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
- strcpyW(filename,ExeStr);
- strcatW(filename,package->files[index].TargetPath);
- strcatW(filename,close);
-
- TRACE("Registering %s\n",debugstr_w(filename));
- brc = CreateProcessW(NULL, filename, NULL, NULL, FALSE, 0, NULL,
- c_colon, &si, &info);
-
- if (brc)
- msi_dialog_check_messages(info.hProcess);
-
- HeapFree(GetProcessHeap(),0,filename);
- msiobj_release(&row->hdr);
- }
- MSI_ViewClose(view);
- 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};
- 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);
-
-end:
- HeapFree(GetProcessHeap(),0,productcode);
- RegCloseKey(hkey);
-
- return ERROR_SUCCESS;
-}
-
-static UINT ACTION_InstallExecute(MSIPACKAGE *package)
-{
- int i;
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- for (i = 0; i < package->DeferredActionCount; i++)
- {
- LPWSTR action;
- action = package->DeferredAction[i];
- ui_actionstart(package, action);
- TRACE("Executing Action (%s)\n",debugstr_w(action));
- ACTION_CustomAction(package,action,TRUE);
- HeapFree(GetProcessHeap(),0,package->DeferredAction[i]);
- }
- HeapFree(GetProcessHeap(),0,package->DeferredAction);
-
- package->DeferredActionCount = 0;
- package->DeferredAction = NULL;
-
- return ERROR_SUCCESS;
-}
-
-static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
-{
- int i;
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- /* first do the same as an InstallExecute */
- ACTION_InstallExecute(package);
-
- /* then handle Commit Actions */
- for (i = 0; i < package->CommitActionCount; i++)
- {
- LPWSTR action;
- action = package->CommitAction[i];
- ui_actionstart(package, action);
- TRACE("Executing Commit Action (%s)\n",debugstr_w(action));
- ACTION_CustomAction(package,action,TRUE);
- HeapFree(GetProcessHeap(),0,package->CommitAction[i]);
- }
- HeapFree(GetProcessHeap(),0,package->CommitAction);
-
- package->CommitActionCount = 0;
- package->CommitAction = NULL;
-
- return ERROR_SUCCESS;
-}
-
-static UINT ACTION_ForceReboot(MSIPACKAGE *package)
-{
- static const WCHAR RunOnce[] = {
- 'S','o','f','t','w','a','r','e','\\',
- 'M','i','c','r','o','s','o','f','t','\\',
- 'W','i','n','d','o','w','s','\\',
- 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
- 'R','u','n','O','n','c','e',0};
- static const WCHAR InstallRunOnce[] = {
- 'S','o','f','t','w','a','r','e','\\',
- 'M','i','c','r','o','s','o','f','t','\\',
- 'W','i','n','d','o','w','s','\\',
- 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
- 'I','n','s','t','a','l','l','e','r','\\',
- 'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
-
- static const WCHAR msiexec_fmt[] = {
- '%','s',
- '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
- '\"','%','s','\"',0};
- static const WCHAR install_fmt[] = {
- '/','I',' ','\"','%','s','\"',' ',
- 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
- 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
- WCHAR buffer[256], sysdir[MAX_PATH];
- HKEY hkey,hukey;
- LPWSTR productcode;
- WCHAR squished_pc[100];
- INT rc;
- DWORD size;
- static const WCHAR szLUS[] = {
- 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0};
- static const WCHAR szSourceList[] = {
- 'S','o','u','r','c','e','L','i','s','t',0};
- static const WCHAR szPackageName[] = {
- 'P','a','c','k','a','g','e','N','a','m','e',0};
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- productcode = load_dynamic_property(package,szProductCode,&rc);
- if (!productcode)
- return rc;
-
- squash_guid(productcode,squished_pc);
-
- GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
- RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
- snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
- squished_pc);
-
- size = strlenW(buffer)*sizeof(WCHAR);
- RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
- RegCloseKey(hkey);
-
- TRACE("Reboot command %s\n",debugstr_w(buffer));
-
- RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
- sprintfW(buffer,install_fmt,productcode,squished_pc);
-
- size = strlenW(buffer)*sizeof(WCHAR);
- RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
- RegCloseKey(hkey);
-
- rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
- if (rc == ERROR_SUCCESS)
- {
- HKEY hukey2;
- LPWSTR buf;
- RegCreateKeyW(hukey, szSourceList, &hukey2);
- buf = load_dynamic_property(package,cszSourceDir,NULL);
- size = strlenW(buf)*sizeof(WCHAR);
- RegSetValueExW(hukey2,szLUS,0,REG_SZ,(LPSTR)buf,size);
- HeapFree(GetProcessHeap(),0,buf);
-
- buf = strrchrW(package->PackagePath,'\\');
- if (buf)
- {
- buf++;
- size = strlenW(buf)*sizeof(WCHAR);
- RegSetValueExW(hukey2,szPackageName,0,REG_SZ,(LPSTR)buf,size);
- }
-
- RegCloseKey(hukey2);
- }
- HeapFree(GetProcessHeap(),0,productcode);
-
- return ERROR_INSTALL_SUSPEND;
-}
-
-UINT ACTION_ResolveSource(MSIPACKAGE* package)
-{
- /*
- * we are currently doing what should be done here in the top level Install
- * however for Adminastrative and uninstalls this step will be needed
- */
- return ERROR_SUCCESS;
-}
-
-
-static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
-{
- UINT rc;
- MSIQUERY * view;
- MSIRECORD * row = 0;
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','E','x','t','e','n','s','i','o','n','`',0};
- static const WCHAR szContentType[] =
- {'C','o','n','t','e','n','t',' ','T','y','p','e',0 };
- HKEY hkey;
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- goto end;
- }
-
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- goto end;
- }
-
- while (1)
- {
- WCHAR buffer[0x100];
- WCHAR extension[257];
- LPWSTR exten;
- DWORD sz;
- INT index;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- sz=0x100;
- MSI_RecordGetStringW(row,2,buffer,&sz);
-
- index = get_loaded_component(package,buffer);
-
- if (index < 0)
- {
- msiobj_release(&row->hdr);
- continue;
- }
-
- if ((!ACTION_VerifyComponentForAction(package, index,
- INSTALLSTATE_LOCAL)) &&
- (!ACTION_VerifyComponentForAction(package, index,
- INSTALLSTATE_ADVERTISED)))
- {
- TRACE("Skipping extension reg due to disabled component\n");
- msiobj_release(&row->hdr);
-
- package->components[index].Action =
- package->components[index].Installed;
-
- continue;
- }
-
- package->components[index].Action = INSTALLSTATE_LOCAL;
-
- exten = load_dynamic_stringW(row,1);
- extension[0] = '.';
- extension[1] = 0;
- strcatW(extension,exten);
- HeapFree(GetProcessHeap(),0,exten);
-
- RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey);
-
- if (!MSI_RecordIsNull(row,4))
- {
- LPWSTR mime = load_dynamic_stringW(row,4);
- RegSetValueExW(hkey,szContentType,0,REG_SZ,(LPVOID)mime,
- (strlenW(mime)+1)*sizeof(WCHAR));
- HeapFree(GetProcessHeap(),0,mime);
- }
-
- if (!MSI_RecordIsNull(row,3))
- {
- static const WCHAR szSN[] =
- {'\\','S','h','e','l','l','N','e','w',0};
- HKEY hkey2;
- LPWSTR newkey;
- LPWSTR progid= load_dynamic_stringW(row,3);
-
- RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid,
- (strlenW(progid)+1)*sizeof(WCHAR));
-
- newkey = HeapAlloc(GetProcessHeap(),0,
- (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR));
-
- strcpyW(newkey,progid);
- strcatW(newkey,szSN);
- RegCreateKeyW(hkey,newkey,&hkey2);
- RegCloseKey(hkey2);
-
- HeapFree(GetProcessHeap(),0,progid);
- HeapFree(GetProcessHeap(),0,newkey);
- }
-
-
- RegCloseKey(hkey);
-
- ui_actiondata(package,szRegisterExtensionInfo,row);
-
- msiobj_release(&row->hdr);
- }
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
-
-end:
- return rc;
-}
-
-static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
-{
- UINT rc;
- MSIQUERY * view;
- MSIRECORD * row = 0;
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','M','I','M','E','`',0};
- static const WCHAR szExten[] =
- {'E','x','t','e','n','s','i','o','n',0 };
- HKEY hkey;
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- goto end;
- }
-
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- goto end;
- }
-
- while (1)
- {
- WCHAR extension[257];
- LPWSTR exten;
- LPWSTR mime;
- static const WCHAR fmt[] =
- {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\',
- 'C','o','n','t','e','n','t',' ','T','y','p','e','\\', '%','s',0};
- LPWSTR key;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- mime = load_dynamic_stringW(row,1);
- exten = load_dynamic_stringW(row,2);
- extension[0] = '.';
- extension[1] = 0;
- strcatW(extension,exten);
- HeapFree(GetProcessHeap(),0,exten);
-
- key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) *
- sizeof(WCHAR));
- sprintfW(key,fmt,mime);
- RegCreateKeyW(HKEY_CLASSES_ROOT,key,&hkey);
- RegSetValueExW(hkey,szExten,0,REG_SZ,(LPVOID)extension,
- (strlenW(extension)+1)*sizeof(WCHAR));
-
- HeapFree(GetProcessHeap(),0,mime);
- HeapFree(GetProcessHeap(),0,key);
-
- if (!MSI_RecordIsNull(row,3))
- {
- FIXME("Handle non null for field 3\n");
- }
-
- RegCloseKey(hkey);
-
- ui_actiondata(package,szRegisterMIMEInfo,row);
-
- msiobj_release(&row->hdr);
- }
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
-
-end:
- return rc;
-}
-
-static UINT ACTION_RegisterUser(MSIPACKAGE *package)
-{
- static const WCHAR szProductID[]=
- {'P','r','o','d','u','c','t','I','D',0};
- HKEY hkey=0;
- LPWSTR buffer;
- LPWSTR productcode;
- LPWSTR productid;
- UINT rc,i;
- DWORD size;
-
- static const WCHAR szPropKeys[][80] =
- {
- {'P','r','o','d','u','c','t','I','D',0},
- {'U','S','E','R','N','A','M','E',0},
- {'C','O','M','P','A','N','Y','N','A','M','E',0},
- {0},
- };
-
- static const WCHAR szRegKeys[][80] =
- {
- {'P','r','o','d','u','c','t','I','D',0},
- {'R','e','g','O','w','n','e','r',0},
- {'R','e','g','C','o','m','p','a','n','y',0},
- {0},
- };
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- productid = load_dynamic_property(package,szProductID,&rc);
- if (!productid)
- return ERROR_SUCCESS;
-
- productcode = load_dynamic_property(package,szProductCode,&rc);
- if (!productcode)
- return rc;
-
- rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);
- if (rc != ERROR_SUCCESS)
- goto end;
-
- i = 0;
- while (szPropKeys[i][0]!=0)
- {
- buffer = load_dynamic_property(package,szPropKeys[i],&rc);
- if (rc == ERROR_SUCCESS)
- {
- size = strlenW(buffer)*sizeof(WCHAR);
- RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size);
- }
- 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 const LPSTR tt = " (TrueType)";
-
- ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
- ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
- nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
- SetFilePointer(handle, tblDir.uOffset +
- ttRecord.uStringOffset +
- ttNTHeader.uStorageOffset,
- NULL, FILE_BEGIN);
- buf = HeapAlloc(GetProcessHeap(), 0,
- ttRecord.uStringLength + 1 + strlen(tt));
- memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
- ReadFile(handle, buf, ttRecord.uStringLength, NULL, NULL);
- if (strlen(buf) > 0)
- {
- strcat(buf,tt);
- ret = strdupAtoW(buf);
- HeapFree(GetProcessHeap(),0,buf);
- break;
- }
-
- HeapFree(GetProcessHeap(),0,buf);
- SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
- }
- }
- }
- CloseHandle(handle);
- }
- else
- ERR("Unable to open font file %s\n", debugstr_w(filename));
-
- TRACE("Returning fontname %s\n",debugstr_w(ret));
- return ret;
-}
-
-static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
-{
- UINT rc;
- MSIQUERY * view;
- MSIRECORD * row = 0;
- static const WCHAR ExecSeqQuery[] =
- {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
- '`','F','o','n','t','`',0};
- static const WCHAR regfont1[] =
- {'S','o','f','t','w','a','r','e','\\',
- 'M','i','c','r','o','s','o','f','t','\\',
- 'W','i','n','d','o','w','s',' ','N','T','\\',
- 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
- 'F','o','n','t','s',0};
- static const WCHAR regfont2[] =
- {'S','o','f','t','w','a','r','e','\\',
- 'M','i','c','r','o','s','o','f','t','\\',
- 'W','i','n','d','o','w','s','\\',
- 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
- 'F','o','n','t','s',0};
- HKEY hkey1;
- HKEY hkey2;
-
- TRACE("%p\n", package);
-
- rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
- if (rc != ERROR_SUCCESS)
- {
- TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
- return ERROR_SUCCESS;
- }
-
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- TRACE("MSI_ViewExecute returned %d\n", rc);
- return ERROR_SUCCESS;
- }
-
- RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
- RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
-
- while (1)
- {
- LPWSTR name;
- LPWSTR file;
- UINT index;
- DWORD size;
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
-
- file = load_dynamic_stringW(row,1);
- index = get_loaded_file(package,file);
- if (index < 0)
- {
- ERR("Unable to load file\n");
- HeapFree(GetProcessHeap(),0,file);
- continue;
- }
-
- /* check to make sure that component is installed */
- if (!ACTION_VerifyComponentForAction(package,
- package->files[index].ComponentIndex, INSTALLSTATE_LOCAL))
- {
- TRACE("Skipping: Component not scheduled for install\n");
- HeapFree(GetProcessHeap(),0,file);
-
- msiobj_release(&row->hdr);
-
- continue;
- }
-
- if (MSI_RecordIsNull(row,2))
- name = load_ttfname_from(package->files[index].TargetPath);
- else
- name = load_dynamic_stringW(row,2);
-
- if (name)
- {
- size = strlenW(package->files[index].FileName) * sizeof(WCHAR);
- RegSetValueExW(hkey1,name,0,REG_SZ,
- (LPBYTE)package->files[index].FileName,size);
- RegSetValueExW(hkey2,name,0,REG_SZ,
- (LPBYTE)package->files[index].FileName,size);
- }
-
- HeapFree(GetProcessHeap(),0,file);
- HeapFree(GetProcessHeap(),0,name);
- msiobj_release(&row->hdr);
- }
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
-
- RegCloseKey(hkey1);
- RegCloseKey(hkey2);
-
- TRACE("returning %d\n", rc);
- return rc;
-}
-
-static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
-{
- MSIPACKAGE *package = (MSIPACKAGE*)param;
- LPWSTR productid=NULL, compgroupid=NULL;
- LPWSTR feature=NULL;
- LPWSTR text = NULL;
- LPWSTR qualifier = NULL;
- LPWSTR component = NULL;
- GUID clsid;
- WCHAR productid_85[21];
- WCHAR component_85[21];
- HKEY hkey;
- UINT rc = ERROR_SUCCESS;
- UINT index;
- /*
- * I have a fair bit of confusion as to when a < is used and when a > is
- * used. I do not think i have it right...
- *
- * Ok it appears that the > is used if there is a guid for the compoenent
- * and the < is used if not.
- */
- static WCHAR fmt1[] = {'%','s','%','s','<',0,0};
- static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0};
- LPWSTR output = NULL;
- DWORD sz = 0;
- INT component_index;
-
- component = load_dynamic_stringW(rec,3);
- component_index = get_loaded_component(package,component);
-
- if (!ACTION_VerifyComponentForAction(package, component_index,
- INSTALLSTATE_LOCAL) &&
- !ACTION_VerifyComponentForAction(package, component_index,
- INSTALLSTATE_SOURCE) &&
- !ACTION_VerifyComponentForAction(package, component_index,
- INSTALLSTATE_ADVERTISED))
- {
- TRACE("Skipping: Component %s not scheduled for install\n",
- debugstr_w(component));
- HeapFree(GetProcessHeap(),0,component);
- return ERROR_SUCCESS;
+ HeapFree(GetProcessHeap(),0,upgrade_code);
}
-
- memset(productid_85,0,sizeof(productid_85));
- memset(component_85,0,sizeof(component_85));
- compgroupid = load_dynamic_stringW(rec,1);
-
- rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
- if (rc != ERROR_SUCCESS)
- goto end;
-
- productid = load_dynamic_property(package,szProductCode,NULL);
- CLSIDFromString(productid, &clsid);
-
- encode_base85_guid(&clsid,productid_85);
-
- text = load_dynamic_stringW(rec,4);
- qualifier = load_dynamic_stringW(rec,2);
-
- feature = load_dynamic_stringW(rec,5);
-
- index = get_loaded_component(package, component);
- CLSIDFromString(package->components[index].ComponentId, &clsid);
- encode_base85_guid(&clsid,component_85);
-
- TRACE("Doing something with this... %s = %s %s %s %s\n",
- debugstr_w(qualifier), debugstr_w(productid_85),
- debugstr_w(feature), debugstr_w(text), debugstr_w(component_85));
-
- sz = lstrlenW(productid_85) + lstrlenW(feature);
- if (text)
- sz += lstrlenW(text);
- if (component && index >= 0)
- sz += lstrlenW(component_85);
-
- sz+=3;
- sz *= sizeof(WCHAR);
-
- output = HeapAlloc(GetProcessHeap(),0,sz);
- memset(output,0,sz);
-
- if (component && index >= 0)
- sprintfW(output,fmt2,productid_85,feature,component_85);
- else
- sprintfW(output,fmt1,productid_85,feature);
-
- if (text)
- strcatW(output,text);
-
- sz = (lstrlenW(output)+2) * sizeof(WCHAR);
- RegSetValueExW(hkey, qualifier,0,REG_MULTI_SZ, (LPBYTE)output, sz);
end:
+ HeapFree(GetProcessHeap(),0,productcode);
RegCloseKey(hkey);
- HeapFree(GetProcessHeap(),0,output);
- HeapFree(GetProcessHeap(),0,compgroupid);
- HeapFree(GetProcessHeap(),0,component);
- HeapFree(GetProcessHeap(),0,productid);
- HeapFree(GetProcessHeap(),0,feature);
- HeapFree(GetProcessHeap(),0,text);
- HeapFree(GetProcessHeap(),0,qualifier);
-
- return rc;
-}
-
-/*
- * 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)
-{
- 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;
-
- rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
- msiobj_release(&view->hdr);
-
- return rc;
-}
-
-/* Msi functions that seem appropriate here */
-
-/***********************************************************************
- * MsiDoActionA (MSI.@)
- */
-UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
-{
- LPWSTR szwAction;
- UINT rc;
-
- TRACE(" exteral attempt at action %s\n",szAction);
-
- if (!szAction)
- return ERROR_FUNCTION_FAILED;
- if (hInstall == 0)
- return ERROR_FUNCTION_FAILED;
-
- szwAction = strdupAtoW(szAction);
-
- if (!szwAction)
- return ERROR_FUNCTION_FAILED;
-
-
- rc = MsiDoActionW(hInstall, szwAction);
- HeapFree(GetProcessHeap(),0,szwAction);
- return rc;
-}
-
-/***********************************************************************
- * MsiDoActionW (MSI.@)
- */
-UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
-{
- MSIPACKAGE *package;
- UINT ret = ERROR_INVALID_HANDLE;
-
- TRACE(" external attempt at action %s \n",debugstr_w(szAction));
- package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
- if( package )
- {
- ret = ACTION_PerformUIAction(package,szAction);
- msiobj_release( &package->hdr );
- }
- return ret;
+ return ERROR_SUCCESS;
}
-UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
- LPSTR szPathBuf, DWORD* pcchPathBuf)
+static UINT ACTION_InstallExecute(MSIPACKAGE *package)
{
- LPWSTR szwFolder;
- LPWSTR szwPathBuf;
UINT rc;
- 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;
+ rc = execute_script(package,INSTALL_SCRIPT);
- szwFolder = strdupAtoW(szFolder);
+ return rc;
+}
- if (!szwFolder)
- return ERROR_FUNCTION_FAILED;
+static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
+{
+ UINT rc;
- szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
+ if (!package)
+ return ERROR_INVALID_HANDLE;
- rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
+ /* turn off scheduleing */
+ package->script->CurrentlyScripting= FALSE;
- WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
- *pcchPathBuf, NULL, NULL );
+ /* first do the same as an InstallExecute */
+ rc = ACTION_InstallExecute(package);
+ if (rc != ERROR_SUCCESS)
+ return rc;
- HeapFree(GetProcessHeap(),0,szwFolder);
- HeapFree(GetProcessHeap(),0,szwPathBuf);
+ /* then handle Commit Actions */
+ rc = execute_script(package,COMMIT_SCRIPT);
return rc;
}
-UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
- szPathBuf, DWORD* pcchPathBuf)
+static UINT ACTION_ForceReboot(MSIPACKAGE *package)
{
- LPWSTR path;
- UINT rc = ERROR_FUNCTION_FAILED;
- 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};
- TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
+ 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};
- 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;
-}
+ productcode = load_dynamic_property(package,szProductCode,&rc);
+ if (!productcode)
+ return rc;
+ squash_guid(productcode,squished_pc);
-UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder,
- LPSTR szPathBuf, DWORD* pcchPathBuf)
-{
- LPWSTR szwFolder;
- LPWSTR szwPathBuf;
- 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("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
+ size = strlenW(buffer)*sizeof(WCHAR);
+ RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
+ RegCloseKey(hkey);
- if (!szFolder)
- return ERROR_FUNCTION_FAILED;
- if (hInstall == 0)
- return ERROR_FUNCTION_FAILED;
+ TRACE("Reboot command %s\n",debugstr_w(buffer));
- szwFolder = strdupAtoW(szFolder);
- if (!szwFolder)
- return ERROR_FUNCTION_FAILED;
+ RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
+ sprintfW(buffer,install_fmt,productcode,squished_pc);
- szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
+ size = strlenW(buffer)*sizeof(WCHAR);
+ RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
+ RegCloseKey(hkey);
- rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
+ 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);
- WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
- *pcchPathBuf, NULL, NULL );
+ buf = strrchrW(package->PackagePath,'\\');
+ if (buf)
+ {
+ buf++;
+ size = strlenW(buf)*sizeof(WCHAR);
+ RegSetValueExW(hukey2,szPackageName,0,REG_SZ,(LPSTR)buf,size);
+ }
- HeapFree(GetProcessHeap(),0,szwFolder);
- HeapFree(GetProcessHeap(),0,szwPathBuf);
+ RegCloseKey(hukey2);
+ }
+ HeapFree(GetProcessHeap(),0,productcode);
- return rc;
+ return ERROR_INSTALL_SUSPEND;
}
-UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
- szPathBuf, DWORD* pcchPathBuf)
+UINT ACTION_ResolveSource(MSIPACKAGE* package)
{
- LPWSTR path;
- UINT rc = ERROR_FUNCTION_FAILED;
- MSIPACKAGE *package;
-
- TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
+ /*
+ * 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;
+}
- package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
- if( !package )
- return ERROR_INVALID_HANDLE;
- path = resolve_folder(package, szFolder, TRUE, FALSE, NULL);
- msiobj_release( &package->hdr );
+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;
- if (path && strlenW(path) > *pcchPathBuf)
+ static const WCHAR szPropKeys[][80] =
{
- *pcchPathBuf = strlenW(path)+1;
- rc = ERROR_MORE_DATA;
- }
- else if (path)
+ {'P','r','o','d','u','c','t','I','D',0},
+ {'U','S','E','R','N','A','M','E',0},
+ {'C','O','M','P','A','N','Y','N','A','M','E',0},
+ {0},
+ };
+
+ static const WCHAR szRegKeys[][80] =
{
- *pcchPathBuf = strlenW(path)+1;
- strcpyW(szPathBuf,path);
- TRACE("Returning Path %s\n",debugstr_w(path));
- rc = ERROR_SUCCESS;
- }
- HeapFree(GetProcessHeap(),0,path);
-
- return rc;
-}
+ {'P','r','o','d','u','c','t','I','D',0},
+ {'R','e','g','O','w','n','e','r',0},
+ {'R','e','g','C','o','m','p','a','n','y',0},
+ {0},
+ };
+ if (!package)
+ return ERROR_INVALID_HANDLE;
-/***********************************************************************
- * MsiSetTargetPathA (MSI.@)
- */
-UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder,
- LPCSTR szFolderPath)
-{
- LPWSTR szwFolder;
- LPWSTR szwFolderPath;
- UINT rc;
+ productid = load_dynamic_property(package,szProductID,&rc);
+ if (!productid)
+ return ERROR_SUCCESS;
- if (!szFolder)
- return ERROR_FUNCTION_FAILED;
- if (hInstall == 0)
- return ERROR_FUNCTION_FAILED;
+ productcode = load_dynamic_property(package,szProductCode,&rc);
+ if (!productcode)
+ return rc;
- szwFolder = strdupAtoW(szFolder);
- if (!szwFolder)
- return ERROR_FUNCTION_FAILED;
+ rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);
+ if (rc != ERROR_SUCCESS)
+ goto end;
- szwFolderPath = strdupAtoW(szFolderPath);
- if (!szwFolderPath)
+ i = 0;
+ while (szPropKeys[i][0]!=0)
{
- HeapFree(GetProcessHeap(),0,szwFolder);
- return ERROR_FUNCTION_FAILED;
+ 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 = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);
-
- HeapFree(GetProcessHeap(),0,szwFolder);
- HeapFree(GetProcessHeap(),0,szwFolderPath);
+end:
+ HeapFree(GetProcessHeap(),0,productcode);
+ HeapFree(GetProcessHeap(),0,productid);
+ RegCloseKey(hkey);
- return rc;
+ return ERROR_SUCCESS;
}
-UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
- LPCWSTR szFolderPath)
+
+static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
{
- DWORD i;
- LPWSTR path = NULL;
- LPWSTR path2 = NULL;
- MSIFOLDER *folder;
+ static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
+ static const WCHAR szTwo[] = {'2',0};
+ UINT rc;
+ LPWSTR level;
+ level = load_dynamic_property(package,szUILevel,NULL);
- TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
+ MSI_SetPropertyW(package,szUILevel,szTwo);
+ rc = ACTION_ProcessExecSequence(package,FALSE);
+ MSI_SetPropertyW(package,szUILevel,level);
+ HeapFree(GetProcessHeap(),0,level);
+ return rc;
+}
- if (package==NULL)
- return ERROR_INVALID_HANDLE;
- if (szFolderPath[0]==0)
- return ERROR_FUNCTION_FAILED;
+/*
+ * 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;
- if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES)
- return ERROR_FUNCTION_FAILED;
+ typedef struct _tagTT_OFFSET_TABLE{
+ USHORT uMajorVersion;
+ USHORT uMinorVersion;
+ USHORT uNumOfTables;
+ USHORT uSearchRange;
+ USHORT uEntrySelector;
+ USHORT uRangeShift;
+ }TT_OFFSET_TABLE;
- path = resolve_folder(package,szFolder,FALSE,FALSE,&folder);
+ 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)
- return ERROR_INVALID_PARAMETER;
+ 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;
- HeapFree(GetProcessHeap(),0,folder->Property);
- folder->Property = build_directory_name(2, szFolderPath, NULL);
+#define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
+#define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
- 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
+ handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, 0 );
+ if (handle != INVALID_HANDLE_VALUE)
{
- for (i = 0; i < package->loaded_folders; i++)
- {
- HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
- package->folders[i].ResolvedTarget=NULL;
- }
+ 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 < package->loaded_folders; i++)
+ for (i=0; i< ttOffsetTable.uNumOfTables; i++)
{
- path2=resolve_folder(package, package->folders[i].Directory, FALSE,
- TRUE, NULL);
- HeapFree(GetProcessHeap(),0,path2);
+ 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;
+ }
}
- }
- 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;
-}
+ if (bFound)
+ {
+ TT_NAME_TABLE_HEADER ttNTHeader;
+ TT_NAME_RECORD ttRecord;
-/***********************************************************************
- * 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;
+ SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
+ ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
+ NULL,NULL);
- szwFeature = strdupAtoW(szFeature);
+ 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)";
- if (!szwFeature)
- return ERROR_FUNCTION_FAILED;
-
- rc = MsiSetFeatureStateW(hInstall,szwFeature, iState);
+ 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,szwFeature);
+ 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 MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
- INSTALLSTATE iState)
+static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param)
{
- INT index, i;
- UINT rc = ERROR_SUCCESS;
-
- TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
+ 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;
- index = get_loaded_feature(package,szFeature);
+ file = MSI_RecordGetString(row,1);
+ index = get_loaded_file(package,file);
if (index < 0)
- return ERROR_UNKNOWN_FEATURE;
-
- package->features[index].ActionRequest= iState;
- package->features[index].Action= iState;
-
- ACTION_UpdateComponentStates(package,szFeature);
-
- /* update all the features that are children of this feature */
- for (i = 0; i < package->loaded_features; i++)
{
- if (strcmpW(szFeature, package->features[i].Feature_Parent) == 0)
- MSI_SetFeatureStateW(package, package->features[i].Feature, iState);
+ ERR("Unable to load file\n");
+ return ERROR_SUCCESS;
}
-
- return rc;
-}
-/***********************************************************************
- * MsiSetFeatureStateW (MSI.@)
- */
-UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
- INSTALLSTATE iState)
-{
- MSIPACKAGE* package;
- UINT rc = ERROR_SUCCESS;
+ /* check to make sure that component is installed */
+ if (!ACTION_VerifyComponentForAction(package,
+ package->files[index].ComponentIndex, INSTALLSTATE_LOCAL))
+ {
+ TRACE("Skipping: Component not scheduled for install\n");
+ return ERROR_SUCCESS;
+ }
- TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
+ RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
+ RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
- package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
- if (!package)
- return ERROR_INVALID_HANDLE;
+ if (MSI_RecordIsNull(row,2))
+ name = load_ttfname_from(package->files[index].TargetPath);
+ else
+ name = load_dynamic_stringW(row,2);
- rc = MSI_SetFeatureStateW(package,szFeature,iState);
+ 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);
+ }
- msiobj_release( &package->hdr );
- return rc;
+ HeapFree(GetProcessHeap(),0,name);
+ RegCloseKey(hkey1);
+ RegCloseKey(hkey2);
+ return ERROR_SUCCESS;
}
-UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature,
- INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
+static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
{
- 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;
+ MSIQUERY * view;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','F','o','n','t','`',0};
- if (piAction)
- *piAction = package->features[index].Action;
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ {
+ TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
+ return ERROR_SUCCESS;
+ }
- TRACE("returning %i %i\n",*piInstalled,*piAction);
+ MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package);
+ msiobj_release(&view->hdr);
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)
+static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
{
- LPWSTR szwComponent= NULL;
- UINT rc;
-
- szwComponent= strdupAtoW(szComponent);
+ 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;
- rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
+ component = MSI_RecordGetString(rec,3);
+ index = get_loaded_component(package,component);
- HeapFree( GetProcessHeap(), 0 , szwComponent);
+ 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));
- return rc;
-}
+ return ERROR_SUCCESS;
+ }
-UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent,
- INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
-{
- INT index;
+ compgroupid = MSI_RecordGetString(rec,1);
- TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled,
-piAction);
+ rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
+ 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);
- index = get_loaded_component(package,szComponent);
- if (index < 0)
- return ERROR_UNKNOWN_COMPONENT;
+ sz = strlenW(advertise);
- if (piInstalled)
- *piInstalled = package->components[index].Installed;
+ if (text)
+ sz += lstrlenW(text);
- if (piAction)
- *piAction = package->components[index].Action;
+ sz+=3;
+ sz *= sizeof(WCHAR);
+
+ output = HeapAlloc(GetProcessHeap(),0,sz);
+ memset(output,0,sz);
+ strcpyW(output,advertise);
- TRACE("states (%i, %i)\n",
-(piInstalled)?*piInstalled:-1,(piAction)?*piAction:-1);
+ if (text)
+ strcatW(output,text);
- return ERROR_SUCCESS;
+ 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;
}
-/***********************************************************************
- * MsiGetComponentStateW (MSI.@)
+/*
+ * At present I am ignorning the advertised components part of this and only
+ * focusing on the qualified component sets
*/
-UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent,
- INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
-{
- MSIPACKAGE* package;
- UINT ret;
-
- TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
- piInstalled, piAction);
-
- package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
- if (!package)
- return ERROR_INVALID_HANDLE;
- ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
- msiobj_release( &package->hdr );
- return ret;
-}
-
-#if 0
-static UINT ACTION_Template(MSIPACKAGE *package)
+static UINT ACTION_PublishComponents(MSIPACKAGE *package)
{
UINT rc;
MSIQUERY * view;
- MSIRECORD * row = 0;
- static const WCHAR ExecSeqQuery[] = {0};
-
+ 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 rc;
-
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
-
- while (1)
- {
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- rc = ERROR_SUCCESS;
- break;
- }
+ return ERROR_SUCCESS;
- msiobj_release(&row->hdr);
- }
- MSI_ViewClose(view);
+ rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
msiobj_release(&view->hdr);
+
return rc;
}
-#endif
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define IDENTIFIER_SIZE 96
+
typedef struct tagMSIFEATURE
{
- WCHAR Feature[96];
- WCHAR Feature_Parent[96];
+ WCHAR Feature[IDENTIFIER_SIZE];
+ WCHAR Feature_Parent[IDENTIFIER_SIZE];
WCHAR Title[0x100];
WCHAR Description[0x100];
INT Display;
INT Level;
- WCHAR Directory[96];
+ WCHAR Directory[IDENTIFIER_SIZE];
INT Attributes;
INSTALLSTATE Installed;
typedef struct tagMSICOMPONENT
{
- WCHAR Component[96];
- WCHAR ComponentId[96];
- WCHAR Directory[96];
+ WCHAR Component[IDENTIFIER_SIZE];
+ WCHAR ComponentId[IDENTIFIER_SIZE];
+ WCHAR Directory[IDENTIFIER_SIZE];
INT Attributes;
WCHAR Condition[0x100];
- WCHAR KeyPath[96];
+ WCHAR KeyPath[IDENTIFIER_SIZE];
INSTALLSTATE Installed;
INSTALLSTATE ActionRequest;
INT RefCount;
LPWSTR FullKeypath;
+ LPWSTR AdvertiseString;
} MSICOMPONENT;
typedef struct tagMSIFOLDER
BOOL Temporary;
}MSIFILE;
+typedef struct tagMSICLASS
+{
+ WCHAR CLSID[IDENTIFIER_SIZE]; /* Primary Key */
+ WCHAR Context[IDENTIFIER_SIZE]; /* Primary Key */
+ INT ComponentIndex; /* Primary Key */
+ INT ProgIDIndex;
+ LPWSTR ProgIDText;
+ LPWSTR Description;
+ INT AppIDIndex;
+ LPWSTR FileTypeMask;
+ LPWSTR IconPath;
+ LPWSTR DefInprocHandler;
+ LPWSTR DefInprocHandler32;
+ LPWSTR Argument;
+ INT FeatureIndex;
+ INT Attributes;
+ /* not in the table, set during installation */
+ BOOL Installed;
+} MSICLASS;
+
+typedef struct tagMSIEXTENSION
+{
+ WCHAR Extension[256]; /* Primary Key */
+ INT ComponentIndex; /* Primary Key */
+ INT ProgIDIndex;
+ LPWSTR ProgIDText;
+ INT MIMEIndex;
+ INT FeatureIndex;
+ /* not in the table, set during installation */
+ BOOL Installed;
+ INT VerbCount;
+ INT Verbs[100]; /* yes hard coded limit, but realistically 100 verbs??? */
+} MSIEXTENSION;
+
+typedef struct tagMSIPROGID
+{
+ LPWSTR ProgID; /* Primary Key */
+ INT ParentIndex;
+ INT ClassIndex;
+ LPWSTR Description;
+ LPWSTR IconPath;
+ /* not in the table, set during installation */
+ BOOL InstallMe;
+ INT CurVerIndex;
+ INT VersionIndIndex;
+} MSIPROGID;
+
+typedef struct tagMSIVERB
+{
+ INT ExtensionIndex;
+ LPWSTR Verb;
+ INT Sequence;
+ LPWSTR Command;
+ LPWSTR Argument;
+} MSIVERB;
+
+typedef struct tagMSIMIME
+{
+ LPWSTR ContentType; /* Primary Key */
+ INT ExtensionIndex;
+ WCHAR CLSID[IDENTIFIER_SIZE];
+ INT ClassIndex;
+ /* not in the table, set during installation */
+ BOOL InstallMe;
+} MSIMIME;
+
+typedef struct tagMSIAPPID
+{
+ WCHAR AppID[IDENTIFIER_SIZE]; /* Primary key */
+ LPWSTR RemoteServerName;
+ LPWSTR LocalServer;
+ LPWSTR ServiceParameters;
+ LPWSTR DllSurrogate;
+ BOOL ActivateAtStorage;
+ BOOL RunAsInteractiveUser;
+} MSIAPPID;
+
+enum SCRIPTS {
+ INSTALL_SCRIPT = 0,
+ COMMIT_SCRIPT = 1,
+ ROLLBACK_SCRIPT = 2,
+ TOTAL_SCRIPTS = 3
+};
+
+typedef struct tagMSISCRIPT
+{
+ LPWSTR *Actions[TOTAL_SCRIPTS];
+ UINT ActionCount[TOTAL_SCRIPTS];
+ BOOL ExecuteSequenceRun;
+ BOOL FindRelatedProductsRun;
+ BOOL CurrentlyScripting;
+}MSISCRIPT;
+
-UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action);
+UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force);
UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action);
void ACTION_FinishCustomActions( MSIPACKAGE* package);
UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action, BOOL execute);
-void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature);
+
+/* 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);
int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature );
int get_loaded_file(MSIPACKAGE* package, LPCWSTR file);
int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path);
+UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action);
+UINT build_icon_path(MSIPACKAGE *, LPCWSTR, LPWSTR *);
+DWORD build_version_dword(LPCWSTR);
+LPWSTR build_directory_name(DWORD , ...);
+BOOL create_full_pathW(const WCHAR *path);
+BOOL ACTION_VerifyComponentForAction(MSIPACKAGE*, INT, INSTALLSTATE);
+BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE*, INT, INSTALLSTATE);
+void reduce_to_longfilename(WCHAR*);
+void reduce_to_shortfilename(WCHAR*);
+LPWSTR create_component_advertise_string(MSIPACKAGE*, MSICOMPONENT*, LPCWSTR);
+void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature);
+
+
+/* control event stuff */
+VOID ControlEvent_FireSubscribedEvent(MSIPACKAGE *package, LPCWSTR event,
+ MSIRECORD *data);
+VOID ControlEvent_CleanupSubscriptions(MSIPACKAGE *package);
+VOID ControlEvent_SubscribeToEvent(MSIPACKAGE *package, LPCWSTR event,
+ LPCWSTR control, LPCWSTR attribute);
+VOID ControlEvent_UnSubscribeToEvent( MSIPACKAGE *package, LPCWSTR event,
+ LPCWSTR control, LPCWSTR attribute );
+
+/* User Interface messages from the actions */
+void ui_progress(MSIPACKAGE *, int, int, int, int);
+void ui_actiondata(MSIPACKAGE *, LPCWSTR, MSIRECORD *);
+
+
+/* string consts use a number of places and defined in helpers.c*/
+extern const WCHAR cszSourceDir[];
+extern const WCHAR szProductCode[];
+extern const WCHAR cszRootDrive[];
+extern const WCHAR cszbs[];
--- /dev/null
+/*
+ * 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 const WCHAR szRegisterExtensionInfo[];
+extern const WCHAR szRegisterMIMEInfo[];
+
+extern const WCHAR szUnregisterClassInfo[];
+extern const WCHAR szUnregisterExtensionInfo[];
+extern const WCHAR szUnregisterMIMEInfo[];
+extern const WCHAR szUnregisterProgIdInfo[];
+
+static INT load_appid(MSIPACKAGE* package, MSIRECORD *row)
+{
+ DWORD index = package->loaded_appids;
+ DWORD sz;
+ LPCWSTR buffer;
+
+ /* fill in the data */
+
+ package->loaded_appids++;
+ if (package->loaded_appids == 1)
+ package->appids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIAPPID));
+ else
+ package->appids = HeapReAlloc(GetProcessHeap(),0,
+ package->appids, package->loaded_appids * sizeof(MSIAPPID));
+
+ memset(&package->appids[index],0,sizeof(MSIAPPID));
+
+ sz = IDENTIFIER_SIZE;
+ MSI_RecordGetStringW(row, 1, package->appids[index].AppID, &sz);
+ TRACE("loading appid %s\n",debugstr_w(package->appids[index].AppID));
+
+ buffer = MSI_RecordGetString(row,2);
+ deformat_string(package,buffer,&package->appids[index].RemoteServerName);
+
+ package->appids[index].LocalServer = load_dynamic_stringW(row,3);
+ package->appids[index].ServiceParameters = load_dynamic_stringW(row,4);
+ package->appids[index].DllSurrogate = load_dynamic_stringW(row,5);
+
+ package->appids[index].ActivateAtStorage = !MSI_RecordIsNull(row,6);
+ package->appids[index].RunAsInteractiveUser = !MSI_RecordIsNull(row,7);
+
+ return index;
+}
+
+static INT load_given_appid(MSIPACKAGE *package, LPCWSTR appid)
+{
+ INT rc;
+ MSIRECORD *row;
+ INT i;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','A','p','p','I','d','`',' ','W','H','E','R','E',' ',
+ '`','A','p','p','I','d','`',' ','=',' ','\'','%','s','\'',0};
+
+ if (!appid)
+ return -1;
+
+ /* check for appids already loaded */
+ for (i = 0; i < package->loaded_appids; i++)
+ if (strcmpiW(package->appids[i].AppID,appid)==0)
+ {
+ TRACE("found appid %s at index %i\n",debugstr_w(appid),i);
+ return i;
+ }
+
+ row = MSI_QueryGetRecord(package->db, ExecSeqQuery, appid);
+ if (!row)
+ return -1;
+
+ rc = load_appid(package, row);
+ msiobj_release(&row->hdr);
+
+ return rc;
+}
+
+static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid);
+static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid);
+
+static INT load_progid(MSIPACKAGE* package, MSIRECORD *row)
+{
+ DWORD index = package->loaded_progids;
+ LPCWSTR buffer;
+
+ /* fill in the data */
+
+ package->loaded_progids++;
+ if (package->loaded_progids == 1)
+ package->progids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIPROGID));
+ else
+ package->progids = HeapReAlloc(GetProcessHeap(),0,
+ package->progids , package->loaded_progids * sizeof(MSIPROGID));
+
+ memset(&package->progids[index],0,sizeof(MSIPROGID));
+
+ package->progids[index].ProgID = load_dynamic_stringW(row,1);
+ TRACE("loading progid %s\n",debugstr_w(package->progids[index].ProgID));
+
+ buffer = MSI_RecordGetString(row,2);
+ package->progids[index].ParentIndex = load_given_progid(package,buffer);
+ if (package->progids[index].ParentIndex < 0 && buffer)
+ FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer));
+
+ buffer = MSI_RecordGetString(row,3);
+ package->progids[index].ClassIndex = load_given_class(package,buffer);
+ if (package->progids[index].ClassIndex< 0 && buffer)
+ FIXME("Unknown class %s\n",debugstr_w(buffer));
+
+ package->progids[index].Description = load_dynamic_stringW(row,4);
+
+ if (!MSI_RecordIsNull(row,6))
+ {
+ INT icon_index = MSI_RecordGetInteger(row,6);
+ LPWSTR FileName = load_dynamic_stringW(row,5);
+ LPWSTR FilePath;
+ static const WCHAR fmt[] = {'%','s',',','%','i',0};
+
+ build_icon_path(package,FileName,&FilePath);
+
+ package->progids[index].IconPath =
+ HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+10)*
+ sizeof(WCHAR));
+
+ sprintfW(package->progids[index].IconPath,fmt,FilePath,icon_index);
+
+ HeapFree(GetProcessHeap(),0,FilePath);
+ HeapFree(GetProcessHeap(),0,FileName);
+ }
+ else
+ {
+ buffer = MSI_RecordGetString(row,5);
+ if (buffer)
+ build_icon_path(package,buffer,&(package->progids[index].IconPath));
+ }
+
+ package->progids[index].CurVerIndex = -1;
+ package->progids[index].VersionIndIndex = -1;
+
+ /* if we have a parent then we may be that parents CurVer */
+ if (package->progids[index].ParentIndex >= 0 &&
+ package->progids[index].ParentIndex != index)
+ {
+ int pindex = package->progids[index].ParentIndex;
+ while (package->progids[pindex].ParentIndex>= 0 &&
+ package->progids[pindex].ParentIndex != pindex)
+ pindex = package->progids[pindex].ParentIndex;
+
+ FIXME("BAD BAD need to determing if we are really the CurVer\n");
+
+ package->progids[index].CurVerIndex = pindex;
+ package->progids[pindex].VersionIndIndex = index;
+ }
+
+ return index;
+}
+
+static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid)
+{
+ INT rc;
+ MSIRECORD *row;
+ INT i;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','P','r','o','g','I','d','`',' ','W','H','E','R','E',' ',
+ '`','P','r','o','g','I','d','`',' ','=',' ','\'','%','s','\'',0};
+
+ if (!progid)
+ return -1;
+
+ /* check for progids already loaded */
+ for (i = 0; i < package->loaded_progids; i++)
+ if (strcmpiW(package->progids[i].ProgID,progid)==0)
+ {
+ TRACE("found progid %s at index %i\n",debugstr_w(progid), i);
+ return i;
+ }
+
+ row = MSI_QueryGetRecord(package->db, ExecSeqQuery, progid);
+ if(!row)
+ return -1;
+
+ rc = load_progid(package, row);
+ msiobj_release(&row->hdr);
+
+ return rc;
+}
+
+static INT load_class(MSIPACKAGE* package, MSIRECORD *row)
+{
+ DWORD index = package->loaded_classes;
+ DWORD sz,i;
+ LPCWSTR buffer;
+
+ /* fill in the data */
+
+ package->loaded_classes++;
+ if (package->loaded_classes== 1)
+ package->classes = HeapAlloc(GetProcessHeap(),0,sizeof(MSICLASS));
+ else
+ package->classes = HeapReAlloc(GetProcessHeap(),0,
+ package->classes, package->loaded_classes * sizeof(MSICLASS));
+
+ memset(&package->classes[index],0,sizeof(MSICLASS));
+
+ sz = IDENTIFIER_SIZE;
+ MSI_RecordGetStringW(row, 1, package->classes[index].CLSID, &sz);
+ TRACE("loading class %s\n",debugstr_w(package->classes[index].CLSID));
+ sz = IDENTIFIER_SIZE;
+ MSI_RecordGetStringW(row, 2, package->classes[index].Context, &sz);
+ buffer = MSI_RecordGetString(row,3);
+ package->classes[index].ComponentIndex = get_loaded_component(package,
+ buffer);
+
+ package->classes[index].ProgIDText = load_dynamic_stringW(row,4);
+ package->classes[index].ProgIDIndex =
+ load_given_progid(package, package->classes[index].ProgIDText);
+
+ package->classes[index].Description = load_dynamic_stringW(row,5);
+
+ buffer = MSI_RecordGetString(row,6);
+ if (buffer)
+ package->classes[index].AppIDIndex =
+ load_given_appid(package, buffer);
+ else
+ package->classes[index].AppIDIndex = -1;
+
+ package->classes[index].FileTypeMask = load_dynamic_stringW(row,7);
+
+ if (!MSI_RecordIsNull(row,9))
+ {
+
+ INT icon_index = MSI_RecordGetInteger(row,9);
+ LPWSTR FileName = load_dynamic_stringW(row,8);
+ LPWSTR FilePath;
+ static const WCHAR fmt[] = {'%','s',',','%','i',0};
+
+ build_icon_path(package,FileName,&FilePath);
+
+ package->classes[index].IconPath =
+ HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)*
+ sizeof(WCHAR));
+
+ sprintfW(package->classes[index].IconPath,fmt,FilePath,icon_index);
+
+ HeapFree(GetProcessHeap(),0,FilePath);
+ HeapFree(GetProcessHeap(),0,FileName);
+ }
+ else
+ {
+ buffer = MSI_RecordGetString(row,8);
+ if (buffer)
+ build_icon_path(package,buffer,&(package->classes[index].IconPath));
+ }
+
+ if (!MSI_RecordIsNull(row,10))
+ {
+ i = MSI_RecordGetInteger(row,10);
+ if (i != MSI_NULL_INTEGER && i > 0 && i < 4)
+ {
+ static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0};
+ static const WCHAR ole32[] = {'o','l','e','3','2','.','d','l','l',0};
+
+ switch(i)
+ {
+ case 1:
+ package->classes[index].DefInprocHandler = strdupW(ole2);
+ break;
+ case 2:
+ package->classes[index].DefInprocHandler32 = strdupW(ole32);
+ break;
+ case 3:
+ package->classes[index].DefInprocHandler = strdupW(ole2);
+ package->classes[index].DefInprocHandler32 = strdupW(ole32);
+ break;
+ }
+ }
+ else
+ {
+ package->classes[index].DefInprocHandler32 = load_dynamic_stringW(
+ row, 10);
+ reduce_to_longfilename(package->classes[index].DefInprocHandler32);
+ }
+ }
+ buffer = MSI_RecordGetString(row,11);
+ deformat_string(package,buffer,&package->classes[index].Argument);
+
+ buffer = MSI_RecordGetString(row,12);
+ package->classes[index].FeatureIndex = get_loaded_feature(package,buffer);
+
+ package->classes[index].Attributes = MSI_RecordGetInteger(row,13);
+
+ return index;
+}
+
+/*
+ * the Class table has 3 primary keys. Generally it is only
+ * referenced through the first CLSID key. However when loading
+ * all of the classes we need to make sure we do not ignore rows
+ * with other Context and ComponentIndexs
+ */
+static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid)
+{
+ INT rc;
+ MSIRECORD *row;
+ INT i;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','C','l','a','s','s','`',' ','W','H','E','R','E',' ',
+ '`','C','L','S','I','D','`',' ','=',' ','\'','%','s','\'',0};
+
+
+ if (!classid)
+ return -1;
+
+ /* check for classes already loaded */
+ for (i = 0; i < package->loaded_classes; i++)
+ if (strcmpiW(package->classes[i].CLSID,classid)==0)
+ {
+ TRACE("found class %s at index %i\n",debugstr_w(classid), i);
+ return i;
+ }
+
+ row = MSI_QueryGetRecord(package->db, ExecSeqQuery, classid);
+ if (!row)
+ return -1;
+
+ rc = load_class(package, row);
+ msiobj_release(&row->hdr);
+
+ return rc;
+}
+
+static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension);
+
+static INT load_mime(MSIPACKAGE* package, MSIRECORD *row)
+{
+ DWORD index = package->loaded_mimes;
+ DWORD sz;
+ LPCWSTR buffer;
+
+ /* fill in the data */
+
+ package->loaded_mimes++;
+ if (package->loaded_mimes== 1)
+ package->mimes= HeapAlloc(GetProcessHeap(),0,sizeof(MSIMIME));
+ else
+ package->mimes= HeapReAlloc(GetProcessHeap(),0,
+ package->mimes, package->loaded_mimes*
+ sizeof(MSIMIME));
+
+ memset(&package->mimes[index],0,sizeof(MSIMIME));
+
+ package->mimes[index].ContentType = load_dynamic_stringW(row,1);
+ TRACE("loading mime %s\n",debugstr_w(package->mimes[index].ContentType));
+
+ buffer = MSI_RecordGetString(row,2);
+ package->mimes[index].ExtensionIndex = load_given_extension(package,
+ buffer);
+
+ sz = IDENTIFIER_SIZE;
+ MSI_RecordGetStringW(row,3,package->mimes[index].CLSID,&sz);
+ package->mimes[index].ClassIndex= load_given_class(package,
+ package->mimes[index].CLSID);
+
+ return index;
+}
+
+static INT load_given_mime(MSIPACKAGE *package, LPCWSTR mime)
+{
+ INT rc;
+ MSIRECORD *row;
+ INT i;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','M','I','M','E','`',' ','W','H','E','R','E',' ',
+ '`','C','o','n','t','e','n','t','T','y','p','e','`',' ','=',' ',
+ '\'','%','s','\'',0};
+
+ if (!mime)
+ return -1;
+
+ /* check for mime already loaded */
+ for (i = 0; i < package->loaded_mimes; i++)
+ if (strcmpiW(package->mimes[i].ContentType,mime)==0)
+ {
+ TRACE("found mime %s at index %i\n",debugstr_w(mime), i);
+ return i;
+ }
+
+ row = MSI_QueryGetRecord(package->db, ExecSeqQuery, mime);
+ if (!row)
+ return -1;
+
+ rc = load_mime(package, row);
+ msiobj_release(&row->hdr);
+
+ return rc;
+}
+
+static INT load_extension(MSIPACKAGE* package, MSIRECORD *row)
+{
+ DWORD index = package->loaded_extensions;
+ DWORD sz;
+ LPCWSTR buffer;
+
+ /* fill in the data */
+
+ package->loaded_extensions++;
+ if (package->loaded_extensions == 1)
+ package->extensions = HeapAlloc(GetProcessHeap(),0,sizeof(MSIEXTENSION));
+ else
+ package->extensions = HeapReAlloc(GetProcessHeap(),0,
+ package->extensions, package->loaded_extensions*
+ sizeof(MSIEXTENSION));
+
+ memset(&package->extensions[index],0,sizeof(MSIEXTENSION));
+
+ sz = 256;
+ MSI_RecordGetStringW(row,1,package->extensions[index].Extension,&sz);
+ TRACE("loading extension %s\n",
+ debugstr_w(package->extensions[index].Extension));
+
+ buffer = MSI_RecordGetString(row,2);
+ package->extensions[index].ComponentIndex =
+ get_loaded_component(package,buffer);
+
+ package->extensions[index].ProgIDText = load_dynamic_stringW(row,3);
+ package->extensions[index].ProgIDIndex = load_given_progid(package,
+ package->extensions[index].ProgIDText);
+
+ buffer = MSI_RecordGetString(row,4);
+ package->extensions[index].MIMEIndex = load_given_mime(package,buffer);
+
+ buffer = MSI_RecordGetString(row,5);
+ package->extensions[index].FeatureIndex =
+ get_loaded_feature(package,buffer);
+
+ return index;
+}
+
+/*
+ * While the extension table has 2 primary keys, this function is only looking
+ * at the Extension key which is what is referenced as a forign key
+ */
+static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension)
+{
+ INT rc;
+ MSIRECORD *row;
+ INT i;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','E','x','t','e','n','s','i','o','n','`',' ',
+ 'W','H','E','R','E',' ',
+ '`','E','x','t','e','n','s','i','o','n','`',' ','=',' ',
+ '\'','%','s','\'',0};
+
+ if (!extension)
+ return -1;
+
+ /* check for extensions already loaded */
+ for (i = 0; i < package->loaded_extensions; i++)
+ if (strcmpiW(package->extensions[i].Extension,extension)==0)
+ {
+ TRACE("extension %s already loaded at %i\n",debugstr_w(extension),
+ i);
+ return i;
+ }
+
+ row = MSI_QueryGetRecord(package->db, ExecSeqQuery, extension);
+ if (!row)
+ return -1;
+
+ rc = load_extension(package, row);
+ msiobj_release(&row->hdr);
+
+ return rc;
+}
+
+static UINT iterate_load_verb(MSIRECORD *row, LPVOID param)
+{
+ MSIPACKAGE* package = (MSIPACKAGE*)param;
+ DWORD index = package->loaded_verbs;
+ LPCWSTR buffer;
+
+ /* fill in the data */
+
+ package->loaded_verbs++;
+ if (package->loaded_verbs == 1)
+ package->verbs = HeapAlloc(GetProcessHeap(),0,sizeof(MSIVERB));
+ else
+ package->verbs = HeapReAlloc(GetProcessHeap(),0,
+ package->verbs , package->loaded_verbs * sizeof(MSIVERB));
+
+ memset(&package->verbs[index],0,sizeof(MSIVERB));
+
+ buffer = MSI_RecordGetString(row,1);
+ package->verbs[index].ExtensionIndex = load_given_extension(package,buffer);
+ if (package->verbs[index].ExtensionIndex < 0 && buffer)
+ ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer));
+
+ package->verbs[index].Verb = load_dynamic_stringW(row,2);
+ TRACE("loading verb %s\n",debugstr_w(package->verbs[index].Verb));
+ package->verbs[index].Sequence = MSI_RecordGetInteger(row,3);
+
+ buffer = MSI_RecordGetString(row,4);
+ deformat_string(package,buffer,&package->verbs[index].Command);
+
+ buffer = MSI_RecordGetString(row,5);
+ deformat_string(package,buffer,&package->verbs[index].Argument);
+
+ /* assosiate the verb with the correct extension */
+ if (package->verbs[index].ExtensionIndex >= 0)
+ {
+ MSIEXTENSION* extension = &package->extensions[package->verbs[index].
+ ExtensionIndex];
+ int count = extension->VerbCount;
+
+ if (count >= 99)
+ FIXME("Exceeding max verb count! Increase that limit!!!\n");
+ else
+ {
+ extension->VerbCount++;
+ extension->Verbs[count] = index;
+ }
+ }
+
+ return ERROR_SUCCESS;
+}
+
+static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param)
+{
+ LPCWSTR clsid;
+ LPCWSTR context;
+ LPCWSTR buffer;
+ INT component_index;
+ MSIPACKAGE* package =(MSIPACKAGE*)param;
+ INT i;
+ BOOL match = FALSE;
+
+ clsid = MSI_RecordGetString(rec,1);
+ context = MSI_RecordGetString(rec,2);
+ buffer = MSI_RecordGetString(rec,3);
+ component_index = get_loaded_component(package,buffer);
+
+ for (i = 0; i < package->loaded_classes; i++)
+ {
+ if (strcmpiW(clsid,package->classes[i].CLSID))
+ continue;
+ if (strcmpW(context,package->classes[i].Context))
+ continue;
+ if (component_index == package->classes[i].ComponentIndex)
+ {
+ match = TRUE;
+ break;
+ }
+ }
+
+ if (!match)
+ load_class(package, rec);
+
+ return ERROR_SUCCESS;
+}
+
+static VOID load_all_classes(MSIPACKAGE *package)
+{
+ UINT rc = ERROR_SUCCESS;
+ MSIQUERY *view;
+
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
+ '`','C','l','a','s','s','`',0};
+
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return;
+
+ rc = MSI_IterateRecords(view, NULL, iterate_all_classes, package);
+ msiobj_release(&view->hdr);
+}
+
+static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param)
+{
+ LPCWSTR buffer;
+ LPCWSTR extension;
+ INT component_index;
+ MSIPACKAGE* package =(MSIPACKAGE*)param;
+ BOOL match = FALSE;
+ INT i;
+
+ extension = MSI_RecordGetString(rec,1);
+ buffer = MSI_RecordGetString(rec,2);
+ component_index = get_loaded_component(package,buffer);
+
+ for (i = 0; i < package->loaded_extensions; i++)
+ {
+ if (strcmpiW(extension,package->extensions[i].Extension))
+ continue;
+ if (component_index == package->extensions[i].ComponentIndex)
+ {
+ match = TRUE;
+ break;
+ }
+ }
+
+ if (!match)
+ load_extension(package, rec);
+
+ return ERROR_SUCCESS;
+}
+
+static VOID load_all_extensions(MSIPACKAGE *package)
+{
+ UINT rc = ERROR_SUCCESS;
+ MSIQUERY *view;
+
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','E','x','t','e','n','s','i','o','n','`',0};
+
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return;
+
+ rc = MSI_IterateRecords(view, NULL, iterate_all_extensions, package);
+ msiobj_release(&view->hdr);
+}
+
+static UINT iterate_all_progids(MSIRECORD *rec, LPVOID param)
+{
+ LPCWSTR buffer;
+ MSIPACKAGE* package =(MSIPACKAGE*)param;
+
+ buffer = MSI_RecordGetString(rec,1);
+ load_given_progid(package,buffer);
+ return ERROR_SUCCESS;
+}
+
+static VOID load_all_progids(MSIPACKAGE *package)
+{
+ UINT rc = ERROR_SUCCESS;
+ MSIQUERY *view;
+
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ',
+ 'F','R','O','M',' ', '`','P','r','o','g','I','d','`',0};
+
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return;
+
+ rc = MSI_IterateRecords(view, NULL, iterate_all_progids, package);
+ msiobj_release(&view->hdr);
+}
+
+static VOID load_all_verbs(MSIPACKAGE *package)
+{
+ UINT rc = ERROR_SUCCESS;
+ MSIQUERY *view;
+
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','V','e','r','b','`',0};
+
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return;
+
+ rc = MSI_IterateRecords(view, NULL, iterate_load_verb, package);
+ msiobj_release(&view->hdr);
+}
+
+static UINT iterate_all_mimes(MSIRECORD *rec, LPVOID param)
+{
+ LPCWSTR buffer;
+ MSIPACKAGE* package =(MSIPACKAGE*)param;
+
+ buffer = MSI_RecordGetString(rec,1);
+ load_given_mime(package,buffer);
+ return ERROR_SUCCESS;
+}
+
+static VOID load_all_mimes(MSIPACKAGE *package)
+{
+ UINT rc = ERROR_SUCCESS;
+ MSIQUERY *view;
+
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ',
+ '`','C','o','n','t','e','n','t','T','y','p','e','`',
+ ' ','F','R','O','M',' ',
+ '`','M','I','M','E','`',0};
+
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return;
+
+ rc = MSI_IterateRecords(view, NULL, iterate_all_mimes, package);
+ msiobj_release(&view->hdr);
+}
+
+static void load_classes_and_such(MSIPACKAGE *package)
+{
+ TRACE("Loading all the class info and related tables\n");
+
+ /* check if already loaded */
+ if (package->classes || package->extensions || package->progids ||
+ package->verbs || package->mimes)
+ return;
+
+ load_all_classes(package);
+ load_all_extensions(package);
+ load_all_progids(package);
+ /* these loads must come after the other loads */
+ load_all_verbs(package);
+ load_all_mimes(package);
+}
+
+static void mark_progid_for_install(MSIPACKAGE* package, INT index)
+{
+ MSIPROGID* progid;
+ int i;
+
+ if (index < 0 || index >= package->loaded_progids)
+ return;
+
+ progid = &package->progids[index];
+
+ if (progid->InstallMe == TRUE)
+ return;
+
+ progid->InstallMe = TRUE;
+
+ /* all children if this is a parent also install */
+ for (i = 0; i < package->loaded_progids; i++)
+ if (package->progids[i].ParentIndex == index)
+ mark_progid_for_install(package,i);
+}
+
+static void mark_mime_for_install(MSIPACKAGE* package, INT index)
+{
+ MSIMIME* mime;
+
+ if (index < 0 || index >= package->loaded_mimes)
+ return;
+
+ mime = &package->mimes[index];
+
+ if (mime->InstallMe == TRUE)
+ return;
+
+ mime->InstallMe = TRUE;
+}
+
+static UINT register_appid(MSIPACKAGE *package, int appidIndex, LPCWSTR app )
+{
+ static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
+ HKEY hkey2,hkey3;
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
+ RegCreateKeyW(hkey2,package->appids[appidIndex].AppID,&hkey3);
+ RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
+ (strlenW(app)+1)*sizeof(WCHAR));
+
+ if (package->appids[appidIndex].RemoteServerName)
+ {
+ UINT size;
+ static const WCHAR szRemoteServerName[] =
+ {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',
+ 0};
+
+ size = (strlenW(package->appids[appidIndex].RemoteServerName)+1) *
+ sizeof(WCHAR);
+
+ RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,
+ (LPVOID)package->appids[appidIndex].RemoteServerName,
+ size);
+ }
+
+ if (package->appids[appidIndex].LocalServer)
+ {
+ static const WCHAR szLocalService[] =
+ {'L','o','c','a','l','S','e','r','v','i','c','e',0};
+ UINT size;
+ size = (strlenW(package->appids[appidIndex].LocalServer)+1) *
+ sizeof(WCHAR);
+
+ RegSetValueExW(hkey3,szLocalService,0,REG_SZ,
+ (LPVOID)package->appids[appidIndex].LocalServer,size);
+ }
+
+ if (package->appids[appidIndex].ServiceParameters)
+ {
+ static const WCHAR szService[] =
+ {'S','e','r','v','i','c','e',
+ 'P','a','r','a','m','e','t','e','r','s',0};
+ UINT size;
+ size = (strlenW(package->appids[appidIndex].ServiceParameters)+1) *
+ sizeof(WCHAR);
+ RegSetValueExW(hkey3,szService,0,REG_SZ,
+ (LPVOID)package->appids[appidIndex].ServiceParameters,
+ size);
+ }
+
+ if (package->appids[appidIndex].DllSurrogate)
+ {
+ static const WCHAR szDLL[] =
+ {'D','l','l','S','u','r','r','o','g','a','t','e',0};
+ UINT size;
+ size = (strlenW(package->appids[appidIndex].DllSurrogate)+1) *
+ sizeof(WCHAR);
+ RegSetValueExW(hkey3,szDLL,0,REG_SZ,
+ (LPVOID)package->appids[appidIndex].DllSurrogate,size);
+ }
+
+ if (package->appids[appidIndex].ActivateAtStorage)
+ {
+ static const WCHAR szActivate[] =
+ {'A','c','t','i','v','a','t','e','A','s',
+ 'S','t','o','r','a','g','e',0};
+ static const WCHAR szY[] = {'Y',0};
+
+ RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
+ }
+
+ if (package->appids[appidIndex].RunAsInteractiveUser)
+ {
+ static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
+ static const WCHAR szUser[] =
+ {'I','n','t','e','r','a','c','t','i','v','e',' ',
+ 'U','s','e','r',0};
+
+ RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,sizeof(szUser));
+ }
+
+ RegCloseKey(hkey3);
+ RegCloseKey(hkey2);
+ return ERROR_SUCCESS;
+}
+
+UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
+{
+ /*
+ * Again I am assuming the words, "Whose key file represents" when referring
+ * to a Component as to meaning that Components KeyPath file
+ */
+
+ UINT rc;
+ MSIRECORD *uirow;
+ static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
+ static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
+ static const WCHAR szVIProgID[] = { 'V','e','r','s','i','o','n','I','n','d','e','p','e','n','d','e','n','t','P','r','o','g','I','D',0 };
+ static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
+ static const WCHAR szSpace[] = {' ',0};
+ static const WCHAR szInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
+ static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0};
+ HKEY hkey,hkey2,hkey3;
+ BOOL install_on_demand = FALSE;
+ int i;
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ load_classes_and_such(package);
+ rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
+ if (rc != ERROR_SUCCESS)
+ return ERROR_FUNCTION_FAILED;
+
+ /* install_on_demand should be set if OLE supports install on demand OLE
+ * servers. For now i am defaulting to FALSE because i do not know how to
+ * check, and i am told our builtin OLE does not support it
+ */
+
+ for (i = 0; i < package->loaded_classes; i++)
+ {
+ INT index,f_index;
+ DWORD size, sz;
+ LPWSTR argument;
+
+ if (package->classes[i].ComponentIndex < 0)
+ {
+ continue;
+ }
+
+ index = package->classes[i].ComponentIndex;
+ f_index = package->classes[i].FeatureIndex;
+
+ /*
+ * yes. MSDN says that these are based on _Feature_ not on
+ * Component. So verify the feature is to be installed
+ */
+ if ((!ACTION_VerifyFeatureForAction(package, f_index,
+ INSTALLSTATE_LOCAL)) &&
+ !(install_on_demand && ACTION_VerifyFeatureForAction(package,
+ f_index, INSTALLSTATE_ADVERTISED)))
+ {
+ TRACE("Skipping class %s reg due to disabled feature %s\n",
+ debugstr_w(package->classes[i].CLSID),
+ debugstr_w(package->features[f_index].Feature));
+
+ continue;
+ }
+
+ TRACE("Registering index %i class %s\n",i,
+ debugstr_w(package->classes[i].CLSID));
+
+ package->classes[i].Installed = TRUE;
+ if (package->classes[i].ProgIDIndex >= 0)
+ mark_progid_for_install(package, package->classes[i].ProgIDIndex);
+
+ RegCreateKeyW(hkey,package->classes[i].CLSID,&hkey2);
+
+ if (package->classes[i].Description)
+ RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)package->classes[i].
+ Description, (strlenW(package->classes[i].
+ Description)+1)*sizeof(WCHAR));
+
+ RegCreateKeyW(hkey2,package->classes[i].Context,&hkey3);
+ index = get_loaded_file(package,package->components[index].KeyPath);
+
+
+ /* the context server is a short path name
+ * except for if it is InprocServer32...
+ */
+ if (strcmpiW(package->classes[i].Context,szInprocServer32)!=0)
+ {
+ sz = 0;
+ sz = GetShortPathNameW(package->files[index].TargetPath, NULL, 0);
+ if (sz == 0)
+ {
+ ERR("Unable to find short path for CLSID COM Server\n");
+ argument = NULL;
+ }
+ else
+ {
+ size = sz * sizeof(WCHAR);
+
+ if (package->classes[i].Argument)
+ {
+ size += strlenW(package->classes[i].Argument) *
+ sizeof(WCHAR);
+ size += sizeof(WCHAR);
+ }
+
+ argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
+ GetShortPathNameW(package->files[index].TargetPath, argument,
+ sz);
+
+ if (package->classes[i].Argument)
+ {
+ strcatW(argument,szSpace);
+ strcatW(argument,package->classes[i].Argument);
+ }
+ }
+ }
+ else
+ {
+ size = lstrlenW(package->files[index].TargetPath) * sizeof(WCHAR);
+
+ if (package->classes[i].Argument)
+ {
+ size += strlenW(package->classes[i].Argument) * sizeof(WCHAR);
+ size += sizeof(WCHAR);
+ }
+
+ argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
+ strcpyW(argument, package->files[index].TargetPath);
+
+ if (package->classes[i].Argument)
+ {
+ strcatW(argument,szSpace);
+ strcatW(argument,package->classes[i].Argument);
+ }
+ }
+
+ if (argument)
+ {
+ RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size);
+ HeapFree(GetProcessHeap(),0,argument);
+ }
+
+ RegCloseKey(hkey3);
+
+ if (package->classes[i].ProgIDIndex >= 0 ||
+ package->classes[i].ProgIDText)
+ {
+ LPCWSTR progid;
+
+ if (package->classes[i].ProgIDIndex >= 0)
+ progid = package->progids[
+ package->classes[i].ProgIDIndex].ProgID;
+ else
+ progid = package->classes[i].ProgIDText;
+
+ RegCreateKeyW(hkey2,szProgID,&hkey3);
+ RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)progid,
+ (strlenW(progid)+1) *sizeof(WCHAR));
+ RegCloseKey(hkey3);
+
+ if (package->classes[i].ProgIDIndex >= 0 &&
+ package->progids[package->classes[i].ProgIDIndex].
+ VersionIndIndex >= 0)
+ {
+ LPWSTR viprogid = strdupW(package->progids[package->progids[
+ package->classes[i].ProgIDIndex].VersionIndIndex].
+ ProgID);
+ RegCreateKeyW(hkey2,szVIProgID,&hkey3);
+ RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)viprogid,
+ (strlenW(viprogid)+1) *sizeof(WCHAR));
+ RegCloseKey(hkey3);
+ HeapFree(GetProcessHeap(), 0, viprogid);
+ }
+ }
+
+ if (package->classes[i].AppIDIndex >= 0)
+ {
+ RegSetValueExW(hkey2,szAppID,0,REG_SZ,
+ (LPVOID)package->appids[package->classes[i].AppIDIndex].AppID,
+ (strlenW(package->appids[package->classes[i].AppIDIndex].AppID)+1)
+ *sizeof(WCHAR));
+
+ register_appid(package,package->classes[i].AppIDIndex,
+ package->classes[i].Description);
+ }
+
+ if (package->classes[i].IconPath)
+ {
+ static const WCHAR szDefaultIcon[] =
+ {'D','e','f','a','u','l','t','I','c','o','n',0};
+
+ RegCreateKeyW(hkey2,szDefaultIcon,&hkey3);
+
+ RegSetValueExW(hkey3,NULL,0,REG_SZ,
+ (LPVOID)package->classes[i].IconPath,
+ (strlenW(package->classes[i].IconPath)+1) *
+ sizeof(WCHAR));
+
+ RegCloseKey(hkey3);
+ }
+
+ if (package->classes[i].DefInprocHandler)
+ {
+ static const WCHAR szInproc[] =
+ {'I','n','p','r','o','c','H','a','n','d','l','e','r',0};
+
+ size = (strlenW(package->classes[i].DefInprocHandler) + 1) *
+ sizeof(WCHAR);
+ RegCreateKeyW(hkey2,szInproc,&hkey3);
+ RegSetValueExW(hkey3,NULL,0,REG_SZ,
+ (LPVOID)package->classes[i].DefInprocHandler, size);
+ RegCloseKey(hkey3);
+ }
+
+ if (package->classes[i].DefInprocHandler32)
+ {
+ static const WCHAR szInproc32[] =
+ {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',
+ 0};
+ size = (strlenW(package->classes[i].DefInprocHandler32) + 1) *
+ sizeof(WCHAR);
+
+ RegCreateKeyW(hkey2,szInproc32,&hkey3);
+ RegSetValueExW(hkey3,NULL,0,REG_SZ,
+ (LPVOID)package->classes[i].DefInprocHandler32,size);
+ RegCloseKey(hkey3);
+ }
+
+ RegCloseKey(hkey2);
+
+ /* if there is a FileTypeMask, register the FileType */
+ if (package->classes[i].FileTypeMask)
+ {
+ LPWSTR ptr, ptr2;
+ LPWSTR keyname;
+ INT index = 0;
+ ptr = package->classes[i].FileTypeMask;
+ while (ptr && *ptr)
+ {
+ ptr2 = strchrW(ptr,';');
+ if (ptr2)
+ *ptr2 = 0;
+ keyname = HeapAlloc(GetProcessHeap(),0,(strlenW(szFileType_fmt)+
+ strlenW(package->classes[i].CLSID) + 4)
+ * sizeof(WCHAR));
+ sprintfW(keyname,szFileType_fmt, package->classes[i].CLSID,
+ index);
+
+ RegCreateKeyW(HKEY_CLASSES_ROOT,keyname,&hkey2);
+ RegSetValueExW(hkey2,NULL,0,REG_SZ, (LPVOID)ptr,
+ strlenW(ptr)*sizeof(WCHAR));
+ RegCloseKey(hkey2);
+ HeapFree(GetProcessHeap(), 0, keyname);
+
+ if (ptr2)
+ ptr = ptr2+1;
+ else
+ ptr = NULL;
+
+ index ++;
+ }
+ }
+
+ uirow = MSI_CreateRecord(1);
+
+ MSI_RecordSetStringW(uirow,1,package->classes[i].CLSID);
+ ui_actiondata(package,szRegisterClassInfo,uirow);
+ msiobj_release(&uirow->hdr);
+ }
+
+ RegCloseKey(hkey);
+ return rc;
+}
+
+static UINT register_progid_base(MSIPACKAGE* package, MSIPROGID* progid,
+ LPWSTR clsid)
+{
+ static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
+ static const WCHAR szDefaultIcon[] =
+ {'D','e','f','a','u','l','t','I','c','o','n',0};
+ HKEY hkey,hkey2;
+
+ RegCreateKeyW(HKEY_CLASSES_ROOT,progid->ProgID,&hkey);
+
+ if (progid->Description)
+ {
+ RegSetValueExW(hkey,NULL,0,REG_SZ,
+ (LPVOID)progid->Description,
+ (strlenW(progid->Description)+1) *
+ sizeof(WCHAR));
+ }
+
+ if (progid->ClassIndex >= 0)
+ {
+ RegCreateKeyW(hkey,szCLSID,&hkey2);
+ RegSetValueExW(hkey2,NULL,0,REG_SZ,
+ (LPVOID)package->classes[progid->ClassIndex].CLSID,
+ (strlenW(package->classes[progid->ClassIndex].CLSID)+1)
+ * sizeof(WCHAR));
+
+ if (clsid)
+ strcpyW(clsid,package->classes[progid->ClassIndex].CLSID);
+
+ RegCloseKey(hkey2);
+ }
+ else
+ {
+ FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
+ }
+
+ if (progid->IconPath)
+ {
+ RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
+
+ RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath,
+ (strlenW(progid->IconPath)+1) * sizeof(WCHAR));
+ RegCloseKey(hkey2);
+ }
+ return ERROR_SUCCESS;
+}
+
+static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid,
+ LPWSTR clsid)
+{
+ UINT rc = ERROR_SUCCESS;
+
+ if (progid->ParentIndex < 0)
+ rc = register_progid_base(package, progid, clsid);
+ else
+ {
+ DWORD disp;
+ HKEY hkey,hkey2;
+ static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
+ static const WCHAR szDefaultIcon[] =
+ {'D','e','f','a','u','l','t','I','c','o','n',0};
+ static const WCHAR szCurVer[] =
+ {'C','u','r','V','e','r',0};
+
+ /* check if already registered */
+ RegCreateKeyExW(HKEY_CLASSES_ROOT, progid->ProgID, 0, NULL, 0,
+ KEY_ALL_ACCESS, NULL, &hkey, &disp );
+ if (disp == REG_OPENED_EXISTING_KEY)
+ {
+ TRACE("Key already registered\n");
+ RegCloseKey(hkey);
+ return rc;
+ }
+
+ TRACE("Registering Parent %s index %i\n",
+ debugstr_w(package->progids[progid->ParentIndex].ProgID),
+ progid->ParentIndex);
+ rc = register_progid(package,&package->progids[progid->ParentIndex],
+ clsid);
+
+ /* clsid is same as parent */
+ RegCreateKeyW(hkey,szCLSID,&hkey2);
+ RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
+ sizeof(WCHAR));
+
+ RegCloseKey(hkey2);
+
+
+ if (progid->Description)
+ {
+ RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid->Description,
+ (strlenW(progid->Description)+1) * sizeof(WCHAR));
+ }
+
+ if (progid->IconPath)
+ {
+ RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
+ RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath,
+ (strlenW(progid->IconPath)+1) * sizeof(WCHAR));
+ RegCloseKey(hkey2);
+ }
+
+ /* write out the current version */
+ if (progid->CurVerIndex >= 0)
+ {
+ RegCreateKeyW(hkey,szCurVer,&hkey2);
+ RegSetValueExW(hkey2,NULL,0,REG_SZ,
+ (LPVOID)package->progids[progid->CurVerIndex].ProgID,
+ (strlenW(package->progids[progid->CurVerIndex].ProgID)+1) *
+ sizeof(WCHAR));
+ RegCloseKey(hkey2);
+ }
+
+ RegCloseKey(hkey);
+ }
+ return rc;
+}
+
+UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
+{
+ INT i;
+ MSIRECORD *uirow;
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ load_classes_and_such(package);
+
+ for (i = 0; i < package->loaded_progids; i++)
+ {
+ WCHAR clsid[0x1000];
+
+ /* check if this progid is to be installed */
+ package->progids[i].InstallMe = ((package->progids[i].InstallMe) ||
+ (package->progids[i].ClassIndex >= 0 &&
+ package->classes[package->progids[i].ClassIndex].Installed));
+
+ if (!package->progids[i].InstallMe)
+ {
+ TRACE("progid %s not scheduled to be installed\n",
+ debugstr_w(package->progids[i].ProgID));
+ continue;
+ }
+
+ TRACE("Registering progid %s index %i\n",
+ debugstr_w(package->progids[i].ProgID), i);
+
+ register_progid(package,&package->progids[i],clsid);
+
+ uirow = MSI_CreateRecord(1);
+ MSI_RecordSetStringW(uirow,1,package->progids[i].ProgID);
+ ui_actiondata(package,szRegisterProgIdInfo,uirow);
+ msiobj_release(&uirow->hdr);
+ }
+
+ return ERROR_SUCCESS;
+}
+
+static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid,
+ MSICOMPONENT* component, MSIEXTENSION* extension,
+ MSIVERB* verb, INT* Sequence )
+{
+ LPWSTR keyname;
+ HKEY key;
+ static const WCHAR szShell[] = {'s','h','e','l','l',0};
+ static const WCHAR szCommand[] = {'c','o','m','m','a','n','d',0};
+ static const WCHAR fmt[] = {'\"','%','s','\"',' ','%','s',0};
+ static const WCHAR fmt2[] = {'\"','%','s','\"',0};
+ LPWSTR command;
+ DWORD size;
+ LPWSTR advertise;
+
+ keyname = build_directory_name(4, progid, szShell, verb->Verb, szCommand);
+
+ TRACE("Making Key %s\n",debugstr_w(keyname));
+ RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
+ size = strlenW(component->FullKeypath);
+ if (verb->Argument)
+ size += strlenW(verb->Argument);
+ size += 4;
+
+ command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
+ if (verb->Argument)
+ sprintfW(command, fmt, component->FullKeypath, verb->Argument);
+ else
+ sprintfW(command, fmt2, component->FullKeypath);
+
+ RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)command, (strlenW(command)+1)*
+ sizeof(WCHAR));
+ HeapFree(GetProcessHeap(),0,command);
+
+ advertise = create_component_advertise_string(package, component,
+ package->features[extension->FeatureIndex].Feature);
+
+ size = strlenW(advertise);
+
+ if (verb->Argument)
+ size += strlenW(verb->Argument);
+ size += 4;
+
+ command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
+ memset(command,0,size*sizeof(WCHAR));
+
+ strcpyW(command,advertise);
+ if (verb->Argument)
+ {
+ static const WCHAR szSpace[] = {' ',0};
+ strcatW(command,szSpace);
+ strcatW(command,verb->Argument);
+ }
+
+ RegSetValueExW(key, szCommand, 0, REG_MULTI_SZ, (LPBYTE)command,
+ (strlenW(command)+2)*sizeof(WCHAR));
+
+ RegCloseKey(key);
+ HeapFree(GetProcessHeap(),0,keyname);
+ HeapFree(GetProcessHeap(),0,advertise);
+ HeapFree(GetProcessHeap(),0,command);
+
+ if (verb->Command)
+ {
+ keyname = build_directory_name(3, progid, szShell, verb->Verb);
+ RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
+ RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Command,
+ (strlenW(verb->Command)+1) *sizeof(WCHAR));
+ RegCloseKey(key);
+ HeapFree(GetProcessHeap(),0,keyname);
+ }
+
+ if (verb->Sequence != MSI_NULL_INTEGER)
+ {
+ if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence)
+ {
+ *Sequence = verb->Sequence;
+ keyname = build_directory_name(2, progid, szShell);
+ RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
+ RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Verb,
+ (strlenW(verb->Verb)+1) *sizeof(WCHAR));
+ RegCloseKey(key);
+ HeapFree(GetProcessHeap(),0,keyname);
+ }
+ }
+ return ERROR_SUCCESS;
+}
+
+UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
+{
+ static const WCHAR szContentType[] =
+ {'C','o','n','t','e','n','t',' ','T','y','p','e',0 };
+ HKEY hkey;
+ INT i;
+ MSIRECORD *uirow;
+ BOOL install_on_demand = TRUE;
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ load_classes_and_such(package);
+
+ /* We need to set install_on_demand based on if the shell handles advertised
+ * shortcuts and the like. Because Mike McCormack is working on this i am
+ * going to default to TRUE
+ */
+
+ for (i = 0; i < package->loaded_extensions; i++)
+ {
+ WCHAR extension[257];
+ INT index,f_index;
+
+ index = package->extensions[i].ComponentIndex;
+ f_index = package->extensions[i].FeatureIndex;
+
+ if (index < 0)
+ continue;
+
+ /*
+ * yes. MSDN says that these are based on _Feature_ not on
+ * Component. So verify the feature is to be installed
+ */
+ if ((!ACTION_VerifyFeatureForAction(package, f_index,
+ INSTALLSTATE_LOCAL)) &&
+ !(install_on_demand && ACTION_VerifyFeatureForAction(package,
+ f_index, INSTALLSTATE_ADVERTISED)))
+ {
+ TRACE("Skipping extension %s reg due to disabled feature %s\n",
+ debugstr_w(package->extensions[i].Extension),
+ debugstr_w(package->features[f_index].Feature));
+
+ continue;
+ }
+
+ TRACE("Registering extension %s index %i\n",
+ debugstr_w(package->extensions[i].Extension), i);
+
+ package->extensions[i].Installed = TRUE;
+
+ /* this is only registered if the extension has at least 1 verb
+ * according to MSDN
+ */
+ if (package->extensions[i].ProgIDIndex >= 0 &&
+ package->extensions[i].VerbCount > 0)
+ mark_progid_for_install(package, package->extensions[i].ProgIDIndex);
+
+ if (package->extensions[i].MIMEIndex >= 0)
+ mark_mime_for_install(package, package->extensions[i].MIMEIndex);
+
+ extension[0] = '.';
+ extension[1] = 0;
+ strcatW(extension,package->extensions[i].Extension);
+
+ RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey);
+
+ if (package->extensions[i].MIMEIndex >= 0)
+ {
+ RegSetValueExW(hkey,szContentType,0,REG_SZ,
+ (LPVOID)package->mimes[package->extensions[i].
+ MIMEIndex].ContentType,
+ (strlenW(package->mimes[package->extensions[i].
+ MIMEIndex].ContentType)+1)*sizeof(WCHAR));
+ }
+
+ if (package->extensions[i].ProgIDIndex >= 0 ||
+ package->extensions[i].ProgIDText)
+ {
+ static const WCHAR szSN[] =
+ {'\\','S','h','e','l','l','N','e','w',0};
+ HKEY hkey2;
+ LPWSTR newkey;
+ LPCWSTR progid;
+ INT v;
+ INT Sequence = MSI_NULL_INTEGER;
+
+ if (package->extensions[i].ProgIDIndex >= 0)
+ progid = package->progids[package->extensions[i].
+ ProgIDIndex].ProgID;
+ else
+ progid = package->extensions[i].ProgIDText;
+
+ RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid,
+ (strlenW(progid)+1)*sizeof(WCHAR));
+
+ newkey = HeapAlloc(GetProcessHeap(),0,
+ (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR));
+
+ strcpyW(newkey,progid);
+ strcatW(newkey,szSN);
+ RegCreateKeyW(hkey,newkey,&hkey2);
+ RegCloseKey(hkey2);
+
+ HeapFree(GetProcessHeap(),0,newkey);
+
+ /* do all the verbs */
+ for (v = 0; v < package->extensions[i].VerbCount; v++)
+ register_verb(package, progid,
+ &package->components[index],
+ &package->extensions[i],
+ &package->verbs[package->extensions[i].Verbs[v]],
+ &Sequence);
+ }
+
+ RegCloseKey(hkey);
+
+ uirow = MSI_CreateRecord(1);
+ MSI_RecordSetStringW(uirow,1,package->extensions[i].Extension);
+ ui_actiondata(package,szRegisterExtensionInfo,uirow);
+ msiobj_release(&uirow->hdr);
+ }
+
+ return ERROR_SUCCESS;
+}
+
+UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
+{
+ static const WCHAR szExten[] =
+ {'E','x','t','e','n','s','i','o','n',0 };
+ HKEY hkey;
+ INT i;
+ MSIRECORD *uirow;
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ load_classes_and_such(package);
+
+ for (i = 0; i < package->loaded_mimes; i++)
+ {
+ WCHAR extension[257];
+ LPCWSTR exten;
+ LPCWSTR mime;
+ static const WCHAR fmt[] =
+ {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\',
+ 'C','o','n','t','e','n','t',' ','T','y','p','e','\\', '%','s',0};
+ LPWSTR key;
+
+ /*
+ * check if the MIME is to be installed. Either as requesed by an
+ * extension or Class
+ */
+ package->mimes[i].InstallMe = ((package->mimes[i].InstallMe) ||
+ (package->mimes[i].ClassIndex >= 0 &&
+ package->classes[package->mimes[i].ClassIndex].Installed) ||
+ (package->mimes[i].ExtensionIndex >=0 &&
+ package->extensions[package->mimes[i].ExtensionIndex].Installed));
+
+ if (!package->mimes[i].InstallMe)
+ {
+ TRACE("MIME %s not scheduled to be installed\n",
+ debugstr_w(package->mimes[i].ContentType));
+ continue;
+ }
+
+ mime = package->mimes[i].ContentType;
+ exten = package->extensions[package->mimes[i].ExtensionIndex].Extension;
+ extension[0] = '.';
+ extension[1] = 0;
+ strcatW(extension,exten);
+
+ key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) *
+ sizeof(WCHAR));
+ sprintfW(key,fmt,mime);
+ RegCreateKeyW(HKEY_CLASSES_ROOT,key,&hkey);
+ RegSetValueExW(hkey,szExten,0,REG_SZ,(LPVOID)extension,
+ (strlenW(extension)+1)*sizeof(WCHAR));
+
+ HeapFree(GetProcessHeap(),0,key);
+
+ if (package->mimes[i].CLSID[0])
+ {
+ FIXME("Handle non null for field 3\n");
+ }
+
+ RegCloseKey(hkey);
+
+ uirow = MSI_CreateRecord(2);
+ MSI_RecordSetStringW(uirow,1,package->mimes[i].ContentType);
+ MSI_RecordSetStringW(uirow,2,exten);
+ ui_actiondata(package,szRegisterMIMEInfo,uirow);
+ msiobj_release(&uirow->hdr);
+ }
+
+ return ERROR_SUCCESS;
+}
#define YYLEX_PARAM info
#define YYPARSE_PARAM info
-static int COND_error(char *str);
+static int COND_error(const char *str);
WINE_DEFAULT_DEBUG_CHANNEL(msi);
return ret;
}
-static int COND_error(char *str)
+static int COND_error(const char *str)
{
return 0;
}
-/* A Bison parser, made by GNU Bison 1.875c. */
+#ifndef BISON_COND_TAB_H
+# define BISON_COND_TAB_H
-/* Skeleton parser for Yacc-like parsing with Bison,
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
-
-/* As a special exception, when this file is copied by Bison into a
- Bison output file, you may use that output file without restriction.
- This special exception was added by the Free Software Foundation
- in version 1.24 of Bison. */
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- COND_SPACE = 258,
- COND_EOF = 259,
- COND_OR = 260,
- COND_AND = 261,
- COND_NOT = 262,
- COND_LT = 263,
- COND_GT = 264,
- COND_EQ = 265,
- COND_LPAR = 266,
- COND_RPAR = 267,
- COND_TILDA = 268,
- COND_PERCENT = 269,
- COND_DOLLARS = 270,
- COND_QUESTION = 271,
- COND_AMPER = 272,
- COND_EXCLAM = 273,
- COND_IDENT = 274,
- COND_NUMBER = 275,
- COND_LITER = 276,
- COND_ERROR = 277
- };
-#endif
-#define COND_SPACE 258
-#define COND_EOF 259
-#define COND_OR 260
-#define COND_AND 261
-#define COND_NOT 262
-#define COND_LT 263
-#define COND_GT 264
-#define COND_EQ 265
-#define COND_LPAR 266
-#define COND_RPAR 267
-#define COND_TILDA 268
-#define COND_PERCENT 269
-#define COND_DOLLARS 270
-#define COND_QUESTION 271
-#define COND_AMPER 272
-#define COND_EXCLAM 273
-#define COND_IDENT 274
-#define COND_NUMBER 275
-#define COND_LITER 276
-#define COND_ERROR 277
-
-
-
-
-#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
-#line 106 "./cond.y"
-typedef union YYSTYPE {
+#ifndef YYSTYPE
+typedef union
+{
struct cond_str str;
LPWSTR string;
INT value;
comp_str fn_comp_str;
comp_m1 fn_comp_m1;
comp_m2 fn_comp_m2;
-} YYSTYPE;
-/* Line 1275 of yacc.c. */
-#line 91 "cond.tab.h"
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
+} yystype;
+# define YYSTYPE yystype
# define YYSTYPE_IS_TRIVIAL 1
#endif
-
-
-
-
-
+# define COND_SPACE 257
+# define COND_EOF 258
+# define COND_OR 259
+# define COND_AND 260
+# define COND_NOT 261
+# define COND_LT 262
+# define COND_GT 263
+# define COND_EQ 264
+# define COND_LPAR 265
+# define COND_RPAR 266
+# define COND_TILDA 267
+# define COND_PERCENT 268
+# define COND_DOLLARS 269
+# define COND_QUESTION 270
+# define COND_AMPER 271
+# define COND_EXCLAM 272
+# define COND_IDENT 273
+# define COND_NUMBER 274
+# define COND_LITER 275
+# define COND_ERROR 276
+
+
+#endif /* not BISON_COND_TAB_H */
#define YYLEX_PARAM info\r
#define YYPARSE_PARAM info\r
\r
-static int COND_error(char *str);\r
+static int COND_error(const char *str);\r
\r
WINE_DEFAULT_DEBUG_CHANNEL(msi);\r
\r
return ret;\r
}\r
\r
-static int COND_error(char *str)\r
+static int COND_error(const char *str)\r
{\r
return 0;\r
}\r
MSIDATABASE *db;
LPWSTR name;
BOOL bIsTemp;
- create_col_info *col_info;
+ column_info *col_info;
} MSICREATEVIEW;
static UINT CREATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
static UINT CREATE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
{
MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
- create_col_info *col;
+ column_info *col;
UINT r, nField, row, table_val, column_val;
static const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 };
static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 };
if( r )
goto err;
- column_val = msi_addstringW( cv->db->strings, 0, col->colname, -1, 1 );
- TRACE("New string %s -> %d\n", debugstr_w( col->colname ), column_val );
+ column_val = msi_addstringW( cv->db->strings, 0, col->column, -1, 1 );
+ TRACE("New string %s -> %d\n", debugstr_w( col->column ), column_val );
if( column_val < 0 )
break;
};
UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
- create_col_info *col_info, BOOL temp )
+ column_info *col_info, BOOL temp )
{
MSICREATEVIEW *cv = NULL;
UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
{
UINT rc = ERROR_SUCCESS;
- MSIQUERY * view;
MSIRECORD * row = 0;
static const WCHAR ExecSeqQuery[] =
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
LPWSTR target;
WCHAR *deformated=NULL;
- rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, action);
- if (rc != ERROR_SUCCESS)
- return rc;
-
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
+ row = MSI_QueryGetRecord( package->db, ExecSeqQuery, action );
+ if (!row)
return ERROR_CALL_NOT_IMPLEMENTED;
- }
type = MSI_RecordGetInteger(row,2);
if (type & 0x100)
{
FIXME("Rollback only action... rollbacks not supported yet\n");
+ schedule_action(package, ROLLBACK_SCRIPT, action);
HeapFree(GetProcessHeap(),0,source);
HeapFree(GetProcessHeap(),0,target);
msiobj_release(&row->hdr);
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
return ERROR_SUCCESS;
}
if (!execute)
{
- LPWSTR *newbuf = NULL;
- INT count;
if (type & 0x200)
{
TRACE("Deferring Commit Action!\n");
- count = package->CommitActionCount;
- package->CommitActionCount++;
- if (count != 0)
- newbuf = HeapReAlloc(GetProcessHeap(),0,
- package->CommitAction,
- package->CommitActionCount * sizeof(LPWSTR));
- else
- newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
-
- newbuf[count] = strdupW(action);
- package->CommitAction = newbuf;
+ schedule_action(package, COMMIT_SCRIPT, action);
}
else
{
TRACE("Deferring Action!\n");
- count = package->DeferredActionCount;
- package->DeferredActionCount++;
- if (count != 0)
- newbuf = HeapReAlloc(GetProcessHeap(),0,
- package->DeferredAction,
- package->DeferredActionCount * sizeof(LPWSTR));
- else
- newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
-
- newbuf[count] = strdupW(action);
- package->DeferredAction = newbuf;
+ schedule_action(package, INSTALL_SCRIPT, action);
}
HeapFree(GetProcessHeap(),0,source);
HeapFree(GetProcessHeap(),0,target);
msiobj_release(&row->hdr);
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
return ERROR_SUCCESS;
}
else
HeapFree(GetProcessHeap(),0,source);
HeapFree(GetProcessHeap(),0,target);
msiobj_release(&row->hdr);
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
return rc;
}
{
/* write out the file */
UINT rc;
- MSIQUERY * view;
MSIRECORD * row = 0;
static const WCHAR fmt[] =
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
HANDLE the_file;
CHAR buffer[1024];
- if (track_tempfile(package, tmp_file, tmp_file)!=0)
- FIXME("File Name in temp tracking collision\n");
-
the_file = CreateFileW(tmp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (the_file == INVALID_HANDLE_VALUE)
return ERROR_FUNCTION_FAILED;
- rc = MSI_OpenQuery(package->db, &view, fmt, source);
- if (rc != ERROR_SUCCESS)
- return rc;
-
- rc = MSI_ViewExecute(view, 0);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
-
- rc = MSI_ViewFetch(view,&row);
- if (rc != ERROR_SUCCESS)
- {
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
- return rc;
- }
+ row = MSI_QueryGetRecord(package->db, fmt, source);
+ if (!row)
+ return ERROR_FUNCTION_FAILED;
do
{
CloseHandle(the_file);
msiobj_release(&row->hdr);
- MSI_ViewClose(view);
- msiobj_release(&view->hdr);
}
return ERROR_SUCCESS;
static UINT process_handle(MSIPACKAGE* package, UINT type,
HANDLE ThreadHandle, HANDLE ProcessHandle,
- LPCWSTR Name)
+ LPCWSTR Name, BOOL *finished)
{
UINT rc = ERROR_SUCCESS;
CloseHandle(ThreadHandle);
if (ProcessHandle);
CloseHandle(ProcessHandle);
+ if (finished)
+ *finished = TRUE;
}
else
{
if (ProcessHandle);
CloseHandle(ProcessHandle);
}
+ if (finished)
+ *finished = FALSE;
}
return rc;
DWORD ThreadId;
HANDLE ThreadHandle;
UINT rc = ERROR_SUCCESS;
+ BOOL finished = FALSE;
store_binary_to_temp(package, source, tmp_file);
ThreadHandle = CreateThread(NULL,0,DllThread,(LPVOID)info,0,&ThreadId);
- rc = process_handle(package, type, ThreadHandle, NULL, action);
+ rc = process_handle(package, type, ThreadHandle, NULL, action, &finished );
+
+ if (!finished)
+ track_tempfile(package, tmp_file, tmp_file);
+ else
+ DeleteFileW(tmp_file);
return rc;
}
WCHAR *cmd;
static const WCHAR spc[] = {' ',0};
UINT prc = ERROR_SUCCESS;
+ BOOL finished = FALSE;
memset(&si,0,sizeof(STARTUPINFOW));
return ERROR_SUCCESS;
}
- prc = process_handle(package, type, info.hThread, info.hProcess, action);
+ prc = process_handle(package, type, info.hThread, info.hProcess, action,
+ &finished);
+ if (!finished)
+ track_tempfile(package, tmp_file, tmp_file);
+ else
+ DeleteFileW(tmp_file);
+
return prc;
}
return ERROR_SUCCESS;
}
- prc = process_handle(package, type, info.hThread, info.hProcess, action);
+ prc = process_handle(package, type, info.hThread, info.hProcess, action,
+ NULL);
return prc;
}
'W','H','E','R','E',' ','`','E','r','r','o','r','`',' ','=',' ',
'\'','%','s','\'',0
};
- MSIQUERY *view = NULL;
MSIRECORD *row = 0;
- UINT r;
LPWSTR deformated = NULL;
deformat_string( package, target, &deformated );
/* first try treat the error as a number */
- r = MSI_OpenQuery( package->db, &view, query, deformated );
- if( r == ERROR_SUCCESS )
+ row = MSI_QueryGetRecord( package->db, query, deformated );
+ if( row )
{
- r = MSI_ViewExecute( view, 0 );
- if( r == ERROR_SUCCESS )
- {
- r = MSI_ViewFetch( view, &row );
- if( r == ERROR_SUCCESS )
- {
- LPCWSTR error = MSI_RecordGetString( row, 1 );
- MessageBoxW( NULL, error, NULL, MB_OK );
- msiobj_release( &row->hdr );
- }
- }
- MSI_ViewClose( view );
- msiobj_release( &view->hdr );
+ LPCWSTR error = MSI_RecordGetString( row, 1 );
+ MessageBoxW( NULL, error, NULL, MB_OK );
+ msiobj_release( &row->hdr );
}
-
- if (r != ERROR_SUCCESS )
- {
+ else
MessageBoxW( NULL, deformated, NULL, MB_OK );
- HeapFree( GetProcessHeap(), 0, deformated );
- }
+
+ HeapFree( GetProcessHeap(), 0, deformated );
return ERROR_FUNCTION_FAILED;
}
return ERROR_SUCCESS;
}
- prc = process_handle(package, type, info.hThread, info.hProcess, action);
+ prc = process_handle(package, type, info.hThread, info.hProcess, action,
+ NULL);
return prc;
}
return ERROR_SUCCESS;
}
- prc = process_handle(package, type, info.hThread, info.hProcess, action);
+ prc = process_handle(package, type, info.hThread, info.hProcess, action,
+ NULL);
return prc;
}
* Any binary data in a table is a reference to a stream.
*/
-VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
+static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
{
MSIDATABASE *db = (MSIDATABASE *) arg;
DWORD r;
HRESULT r;
MSIDATABASE *db = NULL;
UINT ret = ERROR_FUNCTION_FAILED;
- LPWSTR szMode;
+ LPCWSTR szMode;
STATSTG stat;
TRACE("%s %s\n",debugstr_w(szDBPath),debugstr_w(szPersist) );
if( !pdb )
return ERROR_INVALID_PARAMETER;
- szMode = (LPWSTR) szPersist;
+ szMode = szPersist;
if( HIWORD( szPersist ) )
{
/* UINT len = lstrlenW( szPerist ) + 1; */
goto end;
}
else
- szwPersist = (LPWSTR) szPersist;
+ szwPersist = (LPWSTR)(DWORD)szPersist;
r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB );
#include "msidefs.h"
#include "ocidl.h"
#include "olectl.h"
+#include "richedit.h"
#include "wine/debug.h"
#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
-const WCHAR szMsiDialogClass[] = {
- 'M','s','i','D','i','a','l','o','g','C','l','o','s','e','C','l','a','s','s',0
-};
-const WCHAR szMsiHiddenWindow[] = {
- 'M','s','i','H','i','d','d','e','n','W','i','n','d','o','w',0
-};
-const static WCHAR szStatic[] = { 'S','t','a','t','i','c',0 };
-const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 };
-
-const static WCHAR szButtonData[] = { 'M','S','I','D','A','T','A',0 };
-
struct msi_control_tag;
typedef struct msi_control_tag msi_control;
typedef UINT (*msi_handler)( msi_dialog *, msi_control *, WPARAM );
HWND hwnd;
msi_handler handler;
LPWSTR property;
+ LPWSTR value;
IPicture *pic;
+ HICON hIcon;
WCHAR name[1];
};
DWORD attributes;
} radio_button_group_descr;
+const WCHAR szMsiDialogClass[] = {
+ 'M','s','i','D','i','a','l','o','g','C','l','o','s','e','C','l','a','s','s',0
+};
+const WCHAR szMsiHiddenWindow[] = {
+ 'M','s','i','H','i','d','d','e','n','W','i','n','d','o','w',0 };
+const static WCHAR szStatic[] = { 'S','t','a','t','i','c',0 };
+const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 };
+const static WCHAR szButtonData[] = { 'M','S','I','D','A','T','A',0 };
+static const WCHAR szText[] = { 'T','e','x','t',0 };
+static const WCHAR szPushButton[] = { 'P','u','s','h','B','u','t','t','o','n',0 };
+static const WCHAR szLine[] = { 'L','i','n','e',0 };
+static const WCHAR szBitmap[] = { 'B','i','t','m','a','p',0 };
+static const WCHAR szCheckBox[] = { 'C','h','e','c','k','B','o','x',0 };
+static const WCHAR szScrollableText[] = {
+ 'S','c','r','o','l','l','a','b','l','e','T','e','x','t',0 };
+static const WCHAR szComboBox[] = { 'C','o','m','b','o','B','o','x',0 };
+static const WCHAR szEdit[] = { 'E','d','i','t',0 };
+static const WCHAR szMaskedEdit[] = { 'M','a','s','k','e','d','E','d','i','t',0 };
+static const WCHAR szPathEdit[] = { 'P','a','t','h','E','d','i','t',0 };
+static const WCHAR szRadioButtonGroup[] = {
+ 'R','a','d','i','o','B','u','t','t','o','n','G','r','o','u','p',0 };
+static const WCHAR szIcon[] = { 'I','c','o','n',0 };
+
static UINT msi_dialog_checkbox_handler( msi_dialog *, msi_control *, WPARAM );
static void msi_dialog_checkbox_sync_state( msi_dialog *, msi_control * );
static UINT msi_dialog_button_handler( msi_dialog *, msi_control *, WPARAM );
static UINT msi_dialog_edit_handler( msi_dialog *, msi_control *, WPARAM );
static UINT msi_dialog_radiogroup_handler( msi_dialog *, msi_control *, WPARAM param );
+static UINT msi_dialog_evaluate_control_conditions( msi_dialog *dialog );
static LRESULT WINAPI MSIRadioGroup_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
static DWORD uiThreadId;
static HWND hMsiHiddenWindow;
+static HMODULE hRichedit;
-INT msi_dialog_scale_unit( msi_dialog *dialog, INT val )
+static INT msi_dialog_scale_unit( msi_dialog *dialog, INT val )
{
return (dialog->scale * val + 5) / 10;
}
+static msi_control *msi_dialog_find_control( msi_dialog *dialog, LPCWSTR name )
+{
+ msi_control *control;
+
+ for( control = dialog->control_list; control; control = control->next )
+ if( !strcmpW( control->name, name ) ) /* FIXME: case sensitive? */
+ break;
+ return control;
+}
+
+static msi_control *msi_dialog_find_control_by_hwnd( msi_dialog *dialog, HWND hwnd )
+{
+ msi_control *control;
+
+ for( control = dialog->control_list; control; control = control->next )
+ if( hwnd == control->hwnd )
+ break;
+ return control;
+}
+
/*
* msi_dialog_get_style
*
LPWSTR font = NULL, title = NULL;
msi_control *control;
- style |= WS_CHILD | WS_GROUP;
+ style |= WS_CHILD;
control = HeapAlloc( GetProcessHeap(), 0,
sizeof *control + strlenW(name)*sizeof(WCHAR) );
dialog->control_list = control;
control->handler = NULL;
control->property = NULL;
+ control->value = NULL;
control->pic = NULL;
+ control->hIcon = NULL;
x = MSI_RecordGetInteger( rec, 4 );
y = MSI_RecordGetInteger( rec, 5 );
return control;
}
+/* called from the Control Event subscription code */
+void msi_dialog_handle_event( msi_dialog* dialog, LPCWSTR control,
+ LPCWSTR attribute, MSIRECORD *rec )
+{
+ msi_control* ctrl;
+ LPCWSTR text;
+
+ ctrl = msi_dialog_find_control( dialog, control );
+ if (!ctrl)
+ return;
+ if( lstrcmpW(attribute, szText) )
+ return;
+ text = MSI_RecordGetString( rec , 1 );
+ SetWindowTextW( ctrl->hwnd, text );
+ msi_dialog_check_messages( NULL );
+}
+
+static void msi_dialog_map_events(msi_dialog* dialog, LPCWSTR control)
+{
+ static WCHAR Query[] = {
+ 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','E','v','e','n','t','M','a','p','p','i','n','g','`',' ',
+ 'W','H','E','R','E',' ',
+ '`','D','i','a','l','o','g','_','`',' ','=',' ','\'','%','s','\'',' ',
+ 'A','N','D',' ',
+ '`','C','o','n','t','r','o','l','_','`',' ','=',' ','\'','%','s','\'',0
+ };
+ MSIRECORD *row;
+ LPCWSTR event, attribute;
+
+ row = MSI_QueryGetRecord( dialog->package->db, Query, dialog->name, control );
+ if (!row)
+ return;
+
+ event = MSI_RecordGetString( row, 3 );
+ attribute = MSI_RecordGetString( row, 4 );
+ ControlEvent_SubscribeToEvent( dialog->package, event, control, attribute );
+ msiobj_release( &row->hdr );
+}
+
/* everything except radio buttons */
static msi_control *msi_dialog_add_control( msi_dialog *dialog,
MSIRECORD *rec, LPCWSTR szCls, DWORD style )
name = MSI_RecordGetString( rec, 2 );
attributes = MSI_RecordGetInteger( rec, 8 );
text = MSI_RecordGetString( rec, 10 );
- if( attributes & 1 )
+ if( attributes & msidbControlAttributesVisible )
style |= WS_VISIBLE;
- if( ~attributes & 2 )
+ if( ~attributes & msidbControlAttributesEnabled )
style |= WS_DISABLED;
+
+ msi_dialog_map_events(dialog, name);
+
return msi_dialog_create_window( dialog, rec, szCls, name, text,
style, dialog->hwnd );
}
+struct msi_text_info
+{
+ WNDPROC oldproc;
+ DWORD attributes;
+};
+
+/*
+ * we don't erase our own background,
+ * so we have to make sure that the parent window redraws first
+ */
+static void msi_text_on_settext( HWND hWnd )
+{
+ HWND hParent;
+ RECT rc;
+
+ hParent = GetParent( hWnd );
+ GetWindowRect( hWnd, &rc );
+ MapWindowPoints( NULL, hParent, (LPPOINT) &rc, 2 );
+ InvalidateRect( hParent, &rc, TRUE );
+}
+
+static LRESULT WINAPI
+MSIText_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct msi_text_info *info;
+ LRESULT r = 0;
+
+ TRACE("%p %04x %08x %08lx\n", hWnd, msg, wParam, lParam);
+
+ info = GetPropW(hWnd, szButtonData);
+
+ if( msg == WM_CTLCOLORSTATIC &&
+ ( info->attributes & msidbControlAttributesTransparent ) )
+ {
+ SetBkMode( (HDC)wParam, TRANSPARENT );
+ return (LRESULT) GetStockObject(NULL_BRUSH);
+ }
+
+ r = CallWindowProcW(info->oldproc, hWnd, msg, wParam, lParam);
+
+ switch( msg )
+ {
+ case WM_SETTEXT:
+ msi_text_on_settext( hWnd );
+ break;
+ case WM_NCDESTROY:
+ HeapFree( GetProcessHeap(), 0, info );
+ RemovePropW( hWnd, szButtonData );
+ break;
+ }
+
+ return r;
+}
+
static UINT msi_dialog_text_control( msi_dialog *dialog, MSIRECORD *rec )
{
+ msi_control *control;
+ struct msi_text_info *info;
+
TRACE("%p %p\n", dialog, rec);
- msi_dialog_add_control( dialog, rec, szStatic, 0 );
+ control = msi_dialog_add_control( dialog, rec, szStatic, SS_LEFT | WS_GROUP );
+ if( !control )
+ return ERROR_FUNCTION_FAILED;
+
+ info = HeapAlloc( GetProcessHeap(), 0, sizeof *info );
+ if( !info )
+ return ERROR_SUCCESS;
+
+ info->attributes = MSI_RecordGetInteger( rec, 8 );
+ if( info->attributes & msidbControlAttributesTransparent )
+ SetWindowLongPtrW( control->hwnd, GWL_EXSTYLE, WS_EX_TRANSPARENT );
+
+ info->oldproc = (WNDPROC) SetWindowLongPtrW( control->hwnd, GWLP_WNDPROC,
+ (LONG_PTR)MSIText_WndProc );
+ SetPropW( control->hwnd, szButtonData, info );
+
return ERROR_SUCCESS;
}
TRACE("%p %p\n", dialog, rec);
- control = msi_dialog_add_control( dialog, rec, szButton, 0 );
+ control = msi_dialog_add_control( dialog, rec, szButton, WS_TABSTOP );
control->handler = msi_dialog_button_handler;
return ERROR_SUCCESS;
}
+static LPWSTR msi_get_checkbox_value( msi_dialog *dialog, LPCWSTR prop )
+{
+ const static WCHAR query[] = {
+ 'S','E','L','E','C','T',' ','*',' ',
+ 'F','R','O','M',' ','`','C','h','e','c','k','B','o','x',' ','`',
+ 'W','H','E','R','E',' ',
+ '`','P','r','o','p','e','r','t','y','`',' ','=',' ',
+ '\'','%','s','\'',0
+ };
+ MSIRECORD *rec = NULL;
+ LPCWSTR val = NULL;
+ LPWSTR ret = NULL;
+
+ /* find if there is a value associated with the checkbox */
+ rec = MSI_QueryGetRecord( dialog->package->db, query, prop );
+ if (!rec)
+ return ret;
+
+ val = MSI_RecordGetString( rec, 2 );
+ if (val)
+ {
+ deformat_string( dialog->package, val, &ret );
+ if( ret && !ret[0] )
+ {
+ HeapFree( GetProcessHeap(), 0, ret );
+ ret = NULL;
+ }
+ }
+ msiobj_release( &rec->hdr );
+ if (ret)
+ return ret;
+
+ ret = load_dynamic_property(dialog->package, prop, NULL);
+ if( ret && !ret[0] )
+ {
+ HeapFree( GetProcessHeap(), 0, ret );
+ ret = NULL;
+ }
+
+ return ret;
+}
+
static UINT msi_dialog_checkbox_control( msi_dialog *dialog, MSIRECORD *rec )
{
msi_control *control;
TRACE("%p %p\n", dialog, rec);
control = msi_dialog_add_control( dialog, rec, szButton,
- BS_CHECKBOX | BS_MULTILINE );
+ BS_CHECKBOX | BS_MULTILINE | WS_TABSTOP );
control->handler = msi_dialog_checkbox_handler;
prop = MSI_RecordGetString( rec, 9 );
if( prop )
+ {
control->property = strdupW( prop );
+ control->value = msi_get_checkbox_value( dialog, prop );
+ TRACE("control %s value %s\n", debugstr_w(control->property),
+ debugstr_w(control->value));
+ }
msi_dialog_checkbox_sync_state( dialog, control );
return ERROR_SUCCESS;
return ERROR_SUCCESS;
}
+struct msi_streamin_info
+{
+ LPSTR string;
+ DWORD offset;
+ DWORD length;
+};
+
+static DWORD CALLBACK
+msi_richedit_stream_in( DWORD_PTR arg, LPBYTE buffer, LONG count, LONG *pcb )
+{
+ struct msi_streamin_info *info = (struct msi_streamin_info*) arg;
+
+ if( (count + info->offset) > info->length )
+ count = info->length - info->offset;
+ memcpy( buffer, &info->string[ info->offset ], count );
+ *pcb = count;
+ info->offset += count;
+
+ TRACE("%ld/%ld\n", info->offset, info->length);
+
+ return 0;
+}
+
static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec )
{
- const static WCHAR szEdit[] = { 'E','D','I','T',0 };
+ const static WCHAR szRichEdit20W[] = {
+ 'R','i','c','h','E','d','i','t','2','0','W',0
+ };
+ struct msi_streamin_info info;
+ msi_control *control;
+ LPCWSTR text;
+ EDITSTREAM es;
+ DWORD style;
- FIXME("%p %p\n", dialog, rec);
+ style = WS_BORDER | ES_MULTILINE | WS_VSCROLL |
+ ES_READONLY | ES_AUTOVSCROLL | WS_TABSTOP;
+ control = msi_dialog_add_control( dialog, rec, szRichEdit20W, style );
- msi_dialog_add_control( dialog, rec, szEdit, WS_BORDER |
- ES_MULTILINE | WS_VSCROLL | ES_READONLY | ES_AUTOVSCROLL );
+ text = MSI_RecordGetString( rec, 10 );
+ info.string = strdupWtoA( text );
+ info.offset = 0;
+ info.length = lstrlenA( info.string ) + 1;
+
+ es.dwCookie = (DWORD_PTR) &info;
+ es.dwError = 0;
+ es.pfnCallback = msi_richedit_stream_in;
+
+ SendMessageW( control->hwnd, EM_STREAMIN, SF_RTF, (LPARAM) &es );
+
+ HeapFree( GetProcessHeap(), 0, info.string );
return ERROR_SUCCESS;
}
-static UINT msi_load_bitmap( MSIDATABASE *db, LPCWSTR name, IPicture **pic )
+static MSIRECORD *msi_get_binary_record( MSIDATABASE *db, LPCWSTR name )
{
const static WCHAR query[] = {
's','e','l','e','c','t',' ','*',' ',
'w','h','e','r','e',' ',
'`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0
};
- MSIQUERY *view = NULL;
+
+ return MSI_QueryGetRecord( db, query, name );
+}
+
+static UINT msi_load_bitmap( MSIDATABASE *db, LPCWSTR name, IPicture **pic )
+{
MSIRECORD *rec = NULL;
IStream *stm = NULL;
UINT r;
- r = MSI_OpenQuery( db, &view, query, name );
- if( r != ERROR_SUCCESS )
- return r;
-
- MSI_ViewExecute( view, NULL );
- MSI_ViewFetch( view, &rec );
- MSI_ViewClose( view );
- msiobj_release( &view->hdr );
-
+ rec = msi_get_binary_record( db, name );
if( !rec )
return ERROR_FUNCTION_FAILED;
return ERROR_SUCCESS;
}
+static LPWSTR msi_create_tmp_path(void)
+{
+ WCHAR tmp[MAX_PATH];
+ LPWSTR path = NULL;
+ static const WCHAR prefix[] = { 'm','s','i',0 };
+ DWORD len, r;
+
+ r = GetTempPathW( MAX_PATH, tmp );
+ if( !r )
+ return path;
+ len = lstrlenW( tmp ) + 20;
+ path = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
+ if( path )
+ {
+ r = GetTempFileNameW( tmp, prefix, 0, path );
+ if (!r)
+ {
+ HeapFree( GetProcessHeap(), 0, path );
+ path = NULL;
+ }
+ }
+ return path;
+}
+
+static UINT
+msi_load_icon( MSIDATABASE *db, LPCWSTR name, DWORD attributes, HICON *picon )
+{
+ UINT r = ERROR_FUNCTION_FAILED;
+ LPWSTR tmp;
+ MSIRECORD *rec;
+ HICON hicon = 0;
+
+ TRACE("loading %s\n", debugstr_w( name ) );
+
+ tmp = msi_create_tmp_path();
+ if( !tmp )
+ return r;
+
+ rec = msi_get_binary_record( db, name );
+ if( rec )
+ {
+ r = MSI_RecordStreamToFile( rec, 2, tmp );
+ if( r == ERROR_SUCCESS )
+ {
+ DWORD cx = 0, cy = 0, flags = LR_LOADFROMFILE | LR_DEFAULTSIZE;
+
+ if( attributes & msidbControlAttributesFixedSize )
+ {
+ flags &= ~LR_DEFAULTSIZE;
+ if( attributes & msidbControlAttributesIconSize16 )
+ {
+ cx += 16;
+ cy += 16;
+ }
+ if( attributes & msidbControlAttributesIconSize32 )
+ {
+ cx += 32;
+ cy += 32;
+ }
+ /* msidbControlAttributesIconSize48 handled by above logic */
+ }
+
+ hicon = LoadImageW( 0, tmp, IMAGE_ICON, cx, cy, flags );
+ if( hicon )
+ *picon = hicon;
+ else
+ ERR("failed to load icon from %s\n", debugstr_w( tmp ));
+ DeleteFileW( tmp );
+ }
+ msiobj_release( &rec->hdr );
+ }
+
+ HeapFree( GetProcessHeap(), 0, tmp );
+
+ return r;
+}
+
+static UINT msi_dialog_icon_control( msi_dialog *dialog, MSIRECORD *rec )
+{
+ msi_control *control;
+ DWORD attributes;
+ HICON hIcon = 0;
+ LPCWSTR text;
+ UINT r;
+
+ TRACE("\n");
+
+ control = msi_dialog_add_control( dialog, rec, szStatic,
+ SS_ICON | SS_CENTERIMAGE | WS_GROUP );
+ text = MSI_RecordGetString( rec, 10 );
+ attributes = MSI_RecordGetInteger( rec, 8 );
+ r = msi_load_icon( dialog->package->db, text, attributes, &hIcon );
+ if( r == ERROR_SUCCESS )
+ {
+ r = SendMessageW( control->hwnd, STM_SETICON, (WPARAM) hIcon, 0 );
+ control->hIcon = hIcon;
+ }
+ else
+ ERR("Failed to load bitmap %s\n", debugstr_w(text));
+ return ERROR_SUCCESS;
+}
+
static UINT msi_dialog_combo_control( msi_dialog *dialog, MSIRECORD *rec )
{
static const WCHAR szCombo[] = { 'C','O','M','B','O','B','O','X',0 };
static UINT msi_dialog_edit_control( msi_dialog *dialog, MSIRECORD *rec )
{
- const static WCHAR szEdit[] = { 'E','D','I','T',0 };
msi_control *control;
LPCWSTR prop;
LPWSTR val;
- control = msi_dialog_add_control( dialog, rec, szEdit, WS_BORDER );
+ control = msi_dialog_add_control( dialog, rec, szEdit,
+ WS_BORDER | WS_TABSTOP );
control->handler = msi_dialog_edit_handler;
prop = MSI_RecordGetString( rec, 9 );
if( prop )
return ERROR_SUCCESS;
}
+/******************** Masked Edit ********************************************/
+
+#define MASK_MAX_GROUPS 10
+
+struct msi_mask_group
+{
+ UINT len;
+ UINT ofs;
+ WCHAR type;
+ HWND hwnd;
+};
+
+struct msi_maskedit_info
+{
+ msi_dialog *dialog;
+ WNDPROC oldproc;
+ HWND hwnd;
+ LPWSTR prop;
+ UINT num_chars;
+ UINT num_groups;
+ struct msi_mask_group group[MASK_MAX_GROUPS];
+};
+
+static void msi_mask_control_change( struct msi_maskedit_info *info )
+{
+ LPWSTR val;
+ UINT i, n, r;
+
+ val = HeapAlloc( GetProcessHeap(), 0, (info->num_chars+1)*sizeof(WCHAR) );
+ for( i=0, n=0; i<info->num_groups; i++ )
+ {
+ if( (info->group[i].len + n) > info->num_chars )
+ {
+ ERR("can't fit control %d text into template\n",i);
+ break;
+ }
+ r = GetWindowTextW( info->group[i].hwnd, &val[n], info->group[i].len+1 );
+ if( r != info->group[i].len )
+ break;
+ n += r;
+ }
+
+ TRACE("%d/%d controls were good\n", i, info->num_groups);
+
+ if( i == info->num_groups )
+ {
+ TRACE("Set property %s to %s\n",
+ debugstr_w(info->prop), debugstr_w(val) );
+ CharUpperBuffW( val, info->num_chars );
+ MSI_SetPropertyW( info->dialog->package, info->prop, val );
+ msi_dialog_evaluate_control_conditions( info->dialog );
+ }
+ HeapFree( GetProcessHeap(), 0, val );
+}
+
+static LRESULT WINAPI
+MSIMaskedEdit_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct msi_maskedit_info *info;
+ HRESULT r;
+
+ TRACE("%p %04x %08x %08lx\n", hWnd, msg, wParam, lParam);
+
+ info = GetPropW(hWnd, szButtonData);
+
+ r = CallWindowProcW(info->oldproc, hWnd, msg, wParam, lParam);
+
+ switch( msg )
+ {
+ case WM_COMMAND:
+ if (HIWORD(wParam) == EN_CHANGE)
+ msi_mask_control_change( info );
+ break;
+ case WM_NCDESTROY:
+ HeapFree( GetProcessHeap(), 0, info->prop );
+ HeapFree( GetProcessHeap(), 0, info );
+ RemovePropW( hWnd, szButtonData );
+ break;
+ }
+
+ return r;
+}
+
+/* fish the various bits of the property out and put them in the control */
+static void
+msi_maskedit_set_text( struct msi_maskedit_info *info, LPCWSTR text )
+{
+ LPCWSTR p;
+ UINT i;
+
+ p = text;
+ for( i = 0; i < info->num_groups; i++ )
+ {
+ if( info->group[i].len < lstrlenW( p ) )
+ {
+ LPWSTR chunk = strdupW( p );
+ chunk[ info->group[i].len ] = 0;
+ SetWindowTextW( info->group[i].hwnd, chunk );
+ HeapFree( GetProcessHeap(), 0, chunk );
+ }
+ else
+ {
+ SetWindowTextW( info->group[i].hwnd, p );
+ break;
+ }
+ p += info->group[i].len;
+ }
+}
+
+static struct msi_maskedit_info * msi_dialog_parse_groups( LPCWSTR mask )
+{
+ struct msi_maskedit_info * info = NULL;
+ int i = 0, n = 0, total = 0;
+ LPCWSTR p;
+
+ TRACE("masked control, template %s\n", debugstr_w(mask));
+
+ if( !mask )
+ return info;
+
+ p = strchrW(mask, '<');
+ if( !p )
+ return info;
+
+ info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *info );
+ if( !info )
+ return info;
+
+ p++;
+ for( i=0; i<MASK_MAX_GROUPS; i++ )
+ {
+ /* stop at the end of the string */
+ if( p[0] == 0 || p[0] == '>' )
+ break;
+
+ /* count the number of the same identifier */
+ for( n=0; p[n] == p[0]; n++ )
+ ;
+ info->group[i].ofs = total;
+ info->group[i].type = p[0];
+ if( p[n] == '=' )
+ {
+ n++;
+ total++; /* an extra not part of the group */
+ }
+ info->group[i].len = n;
+ total += n;
+ p += n;
+ }
+
+ TRACE("%d characters in %d groups\n", total, info->num_groups );
+ if( i == MASK_MAX_GROUPS )
+ ERR("too many groups in PIDTemplate %s\n", debugstr_w(mask));
+
+ info->num_chars = total;
+ info->num_groups = i;
+
+ return info;
+}
+
+static void
+msi_maskedit_create_children( struct msi_maskedit_info *info )
+{
+ DWORD width, height, style, wx, ww;
+ LPCWSTR text, font = NULL;
+ RECT rect;
+ HWND hwnd;
+ UINT i;
+
+ style = WS_CHILD | WS_BORDER | WS_VISIBLE | WS_TABSTOP;
+
+ GetClientRect( info->hwnd, &rect );
+
+ width = rect.right - rect.left;
+ height = rect.bottom - rect.top;
+
+ if( text )
+ font = msi_dialog_get_style( &text );
+
+ for( i = 0; i < info->num_groups; i++ )
+ {
+ wx = (info->group[i].ofs * width) / info->num_chars;
+ ww = (info->group[i].len * width) / info->num_chars;
+
+ hwnd = CreateWindowW( szEdit, NULL, style, wx, 0, ww, height,
+ info->hwnd, NULL, NULL, NULL );
+ if( !hwnd )
+ {
+ ERR("failed to create mask edit sub window\n");
+ break;
+ }
+
+ SendMessageW( hwnd, EM_LIMITTEXT, info->group[i].len, 0 );
+
+ msi_dialog_set_font( info->dialog, hwnd,
+ font ? font : info->dialog->default_font );
+ info->group[i].hwnd = hwnd;
+ }
+}
+
+/* office 2003 uses "73931<````=````=````=````=`````>@@@@@" */
+static UINT msi_dialog_maskedit_control( msi_dialog *dialog, MSIRECORD *rec )
+{
+ const static WCHAR pidt[] = {'P','I','D','T','e','m','p','l','a','t','e',0};
+ LPWSTR mask = NULL, title = NULL, val = NULL;
+ struct msi_maskedit_info *info = NULL;
+ UINT ret = ERROR_SUCCESS;
+ msi_control *control;
+ LPCWSTR prop;
+
+ mask = load_dynamic_property( dialog->package, pidt, NULL );
+ if( !mask )
+ {
+ ERR("PIDTemplate is empty\n");
+ goto end;
+ }
+
+ info = msi_dialog_parse_groups( mask );
+ if( !info )
+ {
+ ERR("template %s is invalid\n", debugstr_w(mask));
+ goto end;
+ }
+
+ info->dialog = dialog;
+
+ control = msi_dialog_add_control( dialog, rec, szStatic,
+ SS_OWNERDRAW | WS_GROUP | WS_VISIBLE );
+ if( !control )
+ {
+ ERR("Failed to create maskedit container\n");
+ ret = ERROR_FUNCTION_FAILED;
+ goto end;
+ }
+ SetWindowLongPtrW( control->hwnd, GWL_EXSTYLE, WS_EX_CONTROLPARENT );
+
+ info->hwnd = control->hwnd;
+
+ /* subclass the static control */
+ info->oldproc = (WNDPROC) SetWindowLongPtrW( info->hwnd, GWLP_WNDPROC,
+ (LONG_PTR)MSIMaskedEdit_WndProc );
+ SetPropW( control->hwnd, szButtonData, info );
+
+ prop = MSI_RecordGetString( rec, 9 );
+ if( prop )
+ info->prop = strdupW( prop );
+
+ msi_maskedit_create_children( info );
+
+ if( prop )
+ {
+ val = load_dynamic_property( dialog->package, prop, NULL );
+ if( val )
+ {
+ msi_maskedit_set_text( info, val );
+ HeapFree( GetProcessHeap(), 0, val );
+ }
+ }
+
+end:
+ if( ret != ERROR_SUCCESS )
+ HeapFree( GetProcessHeap(), 0, info );
+ HeapFree( GetProcessHeap(), 0, title );
+ HeapFree( GetProcessHeap(), 0, mask );
+ return ret;
+}
+
+/******************** Path Edit ********************************************/
+
static UINT msi_dialog_pathedit_control( msi_dialog *dialog, MSIRECORD *rec )
{
FIXME("not implemented properly\n");
DWORD style;
DWORD attributes = group->attributes;
- style = WS_CHILD | BS_AUTORADIOBUTTON | BS_MULTILINE;
+ style = WS_CHILD | BS_AUTORADIOBUTTON | BS_MULTILINE | WS_TABSTOP;
name = MSI_RecordGetString( rec, 3 );
text = MSI_RecordGetString( rec, 8 );
if( attributes & 1 )
MSIQUERY *view = NULL;
radio_button_group_descr group;
MSIPACKAGE *package = dialog->package;
+ WNDPROC oldproc;
prop = MSI_RecordGetString( rec, 9 );
TRACE("%p %p %s\n", dialog, rec, debugstr_w( prop ));
/* Create parent group box to hold radio buttons */
- control = msi_dialog_add_control( dialog, rec, szButton, BS_OWNERDRAW );
+ control = msi_dialog_add_control( dialog, rec, szButton, BS_OWNERDRAW|WS_GROUP );
+ if( !control )
+ return ERROR_FUNCTION_FAILED;
- if (control->hwnd)
- {
- WNDPROC oldproc = (WNDPROC) SetWindowLongPtrW(control->hwnd, GWLP_WNDPROC,
- (LONG_PTR)MSIRadioGroup_WndProc);
- SetPropW(control->hwnd, szButtonData, oldproc);
- }
+ oldproc = (WNDPROC) SetWindowLongPtrW( control->hwnd, GWLP_WNDPROC,
+ (LONG_PTR)MSIRadioGroup_WndProc );
+ SetPropW(control->hwnd, szButtonData, oldproc);
+ SetWindowLongPtrW( control->hwnd, GWL_EXSTYLE, WS_EX_CONTROLPARENT );
if( prop )
control->property = strdupW( prop );
return r;
}
-static const WCHAR szText[] = { 'T','e','x','t',0 };
-static const WCHAR szPushButton[] = { 'P','u','s','h','B','u','t','t','o','n',0 };
-static const WCHAR szLine[] = { 'L','i','n','e',0 };
-static const WCHAR szBitmap[] = { 'B','i','t','m','a','p',0 };
-static const WCHAR szCheckBox[] = { 'C','h','e','c','k','B','o','x',0 };
-static const WCHAR szScrollableText[] = {
- 'S','c','r','o','l','l','a','b','l','e','T','e','x','t',0 };
-static const WCHAR szComboBox[] = { 'C','o','m','b','o','B','o','x',0 };
-static const WCHAR szEdit[] = { 'E','d','i','t',0 };
-static const WCHAR szMaskedEdit[] = { 'M','a','s','k','e','d','E','d','i','t',0 };
-static const WCHAR szPathEdit[] = { 'P','a','t','h','E','d','i','t',0 };
-static const WCHAR szRadioButtonGroup[] = {
- 'R','a','d','i','o','B','u','t','t','o','n','G','r','o','u','p',0 };
-
struct control_handler msi_dialog_handler[] =
{
{ szText, msi_dialog_text_control },
{ szScrollableText, msi_dialog_scrolltext_control },
{ szComboBox, msi_dialog_combo_control },
{ szEdit, msi_dialog_edit_control },
- { szMaskedEdit, msi_dialog_edit_control },
+ { szMaskedEdit, msi_dialog_maskedit_control },
{ szPathEdit, msi_dialog_pathedit_control },
{ szRadioButtonGroup, msi_dialog_radiogroup_control },
+ { szIcon, msi_dialog_icon_control },
};
#define NUM_CONTROL_TYPES (sizeof msi_dialog_handler/sizeof msi_dialog_handler[0])
return r;
}
-static msi_control *msi_dialog_find_control( msi_dialog *dialog, LPCWSTR name )
-{
- msi_control *control;
-
- for( control = dialog->control_list; control; control = control->next )
- if( !strcmpW( control->name, name ) ) /* FIXME: case sensitive? */
- break;
- return control;
-}
-
-static msi_control *msi_dialog_find_control_by_hwnd( msi_dialog *dialog, HWND hwnd )
-{
- msi_control *control;
-
- for( control = dialog->control_list; control; control = control->next )
- if( hwnd == control->hwnd )
- break;
- return control;
-}
-
static UINT msi_dialog_set_control_condition( MSIRECORD *rec, LPVOID param )
{
static const WCHAR szHide[] = { 'H','i','d','e',0 };
TRACE("%s control %s\n", debugstr_w(action), debugstr_w(name));
/* FIXME: case sensitive? */
- if(!strcmpW(action, szHide))
+ if(!lstrcmpW(action, szHide))
ShowWindow(control->hwnd, SW_HIDE);
else if(!strcmpW(action, szShow))
ShowWindow(control->hwnd, SW_SHOW);
'W','H','E','R','E',' ',
'`','D','i','a','l','o','g','`',' ','=',' ','\'','%','s','\'',0};
MSIPACKAGE *package = dialog->package;
- MSIQUERY *view = NULL;
MSIRECORD *rec = NULL;
- UINT r;
TRACE("%p %s\n", dialog, debugstr_w(dialog->name) );
- r = MSI_OpenQuery( package->db, &view, query, dialog->name );
- if( r != ERROR_SUCCESS )
- {
+ rec = MSI_QueryGetRecord( package->db, query, dialog->name );
+ if( !rec )
ERR("query failed for dialog %s\n", debugstr_w(dialog->name));
- return NULL;
- }
- MSI_ViewExecute( view, NULL );
- MSI_ViewFetch( view, &rec );
- MSI_ViewClose( view );
- msiobj_release( &view->hdr );
return rec;
}
+static void msi_dialog_adjust_dialog_size( msi_dialog *dialog, LPSIZE sz )
+{
+ RECT rect;
+ LONG style;
+
+ /* turn the client size into the window rectangle */
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = msi_dialog_scale_unit( dialog, sz->cx );
+ rect.bottom = msi_dialog_scale_unit( dialog, sz->cy );
+ style = GetWindowLongPtrW( dialog->hwnd, GWL_STYLE );
+ AdjustWindowRect( &rect, style, FALSE );
+ sz->cx = rect.right - rect.left;
+ sz->cy = rect.bottom - rect.top;
+}
+
static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs )
{
static const WCHAR df[] = {
'D','e','f','a','u','l','t','U','I','F','o','n','t',0 };
msi_dialog *dialog = (msi_dialog*) cs->lpCreateParams;
MSIRECORD *rec = NULL;
- DWORD width, height;
LPCWSTR text;
LPWSTR title = NULL;
+ SIZE size;
TRACE("%p %p\n", dialog, dialog->package);
dialog->scale = msi_dialog_get_sans_serif_height(dialog->hwnd);
- width = MSI_RecordGetInteger( rec, 4 );
- height = MSI_RecordGetInteger( rec, 5 );
+ size.cx = MSI_RecordGetInteger( rec, 4 );
+ size.cy = MSI_RecordGetInteger( rec, 5 );
+ msi_dialog_adjust_dialog_size( dialog, &size );
+
dialog->attributes = MSI_RecordGetInteger( rec, 6 );
text = MSI_RecordGetString( rec, 7 );
- width = msi_dialog_scale_unit( dialog, width );
- height = msi_dialog_scale_unit( dialog, height ) + 25; /* FIXME */
-
dialog->default_font = load_dynamic_property( dialog->package, df, NULL );
deformat_string( dialog->package, text, &title );
SetWindowTextW( hwnd, title );
- SetWindowPos( hwnd, 0, 0, 0, width, height,
+ SetWindowPos( hwnd, 0, 0, 0, size.cx, size.cy,
SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW );
HeapFree( GetProcessHeap(), 0, title );
DWORD sz = 2;
MSI_GetPropertyW( dialog->package, control->property, state, &sz );
- return atoiW( state ) ? 1 : 0;
+ return state[0] ? 1 : 0;
}
static void msi_dialog_set_checkbox_state( msi_dialog *dialog,
msi_control *control, UINT state )
{
- WCHAR szState[2] = { '0', 0 };
+ static const WCHAR szState[] = { '1', 0 };
+ LPCWSTR val;
- if( state )
- szState[0]++;
- MSI_SetPropertyW( dialog->package, control->property, szState );
+ /* if uncheck then the property is set to NULL */
+ if (!state)
+ {
+ MSI_SetPropertyW( dialog->package, control->property, NULL );
+ return;
+ }
+
+ /* check for a custom state */
+ if (control->value && control->value[0])
+ val = control->value;
+ else
+ val = szState;
+
+ MSI_SetPropertyW( dialog->package, control->property, val );
}
static void msi_dialog_checkbox_sync_state( msi_dialog *dialog,
case WM_COMMAND:
return msi_dialog_oncommand( dialog, wParam, (HWND)lParam );
+ /* bounce back to our subclassed static control */
+ case WM_CTLCOLORSTATIC:
+ return SendMessageW( (HWND) lParam, WM_CTLCOLORSTATIC, wParam, lParam );
+
case WM_DESTROY:
dialog->hwnd = NULL;
return 0;
return dialog;
}
-static void msi_process_pending_messages(void)
+static void msi_process_pending_messages( HWND hdlg )
{
MSG msg;
while( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ) )
{
+ if( hdlg && IsDialogMessageW( hdlg, &msg ))
+ continue;
TranslateMessage( &msg );
DispatchMessageW( &msg );
}
/* there's two choices for the UI thread */
while (1)
{
- msi_process_pending_messages();
+ msi_process_pending_messages( NULL );
if( !handle )
break;
while( !dialog->finished )
{
MsgWaitForMultipleObjects( 0, NULL, 0, INFINITE, QS_ALLEVENTS );
- msi_process_pending_messages();
+ msi_process_pending_messages( dialog->hwnd );
}
}
else
dialog->control_list = t->next;
/* leave dialog->hwnd - destroying parent destroys child windows */
HeapFree( GetProcessHeap(), 0, t->property );
+ HeapFree( GetProcessHeap(), 0, t->value );
if( t->pic )
IPicture_Release( t->pic );
+ if( t->hIcon )
+ DestroyIcon( t->hIcon );
HeapFree( GetProcessHeap(), 0, t );
}
if( !hMsiHiddenWindow )
return FALSE;
+ hRichedit = LoadLibraryA("riched20");
+
return TRUE;
}
DestroyWindow( hMsiHiddenWindow );
UnregisterClassW( szMsiDialogClass, NULL );
uiThreadId = 0;
+ FreeLibrary( hRichedit );
}
--- /dev/null
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2005 Aric Stewart for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/*
+http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/controlevent_overview.asp
+*/
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "winreg.h"
+#include "msi.h"
+#include "msipriv.h"
+#include "action.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+typedef UINT (*EVENTHANDLER)(MSIPACKAGE*,LPCWSTR,msi_dialog *);
+
+struct _events {
+ LPCSTR event;
+ EVENTHANDLER handler;
+};
+
+struct subscriber {
+ struct list entry;
+ LPWSTR event;
+ LPWSTR control;
+ LPWSTR attribute;
+};
+
+UINT ControlEvent_HandleControlEvent(MSIPACKAGE *, LPCWSTR, LPCWSTR, msi_dialog*);
+
+/*
+ * Create a dialog box and run it if it's modal
+ */
+static UINT event_do_dialog( MSIPACKAGE *package, LPCWSTR name )
+{
+ msi_dialog *dialog;
+ UINT r;
+
+ /* kill the current modeless dialog */
+ if( package->dialog )
+ msi_dialog_destroy( package->dialog );
+ package->dialog = NULL;
+
+ /* create a new dialog */
+ dialog = msi_dialog_create( package, name,
+ ControlEvent_HandleControlEvent );
+ if( dialog )
+ {
+ /* modeless dialogs return an error message */
+ r = msi_dialog_run_message_loop( dialog );
+ if( r == ERROR_SUCCESS )
+ msi_dialog_destroy( dialog );
+ else
+ package->dialog = dialog;
+ }
+ else
+ r = ERROR_FUNCTION_FAILED;
+
+ return r;
+}
+
+
+/*
+ * End a modal dialog box
+ */
+static UINT ControlEvent_EndDialog(MSIPACKAGE* package, LPCWSTR argument,
+ msi_dialog* dialog)
+{
+ static const WCHAR szExit[] = {
+ 'E','x','i','t',0};
+ static const WCHAR szRetry[] = {
+ 'R','e','t','r','y',0};
+ static const WCHAR szIgnore[] = {
+ 'I','g','n','o','r','e',0};
+ static const WCHAR szReturn[] = {
+ 'R','e','t','u','r','n',0};
+
+ if (lstrcmpW(argument,szExit)==0)
+ package->CurrentInstallState = ERROR_INSTALL_USEREXIT;
+ else if (lstrcmpW(argument, szRetry) == 0)
+ package->CurrentInstallState = ERROR_INSTALL_SUSPEND;
+ else if (lstrcmpW(argument, szIgnore) == 0)
+ package->CurrentInstallState = -1;
+ else if (lstrcmpW(argument, szReturn) == 0)
+ package->CurrentInstallState = ERROR_SUCCESS;
+ else
+ {
+ ERR("Unknown argument string %s\n",debugstr_w(argument));
+ package->CurrentInstallState = ERROR_FUNCTION_FAILED;
+ }
+
+ ControlEvent_CleanupSubscriptions(package);
+ msi_dialog_end_dialog( dialog );
+ return ERROR_SUCCESS;
+}
+
+/*
+ * transition from one modal dialog to another modal dialog
+ */
+static UINT ControlEvent_NewDialog(MSIPACKAGE* package, LPCWSTR argument,
+ msi_dialog *dialog)
+{
+ /* store the name of the next dialog, and signal this one to end */
+ package->next_dialog = strdupW(argument);
+ ControlEvent_CleanupSubscriptions(package);
+ msi_dialog_end_dialog( dialog );
+ return ERROR_SUCCESS;
+}
+
+/*
+ * Create a new child dialog of an existing modal dialog
+ */
+static UINT ControlEvent_SpawnDialog(MSIPACKAGE* package, LPCWSTR argument,
+ msi_dialog *dialog)
+{
+ event_do_dialog( package, argument );
+ if( package->CurrentInstallState != ERROR_SUCCESS )
+ msi_dialog_end_dialog( dialog );
+ return ERROR_SUCCESS;
+}
+
+/*
+ * Creates a dialog that remains up for a period of time
+ * based on a condition
+ */
+static UINT ControlEvent_SpawnWaitDialog(MSIPACKAGE* package, LPCWSTR argument,
+ msi_dialog* dialog)
+{
+ FIXME("Doing Nothing\n");
+ return ERROR_SUCCESS;
+}
+
+static UINT ControlEvent_DoAction(MSIPACKAGE* package, LPCWSTR argument,
+ msi_dialog* dialog)
+{
+ ACTION_PerformAction(package,argument,TRUE);
+ return ERROR_SUCCESS;
+}
+
+static UINT ControlEvent_AddLocal(MSIPACKAGE* package, LPCWSTR argument,
+ msi_dialog* dialog)
+{
+ static const WCHAR szAll[] = {'A','L','L',0};
+ int i;
+
+ if (lstrcmpW(szAll,argument))
+ {
+ MSI_SetFeatureStateW(package,argument,INSTALLSTATE_LOCAL);
+ }
+ else
+ {
+ for (i = 0; i < package->loaded_features; i++)
+ {
+ package->features[i].ActionRequest = INSTALLSTATE_LOCAL;
+ package->features[i].Action = INSTALLSTATE_LOCAL;
+ }
+ ACTION_UpdateComponentStates(package,argument);
+ }
+ return ERROR_SUCCESS;
+}
+
+static UINT ControlEvent_Remove(MSIPACKAGE* package, LPCWSTR argument,
+ msi_dialog* dialog)
+{
+ static const WCHAR szAll[] = {'A','L','L',0};
+ int i;
+
+ if (lstrcmpW(szAll,argument))
+ {
+ MSI_SetFeatureStateW(package,argument,INSTALLSTATE_ABSENT);
+ }
+ else
+ {
+ for (i = 0; i < package->loaded_features; i++)
+ {
+ package->features[i].ActionRequest = INSTALLSTATE_ABSENT;
+ package->features[i].Action= INSTALLSTATE_ABSENT;
+ }
+ ACTION_UpdateComponentStates(package,argument);
+ }
+ return ERROR_SUCCESS;
+}
+
+static UINT ControlEvent_AddSource(MSIPACKAGE* package, LPCWSTR argument,
+ msi_dialog* dialog)
+{
+ static const WCHAR szAll[] = {'A','L','L',0};
+ int i;
+
+ if (lstrcmpW(szAll,argument))
+ {
+ MSI_SetFeatureStateW(package,argument,INSTALLSTATE_SOURCE);
+ }
+ else
+ {
+ for (i = 0; i < package->loaded_features; i++)
+ {
+ package->features[i].ActionRequest = INSTALLSTATE_SOURCE;
+ package->features[i].Action = INSTALLSTATE_SOURCE;
+ }
+ ACTION_UpdateComponentStates(package,argument);
+ }
+ return ERROR_SUCCESS;
+}
+
+static UINT ControlEvent_SetTargetPath(MSIPACKAGE* package, LPCWSTR argument,
+ msi_dialog* dialog)
+{
+ LPWSTR path = load_dynamic_property(package,argument, NULL);
+ /* failure to set the path halts the executing of control events */
+ return MSI_SetTargetPathW(package, argument, path);
+}
+
+/*
+ * Subscribed events
+ */
+static void free_subscriber( struct subscriber *sub )
+{
+ HeapFree(GetProcessHeap(),0,sub->event);
+ HeapFree(GetProcessHeap(),0,sub->control);
+ HeapFree(GetProcessHeap(),0,sub->attribute);
+ HeapFree(GetProcessHeap(),0,sub);
+}
+
+VOID ControlEvent_SubscribeToEvent( MSIPACKAGE *package, LPCWSTR event,
+ LPCWSTR control, LPCWSTR attribute )
+{
+ struct subscriber *sub;
+
+ sub = HeapAlloc(GetProcessHeap(),0,sizeof (*sub));
+ if( !sub )
+ return;
+ sub->event = strdupW(event);
+ sub->control = strdupW(control);
+ sub->attribute = strdupW(attribute);
+ list_add_tail( &package->subscriptions, &sub->entry );
+}
+
+VOID ControlEvent_UnSubscribeToEvent( MSIPACKAGE *package, LPCWSTR event,
+ LPCWSTR control, LPCWSTR attribute )
+{
+ struct list *i, *t;
+ struct subscriber *sub;
+
+ LIST_FOR_EACH_SAFE( i, t, &package->subscriptions )
+ {
+ sub = LIST_ENTRY( i, struct subscriber, entry );
+
+ if( lstrcmpiW(sub->control,control) )
+ continue;
+ if( lstrcmpiW(sub->attribute,attribute) )
+ continue;
+ if( lstrcmpiW(sub->event,event) )
+ continue;
+ list_remove( &sub->entry );
+ free_subscriber( sub );
+ }
+}
+
+VOID ControlEvent_FireSubscribedEvent( MSIPACKAGE *package, LPCWSTR event,
+ MSIRECORD *rec )
+{
+ struct subscriber *sub;
+
+ TRACE("Firing Event %s\n",debugstr_w(event));
+
+ if (!package->dialog)
+ return;
+
+ LIST_FOR_EACH_ENTRY( sub, &package->subscriptions, struct subscriber, entry )
+ {
+ if (lstrcmpiW(sub->event, event))
+ continue;
+ msi_dialog_handle_event( package->dialog, sub->control,
+ sub->attribute, rec );
+ }
+}
+
+VOID ControlEvent_CleanupSubscriptions(MSIPACKAGE *package)
+{
+ struct list *i, *t;
+ struct subscriber *sub;
+
+ LIST_FOR_EACH_SAFE( i, t, &package->subscriptions )
+ {
+ sub = LIST_ENTRY( i, struct subscriber, entry );
+
+ list_remove( &sub->entry );
+ free_subscriber( sub );
+ }
+}
+
+/*
+ * ACTION_DialogBox()
+ *
+ * Return ERROR_SUCCESS if dialog is process and ERROR_FUNCTION_FAILED
+ * if the given parameter is not a dialog box
+ */
+UINT ACTION_DialogBox( MSIPACKAGE* package, LPCWSTR szDialogName )
+{
+ UINT r = ERROR_SUCCESS;
+
+ if( package->next_dialog )
+ ERR("Already a next dialog... ignoring it\n");
+ package->next_dialog = NULL;
+
+ /*
+ * Dialogs are chained by filling in the next_dialog member
+ * of the package structure, then terminating the current dialog.
+ * The code below sees the next_dialog member set, and runs the
+ * next dialog.
+ * We fall out of the loop below if we come across a modeless
+ * dialog, as it returns ERROR_IO_PENDING when we try to run
+ * its message loop.
+ */
+ r = event_do_dialog( package, szDialogName );
+ while( r == ERROR_SUCCESS && package->next_dialog )
+ {
+ LPWSTR name = package->next_dialog;
+
+ package->next_dialog = NULL;
+ r = event_do_dialog( package, name );
+ HeapFree( GetProcessHeap(), 0, name );
+ }
+
+ if( r == ERROR_IO_PENDING )
+ r = ERROR_SUCCESS;
+
+ return r;
+}
+
+struct _events Events[] = {
+ { "EndDialog",ControlEvent_EndDialog },
+ { "NewDialog",ControlEvent_NewDialog },
+ { "SpawnDialog",ControlEvent_SpawnDialog },
+ { "SpawnWaitDialog",ControlEvent_SpawnWaitDialog },
+ { "DoAction",ControlEvent_DoAction },
+ { "AddLocal",ControlEvent_AddLocal },
+ { "Remove",ControlEvent_Remove },
+ { "AddSource",ControlEvent_AddSource },
+ { "SetTargetPath",ControlEvent_SetTargetPath },
+ { NULL,NULL },
+};
+
+UINT ControlEvent_HandleControlEvent(MSIPACKAGE *package, LPCWSTR event,
+ LPCWSTR argument, msi_dialog* dialog)
+{
+ int i = 0;
+ UINT rc = ERROR_SUCCESS;
+
+ TRACE("Handling Control Event %s\n",debugstr_w(event));
+ if (!event)
+ return rc;
+
+ while( Events[i].event != NULL)
+ {
+ LPWSTR wevent = strdupAtoW(Events[i].event);
+ if (lstrcmpW(wevent,event)==0)
+ {
+ HeapFree(GetProcessHeap(),0,wevent);
+ rc = Events[i].handler(package,argument,dialog);
+ return rc;
+ }
+ HeapFree(GetProcessHeap(),0,wevent);
+ i++;
+ }
+ FIXME("unhandled control event %s arg(%s)\n",
+ debugstr_w(event), debugstr_w(argument));
+ return rc;
+}
--- /dev/null
+/*
+ * 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;
+} CabData;
+
+static void * cabinet_alloc(ULONG cb)
+{
+ return HeapAlloc(GetProcessHeap(), 0, cb);
+}
+
+static void cabinet_free(void *pv)
+{
+ HeapFree(GetProcessHeap(), 0, pv);
+}
+
+static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
+{
+ DWORD dwAccess = 0;
+ DWORD dwShareMode = 0;
+ DWORD dwCreateDisposition = OPEN_EXISTING;
+ switch (oflag & _O_ACCMODE)
+ {
+ case _O_RDONLY:
+ dwAccess = GENERIC_READ;
+ dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
+ break;
+ case _O_WRONLY:
+ dwAccess = GENERIC_WRITE;
+ dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ break;
+ case _O_RDWR:
+ dwAccess = GENERIC_READ | GENERIC_WRITE;
+ dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+ break;
+ }
+ if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
+ dwCreateDisposition = CREATE_NEW;
+ else if (oflag & _O_CREAT)
+ dwCreateDisposition = CREATE_ALWAYS;
+ return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
+ dwCreateDisposition, 0, NULL);
+}
+
+static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)
+{
+ DWORD dwRead;
+ if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL))
+ return dwRead;
+ return 0;
+}
+
+static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)
+{
+ DWORD dwWritten;
+ if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL))
+ return dwWritten;
+ return 0;
+}
+
+static int cabinet_close(INT_PTR hf)
+{
+ return CloseHandle((HANDLE)hf) ? 0 : -1;
+}
+
+static long cabinet_seek(INT_PTR hf, long dist, int seektype)
+{
+ /* flags are compatible and so are passed straight through */
+ return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
+}
+
+static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
+{
+ switch (fdint)
+ {
+ case fdintCOPY_FILE:
+ {
+ CabData *data = (CabData*) pfdin->pv;
+ ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
+ char *file;
+
+ LPWSTR trackname;
+ LPWSTR trackpath;
+ LPWSTR tracknametmp;
+ static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
+ LPWSTR given_file;
+ INT index;
+
+ MSIRECORD * uirow;
+ LPWSTR uipath;
+
+ given_file = strdupAtoW(pfdin->psz1);
+ index = get_loaded_file(data->package, given_file);
+
+ if (index < 0)
+ {
+ ERR("Unknown File in Cabinent (%s)\n",debugstr_w(given_file));
+ HeapFree(GetProcessHeap(),0,given_file);
+ return 0;
+ }
+
+ if (!((data->package->files[index].State == 1 ||
+ data->package->files[index].State == 2)))
+ {
+ TRACE("Skipping extraction of %s\n",debugstr_w(given_file));
+ HeapFree(GetProcessHeap(),0,given_file);
+ return 0;
+ }
+
+ file = cabinet_alloc((len+1)*sizeof(char));
+ strcpy(file, data->cab_path);
+ strcat(file, pfdin->psz1);
+
+ TRACE("file: %s\n", debugstr_a(file));
+
+ /* track this file so it can be deleted if not installed */
+ trackpath=strdupAtoW(file);
+ tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
+ trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) +
+ strlenW(tmpprefix)+1) * sizeof(WCHAR));
+
+ strcpyW(trackname,tmpprefix);
+ strcatW(trackname,tracknametmp);
+
+ track_tempfile(data->package, trackname, trackpath);
+
+ HeapFree(GetProcessHeap(),0,trackpath);
+ HeapFree(GetProcessHeap(),0,trackname);
+ HeapFree(GetProcessHeap(),0,tracknametmp);
+
+ /* the UI chunk */
+ uirow=MSI_CreateRecord(9);
+ MSI_RecordSetStringW(uirow,1,data->package->files[index].File);
+ uipath = strdupW(data->package->files[index].TargetPath);
+ *(strrchrW(uipath,'\\')+1)=0;
+ MSI_RecordSetStringW(uirow,9,uipath);
+ MSI_RecordSetInteger(uirow,6,data->package->files[index].FileSize);
+ ui_actiondata(data->package,szInstallFiles,uirow);
+ msiobj_release( &uirow->hdr );
+ HeapFree(GetProcessHeap(),0,uipath);
+
+ ui_progress(data->package,2,data->package->files[index].FileSize,0,0);
+
+ return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
+ }
+ case fdintCLOSE_FILE_INFO:
+ {
+ FILETIME ft;
+ FILETIME ftLocal;
+ if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
+ return -1;
+ if (!LocalFileTimeToFileTime(&ft, &ftLocal))
+ return -1;
+ if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal))
+ return -1;
+
+ cabinet_close(pfdin->hf);
+ return 1;
+ }
+ default:
+ return 0;
+ }
+}
+
+/***********************************************************************
+ * extract_cabinet_file
+ *
+ * Extract files from a cab file.
+ */
+static BOOL extract_cabinet_file(MSIPACKAGE* package, LPCWSTR source,
+ LPCWSTR path)
+{
+ HFDI hfdi;
+ ERF erf;
+ BOOL ret;
+ char *cabinet;
+ char *cab_path;
+ CabData data;
+
+ TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path));
+
+ hfdi = FDICreate(cabinet_alloc,
+ cabinet_free,
+ cabinet_open,
+ cabinet_read,
+ cabinet_write,
+ cabinet_close,
+ cabinet_seek,
+ 0,
+ &erf);
+ if (!hfdi)
+ {
+ ERR("FDICreate failed\n");
+ return FALSE;
+ }
+
+ if (!(cabinet = strdupWtoA( source )))
+ {
+ FDIDestroy(hfdi);
+ return FALSE;
+ }
+ if (!(cab_path = strdupWtoA( path )))
+ {
+ FDIDestroy(hfdi);
+ HeapFree(GetProcessHeap(), 0, cabinet);
+ return FALSE;
+ }
+
+ data.package = package;
+ data.cab_path = cab_path;
+
+ ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
+
+ if (!ret)
+ ERR("FDICopy failed\n");
+
+ FDIDestroy(hfdi);
+
+ HeapFree(GetProcessHeap(), 0, cabinet);
+ HeapFree(GetProcessHeap(), 0, cab_path);
+
+ return ret;
+}
+
+static VOID set_file_source(MSIPACKAGE* package, MSIFILE* file, MSICOMPONENT*
+ comp, LPCWSTR path)
+{
+ if (file->Attributes & msidbFileAttributesNoncompressed)
+ {
+ LPWSTR p;
+ p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
+ file->SourcePath = build_directory_name(2, p, file->ShortName);
+ HeapFree(GetProcessHeap(),0,p);
+ }
+ else
+ file->SourcePath = build_directory_name(2, path, file->File);
+}
+
+static UINT ready_media_for_file(MSIPACKAGE *package, int fileindex,
+ MSICOMPONENT* comp)
+{
+ UINT rc = ERROR_SUCCESS;
+ MSIRECORD * row = 0;
+ static WCHAR source[MAX_PATH];
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
+ '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
+ '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',
+ ' ','%', 'i',' ','O','R','D','E','R',' ','B','Y',' ',
+ '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0};
+ LPCWSTR cab;
+ DWORD sz;
+ INT seq;
+ static UINT last_sequence = 0;
+ static LPWSTR last_path = NULL;
+ MSIFILE* file = NULL;
+
+ /* cleanup signal */
+ if (!package)
+ {
+ HeapFree(GetProcessHeap(),0,last_path);
+ return ERROR_SUCCESS;
+ }
+
+ file = &package->files[fileindex];
+
+ if (file->Sequence <= last_sequence)
+ {
+ set_file_source(package,file,comp,last_path);
+ TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence);
+ return ERROR_SUCCESS;
+ }
+
+ row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence);
+ if (!row)
+ {
+ TRACE("Unable to query row\n");
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ seq = MSI_RecordGetInteger(row,2);
+ last_sequence = seq;
+
+ HeapFree(GetProcessHeap(),0,last_path);
+ last_path = NULL;
+
+ if (file->Attributes & msidbFileAttributesNoncompressed)
+ {
+ last_path = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
+ set_file_source(package,file,comp,last_path);
+ msiobj_release(&row->hdr);
+ return rc;
+ }
+
+ cab = MSI_RecordGetString(row,4);
+ if (cab)
+ {
+ TRACE("Source is CAB %s\n",debugstr_w(cab));
+ /* the stream does not contain the # character */
+ if (cab[0]=='#')
+ {
+ writeout_cabinet_stream(package,&cab[1],source);
+ last_path = strdupW(source);
+ *(strrchrW(last_path,'\\')+1)=0;
+ }
+ else
+ {
+ sz = MAX_PATH;
+ last_path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR));
+ if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
+ {
+ ERR("No Source dir defined \n");
+ rc = ERROR_FUNCTION_FAILED;
+ }
+ else
+ {
+ strcpyW(last_path,source);
+ strcatW(source,cab);
+ /* extract the cab file into a folder in the temp folder */
+ sz = MAX_PATH;
+ if (MSI_GetPropertyW(package, cszTempFolder,last_path, &sz)
+ != ERROR_SUCCESS)
+ GetTempPathW(MAX_PATH,last_path);
+ }
+ }
+ rc = !extract_cabinet_file(package, source, last_path);
+ /* reaquire file ptr */
+ file = &package->files[fileindex];
+ }
+ else
+ {
+ sz = MAX_PATH;
+ last_path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR));
+ MSI_GetPropertyW(package,cszSourceDir,source,&sz);
+ strcpyW(last_path,source);
+ }
+ set_file_source(package, file, comp, last_path);
+ msiobj_release(&row->hdr);
+
+ return rc;
+}
+
+inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
+ LPWSTR* file_source)
+{
+ DWORD index;
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ for (index = 0; index < package->loaded_files; index ++)
+ {
+ if (strcmpW(file_key,package->files[index].File)==0)
+ {
+ if (package->files[index].State >= 2)
+ {
+ *file_source = strdupW(package->files[index].TargetPath);
+ return ERROR_SUCCESS;
+ }
+ else
+ return ERROR_FILE_NOT_FOUND;
+ }
+ }
+
+ return ERROR_FUNCTION_FAILED;
+}
+
+/*
+ * In order to make this work more effeciencly I am going to do this in 2
+ * passes.
+ * Pass 1) Correct all the TargetPaths and determin what files are to be
+ * installed.
+ * Pass 2) Extract Cabinents and copy files.
+ */
+UINT ACTION_InstallFiles(MSIPACKAGE *package)
+{
+ UINT rc = ERROR_SUCCESS;
+ DWORD index;
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ /* increment progress bar each time action data is sent */
+ ui_progress(package,1,1,0,0);
+
+ /* Pass 1 */
+ for (index = 0; index < package->loaded_files; index++)
+ {
+ MSIFILE *file;
+ MSICOMPONENT* comp = NULL;
+
+ file = &package->files[index];
+
+ if (file->Temporary)
+ continue;
+
+ if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex,
+ INSTALLSTATE_LOCAL))
+ {
+ ui_progress(package,2,file->FileSize,0,0);
+ TRACE("File %s is not scheduled for install\n",
+ debugstr_w(file->File));
+
+ file->State = 5;
+ continue;
+ }
+
+ if ((file->State == 1) || (file->State == 2))
+ {
+ LPWSTR p = NULL;
+
+ TRACE("Pass 1: %s\n",debugstr_w(file->File));
+
+ create_component_directory( package, file->ComponentIndex);
+
+ /* recalculate file paths because things may have changed */
+
+ if (file->ComponentIndex >= 0)
+ comp = &package->components[file->ComponentIndex];
+ else
+ {
+ ERR("No Component for file\n");
+ continue;
+ }
+
+ p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
+ HeapFree(GetProcessHeap(),0,file->TargetPath);
+
+ file->TargetPath = build_directory_name(2, p, file->FileName);
+ HeapFree(GetProcessHeap(),0,p);
+ }
+ }
+
+ /* Pass 2 */
+ for (index = 0; index < package->loaded_files; index++)
+ {
+ MSIFILE *file;
+ MSICOMPONENT* comp = NULL;
+
+ file = &package->files[index];
+
+ if (file->Temporary)
+ continue;
+
+ if ((file->State == 1) || (file->State == 2))
+ {
+ TRACE("Pass 2: %s\n",debugstr_w(file->File));
+
+ if (file->ComponentIndex >= 0)
+ comp = &package->components[file->ComponentIndex];
+
+ rc = ready_media_for_file(package, index, comp);
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Unable to ready media\n");
+ rc = ERROR_FUNCTION_FAILED;
+ break;
+ }
+
+ /*
+ * WARNING!
+ * our file table could change here because a new temp file
+ * may have been created. So reaquire our ptr.
+ */
+ file = &package->files[index];
+
+ TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
+ debugstr_w(file->TargetPath));
+
+ if (file->Attributes & msidbFileAttributesNoncompressed)
+ rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
+ else
+ rc = MoveFileW(file->SourcePath, file->TargetPath);
+
+ if (!rc)
+ {
+ rc = GetLastError();
+ ERR("Unable to move/copy file (%s -> %s) (error %d)\n",
+ debugstr_w(file->SourcePath), debugstr_w(file->TargetPath),
+ rc);
+ if (rc == ERROR_ALREADY_EXISTS && file->State == 2)
+ {
+ if (!CopyFileW(file->SourcePath,file->TargetPath,FALSE))
+ ERR("Unable to copy file (%s -> %s) (error %ld)\n",
+ debugstr_w(file->SourcePath),
+ debugstr_w(file->TargetPath), GetLastError());
+ if (!(file->Attributes & msidbFileAttributesNoncompressed))
+ DeleteFileW(file->SourcePath);
+ rc = 0;
+ }
+ else if (rc == ERROR_FILE_NOT_FOUND)
+ {
+ ERR("Source File Not Found! Continuing\n");
+ rc = 0;
+ }
+ else if (file->Attributes & msidbFileAttributesVital)
+ {
+ ERR("Ignoring Error and continuing (nonvital file)...\n");
+ rc = 0;
+ }
+ }
+ else
+ {
+ file->State = 4;
+ rc = ERROR_SUCCESS;
+ }
+ }
+ }
+
+ /* cleanup */
+ ready_media_for_file(NULL, 0, NULL);
+ return rc;
+}
+
+static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
+{
+ MSIPACKAGE *package = (MSIPACKAGE*)param;
+ WCHAR *file_source = NULL;
+ WCHAR dest_name[0x100];
+ LPWSTR dest_path, dest;
+ LPCWSTR file_key, component;
+ INT component_index;
+ DWORD sz;
+ DWORD rc;
+
+ component = MSI_RecordGetString(row,2);
+ component_index = get_loaded_component(package,component);
+
+ if (!ACTION_VerifyComponentForAction(package, component_index,
+ INSTALLSTATE_LOCAL))
+ {
+ TRACE("Skipping copy due to disabled component %s\n",
+ debugstr_w(component));
+
+ /* the action taken was the same as the current install state */
+ package->components[component_index].Action =
+ package->components[component_index].Installed;
+
+ return ERROR_SUCCESS;
+ }
+
+ package->components[component_index].Action = INSTALLSTATE_LOCAL;
+
+ file_key = MSI_RecordGetString(row,3);
+ if (!file_key)
+ {
+ ERR("Unable to get file key\n");
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ rc = get_file_target(package,file_key,&file_source);
+
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Original file unknown %s\n",debugstr_w(file_key));
+ HeapFree(GetProcessHeap(),0,file_source);
+ return ERROR_SUCCESS;
+ }
+
+ if (MSI_RecordIsNull(row,4))
+ strcpyW(dest_name,strrchrW(file_source,'\\')+1);
+ else
+ {
+ sz=0x100;
+ MSI_RecordGetStringW(row,4,dest_name,&sz);
+ reduce_to_longfilename(dest_name);
+ }
+
+ if (MSI_RecordIsNull(row,5))
+ {
+ LPWSTR p;
+ dest_path = strdupW(file_source);
+ p = strrchrW(dest_path,'\\');
+ if (p)
+ *p=0;
+ }
+ else
+ {
+ LPCWSTR destkey;
+ destkey = MSI_RecordGetString(row,5);
+ dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);
+ if (!dest_path)
+ {
+ /* try a Property */
+ dest_path = load_dynamic_property(package, destkey, NULL);
+ if (!dest_path)
+ {
+ FIXME("Unable to get destination folder, try AppSearch properties\n");
+ HeapFree(GetProcessHeap(),0,file_source);
+ return ERROR_SUCCESS;
+ }
+ }
+ }
+
+ dest = build_directory_name(2, dest_path, dest_name);
+
+ TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
+ debugstr_w(dest));
+
+ if (strcmpW(file_source,dest))
+ rc = !CopyFileW(file_source,dest,TRUE);
+ else
+ rc = ERROR_SUCCESS;
+
+ if (rc != ERROR_SUCCESS)
+ ERR("Failed to copy file %s -> %s, last error %ld\n", debugstr_w(file_source), debugstr_w(dest_path), GetLastError());
+
+ FIXME("We should track these duplicate files as well\n");
+
+ HeapFree(GetProcessHeap(),0,dest_path);
+ HeapFree(GetProcessHeap(),0,dest);
+ HeapFree(GetProcessHeap(),0,file_source);
+
+ return ERROR_SUCCESS;
+}
+
+UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
+{
+ UINT rc;
+ MSIQUERY * view;
+ static const WCHAR ExecSeqQuery[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+ '`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0};
+
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return ERROR_SUCCESS;
+
+ rc = MSI_IterateRecords(view, NULL, ITERATE_DuplicateFiles, package);
+ msiobj_release(&view->hdr);
+
+ return rc;
+}
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
-#include "winreg.h"
#include "wine/debug.h"
-#include "fdi.h"
#include "msi.h"
-#include "msiquery.h"
-#include "fcntl.h"
-#include "objbase.h"
-#include "objidl.h"
#include "msipriv.h"
#include "winnls.h"
-#include "winuser.h"
-#include "shlobj.h"
#include "wine/unicode.h"
-#include "winver.h"
#include "action.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
-LPWSTR build_default_format(MSIRECORD* record)
+static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
+ WCHAR** data, DWORD len, MSIRECORD* record,
+ BOOL* in_group);
+
+
+static LPWSTR build_default_format(MSIRECORD* record)
{
int i;
int count;
return value;
}
-static LPWSTR deformat_file(MSIPACKAGE* package, LPCWSTR key, DWORD* sz)
+static LPWSTR deformat_file(MSIPACKAGE* package, LPCWSTR key, DWORD* sz,
+ BOOL shortname)
{
LPWSTR value = NULL;
INT index;
index = get_loaded_file(package,key);
if (index >=0)
{
- value = strdupW(package->files[index].TargetPath);
- *sz = (strlenW(value)) * sizeof(WCHAR);
+ if (!shortname)
+ {
+ value = strdupW(package->files[index].TargetPath);
+ *sz = (strlenW(value)) * sizeof(WCHAR);
+ }
+ else
+ {
+ DWORD size = 0;
+ size = GetShortPathNameW(package->files[index].TargetPath, NULL, 0);
+
+ if (size > 0)
+ {
+ *sz = (size-1) * sizeof (WCHAR);
+ size ++;
+ value = HeapAlloc(GetProcessHeap(),0,size * sizeof(WCHAR));
+ GetShortPathNameW(package->files[index].TargetPath, value,
+ size);
+ }
+ else
+ {
+ ERR("Unable to get ShortPath size (%s)\n",
+ debugstr_w(package->files[index].TargetPath));
+ value = NULL;
+ *sz = 0;
+ }
+ }
}
return value;
return value;
}
+/*
+ * Groups cannot be nested. They are just treated as from { to next }
+ */
+static BOOL find_next_group(LPCWSTR source, DWORD len_remaining,
+ LPWSTR *group, LPCWSTR *mark,
+ LPCWSTR* mark2)
+{
+ int i;
+ BOOL found = FALSE;
+
+ *mark = scanW(source,'{',len_remaining);
+ if (!*mark)
+ return FALSE;
+
+ for (i = 1; (*mark - source) + i < len_remaining; i++)
+ {
+ if ((*mark)[i] == '}')
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ if (! found)
+ return FALSE;
+
+ *mark2 = &(*mark)[i];
+
+ i = *mark2 - *mark;
+ *group = HeapAlloc(GetProcessHeap(),0,i*sizeof(WCHAR));
+
+ i -= 1;
+ memcpy(*group,&(*mark)[1],i*sizeof(WCHAR));
+ (*group)[i] = 0;
+
+ TRACE("Found group %s\n",debugstr_w(*group));
+ return TRUE;
+}
+
+
static BOOL find_next_outermost_key(LPCWSTR source, DWORD len_remaining,
LPWSTR *key, LPCWSTR *mark, LPCWSTR* mark2,
BOOL *nested)
return TRUE;
}
+static LPWSTR deformat_group(MSIPACKAGE* package, LPWSTR group, DWORD len,
+ MSIRECORD* record, DWORD* size)
+{
+ LPWSTR value;
+ LPCWSTR mark, mark2;
+ LPWSTR key;
+ BOOL nested;
+ INT failcount;
+ static const WCHAR fmt[] = {'{','%','s','}',0};
+ UINT sz;
+
+ if (!group || group[0] == 0)
+ {
+ *size = 0;
+ return NULL;
+ }
+ /* if no [] then group is returned as is */
+
+ if (!find_next_outermost_key(group, len, &key, &mark, &mark2, &nested))
+ {
+ *size = (len+2)*sizeof(WCHAR);
+ value = HeapAlloc(GetProcessHeap(),0,*size);
+ sprintfW(value,fmt,group);
+ /* do not return size of the null at the end */
+ *size = (len+1)*sizeof(WCHAR);
+ return value;
+ }
+
+ HeapFree(GetProcessHeap(),0,key);
+ failcount = 0;
+ sz = deformat_string_internal(package, group, &value, strlenW(group),
+ record, &failcount);
+ if (failcount==0)
+ {
+ *size = sz * sizeof(WCHAR);
+ return value;
+ }
+ else if (failcount < 0)
+ {
+ LPWSTR v2;
+
+ v2 = HeapAlloc(GetProcessHeap(),0,(sz+2)*sizeof(WCHAR));
+ v2[0] = '{';
+ memcpy(&v2[1],value,sz*sizeof(WCHAR));
+ v2[sz+1]='}';
+ HeapFree(GetProcessHeap(),0,value);
+
+ *size = (sz+2)*sizeof(WCHAR);
+ return v2;
+ }
+ else
+ {
+ *size = 0;
+ return NULL;
+ }
+}
+
/*
* len is in WCHARs
* return is also in WCHARs
*/
static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
- WCHAR** data, DWORD len, MSIRECORD* record)
+ WCHAR** data, DWORD len, MSIRECORD* record,
+ INT* failcount)
{
LPCWSTR mark = NULL;
LPCWSTR mark2 = NULL;
return 0;
}
- TRACE("Starting with %s\n",debugstr_w(ptr));
+ TRACE("Starting with %s\n",debugstr_wn(ptr,len));
/* scan for special characters... fast exit */
- if (!scanW(ptr,'[',len) || (scanW(ptr,'[',len) && !scanW(ptr,']',len)))
+ if ((!scanW(ptr,'[',len) || (scanW(ptr,'[',len) && !scanW(ptr,']',len))) &&
+ (scanW(ptr,'{',len) && !scanW(ptr,'}',len)))
{
/* not formatted */
*data = HeapAlloc(GetProcessHeap(),0,(len*sizeof(WCHAR)));
memcpy(*data,ptr,len*sizeof(WCHAR));
- TRACE("Returning %s\n",debugstr_w(*data));
+ TRACE("Returning %s\n",debugstr_wn(*data,len));
return len;
}
while (progress - ptr < len)
{
+ /* seek out first group if existing */
+ if (find_next_group(progress, len - (progress - ptr), &key,
+ &mark, &mark2))
+ {
+ value = deformat_group(package, key, strlenW(key)+1, record,
+ &chunk);
+ key = NULL;
+ nested = FALSE;
+ }
/* formatted string located */
- if (!find_next_outermost_key(progress, len - (progress - ptr), &key,
- &mark, &mark2, &nested))
+ else if (!find_next_outermost_key(progress, len - (progress - ptr),
+ &key, &mark, &mark2, &nested))
{
LPBYTE nd2;
- TRACE("after value %s .. %s\n",debugstr_w((LPWSTR)newdata),
- debugstr_w(mark));
+ TRACE("after value %s \n",debugstr_wn((LPWSTR)newdata,
+ size/sizeof(WCHAR)));
chunk = (len - (progress - ptr)) * sizeof(WCHAR);
TRACE("after chunk is %li + %li\n",size,chunk);
if (size)
{
TRACE("Nested key... %s\n",debugstr_w(key));
deformat_string_internal(package, key, &value, strlenW(key)+1,
- record);
+ record, failcount);
HeapFree(GetProcessHeap(),0,key);
key = value;
}
- TRACE("Current %s .. %s\n",debugstr_w((LPWSTR)newdata),debugstr_w(key));
+ TRACE("Current %s .. %s\n",debugstr_wn((LPWSTR)newdata,
+ size/sizeof(WCHAR)),debugstr_w(key));
if (!package)
{
/* only deformat number indexs */
- if (is_key_number(key))
+ if (key && is_key_number(key))
+ {
value = deformat_index(record,key,&chunk);
+ if (!chunk && failcount && *failcount >= 0)
+ (*failcount)++;
+ }
else
{
- DWORD keylen = strlenW(key);
- chunk = (keylen + 2)*sizeof(WCHAR);
- value = HeapAlloc(GetProcessHeap(),0,chunk);
- value[0] = '[';
- memcpy(&value[1],key,keylen*sizeof(WCHAR));
- value[1+keylen] = ']';
+ if (failcount)
+ *failcount = -1;
+ if(key)
+ {
+ DWORD keylen = strlenW(key);
+ chunk = (keylen + 2)*sizeof(WCHAR);
+ value = HeapAlloc(GetProcessHeap(),0,chunk);
+ value[0] = '[';
+ memcpy(&value[1],key,keylen*sizeof(WCHAR));
+ value[1+keylen] = ']';
+ }
}
}
else
{
sz = 0;
- switch (key[0])
+ if (key) switch (key[0])
{
case '~':
value = deformat_NULL(&chunk);
value = deformat_component(package,&key[1],&chunk);
break;
case '#':
+ value = deformat_file(package,&key[1], &chunk, FALSE);
+ break;
case '!': /* should be short path */
- value = deformat_file(package,&key[1], &chunk);
+ value = deformat_file(package,&key[1], &chunk, TRUE);
break;
case '\\':
value = deformat_escape(&key[1],&chunk);
value = deformat_environment(package,&key[1],&chunk);
break;
default:
+ /* index keys cannot be nested */
if (is_key_number(key))
- value = deformat_index(record,key,&chunk);
+ if (!nested)
+ value = deformat_index(record,key,&chunk);
+ else
+ {
+ static const WCHAR fmt[] = {'[','%','s',']',0};
+ value = HeapAlloc(GetProcessHeap(),0,10);
+ sprintfW(value,fmt,key);
+ chunk = strlenW(value)*sizeof(WCHAR);
+ }
else
value = deformat_property(package,key,&chunk);
break;
size+=chunk;
HeapFree(GetProcessHeap(),0,value);
}
+ else if (failcount && *failcount >=0 )
+ (*failcount)++;
progress = mark2+1;
}
- TRACE("after everything %s\n",debugstr_w((LPWSTR)newdata));
+ TRACE("after everything %s\n",debugstr_wn((LPWSTR)newdata,
+ size/sizeof(WCHAR)));
*data = (LPWSTR)newdata;
return size / sizeof(WCHAR);
TRACE("(%s)\n",debugstr_w(rec));
len = deformat_string_internal(package,rec,&deformated,strlenW(rec),
- record);
+ record, NULL);
if (buffer)
{
TRACE("(%s)\n",debugstr_w(rec));
len = deformat_string_internal(package,rec,&deformated,strlenW(rec),
- record);
+ record, NULL);
lenA = WideCharToMultiByte(CP_ACP,0,deformated,len,NULL,0,NULL,NULL);
if (buffer)
--- /dev/null
+/*
+ * 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)
+ {
+ LPWSTR check_path;
+ check_path = load_dynamic_property(package,cszTargetDir,NULL);
+ if (!check_path)
+ {
+ check_path = load_dynamic_property(package,cszRootDrive,NULL);
+ if (set_prop)
+ MSI_SetPropertyW(package,cszTargetDir,check_path);
+ }
+
+ /* correct misbuilt target dir */
+ path = build_directory_name(2, check_path, NULL);
+ if (strcmpiW(path,check_path)!=0)
+ MSI_SetPropertyW(package,cszTargetDir,path);
+
+ if (folder)
+ {
+ for (i = 0; i < package->loaded_folders; i++)
+ {
+ if (strcmpW(package->folders[i].Directory,name)==0)
+ break;
+ }
+ *folder = &(package->folders[i]);
+ }
+ return path;
+ }
+ else
+ {
+ path = load_dynamic_property(package,cszSourceDir,NULL);
+ if (!path)
+ {
+ path = load_dynamic_property(package,cszDatabase,NULL);
+ if (path)
+ {
+ p = strrchrW(path,'\\');
+ if (p)
+ *(p+1) = 0;
+ }
+ }
+ if (folder)
+ {
+ for (i = 0; i < package->loaded_folders; i++)
+ {
+ if (strcmpW(package->folders[i].Directory,name)==0)
+ break;
+ }
+ *folder = &(package->folders[i]);
+ }
+ return path;
+ }
+ }
+
+ for (i = 0; i < package->loaded_folders; i++)
+ {
+ if (strcmpW(package->folders[i].Directory,name)==0)
+ break;
+ }
+
+ if (i >= package->loaded_folders)
+ return NULL;
+
+ if (folder)
+ *folder = &(package->folders[i]);
+
+ if (!source && package->folders[i].ResolvedTarget)
+ {
+ path = strdupW(package->folders[i].ResolvedTarget);
+ TRACE(" already resolved to %s\n",debugstr_w(path));
+ return path;
+ }
+ else if (source && package->folders[i].ResolvedSource)
+ {
+ path = strdupW(package->folders[i].ResolvedSource);
+ TRACE(" (source)already resolved to %s\n",debugstr_w(path));
+ return path;
+ }
+ else if (!source && package->folders[i].Property)
+ {
+ path = build_directory_name(2, package->folders[i].Property, NULL);
+
+ TRACE(" internally set to %s\n",debugstr_w(path));
+ if (set_prop)
+ MSI_SetPropertyW(package,name,path);
+ return path;
+ }
+
+ if (package->folders[i].ParentIndex >= 0)
+ {
+ LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory;
+
+ TRACE(" ! Parent is %s\n", debugstr_w(parent));
+
+ p = resolve_folder(package, parent, source, set_prop, NULL);
+ if (!source)
+ {
+ TRACE(" TargetDefault = %s\n",
+ debugstr_w(package->folders[i].TargetDefault));
+
+ path = build_directory_name(3, p,
+ package->folders[i].TargetDefault, NULL);
+ package->folders[i].ResolvedTarget = strdupW(path);
+ TRACE(" resolved into %s\n",debugstr_w(path));
+ if (set_prop)
+ MSI_SetPropertyW(package,name,path);
+ }
+ else
+ {
+ if (package->folders[i].SourceDefault &&
+ package->folders[i].SourceDefault[0]!='.')
+ path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL);
+ else
+ path = strdupW(p);
+ TRACE(" (source)resolved into %s\n",debugstr_w(path));
+ package->folders[i].ResolvedSource = strdupW(path);
+ }
+ HeapFree(GetProcessHeap(),0,p);
+ }
+ return path;
+}
+
+/* wrapper to resist a need for a full rewrite right now */
+DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data )
+{
+ if (ptr)
+ {
+ MSIRECORD *rec = MSI_CreateRecord(1);
+ DWORD size = 0;
+
+ MSI_RecordSetStringW(rec,0,ptr);
+ MSI_FormatRecordW(package,rec,NULL,&size);
+ if (size >= 0)
+ {
+ size++;
+ *data = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
+ if (size > 1)
+ MSI_FormatRecordW(package,rec,*data,&size);
+ else
+ *data[0] = 0;
+ msiobj_release( &rec->hdr );
+ return sizeof(WCHAR)*size;
+ }
+ msiobj_release( &rec->hdr );
+ }
+
+ *data = NULL;
+ return 0;
+}
+
+UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action)
+{
+ UINT count;
+ LPWSTR *newbuf = NULL;
+ if (script >= TOTAL_SCRIPTS)
+ {
+ FIXME("Unknown script requested %i\n",script);
+ return ERROR_FUNCTION_FAILED;
+ }
+ TRACE("Scheduling Action %s in script %i\n",debugstr_w(action), script);
+
+ count = package->script->ActionCount[script];
+ package->script->ActionCount[script]++;
+ if (count != 0)
+ newbuf = HeapReAlloc(GetProcessHeap(),0,
+ package->script->Actions[script],
+ package->script->ActionCount[script]* sizeof(LPWSTR));
+ else
+ newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
+
+ newbuf[count] = strdupW(action);
+ package->script->Actions[script] = newbuf;
+
+ return ERROR_SUCCESS;
+}
+
+static void remove_tracked_tempfiles(MSIPACKAGE* package)
+{
+ DWORD i;
+
+ if (!package)
+ return;
+
+ for (i = 0; i < package->loaded_files; i++)
+ {
+ if (package->files[i].Temporary)
+ {
+ TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath));
+ DeleteFileW(package->files[i].TargetPath);
+ }
+
+ }
+}
+
+/* Called when the package is being closed */
+void ACTION_free_package_structures( MSIPACKAGE* package)
+{
+ INT i;
+
+ TRACE("Freeing package action data\n");
+
+ remove_tracked_tempfiles(package);
+
+ /* No dynamic buffers in features */
+ if (package->features && package->loaded_features > 0)
+ HeapFree(GetProcessHeap(),0,package->features);
+
+ for (i = 0; i < package->loaded_folders; i++)
+ {
+ HeapFree(GetProcessHeap(),0,package->folders[i].Directory);
+ HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault);
+ HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault);
+ HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
+ HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource);
+ HeapFree(GetProcessHeap(),0,package->folders[i].Property);
+ }
+ if (package->folders && package->loaded_folders > 0)
+ HeapFree(GetProcessHeap(),0,package->folders);
+
+ for (i = 0; i < package->loaded_components; i++)
+ HeapFree(GetProcessHeap(),0,package->components[i].FullKeypath);
+
+ if (package->components && package->loaded_components > 0)
+ HeapFree(GetProcessHeap(),0,package->components);
+
+ for (i = 0; i < package->loaded_files; i++)
+ {
+ HeapFree(GetProcessHeap(),0,package->files[i].File);
+ HeapFree(GetProcessHeap(),0,package->files[i].FileName);
+ HeapFree(GetProcessHeap(),0,package->files[i].ShortName);
+ HeapFree(GetProcessHeap(),0,package->files[i].Version);
+ HeapFree(GetProcessHeap(),0,package->files[i].Language);
+ HeapFree(GetProcessHeap(),0,package->files[i].SourcePath);
+ HeapFree(GetProcessHeap(),0,package->files[i].TargetPath);
+ }
+
+ if (package->files && package->loaded_files > 0)
+ HeapFree(GetProcessHeap(),0,package->files);
+
+ /* clean up extension, progid, class and verb structures */
+ for (i = 0; i < package->loaded_classes; i++)
+ {
+ HeapFree(GetProcessHeap(),0,package->classes[i].Description);
+ HeapFree(GetProcessHeap(),0,package->classes[i].FileTypeMask);
+ HeapFree(GetProcessHeap(),0,package->classes[i].IconPath);
+ HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler);
+ HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler32);
+ HeapFree(GetProcessHeap(),0,package->classes[i].Argument);
+ HeapFree(GetProcessHeap(),0,package->classes[i].ProgIDText);
+ }
+
+ if (package->classes && package->loaded_classes > 0)
+ HeapFree(GetProcessHeap(),0,package->classes);
+
+ for (i = 0; i < package->loaded_extensions; i++)
+ {
+ HeapFree(GetProcessHeap(),0,package->extensions[i].ProgIDText);
+ }
+
+ if (package->extensions && package->loaded_extensions > 0)
+ HeapFree(GetProcessHeap(),0,package->extensions);
+
+ for (i = 0; i < package->loaded_progids; i++)
+ {
+ HeapFree(GetProcessHeap(),0,package->progids[i].ProgID);
+ HeapFree(GetProcessHeap(),0,package->progids[i].Description);
+ HeapFree(GetProcessHeap(),0,package->progids[i].IconPath);
+ }
+
+ if (package->progids && package->loaded_progids > 0)
+ HeapFree(GetProcessHeap(),0,package->progids);
+
+ for (i = 0; i < package->loaded_verbs; i++)
+ {
+ HeapFree(GetProcessHeap(),0,package->verbs[i].Verb);
+ HeapFree(GetProcessHeap(),0,package->verbs[i].Command);
+ HeapFree(GetProcessHeap(),0,package->verbs[i].Argument);
+ }
+
+ if (package->verbs && package->loaded_verbs > 0)
+ HeapFree(GetProcessHeap(),0,package->verbs);
+
+ for (i = 0; i < package->loaded_mimes; i++)
+ HeapFree(GetProcessHeap(),0,package->mimes[i].ContentType);
+
+ if (package->mimes && package->loaded_mimes > 0)
+ HeapFree(GetProcessHeap(),0,package->mimes);
+
+ for (i = 0; i < package->loaded_appids; i++)
+ {
+ HeapFree(GetProcessHeap(),0,package->appids[i].RemoteServerName);
+ HeapFree(GetProcessHeap(),0,package->appids[i].LocalServer);
+ HeapFree(GetProcessHeap(),0,package->appids[i].ServiceParameters);
+ HeapFree(GetProcessHeap(),0,package->appids[i].DllSurrogate);
+ }
+
+ if (package->appids && package->loaded_appids > 0)
+ HeapFree(GetProcessHeap(),0,package->appids);
+
+ if (package->script)
+ {
+ for (i = 0; i < TOTAL_SCRIPTS; i++)
+ {
+ int j;
+ for (j = 0; j < package->script->ActionCount[i]; j++)
+ HeapFree(GetProcessHeap(),0,package->script->Actions[i][j]);
+
+ HeapFree(GetProcessHeap(),0,package->script->Actions[i]);
+ }
+ HeapFree(GetProcessHeap(),0,package->script);
+ }
+
+ HeapFree(GetProcessHeap(),0,package->PackagePath);
+
+ /* cleanup control event subscriptions */
+ ControlEvent_CleanupSubscriptions(package);
+}
+
+/*
+ * build_directory_name()
+ *
+ * This function is to save messing round with directory names
+ * It handles adding backslashes between path segments,
+ * and can add \ at the end of the directory name if told to.
+ *
+ * It takes a variable number of arguments.
+ * It always allocates a new string for the result, so make sure
+ * to free the return value when finished with it.
+ *
+ * The first arg is the number of path segments that follow.
+ * The arguments following count are a list of path segments.
+ * A path segment may be NULL.
+ *
+ * Path segments will be added with a \ separating them.
+ * A \ will not be added after the last segment, however if the
+ * last segment is NULL, then the last character will be a \
+ *
+ */
+LPWSTR build_directory_name(DWORD count, ...)
+{
+ DWORD sz = 1, i;
+ LPWSTR dir;
+ va_list va;
+
+ va_start(va,count);
+ for(i=0; 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);
+ }
+}
MSIDATABASE *db;
BOOL bIsTemp;
MSIVIEW *sv;
- value_list *vals;
+ column_info *vals;
} MSIINSERTVIEW;
static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
* Merge a value_list and a record to create a second record.
* Replace wildcard entries in the valuelist with values from the record
*/
-static MSIRECORD *INSERT_merge_record( UINT fields, value_list *vl, MSIRECORD *rec )
+static MSIRECORD *INSERT_merge_record( UINT fields, column_info *vl, MSIRECORD *rec )
{
MSIRECORD *merged;
DWORD wildcard_count = 1, i;
};
UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
- string_list *columns, value_list *values, BOOL temp )
+ column_info *columns, column_info *values, BOOL temp )
{
MSIINSERTVIEW *iv = NULL;
UINT r;
--- /dev/null
+/*
+ * 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;
+}
+
+/***********************************************************************
+ * MsiGetTargetPathA (MSI.@)
+ */
+UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
+ LPSTR szPathBuf, DWORD* pcchPathBuf)
+{
+ LPWSTR szwFolder;
+ LPWSTR szwPathBuf;
+ UINT rc;
+
+ TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
+
+ if (!szFolder)
+ return ERROR_FUNCTION_FAILED;
+ if (hInstall == 0)
+ return ERROR_FUNCTION_FAILED;
+
+ szwFolder = strdupAtoW(szFolder);
+
+ if (!szwFolder)
+ return ERROR_FUNCTION_FAILED;
+
+ szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
+
+ rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
+
+ WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
+ *pcchPathBuf, NULL, NULL );
+
+ HeapFree(GetProcessHeap(),0,szwFolder);
+ HeapFree(GetProcessHeap(),0,szwPathBuf);
+
+ return rc;
+}
+
+/***********************************************************************
+* MsiGetTargetPathW (MSI.@)
+*/
+UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
+ szPathBuf, DWORD* pcchPathBuf)
+{
+ LPWSTR path;
+ UINT rc = ERROR_FUNCTION_FAILED;
+ MSIPACKAGE *package;
+
+ TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
+
+ package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+ path = resolve_folder(package, szFolder, FALSE, FALSE, NULL);
+ msiobj_release( &package->hdr );
+
+ if (path && (strlenW(path) > *pcchPathBuf))
+ {
+ *pcchPathBuf = strlenW(path)+1;
+ rc = ERROR_MORE_DATA;
+ }
+ else if (path)
+ {
+ *pcchPathBuf = strlenW(path)+1;
+ strcpyW(szPathBuf,path);
+ TRACE("Returning Path %s\n",debugstr_w(path));
+ rc = ERROR_SUCCESS;
+ }
+ HeapFree(GetProcessHeap(),0,path);
+
+ return rc;
+}
+
+
+/***********************************************************************
+* MsiGetSourcePathA (MSI.@)
+*/
+UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder,
+ LPSTR szPathBuf, DWORD* pcchPathBuf)
+{
+ LPWSTR szwFolder;
+ LPWSTR szwPathBuf;
+ UINT rc;
+
+ TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
+
+ if (!szFolder)
+ return ERROR_FUNCTION_FAILED;
+ if (hInstall == 0)
+ return ERROR_FUNCTION_FAILED;
+
+ szwFolder = strdupAtoW(szFolder);
+ if (!szwFolder)
+ return ERROR_FUNCTION_FAILED;
+
+ szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
+
+ rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
+
+ WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
+ *pcchPathBuf, NULL, NULL );
+
+ HeapFree(GetProcessHeap(),0,szwFolder);
+ HeapFree(GetProcessHeap(),0,szwPathBuf);
+
+ return rc;
+}
+
+/***********************************************************************
+* MsiGetSourcePathW (MSI.@)
+*/
+UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
+ szPathBuf, DWORD* pcchPathBuf)
+{
+ LPWSTR path;
+ UINT rc = ERROR_FUNCTION_FAILED;
+ MSIPACKAGE *package;
+
+ TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
+
+ package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
+ if( !package )
+ return ERROR_INVALID_HANDLE;
+ path = resolve_folder(package, szFolder, TRUE, FALSE, NULL);
+ msiobj_release( &package->hdr );
+
+ if (path && strlenW(path) > *pcchPathBuf)
+ {
+ *pcchPathBuf = strlenW(path)+1;
+ rc = ERROR_MORE_DATA;
+ }
+ else if (path)
+ {
+ *pcchPathBuf = strlenW(path)+1;
+ strcpyW(szPathBuf,path);
+ TRACE("Returning Path %s\n",debugstr_w(path));
+ rc = ERROR_SUCCESS;
+ }
+ HeapFree(GetProcessHeap(),0,path);
+
+ return rc;
+}
+
+
+/***********************************************************************
+ * MsiSetTargetPathA (MSI.@)
+ */
+UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder,
+ LPCSTR szFolderPath)
+{
+ LPWSTR szwFolder;
+ LPWSTR szwFolderPath;
+ UINT rc;
+
+ if (!szFolder)
+ return ERROR_FUNCTION_FAILED;
+ if (hInstall == 0)
+ return ERROR_FUNCTION_FAILED;
+
+ szwFolder = strdupAtoW(szFolder);
+ if (!szwFolder)
+ return ERROR_FUNCTION_FAILED;
+
+ szwFolderPath = strdupAtoW(szFolderPath);
+ if (!szwFolderPath)
+ {
+ HeapFree(GetProcessHeap(),0,szwFolder);
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);
+
+ HeapFree(GetProcessHeap(),0,szwFolder);
+ HeapFree(GetProcessHeap(),0,szwFolderPath);
+
+ return rc;
+}
+
+/*
+ * Ok my original interpretation of this was wrong. And it looks like msdn has
+ * changed a bit also. The given folder path does not have to actually already
+ * exist, it just cannot be read only and must be a legal folder path.
+ */
+UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
+ LPCWSTR szFolderPath)
+{
+ DWORD i;
+ DWORD attrib;
+ LPWSTR path = NULL;
+ LPWSTR path2 = NULL;
+ MSIFOLDER *folder;
+
+ TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
+
+ if (package==NULL)
+ return ERROR_INVALID_HANDLE;
+
+ if (szFolderPath[0]==0)
+ return ERROR_FUNCTION_FAILED;
+
+ attrib = GetFileAttributesW(szFolderPath);
+ if ( attrib != INVALID_FILE_ATTRIBUTES &&
+ (!(attrib & FILE_ATTRIBUTE_DIRECTORY) ||
+ attrib & FILE_ATTRIBUTE_OFFLINE ||
+ attrib & FILE_ATTRIBUTE_READONLY))
+ return ERROR_FUNCTION_FAILED;
+
+ path = resolve_folder(package,szFolder,FALSE,FALSE,&folder);
+
+ if (!path)
+ return ERROR_INVALID_PARAMETER;
+
+ if (attrib == INVALID_FILE_ATTRIBUTES)
+ {
+ if (!CreateDirectoryW(szFolderPath,NULL))
+ return ERROR_FUNCTION_FAILED;
+ RemoveDirectoryW(szFolderPath);
+ }
+
+ HeapFree(GetProcessHeap(),0,folder->Property);
+ folder->Property = build_directory_name(2, szFolderPath, NULL);
+
+ if (lstrcmpiW(path, folder->Property) == 0)
+ {
+ /*
+ * Resolved Target has not really changed, so just
+ * set this folder and do not recalculate everything.
+ */
+ HeapFree(GetProcessHeap(),0,folder->ResolvedTarget);
+ folder->ResolvedTarget = NULL;
+ path2 = resolve_folder(package,szFolder,FALSE,TRUE,NULL);
+ HeapFree(GetProcessHeap(),0,path2);
+ }
+ else
+ {
+ for (i = 0; i < package->loaded_folders; i++)
+ {
+ HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
+ package->folders[i].ResolvedTarget=NULL;
+ }
+
+ for (i = 0; i < package->loaded_folders; i++)
+ {
+ path2=resolve_folder(package, package->folders[i].Directory, FALSE,
+ TRUE, NULL);
+ HeapFree(GetProcessHeap(),0,path2);
+ }
+ }
+ HeapFree(GetProcessHeap(),0,path);
+
+ return ERROR_SUCCESS;
+}
+
+/***********************************************************************
+ * MsiSetTargetPathW (MSI.@)
+ */
+UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
+ LPCWSTR szFolderPath)
+{
+ MSIPACKAGE *package;
+ UINT ret;
+
+ TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
+
+ package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
+ ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
+ msiobj_release( &package->hdr );
+ return ret;
+}
+
+/***********************************************************************
+ * MsiGetMode (MSI.@)
+ *
+ * Returns an internal installer state (if it is running in a mode iRunMode)
+ *
+ * PARAMS
+ * hInstall [I] Handle to the installation
+ * hRunMode [I] Checking run mode
+ * MSIRUNMODE_ADMIN Administrative mode
+ * MSIRUNMODE_ADVERTISE Advertisement mode
+ * MSIRUNMODE_MAINTENANCE Maintenance mode
+ * MSIRUNMODE_ROLLBACKENABLED Rollback is enabled
+ * MSIRUNMODE_LOGENABLED Log file is writing
+ * MSIRUNMODE_OPERATIONS Operations in progress??
+ * MSIRUNMODE_REBOOTATEND We need to reboot after installation completed
+ * MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation
+ * MSIRUNMODE_CABINET Files from cabinet are installed
+ * MSIRUNMODE_SOURCESHORTNAMES Long names in source files is suppressed
+ * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is suppressed
+ * MSIRUNMODE_RESERVED11 Reserved
+ * MSIRUNMODE_WINDOWS9X Running under Windows95/98
+ * MSIRUNMODE_ZAWENABLED Demand installation is supported
+ * MSIRUNMODE_RESERVED14 Reserved
+ * MSIRUNMODE_RESERVED15 Reserved
+ * MSIRUNMODE_SCHEDULED called from install script
+ * MSIRUNMODE_ROLLBACK called from rollback script
+ * MSIRUNMODE_COMMIT called from commit script
+ *
+ * RETURNS
+ * In the state: TRUE
+ * Not in the state: FALSE
+ *
+ */
+
+BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
+{
+ FIXME("STUB (iRunMode=%i)\n",iRunMode);
+ return TRUE;
+}
+
+/***********************************************************************
+ * MsiSetFeatureStateA (MSI.@)
+ *
+ * According to the docs, when this is called it immediately recalculates
+ * all the component states as well
+ */
+UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
+ INSTALLSTATE iState)
+{
+ LPWSTR szwFeature = NULL;
+ UINT rc;
+
+ szwFeature = strdupAtoW(szFeature);
+
+ if (!szwFeature)
+ return ERROR_FUNCTION_FAILED;
+
+ rc = MsiSetFeatureStateW(hInstall,szwFeature, iState);
+
+ HeapFree(GetProcessHeap(),0,szwFeature);
+
+ return rc;
+}
+
+
+
+UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
+ INSTALLSTATE iState)
+{
+ INT index, i;
+ UINT rc = ERROR_SUCCESS;
+
+ TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
+
+ index = get_loaded_feature(package,szFeature);
+ if (index < 0)
+ return ERROR_UNKNOWN_FEATURE;
+
+ if (iState == INSTALLSTATE_ADVERTISED &&
+ package->features[index].Attributes &
+ msidbFeatureAttributesDisallowAdvertise)
+ return ERROR_FUNCTION_FAILED;
+
+ package->features[index].ActionRequest= iState;
+ package->features[index].Action= iState;
+
+ ACTION_UpdateComponentStates(package,szFeature);
+
+ /* update all the features that are children of this feature */
+ for (i = 0; i < package->loaded_features; i++)
+ {
+ if (strcmpW(szFeature, package->features[i].Feature_Parent) == 0)
+ MSI_SetFeatureStateW(package, package->features[i].Feature, iState);
+ }
+
+ return rc;
+}
+
+/***********************************************************************
+ * MsiSetFeatureStateW (MSI.@)
+ */
+UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
+ INSTALLSTATE iState)
+{
+ MSIPACKAGE* package;
+ UINT rc = ERROR_SUCCESS;
+
+ TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
+
+ package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+
+ rc = MSI_SetFeatureStateW(package,szFeature,iState);
+
+ msiobj_release( &package->hdr );
+ return rc;
+}
+
+/***********************************************************************
+* MsiGetFeatureStateA (MSI.@)
+*/
+UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature,
+ INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
+{
+ LPWSTR szwFeature = NULL;
+ UINT rc;
+
+ szwFeature = strdupAtoW(szFeature);
+
+ rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
+
+ HeapFree( GetProcessHeap(), 0 , szwFeature);
+
+ return rc;
+}
+
+UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
+ INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
+{
+ INT index;
+
+ index = get_loaded_feature(package,szFeature);
+ if (index < 0)
+ return ERROR_UNKNOWN_FEATURE;
+
+ if (piInstalled)
+ *piInstalled = package->features[index].Installed;
+
+ if (piAction)
+ *piAction = package->features[index].Action;
+
+ TRACE("returning %i %i\n",*piInstalled,*piAction);
+
+ return ERROR_SUCCESS;
+}
+
+/***********************************************************************
+* MsiGetFeatureStateW (MSI.@)
+*/
+UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature,
+ INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
+{
+ MSIPACKAGE* package;
+ UINT ret;
+
+ TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,
+piAction);
+
+ package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+ ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
+ msiobj_release( &package->hdr );
+ return ret;
+}
+
+/***********************************************************************
+ * MsiGetComponentStateA (MSI.@)
+ */
+UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent,
+ INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
+{
+ LPWSTR szwComponent= NULL;
+ UINT rc;
+
+ szwComponent= strdupAtoW(szComponent);
+
+ rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
+
+ HeapFree( GetProcessHeap(), 0 , szwComponent);
+
+ return rc;
+}
+
+UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent,
+ INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
+{
+ INT index;
+
+ TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled,
+piAction);
+
+ index = get_loaded_component(package,szComponent);
+ if (index < 0)
+ return ERROR_UNKNOWN_COMPONENT;
+
+ if (piInstalled)
+ *piInstalled = package->components[index].Installed;
+
+ if (piAction)
+ *piAction = package->components[index].Action;
+
+ TRACE("states (%i, %i)\n",
+(piInstalled)?*piInstalled:-1,(piAction)?*piAction:-1);
+
+ return ERROR_SUCCESS;
+}
+
+/***********************************************************************
+ * MsiGetComponentStateW (MSI.@)
+ */
+UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent,
+ INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
+{
+ MSIPACKAGE* package;
+ UINT ret;
+
+ TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
+ piInstalled, piAction);
+
+ package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
+ if (!package)
+ return ERROR_INVALID_HANDLE;
+ ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
+ msiobj_release( &package->hdr );
+ return ret;
+}
#include "wine/unicode.h"
#include "action.h"
-UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf);
-
-
WINE_DEFAULT_DEBUG_CHANNEL(msi);
/*
{
LPWSTR szwProduct = NULL, szwAttribute = NULL, szwBuffer = NULL;
UINT r = ERROR_OUTOFMEMORY;
+ DWORD pcchwValueBuf = 0;
TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute),
szBuffer, pcchValueBuf);
if( szBuffer )
{
szwBuffer = HeapAlloc( GetProcessHeap(), 0, (*pcchValueBuf) * sizeof(WCHAR) );
+ pcchwValueBuf = *pcchValueBuf;
if( !szwBuffer )
goto end;
}
- r = MsiGetProductInfoW( szwProduct, szwAttribute, szwBuffer, pcchValueBuf );
+ r = MsiGetProductInfoW( szwProduct, szwAttribute, szwBuffer,
+ &pcchwValueBuf );
if( ERROR_SUCCESS == r )
- WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, *pcchValueBuf, NULL, NULL);
+ *pcchValueBuf = WideCharToMultiByte(CP_ACP, 0, szwBuffer, pcchwValueBuf,
+ szBuffer, *pcchValueBuf, NULL, NULL);
end:
HeapFree( GetProcessHeap(), 0, szwProduct );
{'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
static const WCHAR szAssignmentType[] =
{'A','s','s','i','g','n','m','e','n','t','T','y','p','e',0};
+ static const WCHAR szLanguage[] =
+ {'L','a','n','g','u','a','g','e',0};
+ static const WCHAR szProductLanguage[] =
+ {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute),
szBuffer, pcchValueBuf);
}
else if (strcmpW(szAttribute, szAssignmentType)==0)
{
- FIXME("0 (zero) if advertised, 1(one) if per machine.\n");
+ FIXME("0 (zero) if advertised or per user , 1(one) if per machine.\n");
if (szBuffer)
- szBuffer[0] = 1;
+ {
+ szBuffer[0] = '1';
+ szBuffer[1] = 0;
+ }
+ if (pcchValueBuf)
+ *pcchValueBuf = 1;
r = ERROR_SUCCESS;
}
+ else if (strcmpW(szAttribute, szLanguage)==0)
+ {
+ r = MsiOpenProductW(szProduct, &hProduct);
+ if (ERROR_SUCCESS != r)
+ return r;
+
+ r = MsiGetPropertyW(hProduct, szProductLanguage, szBuffer, pcchValueBuf);
+ MsiCloseHandle(hProduct);
+ }
else
{
r = MsiOpenProductW(szProduct, &hProduct);
return INSTALLSTATE_UNKNOWN;
}
-INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPSTR lpPathBuf,
+INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
DWORD *pcchBuf)
{
FIXME("%s %p %08lx\n", debugstr_w(szComponent), lpPathBuf, *pcchBuf);
}
if( pcchBuf && *pcchBuf > 0 )
+ {
lpwPathBuf = HeapAlloc( GetProcessHeap(), 0, *pcchBuf * sizeof(WCHAR));
+ incoming_len = *pcchBuf;
+ }
else
+ {
lpwPathBuf = NULL;
+ incoming_len = 0;
+ }
- incoming_len = *pcchBuf;
rc = MsiGetComponentPathW(szwProduct, szwComponent, lpwPathBuf, pcchBuf);
HeapFree( GetProcessHeap(), 0, szwProduct);
lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0,
lpLangBuf, pcchLangBuf?*pcchLangBuf:0);
- dwVerLen = GetFileVersionInfoSizeW((LPWSTR)szFilePath, NULL);
+ dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL);
if( !dwVerLen )
return GetLastError();
goto end;
}
- if( !GetFileVersionInfoW((LPWSTR)szFilePath, 0, dwVerLen, lpVer) )
+ if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) )
{
ret = GetLastError();
goto end;
}
if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
{
- if( VerQueryValueW(lpVer, (LPWSTR)szVersionResource, (LPVOID*)&ffi, &puLen) &&
+ if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) &&
(puLen > 0) )
{
wsprintfW(tmp, szVersionFormat,
typedef struct tagIClassFactoryImpl
{
- IClassFactoryVtbl *lpVtbl;
+ const IClassFactoryVtbl *lpVtbl;
} IClassFactoryImpl;
static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface,
return S_OK;
}
-static IClassFactoryVtbl MsiCF_Vtbl =
+static const IClassFactoryVtbl MsiCF_Vtbl =
{
MsiCF_QueryInterface,
MsiCF_AddRef,
158 stdcall MsiViewClose(long)\r
159 stdcall MsiViewExecute(long long)\r
160 stdcall MsiViewFetch(long ptr)\r
-161 stub MsiViewGetErrorA\r
-162 stub MsiViewGetErrorW\r
+161 stdcall MsiViewGetErrorA(long ptr ptr)\r
+162 stdcall MsiViewGetErrorW(long ptr ptr)\r
163 stdcall MsiViewModify(long long long)\r
164 stdcall MsiDatabaseIsTablePersistentA(long str)\r
165 stdcall MsiDatabaseIsTablePersistentW(long wstr)\r
<library>gdi32</library>
<library>advapi32</library>
<library>shell32</library>
+ <library>shlwapi</library>
<library>winmm</library>
<library>cabinet</library>
<library>ole32</library>
<library>version</library>
<file>action.c</file>
<file>appsearch.c</file>
+ <file>classes.c</file>
<file>cond.tab.c</file>
<file>create.c</file>
<file>custom.c</file>
<file>delete.c</file>
<file>dialog.c</file>
<file>distinct.c</file>
+ <file>events.c</file>
+ <file>files.c</file>
<file>format.c</file>
<file>handle.c</file>
+ <file>helpers.c</file>
<file>insert.c</file>
+ <file>install.c</file>
<file>msi.c</file>
<file>msiquery.c</file>
<file>order.c</file>
<file>table.c</file>
<file>tokenize.c</file>
<file>update.c</file>
+ <file>upgrade.c</file>
<file>where.c</file>
<file>msi.spec</file>
<file>msi.rc</file>
#include "msiquery.h"
#include "objbase.h"
#include "objidl.h"
-#include "wine/unicode.h"
+#include "winnls.h"
#include "wine/list.h"
#define MSI_DATASIZEMASK 0x00ff
MSIOBJECTHDR hdr;
IStorage *storage;
string_table *strings;
- LPWSTR mode;
+ LPCWSTR mode;
MSITABLE *first_table, *last_table;
} MSIDATABASE;
LPWSTR ActionFormat;
LPWSTR LastAction;
- LPWSTR *DeferredAction;
- UINT DeferredActionCount;
-
- LPWSTR *CommitAction;
- UINT CommitActionCount;
+ struct tagMSICLASS *classes;
+ UINT loaded_classes;
+ struct tagMSIEXTENSION *extensions;
+ UINT loaded_extensions;
+ struct tagMSIPROGID *progids;
+ UINT loaded_progids;
+ struct tagMSIVERB *verbs;
+ UINT loaded_verbs;
+ struct tagMSIMIME *mimes;
+ UINT loaded_mimes;
+ struct tagMSIAPPID *appids;
+ UINT loaded_appids;
+
+ struct tagMSISCRIPT *script;
struct tagMSIRUNNINGACTION *RunningAction;
UINT RunningActionCount;
UINT CurrentInstallState;
msi_dialog *dialog;
LPWSTR next_dialog;
-
- BOOL ExecuteSequenceRun;
+
+ struct list subscriptions;
} MSIPACKAGE;
typedef struct tagMSIPREVIEW
extern MSIRECORD *MSI_CreateRecord( unsigned int );
extern UINT MSI_RecordSetInteger( MSIRECORD *, unsigned int, int );
extern UINT MSI_RecordSetStringW( MSIRECORD *, unsigned int, LPCWSTR );
+extern UINT MSI_RecordSetStringA( MSIRECORD *, unsigned int, LPCSTR );
extern BOOL MSI_RecordIsNull( MSIRECORD *, unsigned int );
extern UINT MSI_RecordGetStringW( MSIRECORD * , unsigned int, LPWSTR, DWORD *);
extern UINT MSI_RecordGetStringA( MSIRECORD *, unsigned int, LPSTR, DWORD *);
extern int MSI_RecordGetInteger( MSIRECORD *, unsigned int );
extern UINT MSI_RecordReadStream( MSIRECORD *, unsigned int, char *, DWORD *);
extern unsigned int MSI_RecordGetFieldCount( MSIRECORD *rec );
+extern UINT MSI_RecordSetStreamW( MSIRECORD *, unsigned int, LPCWSTR );
+extern UINT MSI_RecordSetStreamA( MSIRECORD *, unsigned int, LPCSTR );
+extern UINT MSI_RecordDataSize( MSIRECORD *, unsigned int );
+extern UINT MSI_RecordStreamToFile( MSIRECORD *, unsigned int, LPCWSTR );
/* stream internals */
extern UINT get_raw_stream( MSIHANDLE hdb, LPCWSTR stname, IStream **stm );
extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** );
extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** );
extern UINT MSI_OpenQuery( MSIDATABASE *, MSIQUERY **, LPCWSTR, ... );
-typedef UINT (*record_func)( MSIRECORD *rec, LPVOID param );
+typedef UINT (*record_func)( MSIRECORD *, LPVOID );
extern UINT MSI_IterateRecords( MSIQUERY *, DWORD *, record_func, LPVOID );
+extern MSIRECORD *MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR query, ... );
+extern UINT MSI_DatabaseImport( MSIDATABASE *, LPCWSTR, LPCWSTR );
+extern UINT MSI_DatabaseExport( MSIDATABASE *, LPCWSTR, LPCWSTR, LPCWSTR );
+extern UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *, LPCWSTR, MSIRECORD ** );
/* view internals */
extern UINT MSI_ViewExecute( MSIQUERY*, MSIRECORD * );
extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
extern INT MSI_ProcessMessage( MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD * );
extern UINT MSI_GetPropertyW( MSIPACKAGE *, LPCWSTR, LPWSTR, DWORD * );
+extern UINT MSI_GetPropertyA(MSIPACKAGE *, LPCSTR, LPSTR, DWORD* );
extern MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *, LPCWSTR );
extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
extern UINT MSI_GetComponentStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE * );
extern UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE*, LPCWSTR, INSTALLSTATE );
/* for deformating */
-extern UINT MSI_FormatRecordW(MSIPACKAGE* package, MSIRECORD* record,
- LPWSTR buffer, DWORD *size);
+extern UINT MSI_FormatRecordW( MSIPACKAGE *, MSIRECORD *, LPWSTR, DWORD * );
+extern UINT MSI_FormatRecordA( MSIPACKAGE *, MSIRECORD *, LPSTR, DWORD * );
/* registry data encoding/decoding functions */
extern BOOL unsquash_guid(LPCWSTR in, LPWSTR out);
extern UINT MSIREG_OpenComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create);
extern UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create);
extern UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
+extern UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create);
extern UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
+extern UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
/* msi dialog interface */
-typedef VOID (*msi_dialog_event_handler)( MSIPACKAGE*, LPCWSTR, LPCWSTR, msi_dialog* );
+typedef UINT (*msi_dialog_event_handler)( MSIPACKAGE*, LPCWSTR, LPCWSTR, msi_dialog* );
extern msi_dialog *msi_dialog_create( MSIPACKAGE*, LPCWSTR, msi_dialog_event_handler );
extern UINT msi_dialog_run_message_loop( msi_dialog* );
extern void msi_dialog_end_dialog( msi_dialog* );
extern void msi_dialog_destroy( msi_dialog* );
extern BOOL msi_dialog_register_class( void );
extern void msi_dialog_unregister_class( void );
+extern void msi_dialog_handle_event( msi_dialog*, LPCWSTR, LPCWSTR, MSIRECORD * );
+
+/* preview */
+extern MSIPREVIEW *MSI_EnableUIPreview( MSIDATABASE * );
+extern UINT MSI_PreviewDialogW( MSIPREVIEW *, LPCWSTR );
+
+/* undocumented functions */
+UINT WINAPI MsiCreateAndVerifyInstallerDirectory( DWORD );
+UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR, LPWSTR, LPWSTR, LPWSTR, DWORD * );
+UINT WINAPI MsiDecomposeDescriptorA( LPCSTR, LPSTR, LPSTR, LPSTR, DWORD * );
+LANGID WINAPI MsiLoadStringW( MSIHANDLE, UINT, LPWSTR, int, LANGID );
+LANGID WINAPI MsiLoadStringA( MSIHANDLE, UINT, LPSTR, int, LANGID );
+
+HRESULT WINAPI MSI_DllGetClassObject( REFCLSID, REFIID, LPVOID * );
+HRESULT WINAPI MSI_DllRegisterServer( void );
+HRESULT WINAPI MSI_DllUnregisterServer( void );
+BOOL WINAPI MSI_DllCanUnloadNow( void );
/* UI globals */
extern INSTALLUILEVEL gUILevel;
{
LPWSTR dest;
if (!src) return NULL;
- dest = HeapAlloc(GetProcessHeap(), 0, (strlenW(src)+1)*sizeof(WCHAR));
- strcpyW(dest, src);
+ dest = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(src)+1)*sizeof(WCHAR));
+ lstrcpyW(dest, src);
return dest;
}
WINE_DEFAULT_DEBUG_CHANNEL(msi);
-void MSI_CloseView( MSIOBJECTHDR *arg )
+static void MSI_CloseView( MSIOBJECTHDR *arg )
{
MSIQUERY *query = (MSIQUERY*) arg;
struct list *ptr, *t;
return r;
}
-UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
+static UINT MSI_OpenQueryV( MSIDATABASE *db, MSIQUERY **view,
+ LPCWSTR fmt, va_list args )
{
LPWSTR szQuery;
LPCWSTR p;
va_list va;
/* figure out how much space we need to allocate */
- va_start(va, fmt);
+ va = args;
sz = lstrlenW(fmt) + 1;
p = fmt;
while (*p)
}
p++;
}
- va_end(va);
/* construct the string */
szQuery = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));
- va_start(va, fmt);
+ va = args;
vsnprintfW(szQuery, sz, fmt, va);
- va_end(va);
/* perform the query */
rc = MSI_DatabaseOpenViewW(db, szQuery, view);
return rc;
}
+UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
+{
+ UINT r;
+ va_list va;
+
+ va_start(va, fmt);
+ r = MSI_OpenQueryV( db, view, fmt, va );
+ va_end(va);
+
+ return r;
+}
+
UINT MSI_IterateRecords( MSIQUERY *view, DWORD *count,
record_func func, LPVOID param )
{
return r;
}
+/* return a single record from a query */
+MSIRECORD *MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR fmt, ... )
+{
+ MSIRECORD *rec = NULL;
+ MSIQUERY *view = NULL;
+ UINT r;
+ va_list va;
+
+ va_start(va, fmt);
+ r = MSI_OpenQueryV( db, &view, fmt, va );
+ va_end(va);
+
+ if( r == ERROR_SUCCESS )
+ {
+ MSI_ViewExecute( view, NULL );
+ MSI_ViewFetch( view, &rec );
+ MSI_ViewClose( view );
+ msiobj_release( &view->hdr );
+ }
+ return rec;
+}
+
UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
LPCWSTR szQuery, MSIHANDLE *phView)
{
return r;
}
+UINT WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR szColumnNameBuffer,
+ DWORD *pcchBuf )
+{
+ MSIQUERY *query = NULL;
+
+ FIXME("%ld %p %p\n", handle, szColumnNameBuffer, pcchBuf );
+
+ if( !pcchBuf )
+ return MSIDBERROR_INVALIDARG;
+
+ query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
+ if( !query )
+ return MSIDBERROR_INVALIDARG;
+
+ msiobj_release( &query->hdr );
+ return MSIDBERROR_NOERROR;
+}
+
+UINT WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR szColumnNameBuffer,
+ DWORD *pcchBuf )
+{
+ MSIQUERY *query = NULL;
+
+ FIXME("%ld %p %p\n", handle, szColumnNameBuffer, pcchBuf );
+
+ if( !pcchBuf )
+ return MSIDBERROR_INVALIDARG;
+
+ query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
+ if( !query )
+ return MSIDBERROR_INVALIDARG;
+
+ msiobj_release( &query->hdr );
+ return MSIDBERROR_NOERROR;
+}
+
UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb,
LPCSTR szTransformFile, int iErrorCond)
{
}
UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
- string_list *columns )
+ column_info *columns )
{
MSIORDERVIEW *ov = NULL;
UINT count = 0, r;
- string_list *x;
+ column_info *x;
TRACE("%p\n", ov );
*view = (MSIVIEW*) ov;
for( x = columns; x ; x = x->next )
- ORDER_AddColumn( ov, x->string );
+ ORDER_AddColumn( ov, x->column );
return ERROR_SUCCESS;
}
*/
#define LPCTSTR LPCWSTR
-void MSI_FreePackage( MSIOBJECTHDR *arg)
+static void MSI_FreePackage( MSIOBJECTHDR *arg)
{
MSIPACKAGE *package= (MSIPACKAGE*) arg;
package->LastAction = NULL;
package->dialog = NULL;
package->next_dialog = NULL;
+ list_init( &package->subscriptions );
/* OK, here is where we do a slew of things to the database to
* prep for all that is to come as a package */
return r;
}
-static VOID preview_event_handler( MSIPACKAGE *package, LPCWSTR event,
+static UINT preview_event_handler( MSIPACKAGE *package, LPCWSTR event,
LPCWSTR argument, msi_dialog *dialog )
{
MESSAGE("Preview dialog event '%s' (arg='%s')\n",
debugstr_w( event ), debugstr_w( argument ));
+ return ERROR_SUCCESS;
}
UINT MSI_PreviewDialogW( MSIPREVIEW *preview, LPCWSTR szDialogName )
INT len;
};
-typedef struct _string_list
+typedef struct _column_info
{
- LPWSTR string;
- struct _string_list *next;
-} string_list;
+ LPCWSTR table;
+ LPCWSTR column;
+ UINT type;
+ struct expr *val;
+ struct _column_info *next;
+} column_info;
struct complex_expr
{
struct complex_expr expr;
INT ival;
UINT uval;
- LPWSTR sval;
- LPWSTR column;
+ LPCWSTR sval;
+ LPCWSTR column;
UINT col_number;
} u;
};
-typedef struct _create_col_info
-{
- LPWSTR colname;
- UINT type;
- struct _create_col_info *next;
-} create_col_info;
-
-typedef struct _value_list
-{
- struct expr *val;
- struct _value_list *next;
-} value_list;
-
-typedef struct _column_assignment
-{
- string_list *col_list;
- value_list *val_list;
-} column_assignment;
-
-
UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview,
struct list *mem );
UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view );
UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
- string_list *columns );
+ column_info *columns );
UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table );
UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
- string_list *columns );
+ column_info *columns );
UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
struct expr *cond );
UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
- create_col_info *col_info, BOOL temp );
+ column_info *col_info, BOOL temp );
UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
- string_list *columns, value_list *values, BOOL temp );
+ column_info *columns, column_info *values, BOOL temp );
UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **, LPWSTR table,
- column_assignment *list, struct expr *expr );
+ column_info *list, struct expr *expr );
UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table );
#include "winnls.h"
#include "ole2.h"
+#include "winreg.h"
+#include "shlwapi.h"
+
#include "query.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
#define MSIFIELD_WSTR 3
#define MSIFIELD_STREAM 4
-void MSI_FreeField( MSIFIELD *field )
+static void MSI_FreeField( MSIFIELD *field )
{
switch( field->type )
{
}
}
-void MSI_CloseRecord( MSIOBJECTHDR *arg )
+static void MSI_CloseRecord( MSIOBJECTHDR *arg )
{
MSIRECORD *rec = (MSIRECORD *) arg;
UINT i;
return ret;
}
+static UINT msi_get_stream_size( IStream *stm )
+{
+ STATSTG stat;
+ HRESULT r;
+
+ r = IStream_Stat( stm, &stat, STATFLAG_NONAME );
+ if( FAILED(r) )
+ return 0;
+ return stat.cbSize.QuadPart;
+}
+
UINT MSI_RecordDataSize(MSIRECORD *rec, unsigned int iField)
{
TRACE("%p %d\n", rec, iField);
return lstrlenW( rec->fields[iField].u.szwVal );
case MSIFIELD_NULL:
break;
+ case MSIFIELD_STREAM:
+ return msi_get_stream_size( rec->fields[iField].u.stream );
}
return 0;
}
}
/* read the data in a file into an IStream */
-UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
+static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
{
DWORD sz, szHighWord = 0, read;
HANDLE handle;
return ERROR_SUCCESS;
}
+
+static UINT msi_dump_stream_to_file( IStream *stm, LPCWSTR name )
+{
+ ULARGE_INTEGER size;
+ LARGE_INTEGER pos;
+ IStream *out;
+ DWORD stgm;
+ HRESULT r;
+
+ stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE;
+ r = SHCreateStreamOnFileW( name, stgm, &out );
+ if( FAILED( r ) )
+ return ERROR_FUNCTION_FAILED;
+
+ pos.QuadPart = 0;
+ r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size );
+ if( FAILED( r ) )
+ goto end;
+
+ pos.QuadPart = 0;
+ r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
+ if( FAILED( r ) )
+ goto end;
+
+ r = IStream_CopyTo( stm, out, size, NULL, NULL );
+
+end:
+ IStream_Release( out );
+ if( FAILED( r ) )
+ return ERROR_FUNCTION_FAILED;
+ return ERROR_SUCCESS;
+}
+
+UINT MSI_RecordStreamToFile( MSIRECORD *rec, unsigned int iField, LPCWSTR name )
+{
+ IStream *stm = NULL;
+ UINT r;
+
+ TRACE("%p %u %s\n", rec, iField, debugstr_w(name));
+
+ msiobj_lock( &rec->hdr );
+
+ r = MSI_RecordGetIStream( rec, iField, &stm );
+ if( r == ERROR_SUCCESS )
+ {
+ r = msi_dump_stream_to_file( stm, name );
+ IStream_Release( stm );
+ }
+
+ msiobj_unlock( &rec->hdr );
+
+ return r;
+}
'U','p','g','r','a','d','e','C','o','d','e','s','\\',
'%','s',0};
+static const WCHAR szInstaller_UserUpgradeCodes[] = {
+'S','o','f','t','w','a','r','e','\\',
+'M','i','c','r','o','s','o','f','t','\\',
+'I','n','s','t','a','l','l','e','r','\\',
+'U','p','g','r','a','d','e','C','o','d','e','s',0};
+
+static const WCHAR szInstaller_UserUpgradeCodes_fmt[] = {
+'S','o','f','t','w','a','r','e','\\',
+'M','i','c','r','o','s','o','f','t','\\',
+'I','n','s','t','a','l','l','e','r','\\',
+'U','p','g','r','a','d','e','C','o','d','e','s','\\',
+'%','s',0};
+
+
#define SQUISH_GUID_SIZE 33
BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
return rc;
}
+UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
+{
+ UINT rc;
+ WCHAR squished_pc[GUID_SIZE];
+ WCHAR keypath[0x200];
+
+ TRACE("%s\n",debugstr_w(szUpgradeCode));
+ squash_guid(szUpgradeCode,squished_pc);
+ TRACE("squished (%s)\n", debugstr_w(squished_pc));
+
+ sprintfW(keypath,szInstaller_UserUpgradeCodes_fmt,squished_pc);
+
+ if (create)
+ rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
+ else
+ rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
+
+ return rc;
+}
+
+
/*************************************************************************
* MsiDecomposeDescriptorW [MSI.@]
*
SELECT_delete
};
-static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPWSTR name )
+static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name )
{
UINT r, n=0;
MSIVIEW *table;
}
UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
- string_list *columns )
+ column_info *columns )
{
MSISELECTVIEW *sv = NULL;
UINT count = 0, r;
while( columns )
{
- r = SELECT_AddColumn( sv, columns->string );
+ r = SELECT_AddColumn( sv, columns->column );
if( r )
break;
columns = columns->next;
#include "query.h"
#include "wine/list.h"
#include "wine/debug.h"
-#include "wine/unicode.h"
#define YYLEX_PARAM info
#define YYPARSE_PARAM info
static int SQL_lex( void *SQL_lval, SQL_input *info );
static void *parser_alloc( void *info, unsigned int sz );
+static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column );
-static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys);
+static BOOL SQL_MarkPrimaryKeys( column_info *cols, column_info *keys);
static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r );
-static struct expr * EXPR_column( void *info, LPWSTR column );
-static struct expr * EXPR_ival( void *info, struct sql_str *, int sign );
+static struct expr * EXPR_column( void *info, column_info *column );
+static struct expr * EXPR_ival( void *info, int val );
static struct expr * EXPR_sval( void *info, struct sql_str * );
static struct expr * EXPR_wildcard( void *info );
{
struct sql_str str;
LPWSTR string;
- string_list *column_list;
- value_list *val_list;
+ column_info *column_list;
MSIVIEW *query;
struct expr *expr;
USHORT column_type;
- create_col_info *column_info;
- column_assignment update_col_info;
+ int integer;
} yystype;
# define YYSTYPE yystype
# define YYSTYPE_IS_TRIVIAL 1
-#define YYFINAL 126
+#define YYFINAL 127
#define YYFLAG -32768
#define YYNTBASE 147
/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */
-#define YYTRANSLATE(x) ((unsigned)(x) <= 400 ? yytranslate[x] : 175)
+#define YYTRANSLATE(x) ((unsigned)(x) <= 400 ? yytranslate[x] : 177)
/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */
static const short yytranslate[] =
static const short yyprhs[] =
{
0, 0, 2, 4, 6, 8, 10, 12, 23, 35,
- 42, 50, 57, 60, 65, 70, 73, 75, 78, 80,
- 84, 86, 91, 93, 95, 97, 99, 101, 103, 108,
- 110, 113, 117, 120, 122, 126, 128, 130, 134, 137,
- 141, 145, 149, 153, 157, 161, 165, 169, 173, 177,
- 181, 186, 188, 190, 192, 196, 198, 202, 206, 208,
- 211, 213, 215, 217, 221, 223, 225
+ 42, 50, 57, 60, 65, 69, 71, 74, 76, 79,
+ 81, 85, 87, 92, 94, 96, 98, 100, 102, 104,
+ 109, 111, 114, 118, 121, 123, 127, 129, 131, 135,
+ 138, 142, 146, 150, 154, 158, 162, 166, 170, 174,
+ 178, 182, 187, 189, 191, 193, 197, 199, 203, 207,
+ 209, 212, 214, 216, 218, 222, 224, 226, 228
};
static const short yyrhs[] =
{
- 148, 0, 159, 0, 150, 0, 149, 0, 151, 0,
- 152, 0, 67, 72, 173, 83, 162, 110, 134, 83,
- 167, 110, 0, 67, 72, 173, 83, 162, 110, 134,
- 83, 167, 110, 122, 0, 31, 121, 173, 83, 153,
- 110, 0, 31, 121, 173, 83, 153, 110, 59, 0,
- 130, 173, 114, 168, 137, 165, 0, 35, 163, 0,
- 154, 102, 77, 162, 0, 154, 24, 172, 155, 0,
- 172, 155, 0, 156, 0, 156, 86, 0, 157, 0,
- 157, 90, 92, 0, 19, 0, 19, 83, 158, 110,
- 0, 82, 0, 115, 0, 69, 0, 81, 0, 93,
- 0, 70, 0, 160, 99, 16, 162, 0, 160, 0,
- 112, 161, 0, 112, 38, 161, 0, 162, 163, 0,
- 172, 0, 172, 24, 162, 0, 118, 0, 164, 0,
- 164, 137, 165, 0, 52, 173, 0, 83, 165, 110,
- 0, 171, 45, 171, 0, 165, 7, 165, 0, 165,
- 97, 165, 0, 171, 45, 166, 0, 171, 57, 166,
- 0, 171, 85, 166, 0, 171, 78, 166, 0, 171,
- 54, 166, 0, 171, 89, 166, 0, 171, 73, 92,
- 0, 171, 73, 90, 92, 0, 171, 0, 170, 0,
- 170, 0, 170, 24, 167, 0, 169, 0, 169, 24,
- 168, 0, 172, 45, 170, 0, 70, 0, 88, 70,
- 0, 120, 0, 138, 0, 172, 0, 173, 39, 174,
- 0, 174, 0, 174, 0, 66, 0
+ 148, 0, 160, 0, 150, 0, 149, 0, 151, 0,
+ 152, 0, 67, 72, 174, 83, 163, 110, 134, 83,
+ 168, 110, 0, 67, 72, 174, 83, 163, 110, 134,
+ 83, 168, 110, 122, 0, 31, 121, 174, 83, 153,
+ 110, 0, 31, 121, 174, 83, 153, 110, 59, 0,
+ 130, 174, 114, 169, 137, 166, 0, 35, 164, 0,
+ 154, 102, 77, 163, 0, 154, 24, 155, 0, 155,
+ 0, 173, 156, 0, 157, 0, 157, 86, 0, 158,
+ 0, 158, 90, 92, 0, 19, 0, 19, 83, 159,
+ 110, 0, 82, 0, 115, 0, 69, 0, 81, 0,
+ 93, 0, 176, 0, 161, 99, 16, 163, 0, 161,
+ 0, 112, 162, 0, 112, 38, 162, 0, 163, 164,
+ 0, 173, 0, 173, 24, 163, 0, 118, 0, 165,
+ 0, 165, 137, 166, 0, 52, 174, 0, 83, 166,
+ 110, 0, 172, 45, 172, 0, 166, 7, 166, 0,
+ 166, 97, 166, 0, 172, 45, 167, 0, 172, 57,
+ 167, 0, 172, 85, 167, 0, 172, 78, 167, 0,
+ 172, 54, 167, 0, 172, 89, 167, 0, 172, 73,
+ 92, 0, 172, 73, 90, 92, 0, 172, 0, 171,
+ 0, 171, 0, 171, 24, 168, 0, 170, 0, 170,
+ 24, 169, 0, 173, 45, 171, 0, 176, 0, 88,
+ 176, 0, 120, 0, 138, 0, 173, 0, 174, 39,
+ 175, 0, 175, 0, 175, 0, 66, 0, 70, 0
};
#endif
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const short yyrline[] =
{
- 0, 140, 148, 150, 151, 152, 153, 156, 168, 180,
- 193, 207, 220, 233, 243, 263, 274, 279, 286, 291,
- 297, 302, 306, 310, 314, 318, 322, 328, 339, 352,
- 355, 360, 371, 387, 401, 414, 420, 422, 434, 447,
- 454, 460, 466, 472, 478, 484, 490, 496, 502, 508,
- 514, 522, 524, 527, 539, 552, 554, 562, 578, 585,
- 591, 597, 605, 614, 619, 625, 632
+ 0, 137, 145, 147, 148, 149, 150, 153, 165, 177,
+ 190, 204, 217, 230, 240, 251, 257, 265, 270, 277,
+ 282, 288, 293, 297, 301, 305, 309, 313, 319, 328,
+ 341, 344, 349, 360, 376, 378, 382, 388, 390, 402,
+ 415, 422, 428, 434, 440, 446, 452, 458, 464, 470,
+ 476, 482, 490, 492, 495, 503, 513, 515, 522, 530,
+ 537, 543, 549, 557, 566, 573, 581, 588, 597
};
#endif
"TK_WILDCARD", "END_OF_FILE", "ILLEGAL", "SPACE", "UNCLOSED_STRING",
"COMMENT", "FUNCTION", "COLUMN", "AGG_FUNCTION.", "query", "onequery",
"oneinsert", "onecreate", "oneupdate", "onedelete", "table_def",
- "column_def", "column_type", "data_type_l", "data_type", "data_count",
- "oneselect", "unorderedsel", "selectfrom", "selcollist", "from",
- "fromtable", "expr", "val", "constlist", "update_assign_list",
- "column_assignment", "const_val", "column_val", "column", "table", "id", 0
+ "column_def", "column_and_type", "column_type", "data_type_l",
+ "data_type", "data_count", "oneselect", "unorderedsel", "selectfrom",
+ "selcollist", "from", "fromtable", "expr", "val", "constlist",
+ "update_assign_list", "column_assignment", "const_val", "column_val",
+ "column", "table", "id", "number", 0
};
#endif
static const short yyr1[] =
{
0, 147, 148, 148, 148, 148, 148, 149, 149, 150,
- 150, 151, 152, 153, 154, 154, 155, 155, 156, 156,
- 157, 157, 157, 157, 157, 157, 157, 158, 159, 159,
- 160, 160, 161, 162, 162, 162, 163, 163, 164, 165,
- 165, 165, 165, 165, 165, 165, 165, 165, 165, 165,
- 165, 166, 166, 167, 167, 168, 168, 169, 170, 170,
- 170, 170, 171, 172, 172, 173, 174
+ 150, 151, 152, 153, 154, 154, 155, 156, 156, 157,
+ 157, 158, 158, 158, 158, 158, 158, 158, 159, 160,
+ 160, 161, 161, 162, 163, 163, 163, 164, 164, 165,
+ 166, 166, 166, 166, 166, 166, 166, 166, 166, 166,
+ 166, 166, 167, 167, 168, 168, 169, 169, 170, 171,
+ 171, 171, 171, 172, 173, 173, 174, 175, 176
};
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
static const short yyr2[] =
{
0, 1, 1, 1, 1, 1, 1, 10, 11, 6,
- 7, 6, 2, 4, 4, 2, 1, 2, 1, 3,
- 1, 4, 1, 1, 1, 1, 1, 1, 4, 1,
- 2, 3, 2, 1, 3, 1, 1, 3, 2, 3,
+ 7, 6, 2, 4, 3, 1, 2, 1, 2, 1,
+ 3, 1, 4, 1, 1, 1, 1, 1, 1, 4,
+ 1, 2, 3, 2, 1, 3, 1, 1, 3, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 4, 1, 1, 1, 3, 1, 3, 3, 1, 2,
- 1, 1, 1, 3, 1, 1, 1
+ 3, 4, 1, 1, 1, 3, 1, 3, 3, 1,
+ 2, 1, 1, 1, 3, 1, 1, 1, 1
};
/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE
static const short yydefact[] =
{
0, 0, 0, 0, 0, 0, 1, 4, 3, 5,
- 6, 2, 29, 0, 0, 12, 36, 0, 0, 66,
- 35, 30, 0, 33, 0, 64, 0, 65, 0, 0,
- 38, 0, 0, 31, 32, 0, 0, 0, 0, 0,
- 0, 37, 0, 62, 0, 34, 63, 0, 55, 0,
- 28, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 9, 0,
- 0, 20, 24, 25, 22, 26, 23, 15, 16, 18,
- 39, 41, 42, 58, 0, 60, 61, 43, 52, 40,
- 47, 51, 44, 0, 49, 46, 45, 48, 0, 11,
- 56, 57, 10, 0, 0, 0, 17, 0, 59, 50,
- 0, 14, 13, 27, 0, 19, 0, 21, 0, 53,
- 7, 0, 8, 54, 0, 0, 0
+ 6, 2, 30, 0, 0, 12, 37, 0, 0, 67,
+ 36, 31, 0, 34, 0, 65, 0, 66, 0, 0,
+ 39, 0, 0, 32, 33, 0, 0, 0, 0, 0,
+ 0, 38, 0, 63, 0, 35, 64, 0, 56, 0,
+ 29, 0, 0, 15, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
+ 0, 0, 21, 25, 26, 23, 27, 24, 16, 17,
+ 19, 40, 42, 43, 68, 0, 61, 62, 44, 53,
+ 41, 59, 48, 52, 45, 0, 50, 47, 46, 49,
+ 0, 11, 57, 58, 10, 14, 0, 0, 18, 0,
+ 60, 51, 0, 13, 0, 28, 20, 0, 22, 0,
+ 54, 7, 0, 8, 55, 0, 0, 0
};
static const short yydefgoto[] =
{
- 124, 6, 7, 8, 9, 10, 51, 52, 77, 78,
- 79, 114, 11, 12, 21, 22, 15, 16, 41, 87,
- 118, 47, 48, 88, 42, 43, 24, 25
+ 125, 6, 7, 8, 9, 10, 51, 52, 53, 78,
+ 79, 80, 114, 11, 12, 21, 22, 15, 16, 41,
+ 88, 119, 47, 48, 89, 42, 43, 24, 25, 91
};
static const short yypact[] =
{
- -28, -102, -32, -48, -29, -39,-32768,-32768,-32768,-32768,
- -32768,-32768, -61, -39, -39,-32768, -97, -39, -50,-32768,
- -32768,-32768, -32, 19, 6, 9, -65,-32768, 34, -30,
- -32768, -37, -26,-32768,-32768, -50, -39, -39, -50, -39,
- -37, -2, -31,-32768, -50,-32768,-32768, -86, 32, 10,
- -32768, -51, -20, -17, -7, -37, -37, -60, -60, -60,
- -59, -60, -60, -60, -36, -37, -39, -58, 16, -39,
- 2, 0,-32768,-32768,-32768,-32768,-32768,-32768, -5, 1,
- -32768, -2, -2,-32768, 15,-32768,-32768,-32768,-32768,-32768,
- -32768,-32768,-32768, -4,-32768,-32768,-32768,-32768, -42, -2,
- -32768,-32768,-32768, -17, -50, 23,-32768, 5,-32768,-32768,
- 11,-32768,-32768,-32768, -11,-32768, -58,-32768, -10, 83,
- -9, -58,-32768,-32768, 117, 118,-32768
+ -28, -106, -27, -52, -32, -42,-32768,-32768,-32768,-32768,
+ -32768,-32768, -70, -42, -42,-32768, -97, -42, -48,-32768,
+ -32768,-32768, -27, 7, 2, 5, -62,-32768, 40, -23,
+ -32768, -55, -22,-32768,-32768, -48, -42, -42, -48, -42,
+ -55, -3, 0,-32768, -48,-32768,-32768, -65, 43, 29,
+ -32768, -34, -19,-32768, -18, -7, -55, -55, -58, -58,
+ -58, -37, -58, -58, -58, -31, -55, -42, -61, 23,
+ -42, 10, 8,-32768,-32768,-32768,-32768,-32768,-32768, 6,
+ 3,-32768, -3, -3,-32768, 18,-32768,-32768,-32768,-32768,
+ -32768,-32768,-32768,-32768,-32768, 16,-32768,-32768,-32768,-32768,
+ -33, -3,-32768,-32768,-32768,-32768, -48, 18,-32768, 20,
+ -32768,-32768, 30,-32768, 4,-32768,-32768, -61,-32768, 11,
+ 91, -6, -61,-32768,-32768, 117, 118,-32768
};
static const short yypgoto[] =
{
- -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 17,-32768,
- -32768,-32768,-32768,-32768, 101, -27, 99,-32768, 31, 53,
- 3, 57,-32768, -49, 47, -3, 56, 8
+ -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 49,-32768,
+ -32768,-32768,-32768,-32768,-32768, 102, -25, 100,-32768, -8,
+ 36, 1, 57,-32768, -51, 47, -2, 9, 33, -64
};
static const short yytable[] =
{
- 55, 23, 71, 1, 69, 55, 19, 2, 45, 18,
- 83, 50, 83, 27, 57, 23, 19, 64, 101, 13,
- 14, 27, 27, 58, 17, 27, 59, 19, 84, 19,
- 84, 93, 23, 94, 49, 23, 53, 19, 28, 3,
- 31, 23, 60, 35, 46, 36, 40, 61, -65, 37,
- 38, 65, 72, 39, 62, 67, 66, 44, 63, 68,
- 85, 26, 85, 49, 73, 74, 103, 119, 20, 29,
- 30, 54, 119, 32, 98, 102, 75, 112, 86, 104,
- 86, 106, 70, 105, 4, 108, 81, 82, 109, 20,
- 56, 107, 110, 113, 116, 56, 99, 115, 76, 117,
- 120, 23, 5, 80, 89, 91, 91, 121, 91, 91,
- 91, 90, 92, 122, 95, 96, 97, 125, 126, 33,
- 111, 34, 0, 100, 123
+ 56, 72, 23, 1, 56, 70, 18, 2, 19, 84,
+ 45, 19, 84, 50, 26, 13, 23, 103, 19, 65,
+ 17, 110, 29, 30, 19, 14, 32, 85, 40, 28,
+ 85, 35, 55, 23, 19, 49, 23, 54, 27, 3,
+ 31, 36, 23, 115, -66, 58, 27, 27, 82, 83,
+ 27, 73, 37, 95, 59, 96, 38, 60, 101, 86,
+ 39, 44, 86, 74, 75, 49, 120, 67, 54, 46,
+ 20, 120, 66, 61, 68, 76, 69, 87, 62, 100,
+ 87, 113, 104, 71, 4, 63, 20, 106, 84, 64,
+ 57, 107, 108, 109, 57, 92, 94, 77, 97, 98,
+ 99, 112, 5, 81, 23, 90, 93, 93, 111, 93,
+ 93, 93, 116, 117, 118, 122, 123, 126, 127, 105,
+ 33, 121, 34, 124, 102
};
static const short yycheck[] =
{
- 7, 4, 19, 31, 24, 7, 66, 35, 35, 38,
- 70, 38, 70, 5, 45, 18, 66, 44, 67, 121,
- 52, 13, 14, 54, 72, 17, 57, 66, 88, 66,
- 88, 90, 35, 92, 37, 38, 39, 66, 99, 67,
- 137, 44, 73, 24, 36, 39, 83, 78, 39, 114,
- 16, 137, 69, 83, 85, 45, 24, 83, 89, 110,
- 120, 5, 120, 66, 81, 82, 69, 116, 118, 13,
- 14, 40, 121, 17, 110, 59, 93, 104, 138, 77,
- 138, 86, 102, 83, 112, 70, 55, 56, 92, 118,
- 97, 90, 134, 70, 83, 97, 65, 92, 115, 110,
- 110, 104, 130, 110, 57, 58, 59, 24, 61, 62,
- 63, 58, 59, 122, 61, 62, 63, 0, 0, 18,
- 103, 22, -1, 66, 121
+ 7, 19, 4, 31, 7, 24, 38, 35, 66, 70,
+ 35, 66, 70, 38, 5, 121, 18, 68, 66, 44,
+ 72, 85, 13, 14, 66, 52, 17, 88, 83, 99,
+ 88, 24, 40, 35, 66, 37, 38, 39, 5, 67,
+ 137, 39, 44, 107, 39, 45, 13, 14, 56, 57,
+ 17, 69, 114, 90, 54, 92, 16, 57, 66, 120,
+ 83, 83, 120, 81, 82, 67, 117, 24, 70, 36,
+ 118, 122, 137, 73, 45, 93, 110, 138, 78, 110,
+ 138, 106, 59, 102, 112, 85, 118, 77, 70, 89,
+ 97, 83, 86, 90, 97, 59, 60, 115, 62, 63,
+ 64, 134, 130, 110, 106, 58, 59, 60, 92, 62,
+ 63, 64, 92, 83, 110, 24, 122, 0, 0, 70,
+ 18, 110, 22, 122, 67
};
#define YYPURE 1
switch (yyn) {
case 1:
-#line 142 "./sql.y"
+#line 139 "./sql.y"
{
SQL_input* sql = (SQL_input*) info;
*sql->view = yyvsp[0].query;
;
break;}
case 7:
-#line 158 "./sql.y"
+#line 155 "./sql.y"
{
SQL_input *sql = (SQL_input*) info;
MSIVIEW *insert = NULL;
UINT r;
- r = INSERT_CreateView( sql->db, &insert, yyvsp[-7].string, yyvsp[-5].column_list, yyvsp[-1].val_list, FALSE );
+ r = INSERT_CreateView( sql->db, &insert, yyvsp[-7].string, yyvsp[-5].column_list, yyvsp[-1].column_list, FALSE );
if( !insert )
YYABORT;
yyval.query = insert;
;
break;}
case 8:
-#line 169 "./sql.y"
+#line 166 "./sql.y"
{
SQL_input *sql = (SQL_input*) info;
MSIVIEW *insert = NULL;
- INSERT_CreateView( sql->db, &insert, yyvsp[-8].string, yyvsp[-6].column_list, yyvsp[-2].val_list, TRUE );
+ INSERT_CreateView( sql->db, &insert, yyvsp[-8].string, yyvsp[-6].column_list, yyvsp[-2].column_list, TRUE );
if( !insert )
YYABORT;
yyval.query = insert;
;
break;}
case 9:
-#line 182 "./sql.y"
+#line 179 "./sql.y"
{
SQL_input* sql = (SQL_input*) info;
MSIVIEW *create = NULL;
- if( !yyvsp[-1].column_info )
+ if( !yyvsp[-1].column_list )
YYABORT;
- CREATE_CreateView( sql->db, &create, yyvsp[-3].string, yyvsp[-1].column_info, FALSE );
+ CREATE_CreateView( sql->db, &create, yyvsp[-3].string, yyvsp[-1].column_list, FALSE );
if( !create )
YYABORT;
yyval.query = create;
;
break;}
case 10:
-#line 194 "./sql.y"
+#line 191 "./sql.y"
{
SQL_input* sql = (SQL_input*) info;
MSIVIEW *create = NULL;
- if( !yyvsp[-2].column_info )
+ if( !yyvsp[-2].column_list )
YYABORT;
- CREATE_CreateView( sql->db, &create, yyvsp[-4].string, yyvsp[-2].column_info, TRUE );
+ CREATE_CreateView( sql->db, &create, yyvsp[-4].string, yyvsp[-2].column_list, TRUE );
if( !create )
YYABORT;
yyval.query = create;
;
break;}
case 11:
-#line 209 "./sql.y"
+#line 206 "./sql.y"
{
SQL_input* sql = (SQL_input*) info;
MSIVIEW *update = NULL;
- UPDATE_CreateView( sql->db, &update, yyvsp[-4].string, &yyvsp[-2].update_col_info, yyvsp[0].expr );
+ UPDATE_CreateView( sql->db, &update, yyvsp[-4].string, yyvsp[-2].column_list, yyvsp[0].expr );
if( !update )
YYABORT;
yyval.query = update;
;
break;}
case 12:
-#line 222 "./sql.y"
+#line 219 "./sql.y"
{
SQL_input* sql = (SQL_input*) info;
MSIVIEW *delete = NULL;
;
break;}
case 13:
-#line 235 "./sql.y"
+#line 232 "./sql.y"
{
- if( SQL_MarkPrimaryKeys( yyvsp[-3].column_info, yyvsp[0].column_list ) )
- yyval.column_info = yyvsp[-3].column_info;
+ if( SQL_MarkPrimaryKeys( yyvsp[-3].column_list, yyvsp[0].column_list ) )
+ yyval.column_list = yyvsp[-3].column_list;
else
- yyval.column_info = NULL;
+ yyval.column_list = NULL;
;
break;}
case 14:
-#line 245 "./sql.y"
+#line 242 "./sql.y"
{
- create_col_info *ci;
+ column_info *ci;
- for( ci = yyvsp[-3].column_info; ci->next; ci = ci->next )
+ for( ci = yyvsp[-2].column_list; ci->next; ci = ci->next )
;
- ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info );
- if( !ci->next )
- {
- /* FIXME: free $1 */
- YYABORT;
- }
- ci->next->colname = yyvsp[-1].string;
- ci->next->type = yyvsp[0].column_type;
- ci->next->next = NULL;
-
- yyval.column_info = yyvsp[-3].column_info;
+ ci->next = yyvsp[0].column_list;
+ yyval.column_list = yyvsp[-2].column_list;
;
break;}
case 15:
-#line 264 "./sql.y"
+#line 252 "./sql.y"
{
- yyval.column_info = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info );
- if( ! yyval.column_info )
- YYABORT;
- yyval.column_info->colname = yyvsp[-1].string;
- yyval.column_info->type = yyvsp[0].column_type;
- yyval.column_info->next = NULL;
+ yyval.column_list = yyvsp[0].column_list;
;
break;}
case 16:
-#line 276 "./sql.y"
+#line 259 "./sql.y"
{
- yyval.column_type = yyvsp[0].column_type | MSITYPE_VALID;
+ yyval.column_list = yyvsp[-1].column_list;
+ yyval.column_list->type = yyvsp[0].column_type;
;
break;}
case 17:
-#line 280 "./sql.y"
+#line 267 "./sql.y"
{
- FIXME("LOCALIZABLE ignored\n");
- yyval.column_type = yyvsp[-1].column_type | MSITYPE_VALID;
+ yyval.column_type = yyvsp[0].column_type | MSITYPE_VALID;
;
break;}
case 18:
-#line 288 "./sql.y"
+#line 271 "./sql.y"
{
- yyval.column_type |= MSITYPE_NULLABLE;
+ FIXME("LOCALIZABLE ignored\n");
+ yyval.column_type = yyvsp[-1].column_type | MSITYPE_VALID;
;
break;}
case 19:
-#line 292 "./sql.y"
+#line 279 "./sql.y"
{
- yyval.column_type = yyvsp[-2].column_type;
+ yyval.column_type |= MSITYPE_NULLABLE;
;
break;}
case 20:
-#line 299 "./sql.y"
+#line 283 "./sql.y"
{
- yyval.column_type = MSITYPE_STRING | 1;
+ yyval.column_type = yyvsp[-2].column_type;
;
break;}
case 21:
-#line 303 "./sql.y"
+#line 290 "./sql.y"
{
- yyval.column_type = MSITYPE_STRING | 0x400 | yyvsp[-1].column_type;
+ yyval.column_type = MSITYPE_STRING | 1;
;
break;}
case 22:
-#line 307 "./sql.y"
+#line 294 "./sql.y"
{
- yyval.column_type = 2;
+ yyval.column_type = MSITYPE_STRING | 0x400 | yyvsp[-1].column_type;
;
break;}
case 23:
-#line 311 "./sql.y"
+#line 298 "./sql.y"
{
yyval.column_type = 2;
;
break;}
case 24:
-#line 315 "./sql.y"
+#line 302 "./sql.y"
{
yyval.column_type = 2;
;
break;}
case 25:
-#line 319 "./sql.y"
+#line 306 "./sql.y"
{
- yyval.column_type = 4;
+ yyval.column_type = 2;
;
break;}
case 26:
-#line 323 "./sql.y"
+#line 310 "./sql.y"
{
- yyval.column_type = 0;
+ yyval.column_type = 4;
;
break;}
case 27:
-#line 330 "./sql.y"
+#line 314 "./sql.y"
{
- SQL_input* sql = (SQL_input*) info;
- int val = SQL_getint(sql);
- if( ( val > 255 ) || ( val < 0 ) )
- YYABORT;
- yyval.column_type = val;
+ yyval.column_type = 0;
;
break;}
case 28:
-#line 341 "./sql.y"
+#line 321 "./sql.y"
+{
+ if( ( yyvsp[0].integer > 255 ) || ( yyvsp[0].integer < 0 ) )
+ YYABORT;
+ yyval.column_type = yyvsp[0].integer;
+ ;
+ break;}
+case 29:
+#line 330 "./sql.y"
{
SQL_input* sql = (SQL_input*) info;
YYABORT;
;
break;}
-case 30:
-#line 357 "./sql.y"
+case 31:
+#line 346 "./sql.y"
{
yyval.query = yyvsp[0].query;
;
break;}
-case 31:
-#line 361 "./sql.y"
+case 32:
+#line 350 "./sql.y"
{
SQL_input* sql = (SQL_input*) info;
YYABORT;
;
break;}
-case 32:
-#line 373 "./sql.y"
+case 33:
+#line 362 "./sql.y"
{
SQL_input* sql = (SQL_input*) info;
YYABORT;
;
break;}
-case 33:
-#line 389 "./sql.y"
-{
- string_list *list;
-
- list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
- if( !list )
- YYABORT;
- list->string = yyvsp[0].string;
- list->next = NULL;
-
- yyval.column_list = list;
- TRACE("Collist %s\n",debugstr_w(yyval.column_list->string));
- ;
- break;}
-case 34:
-#line 402 "./sql.y"
+case 35:
+#line 379 "./sql.y"
{
- string_list *list;
-
- list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
- if( !list )
- YYABORT;
- list->string = yyvsp[-2].string;
- list->next = yyvsp[0].column_list;
-
- yyval.column_list = list;
- TRACE("From table: %s\n",debugstr_w(yyval.column_list->string));
+ yyvsp[-2].column_list->next = yyvsp[0].column_list;
;
break;}
-case 35:
-#line 415 "./sql.y"
+case 36:
+#line 383 "./sql.y"
{
yyval.column_list = NULL;
;
break;}
-case 37:
-#line 423 "./sql.y"
+case 38:
+#line 391 "./sql.y"
{
SQL_input* sql = (SQL_input*) info;
UINT r;
YYABORT;
;
break;}
-case 38:
-#line 436 "./sql.y"
+case 39:
+#line 404 "./sql.y"
{
SQL_input* sql = (SQL_input*) info;
UINT r;
YYABORT;
;
break;}
-case 39:
-#line 449 "./sql.y"
+case 40:
+#line 417 "./sql.y"
{
yyval.expr = yyvsp[-1].expr;
if( !yyval.expr )
YYABORT;
;
break;}
-case 40:
-#line 455 "./sql.y"
+case 41:
+#line 423 "./sql.y"
{
yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_EQ, yyvsp[0].expr );
if( !yyval.expr )
YYABORT;
;
break;}
-case 41:
-#line 461 "./sql.y"
+case 42:
+#line 429 "./sql.y"
{
yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_AND, yyvsp[0].expr );
if( !yyval.expr )
YYABORT;
;
break;}
-case 42:
-#line 467 "./sql.y"
+case 43:
+#line 435 "./sql.y"
{
yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_OR, yyvsp[0].expr );
if( !yyval.expr )
YYABORT;
;
break;}
-case 43:
-#line 473 "./sql.y"
+case 44:
+#line 441 "./sql.y"
{
yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_EQ, yyvsp[0].expr );
if( !yyval.expr )
YYABORT;
;
break;}
-case 44:
-#line 479 "./sql.y"
+case 45:
+#line 447 "./sql.y"
{
yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_GT, yyvsp[0].expr );
if( !yyval.expr )
YYABORT;
;
break;}
-case 45:
-#line 485 "./sql.y"
+case 46:
+#line 453 "./sql.y"
{
yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_LT, yyvsp[0].expr );
if( !yyval.expr )
YYABORT;
;
break;}
-case 46:
-#line 491 "./sql.y"
+case 47:
+#line 459 "./sql.y"
{
yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_LE, yyvsp[0].expr );
if( !yyval.expr )
YYABORT;
;
break;}
-case 47:
-#line 497 "./sql.y"
+case 48:
+#line 465 "./sql.y"
{
yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_GE, yyvsp[0].expr );
if( !yyval.expr )
YYABORT;
;
break;}
-case 48:
-#line 503 "./sql.y"
+case 49:
+#line 471 "./sql.y"
{
yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_NE, yyvsp[0].expr );
if( !yyval.expr )
YYABORT;
;
break;}
-case 49:
-#line 509 "./sql.y"
+case 50:
+#line 477 "./sql.y"
{
yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_ISNULL, NULL );
if( !yyval.expr )
YYABORT;
;
break;}
-case 50:
-#line 515 "./sql.y"
+case 51:
+#line 483 "./sql.y"
{
yyval.expr = EXPR_complex( info, yyvsp[-3].expr, OP_NOTNULL, NULL );
if( !yyval.expr )
YYABORT;
;
break;}
-case 53:
-#line 529 "./sql.y"
-{
- value_list *vals;
-
- vals = parser_alloc( info, sizeof *vals );
- if( !vals )
- YYABORT;
- vals->val = yyvsp[0].expr;
- vals->next = NULL;
- yyval.val_list = vals;
- ;
- break;}
case 54:
-#line 540 "./sql.y"
+#line 497 "./sql.y"
{
- value_list *vals;
-
- vals = parser_alloc( info, sizeof *vals );
- if( !vals )
+ yyval.column_list = parser_alloc_column( info, NULL, NULL );
+ if( !yyval.column_list )
YYABORT;
- vals->val = yyvsp[-2].expr;
- vals->next = yyvsp[0].val_list;
- yyval.val_list = vals;
+ yyval.column_list->val = yyvsp[0].expr;
;
break;}
-case 56:
-#line 555 "./sql.y"
+case 55:
+#line 504 "./sql.y"
{
- yyvsp[-2].update_col_info.col_list->next = yyvsp[0].update_col_info.col_list;
- yyvsp[-2].update_col_info.val_list->next = yyvsp[0].update_col_info.val_list;
- yyval.update_col_info = yyvsp[-2].update_col_info;
+ yyval.column_list = parser_alloc_column( info, NULL, NULL );
+ if( !yyval.column_list )
+ YYABORT;
+ yyval.column_list->val = yyvsp[-2].expr;
+ yyval.column_list->next = yyvsp[0].column_list;
;
break;}
case 57:
-#line 564 "./sql.y"
+#line 516 "./sql.y"
{
- yyval.update_col_info.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.col_list );
- if( !yyval.update_col_info.col_list )
- YYABORT;
- yyval.update_col_info.col_list->string = yyvsp[-2].string;
- yyval.update_col_info.col_list->next = NULL;
- yyval.update_col_info.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.val_list );
- if( !yyval.update_col_info.val_list )
- YYABORT;
- yyval.update_col_info.val_list->val = yyvsp[0].expr;
- yyval.update_col_info.val_list->next = 0;
+ yyval.column_list = yyvsp[-2].column_list;
+ yyval.column_list->next = yyvsp[0].column_list;
;
break;}
case 58:
-#line 580 "./sql.y"
+#line 524 "./sql.y"
{
- yyval.expr = EXPR_ival( info, &yyvsp[0].str, 1 );
- if( !yyval.expr )
- YYABORT;
+ yyval.column_list = yyvsp[-2].column_list;
+ yyval.column_list->val = yyvsp[0].expr;
;
break;}
case 59:
-#line 586 "./sql.y"
+#line 532 "./sql.y"
{
- yyval.expr = EXPR_ival( info, &yyvsp[0].str, -1 );
+ yyval.expr = EXPR_ival( info, yyvsp[0].integer );
if( !yyval.expr )
YYABORT;
;
break;}
case 60:
-#line 592 "./sql.y"
+#line 538 "./sql.y"
{
- yyval.expr = EXPR_sval( info, &yyvsp[0].str );
+ yyval.expr = EXPR_ival( info, -yyvsp[0].integer );
if( !yyval.expr )
YYABORT;
;
break;}
case 61:
-#line 598 "./sql.y"
+#line 544 "./sql.y"
{
- yyval.expr = EXPR_wildcard( info );
+ yyval.expr = EXPR_sval( info, &yyvsp[0].str );
if( !yyval.expr )
YYABORT;
;
break;}
case 62:
-#line 607 "./sql.y"
+#line 550 "./sql.y"
{
- yyval.expr = EXPR_column( info, yyvsp[0].string );
+ yyval.expr = EXPR_wildcard( info );
if( !yyval.expr )
YYABORT;
;
break;}
case 63:
-#line 616 "./sql.y"
+#line 559 "./sql.y"
{
- yyval.string = yyvsp[0].string; /* FIXME */
+ yyval.expr = EXPR_column( info, yyvsp[0].column_list );
+ if( !yyval.expr )
+ YYABORT;
;
break;}
case 64:
-#line 620 "./sql.y"
+#line 568 "./sql.y"
{
- yyval.string = yyvsp[0].string;
+ yyval.column_list = parser_alloc_column( info, yyvsp[-2].string, yyvsp[0].string );
+ if( !yyval.column_list )
+ YYABORT;
;
break;}
case 65:
-#line 627 "./sql.y"
+#line 574 "./sql.y"
{
- yyval.string = yyvsp[0].string;
+ yyval.column_list = parser_alloc_column( info, NULL, yyvsp[0].string );
+ if( !yyval.column_list )
+ YYABORT;
;
break;}
case 66:
-#line 634 "./sql.y"
+#line 583 "./sql.y"
+{
+ yyval.string = yyvsp[0].string;
+ ;
+ break;}
+case 67:
+#line 590 "./sql.y"
{
yyval.string = SQL_getstring( info, &yyvsp[0].str );
if( !yyval.string )
YYABORT;
;
break;}
+case 68:
+#line 599 "./sql.y"
+{
+ yyval.integer = SQL_getint( info );
+ ;
+ break;}
}
#line 705 "/usr/share/bison/bison.simple"
#endif
return yyresult;
}
-#line 641 "./sql.y"
+#line 604 "./sql.y"
static void *parser_alloc( void *info, unsigned int sz )
return &mem[1];
}
+static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column )
+{
+ column_info *col;
+
+ col = parser_alloc( info, sizeof (*col) );
+ if( col )
+ {
+ col->table = table;
+ col->column = column;
+ col->val = NULL;
+ col->type = 0;
+ col->next = NULL;
+ }
+
+ return col;
+}
+
int SQL_lex( void *SQL_lval, SQL_input *sql )
{
int token;
{
SQL_input* sql = (SQL_input*) info;
LPCWSTR p = &sql->command[sql->n];
+ INT i, r = 0;
+
+ for( i=0; i<sql->len; i++ )
+ {
+ if( '0' > p[i] || '9' < p[i] )
+ {
+ ERR("should only be numbers here!\n");
+ break;
+ }
+ r = (p[i]-'0') + r*10;
+ }
- return atoiW( p );
+ return r;
}
int SQL_error( const char *str )
return e;
}
-static struct expr * EXPR_column( void *info, LPWSTR column )
+static struct expr * EXPR_column( void *info, column_info *column )
{
struct expr *e = parser_alloc( info, sizeof *e );
if( e )
{
e->type = EXPR_COLUMN;
- e->u.sval = column;
+ e->u.sval = column->column;
}
return e;
}
-static struct expr * EXPR_ival( void *info, struct sql_str *str, int sign )
+static struct expr * EXPR_ival( void *info, int val )
{
struct expr *e = parser_alloc( info, sizeof *e );
if( e )
{
e->type = EXPR_IVAL;
- e->u.ival = atoiW( str->data ) * sign;
+ e->u.ival = val;
}
return e;
}
return e;
}
-static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys)
+static BOOL SQL_MarkPrimaryKeys( column_info *cols,
+ column_info *keys )
{
- string_list *k;
+ column_info *k;
BOOL found = TRUE;
for( k = keys; k && found; k = k->next )
{
- create_col_info *c;
+ column_info *c;
found = FALSE;
for( c = cols; c && !found; c = c->next )
{
- if( lstrcmpW( k->string, c->colname ) )
+ if( lstrcmpW( k->column, c->column ) )
continue;
c->type |= MSITYPE_KEY;
found = TRUE;
-/* A Bison parser, made by GNU Bison 1.875b. */
+#ifndef BISON_SQL_TAB_H
+# define BISON_SQL_TAB_H
-/* Skeleton parser for Yacc-like parsing with Bison,
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
-
-/* As a special exception, when this file is copied by Bison into a
- Bison output file, you may use that output file without restriction.
- This special exception was added by the Free Software Foundation
- in version 1.24 of Bison. */
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- TK_ABORT = 258,
- TK_AFTER = 259,
- TK_AGG_FUNCTION = 260,
- TK_ALL = 261,
- TK_AND = 262,
- TK_AS = 263,
- TK_ASC = 264,
- TK_BEFORE = 265,
- TK_BEGIN = 266,
- TK_BETWEEN = 267,
- TK_BITAND = 268,
- TK_BITNOT = 269,
- TK_BITOR = 270,
- TK_BY = 271,
- TK_CASCADE = 272,
- TK_CASE = 273,
- TK_CHAR = 274,
- TK_CHECK = 275,
- TK_CLUSTER = 276,
- TK_COLLATE = 277,
- TK_COLUMN = 278,
- TK_COMMA = 279,
- TK_COMMENT = 280,
- TK_COMMIT = 281,
- TK_CONCAT = 282,
- TK_CONFLICT = 283,
- TK_CONSTRAINT = 284,
- TK_COPY = 285,
- TK_CREATE = 286,
- TK_DEFAULT = 287,
- TK_DEFERRABLE = 288,
- TK_DEFERRED = 289,
- TK_DELETE = 290,
- TK_DELIMITERS = 291,
- TK_DESC = 292,
- TK_DISTINCT = 293,
- TK_DOT = 294,
- TK_DROP = 295,
- TK_EACH = 296,
- TK_ELSE = 297,
- TK_END = 298,
- TK_END_OF_FILE = 299,
- TK_EQ = 300,
- TK_EXCEPT = 301,
- TK_EXPLAIN = 302,
- TK_FAIL = 303,
- TK_FLOAT = 304,
- TK_FOR = 305,
- TK_FOREIGN = 306,
- TK_FROM = 307,
- TK_FUNCTION = 308,
- TK_GE = 309,
- TK_GLOB = 310,
- TK_GROUP = 311,
- TK_GT = 312,
- TK_HAVING = 313,
- TK_HOLD = 314,
- TK_IGNORE = 315,
- TK_ILLEGAL = 316,
- TK_IMMEDIATE = 317,
- TK_IN = 318,
- TK_INDEX = 319,
- TK_INITIALLY = 320,
- TK_ID = 321,
- TK_INSERT = 322,
- TK_INSTEAD = 323,
- TK_INT = 324,
- TK_INTEGER = 325,
- TK_INTERSECT = 326,
- TK_INTO = 327,
- TK_IS = 328,
- TK_ISNULL = 329,
- TK_JOIN = 330,
- TK_JOIN_KW = 331,
- TK_KEY = 332,
- TK_LE = 333,
- TK_LIKE = 334,
- TK_LIMIT = 335,
- TK_LONG = 336,
- TK_LONGCHAR = 337,
- TK_LP = 338,
- TK_LSHIFT = 339,
- TK_LT = 340,
- TK_LOCALIZABLE = 341,
- TK_MATCH = 342,
- TK_MINUS = 343,
- TK_NE = 344,
- TK_NOT = 345,
- TK_NOTNULL = 346,
- TK_NULL = 347,
- TK_OBJECT = 348,
- TK_OF = 349,
- TK_OFFSET = 350,
- TK_ON = 351,
- TK_OR = 352,
- TK_ORACLE_OUTER_JOIN = 353,
- TK_ORDER = 354,
- TK_PLUS = 355,
- TK_PRAGMA = 356,
- TK_PRIMARY = 357,
- TK_RAISE = 358,
- TK_REFERENCES = 359,
- TK_REM = 360,
- TK_REPLACE = 361,
- TK_RESTRICT = 362,
- TK_ROLLBACK = 363,
- TK_ROW = 364,
- TK_RP = 365,
- TK_RSHIFT = 366,
- TK_SELECT = 367,
- TK_SEMI = 368,
- TK_SET = 369,
- TK_SHORT = 370,
- TK_SLASH = 371,
- TK_SPACE = 372,
- TK_STAR = 373,
- TK_STATEMENT = 374,
- TK_STRING = 375,
- TK_TABLE = 376,
- TK_TEMP = 377,
- TK_THEN = 378,
- TK_TRANSACTION = 379,
- TK_TRIGGER = 380,
- TK_UMINUS = 381,
- TK_UNCLOSED_STRING = 382,
- TK_UNION = 383,
- TK_UNIQUE = 384,
- TK_UPDATE = 385,
- TK_UPLUS = 386,
- TK_USING = 387,
- TK_VACUUM = 388,
- TK_VALUES = 389,
- TK_VIEW = 390,
- TK_WHEN = 391,
- TK_WHERE = 392,
- TK_WILDCARD = 393,
- COLUMN = 395,
- FUNCTION = 396,
- COMMENT = 397,
- UNCLOSED_STRING = 398,
- SPACE = 399,
- ILLEGAL = 400,
- END_OF_FILE = 401
- };
-#endif
-#define TK_ABORT 258
-#define TK_AFTER 259
-#define TK_AGG_FUNCTION 260
-#define TK_ALL 261
-#define TK_AND 262
-#define TK_AS 263
-#define TK_ASC 264
-#define TK_BEFORE 265
-#define TK_BEGIN 266
-#define TK_BETWEEN 267
-#define TK_BITAND 268
-#define TK_BITNOT 269
-#define TK_BITOR 270
-#define TK_BY 271
-#define TK_CASCADE 272
-#define TK_CASE 273
-#define TK_CHAR 274
-#define TK_CHECK 275
-#define TK_CLUSTER 276
-#define TK_COLLATE 277
-#define TK_COLUMN 278
-#define TK_COMMA 279
-#define TK_COMMENT 280
-#define TK_COMMIT 281
-#define TK_CONCAT 282
-#define TK_CONFLICT 283
-#define TK_CONSTRAINT 284
-#define TK_COPY 285
-#define TK_CREATE 286
-#define TK_DEFAULT 287
-#define TK_DEFERRABLE 288
-#define TK_DEFERRED 289
-#define TK_DELETE 290
-#define TK_DELIMITERS 291
-#define TK_DESC 292
-#define TK_DISTINCT 293
-#define TK_DOT 294
-#define TK_DROP 295
-#define TK_EACH 296
-#define TK_ELSE 297
-#define TK_END 298
-#define TK_END_OF_FILE 299
-#define TK_EQ 300
-#define TK_EXCEPT 301
-#define TK_EXPLAIN 302
-#define TK_FAIL 303
-#define TK_FLOAT 304
-#define TK_FOR 305
-#define TK_FOREIGN 306
-#define TK_FROM 307
-#define TK_FUNCTION 308
-#define TK_GE 309
-#define TK_GLOB 310
-#define TK_GROUP 311
-#define TK_GT 312
-#define TK_HAVING 313
-#define TK_HOLD 314
-#define TK_IGNORE 315
-#define TK_ILLEGAL 316
-#define TK_IMMEDIATE 317
-#define TK_IN 318
-#define TK_INDEX 319
-#define TK_INITIALLY 320
-#define TK_ID 321
-#define TK_INSERT 322
-#define TK_INSTEAD 323
-#define TK_INT 324
-#define TK_INTEGER 325
-#define TK_INTERSECT 326
-#define TK_INTO 327
-#define TK_IS 328
-#define TK_ISNULL 329
-#define TK_JOIN 330
-#define TK_JOIN_KW 331
-#define TK_KEY 332
-#define TK_LE 333
-#define TK_LIKE 334
-#define TK_LIMIT 335
-#define TK_LONG 336
-#define TK_LONGCHAR 337
-#define TK_LP 338
-#define TK_LSHIFT 339
-#define TK_LT 340
-#define TK_LOCALIZABLE 341
-#define TK_MATCH 342
-#define TK_MINUS 343
-#define TK_NE 344
-#define TK_NOT 345
-#define TK_NOTNULL 346
-#define TK_NULL 347
-#define TK_OBJECT 348
-#define TK_OF 349
-#define TK_OFFSET 350
-#define TK_ON 351
-#define TK_OR 352
-#define TK_ORACLE_OUTER_JOIN 353
-#define TK_ORDER 354
-#define TK_PLUS 355
-#define TK_PRAGMA 356
-#define TK_PRIMARY 357
-#define TK_RAISE 358
-#define TK_REFERENCES 359
-#define TK_REM 360
-#define TK_REPLACE 361
-#define TK_RESTRICT 362
-#define TK_ROLLBACK 363
-#define TK_ROW 364
-#define TK_RP 365
-#define TK_RSHIFT 366
-#define TK_SELECT 367
-#define TK_SEMI 368
-#define TK_SET 369
-#define TK_SHORT 370
-#define TK_SLASH 371
-#define TK_SPACE 372
-#define TK_STAR 373
-#define TK_STATEMENT 374
-#define TK_STRING 375
-#define TK_TABLE 376
-#define TK_TEMP 377
-#define TK_THEN 378
-#define TK_TRANSACTION 379
-#define TK_TRIGGER 380
-#define TK_UMINUS 381
-#define TK_UNCLOSED_STRING 382
-#define TK_UNION 383
-#define TK_UNIQUE 384
-#define TK_UPDATE 385
-#define TK_UPLUS 386
-#define TK_USING 387
-#define TK_VACUUM 388
-#define TK_VALUES 389
-#define TK_VIEW 390
-#define TK_WHEN 391
-#define TK_WHERE 392
-#define TK_WILDCARD 393
-#define COLUMN 395
-#define FUNCTION 396
-#define COMMENT 397
-#define UNCLOSED_STRING 398
-#define SPACE 399
-#define ILLEGAL 400
-#define END_OF_FILE 401
-
-
-
-
-#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
-#line 74 "./sql.y"
-typedef union YYSTYPE {
+#ifndef YYSTYPE
+typedef union
+{
struct sql_str str;
LPWSTR string;
- string_list *column_list;
- value_list *val_list;
+ column_info *column_list;
MSIVIEW *query;
struct expr *expr;
USHORT column_type;
- create_col_info *column_info;
- column_assignment update_col_info;
-} YYSTYPE;
-/* Line 1252 of yacc.c. */
-#line 339 "sql.tab.h"
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
+ int integer;
+} yystype;
+# define YYSTYPE yystype
# define YYSTYPE_IS_TRIVIAL 1
#endif
+# define TK_ABORT 257
+# define TK_AFTER 258
+# define TK_AGG_FUNCTION 259
+# define TK_ALL 260
+# define TK_AND 261
+# define TK_AS 262
+# define TK_ASC 263
+# define TK_BEFORE 264
+# define TK_BEGIN 265
+# define TK_BETWEEN 266
+# define TK_BITAND 267
+# define TK_BITNOT 268
+# define TK_BITOR 269
+# define TK_BY 270
+# define TK_CASCADE 271
+# define TK_CASE 272
+# define TK_CHAR 273
+# define TK_CHECK 274
+# define TK_CLUSTER 275
+# define TK_COLLATE 276
+# define TK_COLUMN 277
+# define TK_COMMA 278
+# define TK_COMMENT 279
+# define TK_COMMIT 280
+# define TK_CONCAT 281
+# define TK_CONFLICT 282
+# define TK_CONSTRAINT 283
+# define TK_COPY 284
+# define TK_CREATE 285
+# define TK_DEFAULT 286
+# define TK_DEFERRABLE 287
+# define TK_DEFERRED 288
+# define TK_DELETE 289
+# define TK_DELIMITERS 290
+# define TK_DESC 291
+# define TK_DISTINCT 292
+# define TK_DOT 293
+# define TK_DROP 294
+# define TK_EACH 295
+# define TK_ELSE 296
+# define TK_END 297
+# define TK_END_OF_FILE 298
+# define TK_EQ 299
+# define TK_EXCEPT 300
+# define TK_EXPLAIN 301
+# define TK_FAIL 302
+# define TK_FLOAT 303
+# define TK_FOR 304
+# define TK_FOREIGN 305
+# define TK_FROM 306
+# define TK_FUNCTION 307
+# define TK_GE 308
+# define TK_GLOB 309
+# define TK_GROUP 310
+# define TK_GT 311
+# define TK_HAVING 312
+# define TK_HOLD 313
+# define TK_IGNORE 314
+# define TK_ILLEGAL 315
+# define TK_IMMEDIATE 316
+# define TK_IN 317
+# define TK_INDEX 318
+# define TK_INITIALLY 319
+# define TK_ID 320
+# define TK_INSERT 321
+# define TK_INSTEAD 322
+# define TK_INT 323
+# define TK_INTEGER 324
+# define TK_INTERSECT 325
+# define TK_INTO 326
+# define TK_IS 327
+# define TK_ISNULL 328
+# define TK_JOIN 329
+# define TK_JOIN_KW 330
+# define TK_KEY 331
+# define TK_LE 332
+# define TK_LIKE 333
+# define TK_LIMIT 334
+# define TK_LONG 335
+# define TK_LONGCHAR 336
+# define TK_LP 337
+# define TK_LSHIFT 338
+# define TK_LT 339
+# define TK_LOCALIZABLE 340
+# define TK_MATCH 341
+# define TK_MINUS 342
+# define TK_NE 343
+# define TK_NOT 344
+# define TK_NOTNULL 345
+# define TK_NULL 346
+# define TK_OBJECT 347
+# define TK_OF 348
+# define TK_OFFSET 349
+# define TK_ON 350
+# define TK_OR 351
+# define TK_ORACLE_OUTER_JOIN 352
+# define TK_ORDER 353
+# define TK_PLUS 354
+# define TK_PRAGMA 355
+# define TK_PRIMARY 356
+# define TK_RAISE 357
+# define TK_REFERENCES 358
+# define TK_REM 359
+# define TK_REPLACE 360
+# define TK_RESTRICT 361
+# define TK_ROLLBACK 362
+# define TK_ROW 363
+# define TK_RP 364
+# define TK_RSHIFT 365
+# define TK_SELECT 366
+# define TK_SEMI 367
+# define TK_SET 368
+# define TK_SHORT 369
+# define TK_SLASH 370
+# define TK_SPACE 371
+# define TK_STAR 372
+# define TK_STATEMENT 373
+# define TK_STRING 374
+# define TK_TABLE 375
+# define TK_TEMP 376
+# define TK_THEN 377
+# define TK_TRANSACTION 378
+# define TK_TRIGGER 379
+# define TK_UMINUS 380
+# define TK_UNCLOSED_STRING 381
+# define TK_UNION 382
+# define TK_UNIQUE 383
+# define TK_UPDATE 384
+# define TK_UPLUS 385
+# define TK_USING 386
+# define TK_VACUUM 387
+# define TK_VALUES 388
+# define TK_VIEW 389
+# define TK_WHEN 390
+# define TK_WHERE 391
+# define TK_WILDCARD 392
+# define END_OF_FILE 393
+# define ILLEGAL 394
+# define SPACE 395
+# define UNCLOSED_STRING 396
+# define COMMENT 397
+# define FUNCTION 398
+# define COLUMN 399
-
-
-
+#endif /* not BISON_SQL_TAB_H */
#include "query.h"\r
#include "wine/list.h"\r
#include "wine/debug.h"\r
-#include "wine/unicode.h"\r
\r
#define YYLEX_PARAM info\r
#define YYPARSE_PARAM info\r
static int SQL_lex( void *SQL_lval, SQL_input *info );\r
\r
static void *parser_alloc( void *info, unsigned int sz );\r
+static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column );\r
\r
-static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys);\r
+static BOOL SQL_MarkPrimaryKeys( column_info *cols, column_info *keys);\r
\r
static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r );\r
-static struct expr * EXPR_column( void *info, LPWSTR column );\r
-static struct expr * EXPR_ival( void *info, struct sql_str *, int sign );\r
+static struct expr * EXPR_column( void *info, column_info *column );\r
+static struct expr * EXPR_ival( void *info, int val );\r
static struct expr * EXPR_sval( void *info, struct sql_str * );\r
static struct expr * EXPR_wildcard( void *info );\r
\r
{\r
struct sql_str str;\r
LPWSTR string;\r
- string_list *column_list;\r
- value_list *val_list;\r
+ column_info *column_list;\r
MSIVIEW *query;\r
struct expr *expr;\r
USHORT column_type;\r
- create_col_info *column_info;\r
- column_assignment update_col_info;\r
+ int integer;\r
}\r
\r
%token TK_ABORT TK_AFTER TK_AGG_FUNCTION TK_ALL TK_AND TK_AS TK_ASC\r
%nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION\r
COLUMN AGG_FUNCTION.\r
\r
-%type <string> column table id\r
-%type <column_list> selcollist\r
-%type <query> query from fromtable unorderedsel selectfrom\r
+%type <string> table id\r
+%type <column_list> selcollist column column_and_type column_def table_def\r
+%type <column_list> column_assignment update_assign_list constlist\r
+%type <query> query from fromtable selectfrom unorderedsel\r
%type <query> oneupdate onedelete oneselect onequery onecreate oneinsert\r
%type <expr> expr val column_val const_val\r
%type <column_type> column_type data_type data_type_l data_count\r
-%type <column_info> column_def table_def\r
-%type <val_list> constlist\r
-%type <update_col_info> column_assignment update_assign_list\r
+%type <integer> number\r
\r
%%\r
\r
SQL_input* sql = (SQL_input*) info;\r
MSIVIEW *update = NULL; \r
\r
- UPDATE_CreateView( sql->db, &update, $2, &$4, $6 );\r
+ UPDATE_CreateView( sql->db, &update, $2, $4, $6 );\r
if( !update )\r
YYABORT;\r
$$ = update;\r
;\r
\r
column_def:\r
- column_def TK_COMMA column column_type\r
+ column_def TK_COMMA column_and_type\r
{\r
- create_col_info *ci;\r
+ column_info *ci;\r
\r
for( ci = $1; ci->next; ci = ci->next )\r
;\r
\r
- ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );\r
- if( !ci->next )\r
- {\r
- /* FIXME: free $1 */\r
- YYABORT;\r
- }\r
- ci->next->colname = $3;\r
- ci->next->type = $4;\r
- ci->next->next = NULL;\r
-\r
+ ci->next = $3;\r
$$ = $1;\r
}\r
- | column column_type\r
+ | column_and_type\r
{\r
- $$ = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );\r
- if( ! $$ )\r
- YYABORT;\r
- $$->colname = $1;\r
+ $$ = $1;\r
+ }\r
+ ;\r
+\r
+column_and_type:\r
+ column column_type\r
+ {\r
+ $$ = $1;\r
$$->type = $2;\r
- $$->next = NULL;\r
}\r
;\r
\r
;\r
\r
data_count:\r
- TK_INTEGER\r
+ number\r
{\r
- SQL_input* sql = (SQL_input*) info;\r
- int val = SQL_getint(sql);\r
- if( ( val > 255 ) || ( val < 0 ) )\r
+ if( ( $1 > 255 ) || ( $1 < 0 ) )\r
YYABORT;\r
- $$ = val;\r
+ $$ = $1;\r
}\r
;\r
\r
\r
selcollist:\r
column \r
- { \r
- string_list *list;\r
-\r
- list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );\r
- if( !list )\r
- YYABORT;\r
- list->string = $1;\r
- list->next = NULL;\r
-\r
- $$ = list;\r
- TRACE("Collist %s\n",debugstr_w($$->string));\r
- }\r
| column TK_COMMA selcollist\r
{ \r
- string_list *list;\r
-\r
- list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );\r
- if( !list )\r
- YYABORT;\r
- list->string = $1;\r
- list->next = $3;\r
-\r
- $$ = list;\r
- TRACE("From table: %s\n",debugstr_w($$->string));\r
+ $1->next = $3;\r
}\r
| TK_STAR\r
{\r
constlist:\r
const_val\r
{\r
- value_list *vals;\r
-\r
- vals = parser_alloc( info, sizeof *vals );\r
- if( !vals )\r
+ $$ = parser_alloc_column( info, NULL, NULL );\r
+ if( !$$ )\r
YYABORT;\r
- vals->val = $1;\r
- vals->next = NULL;\r
- $$ = vals;\r
+ $$->val = $1;\r
}\r
| const_val TK_COMMA constlist\r
{\r
- value_list *vals;\r
-\r
- vals = parser_alloc( info, sizeof *vals );\r
- if( !vals )\r
+ $$ = parser_alloc_column( info, NULL, NULL );\r
+ if( !$$ )\r
YYABORT;\r
- vals->val = $1;\r
- vals->next = $3;\r
- $$ = vals;\r
+ $$->val = $1;\r
+ $$->next = $3;\r
}\r
;\r
\r
column_assignment\r
| column_assignment TK_COMMA update_assign_list\r
{\r
- $1.col_list->next = $3.col_list;\r
- $1.val_list->next = $3.val_list;\r
$$ = $1;\r
+ $$->next = $3;\r
}\r
;\r
\r
column_assignment:\r
column TK_EQ const_val\r
{\r
- $$.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.col_list );\r
- if( !$$.col_list )\r
- YYABORT;\r
- $$.col_list->string = $1;\r
- $$.col_list->next = NULL;\r
- $$.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.val_list );\r
- if( !$$.val_list )\r
- YYABORT;\r
- $$.val_list->val = $3;\r
- $$.val_list->next = 0;\r
+ $$ = $1;\r
+ $$->val = $3;\r
}\r
;\r
\r
const_val:\r
- TK_INTEGER\r
+ number\r
{\r
- $$ = EXPR_ival( info, &$1, 1 );\r
+ $$ = EXPR_ival( info, $1 );\r
if( !$$ )\r
YYABORT;\r
}\r
- | TK_MINUS TK_INTEGER\r
+ | TK_MINUS number\r
{\r
- $$ = EXPR_ival( info, &$2, -1 );\r
+ $$ = EXPR_ival( info, -$2 );\r
if( !$$ )\r
YYABORT;\r
}\r
column:\r
table TK_DOT id\r
{\r
- $$ = $3; /* FIXME */\r
+ $$ = parser_alloc_column( info, $1, $3 );\r
+ if( !$$ )\r
+ YYABORT;\r
}\r
| id\r
{\r
- $$ = $1;\r
+ $$ = parser_alloc_column( info, NULL, $1 );\r
+ if( !$$ )\r
+ YYABORT;\r
}\r
;\r
\r
}\r
;\r
\r
+number:\r
+ TK_INTEGER\r
+ {\r
+ $$ = SQL_getint( info );\r
+ }\r
+ ;\r
+\r
%%\r
\r
static void *parser_alloc( void *info, unsigned int sz )\r
return &mem[1];\r
}\r
\r
+static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column )\r
+{\r
+ column_info *col;\r
+\r
+ col = parser_alloc( info, sizeof (*col) );\r
+ if( col )\r
+ {\r
+ col->table = table;\r
+ col->column = column;\r
+ col->val = NULL;\r
+ col->type = 0;\r
+ col->next = NULL;\r
+ }\r
+\r
+ return col;\r
+}\r
+\r
int SQL_lex( void *SQL_lval, SQL_input *sql )\r
{\r
int token;\r
{\r
SQL_input* sql = (SQL_input*) info;\r
LPCWSTR p = &sql->command[sql->n];\r
+ INT i, r = 0;\r
+\r
+ for( i=0; i<sql->len; i++ )\r
+ {\r
+ if( '0' > p[i] || '9' < p[i] )\r
+ {\r
+ ERR("should only be numbers here!\n");\r
+ break;\r
+ }\r
+ r = (p[i]-'0') + r*10;\r
+ }\r
\r
- return atoiW( p );\r
+ return r;\r
}\r
\r
int SQL_error( const char *str )\r
return e;\r
}\r
\r
-static struct expr * EXPR_column( void *info, LPWSTR column )\r
+static struct expr * EXPR_column( void *info, column_info *column )\r
{\r
struct expr *e = parser_alloc( info, sizeof *e );\r
if( e )\r
{\r
e->type = EXPR_COLUMN;\r
- e->u.sval = column;\r
+ e->u.sval = column->column;\r
}\r
return e;\r
}\r
\r
-static struct expr * EXPR_ival( void *info, struct sql_str *str, int sign )\r
+static struct expr * EXPR_ival( void *info, int val )\r
{\r
struct expr *e = parser_alloc( info, sizeof *e );\r
if( e )\r
{\r
e->type = EXPR_IVAL;\r
- e->u.ival = atoiW( str->data ) * sign;\r
+ e->u.ival = val;\r
}\r
return e;\r
}\r
return e;\r
}\r
\r
-static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys)\r
+static BOOL SQL_MarkPrimaryKeys( column_info *cols,\r
+ column_info *keys )\r
{\r
- string_list *k;\r
+ column_info *k;\r
BOOL found = TRUE;\r
\r
for( k = keys; k && found; k = k->next )\r
{\r
- create_col_info *c;\r
+ column_info *c;\r
\r
found = FALSE;\r
for( c = cols; c && !found; c = c->next )\r
{\r
- if( lstrcmpW( k->string, c->colname ) )\r
+ if( lstrcmpW( k->column, c->column ) )\r
continue;\r
c->type |= MSITYPE_KEY;\r
found = TRUE;\r
} str;
} awstring;
+typedef struct {
+ BOOL unicode;
+ union {
+ LPCSTR a;
+ LPCWSTR w;
+ } str;
+} awcstring;
+
typedef struct tagMSISUMMARYINFO
{
MSIOBJECTHDR hdr;
}
static UINT set_prop( MSIHANDLE handle, UINT uiProperty, UINT uiDataType,
- INT iValue, FILETIME* pftValue, awstring *str )
+ INT iValue, FILETIME* pftValue, awcstring *str )
{
MSISUMMARYINFO *si;
PROPVARIANT *prop;
}
UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty,
- UINT uiDataType, INT iValue, FILETIME* pftValue, LPWSTR szValue )
+ UINT uiDataType, INT iValue, FILETIME* pftValue, LPCWSTR szValue )
{
- awstring str;
+ awcstring str;
TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType,
iValue, pftValue, debugstr_w(szValue) );
}
UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty,
- UINT uiDataType, INT iValue, FILETIME* pftValue, LPSTR szValue )
+ UINT uiDataType, INT iValue, FILETIME* pftValue, LPCSTR szValue )
{
- awstring str;
+ awcstring str;
TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType,
iValue, pftValue, debugstr_a(szValue) );
return ret;
}
-UINT read_table_from_storage( MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable)
+static UINT read_table_from_storage( MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable)
{
MSITABLE *t;
USHORT *rawdata = NULL;
table->prev = NULL;
}
-void release_table( MSIDATABASE *db, MSITABLE *table )
+static void release_table( MSIDATABASE *db, MSITABLE *table )
{
if( !table->ref_count )
ERR("Trying to destroy table with refcount 0\n");
return ERROR_SUCCESS;
}
-UINT save_table( MSIDATABASE *db, MSITABLE *t )
+static UINT save_table( MSIDATABASE *db, MSITABLE *t )
{
USHORT *rawdata = NULL, *p;
UINT rawsize, r, i, j, row_size, num_cols = 0;
return ret;
}
-UINT save_string_table( MSIDATABASE *db )
+static UINT save_string_table( MSIDATABASE *db )
{
UINT i, count, datasize, poolsize, sz, used, r, codepage;
UINT ret = ERROR_FUNCTION_FAILED;
#define STANDARD_TABLE_COUNT \
(sizeof(MSI_standard_tables)/sizeof(struct standard_table))
-UINT get_defaulttablecolumns( LPCWSTR szTable, MSICOLUMNINFO *colinfo, UINT *sz)
+static UINT get_defaulttablecolumns( LPCWSTR szTable, MSICOLUMNINFO *colinfo, UINT *sz)
{
DWORD i, n=0;
return ERROR_SUCCESS;
}
-UINT TABLE_insert_row( struct tagMSIVIEW *view, UINT *num )
+static UINT TABLE_insert_row( struct tagMSIVIEW *view, UINT *num )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
USHORT **p, *row;
** keyword. If it is a keyword, the token code of that keyword is
** returned. If the input is not a keyword, TK_ID is returned.
*/
-int sqliteKeywordCode(const WCHAR *z, int n){
+static int sqliteKeywordCode(const WCHAR *z, int n){
UINT i, len;
char buffer[0x10];
MSIVIEW view;
MSIDATABASE *db;
MSIVIEW *wv;
- value_list *vals;
+ column_info *vals;
} MSIUPDATEVIEW;
static UINT UPDATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
};
UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
- column_assignment *list, struct expr *expr )
+ column_info *columns, struct expr *expr )
{
MSIUPDATEVIEW *uv = NULL;
UINT r;
}
/* then select the columns we want */
- r = SELECT_CreateView( db, &sv, wv, list->col_list );
+ r = SELECT_CreateView( db, &sv, wv, columns );
if( r != ERROR_SUCCESS )
{
if( tv )
uv->view.ops = &update_ops;
msiobj_addref( &db->hdr );
uv->db = db;
- uv->vals = list->val_list;
+ uv->vals = columns;
uv->wv = sv;
*view = (MSIVIEW*) uv;
--- /dev/null
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2005 Aric Stewart for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Actions focused on in this module
+ *
+ * FindRelatedProducts
+ * MigrateFeatureStates (TODO)
+ * RemoveExistingProducts (TODO)
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "winreg.h"
+#include "wine/debug.h"
+#include "msidefs.h"
+#include "msipriv.h"
+#include "winuser.h"
+#include "action.h"
+#include "wine/unicode.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+extern const WCHAR szFindRelatedProducts[];
+extern const WCHAR szMigrateFeatureStates[];
+extern const WCHAR szRemoveExistingProducts[];
+
+static BOOL check_language(DWORD lang1, LPCWSTR lang2, DWORD attributes)
+{
+ DWORD langdword;
+
+ if (!lang2 || lang2[0]==0)
+ return TRUE;
+
+ langdword = atoiW(lang2);
+
+ if (attributes & msidbUpgradeAttributesLanguagesExclusive)
+ return (lang1 != langdword);
+ else
+ return (lang1 == langdword);
+}
+
+static void append_productcode(MSIPACKAGE* package, LPCWSTR action_property,
+ LPCWSTR productid)
+{
+ LPWSTR prop;
+ LPWSTR newprop;
+ DWORD len;
+ static const WCHAR separator[] = {';',0};
+
+ prop = load_dynamic_property(package, action_property, NULL);
+ if (prop)
+ len = strlenW(prop);
+ else
+ len = 0;
+
+ /*separator*/
+ len ++;
+
+ len += strlenW(productid);
+
+ /*null*/
+ len++;
+
+ newprop = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
+
+ if (prop)
+ {
+ strcpyW(newprop,prop);
+ strcatW(newprop,separator);
+ }
+ else
+ newprop[0] = 0;
+ strcatW(newprop,productid);
+
+ MSI_SetPropertyW(package, action_property, newprop);
+ TRACE("Found Related Product... %s now %s\n",debugstr_w(action_property),
+ debugstr_w(newprop));
+ HeapFree(GetProcessHeap(),0,prop);
+ HeapFree(GetProcessHeap(),0,newprop);
+}
+
+static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param)
+{
+ MSIPACKAGE *package = (MSIPACKAGE*)param;
+ WCHAR product[GUID_SIZE];
+ DWORD index = 0;
+ DWORD attributes = 0;
+ DWORD sz = GUID_SIZE;
+ LPCWSTR upgrade_code;
+ HKEY hkey = 0;
+ UINT rc = ERROR_SUCCESS;
+ MSIRECORD *uirow;
+
+ upgrade_code = MSI_RecordGetString(rec,1);
+
+ rc = MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey, FALSE);
+ if (rc != ERROR_SUCCESS)
+ return ERROR_SUCCESS;
+
+ uirow = MSI_CreateRecord(1);
+ attributes = MSI_RecordGetInteger(rec,5);
+
+ while (rc == ERROR_SUCCESS)
+ {
+ rc = RegEnumValueW(hkey, index, product, &sz, NULL, NULL, NULL, NULL);
+ TRACE("Looking at (%li) %s\n",index,debugstr_w(product));
+ if (rc == ERROR_SUCCESS)
+ {
+ WCHAR productid[GUID_SIZE];
+ LPCWSTR ver;
+ LPCWSTR language;
+ LPCWSTR action_property;
+ DWORD check = 0x00000000;
+ DWORD comp_ver = 0x00000000;
+ DWORD sz = 0x100;
+ HKEY hukey;
+ INT r;
+ static const WCHAR szVersion[] =
+ {'V','e','r','s','i','o','n',0};
+ static const WCHAR szLanguage[] =
+ {'L','a','n','g','u','a','g','e',0};
+
+ unsquash_guid(product,productid);
+ rc = MSIREG_OpenUserProductsKey(productid, &hukey, FALSE);
+ if (rc != ERROR_SUCCESS)
+ {
+ rc = ERROR_SUCCESS;
+ index ++;
+ continue;
+ }
+
+ sz = sizeof(DWORD);
+ RegQueryValueExW(hukey, szVersion, NULL, NULL, (LPBYTE)&check,
+ &sz);
+ /* check min */
+ ver = MSI_RecordGetString(rec,2);
+ comp_ver = build_version_dword(ver);
+ r = check - comp_ver;
+ if (r < 0 || (r == 0 && !(attributes &
+ msidbUpgradeAttributesVersionMinInclusive)))
+ {
+ RegCloseKey(hukey);
+ index ++;
+ continue;
+ }
+
+ /* check max */
+ ver = MSI_RecordGetString(rec,3);
+ comp_ver = build_version_dword(ver);
+ r = check - comp_ver;
+ if (r > 0 || (r == 0 && !(attributes &
+ msidbUpgradeAttributesVersionMaxInclusive)))
+ {
+ RegCloseKey(hukey);
+ index ++;
+ continue;
+ }
+
+ /* check language*/
+ sz = sizeof(DWORD);
+ RegQueryValueExW(hukey, szLanguage, NULL, NULL, (LPBYTE)&check,
+ &sz);
+ RegCloseKey(hukey);
+ language = MSI_RecordGetString(rec,4);
+ TRACE("Checking languages 0x%lx and %s\n", check,
+ debugstr_w(language));
+ if (!check_language(check, language, attributes))
+ {
+ index ++;
+ continue;
+ }
+
+ action_property = MSI_RecordGetString(rec,7);
+ append_productcode(package,action_property,productid);
+ ui_actiondata(package,szFindRelatedProducts,uirow);
+ }
+ index ++;
+ }
+ RegCloseKey(hkey);
+ msiobj_release( &uirow->hdr);
+
+ return ERROR_SUCCESS;
+}
+
+UINT ACTION_FindRelatedProducts(MSIPACKAGE *package)
+{
+ static const WCHAR Query[] =
+ {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',
+ ' ','`','U','p','g','r','a','d','e','`',0};
+ UINT rc = ERROR_SUCCESS;
+ MSIQUERY *view;
+
+ if (package->script && package->script->FindRelatedProductsRun)
+ return ERROR_SUCCESS;
+
+ if (package->script)
+ package->script->FindRelatedProductsRun = TRUE;
+
+ rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
+ if (rc != ERROR_SUCCESS)
+ return ERROR_SUCCESS;
+
+ rc = MSI_IterateRecords(view, NULL, ITERATE_FindRelatedProducts, package);
+ msiobj_release(&view->hdr);
+
+ return rc;
+}
#include "winbase.h"
#include "winerror.h"
#include "wine/debug.h"
-#include "wine/unicode.h"
#include "msi.h"
#include "msiquery.h"
#include "objbase.h"
else if( r_str && ! l_str )
sr = -1;
else
- sr = strcmpW( l_str, r_str );
+ sr = lstrcmpW( l_str, r_str );
*val = ( cond->u.expr.op == OP_EQ && ( sr == 0 ) ) ||
( cond->u.expr.op == OP_LT && ( sr < 0 ) ) ||
extern "C" {
#endif
+#ifndef _MSI_NO_CRYPTO
+#include "wincrypt.h"
+#endif
+
typedef unsigned long MSIHANDLE;
typedef enum tagINSTALLSTATE
UINT WINAPI MsiOpenProductW(LPCWSTR, MSIHANDLE*);
#define MsiOpenProduct WINELIB_NAME_AW(MsiOpenProduct)
-UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE, LPCSTR, UINT, MSIHANDLE *);
-UINT WINAPI MsiGetSummaryInformationW(MSIHANDLE, LPCWSTR, UINT, MSIHANDLE *);
-#define MsiGetSummaryInformation WINELIB_NAME_AW(MsiGetSummaryInformation)
-
-UINT WINAPI MsiSummaryInfoGetPropertyA(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPSTR,DWORD*);
-UINT WINAPI MsiSummaryInfoGetPropertyW(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPWSTR,DWORD*);
-#define MsiSummaryInfoGetProperty WINELIB_NAME_AW(MsiSummaryInfoGetProperty)
-
-UINT WINAPI MsiSummaryInfoPersist(MSIHANDLE);
-
-UINT WINAPI MsiSummaryInfoSetPropertyA(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPSTR);
-UINT WINAPI MsiSummaryInfoSetPropertyW(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPWSTR);
-#define MsiSummaryInfoSetProperty WINELIB_NAME_AW(MsiSummaryInfoSetProperty)
-
UINT WINAPI MsiProvideComponentFromDescriptorA(LPCSTR,LPSTR,DWORD*,DWORD*);
UINT WINAPI MsiProvideComponentFromDescriptorW(LPCWSTR,LPWSTR,DWORD*,DWORD*);
#define MsiProvideComponentFromDescriptor WINELIB_NAME_AW(MsiProvideComponentFromDescriptor)
USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR, LPWSTR, DWORD*, LPWSTR, DWORD*, LPWSTR, DWORD*);
#define MsiGetUserInfo WINELIB_NAME_AW(MsiGetUserInfo)
-UINT WINAPI MsiCollectUserInfoA( LPCSTR );
-UINT WINAPI MsiCollectUserInfoW( LPCWSTR );
+UINT WINAPI MsiCollectUserInfoA(LPCSTR);
+UINT WINAPI MsiCollectUserInfoW(LPCWSTR);
#define MsiCollectUserInfo WINELIB_NAME_AW(MsiCollectUserInfo)
+UINT WINAPI MsiReinstallFeatureA(LPCSTR, LPCSTR, DWORD);
+UINT WINAPI MsiReinstallFeatureW(LPCWSTR, LPCWSTR, DWORD);
+#define MsiReinstallFeature WINELIB_NAME_AW(MsiReinstallFeature)
+
+UINT WINAPI MsiGetShortcutTargetA(LPCSTR, LPSTR, LPSTR, LPSTR);
+UINT WINAPI MsiGetShortcutTargetW(LPCWSTR, LPWSTR, LPWSTR, LPWSTR);
+#define MsiGetShortcutTarget WINELIB_NAME_AW(MsiGetShortcutTarget)
+
+INSTALLSTATE WINAPI MsiUseFeatureW(LPCWSTR, LPCWSTR);
+INSTALLSTATE WINAPI MsiUseFeatureA(LPCSTR, LPCSTR);
+#define MsiUseFeature WINELIB_NAME_AW(MsiUseFeature)
+
+INSTALLSTATE WINAPI MsiUseFeatureExW(LPCWSTR, LPCWSTR, DWORD, DWORD);
+INSTALLSTATE WINAPI MsiUseFeatureExA(LPCSTR, LPCSTR, DWORD, DWORD);
+#define MsiUseFeatureEx WINELIB_NAME_AW(MsiUseFeatureEx)
+
+HRESULT WINAPI MsiGetFileSignatureInformationA(LPCSTR, DWORD, PCCERT_CONTEXT*, BYTE*, DWORD*);
+HRESULT WINAPI MsiGetFileSignatureInformationW(LPCWSTR, DWORD, PCCERT_CONTEXT*, BYTE*, DWORD*);
+#define MsiGetFileSignatureInformation WINELIB_NAME_AW(MsiGetFileSignatureInformation)
+
+INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR, LPSTR, DWORD *);
+INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR, LPWSTR, DWORD *);
+#define MsiLocateComponent WINELIB_NAME_AW(MsiLocateComponent)
+
/* Non Unicode */
UINT WINAPI MsiCloseHandle(MSIHANDLE);
UINT WINAPI MsiCloseAllHandles(void);
extern "C" {
#endif
+enum msidbUpgradeAttributes {
+ msidbUpgradeAttributesMigrateFeatures = 0x0000001,
+ msidbUpgradeAttributesOnlyDetect = 0x00000002,
+ msidbUpgradeAttributesIgnoreRemoveFailure = 0x00000004,
+ msidbUpgradeAttributesVersionMinInclusive = 0x00000100,
+ msidbUpgradeAttributesVersionMaxInclusive = 0x00000200,
+ msidbUpgradeAttributesLanguagesExclusive = 0x00000400
+};
+
enum msidbFileAttributes {
msidbFileAttributesReadOnly = 0x00000001,
msidbFileAttributesHidden = 0x00000002,
msidbDialogAttributesError = 0x00010000
};
+enum msidbControlAttributes {
+ msidbControlAttributesVisible = 0x00000001,
+ msidbControlAttributesEnabled = 0x00000002,
+ msidbControlAttributesSunken = 0x00000004,
+ msidbControlAttributesIndirect = 0x00000008,
+ msidbControlAttributesInteger = 0x00000010,
+ msidbControlAttributesRTLRO = 0x00000020,
+ msidbControlAttributesRightAligned = 0x00000040,
+ msidbControlAttributesLeftScroll = 0x00000080,
+ msidbControlAttributesBiDi = 0x000000c0,
+
+ msidbControlAttributesTransparent = 0x00010000,
+ msidbControlAttributesNoPrefix = 0x00020000,
+ msidbControlAttributesNoWrap = 0x00040000,
+ msidbControlAttributesFormatSize = 0x00080000,
+ msidbControlAttributesUsersLanguage = 0x00100000,
+
+ msidbControlAttributesMultiline = 0x00010000,
+ msidbControlAttributesPasswordInput = 0x00200000,
+
+ msidbControlAttributesProgress95 = 0x00010000,
+
+ msidbControlAttributesRemovableVolume = 0x00010000,
+ msidbControlAttributesFixedVolume = 0x00020000,
+ msidbControlAttributesRemoteVolume = 0x00040000,
+ msidbControlAttributesCDROMVolume = 0x00080000,
+ msidbControlAttributesRAMdiskVolume = 0x00100000,
+ msidbControlAttributesFloppyVolume = 0x00200000,
+ msidbControlShowRollbackCost = 0x00400000,
+
+ msidbControlAttributesSorted = 0x00010000,
+ msidbControlAttributesComboList = 0x00020000,
+
+ msidbControlAttributesImageHandle = 0x00010000,
+ msidbControlAttributesPushLike = 0x00020000,
+ msidbControlAttributesBitmap = 0x00040000,
+ msidbControlAttributesIcon = 0x00080000,
+ msidbControlAttributesFixedSize = 0x00100000,
+ msidbControlAttributesIconSize16 = 0x00200000,
+ msidbControlAttributesIconSize32 = 0x00400000,
+ msidbControlAttributesIconSize48 = 0x00600000,
+
+ msidbControlAttributesHasBorder = 0x01000000,
+};
+
enum msidbTextStyleStyleBits
{
msidbTextStyleStyleBitsBold = 0x00000001,
MSIMODIFY_VALIDATE_DELETE = 11
} MSIMODIFY;
-#define MSI_NULL_INTEGER 0x80000000
-
#define MSIDBOPEN_READONLY (LPCTSTR)0
#define MSIDBOPEN_TRANSACT (LPCTSTR)1
#define MSIDBOPEN_DIRECT (LPCTSTR)2
MSIRUNMODE_COMMIT = 18
} MSIRUNMODE;
+typedef enum tagMSIDBERROR
+{
+ MSIDBERROR_INVALIDARG = -3,
+ MSIDBERROR_MOREDATA = -2,
+ MSIDBERROR_FUNCTIONERROR = -1,
+ MSIDBERROR_NOERROR = 0,
+ MSIDBERROR_DUPLICATEKEY = 1,
+ MSIDBERROR_REQUIRED = 2,
+ MSIDBERROR_BADLINK = 3,
+ MSIDBERROR_OVERFLOW = 4,
+ MSIDBERROR_UNDERFLOW = 5,
+ MSIDBERROR_NOTINSET = 6,
+ MSIDBERROR_BADVERSION = 7,
+ MSIDBERROR_BADCASE = 8,
+ MSIDBERROR_BADGUID = 9,
+ MSIDBERROR_BADWILDCARD = 10,
+ MSIDBERROR_BADIDENTIFIER = 11,
+ MSIDBERROR_BADLANGUAGE = 12,
+ MSIDBERROR_BADFILENAME = 13,
+ MSIDBERROR_BADPATH = 14,
+ MSIDBERROR_BADCONDITION = 15,
+ MSIDBERROR_BADFORMATTED = 16,
+ MSIDBERROR_BADTEMPLATE = 17,
+ MSIDBERROR_BADDEFAULTDIR = 18,
+ MSIDBERROR_BADREGPATH = 19,
+ MSIDBERROR_BADCUSTOMSOURCE = 20,
+ MSIDBERROR_BADPROPERTY = 21,
+ MSIDBERROR_MISSINGDATA = 22,
+ MSIDBERROR_BADCATEGORY = 23,
+ MSIDBERROR_BADKEYTABLE = 24,
+ MSIDBERROR_BADMAXMINVALUES = 25,
+ MSIDBERROR_BADCABINET = 26,
+ MSIDBERROR_BADSHORTCUT= 27,
+ MSIDBERROR_STRINGOVERFLOW = 28,
+ MSIDBERROR_BADLOCALIZEATTRIB = 29
+} MSIDBERROR;
+
/* view manipulation */
UINT WINAPI MsiViewFetch(MSIHANDLE,MSIHANDLE*);
UINT WINAPI MsiViewExecute(MSIHANDLE,MSIHANDLE);
UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE,LPCSTR,MSIHANDLE*);
UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE,LPCWSTR,MSIHANDLE*);
#define MsiDatabaseOpenView WINELIB_NAME_AW(MsiDatabaseOpenView)
+UINT WINAPI MsiViewGetErrorA(MSIHANDLE,LPSTR,DWORD*);
+UINT WINAPI MsiViewGetErrorW(MSIHANDLE,LPWSTR,DWORD*);
+#define MsiViewGetError WINELIB_NAME_AW(MsiViewGetError)
/* record manipulation */
MSIHANDLE WINAPI MsiCreateRecord(unsigned int);
UINT WINAPI MsiSetFeatureStateW(MSIHANDLE, LPCWSTR, INSTALLSTATE);
#define MsiSetFeatureState WINELIB_NAME_AW(MsiSetFeatureState)
+UINT WINAPI MsiPreviewDialogA(MSIHANDLE, LPCSTR);
+UINT WINAPI MsiPreviewDialogW(MSIHANDLE, LPCWSTR);
+#define MsiPreviewDialog WINELIB_NAME_AW(MsiPreviewDialog)
+
+UINT WINAPI MsiPreviewBillboardA(MSIHANDLE, LPCSTR, LPCSTR);
+UINT WINAPI MsiPreviewBillboardW(MSIHANDLE, LPCWSTR, LPCWSTR);
+#define MsiPreviewBillboard WINELIB_NAME_AW(MsiPreviewBillboard)
+
+UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE, LPCSTR, UINT, MSIHANDLE *);
+UINT WINAPI MsiGetSummaryInformationW(MSIHANDLE, LPCWSTR, UINT, MSIHANDLE *);
+#define MsiGetSummaryInformation WINELIB_NAME_AW(MsiGetSummaryInformation)
+
+UINT WINAPI MsiSummaryInfoGetPropertyA(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPSTR,DWORD*);
+UINT WINAPI MsiSummaryInfoGetPropertyW(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPWSTR,DWORD*);
+#define MsiSummaryInfoGetProperty WINELIB_NAME_AW(MsiSummaryInfoGetProperty)
+
+UINT WINAPI MsiSummaryInfoSetPropertyA(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPCSTR);
+UINT WINAPI MsiSummaryInfoSetPropertyW(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPCWSTR);
+#define MsiSummaryInfoSetProperty WINELIB_NAME_AW(MsiSummaryInfoSetProperty)
+
+UINT WINAPI MsiDatabaseExportA(MSIHANDLE, LPCSTR, LPCSTR, LPCSTR);
+UINT WINAPI MsiDatabaseExportW(MSIHANDLE, LPCWSTR, LPCWSTR, LPCWSTR);
+#define MsiDatabaseExport WINELIB_NAME_AW(MsiDatabaseExport)
+
+UINT WINAPI MsiDatabaseImportA(MSIHANDLE, LPCSTR, LPCSTR);
+UINT WINAPI MsiDatabaseImportW(MSIHANDLE, LPCWSTR, LPCWSTR);
+#define MsiDatabaseImport WINELIB_NAME_AW(MsiDatabaseImport)
+
+UINT WINAPI MsiOpenDatabaseW(LPCWSTR, LPCWSTR, MSIHANDLE*);
+UINT WINAPI MsiOpenDatabaseA(LPCSTR, LPCSTR, MSIHANDLE*);
+#define MsiOpenDatabase WINELIB_NAME_AW(MsiOpenDatabase)
+
+UINT WINAPI MsiDatabaseIsTablePersistentA(MSIHANDLE, LPSTR);
+UINT WINAPI MsiDatabaseIsTablePersistentW(MSIHANDLE, LPWSTR);
+#define MsiDatabaseIsTablePersistent WINELIB_NAME_AW(MsiDatabaseIsTablePersistent)
+
+UINT WINAPI MsiSummaryInfoPersist(MSIHANDLE);
+UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE,UINT*);
+
+UINT WINAPI MsiEnableUIPreview(MSIHANDLE, MSIHANDLE*);
BOOL WINAPI MsiGetMode(MSIHANDLE, MSIRUNMODE);
+UINT WINAPI MsiViewModify(MSIHANDLE, MSIMODIFY, MSIHANDLE);
+
#endif /* __WINE_MSIQUERY_H */