diff --git a/reactos/include/wine/msvcrt/fcntl.h b/reactos/include/wine/msvcrt/fcntl.h new file mode 100644 index 00000000000..f914f088840 --- /dev/null +++ b/reactos/include/wine/msvcrt/fcntl.h @@ -0,0 +1,10 @@ +#ifndef __WINE_MSVCRT_FCNTL_H +#define __WINE_MSVCRT_FCNTL_H + +/* + * Compatibility header + */ + +#include + +#endif /* __WINE_MSVCRT_FCNTL_H */ diff --git a/reactos/lib/msi/Makefile.in b/reactos/lib/msi/Makefile.in index 12f85fdf719..38098fab66f 100644 --- a/reactos/lib/msi/Makefile.in +++ b/reactos/lib/msi/Makefile.in @@ -4,21 +4,26 @@ SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = msi.dll IMPORTLIB = libmsi.$(IMPLIBEXT) -IMPORTS = shell32 cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32 +IMPORTS = shell32 shlwapi cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32 EXTRALIBS = -luuid $(LIBUNICODE) C_SRCS = \ action.c \ appsearch.c \ + classes.c \ create.c \ custom.c \ database.c \ delete.c \ dialog.c \ distinct.c \ + events.c \ + files.c \ format.c \ handle.c \ + helpers.c \ insert.c \ + install.c \ msi.c \ msiquery.c \ order.c \ @@ -33,6 +38,7 @@ C_SRCS = \ table.c \ tokenize.c \ update.c \ + upgrade.c \ where.c RC_SRCS = msi.rc diff --git a/reactos/lib/msi/action.c b/reactos/lib/msi/action.c index 336a4a863c1..6f6ca2e12c9 100644 --- a/reactos/lib/msi/action.c +++ b/reactos/lib/msi/action.c @@ -1,7 +1,7 @@ /* * Implementation of the Microsoft Installer (msi.dll) * - * Copyright 2004 Aric Stewart for CodeWeavers + * Copyright 2004,2005 Aric Stewart for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,7 +27,6 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/stand */ #include -#include #define COBJMACROS @@ -36,15 +35,8 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/stand #include "winerror.h" #include "winreg.h" #include "wine/debug.h" -#include "fdi.h" -#include "msi.h" -#include "msiquery.h" #include "msidefs.h" -#include "fcntl.h" -#include "objbase.h" -#include "objidl.h" #include "msipriv.h" -#include "winnls.h" #include "winuser.h" #include "shlobj.h" #include "wine/unicode.h" @@ -62,8 +54,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran); static UINT ACTION_ProcessUISequence(MSIPACKAGE *package); static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI); -static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, - LPWSTR *FilePath); /* * action handlers @@ -75,17 +65,11 @@ static UINT ACTION_CostInitialize(MSIPACKAGE *package); static UINT ACTION_CreateFolders(MSIPACKAGE *package); static UINT ACTION_CostFinalize(MSIPACKAGE *package); static UINT ACTION_FileCost(MSIPACKAGE *package); -static UINT ACTION_InstallFiles(MSIPACKAGE *package); -static UINT ACTION_DuplicateFiles(MSIPACKAGE *package); static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package); static UINT ACTION_InstallInitialize(MSIPACKAGE *package); static UINT ACTION_InstallValidate(MSIPACKAGE *package); static UINT ACTION_ProcessComponents(MSIPACKAGE *package); static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package); -static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package); -static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package); -static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package); -static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package); static UINT ACTION_RegisterUser(MSIPACKAGE *package); static UINT ACTION_CreateShortcuts(MSIPACKAGE *package); static UINT ACTION_PublishProduct(MSIPACKAGE *package); @@ -101,26 +85,18 @@ static UINT ACTION_ExecuteAction(MSIPACKAGE *package); static UINT ACTION_RegisterFonts(MSIPACKAGE *package); static UINT ACTION_PublishComponents(MSIPACKAGE *package); - /* * consts and values used */ -static const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0}; -static const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0}; -static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0}; -static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0}; -static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0}; static const WCHAR c_colon[] = {'C',':','\\',0}; -static const WCHAR szProductCode[]= - {'P','r','o','d','u','c','t','C','o','d','e',0}; -static const WCHAR cszbs[]={'\\',0}; + const static WCHAR szCreateFolders[] = {'C','r','e','a','t','e','F','o','l','d','e','r','s',0}; const static WCHAR szCostFinalize[] = {'C','o','s','t','F','i','n','a','l','i','z','e',0}; -const static WCHAR szInstallFiles[] = +const WCHAR szInstallFiles[] = {'I','n','s','t','a','l','l','F','i','l','e','s',0}; -const static WCHAR szDuplicateFiles[] = +const WCHAR szDuplicateFiles[] = {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0}; const static WCHAR szWriteRegistryValues[] = {'W','r','i','t','e','R','e','g','i','s','t','r','y', @@ -140,9 +116,9 @@ const static WCHAR szProcessComponents[] = const static WCHAR szRegisterTypeLibraries[] = {'R','e','g','i','s','t','e','r','T','y','p','e', 'L','i','b','r','a','r','i','e','s',0}; -const static WCHAR szRegisterClassInfo[] = +const WCHAR szRegisterClassInfo[] = {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0}; -const static WCHAR szRegisterProgIdInfo[] = +const WCHAR szRegisterProgIdInfo[] = {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0}; const static WCHAR szCreateShortcuts[] = {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0}; @@ -167,7 +143,7 @@ const static WCHAR szForceReboot[] = {'F','o','r','c','e','R','e','b','o','o','t',0}; const static WCHAR szResolveSource[] = {'R','e','s','o','l','v','e','S','o','u','r','c','e',0}; -const static WCHAR szAppSearch[] = +const WCHAR szAppSearch[] = {'A','p','p','S','e','a','r','c','h',0}; const static WCHAR szAllocateRegistrySpace[] = {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y', @@ -182,7 +158,7 @@ const static WCHAR szDisableRollback[] = {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0}; const static WCHAR szExecuteAction[] = {'E','x','e','c','u','t','e','A','c','t','i','o','n',0}; -const static WCHAR szFindRelatedProducts[] = +const WCHAR szFindRelatedProducts[] = {'F','i','n','d','R','e','l','a','t','e','d', 'P','r','o','d','u','c','t','s',0}; const static WCHAR szInstallAdminPackage[] = @@ -193,10 +169,10 @@ const static WCHAR szInstallSFPCatalogFile[] = 'F','i','l','e',0}; const static WCHAR szIsolateComponents[] = {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0}; -const static WCHAR szMigrateFeatureStates[] = +const WCHAR szMigrateFeatureStates[] = {'M','i','g','r','a','t','e','F','e','a','t','u','r','e', 'S','t','a','t','e','s',0}; -const static WCHAR szMoveFiles[] = +const WCHAR szMoveFiles[] = {'M','o','v','e','F','i','l','e','s',0}; const static WCHAR szMsiPublishAssemblies[] = {'M','s','i','P','u','b','l','i','s','h', @@ -208,31 +184,31 @@ const static WCHAR szInstallODBC[] = {'I','n','s','t','a','l','l','O','D','B','C',0}; const static WCHAR szInstallServices[] = {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0}; -const static WCHAR szPatchFiles[] = +const WCHAR szPatchFiles[] = {'P','a','t','c','h','F','i','l','e','s',0}; const static WCHAR szPublishComponents[] = {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0}; const static WCHAR szRegisterComPlus[] = {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0}; -const static WCHAR szRegisterExtensionInfo[] = +const WCHAR szRegisterExtensionInfo[] = {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n', 'I','n','f','o',0}; const static WCHAR szRegisterFonts[] = {'R','e','g','i','s','t','e','r','F','o','n','t','s',0}; -const static WCHAR szRegisterMIMEInfo[] = +const WCHAR szRegisterMIMEInfo[] = {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0}; const static WCHAR szRegisterUser[] = {'R','e','g','i','s','t','e','r','U','s','e','r',0}; -const static WCHAR szRemoveDuplicateFiles[] = +const WCHAR szRemoveDuplicateFiles[] = {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e', 'F','i','l','e','s',0}; const static WCHAR szRemoveEnvironmentStrings[] = {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t', 'S','t','r','i','n','g','s',0}; -const static WCHAR szRemoveExistingProducts[] = +const WCHAR szRemoveExistingProducts[] = {'R','e','m','o','v','e','E','x','i','s','t','i','n','g', 'P','r','o','d','u','c','t','s',0}; -const static WCHAR szRemoveFiles[] = +const WCHAR szRemoveFiles[] = {'R','e','m','o','v','e','F','i','l','e','s',0}; const static WCHAR szRemoveFolders[] = {'R','e','m','o','v','e','F','o','l','d','e','r','s',0}; @@ -262,19 +238,19 @@ const static WCHAR szUnpublishComponents[] = 'C','o','m','p','o','n','e','n','t','s',0}; const static WCHAR szUnpublishFeatures[] = {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0}; -const static WCHAR szUnregisterClassInfo[] = +const WCHAR szUnregisterClassInfo[] = {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s', 'I','n','f','o',0}; const static WCHAR szUnregisterComPlus[] = {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0}; -const static WCHAR szUnregisterExtensionInfo[] = +const WCHAR szUnregisterExtensionInfo[] = {'U','n','r','e','g','i','s','t','e','r', 'E','x','t','e','n','s','i','o','n','I','n','f','o',0}; const static WCHAR szUnregisterFonts[] = {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0}; -const static WCHAR szUnregisterMIMEInfo[] = +const WCHAR szUnregisterMIMEInfo[] = {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0}; -const static WCHAR szUnregisterProgIdInfo[] = +const WCHAR szUnregisterProgIdInfo[] = {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d', 'I','n','f','o',0}; const static WCHAR szUnregisterTypeLibraries[] = @@ -305,7 +281,7 @@ static struct _actions StandardActions[] = { { szDuplicateFiles, ACTION_DuplicateFiles }, { szExecuteAction, ACTION_ExecuteAction }, { szFileCost, ACTION_FileCost }, - { szFindRelatedProducts, NULL}, + { szFindRelatedProducts, ACTION_FindRelatedProducts }, { szForceReboot, ACTION_ForceReboot }, { szInstallAdminPackage, NULL}, { szInstallExecute, ACTION_InstallExecute }, @@ -371,343 +347,22 @@ static struct _actions StandardActions[] = { }; -/******************************************************** - * helper functions to get around current HACKS and such +/******************************************************** + * helper functions ********************************************************/ -inline static void reduce_to_longfilename(WCHAR* filename) + +static void ce_actiontext(MSIPACKAGE* package, LPCWSTR action) { - LPWSTR p = strchrW(filename,'|'); - if (p) - memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR)); -} - -inline static void reduce_to_shortfilename(WCHAR* filename) -{ - LPWSTR p = strchrW(filename,'|'); - if (p) - *p = 0; -} - -WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index) -{ - UINT rc; - DWORD sz; - LPWSTR ret; - - sz = 0; - if (MSI_RecordIsNull(row,index)) - return NULL; - - rc = MSI_RecordGetStringW(row,index,NULL,&sz); - - /* having an empty string is different than NULL */ - if (sz == 0) - { - ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)); - ret[0] = 0; - return ret; - } - - sz ++; - ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR)); - rc = MSI_RecordGetStringW(row,index,ret,&sz); - if (rc!=ERROR_SUCCESS) - { - ERR("Unable to load dynamic string\n"); - HeapFree(GetProcessHeap(), 0, ret); - ret = NULL; - } - return ret; -} - -LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc) -{ - DWORD sz = 0; - LPWSTR str; - UINT r; - - r = MSI_GetPropertyW(package, prop, NULL, &sz); - if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA) - { - if (rc) - *rc = r; - return NULL; - } - sz++; - str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR)); - r = MSI_GetPropertyW(package, prop, str, &sz); - if (r != ERROR_SUCCESS) - { - HeapFree(GetProcessHeap(),0,str); - str = NULL; - } - if (rc) - *rc = r; - return str; -} - -int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component ) -{ - int rc = -1; - DWORD i; - - for (i = 0; i < package->loaded_components; i++) - { - if (strcmpW(Component,package->components[i].Component)==0) - { - rc = i; - break; - } - } - return rc; -} - -int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature ) -{ - int rc = -1; - DWORD i; - - for (i = 0; i < package->loaded_features; i++) - { - if (strcmpW(Feature,package->features[i].Feature)==0) - { - rc = i; - break; - } - } - return rc; -} - -int get_loaded_file(MSIPACKAGE* package, LPCWSTR file) -{ - int rc = -1; - DWORD i; - - for (i = 0; i < package->loaded_files; i++) - { - if (strcmpW(file,package->files[i].File)==0) - { - rc = i; - break; - } - } - return rc; -} - -int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path) -{ - DWORD i; - DWORD index; - - if (!package) - return -2; - - for (i=0; i < package->loaded_files; i++) - if (strcmpW(package->files[i].File,name)==0) - return -1; - - index = package->loaded_files; - package->loaded_files++; - if (package->loaded_files== 1) - package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE)); - else - package->files = HeapReAlloc(GetProcessHeap(),0, - package->files , package->loaded_files * sizeof(MSIFILE)); - - memset(&package->files[index],0,sizeof(MSIFILE)); - - package->files[index].File = strdupW(name); - package->files[index].TargetPath = strdupW(path); - package->files[index].Temporary = TRUE; - - TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File)); - - return 0; -} - -static void remove_tracked_tempfiles(MSIPACKAGE* package) -{ - DWORD i; - - if (!package) - return; - - for (i = 0; i < package->loaded_files; i++) - { - if (package->files[i].Temporary) - { - TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath)); - DeleteFileW(package->files[i].TargetPath); - } - - } -} - -/* wrapper to resist a need for a full rewrite right now */ -DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data ) -{ - if (ptr) - { - MSIRECORD *rec = MSI_CreateRecord(1); - DWORD size = 0; - - MSI_RecordSetStringW(rec,0,ptr); - MSI_FormatRecordW(package,rec,NULL,&size); - if (size >= 0) - { - size++; - *data = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR)); - if (size > 1) - MSI_FormatRecordW(package,rec,*data,&size); - else - *data[0] = 0; - msiobj_release( &rec->hdr ); - return sizeof(WCHAR)*size; - } - msiobj_release( &rec->hdr ); - } - - *data = NULL; - return 0; -} - -/* Called when the package is being closed */ -void ACTION_free_package_structures( MSIPACKAGE* package) -{ - INT i; - - TRACE("Freeing package action data\n"); - - remove_tracked_tempfiles(package); - - /* No dynamic buffers in features */ - if (package->features && package->loaded_features > 0) - HeapFree(GetProcessHeap(),0,package->features); - - for (i = 0; i < package->loaded_folders; i++) - { - HeapFree(GetProcessHeap(),0,package->folders[i].Directory); - HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault); - HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault); - HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget); - HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource); - HeapFree(GetProcessHeap(),0,package->folders[i].Property); - } - if (package->folders && package->loaded_folders > 0) - HeapFree(GetProcessHeap(),0,package->folders); - - for (i = 0; i < package->loaded_components; i++) - HeapFree(GetProcessHeap(),0,package->components[i].FullKeypath); - - if (package->components && package->loaded_components > 0) - HeapFree(GetProcessHeap(),0,package->components); - - for (i = 0; i < package->loaded_files; i++) - { - HeapFree(GetProcessHeap(),0,package->files[i].File); - HeapFree(GetProcessHeap(),0,package->files[i].FileName); - HeapFree(GetProcessHeap(),0,package->files[i].ShortName); - HeapFree(GetProcessHeap(),0,package->files[i].Version); - HeapFree(GetProcessHeap(),0,package->files[i].Language); - HeapFree(GetProcessHeap(),0,package->files[i].SourcePath); - HeapFree(GetProcessHeap(),0,package->files[i].TargetPath); - } - - if (package->files && package->loaded_files > 0) - HeapFree(GetProcessHeap(),0,package->files); - - for (i = 0; i < package->DeferredActionCount; i++) - HeapFree(GetProcessHeap(),0,package->DeferredAction[i]); - HeapFree(GetProcessHeap(),0,package->DeferredAction); - - for (i = 0; i < package->CommitActionCount; i++) - HeapFree(GetProcessHeap(),0,package->CommitAction[i]); - HeapFree(GetProcessHeap(),0,package->CommitAction); - - HeapFree(GetProcessHeap(),0,package->PackagePath); -} - -static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d ) -{ - MSIRECORD * row; - - row = MSI_CreateRecord(4); - MSI_RecordSetInteger(row,1,a); - MSI_RecordSetInteger(row,2,b); - MSI_RecordSetInteger(row,3,c); - MSI_RecordSetInteger(row,4,d); - MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row); - msiobj_release(&row->hdr); - - msi_dialog_check_messages(NULL); -} - -static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record) -{ - static const WCHAR Query_t[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','A','c','t','i','o', 'n','T','e','x','t','`',' ', - 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=', - ' ','\'','%','s','\'',0}; - WCHAR message[1024]; - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - DWORD size; - - if (!package->LastAction || strcmpW(package->LastAction,action)) - { - rc = MSI_OpenQuery(package->db, &view, Query_t, action); - if (rc != ERROR_SUCCESS) - return; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return; - } - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return; - } - - if (MSI_RecordIsNull(row,3)) - { - msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return; - } - - /* update the cached actionformat */ - HeapFree(GetProcessHeap(),0,package->ActionFormat); - package->ActionFormat = load_dynamic_stringW(row,3); - - HeapFree(GetProcessHeap(),0,package->LastAction); - package->LastAction = strdupW(action); - - msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); - } - - MSI_RecordSetStringW(record,0,package->ActionFormat); - size = 1024; - MSI_FormatRecordW(package,record,message,&size); + static const WCHAR szActionText[] = + {'A','c','t','i','o','n','T','e','x','t',0}; + MSIRECORD *row; row = MSI_CreateRecord(1); - MSI_RecordSetStringW(row,1,message); - - MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row); + MSI_RecordSetStringW(row,1,action); + ControlEvent_FireSubscribedEvent(package,szActionText, row); msiobj_release(&row->hdr); } - static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action) { static const WCHAR template_s[]= @@ -722,44 +377,25 @@ static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action) ' ','\'','%','s','\'',0}; WCHAR message[1024]; WCHAR timet[0x100]; - UINT rc; - MSIQUERY * view; MSIRECORD * row = 0; - WCHAR *ActionText=NULL; + LPCWSTR ActionText; GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100); - rc = MSI_OpenQuery(package->db, &view, Query_t, action); - if (rc != ERROR_SUCCESS) + row = MSI_QueryGetRecord( package->db, Query_t, action ); + if (!row) return; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return; - } - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return; - } - ActionText = load_dynamic_stringW(row,2); - msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); + ActionText = MSI_RecordGetString(row,2); sprintfW(message,template_s,timet,action,ActionText); + msiobj_release(&row->hdr); row = MSI_CreateRecord(1); MSI_RecordSetStringW(row,1,message); MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row); msiobj_release(&row->hdr); - HeapFree(GetProcessHeap(),0,ActionText); } static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, @@ -791,82 +427,6 @@ static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, msiobj_release(&row->hdr); } -/* - * build_directory_name() - * - * This function is to save messing round with directory names - * It handles adding backslashes between path segments, - * and can add \ at the end of the directory name if told to. - * - * It takes a variable number of arguments. - * It always allocates a new string for the result, so make sure - * to free the return value when finished with it. - * - * The first arg is the number of path segments that follow. - * The arguments following count are a list of path segments. - * A path segment may be NULL. - * - * Path segments will be added with a \ separating them. - * A \ will not be added after the last segment, however if the - * last segment is NULL, then the last character will be a \ - * - */ -static LPWSTR build_directory_name(DWORD count, ...) -{ - DWORD sz = 1, i; - LPWSTR dir; - va_list va; - - va_start(va,count); - for(i=0; icomponents[index].Installed == check) - return FALSE; - - if (package->components[index].ActionRequest == check) - return TRUE; - else - return FALSE; -} - -static BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE* package, INT index, - INSTALLSTATE check ) -{ - if (package->features[index].Installed == check) - return FALSE; - - if (package->features[index].ActionRequest == check) - return TRUE; - else - return FALSE; -} - - /**************************************************** * TOP level entry points *****************************************************/ @@ -883,7 +443,9 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath, static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0}; MSI_SetPropertyW(package, szAction, szInstall); - package->ExecuteSequenceRun = FALSE; + + package->script = HeapAlloc(GetProcessHeap(),0,sizeof(MSISCRIPT)); + memset(package->script,0,sizeof(MSISCRIPT)); if (szPackagePath) { @@ -993,15 +555,17 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath, rc = ERROR_SUCCESS; } + package->script->CurrentlyScripting= FALSE; + /* process the ending type action */ if (rc == ERROR_SUCCESS) ACTION_PerformActionSequence(package,-1,ui); else if (rc == ERROR_INSTALL_USEREXIT) ACTION_PerformActionSequence(package,-2,ui); - else if (rc == ERROR_FUNCTION_FAILED) - ACTION_PerformActionSequence(package,-3,ui); else if (rc == ERROR_INSTALL_SUSPEND) ACTION_PerformActionSequence(package,-4,ui); + else /* failed */ + ACTION_PerformActionSequence(package,-3,ui); /* finish up running custom actions */ ACTION_FinishCustomActions(package); @@ -1011,10 +575,7 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath, static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI) { - MSIQUERY * view; - UINT rc; - WCHAR buffer[0x100]; - DWORD sz = 0x100; + UINT rc = ERROR_SUCCESS; MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', @@ -1029,67 +590,39 @@ static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI) ' ', '=',' ','%','i',0}; if (UI) - rc = MSI_OpenQuery(package->db, &view, UISeqQuery, seq); + row = MSI_QueryGetRecord(package->db, UISeqQuery, seq); else - rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq); + row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq); - if (rc == ERROR_SUCCESS) + if (row) { - rc = MSI_ViewExecute(view, 0); + LPCWSTR action, cond; - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - goto end; - } - TRACE("Running the actions\n"); - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - goto end; - } - /* check conditions */ - if (!MSI_RecordIsNull(row,2)) + cond = MSI_RecordGetString(row,2); + if (cond) { - LPWSTR cond = NULL; - cond = load_dynamic_stringW(row,2); - - if (cond) - { - /* this is a hack to skip errors in the condition code */ - if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE) - { - HeapFree(GetProcessHeap(),0,cond); - msiobj_release(&row->hdr); - goto end; - } - else - HeapFree(GetProcessHeap(),0,cond); - } + /* this is a hack to skip errors in the condition code */ + if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE) + goto end; } - sz=0x100; - rc = MSI_RecordGetStringW(row,1,buffer,&sz); - if (rc != ERROR_SUCCESS) + action = MSI_RecordGetString(row,1); + if (!action) { - ERR("Error is %x\n",rc); - msiobj_release(&row->hdr); + ERR("failed to fetch action\n"); + rc = ERROR_FUNCTION_FAILED; goto end; } if (UI) - rc = ACTION_PerformUIAction(package,buffer); + rc = ACTION_PerformUIAction(package,action); else - rc = ACTION_PerformAction(package,buffer); - msiobj_release(&row->hdr); + rc = ACTION_PerformAction(package,action,FALSE); end: - MSI_ViewClose(view); - msiobj_release(&view->hdr); + msiobj_release(&row->hdr); } else rc = ERROR_SUCCESS; @@ -1097,6 +630,51 @@ end: return rc; } +typedef struct { + MSIPACKAGE* package; + BOOL UI; +} iterate_action_param; + +static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param) +{ + iterate_action_param *iap= (iterate_action_param*)param; + UINT rc; + LPCWSTR cond, action; + + action = MSI_RecordGetString(row,1); + if (!action) + { + ERR("Error is retrieving action name\n"); + return ERROR_FUNCTION_FAILED; + } + + /* check conditions */ + cond = MSI_RecordGetString(row,2); + if (cond) + { + /* this is a hack to skip errors in the condition code */ + if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE) + { + TRACE("Skipping action: %s (condition is false)\n", + debugstr_w(action)); + return ERROR_SUCCESS; + } + } + + if (iap->UI) + rc = ACTION_PerformUIAction(iap->package,action); + else + rc = ACTION_PerformAction(iap->package,action,FALSE); + + if (rc == ERROR_FUNCTION_NOT_CALLED) + rc = ERROR_SUCCESS; + + if (rc != ERROR_SUCCESS) + ERR("Execution halted due to error (%i)\n",rc); + + return rc; +} + static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran) { MSIQUERY * view; @@ -1117,122 +695,41 @@ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran) ' ','\'', 'I','n','s','t','a','l','l', 'V','a','l','i','d','a','t','e','\'', 0}; INT seq = 0; + iterate_action_param iap; + iap.package = package; + iap.UI = FALSE; - if (package->ExecuteSequenceRun) + if (package->script->ExecuteSequenceRun) { TRACE("Execute Sequence already Run\n"); return ERROR_SUCCESS; } - package->ExecuteSequenceRun = TRUE; - + package->script->ExecuteSequenceRun = TRUE; + /* get the sequence number */ if (UIran) { - rc = MSI_DatabaseOpenViewW(package->db, IVQuery, &view); - if (rc != ERROR_SUCCESS) - return rc; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } + row = MSI_QueryGetRecord(package->db, IVQuery); + if( !row ) + return ERROR_FUNCTION_FAILED; seq = MSI_RecordGetInteger(row,1); msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); } rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq); if (rc == ERROR_SUCCESS) { - rc = MSI_ViewExecute(view, 0); + TRACE("Running the actions\n"); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - goto end; - } - - TRACE("Running the actions\n"); - - while (1) - { - WCHAR buffer[0x100]; - DWORD sz = 0x100; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - /* check conditions */ - if (!MSI_RecordIsNull(row,2)) - { - LPWSTR cond = NULL; - cond = load_dynamic_stringW(row,2); - - if (cond) - { - /* this is a hack to skip errors in the condition code */ - if (MSI_EvaluateConditionW(package, cond) == - MSICONDITION_FALSE) - { - HeapFree(GetProcessHeap(),0,cond); - msiobj_release(&row->hdr); - continue; - } - else - HeapFree(GetProcessHeap(),0,cond); - } - } - - sz=0x100; - rc = MSI_RecordGetStringW(row,1,buffer,&sz); - if (rc != ERROR_SUCCESS) - { - ERR("Error is %x\n",rc); - msiobj_release(&row->hdr); - break; - } - - rc = ACTION_PerformAction(package,buffer); - - if (rc == ERROR_FUNCTION_NOT_CALLED) - rc = ERROR_SUCCESS; - - if (rc != ERROR_SUCCESS) - { - ERR("Execution halted due to error (%i)\n",rc); - msiobj_release(&row->hdr); - break; - } - - msiobj_release(&row->hdr); - } - - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap); msiobj_release(&view->hdr); } -end: return rc; } - static UINT ACTION_ProcessUISequence(MSIPACKAGE *package) { MSIQUERY * view; @@ -1245,113 +742,70 @@ static UINT ACTION_ProcessUISequence(MSIPACKAGE *package) '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ', '`','S','e','q','u','e','n','c','e','`',0}; - + iterate_action_param iap; + + iap.package = package; + iap.UI = TRUE; + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); if (rc == ERROR_SUCCESS) { - rc = MSI_ViewExecute(view, 0); - - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - goto end; - } - TRACE("Running the actions \n"); - while (1) - { - WCHAR buffer[0x100]; - DWORD sz = 0x100; - MSIRECORD * row = 0; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - /* check conditions */ - if (!MSI_RecordIsNull(row,2)) - { - LPWSTR cond = NULL; - cond = load_dynamic_stringW(row,2); - - if (cond) - { - /* this is a hack to skip errors in the condition code */ - if (MSI_EvaluateConditionW(package, cond) == - MSICONDITION_FALSE) - { - HeapFree(GetProcessHeap(),0,cond); - msiobj_release(&row->hdr); - continue; - } - else - HeapFree(GetProcessHeap(),0,cond); - } - } - - sz=0x100; - rc = MSI_RecordGetStringW(row,1,buffer,&sz); - if (rc != ERROR_SUCCESS) - { - ERR("Error is %x\n",rc); - msiobj_release(&row->hdr); - break; - } - - rc = ACTION_PerformUIAction(package,buffer); - - if (rc == ERROR_FUNCTION_NOT_CALLED) - rc = ERROR_SUCCESS; - - if (rc != ERROR_SUCCESS) - { - ERR("Execution halted due to error (%i)\n",rc); - msiobj_release(&row->hdr); - break; - } - - msiobj_release(&row->hdr); - } - - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap); msiobj_release(&view->hdr); } -end: return rc; } /******************************************************** * ACTION helper functions and functions that perform the actions *******************************************************/ -BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, UINT* rc) +static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, + UINT* rc, BOOL force ) { BOOL ret = FALSE; - + BOOL run = force; int i; + + if (!run && !package->script->CurrentlyScripting) + run = TRUE; + + if (!run) + { + if (strcmpW(action,szInstallFinalize) == 0 || + strcmpW(action,szInstallExecute) == 0 || + strcmpW(action,szInstallExecuteAgain) == 0) + run = TRUE; + } + i = 0; while (StandardActions[i].action != NULL) { if (strcmpW(StandardActions[i].action, action)==0) { - ui_actioninfo(package, action, TRUE, 0); - ui_actionstart(package, action); - if (StandardActions[i].handler) + ce_actiontext(package, action); + if (!run) { - *rc = StandardActions[i].handler(package); + ui_actioninfo(package, action, TRUE, 0); + *rc = schedule_action(package,INSTALL_SCRIPT,action); + ui_actioninfo(package, action, FALSE, *rc); } else { - FIXME("UNHANDLED Standard Action %s\n",debugstr_w(action)); - *rc = ERROR_SUCCESS; + ui_actionstart(package, action); + if (StandardActions[i].handler) + { + *rc = StandardActions[i].handler(package); + } + else + { + FIXME("UNHANDLED Standard Action %s\n",debugstr_w(action)); + *rc = ERROR_SUCCESS; + } } - ui_actioninfo(package, action, FALSE, *rc); ret = TRUE; break; } @@ -1360,28 +814,25 @@ BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, UINT* rc) return ret; } -BOOL ACTION_HandleDialogBox(MSIPACKAGE *package, LPCWSTR dialog, UINT* rc) +static BOOL ACTION_HandleDialogBox( MSIPACKAGE *package, LPCWSTR dialog, UINT* rc ) { BOOL ret = FALSE; - /* - * for the UI when we get that working - * if (ACTION_DialogBox(package,dialog) == ERROR_SUCCESS) { *rc = package->CurrentInstallState; ret = TRUE; } - */ return ret; } -BOOL ACTION_HandleCustomAction(MSIPACKAGE* package, LPCWSTR action, UINT* rc) +static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action, + UINT* rc, BOOL force ) { BOOL ret=FALSE; UINT arc; - arc = ACTION_CustomAction(package,action,FALSE); + arc = ACTION_CustomAction(package,action, force); if (arc != ERROR_CALL_NOT_IMPLEMENTED) { @@ -1399,17 +850,17 @@ BOOL ACTION_HandleCustomAction(MSIPACKAGE* package, LPCWSTR action, UINT* rc) * But until I get write access to the database that is hard, so I am going to * hack it to see if I can get something to run. */ -UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action) +UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force) { UINT rc = ERROR_SUCCESS; BOOL handled; TRACE("Performing action (%s)\n",debugstr_w(action)); - handled = ACTION_HandleStandardAction(package, action, &rc); + handled = ACTION_HandleStandardAction(package, action, &rc, force); if (!handled) - handled = ACTION_HandleCustomAction(package, action, &rc); + handled = ACTION_HandleCustomAction(package, action, &rc, force); if (!handled) { @@ -1428,10 +879,10 @@ UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action) TRACE("Performing action (%s)\n",debugstr_w(action)); - handled = ACTION_HandleStandardAction(package, action, &rc); + handled = ACTION_HandleStandardAction(package, action, &rc,TRUE); if (!handled) - handled = ACTION_HandleCustomAction(package, action, &rc); + handled = ACTION_HandleCustomAction(package, action, &rc, FALSE); if (!handled) handled = ACTION_HandleDialogBox(package, action, &rc); @@ -1448,60 +899,51 @@ UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action) return rc; } -/*********************************************************************** - * create_full_pathW - * - * Recursively create all directories in the path. - * - * shamelessly stolen from setupapi/queue.c + +/* + * Actual Action Handlers */ -static BOOL create_full_pathW(const WCHAR *path) + +static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param) { - BOOL ret = TRUE; - int len; - WCHAR *new_path; + MSIPACKAGE *package = (MSIPACKAGE*)param; + LPCWSTR dir; + LPWSTR full_path; + MSIRECORD *uirow; + MSIFOLDER *folder; - new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) * - sizeof(WCHAR)); - - strcpyW(new_path, path); - - while((len = strlenW(new_path)) && new_path[len - 1] == '\\') - new_path[len - 1] = 0; - - while(!CreateDirectoryW(new_path, NULL)) + dir = MSI_RecordGetString(row,1); + if (!dir) { - WCHAR *slash; - DWORD last_error = GetLastError(); - if(last_error == ERROR_ALREADY_EXISTS) - break; - - if(last_error != ERROR_PATH_NOT_FOUND) - { - ret = FALSE; - break; - } - - if(!(slash = strrchrW(new_path, '\\'))) - { - ret = FALSE; - break; - } - - len = slash - new_path; - new_path[len] = 0; - if(!create_full_pathW(new_path)) - { - ret = FALSE; - break; - } - new_path[len] = '\\'; + ERR("Unable to get folder id \n"); + return ERROR_SUCCESS; } - HeapFree(GetProcessHeap(), 0, new_path); - return ret; + full_path = resolve_folder(package,dir,FALSE,FALSE,&folder); + if (!full_path) + { + ERR("Unable to resolve folder id %s\n",debugstr_w(dir)); + return ERROR_SUCCESS; + } + + TRACE("Folder is %s\n",debugstr_w(full_path)); + + /* UI stuff */ + uirow = MSI_CreateRecord(1); + MSI_RecordSetStringW(uirow,1,full_path); + ui_actiondata(package,szCreateFolders,uirow); + msiobj_release( &uirow->hdr ); + + if (folder->State == 0) + create_full_pathW(full_path); + + folder->State = 3; + + HeapFree(GetProcessHeap(),0,full_path); + return ERROR_SUCCESS; } + /* * Also we cannot enable/disable components either, so for now I am just going * to do all the directories for all the components. @@ -1515,70 +957,12 @@ static UINT ACTION_CreateFolders(MSIPACKAGE *package) '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 }; UINT rc; MSIQUERY *view; - MSIFOLDER *folder; rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view ); if (rc != ERROR_SUCCESS) return ERROR_SUCCESS; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - WCHAR dir[0x100]; - LPWSTR full_path; - DWORD sz; - MSIRECORD *row = NULL, *uirow; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - sz=0x100; - rc = MSI_RecordGetStringW(row,1,dir,&sz); - - if (rc!= ERROR_SUCCESS) - { - ERR("Unable to get folder id \n"); - msiobj_release(&row->hdr); - continue; - } - - sz = MAX_PATH; - full_path = resolve_folder(package,dir,FALSE,FALSE,&folder); - if (!full_path) - { - ERR("Unable to resolve folder id %s\n",debugstr_w(dir)); - msiobj_release(&row->hdr); - continue; - } - - TRACE("Folder is %s\n",debugstr_w(full_path)); - - /* UI stuff */ - uirow = MSI_CreateRecord(1); - MSI_RecordSetStringW(uirow,1,full_path); - ui_actiondata(package,szCreateFolders,uirow); - msiobj_release( &uirow->hdr ); - - if (folder->State == 0) - create_full_pathW(full_path); - - folder->State = 3; - - msiobj_release(&row->hdr); - HeapFree(GetProcessHeap(),0,full_path); - } - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package); msiobj_release(&view->hdr); return rc; @@ -1602,7 +986,7 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row) memset(&package->components[index],0,sizeof(MSICOMPONENT)); - sz = 96; + sz = IDENTIFIER_SIZE; MSI_RecordGetStringW(row,1,package->components[index].Component,&sz); TRACE("Loading Component %s\n", @@ -1612,7 +996,7 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row) if (!MSI_RecordIsNull(row,2)) MSI_RecordGetStringW(row,2,package->components[index].ComponentId,&sz); - sz = 96; + sz = IDENTIFIER_SIZE; MSI_RecordGetStringW(row,3,package->components[index].Directory,&sz); package->components[index].Attributes = MSI_RecordGetInteger(row,4); @@ -1620,7 +1004,7 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row) sz = 0x100; MSI_RecordGetStringW(row,5,package->components[index].Condition,&sz); - sz = 96; + sz = IDENTIFIER_SIZE; MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz); package->components[index].Installed = INSTALLSTATE_ABSENT; @@ -1632,8 +1016,68 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row) return index; } -static void load_feature(MSIPACKAGE* package, MSIRECORD * row) +typedef struct { + MSIPACKAGE *package; + INT index; + INT cnt; +} _ilfs; + +static UINT iterate_component_check(MSIRECORD *row, LPVOID param) { + _ilfs* ilfs= (_ilfs*)param; + INT c_indx; + + c_indx = load_component(ilfs->package,row); + + ilfs->package->features[ilfs->index].Components[ilfs->cnt] = c_indx; + ilfs->package->features[ilfs->index].ComponentCount ++; + TRACE("Loaded new component to index %i\n",c_indx); + + return ERROR_SUCCESS; +} + +static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param) +{ + _ilfs* ilfs= (_ilfs*)param; + LPCWSTR component; + DWORD rc; + INT c_indx; + INT cnt = ilfs->package->features[ilfs->index].ComponentCount; + MSIQUERY * view; + static const WCHAR Query[] = + {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ', + '`','C','o','m','p','o','n','e','n','t','`',' ', + 'W','H','E','R','E',' ', + '`','C','o','m','p','o','n','e','n','t','`',' ', + '=','\'','%','s','\'',0}; + + component = MSI_RecordGetString(row,1); + + /* check to see if the component is already loaded */ + c_indx = get_loaded_component(ilfs->package,component); + if (c_indx != -1) + { + TRACE("Component %s already loaded at %i\n", debugstr_w(component), + c_indx); + ilfs->package->features[ilfs->index].Components[cnt] = c_indx; + ilfs->package->features[ilfs->index].ComponentCount ++; + return ERROR_SUCCESS; + } + + rc = MSI_OpenQuery(ilfs->package->db, &view, Query, component); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + ilfs->cnt = cnt; + rc = MSI_IterateRecords(view, NULL, iterate_component_check, ilfs); + msiobj_release( &view->hdr ); + + return ERROR_SUCCESS; +} + +static UINT load_feature(MSIRECORD * row, LPVOID param) +{ + MSIPACKAGE* package = (MSIPACKAGE*)param; int index = package->loaded_features; DWORD sz; static const WCHAR Query1[] = @@ -1643,17 +1087,12 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) 'C','o','m','p','o','n','e','n','t','s','`',' ', 'W','H','E','R','E',' ', '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0}; - static const WCHAR Query2[] = - {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ', - '`','C','o','m','p','o','n','e','n','t','`',' ', - 'W','H','E','R','E',' ', - '`','C','o','m','p','o','n','e','n','t','`',' ', - '=','\'','%','s','\'',0}; MSIQUERY * view; - MSIQUERY * view2; - MSIRECORD * row2; - MSIRECORD * row3; UINT rc; + _ilfs ilfs; + + ilfs.package = package; + ilfs.index = index; /* fill in the data */ @@ -1666,12 +1105,12 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) memset(&package->features[index],0,sizeof(MSIFEATURE)); - sz = 96; + sz = IDENTIFIER_SIZE; MSI_RecordGetStringW(row,1,package->features[index].Feature,&sz); TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature)); - sz = 96; + sz = IDENTIFIER_SIZE; if (!MSI_RecordIsNull(row,2)) MSI_RecordGetStringW(row,2,package->features[index].Feature_Parent,&sz); @@ -1688,7 +1127,7 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) package->features[index].Level= MSI_RecordGetInteger(row,6); - sz = 96; + sz = IDENTIFIER_SIZE; if (!MSI_RecordIsNull(row,7)) MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz); @@ -1700,84 +1139,22 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) /* load feature components */ - rc = MSI_OpenQuery(package->db, &view, Query1, package->features[index].Feature); + rc = MSI_OpenQuery(package->db, &view, Query1, + package->features[index].Feature); if (rc != ERROR_SUCCESS) - return; - rc = MSI_ViewExecute(view,0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return; - } - while (1) - { - DWORD sz = 0x100; - WCHAR buffer[0x100]; - DWORD rc; - INT c_indx; - INT cnt = package->features[index].ComponentCount; + return ERROR_SUCCESS; - rc = MSI_ViewFetch(view,&row2); - if (rc != ERROR_SUCCESS) - break; - - sz = 0x100; - MSI_RecordGetStringW(row2,1,buffer,&sz); - - /* check to see if the component is already loaded */ - c_indx = get_loaded_component(package,buffer); - if (c_indx != -1) - { - TRACE("Component %s already loaded at %i\n", debugstr_w(buffer), - c_indx); - package->features[index].Components[cnt] = c_indx; - package->features[index].ComponentCount ++; - msiobj_release( &row2->hdr ); - continue; - } - - rc = MSI_OpenQuery(package->db, &view2, Query2, buffer); - if (rc != ERROR_SUCCESS) - { - msiobj_release( &row2->hdr ); - continue; - } - rc = MSI_ViewExecute(view2,0); - if (rc != ERROR_SUCCESS) - { - msiobj_release( &row2->hdr ); - MSI_ViewClose(view2); - msiobj_release( &view2->hdr ); - continue; - } - while (1) - { - DWORD rc; - - rc = MSI_ViewFetch(view2,&row3); - if (rc != ERROR_SUCCESS) - break; - c_indx = load_component(package,row3); - msiobj_release( &row3->hdr ); - - package->features[index].Components[cnt] = c_indx; - package->features[index].ComponentCount ++; - TRACE("Loaded new component to index %i\n",c_indx); - } - MSI_ViewClose(view2); - msiobj_release( &view2->hdr ); - msiobj_release( &row2->hdr ); - } - MSI_ViewClose(view); + MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs); msiobj_release(&view->hdr); + + return ERROR_SUCCESS; } -static UINT load_file(MSIPACKAGE* package, MSIRECORD * row) +static UINT load_file(MSIRECORD *row, LPVOID param) { + MSIPACKAGE* package = (MSIPACKAGE*)param; DWORD index = package->loaded_files; - DWORD i; - LPWSTR buffer; + LPCWSTR component; /* fill in the data */ @@ -1791,18 +1168,13 @@ static UINT load_file(MSIPACKAGE* package, MSIRECORD * row) memset(&package->files[index],0,sizeof(MSIFILE)); package->files[index].File = load_dynamic_stringW(row, 1); - buffer = load_dynamic_stringW(row, 2); - package->files[index].ComponentIndex = -1; - for (i = 0; i < package->loaded_components; i++) - if (strcmpW(package->components[i].Component,buffer)==0) - { - package->files[index].ComponentIndex = i; - break; - } + component = MSI_RecordGetString(row, 2); + package->files[index].ComponentIndex = get_loaded_component(package, + component); + if (package->files[index].ComponentIndex == -1) - ERR("Unfound Component %s\n",debugstr_w(buffer)); - HeapFree(GetProcessHeap(), 0, buffer); + ERR("Unfound Component %s\n",debugstr_w(component)); package->files[index].FileName = load_dynamic_stringW(row,3); reduce_to_longfilename(package->files[index].FileName); @@ -1827,7 +1199,6 @@ static UINT load_file(MSIPACKAGE* package, MSIRECORD * row) static UINT load_all_files(MSIPACKAGE *package) { MSIQUERY * view; - MSIRECORD * row; UINT rc; static const WCHAR Query[] = {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', @@ -1840,27 +1211,8 @@ static UINT load_all_files(MSIPACKAGE *package) rc = MSI_DatabaseOpenViewW(package->db, Query, &view); if (rc != ERROR_SUCCESS) return ERROR_SUCCESS; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return ERROR_SUCCESS; - } - while (1) - { - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - load_file(package,row); - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, load_file, package); msiobj_release(&view->hdr); return ERROR_SUCCESS; @@ -1883,7 +1235,6 @@ static UINT load_all_files(MSIPACKAGE *package) static UINT ACTION_CostInitialize(MSIPACKAGE *package) { MSIQUERY * view; - MSIRECORD * row; UINT rc; static const WCHAR Query_all[] = {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', @@ -1904,25 +1255,8 @@ static UINT ACTION_CostInitialize(MSIPACKAGE *package) rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view); if (rc != ERROR_SUCCESS) return rc; - rc = MSI_ViewExecute(view,0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - while (1) - { - DWORD rc; - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - break; - - load_feature(package,row); - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, load_feature, package); msiobj_release(&view->hdr); load_all_files(package); @@ -1930,6 +1264,31 @@ static UINT ACTION_CostInitialize(MSIPACKAGE *package) return ERROR_SUCCESS; } +static UINT execute_script(MSIPACKAGE *package, UINT script ) +{ + int i; + UINT rc = ERROR_SUCCESS; + + TRACE("Executing Script %i\n",script); + + for (i = 0; i < package->script->ActionCount[script]; i++) + { + LPWSTR action; + action = package->script->Actions[script][i]; + ui_actionstart(package, action); + TRACE("Executing Action (%s)\n",debugstr_w(action)); + rc = ACTION_PerformAction(package, action, TRUE); + HeapFree(GetProcessHeap(),0,package->script->Actions[script][i]); + if (rc != ERROR_SUCCESS) + break; + } + HeapFree(GetProcessHeap(),0,package->script->Actions[script]); + + package->script->ActionCount[script] = 0; + package->script->Actions[script] = NULL; + return rc; +} + static UINT ACTION_FileCost(MSIPACKAGE *package) { return ERROR_SUCCESS; @@ -1944,9 +1303,8 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) 'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`', ' ','=',' ','\'','%','s','\'', 0}; - UINT rc; - MSIQUERY * view; - LPWSTR ptargetdir, targetdir, parent, srcdir; + LPWSTR ptargetdir, targetdir, srcdir; + LPCWSTR parent; LPWSTR shortname = NULL; MSIRECORD * row = 0; INT index = -1; @@ -1978,26 +1336,10 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) package->folders[index].Directory = strdupW(dir); - rc = MSI_OpenQuery(package->db, &view, Query, dir); - if (rc != ERROR_SUCCESS) + row = MSI_QueryGetRecord(package->db, Query, dir); + if (!row) return -1; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return -1; - } - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return -1; - } - ptargetdir = targetdir = load_dynamic_stringW(row,3); /* split src and target dir */ @@ -2048,7 +1390,7 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) HeapFree(GetProcessHeap(), 0, ptargetdir); TRACE(" SourceDefault = %s\n",debugstr_w(package->folders[index].SourceDefault)); - parent = load_dynamic_stringW(row,2); + parent = MSI_RecordGetString(row,2); if (parent) { i = load_folder(package,parent); @@ -2060,138 +1402,16 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) } else package->folders[index].ParentIndex = -2; - HeapFree(GetProcessHeap(), 0, parent); package->folders[index].Property = load_dynamic_property(package, dir,NULL); msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); TRACE(" %s retuning on index %i\n",debugstr_w(dir),index); return index; } - -LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, - BOOL set_prop, MSIFOLDER **folder) -{ - DWORD i; - LPWSTR p, path = NULL; - - TRACE("Working to resolve %s\n",debugstr_w(name)); - - /* special resolving for Target and Source root dir */ - if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0) - { - if (!source) - { - path = load_dynamic_property(package,cszTargetDir,NULL); - if (!path) - { - path = load_dynamic_property(package,cszRootDrive,NULL); - if (set_prop) - MSI_SetPropertyW(package,cszTargetDir,path); - } - if (folder) - { - for (i = 0; i < package->loaded_folders; i++) - { - if (strcmpW(package->folders[i].Directory,name)==0) - break; - } - *folder = &(package->folders[i]); - } - return path; - } - else - { - path = load_dynamic_property(package,cszSourceDir,NULL); - if (!path) - { - path = load_dynamic_property(package,cszDatabase,NULL); - if (path) - { - p = strrchrW(path,'\\'); - if (p) - *(p+1) = 0; - } - } - if (folder) - { - for (i = 0; i < package->loaded_folders; i++) - { - if (strcmpW(package->folders[i].Directory,name)==0) - break; - } - *folder = &(package->folders[i]); - } - return path; - } - } - - for (i = 0; i < package->loaded_folders; i++) - { - if (strcmpW(package->folders[i].Directory,name)==0) - break; - } - - if (i >= package->loaded_folders) - return NULL; - - if (folder) - *folder = &(package->folders[i]); - - if (!source && package->folders[i].ResolvedTarget) - { - path = strdupW(package->folders[i].ResolvedTarget); - TRACE(" already resolved to %s\n",debugstr_w(path)); - return path; - } - else if (source && package->folders[i].ResolvedSource) - { - path = strdupW(package->folders[i].ResolvedSource); - TRACE(" (source)already resolved to %s\n",debugstr_w(path)); - return path; - } - else if (!source && package->folders[i].Property) - { - path = build_directory_name(2, package->folders[i].Property, NULL); - - TRACE(" internally set to %s\n",debugstr_w(path)); - if (set_prop) - MSI_SetPropertyW(package,name,path); - return path; - } - - if (package->folders[i].ParentIndex >= 0) - { - LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory; - - TRACE(" ! Parent is %s\n", debugstr_w(parent)); - - p = resolve_folder(package, parent, source, set_prop, NULL); - if (!source) - { - TRACE(" TargetDefault = %s\n",debugstr_w(package->folders[i].TargetDefault)); - path = build_directory_name(3, p, package->folders[i].TargetDefault, NULL); - package->folders[i].ResolvedTarget = strdupW(path); - TRACE(" resolved into %s\n",debugstr_w(path)); - if (set_prop) - MSI_SetPropertyW(package,name,path); - } - else - { - path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL); - TRACE(" (source)resolved into %s\n",debugstr_w(path)); - package->folders[i].ResolvedSource = strdupW(path); - } - HeapFree(GetProcessHeap(),0,p); - } - return path; -} - /* scan for and update current install states */ -void ACTION_UpdateInstallStates(MSIPACKAGE *package) +static void ACTION_UpdateInstallStates(MSIPACKAGE *package) { int i; LPWSTR productcode; @@ -2230,72 +1450,6 @@ void ACTION_UpdateInstallStates(MSIPACKAGE *package) } } -/* update compoennt state based on a feature change */ -void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature) -{ - int i; - INSTALLSTATE newstate; - MSIFEATURE *feature; - - i = get_loaded_feature(package,szFeature); - if (i < 0) - return; - - feature = &package->features[i]; - newstate = feature->ActionRequest; - - for( i = 0; i < feature->ComponentCount; i++) - { - MSICOMPONENT* component = &package->components[feature->Components[i]]; - - TRACE("MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)\n", - newstate, debugstr_w(component->Component), component->Installed, - component->Action, component->ActionRequest); - - if (!component->Enabled) - continue; - else - { - if (newstate == INSTALLSTATE_LOCAL) - { - component->ActionRequest = INSTALLSTATE_LOCAL; - component->Action = INSTALLSTATE_LOCAL; - } - else - { - int j,k; - - component->ActionRequest = newstate; - component->Action = newstate; - - /*if any other feature wants is local we need to set it local*/ - for (j = 0; - j < package->loaded_features && - component->ActionRequest != INSTALLSTATE_LOCAL; - j++) - { - for (k = 0; k < package->features[j].ComponentCount; k++) - if ( package->features[j].Components[k] == - feature->Components[i] ) - { - if (package->features[j].ActionRequest == - INSTALLSTATE_LOCAL) - { - TRACE("Saved by %s\n", debugstr_w(package->features[j].Feature)); - component->ActionRequest = INSTALLSTATE_LOCAL; - component->Action = INSTALLSTATE_LOCAL; - } - break; - } - } - } - } - TRACE("Result (%i): Component %s (Installed %i, Action %i, Request %i)\n", - newstate, debugstr_w(component->Component), component->Installed, - component->Action, component->ActionRequest); - } -} - static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property, INSTALLSTATE state) { @@ -2429,6 +1583,14 @@ static UINT SetFeatureStates(MSIPACKAGE *package) } } } + else + { + /* set the Preselected Property */ + static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0}; + static const WCHAR szOne[] = { '1', 0 }; + + MSI_SetPropertyW(package,szPreselected,szOne); + } /* * now we want to enable or disable components base on feature @@ -2504,6 +1666,52 @@ static UINT SetFeatureStates(MSIPACKAGE *package) return ERROR_SUCCESS; } +static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE *package = (MSIPACKAGE*)param; + LPCWSTR name; + LPWSTR path; + + name = MSI_RecordGetString(row,1); + + /* This helper function now does ALL the work */ + TRACE("Dir %s ...\n",debugstr_w(name)); + load_folder(package,name); + path = resolve_folder(package,name,FALSE,TRUE,NULL); + TRACE("resolves to %s\n",debugstr_w(path)); + HeapFree( GetProcessHeap(), 0, path); + + return ERROR_SUCCESS; +} + +static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE *package = (MSIPACKAGE*)param; + LPCWSTR Feature; + int feature_index; + + Feature = MSI_RecordGetString(row,1); + + feature_index = get_loaded_feature(package,Feature); + if (feature_index < 0) + ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature)); + else + { + LPCWSTR Condition; + Condition = MSI_RecordGetString(row,3); + + if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE) + { + int level = MSI_RecordGetInteger(row,2); + TRACE("Reseting feature %s to level %i\n", debugstr_w(Feature), + level); + package->features[feature_index].Level = level; + } + } + return ERROR_SUCCESS; +} + + /* * A lot is done in this function aside from just the costing. * The costing needs to be implemented at some point but for now I am going @@ -2539,41 +1747,8 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); if (rc == ERROR_SUCCESS) { - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - WCHAR name[0x100]; - LPWSTR path; - MSIRECORD * row = 0; - DWORD sz; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - sz=0x100; - MSI_RecordGetStringW(row,1,name,&sz); - - /* This helper function now does ALL the work */ - TRACE("Dir %s ...\n",debugstr_w(name)); - load_folder(package,name); - path = resolve_folder(package,name,FALSE,TRUE,NULL); - TRACE("resolves to %s\n",debugstr_w(path)); - HeapFree( GetProcessHeap(), 0, path); - - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories, + package); msiobj_release(&view->hdr); } @@ -2666,54 +1841,8 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view); if (rc == ERROR_SUCCESS) { - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - WCHAR Feature[0x100]; - MSIRECORD * row = 0; - DWORD sz; - int feature_index; - - rc = MSI_ViewFetch(view,&row); - - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - sz = 0x100; - MSI_RecordGetStringW(row,1,Feature,&sz); - - feature_index = get_loaded_feature(package,Feature); - if (feature_index < 0) - ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature)); - else - { - LPWSTR Condition; - Condition = load_dynamic_stringW(row,3); - - if (MSI_EvaluateConditionW(package,Condition) == - MSICONDITION_TRUE) - { - int level = MSI_RecordGetInteger(row,2); - TRACE("Reseting feature %s to level %i\n", - debugstr_w(Feature), level); - package->features[feature_index].Level = level; - } - HeapFree(GetProcessHeap(),0,Condition); - } - - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions, + package); msiobj_release(&view->hdr); } @@ -2745,686 +1874,9 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) return SetFeatureStates(package); } -/* - * This is a helper function for handling embedded cabinet media - */ -static UINT writeout_cabinet_stream(MSIPACKAGE *package, WCHAR* stream_name, - WCHAR* source) -{ - UINT rc; - USHORT* data; - UINT size; - DWORD write; - HANDLE the_file; - WCHAR tmp[MAX_PATH]; - - rc = read_raw_stream_data(package->db,stream_name,&data,&size); - if (rc != ERROR_SUCCESS) - return rc; - - write = MAX_PATH; - if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write)) - GetTempPathW(MAX_PATH,tmp); - - GetTempFileNameW(tmp,stream_name,0,source); - - track_tempfile(package,strrchrW(source,'\\'), source); - the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL); - - if (the_file == INVALID_HANDLE_VALUE) - { - ERR("Unable to create file %s\n",debugstr_w(source)); - rc = ERROR_FUNCTION_FAILED; - goto end; - } - - WriteFile(the_file,data,size,&write,NULL); - CloseHandle(the_file); - TRACE("wrote %li bytes to %s\n",write,debugstr_w(source)); -end: - HeapFree(GetProcessHeap(),0,data); - return rc; -} - - -/* Support functions for FDI functions */ -typedef struct -{ - MSIPACKAGE* package; - LPCSTR cab_path; - LPCSTR file_name; -} CabData; - -static void * cabinet_alloc(ULONG cb) -{ - return HeapAlloc(GetProcessHeap(), 0, cb); -} - -static void cabinet_free(void *pv) -{ - HeapFree(GetProcessHeap(), 0, pv); -} - -static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode) -{ - DWORD dwAccess = 0; - DWORD dwShareMode = 0; - DWORD dwCreateDisposition = OPEN_EXISTING; - switch (oflag & _O_ACCMODE) - { - case _O_RDONLY: - dwAccess = GENERIC_READ; - dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE; - break; - case _O_WRONLY: - dwAccess = GENERIC_WRITE; - dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - break; - case _O_RDWR: - dwAccess = GENERIC_READ | GENERIC_WRITE; - dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; - break; - } - if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL)) - dwCreateDisposition = CREATE_NEW; - else if (oflag & _O_CREAT) - dwCreateDisposition = CREATE_ALWAYS; - return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL, - dwCreateDisposition, 0, NULL); -} - -static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb) -{ - DWORD dwRead; - if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL)) - return dwRead; - return 0; -} - -static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb) -{ - DWORD dwWritten; - if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL)) - return dwWritten; - return 0; -} - -static int cabinet_close(INT_PTR hf) -{ - return CloseHandle((HANDLE)hf) ? 0 : -1; -} - -static long cabinet_seek(INT_PTR hf, long dist, int seektype) -{ - /* flags are compatible and so are passed straight through */ - return SetFilePointer((HANDLE)hf, dist, NULL, seektype); -} - -static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) -{ - /* FIXME: try to do more processing in this function */ - switch (fdint) - { - case fdintCOPY_FILE: - { - CabData *data = (CabData*) pfdin->pv; - ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1); - char *file; - - LPWSTR trackname; - LPWSTR trackpath; - LPWSTR tracknametmp; - static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0}; - - if (data->file_name && lstrcmpiA(data->file_name,pfdin->psz1)) - return 0; - - file = cabinet_alloc((len+1)*sizeof(char)); - strcpy(file, data->cab_path); - strcat(file, pfdin->psz1); - - TRACE("file: %s\n", debugstr_a(file)); - - /* track this file so it can be deleted if not installed */ - trackpath=strdupAtoW(file); - tracknametmp=strdupAtoW(strrchr(file,'\\')+1); - trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) + - strlenW(tmpprefix)+1) * sizeof(WCHAR)); - - strcpyW(trackname,tmpprefix); - strcatW(trackname,tracknametmp); - - track_tempfile(data->package, trackname, trackpath); - - HeapFree(GetProcessHeap(),0,trackpath); - HeapFree(GetProcessHeap(),0,trackname); - HeapFree(GetProcessHeap(),0,tracknametmp); - - return cabinet_open(file, _O_WRONLY | _O_CREAT, 0); - } - case fdintCLOSE_FILE_INFO: - { - FILETIME ft; - FILETIME ftLocal; - if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft)) - return -1; - if (!LocalFileTimeToFileTime(&ft, &ftLocal)) - return -1; - if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal)) - return -1; - - cabinet_close(pfdin->hf); - return 1; - } - default: - return 0; - } -} - -/*********************************************************************** - * extract_cabinet_file - * - * Extract files from a cab file. - */ -static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source, - const WCHAR* path, const WCHAR* file) -{ - HFDI hfdi; - ERF erf; - BOOL ret; - char *cabinet; - char *cab_path; - char *file_name; - CabData data; - - TRACE("Extracting %s (%s) to %s\n",debugstr_w(source), - debugstr_w(file), debugstr_w(path)); - - hfdi = FDICreate(cabinet_alloc, - cabinet_free, - cabinet_open, - cabinet_read, - cabinet_write, - cabinet_close, - cabinet_seek, - 0, - &erf); - if (!hfdi) - { - ERR("FDICreate failed\n"); - return FALSE; - } - - if (!(cabinet = strdupWtoA( source ))) - { - FDIDestroy(hfdi); - return FALSE; - } - if (!(cab_path = strdupWtoA( path ))) - { - FDIDestroy(hfdi); - HeapFree(GetProcessHeap(), 0, cabinet); - return FALSE; - } - - data.package = package; - data.cab_path = cab_path; - if (file) - file_name = strdupWtoA(file); - else - file_name = NULL; - data.file_name = file_name; - - ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data); - - if (!ret) - ERR("FDICopy failed\n"); - - FDIDestroy(hfdi); - - HeapFree(GetProcessHeap(), 0, cabinet); - HeapFree(GetProcessHeap(), 0, cab_path); - HeapFree(GetProcessHeap(), 0, file_name); - - return ret; -} - -static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path, - MSIFILE* file) -{ - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static WCHAR source[MAX_PATH]; - static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', - '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ', - '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=', - ' ','%', 'i',' ','O','R','D','E','R',' ','B','Y',' ', - '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0}; - WCHAR Query[1024]; - WCHAR cab[0x100]; - DWORD sz=0x100; - INT seq; - static UINT last_sequence = 0; - - if (file->Attributes & msidbFileAttributesNoncompressed) - { - TRACE("Uncompressed File, no media to ready.\n"); - return ERROR_SUCCESS; - } - - if (file->Sequence <= last_sequence) - { - TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence); - /*extract_a_cabinet_file(package, source,path,file->File); */ - return ERROR_SUCCESS; - } - - sprintfW(Query,ExecSeqQuery,file->Sequence); - - rc = MSI_DatabaseOpenViewW(package->db, Query, &view); - if (rc != ERROR_SUCCESS) - return rc; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - seq = MSI_RecordGetInteger(row,2); - last_sequence = seq; - - if (!MSI_RecordIsNull(row,4)) - { - sz=0x100; - MSI_RecordGetStringW(row,4,cab,&sz); - TRACE("Source is CAB %s\n",debugstr_w(cab)); - /* the stream does not contain the # character */ - if (cab[0]=='#') - { - writeout_cabinet_stream(package,&cab[1],source); - strcpyW(path,source); - *(strrchrW(path,'\\')+1)=0; - } - else - { - sz = MAX_PATH; - if (MSI_GetPropertyW(package, cszSourceDir, source, &sz)) - { - ERR("No Source dir defined \n"); - rc = ERROR_FUNCTION_FAILED; - } - else - { - strcpyW(path,source); - strcatW(source,cab); - /* extract the cab file into a folder in the temp folder */ - sz = MAX_PATH; - if (MSI_GetPropertyW(package, cszTempFolder,path, &sz) - != ERROR_SUCCESS) - GetTempPathW(MAX_PATH,path); - } - } - rc = !extract_a_cabinet_file(package, source,path,NULL); - } - else - { - sz = MAX_PATH; - MSI_GetPropertyW(package,cszSourceDir,source,&sz); - strcpyW(path,source); - } - msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; -} - -inline static UINT create_component_directory ( MSIPACKAGE* package, INT component) -{ - UINT rc = ERROR_SUCCESS; - MSIFOLDER *folder; - LPWSTR install_path; - - install_path = resolve_folder(package, package->components[component].Directory, - FALSE, FALSE, &folder); - if (!install_path) - return ERROR_FUNCTION_FAILED; - - /* create the path */ - if (folder->State == 0) - { - create_full_pathW(install_path); - folder->State = 2; - } - HeapFree(GetProcessHeap(), 0, install_path); - - return rc; -} - -static UINT ACTION_InstallFiles(MSIPACKAGE *package) -{ - UINT rc = ERROR_SUCCESS; - DWORD index; - MSIRECORD * uirow; - WCHAR uipath[MAX_PATH]; - - if (!package) - return ERROR_INVALID_HANDLE; - - /* increment progress bar each time action data is sent */ - ui_progress(package,1,1,0,0); - - for (index = 0; index < package->loaded_files; index++) - { - WCHAR path_to_source[MAX_PATH]; - MSIFILE *file; - - file = &package->files[index]; - - if (file->Temporary) - continue; - - - if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex, - INSTALLSTATE_LOCAL)) - { - ui_progress(package,2,file->FileSize,0,0); - TRACE("File %s is not scheduled for install\n", - debugstr_w(file->File)); - - continue; - } - - if ((file->State == 1) || (file->State == 2)) - { - LPWSTR p; - MSICOMPONENT* comp = NULL; - - TRACE("Installing %s\n",debugstr_w(file->File)); - rc = ready_media_for_file(package, path_to_source, file); - /* - * WARNING! - * our file table could change here because a new temp file - * may have been created - */ - file = &package->files[index]; - if (rc != ERROR_SUCCESS) - { - ERR("Unable to ready media\n"); - rc = ERROR_FUNCTION_FAILED; - break; - } - - create_component_directory( package, file->ComponentIndex); - - /* recalculate file paths because things may have changed */ - - if (file->ComponentIndex >= 0) - comp = &package->components[file->ComponentIndex]; - - p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL); - HeapFree(GetProcessHeap(),0,file->TargetPath); - - file->TargetPath = build_directory_name(2, p, file->FileName); - HeapFree(GetProcessHeap(),0,p); - - if (file->Attributes & msidbFileAttributesNoncompressed) - { - p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL); - file->SourcePath = build_directory_name(2, p, file->ShortName); - HeapFree(GetProcessHeap(),0,p); - } - else - file->SourcePath = build_directory_name(2, path_to_source, - file->File); - - - TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath), - debugstr_w(file->TargetPath)); - - /* the UI chunk */ - uirow=MSI_CreateRecord(9); - MSI_RecordSetStringW(uirow,1,file->File); - strcpyW(uipath,file->TargetPath); - *(strrchrW(uipath,'\\')+1)=0; - MSI_RecordSetStringW(uirow,9,uipath); - MSI_RecordSetInteger(uirow,6,file->FileSize); - ui_actiondata(package,szInstallFiles,uirow); - msiobj_release( &uirow->hdr ); - ui_progress(package,2,file->FileSize,0,0); - - - if (file->Attributes & msidbFileAttributesNoncompressed) - rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE); - else - rc = MoveFileW(file->SourcePath, file->TargetPath); - - if (!rc) - { - rc = GetLastError(); - ERR("Unable to move/copy file (%s -> %s) (error %d)\n", - debugstr_w(file->SourcePath), debugstr_w(file->TargetPath), - rc); - if (rc == ERROR_ALREADY_EXISTS && file->State == 2) - { - if (!CopyFileW(file->SourcePath,file->TargetPath,FALSE)) - ERR("Unable to copy file (%s -> %s) (error %ld)\n", - debugstr_w(file->SourcePath), - debugstr_w(file->TargetPath), GetLastError()); - if (!(file->Attributes & msidbFileAttributesNoncompressed)) - DeleteFileW(file->SourcePath); - rc = 0; - } - else if (rc == ERROR_FILE_NOT_FOUND) - { - ERR("Source File Not Found! Continuing\n"); - rc = 0; - } - else if (file->Attributes & msidbFileAttributesVital) - { - ERR("Ignoring Error and continuing (nonvital file)...\n"); - rc = 0; - } - } - else - { - file->State = 4; - rc = ERROR_SUCCESS; - } - } - } - - return rc; -} - -inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, - LPWSTR* file_source) -{ - DWORD index; - - if (!package) - return ERROR_INVALID_HANDLE; - - for (index = 0; index < package->loaded_files; index ++) - { - if (strcmpW(file_key,package->files[index].File)==0) - { - if (package->files[index].State >= 2) - { - *file_source = strdupW(package->files[index].TargetPath); - return ERROR_SUCCESS; - } - else - return ERROR_FILE_NOT_FOUND; - } - } - - return ERROR_FUNCTION_FAILED; -} - -static UINT ACTION_DuplicateFiles(MSIPACKAGE *package) -{ - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0}; - - if (!package) - return ERROR_INVALID_HANDLE; - - rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - WCHAR file_key[0x100]; - WCHAR *file_source = NULL; - WCHAR dest_name[0x100]; - LPWSTR dest_path, dest; - WCHAR component[0x100]; - INT component_index; - - DWORD sz=0x100; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - sz=0x100; - rc = MSI_RecordGetStringW(row,2,component,&sz); - if (rc != ERROR_SUCCESS) - { - ERR("Unable to get component\n"); - msiobj_release(&row->hdr); - break; - } - - component_index = get_loaded_component(package,component); - - if (!ACTION_VerifyComponentForAction(package, component_index, - INSTALLSTATE_LOCAL)) - { - TRACE("Skipping copy due to disabled component\n"); - - /* the action taken was the same as the current install state */ - package->components[component_index].Action = - package->components[component_index].Installed; - - msiobj_release(&row->hdr); - continue; - } - - package->components[component_index].Action = INSTALLSTATE_LOCAL; - - sz=0x100; - rc = MSI_RecordGetStringW(row,3,file_key,&sz); - if (rc != ERROR_SUCCESS) - { - ERR("Unable to get file key\n"); - msiobj_release(&row->hdr); - break; - } - - rc = get_file_target(package,file_key,&file_source); - - if (rc != ERROR_SUCCESS) - { - ERR("Original file unknown %s\n",debugstr_w(file_key)); - msiobj_release(&row->hdr); - HeapFree(GetProcessHeap(),0,file_source); - continue; - } - - if (MSI_RecordIsNull(row,4)) - { - strcpyW(dest_name,strrchrW(file_source,'\\')+1); - } - else - { - sz=0x100; - MSI_RecordGetStringW(row,4,dest_name,&sz); - reduce_to_longfilename(dest_name); - } - - if (MSI_RecordIsNull(row,5)) - { - LPWSTR p; - dest_path = strdupW(file_source); - p = strrchrW(dest_path,'\\'); - if (p) - *p=0; - } - else - { - WCHAR destkey[0x100]; - sz=0x100; - MSI_RecordGetStringW(row,5,destkey,&sz); - sz = 0x100; - dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL); - if (!dest_path) - { - ERR("Unable to get destination folder\n"); - msiobj_release(&row->hdr); - HeapFree(GetProcessHeap(),0,file_source); - break; - } - } - - dest = build_directory_name(2, dest_path, dest_name); - - TRACE("Duplicating file %s to %s\n",debugstr_w(file_source), - debugstr_w(dest)); - - if (strcmpW(file_source,dest)) - rc = !CopyFileW(file_source,dest,TRUE); - else - rc = ERROR_SUCCESS; - - if (rc != ERROR_SUCCESS) - ERR("Failed to copy file %s -> %s, last error %ld\n", debugstr_w(file_source), debugstr_w(dest_path), GetLastError()); - - FIXME("We should track these duplicate files as well\n"); - - msiobj_release(&row->hdr); - HeapFree(GetProcessHeap(),0,dest_path); - HeapFree(GetProcessHeap(),0,dest); - HeapFree(GetProcessHeap(),0,file_source); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; -} - - /* OK this value is "interpreted" and then formatted based on the first few characters */ -static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type, +static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type, DWORD *size) { LPSTR data = NULL; @@ -3508,7 +1960,7 @@ static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type, else { static const WCHAR szMulti[] = {'[','~',']',0}; - WCHAR *ptr; + LPCWSTR ptr; *type=REG_SZ; if (value[0]=='#') @@ -3532,11 +1984,193 @@ static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type, return data; } +static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE *package = (MSIPACKAGE*)param; + static const WCHAR szHCR[] = + {'H','K','E','Y','_','C','L','A','S','S','E','S','_', + 'R','O','O','T','\\',0}; + static const WCHAR szHCU[] = + {'H','K','E','Y','_','C','U','R','R','E','N','T','_', + 'U','S','E','R','\\',0}; + static const WCHAR szHLM[] = + {'H','K','E','Y','_','L','O','C','A','L','_', + 'M','A','C','H','I','N','E','\\',0}; + static const WCHAR szHU[] = + {'H','K','E','Y','_','U','S','E','R','S','\\',0}; + + LPSTR value_data = NULL; + HKEY root_key, hkey; + DWORD type,size; + LPWSTR deformated; + LPCWSTR szRoot, component, name, key, value; + INT component_index; + MSIRECORD * uirow; + LPWSTR uikey; + INT root; + BOOL check_first = FALSE; + UINT rc; + + ui_progress(package,2,0,0,0); + + value = NULL; + key = NULL; + uikey = NULL; + name = NULL; + + component = MSI_RecordGetString(row, 6); + component_index = get_loaded_component(package,component); + + if (!ACTION_VerifyComponentForAction(package, component_index, + INSTALLSTATE_LOCAL)) + { + TRACE("Skipping write due to disabled component %s\n", + debugstr_w(component)); + + package->components[component_index].Action = + package->components[component_index].Installed; + + return ERROR_SUCCESS; + } + + package->components[component_index].Action = INSTALLSTATE_LOCAL; + + name = MSI_RecordGetString(row, 4); + if( MSI_RecordIsNull(row,5) && name ) + { + /* null values can have special meanings */ + if (name[0]=='-' && name[1] == 0) + return ERROR_SUCCESS; + else if ((name[0]=='+' && name[1] == 0) || + (name[0] == '*' && name[1] == 0)) + name = NULL; + check_first = TRUE; + } + + root = MSI_RecordGetInteger(row,2); + key = MSI_RecordGetString(row, 3); + + /* get the root key */ + switch (root) + { + case -1: + { + static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0}; + LPWSTR all_users = load_dynamic_property(package, szALLUSER, NULL); + if (all_users && all_users[0] == '1') + { + root_key = HKEY_LOCAL_MACHINE; + szRoot = szHLM; + } + else + { + root_key = HKEY_CURRENT_USER; + szRoot = szHCU; + } + HeapFree(GetProcessHeap(),0,all_users); + } + break; + case 0: root_key = HKEY_CLASSES_ROOT; + szRoot = szHCR; + break; + case 1: root_key = HKEY_CURRENT_USER; + szRoot = szHCU; + break; + case 2: root_key = HKEY_LOCAL_MACHINE; + szRoot = szHLM; + break; + case 3: root_key = HKEY_USERS; + szRoot = szHU; + break; + default: + ERR("Unknown root %i\n",root); + root_key=NULL; + szRoot = NULL; + break; + } + if (!root_key) + return ERROR_SUCCESS; + + deformat_string(package, key , &deformated); + size = strlenW(deformated) + strlenW(szRoot) + 1; + uikey = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR)); + strcpyW(uikey,szRoot); + strcatW(uikey,deformated); + + if (RegCreateKeyW( root_key, deformated, &hkey)) + { + ERR("Could not create key %s\n",debugstr_w(deformated)); + HeapFree(GetProcessHeap(),0,deformated); + HeapFree(GetProcessHeap(),0,uikey); + return ERROR_SUCCESS; + } + HeapFree(GetProcessHeap(),0,deformated); + + value = MSI_RecordGetString(row,5); + if (value) + value_data = parse_value(package, value, &type, &size); + else + { + static const WCHAR szEmpty[] = {0}; + value_data = (LPSTR)strdupW(szEmpty); + size = 0; + type = REG_SZ; + } + + deformat_string(package, name, &deformated); + + /* get the double nulls to terminate SZ_MULTI */ + if (type == REG_MULTI_SZ) + size +=sizeof(WCHAR); + + if (!check_first) + { + TRACE("Setting value %s of %s\n",debugstr_w(deformated), + debugstr_w(uikey)); + RegSetValueExW(hkey, deformated, 0, type, value_data, size); + } + else + { + DWORD sz = 0; + rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz); + if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA) + { + TRACE("value %s of %s checked already exists\n", + debugstr_w(deformated), debugstr_w(uikey)); + } + else + { + TRACE("Checked and setting value %s of %s\n", + debugstr_w(deformated), debugstr_w(uikey)); + if (deformated || size) + RegSetValueExW(hkey, deformated, 0, type, value_data, size); + } + } + RegCloseKey(hkey); + + uirow = MSI_CreateRecord(3); + MSI_RecordSetStringW(uirow,2,deformated); + MSI_RecordSetStringW(uirow,1,uikey); + + if (type == REG_SZ) + MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data); + else + MSI_RecordSetStringW(uirow,3,value); + + ui_actiondata(package,szWriteRegistryValues,uirow); + msiobj_release( &uirow->hdr ); + + HeapFree(GetProcessHeap(),0,value_data); + HeapFree(GetProcessHeap(),0,deformated); + HeapFree(GetProcessHeap(),0,uikey); + + return ERROR_SUCCESS; +} + static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) { UINT rc; MSIQUERY * view; - MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', '`','R','e','g','i','s','t','r','y','`',0 }; @@ -3548,207 +2182,19 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) if (rc != ERROR_SUCCESS) return ERROR_SUCCESS; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - /* increment progress bar each time action data is sent */ ui_progress(package,1,REG_PROGRESS_VALUE,1,0); - while (1) - { - static const WCHAR szHCR[] = - {'H','K','E','Y','_','C','L','A','S','S','E','S','_', - 'R','O','O','T','\\',0}; - static const WCHAR szHCU[] = - {'H','K','E','Y','_','C','U','R','R','E','N','T','_', - 'U','S','E','R','\\',0}; - static const WCHAR szHLM[] = - {'H','K','E','Y','_','L','O','C','A','L','_', - 'M','A','C','H','I','N','E','\\',0}; - static const WCHAR szHU[] = - {'H','K','E','Y','_','U','S','E','R','S','\\',0}; + rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package); - LPSTR value_data = NULL; - HKEY root_key, hkey; - DWORD type,size; - LPWSTR value, key, name, component, deformated; - LPCWSTR szRoot; - INT component_index; - MSIRECORD * uirow; - LPWSTR uikey; - INT root; - BOOL check_first = FALSE; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - ui_progress(package,2,0,0,0); - - value = NULL; - key = NULL; - uikey = NULL; - name = NULL; - - component = load_dynamic_stringW(row, 6); - component_index = get_loaded_component(package,component); - - if (!ACTION_VerifyComponentForAction(package, component_index, - INSTALLSTATE_LOCAL)) - { - TRACE("Skipping write due to disabled component\n"); - msiobj_release(&row->hdr); - - package->components[component_index].Action = - package->components[component_index].Installed; - - goto next; - } - - package->components[component_index].Action = INSTALLSTATE_LOCAL; - - name = load_dynamic_stringW(row, 4); - if( MSI_RecordIsNull(row,5) && name ) - { - /* null values can have special meanings */ - if (name[0]=='-' && name[1] == 0) - { - msiobj_release(&row->hdr); - goto next; - } - else if ((name[0]=='+' && name[1] == 0) || - (name[0] == '*' && name[1] == 0)) - { - HeapFree(GetProcessHeap(),0,name); - name = NULL; - check_first = TRUE; - } - } - - root = MSI_RecordGetInteger(row,2); - key = load_dynamic_stringW(row, 3); - - - /* get the root key */ - switch (root) - { - case 0: root_key = HKEY_CLASSES_ROOT; - szRoot = szHCR; - break; - case 1: root_key = HKEY_CURRENT_USER; - szRoot = szHCU; - break; - case 2: root_key = HKEY_LOCAL_MACHINE; - szRoot = szHLM; - break; - case 3: root_key = HKEY_USERS; - szRoot = szHU; - break; - default: - ERR("Unknown root %i\n",root); - root_key=NULL; - szRoot = NULL; - break; - } - if (!root_key) - { - msiobj_release(&row->hdr); - goto next; - } - - deformat_string(package, key , &deformated); - size = strlenW(deformated) + strlenW(szRoot) + 1; - uikey = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR)); - strcpyW(uikey,szRoot); - strcatW(uikey,deformated); - - if (RegCreateKeyW( root_key, deformated, &hkey)) - { - ERR("Could not create key %s\n",debugstr_w(deformated)); - msiobj_release(&row->hdr); - HeapFree(GetProcessHeap(),0,deformated); - goto next; - } - HeapFree(GetProcessHeap(),0,deformated); - - value = load_dynamic_stringW(row,5); - if (value) - value_data = parse_value(package, value, &type, &size); - else - { - static const WCHAR szEmpty[] = {0}; - value_data = (LPSTR)strdupW(szEmpty); - size = 0; - type = REG_SZ; - } - - deformat_string(package, name, &deformated); - - /* get the double nulls to terminate SZ_MULTI */ - if (type == REG_MULTI_SZ) - size +=sizeof(WCHAR); - - if (!check_first) - { - TRACE("Setting value %s of %s\n",debugstr_w(deformated), - debugstr_w(uikey)); - RegSetValueExW(hkey, deformated, 0, type, value_data, size); - } - else - { - DWORD sz = 0; - rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz); - if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA) - { - TRACE("value %s of %s checked already exists\n", - debugstr_w(deformated), debugstr_w(uikey)); - } - else - { - TRACE("Checked and setting value %s of %s\n", - debugstr_w(deformated), debugstr_w(uikey)); - RegSetValueExW(hkey, deformated, 0, type, value_data, size); - } - } - - uirow = MSI_CreateRecord(3); - MSI_RecordSetStringW(uirow,2,deformated); - MSI_RecordSetStringW(uirow,1,uikey); - - if (type == REG_SZ) - MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data); - else - MSI_RecordSetStringW(uirow,3,value); - - ui_actiondata(package,szWriteRegistryValues,uirow); - msiobj_release( &uirow->hdr ); - - HeapFree(GetProcessHeap(),0,value_data); - HeapFree(GetProcessHeap(),0,value); - HeapFree(GetProcessHeap(),0,deformated); - - msiobj_release(&row->hdr); - RegCloseKey(hkey); -next: - HeapFree(GetProcessHeap(),0,uikey); - HeapFree(GetProcessHeap(),0,key); - HeapFree(GetProcessHeap(),0,name); - HeapFree(GetProcessHeap(),0,component); - } - MSI_ViewClose(view); msiobj_release(&view->hdr); return rc; } static UINT ACTION_InstallInitialize(MSIPACKAGE *package) { + package->script->CurrentlyScripting = TRUE; + return ERROR_SUCCESS; } @@ -3810,16 +2256,36 @@ static UINT ACTION_InstallValidate(MSIPACKAGE *package) return ERROR_SUCCESS; } +static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE* package = (MSIPACKAGE*)param; + LPCWSTR cond = NULL; + LPCWSTR message = NULL; + static const WCHAR title[]= + {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0}; + + cond = MSI_RecordGetString(row,1); + + if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE) + { + LPWSTR deformated; + message = MSI_RecordGetString(row,2); + deformat_string(package,message,&deformated); + MessageBoxW(NULL,deformated,title,MB_OK); + HeapFree(GetProcessHeap(),0,deformated); + return ERROR_FUNCTION_FAILED; + } + + return ERROR_SUCCESS; +} + static UINT ACTION_LaunchConditions(MSIPACKAGE *package) { UINT rc; MSIQUERY * view = NULL; - MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0}; - static const WCHAR title[]= - {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0}; TRACE("Checking launch conditions\n"); @@ -3827,44 +2293,9 @@ static UINT ACTION_LaunchConditions(MSIPACKAGE *package) if (rc != ERROR_SUCCESS) return ERROR_SUCCESS; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - rc = ERROR_SUCCESS; - while (rc == ERROR_SUCCESS) - { - LPWSTR cond = NULL; - LPWSTR message = NULL; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - cond = load_dynamic_stringW(row,1); - - if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE) - { - LPWSTR deformated; - message = load_dynamic_stringW(row,2); - deformat_string(package,message,&deformated); - MessageBoxW(NULL,deformated,title,MB_OK); - HeapFree(GetProcessHeap(),0,message); - HeapFree(GetProcessHeap(),0,deformated); - rc = ERROR_FUNCTION_FAILED; - } - HeapFree(GetProcessHeap(),0,cond); - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package); msiobj_release(&view->hdr); + return rc; } @@ -3880,10 +2311,10 @@ static LPWSTR resolve_keypath( MSIPACKAGE* package, INT } if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath) { - MSIQUERY * view; MSIRECORD * row = 0; - UINT rc,root,len; - LPWSTR key,deformated,buffer,name,deformated_name; + UINT root,len; + LPWSTR deformated,buffer,deformated_name; + LPCWSTR key,name; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', '`','R','e','g','i','s','t','r','y','`',' ', @@ -3893,30 +2324,13 @@ static LPWSTR resolve_keypath( MSIPACKAGE* package, INT static const WCHAR fmt2[]= {'%','0','2','i',':','\\','%','s','\\','%','s',0}; - rc = MSI_OpenQuery(package->db,&view,ExecSeqQuery,cmp->KeyPath); - - if (rc!=ERROR_SUCCESS) + row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath); + if (!row) return NULL; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return NULL; - } - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return NULL; - } - root = MSI_RecordGetInteger(row,2); - key = load_dynamic_stringW(row, 3); - name = load_dynamic_stringW(row, 4); + key = MSI_RecordGetString(row, 3); + name = MSI_RecordGetString(row, 4); deformat_string(package, key , &deformated); deformat_string(package, name, &deformated_name); @@ -3931,13 +2345,9 @@ static LPWSTR resolve_keypath( MSIPACKAGE* package, INT else sprintfW(buffer,fmt,root,deformated); - HeapFree(GetProcessHeap(),0,key); HeapFree(GetProcessHeap(),0,deformated); - HeapFree(GetProcessHeap(),0,name); HeapFree(GetProcessHeap(),0,deformated_name); msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); return buffer; } @@ -3960,7 +2370,7 @@ static LPWSTR resolve_keypath( MSIPACKAGE* package, INT return NULL; } -static HKEY openSharedDLLsKey() +static HKEY openSharedDLLsKey(void) { HKEY hkey=0; static const WCHAR path[] = @@ -4214,7 +2624,7 @@ typedef struct { ITypeLib *ptLib; } typelib_struct; -BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, +static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam) { TLIBATTR *attr; @@ -4232,8 +2642,13 @@ BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, sz = strlenW(tl_struct->source)+4; sz *= sizeof(WCHAR); - tl_struct->path = HeapAlloc(GetProcessHeap(),0,sz); - sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName); + if ((INT)lpszName == 1) + tl_struct->path = strdupW(tl_struct->source); + else + { + tl_struct->path = HeapAlloc(GetProcessHeap(),0,sz); + sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName); + } TRACE("trying %s\n", debugstr_w(tl_struct->path)); res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib); @@ -4261,6 +2676,91 @@ BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, return TRUE; } +static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE* package = (MSIPACKAGE*)param; + LPCWSTR component; + INT index; + typelib_struct tl_struct; + HMODULE module; + static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0}; + + component = MSI_RecordGetString(row,3); + index = get_loaded_component(package,component); + if (index < 0) + return ERROR_SUCCESS; + + if (!ACTION_VerifyComponentForAction(package, index, INSTALLSTATE_LOCAL)) + { + TRACE("Skipping typelib reg due to disabled component\n"); + + package->components[index].Action = + package->components[index].Installed; + + return ERROR_SUCCESS; + } + + package->components[index].Action = INSTALLSTATE_LOCAL; + + index = get_loaded_file(package,package->components[index].KeyPath); + + if (index < 0) + return ERROR_SUCCESS; + + module = LoadLibraryExW(package->files[index].TargetPath, NULL, + LOAD_LIBRARY_AS_DATAFILE); + if (module != NULL) + { + LPWSTR guid; + guid = load_dynamic_stringW(row,1); + CLSIDFromString(guid, &tl_struct.clsid); + HeapFree(GetProcessHeap(),0,guid); + tl_struct.source = strdupW(package->files[index].TargetPath); + tl_struct.path = NULL; + + EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc, + (LONG_PTR)&tl_struct); + + if (tl_struct.path != NULL) + { + LPWSTR help = NULL; + LPCWSTR helpid; + HRESULT res; + + helpid = MSI_RecordGetString(row,6); + + if (helpid) + help = resolve_folder(package,helpid,FALSE,FALSE,NULL); + res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help); + HeapFree(GetProcessHeap(),0,help); + + if (!SUCCEEDED(res)) + ERR("Failed to register type library %s\n", + debugstr_w(tl_struct.path)); + else + { + ui_actiondata(package,szRegisterTypeLibraries,row); + + TRACE("Registered %s\n", debugstr_w(tl_struct.path)); + } + + ITypeLib_Release(tl_struct.ptLib); + HeapFree(GetProcessHeap(),0,tl_struct.path); + } + else + ERR("Failed to load type library %s\n", + debugstr_w(tl_struct.source)); + + FreeLibrary(module); + HeapFree(GetProcessHeap(),0,tl_struct.source); + } + else + ERR("Could not load file! %s\n", + debugstr_w(package->files[index].TargetPath)); + + return ERROR_SUCCESS; +} + static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) { /* @@ -4271,7 +2771,6 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) */ UINT rc; MSIQUERY * view; - MSIRECORD * row = 0; static const WCHAR Query[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', '`','T','y','p','e','L','i','b','`',0}; @@ -4283,688 +2782,154 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) if (rc != ERROR_SUCCESS) return ERROR_SUCCESS; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - WCHAR component[0x100]; - DWORD sz; - INT index; - LPWSTR guid; - typelib_struct tl_struct; - HMODULE module; - static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0}; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - sz = 0x100; - MSI_RecordGetStringW(row,3,component,&sz); - - index = get_loaded_component(package,component); - if (index < 0) - { - msiobj_release(&row->hdr); - continue; - } - - if (!ACTION_VerifyComponentForAction(package, index, - INSTALLSTATE_LOCAL)) - { - TRACE("Skipping typelib reg due to disabled component\n"); - msiobj_release(&row->hdr); - - package->components[index].Action = - package->components[index].Installed; - - continue; - } - - package->components[index].Action = INSTALLSTATE_LOCAL; - - index = get_loaded_file(package,package->components[index].KeyPath); - - if (index < 0) - { - msiobj_release(&row->hdr); - continue; - } - - guid = load_dynamic_stringW(row,1); - module = LoadLibraryExW(package->files[index].TargetPath, NULL, - LOAD_LIBRARY_AS_DATAFILE); - if (module != NULL) - { - CLSIDFromString(guid, &tl_struct.clsid); - tl_struct.source = strdupW(package->files[index].TargetPath); - tl_struct.path = NULL; - - EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc, - (LONG_PTR)&tl_struct); - - if (tl_struct.path != NULL) - { - LPWSTR help; - WCHAR helpid[0x100]; - HRESULT res; - - sz = 0x100; - MSI_RecordGetStringW(row,6,helpid,&sz); - - help = resolve_folder(package,helpid,FALSE,FALSE,NULL); - res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help); - HeapFree(GetProcessHeap(),0,help); - - if (!SUCCEEDED(res)) - ERR("Failed to register type library %s\n", - debugstr_w(tl_struct.path)); - else - { - ui_actiondata(package,szRegisterTypeLibraries,row); - - TRACE("Registered %s\n", debugstr_w(tl_struct.path)); - } - - ITypeLib_Release(tl_struct.ptLib); - HeapFree(GetProcessHeap(),0,tl_struct.path); - } - else - ERR("Failed to load type library %s\n", - debugstr_w(tl_struct.source)); - - FreeLibrary(module); - HeapFree(GetProcessHeap(),0,tl_struct.source); - } - else - ERR("Could not load file! %s\n", - debugstr_w(package->files[index].TargetPath)); - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package); msiobj_release(&view->hdr); return rc; } -static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app ) +static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param) { - static const WCHAR szAppID[] = { 'A','p','p','I','D',0 }; - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','A','p','p','I' ,'d','`',' ','W','H','E','R','E',' ', - '`','A','p','p','I','d','`',' ','=','\'','%','s','\'',0}; - HKEY hkey2,hkey3; - LPWSTR buffer=0; - - if (!package) - return ERROR_INVALID_HANDLE; - - rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, clsid); - if (rc != ERROR_SUCCESS) - return rc; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2); - RegCreateKeyW(hkey2,clsid,&hkey3); - RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app, - (strlenW(app)+1)*sizeof(WCHAR)); - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - if (!MSI_RecordIsNull(row,2)) - { - LPWSTR deformated=0; - UINT size; - static const WCHAR szRemoteServerName[] = - {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e', - 0}; - buffer = load_dynamic_stringW(row,2); - size = deformat_string(package,buffer,&deformated); - RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,(LPVOID)deformated, - size); - HeapFree(GetProcessHeap(),0,deformated); - HeapFree(GetProcessHeap(),0,buffer); - } - - if (!MSI_RecordIsNull(row,3)) - { - static const WCHAR szLocalService[] = - {'L','o','c','a','l','S','e','r','v','i','c','e',0}; - UINT size; - buffer = load_dynamic_stringW(row,3); - size = (strlenW(buffer)+1) * sizeof(WCHAR); - RegSetValueExW(hkey3,szLocalService,0,REG_SZ,(LPVOID)buffer,size); - HeapFree(GetProcessHeap(),0,buffer); - } - - if (!MSI_RecordIsNull(row,4)) - { - static const WCHAR szService[] = - {'S','e','r','v','i','c','e', - 'P','a','r','a','m','e','t','e','r','s',0}; - UINT size; - buffer = load_dynamic_stringW(row,4); - size = (strlenW(buffer)+1) * sizeof(WCHAR); - RegSetValueExW(hkey3,szService,0,REG_SZ,(LPVOID)buffer,size); - HeapFree(GetProcessHeap(),0,buffer); - } - - if (!MSI_RecordIsNull(row,5)) - { - static const WCHAR szDLL[] = - {'D','l','l','S','u','r','r','o','g','a','t','e',0}; - UINT size; - buffer = load_dynamic_stringW(row,5); - size = (strlenW(buffer)+1) * sizeof(WCHAR); - RegSetValueExW(hkey3,szDLL,0,REG_SZ,(LPVOID)buffer,size); - HeapFree(GetProcessHeap(),0,buffer); - } - - if (!MSI_RecordIsNull(row,6)) - { - static const WCHAR szActivate[] = - {'A','c','t','i','v','a','t','e','A','s', - 'S','t','o','r','a','g','e',0}; - static const WCHAR szY[] = {'Y',0}; - - if (MSI_RecordGetInteger(row,6)) - RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4); - } - - if (!MSI_RecordIsNull(row,7)) - { - static const WCHAR szRunAs[] = {'R','u','n','A','s',0}; - static const WCHAR szUser[] = - {'I','n','t','e','r','a','c','t','i','v','e',' ', - 'U','s','e','r',0}; - - if (MSI_RecordGetInteger(row,7)) - RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,34); - } - - msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); - RegCloseKey(hkey3); - RegCloseKey(hkey2); - return rc; -} - -static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) -{ - /* - * Again I am assuming the words, "Whose key file represents" when referring - * to a Component as to meaning that Components KeyPath file - * - * Also there is a very strong connection between ClassInfo and ProgID - * that I am mostly glossing over. - * What would be more propper is to load the ClassInfo and the ProgID info - * into memory data structures and then be able to enable and disable them - * based on component. - */ - - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','C','l','a','s','s','`',0}; - static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; - static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 }; - static const WCHAR szAppID[] = { 'A','p','p','I','D',0 }; - static const WCHAR szSpace[] = {' ',0}; - HKEY hkey,hkey2,hkey3; - LPWSTR argument,deformated; - - if (!package) - return ERROR_INVALID_HANDLE; - - rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey); - if (rc != ERROR_SUCCESS) - return ERROR_FUNCTION_FAILED; - - rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - goto end; - } - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - goto end; - } - - while (1) - { - WCHAR clsid[0x100]; - WCHAR buffer[0x100]; - WCHAR desc[0x100]; - DWORD sz; - INT index; - DWORD size; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - sz=0x100; - MSI_RecordGetStringW(row,3,buffer,&sz); - - index = get_loaded_component(package,buffer); - - if (index < 0) - { - msiobj_release(&row->hdr); - continue; - } - - if ((!ACTION_VerifyComponentForAction(package, index, - INSTALLSTATE_LOCAL)) && - (!ACTION_VerifyComponentForAction(package, index, - INSTALLSTATE_ADVERTISED))) - { - TRACE("Skipping class reg due to disabled component\n"); - msiobj_release(&row->hdr); - - package->components[index].Action = - package->components[index].Installed; - - continue; - } - - package->components[index].Action = INSTALLSTATE_LOCAL; - - sz=0x100; - MSI_RecordGetStringW(row,1,clsid,&sz); - RegCreateKeyW(hkey,clsid,&hkey2); - - if (!MSI_RecordIsNull(row,5)) - { - sz=0x100; - MSI_RecordGetStringW(row,5,desc,&sz); - - RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)desc, - (strlenW(desc)+1)*sizeof(WCHAR)); - } - else - desc[0]=0; - - sz=0x100; - MSI_RecordGetStringW(row,2,buffer,&sz); - - RegCreateKeyW(hkey2,buffer,&hkey3); - - index = get_loaded_file(package,package->components[index].KeyPath); - - argument = load_dynamic_stringW(row,11); - size = deformat_string(package,argument,&deformated); - if (deformated) - size+=sizeof(WCHAR); - HeapFree(GetProcessHeap(),0,argument); - size += (strlenW(package->files[index].TargetPath))*sizeof(WCHAR); - - argument = HeapAlloc(GetProcessHeap(),0,size+sizeof(WCHAR)); - strcpyW(argument,package->files[index].TargetPath); - if (deformated) - { - strcatW(argument,szSpace); - strcatW(argument,deformated); - } - - RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size); - HeapFree(GetProcessHeap(),0,deformated); - HeapFree(GetProcessHeap(),0,argument); - - RegCloseKey(hkey3); - - if (!MSI_RecordIsNull(row,4)) - { - sz=0x100; - MSI_RecordGetStringW(row,4,buffer,&sz); - - RegCreateKeyW(hkey2,szProgID,&hkey3); - - RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)buffer, - (strlenW(buffer)+1)*sizeof(WCHAR)); - - RegCloseKey(hkey3); - } - - if (!MSI_RecordIsNull(row,6)) - { - sz=0x100; - MSI_RecordGetStringW(row,6,buffer,&sz); - - RegSetValueExW(hkey2,szAppID,0,REG_SZ,(LPVOID)buffer, - (strlenW(buffer)+1)*sizeof(WCHAR)); - - register_appid(package,buffer,desc); - } - - - if (!MSI_RecordIsNull(row,7)) - { - FIXME("Process field 7\n"); - } - - if (!MSI_RecordIsNull(row,8)) - { - static const WCHAR szDefaultIcon[] = - {'D','e','f','a','u','l','t','I','c','o','n',0}; - - LPWSTR FileName = load_dynamic_stringW(row,8); - LPWSTR FilePath; - INT index; - - RegCreateKeyW(hkey2,szDefaultIcon,&hkey3); - build_icon_path(package,FileName,&FilePath); - if (!MSI_RecordIsNull(row,9)) - { - static const WCHAR index_fmt[] = {',','%','i',0}; - WCHAR index_buf[20]; - index = MSI_RecordGetInteger(row,9); - sprintfW(index_buf,index_fmt,index); - size = strlenW(FilePath)+strlenW(index_buf)+1; - size *= sizeof(WCHAR); - HeapReAlloc(GetProcessHeap(),0,FilePath,size); - } - RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)FilePath, - (strlenW(FilePath)+1) * sizeof(WCHAR)); - HeapFree(GetProcessHeap(),0,FilePath); - HeapFree(GetProcessHeap(),0,FileName); - RegCloseKey(hkey3); - } - - if (!MSI_RecordIsNull(row,10)) - { - static const WCHAR szInproc32[] = - {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2', - 0}; - static const WCHAR szInproc[] = - {'I','n','p','r','o','c','H','a','n','d','l','e','r',0}; - INT i = MSI_RecordGetInteger(row,10); - if (i != MSI_NULL_INTEGER && i > 0 && i < 4) - { - static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0}; - static const WCHAR ole32[] = - {'o','l','e','3','2','.','d','l','l',0}; - switch(i) - { - case 1: - size = strlenW(ole2) * sizeof(WCHAR); - RegCreateKeyW(hkey2,szInproc,&hkey3); - RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole2, size); - RegCloseKey(hkey3); - break; - case 2: - size = strlenW(ole32) * sizeof(WCHAR); - RegCreateKeyW(hkey2,szInproc32,&hkey3); - RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole32,size); - RegCloseKey(hkey3); - break; - case 3: - size = strlenW(ole2) * sizeof(WCHAR); - RegCreateKeyW(hkey2,szInproc,&hkey3); - RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole2, size); - RegCloseKey(hkey3); - size = strlenW(ole32) * sizeof(WCHAR); - RegCreateKeyW(hkey2,szInproc32,&hkey3); - RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)ole32,size); - RegCloseKey(hkey3); - break; - } - - } - else - { - RegCreateKeyW(hkey2,szInproc32,&hkey3); - argument = load_dynamic_stringW(row,10); - reduce_to_longfilename(argument); - size = strlenW(argument)*sizeof(WCHAR); - - RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size); - HeapFree(GetProcessHeap(),0,argument); - - RegCloseKey(hkey3); - } - } - - RegCloseKey(hkey2); - - ui_actiondata(package,szRegisterClassInfo,row); - - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - -end: - RegCloseKey(hkey); - return rc; -} - -static UINT register_progid_base(MSIPACKAGE* package, MSIRECORD * row, - LPWSTR clsid) -{ - static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; - static const WCHAR szDefaultIcon[] = - {'D','e','f','a','u','l','t','I','c','o','n',0}; - HKEY hkey,hkey2; - WCHAR buffer[0x100]; + MSIPACKAGE *package = (MSIPACKAGE*)param; + LPWSTR target_file, target_folder; + LPCWSTR buffer; + WCHAR filename[0x100]; DWORD sz; + DWORD index; + static const WCHAR szlnk[]={'.','l','n','k',0}; + IShellLinkW *sl; + IPersistFile *pf; + HRESULT res; + buffer = MSI_RecordGetString(row,4); + index = get_loaded_component(package,buffer); + + if (index < 0) + return ERROR_SUCCESS; + + if (!ACTION_VerifyComponentForAction(package, index, INSTALLSTATE_LOCAL)) + { + TRACE("Skipping shortcut creation due to disabled component\n"); + + package->components[index].Action = + package->components[index].Installed; + + return ERROR_SUCCESS; + } + + package->components[index].Action = INSTALLSTATE_LOCAL; + + ui_actiondata(package,szCreateShortcuts,row); + + res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, + &IID_IShellLinkW, (LPVOID *) &sl ); + + if (FAILED(res)) + { + ERR("Is IID_IShellLink\n"); + return ERROR_SUCCESS; + } + + res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf ); + if( FAILED( res ) ) + { + ERR("Is IID_IPersistFile\n"); + return ERROR_SUCCESS; + } + + buffer = MSI_RecordGetString(row,2); + target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL); + + /* may be needed because of a bug somehwere else */ + create_full_pathW(target_folder); sz = 0x100; - MSI_RecordGetStringW(row,1,buffer,&sz); - RegCreateKeyW(HKEY_CLASSES_ROOT,buffer,&hkey); + MSI_RecordGetStringW(row,3,filename,&sz); + reduce_to_longfilename(filename); + if (!strchrW(filename,'.') || strcmpiW(strchrW(filename,'.'),szlnk)) + strcatW(filename,szlnk); + target_file = build_directory_name(2, target_folder, filename); + HeapFree(GetProcessHeap(),0,target_folder); - if (!MSI_RecordIsNull(row,4)) + buffer = MSI_RecordGetString(row,5); + if (strchrW(buffer,'[')) { - sz = 0x100; - MSI_RecordGetStringW(row,4,buffer,&sz); - RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) * - sizeof(WCHAR)); - } - - if (!MSI_RecordIsNull(row,3)) - { - sz = 0x100; - - MSI_RecordGetStringW(row,3,buffer,&sz); - RegCreateKeyW(hkey,szCLSID,&hkey2); - RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)buffer, (strlenW(buffer)+1) * - sizeof(WCHAR)); - - if (clsid) - strcpyW(clsid,buffer); - - RegCloseKey(hkey2); + LPWSTR deformated; + deformat_string(package,buffer,&deformated); + IShellLinkW_SetPath(sl,deformated); + HeapFree(GetProcessHeap(),0,deformated); } else { - FIXME("UNHANDLED case, Parent progid but classid is NULL\n"); - return ERROR_FUNCTION_FAILED; + LPWSTR keypath; + FIXME("poorly handled shortcut format, advertised shortcut\n"); + keypath = strdupW(package->components[index].FullKeypath); + IShellLinkW_SetPath(sl,keypath); + HeapFree(GetProcessHeap(),0,keypath); } - if (!MSI_RecordIsNull(row,5)) + + if (!MSI_RecordIsNull(row,6)) { - INT index = MSI_RecordGetInteger(row,6); - LPWSTR FileName = load_dynamic_stringW(row,5); - LPWSTR FilePath,IconPath; - static const WCHAR fmt[] = {'%','s',',','%','i',0}; - - RegCreateKeyW(hkey,szDefaultIcon,&hkey2); - build_icon_path(package,FileName,&FilePath); - - IconPath = HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)* - sizeof(WCHAR)); - - sprintfW(IconPath,fmt,FilePath,index); - RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)IconPath, - (strlenW(IconPath)+1) * sizeof(WCHAR)); - HeapFree(GetProcessHeap(),0,FilePath); - HeapFree(GetProcessHeap(),0,FileName); - RegCloseKey(hkey2); + LPWSTR deformated; + buffer = MSI_RecordGetString(row,6); + deformat_string(package,buffer,&deformated); + IShellLinkW_SetArguments(sl,deformated); + HeapFree(GetProcessHeap(),0,deformated); } + + if (!MSI_RecordIsNull(row,7)) + { + buffer = MSI_RecordGetString(row,7); + IShellLinkW_SetDescription(sl,buffer); + } + + if (!MSI_RecordIsNull(row,8)) + IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8)); + + if (!MSI_RecordIsNull(row,9)) + { + WCHAR *Path = NULL; + INT index; + + buffer = MSI_RecordGetString(row,9); + + build_icon_path(package,buffer,&Path); + index = MSI_RecordGetInteger(row,10); + + IShellLinkW_SetIconLocation(sl,Path,index); + HeapFree(GetProcessHeap(),0,Path); + } + + if (!MSI_RecordIsNull(row,11)) + IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11)); + + if (!MSI_RecordIsNull(row,12)) + { + LPWSTR Path; + buffer = MSI_RecordGetString(row,12); + Path = resolve_folder(package, buffer, FALSE, FALSE, NULL); + IShellLinkW_SetWorkingDirectory(sl,Path); + HeapFree(GetProcessHeap(), 0, Path); + } + + TRACE("Writing shortcut to %s\n",debugstr_w(target_file)); + IPersistFile_Save(pf,target_file,FALSE); + + HeapFree(GetProcessHeap(),0,target_file); + + IPersistFile_Release( pf ); + IShellLinkW_Release( sl ); + return ERROR_SUCCESS; } -static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid); - -static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent, - LPWSTR clsid) +static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) { UINT rc; + HRESULT res; MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR Query_t[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','P','r','o','g' ,'I','d','`',' ','W','H','E','R','E',' ', - '`','P','r','o','g','I','d','`',' ','=',' ','\'' ,'%','s','\'',0}; - - if (!package) - return ERROR_INVALID_HANDLE; - - rc = MSI_OpenQuery(package->db, &view, Query_t, parent); - if (rc != ERROR_SUCCESS) - return rc; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - register_progid(package,row,clsid); - - msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; -} - -static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid) -{ - UINT rc = ERROR_SUCCESS; - - if (MSI_RecordIsNull(row,2)) - rc = register_progid_base(package,row,clsid); - else - { - WCHAR buffer[0x1000]; - DWORD sz, disp; - HKEY hkey,hkey2; - static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; - static const WCHAR szDefaultIcon[] = - {'D','e','f','a','u','l','t','I','c','o','n',0}; - - /* check if already registered */ - sz = 0x100; - MSI_RecordGetStringW(row,1,buffer,&sz); - RegCreateKeyExW(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0, - KEY_ALL_ACCESS, NULL, &hkey, &disp ); - if (disp == REG_OPENED_EXISTING_KEY) - { - TRACE("Key already registered\n"); - RegCloseKey(hkey); - return rc; - } - - sz = 0x100; - MSI_RecordGetStringW(row,2,buffer,&sz); - rc = register_parent_progid(package,buffer,clsid); - - /* clsid is same as parent */ - RegCreateKeyW(hkey,szCLSID,&hkey2); - RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) * - sizeof(WCHAR)); - - RegCloseKey(hkey2); - - - if (!MSI_RecordIsNull(row,4)) - { - sz = 0x100; - MSI_RecordGetStringW(row,4,buffer,&sz); - RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)buffer, - (strlenW(buffer)+1) * sizeof(WCHAR)); - } - - if (!MSI_RecordIsNull(row,5)) - { - LPWSTR FileName = load_dynamic_stringW(row,5); - LPWSTR FilePath; - RegCreateKeyW(hkey,szDefaultIcon,&hkey2); - build_icon_path(package,FileName,&FilePath); - RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)FilePath, - (strlenW(FilePath)+1) * sizeof(WCHAR)); - HeapFree(GetProcessHeap(),0,FilePath); - HeapFree(GetProcessHeap(),0,FileName); - RegCloseKey(hkey2); - } - - RegCloseKey(hkey); - } - return rc; -} - -static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package) -{ - /* - * Sigh, here I am just brute force registering all progids - * this needs to be linked to the Classes that have been registered - * but the easiest way to do that is to load all these stuff into - * memory for easy checking. - * - * Gives me something to continue to work toward. - */ - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; static const WCHAR Query[] = - {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', - '`','P','r','o','g','I','d','`',0}; + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','S','h','o','r','t','c','u','t','`',0}; if (!package) return ERROR_INVALID_HANDLE; @@ -4973,81 +2938,6 @@ static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package) if (rc != ERROR_SUCCESS) return ERROR_SUCCESS; - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - WCHAR clsid[0x1000]; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - register_progid(package,row,clsid); - ui_actiondata(package,szRegisterProgIdInfo,row); - - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; -} - -static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, - LPWSTR *FilePath) -{ - LPWSTR ProductCode; - LPWSTR SystemFolder; - LPWSTR dest; - UINT rc; - - static const WCHAR szInstaller[] = - {'I','n','s','t','a','l','l','e','r','\\',0}; - static const WCHAR szFolder[] = - {'W','i','n','d','o','w','s','F','o','l','d','e','r',0}; - - ProductCode = load_dynamic_property(package,szProductCode,&rc); - if (!ProductCode) - return rc; - - SystemFolder = load_dynamic_property(package,szFolder,NULL); - - dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode); - - create_full_pathW(dest); - - *FilePath = build_directory_name(2, dest, icon_name); - - HeapFree(GetProcessHeap(),0,SystemFolder); - HeapFree(GetProcessHeap(),0,ProductCode); - HeapFree(GetProcessHeap(),0,dest); - return ERROR_SUCCESS; -} - -static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) -{ - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR Query[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','S','h','o','r','t','c','u','t','`',0}; - IShellLinkW *sl; - IPersistFile *pf; - HRESULT res; - - if (!package) - return ERROR_INVALID_HANDLE; - res = CoInitialize( NULL ); if (FAILED (res)) { @@ -5055,179 +2945,65 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) return ERROR_FUNCTION_FAILED; } - rc = MSI_DatabaseOpenViewW(package->db, Query, &view); - if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - LPWSTR target_file, target_folder; - WCHAR buffer[0x100]; - DWORD sz; - DWORD index; - static const WCHAR szlnk[]={'.','l','n','k',0}; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - sz = 0x100; - MSI_RecordGetStringW(row,4,buffer,&sz); - - index = get_loaded_component(package,buffer); - - if (index < 0) - { - msiobj_release(&row->hdr); - continue; - } - - if (!ACTION_VerifyComponentForAction(package, index, - INSTALLSTATE_LOCAL)) - { - TRACE("Skipping shortcut creation due to disabled component\n"); - msiobj_release(&row->hdr); - - package->components[index].Action = - package->components[index].Installed; - - continue; - } - - package->components[index].Action = INSTALLSTATE_LOCAL; - - ui_actiondata(package,szCreateShortcuts,row); - - res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, - &IID_IShellLinkW, (LPVOID *) &sl ); - - if (FAILED(res)) - { - ERR("Is IID_IShellLink\n"); - msiobj_release(&row->hdr); - continue; - } - - res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf ); - if( FAILED( res ) ) - { - ERR("Is IID_IPersistFile\n"); - msiobj_release(&row->hdr); - continue; - } - - sz = 0x100; - MSI_RecordGetStringW(row,2,buffer,&sz); - target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL); - - /* may be needed because of a bug somehwere else */ - create_full_pathW(target_folder); - - sz = 0x100; - MSI_RecordGetStringW(row,3,buffer,&sz); - reduce_to_longfilename(buffer); - if (!strchrW(buffer,'.') || strcmpiW(strchrW(buffer,'.'),szlnk)) - strcatW(buffer,szlnk); - target_file = build_directory_name(2, target_folder, buffer); - HeapFree(GetProcessHeap(),0,target_folder); - - sz = 0x100; - MSI_RecordGetStringW(row,5,buffer,&sz); - if (strchrW(buffer,'[')) - { - LPWSTR deformated; - deformat_string(package,buffer,&deformated); - IShellLinkW_SetPath(sl,deformated); - HeapFree(GetProcessHeap(),0,deformated); - } - else - { - LPWSTR keypath; - FIXME("poorly handled shortcut format, advertised shortcut\n"); - keypath = strdupW(package->components[index].FullKeypath); - IShellLinkW_SetPath(sl,keypath); - HeapFree(GetProcessHeap(),0,keypath); - } - - if (!MSI_RecordIsNull(row,6)) - { - LPWSTR deformated; - sz = 0x100; - MSI_RecordGetStringW(row,6,buffer,&sz); - deformat_string(package,buffer,&deformated); - IShellLinkW_SetArguments(sl,deformated); - HeapFree(GetProcessHeap(),0,deformated); - } - - if (!MSI_RecordIsNull(row,7)) - { - LPWSTR deformated; - deformated = load_dynamic_stringW(row,7); - IShellLinkW_SetDescription(sl,deformated); - HeapFree(GetProcessHeap(),0,deformated); - } - - if (!MSI_RecordIsNull(row,8)) - IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8)); - - if (!MSI_RecordIsNull(row,9)) - { - WCHAR *Path = NULL; - INT index; - - sz = 0x100; - MSI_RecordGetStringW(row,9,buffer,&sz); - - build_icon_path(package,buffer,&Path); - index = MSI_RecordGetInteger(row,10); - - IShellLinkW_SetIconLocation(sl,Path,index); - HeapFree(GetProcessHeap(),0,Path); - } - - if (!MSI_RecordIsNull(row,11)) - IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11)); - - if (!MSI_RecordIsNull(row,12)) - { - LPWSTR Path; - sz = 0x100; - MSI_RecordGetStringW(row,12,buffer,&sz); - Path = resolve_folder(package, buffer, FALSE, FALSE, NULL); - IShellLinkW_SetWorkingDirectory(sl,Path); - HeapFree(GetProcessHeap(), 0, Path); - } - - TRACE("Writing shortcut to %s\n",debugstr_w(target_file)); - IPersistFile_Save(pf,target_file,FALSE); - - HeapFree(GetProcessHeap(),0,target_file); - - IPersistFile_Release( pf ); - IShellLinkW_Release( sl ); - - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package); msiobj_release(&view->hdr); - CoUninitialize(); return rc; } +static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE* package = (MSIPACKAGE*)param; + HANDLE the_file; + LPWSTR FilePath=NULL; + LPCWSTR FileName=NULL; + CHAR buffer[1024]; + DWORD sz; + UINT rc; + + FileName = MSI_RecordGetString(row,1); + if (!FileName) + { + ERR("Unable to get FileName\n"); + return ERROR_SUCCESS; + } + + build_icon_path(package,FileName,&FilePath); + + TRACE("Creating icon file at %s\n",debugstr_w(FilePath)); + + the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + + if (the_file == INVALID_HANDLE_VALUE) + { + ERR("Unable to create file %s\n",debugstr_w(FilePath)); + HeapFree(GetProcessHeap(),0,FilePath); + return ERROR_SUCCESS; + } + + do + { + DWORD write; + sz = 1024; + rc = MSI_RecordReadStream(row,2,buffer,&sz); + if (rc != ERROR_SUCCESS) + { + ERR("Failed to get stream\n"); + CloseHandle(the_file); + DeleteFileW(FilePath); + break; + } + WriteFile(the_file,buffer,sz,&write,NULL); + } while (sz == 1024); + + HeapFree(GetProcessHeap(),0,FilePath); + + CloseHandle(the_file); + return ERROR_SUCCESS; +} /* * 99% of the work done here is only done for @@ -5239,11 +3015,9 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) { UINT rc; MSIQUERY * view; - MSIRECORD * row = 0; static const WCHAR Query[]= {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', '`','I','c','o','n','`',0}; - DWORD sz; /* for registry stuff */ LPWSTR productcode; HKEY hkey=0; @@ -5252,6 +3026,19 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) {'P','r','o','d','u','c','t','N','a','m','e',0}; static const WCHAR szPackageCode[] = {'P','a','c','k','a','g','e','C','o','d','e',0}; + static const WCHAR szLanguage[] = + {'L','a','n','g','u','a','g','e',0}; + static const WCHAR szProductLanguage[] = + {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0}; + static const WCHAR szProductIcon[] = + {'P','r','o','d','u','c','t','I','c','o','n',0}; + static const WCHAR szARPProductIcon[] = + {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0}; + static const WCHAR szProductVersion[] = + {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0}; + static const WCHAR szVersion[] = + {'V','e','r','s','i','o','n',0}; + DWORD langid; LPWSTR buffer; DWORD size; MSIHANDLE hDb, hSumInfo; @@ -5259,82 +3046,17 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) if (!package) return ERROR_INVALID_HANDLE; + /* write out icon files */ + rc = MSI_DatabaseOpenViewW(package->db, Query, &view); - if (rc != ERROR_SUCCESS) - goto next; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) + if (rc == ERROR_SUCCESS) { - MSI_ViewClose(view); + MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package); msiobj_release(&view->hdr); - goto next; } - while (1) - { - HANDLE the_file; - WCHAR *FilePath=NULL; - WCHAR *FileName=NULL; - CHAR buffer[1024]; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - FileName = load_dynamic_stringW(row,1); - if (!FileName) - { - ERR("Unable to get FileName\n"); - msiobj_release(&row->hdr); - continue; - } - - build_icon_path(package,FileName,&FilePath); - - HeapFree(GetProcessHeap(),0,FileName); - - TRACE("Creating icon file at %s\n",debugstr_w(FilePath)); - - the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL); - - if (the_file == INVALID_HANDLE_VALUE) - { - ERR("Unable to create file %s\n",debugstr_w(FilePath)); - msiobj_release(&row->hdr); - HeapFree(GetProcessHeap(),0,FilePath); - continue; - } - - do - { - DWORD write; - sz = 1024; - rc = MSI_RecordReadStream(row,2,buffer,&sz); - if (rc != ERROR_SUCCESS) - { - ERR("Failed to get stream\n"); - CloseHandle(the_file); - DeleteFileW(FilePath); - break; - } - WriteFile(the_file,buffer,sz,&write,NULL); - } while (sz == 1024); - - HeapFree(GetProcessHeap(),0,FilePath); - - CloseHandle(the_file); - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - -next: /* ok there is a lot more done here but i need to figure out what */ + productcode = load_dynamic_property(package,szProductCode,&rc); if (!productcode) return rc; @@ -5350,8 +3072,34 @@ next: buffer = load_dynamic_property(package,szProductName,NULL); size = strlenW(buffer)*sizeof(WCHAR); - RegSetValueExW(hukey,szProductName,0,REG_SZ, (LPSTR)buffer,size); + RegSetValueExW(hukey,szProductName,0,REG_SZ, (BYTE *)buffer,size); HeapFree(GetProcessHeap(),0,buffer); + + buffer = load_dynamic_property(package,szProductLanguage,NULL); + size = sizeof(DWORD); + langid = atoiW(buffer); + RegSetValueExW(hukey,szLanguage,0,REG_DWORD, (BYTE *)&langid,size); + HeapFree(GetProcessHeap(),0,buffer); + + buffer = load_dynamic_property(package,szARPProductIcon,NULL); + if (buffer) + { + LPWSTR path; + build_icon_path(package,buffer,&path); + size = strlenW(path) * sizeof(WCHAR); + RegSetValueExW(hukey,szProductIcon,0,REG_SZ, (BYTE *)path,size); + } + HeapFree(GetProcessHeap(),0,buffer); + + buffer = load_dynamic_property(package,szProductVersion,NULL); + if (buffer) + { + DWORD verdword = build_version_dword(buffer); + size = sizeof(DWORD); + RegSetValueExW(hukey,szVersion,0,REG_DWORD, (BYTE *)&verdword,size); + } + HeapFree(GetProcessHeap(),0,buffer); + FIXME("Need to write more keys to the user registry\n"); hDb= alloc_msihandle( &package->db->hdr ); @@ -5396,16 +3144,112 @@ end: return rc; } +static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE *package = (MSIPACKAGE*)param; + LPCWSTR component,section,key,value,identifier,filename,dirproperty; + LPWSTR deformated_section, deformated_key, deformated_value; + LPWSTR folder, fullname = NULL; + MSIRECORD * uirow; + INT component_index,action; + static const WCHAR szWindowsFolder[] = + {'W','i','n','d','o','w','s','F','o','l','d','e','r',0}; + + component = MSI_RecordGetString(row, 8); + component_index = get_loaded_component(package,component); + + if (!ACTION_VerifyComponentForAction(package, component_index, + INSTALLSTATE_LOCAL)) + { + TRACE("Skipping ini file due to disabled component %s\n", + debugstr_w(component)); + + package->components[component_index].Action = + package->components[component_index].Installed; + + return ERROR_SUCCESS; + } + + package->components[component_index].Action = INSTALLSTATE_LOCAL; + + identifier = MSI_RecordGetString(row,1); + filename = MSI_RecordGetString(row,2); + dirproperty = MSI_RecordGetString(row,3); + section = MSI_RecordGetString(row,4); + key = MSI_RecordGetString(row,5); + value = MSI_RecordGetString(row,6); + action = MSI_RecordGetInteger(row,7); + + deformat_string(package,section,&deformated_section); + deformat_string(package,key,&deformated_key); + deformat_string(package,value,&deformated_value); + + if (dirproperty) + { + folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL); + if (!folder) + folder = load_dynamic_property(package,dirproperty,NULL); + } + else + folder = load_dynamic_property(package, szWindowsFolder, NULL); + + if (!folder) + { + ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty)); + goto cleanup; + } + + fullname = build_directory_name(3, folder, filename, NULL); + + if (action == 0) + { + TRACE("Adding value %s to section %s in %s\n", + debugstr_w(deformated_key), debugstr_w(deformated_section), + debugstr_w(fullname)); + WritePrivateProfileStringW(deformated_section, deformated_key, + deformated_value, fullname); + } + else if (action == 1) + { + WCHAR returned[10]; + GetPrivateProfileStringW(deformated_section, deformated_key, NULL, + returned, 10, fullname); + if (returned[0] == 0) + { + TRACE("Adding value %s to section %s in %s\n", + debugstr_w(deformated_key), debugstr_w(deformated_section), + debugstr_w(fullname)); + + WritePrivateProfileStringW(deformated_section, deformated_key, + deformated_value, fullname); + } + } + else if (action == 3) + FIXME("Append to existing section not yet implemented\n"); + + uirow = MSI_CreateRecord(4); + MSI_RecordSetStringW(uirow,1,identifier); + MSI_RecordSetStringW(uirow,2,deformated_section); + MSI_RecordSetStringW(uirow,3,deformated_key); + MSI_RecordSetStringW(uirow,4,deformated_value); + ui_actiondata(package,szWriteIniValues,uirow); + msiobj_release( &uirow->hdr ); +cleanup: + HeapFree(GetProcessHeap(),0,fullname); + HeapFree(GetProcessHeap(),0,folder); + HeapFree(GetProcessHeap(),0,deformated_key); + HeapFree(GetProcessHeap(),0,deformated_value); + HeapFree(GetProcessHeap(),0,deformated_section); + return ERROR_SUCCESS; +} + static UINT ACTION_WriteIniValues(MSIPACKAGE *package) { UINT rc; MSIQUERY * view; - MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', '`','I','n','i','F','i','l','e','`',0}; - static const WCHAR szWindowsFolder[] = - {'W','i','n','d','o','w','s','F','o','l','d','e','r',0}; rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); if (rc != ERROR_SUCCESS) @@ -5414,139 +3258,18 @@ static UINT ACTION_WriteIniValues(MSIPACKAGE *package) return ERROR_SUCCESS; } - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - LPWSTR component,filename,dirproperty,section,key,value,identifier; - LPWSTR deformated_section, deformated_key, deformated_value; - LPWSTR folder, fullname = NULL; - MSIRECORD * uirow; - INT component_index,action; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - component = load_dynamic_stringW(row, 8); - component_index = get_loaded_component(package,component); - HeapFree(GetProcessHeap(),0,component); - - if (!ACTION_VerifyComponentForAction(package, component_index, - INSTALLSTATE_LOCAL)) - { - TRACE("Skipping ini file due to disabled component\n"); - msiobj_release(&row->hdr); - - package->components[component_index].Action = - package->components[component_index].Installed; - - continue; - } - - package->components[component_index].Action = INSTALLSTATE_LOCAL; - - identifier = load_dynamic_stringW(row,1); - filename = load_dynamic_stringW(row,2); - dirproperty = load_dynamic_stringW(row,3); - section = load_dynamic_stringW(row,4); - key = load_dynamic_stringW(row,5); - value = load_dynamic_stringW(row,6); - action = MSI_RecordGetInteger(row,7); - - deformat_string(package,section,&deformated_section); - deformat_string(package,key,&deformated_key); - deformat_string(package,value,&deformated_value); - - if (dirproperty) - { - folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL); - if (!folder) - folder = load_dynamic_property(package,dirproperty,NULL); - } - else - folder = load_dynamic_property(package, szWindowsFolder, NULL); - - if (!folder) - { - ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty)); - goto cleanup; - } - - fullname = build_directory_name(3, folder, filename, NULL); - - if (action == 0) - { - TRACE("Adding value %s to section %s in %s\n", - debugstr_w(deformated_key), debugstr_w(deformated_section), - debugstr_w(fullname)); - WritePrivateProfileStringW(deformated_section, deformated_key, - deformated_value, fullname); - } - else if (action == 1) - { - WCHAR returned[10]; - GetPrivateProfileStringW(deformated_section, deformated_key, NULL, - returned, 10, fullname); - if (returned[0] == 0) - { - TRACE("Adding value %s to section %s in %s\n", - debugstr_w(deformated_key), debugstr_w(deformated_section), - debugstr_w(fullname)); - - WritePrivateProfileStringW(deformated_section, deformated_key, - deformated_value, fullname); - } - } - else if (action == 3) - { - FIXME("Append to existing section not yet implemented\n"); - } - - uirow = MSI_CreateRecord(4); - MSI_RecordSetStringW(uirow,1,identifier); - MSI_RecordSetStringW(uirow,2,deformated_section); - MSI_RecordSetStringW(uirow,3,deformated_key); - MSI_RecordSetStringW(uirow,4,deformated_value); - ui_actiondata(package,szWriteIniValues,uirow); - msiobj_release( &uirow->hdr ); -cleanup: - HeapFree(GetProcessHeap(),0,identifier); - HeapFree(GetProcessHeap(),0,fullname); - HeapFree(GetProcessHeap(),0,filename); - HeapFree(GetProcessHeap(),0,key); - HeapFree(GetProcessHeap(),0,value); - HeapFree(GetProcessHeap(),0,section); - HeapFree(GetProcessHeap(),0,dirproperty); - HeapFree(GetProcessHeap(),0,folder); - HeapFree(GetProcessHeap(),0,deformated_key); - HeapFree(GetProcessHeap(),0,deformated_value); - HeapFree(GetProcessHeap(),0,deformated_section); - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package); msiobj_release(&view->hdr); return rc; } -static UINT ACTION_SelfRegModules(MSIPACKAGE *package) +static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param) { - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','S','e','l','f','R','e','g','`',0}; - + MSIPACKAGE *package = (MSIPACKAGE*)param; + LPCWSTR filename; + LPWSTR FullName; + INT index; + DWORD len; static const WCHAR ExeStr[] = {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0}; static const WCHAR close[] = {'\"',0}; @@ -5556,6 +3279,43 @@ static UINT ACTION_SelfRegModules(MSIPACKAGE *package) memset(&si,0,sizeof(STARTUPINFOW)); + filename = MSI_RecordGetString(row,1); + index = get_loaded_file(package,filename); + + if (index < 0) + { + ERR("Unable to find file id %s\n",debugstr_w(filename)); + return ERROR_SUCCESS; + } + + len = strlenW(ExeStr); + len += strlenW(package->files[index].TargetPath); + len +=2; + + FullName = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); + strcpyW(FullName,ExeStr); + strcatW(FullName,package->files[index].TargetPath); + strcatW(FullName,close); + + TRACE("Registering %s\n",debugstr_w(FullName)); + brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon, + &si, &info); + + if (brc) + msi_dialog_check_messages(info.hProcess); + + HeapFree(GetProcessHeap(),0,FullName); + return ERROR_SUCCESS; +} + +static UINT ACTION_SelfRegModules(MSIPACKAGE *package) +{ + UINT rc; + MSIQUERY * view; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','S','e','l','f','R','e','g','`',0}; + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); if (rc != ERROR_SUCCESS) { @@ -5563,61 +3323,10 @@ static UINT ACTION_SelfRegModules(MSIPACKAGE *package) return ERROR_SUCCESS; } - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - LPWSTR filename; - INT index; - DWORD len; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - filename = load_dynamic_stringW(row,1); - index = get_loaded_file(package,filename); - - if (index < 0) - { - ERR("Unable to find file id %s\n",debugstr_w(filename)); - HeapFree(GetProcessHeap(),0,filename); - msiobj_release(&row->hdr); - continue; - } - HeapFree(GetProcessHeap(),0,filename); - - len = strlenW(ExeStr); - len += strlenW(package->files[index].TargetPath); - len +=2; - - filename = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); - strcpyW(filename,ExeStr); - strcatW(filename,package->files[index].TargetPath); - strcatW(filename,close); - - TRACE("Registering %s\n",debugstr_w(filename)); - brc = CreateProcessW(NULL, filename, NULL, NULL, FALSE, 0, NULL, - c_colon, &si, &info); - - if (brc) - msi_dialog_check_messages(info.hProcess); - - HeapFree(GetProcessHeap(),0,filename); - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package); msiobj_release(&view->hdr); - return rc; + + return ERROR_SUCCESS; } static UINT ACTION_PublishFeatures(MSIPACKAGE *package) @@ -5723,7 +3432,7 @@ end: static UINT ACTION_RegisterProduct(MSIPACKAGE *package) { HKEY hkey=0; - LPWSTR buffer; + LPWSTR buffer = NULL; LPWSTR productcode; UINT rc,i; DWORD size; @@ -5777,6 +3486,34 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) '%','x','.','m','s','i',0}; static const WCHAR szLocalPackage[]= {'L','o','c','a','l','P','a','c','k','a','g','e',0}; + static const WCHAR szUpgradeCode[] = + {'U','p','g','r','a','d','e','C','o','d','e',0}; + static const WCHAR modpath_fmt[] = + {'M','s','i','E','x','e','c','.','e','x','e',' ','/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0}; + static const WCHAR szModifyPath[] = + {'M','o','d','i','f','y','P','a','t','h',0}; + static const WCHAR szUninstallString[] = + {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0}; + static const WCHAR szEstimatedSize[] = + {'E','s','t','i','m','a','t','e','d','S','i','z','e',0}; + static const WCHAR szInstallDate[] = + {'I','n','s','t','a','l','l','D','a','t','e',0}; + static const WCHAR szLanguage[] = + {'L','a','n','g','u','a','g','e',0}; + static const WCHAR szProductLanguage[] = + {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0}; + static const WCHAR szProductVersion[] = + {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0}; + static const WCHAR szVersion[] = + {'V','e','r','s','i','o','n',0}; + static const WCHAR szVersionMajor[] = + {'V','e','r','s','i','o','n','M','a','j','o','r',0}; + static const WCHAR szVersionMinor[] = + {'V','e','r','s','i','o','n','M','i','n','o','r',0}; + + SYSTEMTIME systime; + static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0}; + LPWSTR upgrade_code; WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH]; INT num,start; @@ -5802,6 +3539,7 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) buffer = szNONE; size = strlenW(buffer)*sizeof(WCHAR); RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size); + HeapFree(GetProcessHeap(),0,buffer); i++; } @@ -5842,6 +3580,60 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) GetLastError()); size = strlenW(packagefile)*sizeof(WCHAR); RegSetValueExW(hkey,szLocalPackage,0,REG_SZ,(LPSTR)packagefile,size); + + /* do ModifyPath and UninstallString */ + size = deformat_string(package,modpath_fmt,&buffer); + RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPSTR)buffer,size); + RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPSTR)buffer,size); + HeapFree(GetProcessHeap(),0,buffer); + + FIXME("Write real Estimated Size when we have it\n"); + size = 0; + RegSetValueExW(hkey,szEstimatedSize,0,REG_DWORD,(LPSTR)&size,sizeof(DWORD)); + + GetLocalTime(&systime); + size = 9*sizeof(WCHAR); + buffer= HeapAlloc(GetProcessHeap(),0,size); + sprintfW(buffer,date_fmt,systime.wYear,systime.wMonth,systime.wDay); + size = strlenW(buffer)*sizeof(WCHAR); + RegSetValueExW(hkey,szInstallDate,0,REG_SZ,(LPSTR)buffer,size); + HeapFree(GetProcessHeap(),0,buffer); + + buffer = load_dynamic_property(package,szProductLanguage,NULL); + size = atoiW(buffer); + RegSetValueExW(hkey,szLanguage,0,REG_DWORD, (LPSTR)&size,sizeof(DWORD)); + HeapFree(GetProcessHeap(),1,buffer); + + buffer = load_dynamic_property(package,szProductVersion,NULL); + if (buffer) + { + DWORD verdword = build_version_dword(buffer); + DWORD vermajor = verdword>>24; + DWORD verminor = (verdword>>16)&0x00FF; + size = sizeof(DWORD); + RegSetValueExW(hkey,szVersion,0,REG_DWORD,(LPSTR)&verdword,size); + RegSetValueExW(hkey,szVersionMajor,0,REG_DWORD,(LPSTR)&vermajor,size); + RegSetValueExW(hkey,szVersionMinor,0,REG_DWORD,(LPSTR)&verminor,size); + } + HeapFree(GetProcessHeap(),0,buffer); + + /* Handle Upgrade Codes */ + upgrade_code = load_dynamic_property(package,szUpgradeCode, NULL); + if (upgrade_code) + { + HKEY hkey2; + WCHAR squashed[33]; + MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE); + squash_guid(productcode,squashed); + RegSetValueExW(hkey2, squashed, 0,REG_SZ,NULL,0); + RegCloseKey(hkey2); + MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE); + squash_guid(productcode,squashed); + RegSetValueExW(hkey2, squashed, 0,REG_SZ,NULL,0); + RegCloseKey(hkey2); + + HeapFree(GetProcessHeap(),0,upgrade_code); + } end: HeapFree(GetProcessHeap(),0,productcode); @@ -5852,52 +3644,35 @@ end: static UINT ACTION_InstallExecute(MSIPACKAGE *package) { - int i; + UINT rc; + if (!package) return ERROR_INVALID_HANDLE; - for (i = 0; i < package->DeferredActionCount; i++) - { - LPWSTR action; - action = package->DeferredAction[i]; - ui_actionstart(package, action); - TRACE("Executing Action (%s)\n",debugstr_w(action)); - ACTION_CustomAction(package,action,TRUE); - HeapFree(GetProcessHeap(),0,package->DeferredAction[i]); - } - HeapFree(GetProcessHeap(),0,package->DeferredAction); + rc = execute_script(package,INSTALL_SCRIPT); - package->DeferredActionCount = 0; - package->DeferredAction = NULL; - - return ERROR_SUCCESS; + return rc; } static UINT ACTION_InstallFinalize(MSIPACKAGE *package) { - int i; + UINT rc; + if (!package) return ERROR_INVALID_HANDLE; + /* turn off scheduleing */ + package->script->CurrentlyScripting= FALSE; + /* first do the same as an InstallExecute */ - ACTION_InstallExecute(package); + rc = ACTION_InstallExecute(package); + if (rc != ERROR_SUCCESS) + return rc; /* then handle Commit Actions */ - for (i = 0; i < package->CommitActionCount; i++) - { - LPWSTR action; - action = package->CommitAction[i]; - ui_actionstart(package, action); - TRACE("Executing Commit Action (%s)\n",debugstr_w(action)); - ACTION_CustomAction(package,action,TRUE); - HeapFree(GetProcessHeap(),0,package->CommitAction[i]); - } - HeapFree(GetProcessHeap(),0,package->CommitAction); + rc = execute_script(package,COMMIT_SCRIPT); - package->CommitActionCount = 0; - package->CommitAction = NULL; - - return ERROR_SUCCESS; + return rc; } static UINT ACTION_ForceReboot(MSIPACKAGE *package) @@ -5999,214 +3774,6 @@ UINT ACTION_ResolveSource(MSIPACKAGE* package) return ERROR_SUCCESS; } - -static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package) -{ - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','E','x','t','e','n','s','i','o','n','`',0}; - static const WCHAR szContentType[] = - {'C','o','n','t','e','n','t',' ','T','y','p','e',0 }; - HKEY hkey; - - if (!package) - return ERROR_INVALID_HANDLE; - - rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - goto end; - } - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - goto end; - } - - while (1) - { - WCHAR buffer[0x100]; - WCHAR extension[257]; - LPWSTR exten; - DWORD sz; - INT index; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - sz=0x100; - MSI_RecordGetStringW(row,2,buffer,&sz); - - index = get_loaded_component(package,buffer); - - if (index < 0) - { - msiobj_release(&row->hdr); - continue; - } - - if ((!ACTION_VerifyComponentForAction(package, index, - INSTALLSTATE_LOCAL)) && - (!ACTION_VerifyComponentForAction(package, index, - INSTALLSTATE_ADVERTISED))) - { - TRACE("Skipping extension reg due to disabled component\n"); - msiobj_release(&row->hdr); - - package->components[index].Action = - package->components[index].Installed; - - continue; - } - - package->components[index].Action = INSTALLSTATE_LOCAL; - - exten = load_dynamic_stringW(row,1); - extension[0] = '.'; - extension[1] = 0; - strcatW(extension,exten); - HeapFree(GetProcessHeap(),0,exten); - - RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey); - - if (!MSI_RecordIsNull(row,4)) - { - LPWSTR mime = load_dynamic_stringW(row,4); - RegSetValueExW(hkey,szContentType,0,REG_SZ,(LPVOID)mime, - (strlenW(mime)+1)*sizeof(WCHAR)); - HeapFree(GetProcessHeap(),0,mime); - } - - if (!MSI_RecordIsNull(row,3)) - { - static const WCHAR szSN[] = - {'\\','S','h','e','l','l','N','e','w',0}; - HKEY hkey2; - LPWSTR newkey; - LPWSTR progid= load_dynamic_stringW(row,3); - - RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid, - (strlenW(progid)+1)*sizeof(WCHAR)); - - newkey = HeapAlloc(GetProcessHeap(),0, - (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR)); - - strcpyW(newkey,progid); - strcatW(newkey,szSN); - RegCreateKeyW(hkey,newkey,&hkey2); - RegCloseKey(hkey2); - - HeapFree(GetProcessHeap(),0,progid); - HeapFree(GetProcessHeap(),0,newkey); - } - - - RegCloseKey(hkey); - - ui_actiondata(package,szRegisterExtensionInfo,row); - - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - -end: - return rc; -} - -static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package) -{ - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','M','I','M','E','`',0}; - static const WCHAR szExten[] = - {'E','x','t','e','n','s','i','o','n',0 }; - HKEY hkey; - - if (!package) - return ERROR_INVALID_HANDLE; - - rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - goto end; - } - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - goto end; - } - - while (1) - { - WCHAR extension[257]; - LPWSTR exten; - LPWSTR mime; - static const WCHAR fmt[] = - {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\', - 'C','o','n','t','e','n','t',' ','T','y','p','e','\\', '%','s',0}; - LPWSTR key; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - mime = load_dynamic_stringW(row,1); - exten = load_dynamic_stringW(row,2); - extension[0] = '.'; - extension[1] = 0; - strcatW(extension,exten); - HeapFree(GetProcessHeap(),0,exten); - - key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) * - sizeof(WCHAR)); - sprintfW(key,fmt,mime); - RegCreateKeyW(HKEY_CLASSES_ROOT,key,&hkey); - RegSetValueExW(hkey,szExten,0,REG_SZ,(LPVOID)extension, - (strlenW(extension)+1)*sizeof(WCHAR)); - - HeapFree(GetProcessHeap(),0,mime); - HeapFree(GetProcessHeap(),0,key); - - if (!MSI_RecordIsNull(row,3)) - { - FIXME("Handle non null for field 3\n"); - } - - RegCloseKey(hkey); - - ui_actiondata(package,szRegisterMIMEInfo,row); - - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - -end: - return rc; -} - static UINT ACTION_RegisterUser(MSIPACKAGE *package) { static const WCHAR szProductID[]= @@ -6274,8 +3841,16 @@ end: static UINT ACTION_ExecuteAction(MSIPACKAGE *package) { + static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0}; + static const WCHAR szTwo[] = {'2',0}; UINT rc; + LPWSTR level; + level = load_dynamic_property(package,szUILevel,NULL); + + MSI_SetPropertyW(package,szUILevel,szTwo); rc = ACTION_ProcessExecSequence(package,FALSE); + MSI_SetPropertyW(package,szUILevel,level); + HeapFree(GetProcessHeap(),0,level); return rc; } @@ -6377,7 +3952,7 @@ static LPWSTR load_ttfname_from(LPCWSTR filename) { int nPos; LPSTR buf; - static const LPSTR tt = " (TrueType)"; + static LPCSTR tt = " (TrueType)"; ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength); ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset); @@ -6412,14 +3987,13 @@ static LPWSTR load_ttfname_from(LPCWSTR filename) return ret; } -static UINT ACTION_RegisterFonts(MSIPACKAGE *package) +static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param) { - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = - {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', - '`','F','o','n','t','`',0}; + MSIPACKAGE *package = (MSIPACKAGE*)param; + LPWSTR name; + LPCWSTR file; + UINT index; + DWORD size; static const WCHAR regfont1[] = {'S','o','f','t','w','a','r','e','\\', 'M','i','c','r','o','s','o','f','t','\\', @@ -6435,7 +4009,52 @@ static UINT ACTION_RegisterFonts(MSIPACKAGE *package) HKEY hkey1; HKEY hkey2; - TRACE("%p\n", package); + file = MSI_RecordGetString(row,1); + index = get_loaded_file(package,file); + if (index < 0) + { + ERR("Unable to load file\n"); + return ERROR_SUCCESS; + } + + /* check to make sure that component is installed */ + if (!ACTION_VerifyComponentForAction(package, + package->files[index].ComponentIndex, INSTALLSTATE_LOCAL)) + { + TRACE("Skipping: Component not scheduled for install\n"); + return ERROR_SUCCESS; + } + + RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1); + RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2); + + if (MSI_RecordIsNull(row,2)) + name = load_ttfname_from(package->files[index].TargetPath); + else + name = load_dynamic_stringW(row,2); + + if (name) + { + size = strlenW(package->files[index].FileName) * sizeof(WCHAR); + RegSetValueExW(hkey1,name,0,REG_SZ, + (LPBYTE)package->files[index].FileName,size); + RegSetValueExW(hkey2,name,0,REG_SZ, + (LPBYTE)package->files[index].FileName,size); + } + + HeapFree(GetProcessHeap(),0,name); + RegCloseKey(hkey1); + RegCloseKey(hkey2); + return ERROR_SUCCESS; +} + +static UINT ACTION_RegisterFonts(MSIPACKAGE *package) +{ + UINT rc; + MSIQUERY * view; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','F','o','n','t','`',0}; rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); if (rc != ERROR_SUCCESS) @@ -6444,182 +4063,77 @@ static UINT ACTION_RegisterFonts(MSIPACKAGE *package) return ERROR_SUCCESS; } - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - TRACE("MSI_ViewExecute returned %d\n", rc); - return ERROR_SUCCESS; - } - - RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1); - RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2); - - while (1) - { - LPWSTR name; - LPWSTR file; - UINT index; - DWORD size; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - file = load_dynamic_stringW(row,1); - index = get_loaded_file(package,file); - if (index < 0) - { - ERR("Unable to load file\n"); - HeapFree(GetProcessHeap(),0,file); - continue; - } - - /* check to make sure that component is installed */ - if (!ACTION_VerifyComponentForAction(package, - package->files[index].ComponentIndex, INSTALLSTATE_LOCAL)) - { - TRACE("Skipping: Component not scheduled for install\n"); - HeapFree(GetProcessHeap(),0,file); - - msiobj_release(&row->hdr); - - continue; - } - - if (MSI_RecordIsNull(row,2)) - name = load_ttfname_from(package->files[index].TargetPath); - else - name = load_dynamic_stringW(row,2); - - if (name) - { - size = strlenW(package->files[index].FileName) * sizeof(WCHAR); - RegSetValueExW(hkey1,name,0,REG_SZ, - (LPBYTE)package->files[index].FileName,size); - RegSetValueExW(hkey2,name,0,REG_SZ, - (LPBYTE)package->files[index].FileName,size); - } - - HeapFree(GetProcessHeap(),0,file); - HeapFree(GetProcessHeap(),0,name); - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); + MSI_IterateRecords(view, NULL, ITERATE_RegisterFonts, package); msiobj_release(&view->hdr); - RegCloseKey(hkey1); - RegCloseKey(hkey2); - - TRACE("returning %d\n", rc); - return rc; + return ERROR_SUCCESS; } static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param) { MSIPACKAGE *package = (MSIPACKAGE*)param; - LPWSTR productid=NULL, compgroupid=NULL; - LPWSTR feature=NULL; - LPWSTR text = NULL; - LPWSTR qualifier = NULL; - LPWSTR component = NULL; - GUID clsid; - WCHAR productid_85[21]; - WCHAR component_85[21]; + LPCWSTR compgroupid=NULL; + LPCWSTR feature=NULL; + LPCWSTR text = NULL; + LPCWSTR qualifier = NULL; + LPCWSTR component = NULL; + LPWSTR advertise = NULL; + LPWSTR output = NULL; HKEY hkey; UINT rc = ERROR_SUCCESS; UINT index; - /* - * I have a fair bit of confusion as to when a < is used and when a > is - * used. I do not think i have it right... - * - * Ok it appears that the > is used if there is a guid for the compoenent - * and the < is used if not. - */ - static WCHAR fmt1[] = {'%','s','%','s','<',0,0}; - static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0}; - LPWSTR output = NULL; DWORD sz = 0; - INT component_index; - component = load_dynamic_stringW(rec,3); - component_index = get_loaded_component(package,component); + component = MSI_RecordGetString(rec,3); + index = get_loaded_component(package,component); - if (!ACTION_VerifyComponentForAction(package, component_index, + if (!ACTION_VerifyComponentForAction(package, index, INSTALLSTATE_LOCAL) && - !ACTION_VerifyComponentForAction(package, component_index, + !ACTION_VerifyComponentForAction(package, index, INSTALLSTATE_SOURCE) && - !ACTION_VerifyComponentForAction(package, component_index, + !ACTION_VerifyComponentForAction(package, index, INSTALLSTATE_ADVERTISED)) { TRACE("Skipping: Component %s not scheduled for install\n", debugstr_w(component)); - HeapFree(GetProcessHeap(),0,component); + return ERROR_SUCCESS; } - memset(productid_85,0,sizeof(productid_85)); - memset(component_85,0,sizeof(component_85)); - compgroupid = load_dynamic_stringW(rec,1); + compgroupid = MSI_RecordGetString(rec,1); rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE); if (rc != ERROR_SUCCESS) goto end; - productid = load_dynamic_property(package,szProductCode,NULL); - CLSIDFromString(productid, &clsid); - - encode_base85_guid(&clsid,productid_85); - - text = load_dynamic_stringW(rec,4); - qualifier = load_dynamic_stringW(rec,2); - - feature = load_dynamic_stringW(rec,5); + text = MSI_RecordGetString(rec,4); + qualifier = MSI_RecordGetString(rec,2); + feature = MSI_RecordGetString(rec,5); - index = get_loaded_component(package, component); - CLSIDFromString(package->components[index].ComponentId, &clsid); - encode_base85_guid(&clsid,component_85); + advertise = create_component_advertise_string(package, + &package->components[index], feature); + + sz = strlenW(advertise); - TRACE("Doing something with this... %s = %s %s %s %s\n", - debugstr_w(qualifier), debugstr_w(productid_85), - debugstr_w(feature), debugstr_w(text), debugstr_w(component_85)); - - sz = lstrlenW(productid_85) + lstrlenW(feature); if (text) sz += lstrlenW(text); - if (component && index >= 0) - sz += lstrlenW(component_85); sz+=3; sz *= sizeof(WCHAR); output = HeapAlloc(GetProcessHeap(),0,sz); memset(output,0,sz); - - if (component && index >= 0) - sprintfW(output,fmt2,productid_85,feature,component_85); - else - sprintfW(output,fmt1,productid_85,feature); + strcpyW(output,advertise); if (text) strcatW(output,text); sz = (lstrlenW(output)+2) * sizeof(WCHAR); - RegSetValueExW(hkey, qualifier,0,REG_MULTI_SZ, (LPBYTE)output, sz); + RegSetValueExW(hkey, qualifier,0,REG_MULTI_SZ, (LPBYTE)output, sz); end: RegCloseKey(hkey); HeapFree(GetProcessHeap(),0,output); - HeapFree(GetProcessHeap(),0,compgroupid); - HeapFree(GetProcessHeap(),0,component); - HeapFree(GetProcessHeap(),0,productid); - HeapFree(GetProcessHeap(),0,feature); - HeapFree(GetProcessHeap(),0,text); - HeapFree(GetProcessHeap(),0,qualifier); return rc; } @@ -6646,553 +4160,3 @@ static UINT ACTION_PublishComponents(MSIPACKAGE *package) return rc; } - -/* Msi functions that seem appropriate here */ - -/*********************************************************************** - * MsiDoActionA (MSI.@) - */ -UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction ) -{ - LPWSTR szwAction; - UINT rc; - - TRACE(" exteral attempt at action %s\n",szAction); - - if (!szAction) - return ERROR_FUNCTION_FAILED; - if (hInstall == 0) - return ERROR_FUNCTION_FAILED; - - szwAction = strdupAtoW(szAction); - - if (!szwAction) - return ERROR_FUNCTION_FAILED; - - - rc = MsiDoActionW(hInstall, szwAction); - HeapFree(GetProcessHeap(),0,szwAction); - return rc; -} - -/*********************************************************************** - * MsiDoActionW (MSI.@) - */ -UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction ) -{ - MSIPACKAGE *package; - UINT ret = ERROR_INVALID_HANDLE; - - TRACE(" external attempt at action %s \n",debugstr_w(szAction)); - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if( package ) - { - ret = ACTION_PerformUIAction(package,szAction); - msiobj_release( &package->hdr ); - } - return ret; -} - -UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder, - LPSTR szPathBuf, DWORD* pcchPathBuf) -{ - LPWSTR szwFolder; - LPWSTR szwPathBuf; - UINT rc; - - TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf); - - if (!szFolder) - return ERROR_FUNCTION_FAILED; - if (hInstall == 0) - return ERROR_FUNCTION_FAILED; - - szwFolder = strdupAtoW(szFolder); - - if (!szwFolder) - return ERROR_FUNCTION_FAILED; - - szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR)); - - rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf); - - WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf, - *pcchPathBuf, NULL, NULL ); - - HeapFree(GetProcessHeap(),0,szwFolder); - HeapFree(GetProcessHeap(),0,szwPathBuf); - - return rc; -} - -UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR - szPathBuf, DWORD* pcchPathBuf) -{ - LPWSTR path; - UINT rc = ERROR_FUNCTION_FAILED; - MSIPACKAGE *package; - - TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf); - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - path = resolve_folder(package, szFolder, FALSE, FALSE, NULL); - msiobj_release( &package->hdr ); - - if (path && (strlenW(path) > *pcchPathBuf)) - { - *pcchPathBuf = strlenW(path)+1; - rc = ERROR_MORE_DATA; - } - else if (path) - { - *pcchPathBuf = strlenW(path)+1; - strcpyW(szPathBuf,path); - TRACE("Returning Path %s\n",debugstr_w(path)); - rc = ERROR_SUCCESS; - } - HeapFree(GetProcessHeap(),0,path); - - return rc; -} - - -UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder, - LPSTR szPathBuf, DWORD* pcchPathBuf) -{ - LPWSTR szwFolder; - LPWSTR szwPathBuf; - UINT rc; - - TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf); - - if (!szFolder) - return ERROR_FUNCTION_FAILED; - if (hInstall == 0) - return ERROR_FUNCTION_FAILED; - - szwFolder = strdupAtoW(szFolder); - if (!szwFolder) - return ERROR_FUNCTION_FAILED; - - szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR)); - - rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf); - - WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf, - *pcchPathBuf, NULL, NULL ); - - HeapFree(GetProcessHeap(),0,szwFolder); - HeapFree(GetProcessHeap(),0,szwPathBuf); - - return rc; -} - -UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR - szPathBuf, DWORD* pcchPathBuf) -{ - LPWSTR path; - UINT rc = ERROR_FUNCTION_FAILED; - MSIPACKAGE *package; - - TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf); - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if( !package ) - return ERROR_INVALID_HANDLE; - path = resolve_folder(package, szFolder, TRUE, FALSE, NULL); - msiobj_release( &package->hdr ); - - if (path && strlenW(path) > *pcchPathBuf) - { - *pcchPathBuf = strlenW(path)+1; - rc = ERROR_MORE_DATA; - } - else if (path) - { - *pcchPathBuf = strlenW(path)+1; - strcpyW(szPathBuf,path); - TRACE("Returning Path %s\n",debugstr_w(path)); - rc = ERROR_SUCCESS; - } - HeapFree(GetProcessHeap(),0,path); - - return rc; -} - - -/*********************************************************************** - * MsiSetTargetPathA (MSI.@) - */ -UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder, - LPCSTR szFolderPath) -{ - LPWSTR szwFolder; - LPWSTR szwFolderPath; - UINT rc; - - if (!szFolder) - return ERROR_FUNCTION_FAILED; - if (hInstall == 0) - return ERROR_FUNCTION_FAILED; - - szwFolder = strdupAtoW(szFolder); - if (!szwFolder) - return ERROR_FUNCTION_FAILED; - - szwFolderPath = strdupAtoW(szFolderPath); - if (!szwFolderPath) - { - HeapFree(GetProcessHeap(),0,szwFolder); - return ERROR_FUNCTION_FAILED; - } - - rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath); - - HeapFree(GetProcessHeap(),0,szwFolder); - HeapFree(GetProcessHeap(),0,szwFolderPath); - - return rc; -} - -UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, - LPCWSTR szFolderPath) -{ - DWORD i; - LPWSTR path = NULL; - LPWSTR path2 = NULL; - MSIFOLDER *folder; - - TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath)); - - if (package==NULL) - return ERROR_INVALID_HANDLE; - - if (szFolderPath[0]==0) - return ERROR_FUNCTION_FAILED; - - if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES) - return ERROR_FUNCTION_FAILED; - - path = resolve_folder(package,szFolder,FALSE,FALSE,&folder); - - if (!path) - return ERROR_INVALID_PARAMETER; - - HeapFree(GetProcessHeap(),0,folder->Property); - folder->Property = build_directory_name(2, szFolderPath, NULL); - - if (lstrcmpiW(path, folder->Property) == 0) - { - /* - * Resolved Target has not really changed, so just - * set this folder and do not recalculate everything. - */ - HeapFree(GetProcessHeap(),0,folder->ResolvedTarget); - folder->ResolvedTarget = NULL; - path2 = resolve_folder(package,szFolder,FALSE,TRUE,NULL); - HeapFree(GetProcessHeap(),0,path2); - } - else - { - for (i = 0; i < package->loaded_folders; i++) - { - HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget); - package->folders[i].ResolvedTarget=NULL; - } - - for (i = 0; i < package->loaded_folders; i++) - { - path2=resolve_folder(package, package->folders[i].Directory, FALSE, - TRUE, NULL); - HeapFree(GetProcessHeap(),0,path2); - } - } - HeapFree(GetProcessHeap(),0,path); - - return ERROR_SUCCESS; -} - -/*********************************************************************** - * MsiSetTargetPathW (MSI.@) - */ -UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, - LPCWSTR szFolderPath) -{ - MSIPACKAGE *package; - UINT ret; - - TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath)); - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - ret = MSI_SetTargetPathW( package, szFolder, szFolderPath ); - msiobj_release( &package->hdr ); - return ret; -} - -/*********************************************************************** - * MsiGetMode (MSI.@) - * - * Returns an internal installer state (if it is running in a mode iRunMode) - * - * PARAMS - * hInstall [I] Handle to the installation - * hRunMode [I] Checking run mode - * MSIRUNMODE_ADMIN Administrative mode - * MSIRUNMODE_ADVERTISE Advertisement mode - * MSIRUNMODE_MAINTENANCE Maintenance mode - * MSIRUNMODE_ROLLBACKENABLED Rollback is enabled - * MSIRUNMODE_LOGENABLED Log file is writing - * MSIRUNMODE_OPERATIONS Operations in progress?? - * MSIRUNMODE_REBOOTATEND We need to reboot after installation completed - * MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation - * MSIRUNMODE_CABINET Files from cabinet are installed - * MSIRUNMODE_SOURCESHORTNAMES Long names in source files is suppressed - * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is suppressed - * MSIRUNMODE_RESERVED11 Reserved - * MSIRUNMODE_WINDOWS9X Running under Windows95/98 - * MSIRUNMODE_ZAWENABLED Demand installation is supported - * MSIRUNMODE_RESERVED14 Reserved - * MSIRUNMODE_RESERVED15 Reserved - * MSIRUNMODE_SCHEDULED called from install script - * MSIRUNMODE_ROLLBACK called from rollback script - * MSIRUNMODE_COMMIT called from commit script - * - * RETURNS - * In the state: TRUE - * Not in the state: FALSE - * - */ - -BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode) -{ - FIXME("STUB (iRunMode=%i)\n",iRunMode); - return TRUE; -} - -/*********************************************************************** - * MsiSetFeatureStateA (MSI.@) - * - * According to the docs, when this is called it immediately recalculates - * all the component states as well - */ -UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature, - INSTALLSTATE iState) -{ - LPWSTR szwFeature = NULL; - UINT rc; - - szwFeature = strdupAtoW(szFeature); - - if (!szwFeature) - return ERROR_FUNCTION_FAILED; - - rc = MsiSetFeatureStateW(hInstall,szwFeature, iState); - - HeapFree(GetProcessHeap(),0,szwFeature); - - return rc; -} - - - -UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature, - INSTALLSTATE iState) -{ - INT index, i; - UINT rc = ERROR_SUCCESS; - - TRACE(" %s to %i\n",debugstr_w(szFeature), iState); - - index = get_loaded_feature(package,szFeature); - if (index < 0) - return ERROR_UNKNOWN_FEATURE; - - package->features[index].ActionRequest= iState; - package->features[index].Action= iState; - - ACTION_UpdateComponentStates(package,szFeature); - - /* update all the features that are children of this feature */ - for (i = 0; i < package->loaded_features; i++) - { - if (strcmpW(szFeature, package->features[i].Feature_Parent) == 0) - MSI_SetFeatureStateW(package, package->features[i].Feature, iState); - } - - return rc; -} - -/*********************************************************************** - * MsiSetFeatureStateW (MSI.@) - */ -UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature, - INSTALLSTATE iState) -{ - MSIPACKAGE* package; - UINT rc = ERROR_SUCCESS; - - TRACE(" %s to %i\n",debugstr_w(szFeature), iState); - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - - rc = MSI_SetFeatureStateW(package,szFeature,iState); - - msiobj_release( &package->hdr ); - return rc; -} - -UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature, - INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) -{ - LPWSTR szwFeature = NULL; - UINT rc; - - szwFeature = strdupAtoW(szFeature); - - rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction); - - HeapFree( GetProcessHeap(), 0 , szwFeature); - - return rc; -} - -UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature, - INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) -{ - INT index; - - index = get_loaded_feature(package,szFeature); - if (index < 0) - return ERROR_UNKNOWN_FEATURE; - - if (piInstalled) - *piInstalled = package->features[index].Installed; - - if (piAction) - *piAction = package->features[index].Action; - - TRACE("returning %i %i\n",*piInstalled,*piAction); - - return ERROR_SUCCESS; -} - -UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature, - INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) -{ - MSIPACKAGE* package; - UINT ret; - - TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled, -piAction); - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction); - msiobj_release( &package->hdr ); - return ret; -} - -/*********************************************************************** - * MsiGetComponentStateA (MSI.@) - */ -UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent, - INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) -{ - LPWSTR szwComponent= NULL; - UINT rc; - - szwComponent= strdupAtoW(szComponent); - - rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction); - - HeapFree( GetProcessHeap(), 0 , szwComponent); - - return rc; -} - -UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent, - INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) -{ - INT index; - - TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled, -piAction); - - index = get_loaded_component(package,szComponent); - if (index < 0) - return ERROR_UNKNOWN_COMPONENT; - - if (piInstalled) - *piInstalled = package->components[index].Installed; - - if (piAction) - *piAction = package->components[index].Action; - - TRACE("states (%i, %i)\n", -(piInstalled)?*piInstalled:-1,(piAction)?*piAction:-1); - - return ERROR_SUCCESS; -} - -/*********************************************************************** - * MsiGetComponentStateW (MSI.@) - */ -UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent, - INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) -{ - MSIPACKAGE* package; - UINT ret; - - TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent), - piInstalled, piAction); - - package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction); - msiobj_release( &package->hdr ); - return ret; -} - -#if 0 -static UINT ACTION_Template(MSIPACKAGE *package) -{ - UINT rc; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = {0}; - - rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); - if (rc != ERROR_SUCCESS) - return rc; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - while (1) - { - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - rc = ERROR_SUCCESS; - break; - } - - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; -} -#endif diff --git a/reactos/lib/msi/action.h b/reactos/lib/msi/action.h index a88a07f5e15..9c472a53f15 100644 --- a/reactos/lib/msi/action.h +++ b/reactos/lib/msi/action.h @@ -18,15 +18,17 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define IDENTIFIER_SIZE 96 + typedef struct tagMSIFEATURE { - WCHAR Feature[96]; - WCHAR Feature_Parent[96]; + WCHAR Feature[IDENTIFIER_SIZE]; + WCHAR Feature_Parent[IDENTIFIER_SIZE]; WCHAR Title[0x100]; WCHAR Description[0x100]; INT Display; INT Level; - WCHAR Directory[96]; + WCHAR Directory[IDENTIFIER_SIZE]; INT Attributes; INSTALLSTATE Installed; @@ -40,12 +42,12 @@ typedef struct tagMSIFEATURE typedef struct tagMSICOMPONENT { - WCHAR Component[96]; - WCHAR ComponentId[96]; - WCHAR Directory[96]; + WCHAR Component[IDENTIFIER_SIZE]; + WCHAR ComponentId[IDENTIFIER_SIZE]; + WCHAR Directory[IDENTIFIER_SIZE]; INT Attributes; WCHAR Condition[0x100]; - WCHAR KeyPath[96]; + WCHAR KeyPath[IDENTIFIER_SIZE]; INSTALLSTATE Installed; INSTALLSTATE ActionRequest; @@ -56,6 +58,7 @@ typedef struct tagMSICOMPONENT INT RefCount; LPWSTR FullKeypath; + LPWSTR AdvertiseString; } MSICOMPONENT; typedef struct tagMSIFOLDER @@ -100,14 +103,117 @@ typedef struct tagMSIFILE BOOL Temporary; }MSIFILE; +typedef struct tagMSICLASS +{ + WCHAR CLSID[IDENTIFIER_SIZE]; /* Primary Key */ + WCHAR Context[IDENTIFIER_SIZE]; /* Primary Key */ + INT ComponentIndex; /* Primary Key */ + INT ProgIDIndex; + LPWSTR ProgIDText; + LPWSTR Description; + INT AppIDIndex; + LPWSTR FileTypeMask; + LPWSTR IconPath; + LPWSTR DefInprocHandler; + LPWSTR DefInprocHandler32; + LPWSTR Argument; + INT FeatureIndex; + INT Attributes; + /* not in the table, set during installation */ + BOOL Installed; +} MSICLASS; -UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action); +typedef struct tagMSIEXTENSION +{ + WCHAR Extension[256]; /* Primary Key */ + INT ComponentIndex; /* Primary Key */ + INT ProgIDIndex; + LPWSTR ProgIDText; + INT MIMEIndex; + INT FeatureIndex; + /* not in the table, set during installation */ + BOOL Installed; + INT VerbCount; + INT Verbs[100]; /* yes hard coded limit, but realistically 100 verbs??? */ +} MSIEXTENSION; + +typedef struct tagMSIPROGID +{ + LPWSTR ProgID; /* Primary Key */ + INT ParentIndex; + INT ClassIndex; + LPWSTR Description; + LPWSTR IconPath; + /* not in the table, set during installation */ + BOOL InstallMe; + INT CurVerIndex; + INT VersionIndIndex; +} MSIPROGID; + +typedef struct tagMSIVERB +{ + INT ExtensionIndex; + LPWSTR Verb; + INT Sequence; + LPWSTR Command; + LPWSTR Argument; +} MSIVERB; + +typedef struct tagMSIMIME +{ + LPWSTR ContentType; /* Primary Key */ + INT ExtensionIndex; + WCHAR CLSID[IDENTIFIER_SIZE]; + INT ClassIndex; + /* not in the table, set during installation */ + BOOL InstallMe; +} MSIMIME; + +typedef struct tagMSIAPPID +{ + WCHAR AppID[IDENTIFIER_SIZE]; /* Primary key */ + LPWSTR RemoteServerName; + LPWSTR LocalServer; + LPWSTR ServiceParameters; + LPWSTR DllSurrogate; + BOOL ActivateAtStorage; + BOOL RunAsInteractiveUser; +} MSIAPPID; + +enum SCRIPTS { + INSTALL_SCRIPT = 0, + COMMIT_SCRIPT = 1, + ROLLBACK_SCRIPT = 2, + TOTAL_SCRIPTS = 3 +}; + +typedef struct tagMSISCRIPT +{ + LPWSTR *Actions[TOTAL_SCRIPTS]; + UINT ActionCount[TOTAL_SCRIPTS]; + BOOL ExecuteSequenceRun; + BOOL FindRelatedProductsRun; + BOOL CurrentlyScripting; +}MSISCRIPT; + + +UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force); UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action); void ACTION_FinishCustomActions( MSIPACKAGE* package); UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action, BOOL execute); -void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature); -UINT ACTION_AppSearch(MSIPACKAGE *package); +/* actions in other modules */ +UINT ACTION_AppSearch(MSIPACKAGE *package); +UINT ACTION_FindRelatedProducts(MSIPACKAGE *package); +UINT ACTION_InstallFiles(MSIPACKAGE *package); +UINT ACTION_DuplicateFiles(MSIPACKAGE *package); +UINT ACTION_RegisterClassInfo(MSIPACKAGE *package); +UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package); +UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package); +UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package); + + +/* Helpers */ DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data ); WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index); LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc); @@ -117,3 +223,35 @@ int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component ); int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature ); int get_loaded_file(MSIPACKAGE* package, LPCWSTR file); int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path); +UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action); +UINT build_icon_path(MSIPACKAGE *, LPCWSTR, LPWSTR *); +DWORD build_version_dword(LPCWSTR); +LPWSTR build_directory_name(DWORD , ...); +BOOL create_full_pathW(const WCHAR *path); +BOOL ACTION_VerifyComponentForAction(MSIPACKAGE*, INT, INSTALLSTATE); +BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE*, INT, INSTALLSTATE); +void reduce_to_longfilename(WCHAR*); +void reduce_to_shortfilename(WCHAR*); +LPWSTR create_component_advertise_string(MSIPACKAGE*, MSICOMPONENT*, LPCWSTR); +void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature); + + +/* control event stuff */ +VOID ControlEvent_FireSubscribedEvent(MSIPACKAGE *package, LPCWSTR event, + MSIRECORD *data); +VOID ControlEvent_CleanupSubscriptions(MSIPACKAGE *package); +VOID ControlEvent_SubscribeToEvent(MSIPACKAGE *package, LPCWSTR event, + LPCWSTR control, LPCWSTR attribute); +VOID ControlEvent_UnSubscribeToEvent( MSIPACKAGE *package, LPCWSTR event, + LPCWSTR control, LPCWSTR attribute ); + +/* User Interface messages from the actions */ +void ui_progress(MSIPACKAGE *, int, int, int, int); +void ui_actiondata(MSIPACKAGE *, LPCWSTR, MSIRECORD *); + + +/* string consts use a number of places and defined in helpers.c*/ +extern const WCHAR cszSourceDir[]; +extern const WCHAR szProductCode[]; +extern const WCHAR cszRootDrive[]; +extern const WCHAR cszbs[]; diff --git a/reactos/lib/msi/classes.c b/reactos/lib/msi/classes.c new file mode 100644 index 00000000000..ed0f550994c --- /dev/null +++ b/reactos/lib/msi/classes.c @@ -0,0 +1,1602 @@ +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2005 Aric Stewart for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* actions handled in this module + * RegisterClassInfo + * RegisterProgIdInfo + * RegisterExtensionInfo + * RegisterMIMEInfo + * UnRegisterClassInfo (TODO) + * UnRegisterProgIdInfo (TODO) + * UnRegisterExtensionInfo (TODO) + * UnRegisterMIMEInfo (TODO) + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" +#include "wine/debug.h" +#include "msipriv.h" +#include "winuser.h" +#include "wine/unicode.h" +#include "action.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + + +extern const WCHAR szRegisterClassInfo[]; +extern const WCHAR szRegisterProgIdInfo[]; +extern const WCHAR szRegisterExtensionInfo[]; +extern const WCHAR szRegisterMIMEInfo[]; + +extern const WCHAR szUnregisterClassInfo[]; +extern const WCHAR szUnregisterExtensionInfo[]; +extern const WCHAR szUnregisterMIMEInfo[]; +extern const WCHAR szUnregisterProgIdInfo[]; + +static INT load_appid(MSIPACKAGE* package, MSIRECORD *row) +{ + DWORD index = package->loaded_appids; + DWORD sz; + LPCWSTR buffer; + + /* fill in the data */ + + package->loaded_appids++; + if (package->loaded_appids == 1) + package->appids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIAPPID)); + else + package->appids = HeapReAlloc(GetProcessHeap(),0, + package->appids, package->loaded_appids * sizeof(MSIAPPID)); + + memset(&package->appids[index],0,sizeof(MSIAPPID)); + + sz = IDENTIFIER_SIZE; + MSI_RecordGetStringW(row, 1, package->appids[index].AppID, &sz); + TRACE("loading appid %s\n",debugstr_w(package->appids[index].AppID)); + + buffer = MSI_RecordGetString(row,2); + deformat_string(package,buffer,&package->appids[index].RemoteServerName); + + package->appids[index].LocalServer = load_dynamic_stringW(row,3); + package->appids[index].ServiceParameters = load_dynamic_stringW(row,4); + package->appids[index].DllSurrogate = load_dynamic_stringW(row,5); + + package->appids[index].ActivateAtStorage = !MSI_RecordIsNull(row,6); + package->appids[index].RunAsInteractiveUser = !MSI_RecordIsNull(row,7); + + return index; +} + +static INT load_given_appid(MSIPACKAGE *package, LPCWSTR appid) +{ + INT rc; + MSIRECORD *row; + INT i; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','A','p','p','I','d','`',' ','W','H','E','R','E',' ', + '`','A','p','p','I','d','`',' ','=',' ','\'','%','s','\'',0}; + + if (!appid) + return -1; + + /* check for appids already loaded */ + for (i = 0; i < package->loaded_appids; i++) + if (strcmpiW(package->appids[i].AppID,appid)==0) + { + TRACE("found appid %s at index %i\n",debugstr_w(appid),i); + return i; + } + + row = MSI_QueryGetRecord(package->db, ExecSeqQuery, appid); + if (!row) + return -1; + + rc = load_appid(package, row); + msiobj_release(&row->hdr); + + return rc; +} + +static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid); +static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid); + +static INT load_progid(MSIPACKAGE* package, MSIRECORD *row) +{ + DWORD index = package->loaded_progids; + LPCWSTR buffer; + + /* fill in the data */ + + package->loaded_progids++; + if (package->loaded_progids == 1) + package->progids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIPROGID)); + else + package->progids = HeapReAlloc(GetProcessHeap(),0, + package->progids , package->loaded_progids * sizeof(MSIPROGID)); + + memset(&package->progids[index],0,sizeof(MSIPROGID)); + + package->progids[index].ProgID = load_dynamic_stringW(row,1); + TRACE("loading progid %s\n",debugstr_w(package->progids[index].ProgID)); + + buffer = MSI_RecordGetString(row,2); + package->progids[index].ParentIndex = load_given_progid(package,buffer); + if (package->progids[index].ParentIndex < 0 && buffer) + FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer)); + + buffer = MSI_RecordGetString(row,3); + package->progids[index].ClassIndex = load_given_class(package,buffer); + if (package->progids[index].ClassIndex< 0 && buffer) + FIXME("Unknown class %s\n",debugstr_w(buffer)); + + package->progids[index].Description = load_dynamic_stringW(row,4); + + if (!MSI_RecordIsNull(row,6)) + { + INT icon_index = MSI_RecordGetInteger(row,6); + LPWSTR FileName = load_dynamic_stringW(row,5); + LPWSTR FilePath; + static const WCHAR fmt[] = {'%','s',',','%','i',0}; + + build_icon_path(package,FileName,&FilePath); + + package->progids[index].IconPath = + HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+10)* + sizeof(WCHAR)); + + sprintfW(package->progids[index].IconPath,fmt,FilePath,icon_index); + + HeapFree(GetProcessHeap(),0,FilePath); + HeapFree(GetProcessHeap(),0,FileName); + } + else + { + buffer = MSI_RecordGetString(row,5); + if (buffer) + build_icon_path(package,buffer,&(package->progids[index].IconPath)); + } + + package->progids[index].CurVerIndex = -1; + package->progids[index].VersionIndIndex = -1; + + /* if we have a parent then we may be that parents CurVer */ + if (package->progids[index].ParentIndex >= 0 && + package->progids[index].ParentIndex != index) + { + int pindex = package->progids[index].ParentIndex; + while (package->progids[pindex].ParentIndex>= 0 && + package->progids[pindex].ParentIndex != pindex) + pindex = package->progids[pindex].ParentIndex; + + FIXME("BAD BAD need to determing if we are really the CurVer\n"); + + package->progids[index].CurVerIndex = pindex; + package->progids[pindex].VersionIndIndex = index; + } + + return index; +} + +static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid) +{ + INT rc; + MSIRECORD *row; + INT i; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','P','r','o','g','I','d','`',' ','W','H','E','R','E',' ', + '`','P','r','o','g','I','d','`',' ','=',' ','\'','%','s','\'',0}; + + if (!progid) + return -1; + + /* check for progids already loaded */ + for (i = 0; i < package->loaded_progids; i++) + if (strcmpiW(package->progids[i].ProgID,progid)==0) + { + TRACE("found progid %s at index %i\n",debugstr_w(progid), i); + return i; + } + + row = MSI_QueryGetRecord(package->db, ExecSeqQuery, progid); + if(!row) + return -1; + + rc = load_progid(package, row); + msiobj_release(&row->hdr); + + return rc; +} + +static INT load_class(MSIPACKAGE* package, MSIRECORD *row) +{ + DWORD index = package->loaded_classes; + DWORD sz,i; + LPCWSTR buffer; + + /* fill in the data */ + + package->loaded_classes++; + if (package->loaded_classes== 1) + package->classes = HeapAlloc(GetProcessHeap(),0,sizeof(MSICLASS)); + else + package->classes = HeapReAlloc(GetProcessHeap(),0, + package->classes, package->loaded_classes * sizeof(MSICLASS)); + + memset(&package->classes[index],0,sizeof(MSICLASS)); + + sz = IDENTIFIER_SIZE; + MSI_RecordGetStringW(row, 1, package->classes[index].CLSID, &sz); + TRACE("loading class %s\n",debugstr_w(package->classes[index].CLSID)); + sz = IDENTIFIER_SIZE; + MSI_RecordGetStringW(row, 2, package->classes[index].Context, &sz); + buffer = MSI_RecordGetString(row,3); + package->classes[index].ComponentIndex = get_loaded_component(package, + buffer); + + package->classes[index].ProgIDText = load_dynamic_stringW(row,4); + package->classes[index].ProgIDIndex = + load_given_progid(package, package->classes[index].ProgIDText); + + package->classes[index].Description = load_dynamic_stringW(row,5); + + buffer = MSI_RecordGetString(row,6); + if (buffer) + package->classes[index].AppIDIndex = + load_given_appid(package, buffer); + else + package->classes[index].AppIDIndex = -1; + + package->classes[index].FileTypeMask = load_dynamic_stringW(row,7); + + if (!MSI_RecordIsNull(row,9)) + { + + INT icon_index = MSI_RecordGetInteger(row,9); + LPWSTR FileName = load_dynamic_stringW(row,8); + LPWSTR FilePath; + static const WCHAR fmt[] = {'%','s',',','%','i',0}; + + build_icon_path(package,FileName,&FilePath); + + package->classes[index].IconPath = + HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)* + sizeof(WCHAR)); + + sprintfW(package->classes[index].IconPath,fmt,FilePath,icon_index); + + HeapFree(GetProcessHeap(),0,FilePath); + HeapFree(GetProcessHeap(),0,FileName); + } + else + { + buffer = MSI_RecordGetString(row,8); + if (buffer) + build_icon_path(package,buffer,&(package->classes[index].IconPath)); + } + + if (!MSI_RecordIsNull(row,10)) + { + i = MSI_RecordGetInteger(row,10); + if (i != MSI_NULL_INTEGER && i > 0 && i < 4) + { + static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0}; + static const WCHAR ole32[] = {'o','l','e','3','2','.','d','l','l',0}; + + switch(i) + { + case 1: + package->classes[index].DefInprocHandler = strdupW(ole2); + break; + case 2: + package->classes[index].DefInprocHandler32 = strdupW(ole32); + break; + case 3: + package->classes[index].DefInprocHandler = strdupW(ole2); + package->classes[index].DefInprocHandler32 = strdupW(ole32); + break; + } + } + else + { + package->classes[index].DefInprocHandler32 = load_dynamic_stringW( + row, 10); + reduce_to_longfilename(package->classes[index].DefInprocHandler32); + } + } + buffer = MSI_RecordGetString(row,11); + deformat_string(package,buffer,&package->classes[index].Argument); + + buffer = MSI_RecordGetString(row,12); + package->classes[index].FeatureIndex = get_loaded_feature(package,buffer); + + package->classes[index].Attributes = MSI_RecordGetInteger(row,13); + + return index; +} + +/* + * the Class table has 3 primary keys. Generally it is only + * referenced through the first CLSID key. However when loading + * all of the classes we need to make sure we do not ignore rows + * with other Context and ComponentIndexs + */ +static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid) +{ + INT rc; + MSIRECORD *row; + INT i; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','C','l','a','s','s','`',' ','W','H','E','R','E',' ', + '`','C','L','S','I','D','`',' ','=',' ','\'','%','s','\'',0}; + + + if (!classid) + return -1; + + /* check for classes already loaded */ + for (i = 0; i < package->loaded_classes; i++) + if (strcmpiW(package->classes[i].CLSID,classid)==0) + { + TRACE("found class %s at index %i\n",debugstr_w(classid), i); + return i; + } + + row = MSI_QueryGetRecord(package->db, ExecSeqQuery, classid); + if (!row) + return -1; + + rc = load_class(package, row); + msiobj_release(&row->hdr); + + return rc; +} + +static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension); + +static INT load_mime(MSIPACKAGE* package, MSIRECORD *row) +{ + DWORD index = package->loaded_mimes; + DWORD sz; + LPCWSTR buffer; + + /* fill in the data */ + + package->loaded_mimes++; + if (package->loaded_mimes== 1) + package->mimes= HeapAlloc(GetProcessHeap(),0,sizeof(MSIMIME)); + else + package->mimes= HeapReAlloc(GetProcessHeap(),0, + package->mimes, package->loaded_mimes* + sizeof(MSIMIME)); + + memset(&package->mimes[index],0,sizeof(MSIMIME)); + + package->mimes[index].ContentType = load_dynamic_stringW(row,1); + TRACE("loading mime %s\n",debugstr_w(package->mimes[index].ContentType)); + + buffer = MSI_RecordGetString(row,2); + package->mimes[index].ExtensionIndex = load_given_extension(package, + buffer); + + sz = IDENTIFIER_SIZE; + MSI_RecordGetStringW(row,3,package->mimes[index].CLSID,&sz); + package->mimes[index].ClassIndex= load_given_class(package, + package->mimes[index].CLSID); + + return index; +} + +static INT load_given_mime(MSIPACKAGE *package, LPCWSTR mime) +{ + INT rc; + MSIRECORD *row; + INT i; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','M','I','M','E','`',' ','W','H','E','R','E',' ', + '`','C','o','n','t','e','n','t','T','y','p','e','`',' ','=',' ', + '\'','%','s','\'',0}; + + if (!mime) + return -1; + + /* check for mime already loaded */ + for (i = 0; i < package->loaded_mimes; i++) + if (strcmpiW(package->mimes[i].ContentType,mime)==0) + { + TRACE("found mime %s at index %i\n",debugstr_w(mime), i); + return i; + } + + row = MSI_QueryGetRecord(package->db, ExecSeqQuery, mime); + if (!row) + return -1; + + rc = load_mime(package, row); + msiobj_release(&row->hdr); + + return rc; +} + +static INT load_extension(MSIPACKAGE* package, MSIRECORD *row) +{ + DWORD index = package->loaded_extensions; + DWORD sz; + LPCWSTR buffer; + + /* fill in the data */ + + package->loaded_extensions++; + if (package->loaded_extensions == 1) + package->extensions = HeapAlloc(GetProcessHeap(),0,sizeof(MSIEXTENSION)); + else + package->extensions = HeapReAlloc(GetProcessHeap(),0, + package->extensions, package->loaded_extensions* + sizeof(MSIEXTENSION)); + + memset(&package->extensions[index],0,sizeof(MSIEXTENSION)); + + sz = 256; + MSI_RecordGetStringW(row,1,package->extensions[index].Extension,&sz); + TRACE("loading extension %s\n", + debugstr_w(package->extensions[index].Extension)); + + buffer = MSI_RecordGetString(row,2); + package->extensions[index].ComponentIndex = + get_loaded_component(package,buffer); + + package->extensions[index].ProgIDText = load_dynamic_stringW(row,3); + package->extensions[index].ProgIDIndex = load_given_progid(package, + package->extensions[index].ProgIDText); + + buffer = MSI_RecordGetString(row,4); + package->extensions[index].MIMEIndex = load_given_mime(package,buffer); + + buffer = MSI_RecordGetString(row,5); + package->extensions[index].FeatureIndex = + get_loaded_feature(package,buffer); + + return index; +} + +/* + * While the extension table has 2 primary keys, this function is only looking + * at the Extension key which is what is referenced as a forign key + */ +static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension) +{ + INT rc; + MSIRECORD *row; + INT i; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','E','x','t','e','n','s','i','o','n','`',' ', + 'W','H','E','R','E',' ', + '`','E','x','t','e','n','s','i','o','n','`',' ','=',' ', + '\'','%','s','\'',0}; + + if (!extension) + return -1; + + /* check for extensions already loaded */ + for (i = 0; i < package->loaded_extensions; i++) + if (strcmpiW(package->extensions[i].Extension,extension)==0) + { + TRACE("extension %s already loaded at %i\n",debugstr_w(extension), + i); + return i; + } + + row = MSI_QueryGetRecord(package->db, ExecSeqQuery, extension); + if (!row) + return -1; + + rc = load_extension(package, row); + msiobj_release(&row->hdr); + + return rc; +} + +static UINT iterate_load_verb(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE* package = (MSIPACKAGE*)param; + DWORD index = package->loaded_verbs; + LPCWSTR buffer; + + /* fill in the data */ + + package->loaded_verbs++; + if (package->loaded_verbs == 1) + package->verbs = HeapAlloc(GetProcessHeap(),0,sizeof(MSIVERB)); + else + package->verbs = HeapReAlloc(GetProcessHeap(),0, + package->verbs , package->loaded_verbs * sizeof(MSIVERB)); + + memset(&package->verbs[index],0,sizeof(MSIVERB)); + + buffer = MSI_RecordGetString(row,1); + package->verbs[index].ExtensionIndex = load_given_extension(package,buffer); + if (package->verbs[index].ExtensionIndex < 0 && buffer) + ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer)); + + package->verbs[index].Verb = load_dynamic_stringW(row,2); + TRACE("loading verb %s\n",debugstr_w(package->verbs[index].Verb)); + package->verbs[index].Sequence = MSI_RecordGetInteger(row,3); + + buffer = MSI_RecordGetString(row,4); + deformat_string(package,buffer,&package->verbs[index].Command); + + buffer = MSI_RecordGetString(row,5); + deformat_string(package,buffer,&package->verbs[index].Argument); + + /* assosiate the verb with the correct extension */ + if (package->verbs[index].ExtensionIndex >= 0) + { + MSIEXTENSION* extension = &package->extensions[package->verbs[index]. + ExtensionIndex]; + int count = extension->VerbCount; + + if (count >= 99) + FIXME("Exceeding max verb count! Increase that limit!!!\n"); + else + { + extension->VerbCount++; + extension->Verbs[count] = index; + } + } + + return ERROR_SUCCESS; +} + +static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param) +{ + LPCWSTR clsid; + LPCWSTR context; + LPCWSTR buffer; + INT component_index; + MSIPACKAGE* package =(MSIPACKAGE*)param; + INT i; + BOOL match = FALSE; + + clsid = MSI_RecordGetString(rec,1); + context = MSI_RecordGetString(rec,2); + buffer = MSI_RecordGetString(rec,3); + component_index = get_loaded_component(package,buffer); + + for (i = 0; i < package->loaded_classes; i++) + { + if (strcmpiW(clsid,package->classes[i].CLSID)) + continue; + if (strcmpW(context,package->classes[i].Context)) + continue; + if (component_index == package->classes[i].ComponentIndex) + { + match = TRUE; + break; + } + } + + if (!match) + load_class(package, rec); + + return ERROR_SUCCESS; +} + +static VOID load_all_classes(MSIPACKAGE *package) +{ + UINT rc = ERROR_SUCCESS; + MSIQUERY *view; + + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', + '`','C','l','a','s','s','`',0}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return; + + rc = MSI_IterateRecords(view, NULL, iterate_all_classes, package); + msiobj_release(&view->hdr); +} + +static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param) +{ + LPCWSTR buffer; + LPCWSTR extension; + INT component_index; + MSIPACKAGE* package =(MSIPACKAGE*)param; + BOOL match = FALSE; + INT i; + + extension = MSI_RecordGetString(rec,1); + buffer = MSI_RecordGetString(rec,2); + component_index = get_loaded_component(package,buffer); + + for (i = 0; i < package->loaded_extensions; i++) + { + if (strcmpiW(extension,package->extensions[i].Extension)) + continue; + if (component_index == package->extensions[i].ComponentIndex) + { + match = TRUE; + break; + } + } + + if (!match) + load_extension(package, rec); + + return ERROR_SUCCESS; +} + +static VOID load_all_extensions(MSIPACKAGE *package) +{ + UINT rc = ERROR_SUCCESS; + MSIQUERY *view; + + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','E','x','t','e','n','s','i','o','n','`',0}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return; + + rc = MSI_IterateRecords(view, NULL, iterate_all_extensions, package); + msiobj_release(&view->hdr); +} + +static UINT iterate_all_progids(MSIRECORD *rec, LPVOID param) +{ + LPCWSTR buffer; + MSIPACKAGE* package =(MSIPACKAGE*)param; + + buffer = MSI_RecordGetString(rec,1); + load_given_progid(package,buffer); + return ERROR_SUCCESS; +} + +static VOID load_all_progids(MSIPACKAGE *package) +{ + UINT rc = ERROR_SUCCESS; + MSIQUERY *view; + + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ', + 'F','R','O','M',' ', '`','P','r','o','g','I','d','`',0}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return; + + rc = MSI_IterateRecords(view, NULL, iterate_all_progids, package); + msiobj_release(&view->hdr); +} + +static VOID load_all_verbs(MSIPACKAGE *package) +{ + UINT rc = ERROR_SUCCESS; + MSIQUERY *view; + + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','V','e','r','b','`',0}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return; + + rc = MSI_IterateRecords(view, NULL, iterate_load_verb, package); + msiobj_release(&view->hdr); +} + +static UINT iterate_all_mimes(MSIRECORD *rec, LPVOID param) +{ + LPCWSTR buffer; + MSIPACKAGE* package =(MSIPACKAGE*)param; + + buffer = MSI_RecordGetString(rec,1); + load_given_mime(package,buffer); + return ERROR_SUCCESS; +} + +static VOID load_all_mimes(MSIPACKAGE *package) +{ + UINT rc = ERROR_SUCCESS; + MSIQUERY *view; + + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ', + '`','C','o','n','t','e','n','t','T','y','p','e','`', + ' ','F','R','O','M',' ', + '`','M','I','M','E','`',0}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return; + + rc = MSI_IterateRecords(view, NULL, iterate_all_mimes, package); + msiobj_release(&view->hdr); +} + +static void load_classes_and_such(MSIPACKAGE *package) +{ + TRACE("Loading all the class info and related tables\n"); + + /* check if already loaded */ + if (package->classes || package->extensions || package->progids || + package->verbs || package->mimes) + return; + + load_all_classes(package); + load_all_extensions(package); + load_all_progids(package); + /* these loads must come after the other loads */ + load_all_verbs(package); + load_all_mimes(package); +} + +static void mark_progid_for_install(MSIPACKAGE* package, INT index) +{ + MSIPROGID* progid; + int i; + + if (index < 0 || index >= package->loaded_progids) + return; + + progid = &package->progids[index]; + + if (progid->InstallMe == TRUE) + return; + + progid->InstallMe = TRUE; + + /* all children if this is a parent also install */ + for (i = 0; i < package->loaded_progids; i++) + if (package->progids[i].ParentIndex == index) + mark_progid_for_install(package,i); +} + +static void mark_mime_for_install(MSIPACKAGE* package, INT index) +{ + MSIMIME* mime; + + if (index < 0 || index >= package->loaded_mimes) + return; + + mime = &package->mimes[index]; + + if (mime->InstallMe == TRUE) + return; + + mime->InstallMe = TRUE; +} + +static UINT register_appid(MSIPACKAGE *package, int appidIndex, LPCWSTR app ) +{ + static const WCHAR szAppID[] = { 'A','p','p','I','D',0 }; + HKEY hkey2,hkey3; + + if (!package) + return ERROR_INVALID_HANDLE; + + RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2); + RegCreateKeyW(hkey2,package->appids[appidIndex].AppID,&hkey3); + RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app, + (strlenW(app)+1)*sizeof(WCHAR)); + + if (package->appids[appidIndex].RemoteServerName) + { + UINT size; + static const WCHAR szRemoteServerName[] = + {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e', + 0}; + + size = (strlenW(package->appids[appidIndex].RemoteServerName)+1) * + sizeof(WCHAR); + + RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ, + (LPVOID)package->appids[appidIndex].RemoteServerName, + size); + } + + if (package->appids[appidIndex].LocalServer) + { + static const WCHAR szLocalService[] = + {'L','o','c','a','l','S','e','r','v','i','c','e',0}; + UINT size; + size = (strlenW(package->appids[appidIndex].LocalServer)+1) * + sizeof(WCHAR); + + RegSetValueExW(hkey3,szLocalService,0,REG_SZ, + (LPVOID)package->appids[appidIndex].LocalServer,size); + } + + if (package->appids[appidIndex].ServiceParameters) + { + static const WCHAR szService[] = + {'S','e','r','v','i','c','e', + 'P','a','r','a','m','e','t','e','r','s',0}; + UINT size; + size = (strlenW(package->appids[appidIndex].ServiceParameters)+1) * + sizeof(WCHAR); + RegSetValueExW(hkey3,szService,0,REG_SZ, + (LPVOID)package->appids[appidIndex].ServiceParameters, + size); + } + + if (package->appids[appidIndex].DllSurrogate) + { + static const WCHAR szDLL[] = + {'D','l','l','S','u','r','r','o','g','a','t','e',0}; + UINT size; + size = (strlenW(package->appids[appidIndex].DllSurrogate)+1) * + sizeof(WCHAR); + RegSetValueExW(hkey3,szDLL,0,REG_SZ, + (LPVOID)package->appids[appidIndex].DllSurrogate,size); + } + + if (package->appids[appidIndex].ActivateAtStorage) + { + static const WCHAR szActivate[] = + {'A','c','t','i','v','a','t','e','A','s', + 'S','t','o','r','a','g','e',0}; + static const WCHAR szY[] = {'Y',0}; + + RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4); + } + + if (package->appids[appidIndex].RunAsInteractiveUser) + { + static const WCHAR szRunAs[] = {'R','u','n','A','s',0}; + static const WCHAR szUser[] = + {'I','n','t','e','r','a','c','t','i','v','e',' ', + 'U','s','e','r',0}; + + RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,sizeof(szUser)); + } + + RegCloseKey(hkey3); + RegCloseKey(hkey2); + return ERROR_SUCCESS; +} + +UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) +{ + /* + * Again I am assuming the words, "Whose key file represents" when referring + * to a Component as to meaning that Components KeyPath file + */ + + UINT rc; + MSIRECORD *uirow; + static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; + static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 }; + static const WCHAR szVIProgID[] = { 'V','e','r','s','i','o','n','I','n','d','e','p','e','n','d','e','n','t','P','r','o','g','I','D',0 }; + static const WCHAR szAppID[] = { 'A','p','p','I','D',0 }; + static const WCHAR szSpace[] = {' ',0}; + static const WCHAR szInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0}; + static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0}; + HKEY hkey,hkey2,hkey3; + BOOL install_on_demand = FALSE; + int i; + + if (!package) + return ERROR_INVALID_HANDLE; + + load_classes_and_such(package); + rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey); + if (rc != ERROR_SUCCESS) + return ERROR_FUNCTION_FAILED; + + /* install_on_demand should be set if OLE supports install on demand OLE + * servers. For now i am defaulting to FALSE because i do not know how to + * check, and i am told our builtin OLE does not support it + */ + + for (i = 0; i < package->loaded_classes; i++) + { + INT index,f_index; + DWORD size, sz; + LPWSTR argument; + + if (package->classes[i].ComponentIndex < 0) + { + continue; + } + + index = package->classes[i].ComponentIndex; + f_index = package->classes[i].FeatureIndex; + + /* + * yes. MSDN says that these are based on _Feature_ not on + * Component. So verify the feature is to be installed + */ + if ((!ACTION_VerifyFeatureForAction(package, f_index, + INSTALLSTATE_LOCAL)) && + !(install_on_demand && ACTION_VerifyFeatureForAction(package, + f_index, INSTALLSTATE_ADVERTISED))) + { + TRACE("Skipping class %s reg due to disabled feature %s\n", + debugstr_w(package->classes[i].CLSID), + debugstr_w(package->features[f_index].Feature)); + + continue; + } + + TRACE("Registering index %i class %s\n",i, + debugstr_w(package->classes[i].CLSID)); + + package->classes[i].Installed = TRUE; + if (package->classes[i].ProgIDIndex >= 0) + mark_progid_for_install(package, package->classes[i].ProgIDIndex); + + RegCreateKeyW(hkey,package->classes[i].CLSID,&hkey2); + + if (package->classes[i].Description) + RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)package->classes[i]. + Description, (strlenW(package->classes[i]. + Description)+1)*sizeof(WCHAR)); + + RegCreateKeyW(hkey2,package->classes[i].Context,&hkey3); + index = get_loaded_file(package,package->components[index].KeyPath); + + + /* the context server is a short path name + * except for if it is InprocServer32... + */ + if (strcmpiW(package->classes[i].Context,szInprocServer32)!=0) + { + sz = 0; + sz = GetShortPathNameW(package->files[index].TargetPath, NULL, 0); + if (sz == 0) + { + ERR("Unable to find short path for CLSID COM Server\n"); + argument = NULL; + } + else + { + size = sz * sizeof(WCHAR); + + if (package->classes[i].Argument) + { + size += strlenW(package->classes[i].Argument) * + sizeof(WCHAR); + size += sizeof(WCHAR); + } + + argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR)); + GetShortPathNameW(package->files[index].TargetPath, argument, + sz); + + if (package->classes[i].Argument) + { + strcatW(argument,szSpace); + strcatW(argument,package->classes[i].Argument); + } + } + } + else + { + size = lstrlenW(package->files[index].TargetPath) * sizeof(WCHAR); + + if (package->classes[i].Argument) + { + size += strlenW(package->classes[i].Argument) * sizeof(WCHAR); + size += sizeof(WCHAR); + } + + argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR)); + strcpyW(argument, package->files[index].TargetPath); + + if (package->classes[i].Argument) + { + strcatW(argument,szSpace); + strcatW(argument,package->classes[i].Argument); + } + } + + if (argument) + { + RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size); + HeapFree(GetProcessHeap(),0,argument); + } + + RegCloseKey(hkey3); + + if (package->classes[i].ProgIDIndex >= 0 || + package->classes[i].ProgIDText) + { + LPCWSTR progid; + + if (package->classes[i].ProgIDIndex >= 0) + progid = package->progids[ + package->classes[i].ProgIDIndex].ProgID; + else + progid = package->classes[i].ProgIDText; + + RegCreateKeyW(hkey2,szProgID,&hkey3); + RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)progid, + (strlenW(progid)+1) *sizeof(WCHAR)); + RegCloseKey(hkey3); + + if (package->classes[i].ProgIDIndex >= 0 && + package->progids[package->classes[i].ProgIDIndex]. + VersionIndIndex >= 0) + { + LPWSTR viprogid = strdupW(package->progids[package->progids[ + package->classes[i].ProgIDIndex].VersionIndIndex]. + ProgID); + RegCreateKeyW(hkey2,szVIProgID,&hkey3); + RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)viprogid, + (strlenW(viprogid)+1) *sizeof(WCHAR)); + RegCloseKey(hkey3); + HeapFree(GetProcessHeap(), 0, viprogid); + } + } + + if (package->classes[i].AppIDIndex >= 0) + { + RegSetValueExW(hkey2,szAppID,0,REG_SZ, + (LPVOID)package->appids[package->classes[i].AppIDIndex].AppID, + (strlenW(package->appids[package->classes[i].AppIDIndex].AppID)+1) + *sizeof(WCHAR)); + + register_appid(package,package->classes[i].AppIDIndex, + package->classes[i].Description); + } + + if (package->classes[i].IconPath) + { + static const WCHAR szDefaultIcon[] = + {'D','e','f','a','u','l','t','I','c','o','n',0}; + + RegCreateKeyW(hkey2,szDefaultIcon,&hkey3); + + RegSetValueExW(hkey3,NULL,0,REG_SZ, + (LPVOID)package->classes[i].IconPath, + (strlenW(package->classes[i].IconPath)+1) * + sizeof(WCHAR)); + + RegCloseKey(hkey3); + } + + if (package->classes[i].DefInprocHandler) + { + static const WCHAR szInproc[] = + {'I','n','p','r','o','c','H','a','n','d','l','e','r',0}; + + size = (strlenW(package->classes[i].DefInprocHandler) + 1) * + sizeof(WCHAR); + RegCreateKeyW(hkey2,szInproc,&hkey3); + RegSetValueExW(hkey3,NULL,0,REG_SZ, + (LPVOID)package->classes[i].DefInprocHandler, size); + RegCloseKey(hkey3); + } + + if (package->classes[i].DefInprocHandler32) + { + static const WCHAR szInproc32[] = + {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2', + 0}; + size = (strlenW(package->classes[i].DefInprocHandler32) + 1) * + sizeof(WCHAR); + + RegCreateKeyW(hkey2,szInproc32,&hkey3); + RegSetValueExW(hkey3,NULL,0,REG_SZ, + (LPVOID)package->classes[i].DefInprocHandler32,size); + RegCloseKey(hkey3); + } + + RegCloseKey(hkey2); + + /* if there is a FileTypeMask, register the FileType */ + if (package->classes[i].FileTypeMask) + { + LPWSTR ptr, ptr2; + LPWSTR keyname; + INT index = 0; + ptr = package->classes[i].FileTypeMask; + while (ptr && *ptr) + { + ptr2 = strchrW(ptr,';'); + if (ptr2) + *ptr2 = 0; + keyname = HeapAlloc(GetProcessHeap(),0,(strlenW(szFileType_fmt)+ + strlenW(package->classes[i].CLSID) + 4) + * sizeof(WCHAR)); + sprintfW(keyname,szFileType_fmt, package->classes[i].CLSID, + index); + + RegCreateKeyW(HKEY_CLASSES_ROOT,keyname,&hkey2); + RegSetValueExW(hkey2,NULL,0,REG_SZ, (LPVOID)ptr, + strlenW(ptr)*sizeof(WCHAR)); + RegCloseKey(hkey2); + HeapFree(GetProcessHeap(), 0, keyname); + + if (ptr2) + ptr = ptr2+1; + else + ptr = NULL; + + index ++; + } + } + + uirow = MSI_CreateRecord(1); + + MSI_RecordSetStringW(uirow,1,package->classes[i].CLSID); + ui_actiondata(package,szRegisterClassInfo,uirow); + msiobj_release(&uirow->hdr); + } + + RegCloseKey(hkey); + return rc; +} + +static UINT register_progid_base(MSIPACKAGE* package, MSIPROGID* progid, + LPWSTR clsid) +{ + static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; + static const WCHAR szDefaultIcon[] = + {'D','e','f','a','u','l','t','I','c','o','n',0}; + HKEY hkey,hkey2; + + RegCreateKeyW(HKEY_CLASSES_ROOT,progid->ProgID,&hkey); + + if (progid->Description) + { + RegSetValueExW(hkey,NULL,0,REG_SZ, + (LPVOID)progid->Description, + (strlenW(progid->Description)+1) * + sizeof(WCHAR)); + } + + if (progid->ClassIndex >= 0) + { + RegCreateKeyW(hkey,szCLSID,&hkey2); + RegSetValueExW(hkey2,NULL,0,REG_SZ, + (LPVOID)package->classes[progid->ClassIndex].CLSID, + (strlenW(package->classes[progid->ClassIndex].CLSID)+1) + * sizeof(WCHAR)); + + if (clsid) + strcpyW(clsid,package->classes[progid->ClassIndex].CLSID); + + RegCloseKey(hkey2); + } + else + { + FIXME("UNHANDLED case, Parent progid but classid is NULL\n"); + } + + if (progid->IconPath) + { + RegCreateKeyW(hkey,szDefaultIcon,&hkey2); + + RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath, + (strlenW(progid->IconPath)+1) * sizeof(WCHAR)); + RegCloseKey(hkey2); + } + return ERROR_SUCCESS; +} + +static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid, + LPWSTR clsid) +{ + UINT rc = ERROR_SUCCESS; + + if (progid->ParentIndex < 0) + rc = register_progid_base(package, progid, clsid); + else + { + DWORD disp; + HKEY hkey,hkey2; + static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; + static const WCHAR szDefaultIcon[] = + {'D','e','f','a','u','l','t','I','c','o','n',0}; + static const WCHAR szCurVer[] = + {'C','u','r','V','e','r',0}; + + /* check if already registered */ + RegCreateKeyExW(HKEY_CLASSES_ROOT, progid->ProgID, 0, NULL, 0, + KEY_ALL_ACCESS, NULL, &hkey, &disp ); + if (disp == REG_OPENED_EXISTING_KEY) + { + TRACE("Key already registered\n"); + RegCloseKey(hkey); + return rc; + } + + TRACE("Registering Parent %s index %i\n", + debugstr_w(package->progids[progid->ParentIndex].ProgID), + progid->ParentIndex); + rc = register_progid(package,&package->progids[progid->ParentIndex], + clsid); + + /* clsid is same as parent */ + RegCreateKeyW(hkey,szCLSID,&hkey2); + RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) * + sizeof(WCHAR)); + + RegCloseKey(hkey2); + + + if (progid->Description) + { + RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid->Description, + (strlenW(progid->Description)+1) * sizeof(WCHAR)); + } + + if (progid->IconPath) + { + RegCreateKeyW(hkey,szDefaultIcon,&hkey2); + RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath, + (strlenW(progid->IconPath)+1) * sizeof(WCHAR)); + RegCloseKey(hkey2); + } + + /* write out the current version */ + if (progid->CurVerIndex >= 0) + { + RegCreateKeyW(hkey,szCurVer,&hkey2); + RegSetValueExW(hkey2,NULL,0,REG_SZ, + (LPVOID)package->progids[progid->CurVerIndex].ProgID, + (strlenW(package->progids[progid->CurVerIndex].ProgID)+1) * + sizeof(WCHAR)); + RegCloseKey(hkey2); + } + + RegCloseKey(hkey); + } + return rc; +} + +UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package) +{ + INT i; + MSIRECORD *uirow; + + if (!package) + return ERROR_INVALID_HANDLE; + + load_classes_and_such(package); + + for (i = 0; i < package->loaded_progids; i++) + { + WCHAR clsid[0x1000]; + + /* check if this progid is to be installed */ + package->progids[i].InstallMe = ((package->progids[i].InstallMe) || + (package->progids[i].ClassIndex >= 0 && + package->classes[package->progids[i].ClassIndex].Installed)); + + if (!package->progids[i].InstallMe) + { + TRACE("progid %s not scheduled to be installed\n", + debugstr_w(package->progids[i].ProgID)); + continue; + } + + TRACE("Registering progid %s index %i\n", + debugstr_w(package->progids[i].ProgID), i); + + register_progid(package,&package->progids[i],clsid); + + uirow = MSI_CreateRecord(1); + MSI_RecordSetStringW(uirow,1,package->progids[i].ProgID); + ui_actiondata(package,szRegisterProgIdInfo,uirow); + msiobj_release(&uirow->hdr); + } + + return ERROR_SUCCESS; +} + +static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid, + MSICOMPONENT* component, MSIEXTENSION* extension, + MSIVERB* verb, INT* Sequence ) +{ + LPWSTR keyname; + HKEY key; + static const WCHAR szShell[] = {'s','h','e','l','l',0}; + static const WCHAR szCommand[] = {'c','o','m','m','a','n','d',0}; + static const WCHAR fmt[] = {'\"','%','s','\"',' ','%','s',0}; + static const WCHAR fmt2[] = {'\"','%','s','\"',0}; + LPWSTR command; + DWORD size; + LPWSTR advertise; + + keyname = build_directory_name(4, progid, szShell, verb->Verb, szCommand); + + TRACE("Making Key %s\n",debugstr_w(keyname)); + RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key); + size = strlenW(component->FullKeypath); + if (verb->Argument) + size += strlenW(verb->Argument); + size += 4; + + command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR)); + if (verb->Argument) + sprintfW(command, fmt, component->FullKeypath, verb->Argument); + else + sprintfW(command, fmt2, component->FullKeypath); + + RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)command, (strlenW(command)+1)* + sizeof(WCHAR)); + HeapFree(GetProcessHeap(),0,command); + + advertise = create_component_advertise_string(package, component, + package->features[extension->FeatureIndex].Feature); + + size = strlenW(advertise); + + if (verb->Argument) + size += strlenW(verb->Argument); + size += 4; + + command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR)); + memset(command,0,size*sizeof(WCHAR)); + + strcpyW(command,advertise); + if (verb->Argument) + { + static const WCHAR szSpace[] = {' ',0}; + strcatW(command,szSpace); + strcatW(command,verb->Argument); + } + + RegSetValueExW(key, szCommand, 0, REG_MULTI_SZ, (LPBYTE)command, + (strlenW(command)+2)*sizeof(WCHAR)); + + RegCloseKey(key); + HeapFree(GetProcessHeap(),0,keyname); + HeapFree(GetProcessHeap(),0,advertise); + HeapFree(GetProcessHeap(),0,command); + + if (verb->Command) + { + keyname = build_directory_name(3, progid, szShell, verb->Verb); + RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key); + RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Command, + (strlenW(verb->Command)+1) *sizeof(WCHAR)); + RegCloseKey(key); + HeapFree(GetProcessHeap(),0,keyname); + } + + if (verb->Sequence != MSI_NULL_INTEGER) + { + if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence) + { + *Sequence = verb->Sequence; + keyname = build_directory_name(2, progid, szShell); + RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key); + RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Verb, + (strlenW(verb->Verb)+1) *sizeof(WCHAR)); + RegCloseKey(key); + HeapFree(GetProcessHeap(),0,keyname); + } + } + return ERROR_SUCCESS; +} + +UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package) +{ + static const WCHAR szContentType[] = + {'C','o','n','t','e','n','t',' ','T','y','p','e',0 }; + HKEY hkey; + INT i; + MSIRECORD *uirow; + BOOL install_on_demand = TRUE; + + if (!package) + return ERROR_INVALID_HANDLE; + + load_classes_and_such(package); + + /* We need to set install_on_demand based on if the shell handles advertised + * shortcuts and the like. Because Mike McCormack is working on this i am + * going to default to TRUE + */ + + for (i = 0; i < package->loaded_extensions; i++) + { + WCHAR extension[257]; + INT index,f_index; + + index = package->extensions[i].ComponentIndex; + f_index = package->extensions[i].FeatureIndex; + + if (index < 0) + continue; + + /* + * yes. MSDN says that these are based on _Feature_ not on + * Component. So verify the feature is to be installed + */ + if ((!ACTION_VerifyFeatureForAction(package, f_index, + INSTALLSTATE_LOCAL)) && + !(install_on_demand && ACTION_VerifyFeatureForAction(package, + f_index, INSTALLSTATE_ADVERTISED))) + { + TRACE("Skipping extension %s reg due to disabled feature %s\n", + debugstr_w(package->extensions[i].Extension), + debugstr_w(package->features[f_index].Feature)); + + continue; + } + + TRACE("Registering extension %s index %i\n", + debugstr_w(package->extensions[i].Extension), i); + + package->extensions[i].Installed = TRUE; + + /* this is only registered if the extension has at least 1 verb + * according to MSDN + */ + if (package->extensions[i].ProgIDIndex >= 0 && + package->extensions[i].VerbCount > 0) + mark_progid_for_install(package, package->extensions[i].ProgIDIndex); + + if (package->extensions[i].MIMEIndex >= 0) + mark_mime_for_install(package, package->extensions[i].MIMEIndex); + + extension[0] = '.'; + extension[1] = 0; + strcatW(extension,package->extensions[i].Extension); + + RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey); + + if (package->extensions[i].MIMEIndex >= 0) + { + RegSetValueExW(hkey,szContentType,0,REG_SZ, + (LPVOID)package->mimes[package->extensions[i]. + MIMEIndex].ContentType, + (strlenW(package->mimes[package->extensions[i]. + MIMEIndex].ContentType)+1)*sizeof(WCHAR)); + } + + if (package->extensions[i].ProgIDIndex >= 0 || + package->extensions[i].ProgIDText) + { + static const WCHAR szSN[] = + {'\\','S','h','e','l','l','N','e','w',0}; + HKEY hkey2; + LPWSTR newkey; + LPCWSTR progid; + INT v; + INT Sequence = MSI_NULL_INTEGER; + + if (package->extensions[i].ProgIDIndex >= 0) + progid = package->progids[package->extensions[i]. + ProgIDIndex].ProgID; + else + progid = package->extensions[i].ProgIDText; + + RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid, + (strlenW(progid)+1)*sizeof(WCHAR)); + + newkey = HeapAlloc(GetProcessHeap(),0, + (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR)); + + strcpyW(newkey,progid); + strcatW(newkey,szSN); + RegCreateKeyW(hkey,newkey,&hkey2); + RegCloseKey(hkey2); + + HeapFree(GetProcessHeap(),0,newkey); + + /* do all the verbs */ + for (v = 0; v < package->extensions[i].VerbCount; v++) + register_verb(package, progid, + &package->components[index], + &package->extensions[i], + &package->verbs[package->extensions[i].Verbs[v]], + &Sequence); + } + + RegCloseKey(hkey); + + uirow = MSI_CreateRecord(1); + MSI_RecordSetStringW(uirow,1,package->extensions[i].Extension); + ui_actiondata(package,szRegisterExtensionInfo,uirow); + msiobj_release(&uirow->hdr); + } + + return ERROR_SUCCESS; +} + +UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package) +{ + static const WCHAR szExten[] = + {'E','x','t','e','n','s','i','o','n',0 }; + HKEY hkey; + INT i; + MSIRECORD *uirow; + + if (!package) + return ERROR_INVALID_HANDLE; + + load_classes_and_such(package); + + for (i = 0; i < package->loaded_mimes; i++) + { + WCHAR extension[257]; + LPCWSTR exten; + LPCWSTR mime; + static const WCHAR fmt[] = + {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\', + 'C','o','n','t','e','n','t',' ','T','y','p','e','\\', '%','s',0}; + LPWSTR key; + + /* + * check if the MIME is to be installed. Either as requesed by an + * extension or Class + */ + package->mimes[i].InstallMe = ((package->mimes[i].InstallMe) || + (package->mimes[i].ClassIndex >= 0 && + package->classes[package->mimes[i].ClassIndex].Installed) || + (package->mimes[i].ExtensionIndex >=0 && + package->extensions[package->mimes[i].ExtensionIndex].Installed)); + + if (!package->mimes[i].InstallMe) + { + TRACE("MIME %s not scheduled to be installed\n", + debugstr_w(package->mimes[i].ContentType)); + continue; + } + + mime = package->mimes[i].ContentType; + exten = package->extensions[package->mimes[i].ExtensionIndex].Extension; + extension[0] = '.'; + extension[1] = 0; + strcatW(extension,exten); + + key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) * + sizeof(WCHAR)); + sprintfW(key,fmt,mime); + RegCreateKeyW(HKEY_CLASSES_ROOT,key,&hkey); + RegSetValueExW(hkey,szExten,0,REG_SZ,(LPVOID)extension, + (strlenW(extension)+1)*sizeof(WCHAR)); + + HeapFree(GetProcessHeap(),0,key); + + if (package->mimes[i].CLSID[0]) + { + FIXME("Handle non null for field 3\n"); + } + + RegCloseKey(hkey); + + uirow = MSI_CreateRecord(2); + MSI_RecordSetStringW(uirow,1,package->mimes[i].ContentType); + MSI_RecordSetStringW(uirow,2,exten); + ui_actiondata(package,szRegisterMIMEInfo,uirow); + msiobj_release(&uirow->hdr); + } + + return ERROR_SUCCESS; +} diff --git a/reactos/lib/msi/cond.tab.c b/reactos/lib/msi/cond.tab.c index d025c24df54..ae49cc09d5a 100644 --- a/reactos/lib/msi/cond.tab.c +++ b/reactos/lib/msi/cond.tab.c @@ -72,7 +72,7 @@ #define YYLEX_PARAM info #define YYPARSE_PARAM info -static int COND_error(char *str); +static int COND_error(const char *str); WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -1970,7 +1970,7 @@ static LPWSTR COND_GetLiteral( struct cond_str *str ) return ret; } -static int COND_error(char *str) +static int COND_error(const char *str) { return 0; } diff --git a/reactos/lib/msi/cond.tab.h b/reactos/lib/msi/cond.tab.h index f37273b3993..d6099930466 100644 --- a/reactos/lib/msi/cond.tab.h +++ b/reactos/lib/msi/cond.tab.h @@ -1,83 +1,9 @@ -/* A Bison parser, made by GNU Bison 1.875c. */ +#ifndef BISON_COND_TAB_H +# define BISON_COND_TAB_H -/* Skeleton parser for Yacc-like parsing with Bison, - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* As a special exception, when this file is copied by Bison into a - Bison output file, you may use that output file without restriction. - This special exception was added by the Free Software Foundation - in version 1.24 of Bison. */ - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - COND_SPACE = 258, - COND_EOF = 259, - COND_OR = 260, - COND_AND = 261, - COND_NOT = 262, - COND_LT = 263, - COND_GT = 264, - COND_EQ = 265, - COND_LPAR = 266, - COND_RPAR = 267, - COND_TILDA = 268, - COND_PERCENT = 269, - COND_DOLLARS = 270, - COND_QUESTION = 271, - COND_AMPER = 272, - COND_EXCLAM = 273, - COND_IDENT = 274, - COND_NUMBER = 275, - COND_LITER = 276, - COND_ERROR = 277 - }; -#endif -#define COND_SPACE 258 -#define COND_EOF 259 -#define COND_OR 260 -#define COND_AND 261 -#define COND_NOT 262 -#define COND_LT 263 -#define COND_GT 264 -#define COND_EQ 265 -#define COND_LPAR 266 -#define COND_RPAR 267 -#define COND_TILDA 268 -#define COND_PERCENT 269 -#define COND_DOLLARS 270 -#define COND_QUESTION 271 -#define COND_AMPER 272 -#define COND_EXCLAM 273 -#define COND_IDENT 274 -#define COND_NUMBER 275 -#define COND_LITER 276 -#define COND_ERROR 277 - - - - -#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) -#line 106 "./cond.y" -typedef union YYSTYPE { +#ifndef YYSTYPE +typedef union +{ struct cond_str str; LPWSTR string; INT value; @@ -85,15 +11,30 @@ typedef union YYSTYPE { comp_str fn_comp_str; comp_m1 fn_comp_m1; comp_m2 fn_comp_m2; -} YYSTYPE; -/* Line 1275 of yacc.c. */ -#line 91 "cond.tab.h" -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 +} yystype; +# define YYSTYPE yystype # define YYSTYPE_IS_TRIVIAL 1 #endif +# define COND_SPACE 257 +# define COND_EOF 258 +# define COND_OR 259 +# define COND_AND 260 +# define COND_NOT 261 +# define COND_LT 262 +# define COND_GT 263 +# define COND_EQ 264 +# define COND_LPAR 265 +# define COND_RPAR 266 +# define COND_TILDA 267 +# define COND_PERCENT 268 +# define COND_DOLLARS 269 +# define COND_QUESTION 270 +# define COND_AMPER 271 +# define COND_EXCLAM 272 +# define COND_IDENT 273 +# define COND_NUMBER 274 +# define COND_LITER 275 +# define COND_ERROR 276 - - - +#endif /* not BISON_COND_TAB_H */ diff --git a/reactos/lib/msi/cond.y b/reactos/lib/msi/cond.y index fd995b8cb38..5cb921bfe37 100644 --- a/reactos/lib/msi/cond.y +++ b/reactos/lib/msi/cond.y @@ -38,7 +38,7 @@ #define YYLEX_PARAM info #define YYPARSE_PARAM info -static int COND_error(char *str); +static int COND_error(const char *str); WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -722,7 +722,7 @@ static LPWSTR COND_GetLiteral( struct cond_str *str ) return ret; } -static int COND_error(char *str) +static int COND_error(const char *str) { return 0; } diff --git a/reactos/lib/msi/create.c b/reactos/lib/msi/create.c index 51d316e6b50..2d92db1f1f6 100644 --- a/reactos/lib/msi/create.c +++ b/reactos/lib/msi/create.c @@ -44,7 +44,7 @@ typedef struct tagMSICREATEVIEW MSIDATABASE *db; LPWSTR name; BOOL bIsTemp; - create_col_info *col_info; + column_info *col_info; } MSICREATEVIEW; static UINT CREATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) @@ -59,7 +59,7 @@ static UINT CREATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT static UINT CREATE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) { MSICREATEVIEW *cv = (MSICREATEVIEW*)view; - create_col_info *col; + column_info *col; UINT r, nField, row, table_val, column_val; static const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 }; static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 }; @@ -122,8 +122,8 @@ static UINT CREATE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) if( r ) goto err; - column_val = msi_addstringW( cv->db->strings, 0, col->colname, -1, 1 ); - TRACE("New string %s -> %d\n", debugstr_w( col->colname ), column_val ); + column_val = msi_addstringW( cv->db->strings, 0, col->column, -1, 1 ); + TRACE("New string %s -> %d\n", debugstr_w( col->column ), column_val ); if( column_val < 0 ) break; @@ -226,7 +226,7 @@ MSIVIEWOPS create_ops = }; UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, - create_col_info *col_info, BOOL temp ) + column_info *col_info, BOOL temp ) { MSICREATEVIEW *cv = NULL; diff --git a/reactos/lib/msi/custom.c b/reactos/lib/msi/custom.c index 4465fc2ebf2..17645e999cc 100644 --- a/reactos/lib/msi/custom.c +++ b/reactos/lib/msi/custom.c @@ -77,7 +77,6 @@ static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source, UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute) { UINT rc = ERROR_SUCCESS; - MSIQUERY * view; MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', @@ -89,25 +88,9 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute) LPWSTR target; WCHAR *deformated=NULL; - rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, action); - if (rc != ERROR_SUCCESS) - return rc; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); + row = MSI_QueryGetRecord( package->db, ExecSeqQuery, action ); + if (!row) return ERROR_CALL_NOT_IMPLEMENTED; - } type = MSI_RecordGetInteger(row,2); @@ -123,53 +106,28 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute) if (type & 0x100) { FIXME("Rollback only action... rollbacks not supported yet\n"); + schedule_action(package, ROLLBACK_SCRIPT, action); HeapFree(GetProcessHeap(),0,source); HeapFree(GetProcessHeap(),0,target); msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); return ERROR_SUCCESS; } if (!execute) { - LPWSTR *newbuf = NULL; - INT count; if (type & 0x200) { TRACE("Deferring Commit Action!\n"); - count = package->CommitActionCount; - package->CommitActionCount++; - if (count != 0) - newbuf = HeapReAlloc(GetProcessHeap(),0, - package->CommitAction, - package->CommitActionCount * sizeof(LPWSTR)); - else - newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR)); - - newbuf[count] = strdupW(action); - package->CommitAction = newbuf; + schedule_action(package, COMMIT_SCRIPT, action); } else { TRACE("Deferring Action!\n"); - count = package->DeferredActionCount; - package->DeferredActionCount++; - if (count != 0) - newbuf = HeapReAlloc(GetProcessHeap(),0, - package->DeferredAction, - package->DeferredActionCount * sizeof(LPWSTR)); - else - newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR)); - - newbuf[count] = strdupW(action); - package->DeferredAction = newbuf; + schedule_action(package, INSTALL_SCRIPT, action); } HeapFree(GetProcessHeap(),0,source); HeapFree(GetProcessHeap(),0,target); msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); return ERROR_SUCCESS; } else @@ -223,8 +181,6 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute) HeapFree(GetProcessHeap(),0,source); HeapFree(GetProcessHeap(),0,target); msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); return rc; } @@ -249,7 +205,6 @@ static UINT store_binary_to_temp(MSIPACKAGE *package, LPCWSTR source, { /* write out the file */ UINT rc; - MSIQUERY * view; MSIRECORD * row = 0; static const WCHAR fmt[] = {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', @@ -258,34 +213,15 @@ static UINT store_binary_to_temp(MSIPACKAGE *package, LPCWSTR source, HANDLE the_file; CHAR buffer[1024]; - if (track_tempfile(package, tmp_file, tmp_file)!=0) - FIXME("File Name in temp tracking collision\n"); - the_file = CreateFileW(tmp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (the_file == INVALID_HANDLE_VALUE) return ERROR_FUNCTION_FAILED; - rc = MSI_OpenQuery(package->db, &view, fmt, source); - if (rc != ERROR_SUCCESS) - return rc; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } + row = MSI_QueryGetRecord(package->db, fmt, source); + if (!row) + return ERROR_FUNCTION_FAILED; do { @@ -305,8 +241,6 @@ static UINT store_binary_to_temp(MSIPACKAGE *package, LPCWSTR source, CloseHandle(the_file); msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); } return ERROR_SUCCESS; @@ -366,7 +300,7 @@ static UINT process_action_return_value(UINT type, HANDLE ThreadHandle) static UINT process_handle(MSIPACKAGE* package, UINT type, HANDLE ThreadHandle, HANDLE ProcessHandle, - LPCWSTR Name) + LPCWSTR Name, BOOL *finished) { UINT rc = ERROR_SUCCESS; @@ -390,6 +324,8 @@ static UINT process_handle(MSIPACKAGE* package, UINT type, CloseHandle(ThreadHandle); if (ProcessHandle); CloseHandle(ProcessHandle); + if (finished) + *finished = TRUE; } else { @@ -411,6 +347,8 @@ static UINT process_handle(MSIPACKAGE* package, UINT type, if (ProcessHandle); CloseHandle(ProcessHandle); } + if (finished) + *finished = FALSE; } return rc; @@ -496,6 +434,7 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source, DWORD ThreadId; HANDLE ThreadHandle; UINT rc = ERROR_SUCCESS; + BOOL finished = FALSE; store_binary_to_temp(package, source, tmp_file); @@ -516,7 +455,12 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source, ThreadHandle = CreateThread(NULL,0,DllThread,(LPVOID)info,0,&ThreadId); - rc = process_handle(package, type, ThreadHandle, NULL, action); + rc = process_handle(package, type, ThreadHandle, NULL, action, &finished ); + + if (!finished) + track_tempfile(package, tmp_file, tmp_file); + else + DeleteFileW(tmp_file); return rc; } @@ -533,6 +477,7 @@ static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source, WCHAR *cmd; static const WCHAR spc[] = {' ',0}; UINT prc = ERROR_SUCCESS; + BOOL finished = FALSE; memset(&si,0,sizeof(STARTUPINFOW)); @@ -569,8 +514,14 @@ static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source, return ERROR_SUCCESS; } - prc = process_handle(package, type, info.hThread, info.hProcess, action); + prc = process_handle(package, type, info.hThread, info.hProcess, action, + &finished); + if (!finished) + track_tempfile(package, tmp_file, tmp_file); + else + DeleteFileW(tmp_file); + return prc; } @@ -622,7 +573,8 @@ static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source, return ERROR_SUCCESS; } - prc = process_handle(package, type, info.hThread, info.hProcess, action); + prc = process_handle(package, type, info.hThread, info.hProcess, action, + NULL); return prc; } @@ -636,37 +588,23 @@ static UINT HANDLE_CustomType19(MSIPACKAGE *package, LPCWSTR source, 'W','H','E','R','E',' ','`','E','r','r','o','r','`',' ','=',' ', '\'','%','s','\'',0 }; - MSIQUERY *view = NULL; MSIRECORD *row = 0; - UINT r; LPWSTR deformated = NULL; deformat_string( package, target, &deformated ); /* first try treat the error as a number */ - r = MSI_OpenQuery( package->db, &view, query, deformated ); - if( r == ERROR_SUCCESS ) + row = MSI_QueryGetRecord( package->db, query, deformated ); + if( row ) { - r = MSI_ViewExecute( view, 0 ); - if( r == ERROR_SUCCESS ) - { - r = MSI_ViewFetch( view, &row ); - if( r == ERROR_SUCCESS ) - { - LPCWSTR error = MSI_RecordGetString( row, 1 ); - MessageBoxW( NULL, error, NULL, MB_OK ); - msiobj_release( &row->hdr ); - } - } - MSI_ViewClose( view ); - msiobj_release( &view->hdr ); + LPCWSTR error = MSI_RecordGetString( row, 1 ); + MessageBoxW( NULL, error, NULL, MB_OK ); + msiobj_release( &row->hdr ); } - - if (r != ERROR_SUCCESS ) - { + else MessageBoxW( NULL, deformated, NULL, MB_OK ); - HeapFree( GetProcessHeap(), 0, deformated ); - } + + HeapFree( GetProcessHeap(), 0, deformated ); return ERROR_FUNCTION_FAILED; } @@ -720,7 +658,8 @@ static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source, return ERROR_SUCCESS; } - prc = process_handle(package, type, info.hThread, info.hProcess, action); + prc = process_handle(package, type, info.hThread, info.hProcess, action, + NULL); return prc; } @@ -761,7 +700,8 @@ static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source, return ERROR_SUCCESS; } - prc = process_handle(package, type, info.hThread, info.hProcess, action); + prc = process_handle(package, type, info.hThread, info.hProcess, action, + NULL); return prc; } diff --git a/reactos/lib/msi/database.c b/reactos/lib/msi/database.c index 800b1db2f57..aa94a232638 100644 --- a/reactos/lib/msi/database.c +++ b/reactos/lib/msi/database.c @@ -59,7 +59,7 @@ DEFINE_GUID( CLSID_MsiDatabase, 0x000c1084, 0x0000, 0x0000, * Any binary data in a table is a reference to a stream. */ -VOID MSI_CloseDatabase( MSIOBJECTHDR *arg ) +static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg ) { MSIDATABASE *db = (MSIDATABASE *) arg; DWORD r; @@ -77,7 +77,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb) HRESULT r; MSIDATABASE *db = NULL; UINT ret = ERROR_FUNCTION_FAILED; - LPWSTR szMode; + LPCWSTR szMode; STATSTG stat; TRACE("%s %s\n",debugstr_w(szDBPath),debugstr_w(szPersist) ); @@ -85,7 +85,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb) if( !pdb ) return ERROR_INVALID_PARAMETER; - szMode = (LPWSTR) szPersist; + szMode = szPersist; if( HIWORD( szPersist ) ) { /* UINT len = lstrlenW( szPerist ) + 1; */ @@ -209,7 +209,7 @@ UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB) goto end; } else - szwPersist = (LPWSTR) szPersist; + szwPersist = (LPWSTR)(DWORD)szPersist; r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB ); diff --git a/reactos/lib/msi/dialog.c b/reactos/lib/msi/dialog.c index 4977329f471..69e2b1e6fd7 100644 --- a/reactos/lib/msi/dialog.c +++ b/reactos/lib/msi/dialog.c @@ -32,6 +32,7 @@ #include "msidefs.h" #include "ocidl.h" #include "olectl.h" +#include "richedit.h" #include "wine/debug.h" #include "wine/unicode.h" @@ -41,17 +42,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); -const WCHAR szMsiDialogClass[] = { - 'M','s','i','D','i','a','l','o','g','C','l','o','s','e','C','l','a','s','s',0 -}; -const WCHAR szMsiHiddenWindow[] = { - 'M','s','i','H','i','d','d','e','n','W','i','n','d','o','w',0 -}; -const static WCHAR szStatic[] = { 'S','t','a','t','i','c',0 }; -const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 }; - -const static WCHAR szButtonData[] = { 'M','S','I','D','A','T','A',0 }; - struct msi_control_tag; typedef struct msi_control_tag msi_control; typedef UINT (*msi_handler)( msi_dialog *, msi_control *, WPARAM ); @@ -62,7 +52,9 @@ struct msi_control_tag HWND hwnd; msi_handler handler; LPWSTR property; + LPWSTR value; IPicture *pic; + HICON hIcon; WCHAR name[1]; }; @@ -101,11 +93,35 @@ typedef struct DWORD attributes; } radio_button_group_descr; +const WCHAR szMsiDialogClass[] = { + 'M','s','i','D','i','a','l','o','g','C','l','o','s','e','C','l','a','s','s',0 +}; +const WCHAR szMsiHiddenWindow[] = { + 'M','s','i','H','i','d','d','e','n','W','i','n','d','o','w',0 }; +const static WCHAR szStatic[] = { 'S','t','a','t','i','c',0 }; +const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 }; +const static WCHAR szButtonData[] = { 'M','S','I','D','A','T','A',0 }; +static const WCHAR szText[] = { 'T','e','x','t',0 }; +static const WCHAR szPushButton[] = { 'P','u','s','h','B','u','t','t','o','n',0 }; +static const WCHAR szLine[] = { 'L','i','n','e',0 }; +static const WCHAR szBitmap[] = { 'B','i','t','m','a','p',0 }; +static const WCHAR szCheckBox[] = { 'C','h','e','c','k','B','o','x',0 }; +static const WCHAR szScrollableText[] = { + 'S','c','r','o','l','l','a','b','l','e','T','e','x','t',0 }; +static const WCHAR szComboBox[] = { 'C','o','m','b','o','B','o','x',0 }; +static const WCHAR szEdit[] = { 'E','d','i','t',0 }; +static const WCHAR szMaskedEdit[] = { 'M','a','s','k','e','d','E','d','i','t',0 }; +static const WCHAR szPathEdit[] = { 'P','a','t','h','E','d','i','t',0 }; +static const WCHAR szRadioButtonGroup[] = { + 'R','a','d','i','o','B','u','t','t','o','n','G','r','o','u','p',0 }; +static const WCHAR szIcon[] = { 'I','c','o','n',0 }; + static UINT msi_dialog_checkbox_handler( msi_dialog *, msi_control *, WPARAM ); static void msi_dialog_checkbox_sync_state( msi_dialog *, msi_control * ); static UINT msi_dialog_button_handler( msi_dialog *, msi_control *, WPARAM ); static UINT msi_dialog_edit_handler( msi_dialog *, msi_control *, WPARAM ); static UINT msi_dialog_radiogroup_handler( msi_dialog *, msi_control *, WPARAM param ); +static UINT msi_dialog_evaluate_control_conditions( msi_dialog *dialog ); static LRESULT WINAPI MSIRadioGroup_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); @@ -116,12 +132,33 @@ static LRESULT WINAPI MSIRadioGroup_WndProc(HWND hWnd, UINT msg, WPARAM wParam, static DWORD uiThreadId; static HWND hMsiHiddenWindow; +static HMODULE hRichedit; -INT msi_dialog_scale_unit( msi_dialog *dialog, INT val ) +static INT msi_dialog_scale_unit( msi_dialog *dialog, INT val ) { return (dialog->scale * val + 5) / 10; } +static msi_control *msi_dialog_find_control( msi_dialog *dialog, LPCWSTR name ) +{ + msi_control *control; + + for( control = dialog->control_list; control; control = control->next ) + if( !strcmpW( control->name, name ) ) /* FIXME: case sensitive? */ + break; + return control; +} + +static msi_control *msi_dialog_find_control_by_hwnd( msi_dialog *dialog, HWND hwnd ) +{ + msi_control *control; + + for( control = dialog->control_list; control; control = control->next ) + if( hwnd == control->hwnd ) + break; + return control; +} + /* * msi_dialog_get_style * @@ -250,7 +287,7 @@ static msi_control *msi_dialog_create_window( msi_dialog *dialog, LPWSTR font = NULL, title = NULL; msi_control *control; - style |= WS_CHILD | WS_GROUP; + style |= WS_CHILD; control = HeapAlloc( GetProcessHeap(), 0, sizeof *control + strlenW(name)*sizeof(WCHAR) ); @@ -259,7 +296,9 @@ static msi_control *msi_dialog_create_window( msi_dialog *dialog, dialog->control_list = control; control->handler = NULL; control->property = NULL; + control->value = NULL; control->pic = NULL; + control->hIcon = NULL; x = MSI_RecordGetInteger( rec, 4 ); y = MSI_RecordGetInteger( rec, 5 ); @@ -292,6 +331,46 @@ static msi_control *msi_dialog_create_window( msi_dialog *dialog, return control; } +/* called from the Control Event subscription code */ +void msi_dialog_handle_event( msi_dialog* dialog, LPCWSTR control, + LPCWSTR attribute, MSIRECORD *rec ) +{ + msi_control* ctrl; + LPCWSTR text; + + ctrl = msi_dialog_find_control( dialog, control ); + if (!ctrl) + return; + if( lstrcmpW(attribute, szText) ) + return; + text = MSI_RecordGetString( rec , 1 ); + SetWindowTextW( ctrl->hwnd, text ); + msi_dialog_check_messages( NULL ); +} + +static void msi_dialog_map_events(msi_dialog* dialog, LPCWSTR control) +{ + static WCHAR Query[] = { + 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','E','v','e','n','t','M','a','p','p','i','n','g','`',' ', + 'W','H','E','R','E',' ', + '`','D','i','a','l','o','g','_','`',' ','=',' ','\'','%','s','\'',' ', + 'A','N','D',' ', + '`','C','o','n','t','r','o','l','_','`',' ','=',' ','\'','%','s','\'',0 + }; + MSIRECORD *row; + LPCWSTR event, attribute; + + row = MSI_QueryGetRecord( dialog->package->db, Query, dialog->name, control ); + if (!row) + return; + + event = MSI_RecordGetString( row, 3 ); + attribute = MSI_RecordGetString( row, 4 ); + ControlEvent_SubscribeToEvent( dialog->package, event, control, attribute ); + msiobj_release( &row->hdr ); +} + /* everything except radio buttons */ static msi_control *msi_dialog_add_control( msi_dialog *dialog, MSIRECORD *rec, LPCWSTR szCls, DWORD style ) @@ -302,19 +381,94 @@ static msi_control *msi_dialog_add_control( msi_dialog *dialog, name = MSI_RecordGetString( rec, 2 ); attributes = MSI_RecordGetInteger( rec, 8 ); text = MSI_RecordGetString( rec, 10 ); - if( attributes & 1 ) + if( attributes & msidbControlAttributesVisible ) style |= WS_VISIBLE; - if( ~attributes & 2 ) + if( ~attributes & msidbControlAttributesEnabled ) style |= WS_DISABLED; + + msi_dialog_map_events(dialog, name); + return msi_dialog_create_window( dialog, rec, szCls, name, text, style, dialog->hwnd ); } +struct msi_text_info +{ + WNDPROC oldproc; + DWORD attributes; +}; + +/* + * we don't erase our own background, + * so we have to make sure that the parent window redraws first + */ +static void msi_text_on_settext( HWND hWnd ) +{ + HWND hParent; + RECT rc; + + hParent = GetParent( hWnd ); + GetWindowRect( hWnd, &rc ); + MapWindowPoints( NULL, hParent, (LPPOINT) &rc, 2 ); + InvalidateRect( hParent, &rc, TRUE ); +} + +static LRESULT WINAPI +MSIText_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + struct msi_text_info *info; + LRESULT r = 0; + + TRACE("%p %04x %08x %08lx\n", hWnd, msg, wParam, lParam); + + info = GetPropW(hWnd, szButtonData); + + if( msg == WM_CTLCOLORSTATIC && + ( info->attributes & msidbControlAttributesTransparent ) ) + { + SetBkMode( (HDC)wParam, TRANSPARENT ); + return (LRESULT) GetStockObject(NULL_BRUSH); + } + + r = CallWindowProcW(info->oldproc, hWnd, msg, wParam, lParam); + + switch( msg ) + { + case WM_SETTEXT: + msi_text_on_settext( hWnd ); + break; + case WM_NCDESTROY: + HeapFree( GetProcessHeap(), 0, info ); + RemovePropW( hWnd, szButtonData ); + break; + } + + return r; +} + static UINT msi_dialog_text_control( msi_dialog *dialog, MSIRECORD *rec ) { + msi_control *control; + struct msi_text_info *info; + TRACE("%p %p\n", dialog, rec); - msi_dialog_add_control( dialog, rec, szStatic, 0 ); + control = msi_dialog_add_control( dialog, rec, szStatic, SS_LEFT | WS_GROUP ); + if( !control ) + return ERROR_FUNCTION_FAILED; + + info = HeapAlloc( GetProcessHeap(), 0, sizeof *info ); + if( !info ) + return ERROR_SUCCESS; + + info->attributes = MSI_RecordGetInteger( rec, 8 ); + if( info->attributes & msidbControlAttributesTransparent ) + SetWindowLongPtrW( control->hwnd, GWL_EXSTYLE, WS_EX_TRANSPARENT ); + + info->oldproc = (WNDPROC) SetWindowLongPtrW( control->hwnd, GWLP_WNDPROC, + (LONG_PTR)MSIText_WndProc ); + SetPropW( control->hwnd, szButtonData, info ); + return ERROR_SUCCESS; } @@ -324,12 +478,54 @@ static UINT msi_dialog_button_control( msi_dialog *dialog, MSIRECORD *rec ) TRACE("%p %p\n", dialog, rec); - control = msi_dialog_add_control( dialog, rec, szButton, 0 ); + control = msi_dialog_add_control( dialog, rec, szButton, WS_TABSTOP ); control->handler = msi_dialog_button_handler; return ERROR_SUCCESS; } +static LPWSTR msi_get_checkbox_value( msi_dialog *dialog, LPCWSTR prop ) +{ + const static WCHAR query[] = { + 'S','E','L','E','C','T',' ','*',' ', + 'F','R','O','M',' ','`','C','h','e','c','k','B','o','x',' ','`', + 'W','H','E','R','E',' ', + '`','P','r','o','p','e','r','t','y','`',' ','=',' ', + '\'','%','s','\'',0 + }; + MSIRECORD *rec = NULL; + LPCWSTR val = NULL; + LPWSTR ret = NULL; + + /* find if there is a value associated with the checkbox */ + rec = MSI_QueryGetRecord( dialog->package->db, query, prop ); + if (!rec) + return ret; + + val = MSI_RecordGetString( rec, 2 ); + if (val) + { + deformat_string( dialog->package, val, &ret ); + if( ret && !ret[0] ) + { + HeapFree( GetProcessHeap(), 0, ret ); + ret = NULL; + } + } + msiobj_release( &rec->hdr ); + if (ret) + return ret; + + ret = load_dynamic_property(dialog->package, prop, NULL); + if( ret && !ret[0] ) + { + HeapFree( GetProcessHeap(), 0, ret ); + ret = NULL; + } + + return ret; +} + static UINT msi_dialog_checkbox_control( msi_dialog *dialog, MSIRECORD *rec ) { msi_control *control; @@ -338,11 +534,16 @@ static UINT msi_dialog_checkbox_control( msi_dialog *dialog, MSIRECORD *rec ) TRACE("%p %p\n", dialog, rec); control = msi_dialog_add_control( dialog, rec, szButton, - BS_CHECKBOX | BS_MULTILINE ); + BS_CHECKBOX | BS_MULTILINE | WS_TABSTOP ); control->handler = msi_dialog_checkbox_handler; prop = MSI_RecordGetString( rec, 9 ); if( prop ) + { control->property = strdupW( prop ); + control->value = msi_get_checkbox_value( dialog, prop ); + TRACE("control %s value %s\n", debugstr_w(control->property), + debugstr_w(control->value)); + } msi_dialog_checkbox_sync_state( dialog, control ); return ERROR_SUCCESS; @@ -356,19 +557,61 @@ static UINT msi_dialog_line_control( msi_dialog *dialog, MSIRECORD *rec ) return ERROR_SUCCESS; } +struct msi_streamin_info +{ + LPSTR string; + DWORD offset; + DWORD length; +}; + +static DWORD CALLBACK +msi_richedit_stream_in( DWORD_PTR arg, LPBYTE buffer, LONG count, LONG *pcb ) +{ + struct msi_streamin_info *info = (struct msi_streamin_info*) arg; + + if( (count + info->offset) > info->length ) + count = info->length - info->offset; + memcpy( buffer, &info->string[ info->offset ], count ); + *pcb = count; + info->offset += count; + + TRACE("%ld/%ld\n", info->offset, info->length); + + return 0; +} + static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec ) { - const static WCHAR szEdit[] = { 'E','D','I','T',0 }; + const static WCHAR szRichEdit20W[] = { + 'R','i','c','h','E','d','i','t','2','0','W',0 + }; + struct msi_streamin_info info; + msi_control *control; + LPCWSTR text; + EDITSTREAM es; + DWORD style; - FIXME("%p %p\n", dialog, rec); + style = WS_BORDER | ES_MULTILINE | WS_VSCROLL | + ES_READONLY | ES_AUTOVSCROLL | WS_TABSTOP; + control = msi_dialog_add_control( dialog, rec, szRichEdit20W, style ); - msi_dialog_add_control( dialog, rec, szEdit, WS_BORDER | - ES_MULTILINE | WS_VSCROLL | ES_READONLY | ES_AUTOVSCROLL ); + text = MSI_RecordGetString( rec, 10 ); + info.string = strdupWtoA( text ); + info.offset = 0; + info.length = lstrlenA( info.string ) + 1; + + es.dwCookie = (DWORD_PTR) &info; + es.dwError = 0; + es.pfnCallback = msi_richedit_stream_in; + + SendMessageW( control->hwnd, EM_STREAMIN, SF_RTF, (LPARAM) &es ); + + HeapFree( GetProcessHeap(), 0, info.string ); return ERROR_SUCCESS; } -static UINT msi_load_bitmap( MSIDATABASE *db, LPCWSTR name, IPicture **pic ) +static MSIRECORD *msi_get_binary_record( MSIDATABASE *db, LPCWSTR name ) { const static WCHAR query[] = { 's','e','l','e','c','t',' ','*',' ', @@ -376,20 +619,17 @@ static UINT msi_load_bitmap( MSIDATABASE *db, LPCWSTR name, IPicture **pic ) 'w','h','e','r','e',' ', '`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0 }; - MSIQUERY *view = NULL; + + return MSI_QueryGetRecord( db, query, name ); +} + +static UINT msi_load_bitmap( MSIDATABASE *db, LPCWSTR name, IPicture **pic ) +{ MSIRECORD *rec = NULL; IStream *stm = NULL; UINT r; - r = MSI_OpenQuery( db, &view, query, name ); - if( r != ERROR_SUCCESS ) - return r; - - MSI_ViewExecute( view, NULL ); - MSI_ViewFetch( view, &rec ); - MSI_ViewClose( view ); - msiobj_release( &view->hdr ); - + rec = msi_get_binary_record( db, name ); if( !rec ) return ERROR_FUNCTION_FAILED; @@ -429,6 +669,108 @@ static UINT msi_dialog_bitmap_control( msi_dialog *dialog, MSIRECORD *rec ) return ERROR_SUCCESS; } +static LPWSTR msi_create_tmp_path(void) +{ + WCHAR tmp[MAX_PATH]; + LPWSTR path = NULL; + static const WCHAR prefix[] = { 'm','s','i',0 }; + DWORD len, r; + + r = GetTempPathW( MAX_PATH, tmp ); + if( !r ) + return path; + len = lstrlenW( tmp ) + 20; + path = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); + if( path ) + { + r = GetTempFileNameW( tmp, prefix, 0, path ); + if (!r) + { + HeapFree( GetProcessHeap(), 0, path ); + path = NULL; + } + } + return path; +} + +static UINT +msi_load_icon( MSIDATABASE *db, LPCWSTR name, DWORD attributes, HICON *picon ) +{ + UINT r = ERROR_FUNCTION_FAILED; + LPWSTR tmp; + MSIRECORD *rec; + HICON hicon = 0; + + TRACE("loading %s\n", debugstr_w( name ) ); + + tmp = msi_create_tmp_path(); + if( !tmp ) + return r; + + rec = msi_get_binary_record( db, name ); + if( rec ) + { + r = MSI_RecordStreamToFile( rec, 2, tmp ); + if( r == ERROR_SUCCESS ) + { + DWORD cx = 0, cy = 0, flags = LR_LOADFROMFILE | LR_DEFAULTSIZE; + + if( attributes & msidbControlAttributesFixedSize ) + { + flags &= ~LR_DEFAULTSIZE; + if( attributes & msidbControlAttributesIconSize16 ) + { + cx += 16; + cy += 16; + } + if( attributes & msidbControlAttributesIconSize32 ) + { + cx += 32; + cy += 32; + } + /* msidbControlAttributesIconSize48 handled by above logic */ + } + + hicon = LoadImageW( 0, tmp, IMAGE_ICON, cx, cy, flags ); + if( hicon ) + *picon = hicon; + else + ERR("failed to load icon from %s\n", debugstr_w( tmp )); + DeleteFileW( tmp ); + } + msiobj_release( &rec->hdr ); + } + + HeapFree( GetProcessHeap(), 0, tmp ); + + return r; +} + +static UINT msi_dialog_icon_control( msi_dialog *dialog, MSIRECORD *rec ) +{ + msi_control *control; + DWORD attributes; + HICON hIcon = 0; + LPCWSTR text; + UINT r; + + TRACE("\n"); + + control = msi_dialog_add_control( dialog, rec, szStatic, + SS_ICON | SS_CENTERIMAGE | WS_GROUP ); + text = MSI_RecordGetString( rec, 10 ); + attributes = MSI_RecordGetInteger( rec, 8 ); + r = msi_load_icon( dialog->package->db, text, attributes, &hIcon ); + if( r == ERROR_SUCCESS ) + { + r = SendMessageW( control->hwnd, STM_SETICON, (WPARAM) hIcon, 0 ); + control->hIcon = hIcon; + } + else + ERR("Failed to load bitmap %s\n", debugstr_w(text)); + return ERROR_SUCCESS; +} + static UINT msi_dialog_combo_control( msi_dialog *dialog, MSIRECORD *rec ) { static const WCHAR szCombo[] = { 'C','O','M','B','O','B','O','X',0 }; @@ -440,12 +782,12 @@ static UINT msi_dialog_combo_control( msi_dialog *dialog, MSIRECORD *rec ) static UINT msi_dialog_edit_control( msi_dialog *dialog, MSIRECORD *rec ) { - const static WCHAR szEdit[] = { 'E','D','I','T',0 }; msi_control *control; LPCWSTR prop; LPWSTR val; - control = msi_dialog_add_control( dialog, rec, szEdit, WS_BORDER ); + control = msi_dialog_add_control( dialog, rec, szEdit, + WS_BORDER | WS_TABSTOP ); control->handler = msi_dialog_edit_handler; prop = MSI_RecordGetString( rec, 9 ); if( prop ) @@ -456,6 +798,275 @@ static UINT msi_dialog_edit_control( msi_dialog *dialog, MSIRECORD *rec ) return ERROR_SUCCESS; } +/******************** Masked Edit ********************************************/ + +#define MASK_MAX_GROUPS 10 + +struct msi_mask_group +{ + UINT len; + UINT ofs; + WCHAR type; + HWND hwnd; +}; + +struct msi_maskedit_info +{ + msi_dialog *dialog; + WNDPROC oldproc; + HWND hwnd; + LPWSTR prop; + UINT num_chars; + UINT num_groups; + struct msi_mask_group group[MASK_MAX_GROUPS]; +}; + +static void msi_mask_control_change( struct msi_maskedit_info *info ) +{ + LPWSTR val; + UINT i, n, r; + + val = HeapAlloc( GetProcessHeap(), 0, (info->num_chars+1)*sizeof(WCHAR) ); + for( i=0, n=0; inum_groups; i++ ) + { + if( (info->group[i].len + n) > info->num_chars ) + { + ERR("can't fit control %d text into template\n",i); + break; + } + r = GetWindowTextW( info->group[i].hwnd, &val[n], info->group[i].len+1 ); + if( r != info->group[i].len ) + break; + n += r; + } + + TRACE("%d/%d controls were good\n", i, info->num_groups); + + if( i == info->num_groups ) + { + TRACE("Set property %s to %s\n", + debugstr_w(info->prop), debugstr_w(val) ); + CharUpperBuffW( val, info->num_chars ); + MSI_SetPropertyW( info->dialog->package, info->prop, val ); + msi_dialog_evaluate_control_conditions( info->dialog ); + } + HeapFree( GetProcessHeap(), 0, val ); +} + +static LRESULT WINAPI +MSIMaskedEdit_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + struct msi_maskedit_info *info; + HRESULT r; + + TRACE("%p %04x %08x %08lx\n", hWnd, msg, wParam, lParam); + + info = GetPropW(hWnd, szButtonData); + + r = CallWindowProcW(info->oldproc, hWnd, msg, wParam, lParam); + + switch( msg ) + { + case WM_COMMAND: + if (HIWORD(wParam) == EN_CHANGE) + msi_mask_control_change( info ); + break; + case WM_NCDESTROY: + HeapFree( GetProcessHeap(), 0, info->prop ); + HeapFree( GetProcessHeap(), 0, info ); + RemovePropW( hWnd, szButtonData ); + break; + } + + return r; +} + +/* fish the various bits of the property out and put them in the control */ +static void +msi_maskedit_set_text( struct msi_maskedit_info *info, LPCWSTR text ) +{ + LPCWSTR p; + UINT i; + + p = text; + for( i = 0; i < info->num_groups; i++ ) + { + if( info->group[i].len < lstrlenW( p ) ) + { + LPWSTR chunk = strdupW( p ); + chunk[ info->group[i].len ] = 0; + SetWindowTextW( info->group[i].hwnd, chunk ); + HeapFree( GetProcessHeap(), 0, chunk ); + } + else + { + SetWindowTextW( info->group[i].hwnd, p ); + break; + } + p += info->group[i].len; + } +} + +static struct msi_maskedit_info * msi_dialog_parse_groups( LPCWSTR mask ) +{ + struct msi_maskedit_info * info = NULL; + int i = 0, n = 0, total = 0; + LPCWSTR p; + + TRACE("masked control, template %s\n", debugstr_w(mask)); + + if( !mask ) + return info; + + p = strchrW(mask, '<'); + if( !p ) + return info; + + info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *info ); + if( !info ) + return info; + + p++; + for( i=0; i' ) + break; + + /* count the number of the same identifier */ + for( n=0; p[n] == p[0]; n++ ) + ; + info->group[i].ofs = total; + info->group[i].type = p[0]; + if( p[n] == '=' ) + { + n++; + total++; /* an extra not part of the group */ + } + info->group[i].len = n; + total += n; + p += n; + } + + TRACE("%d characters in %d groups\n", total, info->num_groups ); + if( i == MASK_MAX_GROUPS ) + ERR("too many groups in PIDTemplate %s\n", debugstr_w(mask)); + + info->num_chars = total; + info->num_groups = i; + + return info; +} + +static void +msi_maskedit_create_children( struct msi_maskedit_info *info ) +{ + DWORD width, height, style, wx, ww; + LPCWSTR text, font = NULL; + RECT rect; + HWND hwnd; + UINT i; + + style = WS_CHILD | WS_BORDER | WS_VISIBLE | WS_TABSTOP; + + GetClientRect( info->hwnd, &rect ); + + width = rect.right - rect.left; + height = rect.bottom - rect.top; + + if( text ) + font = msi_dialog_get_style( &text ); + + for( i = 0; i < info->num_groups; i++ ) + { + wx = (info->group[i].ofs * width) / info->num_chars; + ww = (info->group[i].len * width) / info->num_chars; + + hwnd = CreateWindowW( szEdit, NULL, style, wx, 0, ww, height, + info->hwnd, NULL, NULL, NULL ); + if( !hwnd ) + { + ERR("failed to create mask edit sub window\n"); + break; + } + + SendMessageW( hwnd, EM_LIMITTEXT, info->group[i].len, 0 ); + + msi_dialog_set_font( info->dialog, hwnd, + font ? font : info->dialog->default_font ); + info->group[i].hwnd = hwnd; + } +} + +/* office 2003 uses "73931<````=````=````=````=`````>@@@@@" */ +static UINT msi_dialog_maskedit_control( msi_dialog *dialog, MSIRECORD *rec ) +{ + const static WCHAR pidt[] = {'P','I','D','T','e','m','p','l','a','t','e',0}; + LPWSTR mask = NULL, title = NULL, val = NULL; + struct msi_maskedit_info *info = NULL; + UINT ret = ERROR_SUCCESS; + msi_control *control; + LPCWSTR prop; + + mask = load_dynamic_property( dialog->package, pidt, NULL ); + if( !mask ) + { + ERR("PIDTemplate is empty\n"); + goto end; + } + + info = msi_dialog_parse_groups( mask ); + if( !info ) + { + ERR("template %s is invalid\n", debugstr_w(mask)); + goto end; + } + + info->dialog = dialog; + + control = msi_dialog_add_control( dialog, rec, szStatic, + SS_OWNERDRAW | WS_GROUP | WS_VISIBLE ); + if( !control ) + { + ERR("Failed to create maskedit container\n"); + ret = ERROR_FUNCTION_FAILED; + goto end; + } + SetWindowLongPtrW( control->hwnd, GWL_EXSTYLE, WS_EX_CONTROLPARENT ); + + info->hwnd = control->hwnd; + + /* subclass the static control */ + info->oldproc = (WNDPROC) SetWindowLongPtrW( info->hwnd, GWLP_WNDPROC, + (LONG_PTR)MSIMaskedEdit_WndProc ); + SetPropW( control->hwnd, szButtonData, info ); + + prop = MSI_RecordGetString( rec, 9 ); + if( prop ) + info->prop = strdupW( prop ); + + msi_maskedit_create_children( info ); + + if( prop ) + { + val = load_dynamic_property( dialog->package, prop, NULL ); + if( val ) + { + msi_maskedit_set_text( info, val ); + HeapFree( GetProcessHeap(), 0, val ); + } + } + +end: + if( ret != ERROR_SUCCESS ) + HeapFree( GetProcessHeap(), 0, info ); + HeapFree( GetProcessHeap(), 0, title ); + HeapFree( GetProcessHeap(), 0, mask ); + return ret; +} + +/******************** Path Edit ********************************************/ + static UINT msi_dialog_pathedit_control( msi_dialog *dialog, MSIRECORD *rec ) { FIXME("not implemented properly\n"); @@ -472,7 +1083,7 @@ static UINT msi_dialog_create_radiobutton( MSIRECORD *rec, LPVOID param ) DWORD style; DWORD attributes = group->attributes; - style = WS_CHILD | BS_AUTORADIOBUTTON | BS_MULTILINE; + style = WS_CHILD | BS_AUTORADIOBUTTON | BS_MULTILINE | WS_TABSTOP; name = MSI_RecordGetString( rec, 3 ); text = MSI_RecordGetString( rec, 8 ); if( attributes & 1 ) @@ -504,20 +1115,21 @@ static UINT msi_dialog_radiogroup_control( msi_dialog *dialog, MSIRECORD *rec ) MSIQUERY *view = NULL; radio_button_group_descr group; MSIPACKAGE *package = dialog->package; + WNDPROC oldproc; prop = MSI_RecordGetString( rec, 9 ); TRACE("%p %p %s\n", dialog, rec, debugstr_w( prop )); /* Create parent group box to hold radio buttons */ - control = msi_dialog_add_control( dialog, rec, szButton, BS_OWNERDRAW ); + control = msi_dialog_add_control( dialog, rec, szButton, BS_OWNERDRAW|WS_GROUP ); + if( !control ) + return ERROR_FUNCTION_FAILED; - if (control->hwnd) - { - WNDPROC oldproc = (WNDPROC) SetWindowLongPtrW(control->hwnd, GWLP_WNDPROC, - (LONG_PTR)MSIRadioGroup_WndProc); - SetPropW(control->hwnd, szButtonData, oldproc); - } + oldproc = (WNDPROC) SetWindowLongPtrW( control->hwnd, GWLP_WNDPROC, + (LONG_PTR)MSIRadioGroup_WndProc ); + SetPropW(control->hwnd, szButtonData, oldproc); + SetWindowLongPtrW( control->hwnd, GWL_EXSTYLE, WS_EX_CONTROLPARENT ); if( prop ) control->property = strdupW( prop ); @@ -541,20 +1153,6 @@ static UINT msi_dialog_radiogroup_control( msi_dialog *dialog, MSIRECORD *rec ) return r; } -static const WCHAR szText[] = { 'T','e','x','t',0 }; -static const WCHAR szPushButton[] = { 'P','u','s','h','B','u','t','t','o','n',0 }; -static const WCHAR szLine[] = { 'L','i','n','e',0 }; -static const WCHAR szBitmap[] = { 'B','i','t','m','a','p',0 }; -static const WCHAR szCheckBox[] = { 'C','h','e','c','k','B','o','x',0 }; -static const WCHAR szScrollableText[] = { - 'S','c','r','o','l','l','a','b','l','e','T','e','x','t',0 }; -static const WCHAR szComboBox[] = { 'C','o','m','b','o','B','o','x',0 }; -static const WCHAR szEdit[] = { 'E','d','i','t',0 }; -static const WCHAR szMaskedEdit[] = { 'M','a','s','k','e','d','E','d','i','t',0 }; -static const WCHAR szPathEdit[] = { 'P','a','t','h','E','d','i','t',0 }; -static const WCHAR szRadioButtonGroup[] = { - 'R','a','d','i','o','B','u','t','t','o','n','G','r','o','u','p',0 }; - struct control_handler msi_dialog_handler[] = { { szText, msi_dialog_text_control }, @@ -565,9 +1163,10 @@ struct control_handler msi_dialog_handler[] = { szScrollableText, msi_dialog_scrolltext_control }, { szComboBox, msi_dialog_combo_control }, { szEdit, msi_dialog_edit_control }, - { szMaskedEdit, msi_dialog_edit_control }, + { szMaskedEdit, msi_dialog_maskedit_control }, { szPathEdit, msi_dialog_pathedit_control }, { szRadioButtonGroup, msi_dialog_radiogroup_control }, + { szIcon, msi_dialog_icon_control }, }; #define NUM_CONTROL_TYPES (sizeof msi_dialog_handler/sizeof msi_dialog_handler[0]) @@ -618,26 +1217,6 @@ static UINT msi_dialog_fill_controls( msi_dialog *dialog ) return r; } -static msi_control *msi_dialog_find_control( msi_dialog *dialog, LPCWSTR name ) -{ - msi_control *control; - - for( control = dialog->control_list; control; control = control->next ) - if( !strcmpW( control->name, name ) ) /* FIXME: case sensitive? */ - break; - return control; -} - -static msi_control *msi_dialog_find_control_by_hwnd( msi_dialog *dialog, HWND hwnd ) -{ - msi_control *control; - - for( control = dialog->control_list; control; control = control->next ) - if( hwnd == control->hwnd ) - break; - return control; -} - static UINT msi_dialog_set_control_condition( MSIRECORD *rec, LPVOID param ) { static const WCHAR szHide[] = { 'H','i','d','e',0 }; @@ -659,7 +1238,7 @@ static UINT msi_dialog_set_control_condition( MSIRECORD *rec, LPVOID param ) TRACE("%s control %s\n", debugstr_w(action), debugstr_w(name)); /* FIXME: case sensitive? */ - if(!strcmpW(action, szHide)) + if(!lstrcmpW(action, szHide)) ShowWindow(control->hwnd, SW_HIDE); else if(!strcmpW(action, szShow)) ShowWindow(control->hwnd, SW_SHOW); @@ -745,35 +1324,42 @@ static MSIRECORD *msi_get_dialog_record( msi_dialog *dialog ) 'W','H','E','R','E',' ', '`','D','i','a','l','o','g','`',' ','=',' ','\'','%','s','\'',0}; MSIPACKAGE *package = dialog->package; - MSIQUERY *view = NULL; MSIRECORD *rec = NULL; - UINT r; TRACE("%p %s\n", dialog, debugstr_w(dialog->name) ); - r = MSI_OpenQuery( package->db, &view, query, dialog->name ); - if( r != ERROR_SUCCESS ) - { + rec = MSI_QueryGetRecord( package->db, query, dialog->name ); + if( !rec ) ERR("query failed for dialog %s\n", debugstr_w(dialog->name)); - return NULL; - } - MSI_ViewExecute( view, NULL ); - MSI_ViewFetch( view, &rec ); - MSI_ViewClose( view ); - msiobj_release( &view->hdr ); return rec; } +static void msi_dialog_adjust_dialog_size( msi_dialog *dialog, LPSIZE sz ) +{ + RECT rect; + LONG style; + + /* turn the client size into the window rectangle */ + rect.left = 0; + rect.top = 0; + rect.right = msi_dialog_scale_unit( dialog, sz->cx ); + rect.bottom = msi_dialog_scale_unit( dialog, sz->cy ); + style = GetWindowLongPtrW( dialog->hwnd, GWL_STYLE ); + AdjustWindowRect( &rect, style, FALSE ); + sz->cx = rect.right - rect.left; + sz->cy = rect.bottom - rect.top; +} + static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs ) { static const WCHAR df[] = { 'D','e','f','a','u','l','t','U','I','F','o','n','t',0 }; msi_dialog *dialog = (msi_dialog*) cs->lpCreateParams; MSIRECORD *rec = NULL; - DWORD width, height; LPCWSTR text; LPWSTR title = NULL; + SIZE size; TRACE("%p %p\n", dialog, dialog->package); @@ -789,19 +1375,18 @@ static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs ) dialog->scale = msi_dialog_get_sans_serif_height(dialog->hwnd); - width = MSI_RecordGetInteger( rec, 4 ); - height = MSI_RecordGetInteger( rec, 5 ); + size.cx = MSI_RecordGetInteger( rec, 4 ); + size.cy = MSI_RecordGetInteger( rec, 5 ); + msi_dialog_adjust_dialog_size( dialog, &size ); + dialog->attributes = MSI_RecordGetInteger( rec, 6 ); text = MSI_RecordGetString( rec, 7 ); - width = msi_dialog_scale_unit( dialog, width ); - height = msi_dialog_scale_unit( dialog, height ) + 25; /* FIXME */ - dialog->default_font = load_dynamic_property( dialog->package, df, NULL ); deformat_string( dialog->package, text, &title ); SetWindowTextW( hwnd, title ); - SetWindowPos( hwnd, 0, 0, 0, width, height, + SetWindowPos( hwnd, 0, 0, 0, size.cx, size.cy, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW ); HeapFree( GetProcessHeap(), 0, title ); @@ -914,17 +1499,29 @@ static UINT msi_dialog_get_checkbox_state( msi_dialog *dialog, DWORD sz = 2; MSI_GetPropertyW( dialog->package, control->property, state, &sz ); - return atoiW( state ) ? 1 : 0; + return state[0] ? 1 : 0; } static void msi_dialog_set_checkbox_state( msi_dialog *dialog, msi_control *control, UINT state ) { - WCHAR szState[2] = { '0', 0 }; + static const WCHAR szState[] = { '1', 0 }; + LPCWSTR val; - if( state ) - szState[0]++; - MSI_SetPropertyW( dialog->package, control->property, szState ); + /* if uncheck then the property is set to NULL */ + if (!state) + { + MSI_SetPropertyW( dialog->package, control->property, NULL ); + return; + } + + /* check for a custom state */ + if (control->value && control->value[0]) + val = control->value; + else + val = szState; + + MSI_SetPropertyW( dialog->package, control->property, val ); } static void msi_dialog_checkbox_sync_state( msi_dialog *dialog, @@ -1035,6 +1632,10 @@ static LRESULT WINAPI MSIDialog_WndProc( HWND hwnd, UINT msg, case WM_COMMAND: return msi_dialog_oncommand( dialog, wParam, (HWND)lParam ); + /* bounce back to our subclassed static control */ + case WM_CTLCOLORSTATIC: + return SendMessageW( (HWND) lParam, WM_CTLCOLORSTATIC, wParam, lParam ); + case WM_DESTROY: dialog->hwnd = NULL; return 0; @@ -1106,12 +1707,14 @@ msi_dialog *msi_dialog_create( MSIPACKAGE* package, LPCWSTR szDialogName, return dialog; } -static void msi_process_pending_messages(void) +static void msi_process_pending_messages( HWND hdlg ) { MSG msg; while( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ) ) { + if( hdlg && IsDialogMessageW( hdlg, &msg )) + continue; TranslateMessage( &msg ); DispatchMessageW( &msg ); } @@ -1139,7 +1742,7 @@ void msi_dialog_check_messages( HANDLE handle ) /* there's two choices for the UI thread */ while (1) { - msi_process_pending_messages(); + msi_process_pending_messages( NULL ); if( !handle ) break; @@ -1182,7 +1785,7 @@ UINT msi_dialog_run_message_loop( msi_dialog *dialog ) while( !dialog->finished ) { MsgWaitForMultipleObjects( 0, NULL, 0, INFINITE, QS_ALLEVENTS ); - msi_process_pending_messages(); + msi_process_pending_messages( dialog->hwnd ); } } else @@ -1217,8 +1820,11 @@ void msi_dialog_destroy( msi_dialog *dialog ) dialog->control_list = t->next; /* leave dialog->hwnd - destroying parent destroys child windows */ HeapFree( GetProcessHeap(), 0, t->property ); + HeapFree( GetProcessHeap(), 0, t->value ); if( t->pic ) IPicture_Release( t->pic ); + if( t->hIcon ) + DestroyIcon( t->hIcon ); HeapFree( GetProcessHeap(), 0, t ); } @@ -1269,6 +1875,8 @@ BOOL msi_dialog_register_class( void ) if( !hMsiHiddenWindow ) return FALSE; + hRichedit = LoadLibraryA("riched20"); + return TRUE; } @@ -1277,4 +1885,5 @@ void msi_dialog_unregister_class( void ) DestroyWindow( hMsiHiddenWindow ); UnregisterClassW( szMsiDialogClass, NULL ); uiThreadId = 0; + FreeLibrary( hRichedit ); } diff --git a/reactos/lib/msi/events.c b/reactos/lib/msi/events.c new file mode 100644 index 00000000000..6d6682bb91f --- /dev/null +++ b/reactos/lib/msi/events.c @@ -0,0 +1,396 @@ +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2005 Aric Stewart for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* +http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/controlevent_overview.asp +*/ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" +#include "msi.h" +#include "msipriv.h" +#include "action.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +typedef UINT (*EVENTHANDLER)(MSIPACKAGE*,LPCWSTR,msi_dialog *); + +struct _events { + LPCSTR event; + EVENTHANDLER handler; +}; + +struct subscriber { + struct list entry; + LPWSTR event; + LPWSTR control; + LPWSTR attribute; +}; + +UINT ControlEvent_HandleControlEvent(MSIPACKAGE *, LPCWSTR, LPCWSTR, msi_dialog*); + +/* + * Create a dialog box and run it if it's modal + */ +static UINT event_do_dialog( MSIPACKAGE *package, LPCWSTR name ) +{ + msi_dialog *dialog; + UINT r; + + /* kill the current modeless dialog */ + if( package->dialog ) + msi_dialog_destroy( package->dialog ); + package->dialog = NULL; + + /* create a new dialog */ + dialog = msi_dialog_create( package, name, + ControlEvent_HandleControlEvent ); + if( dialog ) + { + /* modeless dialogs return an error message */ + r = msi_dialog_run_message_loop( dialog ); + if( r == ERROR_SUCCESS ) + msi_dialog_destroy( dialog ); + else + package->dialog = dialog; + } + else + r = ERROR_FUNCTION_FAILED; + + return r; +} + + +/* + * End a modal dialog box + */ +static UINT ControlEvent_EndDialog(MSIPACKAGE* package, LPCWSTR argument, + msi_dialog* dialog) +{ + static const WCHAR szExit[] = { + 'E','x','i','t',0}; + static const WCHAR szRetry[] = { + 'R','e','t','r','y',0}; + static const WCHAR szIgnore[] = { + 'I','g','n','o','r','e',0}; + static const WCHAR szReturn[] = { + 'R','e','t','u','r','n',0}; + + if (lstrcmpW(argument,szExit)==0) + package->CurrentInstallState = ERROR_INSTALL_USEREXIT; + else if (lstrcmpW(argument, szRetry) == 0) + package->CurrentInstallState = ERROR_INSTALL_SUSPEND; + else if (lstrcmpW(argument, szIgnore) == 0) + package->CurrentInstallState = -1; + else if (lstrcmpW(argument, szReturn) == 0) + package->CurrentInstallState = ERROR_SUCCESS; + else + { + ERR("Unknown argument string %s\n",debugstr_w(argument)); + package->CurrentInstallState = ERROR_FUNCTION_FAILED; + } + + ControlEvent_CleanupSubscriptions(package); + msi_dialog_end_dialog( dialog ); + return ERROR_SUCCESS; +} + +/* + * transition from one modal dialog to another modal dialog + */ +static UINT ControlEvent_NewDialog(MSIPACKAGE* package, LPCWSTR argument, + msi_dialog *dialog) +{ + /* store the name of the next dialog, and signal this one to end */ + package->next_dialog = strdupW(argument); + ControlEvent_CleanupSubscriptions(package); + msi_dialog_end_dialog( dialog ); + return ERROR_SUCCESS; +} + +/* + * Create a new child dialog of an existing modal dialog + */ +static UINT ControlEvent_SpawnDialog(MSIPACKAGE* package, LPCWSTR argument, + msi_dialog *dialog) +{ + event_do_dialog( package, argument ); + if( package->CurrentInstallState != ERROR_SUCCESS ) + msi_dialog_end_dialog( dialog ); + return ERROR_SUCCESS; +} + +/* + * Creates a dialog that remains up for a period of time + * based on a condition + */ +static UINT ControlEvent_SpawnWaitDialog(MSIPACKAGE* package, LPCWSTR argument, + msi_dialog* dialog) +{ + FIXME("Doing Nothing\n"); + return ERROR_SUCCESS; +} + +static UINT ControlEvent_DoAction(MSIPACKAGE* package, LPCWSTR argument, + msi_dialog* dialog) +{ + ACTION_PerformAction(package,argument,TRUE); + return ERROR_SUCCESS; +} + +static UINT ControlEvent_AddLocal(MSIPACKAGE* package, LPCWSTR argument, + msi_dialog* dialog) +{ + static const WCHAR szAll[] = {'A','L','L',0}; + int i; + + if (lstrcmpW(szAll,argument)) + { + MSI_SetFeatureStateW(package,argument,INSTALLSTATE_LOCAL); + } + else + { + for (i = 0; i < package->loaded_features; i++) + { + package->features[i].ActionRequest = INSTALLSTATE_LOCAL; + package->features[i].Action = INSTALLSTATE_LOCAL; + } + ACTION_UpdateComponentStates(package,argument); + } + return ERROR_SUCCESS; +} + +static UINT ControlEvent_Remove(MSIPACKAGE* package, LPCWSTR argument, + msi_dialog* dialog) +{ + static const WCHAR szAll[] = {'A','L','L',0}; + int i; + + if (lstrcmpW(szAll,argument)) + { + MSI_SetFeatureStateW(package,argument,INSTALLSTATE_ABSENT); + } + else + { + for (i = 0; i < package->loaded_features; i++) + { + package->features[i].ActionRequest = INSTALLSTATE_ABSENT; + package->features[i].Action= INSTALLSTATE_ABSENT; + } + ACTION_UpdateComponentStates(package,argument); + } + return ERROR_SUCCESS; +} + +static UINT ControlEvent_AddSource(MSIPACKAGE* package, LPCWSTR argument, + msi_dialog* dialog) +{ + static const WCHAR szAll[] = {'A','L','L',0}; + int i; + + if (lstrcmpW(szAll,argument)) + { + MSI_SetFeatureStateW(package,argument,INSTALLSTATE_SOURCE); + } + else + { + for (i = 0; i < package->loaded_features; i++) + { + package->features[i].ActionRequest = INSTALLSTATE_SOURCE; + package->features[i].Action = INSTALLSTATE_SOURCE; + } + ACTION_UpdateComponentStates(package,argument); + } + return ERROR_SUCCESS; +} + +static UINT ControlEvent_SetTargetPath(MSIPACKAGE* package, LPCWSTR argument, + msi_dialog* dialog) +{ + LPWSTR path = load_dynamic_property(package,argument, NULL); + /* failure to set the path halts the executing of control events */ + return MSI_SetTargetPathW(package, argument, path); +} + +/* + * Subscribed events + */ +static void free_subscriber( struct subscriber *sub ) +{ + HeapFree(GetProcessHeap(),0,sub->event); + HeapFree(GetProcessHeap(),0,sub->control); + HeapFree(GetProcessHeap(),0,sub->attribute); + HeapFree(GetProcessHeap(),0,sub); +} + +VOID ControlEvent_SubscribeToEvent( MSIPACKAGE *package, LPCWSTR event, + LPCWSTR control, LPCWSTR attribute ) +{ + struct subscriber *sub; + + sub = HeapAlloc(GetProcessHeap(),0,sizeof (*sub)); + if( !sub ) + return; + sub->event = strdupW(event); + sub->control = strdupW(control); + sub->attribute = strdupW(attribute); + list_add_tail( &package->subscriptions, &sub->entry ); +} + +VOID ControlEvent_UnSubscribeToEvent( MSIPACKAGE *package, LPCWSTR event, + LPCWSTR control, LPCWSTR attribute ) +{ + struct list *i, *t; + struct subscriber *sub; + + LIST_FOR_EACH_SAFE( i, t, &package->subscriptions ) + { + sub = LIST_ENTRY( i, struct subscriber, entry ); + + if( lstrcmpiW(sub->control,control) ) + continue; + if( lstrcmpiW(sub->attribute,attribute) ) + continue; + if( lstrcmpiW(sub->event,event) ) + continue; + list_remove( &sub->entry ); + free_subscriber( sub ); + } +} + +VOID ControlEvent_FireSubscribedEvent( MSIPACKAGE *package, LPCWSTR event, + MSIRECORD *rec ) +{ + struct subscriber *sub; + + TRACE("Firing Event %s\n",debugstr_w(event)); + + if (!package->dialog) + return; + + LIST_FOR_EACH_ENTRY( sub, &package->subscriptions, struct subscriber, entry ) + { + if (lstrcmpiW(sub->event, event)) + continue; + msi_dialog_handle_event( package->dialog, sub->control, + sub->attribute, rec ); + } +} + +VOID ControlEvent_CleanupSubscriptions(MSIPACKAGE *package) +{ + struct list *i, *t; + struct subscriber *sub; + + LIST_FOR_EACH_SAFE( i, t, &package->subscriptions ) + { + sub = LIST_ENTRY( i, struct subscriber, entry ); + + list_remove( &sub->entry ); + free_subscriber( sub ); + } +} + +/* + * ACTION_DialogBox() + * + * Return ERROR_SUCCESS if dialog is process and ERROR_FUNCTION_FAILED + * if the given parameter is not a dialog box + */ +UINT ACTION_DialogBox( MSIPACKAGE* package, LPCWSTR szDialogName ) +{ + UINT r = ERROR_SUCCESS; + + if( package->next_dialog ) + ERR("Already a next dialog... ignoring it\n"); + package->next_dialog = NULL; + + /* + * Dialogs are chained by filling in the next_dialog member + * of the package structure, then terminating the current dialog. + * The code below sees the next_dialog member set, and runs the + * next dialog. + * We fall out of the loop below if we come across a modeless + * dialog, as it returns ERROR_IO_PENDING when we try to run + * its message loop. + */ + r = event_do_dialog( package, szDialogName ); + while( r == ERROR_SUCCESS && package->next_dialog ) + { + LPWSTR name = package->next_dialog; + + package->next_dialog = NULL; + r = event_do_dialog( package, name ); + HeapFree( GetProcessHeap(), 0, name ); + } + + if( r == ERROR_IO_PENDING ) + r = ERROR_SUCCESS; + + return r; +} + +struct _events Events[] = { + { "EndDialog",ControlEvent_EndDialog }, + { "NewDialog",ControlEvent_NewDialog }, + { "SpawnDialog",ControlEvent_SpawnDialog }, + { "SpawnWaitDialog",ControlEvent_SpawnWaitDialog }, + { "DoAction",ControlEvent_DoAction }, + { "AddLocal",ControlEvent_AddLocal }, + { "Remove",ControlEvent_Remove }, + { "AddSource",ControlEvent_AddSource }, + { "SetTargetPath",ControlEvent_SetTargetPath }, + { NULL,NULL }, +}; + +UINT ControlEvent_HandleControlEvent(MSIPACKAGE *package, LPCWSTR event, + LPCWSTR argument, msi_dialog* dialog) +{ + int i = 0; + UINT rc = ERROR_SUCCESS; + + TRACE("Handling Control Event %s\n",debugstr_w(event)); + if (!event) + return rc; + + while( Events[i].event != NULL) + { + LPWSTR wevent = strdupAtoW(Events[i].event); + if (lstrcmpW(wevent,event)==0) + { + HeapFree(GetProcessHeap(),0,wevent); + rc = Events[i].handler(package,argument,dialog); + return rc; + } + HeapFree(GetProcessHeap(),0,wevent); + i++; + } + FIXME("unhandled control event %s arg(%s)\n", + debugstr_w(event), debugstr_w(argument)); + return rc; +} diff --git a/reactos/lib/msi/files.c b/reactos/lib/msi/files.c new file mode 100644 index 00000000000..a4fd40e493d --- /dev/null +++ b/reactos/lib/msi/files.c @@ -0,0 +1,759 @@ +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2005 Aric Stewart for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* + * Actions dealing with files These are + * + * InstallFiles + * DuplicateFiles + * MoveFiles (TODO) + * PatchFiles (TODO) + * RemoveDuplicateFiles(TODO) + * RemoveFiles(TODO) + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "fdi.h" +#include "msidefs.h" +#include "msvcrt/fcntl.h" +#include "msipriv.h" +#include "winuser.h" +#include "wine/unicode.h" +#include "action.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +extern const WCHAR szInstallFiles[]; +extern const WCHAR szDuplicateFiles[]; +extern const WCHAR szMoveFiles[]; +extern const WCHAR szPatchFiles[]; +extern const WCHAR szRemoveDuplicateFiles[]; +extern const WCHAR szRemoveFiles[]; + +static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0}; + +inline static UINT create_component_directory ( MSIPACKAGE* package, INT component) +{ + UINT rc = ERROR_SUCCESS; + MSIFOLDER *folder; + LPWSTR install_path; + + install_path = resolve_folder(package, package->components[component].Directory, + FALSE, FALSE, &folder); + if (!install_path) + return ERROR_FUNCTION_FAILED; + + /* create the path */ + if (folder->State == 0) + { + create_full_pathW(install_path); + folder->State = 2; + } + HeapFree(GetProcessHeap(), 0, install_path); + + return rc; +} + +/* + * This is a helper function for handling embedded cabinet media + */ +static UINT writeout_cabinet_stream(MSIPACKAGE *package, LPCWSTR stream_name, + WCHAR* source) +{ + UINT rc; + USHORT* data; + UINT size; + DWORD write; + HANDLE the_file; + WCHAR tmp[MAX_PATH]; + + rc = read_raw_stream_data(package->db,stream_name,&data,&size); + if (rc != ERROR_SUCCESS) + return rc; + + write = MAX_PATH; + if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write)) + GetTempPathW(MAX_PATH,tmp); + + GetTempFileNameW(tmp,stream_name,0,source); + + track_tempfile(package,strrchrW(source,'\\'), source); + the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + + if (the_file == INVALID_HANDLE_VALUE) + { + ERR("Unable to create file %s\n",debugstr_w(source)); + rc = ERROR_FUNCTION_FAILED; + goto end; + } + + WriteFile(the_file,data,size,&write,NULL); + CloseHandle(the_file); + TRACE("wrote %li bytes to %s\n",write,debugstr_w(source)); +end: + HeapFree(GetProcessHeap(),0,data); + return rc; +} + + +/* Support functions for FDI functions */ +typedef struct +{ + MSIPACKAGE* package; + LPCSTR cab_path; +} CabData; + +static void * cabinet_alloc(ULONG cb) +{ + return HeapAlloc(GetProcessHeap(), 0, cb); +} + +static void cabinet_free(void *pv) +{ + HeapFree(GetProcessHeap(), 0, pv); +} + +static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode) +{ + DWORD dwAccess = 0; + DWORD dwShareMode = 0; + DWORD dwCreateDisposition = OPEN_EXISTING; + switch (oflag & _O_ACCMODE) + { + case _O_RDONLY: + dwAccess = GENERIC_READ; + dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE; + break; + case _O_WRONLY: + dwAccess = GENERIC_WRITE; + dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + break; + case _O_RDWR: + dwAccess = GENERIC_READ | GENERIC_WRITE; + dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + break; + } + if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL)) + dwCreateDisposition = CREATE_NEW; + else if (oflag & _O_CREAT) + dwCreateDisposition = CREATE_ALWAYS; + return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL, + dwCreateDisposition, 0, NULL); +} + +static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb) +{ + DWORD dwRead; + if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL)) + return dwRead; + return 0; +} + +static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb) +{ + DWORD dwWritten; + if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL)) + return dwWritten; + return 0; +} + +static int cabinet_close(INT_PTR hf) +{ + return CloseHandle((HANDLE)hf) ? 0 : -1; +} + +static long cabinet_seek(INT_PTR hf, long dist, int seektype) +{ + /* flags are compatible and so are passed straight through */ + return SetFilePointer((HANDLE)hf, dist, NULL, seektype); +} + +static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) +{ + switch (fdint) + { + case fdintCOPY_FILE: + { + CabData *data = (CabData*) pfdin->pv; + ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1); + char *file; + + LPWSTR trackname; + LPWSTR trackpath; + LPWSTR tracknametmp; + static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0}; + LPWSTR given_file; + INT index; + + MSIRECORD * uirow; + LPWSTR uipath; + + given_file = strdupAtoW(pfdin->psz1); + index = get_loaded_file(data->package, given_file); + + if (index < 0) + { + ERR("Unknown File in Cabinent (%s)\n",debugstr_w(given_file)); + HeapFree(GetProcessHeap(),0,given_file); + return 0; + } + + if (!((data->package->files[index].State == 1 || + data->package->files[index].State == 2))) + { + TRACE("Skipping extraction of %s\n",debugstr_w(given_file)); + HeapFree(GetProcessHeap(),0,given_file); + return 0; + } + + file = cabinet_alloc((len+1)*sizeof(char)); + strcpy(file, data->cab_path); + strcat(file, pfdin->psz1); + + TRACE("file: %s\n", debugstr_a(file)); + + /* track this file so it can be deleted if not installed */ + trackpath=strdupAtoW(file); + tracknametmp=strdupAtoW(strrchr(file,'\\')+1); + trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) + + strlenW(tmpprefix)+1) * sizeof(WCHAR)); + + strcpyW(trackname,tmpprefix); + strcatW(trackname,tracknametmp); + + track_tempfile(data->package, trackname, trackpath); + + HeapFree(GetProcessHeap(),0,trackpath); + HeapFree(GetProcessHeap(),0,trackname); + HeapFree(GetProcessHeap(),0,tracknametmp); + + /* the UI chunk */ + uirow=MSI_CreateRecord(9); + MSI_RecordSetStringW(uirow,1,data->package->files[index].File); + uipath = strdupW(data->package->files[index].TargetPath); + *(strrchrW(uipath,'\\')+1)=0; + MSI_RecordSetStringW(uirow,9,uipath); + MSI_RecordSetInteger(uirow,6,data->package->files[index].FileSize); + ui_actiondata(data->package,szInstallFiles,uirow); + msiobj_release( &uirow->hdr ); + HeapFree(GetProcessHeap(),0,uipath); + + ui_progress(data->package,2,data->package->files[index].FileSize,0,0); + + return cabinet_open(file, _O_WRONLY | _O_CREAT, 0); + } + case fdintCLOSE_FILE_INFO: + { + FILETIME ft; + FILETIME ftLocal; + if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft)) + return -1; + if (!LocalFileTimeToFileTime(&ft, &ftLocal)) + return -1; + if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal)) + return -1; + + cabinet_close(pfdin->hf); + return 1; + } + default: + return 0; + } +} + +/*********************************************************************** + * extract_cabinet_file + * + * Extract files from a cab file. + */ +static BOOL extract_cabinet_file(MSIPACKAGE* package, LPCWSTR source, + LPCWSTR path) +{ + HFDI hfdi; + ERF erf; + BOOL ret; + char *cabinet; + char *cab_path; + CabData data; + + TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path)); + + hfdi = FDICreate(cabinet_alloc, + cabinet_free, + cabinet_open, + cabinet_read, + cabinet_write, + cabinet_close, + cabinet_seek, + 0, + &erf); + if (!hfdi) + { + ERR("FDICreate failed\n"); + return FALSE; + } + + if (!(cabinet = strdupWtoA( source ))) + { + FDIDestroy(hfdi); + return FALSE; + } + if (!(cab_path = strdupWtoA( path ))) + { + FDIDestroy(hfdi); + HeapFree(GetProcessHeap(), 0, cabinet); + return FALSE; + } + + data.package = package; + data.cab_path = cab_path; + + ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data); + + if (!ret) + ERR("FDICopy failed\n"); + + FDIDestroy(hfdi); + + HeapFree(GetProcessHeap(), 0, cabinet); + HeapFree(GetProcessHeap(), 0, cab_path); + + return ret; +} + +static VOID set_file_source(MSIPACKAGE* package, MSIFILE* file, MSICOMPONENT* + comp, LPCWSTR path) +{ + if (file->Attributes & msidbFileAttributesNoncompressed) + { + LPWSTR p; + p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL); + file->SourcePath = build_directory_name(2, p, file->ShortName); + HeapFree(GetProcessHeap(),0,p); + } + else + file->SourcePath = build_directory_name(2, path, file->File); +} + +static UINT ready_media_for_file(MSIPACKAGE *package, int fileindex, + MSICOMPONENT* comp) +{ + UINT rc = ERROR_SUCCESS; + MSIRECORD * row = 0; + static WCHAR source[MAX_PATH]; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ', + '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ', + '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=', + ' ','%', 'i',' ','O','R','D','E','R',' ','B','Y',' ', + '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0}; + LPCWSTR cab; + DWORD sz; + INT seq; + static UINT last_sequence = 0; + static LPWSTR last_path = NULL; + MSIFILE* file = NULL; + + /* cleanup signal */ + if (!package) + { + HeapFree(GetProcessHeap(),0,last_path); + return ERROR_SUCCESS; + } + + file = &package->files[fileindex]; + + if (file->Sequence <= last_sequence) + { + set_file_source(package,file,comp,last_path); + TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence); + return ERROR_SUCCESS; + } + + row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence); + if (!row) + { + TRACE("Unable to query row\n"); + return ERROR_FUNCTION_FAILED; + } + + seq = MSI_RecordGetInteger(row,2); + last_sequence = seq; + + HeapFree(GetProcessHeap(),0,last_path); + last_path = NULL; + + if (file->Attributes & msidbFileAttributesNoncompressed) + { + last_path = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL); + set_file_source(package,file,comp,last_path); + msiobj_release(&row->hdr); + return rc; + } + + cab = MSI_RecordGetString(row,4); + if (cab) + { + TRACE("Source is CAB %s\n",debugstr_w(cab)); + /* the stream does not contain the # character */ + if (cab[0]=='#') + { + writeout_cabinet_stream(package,&cab[1],source); + last_path = strdupW(source); + *(strrchrW(last_path,'\\')+1)=0; + } + else + { + sz = MAX_PATH; + last_path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR)); + if (MSI_GetPropertyW(package, cszSourceDir, source, &sz)) + { + ERR("No Source dir defined \n"); + rc = ERROR_FUNCTION_FAILED; + } + else + { + strcpyW(last_path,source); + strcatW(source,cab); + /* extract the cab file into a folder in the temp folder */ + sz = MAX_PATH; + if (MSI_GetPropertyW(package, cszTempFolder,last_path, &sz) + != ERROR_SUCCESS) + GetTempPathW(MAX_PATH,last_path); + } + } + rc = !extract_cabinet_file(package, source, last_path); + /* reaquire file ptr */ + file = &package->files[fileindex]; + } + else + { + sz = MAX_PATH; + last_path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR)); + MSI_GetPropertyW(package,cszSourceDir,source,&sz); + strcpyW(last_path,source); + } + set_file_source(package, file, comp, last_path); + msiobj_release(&row->hdr); + + return rc; +} + +inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, + LPWSTR* file_source) +{ + DWORD index; + + if (!package) + return ERROR_INVALID_HANDLE; + + for (index = 0; index < package->loaded_files; index ++) + { + if (strcmpW(file_key,package->files[index].File)==0) + { + if (package->files[index].State >= 2) + { + *file_source = strdupW(package->files[index].TargetPath); + return ERROR_SUCCESS; + } + else + return ERROR_FILE_NOT_FOUND; + } + } + + return ERROR_FUNCTION_FAILED; +} + +/* + * In order to make this work more effeciencly I am going to do this in 2 + * passes. + * Pass 1) Correct all the TargetPaths and determin what files are to be + * installed. + * Pass 2) Extract Cabinents and copy files. + */ +UINT ACTION_InstallFiles(MSIPACKAGE *package) +{ + UINT rc = ERROR_SUCCESS; + DWORD index; + + if (!package) + return ERROR_INVALID_HANDLE; + + /* increment progress bar each time action data is sent */ + ui_progress(package,1,1,0,0); + + /* Pass 1 */ + for (index = 0; index < package->loaded_files; index++) + { + MSIFILE *file; + MSICOMPONENT* comp = NULL; + + file = &package->files[index]; + + if (file->Temporary) + continue; + + if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex, + INSTALLSTATE_LOCAL)) + { + ui_progress(package,2,file->FileSize,0,0); + TRACE("File %s is not scheduled for install\n", + debugstr_w(file->File)); + + file->State = 5; + continue; + } + + if ((file->State == 1) || (file->State == 2)) + { + LPWSTR p = NULL; + + TRACE("Pass 1: %s\n",debugstr_w(file->File)); + + create_component_directory( package, file->ComponentIndex); + + /* recalculate file paths because things may have changed */ + + if (file->ComponentIndex >= 0) + comp = &package->components[file->ComponentIndex]; + else + { + ERR("No Component for file\n"); + continue; + } + + p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL); + HeapFree(GetProcessHeap(),0,file->TargetPath); + + file->TargetPath = build_directory_name(2, p, file->FileName); + HeapFree(GetProcessHeap(),0,p); + } + } + + /* Pass 2 */ + for (index = 0; index < package->loaded_files; index++) + { + MSIFILE *file; + MSICOMPONENT* comp = NULL; + + file = &package->files[index]; + + if (file->Temporary) + continue; + + if ((file->State == 1) || (file->State == 2)) + { + TRACE("Pass 2: %s\n",debugstr_w(file->File)); + + if (file->ComponentIndex >= 0) + comp = &package->components[file->ComponentIndex]; + + rc = ready_media_for_file(package, index, comp); + if (rc != ERROR_SUCCESS) + { + ERR("Unable to ready media\n"); + rc = ERROR_FUNCTION_FAILED; + break; + } + + /* + * WARNING! + * our file table could change here because a new temp file + * may have been created. So reaquire our ptr. + */ + file = &package->files[index]; + + TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath), + debugstr_w(file->TargetPath)); + + if (file->Attributes & msidbFileAttributesNoncompressed) + rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE); + else + rc = MoveFileW(file->SourcePath, file->TargetPath); + + if (!rc) + { + rc = GetLastError(); + ERR("Unable to move/copy file (%s -> %s) (error %d)\n", + debugstr_w(file->SourcePath), debugstr_w(file->TargetPath), + rc); + if (rc == ERROR_ALREADY_EXISTS && file->State == 2) + { + if (!CopyFileW(file->SourcePath,file->TargetPath,FALSE)) + ERR("Unable to copy file (%s -> %s) (error %ld)\n", + debugstr_w(file->SourcePath), + debugstr_w(file->TargetPath), GetLastError()); + if (!(file->Attributes & msidbFileAttributesNoncompressed)) + DeleteFileW(file->SourcePath); + rc = 0; + } + else if (rc == ERROR_FILE_NOT_FOUND) + { + ERR("Source File Not Found! Continuing\n"); + rc = 0; + } + else if (file->Attributes & msidbFileAttributesVital) + { + ERR("Ignoring Error and continuing (nonvital file)...\n"); + rc = 0; + } + } + else + { + file->State = 4; + rc = ERROR_SUCCESS; + } + } + } + + /* cleanup */ + ready_media_for_file(NULL, 0, NULL); + return rc; +} + +static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param) +{ + MSIPACKAGE *package = (MSIPACKAGE*)param; + WCHAR *file_source = NULL; + WCHAR dest_name[0x100]; + LPWSTR dest_path, dest; + LPCWSTR file_key, component; + INT component_index; + DWORD sz; + DWORD rc; + + component = MSI_RecordGetString(row,2); + component_index = get_loaded_component(package,component); + + if (!ACTION_VerifyComponentForAction(package, component_index, + INSTALLSTATE_LOCAL)) + { + TRACE("Skipping copy due to disabled component %s\n", + debugstr_w(component)); + + /* the action taken was the same as the current install state */ + package->components[component_index].Action = + package->components[component_index].Installed; + + return ERROR_SUCCESS; + } + + package->components[component_index].Action = INSTALLSTATE_LOCAL; + + file_key = MSI_RecordGetString(row,3); + if (!file_key) + { + ERR("Unable to get file key\n"); + return ERROR_FUNCTION_FAILED; + } + + rc = get_file_target(package,file_key,&file_source); + + if (rc != ERROR_SUCCESS) + { + ERR("Original file unknown %s\n",debugstr_w(file_key)); + HeapFree(GetProcessHeap(),0,file_source); + return ERROR_SUCCESS; + } + + if (MSI_RecordIsNull(row,4)) + strcpyW(dest_name,strrchrW(file_source,'\\')+1); + else + { + sz=0x100; + MSI_RecordGetStringW(row,4,dest_name,&sz); + reduce_to_longfilename(dest_name); + } + + if (MSI_RecordIsNull(row,5)) + { + LPWSTR p; + dest_path = strdupW(file_source); + p = strrchrW(dest_path,'\\'); + if (p) + *p=0; + } + else + { + LPCWSTR destkey; + destkey = MSI_RecordGetString(row,5); + dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL); + if (!dest_path) + { + /* try a Property */ + dest_path = load_dynamic_property(package, destkey, NULL); + if (!dest_path) + { + FIXME("Unable to get destination folder, try AppSearch properties\n"); + HeapFree(GetProcessHeap(),0,file_source); + return ERROR_SUCCESS; + } + } + } + + dest = build_directory_name(2, dest_path, dest_name); + + TRACE("Duplicating file %s to %s\n",debugstr_w(file_source), + debugstr_w(dest)); + + if (strcmpW(file_source,dest)) + rc = !CopyFileW(file_source,dest,TRUE); + else + rc = ERROR_SUCCESS; + + if (rc != ERROR_SUCCESS) + ERR("Failed to copy file %s -> %s, last error %ld\n", debugstr_w(file_source), debugstr_w(dest_path), GetLastError()); + + FIXME("We should track these duplicate files as well\n"); + + HeapFree(GetProcessHeap(),0,dest_path); + HeapFree(GetProcessHeap(),0,dest); + HeapFree(GetProcessHeap(),0,file_source); + + return ERROR_SUCCESS; +} + +UINT ACTION_DuplicateFiles(MSIPACKAGE *package) +{ + UINT rc; + MSIQUERY * view; + static const WCHAR ExecSeqQuery[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0}; + + if (!package) + return ERROR_INVALID_HANDLE; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + rc = MSI_IterateRecords(view, NULL, ITERATE_DuplicateFiles, package); + msiobj_release(&view->hdr); + + return rc; +} diff --git a/reactos/lib/msi/format.c b/reactos/lib/msi/format.c index d85fd27c58b..4bd8f98a9e8 100644 --- a/reactos/lib/msi/format.c +++ b/reactos/lib/msi/format.c @@ -31,26 +31,22 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msifo #include "windef.h" #include "winbase.h" #include "winerror.h" -#include "winreg.h" #include "wine/debug.h" -#include "fdi.h" #include "msi.h" -#include "msiquery.h" -#include "fcntl.h" -#include "objbase.h" -#include "objidl.h" #include "msipriv.h" #include "winnls.h" -#include "winuser.h" -#include "shlobj.h" #include "wine/unicode.h" -#include "winver.h" #include "action.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); -LPWSTR build_default_format(MSIRECORD* record) +static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, + WCHAR** data, DWORD len, MSIRECORD* record, + BOOL* in_group); + + +static LPWSTR build_default_format(MSIRECORD* record) { int i; int count; @@ -101,7 +97,8 @@ static LPWSTR deformat_component(MSIPACKAGE* package, LPCWSTR key, DWORD* sz) return value; } -static LPWSTR deformat_file(MSIPACKAGE* package, LPCWSTR key, DWORD* sz) +static LPWSTR deformat_file(MSIPACKAGE* package, LPCWSTR key, DWORD* sz, + BOOL shortname) { LPWSTR value = NULL; INT index; @@ -114,8 +111,32 @@ static LPWSTR deformat_file(MSIPACKAGE* package, LPCWSTR key, DWORD* sz) index = get_loaded_file(package,key); if (index >=0) { - value = strdupW(package->files[index].TargetPath); - *sz = (strlenW(value)) * sizeof(WCHAR); + if (!shortname) + { + value = strdupW(package->files[index].TargetPath); + *sz = (strlenW(value)) * sizeof(WCHAR); + } + else + { + DWORD size = 0; + size = GetShortPathNameW(package->files[index].TargetPath, NULL, 0); + + if (size > 0) + { + *sz = (size-1) * sizeof (WCHAR); + size ++; + value = HeapAlloc(GetProcessHeap(),0,size * sizeof(WCHAR)); + GetShortPathNameW(package->files[index].TargetPath, value, + size); + } + else + { + ERR("Unable to get ShortPath size (%s)\n", + debugstr_w(package->files[index].TargetPath)); + value = NULL; + *sz = 0; + } + } } return value; @@ -214,6 +235,45 @@ static LPWSTR deformat_property(MSIPACKAGE* package, LPCWSTR key, DWORD* chunk) return value; } +/* + * Groups cannot be nested. They are just treated as from { to next } + */ +static BOOL find_next_group(LPCWSTR source, DWORD len_remaining, + LPWSTR *group, LPCWSTR *mark, + LPCWSTR* mark2) +{ + int i; + BOOL found = FALSE; + + *mark = scanW(source,'{',len_remaining); + if (!*mark) + return FALSE; + + for (i = 1; (*mark - source) + i < len_remaining; i++) + { + if ((*mark)[i] == '}') + { + found = TRUE; + break; + } + } + if (! found) + return FALSE; + + *mark2 = &(*mark)[i]; + + i = *mark2 - *mark; + *group = HeapAlloc(GetProcessHeap(),0,i*sizeof(WCHAR)); + + i -= 1; + memcpy(*group,&(*mark)[1],i*sizeof(WCHAR)); + (*group)[i] = 0; + + TRACE("Found group %s\n",debugstr_w(*group)); + return TRUE; +} + + static BOOL find_next_outermost_key(LPCWSTR source, DWORD len_remaining, LPWSTR *key, LPCWSTR *mark, LPCWSTR* mark2, BOOL *nested) @@ -259,13 +319,71 @@ static BOOL find_next_outermost_key(LPCWSTR source, DWORD len_remaining, return TRUE; } +static LPWSTR deformat_group(MSIPACKAGE* package, LPWSTR group, DWORD len, + MSIRECORD* record, DWORD* size) +{ + LPWSTR value; + LPCWSTR mark, mark2; + LPWSTR key; + BOOL nested; + INT failcount; + static const WCHAR fmt[] = {'{','%','s','}',0}; + UINT sz; + + if (!group || group[0] == 0) + { + *size = 0; + return NULL; + } + /* if no [] then group is returned as is */ + + if (!find_next_outermost_key(group, len, &key, &mark, &mark2, &nested)) + { + *size = (len+2)*sizeof(WCHAR); + value = HeapAlloc(GetProcessHeap(),0,*size); + sprintfW(value,fmt,group); + /* do not return size of the null at the end */ + *size = (len+1)*sizeof(WCHAR); + return value; + } + + HeapFree(GetProcessHeap(),0,key); + failcount = 0; + sz = deformat_string_internal(package, group, &value, strlenW(group), + record, &failcount); + if (failcount==0) + { + *size = sz * sizeof(WCHAR); + return value; + } + else if (failcount < 0) + { + LPWSTR v2; + + v2 = HeapAlloc(GetProcessHeap(),0,(sz+2)*sizeof(WCHAR)); + v2[0] = '{'; + memcpy(&v2[1],value,sz*sizeof(WCHAR)); + v2[sz+1]='}'; + HeapFree(GetProcessHeap(),0,value); + + *size = (sz+2)*sizeof(WCHAR); + return v2; + } + else + { + *size = 0; + return NULL; + } +} + /* * len is in WCHARs * return is also in WCHARs */ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, - WCHAR** data, DWORD len, MSIRECORD* record) + WCHAR** data, DWORD len, MSIRECORD* record, + INT* failcount) { LPCWSTR mark = NULL; LPCWSTR mark2 = NULL; @@ -285,15 +403,16 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, return 0; } - TRACE("Starting with %s\n",debugstr_w(ptr)); + TRACE("Starting with %s\n",debugstr_wn(ptr,len)); /* scan for special characters... fast exit */ - if (!scanW(ptr,'[',len) || (scanW(ptr,'[',len) && !scanW(ptr,']',len))) + if ((!scanW(ptr,'[',len) || (scanW(ptr,'[',len) && !scanW(ptr,']',len))) && + (scanW(ptr,'{',len) && !scanW(ptr,'}',len))) { /* not formatted */ *data = HeapAlloc(GetProcessHeap(),0,(len*sizeof(WCHAR))); memcpy(*data,ptr,len*sizeof(WCHAR)); - TRACE("Returning %s\n",debugstr_w(*data)); + TRACE("Returning %s\n",debugstr_wn(*data,len)); return len; } @@ -301,14 +420,23 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, while (progress - ptr < len) { + /* seek out first group if existing */ + if (find_next_group(progress, len - (progress - ptr), &key, + &mark, &mark2)) + { + value = deformat_group(package, key, strlenW(key)+1, record, + &chunk); + key = NULL; + nested = FALSE; + } /* formatted string located */ - if (!find_next_outermost_key(progress, len - (progress - ptr), &key, - &mark, &mark2, &nested)) + else if (!find_next_outermost_key(progress, len - (progress - ptr), + &key, &mark, &mark2, &nested)) { LPBYTE nd2; - TRACE("after value %s .. %s\n",debugstr_w((LPWSTR)newdata), - debugstr_w(mark)); + TRACE("after value %s \n",debugstr_wn((LPWSTR)newdata, + size/sizeof(WCHAR))); chunk = (len - (progress - ptr)) * sizeof(WCHAR); TRACE("after chunk is %li + %li\n",size,chunk); if (size) @@ -343,33 +471,43 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, { TRACE("Nested key... %s\n",debugstr_w(key)); deformat_string_internal(package, key, &value, strlenW(key)+1, - record); + record, failcount); HeapFree(GetProcessHeap(),0,key); key = value; } - TRACE("Current %s .. %s\n",debugstr_w((LPWSTR)newdata),debugstr_w(key)); + TRACE("Current %s .. %s\n",debugstr_wn((LPWSTR)newdata, + size/sizeof(WCHAR)),debugstr_w(key)); if (!package) { /* only deformat number indexs */ - if (is_key_number(key)) + if (key && is_key_number(key)) + { value = deformat_index(record,key,&chunk); + if (!chunk && failcount && *failcount >= 0) + (*failcount)++; + } else { - DWORD keylen = strlenW(key); - chunk = (keylen + 2)*sizeof(WCHAR); - value = HeapAlloc(GetProcessHeap(),0,chunk); - value[0] = '['; - memcpy(&value[1],key,keylen*sizeof(WCHAR)); - value[1+keylen] = ']'; + if (failcount) + *failcount = -1; + if(key) + { + DWORD keylen = strlenW(key); + chunk = (keylen + 2)*sizeof(WCHAR); + value = HeapAlloc(GetProcessHeap(),0,chunk); + value[0] = '['; + memcpy(&value[1],key,keylen*sizeof(WCHAR)); + value[1+keylen] = ']'; + } } } else { sz = 0; - switch (key[0]) + if (key) switch (key[0]) { case '~': value = deformat_NULL(&chunk); @@ -378,8 +516,10 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, value = deformat_component(package,&key[1],&chunk); break; case '#': + value = deformat_file(package,&key[1], &chunk, FALSE); + break; case '!': /* should be short path */ - value = deformat_file(package,&key[1], &chunk); + value = deformat_file(package,&key[1], &chunk, TRUE); break; case '\\': value = deformat_escape(&key[1],&chunk); @@ -388,8 +528,17 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, value = deformat_environment(package,&key[1],&chunk); break; default: + /* index keys cannot be nested */ if (is_key_number(key)) - value = deformat_index(record,key,&chunk); + if (!nested) + value = deformat_index(record,key,&chunk); + else + { + static const WCHAR fmt[] = {'[','%','s',']',0}; + value = HeapAlloc(GetProcessHeap(),0,10); + sprintfW(value,fmt,key); + chunk = strlenW(value)*sizeof(WCHAR); + } else value = deformat_property(package,key,&chunk); break; @@ -412,11 +561,14 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, size+=chunk; HeapFree(GetProcessHeap(),0,value); } + else if (failcount && *failcount >=0 ) + (*failcount)++; progress = mark2+1; } - TRACE("after everything %s\n",debugstr_w((LPWSTR)newdata)); + TRACE("after everything %s\n",debugstr_wn((LPWSTR)newdata, + size/sizeof(WCHAR))); *data = (LPWSTR)newdata; return size / sizeof(WCHAR); @@ -440,7 +592,7 @@ UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer, TRACE("(%s)\n",debugstr_w(rec)); len = deformat_string_internal(package,rec,&deformated,strlenW(rec), - record); + record, NULL); if (buffer) { @@ -487,7 +639,7 @@ UINT MSI_FormatRecordA( MSIPACKAGE* package, MSIRECORD* record, LPSTR buffer, TRACE("(%s)\n",debugstr_w(rec)); len = deformat_string_internal(package,rec,&deformated,strlenW(rec), - record); + record, NULL); lenA = WideCharToMultiByte(CP_ACP,0,deformated,len,NULL,0,NULL,NULL); if (buffer) diff --git a/reactos/lib/msi/helpers.c b/reactos/lib/msi/helpers.c new file mode 100644 index 00000000000..e9e12f12214 --- /dev/null +++ b/reactos/lib/msi/helpers.c @@ -0,0 +1,913 @@ +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2005 Aric Stewart for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Here are helper functions formally in action.c that are used by a variaty of + * actions and functions. + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "msipriv.h" +#include "winuser.h" +#include "wine/unicode.h" +#include "action.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0}; +static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0}; + +const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0}; +const WCHAR szProductCode[]= {'P','r','o','d','u','c','t','C','o','d','e',0}; +const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0}; +const WCHAR cszbs[]={'\\',0}; + +DWORD build_version_dword(LPCWSTR version_string) +{ + SHORT major,minor; + WORD build; + DWORD rc = 0x00000000; + LPCWSTR ptr1; + + ptr1 = version_string; + + if (!ptr1) + return rc; + else + major = atoiW(ptr1); + + + if(ptr1) + ptr1 = strchrW(ptr1,'.'); + if (ptr1) + { + ptr1++; + minor = atoiW(ptr1); + } + else + minor = 0; + + if (ptr1) + ptr1 = strchrW(ptr1,'.'); + + if (ptr1) + { + ptr1++; + build = atoiW(ptr1); + } + else + build = 0; + + rc = MAKELONG(build,MAKEWORD(minor,major)); + TRACE("%s -> 0x%lx\n",debugstr_w(version_string),rc); + return rc; +} + +UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, + LPWSTR *FilePath) +{ + LPWSTR ProductCode; + LPWSTR SystemFolder; + LPWSTR dest; + UINT rc; + + static const WCHAR szInstaller[] = + {'M','i','c','r','o','s','o','f','t','\\', + 'I','n','s','t','a','l','l','e','r','\\',0}; + static const WCHAR szFolder[] = + {'A','p','p','D','a','t','a','F','o','l','d','e','r',0}; + + ProductCode = load_dynamic_property(package,szProductCode,&rc); + if (!ProductCode) + return rc; + + SystemFolder = load_dynamic_property(package,szFolder,NULL); + + dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode); + + create_full_pathW(dest); + + *FilePath = build_directory_name(2, dest, icon_name); + + HeapFree(GetProcessHeap(),0,SystemFolder); + HeapFree(GetProcessHeap(),0,ProductCode); + HeapFree(GetProcessHeap(),0,dest); + return ERROR_SUCCESS; +} + +WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index) +{ + UINT rc; + DWORD sz; + LPWSTR ret; + + sz = 0; + if (MSI_RecordIsNull(row,index)) + return NULL; + + rc = MSI_RecordGetStringW(row,index,NULL,&sz); + + /* having an empty string is different than NULL */ + if (sz == 0) + { + ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)); + ret[0] = 0; + return ret; + } + + sz ++; + ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR)); + rc = MSI_RecordGetStringW(row,index,ret,&sz); + if (rc!=ERROR_SUCCESS) + { + ERR("Unable to load dynamic string\n"); + HeapFree(GetProcessHeap(), 0, ret); + ret = NULL; + } + return ret; +} + +LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc) +{ + DWORD sz = 0; + LPWSTR str; + UINT r; + + r = MSI_GetPropertyW(package, prop, NULL, &sz); + if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA) + { + if (rc) + *rc = r; + return NULL; + } + sz++; + str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR)); + r = MSI_GetPropertyW(package, prop, str, &sz); + if (r != ERROR_SUCCESS) + { + HeapFree(GetProcessHeap(),0,str); + str = NULL; + } + if (rc) + *rc = r; + return str; +} + +int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component ) +{ + int rc = -1; + DWORD i; + + for (i = 0; i < package->loaded_components; i++) + { + if (strcmpW(Component,package->components[i].Component)==0) + { + rc = i; + break; + } + } + return rc; +} + +int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature ) +{ + int rc = -1; + DWORD i; + + for (i = 0; i < package->loaded_features; i++) + { + if (strcmpW(Feature,package->features[i].Feature)==0) + { + rc = i; + break; + } + } + return rc; +} + +int get_loaded_file(MSIPACKAGE* package, LPCWSTR file) +{ + int rc = -1; + DWORD i; + + for (i = 0; i < package->loaded_files; i++) + { + if (strcmpW(file,package->files[i].File)==0) + { + rc = i; + break; + } + } + return rc; +} + +int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path) +{ + DWORD i; + DWORD index; + + if (!package) + return -2; + + for (i=0; i < package->loaded_files; i++) + if (strcmpW(package->files[i].File,name)==0) + return -1; + + index = package->loaded_files; + package->loaded_files++; + if (package->loaded_files== 1) + package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE)); + else + package->files = HeapReAlloc(GetProcessHeap(),0, + package->files , package->loaded_files * sizeof(MSIFILE)); + + memset(&package->files[index],0,sizeof(MSIFILE)); + + package->files[index].File = strdupW(name); + package->files[index].TargetPath = strdupW(path); + package->files[index].Temporary = TRUE; + + TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File)); + + return 0; +} + +LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, + BOOL set_prop, MSIFOLDER **folder) +{ + DWORD i; + LPWSTR p, path = NULL; + + TRACE("Working to resolve %s\n",debugstr_w(name)); + + if (!name) + return NULL; + + /* special resolving for Target and Source root dir */ + if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0) + { + if (!source) + { + LPWSTR check_path; + check_path = load_dynamic_property(package,cszTargetDir,NULL); + if (!check_path) + { + check_path = load_dynamic_property(package,cszRootDrive,NULL); + if (set_prop) + MSI_SetPropertyW(package,cszTargetDir,check_path); + } + + /* correct misbuilt target dir */ + path = build_directory_name(2, check_path, NULL); + if (strcmpiW(path,check_path)!=0) + MSI_SetPropertyW(package,cszTargetDir,path); + + if (folder) + { + for (i = 0; i < package->loaded_folders; i++) + { + if (strcmpW(package->folders[i].Directory,name)==0) + break; + } + *folder = &(package->folders[i]); + } + return path; + } + else + { + path = load_dynamic_property(package,cszSourceDir,NULL); + if (!path) + { + path = load_dynamic_property(package,cszDatabase,NULL); + if (path) + { + p = strrchrW(path,'\\'); + if (p) + *(p+1) = 0; + } + } + if (folder) + { + for (i = 0; i < package->loaded_folders; i++) + { + if (strcmpW(package->folders[i].Directory,name)==0) + break; + } + *folder = &(package->folders[i]); + } + return path; + } + } + + for (i = 0; i < package->loaded_folders; i++) + { + if (strcmpW(package->folders[i].Directory,name)==0) + break; + } + + if (i >= package->loaded_folders) + return NULL; + + if (folder) + *folder = &(package->folders[i]); + + if (!source && package->folders[i].ResolvedTarget) + { + path = strdupW(package->folders[i].ResolvedTarget); + TRACE(" already resolved to %s\n",debugstr_w(path)); + return path; + } + else if (source && package->folders[i].ResolvedSource) + { + path = strdupW(package->folders[i].ResolvedSource); + TRACE(" (source)already resolved to %s\n",debugstr_w(path)); + return path; + } + else if (!source && package->folders[i].Property) + { + path = build_directory_name(2, package->folders[i].Property, NULL); + + TRACE(" internally set to %s\n",debugstr_w(path)); + if (set_prop) + MSI_SetPropertyW(package,name,path); + return path; + } + + if (package->folders[i].ParentIndex >= 0) + { + LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory; + + TRACE(" ! Parent is %s\n", debugstr_w(parent)); + + p = resolve_folder(package, parent, source, set_prop, NULL); + if (!source) + { + TRACE(" TargetDefault = %s\n", + debugstr_w(package->folders[i].TargetDefault)); + + path = build_directory_name(3, p, + package->folders[i].TargetDefault, NULL); + package->folders[i].ResolvedTarget = strdupW(path); + TRACE(" resolved into %s\n",debugstr_w(path)); + if (set_prop) + MSI_SetPropertyW(package,name,path); + } + else + { + if (package->folders[i].SourceDefault && + package->folders[i].SourceDefault[0]!='.') + path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL); + else + path = strdupW(p); + TRACE(" (source)resolved into %s\n",debugstr_w(path)); + package->folders[i].ResolvedSource = strdupW(path); + } + HeapFree(GetProcessHeap(),0,p); + } + return path; +} + +/* wrapper to resist a need for a full rewrite right now */ +DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data ) +{ + if (ptr) + { + MSIRECORD *rec = MSI_CreateRecord(1); + DWORD size = 0; + + MSI_RecordSetStringW(rec,0,ptr); + MSI_FormatRecordW(package,rec,NULL,&size); + if (size >= 0) + { + size++; + *data = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR)); + if (size > 1) + MSI_FormatRecordW(package,rec,*data,&size); + else + *data[0] = 0; + msiobj_release( &rec->hdr ); + return sizeof(WCHAR)*size; + } + msiobj_release( &rec->hdr ); + } + + *data = NULL; + return 0; +} + +UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action) +{ + UINT count; + LPWSTR *newbuf = NULL; + if (script >= TOTAL_SCRIPTS) + { + FIXME("Unknown script requested %i\n",script); + return ERROR_FUNCTION_FAILED; + } + TRACE("Scheduling Action %s in script %i\n",debugstr_w(action), script); + + count = package->script->ActionCount[script]; + package->script->ActionCount[script]++; + if (count != 0) + newbuf = HeapReAlloc(GetProcessHeap(),0, + package->script->Actions[script], + package->script->ActionCount[script]* sizeof(LPWSTR)); + else + newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR)); + + newbuf[count] = strdupW(action); + package->script->Actions[script] = newbuf; + + return ERROR_SUCCESS; +} + +static void remove_tracked_tempfiles(MSIPACKAGE* package) +{ + DWORD i; + + if (!package) + return; + + for (i = 0; i < package->loaded_files; i++) + { + if (package->files[i].Temporary) + { + TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath)); + DeleteFileW(package->files[i].TargetPath); + } + + } +} + +/* Called when the package is being closed */ +void ACTION_free_package_structures( MSIPACKAGE* package) +{ + INT i; + + TRACE("Freeing package action data\n"); + + remove_tracked_tempfiles(package); + + /* No dynamic buffers in features */ + if (package->features && package->loaded_features > 0) + HeapFree(GetProcessHeap(),0,package->features); + + for (i = 0; i < package->loaded_folders; i++) + { + HeapFree(GetProcessHeap(),0,package->folders[i].Directory); + HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault); + HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault); + HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget); + HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource); + HeapFree(GetProcessHeap(),0,package->folders[i].Property); + } + if (package->folders && package->loaded_folders > 0) + HeapFree(GetProcessHeap(),0,package->folders); + + for (i = 0; i < package->loaded_components; i++) + HeapFree(GetProcessHeap(),0,package->components[i].FullKeypath); + + if (package->components && package->loaded_components > 0) + HeapFree(GetProcessHeap(),0,package->components); + + for (i = 0; i < package->loaded_files; i++) + { + HeapFree(GetProcessHeap(),0,package->files[i].File); + HeapFree(GetProcessHeap(),0,package->files[i].FileName); + HeapFree(GetProcessHeap(),0,package->files[i].ShortName); + HeapFree(GetProcessHeap(),0,package->files[i].Version); + HeapFree(GetProcessHeap(),0,package->files[i].Language); + HeapFree(GetProcessHeap(),0,package->files[i].SourcePath); + HeapFree(GetProcessHeap(),0,package->files[i].TargetPath); + } + + if (package->files && package->loaded_files > 0) + HeapFree(GetProcessHeap(),0,package->files); + + /* clean up extension, progid, class and verb structures */ + for (i = 0; i < package->loaded_classes; i++) + { + HeapFree(GetProcessHeap(),0,package->classes[i].Description); + HeapFree(GetProcessHeap(),0,package->classes[i].FileTypeMask); + HeapFree(GetProcessHeap(),0,package->classes[i].IconPath); + HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler); + HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler32); + HeapFree(GetProcessHeap(),0,package->classes[i].Argument); + HeapFree(GetProcessHeap(),0,package->classes[i].ProgIDText); + } + + if (package->classes && package->loaded_classes > 0) + HeapFree(GetProcessHeap(),0,package->classes); + + for (i = 0; i < package->loaded_extensions; i++) + { + HeapFree(GetProcessHeap(),0,package->extensions[i].ProgIDText); + } + + if (package->extensions && package->loaded_extensions > 0) + HeapFree(GetProcessHeap(),0,package->extensions); + + for (i = 0; i < package->loaded_progids; i++) + { + HeapFree(GetProcessHeap(),0,package->progids[i].ProgID); + HeapFree(GetProcessHeap(),0,package->progids[i].Description); + HeapFree(GetProcessHeap(),0,package->progids[i].IconPath); + } + + if (package->progids && package->loaded_progids > 0) + HeapFree(GetProcessHeap(),0,package->progids); + + for (i = 0; i < package->loaded_verbs; i++) + { + HeapFree(GetProcessHeap(),0,package->verbs[i].Verb); + HeapFree(GetProcessHeap(),0,package->verbs[i].Command); + HeapFree(GetProcessHeap(),0,package->verbs[i].Argument); + } + + if (package->verbs && package->loaded_verbs > 0) + HeapFree(GetProcessHeap(),0,package->verbs); + + for (i = 0; i < package->loaded_mimes; i++) + HeapFree(GetProcessHeap(),0,package->mimes[i].ContentType); + + if (package->mimes && package->loaded_mimes > 0) + HeapFree(GetProcessHeap(),0,package->mimes); + + for (i = 0; i < package->loaded_appids; i++) + { + HeapFree(GetProcessHeap(),0,package->appids[i].RemoteServerName); + HeapFree(GetProcessHeap(),0,package->appids[i].LocalServer); + HeapFree(GetProcessHeap(),0,package->appids[i].ServiceParameters); + HeapFree(GetProcessHeap(),0,package->appids[i].DllSurrogate); + } + + if (package->appids && package->loaded_appids > 0) + HeapFree(GetProcessHeap(),0,package->appids); + + if (package->script) + { + for (i = 0; i < TOTAL_SCRIPTS; i++) + { + int j; + for (j = 0; j < package->script->ActionCount[i]; j++) + HeapFree(GetProcessHeap(),0,package->script->Actions[i][j]); + + HeapFree(GetProcessHeap(),0,package->script->Actions[i]); + } + HeapFree(GetProcessHeap(),0,package->script); + } + + HeapFree(GetProcessHeap(),0,package->PackagePath); + + /* cleanup control event subscriptions */ + ControlEvent_CleanupSubscriptions(package); +} + +/* + * build_directory_name() + * + * This function is to save messing round with directory names + * It handles adding backslashes between path segments, + * and can add \ at the end of the directory name if told to. + * + * It takes a variable number of arguments. + * It always allocates a new string for the result, so make sure + * to free the return value when finished with it. + * + * The first arg is the number of path segments that follow. + * The arguments following count are a list of path segments. + * A path segment may be NULL. + * + * Path segments will be added with a \ separating them. + * A \ will not be added after the last segment, however if the + * last segment is NULL, then the last character will be a \ + * + */ +LPWSTR build_directory_name(DWORD count, ...) +{ + DWORD sz = 1, i; + LPWSTR dir; + va_list va; + + va_start(va,count); + for(i=0; ihdr); + + msi_dialog_check_messages(NULL); +} + +void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record) +{ + static const WCHAR Query_t[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','A','c','t','i','o', 'n','T','e','x','t','`',' ', + 'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=', + ' ','\'','%','s','\'',0}; + WCHAR message[1024]; + MSIRECORD * row = 0; + DWORD size; + static const WCHAR szActionData[] = + {'A','c','t','i','o','n','D','a','t','a',0}; + + if (!package->LastAction || strcmpW(package->LastAction,action)) + { + row = MSI_QueryGetRecord(package->db, Query_t, action); + if (!row) + return; + + if (MSI_RecordIsNull(row,3)) + { + msiobj_release(&row->hdr); + return; + } + + /* update the cached actionformat */ + HeapFree(GetProcessHeap(),0,package->ActionFormat); + package->ActionFormat = load_dynamic_stringW(row,3); + + HeapFree(GetProcessHeap(),0,package->LastAction); + package->LastAction = strdupW(action); + + msiobj_release(&row->hdr); + } + + MSI_RecordSetStringW(record,0,package->ActionFormat); + size = 1024; + MSI_FormatRecordW(package,record,message,&size); + + row = MSI_CreateRecord(1); + MSI_RecordSetStringW(row,1,message); + + MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row); + + ControlEvent_FireSubscribedEvent(package,szActionData, row); + + msiobj_release(&row->hdr); +} + +BOOL ACTION_VerifyComponentForAction(MSIPACKAGE* package, INT index, + INSTALLSTATE check ) +{ + if (package->components[index].Installed == check) + return FALSE; + + if (package->components[index].ActionRequest == check) + return TRUE; + else + return FALSE; +} + +BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE* package, INT index, + INSTALLSTATE check ) +{ + if (package->features[index].Installed == check) + return FALSE; + + if (package->features[index].ActionRequest == check) + return TRUE; + else + return FALSE; +} + +void reduce_to_longfilename(WCHAR* filename) +{ + LPWSTR p = strchrW(filename,'|'); + if (p) + memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR)); +} + +void reduce_to_shortfilename(WCHAR* filename) +{ + LPWSTR p = strchrW(filename,'|'); + if (p) + *p = 0; +} + +LPWSTR create_component_advertise_string(MSIPACKAGE* package, + MSICOMPONENT* component, LPCWSTR feature) +{ + LPWSTR productid=NULL; + GUID clsid; + WCHAR productid_85[21]; + WCHAR component_85[21]; + /* + * I have a fair bit of confusion as to when a < is used and when a > is + * used. I do not think i have it right... + * + * Ok it appears that the > is used if there is a guid for the compoenent + * and the < is used if not. + */ + static WCHAR fmt1[] = {'%','s','%','s','<',0,0}; + static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0}; + LPWSTR output = NULL; + DWORD sz = 0; + + memset(productid_85,0,sizeof(productid_85)); + memset(component_85,0,sizeof(component_85)); + + productid = load_dynamic_property(package,szProductCode,NULL); + CLSIDFromString(productid, &clsid); + + encode_base85_guid(&clsid,productid_85); + + CLSIDFromString(component->ComponentId, &clsid); + encode_base85_guid(&clsid,component_85); + + TRACE("Doing something with this... %s %s %s\n", + debugstr_w(productid_85), debugstr_w(feature), + debugstr_w(component_85)); + + sz = lstrlenW(productid_85) + lstrlenW(feature); + if (component) + sz += lstrlenW(component_85); + + sz+=3; + sz *= sizeof(WCHAR); + + output = HeapAlloc(GetProcessHeap(),0,sz); + memset(output,0,sz); + + if (component) + sprintfW(output,fmt2,productid_85,feature,component_85); + else + sprintfW(output,fmt1,productid_85,feature); + + HeapFree(GetProcessHeap(),0,productid); + + return output; +} + +/* update compoennt state based on a feature change */ +void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature) +{ + int i; + INSTALLSTATE newstate; + MSIFEATURE *feature; + + i = get_loaded_feature(package,szFeature); + if (i < 0) + return; + + feature = &package->features[i]; + newstate = feature->ActionRequest; + + for( i = 0; i < feature->ComponentCount; i++) + { + MSICOMPONENT* component = &package->components[feature->Components[i]]; + + TRACE("MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)\n", + newstate, debugstr_w(component->Component), component->Installed, + component->Action, component->ActionRequest); + + if (!component->Enabled) + continue; + else + { + if (newstate == INSTALLSTATE_LOCAL) + { + component->ActionRequest = INSTALLSTATE_LOCAL; + component->Action = INSTALLSTATE_LOCAL; + } + else + { + int j,k; + + component->ActionRequest = newstate; + component->Action = newstate; + + /*if any other feature wants is local we need to set it local*/ + for (j = 0; + j < package->loaded_features && + component->ActionRequest != INSTALLSTATE_LOCAL; + j++) + { + for (k = 0; k < package->features[j].ComponentCount; k++) + if ( package->features[j].Components[k] == + feature->Components[i] ) + { + if (package->features[j].ActionRequest == + INSTALLSTATE_LOCAL) + { + TRACE("Saved by %s\n", debugstr_w(package->features[j].Feature)); + component->ActionRequest = INSTALLSTATE_LOCAL; + component->Action = INSTALLSTATE_LOCAL; + } + break; + } + } + } + } + TRACE("Result (%i): Component %s (Installed %i, Action %i, Request %i)\n", + newstate, debugstr_w(component->Component), component->Installed, + component->Action, component->ActionRequest); + } +} diff --git a/reactos/lib/msi/insert.c b/reactos/lib/msi/insert.c index 1ec84bf3523..c3932907a15 100644 --- a/reactos/lib/msi/insert.c +++ b/reactos/lib/msi/insert.c @@ -44,7 +44,7 @@ typedef struct tagMSIINSERTVIEW MSIDATABASE *db; BOOL bIsTemp; MSIVIEW *sv; - value_list *vals; + column_info *vals; } MSIINSERTVIEW; static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) @@ -62,7 +62,7 @@ static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT * Merge a value_list and a record to create a second record. * Replace wildcard entries in the valuelist with values from the record */ -static MSIRECORD *INSERT_merge_record( UINT fields, value_list *vl, MSIRECORD *rec ) +static MSIRECORD *INSERT_merge_record( UINT fields, column_info *vl, MSIRECORD *rec ) { MSIRECORD *merged; DWORD wildcard_count = 1, i; @@ -255,7 +255,7 @@ MSIVIEWOPS insert_ops = }; UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, - string_list *columns, value_list *values, BOOL temp ) + column_info *columns, column_info *values, BOOL temp ) { MSIINSERTVIEW *iv = NULL; UINT r; diff --git a/reactos/lib/msi/install.c b/reactos/lib/msi/install.c new file mode 100644 index 00000000000..9b9ea41dcf7 --- /dev/null +++ b/reactos/lib/msi/install.c @@ -0,0 +1,587 @@ +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2005 Aric Stewart for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Msi top level apis directly related to installs */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "msi.h" +#include "msidefs.h" +#include "msipriv.h" +#include "winuser.h" +#include "wine/unicode.h" +#include "action.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +/*********************************************************************** + * MsiDoActionA (MSI.@) + */ +UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction ) +{ + LPWSTR szwAction; + UINT rc; + + TRACE(" exteral attempt at action %s\n",szAction); + + if (!szAction) + return ERROR_FUNCTION_FAILED; + if (hInstall == 0) + return ERROR_FUNCTION_FAILED; + + szwAction = strdupAtoW(szAction); + + if (!szwAction) + return ERROR_FUNCTION_FAILED; + + + rc = MsiDoActionW(hInstall, szwAction); + HeapFree(GetProcessHeap(),0,szwAction); + return rc; +} + +/*********************************************************************** + * MsiDoActionW (MSI.@) + */ +UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction ) +{ + MSIPACKAGE *package; + UINT ret = ERROR_INVALID_HANDLE; + + TRACE(" external attempt at action %s \n",debugstr_w(szAction)); + + package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); + if( package ) + { + ret = ACTION_PerformUIAction(package,szAction); + msiobj_release( &package->hdr ); + } + return ret; +} + +/*********************************************************************** + * MsiGetTargetPathA (MSI.@) + */ +UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder, + LPSTR szPathBuf, DWORD* pcchPathBuf) +{ + LPWSTR szwFolder; + LPWSTR szwPathBuf; + UINT rc; + + TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf); + + if (!szFolder) + return ERROR_FUNCTION_FAILED; + if (hInstall == 0) + return ERROR_FUNCTION_FAILED; + + szwFolder = strdupAtoW(szFolder); + + if (!szwFolder) + return ERROR_FUNCTION_FAILED; + + szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR)); + + rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf); + + WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf, + *pcchPathBuf, NULL, NULL ); + + HeapFree(GetProcessHeap(),0,szwFolder); + HeapFree(GetProcessHeap(),0,szwPathBuf); + + return rc; +} + +/*********************************************************************** +* MsiGetTargetPathW (MSI.@) +*/ +UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR + szPathBuf, DWORD* pcchPathBuf) +{ + LPWSTR path; + UINT rc = ERROR_FUNCTION_FAILED; + MSIPACKAGE *package; + + TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf); + + package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); + if (!package) + return ERROR_INVALID_HANDLE; + path = resolve_folder(package, szFolder, FALSE, FALSE, NULL); + msiobj_release( &package->hdr ); + + if (path && (strlenW(path) > *pcchPathBuf)) + { + *pcchPathBuf = strlenW(path)+1; + rc = ERROR_MORE_DATA; + } + else if (path) + { + *pcchPathBuf = strlenW(path)+1; + strcpyW(szPathBuf,path); + TRACE("Returning Path %s\n",debugstr_w(path)); + rc = ERROR_SUCCESS; + } + HeapFree(GetProcessHeap(),0,path); + + return rc; +} + + +/*********************************************************************** +* MsiGetSourcePathA (MSI.@) +*/ +UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder, + LPSTR szPathBuf, DWORD* pcchPathBuf) +{ + LPWSTR szwFolder; + LPWSTR szwPathBuf; + UINT rc; + + TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf); + + if (!szFolder) + return ERROR_FUNCTION_FAILED; + if (hInstall == 0) + return ERROR_FUNCTION_FAILED; + + szwFolder = strdupAtoW(szFolder); + if (!szwFolder) + return ERROR_FUNCTION_FAILED; + + szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR)); + + rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf); + + WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf, + *pcchPathBuf, NULL, NULL ); + + HeapFree(GetProcessHeap(),0,szwFolder); + HeapFree(GetProcessHeap(),0,szwPathBuf); + + return rc; +} + +/*********************************************************************** +* MsiGetSourcePathW (MSI.@) +*/ +UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR + szPathBuf, DWORD* pcchPathBuf) +{ + LPWSTR path; + UINT rc = ERROR_FUNCTION_FAILED; + MSIPACKAGE *package; + + TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf); + + package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); + if( !package ) + return ERROR_INVALID_HANDLE; + path = resolve_folder(package, szFolder, TRUE, FALSE, NULL); + msiobj_release( &package->hdr ); + + if (path && strlenW(path) > *pcchPathBuf) + { + *pcchPathBuf = strlenW(path)+1; + rc = ERROR_MORE_DATA; + } + else if (path) + { + *pcchPathBuf = strlenW(path)+1; + strcpyW(szPathBuf,path); + TRACE("Returning Path %s\n",debugstr_w(path)); + rc = ERROR_SUCCESS; + } + HeapFree(GetProcessHeap(),0,path); + + return rc; +} + + +/*********************************************************************** + * MsiSetTargetPathA (MSI.@) + */ +UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder, + LPCSTR szFolderPath) +{ + LPWSTR szwFolder; + LPWSTR szwFolderPath; + UINT rc; + + if (!szFolder) + return ERROR_FUNCTION_FAILED; + if (hInstall == 0) + return ERROR_FUNCTION_FAILED; + + szwFolder = strdupAtoW(szFolder); + if (!szwFolder) + return ERROR_FUNCTION_FAILED; + + szwFolderPath = strdupAtoW(szFolderPath); + if (!szwFolderPath) + { + HeapFree(GetProcessHeap(),0,szwFolder); + return ERROR_FUNCTION_FAILED; + } + + rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath); + + HeapFree(GetProcessHeap(),0,szwFolder); + HeapFree(GetProcessHeap(),0,szwFolderPath); + + return rc; +} + +/* + * Ok my original interpretation of this was wrong. And it looks like msdn has + * changed a bit also. The given folder path does not have to actually already + * exist, it just cannot be read only and must be a legal folder path. + */ +UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, + LPCWSTR szFolderPath) +{ + DWORD i; + DWORD attrib; + LPWSTR path = NULL; + LPWSTR path2 = NULL; + MSIFOLDER *folder; + + TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath)); + + if (package==NULL) + return ERROR_INVALID_HANDLE; + + if (szFolderPath[0]==0) + return ERROR_FUNCTION_FAILED; + + attrib = GetFileAttributesW(szFolderPath); + if ( attrib != INVALID_FILE_ATTRIBUTES && + (!(attrib & FILE_ATTRIBUTE_DIRECTORY) || + attrib & FILE_ATTRIBUTE_OFFLINE || + attrib & FILE_ATTRIBUTE_READONLY)) + return ERROR_FUNCTION_FAILED; + + path = resolve_folder(package,szFolder,FALSE,FALSE,&folder); + + if (!path) + return ERROR_INVALID_PARAMETER; + + if (attrib == INVALID_FILE_ATTRIBUTES) + { + if (!CreateDirectoryW(szFolderPath,NULL)) + return ERROR_FUNCTION_FAILED; + RemoveDirectoryW(szFolderPath); + } + + HeapFree(GetProcessHeap(),0,folder->Property); + folder->Property = build_directory_name(2, szFolderPath, NULL); + + if (lstrcmpiW(path, folder->Property) == 0) + { + /* + * Resolved Target has not really changed, so just + * set this folder and do not recalculate everything. + */ + HeapFree(GetProcessHeap(),0,folder->ResolvedTarget); + folder->ResolvedTarget = NULL; + path2 = resolve_folder(package,szFolder,FALSE,TRUE,NULL); + HeapFree(GetProcessHeap(),0,path2); + } + else + { + for (i = 0; i < package->loaded_folders; i++) + { + HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget); + package->folders[i].ResolvedTarget=NULL; + } + + for (i = 0; i < package->loaded_folders; i++) + { + path2=resolve_folder(package, package->folders[i].Directory, FALSE, + TRUE, NULL); + HeapFree(GetProcessHeap(),0,path2); + } + } + HeapFree(GetProcessHeap(),0,path); + + return ERROR_SUCCESS; +} + +/*********************************************************************** + * MsiSetTargetPathW (MSI.@) + */ +UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, + LPCWSTR szFolderPath) +{ + MSIPACKAGE *package; + UINT ret; + + TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath)); + + package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); + ret = MSI_SetTargetPathW( package, szFolder, szFolderPath ); + msiobj_release( &package->hdr ); + return ret; +} + +/*********************************************************************** + * MsiGetMode (MSI.@) + * + * Returns an internal installer state (if it is running in a mode iRunMode) + * + * PARAMS + * hInstall [I] Handle to the installation + * hRunMode [I] Checking run mode + * MSIRUNMODE_ADMIN Administrative mode + * MSIRUNMODE_ADVERTISE Advertisement mode + * MSIRUNMODE_MAINTENANCE Maintenance mode + * MSIRUNMODE_ROLLBACKENABLED Rollback is enabled + * MSIRUNMODE_LOGENABLED Log file is writing + * MSIRUNMODE_OPERATIONS Operations in progress?? + * MSIRUNMODE_REBOOTATEND We need to reboot after installation completed + * MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation + * MSIRUNMODE_CABINET Files from cabinet are installed + * MSIRUNMODE_SOURCESHORTNAMES Long names in source files is suppressed + * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is suppressed + * MSIRUNMODE_RESERVED11 Reserved + * MSIRUNMODE_WINDOWS9X Running under Windows95/98 + * MSIRUNMODE_ZAWENABLED Demand installation is supported + * MSIRUNMODE_RESERVED14 Reserved + * MSIRUNMODE_RESERVED15 Reserved + * MSIRUNMODE_SCHEDULED called from install script + * MSIRUNMODE_ROLLBACK called from rollback script + * MSIRUNMODE_COMMIT called from commit script + * + * RETURNS + * In the state: TRUE + * Not in the state: FALSE + * + */ + +BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode) +{ + FIXME("STUB (iRunMode=%i)\n",iRunMode); + return TRUE; +} + +/*********************************************************************** + * MsiSetFeatureStateA (MSI.@) + * + * According to the docs, when this is called it immediately recalculates + * all the component states as well + */ +UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature, + INSTALLSTATE iState) +{ + LPWSTR szwFeature = NULL; + UINT rc; + + szwFeature = strdupAtoW(szFeature); + + if (!szwFeature) + return ERROR_FUNCTION_FAILED; + + rc = MsiSetFeatureStateW(hInstall,szwFeature, iState); + + HeapFree(GetProcessHeap(),0,szwFeature); + + return rc; +} + + + +UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature, + INSTALLSTATE iState) +{ + INT index, i; + UINT rc = ERROR_SUCCESS; + + TRACE(" %s to %i\n",debugstr_w(szFeature), iState); + + index = get_loaded_feature(package,szFeature); + if (index < 0) + return ERROR_UNKNOWN_FEATURE; + + if (iState == INSTALLSTATE_ADVERTISED && + package->features[index].Attributes & + msidbFeatureAttributesDisallowAdvertise) + return ERROR_FUNCTION_FAILED; + + package->features[index].ActionRequest= iState; + package->features[index].Action= iState; + + ACTION_UpdateComponentStates(package,szFeature); + + /* update all the features that are children of this feature */ + for (i = 0; i < package->loaded_features; i++) + { + if (strcmpW(szFeature, package->features[i].Feature_Parent) == 0) + MSI_SetFeatureStateW(package, package->features[i].Feature, iState); + } + + return rc; +} + +/*********************************************************************** + * MsiSetFeatureStateW (MSI.@) + */ +UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature, + INSTALLSTATE iState) +{ + MSIPACKAGE* package; + UINT rc = ERROR_SUCCESS; + + TRACE(" %s to %i\n",debugstr_w(szFeature), iState); + + package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); + if (!package) + return ERROR_INVALID_HANDLE; + + rc = MSI_SetFeatureStateW(package,szFeature,iState); + + msiobj_release( &package->hdr ); + return rc; +} + +/*********************************************************************** +* MsiGetFeatureStateA (MSI.@) +*/ +UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature, + INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) +{ + LPWSTR szwFeature = NULL; + UINT rc; + + szwFeature = strdupAtoW(szFeature); + + rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction); + + HeapFree( GetProcessHeap(), 0 , szwFeature); + + return rc; +} + +UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature, + INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) +{ + INT index; + + index = get_loaded_feature(package,szFeature); + if (index < 0) + return ERROR_UNKNOWN_FEATURE; + + if (piInstalled) + *piInstalled = package->features[index].Installed; + + if (piAction) + *piAction = package->features[index].Action; + + TRACE("returning %i %i\n",*piInstalled,*piAction); + + return ERROR_SUCCESS; +} + +/*********************************************************************** +* MsiGetFeatureStateW (MSI.@) +*/ +UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature, + INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) +{ + MSIPACKAGE* package; + UINT ret; + + TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled, +piAction); + + package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); + if (!package) + return ERROR_INVALID_HANDLE; + ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction); + msiobj_release( &package->hdr ); + return ret; +} + +/*********************************************************************** + * MsiGetComponentStateA (MSI.@) + */ +UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent, + INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) +{ + LPWSTR szwComponent= NULL; + UINT rc; + + szwComponent= strdupAtoW(szComponent); + + rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction); + + HeapFree( GetProcessHeap(), 0 , szwComponent); + + return rc; +} + +UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent, + INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) +{ + INT index; + + TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled, +piAction); + + index = get_loaded_component(package,szComponent); + if (index < 0) + return ERROR_UNKNOWN_COMPONENT; + + if (piInstalled) + *piInstalled = package->components[index].Installed; + + if (piAction) + *piAction = package->components[index].Action; + + TRACE("states (%i, %i)\n", +(piInstalled)?*piInstalled:-1,(piAction)?*piAction:-1); + + return ERROR_SUCCESS; +} + +/*********************************************************************** + * MsiGetComponentStateW (MSI.@) + */ +UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent, + INSTALLSTATE *piInstalled, INSTALLSTATE *piAction) +{ + MSIPACKAGE* package; + UINT ret; + + TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent), + piInstalled, piAction); + + package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); + if (!package) + return ERROR_INVALID_HANDLE; + ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction); + msiobj_release( &package->hdr ); + return ret; +} diff --git a/reactos/lib/msi/msi.c b/reactos/lib/msi/msi.c index e7d1fa1a094..bec3ccbf05a 100644 --- a/reactos/lib/msi/msi.c +++ b/reactos/lib/msi/msi.c @@ -38,9 +38,6 @@ #include "wine/unicode.h" #include "action.h" -UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf); - - WINE_DEFAULT_DEBUG_CHANNEL(msi); /* @@ -465,6 +462,7 @@ UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, { LPWSTR szwProduct = NULL, szwAttribute = NULL, szwBuffer = NULL; UINT r = ERROR_OUTOFMEMORY; + DWORD pcchwValueBuf = 0; TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute), szBuffer, pcchValueBuf); @@ -486,14 +484,17 @@ UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, if( szBuffer ) { szwBuffer = HeapAlloc( GetProcessHeap(), 0, (*pcchValueBuf) * sizeof(WCHAR) ); + pcchwValueBuf = *pcchValueBuf; if( !szwBuffer ) goto end; } - r = MsiGetProductInfoW( szwProduct, szwAttribute, szwBuffer, pcchValueBuf ); + r = MsiGetProductInfoW( szwProduct, szwAttribute, szwBuffer, + &pcchwValueBuf ); if( ERROR_SUCCESS == r ) - WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, *pcchValueBuf, NULL, NULL); + *pcchValueBuf = WideCharToMultiByte(CP_ACP, 0, szwBuffer, pcchwValueBuf, + szBuffer, *pcchValueBuf, NULL, NULL); end: HeapFree( GetProcessHeap(), 0, szwProduct ); @@ -516,6 +517,10 @@ UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0}; static const WCHAR szAssignmentType[] = {'A','s','s','i','g','n','m','e','n','t','T','y','p','e',0}; + static const WCHAR szLanguage[] = + {'L','a','n','g','u','a','g','e',0}; + static const WCHAR szProductLanguage[] = + {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0}; FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute), szBuffer, pcchValueBuf); @@ -569,11 +574,25 @@ UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, } else if (strcmpW(szAttribute, szAssignmentType)==0) { - FIXME("0 (zero) if advertised, 1(one) if per machine.\n"); + FIXME("0 (zero) if advertised or per user , 1(one) if per machine.\n"); if (szBuffer) - szBuffer[0] = 1; + { + szBuffer[0] = '1'; + szBuffer[1] = 0; + } + if (pcchValueBuf) + *pcchValueBuf = 1; r = ERROR_SUCCESS; } + else if (strcmpW(szAttribute, szLanguage)==0) + { + r = MsiOpenProductW(szProduct, &hProduct); + if (ERROR_SUCCESS != r) + return r; + + r = MsiGetPropertyW(hProduct, szProductLanguage, szBuffer, pcchValueBuf); + MsiCloseHandle(hProduct); + } else { r = MsiOpenProductW(szProduct, &hProduct); @@ -820,7 +839,7 @@ INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf, return INSTALLSTATE_UNKNOWN; } -INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPSTR lpPathBuf, +INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf, DWORD *pcchBuf) { FIXME("%s %p %08lx\n", debugstr_w(szComponent), lpPathBuf, *pcchBuf); @@ -968,11 +987,16 @@ INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent, } if( pcchBuf && *pcchBuf > 0 ) + { lpwPathBuf = HeapAlloc( GetProcessHeap(), 0, *pcchBuf * sizeof(WCHAR)); + incoming_len = *pcchBuf; + } else + { lpwPathBuf = NULL; + incoming_len = 0; + } - incoming_len = *pcchBuf; rc = MsiGetComponentPathW(szwProduct, szwComponent, lpwPathBuf, pcchBuf); HeapFree( GetProcessHeap(), 0, szwProduct); @@ -1195,7 +1219,7 @@ UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0, lpLangBuf, pcchLangBuf?*pcchLangBuf:0); - dwVerLen = GetFileVersionInfoSizeW((LPWSTR)szFilePath, NULL); + dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL); if( !dwVerLen ) return GetLastError(); @@ -1206,14 +1230,14 @@ UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, goto end; } - if( !GetFileVersionInfoW((LPWSTR)szFilePath, 0, dwVerLen, lpVer) ) + if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) ) { ret = GetLastError(); goto end; } if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf ) { - if( VerQueryValueW(lpVer, (LPWSTR)szVersionResource, (LPVOID*)&ffi, &puLen) && + if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) && (puLen > 0) ) { wsprintfW(tmp, szVersionFormat, @@ -1267,7 +1291,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) typedef struct tagIClassFactoryImpl { - IClassFactoryVtbl *lpVtbl; + const IClassFactoryVtbl *lpVtbl; } IClassFactoryImpl; static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface, @@ -1305,7 +1329,7 @@ static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface, BOOL dolock) return S_OK; } -static IClassFactoryVtbl MsiCF_Vtbl = +static const IClassFactoryVtbl MsiCF_Vtbl = { MsiCF_QueryInterface, MsiCF_AddRef, diff --git a/reactos/lib/msi/msi.spec b/reactos/lib/msi/msi.spec index 91464064b0d..ecb7621ff39 100644 --- a/reactos/lib/msi/msi.spec +++ b/reactos/lib/msi/msi.spec @@ -158,8 +158,8 @@ 158 stdcall MsiViewClose(long) 159 stdcall MsiViewExecute(long long) 160 stdcall MsiViewFetch(long ptr) -161 stub MsiViewGetErrorA -162 stub MsiViewGetErrorW +161 stdcall MsiViewGetErrorA(long ptr ptr) +162 stdcall MsiViewGetErrorW(long ptr ptr) 163 stdcall MsiViewModify(long long long) 164 stdcall MsiDatabaseIsTablePersistentA(long str) 165 stdcall MsiDatabaseIsTablePersistentW(long wstr) diff --git a/reactos/lib/msi/msi.xml b/reactos/lib/msi/msi.xml index 221c50fa42a..81bb068d370 100644 --- a/reactos/lib/msi/msi.xml +++ b/reactos/lib/msi/msi.xml @@ -15,6 +15,7 @@ gdi32 advapi32 shell32 + shlwapi winmm cabinet ole32 @@ -22,6 +23,7 @@ version action.c appsearch.c + classes.c cond.tab.c create.c custom.c @@ -29,9 +31,13 @@ delete.c dialog.c distinct.c + events.c + files.c format.c handle.c + helpers.c insert.c + install.c msi.c msiquery.c order.c @@ -47,6 +53,7 @@ table.c tokenize.c update.c + upgrade.c where.c msi.spec msi.rc diff --git a/reactos/lib/msi/msipriv.h b/reactos/lib/msi/msipriv.h index 8aa931a198b..dde612992fe 100644 --- a/reactos/lib/msi/msipriv.h +++ b/reactos/lib/msi/msipriv.h @@ -29,7 +29,7 @@ #include "msiquery.h" #include "objbase.h" #include "objidl.h" -#include "wine/unicode.h" +#include "winnls.h" #include "wine/list.h" #define MSI_DATASIZEMASK 0x00ff @@ -66,7 +66,7 @@ typedef struct tagMSIDATABASE MSIOBJECTHDR hdr; IStorage *storage; string_table *strings; - LPWSTR mode; + LPCWSTR mode; MSITABLE *first_table, *last_table; } MSIDATABASE; @@ -197,11 +197,20 @@ typedef struct tagMSIPACKAGE LPWSTR ActionFormat; LPWSTR LastAction; - LPWSTR *DeferredAction; - UINT DeferredActionCount; - - LPWSTR *CommitAction; - UINT CommitActionCount; + struct tagMSICLASS *classes; + UINT loaded_classes; + struct tagMSIEXTENSION *extensions; + UINT loaded_extensions; + struct tagMSIPROGID *progids; + UINT loaded_progids; + struct tagMSIVERB *verbs; + UINT loaded_verbs; + struct tagMSIMIME *mimes; + UINT loaded_mimes; + struct tagMSIAPPID *appids; + UINT loaded_appids; + + struct tagMSISCRIPT *script; struct tagMSIRUNNINGACTION *RunningAction; UINT RunningActionCount; @@ -211,8 +220,8 @@ typedef struct tagMSIPACKAGE UINT CurrentInstallState; msi_dialog *dialog; LPWSTR next_dialog; - - BOOL ExecuteSequenceRun; + + struct list subscriptions; } MSIPACKAGE; typedef struct tagMSIPREVIEW @@ -309,12 +318,17 @@ extern const WCHAR *MSI_RecordGetString( MSIRECORD *, unsigned int ); extern MSIRECORD *MSI_CreateRecord( unsigned int ); extern UINT MSI_RecordSetInteger( MSIRECORD *, unsigned int, int ); extern UINT MSI_RecordSetStringW( MSIRECORD *, unsigned int, LPCWSTR ); +extern UINT MSI_RecordSetStringA( MSIRECORD *, unsigned int, LPCSTR ); extern BOOL MSI_RecordIsNull( MSIRECORD *, unsigned int ); extern UINT MSI_RecordGetStringW( MSIRECORD * , unsigned int, LPWSTR, DWORD *); extern UINT MSI_RecordGetStringA( MSIRECORD *, unsigned int, LPSTR, DWORD *); extern int MSI_RecordGetInteger( MSIRECORD *, unsigned int ); extern UINT MSI_RecordReadStream( MSIRECORD *, unsigned int, char *, DWORD *); extern unsigned int MSI_RecordGetFieldCount( MSIRECORD *rec ); +extern UINT MSI_RecordSetStreamW( MSIRECORD *, unsigned int, LPCWSTR ); +extern UINT MSI_RecordSetStreamA( MSIRECORD *, unsigned int, LPCSTR ); +extern UINT MSI_RecordDataSize( MSIRECORD *, unsigned int ); +extern UINT MSI_RecordStreamToFile( MSIRECORD *, unsigned int, LPCWSTR ); /* stream internals */ extern UINT get_raw_stream( MSIHANDLE hdb, LPCWSTR stname, IStream **stm ); @@ -325,8 +339,12 @@ extern void enum_stream_names( IStorage *stg ); extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** ); extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** ); extern UINT MSI_OpenQuery( MSIDATABASE *, MSIQUERY **, LPCWSTR, ... ); -typedef UINT (*record_func)( MSIRECORD *rec, LPVOID param ); +typedef UINT (*record_func)( MSIRECORD *, LPVOID ); extern UINT MSI_IterateRecords( MSIQUERY *, DWORD *, record_func, LPVOID ); +extern MSIRECORD *MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR query, ... ); +extern UINT MSI_DatabaseImport( MSIDATABASE *, LPCWSTR, LPCWSTR ); +extern UINT MSI_DatabaseExport( MSIDATABASE *, LPCWSTR, LPCWSTR, LPCWSTR ); +extern UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *, LPCWSTR, MSIRECORD ** ); /* view internals */ extern UINT MSI_ViewExecute( MSIQUERY*, MSIRECORD * ); @@ -340,6 +358,7 @@ extern UINT MSI_SetTargetPathW( MSIPACKAGE *, LPCWSTR, LPCWSTR ); extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR ); extern INT MSI_ProcessMessage( MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD * ); extern UINT MSI_GetPropertyW( MSIPACKAGE *, LPCWSTR, LPWSTR, DWORD * ); +extern UINT MSI_GetPropertyA(MSIPACKAGE *, LPCSTR, LPSTR, DWORD* ); extern MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *, LPCWSTR ); extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR ); extern UINT MSI_GetComponentStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE * ); @@ -347,8 +366,8 @@ extern UINT MSI_GetFeatureStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLS extern UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE*, LPCWSTR, INSTALLSTATE ); /* for deformating */ -extern UINT MSI_FormatRecordW(MSIPACKAGE* package, MSIRECORD* record, - LPWSTR buffer, DWORD *size); +extern UINT MSI_FormatRecordW( MSIPACKAGE *, MSIRECORD *, LPWSTR, DWORD * ); +extern UINT MSI_FormatRecordA( MSIPACKAGE *, MSIRECORD *, LPSTR, DWORD * ); /* registry data encoding/decoding functions */ extern BOOL unsquash_guid(LPCWSTR in, LPWSTR out); @@ -364,10 +383,12 @@ extern UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL cr extern UINT MSIREG_OpenComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create); extern UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create); extern UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create); +extern UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create); extern UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create); +extern UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create); /* msi dialog interface */ -typedef VOID (*msi_dialog_event_handler)( MSIPACKAGE*, LPCWSTR, LPCWSTR, msi_dialog* ); +typedef UINT (*msi_dialog_event_handler)( MSIPACKAGE*, LPCWSTR, LPCWSTR, msi_dialog* ); extern msi_dialog *msi_dialog_create( MSIPACKAGE*, LPCWSTR, msi_dialog_event_handler ); extern UINT msi_dialog_run_message_loop( msi_dialog* ); extern void msi_dialog_end_dialog( msi_dialog* ); @@ -376,6 +397,23 @@ extern void msi_dialog_do_preview( msi_dialog* ); extern void msi_dialog_destroy( msi_dialog* ); extern BOOL msi_dialog_register_class( void ); extern void msi_dialog_unregister_class( void ); +extern void msi_dialog_handle_event( msi_dialog*, LPCWSTR, LPCWSTR, MSIRECORD * ); + +/* preview */ +extern MSIPREVIEW *MSI_EnableUIPreview( MSIDATABASE * ); +extern UINT MSI_PreviewDialogW( MSIPREVIEW *, LPCWSTR ); + +/* undocumented functions */ +UINT WINAPI MsiCreateAndVerifyInstallerDirectory( DWORD ); +UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR, LPWSTR, LPWSTR, LPWSTR, DWORD * ); +UINT WINAPI MsiDecomposeDescriptorA( LPCSTR, LPSTR, LPSTR, LPSTR, DWORD * ); +LANGID WINAPI MsiLoadStringW( MSIHANDLE, UINT, LPWSTR, int, LANGID ); +LANGID WINAPI MsiLoadStringA( MSIHANDLE, UINT, LPSTR, int, LANGID ); + +HRESULT WINAPI MSI_DllGetClassObject( REFCLSID, REFIID, LPVOID * ); +HRESULT WINAPI MSI_DllRegisterServer( void ); +HRESULT WINAPI MSI_DllUnregisterServer( void ); +BOOL WINAPI MSI_DllCanUnloadNow( void ); /* UI globals */ extern INSTALLUILEVEL gUILevel; @@ -415,8 +453,8 @@ inline static LPWSTR strdupW( LPCWSTR src ) { LPWSTR dest; if (!src) return NULL; - dest = HeapAlloc(GetProcessHeap(), 0, (strlenW(src)+1)*sizeof(WCHAR)); - strcpyW(dest, src); + dest = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(src)+1)*sizeof(WCHAR)); + lstrcpyW(dest, src); return dest; } diff --git a/reactos/lib/msi/msiquery.c b/reactos/lib/msi/msiquery.c index f833847c840..49fd3e9ad4e 100644 --- a/reactos/lib/msi/msiquery.c +++ b/reactos/lib/msi/msiquery.c @@ -38,7 +38,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); -void MSI_CloseView( MSIOBJECTHDR *arg ) +static void MSI_CloseView( MSIOBJECTHDR *arg ) { MSIQUERY *query = (MSIQUERY*) arg; struct list *ptr, *t; @@ -139,7 +139,8 @@ UINT MSI_DatabaseOpenViewW(MSIDATABASE *db, return r; } -UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) +static UINT MSI_OpenQueryV( MSIDATABASE *db, MSIQUERY **view, + LPCWSTR fmt, va_list args ) { LPWSTR szQuery; LPCWSTR p; @@ -147,7 +148,7 @@ UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) va_list va; /* figure out how much space we need to allocate */ - va_start(va, fmt); + va = args; sz = lstrlenW(fmt) + 1; p = fmt; while (*p) @@ -173,13 +174,11 @@ UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) } p++; } - va_end(va); /* construct the string */ szQuery = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR)); - va_start(va, fmt); + va = args; vsnprintfW(szQuery, sz, fmt, va); - va_end(va); /* perform the query */ rc = MSI_DatabaseOpenViewW(db, szQuery, view); @@ -187,6 +186,18 @@ UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) return rc; } +UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) +{ + UINT r; + va_list va; + + va_start(va, fmt); + r = MSI_OpenQueryV( db, view, fmt, va ); + va_end(va); + + return r; +} + UINT MSI_IterateRecords( MSIQUERY *view, DWORD *count, record_func func, LPVOID param ) { @@ -223,6 +234,28 @@ UINT MSI_IterateRecords( MSIQUERY *view, DWORD *count, return r; } +/* return a single record from a query */ +MSIRECORD *MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR fmt, ... ) +{ + MSIRECORD *rec = NULL; + MSIQUERY *view = NULL; + UINT r; + va_list va; + + va_start(va, fmt); + r = MSI_OpenQueryV( db, &view, fmt, va ); + va_end(va); + + if( r == ERROR_SUCCESS ) + { + MSI_ViewExecute( view, NULL ); + MSI_ViewFetch( view, &rec ); + MSI_ViewClose( view ); + msiobj_release( &view->hdr ); + } + return rec; +} + UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb, LPCWSTR szQuery, MSIHANDLE *phView) { @@ -530,6 +563,42 @@ out: return r; } +UINT WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR szColumnNameBuffer, + DWORD *pcchBuf ) +{ + MSIQUERY *query = NULL; + + FIXME("%ld %p %p\n", handle, szColumnNameBuffer, pcchBuf ); + + if( !pcchBuf ) + return MSIDBERROR_INVALIDARG; + + query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW ); + if( !query ) + return MSIDBERROR_INVALIDARG; + + msiobj_release( &query->hdr ); + return MSIDBERROR_NOERROR; +} + +UINT WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR szColumnNameBuffer, + DWORD *pcchBuf ) +{ + MSIQUERY *query = NULL; + + FIXME("%ld %p %p\n", handle, szColumnNameBuffer, pcchBuf ); + + if( !pcchBuf ) + return MSIDBERROR_INVALIDARG; + + query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW ); + if( !query ) + return MSIDBERROR_INVALIDARG; + + msiobj_release( &query->hdr ); + return MSIDBERROR_NOERROR; +} + UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb, LPCSTR szTransformFile, int iErrorCond) { diff --git a/reactos/lib/msi/order.c b/reactos/lib/msi/order.c index 0e3b98fa84e..2a03bab63b8 100644 --- a/reactos/lib/msi/order.c +++ b/reactos/lib/msi/order.c @@ -302,11 +302,11 @@ static UINT ORDER_AddColumn( MSIORDERVIEW *ov, LPCWSTR name ) } UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, - string_list *columns ) + column_info *columns ) { MSIORDERVIEW *ov = NULL; UINT count = 0, r; - string_list *x; + column_info *x; TRACE("%p\n", ov ); @@ -332,7 +332,7 @@ UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, *view = (MSIVIEW*) ov; for( x = columns; x ; x = x->next ) - ORDER_AddColumn( ov, x->string ); + ORDER_AddColumn( ov, x->column ); return ERROR_SUCCESS; } diff --git a/reactos/lib/msi/package.c b/reactos/lib/msi/package.c index 53808ab0679..54a692452eb 100644 --- a/reactos/lib/msi/package.c +++ b/reactos/lib/msi/package.c @@ -49,7 +49,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); */ #define LPCTSTR LPCWSTR -void MSI_FreePackage( MSIOBJECTHDR *arg) +static void MSI_FreePackage( MSIOBJECTHDR *arg) { MSIPACKAGE *package= (MSIPACKAGE*) arg; @@ -389,6 +389,7 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db ) package->LastAction = NULL; package->dialog = NULL; package->next_dialog = NULL; + list_init( &package->subscriptions ); /* OK, here is where we do a slew of things to the database to * prep for all that is to come as a package */ diff --git a/reactos/lib/msi/preview.c b/reactos/lib/msi/preview.c index 540d65174b6..5c596fbc85a 100644 --- a/reactos/lib/msi/preview.c +++ b/reactos/lib/msi/preview.c @@ -82,11 +82,12 @@ UINT WINAPI MsiEnableUIPreview( MSIHANDLE hdb, MSIHANDLE* phPreview ) return r; } -static VOID preview_event_handler( MSIPACKAGE *package, LPCWSTR event, +static UINT preview_event_handler( MSIPACKAGE *package, LPCWSTR event, LPCWSTR argument, msi_dialog *dialog ) { MESSAGE("Preview dialog event '%s' (arg='%s')\n", debugstr_w( event ), debugstr_w( argument )); + return ERROR_SUCCESS; } UINT MSI_PreviewDialogW( MSIPREVIEW *preview, LPCWSTR szDialogName ) diff --git a/reactos/lib/msi/query.h b/reactos/lib/msi/query.h index 28f74b515e4..e1fa104e603 100644 --- a/reactos/lib/msi/query.h +++ b/reactos/lib/msi/query.h @@ -59,11 +59,14 @@ struct sql_str { INT len; }; -typedef struct _string_list +typedef struct _column_info { - LPWSTR string; - struct _string_list *next; -} string_list; + LPCWSTR table; + LPCWSTR column; + UINT type; + struct expr *val; + struct _column_info *next; +} column_info; struct complex_expr { @@ -80,56 +83,36 @@ struct expr struct complex_expr expr; INT ival; UINT uval; - LPWSTR sval; - LPWSTR column; + LPCWSTR sval; + LPCWSTR column; UINT col_number; } u; }; -typedef struct _create_col_info -{ - LPWSTR colname; - UINT type; - struct _create_col_info *next; -} create_col_info; - -typedef struct _value_list -{ - struct expr *val; - struct _value_list *next; -} value_list; - -typedef struct _column_assignment -{ - string_list *col_list; - value_list *val_list; -} column_assignment; - - UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview, struct list *mem ); UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view ); UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, - string_list *columns ); + column_info *columns ); UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table ); UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, - string_list *columns ); + column_info *columns ); UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, struct expr *cond ); UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, - create_col_info *col_info, BOOL temp ); + column_info *col_info, BOOL temp ); UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, - string_list *columns, value_list *values, BOOL temp ); + column_info *columns, column_info *values, BOOL temp ); UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **, LPWSTR table, - column_assignment *list, struct expr *expr ); + column_info *list, struct expr *expr ); UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table ); diff --git a/reactos/lib/msi/record.c b/reactos/lib/msi/record.c index 57a1d71279a..8bdc3c4cf47 100644 --- a/reactos/lib/msi/record.c +++ b/reactos/lib/msi/record.c @@ -34,6 +34,9 @@ #include "winnls.h" #include "ole2.h" +#include "winreg.h" +#include "shlwapi.h" + #include "query.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); @@ -44,7 +47,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); #define MSIFIELD_WSTR 3 #define MSIFIELD_STREAM 4 -void MSI_FreeField( MSIFIELD *field ) +static void MSI_FreeField( MSIFIELD *field ) { switch( field->type ) { @@ -62,7 +65,7 @@ void MSI_FreeField( MSIFIELD *field ) } } -void MSI_CloseRecord( MSIOBJECTHDR *arg ) +static void MSI_CloseRecord( MSIOBJECTHDR *arg ) { MSIRECORD *rec = (MSIRECORD *) arg; UINT i; @@ -410,6 +413,17 @@ UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, unsigned int iField, return ret; } +static UINT msi_get_stream_size( IStream *stm ) +{ + STATSTG stat; + HRESULT r; + + r = IStream_Stat( stm, &stat, STATFLAG_NONAME ); + if( FAILED(r) ) + return 0; + return stat.cbSize.QuadPart; +} + UINT MSI_RecordDataSize(MSIRECORD *rec, unsigned int iField) { TRACE("%p %d\n", rec, iField); @@ -425,6 +439,8 @@ UINT MSI_RecordDataSize(MSIRECORD *rec, unsigned int iField) return lstrlenW( rec->fields[iField].u.szwVal ); case MSIFIELD_NULL: break; + case MSIFIELD_STREAM: + return msi_get_stream_size( rec->fields[iField].u.stream ); } return 0; } @@ -533,7 +549,7 @@ UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, unsigned int iField, LPCWSTR } /* read the data in a file into an IStream */ -UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm) +static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm) { DWORD sz, szHighWord = 0, read; HANDLE handle; @@ -761,3 +777,56 @@ UINT MSI_RecordGetIStream( MSIRECORD *rec, unsigned int iField, IStream **pstm) return ERROR_SUCCESS; } + +static UINT msi_dump_stream_to_file( IStream *stm, LPCWSTR name ) +{ + ULARGE_INTEGER size; + LARGE_INTEGER pos; + IStream *out; + DWORD stgm; + HRESULT r; + + stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE; + r = SHCreateStreamOnFileW( name, stgm, &out ); + if( FAILED( r ) ) + return ERROR_FUNCTION_FAILED; + + pos.QuadPart = 0; + r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size ); + if( FAILED( r ) ) + goto end; + + pos.QuadPart = 0; + r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL ); + if( FAILED( r ) ) + goto end; + + r = IStream_CopyTo( stm, out, size, NULL, NULL ); + +end: + IStream_Release( out ); + if( FAILED( r ) ) + return ERROR_FUNCTION_FAILED; + return ERROR_SUCCESS; +} + +UINT MSI_RecordStreamToFile( MSIRECORD *rec, unsigned int iField, LPCWSTR name ) +{ + IStream *stm = NULL; + UINT r; + + TRACE("%p %u %s\n", rec, iField, debugstr_w(name)); + + msiobj_lock( &rec->hdr ); + + r = MSI_RecordGetIStream( rec, iField, &stm ); + if( r == ERROR_SUCCESS ) + { + r = msi_dump_stream_to_file( stm, name ); + IStream_Release( stm ); + } + + msiobj_unlock( &rec->hdr ); + + return r; +} diff --git a/reactos/lib/msi/registry.c b/reactos/lib/msi/registry.c index 15e91090dc5..012986115c2 100644 --- a/reactos/lib/msi/registry.c +++ b/reactos/lib/msi/registry.c @@ -141,6 +141,20 @@ static const WCHAR szInstaller_UpgradeCodes_fmt[] = { 'U','p','g','r','a','d','e','C','o','d','e','s','\\', '%','s',0}; +static const WCHAR szInstaller_UserUpgradeCodes[] = { +'S','o','f','t','w','a','r','e','\\', +'M','i','c','r','o','s','o','f','t','\\', +'I','n','s','t','a','l','l','e','r','\\', +'U','p','g','r','a','d','e','C','o','d','e','s',0}; + +static const WCHAR szInstaller_UserUpgradeCodes_fmt[] = { +'S','o','f','t','w','a','r','e','\\', +'M','i','c','r','o','s','o','f','t','\\', +'I','n','s','t','a','l','l','e','r','\\', +'U','p','g','r','a','d','e','C','o','d','e','s','\\', +'%','s',0}; + + #define SQUISH_GUID_SIZE 33 BOOL unsquash_guid(LPCWSTR in, LPWSTR out) @@ -455,6 +469,27 @@ UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create) return rc; } +UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create) +{ + UINT rc; + WCHAR squished_pc[GUID_SIZE]; + WCHAR keypath[0x200]; + + TRACE("%s\n",debugstr_w(szUpgradeCode)); + squash_guid(szUpgradeCode,squished_pc); + TRACE("squished (%s)\n", debugstr_w(squished_pc)); + + sprintfW(keypath,szInstaller_UserUpgradeCodes_fmt,squished_pc); + + if (create) + rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key); + else + rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key); + + return rc; +} + + /************************************************************************* * MsiDecomposeDescriptorW [MSI.@] * diff --git a/reactos/lib/msi/select.c b/reactos/lib/msi/select.c index 6118966d072..9378676f719 100644 --- a/reactos/lib/msi/select.c +++ b/reactos/lib/msi/select.c @@ -210,7 +210,7 @@ MSIVIEWOPS select_ops = SELECT_delete }; -static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPWSTR name ) +static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name ) { UINT r, n=0; MSIVIEW *table; @@ -245,7 +245,7 @@ static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPWSTR name ) } UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, - string_list *columns ) + column_info *columns ) { MSISELECTVIEW *sv = NULL; UINT count = 0, r; @@ -273,7 +273,7 @@ UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, while( columns ) { - r = SELECT_AddColumn( sv, columns->string ); + r = SELECT_AddColumn( sv, columns->column ); if( r ) break; columns = columns->next; diff --git a/reactos/lib/msi/sql.tab.c b/reactos/lib/msi/sql.tab.c index 6ead0d2e7c0..39dc0f0e955 100644 --- a/reactos/lib/msi/sql.tab.c +++ b/reactos/lib/msi/sql.tab.c @@ -189,7 +189,6 @@ #include "query.h" #include "wine/list.h" #include "wine/debug.h" -#include "wine/unicode.h" #define YYLEX_PARAM info #define YYPARSE_PARAM info @@ -212,12 +211,13 @@ static INT SQL_getint( void *info ); static int SQL_lex( void *SQL_lval, SQL_input *info ); static void *parser_alloc( void *info, unsigned int sz ); +static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column ); -static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys); +static BOOL SQL_MarkPrimaryKeys( column_info *cols, column_info *keys); static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r ); -static struct expr * EXPR_column( void *info, LPWSTR column ); -static struct expr * EXPR_ival( void *info, struct sql_str *, int sign ); +static struct expr * EXPR_column( void *info, column_info *column ); +static struct expr * EXPR_ival( void *info, int val ); static struct expr * EXPR_sval( void *info, struct sql_str * ); static struct expr * EXPR_wildcard( void *info ); @@ -228,13 +228,11 @@ typedef union { struct sql_str str; LPWSTR string; - string_list *column_list; - value_list *val_list; + column_info *column_list; MSIVIEW *query; struct expr *expr; USHORT column_type; - create_col_info *column_info; - column_assignment update_col_info; + int integer; } yystype; # define YYSTYPE yystype # define YYSTYPE_IS_TRIVIAL 1 @@ -245,12 +243,12 @@ typedef union -#define YYFINAL 126 +#define YYFINAL 127 #define YYFLAG -32768 #define YYNTBASE 147 /* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ -#define YYTRANSLATE(x) ((unsigned)(x) <= 400 ? yytranslate[x] : 175) +#define YYTRANSLATE(x) ((unsigned)(x) <= 400 ? yytranslate[x] : 177) /* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ static const short yytranslate[] = @@ -302,38 +300,38 @@ static const short yytranslate[] = static const short yyprhs[] = { 0, 0, 2, 4, 6, 8, 10, 12, 23, 35, - 42, 50, 57, 60, 65, 70, 73, 75, 78, 80, - 84, 86, 91, 93, 95, 97, 99, 101, 103, 108, - 110, 113, 117, 120, 122, 126, 128, 130, 134, 137, - 141, 145, 149, 153, 157, 161, 165, 169, 173, 177, - 181, 186, 188, 190, 192, 196, 198, 202, 206, 208, - 211, 213, 215, 217, 221, 223, 225 + 42, 50, 57, 60, 65, 69, 71, 74, 76, 79, + 81, 85, 87, 92, 94, 96, 98, 100, 102, 104, + 109, 111, 114, 118, 121, 123, 127, 129, 131, 135, + 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, + 178, 182, 187, 189, 191, 193, 197, 199, 203, 207, + 209, 212, 214, 216, 218, 222, 224, 226, 228 }; static const short yyrhs[] = { - 148, 0, 159, 0, 150, 0, 149, 0, 151, 0, - 152, 0, 67, 72, 173, 83, 162, 110, 134, 83, - 167, 110, 0, 67, 72, 173, 83, 162, 110, 134, - 83, 167, 110, 122, 0, 31, 121, 173, 83, 153, - 110, 0, 31, 121, 173, 83, 153, 110, 59, 0, - 130, 173, 114, 168, 137, 165, 0, 35, 163, 0, - 154, 102, 77, 162, 0, 154, 24, 172, 155, 0, - 172, 155, 0, 156, 0, 156, 86, 0, 157, 0, - 157, 90, 92, 0, 19, 0, 19, 83, 158, 110, - 0, 82, 0, 115, 0, 69, 0, 81, 0, 93, - 0, 70, 0, 160, 99, 16, 162, 0, 160, 0, - 112, 161, 0, 112, 38, 161, 0, 162, 163, 0, - 172, 0, 172, 24, 162, 0, 118, 0, 164, 0, - 164, 137, 165, 0, 52, 173, 0, 83, 165, 110, - 0, 171, 45, 171, 0, 165, 7, 165, 0, 165, - 97, 165, 0, 171, 45, 166, 0, 171, 57, 166, - 0, 171, 85, 166, 0, 171, 78, 166, 0, 171, - 54, 166, 0, 171, 89, 166, 0, 171, 73, 92, - 0, 171, 73, 90, 92, 0, 171, 0, 170, 0, - 170, 0, 170, 24, 167, 0, 169, 0, 169, 24, - 168, 0, 172, 45, 170, 0, 70, 0, 88, 70, - 0, 120, 0, 138, 0, 172, 0, 173, 39, 174, - 0, 174, 0, 174, 0, 66, 0 + 148, 0, 160, 0, 150, 0, 149, 0, 151, 0, + 152, 0, 67, 72, 174, 83, 163, 110, 134, 83, + 168, 110, 0, 67, 72, 174, 83, 163, 110, 134, + 83, 168, 110, 122, 0, 31, 121, 174, 83, 153, + 110, 0, 31, 121, 174, 83, 153, 110, 59, 0, + 130, 174, 114, 169, 137, 166, 0, 35, 164, 0, + 154, 102, 77, 163, 0, 154, 24, 155, 0, 155, + 0, 173, 156, 0, 157, 0, 157, 86, 0, 158, + 0, 158, 90, 92, 0, 19, 0, 19, 83, 159, + 110, 0, 82, 0, 115, 0, 69, 0, 81, 0, + 93, 0, 176, 0, 161, 99, 16, 163, 0, 161, + 0, 112, 162, 0, 112, 38, 162, 0, 163, 164, + 0, 173, 0, 173, 24, 163, 0, 118, 0, 165, + 0, 165, 137, 166, 0, 52, 174, 0, 83, 166, + 110, 0, 172, 45, 172, 0, 166, 7, 166, 0, + 166, 97, 166, 0, 172, 45, 167, 0, 172, 57, + 167, 0, 172, 85, 167, 0, 172, 78, 167, 0, + 172, 54, 167, 0, 172, 89, 167, 0, 172, 73, + 92, 0, 172, 73, 90, 92, 0, 172, 0, 171, + 0, 171, 0, 171, 24, 168, 0, 170, 0, 170, + 24, 169, 0, 173, 45, 171, 0, 176, 0, 88, + 176, 0, 120, 0, 138, 0, 173, 0, 174, 39, + 175, 0, 175, 0, 175, 0, 66, 0, 70, 0 }; #endif @@ -342,13 +340,13 @@ static const short yyrhs[] = /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const short yyrline[] = { - 0, 140, 148, 150, 151, 152, 153, 156, 168, 180, - 193, 207, 220, 233, 243, 263, 274, 279, 286, 291, - 297, 302, 306, 310, 314, 318, 322, 328, 339, 352, - 355, 360, 371, 387, 401, 414, 420, 422, 434, 447, - 454, 460, 466, 472, 478, 484, 490, 496, 502, 508, - 514, 522, 524, 527, 539, 552, 554, 562, 578, 585, - 591, 597, 605, 614, 619, 625, 632 + 0, 137, 145, 147, 148, 149, 150, 153, 165, 177, + 190, 204, 217, 230, 240, 251, 257, 265, 270, 277, + 282, 288, 293, 297, 301, 305, 309, 313, 319, 328, + 341, 344, 349, 360, 376, 378, 382, 388, 390, 402, + 415, 422, 428, 434, 440, 446, 452, 458, 464, 470, + 476, 482, 490, 492, 495, 503, 513, 515, 522, 530, + 537, 543, 549, 557, 566, 573, 581, 588, 597 }; #endif @@ -387,10 +385,11 @@ static const char *const yytname[] = "TK_WILDCARD", "END_OF_FILE", "ILLEGAL", "SPACE", "UNCLOSED_STRING", "COMMENT", "FUNCTION", "COLUMN", "AGG_FUNCTION.", "query", "onequery", "oneinsert", "onecreate", "oneupdate", "onedelete", "table_def", - "column_def", "column_type", "data_type_l", "data_type", "data_count", - "oneselect", "unorderedsel", "selectfrom", "selcollist", "from", - "fromtable", "expr", "val", "constlist", "update_assign_list", - "column_assignment", "const_val", "column_val", "column", "table", "id", 0 + "column_def", "column_and_type", "column_type", "data_type_l", + "data_type", "data_count", "oneselect", "unorderedsel", "selectfrom", + "selcollist", "from", "fromtable", "expr", "val", "constlist", + "update_assign_list", "column_assignment", "const_val", "column_val", + "column", "table", "id", "number", 0 }; #endif @@ -398,24 +397,24 @@ static const char *const yytname[] = static const short yyr1[] = { 0, 147, 148, 148, 148, 148, 148, 149, 149, 150, - 150, 151, 152, 153, 154, 154, 155, 155, 156, 156, - 157, 157, 157, 157, 157, 157, 157, 158, 159, 159, - 160, 160, 161, 162, 162, 162, 163, 163, 164, 165, - 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, - 165, 166, 166, 167, 167, 168, 168, 169, 170, 170, - 170, 170, 171, 172, 172, 173, 174 + 150, 151, 152, 153, 154, 154, 155, 156, 156, 157, + 157, 158, 158, 158, 158, 158, 158, 158, 159, 160, + 160, 161, 161, 162, 163, 163, 163, 164, 164, 165, + 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, + 166, 166, 167, 167, 168, 168, 169, 169, 170, 171, + 171, 171, 171, 172, 173, 173, 174, 175, 176 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const short yyr2[] = { 0, 1, 1, 1, 1, 1, 1, 10, 11, 6, - 7, 6, 2, 4, 4, 2, 1, 2, 1, 3, - 1, 4, 1, 1, 1, 1, 1, 1, 4, 1, - 2, 3, 2, 1, 3, 1, 1, 3, 2, 3, + 7, 6, 2, 4, 3, 1, 2, 1, 2, 1, + 3, 1, 4, 1, 1, 1, 1, 1, 1, 4, + 1, 2, 3, 2, 1, 3, 1, 1, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 1, 1, 1, 3, 1, 3, 3, 1, 2, - 1, 1, 1, 3, 1, 1, 1 + 3, 4, 1, 1, 1, 3, 1, 3, 3, 1, + 2, 1, 1, 1, 3, 1, 1, 1, 1 }; /* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE @@ -424,49 +423,49 @@ static const short yyr2[] = static const short yydefact[] = { 0, 0, 0, 0, 0, 0, 1, 4, 3, 5, - 6, 2, 29, 0, 0, 12, 36, 0, 0, 66, - 35, 30, 0, 33, 0, 64, 0, 65, 0, 0, - 38, 0, 0, 31, 32, 0, 0, 0, 0, 0, - 0, 37, 0, 62, 0, 34, 63, 0, 55, 0, - 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, - 0, 20, 24, 25, 22, 26, 23, 15, 16, 18, - 39, 41, 42, 58, 0, 60, 61, 43, 52, 40, - 47, 51, 44, 0, 49, 46, 45, 48, 0, 11, - 56, 57, 10, 0, 0, 0, 17, 0, 59, 50, - 0, 14, 13, 27, 0, 19, 0, 21, 0, 53, - 7, 0, 8, 54, 0, 0, 0 + 6, 2, 30, 0, 0, 12, 37, 0, 0, 67, + 36, 31, 0, 34, 0, 65, 0, 66, 0, 0, + 39, 0, 0, 32, 33, 0, 0, 0, 0, 0, + 0, 38, 0, 63, 0, 35, 64, 0, 56, 0, + 29, 0, 0, 15, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 0, 0, 21, 25, 26, 23, 27, 24, 16, 17, + 19, 40, 42, 43, 68, 0, 61, 62, 44, 53, + 41, 59, 48, 52, 45, 0, 50, 47, 46, 49, + 0, 11, 57, 58, 10, 14, 0, 0, 18, 0, + 60, 51, 0, 13, 0, 28, 20, 0, 22, 0, + 54, 7, 0, 8, 55, 0, 0, 0 }; static const short yydefgoto[] = { - 124, 6, 7, 8, 9, 10, 51, 52, 77, 78, - 79, 114, 11, 12, 21, 22, 15, 16, 41, 87, - 118, 47, 48, 88, 42, 43, 24, 25 + 125, 6, 7, 8, 9, 10, 51, 52, 53, 78, + 79, 80, 114, 11, 12, 21, 22, 15, 16, 41, + 88, 119, 47, 48, 89, 42, 43, 24, 25, 91 }; static const short yypact[] = { - -28, -102, -32, -48, -29, -39,-32768,-32768,-32768,-32768, - -32768,-32768, -61, -39, -39,-32768, -97, -39, -50,-32768, - -32768,-32768, -32, 19, 6, 9, -65,-32768, 34, -30, - -32768, -37, -26,-32768,-32768, -50, -39, -39, -50, -39, - -37, -2, -31,-32768, -50,-32768,-32768, -86, 32, 10, - -32768, -51, -20, -17, -7, -37, -37, -60, -60, -60, - -59, -60, -60, -60, -36, -37, -39, -58, 16, -39, - 2, 0,-32768,-32768,-32768,-32768,-32768,-32768, -5, 1, - -32768, -2, -2,-32768, 15,-32768,-32768,-32768,-32768,-32768, - -32768,-32768,-32768, -4,-32768,-32768,-32768,-32768, -42, -2, - -32768,-32768,-32768, -17, -50, 23,-32768, 5,-32768,-32768, - 11,-32768,-32768,-32768, -11,-32768, -58,-32768, -10, 83, - -9, -58,-32768,-32768, 117, 118,-32768 + -28, -106, -27, -52, -32, -42,-32768,-32768,-32768,-32768, + -32768,-32768, -70, -42, -42,-32768, -97, -42, -48,-32768, + -32768,-32768, -27, 7, 2, 5, -62,-32768, 40, -23, + -32768, -55, -22,-32768,-32768, -48, -42, -42, -48, -42, + -55, -3, 0,-32768, -48,-32768,-32768, -65, 43, 29, + -32768, -34, -19,-32768, -18, -7, -55, -55, -58, -58, + -58, -37, -58, -58, -58, -31, -55, -42, -61, 23, + -42, 10, 8,-32768,-32768,-32768,-32768,-32768,-32768, 6, + 3,-32768, -3, -3,-32768, 18,-32768,-32768,-32768,-32768, + -32768,-32768,-32768,-32768,-32768, 16,-32768,-32768,-32768,-32768, + -33, -3,-32768,-32768,-32768,-32768, -48, 18,-32768, 20, + -32768,-32768, 30,-32768, 4,-32768,-32768, -61,-32768, 11, + 91, -6, -61,-32768,-32768, 117, 118,-32768 }; static const short yypgoto[] = { - -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 17,-32768, - -32768,-32768,-32768,-32768, 101, -27, 99,-32768, 31, 53, - 3, 57,-32768, -49, 47, -3, 56, 8 + -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 49,-32768, + -32768,-32768,-32768,-32768,-32768, 102, -25, 100,-32768, -8, + 36, 1, 57,-32768, -51, 47, -2, 9, 33, -64 }; @@ -475,36 +474,36 @@ static const short yypgoto[] = static const short yytable[] = { - 55, 23, 71, 1, 69, 55, 19, 2, 45, 18, - 83, 50, 83, 27, 57, 23, 19, 64, 101, 13, - 14, 27, 27, 58, 17, 27, 59, 19, 84, 19, - 84, 93, 23, 94, 49, 23, 53, 19, 28, 3, - 31, 23, 60, 35, 46, 36, 40, 61, -65, 37, - 38, 65, 72, 39, 62, 67, 66, 44, 63, 68, - 85, 26, 85, 49, 73, 74, 103, 119, 20, 29, - 30, 54, 119, 32, 98, 102, 75, 112, 86, 104, - 86, 106, 70, 105, 4, 108, 81, 82, 109, 20, - 56, 107, 110, 113, 116, 56, 99, 115, 76, 117, - 120, 23, 5, 80, 89, 91, 91, 121, 91, 91, - 91, 90, 92, 122, 95, 96, 97, 125, 126, 33, - 111, 34, 0, 100, 123 + 56, 72, 23, 1, 56, 70, 18, 2, 19, 84, + 45, 19, 84, 50, 26, 13, 23, 103, 19, 65, + 17, 110, 29, 30, 19, 14, 32, 85, 40, 28, + 85, 35, 55, 23, 19, 49, 23, 54, 27, 3, + 31, 36, 23, 115, -66, 58, 27, 27, 82, 83, + 27, 73, 37, 95, 59, 96, 38, 60, 101, 86, + 39, 44, 86, 74, 75, 49, 120, 67, 54, 46, + 20, 120, 66, 61, 68, 76, 69, 87, 62, 100, + 87, 113, 104, 71, 4, 63, 20, 106, 84, 64, + 57, 107, 108, 109, 57, 92, 94, 77, 97, 98, + 99, 112, 5, 81, 23, 90, 93, 93, 111, 93, + 93, 93, 116, 117, 118, 122, 123, 126, 127, 105, + 33, 121, 34, 124, 102 }; static const short yycheck[] = { - 7, 4, 19, 31, 24, 7, 66, 35, 35, 38, - 70, 38, 70, 5, 45, 18, 66, 44, 67, 121, - 52, 13, 14, 54, 72, 17, 57, 66, 88, 66, - 88, 90, 35, 92, 37, 38, 39, 66, 99, 67, - 137, 44, 73, 24, 36, 39, 83, 78, 39, 114, - 16, 137, 69, 83, 85, 45, 24, 83, 89, 110, - 120, 5, 120, 66, 81, 82, 69, 116, 118, 13, - 14, 40, 121, 17, 110, 59, 93, 104, 138, 77, - 138, 86, 102, 83, 112, 70, 55, 56, 92, 118, - 97, 90, 134, 70, 83, 97, 65, 92, 115, 110, - 110, 104, 130, 110, 57, 58, 59, 24, 61, 62, - 63, 58, 59, 122, 61, 62, 63, 0, 0, 18, - 103, 22, -1, 66, 121 + 7, 19, 4, 31, 7, 24, 38, 35, 66, 70, + 35, 66, 70, 38, 5, 121, 18, 68, 66, 44, + 72, 85, 13, 14, 66, 52, 17, 88, 83, 99, + 88, 24, 40, 35, 66, 37, 38, 39, 5, 67, + 137, 39, 44, 107, 39, 45, 13, 14, 56, 57, + 17, 69, 114, 90, 54, 92, 16, 57, 66, 120, + 83, 83, 120, 81, 82, 67, 117, 24, 70, 36, + 118, 122, 137, 73, 45, 93, 110, 138, 78, 110, + 138, 106, 59, 102, 112, 85, 118, 77, 70, 89, + 97, 83, 86, 90, 97, 59, 60, 115, 62, 63, + 64, 134, 130, 110, 106, 58, 59, 60, 92, 62, + 63, 64, 92, 83, 110, 24, 122, 0, 0, 70, + 18, 110, 22, 122, 67 }; #define YYPURE 1 @@ -1216,79 +1215,79 @@ yyreduce: switch (yyn) { case 1: -#line 142 "./sql.y" +#line 139 "./sql.y" { SQL_input* sql = (SQL_input*) info; *sql->view = yyvsp[0].query; ; break;} case 7: -#line 158 "./sql.y" +#line 155 "./sql.y" { SQL_input *sql = (SQL_input*) info; MSIVIEW *insert = NULL; UINT r; - r = INSERT_CreateView( sql->db, &insert, yyvsp[-7].string, yyvsp[-5].column_list, yyvsp[-1].val_list, FALSE ); + r = INSERT_CreateView( sql->db, &insert, yyvsp[-7].string, yyvsp[-5].column_list, yyvsp[-1].column_list, FALSE ); if( !insert ) YYABORT; yyval.query = insert; ; break;} case 8: -#line 169 "./sql.y" +#line 166 "./sql.y" { SQL_input *sql = (SQL_input*) info; MSIVIEW *insert = NULL; - INSERT_CreateView( sql->db, &insert, yyvsp[-8].string, yyvsp[-6].column_list, yyvsp[-2].val_list, TRUE ); + INSERT_CreateView( sql->db, &insert, yyvsp[-8].string, yyvsp[-6].column_list, yyvsp[-2].column_list, TRUE ); if( !insert ) YYABORT; yyval.query = insert; ; break;} case 9: -#line 182 "./sql.y" +#line 179 "./sql.y" { SQL_input* sql = (SQL_input*) info; MSIVIEW *create = NULL; - if( !yyvsp[-1].column_info ) + if( !yyvsp[-1].column_list ) YYABORT; - CREATE_CreateView( sql->db, &create, yyvsp[-3].string, yyvsp[-1].column_info, FALSE ); + CREATE_CreateView( sql->db, &create, yyvsp[-3].string, yyvsp[-1].column_list, FALSE ); if( !create ) YYABORT; yyval.query = create; ; break;} case 10: -#line 194 "./sql.y" +#line 191 "./sql.y" { SQL_input* sql = (SQL_input*) info; MSIVIEW *create = NULL; - if( !yyvsp[-2].column_info ) + if( !yyvsp[-2].column_list ) YYABORT; - CREATE_CreateView( sql->db, &create, yyvsp[-4].string, yyvsp[-2].column_info, TRUE ); + CREATE_CreateView( sql->db, &create, yyvsp[-4].string, yyvsp[-2].column_list, TRUE ); if( !create ) YYABORT; yyval.query = create; ; break;} case 11: -#line 209 "./sql.y" +#line 206 "./sql.y" { SQL_input* sql = (SQL_input*) info; MSIVIEW *update = NULL; - UPDATE_CreateView( sql->db, &update, yyvsp[-4].string, &yyvsp[-2].update_col_info, yyvsp[0].expr ); + UPDATE_CreateView( sql->db, &update, yyvsp[-4].string, yyvsp[-2].column_list, yyvsp[0].expr ); if( !update ) YYABORT; yyval.query = update; ; break;} case 12: -#line 222 "./sql.y" +#line 219 "./sql.y" { SQL_input* sql = (SQL_input*) info; MSIVIEW *delete = NULL; @@ -1300,125 +1299,116 @@ case 12: ; break;} case 13: -#line 235 "./sql.y" +#line 232 "./sql.y" { - if( SQL_MarkPrimaryKeys( yyvsp[-3].column_info, yyvsp[0].column_list ) ) - yyval.column_info = yyvsp[-3].column_info; + if( SQL_MarkPrimaryKeys( yyvsp[-3].column_list, yyvsp[0].column_list ) ) + yyval.column_list = yyvsp[-3].column_list; else - yyval.column_info = NULL; + yyval.column_list = NULL; ; break;} case 14: -#line 245 "./sql.y" +#line 242 "./sql.y" { - create_col_info *ci; + column_info *ci; - for( ci = yyvsp[-3].column_info; ci->next; ci = ci->next ) + for( ci = yyvsp[-2].column_list; ci->next; ci = ci->next ) ; - ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info ); - if( !ci->next ) - { - /* FIXME: free $1 */ - YYABORT; - } - ci->next->colname = yyvsp[-1].string; - ci->next->type = yyvsp[0].column_type; - ci->next->next = NULL; - - yyval.column_info = yyvsp[-3].column_info; + ci->next = yyvsp[0].column_list; + yyval.column_list = yyvsp[-2].column_list; ; break;} case 15: -#line 264 "./sql.y" +#line 252 "./sql.y" { - yyval.column_info = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info ); - if( ! yyval.column_info ) - YYABORT; - yyval.column_info->colname = yyvsp[-1].string; - yyval.column_info->type = yyvsp[0].column_type; - yyval.column_info->next = NULL; + yyval.column_list = yyvsp[0].column_list; ; break;} case 16: -#line 276 "./sql.y" +#line 259 "./sql.y" +{ + yyval.column_list = yyvsp[-1].column_list; + yyval.column_list->type = yyvsp[0].column_type; + ; + break;} +case 17: +#line 267 "./sql.y" { yyval.column_type = yyvsp[0].column_type | MSITYPE_VALID; ; break;} -case 17: -#line 280 "./sql.y" +case 18: +#line 271 "./sql.y" { FIXME("LOCALIZABLE ignored\n"); yyval.column_type = yyvsp[-1].column_type | MSITYPE_VALID; ; break;} -case 18: -#line 288 "./sql.y" +case 19: +#line 279 "./sql.y" { yyval.column_type |= MSITYPE_NULLABLE; ; break;} -case 19: -#line 292 "./sql.y" +case 20: +#line 283 "./sql.y" { yyval.column_type = yyvsp[-2].column_type; ; break;} -case 20: -#line 299 "./sql.y" +case 21: +#line 290 "./sql.y" { yyval.column_type = MSITYPE_STRING | 1; ; break;} -case 21: -#line 303 "./sql.y" +case 22: +#line 294 "./sql.y" { yyval.column_type = MSITYPE_STRING | 0x400 | yyvsp[-1].column_type; ; break;} -case 22: -#line 307 "./sql.y" -{ - yyval.column_type = 2; - ; - break;} case 23: -#line 311 "./sql.y" +#line 298 "./sql.y" { yyval.column_type = 2; ; break;} case 24: -#line 315 "./sql.y" +#line 302 "./sql.y" { yyval.column_type = 2; ; break;} case 25: -#line 319 "./sql.y" +#line 306 "./sql.y" +{ + yyval.column_type = 2; + ; + break;} +case 26: +#line 310 "./sql.y" { yyval.column_type = 4; ; break;} -case 26: -#line 323 "./sql.y" +case 27: +#line 314 "./sql.y" { yyval.column_type = 0; ; break;} -case 27: -#line 330 "./sql.y" +case 28: +#line 321 "./sql.y" { - SQL_input* sql = (SQL_input*) info; - int val = SQL_getint(sql); - if( ( val > 255 ) || ( val < 0 ) ) + if( ( yyvsp[0].integer > 255 ) || ( yyvsp[0].integer < 0 ) ) YYABORT; - yyval.column_type = val; + yyval.column_type = yyvsp[0].integer; ; break;} -case 28: -#line 341 "./sql.y" +case 29: +#line 330 "./sql.y" { SQL_input* sql = (SQL_input*) info; @@ -1431,14 +1421,14 @@ case 28: YYABORT; ; break;} -case 30: -#line 357 "./sql.y" +case 31: +#line 346 "./sql.y" { yyval.query = yyvsp[0].query; ; break;} -case 31: -#line 361 "./sql.y" +case 32: +#line 350 "./sql.y" { SQL_input* sql = (SQL_input*) info; @@ -1448,8 +1438,8 @@ case 31: YYABORT; ; break;} -case 32: -#line 373 "./sql.y" +case 33: +#line 362 "./sql.y" { SQL_input* sql = (SQL_input*) info; @@ -1463,44 +1453,20 @@ case 32: YYABORT; ; break;} -case 33: -#line 389 "./sql.y" -{ - string_list *list; - - list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); - if( !list ) - YYABORT; - list->string = yyvsp[0].string; - list->next = NULL; - - yyval.column_list = list; - TRACE("Collist %s\n",debugstr_w(yyval.column_list->string)); - ; - break;} -case 34: -#line 402 "./sql.y" -{ - string_list *list; - - list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); - if( !list ) - YYABORT; - list->string = yyvsp[-2].string; - list->next = yyvsp[0].column_list; - - yyval.column_list = list; - TRACE("From table: %s\n",debugstr_w(yyval.column_list->string)); - ; - break;} case 35: -#line 415 "./sql.y" +#line 379 "./sql.y" +{ + yyvsp[-2].column_list->next = yyvsp[0].column_list; + ; + break;} +case 36: +#line 383 "./sql.y" { yyval.column_list = NULL; ; break;} -case 37: -#line 423 "./sql.y" +case 38: +#line 391 "./sql.y" { SQL_input* sql = (SQL_input*) info; UINT r; @@ -1511,8 +1477,8 @@ case 37: YYABORT; ; break;} -case 38: -#line 436 "./sql.y" +case 39: +#line 404 "./sql.y" { SQL_input* sql = (SQL_input*) info; UINT r; @@ -1523,217 +1489,211 @@ case 38: YYABORT; ; break;} -case 39: -#line 449 "./sql.y" +case 40: +#line 417 "./sql.y" { yyval.expr = yyvsp[-1].expr; if( !yyval.expr ) YYABORT; ; break;} -case 40: -#line 455 "./sql.y" +case 41: +#line 423 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_EQ, yyvsp[0].expr ); if( !yyval.expr ) YYABORT; ; break;} -case 41: -#line 461 "./sql.y" +case 42: +#line 429 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_AND, yyvsp[0].expr ); if( !yyval.expr ) YYABORT; ; break;} -case 42: -#line 467 "./sql.y" +case 43: +#line 435 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_OR, yyvsp[0].expr ); if( !yyval.expr ) YYABORT; ; break;} -case 43: -#line 473 "./sql.y" +case 44: +#line 441 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_EQ, yyvsp[0].expr ); if( !yyval.expr ) YYABORT; ; break;} -case 44: -#line 479 "./sql.y" +case 45: +#line 447 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_GT, yyvsp[0].expr ); if( !yyval.expr ) YYABORT; ; break;} -case 45: -#line 485 "./sql.y" +case 46: +#line 453 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_LT, yyvsp[0].expr ); if( !yyval.expr ) YYABORT; ; break;} -case 46: -#line 491 "./sql.y" +case 47: +#line 459 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_LE, yyvsp[0].expr ); if( !yyval.expr ) YYABORT; ; break;} -case 47: -#line 497 "./sql.y" +case 48: +#line 465 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_GE, yyvsp[0].expr ); if( !yyval.expr ) YYABORT; ; break;} -case 48: -#line 503 "./sql.y" +case 49: +#line 471 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_NE, yyvsp[0].expr ); if( !yyval.expr ) YYABORT; ; break;} -case 49: -#line 509 "./sql.y" +case 50: +#line 477 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_ISNULL, NULL ); if( !yyval.expr ) YYABORT; ; break;} -case 50: -#line 515 "./sql.y" +case 51: +#line 483 "./sql.y" { yyval.expr = EXPR_complex( info, yyvsp[-3].expr, OP_NOTNULL, NULL ); if( !yyval.expr ) YYABORT; ; break;} -case 53: -#line 529 "./sql.y" -{ - value_list *vals; - - vals = parser_alloc( info, sizeof *vals ); - if( !vals ) - YYABORT; - vals->val = yyvsp[0].expr; - vals->next = NULL; - yyval.val_list = vals; - ; - break;} case 54: -#line 540 "./sql.y" +#line 497 "./sql.y" { - value_list *vals; - - vals = parser_alloc( info, sizeof *vals ); - if( !vals ) + yyval.column_list = parser_alloc_column( info, NULL, NULL ); + if( !yyval.column_list ) YYABORT; - vals->val = yyvsp[-2].expr; - vals->next = yyvsp[0].val_list; - yyval.val_list = vals; + yyval.column_list->val = yyvsp[0].expr; ; break;} -case 56: -#line 555 "./sql.y" +case 55: +#line 504 "./sql.y" { - yyvsp[-2].update_col_info.col_list->next = yyvsp[0].update_col_info.col_list; - yyvsp[-2].update_col_info.val_list->next = yyvsp[0].update_col_info.val_list; - yyval.update_col_info = yyvsp[-2].update_col_info; + yyval.column_list = parser_alloc_column( info, NULL, NULL ); + if( !yyval.column_list ) + YYABORT; + yyval.column_list->val = yyvsp[-2].expr; + yyval.column_list->next = yyvsp[0].column_list; ; break;} case 57: -#line 564 "./sql.y" +#line 516 "./sql.y" { - yyval.update_col_info.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.col_list ); - if( !yyval.update_col_info.col_list ) - YYABORT; - yyval.update_col_info.col_list->string = yyvsp[-2].string; - yyval.update_col_info.col_list->next = NULL; - yyval.update_col_info.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.val_list ); - if( !yyval.update_col_info.val_list ) - YYABORT; - yyval.update_col_info.val_list->val = yyvsp[0].expr; - yyval.update_col_info.val_list->next = 0; + yyval.column_list = yyvsp[-2].column_list; + yyval.column_list->next = yyvsp[0].column_list; ; break;} case 58: -#line 580 "./sql.y" +#line 524 "./sql.y" { - yyval.expr = EXPR_ival( info, &yyvsp[0].str, 1 ); - if( !yyval.expr ) - YYABORT; + yyval.column_list = yyvsp[-2].column_list; + yyval.column_list->val = yyvsp[0].expr; ; break;} case 59: -#line 586 "./sql.y" +#line 532 "./sql.y" { - yyval.expr = EXPR_ival( info, &yyvsp[0].str, -1 ); + yyval.expr = EXPR_ival( info, yyvsp[0].integer ); if( !yyval.expr ) YYABORT; ; break;} case 60: -#line 592 "./sql.y" +#line 538 "./sql.y" +{ + yyval.expr = EXPR_ival( info, -yyvsp[0].integer ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 61: +#line 544 "./sql.y" { yyval.expr = EXPR_sval( info, &yyvsp[0].str ); if( !yyval.expr ) YYABORT; ; break;} -case 61: -#line 598 "./sql.y" +case 62: +#line 550 "./sql.y" { yyval.expr = EXPR_wildcard( info ); if( !yyval.expr ) YYABORT; ; break;} -case 62: -#line 607 "./sql.y" +case 63: +#line 559 "./sql.y" { - yyval.expr = EXPR_column( info, yyvsp[0].string ); + yyval.expr = EXPR_column( info, yyvsp[0].column_list ); if( !yyval.expr ) YYABORT; ; break;} -case 63: -#line 616 "./sql.y" -{ - yyval.string = yyvsp[0].string; /* FIXME */ - ; - break;} case 64: -#line 620 "./sql.y" +#line 568 "./sql.y" { - yyval.string = yyvsp[0].string; + yyval.column_list = parser_alloc_column( info, yyvsp[-2].string, yyvsp[0].string ); + if( !yyval.column_list ) + YYABORT; ; break;} case 65: -#line 627 "./sql.y" +#line 574 "./sql.y" +{ + yyval.column_list = parser_alloc_column( info, NULL, yyvsp[0].string ); + if( !yyval.column_list ) + YYABORT; + ; + break;} +case 66: +#line 583 "./sql.y" { yyval.string = yyvsp[0].string; ; break;} -case 66: -#line 634 "./sql.y" +case 67: +#line 590 "./sql.y" { yyval.string = SQL_getstring( info, &yyvsp[0].str ); if( !yyval.string ) YYABORT; ; break;} +case 68: +#line 599 "./sql.y" +{ + yyval.integer = SQL_getint( info ); + ; + break;} } #line 705 "/usr/share/bison/bison.simple" @@ -1967,7 +1927,7 @@ yyreturn: #endif return yyresult; } -#line 641 "./sql.y" +#line 604 "./sql.y" static void *parser_alloc( void *info, unsigned int sz ) @@ -1980,6 +1940,23 @@ static void *parser_alloc( void *info, unsigned int sz ) return &mem[1]; } +static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column ) +{ + column_info *col; + + col = parser_alloc( info, sizeof (*col) ); + if( col ) + { + col->table = table; + col->column = column; + col->val = NULL; + col->type = 0; + col->next = NULL; + } + + return col; +} + int SQL_lex( void *SQL_lval, SQL_input *sql ) { int token; @@ -2031,8 +2008,19 @@ INT SQL_getint( void *info ) { SQL_input* sql = (SQL_input*) info; LPCWSTR p = &sql->command[sql->n]; + INT i, r = 0; - return atoiW( p ); + for( i=0; ilen; i++ ) + { + if( '0' > p[i] || '9' < p[i] ) + { + ERR("should only be numbers here!\n"); + break; + } + r = (p[i]-'0') + r*10; + } + + return r; } int SQL_error( const char *str ) @@ -2063,24 +2051,24 @@ static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct e return e; } -static struct expr * EXPR_column( void *info, LPWSTR column ) +static struct expr * EXPR_column( void *info, column_info *column ) { struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { e->type = EXPR_COLUMN; - e->u.sval = column; + e->u.sval = column->column; } return e; } -static struct expr * EXPR_ival( void *info, struct sql_str *str, int sign ) +static struct expr * EXPR_ival( void *info, int val ) { struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { e->type = EXPR_IVAL; - e->u.ival = atoiW( str->data ) * sign; + e->u.ival = val; } return e; } @@ -2096,19 +2084,20 @@ static struct expr * EXPR_sval( void *info, struct sql_str *str ) return e; } -static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys) +static BOOL SQL_MarkPrimaryKeys( column_info *cols, + column_info *keys ) { - string_list *k; + column_info *k; BOOL found = TRUE; for( k = keys; k && found; k = k->next ) { - create_col_info *c; + column_info *c; found = FALSE; for( c = cols; c && !found; c = c->next ) { - if( lstrcmpW( k->string, c->colname ) ) + if( lstrcmpW( k->column, c->column ) ) continue; c->type |= MSITYPE_KEY; found = TRUE; diff --git a/reactos/lib/msi/sql.tab.h b/reactos/lib/msi/sql.tab.h index bfc66b3f050..f49301be8b1 100644 --- a/reactos/lib/msi/sql.tab.h +++ b/reactos/lib/msi/sql.tab.h @@ -1,347 +1,163 @@ -/* A Bison parser, made by GNU Bison 1.875b. */ +#ifndef BISON_SQL_TAB_H +# define BISON_SQL_TAB_H -/* Skeleton parser for Yacc-like parsing with Bison, - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* As a special exception, when this file is copied by Bison into a - Bison output file, you may use that output file without restriction. - This special exception was added by the Free Software Foundation - in version 1.24 of Bison. */ - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - TK_ABORT = 258, - TK_AFTER = 259, - TK_AGG_FUNCTION = 260, - TK_ALL = 261, - TK_AND = 262, - TK_AS = 263, - TK_ASC = 264, - TK_BEFORE = 265, - TK_BEGIN = 266, - TK_BETWEEN = 267, - TK_BITAND = 268, - TK_BITNOT = 269, - TK_BITOR = 270, - TK_BY = 271, - TK_CASCADE = 272, - TK_CASE = 273, - TK_CHAR = 274, - TK_CHECK = 275, - TK_CLUSTER = 276, - TK_COLLATE = 277, - TK_COLUMN = 278, - TK_COMMA = 279, - TK_COMMENT = 280, - TK_COMMIT = 281, - TK_CONCAT = 282, - TK_CONFLICT = 283, - TK_CONSTRAINT = 284, - TK_COPY = 285, - TK_CREATE = 286, - TK_DEFAULT = 287, - TK_DEFERRABLE = 288, - TK_DEFERRED = 289, - TK_DELETE = 290, - TK_DELIMITERS = 291, - TK_DESC = 292, - TK_DISTINCT = 293, - TK_DOT = 294, - TK_DROP = 295, - TK_EACH = 296, - TK_ELSE = 297, - TK_END = 298, - TK_END_OF_FILE = 299, - TK_EQ = 300, - TK_EXCEPT = 301, - TK_EXPLAIN = 302, - TK_FAIL = 303, - TK_FLOAT = 304, - TK_FOR = 305, - TK_FOREIGN = 306, - TK_FROM = 307, - TK_FUNCTION = 308, - TK_GE = 309, - TK_GLOB = 310, - TK_GROUP = 311, - TK_GT = 312, - TK_HAVING = 313, - TK_HOLD = 314, - TK_IGNORE = 315, - TK_ILLEGAL = 316, - TK_IMMEDIATE = 317, - TK_IN = 318, - TK_INDEX = 319, - TK_INITIALLY = 320, - TK_ID = 321, - TK_INSERT = 322, - TK_INSTEAD = 323, - TK_INT = 324, - TK_INTEGER = 325, - TK_INTERSECT = 326, - TK_INTO = 327, - TK_IS = 328, - TK_ISNULL = 329, - TK_JOIN = 330, - TK_JOIN_KW = 331, - TK_KEY = 332, - TK_LE = 333, - TK_LIKE = 334, - TK_LIMIT = 335, - TK_LONG = 336, - TK_LONGCHAR = 337, - TK_LP = 338, - TK_LSHIFT = 339, - TK_LT = 340, - TK_LOCALIZABLE = 341, - TK_MATCH = 342, - TK_MINUS = 343, - TK_NE = 344, - TK_NOT = 345, - TK_NOTNULL = 346, - TK_NULL = 347, - TK_OBJECT = 348, - TK_OF = 349, - TK_OFFSET = 350, - TK_ON = 351, - TK_OR = 352, - TK_ORACLE_OUTER_JOIN = 353, - TK_ORDER = 354, - TK_PLUS = 355, - TK_PRAGMA = 356, - TK_PRIMARY = 357, - TK_RAISE = 358, - TK_REFERENCES = 359, - TK_REM = 360, - TK_REPLACE = 361, - TK_RESTRICT = 362, - TK_ROLLBACK = 363, - TK_ROW = 364, - TK_RP = 365, - TK_RSHIFT = 366, - TK_SELECT = 367, - TK_SEMI = 368, - TK_SET = 369, - TK_SHORT = 370, - TK_SLASH = 371, - TK_SPACE = 372, - TK_STAR = 373, - TK_STATEMENT = 374, - TK_STRING = 375, - TK_TABLE = 376, - TK_TEMP = 377, - TK_THEN = 378, - TK_TRANSACTION = 379, - TK_TRIGGER = 380, - TK_UMINUS = 381, - TK_UNCLOSED_STRING = 382, - TK_UNION = 383, - TK_UNIQUE = 384, - TK_UPDATE = 385, - TK_UPLUS = 386, - TK_USING = 387, - TK_VACUUM = 388, - TK_VALUES = 389, - TK_VIEW = 390, - TK_WHEN = 391, - TK_WHERE = 392, - TK_WILDCARD = 393, - COLUMN = 395, - FUNCTION = 396, - COMMENT = 397, - UNCLOSED_STRING = 398, - SPACE = 399, - ILLEGAL = 400, - END_OF_FILE = 401 - }; -#endif -#define TK_ABORT 258 -#define TK_AFTER 259 -#define TK_AGG_FUNCTION 260 -#define TK_ALL 261 -#define TK_AND 262 -#define TK_AS 263 -#define TK_ASC 264 -#define TK_BEFORE 265 -#define TK_BEGIN 266 -#define TK_BETWEEN 267 -#define TK_BITAND 268 -#define TK_BITNOT 269 -#define TK_BITOR 270 -#define TK_BY 271 -#define TK_CASCADE 272 -#define TK_CASE 273 -#define TK_CHAR 274 -#define TK_CHECK 275 -#define TK_CLUSTER 276 -#define TK_COLLATE 277 -#define TK_COLUMN 278 -#define TK_COMMA 279 -#define TK_COMMENT 280 -#define TK_COMMIT 281 -#define TK_CONCAT 282 -#define TK_CONFLICT 283 -#define TK_CONSTRAINT 284 -#define TK_COPY 285 -#define TK_CREATE 286 -#define TK_DEFAULT 287 -#define TK_DEFERRABLE 288 -#define TK_DEFERRED 289 -#define TK_DELETE 290 -#define TK_DELIMITERS 291 -#define TK_DESC 292 -#define TK_DISTINCT 293 -#define TK_DOT 294 -#define TK_DROP 295 -#define TK_EACH 296 -#define TK_ELSE 297 -#define TK_END 298 -#define TK_END_OF_FILE 299 -#define TK_EQ 300 -#define TK_EXCEPT 301 -#define TK_EXPLAIN 302 -#define TK_FAIL 303 -#define TK_FLOAT 304 -#define TK_FOR 305 -#define TK_FOREIGN 306 -#define TK_FROM 307 -#define TK_FUNCTION 308 -#define TK_GE 309 -#define TK_GLOB 310 -#define TK_GROUP 311 -#define TK_GT 312 -#define TK_HAVING 313 -#define TK_HOLD 314 -#define TK_IGNORE 315 -#define TK_ILLEGAL 316 -#define TK_IMMEDIATE 317 -#define TK_IN 318 -#define TK_INDEX 319 -#define TK_INITIALLY 320 -#define TK_ID 321 -#define TK_INSERT 322 -#define TK_INSTEAD 323 -#define TK_INT 324 -#define TK_INTEGER 325 -#define TK_INTERSECT 326 -#define TK_INTO 327 -#define TK_IS 328 -#define TK_ISNULL 329 -#define TK_JOIN 330 -#define TK_JOIN_KW 331 -#define TK_KEY 332 -#define TK_LE 333 -#define TK_LIKE 334 -#define TK_LIMIT 335 -#define TK_LONG 336 -#define TK_LONGCHAR 337 -#define TK_LP 338 -#define TK_LSHIFT 339 -#define TK_LT 340 -#define TK_LOCALIZABLE 341 -#define TK_MATCH 342 -#define TK_MINUS 343 -#define TK_NE 344 -#define TK_NOT 345 -#define TK_NOTNULL 346 -#define TK_NULL 347 -#define TK_OBJECT 348 -#define TK_OF 349 -#define TK_OFFSET 350 -#define TK_ON 351 -#define TK_OR 352 -#define TK_ORACLE_OUTER_JOIN 353 -#define TK_ORDER 354 -#define TK_PLUS 355 -#define TK_PRAGMA 356 -#define TK_PRIMARY 357 -#define TK_RAISE 358 -#define TK_REFERENCES 359 -#define TK_REM 360 -#define TK_REPLACE 361 -#define TK_RESTRICT 362 -#define TK_ROLLBACK 363 -#define TK_ROW 364 -#define TK_RP 365 -#define TK_RSHIFT 366 -#define TK_SELECT 367 -#define TK_SEMI 368 -#define TK_SET 369 -#define TK_SHORT 370 -#define TK_SLASH 371 -#define TK_SPACE 372 -#define TK_STAR 373 -#define TK_STATEMENT 374 -#define TK_STRING 375 -#define TK_TABLE 376 -#define TK_TEMP 377 -#define TK_THEN 378 -#define TK_TRANSACTION 379 -#define TK_TRIGGER 380 -#define TK_UMINUS 381 -#define TK_UNCLOSED_STRING 382 -#define TK_UNION 383 -#define TK_UNIQUE 384 -#define TK_UPDATE 385 -#define TK_UPLUS 386 -#define TK_USING 387 -#define TK_VACUUM 388 -#define TK_VALUES 389 -#define TK_VIEW 390 -#define TK_WHEN 391 -#define TK_WHERE 392 -#define TK_WILDCARD 393 -#define COLUMN 395 -#define FUNCTION 396 -#define COMMENT 397 -#define UNCLOSED_STRING 398 -#define SPACE 399 -#define ILLEGAL 400 -#define END_OF_FILE 401 - - - - -#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) -#line 74 "./sql.y" -typedef union YYSTYPE { +#ifndef YYSTYPE +typedef union +{ struct sql_str str; LPWSTR string; - string_list *column_list; - value_list *val_list; + column_info *column_list; MSIVIEW *query; struct expr *expr; USHORT column_type; - create_col_info *column_info; - column_assignment update_col_info; -} YYSTYPE; -/* Line 1252 of yacc.c. */ -#line 339 "sql.tab.h" -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 + int integer; +} yystype; +# define YYSTYPE yystype # define YYSTYPE_IS_TRIVIAL 1 #endif +# define TK_ABORT 257 +# define TK_AFTER 258 +# define TK_AGG_FUNCTION 259 +# define TK_ALL 260 +# define TK_AND 261 +# define TK_AS 262 +# define TK_ASC 263 +# define TK_BEFORE 264 +# define TK_BEGIN 265 +# define TK_BETWEEN 266 +# define TK_BITAND 267 +# define TK_BITNOT 268 +# define TK_BITOR 269 +# define TK_BY 270 +# define TK_CASCADE 271 +# define TK_CASE 272 +# define TK_CHAR 273 +# define TK_CHECK 274 +# define TK_CLUSTER 275 +# define TK_COLLATE 276 +# define TK_COLUMN 277 +# define TK_COMMA 278 +# define TK_COMMENT 279 +# define TK_COMMIT 280 +# define TK_CONCAT 281 +# define TK_CONFLICT 282 +# define TK_CONSTRAINT 283 +# define TK_COPY 284 +# define TK_CREATE 285 +# define TK_DEFAULT 286 +# define TK_DEFERRABLE 287 +# define TK_DEFERRED 288 +# define TK_DELETE 289 +# define TK_DELIMITERS 290 +# define TK_DESC 291 +# define TK_DISTINCT 292 +# define TK_DOT 293 +# define TK_DROP 294 +# define TK_EACH 295 +# define TK_ELSE 296 +# define TK_END 297 +# define TK_END_OF_FILE 298 +# define TK_EQ 299 +# define TK_EXCEPT 300 +# define TK_EXPLAIN 301 +# define TK_FAIL 302 +# define TK_FLOAT 303 +# define TK_FOR 304 +# define TK_FOREIGN 305 +# define TK_FROM 306 +# define TK_FUNCTION 307 +# define TK_GE 308 +# define TK_GLOB 309 +# define TK_GROUP 310 +# define TK_GT 311 +# define TK_HAVING 312 +# define TK_HOLD 313 +# define TK_IGNORE 314 +# define TK_ILLEGAL 315 +# define TK_IMMEDIATE 316 +# define TK_IN 317 +# define TK_INDEX 318 +# define TK_INITIALLY 319 +# define TK_ID 320 +# define TK_INSERT 321 +# define TK_INSTEAD 322 +# define TK_INT 323 +# define TK_INTEGER 324 +# define TK_INTERSECT 325 +# define TK_INTO 326 +# define TK_IS 327 +# define TK_ISNULL 328 +# define TK_JOIN 329 +# define TK_JOIN_KW 330 +# define TK_KEY 331 +# define TK_LE 332 +# define TK_LIKE 333 +# define TK_LIMIT 334 +# define TK_LONG 335 +# define TK_LONGCHAR 336 +# define TK_LP 337 +# define TK_LSHIFT 338 +# define TK_LT 339 +# define TK_LOCALIZABLE 340 +# define TK_MATCH 341 +# define TK_MINUS 342 +# define TK_NE 343 +# define TK_NOT 344 +# define TK_NOTNULL 345 +# define TK_NULL 346 +# define TK_OBJECT 347 +# define TK_OF 348 +# define TK_OFFSET 349 +# define TK_ON 350 +# define TK_OR 351 +# define TK_ORACLE_OUTER_JOIN 352 +# define TK_ORDER 353 +# define TK_PLUS 354 +# define TK_PRAGMA 355 +# define TK_PRIMARY 356 +# define TK_RAISE 357 +# define TK_REFERENCES 358 +# define TK_REM 359 +# define TK_REPLACE 360 +# define TK_RESTRICT 361 +# define TK_ROLLBACK 362 +# define TK_ROW 363 +# define TK_RP 364 +# define TK_RSHIFT 365 +# define TK_SELECT 366 +# define TK_SEMI 367 +# define TK_SET 368 +# define TK_SHORT 369 +# define TK_SLASH 370 +# define TK_SPACE 371 +# define TK_STAR 372 +# define TK_STATEMENT 373 +# define TK_STRING 374 +# define TK_TABLE 375 +# define TK_TEMP 376 +# define TK_THEN 377 +# define TK_TRANSACTION 378 +# define TK_TRIGGER 379 +# define TK_UMINUS 380 +# define TK_UNCLOSED_STRING 381 +# define TK_UNION 382 +# define TK_UNIQUE 383 +# define TK_UPDATE 384 +# define TK_UPLUS 385 +# define TK_USING 386 +# define TK_VACUUM 387 +# define TK_VALUES 388 +# define TK_VIEW 389 +# define TK_WHEN 390 +# define TK_WHERE 391 +# define TK_WILDCARD 392 +# define END_OF_FILE 393 +# define ILLEGAL 394 +# define SPACE 395 +# define UNCLOSED_STRING 396 +# define COMMENT 397 +# define FUNCTION 398 +# define COLUMN 399 - - - +#endif /* not BISON_SQL_TAB_H */ diff --git a/reactos/lib/msi/sql.y b/reactos/lib/msi/sql.y index 7a0edd9f6ab..a311d6aa886 100644 --- a/reactos/lib/msi/sql.y +++ b/reactos/lib/msi/sql.y @@ -32,7 +32,6 @@ #include "query.h" #include "wine/list.h" #include "wine/debug.h" -#include "wine/unicode.h" #define YYLEX_PARAM info #define YYPARSE_PARAM info @@ -55,12 +54,13 @@ static INT SQL_getint( void *info ); static int SQL_lex( void *SQL_lval, SQL_input *info ); static void *parser_alloc( void *info, unsigned int sz ); +static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column ); -static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys); +static BOOL SQL_MarkPrimaryKeys( column_info *cols, column_info *keys); static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r ); -static struct expr * EXPR_column( void *info, LPWSTR column ); -static struct expr * EXPR_ival( void *info, struct sql_str *, int sign ); +static struct expr * EXPR_column( void *info, column_info *column ); +static struct expr * EXPR_ival( void *info, int val ); static struct expr * EXPR_sval( void *info, struct sql_str * ); static struct expr * EXPR_wildcard( void *info ); @@ -72,13 +72,11 @@ static struct expr * EXPR_wildcard( void *info ); { struct sql_str str; LPWSTR string; - string_list *column_list; - value_list *val_list; + column_info *column_list; MSIVIEW *query; struct expr *expr; USHORT column_type; - create_col_info *column_info; - column_assignment update_col_info; + int integer; } %token TK_ABORT TK_AFTER TK_AGG_FUNCTION TK_ALL TK_AND TK_AS TK_ASC @@ -125,15 +123,14 @@ static struct expr * EXPR_wildcard( void *info ); %nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION COLUMN AGG_FUNCTION. -%type column table id -%type selcollist -%type query from fromtable unorderedsel selectfrom +%type table id +%type selcollist column column_and_type column_def table_def +%type column_assignment update_assign_list constlist +%type query from fromtable selectfrom unorderedsel %type oneupdate onedelete oneselect onequery onecreate oneinsert %type expr val column_val const_val %type column_type data_type data_type_l data_count -%type column_def table_def -%type constlist -%type column_assignment update_assign_list +%type number %% @@ -210,7 +207,7 @@ oneupdate: SQL_input* sql = (SQL_input*) info; MSIVIEW *update = NULL; - UPDATE_CreateView( sql->db, &update, $2, &$4, $6 ); + UPDATE_CreateView( sql->db, &update, $2, $4, $6 ); if( !update ) YYABORT; $$ = update; @@ -241,33 +238,27 @@ table_def: ; column_def: - column_def TK_COMMA column column_type + column_def TK_COMMA column_and_type { - create_col_info *ci; + column_info *ci; for( ci = $1; ci->next; ci = ci->next ) ; - ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ ); - if( !ci->next ) - { - /* FIXME: free $1 */ - YYABORT; - } - ci->next->colname = $3; - ci->next->type = $4; - ci->next->next = NULL; - + ci->next = $3; $$ = $1; } - | column column_type + | column_and_type { - $$ = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ ); - if( ! $$ ) - YYABORT; - $$->colname = $1; + $$ = $1; + } + ; + +column_and_type: + column column_type + { + $$ = $1; $$->type = $2; - $$->next = NULL; } ; @@ -326,13 +317,11 @@ data_type: ; data_count: - TK_INTEGER + number { - SQL_input* sql = (SQL_input*) info; - int val = SQL_getint(sql); - if( ( val > 255 ) || ( val < 0 ) ) + if( ( $1 > 255 ) || ( $1 < 0 ) ) YYABORT; - $$ = val; + $$ = $1; } ; @@ -386,30 +375,9 @@ selectfrom: selcollist: column - { - string_list *list; - - list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); - if( !list ) - YYABORT; - list->string = $1; - list->next = NULL; - - $$ = list; - TRACE("Collist %s\n",debugstr_w($$->string)); - } | column TK_COMMA selcollist { - string_list *list; - - list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); - if( !list ) - YYABORT; - list->string = $1; - list->next = $3; - - $$ = list; - TRACE("From table: %s\n",debugstr_w($$->string)); + $1->next = $3; } | TK_STAR { @@ -527,25 +495,18 @@ val: constlist: const_val { - value_list *vals; - - vals = parser_alloc( info, sizeof *vals ); - if( !vals ) + $$ = parser_alloc_column( info, NULL, NULL ); + if( !$$ ) YYABORT; - vals->val = $1; - vals->next = NULL; - $$ = vals; + $$->val = $1; } | const_val TK_COMMA constlist { - value_list *vals; - - vals = parser_alloc( info, sizeof *vals ); - if( !vals ) + $$ = parser_alloc_column( info, NULL, NULL ); + if( !$$ ) YYABORT; - vals->val = $1; - vals->next = $3; - $$ = vals; + $$->val = $1; + $$->next = $3; } ; @@ -553,38 +514,29 @@ update_assign_list: column_assignment | column_assignment TK_COMMA update_assign_list { - $1.col_list->next = $3.col_list; - $1.val_list->next = $3.val_list; $$ = $1; + $$->next = $3; } ; column_assignment: column TK_EQ const_val { - $$.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.col_list ); - if( !$$.col_list ) - YYABORT; - $$.col_list->string = $1; - $$.col_list->next = NULL; - $$.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.val_list ); - if( !$$.val_list ) - YYABORT; - $$.val_list->val = $3; - $$.val_list->next = 0; + $$ = $1; + $$->val = $3; } ; const_val: - TK_INTEGER + number { - $$ = EXPR_ival( info, &$1, 1 ); + $$ = EXPR_ival( info, $1 ); if( !$$ ) YYABORT; } - | TK_MINUS TK_INTEGER + | TK_MINUS number { - $$ = EXPR_ival( info, &$2, -1 ); + $$ = EXPR_ival( info, -$2 ); if( !$$ ) YYABORT; } @@ -614,11 +566,15 @@ column_val: column: table TK_DOT id { - $$ = $3; /* FIXME */ + $$ = parser_alloc_column( info, $1, $3 ); + if( !$$ ) + YYABORT; } | id { - $$ = $1; + $$ = parser_alloc_column( info, NULL, $1 ); + if( !$$ ) + YYABORT; } ; @@ -638,6 +594,13 @@ id: } ; +number: + TK_INTEGER + { + $$ = SQL_getint( info ); + } + ; + %% static void *parser_alloc( void *info, unsigned int sz ) @@ -650,6 +613,23 @@ static void *parser_alloc( void *info, unsigned int sz ) return &mem[1]; } +static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column ) +{ + column_info *col; + + col = parser_alloc( info, sizeof (*col) ); + if( col ) + { + col->table = table; + col->column = column; + col->val = NULL; + col->type = 0; + col->next = NULL; + } + + return col; +} + int SQL_lex( void *SQL_lval, SQL_input *sql ) { int token; @@ -701,8 +681,19 @@ INT SQL_getint( void *info ) { SQL_input* sql = (SQL_input*) info; LPCWSTR p = &sql->command[sql->n]; + INT i, r = 0; - return atoiW( p ); + for( i=0; ilen; i++ ) + { + if( '0' > p[i] || '9' < p[i] ) + { + ERR("should only be numbers here!\n"); + break; + } + r = (p[i]-'0') + r*10; + } + + return r; } int SQL_error( const char *str ) @@ -733,24 +724,24 @@ static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct e return e; } -static struct expr * EXPR_column( void *info, LPWSTR column ) +static struct expr * EXPR_column( void *info, column_info *column ) { struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { e->type = EXPR_COLUMN; - e->u.sval = column; + e->u.sval = column->column; } return e; } -static struct expr * EXPR_ival( void *info, struct sql_str *str, int sign ) +static struct expr * EXPR_ival( void *info, int val ) { struct expr *e = parser_alloc( info, sizeof *e ); if( e ) { e->type = EXPR_IVAL; - e->u.ival = atoiW( str->data ) * sign; + e->u.ival = val; } return e; } @@ -766,19 +757,20 @@ static struct expr * EXPR_sval( void *info, struct sql_str *str ) return e; } -static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys) +static BOOL SQL_MarkPrimaryKeys( column_info *cols, + column_info *keys ) { - string_list *k; + column_info *k; BOOL found = TRUE; for( k = keys; k && found; k = k->next ) { - create_col_info *c; + column_info *c; found = FALSE; for( c = cols; c && !found; c = c->next ) { - if( lstrcmpW( k->string, c->colname ) ) + if( lstrcmpW( k->column, c->column ) ) continue; c->type |= MSITYPE_KEY; found = TRUE; diff --git a/reactos/lib/msi/suminfo.c b/reactos/lib/msi/suminfo.c index 744898d3379..cd507f2c082 100644 --- a/reactos/lib/msi/suminfo.c +++ b/reactos/lib/msi/suminfo.c @@ -91,6 +91,14 @@ typedef struct { } str; } awstring; +typedef struct { + BOOL unicode; + union { + LPCSTR a; + LPCWSTR w; + } str; +} awcstring; + typedef struct tagMSISUMMARYINFO { MSIOBJECTHDR hdr; @@ -627,7 +635,7 @@ UINT WINAPI MsiSummaryInfoGetPropertyW( } static UINT set_prop( MSIHANDLE handle, UINT uiProperty, UINT uiDataType, - INT iValue, FILETIME* pftValue, awstring *str ) + INT iValue, FILETIME* pftValue, awcstring *str ) { MSISUMMARYINFO *si; PROPVARIANT *prop; @@ -701,9 +709,9 @@ end: } UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty, - UINT uiDataType, INT iValue, FILETIME* pftValue, LPWSTR szValue ) + UINT uiDataType, INT iValue, FILETIME* pftValue, LPCWSTR szValue ) { - awstring str; + awcstring str; TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType, iValue, pftValue, debugstr_w(szValue) ); @@ -714,9 +722,9 @@ UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty, } UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty, - UINT uiDataType, INT iValue, FILETIME* pftValue, LPSTR szValue ) + UINT uiDataType, INT iValue, FILETIME* pftValue, LPCSTR szValue ) { - awstring str; + awcstring str; TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType, iValue, pftValue, debugstr_a(szValue) ); diff --git a/reactos/lib/msi/table.c b/reactos/lib/msi/table.c index 29f19117a66..60fd269be4c 100644 --- a/reactos/lib/msi/table.c +++ b/reactos/lib/msi/table.c @@ -397,7 +397,7 @@ end: return ret; } -UINT read_table_from_storage( MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable) +static UINT read_table_from_storage( MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable) { MSITABLE *t; USHORT *rawdata = NULL; @@ -507,7 +507,7 @@ void remove_table( MSIDATABASE *db, MSITABLE *table ) table->prev = NULL; } -void release_table( MSIDATABASE *db, MSITABLE *table ) +static void release_table( MSIDATABASE *db, MSITABLE *table ) { if( !table->ref_count ) ERR("Trying to destroy table with refcount 0\n"); @@ -610,7 +610,7 @@ UINT get_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable) return ERROR_SUCCESS; } -UINT save_table( MSIDATABASE *db, MSITABLE *t ) +static UINT save_table( MSIDATABASE *db, MSITABLE *t ) { USHORT *rawdata = NULL, *p; UINT rawsize, r, i, j, row_size, num_cols = 0; @@ -751,7 +751,7 @@ end: return ret; } -UINT save_string_table( MSIDATABASE *db ) +static UINT save_string_table( MSIDATABASE *db ) { UINT i, count, datasize, poolsize, sz, used, r, codepage; UINT ret = ERROR_FUNCTION_FAILED; @@ -858,7 +858,7 @@ struct standard_table { #define STANDARD_TABLE_COUNT \ (sizeof(MSI_standard_tables)/sizeof(struct standard_table)) -UINT get_defaulttablecolumns( LPCWSTR szTable, MSICOLUMNINFO *colinfo, UINT *sz) +static UINT get_defaulttablecolumns( LPCWSTR szTable, MSICOLUMNINFO *colinfo, UINT *sz) { DWORD i, n=0; @@ -1167,7 +1167,7 @@ static UINT TABLE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val return ERROR_SUCCESS; } -UINT TABLE_insert_row( struct tagMSIVIEW *view, UINT *num ) +static UINT TABLE_insert_row( struct tagMSIVIEW *view, UINT *num ) { MSITABLEVIEW *tv = (MSITABLEVIEW*)view; USHORT **p, *row; diff --git a/reactos/lib/msi/tokenize.c b/reactos/lib/msi/tokenize.c index 315bac9a670..05c3cda38e2 100644 --- a/reactos/lib/msi/tokenize.c +++ b/reactos/lib/msi/tokenize.c @@ -158,7 +158,7 @@ static const Keyword aKeywordTable[] = { ** keyword. If it is a keyword, the token code of that keyword is ** returned. If the input is not a keyword, TK_ID is returned. */ -int sqliteKeywordCode(const WCHAR *z, int n){ +static int sqliteKeywordCode(const WCHAR *z, int n){ UINT i, len; char buffer[0x10]; diff --git a/reactos/lib/msi/update.c b/reactos/lib/msi/update.c index 3ab38603a10..0af29e07b17 100644 --- a/reactos/lib/msi/update.c +++ b/reactos/lib/msi/update.c @@ -43,7 +43,7 @@ typedef struct tagMSIUPDATEVIEW MSIVIEW view; MSIDATABASE *db; MSIVIEW *wv; - value_list *vals; + column_info *vals; } MSIUPDATEVIEW; static UINT UPDATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) @@ -193,7 +193,7 @@ static MSIVIEWOPS update_ops = }; UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, - column_assignment *list, struct expr *expr ) + column_info *columns, struct expr *expr ) { MSIUPDATEVIEW *uv = NULL; UINT r; @@ -215,7 +215,7 @@ UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, } /* then select the columns we want */ - r = SELECT_CreateView( db, &sv, wv, list->col_list ); + r = SELECT_CreateView( db, &sv, wv, columns ); if( r != ERROR_SUCCESS ) { if( tv ) @@ -231,7 +231,7 @@ UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, uv->view.ops = &update_ops; msiobj_addref( &db->hdr ); uv->db = db; - uv->vals = list->val_list; + uv->vals = columns; uv->wv = sv; *view = (MSIVIEW*) uv; diff --git a/reactos/lib/msi/upgrade.c b/reactos/lib/msi/upgrade.c new file mode 100644 index 00000000000..7a066ca621a --- /dev/null +++ b/reactos/lib/msi/upgrade.c @@ -0,0 +1,228 @@ +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2005 Aric Stewart for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Actions focused on in this module + * + * FindRelatedProducts + * MigrateFeatureStates (TODO) + * RemoveExistingProducts (TODO) + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" +#include "wine/debug.h" +#include "msidefs.h" +#include "msipriv.h" +#include "winuser.h" +#include "action.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +extern const WCHAR szFindRelatedProducts[]; +extern const WCHAR szMigrateFeatureStates[]; +extern const WCHAR szRemoveExistingProducts[]; + +static BOOL check_language(DWORD lang1, LPCWSTR lang2, DWORD attributes) +{ + DWORD langdword; + + if (!lang2 || lang2[0]==0) + return TRUE; + + langdword = atoiW(lang2); + + if (attributes & msidbUpgradeAttributesLanguagesExclusive) + return (lang1 != langdword); + else + return (lang1 == langdword); +} + +static void append_productcode(MSIPACKAGE* package, LPCWSTR action_property, + LPCWSTR productid) +{ + LPWSTR prop; + LPWSTR newprop; + DWORD len; + static const WCHAR separator[] = {';',0}; + + prop = load_dynamic_property(package, action_property, NULL); + if (prop) + len = strlenW(prop); + else + len = 0; + + /*separator*/ + len ++; + + len += strlenW(productid); + + /*null*/ + len++; + + newprop = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); + + if (prop) + { + strcpyW(newprop,prop); + strcatW(newprop,separator); + } + else + newprop[0] = 0; + strcatW(newprop,productid); + + MSI_SetPropertyW(package, action_property, newprop); + TRACE("Found Related Product... %s now %s\n",debugstr_w(action_property), + debugstr_w(newprop)); + HeapFree(GetProcessHeap(),0,prop); + HeapFree(GetProcessHeap(),0,newprop); +} + +static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param) +{ + MSIPACKAGE *package = (MSIPACKAGE*)param; + WCHAR product[GUID_SIZE]; + DWORD index = 0; + DWORD attributes = 0; + DWORD sz = GUID_SIZE; + LPCWSTR upgrade_code; + HKEY hkey = 0; + UINT rc = ERROR_SUCCESS; + MSIRECORD *uirow; + + upgrade_code = MSI_RecordGetString(rec,1); + + rc = MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey, FALSE); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + uirow = MSI_CreateRecord(1); + attributes = MSI_RecordGetInteger(rec,5); + + while (rc == ERROR_SUCCESS) + { + rc = RegEnumValueW(hkey, index, product, &sz, NULL, NULL, NULL, NULL); + TRACE("Looking at (%li) %s\n",index,debugstr_w(product)); + if (rc == ERROR_SUCCESS) + { + WCHAR productid[GUID_SIZE]; + LPCWSTR ver; + LPCWSTR language; + LPCWSTR action_property; + DWORD check = 0x00000000; + DWORD comp_ver = 0x00000000; + DWORD sz = 0x100; + HKEY hukey; + INT r; + static const WCHAR szVersion[] = + {'V','e','r','s','i','o','n',0}; + static const WCHAR szLanguage[] = + {'L','a','n','g','u','a','g','e',0}; + + unsquash_guid(product,productid); + rc = MSIREG_OpenUserProductsKey(productid, &hukey, FALSE); + if (rc != ERROR_SUCCESS) + { + rc = ERROR_SUCCESS; + index ++; + continue; + } + + sz = sizeof(DWORD); + RegQueryValueExW(hukey, szVersion, NULL, NULL, (LPBYTE)&check, + &sz); + /* check min */ + ver = MSI_RecordGetString(rec,2); + comp_ver = build_version_dword(ver); + r = check - comp_ver; + if (r < 0 || (r == 0 && !(attributes & + msidbUpgradeAttributesVersionMinInclusive))) + { + RegCloseKey(hukey); + index ++; + continue; + } + + /* check max */ + ver = MSI_RecordGetString(rec,3); + comp_ver = build_version_dword(ver); + r = check - comp_ver; + if (r > 0 || (r == 0 && !(attributes & + msidbUpgradeAttributesVersionMaxInclusive))) + { + RegCloseKey(hukey); + index ++; + continue; + } + + /* check language*/ + sz = sizeof(DWORD); + RegQueryValueExW(hukey, szLanguage, NULL, NULL, (LPBYTE)&check, + &sz); + RegCloseKey(hukey); + language = MSI_RecordGetString(rec,4); + TRACE("Checking languages 0x%lx and %s\n", check, + debugstr_w(language)); + if (!check_language(check, language, attributes)) + { + index ++; + continue; + } + + action_property = MSI_RecordGetString(rec,7); + append_productcode(package,action_property,productid); + ui_actiondata(package,szFindRelatedProducts,uirow); + } + index ++; + } + RegCloseKey(hkey); + msiobj_release( &uirow->hdr); + + return ERROR_SUCCESS; +} + +UINT ACTION_FindRelatedProducts(MSIPACKAGE *package) +{ + static const WCHAR Query[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M', + ' ','`','U','p','g','r','a','d','e','`',0}; + UINT rc = ERROR_SUCCESS; + MSIQUERY *view; + + if (package->script && package->script->FindRelatedProductsRun) + return ERROR_SUCCESS; + + if (package->script) + package->script->FindRelatedProductsRun = TRUE; + + rc = MSI_DatabaseOpenViewW(package->db, Query, &view); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + rc = MSI_IterateRecords(view, NULL, ITERATE_FindRelatedProducts, package); + msiobj_release(&view->hdr); + + return rc; +} diff --git a/reactos/lib/msi/where.c b/reactos/lib/msi/where.c index e43e3c48984..9bad7b54c8d 100644 --- a/reactos/lib/msi/where.c +++ b/reactos/lib/msi/where.c @@ -24,7 +24,6 @@ #include "winbase.h" #include "winerror.h" #include "wine/debug.h" -#include "wine/unicode.h" #include "msi.h" #include "msiquery.h" #include "objbase.h" @@ -171,7 +170,7 @@ static UINT STRCMP_Evaluate( string_table *st, MSIVIEW *table, UINT row, else if( r_str && ! l_str ) sr = -1; else - sr = strcmpW( l_str, r_str ); + sr = lstrcmpW( l_str, r_str ); *val = ( cond->u.expr.op == OP_EQ && ( sr == 0 ) ) || ( cond->u.expr.op == OP_LT && ( sr < 0 ) ) || diff --git a/reactos/w32api/include/msi.h b/reactos/w32api/include/msi.h index 9ae0f6c2a2d..1c1278272c4 100644 --- a/reactos/w32api/include/msi.h +++ b/reactos/w32api/include/msi.h @@ -23,6 +23,10 @@ extern "C" { #endif +#ifndef _MSI_NO_CRYPTO +#include "wincrypt.h" +#endif + typedef unsigned long MSIHANDLE; typedef enum tagINSTALLSTATE @@ -201,20 +205,6 @@ UINT WINAPI MsiOpenProductA(LPCSTR, MSIHANDLE*); UINT WINAPI MsiOpenProductW(LPCWSTR, MSIHANDLE*); #define MsiOpenProduct WINELIB_NAME_AW(MsiOpenProduct) -UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE, LPCSTR, UINT, MSIHANDLE *); -UINT WINAPI MsiGetSummaryInformationW(MSIHANDLE, LPCWSTR, UINT, MSIHANDLE *); -#define MsiGetSummaryInformation WINELIB_NAME_AW(MsiGetSummaryInformation) - -UINT WINAPI MsiSummaryInfoGetPropertyA(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPSTR,DWORD*); -UINT WINAPI MsiSummaryInfoGetPropertyW(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPWSTR,DWORD*); -#define MsiSummaryInfoGetProperty WINELIB_NAME_AW(MsiSummaryInfoGetProperty) - -UINT WINAPI MsiSummaryInfoPersist(MSIHANDLE); - -UINT WINAPI MsiSummaryInfoSetPropertyA(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPSTR); -UINT WINAPI MsiSummaryInfoSetPropertyW(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPWSTR); -#define MsiSummaryInfoSetProperty WINELIB_NAME_AW(MsiSummaryInfoSetProperty) - UINT WINAPI MsiProvideComponentFromDescriptorA(LPCSTR,LPSTR,DWORD*,DWORD*); UINT WINAPI MsiProvideComponentFromDescriptorW(LPCWSTR,LPWSTR,DWORD*,DWORD*); #define MsiProvideComponentFromDescriptor WINELIB_NAME_AW(MsiProvideComponentFromDescriptor) @@ -303,10 +293,34 @@ USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR, LPSTR, DWORD*, LPSTR, DWORD*, LPSTR USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR, LPWSTR, DWORD*, LPWSTR, DWORD*, LPWSTR, DWORD*); #define MsiGetUserInfo WINELIB_NAME_AW(MsiGetUserInfo) -UINT WINAPI MsiCollectUserInfoA( LPCSTR ); -UINT WINAPI MsiCollectUserInfoW( LPCWSTR ); +UINT WINAPI MsiCollectUserInfoA(LPCSTR); +UINT WINAPI MsiCollectUserInfoW(LPCWSTR); #define MsiCollectUserInfo WINELIB_NAME_AW(MsiCollectUserInfo) +UINT WINAPI MsiReinstallFeatureA(LPCSTR, LPCSTR, DWORD); +UINT WINAPI MsiReinstallFeatureW(LPCWSTR, LPCWSTR, DWORD); +#define MsiReinstallFeature WINELIB_NAME_AW(MsiReinstallFeature) + +UINT WINAPI MsiGetShortcutTargetA(LPCSTR, LPSTR, LPSTR, LPSTR); +UINT WINAPI MsiGetShortcutTargetW(LPCWSTR, LPWSTR, LPWSTR, LPWSTR); +#define MsiGetShortcutTarget WINELIB_NAME_AW(MsiGetShortcutTarget) + +INSTALLSTATE WINAPI MsiUseFeatureW(LPCWSTR, LPCWSTR); +INSTALLSTATE WINAPI MsiUseFeatureA(LPCSTR, LPCSTR); +#define MsiUseFeature WINELIB_NAME_AW(MsiUseFeature) + +INSTALLSTATE WINAPI MsiUseFeatureExW(LPCWSTR, LPCWSTR, DWORD, DWORD); +INSTALLSTATE WINAPI MsiUseFeatureExA(LPCSTR, LPCSTR, DWORD, DWORD); +#define MsiUseFeatureEx WINELIB_NAME_AW(MsiUseFeatureEx) + +HRESULT WINAPI MsiGetFileSignatureInformationA(LPCSTR, DWORD, PCCERT_CONTEXT*, BYTE*, DWORD*); +HRESULT WINAPI MsiGetFileSignatureInformationW(LPCWSTR, DWORD, PCCERT_CONTEXT*, BYTE*, DWORD*); +#define MsiGetFileSignatureInformation WINELIB_NAME_AW(MsiGetFileSignatureInformation) + +INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR, LPSTR, DWORD *); +INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR, LPWSTR, DWORD *); +#define MsiLocateComponent WINELIB_NAME_AW(MsiLocateComponent) + /* Non Unicode */ UINT WINAPI MsiCloseHandle(MSIHANDLE); UINT WINAPI MsiCloseAllHandles(void); diff --git a/reactos/w32api/include/msidefs.h b/reactos/w32api/include/msidefs.h index 71b054b80ca..9d06d6da508 100644 --- a/reactos/w32api/include/msidefs.h +++ b/reactos/w32api/include/msidefs.h @@ -23,6 +23,15 @@ extern "C" { #endif +enum msidbUpgradeAttributes { + msidbUpgradeAttributesMigrateFeatures = 0x0000001, + msidbUpgradeAttributesOnlyDetect = 0x00000002, + msidbUpgradeAttributesIgnoreRemoveFailure = 0x00000004, + msidbUpgradeAttributesVersionMinInclusive = 0x00000100, + msidbUpgradeAttributesVersionMaxInclusive = 0x00000200, + msidbUpgradeAttributesLanguagesExclusive = 0x00000400 +}; + enum msidbFileAttributes { msidbFileAttributesReadOnly = 0x00000001, msidbFileAttributesHidden = 0x00000002, @@ -49,6 +58,51 @@ enum msidbDialogAttributes { msidbDialogAttributesError = 0x00010000 }; +enum msidbControlAttributes { + msidbControlAttributesVisible = 0x00000001, + msidbControlAttributesEnabled = 0x00000002, + msidbControlAttributesSunken = 0x00000004, + msidbControlAttributesIndirect = 0x00000008, + msidbControlAttributesInteger = 0x00000010, + msidbControlAttributesRTLRO = 0x00000020, + msidbControlAttributesRightAligned = 0x00000040, + msidbControlAttributesLeftScroll = 0x00000080, + msidbControlAttributesBiDi = 0x000000c0, + + msidbControlAttributesTransparent = 0x00010000, + msidbControlAttributesNoPrefix = 0x00020000, + msidbControlAttributesNoWrap = 0x00040000, + msidbControlAttributesFormatSize = 0x00080000, + msidbControlAttributesUsersLanguage = 0x00100000, + + msidbControlAttributesMultiline = 0x00010000, + msidbControlAttributesPasswordInput = 0x00200000, + + msidbControlAttributesProgress95 = 0x00010000, + + msidbControlAttributesRemovableVolume = 0x00010000, + msidbControlAttributesFixedVolume = 0x00020000, + msidbControlAttributesRemoteVolume = 0x00040000, + msidbControlAttributesCDROMVolume = 0x00080000, + msidbControlAttributesRAMdiskVolume = 0x00100000, + msidbControlAttributesFloppyVolume = 0x00200000, + msidbControlShowRollbackCost = 0x00400000, + + msidbControlAttributesSorted = 0x00010000, + msidbControlAttributesComboList = 0x00020000, + + msidbControlAttributesImageHandle = 0x00010000, + msidbControlAttributesPushLike = 0x00020000, + msidbControlAttributesBitmap = 0x00040000, + msidbControlAttributesIcon = 0x00080000, + msidbControlAttributesFixedSize = 0x00100000, + msidbControlAttributesIconSize16 = 0x00200000, + msidbControlAttributesIconSize32 = 0x00400000, + msidbControlAttributesIconSize48 = 0x00600000, + + msidbControlAttributesHasBorder = 0x01000000, +}; + enum msidbTextStyleStyleBits { msidbTextStyleStyleBitsBold = 0x00000001, diff --git a/reactos/w32api/include/msiquery.h b/reactos/w32api/include/msiquery.h index 9b61ae6acd4..a836f630464 100644 --- a/reactos/w32api/include/msiquery.h +++ b/reactos/w32api/include/msiquery.h @@ -53,8 +53,6 @@ typedef enum tagMSIMODIFY MSIMODIFY_VALIDATE_DELETE = 11 } MSIMODIFY; -#define MSI_NULL_INTEGER 0x80000000 - #define MSIDBOPEN_READONLY (LPCTSTR)0 #define MSIDBOPEN_TRANSACT (LPCTSTR)1 #define MSIDBOPEN_DIRECT (LPCTSTR)2 @@ -84,6 +82,43 @@ typedef enum tagMSIRUNMODE MSIRUNMODE_COMMIT = 18 } MSIRUNMODE; +typedef enum tagMSIDBERROR +{ + MSIDBERROR_INVALIDARG = -3, + MSIDBERROR_MOREDATA = -2, + MSIDBERROR_FUNCTIONERROR = -1, + MSIDBERROR_NOERROR = 0, + MSIDBERROR_DUPLICATEKEY = 1, + MSIDBERROR_REQUIRED = 2, + MSIDBERROR_BADLINK = 3, + MSIDBERROR_OVERFLOW = 4, + MSIDBERROR_UNDERFLOW = 5, + MSIDBERROR_NOTINSET = 6, + MSIDBERROR_BADVERSION = 7, + MSIDBERROR_BADCASE = 8, + MSIDBERROR_BADGUID = 9, + MSIDBERROR_BADWILDCARD = 10, + MSIDBERROR_BADIDENTIFIER = 11, + MSIDBERROR_BADLANGUAGE = 12, + MSIDBERROR_BADFILENAME = 13, + MSIDBERROR_BADPATH = 14, + MSIDBERROR_BADCONDITION = 15, + MSIDBERROR_BADFORMATTED = 16, + MSIDBERROR_BADTEMPLATE = 17, + MSIDBERROR_BADDEFAULTDIR = 18, + MSIDBERROR_BADREGPATH = 19, + MSIDBERROR_BADCUSTOMSOURCE = 20, + MSIDBERROR_BADPROPERTY = 21, + MSIDBERROR_MISSINGDATA = 22, + MSIDBERROR_BADCATEGORY = 23, + MSIDBERROR_BADKEYTABLE = 24, + MSIDBERROR_BADMAXMINVALUES = 25, + MSIDBERROR_BADCABINET = 26, + MSIDBERROR_BADSHORTCUT= 27, + MSIDBERROR_STRINGOVERFLOW = 28, + MSIDBERROR_BADLOCALIZEATTRIB = 29 +} MSIDBERROR; + /* view manipulation */ UINT WINAPI MsiViewFetch(MSIHANDLE,MSIHANDLE*); UINT WINAPI MsiViewExecute(MSIHANDLE,MSIHANDLE); @@ -91,6 +126,9 @@ UINT WINAPI MsiViewClose(MSIHANDLE); UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE,LPCSTR,MSIHANDLE*); UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE,LPCWSTR,MSIHANDLE*); #define MsiDatabaseOpenView WINELIB_NAME_AW(MsiDatabaseOpenView) +UINT WINAPI MsiViewGetErrorA(MSIHANDLE,LPSTR,DWORD*); +UINT WINAPI MsiViewGetErrorW(MSIHANDLE,LPWSTR,DWORD*); +#define MsiViewGetError WINELIB_NAME_AW(MsiViewGetError) /* record manipulation */ MSIHANDLE WINAPI MsiCreateRecord(unsigned int); @@ -175,6 +213,48 @@ UINT WINAPI MsiSetFeatureStateA(MSIHANDLE, LPCSTR, INSTALLSTATE); UINT WINAPI MsiSetFeatureStateW(MSIHANDLE, LPCWSTR, INSTALLSTATE); #define MsiSetFeatureState WINELIB_NAME_AW(MsiSetFeatureState) +UINT WINAPI MsiPreviewDialogA(MSIHANDLE, LPCSTR); +UINT WINAPI MsiPreviewDialogW(MSIHANDLE, LPCWSTR); +#define MsiPreviewDialog WINELIB_NAME_AW(MsiPreviewDialog) + +UINT WINAPI MsiPreviewBillboardA(MSIHANDLE, LPCSTR, LPCSTR); +UINT WINAPI MsiPreviewBillboardW(MSIHANDLE, LPCWSTR, LPCWSTR); +#define MsiPreviewBillboard WINELIB_NAME_AW(MsiPreviewBillboard) + +UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE, LPCSTR, UINT, MSIHANDLE *); +UINT WINAPI MsiGetSummaryInformationW(MSIHANDLE, LPCWSTR, UINT, MSIHANDLE *); +#define MsiGetSummaryInformation WINELIB_NAME_AW(MsiGetSummaryInformation) + +UINT WINAPI MsiSummaryInfoGetPropertyA(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPSTR,DWORD*); +UINT WINAPI MsiSummaryInfoGetPropertyW(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPWSTR,DWORD*); +#define MsiSummaryInfoGetProperty WINELIB_NAME_AW(MsiSummaryInfoGetProperty) + +UINT WINAPI MsiSummaryInfoSetPropertyA(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPCSTR); +UINT WINAPI MsiSummaryInfoSetPropertyW(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPCWSTR); +#define MsiSummaryInfoSetProperty WINELIB_NAME_AW(MsiSummaryInfoSetProperty) + +UINT WINAPI MsiDatabaseExportA(MSIHANDLE, LPCSTR, LPCSTR, LPCSTR); +UINT WINAPI MsiDatabaseExportW(MSIHANDLE, LPCWSTR, LPCWSTR, LPCWSTR); +#define MsiDatabaseExport WINELIB_NAME_AW(MsiDatabaseExport) + +UINT WINAPI MsiDatabaseImportA(MSIHANDLE, LPCSTR, LPCSTR); +UINT WINAPI MsiDatabaseImportW(MSIHANDLE, LPCWSTR, LPCWSTR); +#define MsiDatabaseImport WINELIB_NAME_AW(MsiDatabaseImport) + +UINT WINAPI MsiOpenDatabaseW(LPCWSTR, LPCWSTR, MSIHANDLE*); +UINT WINAPI MsiOpenDatabaseA(LPCSTR, LPCSTR, MSIHANDLE*); +#define MsiOpenDatabase WINELIB_NAME_AW(MsiOpenDatabase) + +UINT WINAPI MsiDatabaseIsTablePersistentA(MSIHANDLE, LPSTR); +UINT WINAPI MsiDatabaseIsTablePersistentW(MSIHANDLE, LPWSTR); +#define MsiDatabaseIsTablePersistent WINELIB_NAME_AW(MsiDatabaseIsTablePersistent) + +UINT WINAPI MsiSummaryInfoPersist(MSIHANDLE); +UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE,UINT*); + +UINT WINAPI MsiEnableUIPreview(MSIHANDLE, MSIHANDLE*); BOOL WINAPI MsiGetMode(MSIHANDLE, MSIRUNMODE); +UINT WINAPI MsiViewModify(MSIHANDLE, MSIMODIFY, MSIHANDLE); + #endif /* __WINE_MSIQUERY_H */