diff --git a/reactos/include/wine/msi.h b/reactos/include/wine/msi.h index f461e998c7f..9ae0f6c2a2d 100644 --- a/reactos/include/wine/msi.h +++ b/reactos/include/wine/msi.h @@ -55,6 +55,15 @@ typedef enum tagINSTALLUILEVEL INSTALLUILEVEL_SOURCERESONLY = 0x100 } INSTALLUILEVEL; +typedef enum tagUSERINFOSTATE +{ + USERINFOSTATE_MOREDATA = -3, + USERINFOSTATE_INVALIDARG = -2, + USERINFOSTATE_UNKNOWN = -1, + USERINFOSTATE_ABSENT = 0, + USERINFOSTATE_PRESENT = 1, +} USERINFOSTATE; + typedef enum tagINSTALLLEVEL { INSTALLLEVEL_DEFAULT = 0, @@ -137,15 +146,17 @@ typedef enum tagINSTALLTYPE #define MAX_FEATURE_CHARS 38 -typedef INT (CALLBACK *INSTALLUI_HANDLERA)(LPVOID pvContext, UINT iMessageType, - LPCSTR szMessage); -typedef INT (CALLBACK *INSTALLUI_HANDLERW)(LPVOID pvContext, UINT iMessageType, - LPCWSTR szMessage); +typedef INT (CALLBACK *INSTALLUI_HANDLERA)(LPVOID, UINT, LPCSTR); +typedef INT (CALLBACK *INSTALLUI_HANDLERW)(LPVOID, UINT, LPCWSTR); UINT WINAPI MsiAdvertiseProductA(LPCSTR, LPCSTR, LPCSTR, LANGID); UINT WINAPI MsiAdvertiseProductW(LPCWSTR, LPCWSTR, LPCWSTR, LANGID); #define MsiAdvertiseProduct WINELIB_NAME_AW(MsiAdvertiseProduct) +UINT WINAPI MsiAdvertiseProductExA(LPCSTR, LPCSTR, LPCSTR, LANGID, DWORD, DWORD); +UINT WINAPI MsiAdvertiseProductExW(LPCWSTR, LPCWSTR, LPCWSTR, LANGID, DWORD, DWORD); +#define MsiAdvertiseProductEx WINELIB_NAME_AW(MsiAdvertiseProductEx) + UINT WINAPI MsiInstallProductA(LPCSTR, LPCSTR); UINT WINAPI MsiInstallProductW(LPCWSTR, LPCWSTR); #define MsiInstallProduct WINELIB_NAME_AW(MsiInstallProduct) @@ -158,8 +169,8 @@ UINT WINAPI MsiApplyPatchA(LPCSTR, LPCSTR, INSTALLTYPE, LPCSTR); UINT WINAPI MsiApplyPatchW(LPCWSTR, LPCWSTR, INSTALLTYPE, LPCWSTR); #define MsiApplyPatch WINELIB_NAME_AW(MsiApplyPatch) -UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid); -UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid); +UINT WINAPI MsiEnumProductsA(DWORD, LPSTR); +UINT WINAPI MsiEnumProductsW(DWORD, LPWSTR); #define MsiEnumProducts WINELIB_NAME_AW(MsiEnumProducts) UINT WINAPI MsiEnumFeaturesA(LPCSTR, DWORD, LPSTR, LPSTR); @@ -198,6 +209,12 @@ UINT WINAPI MsiSummaryInfoGetPropertyA(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPSTR 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) @@ -218,20 +235,24 @@ INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR); INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR); #define MsiQueryProductState WINELIB_NAME_AW(MsiQueryProductState) -UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState); -UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState); +UINT WINAPI MsiConfigureProductA(LPCSTR, int, INSTALLSTATE); +UINT WINAPI MsiConfigureProductW(LPCWSTR, int, INSTALLSTATE); #define MsiConfigureProduct WINELIB_NAME_AW(MsiConfigureProduct); -UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer); -UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer); +UINT WINAPI MsiConfigureProductExA(LPCSTR, int, INSTALLSTATE, LPCSTR); +UINT WINAPI MsiConfigureProductExW(LPCWSTR, int, INSTALLSTATE, LPCWSTR); +#define MsiConfigureProductEx WINELIB_NAME_AW(MsiConfigureProductEx); + +UINT WINAPI MsiGetProductCodeA(LPCSTR, LPSTR); +UINT WINAPI MsiGetProductCodeW(LPCWSTR, LPWSTR); #define MsiGetProductCode WINELIB_NAME_AW(MsiGetProductCode) -UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, LPSTR szBuffer, DWORD *pcchValueBuf); -UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szBuffer, DWORD *pcchValueBuf); +UINT WINAPI MsiGetProductInfoA(LPCSTR, LPCSTR, LPSTR, DWORD *); +UINT WINAPI MsiGetProductInfoW(LPCWSTR, LPCWSTR, LPWSTR, DWORD *); #define MsiGetProductInfo WINELIB_NAME_AW(MsiGetProductInfo) -UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes); -UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes); +UINT WINAPI MsiEnableLogA(DWORD, LPCSTR, DWORD); +UINT WINAPI MsiEnableLogW(DWORD, LPCWSTR, DWORD); #define MsiEnableLog WINELIB_NAME_AW(MsiEnableLog) INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA, DWORD, LPVOID); @@ -242,15 +263,53 @@ INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR, LPCSTR, LPSTR, DWORD*); INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR, LPCWSTR, LPWSTR, DWORD*); #define MsiGetComponentPath WINELIB_NAME_AW(MsiGetComponentPath) -INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature); -INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature); +INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR, LPCSTR); +INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR, LPCWSTR); #define MsiQueryFeatureState WINELIB_NAME_AW(MsiQueryFeatureState) -/** - * Non Unicode - */ +UINT WINAPI MsiGetFeatureUsageA(LPCSTR, LPCSTR, DWORD*, WORD*); +UINT WINAPI MsiGetFeatureUsageW(LPCWSTR, LPCWSTR, DWORD*, WORD*); +#define MsiGetFeatureUsage WINELIB_NAME_AW(MsiGetFeatureUsage) + +UINT WINAPI MsiEnumRelatedProductsA(LPCSTR, DWORD, DWORD, LPSTR); +UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR, DWORD, DWORD, LPWSTR); +#define MsiEnumRelatedProducts WINELIB_NAME_AW(MsiEnumRelatedProducts) + +UINT WINAPI MsiProvideAssemblyA(LPCSTR, LPCSTR, DWORD, DWORD, LPSTR, DWORD*); +UINT WINAPI MsiProvideAssemblyW(LPCWSTR, LPCWSTR, DWORD, DWORD, LPWSTR, DWORD*); +#define MsiProvideAssembly WINELIB_NAME_AW(MsiProvideAssembly) + +UINT WINAPI MsiEnumComponentQualifiersA(LPSTR, DWORD, LPSTR, DWORD*, LPSTR, DWORD*); +UINT WINAPI MsiEnumComponentQualifiersW(LPWSTR, DWORD, LPWSTR, DWORD*, LPWSTR, DWORD*); +#define MsiEnumComponentQualifiers WINELIB_NAME_AW(MsiEnumComponentQualifiers) + +UINT WINAPI MsiGetFileVersionA(LPCSTR, LPSTR, DWORD*, LPSTR, DWORD*); +UINT WINAPI MsiGetFileVersionW(LPCWSTR, LPWSTR, DWORD*, LPWSTR, DWORD*); +#define MsiGetFileVersion WINELIB_NAME_AW(MsiGetFileVersion) + +UINT WINAPI MsiMessageBoxA(HWND, LPCSTR, LPCSTR, UINT, WORD, DWORD); +UINT WINAPI MsiMessageBoxW(HWND, LPCWSTR, LPCWSTR, UINT, WORD, DWORD); +#define MsiMessageBox WINELIB_NAME_AW(MsiMessageBox) + +UINT WINAPI MsiProvideQualifiedComponentExA(LPCSTR, LPCSTR, DWORD, LPSTR, DWORD, DWORD, LPSTR, DWORD*); +UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR, LPCWSTR, DWORD, LPWSTR, DWORD, DWORD, LPWSTR, DWORD*); +#define MsiProvideQualifiedComponentEx WINELIB_NAME_AW(MsiProvideQualifiedComponentEx) + +UINT WINAPI MsiProvideQualifiedComponentA(LPCSTR, LPCSTR, DWORD, LPSTR, DWORD*); +UINT WINAPI MsiProvideQualifiedComponentW(LPCWSTR, LPCWSTR, DWORD, LPWSTR, DWORD*); +#define MsiProvideQualifiedComponent WINELIB_NAME_AW(MsiProvideQualifiedComponent) + +USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR, LPSTR, DWORD*, LPSTR, DWORD*, LPSTR, DWORD*); +USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR, LPWSTR, DWORD*, LPWSTR, DWORD*, LPWSTR, DWORD*); +#define MsiGetUserInfo WINELIB_NAME_AW(MsiGetUserInfo) + +UINT WINAPI MsiCollectUserInfoA( LPCSTR ); +UINT WINAPI MsiCollectUserInfoW( LPCWSTR ); +#define MsiCollectUserInfo WINELIB_NAME_AW(MsiCollectUserInfo) + +/* Non Unicode */ UINT WINAPI MsiCloseHandle(MSIHANDLE); -UINT WINAPI MsiCloseAllHandles(); +UINT WINAPI MsiCloseAllHandles(void); INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL, HWND*); #ifdef __cplusplus diff --git a/reactos/include/wine/msidefs.h b/reactos/include/wine/msidefs.h new file mode 100644 index 00000000000..b2cf55cd818 --- /dev/null +++ b/reactos/include/wine/msidefs.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2005 Mike McCormack + * + * 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 + */ + +#ifndef __WINE_MSIDEFS_H +#define __WINE_MSIDEFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum msidbDialogAttributes { + msidbDialogAttributesVisible = 0x00000001, + msidbDialogAttributesModal = 0x00000002, + msidbDialogAttributesMinimize = 0x00000004, + msidbDialogAttributesSysModal = 0x00000008, + msidbDialogAttributesKeepModeless = 0x00000010, + msidbDialogAttributesTrackDiskSpace = 0x00000020, + msidbDialogAttributesUseCustomPalette = 0x00000040, + msidbDialogAttributesRTLRO = 0x00000080, + msidbDialogAttributesRightAligned = 0x00000100, + msidbDialogAttributesLeftScroll = 0x00000200, + msidbDialogAttributesBidi = 0x00000380, + msidbDialogAttributesError = 0x00010000 +}; + +enum msidbTextStyleStyleBits +{ + msidbTextStyleStyleBitsBold = 0x00000001, + msidbTextStyleStyleBitsItalic = 0x00000002, + msidbTextStyleStyleBitsUnderline = 0x00000004, + msidbTextStyleStyleBitsStrike = 0x00000008, +}; + +enum msidbCustomActionType +{ + msidbCustomActionTypeDll = 0x00000001, + msidbCustomActionTypeExe = 0x00000002, + msidbCustomActionTypeTextData = 0x00000003, + msidbCustomActionTypeJScript = 0x00000005, + msidbCustomActionTypeVBScript = 0x00000006, + msidbCustomActionTypeInstall = 0x00000007, + + msidbCustomActionTypeBinaryData = 0x00000000, + msidbCustomActionTypeSourceFile = 0x00000010, + msidbCustomActionTypeDirectory = 0x00000020, + msidbCustomActionTypeProperty = 0x00000030, + + msidbCustomActionTypeContinue = 0x00000040, + msidbCustomActionTypeAsync = 0x00000080, + + msidbCustomActionTypeFirstSequence = 0x00000100, + msidbCustomActionTypeOncePerProcess = 0x00000200, + msidbCustomActionTypeClientRepeat = 0x00000300, + msidbCustomActionTypeInScript = 0x00000400, + + msidbCustomActionTypeRollback = 0x00000100, + msidbCustomActionTypeCommit = 0x00000200, + + msidbCustomActionTypeNoImpersonate = 0x00000800, + msidbCustomActionTypeTSAware = 0x00004000, + + msidbCustomActionType64BitScript = 0x00001000, + msidbCustomActionTypeHideTarget = 0x00002000 +}; + +enum msidbFeatureAttributes +{ + msidbFeatureAttributesFavorLocal = 0x00000000, + msidbFeatureAttributesFavorSource = 0x00000001, + msidbFeatureAttributesFollowParent = 0x00000002, + msidbFeatureAttributesFavorAdvertise = 0x00000004, + msidbFeatureAttributesDisallowAdvertise = 0x00000008, + msidbFeatureAttributesUIDisallowAbsent = 0x00000010, + msidbFeatureAttributesNoUnsupportedAdvertise = 0x00000020 +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __WINE_MSIDEFS_H */ diff --git a/reactos/lib/msi/Makefile.in b/reactos/lib/msi/Makefile.in index df2489801a5..27ce824fa1c 100644 --- a/reactos/lib/msi/Makefile.in +++ b/reactos/lib/msi/Makefile.in @@ -8,15 +8,21 @@ EXTRALIBS = -luuid $(LIBUNICODE) C_SRCS = \ action.c \ + appsearch.c \ create.c \ + custom.c \ + dialog.c \ distinct.c \ + format.c \ handle.c \ insert.c \ msi.c \ msiquery.c \ order.c \ package.c \ + preview.c \ record.c \ + registry.c \ regsvr.c \ select.c \ string.c \ @@ -26,7 +32,7 @@ C_SRCS = \ update.c \ where.c -RC_SRCS = version.rc +RC_SRCS = msi.rc EXTRA_SRCS = sql.y cond.y EXTRA_OBJS = sql.tab.o cond.tab.o diff --git a/reactos/lib/msi/action.c b/reactos/lib/msi/action.c index ec066ac054b..5b4c8e117c7 100644 --- a/reactos/lib/msi/action.c +++ b/reactos/lib/msi/action.c @@ -49,99 +49,26 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/stand #include "shlobj.h" #include "wine/unicode.h" #include "ver.h" +#include "action.h" -#define CUSTOM_ACTION_TYPE_MASK 0x3F #define REG_PROGRESS_VALUE 13200 #define COMPONENT_PROGRESS_VALUE 24000 WINE_DEFAULT_DEBUG_CHANNEL(msi); -typedef struct tagMSIFEATURE -{ - WCHAR Feature[96]; - WCHAR Feature_Parent[96]; - WCHAR Title[0x100]; - WCHAR Description[0x100]; - INT Display; - INT Level; - WCHAR Directory[96]; - INT Attributes; - - INSTALLSTATE Installed; - INSTALLSTATE ActionRequest; - INSTALLSTATE Action; - - INT ComponentCount; - INT Components[1024]; /* yes hardcoded limit.... I am bad */ - INT Cost; -} MSIFEATURE; - -typedef struct tagMSICOMPONENT -{ - WCHAR Component[96]; - WCHAR ComponentId[96]; - WCHAR Directory[96]; - INT Attributes; - WCHAR Condition[0x100]; - WCHAR KeyPath[96]; - - INSTALLSTATE Installed; - INSTALLSTATE ActionRequest; - INSTALLSTATE Action; - - BOOL Enabled; - INT Cost; -} MSICOMPONENT; - -typedef struct tagMSIFOLDER -{ - LPWSTR Directory; - LPWSTR TargetDefault; - LPWSTR SourceDefault; - - LPWSTR ResolvedTarget; - LPWSTR ResolvedSource; - LPWSTR Property; /* initially set property */ - INT ParentIndex; - INT State; - /* 0 = uninitialized */ - /* 1 = existing */ - /* 2 = created remove if empty */ - /* 3 = created persist if empty */ - INT Cost; - INT Space; -}MSIFOLDER; - -typedef struct tagMSIFILE -{ - LPWSTR File; - INT ComponentIndex; - LPWSTR FileName; - INT FileSize; - LPWSTR Version; - LPWSTR Language; - INT Attributes; - INT Sequence; - - INT State; - /* 0 = uninitialize */ - /* 1 = not present */ - /* 2 = present but replace */ - /* 3 = present do not replace */ - /* 4 = Installed */ - LPWSTR SourcePath; - LPWSTR TargetPath; - BOOL Temporary; -}MSIFILE; - /* * Prototypes */ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran); static UINT ACTION_ProcessUISequence(MSIPACKAGE *package); - static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq); -UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action); +static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, + LPWSTR *FilePath); + +/* + * action handlers + */ +typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*); static UINT ACTION_LaunchConditions(MSIPACKAGE *package); static UINT ACTION_CostInitialize(MSIPACKAGE *package); @@ -151,32 +78,26 @@ 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_CustomAction(MSIPACKAGE *package,const WCHAR *action); static UINT ACTION_InstallInitialize(MSIPACKAGE *package); static UINT ACTION_InstallValidate(MSIPACKAGE *package); static UINT ACTION_ProcessComponents(MSIPACKAGE *package); static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package); static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package); static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package); +static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package); +static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package); +static UINT ACTION_RegisterUser(MSIPACKAGE *package); static UINT ACTION_CreateShortcuts(MSIPACKAGE *package); static UINT ACTION_PublishProduct(MSIPACKAGE *package); +static UINT ACTION_WriteIniValues(MSIPACKAGE *package); +static UINT ACTION_SelfRegModules(MSIPACKAGE *package); +static UINT ACTION_PublishFeatures(MSIPACKAGE *package); +static UINT ACTION_RegisterProduct(MSIPACKAGE *package); +static UINT ACTION_InstallExecute(MSIPACKAGE *package); +static UINT ACTION_InstallFinalize(MSIPACKAGE *package); +static UINT ACTION_ForceReboot(MSIPACKAGE *package); +static UINT ACTION_ResolveSource(MSIPACKAGE *package); -static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source, - const LPWSTR target, const INT type); -static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source, - const LPWSTR target, const INT type); -static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source, - const LPWSTR target, const INT type); -static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source, - const LPWSTR target, const INT type); -static UINT HANDLE_CustomType34(MSIPACKAGE *package, const LPWSTR source, - const LPWSTR target, const INT type); - -static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data); -static LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, - BOOL source, BOOL set_prop, MSIFOLDER **folder); - -static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path); /* * consts and values used @@ -188,31 +109,30 @@ static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0}; static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0}; static const WCHAR c_collen[] = {'C',':','\\',0}; -static const WCHAR cszlsb[]={'[',0}; -static const WCHAR cszrsb[]={']',0}; static const WCHAR cszbs[]={'\\',0}; const static WCHAR szCreateFolders[] = - {'C','r','e','a','t','e','F','o','l','d','e','r','s',0}; +{'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}; +{'C','o','s','t','F','i','n','a','l','i','z','e',0}; const static WCHAR szInstallFiles[] = - {'I','n','s','t','a','l','l','F','i','l','e','s',0}; +{'I','n','s','t','a','l','l','F','i','l','e','s',0}; const static WCHAR szDuplicateFiles[] = - {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0}; +{'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0}; const static WCHAR szWriteRegistryValues[] = {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0}; const static WCHAR szCostInitialize[] = - {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0}; -const static WCHAR szFileCost[] = {'F','i','l','e','C','o','s','t',0}; +{'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0}; +const static WCHAR szFileCost[] = +{'F','i','l','e','C','o','s','t',0}; const static WCHAR szInstallInitialize[] = - {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0}; +{'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0}; const static WCHAR szInstallValidate[] = - {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0}; +{'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0}; const static WCHAR szLaunchConditions[] = - {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0}; +{'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0}; const static WCHAR szProcessComponents[] = - {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0}; +{'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0}; const static WCHAR szRegisterTypeLibraries[] = {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r', 'i','e','s',0}; @@ -224,6 +144,209 @@ const static WCHAR szCreateShortcuts[] = {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0}; const static WCHAR szPublishProduct[] = {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0}; +const static WCHAR szWriteIniValues[] = +{'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0}; +const static WCHAR szSelfRegModules[] = +{'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0}; +const static WCHAR szPublishFeatures[] = +{'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0}; +const static WCHAR szRegisterProduct[] = +{'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0}; +const static WCHAR szInstallExecute[] = +{'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0}; +const static WCHAR szInstallExecuteAgain[] = +{'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0}; +const static WCHAR szInstallFinalize[] = +{'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0}; +const static WCHAR szForceReboot[] = +{'F','o','r','c','e','R','e','b','o','o','t',0}; +const static WCHAR szResolveSource[] = +{'R','e','s','o','l','v','e','S','o','u','r','c','e',0}; +const static WCHAR szAppSearch[] = +{'A','p','p','S','e','a','r','c','h',0}; +const static WCHAR szAllocateRegistrySpace[] = +{'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0}; +const static WCHAR szBindImage[] = +{'B','i','n','d','I','m','a','g','e',0}; +const static WCHAR szCCPSearch[] = +{'C','C','P','S','e','a','r','c','h',0}; +const static WCHAR szDeleteServices[] = +{'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0}; +const static WCHAR szDisableRollback[] = +{'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0}; +const static WCHAR szExecuteAction[] = +{'E','x','e','c','u','t','e','A','c','t','i','o','n',0}; +const static WCHAR szFindRelatedProducts[] = +{'F','i','n','d','R','e','l','a','t','e','d','P','r','o','d','u','c','t','s',0}; +const static WCHAR szInstallAdminPackage[] = +{'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0}; +const static WCHAR szInstallSFPCatalogFile[] = +{'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0}; +const static WCHAR szIsolateComponents[] = +{'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0}; +const static WCHAR szMigrateFeatureStates[] = +{'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0}; +const static WCHAR szMoveFiles[] = +{'M','o','v','e','F','i','l','e','s',0}; +const static WCHAR szMsiPublishAssemblies[] = +{'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0}; +const static WCHAR szMsiUnpublishAssemblies[] = +{'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0}; +const static WCHAR szInstallODBC[] = +{'I','n','s','t','a','l','l','O','D','B','C',0}; +const static WCHAR szInstallServices[] = +{'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0}; +const static WCHAR szPatchFiles[] = +{'P','a','t','c','h','F','i','l','e','s',0}; +const static WCHAR szPublishComponents[] = +{'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0}; +const static WCHAR szRegisterComPlus[] = +{'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0}; +const static WCHAR szRegisterExtensionInfo[] = +{'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0}; +const static WCHAR szRegisterFonts[] = +{'R','e','g','i','s','t','e','r','F','o','n','t','s',0}; +const static WCHAR szRegisterMIMEInfo[] = +{'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0}; +const static WCHAR szRegisterUser[] = +{'R','e','g','i','s','t','e','r','U','s','e','r',0}; +const static WCHAR szRemoveDuplicateFiles[] = +{'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e','F','i','l','e','s',0}; +const static WCHAR szRemoveEnvironmentStrings[] = +{'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0}; +const static WCHAR szRemoveExistingProducts[] = +{'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0}; +const static WCHAR szRemoveFiles[] = +{'R','e','m','o','v','e','F','i','l','e','s',0}; +const static WCHAR szRemoveFolders[] = +{'R','e','m','o','v','e','F','o','l','d','e','r','s',0}; +const static WCHAR szRemoveIniValues[] = +{'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0}; +const static WCHAR szRemoveODBC[] = +{'R','e','m','o','v','e','O','D','B','C',0}; +const static WCHAR szRemoveRegistryValues[] = +{'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0}; +const static WCHAR szRemoveShortcuts[] = +{'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0}; +const static WCHAR szRMCCPSearch[] = +{'R','M','C','C','P','S','e','a','r','c','h',0}; +const static WCHAR szScheduleReboot[] = +{'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0}; +const static WCHAR szSelfUnregModules[] = +{'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0}; +const static WCHAR szSetODBCFolders[] = +{'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0}; +const static WCHAR szStartServices[] = +{'S','t','a','r','t','S','e','r','v','i','c','e','s',0}; +const static WCHAR szStopServices[] = +{'S','t','o','p','S','e','r','v','i','c','e','s',0}; +const static WCHAR szUnpublishComponents[] = +{'U','n','p','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0}; +const static WCHAR szUnpublishFeatures[] = +{'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0}; +const static WCHAR szUnregisterClassInfo[] = +{'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0}; +const static WCHAR szUnregisterComPlus[] = +{'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0}; +const static WCHAR szUnregisterExtensionInfo[] = +{'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0}; +const static WCHAR szUnregisterFonts[] = +{'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0}; +const static WCHAR szUnregisterMIMEInfo[] = +{'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0}; +const static WCHAR szUnregisterProgIdInfo[] = +{'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0}; +const static WCHAR szUnregisterTypeLibraries[] = +{'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0}; +const static WCHAR szValidateProductID[] = +{'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0}; +const static WCHAR szWriteEnvironmentStrings[] = +{'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0}; + +struct _actions { + LPCWSTR action; + STANDARDACTIONHANDLER handler; +}; + +struct _actions StandardActions[] = { + { szAllocateRegistrySpace, NULL}, + { szAppSearch, ACTION_AppSearch }, + { szBindImage, NULL}, + { szCCPSearch, NULL}, + { szCostFinalize, ACTION_CostFinalize }, + { szCostInitialize, ACTION_CostInitialize }, + { szCreateFolders, ACTION_CreateFolders }, + { szCreateShortcuts, ACTION_CreateShortcuts }, + { szDeleteServices, NULL}, + { szDisableRollback, NULL}, + { szDuplicateFiles, ACTION_DuplicateFiles}, + { szExecuteAction, NULL}, + { szFileCost, ACTION_FileCost }, + { szFindRelatedProducts, NULL}, + { szForceReboot, ACTION_ForceReboot }, + { szInstallAdminPackage, NULL}, + { szInstallExecute, ACTION_InstallExecute }, + { szInstallExecuteAgain, ACTION_InstallExecute }, + { szInstallFiles, ACTION_InstallFiles}, + { szInstallFinalize, ACTION_InstallFinalize }, + { szInstallInitialize, ACTION_InstallInitialize }, + { szInstallSFPCatalogFile, NULL}, + { szInstallValidate, ACTION_InstallValidate }, + { szIsolateComponents, NULL}, + { szLaunchConditions, ACTION_LaunchConditions }, + { szMigrateFeatureStates, NULL}, + { szMoveFiles, NULL}, + { szMsiPublishAssemblies, NULL}, + { szMsiUnpublishAssemblies, NULL}, + { szInstallODBC, NULL}, + { szInstallServices, NULL}, + { szPatchFiles, NULL}, + { szProcessComponents, ACTION_ProcessComponents }, + { szPublishComponents, NULL}, + { szPublishFeatures, ACTION_PublishFeatures }, + { szPublishProduct, ACTION_PublishProduct }, + { szRegisterClassInfo, ACTION_RegisterClassInfo }, + { szRegisterComPlus, NULL}, + { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo }, + { szRegisterFonts, NULL}, + { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo }, + { szRegisterProduct, ACTION_RegisterProduct }, + { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo }, + { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries }, + { szRegisterUser, ACTION_RegisterUser}, + { szRemoveDuplicateFiles, NULL}, + { szRemoveEnvironmentStrings, NULL}, + { szRemoveExistingProducts, NULL}, + { szRemoveFiles, NULL}, + { szRemoveFolders, NULL}, + { szRemoveIniValues, NULL}, + { szRemoveODBC, NULL}, + { szRemoveRegistryValues, NULL}, + { szRemoveShortcuts, NULL}, + { szResolveSource, ACTION_ResolveSource}, + { szRMCCPSearch, NULL}, + { szScheduleReboot, NULL}, + { szSelfRegModules, ACTION_SelfRegModules }, + { szSelfUnregModules, NULL}, + { szSetODBCFolders, NULL}, + { szStartServices, NULL}, + { szStopServices, NULL}, + { szUnpublishComponents, NULL}, + { szUnpublishFeatures, NULL}, + { szUnregisterClassInfo, NULL}, + { szUnregisterComPlus, NULL}, + { szUnregisterExtensionInfo, NULL}, + { szUnregisterFonts, NULL}, + { szUnregisterMIMEInfo, NULL}, + { szUnregisterProgIdInfo, NULL}, + { szUnregisterTypeLibraries, NULL}, + { szValidateProductID, NULL}, + { szWriteEnvironmentStrings, NULL}, + { szWriteIniValues, ACTION_WriteIniValues }, + { szWriteRegistryValues, ACTION_WriteRegistryValues}, + { NULL, NULL}, +}; + /******************************************************** * helper functions to get around current HACKS and such @@ -235,41 +358,7 @@ inline static void reduce_to_longfilename(WCHAR* filename) memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR)); } -inline static char *strdupWtoA( const WCHAR *str ) -{ - char *ret = NULL; - if (str) - { - DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL -); - if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) - WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL ); - } - return ret; -} - -inline static WCHAR *strdupAtoW( const char *str ) -{ - WCHAR *ret = NULL; - if (str) - { - DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 ); - if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) - MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len ); - } - return ret; -} - -static LPWSTR dupstrW(LPCWSTR src) -{ - LPWSTR dest; - if (!src) return NULL; - dest = HeapAlloc(GetProcessHeap(), 0, (strlenW(src)+1)*sizeof(WCHAR)); - strcpyW(dest, src); - return dest; -} - -inline static WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index) +WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index) { UINT rc; DWORD sz; @@ -301,8 +390,7 @@ inline static WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index) return ret; } -inline static LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, - UINT* rc) +LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc) { DWORD sz = 0; LPWSTR str; @@ -328,7 +416,7 @@ inline static LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, return str; } -inline static int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component ) +int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component ) { int rc = -1; DWORD i; @@ -344,7 +432,7 @@ inline static int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component ) return rc; } -inline static int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature ) +int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature ) { int rc = -1; DWORD i; @@ -360,7 +448,7 @@ inline static int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature ) return rc; } -inline static int get_loaded_file(MSIPACKAGE* package, LPCWSTR file) +int get_loaded_file(MSIPACKAGE* package, LPCWSTR file) { int rc = -1; DWORD i; @@ -376,8 +464,7 @@ inline static int get_loaded_file(MSIPACKAGE* package, LPCWSTR file) return rc; } - -static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path) +int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path) { DWORD i; DWORD index; @@ -408,7 +495,7 @@ static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path) return 0; } -void ACTION_remove_tracked_tempfiles(MSIPACKAGE* package) +static void remove_tracked_tempfiles(MSIPACKAGE* package) { DWORD i; @@ -426,13 +513,43 @@ void ACTION_remove_tracked_tempfiles(MSIPACKAGE* package) } } +/* 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 */ -extern void ACTION_free_package_structures( MSIPACKAGE* package) +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); @@ -465,54 +582,16 @@ extern void ACTION_free_package_structures( MSIPACKAGE* package) if (package->files && package->loaded_files > 0) HeapFree(GetProcessHeap(),0,package->files); -} -static UINT ACTION_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) -{ - LPWSTR szQuery; - LPCWSTR p; - UINT sz, rc; - va_list va; + for (i = 0; i < package->DeferredActionCount; i++) + HeapFree(GetProcessHeap(),0,package->DeferredAction[i]); + HeapFree(GetProcessHeap(),0,package->DeferredAction); - /* figure out how much space we need to allocate */ - va_start(va, fmt); - sz = strlenW(fmt) + 1; - p = fmt; - while (*p) - { - p = strchrW(p, '%'); - if (!p) - break; - p++; - switch (*p) - { - case 's': /* a string */ - sz += strlenW(va_arg(va,LPCWSTR)); - break; - case 'd': - case 'i': /* an integer -2147483648 seems to be longest */ - sz += 3*sizeof(int); - (void)va_arg(va,int); - break; - case '%': /* a single % - leave it alone */ - break; - default: - FIXME("Unhandled character type %c\n",*p); - } - p++; - } - va_end(va); + for (i = 0; i < package->CommitActionCount; i++) + HeapFree(GetProcessHeap(),0,package->CommitAction[i]); + HeapFree(GetProcessHeap(),0,package->CommitAction); - /* construct the string */ - szQuery = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR)); - va_start(va, fmt); - vsnprintfW(szQuery, sz, fmt, va); - va_end(va); - - /* perform the query */ - rc = MSI_DatabaseOpenViewW(db, szQuery, view); - HeapFree(GetProcessHeap(), 0, szQuery); - return rc; + HeapFree(GetProcessHeap(),0,package->PackagePath); } static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d ) @@ -526,6 +605,8 @@ static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d ) MSI_RecordSetInteger(row,4,d); MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row); msiobj_release(&row->hdr); + + msi_dialog_check_messages(package->dialog, NULL); } static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record) @@ -538,11 +619,11 @@ static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * recor UINT rc; MSIQUERY * view; MSIRECORD * row = 0; - LPWSTR ptr; + DWORD size; if (!package->LastAction || strcmpW(package->LastAction,action)) { - rc = ACTION_OpenQuery(package->db, &view, Query_t, action); + rc = MSI_OpenQuery(package->db, &view, Query_t, action); if (rc != ERROR_SUCCESS) return; @@ -568,12 +649,10 @@ static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * recor } /* update the cached actionformat */ - if (package->ActionFormat) - HeapFree(GetProcessHeap(),0,package->ActionFormat); + HeapFree(GetProcessHeap(),0,package->ActionFormat); package->ActionFormat = load_dynamic_stringW(row,3); - if (package->LastAction) - HeapFree(GetProcessHeap(),0,package->LastAction); + HeapFree(GetProcessHeap(),0,package->LastAction); package->LastAction = dupstrW(action); msiobj_release(&row->hdr); @@ -581,38 +660,9 @@ static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * recor msiobj_release(&view->hdr); } - message[0]=0; - ptr = package->ActionFormat; - while (*ptr) - { - LPWSTR ptr2; - LPWSTR data=NULL; - WCHAR tmp[1023]; - INT field; - - ptr2 = strchrW(ptr,'['); - if (ptr2) - { - strncpyW(tmp,ptr,ptr2-ptr); - tmp[ptr2-ptr]=0; - strcatW(message,tmp); - ptr2++; - field = atoiW(ptr2); - data = load_dynamic_stringW(record,field); - if (data) - { - strcatW(message,data); - HeapFree(GetProcessHeap(),0,data); - } - ptr=strchrW(ptr2,']'); - ptr++; - } - else - { - strcatW(message,ptr); - break; - } - } + MSI_RecordSetStringW(record,0,package->ActionFormat); + size = 1024; + MSI_FormatRecordW(package,record,message,&size); row = MSI_CreateRecord(1); MSI_RecordSetStringW(row,1,message); @@ -641,7 +691,7 @@ static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action) GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100); - rc = ACTION_OpenQuery(package->db, &view, Query_t, action); + rc = MSI_OpenQuery(package->db, &view, Query_t, action); if (rc != ERROR_SUCCESS) return; rc = MSI_ViewExecute(view, 0); @@ -765,11 +815,16 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath, WCHAR buffer[10]; UINT rc; static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0}; + static const WCHAR szAction[] = {'A','C','T','I','O','N',0}; + static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0}; + + MSI_SetPropertyW(package, szAction, szInstall); if (szPackagePath) { LPWSTR p, check, path; + package->PackagePath = dupstrW(szPackagePath); path = dupstrW(szPackagePath); p = strrchrW(path,'\\'); if (p) @@ -777,6 +832,13 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath, p++; *p=0; } + else + { + HeapFree(GetProcessHeap(),0,path); + path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR)); + GetCurrentDirectoryW(MAX_PATH,path); + strcatW(path,cszbs); + } check = load_dynamic_property(package, cszSourceDir,NULL); if (!check) @@ -858,12 +920,25 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath, } else rc = ACTION_ProcessExecSequence(package,FALSE); + + if (rc == -1) + { + /* install was halted but should be considered a success */ + rc = ERROR_SUCCESS; + } /* process the ending type action */ if (rc == ERROR_SUCCESS) - rc = ACTION_PerformActionSequence(package,-1); + ACTION_PerformActionSequence(package,-1); + else if (rc == ERROR_INSTALL_USEREXIT) + ACTION_PerformActionSequence(package,-2); else if (rc == ERROR_FUNCTION_FAILED) - rc = ACTION_PerformActionSequence(package,-3); + ACTION_PerformActionSequence(package,-3); + else if (rc == ERROR_INSTALL_SUSPEND) + ACTION_PerformActionSequence(package,-4); + + /* finish up running custom actions */ + ACTION_FinishCustomActions(package); return rc; } @@ -883,7 +958,7 @@ static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq) 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', '=',' ','%','i',0}; - rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, seq); + rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq); if (rc == ERROR_SUCCESS) { @@ -994,7 +1069,7 @@ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran) msiobj_release(&view->hdr); } - rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, seq); + rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq); if (rc == ERROR_SUCCESS) { rc = MSI_ViewExecute(view, 0); @@ -1143,7 +1218,7 @@ static UINT ACTION_ProcessUISequence(MSIPACKAGE *package) break; } - rc = ACTION_PerformAction(package,buffer); + rc = ACTION_PerformUIAction(package,buffer); if (rc == ERROR_FUNCTION_NOT_CALLED) rc = ERROR_SUCCESS; @@ -1169,11 +1244,71 @@ end: /******************************************************** * ACTION helper functions and functions that perform the actions *******************************************************/ +BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, UINT* rc) +{ + BOOL ret = FALSE; + + int i; + i = 0; + while (StandardActions[i].action != NULL) + { + if (strcmpW(StandardActions[i].action, action)==0) + { + ui_actioninfo(package, action, TRUE, 0); + ui_actionstart(package, action); + if (StandardActions[i].handler) + { + *rc = StandardActions[i].handler(package); + } + else + { + FIXME("UNHANDLED Standard Action %s\n",debugstr_w(action)); + *rc = ERROR_SUCCESS; + } + ui_actioninfo(package, action, FALSE, *rc); + ret = TRUE; + break; + } + i++; + } + return ret; +} + +BOOL ACTION_HandleDialogBox(MSIPACKAGE *package, LPCWSTR dialog, UINT* rc) +{ + BOOL ret = FALSE; + + /* + * for the UI when we get that working + * + if (ACTION_DialogBox(package,dialog) == ERROR_SUCCESS) + { + *rc = package->CurrentInstallState; + ret = TRUE; + } + */ + return ret; +} + +BOOL ACTION_HandleCustomAction(MSIPACKAGE* package, LPCWSTR action, UINT* rc) +{ + BOOL ret=FALSE; + UINT arc; + + arc = ACTION_CustomAction(package,action,FALSE); + + if (arc != ERROR_CALL_NOT_IMPLEMENTED) + { + *rc = arc; + ret = TRUE; + } + return ret; +} /* - * Alot of actions are really important even if they don't do anything - * explicit.. Lots of properties are set at the beginning of the installation - * CostFinalize does a bunch of work to translated the directories and such + * A lot of actions are really important even if they don't do anything + * explicit... Lots of properties are set at the beginning of the installation + * CostFinalize does a bunch of work to translate the directories and such * * But until I get write access to the database that is hard, so I am going to * hack it to see if I can get something to run. @@ -1181,526 +1316,52 @@ end: UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action) { UINT rc = ERROR_SUCCESS; + BOOL handled; TRACE("Performing action (%s)\n",debugstr_w(action)); - ui_actioninfo(package, action, TRUE, 0); - ui_actionstart(package, action); - /* pre install, setup and configuration block */ - if (strcmpW(action,szLaunchConditions)==0) - rc = ACTION_LaunchConditions(package); - else if (strcmpW(action,szCostInitialize)==0) - rc = ACTION_CostInitialize(package); - else if (strcmpW(action,szFileCost)==0) - rc = ACTION_FileCost(package); - else if (strcmpW(action,szCostFinalize)==0) - rc = ACTION_CostFinalize(package); - else if (strcmpW(action,szInstallValidate)==0) - rc = ACTION_InstallValidate(package); + handled = ACTION_HandleStandardAction(package, action, &rc); - /* install block */ - else if (strcmpW(action,szProcessComponents)==0) - rc = ACTION_ProcessComponents(package); - else if (strcmpW(action,szInstallInitialize)==0) - rc = ACTION_InstallInitialize(package); - else if (strcmpW(action,szCreateFolders)==0) - rc = ACTION_CreateFolders(package); - else if (strcmpW(action,szInstallFiles)==0) - rc = ACTION_InstallFiles(package); - else if (strcmpW(action,szDuplicateFiles)==0) - rc = ACTION_DuplicateFiles(package); - else if (strcmpW(action,szWriteRegistryValues)==0) - rc = ACTION_WriteRegistryValues(package); - else if (strcmpW(action,szRegisterTypeLibraries)==0) - rc = ACTION_RegisterTypeLibraries(package); - else if (strcmpW(action,szRegisterClassInfo)==0) - rc = ACTION_RegisterClassInfo(package); - else if (strcmpW(action,szRegisterProgIdInfo)==0) - rc = ACTION_RegisterProgIdInfo(package); - else if (strcmpW(action,szCreateShortcuts)==0) - rc = ACTION_CreateShortcuts(package); - else if (strcmpW(action,szPublishProduct)==0) - rc = ACTION_PublishProduct(package); + if (!handled) + handled = ACTION_HandleCustomAction(package, action, &rc); - /* - Called during iTunes but unimplemented and seem important - - ResolveSource (sets SourceDir) - RegisterProduct - InstallFinalize - */ - else if ((rc = ACTION_CustomAction(package,action)) != ERROR_SUCCESS) - { + if (!handled) + { FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action)); rc = ERROR_FUNCTION_NOT_CALLED; - } + } - ui_actioninfo(package, action, FALSE, rc); + package->CurrentInstallState = rc; return rc; } - -static UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action) +UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action) { UINT rc = ERROR_SUCCESS; - MSIQUERY * view; - MSIRECORD * row = 0; - static const WCHAR ExecSeqQuery[] = - {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','C','u','s','t','o' - ,'m','A','c','t','i','o','n',' ','w','h','e','r','e',' ','`','A','c','t','i' - ,'o','n','`',' ','=',' ','`','%','s','`',0}; - UINT type; - LPWSTR source; - LPWSTR target; - WCHAR *deformated=NULL; + BOOL handled = FALSE; - rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, action); - if (rc != ERROR_SUCCESS) - return rc; + TRACE("Performing action (%s)\n",debugstr_w(action)); - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) + handled = ACTION_HandleStandardAction(package, action, &rc); + + if (!handled) + handled = ACTION_HandleCustomAction(package, action, &rc); + + if (!handled) + handled = ACTION_HandleDialogBox(package, action, &rc); + + msi_dialog_check_messages( package->dialog, NULL ); + + if (!handled) { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; + FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action)); + rc = ERROR_FUNCTION_NOT_CALLED; } - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - - type = MSI_RecordGetInteger(row,2); - - source = load_dynamic_stringW(row,3); - target = load_dynamic_stringW(row,4); - - TRACE("Handling custom action %s (%x %s %s)\n",debugstr_w(action),type, - debugstr_w(source), debugstr_w(target)); - - /* we are ignoring ALOT of flags and important synchronization stuff */ - switch (type & CUSTOM_ACTION_TYPE_MASK) - { - case 1: /* DLL file stored in a Binary table stream */ - rc = HANDLE_CustomType1(package,source,target,type); - break; - case 2: /* EXE file stored in a Binary table strem */ - rc = HANDLE_CustomType2(package,source,target,type); - break; - case 18: /*EXE file installed with package */ - rc = HANDLE_CustomType18(package,source,target,type); - break; - case 50: /*EXE file specified by a property value */ - rc = HANDLE_CustomType50(package,source,target,type); - break; - case 34: /*EXE to be run in specified directory */ - rc = HANDLE_CustomType34(package,source,target,type); - break; - case 35: /* Directory set with formatted text. */ - deformat_string(package,target,&deformated); - MSI_SetTargetPathW(package, source, deformated); - HeapFree(GetProcessHeap(),0,deformated); - break; - case 51: /* Property set with formatted text. */ - deformat_string(package,target,&deformated); - rc = MSI_SetPropertyW(package,source,deformated); - HeapFree(GetProcessHeap(),0,deformated); - break; - default: - FIXME("UNHANDLED ACTION TYPE %i (%s %s)\n", - type & CUSTOM_ACTION_TYPE_MASK, debugstr_w(source), - debugstr_w(target)); - } - - HeapFree(GetProcessHeap(),0,source); - HeapFree(GetProcessHeap(),0,target); - msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); + package->CurrentInstallState = rc; return rc; } -static UINT store_binary_to_temp(MSIPACKAGE *package, const LPWSTR source, - LPWSTR tmp_file) -{ - DWORD sz=MAX_PATH; - - if (MSI_GetPropertyW(package, cszTempFolder, tmp_file, &sz) - != ERROR_SUCCESS) - GetTempPathW(MAX_PATH,tmp_file); - - strcatW(tmp_file,source); - - if (GetFileAttributesW(tmp_file) != INVALID_FILE_ATTRIBUTES) - { - TRACE("File already exists\n"); - return ERROR_SUCCESS; - } - else - { - /* 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',' ','B','i' -,'n','a','r','y',' ','w','h','e','r','e',' ','N','a','m','e','=','`','%','s','`',0}; - HANDLE the_file; - CHAR buffer[1024]; - - if (track_tempfile(package, source, 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 = ACTION_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; - } - - 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(tmp_file); - break; - } - WriteFile(the_file,buffer,sz,&write,NULL); - } while (sz == 1024); - - CloseHandle(the_file); - - msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); - } - - return ERROR_SUCCESS; -} - -typedef UINT __stdcall CustomEntry(MSIHANDLE); -typedef struct -{ - MSIPACKAGE *package; - WCHAR *target; - WCHAR *source; -} thread_struct; - -static DWORD WINAPI ACTION_CallDllFunction(thread_struct *stuff) -{ - HANDLE hModule; - LPSTR proc; - CustomEntry *fn; - - TRACE("calling function (%s, %s) \n", debugstr_w(stuff->source), - debugstr_w(stuff->target)); - - hModule = LoadLibraryW(stuff->source); - if (hModule) - { - proc = strdupWtoA( stuff->target ); - fn = (CustomEntry*)GetProcAddress(hModule,proc); - if (fn) - { - MSIHANDLE hPackage; - MSIPACKAGE *package = stuff->package; - - TRACE("Calling function %s\n", proc); - hPackage = msiobj_findhandle( &package->hdr ); - if (hPackage ) - { - fn(hPackage); - msiobj_release( &package->hdr ); - } - else - ERR("Handle for object %p not found\n", package ); - } - else - ERR("Cannot load functon\n"); - - HeapFree(GetProcessHeap(),0,proc); - FreeLibrary(hModule); - } - else - ERR("Unable to load library\n"); - msiobj_release( &stuff->package->hdr ); - HeapFree(GetProcessHeap(),0,stuff->source); - HeapFree(GetProcessHeap(),0,stuff->target); - HeapFree(GetProcessHeap(), 0, stuff); - return 0; -} - -static DWORD WINAPI DllThread(LPVOID info) -{ - thread_struct *stuff; - DWORD rc = 0; - - TRACE("MSI Thread (0x%lx) started for custom action\n", - GetCurrentThreadId()); - - stuff = (thread_struct*)info; - rc = ACTION_CallDllFunction(stuff); - - TRACE("MSI Thread (0x%lx) finished\n",GetCurrentThreadId()); - /* clse all handles for this thread */ - MsiCloseAllHandles(); - return rc; -} - -static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source, - const LPWSTR target, const INT type) -{ - WCHAR tmp_file[MAX_PATH]; - thread_struct *info; - DWORD ThreadId; - HANDLE ThreadHandle; - - store_binary_to_temp(package, source, tmp_file); - - TRACE("Calling function %s from %s\n",debugstr_w(target), - debugstr_w(tmp_file)); - - if (!strchrW(tmp_file,'.')) - { - static const WCHAR dot[]={'.',0}; - strcatW(tmp_file,dot); - } - - info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) ); - msiobj_addref( &package->hdr ); - info->package = package; - info->target = dupstrW(target); - info->source = dupstrW(tmp_file); - - ThreadHandle = CreateThread(NULL,0,DllThread,(LPVOID)info,0,&ThreadId); - - if (!(type & 0xc0)) - WaitForSingleObject(ThreadHandle,INFINITE); - - CloseHandle(ThreadHandle); - - return ERROR_SUCCESS; -} - -static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source, - const LPWSTR target, const INT type) -{ - WCHAR tmp_file[MAX_PATH]; - STARTUPINFOW si; - PROCESS_INFORMATION info; - BOOL rc; - INT len; - WCHAR *deformated; - WCHAR *cmd; - static const WCHAR spc[] = {' ',0}; - - memset(&si,0,sizeof(STARTUPINFOW)); - - store_binary_to_temp(package, source, tmp_file); - - deformat_string(package,target,&deformated); - - len = strlenW(tmp_file) + strlenW(deformated) + 2; - - cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*len); - - strcpyW(cmd,tmp_file); - strcatW(cmd,spc); - strcatW(cmd,deformated); - - HeapFree(GetProcessHeap(),0,deformated); - - TRACE("executing exe %s \n",debugstr_w(cmd)); - - rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL, - c_collen, &si, &info); - - HeapFree(GetProcessHeap(),0,cmd); - - if ( !rc ) - { - ERR("Unable to execute command\n"); - return ERROR_SUCCESS; - } - - if (!(type & 0xc0)) - WaitForSingleObject(info.hProcess,INFINITE); - - CloseHandle( info.hProcess ); - CloseHandle( info.hThread ); - return ERROR_SUCCESS; -} - -static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source, - const LPWSTR target, const INT type) -{ - STARTUPINFOW si; - PROCESS_INFORMATION info; - BOOL rc; - WCHAR *deformated; - WCHAR *cmd; - INT len; - static const WCHAR spc[] = {' ',0}; - int index; - - memset(&si,0,sizeof(STARTUPINFOW)); - - index = get_loaded_file(package,source); - - len = strlenW(package->files[index].TargetPath); - - deformat_string(package,target,&deformated); - len += strlenW(deformated); - len += 2; - - cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,len * sizeof(WCHAR)); - - strcpyW(cmd, package->files[index].TargetPath); - strcatW(cmd, spc); - strcatW(cmd, deformated); - - HeapFree(GetProcessHeap(),0,deformated); - - TRACE("executing exe %s \n",debugstr_w(cmd)); - - rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL, - c_collen, &si, &info); - - HeapFree(GetProcessHeap(),0,cmd); - - if ( !rc ) - { - ERR("Unable to execute command\n"); - return ERROR_SUCCESS; - } - - if (!(type & 0xc0)) - WaitForSingleObject(info.hProcess,INFINITE); - - CloseHandle( info.hProcess ); - CloseHandle( info.hThread ); - return ERROR_SUCCESS; -} - -static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source, - const LPWSTR target, const INT type) -{ - STARTUPINFOW si; - PROCESS_INFORMATION info; - WCHAR *prop; - BOOL rc; - WCHAR *deformated; - WCHAR *cmd; - INT len; - UINT prc; - static const WCHAR spc[] = {' ',0}; - - memset(&si,0,sizeof(STARTUPINFOW)); - memset(&info,0,sizeof(PROCESS_INFORMATION)); - - prop = load_dynamic_property(package,source,&prc); - if (!prop) - return prc; - - deformat_string(package,target,&deformated); - len = strlenW(prop) + strlenW(deformated) + 2; - cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*len); - - strcpyW(cmd,prop); - strcatW(cmd,spc); - strcatW(cmd,deformated); - - HeapFree(GetProcessHeap(),0,deformated); - - TRACE("executing exe %s \n",debugstr_w(cmd)); - - rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL, - c_collen, &si, &info); - - HeapFree(GetProcessHeap(),0,cmd); - - if ( !rc ) - { - ERR("Unable to execute command\n"); - return ERROR_SUCCESS; - } - - if (!(type & 0xc0)) - WaitForSingleObject(info.hProcess,INFINITE); - - CloseHandle( info.hProcess ); - CloseHandle( info.hThread ); - return ERROR_SUCCESS; -} - -static UINT HANDLE_CustomType34(MSIPACKAGE *package, const LPWSTR source, - const LPWSTR target, const INT type) -{ - LPWSTR filename, deformated; - STARTUPINFOW si; - PROCESS_INFORMATION info; - BOOL rc; - - memset(&si,0,sizeof(STARTUPINFOW)); - - filename = resolve_folder(package, source, FALSE, FALSE, NULL); - - if (!filename) - return ERROR_FUNCTION_FAILED; - - SetCurrentDirectoryW(filename); - HeapFree(GetProcessHeap(),0,filename); - - deformat_string(package,target,&deformated); - - TRACE("executing exe %s \n",debugstr_w(deformated)); - - rc = CreateProcessW(NULL, deformated, NULL, NULL, FALSE, 0, NULL, - c_collen, &si, &info); - HeapFree(GetProcessHeap(),0,deformated); - - if ( !rc ) - { - ERR("Unable to execute command\n"); - return ERROR_SUCCESS; - } - - if (!(type & 0xc0)) - WaitForSingleObject(info.hProcess,INFINITE); - - CloseHandle( info.hProcess ); - CloseHandle( info.hThread ); - return ERROR_SUCCESS; -} - /*********************************************************************** * create_full_pathW * @@ -1945,7 +1606,7 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) /* load feature components */ - rc = ACTION_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); @@ -1981,7 +1642,7 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) continue; } - rc = ACTION_OpenQuery(package->db, &view2, Query2, buffer); + rc = MSI_OpenQuery(package->db, &view2, Query2, buffer); if (rc != ERROR_SUCCESS) { msiobj_release( &row2->hdr ); @@ -2021,13 +1682,13 @@ static void load_feature(MSIPACKAGE* package, MSIRECORD * row) * I am not doing any of the costing functionality yet. * Mostly looking at doing the Component and Feature loading * - * The native MSI does ALOT of modification to tables here. Mostly adding alot - * of temporary columns to the Feature and Component tables. + * The native MSI does A LOT of modification to tables here. Mostly adding + * a lot of temporary columns to the Feature and Component tables. * - * note: native msi also tracks the short filename. but I am only going to + * note: Native msi also tracks the short filename. But I am only going to * track the long ones. Also looking at this directory table * it appears that the directory table does not get the parents - * resolved base on property only based on their entrys in the + * resolved base on property only based on their entries in the * directory table. */ static UINT ACTION_CostInitialize(MSIPACKAGE *package) @@ -2203,7 +1864,7 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) package->folders[index].Directory = dupstrW(dir); - rc = ACTION_OpenQuery(package->db, &view, Query, dir); + rc = MSI_OpenQuery(package->db, &view, Query, dir); if (rc != ERROR_SUCCESS) return -1; @@ -2259,8 +1920,7 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) if (targetdir) { TRACE(" TargetDefault = %s\n",debugstr_w(targetdir)); - if (package->folders[index].TargetDefault) - HeapFree(GetProcessHeap(),0, package->folders[index].TargetDefault); + HeapFree(GetProcessHeap(),0, package->folders[index].TargetDefault); package->folders[index].TargetDefault = dupstrW(targetdir); } @@ -2294,8 +1954,8 @@ static INT load_folder(MSIPACKAGE *package, const WCHAR* dir) } -static LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, - BOOL source, BOOL set_prop, MSIFOLDER **folder) +LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, + BOOL set_prop, MSIFOLDER **folder) { DWORD i; LPWSTR p, path = NULL; @@ -2376,7 +2036,8 @@ static LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, } else if (!source && package->folders[i].Property) { - path = dupstrW(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); @@ -2409,6 +2070,57 @@ static LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, return path; } +/* update compoennt state based on a feature change */ +void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature) +{ + int i; + INSTALLSTATE newstate; + MSIFEATURE *feature; + + i = get_loaded_feature(package,szFeature); + if (i < 0) + return; + + feature = &package->features[i]; + newstate = feature->ActionRequest; + + for( i = 0; i < feature->ComponentCount; i++) + { + MSICOMPONENT* component = &package->components[feature->Components[i]]; + + if (!component->Enabled) + continue; + else + { + if (newstate == INSTALLSTATE_LOCAL) + component->ActionRequest = INSTALLSTATE_LOCAL; + else + { + int j,k; + + component->ActionRequest = newstate; + + /*if any other feature wants is local we need to set it local*/ + for (j = 0; + j < package->loaded_features && + component->ActionRequest != INSTALLSTATE_LOCAL; + j++) + { + for (k = 0; k < package->features[j].ComponentCount; k++) + if ( package->features[j].Components[k] == + feature->Components[i] ) + { + if (package->features[j].ActionRequest == + INSTALLSTATE_LOCAL) + component->ActionRequest = INSTALLSTATE_LOCAL; + break; + } + } + } + } + } +} + static UINT SetFeatureStates(MSIPACKAGE *package) { LPWSTR level; @@ -2541,7 +2253,7 @@ static UINT SetFeatureStates(MSIPACKAGE *package) } /* - * Alot is done in this function aside from just the costing. + * A lot is done in this function aside from just the costing. * The costing needs to be implemented at some point but for now I am going * to focus on the directory building * @@ -2628,8 +2340,7 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) /* calculate target */ p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL); - if (file->TargetPath) - HeapFree(GetProcessHeap(),0,file->TargetPath); + HeapFree(GetProcessHeap(),0,file->TargetPath); TRACE("file %s is named %s\n", debugstr_w(file->File),debugstr_w(file->FileName)); @@ -2661,7 +2372,7 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) WCHAR filever[0x100]; VS_FIXEDFILEINFO *lpVer; - FIXME("Version comparison.. \n"); + TRACE("Version comparison.. \n"); versize = GetFileVersionInfoSizeW(file->TargetPath,&handle); version = HeapAlloc(GetProcessHeap(),0,versize); GetFileVersionInfoW(file->TargetPath, 0, versize, version); @@ -2998,7 +2709,10 @@ static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source, data.package = package; data.cab_path = cab_path; - file_name = strdupWtoA(file); + if (file) + file_name = strdupWtoA(file); + else + file_name = NULL; data.file_name = file_name; ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data); @@ -3036,7 +2750,7 @@ static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence, if (sequence <= last_sequence) { TRACE("Media already ready (%u, %u)\n",sequence,last_sequence); - extract_a_cabinet_file(package, source,path,file); + /*extract_a_cabinet_file(package, source,path,file); */ return ERROR_SUCCESS; } @@ -3095,7 +2809,13 @@ static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence, GetTempPathW(MAX_PATH,path); } } - rc = !extract_a_cabinet_file(package, source,path,file); + 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); @@ -3105,7 +2825,7 @@ static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence, inline static UINT create_component_directory ( MSIPACKAGE* package, INT component) { - UINT rc; + UINT rc = ERROR_SUCCESS; MSIFOLDER *folder; LPWSTR install_path; @@ -3188,8 +2908,7 @@ static UINT ACTION_InstallFiles(MSIPACKAGE *package) comp = &package->components[file->ComponentIndex]; p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL); - if (file->TargetPath) - HeapFree(GetProcessHeap(),0,file->TargetPath); + HeapFree(GetProcessHeap(),0,file->TargetPath); file->TargetPath = build_directory_name(2, p, file->FileName); @@ -3255,7 +2974,7 @@ inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, { if (strcmpW(file_key,package->files[index].File)==0) { - if (package->files[index].State >= 3) + if (package->files[index].State >= 2) { *file_source = dupstrW(package->files[index].TargetPath); return ERROR_SUCCESS; @@ -3324,10 +3043,18 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package) INSTALLSTATE_LOCAL) { TRACE("Skipping copy due to disabled component\n"); + + /* the action taken was the same as the current install state */ + package->components[component_index].Action = + package->components[component_index].Installed; + msiobj_release(&row->hdr); continue; } + package->components[component_index].Action = INSTALLSTATE_LOCAL; + package->components[component_index].Installed = INSTALLSTATE_LOCAL; + sz=0x100; rc = MSI_RecordGetStringW(row,3,file_key,&sz); if (rc != ERROR_SUCCESS) @@ -3343,9 +3070,8 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package) { ERR("Original file unknown %s\n",debugstr_w(file_key)); msiobj_release(&row->hdr); - if (file_source) - HeapFree(GetProcessHeap(),0,file_source); - break; + HeapFree(GetProcessHeap(),0,file_source); + continue; } if (MSI_RecordIsNull(row,4)) @@ -3378,8 +3104,7 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package) { ERR("Unable to get destination folder\n"); msiobj_release(&row->hdr); - if (file_source) - HeapFree(GetProcessHeap(),0,file_source); + HeapFree(GetProcessHeap(),0,file_source); break; } } @@ -3410,7 +3135,7 @@ static UINT ACTION_DuplicateFiles(MSIPACKAGE *package) } -/* OK this value is "interpretted" and then formatted based on the +/* OK this value is "interpreted" and then formatted based on the first few characters */ static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type, DWORD *size) @@ -3466,6 +3191,7 @@ static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type, } else { + static const WCHAR szMulti[] = {'[','~',']',0}; WCHAR *ptr; *type=REG_SZ; @@ -3482,6 +3208,9 @@ static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type, else ptr=value; + if (strstrW(value,szMulti)) + *type = REG_MULTI_SZ; + *size = deformat_string(package, ptr,(LPWSTR*)&data); } return data; @@ -3557,9 +3286,16 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) { TRACE("Skipping write due to disabled component\n"); msiobj_release(&row->hdr); + + package->components[component_index].Action = + package->components[component_index].Installed; + goto next; } + package->components[component_index].Action = INSTALLSTATE_LOCAL; + package->components[component_index].Installed = INSTALLSTATE_LOCAL; + /* null values have special meanings during uninstalls and such */ if(MSI_RecordIsNull(row,5)) @@ -3645,113 +3381,16 @@ static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package) msiobj_release(&row->hdr); RegCloseKey(hkey); next: - if (uikey) - HeapFree(GetProcessHeap(),0,uikey); - if (key) - HeapFree(GetProcessHeap(),0,key); - if (name) - HeapFree(GetProcessHeap(),0,name); - if (component) - HeapFree(GetProcessHeap(),0,component); + 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; } -/* - * This helper function should probably go alot of places - * - * Thinking about this, maybe this should become yet another Bison file - */ -static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data) -{ - WCHAR* mark=NULL; - DWORD size=0; - DWORD chunk=0; - WCHAR key[0x100]; - LPWSTR value; - DWORD sz; - UINT rc; - - if (ptr==NULL) - { - TRACE("Deformatting NULL string\n"); - *data = NULL; - return 0; - } - /* scan for special characters */ - if (!strchrW(ptr,'[') || (strchrW(ptr,'[') && !strchrW(ptr,']'))) - { - /* not formatted */ - size = (strlenW(ptr)+1) * sizeof(WCHAR); - *data = HeapAlloc(GetProcessHeap(),0,size); - strcpyW(*data,ptr); - return size; - } - - /* formatted string located */ - mark = strchrW(ptr,'['); - if (mark != ptr) - { - INT cnt = (mark - ptr); - TRACE("%i (%i) characters before marker\n",cnt,(mark-ptr)); - size = cnt * sizeof(WCHAR); - size += sizeof(WCHAR); - *data = HeapAlloc(GetProcessHeap(),0,size); - strncpyW(*data,ptr,cnt); - (*data)[cnt]=0; - } - else - { - size = sizeof(WCHAR); - *data = HeapAlloc(GetProcessHeap(),0,size); - (*data)[0]=0; - } - mark++; - strcpyW(key,mark); - *strchrW(key,']')=0; - mark = strchrW(mark,']'); - mark++; - TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark)); - sz = 0; - rc = MSI_GetPropertyW(package, key, NULL, &sz); - if ((rc == ERROR_SUCCESS) || (rc == ERROR_MORE_DATA)) - { - LPWSTR newdata; - - sz++; - value = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR)); - MSI_GetPropertyW(package, key, value, &sz); - - chunk = (strlenW(value)+1) * sizeof(WCHAR); - size+=chunk; - newdata = HeapReAlloc(GetProcessHeap(),0,*data,size); - *data = newdata; - strcatW(*data,value); - } - TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark)); - if (*mark!=0) - { - LPWSTR newdata; - chunk = (strlenW(mark)+1) * sizeof(WCHAR); - size+=chunk; - newdata = HeapReAlloc(GetProcessHeap(),0,*data,size); - *data = newdata; - strcatW(*data,mark); - } - (*data)[strlenW(*data)]=0; - TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark)); - - /* recursively do this to clean up */ - mark = HeapAlloc(GetProcessHeap(),0,size); - strcpyW(mark,*data); - TRACE("String at this point %s\n",debugstr_w(mark)); - size = deformat_string(package,mark,data); - HeapFree(GetProcessHeap(),0,mark); - return size; -} - static UINT ACTION_InstallInitialize(MSIPACKAGE *package) { return ERROR_SUCCESS; @@ -3849,9 +3488,12 @@ static UINT ACTION_LaunchConditions(MSIPACKAGE *package) if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE) { + LPWSTR deformated; message = load_dynamic_stringW(row,2); - MessageBoxW(NULL,message,title,MB_OK); + 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); @@ -3872,9 +3514,71 @@ static LPWSTR resolve_keypath( MSIPACKAGE* package, INT LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL); return p; } - if ((cmp->Attributes & 0x4) || (cmp->Attributes & 0x20)) + if (cmp->Attributes & 0x4) { - FIXME("UNIMPLEMENTED keypath as Registry or ODBC Source\n"); + MSIQUERY * view; + MSIRECORD * row = 0; + UINT rc,root,len; + LPWSTR key,deformated,buffer,name,deformated_name; + static const WCHAR ExecSeqQuery[] = { + 's','e','l','e','c','t',' ','*',' ', + 'f','r','o','m',' ','R','e','g','i','s','t','r','y',' ', +'w','h','e','r','e',' ','R','e','g','i','s','t','r','y',' ','=',' ' +,'`','%','s','`',0 }; + static const WCHAR fmt[]={'%','0','2','i',':','%','s',0}; + static const WCHAR fmt2[]={'%','0','2','i',':','%','s','\\','%','s',0}; + + rc = MSI_OpenQuery(package->db,&view,ExecSeqQuery,cmp->KeyPath); + + if (rc!=ERROR_SUCCESS) + return NULL; + + rc = MSI_ViewExecute(view, 0); + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return NULL; + } + + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return NULL; + } + + root = MSI_RecordGetInteger(row,2); + key = load_dynamic_stringW(row, 3); + name = load_dynamic_stringW(row, 4); + deformat_string(package, key , &deformated); + deformat_string(package, name, &deformated_name); + + len = strlenW(deformated) + 5; + if (deformated_name) + len+=strlenW(deformated_name); + + buffer = HeapAlloc(GetProcessHeap(),0, len *sizeof(WCHAR)); + + if (deformated_name) + sprintfW(buffer,fmt2,root,deformated,deformated_name); + else + sprintfW(buffer,fmt,root,deformated); + + HeapFree(GetProcessHeap(),0,key); + HeapFree(GetProcessHeap(),0,deformated); + HeapFree(GetProcessHeap(),0,name); + HeapFree(GetProcessHeap(),0,deformated_name); + msiobj_release(&row->hdr); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + + return buffer; + } + else if (cmp->Attributes & 0x20) + { + FIXME("UNIMPLEMENTED keypath as ODBC Source\n"); return NULL; } else @@ -3901,23 +3605,13 @@ static LPWSTR resolve_keypath( MSIPACKAGE* package, INT static UINT ACTION_ProcessComponents(MSIPACKAGE *package) { LPWSTR productcode; - WCHAR squished_pc[0x100]; - WCHAR squished_cc[0x100]; + WCHAR squished_pc[GUID_SIZE]; + WCHAR squished_cc[GUID_SIZE]; UINT rc; DWORD i; - HKEY hkey=0,hkey2=0,hkey3=0; + HKEY hkey=0,hkey2=0; static const WCHAR szProductCode[]= {'P','r','o','d','u','c','t','C','o','d','e',0}; - static const WCHAR szInstaller[] = { - 'S','o','f','t','w','a','r','e','\\', - 'M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s','\\', - 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'I','n','s','t','a','l','l','e','r',0 }; - static const WCHAR szFeatures[] = { - 'F','e','a','t','u','r','e','s',0 }; - static const WCHAR szComponents[] = { - 'C','o','m','p','o','n','e','n','t','s',0 }; if (!package) return ERROR_INVALID_HANDLE; @@ -3927,57 +3621,11 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) if (!productcode) return rc; - squash_guid(productcode,squished_pc); - rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller,&hkey); - if (rc != ERROR_SUCCESS) - goto end; - - rc = RegCreateKeyW(hkey,szFeatures,&hkey2); - if (rc != ERROR_SUCCESS) - goto end; - - rc = RegCreateKeyW(hkey2,squished_pc,&hkey3); - if (rc != ERROR_SUCCESS) - goto end; - - /* here the guids are base 85 encoded */ - for (i = 0; i < package->loaded_features; i++) - { - LPWSTR data = NULL; - GUID clsid; - int j; - INT size; - - size = package->features[i].ComponentCount*21*sizeof(WCHAR); - data = HeapAlloc(GetProcessHeap(), 0, size); - - data[0] = 0; - for (j = 0; j < package->features[i].ComponentCount; j++) - { - WCHAR buf[21]; - TRACE("From %s\n",debugstr_w(package->components - [package->features[i].Components[j]].ComponentId)); - CLSIDFromString(package->components - [package->features[i].Components[j]].ComponentId, - &clsid); - encode_base85_guid(&clsid,buf); - TRACE("to %s\n",debugstr_w(buf)); - strcatW(data,buf); - } - - size = strlenW(data)*sizeof(WCHAR); - RegSetValueExW(hkey3,package->features[i].Feature,0,REG_SZ, - (LPSTR)data,size); - HeapFree(GetProcessHeap(),0,data); - } - - RegCloseKey(hkey3); - RegCloseKey(hkey2); - - rc = RegCreateKeyW(hkey,szComponents,&hkey2); + rc = MSIREG_OpenComponents(&hkey); if (rc != ERROR_SUCCESS) goto end; + squash_guid(productcode,squished_pc); ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0); for (i = 0; i < package->loaded_components; i++) { @@ -3988,16 +3636,16 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) MSIRECORD * uirow; squash_guid(package->components[i].ComponentId,squished_cc); - rc = RegCreateKeyW(hkey2,squished_cc,&hkey3); + rc = RegCreateKeyW(hkey,squished_cc,&hkey2); if (rc != ERROR_SUCCESS) continue; keypath = resolve_keypath(package,i); if (keypath) { - RegSetValueExW(hkey3,squished_pc,0,REG_SZ,(LPVOID)keypath, + RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath, (strlenW(keypath)+1)*sizeof(WCHAR)); - RegCloseKey(hkey3); + RegCloseKey(hkey2); /* UI stuff */ uirow = MSI_CreateRecord(3); @@ -4013,7 +3661,6 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) } end: HeapFree(GetProcessHeap(), 0, productcode); - RegCloseKey(hkey2); RegCloseKey(hkey); return rc; } @@ -4077,9 +3724,16 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) { TRACE("Skipping typelib reg due to disabled component\n"); msiobj_release(&row->hdr); + + package->components[index].Action = + package->components[index].Installed; + continue; } + package->components[index].Action = INSTALLSTATE_LOCAL; + package->components[index].Installed = INSTALLSTATE_LOCAL; + index = get_loaded_file(package,package->components[index].KeyPath); if (index < 0) @@ -4145,7 +3799,7 @@ static UINT register_appid(MSIPACKAGE *package, LPCWSTR clsid, LPCWSTR app ) if (!package) return ERROR_INVALID_HANDLE; - rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, clsid); + rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, clsid); if (rc != ERROR_SUCCESS) return rc; @@ -4267,7 +3921,9 @@ static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) 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; @@ -4298,6 +3954,7 @@ static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) WCHAR desc[0x100]; DWORD sz; INT index; + DWORD size; rc = MSI_ViewFetch(view,&row); if (rc != ERROR_SUCCESS) @@ -4321,9 +3978,16 @@ static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) { TRACE("Skipping class reg due to disabled component\n"); msiobj_release(&row->hdr); + + package->components[index].Action = + package->components[index].Installed; + continue; } + package->components[index].Action = INSTALLSTATE_LOCAL; + package->components[index].Installed = INSTALLSTATE_LOCAL; + sz=0x100; MSI_RecordGetStringW(row,1,clsid,&sz); RegCreateKeyW(hkey,clsid,&hkey2); @@ -4345,10 +4009,25 @@ static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) RegCreateKeyW(hkey2,buffer,&hkey3); index = get_loaded_file(package,package->components[index].KeyPath); - RegSetValueExW(hkey3,NULL,0,REG_SZ, - (LPVOID)package->files[index].TargetPath, - (strlenW(package->files[index].TargetPath)+1) - *sizeof(WCHAR)); + + argument = load_dynamic_stringW(row,11); + size = deformat_string(package,argument,&deformated); + if (deformated) + size+=sizeof(WCHAR); + HeapFree(GetProcessHeap(),0,argument); + size += (strlenW(package->files[index].TargetPath))*sizeof(WCHAR); + + argument = (LPWSTR)HeapAlloc(GetProcessHeap(),0,size+sizeof(WCHAR)); + strcpyW(argument,package->files[index].TargetPath); + if (deformated) + { + strcatW(argument,szSpace); + strcatW(argument,deformated); + } + + RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size); + HeapFree(GetProcessHeap(),0,deformated); + HeapFree(GetProcessHeap(),0,argument); RegCloseKey(hkey3); @@ -4376,9 +4055,94 @@ static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) register_appid(package,buffer,desc); } - RegCloseKey(hkey2); - FIXME("Process the rest of the fields >7\n"); + 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); @@ -4392,9 +4156,12 @@ end: return rc; } -static UINT register_progid_base(MSIRECORD * row, LPWSTR clsid) +static UINT register_progid_base(MSIPACKAGE* package, MSIRECORD * row, + LPWSTR clsid) { static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; + static const WCHAR szDefaultIcon[] = { + 'D','e','f','a','u','l','t','I','c','o','n',0}; HKEY hkey,hkey2; WCHAR buffer[0x100]; DWORD sz; @@ -4432,7 +4199,25 @@ static UINT register_progid_base(MSIRECORD * row, LPWSTR clsid) return ERROR_FUNCTION_FAILED; } if (!MSI_RecordIsNull(row,5)) - FIXME ("UNHANDLED icon in Progid\n"); + { + INT index = MSI_RecordGetInteger(row,6); + LPWSTR FileName = load_dynamic_stringW(row,5); + LPWSTR FilePath,IconPath; + static const WCHAR fmt[] = {'%','s',',','%','i',0}; + + RegCreateKeyW(hkey,szDefaultIcon,&hkey2); + build_icon_path(package,FileName,&FilePath); + + IconPath = HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)* + sizeof(WCHAR)); + + sprintfW(IconPath,fmt,FilePath,index); + RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)IconPath, + (strlenW(IconPath)+1) * sizeof(WCHAR)); + HeapFree(GetProcessHeap(),0,FilePath); + HeapFree(GetProcessHeap(),0,FileName); + RegCloseKey(hkey2); + } return ERROR_SUCCESS; } @@ -4452,7 +4237,7 @@ static UINT register_parent_progid(MSIPACKAGE *package, LPCWSTR parent, if (!package) return ERROR_INVALID_HANDLE; - rc = ACTION_OpenQuery(package->db, &view, Query_t, parent); + rc = MSI_OpenQuery(package->db, &view, Query_t, parent); if (rc != ERROR_SUCCESS) return rc; @@ -4485,13 +4270,15 @@ static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid) UINT rc = ERROR_SUCCESS; if (MSI_RecordIsNull(row,2)) - rc = register_progid_base(row,clsid); + 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; @@ -4504,6 +4291,11 @@ static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid) 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) * @@ -4511,9 +4303,6 @@ static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid) RegCloseKey(hkey2); - sz = 0x100; - MSI_RecordGetStringW(row,2,buffer,&sz); - rc = register_parent_progid(package,buffer,clsid); if (!MSI_RecordIsNull(row,4)) { @@ -4524,7 +4313,17 @@ static UINT register_progid(MSIPACKAGE *package, MSIRECORD * row, LPWSTR clsid) } if (!MSI_RecordIsNull(row,5)) - FIXME ("UNHANDLED icon in Progid\n"); + { + 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); } @@ -4681,9 +4480,16 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) { TRACE("Skipping shortcut creation due to disabled component\n"); msiobj_release(&row->hdr); + + package->components[index].Action = + package->components[index].Installed; + continue; } + package->components[index].Action = INSTALLSTATE_LOCAL; + package->components[index].Installed = INSTALLSTATE_LOCAL; + ui_actiondata(package,szCreateShortcuts,row); res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, @@ -4821,20 +4627,33 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) 'S','E','L','E','C','T',' ','*',' ', 'f','r','o','m',' ','I','c','o','n',0}; DWORD sz; + /* for registry stuff */ + LPWSTR productcode; + HKEY hkey=0; + HKEY hukey=0; + static const WCHAR szProductCode[]= + {'P','r','o','d','u','c','t','C','o','d','e',0}; + static const WCHAR szProductName[] = { + 'P','r','o','d','u','c','t','N','a','m','e',0}; + static const WCHAR szPackageCode[] = { + 'P','a','c','k','a','g','e','C','o','d','e',0}; + LPWSTR buffer; + DWORD size; + MSIHANDLE hDb, hSumInfo; if (!package) return ERROR_INVALID_HANDLE; rc = MSI_DatabaseOpenViewW(package->db, Query, &view); if (rc != ERROR_SUCCESS) - return ERROR_SUCCESS; + goto next; rc = MSI_ViewExecute(view, 0); if (rc != ERROR_SUCCESS) { MSI_ViewClose(view); msiobj_release(&view->hdr); - return rc; + goto next; } while (1) @@ -4898,8 +4717,912 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) } MSI_ViewClose(view); msiobj_release(&view->hdr); - return rc; +next: + /* ok there is a lot more done here but i need to figure out what */ + productcode = load_dynamic_property(package,szProductCode,&rc); + if (!productcode) + return rc; + + rc = MSIREG_OpenProductsKey(productcode,&hkey,TRUE); + if (rc != ERROR_SUCCESS) + goto end; + + rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE); + if (rc != ERROR_SUCCESS) + goto end; + + + buffer = load_dynamic_property(package,szProductName,NULL); + size = strlenW(buffer)*sizeof(WCHAR); + RegSetValueExW(hukey,szProductName,0,REG_SZ, (LPSTR)buffer,size); + HeapFree(GetProcessHeap(),0,buffer); + FIXME("Need to write more keys to the user registry\n"); + + hDb= msiobj_findhandle( &package->db->hdr ); + rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo); + if (rc == ERROR_SUCCESS) + { + WCHAR guidbuffer[0x200]; + size = 0x200; + rc = MsiSummaryInfoGetPropertyW(hSumInfo, 8, NULL, NULL, NULL, + guidbuffer, &size); + if (rc == ERROR_SUCCESS) + { + WCHAR squashed[GUID_SIZE]; + /* for now we only care about the first guid */ + LPWSTR ptr = strchrW(guidbuffer,';'); + if (ptr) *ptr = 0; + squash_guid(guidbuffer,squashed); + size = strlenW(guidbuffer)*sizeof(WCHAR); + RegSetValueExW(hukey,szPackageCode,0,REG_SZ, (LPSTR)guidbuffer, + size); + + } + else + { + ERR("Unable to query Revision_Number... \n"); + rc = ERROR_SUCCESS; + } + MsiCloseHandle(hSumInfo); + } + else + { + ERR("Unable to open Summary Information\n"); + rc = ERROR_SUCCESS; + } + +end: + + HeapFree(GetProcessHeap(),0,productcode); + RegCloseKey(hkey); + RegCloseKey(hukey); + + return rc; +} + +static UINT ACTION_WriteIniValues(MSIPACKAGE *package) +{ + UINT rc; + MSIQUERY * view; + MSIRECORD * row = 0; + static const WCHAR ExecSeqQuery[] = {'S','e','l','e','c','t',' ','*', + ' ','f','r','o','m',' ','I','n','i','F','i','l','e',0}; + static const WCHAR szWindowsFolder[] = + {'W','i','n','d','o','w','s','F','o','l','d','e','r',0}; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + { + TRACE("no IniFile table\n"); + return ERROR_SUCCESS; + } + + rc = MSI_ViewExecute(view, 0); + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return rc; + } + + while (1) + { + LPWSTR component,filename,dirproperty,section,key,value,identifier; + LPWSTR deformated_section, deformated_key, deformated_value; + LPWSTR folder, fullname = NULL; + MSIRECORD * uirow; + INT component_index,action; + + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + rc = ERROR_SUCCESS; + break; + } + + component = load_dynamic_stringW(row, 8); + component_index = get_loaded_component(package,component); + HeapFree(GetProcessHeap(),0,component); + + if (package->components[component_index].ActionRequest != + INSTALLSTATE_LOCAL) + { + TRACE("Skipping ini file due to disabled component\n"); + msiobj_release(&row->hdr); + + package->components[component_index].Action = + package->components[component_index].Installed; + + continue; + } + + package->components[component_index].Action = INSTALLSTATE_LOCAL; + package->components[component_index].Installed = INSTALLSTATE_LOCAL; + + identifier = load_dynamic_stringW(row,1); + filename = load_dynamic_stringW(row,2); + dirproperty = load_dynamic_stringW(row,3); + section = load_dynamic_stringW(row,4); + key = load_dynamic_stringW(row,5); + value = load_dynamic_stringW(row,6); + action = MSI_RecordGetInteger(row,7); + + deformat_string(package,section,&deformated_section); + deformat_string(package,key,&deformated_key); + deformat_string(package,value,&deformated_value); + + if (dirproperty) + { + folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL); + if (!folder) + folder = load_dynamic_property(package,dirproperty,NULL); + } + else + folder = load_dynamic_property(package, szWindowsFolder, NULL); + + if (!folder) + { + ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty)); + goto cleanup; + } + + fullname = build_directory_name(3, folder, filename, NULL); + + if (action == 0) + { + TRACE("Adding value %s to section %s in %s\n", + debugstr_w(deformated_key), debugstr_w(deformated_section), + debugstr_w(fullname)); + WritePrivateProfileStringW(deformated_section, deformated_key, + deformated_value, fullname); + } + else if (action == 1) + { + WCHAR returned[10]; + GetPrivateProfileStringW(deformated_section, deformated_key, NULL, + returned, 10, fullname); + if (returned[0] == 0) + { + TRACE("Adding value %s to section %s in %s\n", + debugstr_w(deformated_key), debugstr_w(deformated_section), + debugstr_w(fullname)); + + WritePrivateProfileStringW(deformated_section, deformated_key, + deformated_value, fullname); + } + } + else if (action == 3) + { + FIXME("Append to existing section not yet implemented\n"); + } + + uirow = MSI_CreateRecord(4); + MSI_RecordSetStringW(uirow,1,identifier); + MSI_RecordSetStringW(uirow,2,deformated_section); + MSI_RecordSetStringW(uirow,3,deformated_key); + MSI_RecordSetStringW(uirow,4,deformated_value); + ui_actiondata(package,szWriteIniValues,uirow); + msiobj_release( &uirow->hdr ); +cleanup: + HeapFree(GetProcessHeap(),0,identifier); + HeapFree(GetProcessHeap(),0,fullname); + HeapFree(GetProcessHeap(),0,filename); + HeapFree(GetProcessHeap(),0,key); + HeapFree(GetProcessHeap(),0,value); + HeapFree(GetProcessHeap(),0,section); + HeapFree(GetProcessHeap(),0,dirproperty); + HeapFree(GetProcessHeap(),0,folder); + HeapFree(GetProcessHeap(),0,deformated_key); + HeapFree(GetProcessHeap(),0,deformated_value); + HeapFree(GetProcessHeap(),0,deformated_section); + msiobj_release(&row->hdr); + } + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return rc; +} + +static UINT ACTION_SelfRegModules(MSIPACKAGE *package) +{ + UINT rc; + MSIQUERY * view; + MSIRECORD * row = 0; + static const WCHAR ExecSeqQuery[] = {'S','e','l','e','c','t',' ','*',' ', +'f','r','o','m',' ','S','e','l','f','R','e','g',0}; + + static const WCHAR ExeStr[] = { +'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','s',' ',0}; + STARTUPINFOW si; + PROCESS_INFORMATION info; + BOOL brc; + + memset(&si,0,sizeof(STARTUPINFOW)); + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + { + TRACE("no SelfReg table\n"); + return ERROR_SUCCESS; + } + + rc = MSI_ViewExecute(view, 0); + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return rc; + } + + while (1) + { + LPWSTR filename; + INT index; + DWORD len; + + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + rc = ERROR_SUCCESS; + break; + } + + filename = load_dynamic_stringW(row,1); + index = get_loaded_file(package,filename); + + if (index < 0) + { + ERR("Unable to find file id %s\n",debugstr_w(filename)); + HeapFree(GetProcessHeap(),0,filename); + msiobj_release(&row->hdr); + continue; + } + HeapFree(GetProcessHeap(),0,filename); + + len = strlenW(ExeStr); + len += strlenW(package->files[index].TargetPath); + len +=2; + + filename = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); + strcpyW(filename,ExeStr); + strcatW(filename,package->files[index].TargetPath); + + TRACE("Registering %s\n",debugstr_w(filename)); + brc = CreateProcessW(NULL, filename, NULL, NULL, FALSE, 0, NULL, + c_collen, &si, &info); + + if (brc) + msi_dialog_check_messages(package->dialog, info.hProcess); + + HeapFree(GetProcessHeap(),0,filename); + msiobj_release(&row->hdr); + } + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return rc; +} + +static UINT ACTION_PublishFeatures(MSIPACKAGE *package) +{ + LPWSTR productcode; + UINT rc; + DWORD i; + HKEY hkey=0; + HKEY hukey=0; + static const WCHAR szProductCode[]= + {'P','r','o','d','u','c','t','C','o','d','e',0}; + + if (!package) + return ERROR_INVALID_HANDLE; + + productcode = load_dynamic_property(package,szProductCode,&rc); + if (!productcode) + return rc; + + rc = MSIREG_OpenFeaturesKey(productcode,&hkey,TRUE); + if (rc != ERROR_SUCCESS) + goto end; + + rc = MSIREG_OpenUserFeaturesKey(productcode,&hukey,TRUE); + if (rc != ERROR_SUCCESS) + goto end; + + /* here the guids are base 85 encoded */ + for (i = 0; i < package->loaded_features; i++) + { + LPWSTR data = NULL; + GUID clsid; + int j; + INT size; + + size = package->features[i].ComponentCount*21; + size +=1; + if (package->features[i].Feature_Parent[0]) + size += strlenW(package->features[i].Feature_Parent)+2; + + data = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); + + data[0] = 0; + for (j = 0; j < package->features[i].ComponentCount; j++) + { + WCHAR buf[21]; + memset(buf,0,sizeof(buf)); + TRACE("From %s\n",debugstr_w(package->components + [package->features[i].Components[j]].ComponentId)); + CLSIDFromString(package->components + [package->features[i].Components[j]].ComponentId, + &clsid); + encode_base85_guid(&clsid,buf); + TRACE("to %s\n",debugstr_w(buf)); + strcatW(data,buf); + } + if (package->features[i].Feature_Parent[0]) + { + static const WCHAR sep[] = {'\2',0}; + strcatW(data,sep); + strcatW(data,package->features[i].Feature_Parent); + } + + size = (strlenW(data)+1)*sizeof(WCHAR); + RegSetValueExW(hkey,package->features[i].Feature,0,REG_SZ, + (LPSTR)data,size); + HeapFree(GetProcessHeap(),0,data); + + size = strlenW(package->features[i].Feature_Parent)*sizeof(WCHAR); + RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ, + (LPSTR)package->features[i].Feature_Parent,size); + } + +end: + RegCloseKey(hkey); + RegCloseKey(hukey); + HeapFree(GetProcessHeap(), 0, productcode); + return rc; +} + +static UINT ACTION_RegisterProduct(MSIPACKAGE *package) +{ + static const WCHAR szProductCode[]= + {'P','r','o','d','u','c','t','C','o','d','e',0}; + HKEY hkey=0; + LPWSTR buffer; + LPWSTR productcode; + UINT rc,i; + DWORD size; + static WCHAR szNONE[] = {0}; + static const WCHAR szWindowsInstaler[] = + {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0}; + static const WCHAR szPropKeys[][80] = + { +{'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0}, +{'A','R','P','C','O','N','T','A','C','T'}, +{'A','R','P','C','O','M','M','E','N','T','S',0}, +{'P','r','o','d','u','c','t','N','a','m','e',0}, +{'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0}, +{'A','R','P','H','E','L','P','L','I','N','K',0}, +{'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0}, +{'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0}, +{'S','O','U','R','C','E','D','I','R',0}, +{'M','a','n','u','f','a','c','t','u','r','e','r',0}, +{'A','R','P','R','E','A','D','M','E',0}, +{'A','R','P','S','I','Z','E',0}, +{'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0}, +{'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0}, +{0}, + }; + + static const WCHAR szRegKeys[][80] = + { +{'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0}, +{'C','o','n','t','a','c','t',0}, +{'C','o','m','m','e','n','t','s',0}, +{'D','i','s','p','l','a','y','N','a','m','e',0}, +{'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0}, +{'H','e','l','p','L','i','n','k',0}, +{'H','e','l','p','T','e','l','e','p','h','o','n','e',0}, +{'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0}, +{'I','n','s','t','a','l','l','S','o','u','r','c','e',0}, +{'P','u','b','l','i','s','h','e','r',0}, +{'R','e','a','d','m','e',0}, +{'S','i','z','e',0}, +{'U','R','L','I','n','f','o','A','b','o','u','t',0}, +{'U','R','L','U','p','d','a','t','e','I','n','f','o',0}, +{0}, + }; + + static const WCHAR path[] = { + 'C',':','\\','W','i','n','d','o','w','s','\\', + 'I','n','s','t','a','l','l','e','r','\\'}; + static const WCHAR fmt[] = { + 'C',':','\\','W','i','n','d','o','w','s','\\', + 'I','n','s','t','a','l','l','e','r','\\', + '%','x','.','m','s','i',0}; + static const WCHAR szLocalPackage[]= + {'L','o','c','a','l','P','a','c','k','a','g','e',0}; + WCHAR packagefile[MAX_PATH]; + INT num,start; + + if (!package) + return ERROR_INVALID_HANDLE; + + productcode = load_dynamic_property(package,szProductCode,&rc); + if (!productcode) + return rc; + + rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE); + if (rc != ERROR_SUCCESS) + goto end; + + /* dump all the info i can grab */ + FIXME("Flesh out more information \n"); + + i = 0; + while (szPropKeys[i][0]!=0) + { + buffer = load_dynamic_property(package,szPropKeys[i],&rc); + if (rc != ERROR_SUCCESS) + buffer = szNONE; + size = strlenW(buffer)*sizeof(WCHAR); + RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size); + i++; + } + + rc = 0x1; + size = sizeof(rc); + RegSetValueExW(hkey,szWindowsInstaler,0,REG_DWORD,(LPSTR)&rc,size); + + /* copy the package locally */ + num = GetTickCount() & 0xffff; + if (!num) + num = 1; + start = num; + sprintfW(packagefile,fmt,num); + do + { + HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL, + CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 ); + if (handle != INVALID_HANDLE_VALUE) + { + CloseHandle(handle); + break; + } + if (GetLastError() != ERROR_FILE_EXISTS && + GetLastError() != ERROR_SHARING_VIOLATION) + break; + if (!(++num & 0xffff)) num = 1; + sprintfW(packagefile,fmt,num); + } while (num != start); + + create_full_pathW(path); + TRACE("Copying to local package %s\n",debugstr_w(packagefile)); + CopyFileW(package->PackagePath,packagefile,FALSE); + size = strlenW(packagefile)*sizeof(WCHAR); + RegSetValueExW(hkey,szLocalPackage,0,REG_SZ,(LPSTR)packagefile,size); + +end: + HeapFree(GetProcessHeap(),0,productcode); + RegCloseKey(hkey); + + return ERROR_SUCCESS; +} + +static UINT ACTION_InstallExecute(MSIPACKAGE *package) +{ + int i; + if (!package) + return ERROR_INVALID_HANDLE; + + for (i = 0; i < package->DeferredActionCount; i++) + { + LPWSTR action; + action = package->DeferredAction[i]; + ui_actionstart(package, action); + TRACE("Executing Action (%s)\n",debugstr_w(action)); + ACTION_CustomAction(package,action,TRUE); + HeapFree(GetProcessHeap(),0,package->DeferredAction[i]); + } + HeapFree(GetProcessHeap(),0,package->DeferredAction); + + package->DeferredActionCount = 0; + package->DeferredAction = NULL; + + return ERROR_SUCCESS; +} + +static UINT ACTION_InstallFinalize(MSIPACKAGE *package) +{ + int i; + if (!package) + return ERROR_INVALID_HANDLE; + + /* first do the same as an InstallExecute */ + ACTION_InstallExecute(package); + + /* then handle Commit Actions */ + for (i = 0; i < package->CommitActionCount; i++) + { + LPWSTR action; + action = package->CommitAction[i]; + ui_actionstart(package, action); + TRACE("Executing Commit Action (%s)\n",debugstr_w(action)); + ACTION_CustomAction(package,action,TRUE); + HeapFree(GetProcessHeap(),0,package->CommitAction[i]); + } + HeapFree(GetProcessHeap(),0,package->CommitAction); + + package->CommitActionCount = 0; + package->CommitAction = NULL; + + return ERROR_SUCCESS; +} + +static UINT ACTION_ForceReboot(MSIPACKAGE *package) +{ + static const WCHAR RunOnce[] = { + 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'R','u','n','O','n','c','e'}; + static const WCHAR InstallRunOnce[] = { + 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'I','n','s','t','a','l','l','e','r','\\', + 'R','u','n','O','n','c','e','E','n','t','r','i','e','s'}; + + static const WCHAR msiexec_fmt[] = { + 'C',':','\\','W','i','n','d','o','w','s','\\','S','y','s','t','e','m', + '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ', + '\"','%','s','\"',0}; + static const WCHAR install_fmt[] = { + '/','I',' ','\"','%','s','\"',' ', + 'A','F','T','E','R','R','E','B','O','O','T','=','1',' ', + 'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0}; + WCHAR buffer[256]; + HKEY hkey,hukey; + LPWSTR productcode; + WCHAR squished_pc[100]; + INT rc; + DWORD size; + static const WCHAR szProductCode[]= + {'P','r','o','d','u','c','t','C','o','d','e',0}; + static const WCHAR szLUS[] = { + 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0}; + static const WCHAR szSourceList[] = { + 'S','o','u','r','c','e','L','i','s','t',0}; + static const WCHAR szPackageName[] = { + 'P','a','c','k','a','g','e','N','a','m','e',0}; + + if (!package) + return ERROR_INVALID_HANDLE; + + productcode = load_dynamic_property(package,szProductCode,&rc); + if (!productcode) + return rc; + + squash_guid(productcode,squished_pc); + + RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey); + sprintfW(buffer,msiexec_fmt,squished_pc); + + size = strlenW(buffer)*sizeof(WCHAR); + RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size); + RegCloseKey(hkey); + + TRACE("Reboot command %s\n",debugstr_w(buffer)); + + RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey); + sprintfW(buffer,install_fmt,productcode,squished_pc); + RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size); + RegCloseKey(hkey); + + rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE); + if (rc == ERROR_SUCCESS) + { + HKEY hukey2; + LPWSTR buf; + RegCreateKeyW(hukey, szSourceList, &hukey2); + buf = load_dynamic_property(package,cszSourceDir,NULL); + size = strlenW(buf)*sizeof(WCHAR); + RegSetValueExW(hukey2,szLUS,0,REG_SZ,(LPSTR)buf,size); + HeapFree(GetProcessHeap(),0,buf); + + buf = strrchrW(package->PackagePath,'\\'); + if (buf) + { + buf++; + size = strlenW(buf)*sizeof(WCHAR); + RegSetValueExW(hukey2,szPackageName,0,REG_SZ,(LPSTR)buf,size); + } + + RegCloseKey(hukey2); + } + HeapFree(GetProcessHeap(),0,productcode); + + return ERROR_INSTALL_SUSPEND; +} + +UINT ACTION_ResolveSource(MSIPACKAGE* package) +{ + /* + * we are currently doing what should be done here in the top level Install + * however for Adminastrative and uninstalls this step will be needed + */ + return ERROR_SUCCESS; +} + + +static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package) +{ + UINT rc; + MSIQUERY * view; + MSIRECORD * row = 0; + static const WCHAR ExecSeqQuery[] = { + 'S','E','L','E','C','T',' ','*',' ', + 'f','r','o','m',' ','E','x','t','e','n','s','i','o','n',0}; + static const WCHAR szContentType[] = +{ 'C','o','n','t','e','n','t',' ','T','y','p','e',0 }; + HKEY hkey; + + if (!package) + return ERROR_INVALID_HANDLE; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + { + rc = ERROR_SUCCESS; + goto end; + } + + rc = MSI_ViewExecute(view, 0); + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + msiobj_release(&view->hdr); + goto end; + } + + while (1) + { + WCHAR buffer[0x100]; + WCHAR extension[257]; + LPWSTR exten; + DWORD sz; + INT index; + + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + rc = ERROR_SUCCESS; + break; + } + + sz=0x100; + MSI_RecordGetStringW(row,2,buffer,&sz); + + index = get_loaded_component(package,buffer); + + if (index < 0) + { + msiobj_release(&row->hdr); + continue; + } + + if (package->components[index].ActionRequest != INSTALLSTATE_LOCAL) + { + TRACE("Skipping extension reg due to disabled component\n"); + msiobj_release(&row->hdr); + + package->components[index].Action = + package->components[index].Installed; + + continue; + } + + package->components[index].Action = INSTALLSTATE_LOCAL; + package->components[index].Installed = INSTALLSTATE_LOCAL; + + exten = load_dynamic_stringW(row,1); + extension[0] = '.'; + extension[1] = 0; + strcatW(extension,exten); + HeapFree(GetProcessHeap(),0,exten); + + RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey); + + if (!MSI_RecordIsNull(row,4)) + { + LPWSTR mime = load_dynamic_stringW(row,4); + RegSetValueExW(hkey,szContentType,0,REG_SZ,(LPVOID)mime, + (strlenW(mime)+1)*sizeof(WCHAR)); + HeapFree(GetProcessHeap(),0,mime); + } + + if (!MSI_RecordIsNull(row,3)) + { + static const WCHAR szSN[] = + {'\\','S','h','e','l','l','N','e','w',0}; + HKEY hkey2; + LPWSTR newkey; + LPWSTR progid= load_dynamic_stringW(row,3); + + RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid, + (strlenW(progid)+1)*sizeof(WCHAR)); + + newkey = HeapAlloc(GetProcessHeap(),0, + (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR)); + + strcpyW(newkey,progid); + strcatW(newkey,szSN); + RegCreateKeyW(hkey,newkey,&hkey2); + RegCloseKey(hkey2); + + HeapFree(GetProcessHeap(),0,progid); + HeapFree(GetProcessHeap(),0,newkey); + } + + + RegCloseKey(hkey); + + ui_actiondata(package,szRegisterExtensionInfo,row); + + msiobj_release(&row->hdr); + } + MSI_ViewClose(view); + msiobj_release(&view->hdr); + +end: + return rc; +} + +static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package) +{ + UINT rc; + MSIQUERY * view; + MSIRECORD * row = 0; + static const WCHAR ExecSeqQuery[] = { + 'S','E','L','E','C','T',' ','*',' ', + 'f','r','o','m',' ','M','I','M','E',0}; + static const WCHAR szExten[] = +{ 'E','x','t','e','n','s','i','o','n',0 }; + HKEY hkey; + + if (!package) + return ERROR_INVALID_HANDLE; + + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); + if (rc != ERROR_SUCCESS) + { + rc = ERROR_SUCCESS; + goto end; + } + + rc = MSI_ViewExecute(view, 0); + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + msiobj_release(&view->hdr); + goto end; + } + + while (1) + { + WCHAR extension[257]; + LPWSTR exten; + LPWSTR mime; + static const WCHAR fmt[] = +{'M','I','M','E','\\', +'D','a','t','a','b','a','s','e','\\', +'C','o','n','t','e','n','t',' ','T','y','p','e','\\', +'%','s',0}; + LPWSTR key; + + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + rc = ERROR_SUCCESS; + break; + } + + mime = load_dynamic_stringW(row,1); + exten = load_dynamic_stringW(row,2); + extension[0] = '.'; + extension[1] = 0; + strcatW(extension,exten); + HeapFree(GetProcessHeap(),0,exten); + + key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) * + sizeof(WCHAR)); + sprintfW(key,fmt,mime); + RegCreateKeyW(HKEY_CLASSES_ROOT,key,&hkey); + RegSetValueExW(hkey,szExten,0,REG_SZ,(LPVOID)extension, + (strlenW(extension)+1)*sizeof(WCHAR)); + + HeapFree(GetProcessHeap(),0,mime); + HeapFree(GetProcessHeap(),0,key); + + if (!MSI_RecordIsNull(row,3)) + { + FIXME("Handle non null for field 3\n"); + } + + RegCloseKey(hkey); + + ui_actiondata(package,szRegisterMIMEInfo,row); + + msiobj_release(&row->hdr); + } + MSI_ViewClose(view); + msiobj_release(&view->hdr); + +end: + return rc; +} + +static UINT ACTION_RegisterUser(MSIPACKAGE *package) +{ + static const WCHAR szProductCode[]= + {'P','r','o','d','u','c','t','C','o','d','e',0}; + static const WCHAR szProductID[]= + {'P','r','o','d','u','c','t','I','D',0}; + HKEY hkey=0; + LPWSTR buffer; + LPWSTR productcode; + LPWSTR productid; + UINT rc,i; + DWORD size; + + static const WCHAR szPropKeys[][80] = + { +{'P','r','o','d','u','c','t','I','D',0}, +{'U','S','E','R','N','A','M','E',0}, +{'C','O','M','P','A','N','Y','N','A','M','E',0}, +{0}, + }; + + static const WCHAR szRegKeys[][80] = + { +{'P','r','o','d','u','c','t','I','D',0}, +{'R','e','g','O','w','n','e','r',0}, +{'R','e','g','C','o','m','p','a','n','y',0}, +{0}, + }; + + if (!package) + return ERROR_INVALID_HANDLE; + + productid = load_dynamic_property(package,szProductID,&rc); + if (!productid) + return ERROR_SUCCESS; + + productcode = load_dynamic_property(package,szProductCode,&rc); + if (!productcode) + return rc; + + rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE); + if (rc != ERROR_SUCCESS) + goto end; + + i = 0; + while (szPropKeys[i][0]!=0) + { + buffer = load_dynamic_property(package,szPropKeys[i],&rc); + if (rc == ERROR_SUCCESS) + { + size = strlenW(buffer)*sizeof(WCHAR); + RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size); + } + i++; + } + +end: + HeapFree(GetProcessHeap(),0,productcode); + HeapFree(GetProcessHeap(),0,productid); + RegCloseKey(hkey); + + return ERROR_SUCCESS; } /* Msi functions that seem appropriate here */ @@ -5108,7 +5831,6 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, DWORD i; LPWSTR path = NULL; LPWSTR path2 = NULL; - INT len; MSIFOLDER *folder; TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath)); @@ -5127,22 +5849,10 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, if (!path) return ERROR_INVALID_PARAMETER; - if (folder->Property) - HeapFree(GetProcessHeap(),0,folder->Property); + HeapFree(GetProcessHeap(),0,folder->Property); + folder->Property = build_directory_name(2, szFolderPath, NULL); - len = strlenW(szFolderPath); - - if (szFolderPath[len-1]!='\\') - { - len +=2; - folder->Property = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); - strcpyW(folder->Property,szFolderPath); - strcatW(folder->Property,cszbs); - } - else - folder->Property = dupstrW(szFolderPath); - - if (strcmpiW(path, szFolderPath) == 0) + if (strcmpiW(path, folder->Property) == 0) { /* * Resolved Target has not really changed, so just @@ -5157,8 +5867,7 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, { for (i = 0; i < package->loaded_folders; i++) { - if (package->folders[i].ResolvedTarget) - HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget); + HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget); package->folders[i].ResolvedTarget=NULL; } @@ -5205,8 +5914,8 @@ UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, * 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 supressed - * MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is supressed + * 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 @@ -5267,6 +5976,7 @@ UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature, return ERROR_UNKNOWN_FEATURE; package->features[index].ActionRequest= iState; + ACTION_UpdateComponentStates(package,szFeature); return ERROR_SUCCESS; } @@ -5354,7 +6064,10 @@ piAction); *piInstalled = package->components[index].Installed; if (piAction) - *piInstalled = package->components[index].Action; + *piAction = package->components[index].Action; + + TRACE("states (%i, %i)\n", +(piInstalled)?*piInstalled:-1,(piAction)?*piAction:-1); return ERROR_SUCCESS; } @@ -5384,21 +6097,21 @@ static UINT ACTION_Template(MSIPACKAGE *package) MSIRECORD * row = 0; static const WCHAR ExecSeqQuery[] = {0}; - rc = MsiDatabaseOpenViewW(package->db, ExecSeqQuery, &view); + rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); if (rc != ERROR_SUCCESS) return rc; - rc = MsiViewExecute(view, 0); + rc = MSI_ViewExecute(view, 0); if (rc != ERROR_SUCCESS) { - MsiViewClose(view); + MSI_ViewClose(view); msiobj_release(&view->hdr); return rc; } while (1) { - rc = MsiViewFetch(view,&row); + rc = MSI_ViewFetch(view,&row); if (rc != ERROR_SUCCESS) { rc = ERROR_SUCCESS; @@ -5407,7 +6120,7 @@ static UINT ACTION_Template(MSIPACKAGE *package) msiobj_release(&row->hdr); } - MsiViewClose(view); + MSI_ViewClose(view); msiobj_release(&view->hdr); return rc; } diff --git a/reactos/lib/msi/action.h b/reactos/lib/msi/action.h new file mode 100644 index 00000000000..221e2a22275 --- /dev/null +++ b/reactos/lib/msi/action.h @@ -0,0 +1,151 @@ +/* + * Common prototypes for Action handlers + * + * 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 + */ + +typedef struct tagMSIFEATURE +{ + WCHAR Feature[96]; + WCHAR Feature_Parent[96]; + WCHAR Title[0x100]; + WCHAR Description[0x100]; + INT Display; + INT Level; + WCHAR Directory[96]; + INT Attributes; + + INSTALLSTATE Installed; + INSTALLSTATE ActionRequest; + INSTALLSTATE Action; + + INT ComponentCount; + INT Components[1024]; /* yes hardcoded limit.... I am bad */ + INT Cost; +} MSIFEATURE; + +typedef struct tagMSICOMPONENT +{ + WCHAR Component[96]; + WCHAR ComponentId[96]; + WCHAR Directory[96]; + INT Attributes; + WCHAR Condition[0x100]; + WCHAR KeyPath[96]; + + INSTALLSTATE Installed; + INSTALLSTATE ActionRequest; + INSTALLSTATE Action; + + BOOL Enabled; + INT Cost; +} MSICOMPONENT; + +typedef struct tagMSIFOLDER +{ + LPWSTR Directory; + LPWSTR TargetDefault; + LPWSTR SourceDefault; + + LPWSTR ResolvedTarget; + LPWSTR ResolvedSource; + LPWSTR Property; /* initially set property */ + INT ParentIndex; + INT State; + /* 0 = uninitialized */ + /* 1 = existing */ + /* 2 = created remove if empty */ + /* 3 = created persist if empty */ + INT Cost; + INT Space; +}MSIFOLDER; + +typedef struct tagMSIFILE +{ + LPWSTR File; + INT ComponentIndex; + LPWSTR FileName; + INT FileSize; + LPWSTR Version; + LPWSTR Language; + INT Attributes; + INT Sequence; + + INT State; + /* 0 = uninitialize */ + /* 1 = not present */ + /* 2 = present but replace */ + /* 3 = present do not replace */ + /* 4 = Installed */ + LPWSTR SourcePath; + LPWSTR TargetPath; + BOOL Temporary; +}MSIFILE; + + +UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action); +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); + +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); +LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, + BOOL set_prop, MSIFOLDER **folder); +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); + + + +inline static char *strdupWtoA( const WCHAR *str ) +{ + char *ret = NULL; + if (str) + { + DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL +); + if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) + WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL ); + } + return ret; +} + +inline static WCHAR *strdupAtoW( const char *str ) +{ + WCHAR *ret = NULL; + if (str) + { + DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 ); + if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) + MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len ); + } + return ret; +} + +inline static LPWSTR dupstrW(LPCWSTR src) +{ + LPWSTR dest; + if (!src) return NULL; + dest = HeapAlloc(GetProcessHeap(), 0, (strlenW(src)+1)*sizeof(WCHAR)); + strcpyW(dest, src); + return dest; +} diff --git a/reactos/lib/msi/appsearch.c b/reactos/lib/msi/appsearch.c new file mode 100644 index 00000000000..60059b6429b --- /dev/null +++ b/reactos/lib/msi/appsearch.c @@ -0,0 +1,855 @@ +/* + * Implementation of the AppSearch action of the Microsoft Installer (msi.dll) + * + * Copyright 2005 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "msi.h" +#include "msiquery.h" +#include "winver.h" +#include "wine/unicode.h" +#include "wine/debug.h" +#include "msipriv.h" +#include "action.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +typedef struct tagMSISIGNATURE +{ + LPWSTR Name; /* NOT owned by this structure */ + LPWSTR Property; /* NOT owned by this structure */ + LPWSTR File; + DWORD MinVersionMS; + DWORD MinVersionLS; + DWORD MaxVersionMS; + DWORD MaxVersionLS; + DWORD MinSize; + DWORD MaxSize; + FILETIME MinTime; + FILETIME MaxTime; + LPWSTR Languages; +}MSISIGNATURE; + +static void ACTION_VerStrToInteger(LPCWSTR verStr, PDWORD ms, PDWORD ls) +{ + const WCHAR *ptr; + int x1 = 0, x2 = 0, x3 = 0, x4 = 0; + + x1 = atoiW(verStr); + ptr = strchrW(verStr, '.'); + if (ptr) + { + x2 = atoiW(ptr + 1); + ptr = strchrW(ptr + 1, '.'); + } + if (ptr) + { + x3 = atoiW(ptr + 1); + ptr = strchrW(ptr + 1, '.'); + } + if (ptr) + x4 = atoiW(ptr + 1); + /* FIXME: byte-order dependent? */ + *ms = x1 << 16 | x2; + *ls = x3 << 16 | x4; +} + +/* Fills in sig with the the values from the Signature table, where name is the + * signature to find. Upon return, sig->File will be NULL if the record is not + * found, and not NULL if it is found. + * Warning: clears all fields in sig! + * Returns ERROR_SUCCESS upon success (where not finding the record counts as + * success), something else on error. + */ +static UINT ACTION_AppSearchGetSignature(MSIPACKAGE *package, MSISIGNATURE *sig, + LPCWSTR name) +{ + MSIQUERY *view; + UINT rc; + static const WCHAR ExecSeqQuery[] = { + 's','e','l','e','c','t',' ','*',' ', + 'f','r','o','m',' ', + 'S','i','g','n','a','t','u','r','e',' ', + 'w','h','e','r','e',' ','S','i','g','n','a','t','u','r','e',' ','=',' ', + '\'','%','s','\'',0}; + + TRACE("(package %p, sig %p)\n", package, sig); + memset(sig, 0, sizeof(*sig)); + rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, name); + if (rc == ERROR_SUCCESS) + { + MSIRECORD *row = 0; + DWORD time; + WCHAR *minVersion, *maxVersion; + + rc = MSI_ViewExecute(view, 0); + if (rc != ERROR_SUCCESS) + { + TRACE("MSI_ViewExecute returned %d\n", rc); + goto end; + } + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + TRACE("MSI_ViewFetch returned %d\n", rc); + rc = ERROR_SUCCESS; + goto end; + } + + /* get properties */ + sig->File = load_dynamic_stringW(row,2); + minVersion = load_dynamic_stringW(row,3); + if (minVersion) + { + ACTION_VerStrToInteger(minVersion, &sig->MinVersionMS, + &sig->MinVersionLS); + HeapFree(GetProcessHeap(), 0, minVersion); + } + maxVersion = load_dynamic_stringW(row,4); + if (maxVersion) + { + ACTION_VerStrToInteger(maxVersion, &sig->MaxVersionMS, + &sig->MaxVersionLS); + HeapFree(GetProcessHeap(), 0, maxVersion); + } + sig->MinSize = MSI_RecordGetInteger(row,5); + if (sig->MinSize == MSI_NULL_INTEGER) + sig->MinSize = 0; + sig->MaxSize = MSI_RecordGetInteger(row,6); + if (sig->MaxSize == MSI_NULL_INTEGER) + sig->MaxSize = 0; + sig->Languages = load_dynamic_stringW(row,9); + time = MSI_RecordGetInteger(row,7); + if (time != MSI_NULL_INTEGER) + DosDateTimeToFileTime(HIWORD(time), LOWORD(time), &sig->MinTime); + time = MSI_RecordGetInteger(row,8); + if (time != MSI_NULL_INTEGER) + DosDateTimeToFileTime(HIWORD(time), LOWORD(time), &sig->MaxTime); + TRACE("Found file name %s for Signature_ %s;\n", + debugstr_w(sig->File), debugstr_w(name)); + TRACE("MinVersion is %d.%d.%d.%d\n", HIWORD(sig->MinVersionMS), + LOWORD(sig->MinVersionMS), HIWORD(sig->MinVersionLS), + LOWORD(sig->MinVersionLS)); + TRACE("MaxVersion is %d.%d.%d.%d\n", HIWORD(sig->MaxVersionMS), + LOWORD(sig->MaxVersionMS), HIWORD(sig->MaxVersionLS), + LOWORD(sig->MaxVersionLS)); + TRACE("MinSize is %ld, MaxSize is %ld;\n", sig->MinSize, sig->MaxSize); + TRACE("Languages is %s\n", debugstr_w(sig->Languages)); + +end: + msiobj_release(&row->hdr); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + } + else + { + TRACE("MSI_OpenQuery returned %d\n", rc); + rc = ERROR_SUCCESS; + } + + TRACE("returning %d\n", rc); + return rc; +} + +static UINT ACTION_AppSearchComponents(MSIPACKAGE *package, BOOL *appFound, + MSISIGNATURE *sig) +{ + MSIQUERY *view; + UINT rc; + static const WCHAR ExecSeqQuery[] = { + 's','e','l','e','c','t',' ','*',' ', + 'f','r','o','m',' ', + 'C','o','m','p','L','o','c','a','t','o','r',' ', + 'w','h','e','r','e',' ','S','i','g','n','a','t','u','r','e','_',' ','=',' ', + '\'','%','s','\'',0}; + + TRACE("(package %p, appFound %p, sig %p)\n", package, appFound, sig); + *appFound = FALSE; + rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, sig->Name); + if (rc == ERROR_SUCCESS) + { + MSIRECORD *row = 0; + WCHAR guid[50]; + DWORD sz; + + rc = MSI_ViewExecute(view, 0); + if (rc != ERROR_SUCCESS) + { + TRACE("MSI_ViewExecute returned %d\n", rc); + goto end; + } + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + TRACE("MSI_ViewFetch returned %d\n", rc); + rc = ERROR_SUCCESS; + goto end; + } + + /* get GUID */ + guid[0] = 0; + sz=sizeof(guid)/sizeof(guid[0]); + rc = MSI_RecordGetStringW(row,2,guid,&sz); + if (rc != ERROR_SUCCESS) + { + ERR("Error is %x\n",rc); + goto end; + } + FIXME("AppSearch unimplemented for CompLocator table (GUID %s)\n", + debugstr_w(guid)); + +end: + msiobj_release(&row->hdr); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + } + else + { + TRACE("MSI_OpenQuery returned %d\n", rc); + rc = ERROR_SUCCESS; + } + + TRACE("returning %d\n", rc); + return rc; +} + +static UINT ACTION_AppSearchReg(MSIPACKAGE *package, BOOL *appFound, + MSISIGNATURE *sig) +{ + MSIQUERY *view; + UINT rc; + static const WCHAR ExecSeqQuery[] = { + 's','e','l','e','c','t',' ','*',' ', + 'f','r','o','m',' ', + 'R','e','g','L','o','c','a','t','o','r',' ', + 'w','h','e','r','e',' ','S','i','g','n','a','t','u','r','e','_',' ','=',' ', + '\'','%','s','\'',0}; + + TRACE("(package %p, appFound %p, sig %p)\n", package, appFound, sig); + *appFound = FALSE; + rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, sig->Name); + if (rc == ERROR_SUCCESS) + { + MSIRECORD *row = 0; + LPWSTR keyPath; + + rc = MSI_ViewExecute(view, 0); + if (rc != ERROR_SUCCESS) + { + TRACE("MSI_ViewExecute returned %d\n", rc); + goto end; + } + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + TRACE("MSI_ViewFetch returned %d\n", rc); + rc = ERROR_SUCCESS; + goto end; + } + + /* get key path */ + keyPath = load_dynamic_stringW(row,3); + FIXME("AppSearch unimplemented for RegLocator (key path %s)\n", + debugstr_w(keyPath)); + HeapFree(GetProcessHeap(), 0, keyPath); + +end: + msiobj_release(&row->hdr); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + } + else + { + TRACE("MSI_OpenQuery returned %d\n", rc); + rc = ERROR_SUCCESS; + } + + TRACE("returning %d\n", rc); + return rc; +} + +static UINT ACTION_AppSearchIni(MSIPACKAGE *package, BOOL *appFound, + MSISIGNATURE *sig) +{ + MSIQUERY *view; + UINT rc; + static const WCHAR ExecSeqQuery[] = { + 's','e','l','e','c','t',' ','*',' ', + 'f','r','o','m',' ', + 'I','n','i','L','o','c','a','t','o','r',' ', + 'w','h','e','r','e',' ','S','i','g','n','a','t','u','r','e','_',' ','=',' ', + '\'','%','s','\'',0}; + + TRACE("(package %p, appFound %p, sig %p)\n", package, appFound, sig); + *appFound = FALSE; + rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, sig->Name); + if (rc == ERROR_SUCCESS) + { + MSIRECORD *row = 0; + LPWSTR fileName; + + rc = MSI_ViewExecute(view, 0); + if (rc != ERROR_SUCCESS) + { + TRACE("MSI_ViewExecute returned %d\n", rc); + goto end; + } + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + TRACE("MSI_ViewFetch returned %d\n", rc); + rc = ERROR_SUCCESS; + goto end; + } + + /* get file name */ + fileName = load_dynamic_stringW(row,2); + FIXME("AppSearch unimplemented for IniLocator (ini file name %s)\n", + debugstr_w(fileName)); + HeapFree(GetProcessHeap(), 0, fileName); + +end: + msiobj_release(&row->hdr); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + } + else + { + TRACE("MSI_OpenQuery returned %d\n", rc); + rc = ERROR_SUCCESS; + } + + + TRACE("returning %d\n", rc); + return rc; +} + +/* Expands the value in src into a path without property names and only + * containing long path names into dst. Replaces at most len characters of dst, + * and always NULL-terminates dst if dst is not NULL and len >= 1. + * May modify src. + * Assumes src and dst are non-overlapping. + * FIXME: return code probably needed: + * - what does AppSearch return if the table values are invalid? + * - what if dst is too small? + */ +static void ACTION_ExpandAnyPath(MSIPACKAGE *package, WCHAR *src, WCHAR *dst, + size_t len) +{ + WCHAR *ptr; + size_t copied = 0; + + if (!src || !dst || !len) + return; + + /* Ignore the short portion of the path, don't think we can use it anyway */ + if ((ptr = strchrW(src, '|'))) + ptr++; + else + ptr = src; + while (*ptr && copied < len - 1) + { + WCHAR *prop = strchrW(ptr, '['); + + if (prop) + { + WCHAR *propEnd = strchrW(prop + 1, ']'); + + if (!propEnd) + { + WARN("Unterminated property name in AnyPath: %s\n", + debugstr_w(prop)); + break; + } + else + { + DWORD propLen; + + *propEnd = 0; + propLen = len - copied - 1; + MSI_GetPropertyW(package, prop + 1, dst + copied, &propLen); + ptr = propEnd + 1; + copied += propLen; + } + } + else + { + size_t toCopy = min(strlenW(ptr) + 1, len - copied - 1); + + memcpy(dst + copied, ptr, toCopy * sizeof(WCHAR)); + ptr += toCopy; + copied += toCopy; + } + } + *(dst + copied) = '\0'; +} + +/* Sets *matches to whether the file (whose path is filePath) matches the + * versions set in sig. + * Return ERROR_SUCCESS in case of success (whether or not the file matches), + * something else if a install-halting error occurs. + */ +static UINT ACTION_FileVersionMatches(MSISIGNATURE *sig, LPCWSTR filePath, + BOOL *matches) +{ + UINT rc = ERROR_SUCCESS; + + *matches = FALSE; + if (sig->Languages) + { + FIXME(": need to check version for languages %s\n", + debugstr_w(sig->Languages)); + } + else + { + DWORD zero, size = GetFileVersionInfoSizeW(filePath, &zero); + + if (size) + { + LPVOID buf = HeapAlloc(GetProcessHeap(), 0, size); + + if (buf) + { + static const WCHAR rootW[] = { '\\',0 }; + UINT versionLen; + LPVOID subBlock = NULL; + + if (GetFileVersionInfoW(filePath, 0, size, buf)) + VerQueryValueW(buf, rootW, &subBlock, &versionLen); + if (subBlock) + { + VS_FIXEDFILEINFO *info = + (VS_FIXEDFILEINFO *)subBlock; + + TRACE("Comparing file version %d.%d.%d.%d:\n", + HIWORD(info->dwFileVersionMS), + LOWORD(info->dwFileVersionMS), + HIWORD(info->dwFileVersionLS), + LOWORD(info->dwFileVersionLS)); + if (info->dwFileVersionMS < sig->MinVersionMS + || (info->dwFileVersionMS == sig->MinVersionMS && + info->dwFileVersionLS < sig->MinVersionLS)) + { + TRACE("Less than minimum version %d.%d.%d.%d\n", + HIWORD(sig->MinVersionMS), + LOWORD(sig->MinVersionMS), + HIWORD(sig->MinVersionLS), + LOWORD(sig->MinVersionLS)); + } + else if (info->dwFileVersionMS < sig->MinVersionMS + || (info->dwFileVersionMS == sig->MinVersionMS && + info->dwFileVersionLS < sig->MinVersionLS)) + { + TRACE("Greater than minimum version %d.%d.%d.%d\n", + HIWORD(sig->MaxVersionMS), + LOWORD(sig->MaxVersionMS), + HIWORD(sig->MaxVersionLS), + LOWORD(sig->MaxVersionLS)); + } + else + *matches = TRUE; + } + HeapFree(GetProcessHeap(), 0, buf); + } + else + rc = ERROR_OUTOFMEMORY; + } + } + return rc; +} + +/* Sets *matches to whether the file in findData matches that in sig. + * fullFilePath is assumed to be the full path of the file specified in + * findData, which may be necessary to compare the version. + * Return ERROR_SUCCESS in case of success (whether or not the file matches), + * something else if a install-halting error occurs. + */ +static UINT ACTION_FileMatchesSig(MSISIGNATURE *sig, + LPWIN32_FIND_DATAW findData, LPCWSTR fullFilePath, BOOL *matches) +{ + UINT rc = ERROR_SUCCESS; + + *matches = TRUE; + /* assumes the caller has already ensured the filenames match, so check + * the other fields.. + */ + if (sig->MinTime.dwLowDateTime || sig->MinTime.dwHighDateTime) + { + if (findData->ftCreationTime.dwHighDateTime < + sig->MinTime.dwHighDateTime || + (findData->ftCreationTime.dwHighDateTime == sig->MinTime.dwHighDateTime + && findData->ftCreationTime.dwLowDateTime < + sig->MinTime.dwLowDateTime)) + *matches = FALSE; + } + if (*matches && (sig->MaxTime.dwLowDateTime || sig->MaxTime.dwHighDateTime)) + { + if (findData->ftCreationTime.dwHighDateTime > + sig->MaxTime.dwHighDateTime || + (findData->ftCreationTime.dwHighDateTime == sig->MaxTime.dwHighDateTime + && findData->ftCreationTime.dwLowDateTime > + sig->MaxTime.dwLowDateTime)) + *matches = FALSE; + } + if (*matches && sig->MinSize && findData->nFileSizeLow < sig->MinSize) + *matches = FALSE; + if (*matches && sig->MaxSize && findData->nFileSizeLow > sig->MaxSize) + *matches = FALSE; + if (*matches && (sig->MinVersionMS || sig->MinVersionLS || + sig->MaxVersionMS || sig->MaxVersionLS)) + rc = ACTION_FileVersionMatches(sig, fullFilePath, matches); + return rc; +} + +/* Recursively searches the directory dir for files that match the signature + * sig, up to (depth + 1) levels deep. That is, if depth is 0, it searches dir + * (and only dir). If depth is 1, searches dir and its immediate + * subdirectories. + * Assumes sig->File is not NULL. + * Returns ERROR_SUCCESS on success (which may include non-critical errors), + * something else on failures which should halt the install. + */ +static UINT ACTION_RecurseSearchDirectory(MSIPACKAGE *package, BOOL *appFound, + MSISIGNATURE *sig, LPCWSTR dir, int depth) +{ + static const WCHAR starDotStarW[] = { '*','.','*',0 }; + UINT rc = ERROR_SUCCESS; + size_t dirLen = lstrlenW(dir), fileLen = lstrlenW(sig->File); + WCHAR *buf; + + TRACE("Searching directory %s for file %s, depth %d\n", debugstr_w(dir), + debugstr_w(sig->File), depth); + + if (depth < 0) + return ERROR_INVALID_PARAMETER; + + *appFound = FALSE; + /* We need the buffer in both paths below, so go ahead and allocate it + * here. Add two because we might need to add a backslash if the dir name + * isn't backslash-terminated. + */ + buf = HeapAlloc(GetProcessHeap(), 0, + (dirLen + max(fileLen, lstrlenW(starDotStarW)) + 2) * sizeof(WCHAR)); + if (buf) + { + /* a depth of 0 implies we should search dir, so go ahead and search */ + HANDLE hFind; + WIN32_FIND_DATAW findData; + + memcpy(buf, dir, dirLen * sizeof(WCHAR)); + if (buf[dirLen - 1] != '\\') + buf[dirLen++ - 1] = '\\'; + memcpy(buf + dirLen, sig->File, (fileLen + 1) * sizeof(WCHAR)); + hFind = FindFirstFileW(buf, &findData); + if (hFind != INVALID_HANDLE_VALUE) + { + BOOL matches; + + /* assuming Signature can't contain wildcards for the file name, + * so don't bother with FindNextFileW here. + */ + if (!(rc = ACTION_FileMatchesSig(sig, &findData, buf, &matches)) + && matches) + { + TRACE("found file, setting %s to %s\n", + debugstr_w(sig->Property), debugstr_w(buf)); + rc = MSI_SetPropertyW(package, sig->Property, buf); + *appFound = TRUE; + } + FindClose(hFind); + } + if (rc == ERROR_SUCCESS && !*appFound && depth > 0) + { + HANDLE hFind; + WIN32_FIND_DATAW findData; + + memcpy(buf, dir, dirLen * sizeof(WCHAR)); + if (buf[dirLen - 1] != '\\') + buf[dirLen++ - 1] = '\\'; + lstrcpyW(buf + dirLen, starDotStarW); + hFind = FindFirstFileW(buf, &findData); + if (hFind != INVALID_HANDLE_VALUE) + { + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + rc = ACTION_RecurseSearchDirectory(package, appFound, + sig, findData.cFileName, depth - 1); + while (rc == ERROR_SUCCESS && !*appFound && + FindNextFileW(hFind, &findData) != 0) + { + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + rc = ACTION_RecurseSearchDirectory(package, appFound, + sig, findData.cFileName, depth - 1); + } + FindClose(hFind); + } + } + HeapFree(GetProcessHeap(), 0, buf); + } + else + rc = ERROR_OUTOFMEMORY; + + return rc; +} + +static UINT ACTION_CheckDirectory(MSIPACKAGE *package, MSISIGNATURE *sig, + LPCWSTR dir) +{ + UINT rc = ERROR_SUCCESS; + + if (GetFileAttributesW(dir) & FILE_ATTRIBUTE_DIRECTORY) + { + TRACE("directory exists, setting %s to %s\n", + debugstr_w(sig->Property), debugstr_w(dir)); + rc = MSI_SetPropertyW(package, sig->Property, dir); + } + return rc; +} + +static BOOL ACTION_IsFullPath(LPCWSTR path) +{ + WCHAR first = toupperW(path[0]); + BOOL ret; + + if (first >= 'A' && first <= 'A' && path[1] == ':') + ret = TRUE; + else if (path[0] == '\\' && path[1] == '\\') + ret = TRUE; + else + ret = FALSE; + return ret; +} + +static UINT ACTION_SearchDirectory(MSIPACKAGE *package, MSISIGNATURE *sig, + LPCWSTR expanded, int depth) +{ + UINT rc; + BOOL found; + + if (ACTION_IsFullPath(expanded)) + { + if (sig->File) + rc = ACTION_RecurseSearchDirectory(package, &found, sig, + expanded, depth); + else + { + /* Recursively searching a directory makes no sense when the + * directory to search is the thing you're trying to find. + */ + rc = ACTION_CheckDirectory(package, sig, expanded); + } + } + else + { + WCHAR pathWithDrive[MAX_PATH] = { 'C',':','\\',0 }; + DWORD drives = GetLogicalDrives(); + int i; + + rc = ERROR_SUCCESS; + found = FALSE; + for (i = 0; rc == ERROR_SUCCESS && !found && i < 26; i++) + if (drives & (1 << drives)) + { + pathWithDrive[0] = 'A' + i; + if (GetDriveTypeW(pathWithDrive) == DRIVE_FIXED) + { + strncpyW(pathWithDrive + 3, expanded, + sizeof(pathWithDrive) / sizeof(pathWithDrive[0]) - 3); + if (sig->File) + rc = ACTION_RecurseSearchDirectory(package, &found, sig, + pathWithDrive, depth); + else + rc = ACTION_CheckDirectory(package, sig, pathWithDrive); + } + } + } + return rc; +} + +static UINT ACTION_AppSearchDr(MSIPACKAGE *package, MSISIGNATURE *sig) +{ + MSIQUERY *view; + UINT rc; + static const WCHAR ExecSeqQuery[] = { + 's','e','l','e','c','t',' ','*',' ', + 'f','r','o','m',' ', + 'D','r','L','o','c','a','t','o','r',' ', + 'w','h','e','r','e',' ','S','i','g','n','a','t','u','r','e','_',' ','=',' ', + '\'','%','s','\'',0}; + + TRACE("(package %p, sig %p)\n", package, sig); + rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, sig->Name); + if (rc == ERROR_SUCCESS) + { + MSIRECORD *row = 0; + WCHAR buffer[MAX_PATH], expanded[MAX_PATH]; + DWORD sz; + int depth; + + rc = MSI_ViewExecute(view, 0); + if (rc != ERROR_SUCCESS) + { + TRACE("MSI_ViewExecute returned %d\n", rc); + goto end; + } + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + TRACE("MSI_ViewFetch returned %d\n", rc); + rc = ERROR_SUCCESS; + goto end; + } + + /* check whether parent is set */ + buffer[0] = 0; + sz=sizeof(buffer)/sizeof(buffer[0]); + rc = MSI_RecordGetStringW(row,2,buffer,&sz); + if (rc != ERROR_SUCCESS) + { + ERR("Error is %x\n",rc); + goto end; + } + else if (buffer[0]) + { + FIXME(": searching parent (%s) unimplemented\n", + debugstr_w(buffer)); + goto end; + } + /* no parent, now look for path */ + buffer[0] = 0; + sz=sizeof(buffer)/sizeof(buffer[0]); + rc = MSI_RecordGetStringW(row,3,buffer,&sz); + if (rc != ERROR_SUCCESS) + { + ERR("Error is %x\n",rc); + goto end; + } + if (MSI_RecordIsNull(row,4)) + depth = 0; + else + depth = MSI_RecordGetInteger(row,4); + ACTION_ExpandAnyPath(package, buffer, expanded, + sizeof(expanded) / sizeof(expanded[0])); + rc = ACTION_SearchDirectory(package, sig, expanded, depth); + +end: + msiobj_release(&row->hdr); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + } + else + { + TRACE("MSI_OpenQuery returned %d\n", rc); + rc = ERROR_SUCCESS; + } + + + TRACE("returning %d\n", rc); + return rc; +} + +/* http://msdn.microsoft.com/library/en-us/msi/setup/appsearch_table.asp + * is the best reference for the AppSearch table and how it's used. + */ +UINT ACTION_AppSearch(MSIPACKAGE *package) +{ + MSIQUERY *view; + UINT rc; + static const WCHAR ExecSeqQuery[] = { + 's','e','l','e','c','t',' ','*',' ', + 'f','r','o','m',' ', + 'A','p','p','S','e','a','r','c','h',0}; + + rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery); + if (rc == ERROR_SUCCESS) + { + MSIRECORD *row = 0; + WCHAR propBuf[0x100], sigBuf[0x100]; + DWORD sz; + MSISIGNATURE sig; + BOOL appFound = FALSE; + + rc = MSI_ViewExecute(view, 0); + if (rc != ERROR_SUCCESS) + goto end; + + while (!rc) + { + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + rc = ERROR_SUCCESS; + break; + } + + /* get property and signature */ + propBuf[0] = 0; + sz=sizeof(propBuf)/sizeof(propBuf[0]); + rc = MSI_RecordGetStringW(row,1,propBuf,&sz); + if (rc != ERROR_SUCCESS) + { + ERR("Error is %x\n",rc); + msiobj_release(&row->hdr); + break; + } + sigBuf[0] = 0; + sz=sizeof(sigBuf)/sizeof(sigBuf[0]); + rc = MSI_RecordGetStringW(row,2,sigBuf,&sz); + if (rc != ERROR_SUCCESS) + { + ERR("Error is %x\n",rc); + msiobj_release(&row->hdr); + break; + } + TRACE("Searching for Property %s, Signature_ %s\n", + debugstr_w(propBuf), debugstr_w(sigBuf)); + /* This clears all the fields, so set Name and Property afterward */ + rc = ACTION_AppSearchGetSignature(package, &sig, sigBuf); + sig.Name = sigBuf; + sig.Property = propBuf; + if (rc == ERROR_SUCCESS) + { + rc = ACTION_AppSearchComponents(package, &appFound, &sig); + if (rc == ERROR_SUCCESS && !appFound) + { + rc = ACTION_AppSearchReg(package, &appFound, &sig); + if (rc == ERROR_SUCCESS && !appFound) + { + rc = ACTION_AppSearchIni(package, &appFound, &sig); + if (rc == ERROR_SUCCESS && !appFound) + rc = ACTION_AppSearchDr(package, &sig); + } + } + } + HeapFree(GetProcessHeap(), 0, sig.File); + HeapFree(GetProcessHeap(), 0, sig.Languages); + msiobj_release(&row->hdr); + } + +end: + MSI_ViewClose(view); + msiobj_release(&view->hdr); + } + else + rc = ERROR_SUCCESS; + + return rc; +} diff --git a/reactos/lib/msi/cond.tab.c b/reactos/lib/msi/cond.tab.c index 6a4e64c88c6..31fa5f736a6 100644 --- a/reactos/lib/msi/cond.tab.c +++ b/reactos/lib/msi/cond.tab.c @@ -1,2022 +1,2204 @@ -/* A Bison parser, made from ./cond.y - by GNU bison 1.35. */ - -#define YYBISON 1 /* Identify Bison output. */ - -#define yyparse COND_parse -#define yylex COND_lex -#define yyerror COND_error -#define yylval COND_lval -#define yychar COND_char -#define yydebug COND_debug -#define yynerrs COND_nerrs -# 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 - -#line 1 "./cond.y" - - -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2003 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wine/debug.h" -#include "wine/unicode.h" - -#include "msi.h" -#include "msiquery.h" -#include "msipriv.h" - -#define YYLEX_PARAM info -#define YYPARSE_PARAM info - -static int COND_error(char *str); - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -typedef struct tag_yyinput -{ - MSIPACKAGE *package; - LPCWSTR str; - INT n; - MSICONDITION result; -} COND_input; - -struct cond_str { - LPCWSTR data; - INT len; -}; - -static LPWSTR COND_GetString( struct cond_str *str ); -static LPWSTR COND_GetLiteral( struct cond_str *str ); -static int COND_lex( void *COND_lval, COND_input *info); - -typedef INT (*comp_int)(INT a, INT b); -typedef INT (*comp_str)(LPWSTR a, LPWSTR b, BOOL caseless); -typedef INT (*comp_m1)(LPWSTR a,int b); -typedef INT (*comp_m2)(int a,LPWSTR b); - -static INT comp_lt_i(INT a, INT b); -static INT comp_gt_i(INT a, INT b); -static INT comp_le_i(INT a, INT b); -static INT comp_ge_i(INT a, INT b); -static INT comp_eq_i(INT a, INT b); -static INT comp_ne_i(INT a, INT b); -static INT comp_bitand(INT a, INT b); -static INT comp_highcomp(INT a, INT b); -static INT comp_lowcomp(INT a, INT b); - -static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless); - -static INT comp_eq_m1(LPWSTR a, INT b); -static INT comp_ne_m1(LPWSTR a, INT b); -static INT comp_lt_m1(LPWSTR a, INT b); -static INT comp_gt_m1(LPWSTR a, INT b); -static INT comp_le_m1(LPWSTR a, INT b); -static INT comp_ge_m1(LPWSTR a, INT b); - -static INT comp_eq_m2(INT a, LPWSTR b); -static INT comp_ne_m2(INT a, LPWSTR b); -static INT comp_lt_m2(INT a, LPWSTR b); -static INT comp_gt_m2(INT a, LPWSTR b); -static INT comp_le_m2(INT a, LPWSTR b); -static INT comp_ge_m2(INT a, LPWSTR b); - - -#line 105 "./cond.y" -#ifndef YYSTYPE -typedef union -{ - struct cond_str str; - LPWSTR string; - INT value; - comp_int fn_comp_int; - comp_str fn_comp_str; - comp_m1 fn_comp_m1; - comp_m2 fn_comp_m2; -} yystype; -# define YYSTYPE yystype -# define YYSTYPE_IS_TRIVIAL 1 -#endif -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - - - -#define YYFINAL 74 -#define YYFLAG -32768 -#define YYNTBASE 23 - -/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ -#define YYTRANSLATE(x) ((unsigned)(x) <= 276 ? yytranslate[x] : 39) - -/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ -static const char yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22 -}; - -#if YYDEBUG -static const short yyprhs[] = -{ - 0, 0, 2, 4, 8, 10, 14, 16, 19, 21, - 23, 27, 31, 36, 40, 44, 48, 50, 53, 55, - 57, 60, 63, 66, 69, 72, 74, 77, 79, 81, - 84, 87, 90, 93, 96, 98, 101, 103, 105, 108, - 111, 114, 117, 120, 122, 125, 127, 129, 132, 135, - 138, 141, 144, 146, 148, 150, 152, 154, 157, 160, - 163, 166, 168, 171, 173 -}; -static const short yyrhs[] = -{ - 24, 0, 25, 0, 25, 5, 24, 0, 26, 0, - 25, 6, 26, 0, 27, 0, 7, 27, 0, 32, - 0, 33, 0, 32, 28, 32, 0, 33, 29, 33, - 0, 33, 13, 29, 33, 0, 33, 30, 32, 0, - 32, 31, 33, 0, 11, 24, 12, 0, 10, 0, - 8, 9, 0, 8, 0, 9, 0, 8, 10, 0, - 9, 10, 0, 9, 8, 0, 8, 8, 0, 9, - 9, 0, 10, 0, 8, 9, 0, 8, 0, 9, - 0, 8, 10, 0, 9, 10, 0, 9, 8, 0, - 8, 8, 0, 9, 9, 0, 10, 0, 8, 9, - 0, 8, 0, 9, 0, 8, 10, 0, 9, 10, - 0, 9, 8, 0, 8, 8, 0, 9, 9, 0, - 10, 0, 8, 9, 0, 8, 0, 9, 0, 8, - 10, 0, 9, 10, 0, 9, 8, 0, 8, 8, - 0, 9, 9, 0, 35, 0, 38, 0, 36, 0, - 34, 0, 21, 0, 15, 37, 0, 16, 37, 0, - 17, 37, 0, 18, 37, 0, 37, 0, 14, 37, - 0, 19, 0, 20, 0 -}; - -#endif - -#if YYDEBUG -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ -static const short yyrline[] = -{ - 0, 135, 143, 148, 154, 159, 165, 170, 177, 182, - 186, 190, 194, 198, 202, 206, 212, 218, 222, 226, - 230, 234, 239, 243, 247, 253, 259, 263, 267, 271, - 275, 280, 284, 288, 294, 300, 304, 308, 312, 316, - 321, 325, 329, 335, 341, 345, 349, 353, 357, 362, - 366, 370, 376, 381, 387, 392, 398, 407, 417, 426, - 435, 446, 462, 475, 484 -}; -#endif - - -#if (YYDEBUG) || defined YYERROR_VERBOSE - -/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */ -static const char *const yytname[] = -{ - "$", "error", "$undefined.", "COND_SPACE", "COND_EOF", "COND_OR", - "COND_AND", "COND_NOT", "COND_LT", "COND_GT", "COND_EQ", "COND_LPAR", - "COND_RPAR", "COND_TILDA", "COND_PERCENT", "COND_DOLLARS", - "COND_QUESTION", "COND_AMPER", "COND_EXCLAM", "COND_IDENT", - "COND_NUMBER", "COND_LITER", "COND_ERROR", "condition", "expression", - "boolean_term", "boolean_factor", "term", "comp_op_i", "comp_op_s", - "comp_op_m1", "comp_op_m2", "value_i", "value_s", "literal", "symbol_i", - "symbol_s", "identifier", "integer", 0 -}; -#endif - -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const short yyr1[] = -{ - 0, 23, 24, 24, 25, 25, 26, 26, 27, 27, - 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 32, 32, 33, 33, 34, 35, 35, 35, - 35, 36, 36, 37, 38 -}; - -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const short yyr2[] = -{ - 0, 1, 1, 3, 1, 3, 1, 2, 1, 1, - 3, 3, 4, 3, 3, 3, 1, 2, 1, 1, - 2, 2, 2, 2, 2, 1, 2, 1, 1, 2, - 2, 2, 2, 2, 1, 2, 1, 1, 2, 2, - 2, 2, 2, 1, 2, 1, 1, 2, 2, 2, - 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, - 2, 1, 2, 1, 1 -}; - -/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE - doesn't specify something else to do. Zero means the default is an - error. */ -static const short yydefact[] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, - 56, 1, 2, 4, 6, 8, 9, 55, 52, 54, - 61, 53, 7, 0, 62, 57, 58, 59, 60, 0, - 0, 18, 19, 16, 0, 0, 36, 37, 34, 0, - 0, 0, 15, 3, 5, 23, 17, 20, 22, 24, - 21, 10, 14, 41, 35, 38, 40, 42, 39, 27, - 28, 25, 0, 11, 13, 32, 26, 29, 31, 33, - 30, 12, 0, 0, 0 -}; - -static const short yydefgoto[] = -{ - 72, 11, 12, 13, 14, 34, 40, 41, 35, 15, - 16, 17, 18, 19, 20, 21 -}; - -static const short yypact[] = -{ - -5, 50, -5, -12, -12, -12, -12, -12,-32768,-32768, - -32768,-32768, -2,-32768,-32768, 48, 123,-32768,-32768,-32768, - -32768,-32768,-32768, -4,-32768,-32768,-32768,-32768,-32768, -5, - -5, 10, 24, 33, 110, 58, 27, 41, 59, 135, - 58, 110,-32768,-32768,-32768, 62, 68, 71, 72, 80, - 81,-32768,-32768, 84, 90, 93, 94, 102, 103, 138, - 141,-32768, 58,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - -32768,-32768, 17, 21,-32768 -}; - -static const short yypgoto[] = -{ - -32768, -1,-32768, -8, 25,-32768, -14,-32768,-32768, -11, - -35,-32768,-32768,-32768, 134,-32768 -}; - - -#define YYLAST 151 - - -static const short yytable[] = -{ - 52, 23, 1, 29, 30, 63, 2, 8, 42, 3, - 4, 5, 6, 7, 8, 9, 10, 73, 45, 46, - 47, 74, 44, 51, -45, 62, 22, 71, 43, -45, - 64, -45, 48, 49, 50, 53, 54, 55, -46, 0, - 0, -27, 0, -46, 0, -46, -27, -43, -27, 56, - 57, 58, -43, 0, -43, -28, 31, 32, 33, 0, - -28, 2, -28, 0, 3, 4, 5, 6, 7, 8, - 9, 10, 3, -25, 0, 0, -50, 8, -25, 10, - -25, -50, -44, -50, 0, -47, -49, -44, 0, -44, - -47, -49, -47, -49, -51, -48, 0, 0, -32, -51, - -48, -51, -48, -32, -26, -32, 0, -29, -31, -26, - 0, -26, -29, -31, -29, -31, -33, -30, 0, 0, - 0, -33, -30, -33, -30, 4, 5, 6, 7, 0, - 9, 36, 37, 38, 0, 0, 39, 24, 25, 26, - 27, 28, 0, 59, 60, 61, 65, 66, 67, 68, - 69, 70 -}; - -static const short yycheck[] = -{ - 35, 2, 7, 5, 6, 40, 11, 19, 12, 14, - 15, 16, 17, 18, 19, 20, 21, 0, 8, 9, - 10, 0, 30, 34, 14, 39, 1, 62, 29, 19, - 41, 21, 8, 9, 10, 8, 9, 10, 14, -1, - -1, 14, -1, 19, -1, 21, 19, 14, 21, 8, - 9, 10, 19, -1, 21, 14, 8, 9, 10, -1, - 19, 11, 21, -1, 14, 15, 16, 17, 18, 19, - 20, 21, 14, 14, -1, -1, 14, 19, 19, 21, - 21, 19, 14, 21, -1, 14, 14, 19, -1, 21, - 19, 19, 21, 21, 14, 14, -1, -1, 14, 19, - 19, 21, 21, 19, 14, 21, -1, 14, 14, 19, - -1, 21, 19, 19, 21, 21, 14, 14, -1, -1, - -1, 19, 19, 21, 21, 15, 16, 17, 18, -1, - 20, 8, 9, 10, -1, -1, 13, 3, 4, 5, - 6, 7, -1, 8, 9, 10, 8, 9, 10, 8, - 9, 10 -}; -#define YYPURE 1 - -/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ -#line 3 "/usr/share/bison/bison.simple" - -/* Skeleton output parser for bison, - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 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. */ - -/* This is the parser code that is written into each bison parser when - the %semantic_parser declaration is not specified in the grammar. - It was written by Richard Stallman by simplifying the hairy parser - used when %semantic_parser is specified. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE) - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# if YYSTACK_USE_ALLOCA -# define YYSTACK_ALLOC alloca -# else -# ifndef YYSTACK_USE_ALLOCA -# if defined (alloca) || defined (_ALLOCA_H) -# define YYSTACK_ALLOC alloca -# else -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) -# else -# if defined (__STDC__) || defined (__cplusplus) -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -# define YYSTACK_ALLOC malloc -# define YYSTACK_FREE free -# endif -#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */ - - -#if (! defined (yyoverflow) \ - && (! defined (__cplusplus) \ - || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - short yyss; - YYSTYPE yyvs; -# if YYLSP_NEEDED - YYLTYPE yyls; -# endif -}; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# if YYLSP_NEEDED -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ - + 2 * YYSTACK_GAP_MAX) -# else -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAX) -# endif - -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - register YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (0) -# endif -# endif - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack, Stack, yysize); \ - Stack = &yyptr->Stack; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (0) - -#endif - - -#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) -# define YYSIZE_T __SIZE_TYPE__ -#endif -#if ! defined (YYSIZE_T) && defined (size_t) -# define YYSIZE_T size_t -#endif -#if ! defined (YYSIZE_T) -# if defined (__STDC__) || defined (__cplusplus) -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -#endif -#if ! defined (YYSIZE_T) -# define YYSIZE_T unsigned int -#endif - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY -2 -#define YYEOF 0 -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrlab1 -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. */ -#define YYFAIL goto yyerrlab -#define YYRECOVERING() (!!yyerrstatus) -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - yychar1 = YYTRANSLATE (yychar); \ - YYPOPSTACK; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror ("syntax error: cannot back up"); \ - YYERROR; \ - } \ -while (0) - -#define YYTERROR 1 -#define YYERRCODE 256 - - -/* YYLLOC_DEFAULT -- Compute the default location (before the actions - are run). - - When YYLLOC_DEFAULT is run, CURRENT is set the location of the - first token. By default, to implement support for ranges, extend - its range to the last symbol. */ - -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - Current.last_line = Rhs[N].last_line; \ - Current.last_column = Rhs[N].last_column; -#endif - - -/* YYLEX -- calling `yylex' with the right arguments. */ - -#if YYPURE -# if YYLSP_NEEDED -# ifdef YYLEX_PARAM -# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) -# else -# define YYLEX yylex (&yylval, &yylloc) -# endif -# else /* !YYLSP_NEEDED */ -# ifdef YYLEX_PARAM -# define YYLEX yylex (&yylval, YYLEX_PARAM) -# else -# define YYLEX yylex (&yylval) -# endif -# endif /* !YYLSP_NEEDED */ -#else /* !YYPURE */ -# define YYLEX yylex () -#endif /* !YYPURE */ - - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (0) -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -#endif /* !YYDEBUG */ - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#if YYMAXDEPTH == 0 -# undef YYMAXDEPTH -#endif - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - -#ifdef YYERROR_VERBOSE - -# ifndef yystrlen -# if defined (__GLIBC__) && defined (_STRING_H) -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -static YYSIZE_T -# if defined (__STDC__) || defined (__cplusplus) -yystrlen (const char *yystr) -# else -yystrlen (yystr) - const char *yystr; -# endif -{ - register const char *yys = yystr; - - while (*yys++ != '\0') - continue; - - return yys - yystr - 1; -} -# endif -# endif - -# ifndef yystpcpy -# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -static char * -# if defined (__STDC__) || defined (__cplusplus) -yystpcpy (char *yydest, const char *yysrc) -# else -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -# endif -{ - register char *yyd = yydest; - register const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif -#endif - -#line 315 "/usr/share/bison/bison.simple" - - -/* The user can define YYPARSE_PARAM as the name of an argument to be passed - into yyparse. The argument should have type void *. - It should actually point to an object. - Grammar actions can access the variable by casting it - to the proper pointer type. */ - -#ifdef YYPARSE_PARAM -# if defined (__STDC__) || defined (__cplusplus) -# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM -# define YYPARSE_PARAM_DECL -# else -# define YYPARSE_PARAM_ARG YYPARSE_PARAM -# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; -# endif -#else /* !YYPARSE_PARAM */ -# define YYPARSE_PARAM_ARG -# define YYPARSE_PARAM_DECL -#endif /* !YYPARSE_PARAM */ - -/* Prevent warning if -Wstrict-prototypes. */ -#ifdef __GNUC__ -# ifdef YYPARSE_PARAM -int yyparse (void *); -# else -int yyparse (void); -# endif -#endif - -/* YY_DECL_VARIABLES -- depending whether we use a pure parser, - variables are global, or local to YYPARSE. */ - -#define YY_DECL_NON_LSP_VARIABLES \ -/* The lookahead symbol. */ \ -int yychar; \ - \ -/* The semantic value of the lookahead symbol. */ \ -YYSTYPE yylval; \ - \ -/* Number of parse errors so far. */ \ -int yynerrs; - -#if YYLSP_NEEDED -# define YY_DECL_VARIABLES \ -YY_DECL_NON_LSP_VARIABLES \ - \ -/* Location data for the lookahead symbol. */ \ -YYLTYPE yylloc; -#else -# define YY_DECL_VARIABLES \ -YY_DECL_NON_LSP_VARIABLES -#endif - - -/* If nonreentrant, generate the variables here. */ - -#if !YYPURE -YY_DECL_VARIABLES -#endif /* !YYPURE */ - -int -yyparse (YYPARSE_PARAM_ARG) - YYPARSE_PARAM_DECL -{ - /* If reentrant, generate the variables here. */ -#if YYPURE - YY_DECL_VARIABLES -#endif /* !YYPURE */ - - register int yystate; - register int yyn; - int yyresult; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - /* Lookahead token as an internal (translated) token number. */ - int yychar1 = 0; - - /* Three stacks and their tools: - `yyss': related to states, - `yyvs': related to semantic values, - `yyls': related to locations. - - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - short yyssa[YYINITDEPTH]; - short *yyss = yyssa; - register short *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - register YYSTYPE *yyvsp; - -#if YYLSP_NEEDED - /* The location stack. */ - YYLTYPE yylsa[YYINITDEPTH]; - YYLTYPE *yyls = yylsa; - YYLTYPE *yylsp; -#endif - -#if YYLSP_NEEDED -# define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) -#else -# define YYPOPSTACK (yyvsp--, yyssp--) -#endif - - YYSIZE_T yystacksize = YYINITDEPTH; - - - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; -#if YYLSP_NEEDED - YYLTYPE yyloc; -#endif - - /* When reducing, the number of symbols on the RHS of the reduced - rule. */ - int yylen; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - - yyssp = yyss; - yyvsp = yyvs; -#if YYLSP_NEEDED - yylsp = yyls; -#endif - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. so pushing a state here evens the stacks. - */ - yyssp++; - - yysetstate: - *yyssp = yystate; - - if (yyssp >= yyss + yystacksize - 1) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - short *yyss1 = yyss; - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. */ -# if YYLSP_NEEDED - YYLTYPE *yyls1 = yyls; - /* This used to be a conditional around just the two extra args, - but that might be undefined if yyoverflow is a macro. */ - yyoverflow ("parser stack overflow", - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yyls1, yysize * sizeof (*yylsp), - &yystacksize); - yyls = yyls1; -# else - yyoverflow ("parser stack overflow", - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yystacksize); -# endif - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyoverflowlab; -# else - /* Extend the stack our own way. */ - if (yystacksize >= YYMAXDEPTH) - goto yyoverflowlab; - yystacksize *= 2; - if (yystacksize > YYMAXDEPTH) - yystacksize = YYMAXDEPTH; - - { - short *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyoverflowlab; - YYSTACK_RELOCATE (yyss); - YYSTACK_RELOCATE (yyvs); -# if YYLSP_NEEDED - YYSTACK_RELOCATE (yyls); -# endif -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; -#if YYLSP_NEEDED - yylsp = yyls + yysize - 1; -#endif - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyssp >= yyss + yystacksize - 1) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - goto yybackup; - - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - -/* Do appropriate processing given the current state. */ -/* Read a lookahead token if we need one and don't already have one. */ -/* yyresume: */ - - /* First try to decide what to do without reference to lookahead token. */ - - yyn = yypact[yystate]; - if (yyn == YYFLAG) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* yychar is either YYEMPTY or YYEOF - or a valid token in external form. */ - - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; - } - - /* Convert token to internal form (in yychar1) for indexing tables with */ - - if (yychar <= 0) /* This means end of input. */ - { - yychar1 = 0; - yychar = YYEOF; /* Don't call YYLEX any more */ - - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yychar1 = YYTRANSLATE (yychar); - -#if YYDEBUG - /* We have to keep this `#if YYDEBUG', since we use variables - which are defined only if `YYDEBUG' is set. */ - if (yydebug) - { - YYFPRINTF (stderr, "Next token is %d (%s", - yychar, yytname[yychar1]); - /* Give the individual parser a way to print the precise - meaning of a token, for further debugging info. */ -# ifdef YYPRINT - YYPRINT (stderr, yychar, yylval); -# endif - YYFPRINTF (stderr, ")\n"); - } -#endif - } - - yyn += yychar1; - if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) - goto yydefault; - - yyn = yytable[yyn]; - - /* yyn is what to do for this token type in this state. - Negative => reduce, -yyn is rule number. - Positive => shift, yyn is new state. - New state is final state => don't bother to shift, - just return success. - 0, or most negative number => error. */ - - if (yyn < 0) - { - if (yyn == YYFLAG) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - else if (yyn == 0) - goto yyerrlab; - - if (yyn == YYFINAL) - YYACCEPT; - - /* Shift the lookahead token. */ - YYDPRINTF ((stderr, "Shifting token %d (%s), ", - yychar, yytname[yychar1])); - - /* Discard the token being shifted unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; - - *++yyvsp = yylval; -#if YYLSP_NEEDED - *++yylsp = yylloc; -#endif - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - yystate = yyn; - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. - - Otherwise, the following line sets YYVAL to the semantic value of - the lookahead token. This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - -#if YYLSP_NEEDED - /* Similarly for the default location. Let the user run additional - commands if for instance locations are ranges. */ - yyloc = yylsp[1-yylen]; - YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); -#endif - -#if YYDEBUG - /* We have to keep this `#if YYDEBUG', since we use variables which - are defined only if `YYDEBUG' is set. */ - if (yydebug) - { - int yyi; - - YYFPRINTF (stderr, "Reducing via rule %d (line %d), ", - yyn, yyrline[yyn]); - - /* Print the symbols being reduced, and their result. */ - for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++) - YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]); - YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]); - } -#endif - - switch (yyn) { - -case 1: -#line 137 "./cond.y" -{ - COND_input* cond = (COND_input*) info; - cond->result = yyvsp[0].value; - ; - break;} -case 2: -#line 145 "./cond.y" -{ - yyval.value = yyvsp[0].value; - ; - break;} -case 3: -#line 149 "./cond.y" -{ - yyval.value = yyvsp[-2].value || yyvsp[0].value; - ; - break;} -case 4: -#line 156 "./cond.y" -{ - yyval.value = yyvsp[0].value; - ; - break;} -case 5: -#line 160 "./cond.y" -{ - yyval.value = yyvsp[-2].value && yyvsp[0].value; - ; - break;} -case 6: -#line 167 "./cond.y" -{ - yyval.value = yyvsp[0].value; - ; - break;} -case 7: -#line 171 "./cond.y" -{ - yyval.value = ! yyvsp[0].value; - ; - break;} -case 8: -#line 179 "./cond.y" -{ - yyval.value = yyvsp[0].value; - ; - break;} -case 9: -#line 183 "./cond.y" -{ - yyval.value = atoiW(yyvsp[0].string); - ; - break;} -case 10: -#line 187 "./cond.y" -{ - yyval.value = yyvsp[-1].fn_comp_int( yyvsp[-2].value, yyvsp[0].value ); - ; - break;} -case 11: -#line 191 "./cond.y" -{ - yyval.value = yyvsp[-1].fn_comp_str( yyvsp[-2].string, yyvsp[0].string, FALSE ); - ; - break;} -case 12: -#line 195 "./cond.y" -{ - yyval.value = yyvsp[-1].fn_comp_str( yyvsp[-3].string, yyvsp[0].string, TRUE ); - ; - break;} -case 13: -#line 199 "./cond.y" -{ - yyval.value = yyvsp[-1].fn_comp_m1( yyvsp[-2].string, yyvsp[0].value ); - ; - break;} -case 14: -#line 203 "./cond.y" -{ - yyval.value = yyvsp[-1].fn_comp_m2( yyvsp[-2].value, yyvsp[0].string ); - ; - break;} -case 15: -#line 207 "./cond.y" -{ - yyval.value = yyvsp[-1].value; - ; - break;} -case 16: -#line 215 "./cond.y" -{ - yyval.fn_comp_int = comp_eq_i; - ; - break;} -case 17: -#line 219 "./cond.y" -{ - yyval.fn_comp_int = comp_ne_i; - ; - break;} -case 18: -#line 223 "./cond.y" -{ - yyval.fn_comp_int = comp_lt_i; - ; - break;} -case 19: -#line 227 "./cond.y" -{ - yyval.fn_comp_int = comp_gt_i; - ; - break;} -case 20: -#line 231 "./cond.y" -{ - yyval.fn_comp_int = comp_le_i; - ; - break;} -case 21: -#line 235 "./cond.y" -{ - yyval.fn_comp_int = comp_ge_i; - ; - break;} -case 22: -#line 240 "./cond.y" -{ - yyval.fn_comp_int = comp_bitand; - ; - break;} -case 23: -#line 244 "./cond.y" -{ - yyval.fn_comp_int = comp_highcomp; - ; - break;} -case 24: -#line 248 "./cond.y" -{ - yyval.fn_comp_int = comp_lowcomp; - ; - break;} -case 25: -#line 256 "./cond.y" -{ - yyval.fn_comp_str = comp_eq_s; - ; - break;} -case 26: -#line 260 "./cond.y" -{ - yyval.fn_comp_str = comp_ne_s; - ; - break;} -case 27: -#line 264 "./cond.y" -{ - yyval.fn_comp_str = comp_lt_s; - ; - break;} -case 28: -#line 268 "./cond.y" -{ - yyval.fn_comp_str = comp_gt_s; - ; - break;} -case 29: -#line 272 "./cond.y" -{ - yyval.fn_comp_str = comp_le_s; - ; - break;} -case 30: -#line 276 "./cond.y" -{ - yyval.fn_comp_str = comp_ge_s; - ; - break;} -case 31: -#line 281 "./cond.y" -{ - yyval.fn_comp_str = comp_substring; - ; - break;} -case 32: -#line 285 "./cond.y" -{ - yyval.fn_comp_str = comp_start; - ; - break;} -case 33: -#line 289 "./cond.y" -{ - yyval.fn_comp_str = comp_end; - ; - break;} -case 34: -#line 297 "./cond.y" -{ - yyval.fn_comp_m1 = comp_eq_m1; - ; - break;} -case 35: -#line 301 "./cond.y" -{ - yyval.fn_comp_m1 = comp_ne_m1; - ; - break;} -case 36: -#line 305 "./cond.y" -{ - yyval.fn_comp_m1 = comp_lt_m1; - ; - break;} -case 37: -#line 309 "./cond.y" -{ - yyval.fn_comp_m1 = comp_gt_m1; - ; - break;} -case 38: -#line 313 "./cond.y" -{ - yyval.fn_comp_m1 = comp_le_m1; - ; - break;} -case 39: -#line 317 "./cond.y" -{ - yyval.fn_comp_m1 = comp_ge_m1; - ; - break;} -case 40: -#line 322 "./cond.y" -{ - yyval.fn_comp_m1 = 0; - ; - break;} -case 41: -#line 326 "./cond.y" -{ - yyval.fn_comp_m1 = 0; - ; - break;} -case 42: -#line 330 "./cond.y" -{ - yyval.fn_comp_m1 = 0; - ; - break;} -case 43: -#line 338 "./cond.y" -{ - yyval.fn_comp_m2 = comp_eq_m2; - ; - break;} -case 44: -#line 342 "./cond.y" -{ - yyval.fn_comp_m2 = comp_ne_m2; - ; - break;} -case 45: -#line 346 "./cond.y" -{ - yyval.fn_comp_m2 = comp_lt_m2; - ; - break;} -case 46: -#line 350 "./cond.y" -{ - yyval.fn_comp_m2 = comp_gt_m2; - ; - break;} -case 47: -#line 354 "./cond.y" -{ - yyval.fn_comp_m2 = comp_le_m2; - ; - break;} -case 48: -#line 358 "./cond.y" -{ - yyval.fn_comp_m2 = comp_ge_m2; - ; - break;} -case 49: -#line 363 "./cond.y" -{ - yyval.fn_comp_m2 = 0; - ; - break;} -case 50: -#line 367 "./cond.y" -{ - yyval.fn_comp_m2 = 0; - ; - break;} -case 51: -#line 371 "./cond.y" -{ - yyval.fn_comp_m2 = 0; - ; - break;} -case 52: -#line 378 "./cond.y" -{ - yyval.value = yyvsp[0].value; - ; - break;} -case 53: -#line 382 "./cond.y" -{ - yyval.value = yyvsp[0].value; - ; - break;} -case 54: -#line 389 "./cond.y" -{ - yyval.string = yyvsp[0].string; - ; - break;} -case 55: -#line 393 "./cond.y" -{ - yyval.string = yyvsp[0].string; - ; - break;} -case 56: -#line 400 "./cond.y" -{ - yyval.string = COND_GetLiteral(&yyvsp[0].str); - if( !yyval.string ) - YYABORT; - ; - break;} -case 57: -#line 409 "./cond.y" -{ - COND_input* cond = (COND_input*) info; - INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; - - MSI_GetComponentStateW(cond->package, yyvsp[0].string, &install, &action ); - yyval.value = action; - HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); - ; - break;} -case 58: -#line 418 "./cond.y" -{ - COND_input* cond = (COND_input*) info; - INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; - - MSI_GetComponentStateW(cond->package, yyvsp[0].string, &install, &action ); - yyval.value = install; - HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); - ; - break;} -case 59: -#line 427 "./cond.y" -{ - COND_input* cond = (COND_input*) info; - INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; - - MSI_GetFeatureStateW(cond->package, yyvsp[0].string, &install, &action ); - yyval.value = action; - HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); - ; - break;} -case 60: -#line 436 "./cond.y" -{ - COND_input* cond = (COND_input*) info; - INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; - - MSI_GetFeatureStateW(cond->package, yyvsp[0].string, &install, &action ); - yyval.value = install; - HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); - ; - break;} -case 61: -#line 448 "./cond.y" -{ - DWORD sz; - COND_input* cond = (COND_input*) info; - yyval.string = HeapAlloc( GetProcessHeap(), 0, 0x100*sizeof (WCHAR) ); - - /* Lookup the identifier */ - - sz=0x100; - if (MSI_GetPropertyW(cond->package,yyvsp[0].string,yyval.string,&sz) != ERROR_SUCCESS) - { - yyval.string[0]=0; - } - HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); - ; - break;} -case 62: -#line 463 "./cond.y" -{ - UINT len = GetEnvironmentVariableW( yyvsp[0].string, NULL, 0 ); - if( len++ ) - { - yyval.string = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) ); - if( yyval.string ) - GetEnvironmentVariableW( yyvsp[0].string, yyval.string, len ); - } - HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); - ; - break;} -case 63: -#line 477 "./cond.y" -{ - yyval.string = COND_GetString(&yyvsp[0].str); - if( !yyval.string ) - YYABORT; - ; - break;} -case 64: -#line 486 "./cond.y" -{ - LPWSTR szNum = COND_GetString(&yyvsp[0].str); - if( !szNum ) - YYABORT; - yyval.value = atoiW( szNum ); - HeapFree( GetProcessHeap(), 0, szNum ); - ; - break;} -} - -#line 705 "/usr/share/bison/bison.simple" - - - yyvsp -= yylen; - yyssp -= yylen; -#if YYLSP_NEEDED - yylsp -= yylen; -#endif - -#if YYDEBUG - if (yydebug) - { - short *yyssp1 = yyss - 1; - YYFPRINTF (stderr, "state stack now"); - while (yyssp1 != yyssp) - YYFPRINTF (stderr, " %d", *++yyssp1); - YYFPRINTF (stderr, "\n"); - } -#endif - - *++yyvsp = yyval; -#if YYLSP_NEEDED - *++yylsp = yyloc; -#endif - - /* Now `shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTBASE] + *yyssp; - if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTBASE]; - - goto yynewstate; - - -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ -yyerrlab: - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; - -#ifdef YYERROR_VERBOSE - yyn = yypact[yystate]; - - if (yyn > YYFLAG && yyn < YYLAST) - { - YYSIZE_T yysize = 0; - char *yymsg; - int yyx, yycount; - - yycount = 0; - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - for (yyx = yyn < 0 ? -yyn : 0; - yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) - if (yycheck[yyx + yyn] == yyx) - yysize += yystrlen (yytname[yyx]) + 15, yycount++; - yysize += yystrlen ("parse error, unexpected ") + 1; - yysize += yystrlen (yytname[YYTRANSLATE (yychar)]); - yymsg = (char *) YYSTACK_ALLOC (yysize); - if (yymsg != 0) - { - char *yyp = yystpcpy (yymsg, "parse error, unexpected "); - yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]); - - if (yycount < 5) - { - yycount = 0; - for (yyx = yyn < 0 ? -yyn : 0; - yyx < (int) (sizeof (yytname) / sizeof (char *)); - yyx++) - if (yycheck[yyx + yyn] == yyx) - { - const char *yyq = ! yycount ? ", expecting " : " or "; - yyp = yystpcpy (yyp, yyq); - yyp = yystpcpy (yyp, yytname[yyx]); - yycount++; - } - } - yyerror (yymsg); - YYSTACK_FREE (yymsg); - } - else - yyerror ("parse error; also virtual memory exhausted"); - } - else -#endif /* defined (YYERROR_VERBOSE) */ - yyerror ("parse error"); - } - goto yyerrlab1; - - -/*--------------------------------------------------. -| yyerrlab1 -- error raised explicitly by an action | -`--------------------------------------------------*/ -yyerrlab1: - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - /* return failure if at end of input */ - if (yychar == YYEOF) - YYABORT; - YYDPRINTF ((stderr, "Discarding token %d (%s).\n", - yychar, yytname[yychar1])); - yychar = YYEMPTY; - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - - yyerrstatus = 3; /* Each real token shifted decrements this */ - - goto yyerrhandle; - - -/*-------------------------------------------------------------------. -| yyerrdefault -- current state does not do anything special for the | -| error token. | -`-------------------------------------------------------------------*/ -yyerrdefault: -#if 0 - /* This is wrong; only states that explicitly want error tokens - should shift them. */ - - /* If its default is to accept any token, ok. Otherwise pop it. */ - yyn = yydefact[yystate]; - if (yyn) - goto yydefault; -#endif - - -/*---------------------------------------------------------------. -| yyerrpop -- pop the current state because it cannot handle the | -| error token | -`---------------------------------------------------------------*/ -yyerrpop: - if (yyssp == yyss) - YYABORT; - yyvsp--; - yystate = *--yyssp; -#if YYLSP_NEEDED - yylsp--; -#endif - -#if YYDEBUG - if (yydebug) - { - short *yyssp1 = yyss - 1; - YYFPRINTF (stderr, "Error: state stack now"); - while (yyssp1 != yyssp) - YYFPRINTF (stderr, " %d", *++yyssp1); - YYFPRINTF (stderr, "\n"); - } -#endif - -/*--------------. -| yyerrhandle. | -`--------------*/ -yyerrhandle: - yyn = yypact[yystate]; - if (yyn == YYFLAG) - goto yyerrdefault; - - yyn += YYTERROR; - if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) - goto yyerrdefault; - - yyn = yytable[yyn]; - if (yyn < 0) - { - if (yyn == YYFLAG) - goto yyerrpop; - yyn = -yyn; - goto yyreduce; - } - else if (yyn == 0) - goto yyerrpop; - - if (yyn == YYFINAL) - YYACCEPT; - - YYDPRINTF ((stderr, "Shifting error token, ")); - - *++yyvsp = yylval; -#if YYLSP_NEEDED - *++yylsp = yylloc; -#endif - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -/*---------------------------------------------. -| yyoverflowab -- parser overflow comes here. | -`---------------------------------------------*/ -yyoverflowlab: - yyerror ("parser stack overflow"); - yyresult = 2; - /* Fall through. */ - -yyreturn: -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif - return yyresult; -} -#line 495 "./cond.y" - - - -static int COND_IsAlpha( WCHAR x ) -{ - return( ( ( x >= 'A' ) && ( x <= 'Z' ) ) || - ( ( x >= 'a' ) && ( x <= 'z' ) ) || - ( ( x == '_' ) ) ); -} - -static int COND_IsNumber( WCHAR x ) -{ - return( (( x >= '0' ) && ( x <= '9' )) || (x =='-') || (x =='.') ); -} - - -/* the mess of comparison functions */ - -static INT comp_lt_i(INT a, INT b) -{ return (a < b); } -static INT comp_gt_i(INT a, INT b) -{ return (a > b); } -static INT comp_le_i(INT a, INT b) -{ return (a <= b); } -static INT comp_ge_i(INT a, INT b) -{ return (a >= b); } -static INT comp_eq_i(INT a, INT b) -{ return (a == b); } -static INT comp_ne_i(INT a, INT b) -{ return (a != b); } -static INT comp_bitand(INT a, INT b) -{ return a & b;} -static INT comp_highcomp(INT a, INT b) -{ return HIWORD(a)==b; } -static INT comp_lowcomp(INT a, INT b) -{ return LOWORD(a)==b; } - -static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return !strcmpiW(a,b); else return !strcmpW(a,b);} -static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b); else return strcmpW(a,b);} -static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)<0; else return strcmpW(a,b)<0;} -static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)>0; else return strcmpW(a,b)>0;} -static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)<=0; else return strcmpW(a,b)<=0;} -static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)>=0; else return strcmpW(a,b)>=0;} -static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless) -/* ERROR NOT WORKING REWRITE */ -{ if (casless) return strstrW(a,b)!=NULL; else return strstrW(a,b)!=NULL;} -static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strncmpiW(a,b,strlenW(b))==0; - else return strncmpW(a,b,strlenW(b))==0;} -static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless) -{ - int i = strlenW(a); - int j = strlenW(b); - if (j>i) - return 0; - if (casless) return (!strcmpiW(&a[i-j-1],b)); - else return (!strcmpW(&a[i-j-1],b)); -} - - -static INT comp_eq_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)==b; else return 0;} -static INT comp_ne_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)!=b; else return 1;} -static INT comp_lt_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)b; else return 0;} -static INT comp_le_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)<=b; else return 0;} -static INT comp_ge_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)>=b; else return 0;} - -static INT comp_eq_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a == atoiW(b); else return 0;} -static INT comp_ne_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a != atoiW(b); else return 1;} -static INT comp_lt_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a < atoiW(b); else return 0;} -static INT comp_gt_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a > atoiW(b); else return 0;} -static INT comp_le_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a <= atoiW(b); else return 0;} -static INT comp_ge_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a >= atoiW(b); else return 0;} - - - -static int COND_IsIdent( WCHAR x ) -{ - return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' ) - || ( x == '#' ) || (x == '.') ); -} - -static int COND_GetOne( struct cond_str *str, COND_input *cond ) -{ - static const WCHAR szNot[] = {'N','O','T',0}; - static const WCHAR szAnd[] = {'A','N','D',0}; - static const WCHAR szOr[] = {'O','R',0}; - WCHAR ch; - int rc, len = 1; - - str->data = &cond->str[cond->n]; - - ch = str->data[0]; - switch( ch ) - { - case 0: return 0; - case '(': rc = COND_LPAR; break; - case ')': rc = COND_RPAR; break; - case '&': rc = COND_AMPER; break; - case '!': rc = COND_EXCLAM; break; - case '$': rc = COND_DOLLARS; break; - case '?': rc = COND_QUESTION; break; - case '%': rc = COND_PERCENT; break; - case ' ': rc = COND_SPACE; break; - case '=': rc = COND_EQ; break; - case '~': rc = COND_TILDA; break; - case '<': rc = COND_LT; break; - case '>': rc = COND_GT; break; - case '"': - { - const WCHAR *ch2 = str->data + 1; - - - while ( *ch2 && *ch2 != '"' ) - ++ch2; - if (*ch2 == '"') - { - len = ch2 - str->data + 1; - rc = COND_LITER; - break; - } - } - ERR("Unterminated string\n"); - rc = COND_ERROR; - break; - default: - if( COND_IsAlpha( ch ) ) - { - while( COND_IsIdent( str->data[len] ) ) - len++; - rc = COND_IDENT; - break; - } - - if( COND_IsNumber( ch ) ) - { - while( COND_IsNumber( str->data[len] ) ) - len++; - rc = COND_NUMBER; - break; - } - - ERR("Got unknown character %c(%x)\n",ch,ch); - rc = COND_ERROR; - break; - } - - /* keyword identifiers */ - if( rc == COND_IDENT ) - { - if( (len==3) && (strncmpiW(str->data,szNot,len)==0) ) - rc = COND_NOT; - else if( (len==3) && (strncmpiW(str->data,szAnd,len)==0) ) - rc = COND_AND; - else if( (len==2) && (strncmpiW(str->data,szOr,len)==0) ) - rc = COND_OR; - } - - cond->n += len; - str->len = len; - - return rc; -} - -static int COND_lex( void *COND_lval, COND_input *cond ) -{ - int rc; - struct cond_str *str = COND_lval; - - do { - rc = COND_GetOne( str, cond ); - } while (rc == COND_SPACE); - - return rc; -} - -static LPWSTR COND_GetString( struct cond_str *str ) -{ - LPWSTR ret; - - ret = HeapAlloc( GetProcessHeap(), 0, (str->len+1) * sizeof (WCHAR) ); - if( ret ) - { - strncpyW( ret, str->data, str->len ); - ret[str->len]=0; - } - TRACE("Got identifier %s\n",debugstr_w(ret)); - return ret; -} - -static LPWSTR COND_GetLiteral( struct cond_str *str ) -{ - LPWSTR ret; - - ret = HeapAlloc( GetProcessHeap(), 0, (str->len-1) * sizeof (WCHAR) ); - if( ret ) - { - memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) ); - ret[str->len - 2]=0; - } - TRACE("Got literal %s\n",debugstr_w(ret)); - return ret; -} - -static int COND_error(char *str) -{ - return 0; -} - -MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition ) -{ - COND_input cond; - MSICONDITION r; - - cond.package = package; - cond.str = szCondition; - cond.n = 0; - cond.result = -1; - - TRACE("Evaluating %s\n",debugstr_w(szCondition)); - - if( !COND_parse( &cond ) ) - r = cond.result; - else - r = MSICONDITION_ERROR; - - TRACE("Evaluates to %i\n",r); - return r; -} - -MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition ) -{ - MSIPACKAGE *package; - UINT ret; - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); - if( !package) - return ERROR_INVALID_HANDLE; - ret = MSI_EvaluateConditionW( package, szCondition ); - msiobj_release( &package->hdr ); - return ret; -} - -MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition ) -{ - LPWSTR szwCond = NULL; - MSICONDITION r; - - if( szCondition ) - { - UINT len = MultiByteToWideChar( CP_ACP, 0, szCondition, -1, NULL, 0 ); - szwCond = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, szCondition, -1, szwCond, len ); - } - - r = MsiEvaluateConditionW( hInstall, szwCond ); - - if( szwCond ) - HeapFree( GetProcessHeap(), 0, szwCond ); - - return r; -} +/* A Bison parser, made by GNU Bison 1.875b. */ + +/* 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. */ + +/* Written by Richard Stallman by simplifying the original so called + ``semantic'' parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + +/* If NAME_PREFIX is specified substitute the variables and functions + names. */ +#define yyparse COND_parse +#define yylex COND_lex +#define yyerror COND_error +#define yylval COND_lval +#define yychar COND_char +#define yydebug COND_debug +#define yynerrs COND_nerrs + + +/* 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 + + + + +/* Copy the first part of user declarations. */ +#line 1 "./cond.y" + + +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2003 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +#include "msi.h" +#include "msiquery.h" +#include "msipriv.h" + +#define YYLEX_PARAM info +#define YYPARSE_PARAM info + +static int COND_error(char *str); + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +typedef struct tag_yyinput +{ + MSIPACKAGE *package; + LPCWSTR str; + INT n; + MSICONDITION result; +} COND_input; + +struct cond_str { + LPCWSTR data; + INT len; +}; + +static LPWSTR COND_GetString( struct cond_str *str ); +static LPWSTR COND_GetLiteral( struct cond_str *str ); +static int COND_lex( void *COND_lval, COND_input *info); + +typedef INT (*comp_int)(INT a, INT b); +typedef INT (*comp_str)(LPWSTR a, LPWSTR b, BOOL caseless); +typedef INT (*comp_m1)(LPWSTR a,int b); +typedef INT (*comp_m2)(int a,LPWSTR b); + +static INT comp_lt_i(INT a, INT b); +static INT comp_gt_i(INT a, INT b); +static INT comp_le_i(INT a, INT b); +static INT comp_ge_i(INT a, INT b); +static INT comp_eq_i(INT a, INT b); +static INT comp_ne_i(INT a, INT b); +static INT comp_bitand(INT a, INT b); +static INT comp_highcomp(INT a, INT b); +static INT comp_lowcomp(INT a, INT b); + +static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless); + +static INT comp_eq_m1(LPWSTR a, INT b); +static INT comp_ne_m1(LPWSTR a, INT b); +static INT comp_lt_m1(LPWSTR a, INT b); +static INT comp_gt_m1(LPWSTR a, INT b); +static INT comp_le_m1(LPWSTR a, INT b); +static INT comp_ge_m1(LPWSTR a, INT b); + +static INT comp_eq_m2(INT a, LPWSTR b); +static INT comp_ne_m2(INT a, LPWSTR b); +static INT comp_lt_m2(INT a, LPWSTR b); +static INT comp_gt_m2(INT a, LPWSTR b); +static INT comp_le_m2(INT a, LPWSTR b); +static INT comp_ge_m2(INT a, LPWSTR b); + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) +#line 106 "./cond.y" +typedef union YYSTYPE { + struct cond_str str; + LPWSTR string; + INT value; + comp_int fn_comp_int; + comp_str fn_comp_str; + comp_m1 fn_comp_m1; + comp_m2 fn_comp_m2; +} YYSTYPE; +/* Line 191 of yacc.c. */ +#line 241 "cond.tab.c" +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +/* Copy the second part of user declarations. */ + + +/* Line 214 of yacc.c. */ +#line 253 "cond.tab.c" + +#if ! defined (yyoverflow) || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# if YYSTACK_USE_ALLOCA +# define YYSTACK_ALLOC alloca +# else +# ifndef YYSTACK_USE_ALLOCA +# if defined (alloca) || defined (_ALLOCA_H) +# define YYSTACK_ALLOC alloca +# else +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# else +# if defined (__STDC__) || defined (__cplusplus) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +# define YYSTACK_ALLOC malloc +# define YYSTACK_FREE free +# endif +#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */ + + +#if (! defined (yyoverflow) \ + && (! defined (__cplusplus) \ + || (YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + short yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + register YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (0) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined (__STDC__) || defined (__cplusplus) + typedef signed char yysigned_char; +#else + typedef short yysigned_char; +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 30 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 146 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 23 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 17 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 65 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 74 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 277 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const unsigned char yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const unsigned char yyprhs[] = +{ + 0, 0, 3, 5, 7, 11, 13, 17, 19, 22, + 24, 26, 30, 34, 39, 43, 47, 51, 53, 56, + 58, 60, 63, 66, 69, 72, 75, 77, 80, 82, + 84, 87, 90, 93, 96, 99, 101, 104, 106, 108, + 111, 114, 117, 120, 123, 125, 128, 130, 132, 135, + 138, 141, 144, 147, 149, 151, 153, 155, 157, 160, + 163, 166, 169, 171, 174, 176 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yysigned_char yyrhs[] = +{ + 24, 0, -1, 25, -1, 26, -1, 26, 5, 25, + -1, 27, -1, 26, 6, 27, -1, 28, -1, 7, + 28, -1, 33, -1, 34, -1, 33, 29, 33, -1, + 34, 30, 34, -1, 34, 13, 30, 34, -1, 34, + 31, 33, -1, 33, 32, 34, -1, 11, 25, 12, + -1, 10, -1, 8, 9, -1, 8, -1, 9, -1, + 8, 10, -1, 9, 10, -1, 9, 8, -1, 8, + 8, -1, 9, 9, -1, 10, -1, 8, 9, -1, + 8, -1, 9, -1, 8, 10, -1, 9, 10, -1, + 9, 8, -1, 8, 8, -1, 9, 9, -1, 10, + -1, 8, 9, -1, 8, -1, 9, -1, 8, 10, + -1, 9, 10, -1, 9, 8, -1, 8, 8, -1, + 9, 9, -1, 10, -1, 8, 9, -1, 8, -1, + 9, -1, 8, 10, -1, 9, 10, -1, 9, 8, + -1, 8, 8, -1, 9, 9, -1, 36, -1, 39, + -1, 37, -1, 35, -1, 21, -1, 15, 38, -1, + 16, 38, -1, 17, 38, -1, 18, 38, -1, 38, + -1, 14, 38, -1, 19, -1, 20, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const unsigned short yyrline[] = +{ + 0, 136, 136, 144, 148, 155, 159, 166, 170, 178, + 182, 186, 190, 194, 198, 202, 206, 214, 218, 222, + 226, 230, 234, 239, 243, 247, 255, 259, 263, 267, + 271, 275, 280, 284, 288, 296, 300, 304, 308, 312, + 316, 321, 325, 329, 337, 341, 345, 349, 353, 357, + 362, 366, 370, 377, 381, 388, 392, 399, 408, 417, + 426, 435, 447, 470, 484, 493 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE +/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "COND_SPACE", "COND_EOF", "COND_OR", + "COND_AND", "COND_NOT", "COND_LT", "COND_GT", "COND_EQ", "COND_LPAR", + "COND_RPAR", "COND_TILDA", "COND_PERCENT", "COND_DOLLARS", + "COND_QUESTION", "COND_AMPER", "COND_EXCLAM", "COND_IDENT", + "COND_NUMBER", "COND_LITER", "COND_ERROR", "$accept", "condition", + "expression", "boolean_term", "boolean_factor", "term", "comp_op_i", + "comp_op_s", "comp_op_m1", "comp_op_m2", "value_i", "value_s", + "literal", "symbol_i", "symbol_s", "identifier", "integer", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const unsigned short yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const unsigned char yyr1[] = +{ + 0, 23, 24, 25, 25, 26, 26, 27, 27, 28, + 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 33, 33, 34, 34, 35, 36, 36, + 36, 36, 37, 37, 38, 39 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const unsigned char yyr2[] = +{ + 0, 2, 1, 1, 3, 1, 3, 1, 2, 1, + 1, 3, 3, 4, 3, 3, 3, 1, 2, 1, + 1, 2, 2, 2, 2, 2, 1, 2, 1, 1, + 2, 2, 2, 2, 2, 1, 2, 1, 1, 2, + 2, 2, 2, 2, 1, 2, 1, 1, 2, 2, + 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, + 2, 2, 1, 2, 1, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const unsigned char yydefact[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 64, 65, + 57, 0, 2, 3, 5, 7, 9, 10, 56, 53, + 55, 62, 54, 8, 0, 63, 58, 59, 60, 61, + 1, 0, 0, 19, 20, 17, 0, 0, 37, 38, + 35, 0, 0, 0, 16, 4, 6, 24, 18, 21, + 23, 25, 22, 11, 15, 42, 36, 39, 41, 43, + 40, 28, 29, 26, 0, 12, 14, 33, 27, 30, + 32, 34, 31, 13 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yysigned_char yydefgoto[] = +{ + -1, 11, 12, 13, 14, 15, 36, 42, 43, 37, + 16, 17, 18, 19, 20, 21, 22 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -37 +static const short yypact[] = +{ + -4, 51, -4, -11, -11, -11, -11, -11, -37, -37, + -37, 18, -37, -1, -37, -37, 49, 14, -37, -37, + -37, -37, -37, -37, 19, -37, -37, -37, -37, -37, + -37, -4, -4, 11, 25, 34, 111, 59, 28, 42, + 60, 130, 59, 111, -37, -37, -37, 63, 69, 72, + 73, 81, 82, -37, -37, 85, 91, 94, 95, 103, + 104, 133, 136, -37, 59, -37, -37, -37, -37, -37, + -37, -37, -37, -37 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const short yypgoto[] = +{ + -37, -37, -2, -37, -6, 39, -37, 0, -37, -37, + -34, -36, -37, -37, -37, 129, -37 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -53 +static const yysigned_char yytable[] = +{ + 24, 54, 53, 1, 31, 32, 65, 2, 8, 66, + 3, 4, 5, 6, 7, 8, 9, 10, 30, 47, + 48, 49, 38, 39, 40, -46, 46, 41, 73, 45, + -46, 44, -46, 50, 51, 52, 55, 56, 57, -47, + 23, 64, -28, 0, -47, 0, -47, -28, -44, -28, + 58, 59, 60, -44, 0, -44, -29, 33, 34, 35, + 0, -29, 2, -29, 0, 3, 4, 5, 6, 7, + 8, 9, 10, 3, -26, 0, 0, -51, 8, -26, + 10, -26, -51, -45, -51, 0, -48, -50, -45, 0, + -45, -48, -50, -48, -50, -52, -49, 0, 0, -33, + -52, -49, -52, -49, -33, -27, -33, 0, -30, -32, + -27, 0, -27, -30, -32, -30, -32, -34, -31, 0, + 0, 0, -34, -31, -34, -31, 4, 5, 6, 7, + 0, 9, 25, 26, 27, 28, 29, 0, 61, 62, + 63, 67, 68, 69, 70, 71, 72 +}; + +static const yysigned_char yycheck[] = +{ + 2, 37, 36, 7, 5, 6, 42, 11, 19, 43, + 14, 15, 16, 17, 18, 19, 20, 21, 0, 8, + 9, 10, 8, 9, 10, 14, 32, 13, 64, 31, + 19, 12, 21, 8, 9, 10, 8, 9, 10, 14, + 1, 41, 14, -1, 19, -1, 21, 19, 14, 21, + 8, 9, 10, 19, -1, 21, 14, 8, 9, 10, + -1, 19, 11, 21, -1, 14, 15, 16, 17, 18, + 19, 20, 21, 14, 14, -1, -1, 14, 19, 19, + 21, 21, 19, 14, 21, -1, 14, 14, 19, -1, + 21, 19, 19, 21, 21, 14, 14, -1, -1, 14, + 19, 19, 21, 21, 19, 14, 21, -1, 14, 14, + 19, -1, 21, 19, 19, 21, 21, 14, 14, -1, + -1, -1, 19, 19, 21, 21, 15, 16, 17, 18, + -1, 20, 3, 4, 5, 6, 7, -1, 8, 9, + 10, 8, 9, 10, 8, 9, 10 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const unsigned char yystos[] = +{ + 0, 7, 11, 14, 15, 16, 17, 18, 19, 20, + 21, 24, 25, 26, 27, 28, 33, 34, 35, 36, + 37, 38, 39, 28, 25, 38, 38, 38, 38, 38, + 0, 5, 6, 8, 9, 10, 29, 32, 8, 9, + 10, 13, 30, 31, 12, 25, 27, 8, 9, 10, + 8, 9, 10, 33, 34, 8, 9, 10, 8, 9, + 10, 8, 9, 10, 30, 34, 33, 8, 9, 10, + 8, 9, 10, 34 +}; + +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# if defined (__STDC__) || defined (__cplusplus) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int +#endif + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrlab1 + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror ("syntax error: cannot back up");\ + YYERROR; \ + } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +/* YYLLOC_DEFAULT -- Compute the default location (before the actions + are run). */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + Current.first_line = Rhs[1].first_line; \ + Current.first_column = Rhs[1].first_column; \ + Current.last_line = Rhs[N].last_line; \ + Current.last_column = Rhs[N].last_column; +#endif + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, YYLEX_PARAM) +#else +# define YYLEX yylex (&yylval) +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +# define YYDSYMPRINT(Args) \ +do { \ + if (yydebug) \ + yysymprint Args; \ +} while (0) + +# define YYDSYMPRINTF(Title, Token, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yysymprint (stderr, \ + Token, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (cinluded). | +`------------------------------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yy_stack_print (short *bottom, short *top) +#else +static void +yy_stack_print (bottom, top) + short *bottom; + short *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (/* Nothing. */; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yy_reduce_print (int yyrule) +#else +static void +yy_reduce_print (yyrule) + int yyrule; +#endif +{ + int yyi; + unsigned int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ", + yyrule - 1, yylno); + /* Print the symbols being reduced, and their result. */ + for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++) + YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]); + YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]); +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (Rule); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YYDSYMPRINT(Args) +# define YYDSYMPRINTF(Title, Token, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#if YYMAXDEPTH == 0 +# undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +yystrlen (const char *yystr) +# else +yystrlen (yystr) + const char *yystr; +# endif +{ + register const char *yys = yystr; + + while (*yys++ != '\0') + continue; + + return yys - yystr - 1; +} +# endif +# endif + +# ifndef yystpcpy +# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +yystpcpy (char *yydest, const char *yysrc) +# else +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +# endif +{ + register char *yyd = yydest; + register const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +#endif /* !YYERROR_VERBOSE */ + + + +#if YYDEBUG +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep) +#else +static void +yysymprint (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + /* Pacify ``unused variable'' warnings. */ + (void) yyvaluep; + + if (yytype < YYNTOKENS) + { + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); +# ifdef YYPRINT + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + } + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + switch (yytype) + { + default: + break; + } + YYFPRINTF (yyoutput, ")"); +} + +#endif /* ! YYDEBUG */ +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yydestruct (int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yytype, yyvaluep) + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + /* Pacify ``unused variable'' warnings. */ + (void) yyvaluep; + + switch (yytype) + { + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +int yyparse (void *YYPARSE_PARAM); +# else +int yyparse (); +# endif +#else /* ! YYPARSE_PARAM */ +#if defined (__STDC__) || defined (__cplusplus) +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +int yyparse (void *YYPARSE_PARAM) +# else +int yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +# endif +#else /* ! YYPARSE_PARAM */ +#if defined (__STDC__) || defined (__cplusplus) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + /* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + register int yystate; + register int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + short yyssa[YYINITDEPTH]; + short *yyss = yyssa; + register short *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + register YYSTYPE *yyvsp; + + + +#define YYPOPSTACK (yyvsp--, yyssp--) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ + int yylen; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. + */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyoverflowlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyoverflowlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + short *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyoverflowlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken])); + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; + + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + yystate = yyn; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: +#line 137 "./cond.y" + { + COND_input* cond = (COND_input*) info; + cond->result = yyvsp[0].value; + ;} + break; + + case 3: +#line 145 "./cond.y" + { + yyval.value = yyvsp[0].value; + ;} + break; + + case 4: +#line 149 "./cond.y" + { + yyval.value = yyvsp[-2].value || yyvsp[0].value; + ;} + break; + + case 5: +#line 156 "./cond.y" + { + yyval.value = yyvsp[0].value; + ;} + break; + + case 6: +#line 160 "./cond.y" + { + yyval.value = yyvsp[-2].value && yyvsp[0].value; + ;} + break; + + case 7: +#line 167 "./cond.y" + { + yyval.value = yyvsp[0].value; + ;} + break; + + case 8: +#line 171 "./cond.y" + { + yyval.value = ! yyvsp[0].value; + ;} + break; + + case 9: +#line 179 "./cond.y" + { + yyval.value = yyvsp[0].value; + ;} + break; + + case 10: +#line 183 "./cond.y" + { + yyval.value = yyvsp[0].string[0] ? MSICONDITION_TRUE : MSICONDITION_FALSE; + ;} + break; + + case 11: +#line 187 "./cond.y" + { + yyval.value = yyvsp[-1].fn_comp_int( yyvsp[-2].value, yyvsp[0].value ); + ;} + break; + + case 12: +#line 191 "./cond.y" + { + yyval.value = yyvsp[-1].fn_comp_str( yyvsp[-2].string, yyvsp[0].string, FALSE ); + ;} + break; + + case 13: +#line 195 "./cond.y" + { + yyval.value = yyvsp[-1].fn_comp_str( yyvsp[-3].string, yyvsp[0].string, TRUE ); + ;} + break; + + case 14: +#line 199 "./cond.y" + { + yyval.value = yyvsp[-1].fn_comp_m1( yyvsp[-2].string, yyvsp[0].value ); + ;} + break; + + case 15: +#line 203 "./cond.y" + { + yyval.value = yyvsp[-1].fn_comp_m2( yyvsp[-2].value, yyvsp[0].string ); + ;} + break; + + case 16: +#line 207 "./cond.y" + { + yyval.value = yyvsp[-1].value; + ;} + break; + + case 17: +#line 215 "./cond.y" + { + yyval.fn_comp_int = comp_eq_i; + ;} + break; + + case 18: +#line 219 "./cond.y" + { + yyval.fn_comp_int = comp_ne_i; + ;} + break; + + case 19: +#line 223 "./cond.y" + { + yyval.fn_comp_int = comp_lt_i; + ;} + break; + + case 20: +#line 227 "./cond.y" + { + yyval.fn_comp_int = comp_gt_i; + ;} + break; + + case 21: +#line 231 "./cond.y" + { + yyval.fn_comp_int = comp_le_i; + ;} + break; + + case 22: +#line 235 "./cond.y" + { + yyval.fn_comp_int = comp_ge_i; + ;} + break; + + case 23: +#line 240 "./cond.y" + { + yyval.fn_comp_int = comp_bitand; + ;} + break; + + case 24: +#line 244 "./cond.y" + { + yyval.fn_comp_int = comp_highcomp; + ;} + break; + + case 25: +#line 248 "./cond.y" + { + yyval.fn_comp_int = comp_lowcomp; + ;} + break; + + case 26: +#line 256 "./cond.y" + { + yyval.fn_comp_str = comp_eq_s; + ;} + break; + + case 27: +#line 260 "./cond.y" + { + yyval.fn_comp_str = comp_ne_s; + ;} + break; + + case 28: +#line 264 "./cond.y" + { + yyval.fn_comp_str = comp_lt_s; + ;} + break; + + case 29: +#line 268 "./cond.y" + { + yyval.fn_comp_str = comp_gt_s; + ;} + break; + + case 30: +#line 272 "./cond.y" + { + yyval.fn_comp_str = comp_le_s; + ;} + break; + + case 31: +#line 276 "./cond.y" + { + yyval.fn_comp_str = comp_ge_s; + ;} + break; + + case 32: +#line 281 "./cond.y" + { + yyval.fn_comp_str = comp_substring; + ;} + break; + + case 33: +#line 285 "./cond.y" + { + yyval.fn_comp_str = comp_start; + ;} + break; + + case 34: +#line 289 "./cond.y" + { + yyval.fn_comp_str = comp_end; + ;} + break; + + case 35: +#line 297 "./cond.y" + { + yyval.fn_comp_m1 = comp_eq_m1; + ;} + break; + + case 36: +#line 301 "./cond.y" + { + yyval.fn_comp_m1 = comp_ne_m1; + ;} + break; + + case 37: +#line 305 "./cond.y" + { + yyval.fn_comp_m1 = comp_lt_m1; + ;} + break; + + case 38: +#line 309 "./cond.y" + { + yyval.fn_comp_m1 = comp_gt_m1; + ;} + break; + + case 39: +#line 313 "./cond.y" + { + yyval.fn_comp_m1 = comp_le_m1; + ;} + break; + + case 40: +#line 317 "./cond.y" + { + yyval.fn_comp_m1 = comp_ge_m1; + ;} + break; + + case 41: +#line 322 "./cond.y" + { + yyval.fn_comp_m1 = 0; + ;} + break; + + case 42: +#line 326 "./cond.y" + { + yyval.fn_comp_m1 = 0; + ;} + break; + + case 43: +#line 330 "./cond.y" + { + yyval.fn_comp_m1 = 0; + ;} + break; + + case 44: +#line 338 "./cond.y" + { + yyval.fn_comp_m2 = comp_eq_m2; + ;} + break; + + case 45: +#line 342 "./cond.y" + { + yyval.fn_comp_m2 = comp_ne_m2; + ;} + break; + + case 46: +#line 346 "./cond.y" + { + yyval.fn_comp_m2 = comp_lt_m2; + ;} + break; + + case 47: +#line 350 "./cond.y" + { + yyval.fn_comp_m2 = comp_gt_m2; + ;} + break; + + case 48: +#line 354 "./cond.y" + { + yyval.fn_comp_m2 = comp_le_m2; + ;} + break; + + case 49: +#line 358 "./cond.y" + { + yyval.fn_comp_m2 = comp_ge_m2; + ;} + break; + + case 50: +#line 363 "./cond.y" + { + yyval.fn_comp_m2 = 0; + ;} + break; + + case 51: +#line 367 "./cond.y" + { + yyval.fn_comp_m2 = 0; + ;} + break; + + case 52: +#line 371 "./cond.y" + { + yyval.fn_comp_m2 = 0; + ;} + break; + + case 53: +#line 378 "./cond.y" + { + yyval.value = yyvsp[0].value; + ;} + break; + + case 54: +#line 382 "./cond.y" + { + yyval.value = yyvsp[0].value; + ;} + break; + + case 55: +#line 389 "./cond.y" + { + yyval.string = yyvsp[0].string; + ;} + break; + + case 56: +#line 393 "./cond.y" + { + yyval.string = yyvsp[0].string; + ;} + break; + + case 57: +#line 400 "./cond.y" + { + yyval.string = COND_GetLiteral(&yyvsp[0].str); + if( !yyval.string ) + YYABORT; + ;} + break; + + case 58: +#line 409 "./cond.y" + { + COND_input* cond = (COND_input*) info; + INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; + + MSI_GetComponentStateW(cond->package, yyvsp[0].string, &install, &action ); + yyval.value = action; + HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); + ;} + break; + + case 59: +#line 418 "./cond.y" + { + COND_input* cond = (COND_input*) info; + INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; + + MSI_GetComponentStateW(cond->package, yyvsp[0].string, &install, &action ); + yyval.value = install; + HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); + ;} + break; + + case 60: +#line 427 "./cond.y" + { + COND_input* cond = (COND_input*) info; + INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; + + MSI_GetFeatureStateW(cond->package, yyvsp[0].string, &install, &action ); + yyval.value = action; + HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); + ;} + break; + + case 61: +#line 436 "./cond.y" + { + COND_input* cond = (COND_input*) info; + INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; + + MSI_GetFeatureStateW(cond->package, yyvsp[0].string, &install, &action ); + yyval.value = install; + HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); + ;} + break; + + case 62: +#line 448 "./cond.y" + { + DWORD sz; + COND_input* cond = (COND_input*) info; + + sz = 0; + MSI_GetPropertyW(cond->package, yyvsp[0].string, NULL, &sz); + if (sz == 0) + { + yyval.string = HeapAlloc( GetProcessHeap(), 0 ,sizeof(WCHAR)); + yyval.string[0] = 0; + } + else + { + sz ++; + yyval.string = HeapAlloc( GetProcessHeap(), 0, sz*sizeof (WCHAR) ); + + /* Lookup the identifier */ + + MSI_GetPropertyW(cond->package,yyvsp[0].string,yyval.string,&sz); + } + HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); + ;} + break; + + case 63: +#line 471 "./cond.y" + { + UINT len = GetEnvironmentVariableW( yyvsp[0].string, NULL, 0 ); + if( len++ ) + { + yyval.string = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) ); + if( yyval.string ) + GetEnvironmentVariableW( yyvsp[0].string, yyval.string, len ); + } + HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); + ;} + break; + + case 64: +#line 485 "./cond.y" + { + yyval.string = COND_GetString(&yyvsp[0].str); + if( !yyval.string ) + YYABORT; + ;} + break; + + case 65: +#line 494 "./cond.y" + { + LPWSTR szNum = COND_GetString(&yyvsp[0].str); + if( !szNum ) + YYABORT; + yyval.value = atoiW( szNum ); + HeapFree( GetProcessHeap(), 0, szNum ); + ;} + break; + + + } + +/* Line 999 of yacc.c. */ +#line 1719 "cond.tab.c" + + yyvsp -= yylen; + yyssp -= yylen; + + + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (YYPACT_NINF < yyn && yyn < YYLAST) + { + YYSIZE_T yysize = 0; + int yytype = YYTRANSLATE (yychar); + const char* yyprefix; + char *yymsg; + int yyx; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 0; + + yyprefix = ", expecting "; + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]); + yycount += 1; + if (yycount == 5) + { + yysize = 0; + break; + } + } + yysize += (sizeof ("syntax error, unexpected ") + + yystrlen (yytname[yytype])); + yymsg = (char *) YYSTACK_ALLOC (yysize); + if (yymsg != 0) + { + char *yyp = yystpcpy (yymsg, "syntax error, unexpected "); + yyp = yystpcpy (yyp, yytname[yytype]); + + if (yycount < 5) + { + yyprefix = ", expecting "; + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + yyp = yystpcpy (yyp, yyprefix); + yyp = yystpcpy (yyp, yytname[yyx]); + yyprefix = " or "; + } + } + yyerror (yymsg); + YYSTACK_FREE (yymsg); + } + else + yyerror ("syntax error; also virtual memory exhausted"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror ("syntax error"); + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + /* Return failure if at end of input. */ + if (yychar == YYEOF) + { + /* Pop the error token. */ + YYPOPSTACK; + /* Pop the rest of the stack. */ + while (yyss < yyssp) + { + YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); + yydestruct (yystos[*yyssp], yyvsp); + YYPOPSTACK; + } + YYABORT; + } + + YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc); + yydestruct (yytoken, &yylval); + yychar = YYEMPTY; + + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*----------------------------------------------------. +| yyerrlab1 -- error raised explicitly by an action. | +`----------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); + yydestruct (yystos[yystate], yyvsp); + yyvsp--; + yystate = *--yyssp; + + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + YYDPRINTF ((stderr, "Shifting error token, ")); + + *++yyvsp = yylval; + + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*----------------------------------------------. +| yyoverflowlab -- parser overflow comes here. | +`----------------------------------------------*/ +yyoverflowlab: + yyerror ("parser stack overflow"); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + return yyresult; +} + + +#line 503 "./cond.y" + + + +static int COND_IsAlpha( WCHAR x ) +{ + return( ( ( x >= 'A' ) && ( x <= 'Z' ) ) || + ( ( x >= 'a' ) && ( x <= 'z' ) ) || + ( ( x == '_' ) ) ); +} + +static int COND_IsNumber( WCHAR x ) +{ + return( (( x >= '0' ) && ( x <= '9' )) || (x =='-') || (x =='.') ); +} + + +/* the mess of comparison functions */ + +static INT comp_lt_i(INT a, INT b) +{ return (a < b); } +static INT comp_gt_i(INT a, INT b) +{ return (a > b); } +static INT comp_le_i(INT a, INT b) +{ return (a <= b); } +static INT comp_ge_i(INT a, INT b) +{ return (a >= b); } +static INT comp_eq_i(INT a, INT b) +{ return (a == b); } +static INT comp_ne_i(INT a, INT b) +{ return (a != b); } +static INT comp_bitand(INT a, INT b) +{ return a & b;} +static INT comp_highcomp(INT a, INT b) +{ return HIWORD(a)==b; } +static INT comp_lowcomp(INT a, INT b) +{ return LOWORD(a)==b; } + +static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return !strcmpiW(a,b); else return !strcmpW(a,b);} +static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return strcmpiW(a,b); else return strcmpW(a,b);} +static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return strcmpiW(a,b)<0; else return strcmpW(a,b)<0;} +static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return strcmpiW(a,b)>0; else return strcmpW(a,b)>0;} +static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return strcmpiW(a,b)<=0; else return strcmpW(a,b)<=0;} +static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return strcmpiW(a,b)>=0; else return strcmpW(a,b)>=0;} +static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless) +/* ERROR NOT WORKING REWRITE */ +{ if (casless) return strstrW(a,b)!=NULL; else return strstrW(a,b)!=NULL;} +static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return strncmpiW(a,b,strlenW(b))==0; + else return strncmpW(a,b,strlenW(b))==0;} +static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless) +{ + int i = strlenW(a); + int j = strlenW(b); + if (j>i) + return 0; + if (casless) return (!strcmpiW(&a[i-j-1],b)); + else return (!strcmpW(&a[i-j-1],b)); +} + + +static INT comp_eq_m1(LPWSTR a, INT b) +{ if (COND_IsNumber(a[0])) return atoiW(a)==b; else return 0;} +static INT comp_ne_m1(LPWSTR a, INT b) +{ if (COND_IsNumber(a[0])) return atoiW(a)!=b; else return 1;} +static INT comp_lt_m1(LPWSTR a, INT b) +{ if (COND_IsNumber(a[0])) return atoiW(a)b; else return 0;} +static INT comp_le_m1(LPWSTR a, INT b) +{ if (COND_IsNumber(a[0])) return atoiW(a)<=b; else return 0;} +static INT comp_ge_m1(LPWSTR a, INT b) +{ if (COND_IsNumber(a[0])) return atoiW(a)>=b; else return 0;} + +static INT comp_eq_m2(INT a, LPWSTR b) +{ if (COND_IsNumber(b[0])) return a == atoiW(b); else return 0;} +static INT comp_ne_m2(INT a, LPWSTR b) +{ if (COND_IsNumber(b[0])) return a != atoiW(b); else return 1;} +static INT comp_lt_m2(INT a, LPWSTR b) +{ if (COND_IsNumber(b[0])) return a < atoiW(b); else return 0;} +static INT comp_gt_m2(INT a, LPWSTR b) +{ if (COND_IsNumber(b[0])) return a > atoiW(b); else return 0;} +static INT comp_le_m2(INT a, LPWSTR b) +{ if (COND_IsNumber(b[0])) return a <= atoiW(b); else return 0;} +static INT comp_ge_m2(INT a, LPWSTR b) +{ if (COND_IsNumber(b[0])) return a >= atoiW(b); else return 0;} + + + +static int COND_IsIdent( WCHAR x ) +{ + return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' ) + || ( x == '#' ) || (x == '.') ); +} + +static int COND_GetOne( struct cond_str *str, COND_input *cond ) +{ + static const WCHAR szNot[] = {'N','O','T',0}; + static const WCHAR szAnd[] = {'A','N','D',0}; + static const WCHAR szOr[] = {'O','R',0}; + WCHAR ch; + int rc, len = 1; + + str->data = &cond->str[cond->n]; + + ch = str->data[0]; + switch( ch ) + { + case 0: return 0; + case '(': rc = COND_LPAR; break; + case ')': rc = COND_RPAR; break; + case '&': rc = COND_AMPER; break; + case '!': rc = COND_EXCLAM; break; + case '$': rc = COND_DOLLARS; break; + case '?': rc = COND_QUESTION; break; + case '%': rc = COND_PERCENT; break; + case ' ': rc = COND_SPACE; break; + case '=': rc = COND_EQ; break; + case '~': rc = COND_TILDA; break; + case '<': rc = COND_LT; break; + case '>': rc = COND_GT; break; + case '"': + { + const WCHAR *ch2 = str->data + 1; + + + while ( *ch2 && *ch2 != '"' ) + ++ch2; + if (*ch2 == '"') + { + len = ch2 - str->data + 1; + rc = COND_LITER; + break; + } + } + ERR("Unterminated string\n"); + rc = COND_ERROR; + break; + default: + if( COND_IsAlpha( ch ) ) + { + while( COND_IsIdent( str->data[len] ) ) + len++; + rc = COND_IDENT; + break; + } + + if( COND_IsNumber( ch ) ) + { + while( COND_IsNumber( str->data[len] ) ) + len++; + rc = COND_NUMBER; + break; + } + + ERR("Got unknown character %c(%x)\n",ch,ch); + rc = COND_ERROR; + break; + } + + /* keyword identifiers */ + if( rc == COND_IDENT ) + { + if( (len==3) && (strncmpiW(str->data,szNot,len)==0) ) + rc = COND_NOT; + else if( (len==3) && (strncmpiW(str->data,szAnd,len)==0) ) + rc = COND_AND; + else if( (len==2) && (strncmpiW(str->data,szOr,len)==0) ) + rc = COND_OR; + } + + cond->n += len; + str->len = len; + + return rc; +} + +static int COND_lex( void *COND_lval, COND_input *cond ) +{ + int rc; + struct cond_str *str = COND_lval; + + do { + rc = COND_GetOne( str, cond ); + } while (rc == COND_SPACE); + + return rc; +} + +static LPWSTR COND_GetString( struct cond_str *str ) +{ + LPWSTR ret; + + ret = HeapAlloc( GetProcessHeap(), 0, (str->len+1) * sizeof (WCHAR) ); + if( ret ) + { + strncpyW( ret, str->data, str->len ); + ret[str->len]=0; + } + TRACE("Got identifier %s\n",debugstr_w(ret)); + return ret; +} + +static LPWSTR COND_GetLiteral( struct cond_str *str ) +{ + LPWSTR ret; + + ret = HeapAlloc( GetProcessHeap(), 0, (str->len-1) * sizeof (WCHAR) ); + if( ret ) + { + memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) ); + ret[str->len - 2]=0; + } + TRACE("Got literal %s\n",debugstr_w(ret)); + return ret; +} + +static int COND_error(char *str) +{ + return 0; +} + +MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition ) +{ + COND_input cond; + MSICONDITION r; + + cond.package = package; + cond.str = szCondition; + cond.n = 0; + cond.result = -1; + + TRACE("Evaluating %s\n",debugstr_w(szCondition)); + + if( szCondition && !COND_parse( &cond ) ) + r = cond.result; + else + r = MSICONDITION_ERROR; + + TRACE("Evaluates to %i\n",r); + return r; +} + +MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition ) +{ + MSIPACKAGE *package; + UINT ret; + + package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); + if( !package) + return ERROR_INVALID_HANDLE; + ret = MSI_EvaluateConditionW( package, szCondition ); + msiobj_release( &package->hdr ); + return ret; +} + +MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition ) +{ + LPWSTR szwCond = NULL; + MSICONDITION r; + + if( szCondition ) + { + UINT len = MultiByteToWideChar( CP_ACP, 0, szCondition, -1, NULL, 0 ); + szwCond = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, szCondition, -1, szwCond, len ); + } + + r = MsiEvaluateConditionW( hInstall, szwCond ); + + HeapFree( GetProcessHeap(), 0, szwCond ); + + return r; +} + diff --git a/reactos/lib/msi/cond.tab.h b/reactos/lib/msi/cond.tab.h index 2392ce59d46..4870215530d 100644 --- a/reactos/lib/msi/cond.tab.h +++ b/reactos/lib/msi/cond.tab.h @@ -1,40 +1,99 @@ -#ifndef BISON_COND_TAB_H -# define BISON_COND_TAB_H - -#ifndef YYSTYPE -typedef union -{ - struct cond_str str; - LPWSTR string; - INT value; - comp_int fn_comp_int; - comp_str fn_comp_str; - comp_m1 fn_comp_m1; - comp_m2 fn_comp_m2; -} 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 */ +/* A Bison parser, made by GNU Bison 1.875b. */ + +/* 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 { + struct cond_str str; + LPWSTR string; + INT value; + comp_int fn_comp_int; + comp_str fn_comp_str; + comp_m1 fn_comp_m1; + comp_m2 fn_comp_m2; +} YYSTYPE; +/* Line 1252 of yacc.c. */ +#line 91 "cond.tab.h" +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + + + diff --git a/reactos/lib/msi/cond.y b/reactos/lib/msi/cond.y index 1cc096a7075..2221fb156ba 100644 --- a/reactos/lib/msi/cond.y +++ b/reactos/lib/msi/cond.y @@ -181,7 +181,7 @@ term: } | value_s { - $$ = atoiW($1); + $$ = $1[0] ? MSICONDITION_TRUE : MSICONDITION_FALSE; } | value_i comp_op_i value_i { @@ -448,14 +448,22 @@ symbol_s: { DWORD sz; COND_input* cond = (COND_input*) info; - $$ = HeapAlloc( GetProcessHeap(), 0, 0x100*sizeof (WCHAR) ); - /* Lookup the identifier */ - - sz=0x100; - if (MSI_GetPropertyW(cond->package,$1,$$,&sz) != ERROR_SUCCESS) + sz = 0; + MSI_GetPropertyW(cond->package, $1, NULL, &sz); + if (sz == 0) { - $$[0]=0; + $$ = HeapAlloc( GetProcessHeap(), 0 ,sizeof(WCHAR)); + $$[0] = 0; + } + else + { + sz ++; + $$ = HeapAlloc( GetProcessHeap(), 0, sz*sizeof (WCHAR) ); + + /* Lookup the identifier */ + + MSI_GetPropertyW(cond->package,$1,$$,&sz); } HeapFree( GetProcessHeap(), 0, $1 ); } @@ -731,7 +739,7 @@ MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition ) TRACE("Evaluating %s\n",debugstr_w(szCondition)); - if( !COND_parse( &cond ) ) + if( szCondition && !COND_parse( &cond ) ) r = cond.result; else r = MSICONDITION_ERROR; @@ -767,8 +775,7 @@ MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szConditio r = MsiEvaluateConditionW( hInstall, szwCond ); - if( szwCond ) - HeapFree( GetProcessHeap(), 0, szwCond ); + HeapFree( GetProcessHeap(), 0, szwCond ); return r; } diff --git a/reactos/lib/msi/create.c b/reactos/lib/msi/create.c index 356860d4cc3..b22a2aac61f 100644 --- a/reactos/lib/msi/create.c +++ b/reactos/lib/msi/create.c @@ -188,11 +188,12 @@ static UINT CREATE_get_column_info( struct tagMSIVIEW *view, return ERROR_FUNCTION_FAILED; } -static UINT CREATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec) +static UINT CREATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, + MSIRECORD *rec) { MSICREATEVIEW *cv = (MSICREATEVIEW*)view; - TRACE("%p %d %ld\n", cv, eModifyMode, hrec ); + TRACE("%p %d %p\n", cv, eModifyMode, rec ); return ERROR_FUNCTION_FAILED; } diff --git a/reactos/lib/msi/custom.c b/reactos/lib/msi/custom.c new file mode 100644 index 00000000000..ae79b3db5aa --- /dev/null +++ b/reactos/lib/msi/custom.c @@ -0,0 +1,794 @@ +/* + * Custom Action processing for 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 + */ + +/* + * Pages I need + * +http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/summary_list_of_all_custom_action_types.asp + */ + +#include +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" +#include "wine/debug.h" +#include "fdi.h" +#include "msi.h" +#include "msiquery.h" +#include "fcntl.h" +#include "objbase.h" +#include "objidl.h" +#include "msipriv.h" +#include "winnls.h" +#include "winuser.h" +#include "shlobj.h" +#include "wine/unicode.h" +#include "ver.h" +#include "action.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +#define CUSTOM_ACTION_TYPE_MASK 0x3F +static const WCHAR c_collen[] = {'C',':','\\',0}; +static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0}; + +typedef struct tagMSIRUNNINGACTION +{ + HANDLE handle; + BOOL process; + LPWSTR name; +} MSIRUNNINGACTION; + +static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source, + LPCWSTR target, const INT type, LPCWSTR action); +static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source, + LPCWSTR target, const INT type, LPCWSTR action); +static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source, + LPCWSTR target, const INT type, LPCWSTR action); +static UINT HANDLE_CustomType19(MSIPACKAGE *package, LPCWSTR source, + LPCWSTR target, const INT type, LPCWSTR action); +static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source, + LPCWSTR target, const INT type, LPCWSTR action); +static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source, + LPCWSTR target, const INT type, LPCWSTR action); + +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',' ','C','u','s','t','o' + ,'m','A','c','t','i','o','n',' ','w','h','e','r','e',' ','`','A','c','t','i' + ,'o','n','`',' ','=',' ','`','%','s','`',0}; + UINT type; + LPWSTR source; + 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); + return ERROR_CALL_NOT_IMPLEMENTED; + } + + type = MSI_RecordGetInteger(row,2); + + source = load_dynamic_stringW(row,3); + target = load_dynamic_stringW(row,4); + + TRACE("Handling custom action %s (%x %s %s)\n",debugstr_w(action),type, + debugstr_w(source), debugstr_w(target)); + + /* handle some of the deferred actions */ + if (type & 0x400) + { + if (type & 0x100) + { + FIXME("Rollback only action... rollbacks not supported yet\n"); + 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] = dupstrW(action); + package->CommitAction = newbuf; + } + 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] = dupstrW(action); + package->DeferredAction = newbuf; + } + + HeapFree(GetProcessHeap(),0,source); + HeapFree(GetProcessHeap(),0,target); + msiobj_release(&row->hdr); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return ERROR_SUCCESS; + } + else + { + /*Set ActionData*/ + + static const WCHAR szActionData[] = { + 'C','u','s','t','o','m','A','c','t','i','o','n','D','a','t','a',0}; + LPWSTR actiondata = load_dynamic_property(package,action,NULL); + if (actiondata) + MSI_SetPropertyW(package,szActionData,actiondata); + } + } + + switch (type & CUSTOM_ACTION_TYPE_MASK) + { + case 1: /* DLL file stored in a Binary table stream */ + rc = HANDLE_CustomType1(package,source,target,type,action); + break; + case 2: /* EXE file stored in a Binary table strem */ + rc = HANDLE_CustomType2(package,source,target,type,action); + break; + case 18: /*EXE file installed with package */ + rc = HANDLE_CustomType18(package,source,target,type,action); + break; + case 19: /* Error that halts install */ + rc = HANDLE_CustomType19(package,source,target,type,action); + break; + case 50: /*EXE file specified by a property value */ + rc = HANDLE_CustomType50(package,source,target,type,action); + break; + case 34: /*EXE to be run in specified directory */ + rc = HANDLE_CustomType34(package,source,target,type,action); + break; + case 35: /* Directory set with formatted text. */ + deformat_string(package,target,&deformated); + MSI_SetTargetPathW(package, source, deformated); + HeapFree(GetProcessHeap(),0,deformated); + break; + case 51: /* Property set with formatted text. */ + deformat_string(package,target,&deformated); + rc = MSI_SetPropertyW(package,source,deformated); + HeapFree(GetProcessHeap(),0,deformated); + break; + default: + FIXME("UNHANDLED ACTION TYPE %i (%s %s)\n", + type & CUSTOM_ACTION_TYPE_MASK, debugstr_w(source), + debugstr_w(target)); + } + + HeapFree(GetProcessHeap(),0,source); + HeapFree(GetProcessHeap(),0,target); + msiobj_release(&row->hdr); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return rc; +} + + +static UINT store_binary_to_temp(MSIPACKAGE *package, LPCWSTR source, + LPWSTR tmp_file) +{ + DWORD sz=MAX_PATH; + static const WCHAR f1[] = {'m','s','i',0}; + WCHAR fmt[MAX_PATH]; + + if (MSI_GetPropertyW(package, cszTempFolder, fmt, &sz) + != ERROR_SUCCESS) + GetTempPathW(MAX_PATH,fmt); + + if (GetTempFileNameW(fmt,f1,0,tmp_file) == 0) + { + TRACE("Unable to create file\n"); + return ERROR_FUNCTION_FAILED; + } + else + { + /* 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',' ','B','i' +,'n','a','r','y',' ','w','h','e','r','e',' ','N','a','m','e','=','`','%','s','`',0}; + 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; + } + + 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(tmp_file); + break; + } + WriteFile(the_file,buffer,sz,&write,NULL); + } while (sz == 1024); + + CloseHandle(the_file); + + msiobj_release(&row->hdr); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + } + + return ERROR_SUCCESS; +} + +static void file_running_action(MSIPACKAGE* package, HANDLE Handle, + BOOL process, LPCWSTR name) +{ + MSIRUNNINGACTION *newbuf = NULL; + INT count; + count = package->RunningActionCount; + package->RunningActionCount++; + if (count != 0) + newbuf = HeapReAlloc(GetProcessHeap(),0, + package->RunningAction, + package->RunningActionCount * sizeof(MSIRUNNINGACTION)); + else + newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(MSIRUNNINGACTION)); + + newbuf[count].handle = Handle; + newbuf[count].process = process; + newbuf[count].name = dupstrW(name); + + package->RunningAction = newbuf; +} + +static UINT process_action_return_value(UINT type, HANDLE ThreadHandle) +{ + DWORD rc; + + if (type == 2) + { + GetExitCodeProcess(ThreadHandle,&rc); + + if (rc == 0) + return ERROR_SUCCESS; + else + return ERROR_FUNCTION_FAILED; + } + + GetExitCodeThread(ThreadHandle,&rc); + + switch (rc) + { + case ERROR_FUNCTION_NOT_CALLED: + case ERROR_SUCCESS: + case ERROR_INSTALL_USEREXIT: + case ERROR_INSTALL_FAILURE: + return rc; + case ERROR_NO_MORE_ITEMS: + return ERROR_SUCCESS; + default: + return ERROR_FUNCTION_FAILED; + } +} + +static UINT process_handle(MSIPACKAGE* package, UINT type, + HANDLE ThreadHandle, HANDLE ProcessHandle, + LPCWSTR Name) +{ + UINT rc = ERROR_SUCCESS; + + if (!(type & 0x80)) + { + /* synchronous */ + TRACE("Synchronous Execution of action %s\n",debugstr_w(Name)); + if (ProcessHandle) + msi_dialog_check_messages(package->dialog, ProcessHandle); + else + msi_dialog_check_messages(package->dialog, ThreadHandle); + + if (!(type & 0x40)) + { + if (ProcessHandle) + rc = process_action_return_value(2,ProcessHandle); + else + rc = process_action_return_value(1,ThreadHandle); + } + + CloseHandle(ThreadHandle); + if (ProcessHandle); + CloseHandle(ProcessHandle); + } + else + { + TRACE("Asynchronous Execution of action %s\n",debugstr_w(Name)); + /* asynchronous */ + if (type & 0x40) + { + if (ProcessHandle) + { + file_running_action(package, ProcessHandle, TRUE, Name); + CloseHandle(ThreadHandle); + } + else + file_running_action(package, ThreadHandle, FALSE, Name); + } + else + { + CloseHandle(ThreadHandle); + if (ProcessHandle); + CloseHandle(ProcessHandle); + } + } + + return rc; +} + + +typedef UINT __stdcall CustomEntry(MSIHANDLE); + +typedef struct +{ + MSIPACKAGE *package; + WCHAR *target; + WCHAR *source; +} thread_struct; + +static DWORD WINAPI ACTION_CallDllFunction(thread_struct *stuff) +{ + HANDLE hModule; + LPSTR proc; + CustomEntry *fn; + DWORD rc = ERROR_SUCCESS; + + TRACE("calling function (%s, %s) \n", debugstr_w(stuff->source), + debugstr_w(stuff->target)); + + hModule = LoadLibraryW(stuff->source); + if (hModule) + { + proc = strdupWtoA( stuff->target ); + fn = (CustomEntry*)GetProcAddress(hModule,proc); + if (fn) + { + MSIHANDLE hPackage; + MSIPACKAGE *package = stuff->package; + + TRACE("Calling function %s\n", proc); + hPackage = msiobj_findhandle( &package->hdr ); + if (hPackage ) + { + rc = fn(hPackage); + msiobj_release( &package->hdr ); + } + else + ERR("Handle for object %p not found\n", package ); + } + else + ERR("Cannot load functon\n"); + + HeapFree(GetProcessHeap(),0,proc); + FreeLibrary(hModule); + } + else + ERR("Unable to load library\n"); + msiobj_release( &stuff->package->hdr ); + HeapFree(GetProcessHeap(),0,stuff->source); + HeapFree(GetProcessHeap(),0,stuff->target); + HeapFree(GetProcessHeap(), 0, stuff); + return rc; +} + +static DWORD WINAPI DllThread(LPVOID info) +{ + thread_struct *stuff; + DWORD rc = 0; + + TRACE("MSI Thread (0x%lx) started for custom action\n", + GetCurrentThreadId()); + + stuff = (thread_struct*)info; + rc = ACTION_CallDllFunction(stuff); + + TRACE("MSI Thread (0x%lx) finished\n",GetCurrentThreadId()); + /* clse all handles for this thread */ + MsiCloseAllHandles(); + return rc; +} + +static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source, + LPCWSTR target, const INT type, LPCWSTR action) +{ + WCHAR tmp_file[MAX_PATH]; + thread_struct *info; + DWORD ThreadId; + HANDLE ThreadHandle; + UINT rc = ERROR_SUCCESS; + + store_binary_to_temp(package, source, tmp_file); + + TRACE("Calling function %s from %s\n",debugstr_w(target), + debugstr_w(tmp_file)); + + if (!strchrW(tmp_file,'.')) + { + static const WCHAR dot[]={'.',0}; + strcatW(tmp_file,dot); + } + + info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) ); + msiobj_addref( &package->hdr ); + info->package = package; + info->target = dupstrW(target); + info->source = dupstrW(tmp_file); + + ThreadHandle = CreateThread(NULL,0,DllThread,(LPVOID)info,0,&ThreadId); + + rc = process_handle(package, type, ThreadHandle, NULL, action); + + return rc; +} + +static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source, + LPCWSTR target, const INT type, LPCWSTR action) +{ + WCHAR tmp_file[MAX_PATH]; + STARTUPINFOW si; + PROCESS_INFORMATION info; + BOOL rc; + INT len; + WCHAR *deformated; + WCHAR *cmd; + static const WCHAR spc[] = {' ',0}; + UINT prc = ERROR_SUCCESS; + + memset(&si,0,sizeof(STARTUPINFOW)); + + store_binary_to_temp(package, source, tmp_file); + + deformat_string(package,target,&deformated); + + len = strlenW(tmp_file)+2; + + if (deformated) + len += strlenW(deformated); + + cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*len); + + strcpyW(cmd,tmp_file); + if (deformated) + { + strcatW(cmd,spc); + strcatW(cmd,deformated); + + HeapFree(GetProcessHeap(),0,deformated); + } + + TRACE("executing exe %s \n",debugstr_w(cmd)); + + rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL, + c_collen, &si, &info); + + HeapFree(GetProcessHeap(),0,cmd); + + if ( !rc ) + { + ERR("Unable to execute command\n"); + return ERROR_SUCCESS; + } + + prc = process_handle(package, type, info.hThread, info.hProcess, action); + + return prc; +} + +static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source, + LPCWSTR target, const INT type, LPCWSTR action) +{ + STARTUPINFOW si; + PROCESS_INFORMATION info; + BOOL rc; + WCHAR *deformated; + WCHAR *cmd; + INT len; + static const WCHAR spc[] = {' ',0}; + int index; + UINT prc; + + memset(&si,0,sizeof(STARTUPINFOW)); + + index = get_loaded_file(package,source); + + len = strlenW(package->files[index].TargetPath); + + deformat_string(package,target,&deformated); + if (deformated) + len += strlenW(deformated); + len += 2; + + cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,len * sizeof(WCHAR)); + + strcpyW(cmd, package->files[index].TargetPath); + if (deformated) + { + strcatW(cmd, spc); + strcatW(cmd, deformated); + + HeapFree(GetProcessHeap(),0,deformated); + } + + TRACE("executing exe %s \n",debugstr_w(cmd)); + + rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL, + c_collen, &si, &info); + + HeapFree(GetProcessHeap(),0,cmd); + + if ( !rc ) + { + ERR("Unable to execute command\n"); + return ERROR_SUCCESS; + } + + prc = process_handle(package, type, info.hThread, info.hProcess, action); + + return prc; +} + +static UINT HANDLE_CustomType19(MSIPACKAGE *package, LPCWSTR source, + LPCWSTR target, const INT type, LPCWSTR action) +{ + static const WCHAR query[] = { + 'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ', + 'F','R','O','M',' ','`','E','r','r','o','r','`',' ', + '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 ) + { + 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 ); + } + + if (r != ERROR_SUCCESS ) + { + MessageBoxW( NULL, deformated, NULL, MB_OK ); + HeapFree( GetProcessHeap(), 0, deformated ); + } + + return ERROR_FUNCTION_FAILED; +} + +static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source, + LPCWSTR target, const INT type, LPCWSTR action) +{ + STARTUPINFOW si; + PROCESS_INFORMATION info; + WCHAR *prop; + BOOL rc; + WCHAR *deformated; + WCHAR *cmd; + INT len; + UINT prc; + static const WCHAR spc[] = {' ',0}; + + memset(&si,0,sizeof(STARTUPINFOW)); + memset(&info,0,sizeof(PROCESS_INFORMATION)); + + prop = load_dynamic_property(package,source,&prc); + if (!prop) + return prc; + + deformat_string(package,target,&deformated); + len = strlenW(prop) + 2; + if (deformated) + len += strlenW(deformated); + + cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*len); + + strcpyW(cmd,prop); + if (deformated) + { + strcatW(cmd,spc); + strcatW(cmd,deformated); + + HeapFree(GetProcessHeap(),0,deformated); + } + + TRACE("executing exe %s \n",debugstr_w(cmd)); + + rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL, + c_collen, &si, &info); + + HeapFree(GetProcessHeap(),0,cmd); + + if ( !rc ) + { + ERR("Unable to execute command\n"); + return ERROR_SUCCESS; + } + + prc = process_handle(package, type, info.hThread, info.hProcess, action); + + return prc; +} + +static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source, + LPCWSTR target, const INT type, LPCWSTR action) +{ + LPWSTR filename, deformated; + STARTUPINFOW si; + PROCESS_INFORMATION info; + BOOL rc; + UINT prc; + + memset(&si,0,sizeof(STARTUPINFOW)); + + filename = resolve_folder(package, source, FALSE, FALSE, NULL); + + if (!filename) + return ERROR_FUNCTION_FAILED; + + SetCurrentDirectoryW(filename); + HeapFree(GetProcessHeap(),0,filename); + + deformat_string(package,target,&deformated); + + if (!deformated) + return ERROR_FUNCTION_FAILED; + + TRACE("executing exe %s \n",debugstr_w(deformated)); + + rc = CreateProcessW(NULL, deformated, NULL, NULL, FALSE, 0, NULL, + c_collen, &si, &info); + HeapFree(GetProcessHeap(),0,deformated); + + if ( !rc ) + { + ERR("Unable to execute command\n"); + return ERROR_SUCCESS; + } + + prc = process_handle(package, type, info.hThread, info.hProcess, action); + + return prc; +} + + +void ACTION_FinishCustomActions(MSIPACKAGE* package) +{ + INT i; + DWORD rc; + + for (i = 0; i < package->RunningActionCount; i++) + { + TRACE("Checking on action %s\n", + debugstr_w(package->RunningAction[i].name)); + + if (package->RunningAction[i].process) + GetExitCodeProcess(package->RunningAction[i].handle, &rc); + else + GetExitCodeThread(package->RunningAction[i].handle, &rc); + + if (rc == STILL_ACTIVE) + { + TRACE("Waiting on action %s\n", + debugstr_w(package->RunningAction[i].name)); + msi_dialog_check_messages(package->dialog, + package->RunningAction[i].handle); + } + + HeapFree(GetProcessHeap(),0,package->RunningAction[i].name); + CloseHandle(package->RunningAction[i].handle); + } + + HeapFree(GetProcessHeap(),0,package->RunningAction); +} diff --git a/reactos/lib/msi/dialog.c b/reactos/lib/msi/dialog.c new file mode 100644 index 00000000000..db8328f14d1 --- /dev/null +++ b/reactos/lib/msi/dialog.c @@ -0,0 +1,973 @@ +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2005 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winnls.h" +#include "wingdi.h" +#include "msi.h" +#include "msipriv.h" +#include "msidefs.h" + +#include "wine/debug.h" +#include "wine/unicode.h" + +#include "action.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + + +const WCHAR szMsiDialogClass[] = { + 'M','s','i','D','i','a','l','o','g','C','l','o','s','e','C','l','a','s','s',0 +}; +const static WCHAR szStatic[] = { 'S','t','a','t','i','c',0 }; + +struct msi_control_tag; +typedef struct msi_control_tag msi_control; +typedef UINT (*msi_handler)( msi_dialog *, msi_control *, WPARAM ); + +struct msi_control_tag +{ + struct msi_control_tag *next; + HWND hwnd; + msi_handler handler; + LPWSTR property; + WCHAR name[1]; +}; + +typedef struct msi_font_tag +{ + struct msi_font_tag *next; + HFONT hfont; + WCHAR name[1]; +} msi_font; + +struct msi_dialog_tag +{ + MSIPACKAGE *package; + msi_dialog_event_handler event_handler; + BOOL finished; + INT scale; + DWORD attributes; + HWND hwnd; + LPWSTR default_font; + msi_font *font_list; + msi_control *control_list; + WCHAR name[1]; +}; + +typedef UINT (*msi_dialog_control_func)( msi_dialog *dialog, MSIRECORD *rec ); +struct control_handler +{ + LPCWSTR control_type; + msi_dialog_control_func func; +}; + +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 ); + + +INT msi_dialog_scale_unit( msi_dialog *dialog, INT val ) +{ + return (dialog->scale * val + 5) / 10; +} + +/* + * msi_dialog_get_style + * + * Extract the {\style} string from the front of the text to display and + * update the pointer. + */ +static LPWSTR msi_dialog_get_style( LPCWSTR *text ) +{ + LPWSTR ret = NULL; + LPCWSTR p = *text, q; + DWORD len; + + if( *p++ != '{' ) + return ret; + q = strchrW( p, '}' ); + if( !q ) + return ret; + *text = ++q; + if( *p++ != '\\' ) + return ret; + len = q - p; + + ret = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); + if( !ret ) + return ret; + strncpyW( ret, p, len ); + ret[len-1] = 0; + return ret; +} + +static UINT msi_dialog_add_font( MSIRECORD *rec, LPVOID param ) +{ + msi_dialog *dialog = param; + msi_font *font; + LPCWSTR face, name; + LOGFONTW lf; + INT style; + HDC hdc; + + /* create a font and add it to the list */ + name = MSI_RecordGetString( rec, 1 ); + font = HeapAlloc( GetProcessHeap(), 0, + sizeof *font + strlenW( name )*sizeof (WCHAR) ); + strcpyW( font->name, name ); + font->next = dialog->font_list; + dialog->font_list = font; + + memset( &lf, 0, sizeof lf ); + face = MSI_RecordGetString( rec, 2 ); + lf.lfHeight = MSI_RecordGetInteger( rec, 3 ); + style = MSI_RecordGetInteger( rec, 5 ); + if( style & msidbTextStyleStyleBitsBold ) + lf.lfWeight = FW_BOLD; + if( style & msidbTextStyleStyleBitsItalic ) + lf.lfItalic = TRUE; + if( style & msidbTextStyleStyleBitsUnderline ) + lf.lfUnderline = TRUE; + if( style & msidbTextStyleStyleBitsStrike ) + lf.lfStrikeOut = TRUE; + lstrcpynW( lf.lfFaceName, face, LF_FACESIZE ); + + /* adjust the height */ + hdc = GetDC( dialog->hwnd ); + if (hdc) + { + lf.lfHeight = -MulDiv(lf.lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72); + ReleaseDC( dialog->hwnd, hdc ); + } + + font->hfont = CreateFontIndirectW( &lf ); + + TRACE("Adding font style %s\n", debugstr_w(font->name) ); + + return ERROR_SUCCESS; +} + +static msi_font *msi_dialog_find_font( msi_dialog *dialog, LPCWSTR name ) +{ + msi_font *font; + + for( font = dialog->font_list; font; font = font->next ) + if( !strcmpW( font->name, name ) ) /* FIXME: case sensitive? */ + break; + + return font; +} + +static UINT msi_dialog_set_font( msi_dialog *dialog, HWND hwnd, LPCWSTR name ) +{ + msi_font *font; + + font = msi_dialog_find_font( dialog, name ); + if( font ) + SendMessageW( hwnd, WM_SETFONT, (WPARAM) font->hfont, TRUE ); + else + ERR("No font entry for %s\n", debugstr_w(name)); + return ERROR_SUCCESS; +} + +static UINT msi_dialog_build_font_list( msi_dialog *dialog ) +{ + static const WCHAR query[] = { + 'S','E','L','E','C','T',' ','*',' ', + 'F','R','O','M',' ','`','T','e','x','t','S','t','y','l','e','`',' ',0 + }; + UINT r; + MSIQUERY *view = NULL; + + TRACE("dialog %p\n", dialog ); + + r = MSI_OpenQuery( dialog->package->db, &view, query ); + if( r != ERROR_SUCCESS ) + return r; + + r = MSI_IterateRecords( view, NULL, msi_dialog_add_font, dialog ); + msiobj_release( &view->hdr ); + + return r; +} + +static msi_control *msi_dialog_add_control( msi_dialog *dialog, + MSIRECORD *rec, LPCWSTR szCls, DWORD style ) +{ + DWORD x, y, width, height, attributes; + LPCWSTR text, name; + LPWSTR font = NULL, title = NULL; + msi_control *control = NULL; + + style |= WS_CHILD | WS_GROUP; + + name = MSI_RecordGetString( rec, 2 ); + control = HeapAlloc( GetProcessHeap(), 0, + sizeof *control + strlenW(name)*sizeof(WCHAR) ); + strcpyW( control->name, name ); + control->next = dialog->control_list; + dialog->control_list = control; + control->handler = NULL; + control->property = NULL; + + x = MSI_RecordGetInteger( rec, 4 ); + y = MSI_RecordGetInteger( rec, 5 ); + width = MSI_RecordGetInteger( rec, 6 ); + height = MSI_RecordGetInteger( rec, 7 ); + attributes = MSI_RecordGetInteger( rec, 8 ); + text = MSI_RecordGetString( rec, 10 ); + + TRACE("Dialog %s control %s\n", debugstr_w(dialog->name), debugstr_w(text)); + + x = msi_dialog_scale_unit( dialog, x ); + y = msi_dialog_scale_unit( dialog, y ); + width = msi_dialog_scale_unit( dialog, width ); + height = msi_dialog_scale_unit( dialog, height ); + + if( attributes & 1 ) + style |= WS_VISIBLE; + if( ~attributes & 2 ) + style |= WS_DISABLED; + if( text ) + { + font = msi_dialog_get_style( &text ); + deformat_string( dialog->package, text, &title ); + } + control->hwnd = CreateWindowW( szCls, title, style, + x, y, width, height, dialog->hwnd, NULL, NULL, NULL ); + msi_dialog_set_font( dialog, control->hwnd, + font ? font : dialog->default_font ); + HeapFree( GetProcessHeap(), 0, font ); + HeapFree( GetProcessHeap(), 0, title ); + return control; +} + +static UINT msi_dialog_text_control( msi_dialog *dialog, MSIRECORD *rec ) +{ + TRACE("%p %p\n", dialog, rec); + + msi_dialog_add_control( dialog, rec, szStatic, 0 ); + return ERROR_SUCCESS; +} + +static UINT msi_dialog_button_control( msi_dialog *dialog, MSIRECORD *rec ) +{ + const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 }; + msi_control *control; + + TRACE("%p %p\n", dialog, rec); + + control = msi_dialog_add_control( dialog, rec, szButton, 0 ); + control->handler = msi_dialog_button_handler; + + return ERROR_SUCCESS; +} + +static UINT msi_dialog_checkbox_control( msi_dialog *dialog, MSIRECORD *rec ) +{ + const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 }; + msi_control *control; + LPCWSTR prop; + + TRACE("%p %p\n", dialog, rec); + + control = msi_dialog_add_control( dialog, rec, szButton, + BS_CHECKBOX | BS_MULTILINE ); + control->handler = msi_dialog_checkbox_handler; + prop = MSI_RecordGetString( rec, 9 ); + if( prop ) + control->property = dupstrW( prop ); + msi_dialog_checkbox_sync_state( dialog, control ); + + return ERROR_SUCCESS; +} + +static UINT msi_dialog_line_control( msi_dialog *dialog, MSIRECORD *rec ) +{ + TRACE("%p %p\n", dialog, rec); + + msi_dialog_add_control( dialog, rec, szStatic, SS_ETCHEDHORZ | SS_SUNKEN ); + return ERROR_SUCCESS; +} + +static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec ) +{ + const static WCHAR szEdit[] = { 'E','D','I','T',0 }; + + TRACE("%p %p\n", dialog, rec); + + msi_dialog_add_control( dialog, rec, szEdit, + ES_MULTILINE | WS_VSCROLL | ES_READONLY | ES_AUTOVSCROLL ); + + return ERROR_SUCCESS; +} + +static UINT msi_dialog_bitmap_control( msi_dialog *dialog, MSIRECORD *rec ) +{ + TRACE("%p %p\n", dialog, rec); + + msi_dialog_add_control( dialog, rec, szStatic, + SS_BITMAP | SS_LEFT | SS_CENTERIMAGE ); + 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 }; + + msi_dialog_add_control( dialog, rec, szCombo, + SS_BITMAP | SS_LEFT | SS_CENTERIMAGE ); + return ERROR_SUCCESS; +} + +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, 0 ); + control->handler = msi_dialog_edit_handler; + prop = MSI_RecordGetString( rec, 9 ); + if( prop ) + control->property = dupstrW( prop ); + val = load_dynamic_property( dialog->package, control->property, NULL ); + SetWindowTextW( control->hwnd, val ); + HeapFree( GetProcessHeap(), 0, val ); + return ERROR_SUCCESS; +} + +static const WCHAR szText[] = { 'T','e','x','t',0 }; +static const WCHAR szButton[] = { 'P','u','s','h','B','u','t','t','o','n',0 }; +static const WCHAR 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 }; + +struct control_handler msi_dialog_handler[] = +{ + { szText, msi_dialog_text_control }, + { szButton, msi_dialog_button_control }, + { szLine, msi_dialog_line_control }, + { szBitmap, msi_dialog_bitmap_control }, + { szCheckBox, msi_dialog_checkbox_control }, + { szScrollableText, msi_dialog_scrolltext_control }, + { szComboBox, msi_dialog_combo_control }, + { szEdit, msi_dialog_edit_control }, + { szMaskedEdit, msi_dialog_edit_control }, +}; + +#define NUM_CONTROL_TYPES (sizeof msi_dialog_handler/sizeof msi_dialog_handler[0]) + +static UINT msi_dialog_create_controls( MSIRECORD *rec, LPVOID param ) +{ + msi_dialog *dialog = param; + LPCWSTR control_type; + UINT i; + + /* find and call the function that can create this type of control */ + control_type = MSI_RecordGetString( rec, 3 ); + for( i=0; ipackage; + + TRACE("%p %s\n", dialog, debugstr_w(dialog->name) ); + + /* query the Control table for all the elements of the control */ + r = MSI_OpenQuery( package->db, &view, query, dialog->name ); + if( r != ERROR_SUCCESS ) + { + ERR("query failed for dialog %s\n", debugstr_w(dialog->name)); + return ERROR_INVALID_PARAMETER; + } + + r = MSI_IterateRecords( view, 0, msi_dialog_create_controls, dialog ); + msiobj_release( &view->hdr ); + + 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 }; + static const WCHAR szShow[] = { 'S','h','o','w',0 }; + static const WCHAR szDisable[] = { 'D','i','s','a','b','l','e',0 }; + static const WCHAR szEnable[] = { 'E','n','a','b','l','e',0 }; + msi_dialog *dialog = param; + msi_control *control; + LPCWSTR name, action, condition; + UINT r; + + name = MSI_RecordGetString( rec, 2 ); + action = MSI_RecordGetString( rec, 3 ); + condition = MSI_RecordGetString( rec, 4 ); + r = MSI_EvaluateConditionW( dialog->package, condition ); + control = msi_dialog_find_control( dialog, name ); + if( r && control ) + { + TRACE("%s control %s\n", debugstr_w(action), debugstr_w(name)); + + /* FIXME: case sensitive? */ + if(!strcmpW(action, szHide)) + ShowWindow(control->hwnd, SW_HIDE); + else if(!strcmpW(action, szShow)) + ShowWindow(control->hwnd, SW_SHOW); + else if(!strcmpW(action, szDisable)) + EnableWindow(control->hwnd, FALSE); + else if(!strcmpW(action, szEnable)) + EnableWindow(control->hwnd, TRUE); + else + FIXME("Unhandled action %s\n", debugstr_w(action)); + } + + return ERROR_SUCCESS; +} + +static UINT msi_dialog_evaluate_control_conditions( msi_dialog *dialog ) +{ + static const WCHAR query[] = { + 'S','E','L','E','C','T',' ','*',' ', + 'F','R','O','M',' ', + 'C','o','n','t','r','o','l','C','o','n','d','i','t','i','o','n',' ', + 'W','H','E','R','E',' ', + '`','D','i','a','l','o','g','_','`',' ','=',' ','\'','%','s','\'',0 + }; + UINT r; + MSIQUERY *view = NULL; + MSIPACKAGE *package = dialog->package; + + TRACE("%p %s\n", dialog, debugstr_w(dialog->name) ); + + /* query the Control table for all the elements of the control */ + r = MSI_OpenQuery( package->db, &view, query, dialog->name ); + if( r != ERROR_SUCCESS ) + { + ERR("query failed for dialog %s\n", debugstr_w(dialog->name)); + return ERROR_INVALID_PARAMETER; + } + + r = MSI_IterateRecords( view, 0, msi_dialog_set_control_condition, dialog ); + msiobj_release( &view->hdr ); + + return r; +} + +/* figure out the height of 10 point MS Sans Serif */ +static INT msi_dialog_get_sans_serif_height( HWND hwnd ) +{ + static const WCHAR szSansSerif[] = { + 'M','S',' ','S','a','n','s',' ','S','e','r','i','f',0 }; + LOGFONTW lf; + TEXTMETRICW tm; + BOOL r; + LONG height = 0; + HFONT hFont, hOldFont; + HDC hdc; + + hdc = GetDC( hwnd ); + if (hdc) + { + memset( &lf, 0, sizeof lf ); + lf.lfHeight = MulDiv(10, GetDeviceCaps(hdc, LOGPIXELSY), 72); + strcpyW( lf.lfFaceName, szSansSerif ); + hFont = CreateFontIndirectW(&lf); + if (hFont) + { + hOldFont = SelectObject( hdc, hFont ); + r = GetTextMetricsW( hdc, &tm ); + if (r) + height = tm.tmHeight; + SelectObject( hdc, hOldFont ); + DeleteObject( hFont ); + } + ReleaseDC( hwnd, hdc ); + } + return height; +} + +static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs ) +{ + static const WCHAR query[] = { + 'S','E','L','E','C','T',' ','*',' ', + 'F','R','O','M',' ','D','i','a','l','o','g',' ', + 'W','H','E','R','E',' ', + '`','D','i','a','l','o','g','`',' ','=',' ','\'','%','s','\'',0}; + 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; + MSIPACKAGE *package = dialog->package; + MSIQUERY *view = NULL; + MSIRECORD *rec = NULL; + DWORD width, height; + LPCWSTR text; + LPWSTR title = NULL; + UINT r; + + TRACE("%p %p\n", dialog, package); + + dialog->hwnd = hwnd; + SetWindowLongPtrW( hwnd, GWLP_USERDATA, (LONG_PTR) dialog ); + + /* fetch the associated record from the Dialog table */ + r = MSI_OpenQuery( package->db, &view, query, dialog->name ); + if( r != ERROR_SUCCESS ) + { + ERR("query failed for dialog %s\n", debugstr_w(dialog->name)); + return -1; + } + MSI_ViewExecute( view, NULL ); + MSI_ViewFetch( view, &rec ); + MSI_ViewClose( view ); + msiobj_release( &view->hdr ); + + if( !rec ) + { + TRACE("No record found for dialog %s\n", debugstr_w(dialog->name)); + return -1; + } + + dialog->scale = msi_dialog_get_sans_serif_height(dialog->hwnd); + + width = MSI_RecordGetInteger( rec, 4 ); + height = MSI_RecordGetInteger( rec, 5 ); + 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, + SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW ); + + HeapFree( GetProcessHeap(), 0, title ); + msiobj_release( &rec->hdr ); + + msi_dialog_build_font_list( dialog ); + msi_dialog_fill_controls( dialog ); + msi_dialog_evaluate_control_conditions( dialog ); + + return 0; +} + +static UINT msi_dialog_send_event( msi_dialog *dialog, LPCWSTR event, LPCWSTR arg ) +{ + LPWSTR event_fmt = NULL, arg_fmt = NULL; + + TRACE("Sending control event %s %s\n", debugstr_w(event), debugstr_w(arg)); + + deformat_string( dialog->package, event, &event_fmt ); + deformat_string( dialog->package, arg, &arg_fmt ); + + dialog->event_handler( dialog->package, event_fmt, arg_fmt, dialog ); + + HeapFree( GetProcessHeap(), 0, event_fmt ); + HeapFree( GetProcessHeap(), 0, arg_fmt ); + + return ERROR_SUCCESS; +} + +static UINT msi_dialog_set_property( msi_dialog *dialog, LPCWSTR event, LPCWSTR arg ) +{ + static const WCHAR szNullArg[] = { '{','}',0 }; + LPWSTR p, prop, arg_fmt = NULL; + UINT len; + + len = strlenW(event); + prop = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR)); + strcpyW( prop, &event[1] ); + p = strchrW( prop, ']' ); + if( p && p[1] == 0 ) + { + *p = 0; + if( strcmpW( szNullArg, arg ) ) + deformat_string( dialog->package, arg, &arg_fmt ); + MSI_SetPropertyW( dialog->package, prop, arg_fmt ); + } + else + ERR("Badly formatted property string - what happens?\n"); + HeapFree( GetProcessHeap(), 0, prop ); + return ERROR_SUCCESS; +} + +static UINT msi_dialog_control_event( MSIRECORD *rec, LPVOID param ) +{ + msi_dialog *dialog = param; + LPCWSTR condition, event, arg; + UINT r; + + condition = MSI_RecordGetString( rec, 5 ); + r = MSI_EvaluateConditionW( dialog->package, condition ); + if( r ) + { + event = MSI_RecordGetString( rec, 3 ); + arg = MSI_RecordGetString( rec, 4 ); + if( event[0] == '[' ) + msi_dialog_set_property( dialog, event, arg ); + else + msi_dialog_send_event( dialog, event, arg ); + } + + return ERROR_SUCCESS; +} + +static UINT msi_dialog_button_handler( msi_dialog *dialog, + msi_control *control, WPARAM param ) +{ + static const WCHAR query[] = { + 'S','E','L','E','C','T',' ','*',' ', + 'F','R','O','M',' ','C','o','n','t','r','o','l','E','v','e','n','t',' ', + 'W','H','E','R','E',' ', + '`','D','i','a','l','o','g','_','`',' ','=',' ','\'','%','s','\'',' ', + 'A','N','D',' ', + '`','C','o','n','t','r','o','l','_','`',' ','=',' ','\'','%','s','\'',' ', + 'O','R','D','E','R',' ','B','Y',' ','`','O','r','d','e','r','i','n','g','`',0 + }; + MSIQUERY *view = NULL; + UINT r; + + if( HIWORD(param) != BN_CLICKED ) + return ERROR_SUCCESS; + + r = MSI_OpenQuery( dialog->package->db, &view, query, + dialog->name, control->name ); + if( r != ERROR_SUCCESS ) + { + ERR("query failed\n"); + return 0; + } + + r = MSI_IterateRecords( view, 0, msi_dialog_control_event, dialog ); + msiobj_release( &view->hdr ); + + return r; +} + +static UINT msi_dialog_get_checkbox_state( msi_dialog *dialog, + msi_control *control ) +{ + WCHAR state[2] = { 0 }; + DWORD sz = 2; + + MSI_GetPropertyW( dialog->package, control->property, state, &sz ); + return atoiW( state ) ? 1 : 0; +} + +static void msi_dialog_set_checkbox_state( msi_dialog *dialog, + msi_control *control, UINT state ) +{ + WCHAR szState[2] = { '0', 0 }; + + if( state ) + szState[0]++; + MSI_SetPropertyW( dialog->package, control->property, szState ); +} + +static void msi_dialog_checkbox_sync_state( msi_dialog *dialog, + msi_control *control ) +{ + UINT state; + + state = msi_dialog_get_checkbox_state( dialog, control ); + SendMessageW( control->hwnd, BM_SETCHECK, + state ? BST_CHECKED : BST_UNCHECKED, 0 ); +} + +static UINT msi_dialog_checkbox_handler( msi_dialog *dialog, + msi_control *control, WPARAM param ) +{ + UINT state; + + if( HIWORD(param) != BN_CLICKED ) + return ERROR_SUCCESS; + + TRACE("clicked checkbox %s, set %s\n", debugstr_w(control->name), + debugstr_w(control->property)); + + state = msi_dialog_get_checkbox_state( dialog, control ); + state = state ? 0 : 1; + msi_dialog_set_checkbox_state( dialog, control, state ); + msi_dialog_checkbox_sync_state( dialog, control ); + + return msi_dialog_button_handler( dialog, control, param ); +} + +static UINT msi_dialog_edit_handler( msi_dialog *dialog, + msi_control *control, WPARAM param ) +{ + UINT sz, r; + LPWSTR buf; + + if( HIWORD(param) != EN_CHANGE ) + return ERROR_SUCCESS; + + TRACE("edit %s contents changed, set %s\n", debugstr_w(control->name), + debugstr_w(control->property)); + + sz = 0x20; + buf = HeapAlloc( GetProcessHeap(), 0, sz*sizeof(WCHAR) ); + while( buf ) + { + r = GetWindowTextW( control->hwnd, buf, sz ); + if( r < (sz-1) ) + break; + sz *= 2; + buf = HeapReAlloc( GetProcessHeap(), 0, buf, sz*sizeof(WCHAR) ); + } + + MSI_SetPropertyW( dialog->package, control->property, buf ); + + HeapFree( GetProcessHeap(), 0, buf ); + + return ERROR_SUCCESS; +} + +static LRESULT msi_dialog_oncommand( msi_dialog *dialog, WPARAM param, HWND hwnd ) +{ + msi_control *control; + + TRACE("%p %p %08x\n", dialog, hwnd, param); + + control = msi_dialog_find_control_by_hwnd( dialog, hwnd ); + if( control ) + { + if( control->handler ) + { + control->handler( dialog, control, param ); + msi_dialog_evaluate_control_conditions( dialog ); + } + } + else + ERR("button click from nowhere\n"); + return 0; +} + +static LRESULT WINAPI MSIDialog_WndProc( HWND hwnd, UINT msg, + WPARAM wParam, LPARAM lParam ) +{ + msi_dialog *dialog = (LPVOID) GetWindowLongPtrW( hwnd, GWLP_USERDATA ); + + switch (msg) + { + case WM_CREATE: + return msi_dialog_oncreate( hwnd, (LPCREATESTRUCTW)lParam ); + + case WM_COMMAND: + return msi_dialog_oncommand( dialog, wParam, (HWND)lParam ); + + case WM_DESTROY: + dialog->hwnd = NULL; + return 0; + } + return DefWindowProcW(hwnd, msg, wParam, lParam); +} + +/* functions that interface to other modules within MSI */ + +msi_dialog *msi_dialog_create( MSIPACKAGE* package, LPCWSTR szDialogName, + msi_dialog_event_handler event_handler ) +{ + msi_dialog *dialog; + HWND hwnd; + + TRACE("%p %s\n", package, debugstr_w(szDialogName)); + + /* allocate the structure for the dialog to use */ + dialog = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof *dialog + sizeof(WCHAR)*strlenW(szDialogName) ); + if( !dialog ) + return NULL; + strcpyW( dialog->name, szDialogName ); + dialog->package = package; + dialog->event_handler = event_handler; + + /* create the dialog window, don't show it yet */ + hwnd = CreateWindowW( szMsiDialogClass, szDialogName, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, NULL, dialog ); + if( !hwnd ) + { + ERR("Failed to create dialog %s\n", debugstr_w( szDialogName )); + msi_dialog_destroy( dialog ); + return NULL; + } + + return dialog; +} + +void msi_dialog_end_dialog( msi_dialog *dialog ) +{ + dialog->finished = 1; +} + +UINT msi_dialog_run_message_loop( msi_dialog *dialog ) +{ + MSG msg; + + if( dialog->attributes & msidbDialogAttributesVisible ) + { + ShowWindow( dialog->hwnd, SW_SHOW ); + UpdateWindow( dialog->hwnd ); + } + + if( dialog->attributes & msidbDialogAttributesModal ) + { + while( !dialog->finished && GetMessageW( &msg, 0, 0, 0 ) ) + { + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } + } + else + return ERROR_IO_PENDING; + + return ERROR_SUCCESS; +} + +void msi_dialog_check_messages( msi_dialog *dialog, HANDLE handle ) +{ + MSG msg; + DWORD r; + + do + { + while( PeekMessageW( &msg, 0, 0, 0, PM_REMOVE ) ) + { + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } + if( !handle ) + break; + r = MsgWaitForMultipleObjects( 1, &handle, 0, INFINITE, QS_ALLEVENTS ); + } + while( WAIT_OBJECT_0 != r ); +} + +void msi_dialog_do_preview( msi_dialog *dialog ) +{ + dialog->attributes |= msidbDialogAttributesVisible; + dialog->attributes &= ~msidbDialogAttributesModal; + msi_dialog_run_message_loop( dialog ); +} + +void msi_dialog_destroy( msi_dialog *dialog ) +{ + if( dialog->hwnd ) + ShowWindow( dialog->hwnd, SW_HIDE ); + + /* destroy the list of controls */ + while( dialog->control_list ) + { + msi_control *t = dialog->control_list; + dialog->control_list = t->next; + /* leave dialog->hwnd - destroying parent destroys child windows */ + HeapFree( GetProcessHeap(), 0, t->property ); + HeapFree( GetProcessHeap(), 0, t ); + } + + /* destroy the list of fonts */ + while( dialog->font_list ) + { + msi_font *t = dialog->font_list; + dialog->font_list = t->next; + DeleteObject( t->hfont ); + HeapFree( GetProcessHeap(), 0, t ); + } + HeapFree( GetProcessHeap(), 0, dialog->default_font ); + + if( dialog->hwnd ) + DestroyWindow( dialog->hwnd ); + + dialog->package = NULL; + HeapFree( GetProcessHeap(), 0, dialog ); +} + +void msi_dialog_register_class( void ) +{ + WNDCLASSW cls; + + ZeroMemory( &cls, sizeof cls ); + cls.lpfnWndProc = MSIDialog_WndProc; + cls.hInstance = NULL; + cls.hIcon = LoadIconW(0, (LPWSTR)IDI_APPLICATION); + cls.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); + cls.hbrBackground = (HBRUSH)(COLOR_WINDOW); + cls.lpszMenuName = NULL; + cls.lpszClassName = szMsiDialogClass; + + RegisterClassW( &cls ); +} + +void msi_dialog_unregister_class( void ) +{ + UnregisterClassW( szMsiDialogClass, NULL ); +} diff --git a/reactos/lib/msi/distinct.c b/reactos/lib/msi/distinct.c index c1a463d7666..c74759ca8f4 100644 --- a/reactos/lib/msi/distinct.c +++ b/reactos/lib/msi/distinct.c @@ -178,8 +178,7 @@ static UINT DISTINCT_close( struct tagMSIVIEW *view ) if( !dv->table ) return ERROR_FUNCTION_FAILED; - if( dv->translation ) - HeapFree( GetProcessHeap(), 0, dv->translation ); + HeapFree( GetProcessHeap(), 0, dv->translation ); dv->translation = NULL; dv->row_count = 0; @@ -218,16 +217,17 @@ static UINT DISTINCT_get_column_info( struct tagMSIVIEW *view, return dv->table->ops->get_column_info( dv->table, n, name, type ); } -static UINT DISTINCT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec) +static UINT DISTINCT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, + MSIRECORD *rec ) { MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view; - TRACE("%p %d %ld\n", dv, eModifyMode, hrec ); + TRACE("%p %d %p\n", dv, eModifyMode, rec ); if( !dv->table ) return ERROR_FUNCTION_FAILED; - return dv->table->ops->modify( dv->table, eModifyMode, hrec ); + return dv->table->ops->modify( dv->table, eModifyMode, rec ); } static UINT DISTINCT_delete( struct tagMSIVIEW *view ) @@ -239,8 +239,7 @@ static UINT DISTINCT_delete( struct tagMSIVIEW *view ) if( dv->table ) dv->table->ops->delete( dv->table ); - if( dv->translation ) - HeapFree( GetProcessHeap(), 0, dv->translation ); + HeapFree( GetProcessHeap(), 0, dv->translation ); msiobj_release( &dv->db->hdr ); HeapFree( GetProcessHeap(), 0, dv ); diff --git a/reactos/lib/msi/format.c b/reactos/lib/msi/format.c new file mode 100644 index 00000000000..a5a9d2b778b --- /dev/null +++ b/reactos/lib/msi/format.c @@ -0,0 +1,583 @@ +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2005 Mike McCormack for CodeWeavers + * 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/msiformatrecord.asp + */ + +#include +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" +#include "wine/debug.h" +#include "fdi.h" +#include "msi.h" +#include "msiquery.h" +#include "fcntl.h" +#include "objbase.h" +#include "objidl.h" +#include "msipriv.h" +#include "winnls.h" +#include "winuser.h" +#include "shlobj.h" +#include "wine/unicode.h" +#include "ver.h" +#include "action.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + + +LPWSTR build_default_format(MSIRECORD* record) +{ + int i; + int count; + LPWSTR rc; + static const WCHAR fmt[] = {'%','i',':',' ','[','%','i',']',' ',0}; + WCHAR buf[11]; + + count = MSI_RecordGetFieldCount(record); + + rc = HeapAlloc(GetProcessHeap(),0,(11*count)*sizeof(WCHAR)); + rc[0] = 0; + for (i = 1; i <= count; i++) + { + sprintfW(buf,fmt,i,i); + strcatW(rc,buf); + } + return rc; +} + +static const WCHAR* scanW(LPCWSTR buf, WCHAR token, DWORD len) +{ + DWORD i; + for (i = 0; i < len; i++) + if (buf[i] == token) + return &buf[i]; + return NULL; +} + +/* break out helper functions for deformating */ +static LPWSTR deformat_component(MSIPACKAGE* package, LPCWSTR key, DWORD* sz) +{ + LPWSTR value = NULL; + INT index; + + *sz = 0; + if (!package) + return NULL; + + ERR("POORLY HANDLED DEFORMAT.. [$componentkey] \n"); + index = get_loaded_component(package,key); + if (index >= 0) + { + value = resolve_folder(package, package->components[index].Directory, + FALSE, FALSE, NULL); + *sz = (strlenW(value)) * sizeof(WCHAR); + } + + return value; +} + +static LPWSTR deformat_file(MSIPACKAGE* package, LPCWSTR key, DWORD* sz) +{ + LPWSTR value = NULL; + INT index; + + *sz = 0; + + if (!package) + return NULL; + + index = get_loaded_file(package,key); + if (index >=0) + { + value = dupstrW(package->files[index].TargetPath); + *sz = (strlenW(value)) * sizeof(WCHAR); + } + + return value; +} + +static LPWSTR deformat_environment(MSIPACKAGE* package, LPCWSTR key, + DWORD* chunk) +{ + LPWSTR value = NULL; + DWORD sz; + + sz = GetEnvironmentVariableW(key,NULL,0); + if (sz > 0) + { + sz++; + value = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR)); + GetEnvironmentVariableW(&key[1],value,sz); + *chunk = (strlenW(value)) * sizeof(WCHAR); + } + else + { + ERR("Unknown environment variable\n"); + *chunk = 0; + value = NULL; + } + return value; +} + + +static LPWSTR deformat_NULL(DWORD* chunk) +{ + LPWSTR value; + + value = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*2); + value[0] = 0; + *chunk = sizeof(WCHAR); + return value; +} + +static LPWSTR deformat_escape(LPCWSTR key, DWORD* chunk) +{ + LPWSTR value; + + value = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*2); + value[0] = key[0]; + *chunk = sizeof(WCHAR); + + return value; +} + + +static BOOL is_key_number(LPCWSTR key) +{ + INT index = 0; + if (key[0] == 0) + return FALSE; + + while (isdigitW(key[index])) index++; + if (key[index] == 0) + return TRUE; + else + return FALSE; +} + +static LPWSTR deformat_index(MSIRECORD* record, LPCWSTR key, DWORD* chunk ) +{ + INT index; + LPWSTR value; + + index = atoiW(key); + TRACE("record index %i\n",index); + value = load_dynamic_stringW(record,index); + if (value) + *chunk = strlenW(value) * sizeof(WCHAR); + else + { + value = NULL; + *chunk = 0; + } + return value; +} + +static LPWSTR deformat_property(MSIPACKAGE* package, LPCWSTR key, DWORD* chunk) +{ + UINT rc; + LPWSTR value; + + if (!package) + return NULL; + + value = load_dynamic_property(package,key, &rc); + + if (rc == ERROR_SUCCESS) + *chunk = (strlenW(value)) * sizeof(WCHAR); + + return value; +} + +static BOOL find_next_outermost_key(LPCWSTR source, DWORD len_remaining, + LPWSTR *key, LPCWSTR *mark, LPCWSTR* mark2, + BOOL *nested) +{ + INT count = 0; + INT total_count = 0; + int i; + + *mark = scanW(source,'[',len_remaining); + if (!*mark) + return FALSE; + + count = 1; + total_count = 1; + *nested = FALSE; + for (i = 1; (*mark - source) + i < len_remaining && count > 0; i++) + { + if ((*mark)[i] == '[') + { + count ++; + total_count ++; + *nested = TRUE; + } + else if ((*mark)[i] == ']') + { + count --; + } + } + + if (count > 0) + return FALSE; + + *mark2 = &(*mark)[i-1]; + + i = *mark2 - *mark; + *key = HeapAlloc(GetProcessHeap(),0,i*sizeof(WCHAR)); + /* do not have the [] in the key */ + i -= 1; + strncpyW(*key,&(*mark)[1],i); + (*key)[i] = 0; + + TRACE("Found Key %s\n",debugstr_w(*key)); + return TRUE; +} + + +/* + * len is in WCHARs + * return is also in WCHARs + */ +static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, + WCHAR** data, DWORD len, MSIRECORD* record) +{ + LPCWSTR mark = NULL; + LPCWSTR mark2 = NULL; + DWORD size=0; + DWORD chunk=0; + LPWSTR key; + LPWSTR value = NULL; + DWORD sz; + LPBYTE newdata = NULL; + const WCHAR* progress = NULL; + BOOL nested; + + if (ptr==NULL) + { + TRACE("Deformatting NULL string\n"); + *data = NULL; + return 0; + } + + TRACE("Starting with %s\n",debugstr_w(ptr)); + + /* scan for special characters... fast exit */ + if (!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)); + return len; + } + + progress = ptr; + + while (progress - ptr < len) + { + /* formatted string located */ + 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)); + chunk = (len - (progress - ptr)) * sizeof(WCHAR); + TRACE("after chunk is %li + %li\n",size,chunk); + if (size) + nd2 = HeapReAlloc(GetProcessHeap(),0,newdata,(size+chunk)); + else + nd2 = HeapAlloc(GetProcessHeap(),0,chunk); + + newdata = nd2; + memcpy(&newdata[size],progress,chunk); + size+=chunk; + break; + } + + if (mark != progress) + { + LPBYTE tgt; + DWORD old_size = size; + INT cnt = (mark - progress); + TRACE("%i (%i) characters before marker\n",cnt,(mark-progress)); + size += cnt * sizeof(WCHAR); + if (!old_size) + tgt = HeapAlloc(GetProcessHeap(),0,size); + else + tgt = HeapReAlloc(GetProcessHeap(),0,newdata,size); + newdata = tgt; + memcpy(&newdata[old_size],progress,(cnt * sizeof(WCHAR))); + } + + progress = mark; + + if (nested) + { + TRACE("Nested key... %s\n",debugstr_w(key)); + deformat_string_internal(package, key, &value, strlenW(key)+1, + record); + + HeapFree(GetProcessHeap(),0,key); + key = value; + } + + TRACE("Current %s .. %s\n",debugstr_w((LPWSTR)newdata),debugstr_w(key)); + + if (!package) + { + /* only deformat number indexs */ + if (is_key_number(key)) + value = deformat_index(record,key,&chunk); + else + { + chunk = (strlenW(key) + 2)*sizeof(WCHAR); + value = HeapAlloc(GetProcessHeap(),0,chunk); + value[0] = '['; + memcpy(&value[1],key,strlenW(key)*sizeof(WCHAR)); + value[strlenW(key)+1] = ']'; + } + } + else + { + sz = 0; + switch (key[0]) + { + case '~': + value = deformat_NULL(&chunk); + break; + case '$': + value = deformat_component(package,&key[1],&chunk); + break; + case '#': + case '!': /* should be short path */ + value = deformat_file(package,&key[1], &chunk); + break; + case '\\': + value = deformat_escape(&key[1],&chunk); + break; + case '%': + value = deformat_environment(package,&key[1],&chunk); + break; + default: + if (is_key_number(key)) + value = deformat_index(record,key,&chunk); + else + value = deformat_property(package,key,&chunk); + break; + } + } + + HeapFree(GetProcessHeap(),0,key); + + if (value!=NULL) + { + LPBYTE nd2; + TRACE("value %s, chunk %li size %li\n",debugstr_w((LPWSTR)value), + chunk, size); + if (size) + nd2= HeapReAlloc(GetProcessHeap(),0,newdata,(size + chunk)); + else + nd2= HeapAlloc(GetProcessHeap(),0,chunk); + newdata = nd2; + memcpy(&newdata[size],value,chunk); + size+=chunk; + HeapFree(GetProcessHeap(),0,value); + } + + progress = mark2+1; + } + + TRACE("after everything %s\n",debugstr_w((LPWSTR)newdata)); + + *data = (LPWSTR)newdata; + return size / sizeof(WCHAR); +} + + +UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer, + DWORD *size ) +{ + LPWSTR deformated; + LPWSTR rec; + DWORD len; + UINT rc = ERROR_INVALID_PARAMETER; + + TRACE("%p %p %p %li\n",package, record ,buffer, *size); + + rec = load_dynamic_stringW(record,0); + if (!rec) + rec = build_default_format(record); + + TRACE("(%s)\n",debugstr_w(rec)); + + len = deformat_string_internal(package,rec,&deformated,strlenW(rec), + record); + + if (buffer) + { + if (*size>len) + { + memcpy(buffer,deformated,len*sizeof(WCHAR)); + rc = ERROR_SUCCESS; + buffer[len] = 0; + } + else + { + if (*size > 0) + { + memcpy(buffer,deformated,(*size)*sizeof(WCHAR)); + buffer[(*size)-1] = 0; + } + rc = ERROR_MORE_DATA; + } + } + else + rc = ERROR_SUCCESS; + + *size = len; + + HeapFree(GetProcessHeap(),0,rec); + HeapFree(GetProcessHeap(),0,deformated); + return rc; +} + +UINT MSI_FormatRecordA( MSIPACKAGE* package, MSIRECORD* record, LPSTR buffer, + DWORD *size ) +{ + LPWSTR deformated; + LPWSTR rec; + DWORD len,lenA; + UINT rc = ERROR_INVALID_PARAMETER; + + TRACE("%p %p %p %li\n",package, record ,buffer, *size); + + rec = load_dynamic_stringW(record,0); + if (!rec) + rec = build_default_format(record); + + TRACE("(%s)\n",debugstr_w(rec)); + + len = deformat_string_internal(package,rec,&deformated,strlenW(rec), + record); + lenA = WideCharToMultiByte(CP_ACP,0,deformated,len,NULL,0,NULL,NULL); + + if (buffer) + { + WideCharToMultiByte(CP_ACP,0,deformated,len,buffer,*size,NULL, NULL); + if (*size>lenA) + { + rc = ERROR_SUCCESS; + buffer[lenA] = 0; + } + else + { + rc = ERROR_MORE_DATA; + buffer[(*size)-1] = 0; + } + } + else + rc = ERROR_SUCCESS; + + *size = lenA; + + HeapFree(GetProcessHeap(),0,rec); + HeapFree(GetProcessHeap(),0,deformated); + return rc; +} + + +UINT WINAPI MsiFormatRecordW( MSIHANDLE hInstall, MSIHANDLE hRecord, + LPWSTR szResult, DWORD *sz ) +{ + UINT r = ERROR_INVALID_HANDLE; + MSIPACKAGE *package; + MSIRECORD *record; + + TRACE("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz); + + record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD ); + + if (!record) + return ERROR_INVALID_HANDLE; + if (!sz) + { + msiobj_release( &record->hdr ); + if (szResult) + return ERROR_INVALID_PARAMETER; + else + return ERROR_SUCCESS; + } + + package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); + + if( record ) + { + r = MSI_FormatRecordW( package, record, szResult, sz ); + msiobj_release( &record->hdr ); + } + if (package) + msiobj_release( &package->hdr ); + return r; +} + +UINT WINAPI MsiFormatRecordA( MSIHANDLE hInstall, MSIHANDLE hRecord, + LPSTR szResult, DWORD *sz ) +{ + UINT r = ERROR_INVALID_HANDLE; + MSIPACKAGE *package = NULL; + MSIRECORD *record = NULL; + + TRACE("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz); + + record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD ); + + if (!record) + return ERROR_INVALID_HANDLE; + if (!sz) + { + msiobj_release( &record->hdr ); + if (szResult) + return ERROR_INVALID_PARAMETER; + else + return ERROR_SUCCESS; + } + + package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); + + if( record ) + { + r = MSI_FormatRecordA( package, record, szResult, sz ); + msiobj_release( &record->hdr ); + } + if (package) + msiobj_release( &package->hdr ); + return r; +} diff --git a/reactos/lib/msi/handle.c b/reactos/lib/msi/handle.c index bd33099c1f0..281a16c0325 100644 --- a/reactos/lib/msi/handle.c +++ b/reactos/lib/msi/handle.c @@ -157,7 +157,7 @@ void msiobj_addref( MSIOBJECTHDR *info ) return; } - info->refcount++; + InterlockedIncrement(&info->refcount); } void msiobj_lock( MSIOBJECTHDR *info ) @@ -185,12 +185,12 @@ int msiobj_release( MSIOBJECTHDR *info ) return -1; } - ret = info->refcount--; - if (info->refcount == 0) + ret = InterlockedDecrement( &info->refcount ); + if( ret==0 ) { - if( info->destructor ) + if( info->destructor ) info->destructor( info ); - HeapFree( GetProcessHeap(), 0, info ); + HeapFree( GetProcessHeap(), 0, info ); TRACE("object %p destroyed\n", info); } diff --git a/reactos/lib/msi/insert.c b/reactos/lib/msi/insert.c index f589be410c5..40dba1a9d4f 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; /* looks like these may be ignored... */ + value_list *vals; } MSIINSERTVIEW; static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) @@ -56,11 +56,62 @@ static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT return ERROR_FUNCTION_FAILED; } +/* + * INSERT_merge_record + * + * 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 ) +{ + MSIRECORD *merged; + DWORD wildcard_count = 1, i; + const WCHAR *str; + + merged = MSI_CreateRecord( fields ); + for( i=1; i <= fields; i++ ) + { + if( !vl ) + { + TRACE("Not enough elements in the list to insert\n"); + goto err; + } + switch( vl->val->type ) + { + case EXPR_SVAL: + TRACE("field %ld -> %s\n", i, debugstr_w(vl->val->u.sval)); + MSI_RecordSetStringW( merged, i, vl->val->u.sval ); + break; + case EXPR_IVAL: + MSI_RecordSetInteger( merged, i, vl->val->u.ival ); + break; + case EXPR_WILDCARD: + if( !rec ) + goto err; + if( MSI_RecordIsNull( rec, wildcard_count ) ) + goto err; + str = MSI_RecordGetString( rec, wildcard_count ); + MSI_RecordSetStringW( merged, i, str ); + wildcard_count++; + break; + default: + ERR("Unknown expression type %d\n", vl->val->type); + } + vl = vl->next; + } + + return merged; +err: + msiobj_release( &merged->hdr ); + return NULL; +} + static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record ) { MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; UINT n, type, val, r, row, col_count = 0; MSIVIEW *sv; + MSIRECORD *values = NULL; TRACE("%p %p\n", iv, record ); @@ -77,12 +128,13 @@ static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record ) if( r ) goto err; - n = MSI_RecordGetFieldCount( record ); - if( n != col_count ) - { - ERR("Number of fields do not match\n"); + /* + * Merge the wildcard values into the list of values provided + * in the query, and create a record containing both. + */ + values = INSERT_merge_record( col_count, iv->vals, record ); + if( !values ) goto err; - } row = -1; r = sv->ops->insert_row( sv, &row ); @@ -98,12 +150,12 @@ static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record ) if( type & MSITYPE_STRING ) { - const WCHAR *str = MSI_RecordGetString( record, n ); + const WCHAR *str = MSI_RecordGetString( values, n ); val = msi_addstringW( iv->db->strings, 0, str, -1, 1 ); } else { - val = MSI_RecordGetInteger( record, n ); + val = MSI_RecordGetInteger( values, n ); val |= 0x8000; } r = sv->ops->set_int( sv, row, n, val ); @@ -112,6 +164,9 @@ static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record ) } err: + if( values ) + msiobj_release( &values->hdr ); + return ERROR_SUCCESS; } @@ -159,11 +214,11 @@ static UINT INSERT_get_column_info( struct tagMSIVIEW *view, return sv->ops->get_column_info( sv, n, name, type ); } -static UINT INSERT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec) +static UINT INSERT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIRECORD *rec) { MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; - TRACE("%p %d %ld\n", iv, eModifyMode, hrec ); + TRACE("%p %d %p\n", iv, eModifyMode, rec ); return ERROR_FUNCTION_FAILED; } diff --git a/reactos/lib/msi/msi.c b/reactos/lib/msi/msi.c index 77ccf30658c..78f8ce7750a 100644 --- a/reactos/lib/msi/msi.c +++ b/reactos/lib/msi/msi.c @@ -1,7 +1,7 @@ /* * Implementation of the Microsoft Installer (msi.dll) * - * Copyright 2002,2003,2004 Mike McCormack for CodeWeavers + * Copyright 2002,2003,2004,2005 Mike McCormack for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -37,6 +37,7 @@ #include "wine/unicode.h" #include "objbase.h" #include "winver.h" +#include "winuser.h" #include "initguid.h" @@ -53,28 +54,18 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); */ #define LPCTSTR LPCWSTR -DEFINE_GUID( CLSID_MsiDatabase, 0x000c1084, 0x0000, 0x0000, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); - -static const WCHAR szInstaller[] = { -'S','o','f','t','w','a','r','e','\\', -'M','i','c','r','o','s','o','f','t','\\', -'W','i','n','d','o','w','s','\\', -'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', -'I','n','s','t','a','l','l','e','r',0 }; - -static const WCHAR szFeatures[] = { -'F','e','a','t','u','r','e','s',0 }; -static const WCHAR szComponents[] = { -'C','o','m','p','o','n','e','n','t','s',0 }; +DEFINE_GUID( CLSID_MsiDatabase, 0x000c1084, 0x0000, 0x0000, + 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); /* the UI level */ -INSTALLUILEVEL gUILevel; -HWND gUIhwnd; -INSTALLUI_HANDLERA gUIHandler; -INSTALLUI_HANDLERW gUIHandlerW; -DWORD gUIFilter; -LPVOID gUIContext; +INSTALLUILEVEL gUILevel = INSTALLUILEVEL_BASIC; +HWND gUIhwnd = 0; +INSTALLUI_HANDLERA gUIHandlerA = NULL; +INSTALLUI_HANDLERW gUIHandlerW = NULL; +DWORD gUIFilter = 0; +LPVOID gUIContext = NULL; WCHAR gszLogFile[MAX_PATH]; +HINSTANCE msi_hInstance; /* * .MSI file format @@ -83,157 +74,15 @@ WCHAR gszLogFile[MAX_PATH]; * It should contain a number of streams. */ -BOOL unsquash_guid(LPCWSTR in, LPWSTR out) -{ - DWORD i,n=0; - - out[n++]='{'; - for(i=0; i<8; i++) - out[n++] = in[7-i]; - out[n++]='-'; - for(i=0; i<4; i++) - out[n++] = in[11-i]; - out[n++]='-'; - for(i=0; i<4; i++) - out[n++] = in[15-i]; - out[n++]='-'; - for(i=0; i<2; i++) - { - out[n++] = in[17+i*2]; - out[n++] = in[16+i*2]; - } - out[n++]='-'; - for( ; i<8; i++) - { - out[n++] = in[17+i*2]; - out[n++] = in[16+i*2]; - } - out[n++]='}'; - out[n]=0; - return TRUE; -} - -BOOL squash_guid(LPCWSTR in, LPWSTR out) -{ - DWORD i,n=0; - - if(in[n++] != '{') - return FALSE; - for(i=0; i<8; i++) - out[7-i] = in[n++]; - if(in[n++] != '-') - return FALSE; - for(i=0; i<4; i++) - out[11-i] = in[n++]; - if(in[n++] != '-') - return FALSE; - for(i=0; i<4; i++) - out[15-i] = in[n++]; - if(in[n++] != '-') - return FALSE; - for(i=0; i<2; i++) - { - out[17+i*2] = in[n++]; - out[16+i*2] = in[n++]; - } - if(in[n++] != '-') - return FALSE; - for( ; i<8; i++) - { - out[17+i*2] = in[n++]; - out[16+i*2] = in[n++]; - } - out[32]=0; - if(in[n++] != '}') - return FALSE; - if(in[n]) - return FALSE; - return TRUE; -} - -/* tables for encoding and decoding base85 */ -static const unsigned char table_dec85[0x80] = { -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff, -0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17, -0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, -0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36, -0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46, -0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff, -}; - -static const char table_enc85[] = -"!$%&'()*+,-.0123456789=?@ABCDEFGHIJKLMNO" -"PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwx" -"yz{}~"; - -/* - * Converts a base85 encoded guid into a GUID pointer - * Base85 encoded GUIDs should be 20 characters long. - * - * returns TRUE if successful, FALSE if not - */ -BOOL decode_base85_guid( LPCWSTR str, GUID *guid ) -{ - DWORD i, val = 0, base = 1, *p; - - p = (DWORD*) guid; - for( i=0; i<20; i++ ) - { - if( (i%5) == 0 ) - { - val = 0; - base = 1; - } - val += table_dec85[str[i]] * base; - if( str[i] >= 0x80 ) - return FALSE; - if( table_dec85[str[i]] == 0xff ) - return FALSE; - if( (i%5) == 4 ) - p[i/5] = val; - base *= 85; - } - return TRUE; -} - -/* - * Encodes a base85 guid given a GUID pointer - * Caller should provide a 21 character buffer for the encoded string. - * - * returns TRUE if successful, FALSE if not - */ -BOOL encode_base85_guid( GUID *guid, LPWSTR str ) -{ - unsigned int x, *p, i; - - p = (unsigned int*) guid; - for( i=0; i<4; i++ ) - { - x = p[i]; - *str++ = table_enc85[x%85]; - x = x/85; - *str++ = table_enc85[x%85]; - x = x/85; - *str++ = table_enc85[x%85]; - x = x/85; - *str++ = table_enc85[x%85]; - x = x/85; - *str++ = table_enc85[x%85]; - } - *str = 0; - - return TRUE; -} - - VOID MSI_CloseDatabase( MSIOBJECTHDR *arg ) { MSIDATABASE *db = (MSIDATABASE *) arg; + DWORD r; free_cached_tables( db ); - IStorage_Release( db->storage ); + r = IStorage_Release( db->storage ); + if( r ) + ERR("database reference count was not zero (%ld)\n", r); } UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb) @@ -384,10 +233,8 @@ UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB) r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB ); end: - if( szwPersist ) - HeapFree( GetProcessHeap(), 0, szwPersist ); - if( szwDBPath ) - HeapFree( GetProcessHeap(), 0, szwDBPath ); + HeapFree( GetProcessHeap(), 0, szwPersist ); + HeapFree( GetProcessHeap(), 0, szwDBPath ); return r; } @@ -409,35 +256,24 @@ UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct) ret = MsiOpenProductW( szwProd, phProduct ); - if( szwProd ) - HeapFree( GetProcessHeap(), 0, szwProd ); + HeapFree( GetProcessHeap(), 0, szwProd ); return ret; } UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct) { - static const WCHAR szKey[] = { - 'S','o','f','t','w','a','r','e','\\', - 'M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s','\\', - 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'U','n','i','n','s','t','a','l','l',0 }; static const WCHAR szLocalPackage[] = { 'L','o','c','a','l','P','a','c','k','a','g','e', 0 }; LPWSTR path = NULL; UINT r; - HKEY hKeyProduct = NULL, hKeyUninstall = NULL; + HKEY hKeyProduct = NULL; DWORD count, type; TRACE("%s %p\n",debugstr_w(szProduct), phProduct); - r = RegOpenKeyW( HKEY_LOCAL_MACHINE, szKey, &hKeyUninstall ); - if( r != ERROR_SUCCESS ) - return ERROR_UNKNOWN_PRODUCT; - - r = RegOpenKeyW( hKeyUninstall, szProduct, &hKeyProduct ); + r = MSIREG_OpenUninstallKey(szProduct,&hKeyProduct,FALSE); if( r != ERROR_SUCCESS ) { r = ERROR_UNKNOWN_PRODUCT; @@ -470,38 +306,44 @@ UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct) r = MsiOpenPackageW( path, phProduct ); end: - if( path ) - HeapFree( GetProcessHeap(), 0, path ); + HeapFree( GetProcessHeap(), 0, path ); if( hKeyProduct ) RegCloseKey( hKeyProduct ); - RegCloseKey( hKeyUninstall ); return r; } -UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath, LPCSTR szTransforms, LANGID lgidLanguage) +UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath, + LPCSTR szTransforms, LANGID lgidLanguage) { - FIXME("%s %s %s 0x%08x\n",debugstr_a(szPackagePath), debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage); + FIXME("%s %s %s %08x\n",debugstr_a(szPackagePath), + debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage); return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, LPCWSTR szTransforms, LANGID lgidLanguage) +UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, + LPCWSTR szTransforms, LANGID lgidLanguage) { - FIXME("%s %s %s 0x%08x\n",debugstr_w(szPackagePath), debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage); + FIXME("%s %s %s %08x\n",debugstr_w(szPackagePath), + debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage); return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiAdvertiseProductExA(LPCSTR szPackagePath, LPCSTR szScriptfilePath, LPCSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions) +UINT WINAPI MsiAdvertiseProductExA(LPCSTR szPackagePath, LPCSTR szScriptfilePath, + LPCSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions) { - FIXME("%s %s %s 0x%08x 0x%08lx 0x%08lx\n", - debugstr_a(szPackagePath), debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage, dwPlatform, dwOptions); + FIXME("%s %s %s %08x %08lx %08lx\n", debugstr_a(szPackagePath), + debugstr_a(szScriptfilePath), debugstr_a(szTransforms), + lgidLanguage, dwPlatform, dwOptions); return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiAdvertiseProductExW( LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, LPCWSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions) +UINT WINAPI MsiAdvertiseProductExW( LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, + LPCWSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions) { - FIXME("%s %s %s 0x%08x 0x%08lx 0x%08lx\n", - debugstr_w(szPackagePath), debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage, dwPlatform, dwOptions); + FIXME("%s %s %s %08x %08lx %08lx\n", debugstr_w(szPackagePath), + debugstr_w(szScriptfilePath), debugstr_w(szTransforms), + lgidLanguage, dwPlatform, dwOptions); return ERROR_CALL_NOT_IMPLEMENTED; } @@ -533,11 +375,8 @@ UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine) r = MsiInstallProductW( szwPath, szwCommand ); end: - if( szwPath ) - HeapFree( GetProcessHeap(), 0, szwPath ); - - if( szwCommand ) - HeapFree( GetProcessHeap(), 0, szwCommand ); + HeapFree( GetProcessHeap(), 0, szwPath ); + HeapFree( GetProcessHeap(), 0, szwCommand ); return r; } @@ -569,29 +408,148 @@ UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine) UINT WINAPI MsiReinstallProductA(LPCSTR szProduct, DWORD dwReinstallMode) { - FIXME("%s 0x%08lx\n", debugstr_a(szProduct), dwReinstallMode); - return ERROR_CALL_NOT_IMPLEMENTED; + FIXME("%s %08lx\n", debugstr_a(szProduct), dwReinstallMode); + return ERROR_CALL_NOT_IMPLEMENTED; } UINT WINAPI MsiReinstallProductW(LPCWSTR szProduct, DWORD dwReinstallMode) { - FIXME("%s 0x%08lx\n", debugstr_w(szProduct), dwReinstallMode); - return ERROR_CALL_NOT_IMPLEMENTED; + FIXME("%s %08lx\n", debugstr_w(szProduct), dwReinstallMode); + return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiApplyPatchA(LPCSTR szPatchPackage, LPCSTR szInstallPackage, INSTALLTYPE eInstallType, LPCSTR szCommandLine) +UINT WINAPI MsiApplyPatchA(LPCSTR szPatchPackage, LPCSTR szInstallPackage, + INSTALLTYPE eInstallType, LPCSTR szCommandLine) { - FIXME("%s %s %d %s\n", debugstr_a(szPatchPackage), debugstr_a(szInstallPackage), eInstallType, debugstr_a(szCommandLine)); - return ERROR_CALL_NOT_IMPLEMENTED; + FIXME("%s %s %d %s\n", debugstr_a(szPatchPackage), debugstr_a(szInstallPackage), + eInstallType, debugstr_a(szCommandLine)); + return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage, INSTALLTYPE eInstallType, LPCWSTR szCommandLine) +UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage, + INSTALLTYPE eInstallType, LPCWSTR szCommandLine) { - FIXME("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage), eInstallType, debugstr_w(szCommandLine)); - return ERROR_CALL_NOT_IMPLEMENTED; + FIXME("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage), + eInstallType, debugstr_w(szCommandLine)); + return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState) +UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel, + INSTALLSTATE eInstallState, LPCWSTR szCommandLine) +{ + MSIHANDLE handle; + MSIPACKAGE* package; + UINT rc; + HKEY hkey=0,hkey1=0; + DWORD sz; + static const WCHAR szSouceList[] = { + 'S','o','u','r','c','e','L','i','s','t',0}; + static const WCHAR szLUS[] = { + 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0}; + WCHAR sourcepath[0x200]; + static const WCHAR szInstalled[] = { + ' ','I','n','s','t','a','l','l','e','d','=','1',0}; + LPWSTR commandline; + + FIXME("%s %d %d %s\n",debugstr_w(szProduct), iInstallLevel, eInstallState, + debugstr_w(szCommandLine)); + + if (eInstallState != INSTALLSTATE_LOCAL && + eInstallState != INSTALLSTATE_DEFAULT) + { + FIXME("Not implemented for anything other than local installs\n"); + return ERROR_CALL_NOT_IMPLEMENTED; + } + + rc = MSIREG_OpenUserProductsKey(szProduct,&hkey,FALSE); + if (rc != ERROR_SUCCESS) + goto end; + + rc = RegOpenKeyW(hkey,szSouceList,&hkey1); + if (rc != ERROR_SUCCESS) + goto end; + + sz = sizeof(sourcepath); + rc = RegQueryValueExW(hkey1, szLUS, NULL, NULL,(LPBYTE)sourcepath, &sz); + if (rc != ERROR_SUCCESS) + goto end; + + RegCloseKey(hkey1); + /* + * ok 1, we need to find the msi file for this product. + * 2, find the source dir for the files + * 3, do the configure/install. + * 4, cleanupany runonce entry. + */ + + rc = MsiOpenProductW(szProduct,&handle); + if (rc != ERROR_SUCCESS) + goto end; + + package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE); + + sz = strlenW(szInstalled); + + if (szCommandLine) + sz += strlenW(szCommandLine); + + commandline = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR)); + + if (szCommandLine) + strcpyW(commandline,szCommandLine); + else + commandline[0] = 0; + + if (MsiQueryProductStateW(szProduct) != INSTALLSTATE_UNKNOWN) + strcatW(commandline,szInstalled); + + rc = ACTION_DoTopLevelINSTALL(package, sourcepath, commandline); + + msiobj_release( &package->hdr ); + + HeapFree(GetProcessHeap(),0,commandline); +end: + RegCloseKey(hkey); + + return rc; +} + +UINT WINAPI MsiConfigureProductExA(LPCSTR szProduct, int iInstallLevel, + INSTALLSTATE eInstallState, LPCSTR szCommandLine) +{ + LPWSTR szwProduct = NULL; + LPWSTR szwCommandLine = NULL; + UINT hr = ERROR_FUNCTION_FAILED; + + if( szProduct ) + { + UINT len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 ); + szwProduct = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); + if( !szwProduct ) + goto end; + MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len ); + } + + if( szCommandLine) + { + UINT len = MultiByteToWideChar( CP_ACP, 0, szCommandLine, -1, NULL, 0 ); + szwCommandLine= HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); + if( !szwCommandLine) + goto end; + MultiByteToWideChar( CP_ACP, 0, szCommandLine, -1, szwCommandLine, len ); + } + + hr = MsiConfigureProductExW( szwProduct, iInstallLevel, eInstallState, + szwCommandLine ); +end: + HeapFree( GetProcessHeap(), 0, szwProduct ); + HeapFree( GetProcessHeap(), 0, szwCommandLine); + + return hr; +} + +UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel, + INSTALLSTATE eInstallState) { LPWSTR szwProduct = NULL; UINT hr = ERROR_SUCCESS; @@ -610,22 +568,25 @@ UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel, INSTALLSTA hr = MsiConfigureProductW( szwProduct, iInstallLevel, eInstallState ); end: - if( szwProduct ) - HeapFree( GetProcessHeap(), 0, szwProduct ); + HeapFree( GetProcessHeap(), 0, szwProduct ); return hr; } -UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState) +UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel, + INSTALLSTATE eInstallState) { - FIXME("%s %d %d\n",debugstr_w(szProduct), iInstallLevel, eInstallState); - return ERROR_CALL_NOT_IMPLEMENTED; + FIXME("%s %d %d\n", debugstr_w(szProduct), iInstallLevel, eInstallState); + + return MsiConfigureProductExW(szProduct, iInstallLevel, eInstallState, + NULL); } UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer) { - LPWSTR szwComponent = NULL, szwBuffer = NULL; + LPWSTR szwComponent = NULL; UINT hr = ERROR_INSTALL_FAILURE; + WCHAR szwBuffer[GUID_SIZE]; FIXME("%s %s\n",debugstr_a(szComponent), debugstr_a(szBuffer)); @@ -636,28 +597,17 @@ UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer) if( !szwComponent ) goto end; MultiByteToWideChar( CP_ACP, 0, szComponent, -1, szwComponent, len ); - } else { - return ERROR_INVALID_PARAMETER; - } - - { - szwBuffer = HeapAlloc( GetProcessHeap(), 0, GUID_SIZE * sizeof(WCHAR) ); - if( !szwBuffer ) - goto end; } + else + return ERROR_INVALID_PARAMETER; hr = MsiGetProductCodeW( szwComponent, szwBuffer ); if( ERROR_SUCCESS == hr ) - { WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, GUID_SIZE, NULL, NULL); - } end: - if( szwComponent ) - HeapFree( GetProcessHeap(), 0, szwComponent ); - if( szwBuffer ) - HeapFree( GetProcessHeap(), 0, szwBuffer ); + HeapFree( GetProcessHeap(), 0, szwComponent ); return hr; } @@ -665,25 +615,22 @@ end: UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer) { FIXME("%s %s\n",debugstr_w(szComponent), debugstr_w(szBuffer)); - if (NULL == szComponent) { - return ERROR_INVALID_PARAMETER; - } + if (NULL == szComponent) + return ERROR_INVALID_PARAMETER; return ERROR_CALL_NOT_IMPLEMENTED; } - - - -UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, LPSTR szBuffer, DWORD *pcchValueBuf) +UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, + LPSTR szBuffer, DWORD *pcchValueBuf) { LPWSTR szwProduct = NULL, szwAttribute = NULL, szwBuffer = NULL; UINT hr = ERROR_INSTALL_FAILURE; - FIXME("%s %s %p %p\n",debugstr_a(szProduct), debugstr_a(szAttribute), szBuffer, pcchValueBuf); + FIXME("%s %s %p %p\n",debugstr_a(szProduct), debugstr_a(szAttribute), + szBuffer, pcchValueBuf); - if (NULL != szBuffer && NULL == pcchValueBuf) { - return ERROR_INVALID_PARAMETER; - } + if( NULL != szBuffer && NULL == pcchValueBuf ) + return ERROR_INVALID_PARAMETER; if( szProduct ) { UINT len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 ); @@ -691,9 +638,9 @@ UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, LPSTR szBuf if( !szwProduct ) goto end; MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len ); - } else { - return ERROR_INVALID_PARAMETER; } + else + return ERROR_INVALID_PARAMETER; if( szAttribute ) { @@ -702,52 +649,50 @@ UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, LPSTR szBuf if( !szwAttribute ) goto end; MultiByteToWideChar( CP_ACP, 0, szAttribute, -1, szwAttribute, len ); - } else { - hr = ERROR_INVALID_PARAMETER; - goto end; + } + else + { + hr = ERROR_INVALID_PARAMETER; + goto end; } if( szBuffer ) { szwBuffer = HeapAlloc( GetProcessHeap(), 0, (*pcchValueBuf) * sizeof(WCHAR) ); - if( !szwBuffer ) + if( !szwBuffer ) goto end; } hr = MsiGetProductInfoW( szwProduct, szwAttribute, szwBuffer, pcchValueBuf ); if( ERROR_SUCCESS == hr ) - { WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, *pcchValueBuf, NULL, NULL); - } end: - if( szwProduct ) - HeapFree( GetProcessHeap(), 0, szwProduct ); - if( szwAttribute ) - HeapFree( GetProcessHeap(), 0, szwAttribute ); - if( szwBuffer ) - HeapFree( GetProcessHeap(), 0, szwBuffer ); + HeapFree( GetProcessHeap(), 0, szwProduct ); + HeapFree( GetProcessHeap(), 0, szwAttribute ); + HeapFree( GetProcessHeap(), 0, szwBuffer ); return hr; } -UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szBuffer, DWORD *pcchValueBuf) +UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, + LPWSTR szBuffer, DWORD *pcchValueBuf) { MSIHANDLE hProduct; UINT hr; - FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute), szBuffer, pcchValueBuf); + FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute), + szBuffer, pcchValueBuf); - if (NULL != szBuffer && NULL == pcchValueBuf) { - return ERROR_INVALID_PARAMETER; - } - if (NULL == szProduct || NULL == szAttribute) { - return ERROR_INVALID_PARAMETER; - } + if (NULL != szBuffer && NULL == pcchValueBuf) + return ERROR_INVALID_PARAMETER; + if (NULL == szProduct || NULL == szAttribute) + return ERROR_INVALID_PARAMETER; hr = MsiOpenProductW(szProduct, &hProduct); - if (ERROR_SUCCESS != hr) return hr; + if (ERROR_SUCCESS != hr) + return hr; hr = MsiGetPropertyW(hProduct, szAttribute, szBuffer, pcchValueBuf); MsiCloseHandle(hProduct); @@ -780,30 +725,31 @@ UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes) if( !szwLogFile ) goto end; MultiByteToWideChar( CP_ACP, 0, szLogFile, -1, szwLogFile, len ); - } else { - return ERROR_INVALID_PARAMETER; } + else + return ERROR_INVALID_PARAMETER; hr = MsiEnableLogW( dwLogMode, szwLogFile, attributes ); end: - if( szwLogFile ) - HeapFree( GetProcessHeap(), 0, szwLogFile ); + HeapFree( GetProcessHeap(), 0, szwLogFile ); return hr; } UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes) { - HANDLE the_file = INVALID_HANDLE_VALUE; + HANDLE file = INVALID_HANDLE_VALUE; + TRACE("%08lx %s %08lx\n", dwLogMode, debugstr_w(szLogFile), attributes); + strcpyW(gszLogFile,szLogFile); if (!(attributes & INSTALLLOGATTRIBUTES_APPEND)) DeleteFileW(szLogFile); - the_file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, + file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (the_file != INVALID_HANDLE_VALUE) - CloseHandle(the_file); + if (file != INVALID_HANDLE_VALUE) + CloseHandle(file); else ERR("Unable to enable log %s\n",debugstr_w(szLogFile)); @@ -812,20 +758,65 @@ UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes) INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct) { - FIXME("%s\n", debugstr_a(szProduct)); - return INSTALLSTATE_UNKNOWN; + LPWSTR szwProduct; + UINT len; + INSTALLSTATE rc; + + len = MultiByteToWideChar(CP_ACP,0,szProduct,-1,NULL,0); + szwProduct = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP,0,szProduct,-1,szwProduct,len); + rc = MsiQueryProductStateW(szwProduct); + HeapFree(GetProcessHeap(),0,szwProduct); + return rc; } INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct) { - FIXME("%s\n", debugstr_w(szProduct)); - return INSTALLSTATE_UNKNOWN; + UINT rc; + INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN; + HKEY hkey=0; + static const WCHAR szWindowsInstaller[] = { + 'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0 }; + DWORD sz; + + TRACE("%s\n", debugstr_w(szProduct)); + + rc = MSIREG_OpenUserProductsKey(szProduct,&hkey,FALSE); + if (rc != ERROR_SUCCESS) + goto end; + + RegCloseKey(hkey); + + rc = MSIREG_OpenUninstallKey(szProduct,&hkey,FALSE); + if (rc != ERROR_SUCCESS) + goto end; + + sz = sizeof(rrc); + rc = RegQueryValueExW(hkey,szWindowsInstaller,NULL,NULL,(LPVOID)&rrc, &sz); + if (rc != ERROR_SUCCESS) + goto end; + + switch (rrc) + { + case 1: + /* default */ + rrc = INSTALLSTATE_DEFAULT; + break; + default: + FIXME("Unknown install state read from registry (%i)\n",rrc); + rrc = INSTALLSTATE_UNKNOWN; + break; + } +end: + RegCloseKey(hkey); + return rrc; } INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd) { INSTALLUILEVEL old = gUILevel; HWND oldwnd = gUIhwnd; + TRACE("%08x %p\n", dwUILevel, phWnd); gUILevel = dwUILevel; @@ -840,10 +831,10 @@ INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd) INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler, DWORD dwMessageFilter, LPVOID pvContext) { - INSTALLUI_HANDLERA prev = gUIHandler; + INSTALLUI_HANDLERA prev = gUIHandlerA; - TRACE("(%p %lx %p)\n",puiHandler, dwMessageFilter,pvContext); - gUIHandler = puiHandler; + TRACE("%p %lx %p\n",puiHandler, dwMessageFilter,pvContext); + gUIHandlerA = puiHandler; gUIFilter = dwMessageFilter; gUIContext = pvContext; @@ -855,7 +846,7 @@ INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler, { INSTALLUI_HANDLERW prev = gUIHandlerW; - TRACE("(%p %lx %p)\n",puiHandler,dwMessageFilter,pvContext); + TRACE("%p %lx %p\n",puiHandler,dwMessageFilter,pvContext); gUIHandlerW = puiHandler; gUIFilter = dwMessageFilter; gUIContext = pvContext; @@ -863,54 +854,122 @@ INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler, return prev; } -UINT WINAPI MsiLoadStringA(HINSTANCE hInstance, UINT uID, LPSTR lpBuffer, int nBufferMax, DWORD e) +/****************************************************************** + * MsiLoadStringW [MSI.@] + * + * Loads a string from MSI's string resources. + * + * PARAMS + * + * handle [I] only -1 is handled currently + * id [I] id of the string to be loaded + * lpBuffer [O] buffer for the string to be written to + * nBufferMax [I] maximum size of the buffer in characters + * lang [I] the prefered language for the string + * + * RETURNS + * + * If successful, this function returns the language id of the string loaded + * If the function fails, the function returns zero. + * + * NOTES + * + * The type of the first parameter is unknown. LoadString's prototype + * suggests that it might be a module handle. I have made it an MSI handle + * for starters, as -1 is an invalid MSI handle, but not an invalid module + * handle. Maybe strings can be stored in an MSI database somehow. + */ +LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, LPWSTR lpBuffer, + int nBufferMax, LANGID lang ) { - /*FIXME("%08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e);*/ - FIXME("%p %u %p %d %08lx\n",hInstance,uID,lpBuffer,nBufferMax,e); - return ERROR_CALL_NOT_IMPLEMENTED; + HRSRC hres; + HGLOBAL hResData; + LPWSTR p; + DWORD i, len; + + TRACE("%ld %u %p %d %d\n", handle, id, lpBuffer, nBufferMax, lang); + + if( handle != -1 ) + FIXME("don't know how to deal with handle = %08lx\n", handle); + + if( !lang ) + lang = GetUserDefaultLangID(); + + hres = FindResourceExW( msi_hInstance, (LPCWSTR) RT_STRING, + (LPWSTR)1, lang ); + if( !hres ) + return 0; + hResData = LoadResource( msi_hInstance, hres ); + if( !hResData ) + return 0; + p = LockResource( hResData ); + if( !p ) + return 0; + + for (i = 0; i < (id&0xf); i++) + p += *p + 1; + len = *p; + + if( nBufferMax <= len ) + return 0; + + memcpy( lpBuffer, p+1, len * sizeof(WCHAR)); + lpBuffer[ len ] = 0; + + TRACE("found -> %s\n", debugstr_w(lpBuffer)); + + return lang; } -UINT WINAPI MsiLoadStringW(HINSTANCE hInstance, UINT uID, LPWSTR lpBuffer, int nBufferMax, DWORD e) +LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer, + int nBufferMax, LANGID lang ) { - FIXME("%p %u %p %d %08lx\n",hInstance,uID,lpBuffer,nBufferMax,e); - /* - int ret = LoadStringW(hInstance,uID,lpBuffer,nBufferMax); - FIXME("%s\n",debugstr_w(lpBuffer)); - return ret; - */ - return ERROR_CALL_NOT_IMPLEMENTED; + LPWSTR bufW; + LANGID r; + DWORD len; + + bufW = HeapAlloc(GetProcessHeap(), 0, nBufferMax*sizeof(WCHAR)); + r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang); + if( r ) + { + len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL ); + if( len <= nBufferMax ) + WideCharToMultiByte( CP_ACP, 0, bufW, -1, + lpBuffer, nBufferMax, NULL, NULL ); + else + r = 0; + } + HeapFree(GetProcessHeap(), 0, bufW); + return r; } -INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf, DWORD *pcchBuf) +INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf, + DWORD *pcchBuf) { FIXME("%s %p %08lx\n", debugstr_a(szComponent), lpPathBuf, *pcchBuf); return INSTALLSTATE_UNKNOWN; } -INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPSTR lpPathBuf, DWORD *pcchBuf) +INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPSTR lpPathBuf, + DWORD *pcchBuf) { FIXME("%s %p %08lx\n", debugstr_w(szComponent), lpPathBuf, *pcchBuf); return INSTALLSTATE_UNKNOWN; } -#include "winuser.h" - -UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType, WORD wLanguageId, DWORD f) +UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType, + WORD wLanguageId, DWORD f) { - FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_a(lpText),debugstr_a(lpCaption),uType,wLanguageId,f); - /* - MessageBoxExA(hWnd,lpText,lpCaption,uType|MB_OK,wLanguageId); - */ + FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_a(lpText),debugstr_a(lpCaption), + uType,wLanguageId,f); return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType, WORD wLanguageId, DWORD f) +UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType, + WORD wLanguageId, DWORD f) { - /*FIXME("%08lx %08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e,f);*/ - FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_w(lpText),debugstr_w(lpCaption),uType,wLanguageId,f); - /* - MessageBoxExW(hWnd,lpText,lpCaption,uType|MB_OK,wLanguageId); - */ + FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_w(lpText),debugstr_w(lpCaption), + uType,wLanguageId,f); return ERROR_CALL_NOT_IMPLEMENTED; } @@ -933,20 +992,16 @@ UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid) UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid) { - HKEY hkey = 0, hkeyFeatures = 0; + HKEY hkeyFeatures = 0; DWORD r; WCHAR szKeyName[33]; TRACE("%ld %p\n",index,lpguid); - if (NULL == lpguid) { - return ERROR_INVALID_PARAMETER; - } - r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey); - if( r != ERROR_SUCCESS ) - goto end; + if (NULL == lpguid) + return ERROR_INVALID_PARAMETER; - r = RegOpenKeyW(hkey, szFeatures, &hkeyFeatures); + r = MSIREG_OpenFeatures(&hkeyFeatures); if( r != ERROR_SUCCESS ) goto end; @@ -958,8 +1013,6 @@ end: if( hkeyFeatures ) RegCloseKey(hkeyFeatures); - if( hkey ) - RegCloseKey(hkey); return r; } @@ -992,8 +1045,7 @@ UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index, szParent, GUID_SIZE, NULL, NULL); } - if( szwProduct ) - HeapFree( GetProcessHeap(), 0, szwProduct); + HeapFree( GetProcessHeap(), 0, szwProduct); return r; } @@ -1001,24 +1053,12 @@ UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index, UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index, LPWSTR szFeature, LPWSTR szParent) { - HKEY hkey = 0, hkeyFeatures = 0, hkeyProduct = 0; + HKEY hkeyProduct = 0; DWORD r, sz; - WCHAR szRegName[GUID_SIZE]; TRACE("%s %ld %p %p\n",debugstr_w(szProduct),index,szFeature,szParent); - if( !squash_guid(szProduct, szRegName) ) - return ERROR_INVALID_PARAMETER; - - r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey); - if( r != ERROR_SUCCESS ) - goto end; - - r = RegOpenKeyW(hkey, szFeatures, &hkeyFeatures); - if( r != ERROR_SUCCESS ) - goto end; - - r = RegOpenKeyW(hkeyFeatures, szRegName, &hkeyProduct); + r = MSIREG_OpenFeaturesKey(szProduct,&hkeyProduct,FALSE); if( r != ERROR_SUCCESS ) goto end; @@ -1028,10 +1068,6 @@ UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index, end: if( hkeyProduct ) RegCloseKey(hkeyProduct); - if( hkeyFeatures ) - RegCloseKey(hkeyFeatures); - if( hkey ) - RegCloseKey(hkey); return r; } @@ -1052,17 +1088,13 @@ UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid) UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid) { - HKEY hkey = 0, hkeyComponents = 0; + HKEY hkeyComponents = 0; DWORD r; WCHAR szKeyName[33]; TRACE("%ld %p\n",index,lpguid); - r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey); - if( r != ERROR_SUCCESS ) - goto end; - - r = RegOpenKeyW(hkey, szComponents, &hkeyComponents); + r = MSIREG_OpenComponents(&hkeyComponents); if( r != ERROR_SUCCESS ) goto end; @@ -1074,8 +1106,6 @@ end: if( hkeyComponents ) RegCloseKey(hkeyComponents); - if( hkey ) - RegCloseKey(hkey); return r; } @@ -1105,32 +1135,20 @@ UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct) szProduct, GUID_SIZE, NULL, NULL); } - if( szwComponent ) - HeapFree( GetProcessHeap(), 0, szwComponent); + HeapFree( GetProcessHeap(), 0, szwComponent); return r; } UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct) { - HKEY hkey = 0, hkeyComponents = 0, hkeyComp = 0; + HKEY hkeyComp = 0; DWORD r, sz; - WCHAR szRegName[GUID_SIZE], szValName[GUID_SIZE]; + WCHAR szValName[GUID_SIZE]; TRACE("%s %ld %p\n",debugstr_w(szComponent),index,szProduct); - if( !squash_guid(szComponent, szRegName) ) - return ERROR_INVALID_PARAMETER; - - r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey); - if( r != ERROR_SUCCESS ) - goto end; - - r = RegOpenKeyW(hkey, szComponents, &hkeyComponents); - if( r != ERROR_SUCCESS ) - goto end; - - r = RegOpenKeyW(hkeyComponents, szRegName, &hkeyComp); + r = MSIREG_OpenComponentsKey(szComponent,&hkeyComp,FALSE); if( r != ERROR_SUCCESS ) goto end; @@ -1144,67 +1162,79 @@ UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct) end: if( hkeyComp ) RegCloseKey(hkeyComp); - if( hkeyComponents ) - RegCloseKey(hkeyComponents); - if( hkey ) - RegCloseKey(hkey); return r; } -UINT WINAPI MsiEnumComponentQualifiersA( - LPSTR szComponent, DWORD iIndex, LPSTR lpQualifierBuf, DWORD* pcchQualifierBuf, LPSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf) +UINT WINAPI MsiEnumComponentQualifiersA( LPSTR szComponent, DWORD iIndex, + LPSTR lpQualifierBuf, DWORD* pcchQualifierBuf, + LPSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf) { -FIXME("%s 0x%08lx %p %p %p %p\n", debugstr_a(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, pcchApplicationDataBuf); + FIXME("%s %08lx %p %p %p %p\n", debugstr_a(szComponent), iIndex, + lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, + pcchApplicationDataBuf); return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiEnumComponentQualifiersW( - LPWSTR szComponent, DWORD iIndex, LPWSTR lpQualifierBuf, DWORD* pcchQualifierBuf, LPWSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf) +UINT WINAPI MsiEnumComponentQualifiersW( LPWSTR szComponent, DWORD iIndex, + LPWSTR lpQualifierBuf, DWORD* pcchQualifierBuf, + LPWSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf ) { -FIXME("%s 0x%08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, pcchApplicationDataBuf); + FIXME("%s %08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex, + lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, + pcchApplicationDataBuf); return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiProvideAssemblyA( - LPCSTR szAssemblyName, LPCSTR szAppContext, DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf, DWORD* pcchPathBuf) +UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext, + DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf, + DWORD* pcchPathBuf ) { - FIXME("%s %s 0x%08lx 0x%08lx %p %p\n", - debugstr_a(szAssemblyName), debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf, pcchPathBuf); + FIXME("%s %s %08lx %08lx %p %p\n", debugstr_a(szAssemblyName), + debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf, + pcchPathBuf); return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiProvideAssemblyW( - LPCWSTR szAssemblyName, LPCWSTR szAppContext, DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf, DWORD* pcchPathBuf) +UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext, + DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf, + DWORD* pcchPathBuf ) { - FIXME("%s %s 0x%08lx 0x%08lx %p %p\n", - debugstr_w(szAssemblyName), debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf, pcchPathBuf); + FIXME("%s %s %08lx %08lx %p %p\n", debugstr_w(szAssemblyName), + debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf, + pcchPathBuf); return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor, LPSTR szPath, DWORD *pcchPath, DWORD *pcchArgs ) +UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor, + LPSTR szPath, DWORD *pcchPath, DWORD *pcchArgs ) { FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs ); return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor, LPWSTR szPath, DWORD *pcchPath, DWORD *pcchArgs ) +UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor, + LPWSTR szPath, DWORD *pcchPath, DWORD *pcchArgs ) { FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs ); return ERROR_CALL_NOT_IMPLEMENTED; } -HRESULT WINAPI MsiGetFileSignatureInformationA( - LPCSTR szSignedObjectPath, DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData, DWORD* pcbHashData) +HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath, + DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData, + DWORD* pcbHashData) { - FIXME("%s 0x%08lx %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags, ppcCertContext, pbHashData, pcbHashData); + FIXME("%s %08lx %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags, + ppcCertContext, pbHashData, pcbHashData); return ERROR_CALL_NOT_IMPLEMENTED; } -HRESULT WINAPI MsiGetFileSignatureInformationW( - LPCWSTR szSignedObjectPath, DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData, DWORD* pcbHashData) +HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath, + DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData, + DWORD* pcbHashData) { - FIXME("%s 0x%08lx %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags, ppcCertContext, pbHashData, pcbHashData); + FIXME("%s %08lx %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags, + ppcCertContext, pbHashData, pcbHashData); return ERROR_CALL_NOT_IMPLEMENTED; } @@ -1261,13 +1291,11 @@ UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage ) INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent, LPSTR lpPathBuf, DWORD* pcchBuf) { + LPWSTR szwProduct = NULL, szwComponent = NULL, lpwPathBuf= NULL; INSTALLSTATE rc; - UINT len; - LPWSTR szwProduct= NULL; - LPWSTR szwComponent= NULL; - LPWSTR lpwPathBuf= NULL; + UINT len, incoming_len; - if( szProduct) + if( szProduct ) { len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 ); szwProduct= HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); @@ -1276,11 +1304,11 @@ INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent, MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len ); } - if( szComponent) + if( szComponent ) { len = MultiByteToWideChar( CP_ACP, 0, szComponent, -1, NULL, 0 ); szwComponent= HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); - if( !szwComponent) + if( !szwComponent ) { HeapFree( GetProcessHeap(), 0, szwProduct); return ERROR_OUTOFMEMORY; @@ -1288,19 +1316,21 @@ INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent, MultiByteToWideChar( CP_ACP, 0, szComponent, -1, szwComponent, len ); } - if (pcchBuf && *pcchBuf > 0) + if( pcchBuf && *pcchBuf > 0 ) lpwPathBuf = HeapAlloc( GetProcessHeap(), 0, *pcchBuf * sizeof(WCHAR)); else lpwPathBuf = NULL; + incoming_len = *pcchBuf; rc = MsiGetComponentPathW(szwProduct, szwComponent, lpwPathBuf, pcchBuf); HeapFree( GetProcessHeap(), 0, szwProduct); HeapFree( GetProcessHeap(), 0, szwComponent); if (lpwPathBuf) { - WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, *pcchBuf, - lpPathBuf, GUID_SIZE, NULL, NULL); + if (rc != INSTALLSTATE_UNKNOWN) + WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, incoming_len, + lpPathBuf, incoming_len, NULL, NULL); HeapFree( GetProcessHeap(), 0, lpwPathBuf); } @@ -1310,10 +1340,46 @@ INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent, INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent, LPWSTR lpPathBuf, DWORD* pcchBuf) { - FIXME("STUB: (%s %s %p %p)\n", debugstr_w(szProduct), + WCHAR squished_pc[GUID_SIZE]; + UINT rc; + INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN; + HKEY hkey=0; + + TRACE("%s %s %p %p\n", debugstr_w(szProduct), debugstr_w(szComponent), lpPathBuf, pcchBuf); - return INSTALLSTATE_UNKNOWN; + squash_guid(szProduct,squished_pc); + + rc = MSIREG_OpenProductsKey(szProduct,&hkey,FALSE); + if (rc != ERROR_SUCCESS) + goto end; + + RegCloseKey(hkey); + + rc = MSIREG_OpenComponentsKey(szComponent,&hkey,FALSE); + if (rc != ERROR_SUCCESS) + goto end; + + *pcchBuf *= sizeof(WCHAR); + rc = RegQueryValueExW(hkey,squished_pc,NULL,NULL,(LPVOID)lpPathBuf, + pcchBuf); + *pcchBuf /= sizeof(WCHAR); + + if (rc!= ERROR_SUCCESS) + goto end; + + TRACE("found path of (%s:%s)(%s)\n", debugstr_w(szComponent), + debugstr_w(szProduct), debugstr_w(lpPathBuf)); + + FIXME("Only working for installed files, not registry keys\n"); + if (GetFileAttributesW(lpPathBuf) != INVALID_FILE_ATTRIBUTES) + rrc = INSTALLSTATE_LOCAL; + else + rrc = INSTALLSTATE_ABSENT; + +end: + RegCloseKey(hkey); + return rrc; } INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature) @@ -1323,7 +1389,7 @@ INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature) LPWSTR szwProduct= NULL; LPWSTR szwFeature= NULL; - if( szProduct) + if( szProduct ) { len = MultiByteToWideChar( CP_ACP, 0, szProduct, -1, NULL, 0 ); szwProduct= HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); @@ -1332,7 +1398,7 @@ INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature) MultiByteToWideChar( CP_ACP, 0, szProduct, -1, szwProduct, len ); } - if( szFeature) + if( szFeature ) { len = MultiByteToWideChar( CP_ACP, 0, szFeature, -1, NULL, 0 ); szwFeature= HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); @@ -1354,63 +1420,63 @@ INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature) INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature) { - FIXME("STUB: (%s %s)\n", debugstr_w(szProduct), debugstr_w(szFeature)); + FIXME("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature)); return INSTALLSTATE_UNKNOWN; } -UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf, DWORD* pcchVersionBuf, LPSTR lpLangBuf, DWORD* pcchLangBuf) +UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf, + DWORD* pcchVersionBuf, LPSTR lpLangBuf, DWORD* pcchLangBuf) { - UINT len; - UINT ret; - LPWSTR szwFilePath = NULL; - LPWSTR lpwVersionBuff = NULL; - LPWSTR lpwLangBuff = NULL; + LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL; + UINT len, ret = ERROR_OUTOFMEMORY; - if(szFilePath) { + if( szFilePath ) + { len = MultiByteToWideChar( CP_ACP, 0, szFilePath, -1, NULL, 0 ); szwFilePath = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); - if( !szwFilePath) - return ERROR_OUTOFMEMORY; + if( !szwFilePath ) + goto end; MultiByteToWideChar( CP_ACP, 0, szFilePath, -1, szwFilePath, len ); } - if(lpVersionBuf && pcchVersionBuf && *pcchVersionBuf) { - lpwVersionBuff = HeapAlloc(GetProcessHeap(), 0, *pcchVersionBuf * sizeof(WCHAR)); - if( !lpwVersionBuff) - { - ret = ERROR_OUTOFMEMORY; + if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf ) + { + lpwVersionBuff = HeapAlloc(GetProcessHeap(), 0, *pcchVersionBuf*sizeof(WCHAR)); + if( !lpwVersionBuff ) goto end; - } } - if(lpLangBuf && pcchLangBuf && *pcchLangBuf) { - lpwLangBuff = HeapAlloc(GetProcessHeap(), 0, *pcchVersionBuf * sizeof(WCHAR)); - if( !lpwLangBuff) - { - ret = ERROR_OUTOFMEMORY; + if( lpLangBuf && pcchLangBuf && *pcchLangBuf ) + { + lpwLangBuff = HeapAlloc(GetProcessHeap(), 0, *pcchVersionBuf*sizeof(WCHAR)); + if( !lpwLangBuff ) goto end; - } } - ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf, lpwLangBuff, pcchLangBuf); + ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf, + lpwLangBuff, pcchLangBuf); - if(lpwVersionBuff) - WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1, lpVersionBuf, *pcchVersionBuf, NULL, NULL); - if(lpwLangBuff) - WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1, lpLangBuf, *pcchLangBuf, NULL, NULL); + if( lpwVersionBuff ) + WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1, + lpVersionBuf, *pcchVersionBuf, NULL, NULL); + if( lpwLangBuff ) + WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1, + lpLangBuf, *pcchLangBuf, NULL, NULL); end: - if(szwFilePath) HeapFree(GetProcessHeap(), 0, szwFilePath); - if(lpwVersionBuff) HeapFree(GetProcessHeap(), 0, lpwVersionBuff); - if(lpwLangBuff) HeapFree(GetProcessHeap(), 0, lpwLangBuff); + HeapFree(GetProcessHeap(), 0, szwFilePath); + HeapFree(GetProcessHeap(), 0, lpwVersionBuff); + HeapFree(GetProcessHeap(), 0, lpwLangBuff); return ret; } -UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf) +UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, + DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf) { static const WCHAR szVersionResource[] = {'\\',0}; - static const WCHAR szVersionFormat[] = {'%','d','.','%','d','.','%','d','.','%','d',0}; + static const WCHAR szVersionFormat[] = { + '%','d','.','%','d','.','%','d','.','%','d',0}; static const WCHAR szLangFormat[] = {'%','d',0}; UINT ret = 0; DWORD dwVerLen; @@ -1419,38 +1485,48 @@ UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, DWORD* p UINT puLen; WCHAR tmp[32]; - TRACE("(%s,%p,%ld,%p,%ld)\n", debugstr_w(szFilePath), + TRACE("%s %p %ld %p %ld\n", debugstr_w(szFilePath), lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0, lpLangBuf, pcchLangBuf?*pcchLangBuf:0); dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL); - if(!dwVerLen) + if( !dwVerLen ) return GetLastError(); lpVer = HeapAlloc(GetProcessHeap(), 0, dwVerLen); - if(!lpVer) { + if( !lpVer ) + { ret = ERROR_OUTOFMEMORY; goto end; } - if(!GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer)) { + if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) ) + { ret = GetLastError(); goto end; } - if(lpVersionBuf && pcchVersionBuf && *pcchVersionBuf) { - if(VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) && puLen > 0) { - wsprintfW(tmp, szVersionFormat, HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS), HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS)); + if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf ) + { + if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) && + (puLen > 0) ) + { + wsprintfW(tmp, szVersionFormat, + HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS), + HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS)); lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf); *pcchVersionBuf = strlenW(lpVersionBuf); } - else { + else + { *lpVersionBuf = 0; *pcchVersionBuf = 0; } } - if(lpLangBuf && pcchLangBuf && *pcchLangBuf) { + if( lpLangBuf && pcchLangBuf && *pcchLangBuf ) + { DWORD lang = GetUserDefaultLangID(); + FIXME("Retrieve language from file\n"); wsprintfW(tmp, szLangFormat, lang); lstrcpynW(lpLangBuf, tmp, *pcchLangBuf); @@ -1458,152 +1534,125 @@ UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, DWORD* p } end: - if(lpVer) HeapFree(GetProcessHeap(), 0, lpVer); + HeapFree(GetProcessHeap(), 0, lpVer); return ret; } /****************************************************************** - * DllMain - * - * @todo: maybe we can check here if MsiServer service is declared no ? + * DllMain */ -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { - if (fdwReason == DLL_PROCESS_ATTACH) { - DisableThreadLibraryCalls(hinstDLL); - /* - * UI Initialization - */ - gUILevel = INSTALLUILEVEL_BASIC; - gUIhwnd = 0; - gUIHandler = NULL; - gUIFilter = 0; - gUIContext = NULL; - gszLogFile[0]=0; - /* FIXME: Initialisation */ - } else if (fdwReason == DLL_PROCESS_DETACH) { - /* FIXME: Cleanup */ - } - /* - static const WCHAR szMSIServerSvc[] = { 'M','S','I','S','e','r','v','e','r',0 }; - static const WCHAR szNull[] = { 0 }; - if (!strcmpW(lpServiceName, szMSIServerSvc)) { - hKey = CreateServiceW(hSCManager, - szMSIServerSvc, - szMSIServerSvc, - SC_MANAGER_ALL_ACCESS, - SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS, - SERVICE_AUTO_START, - SERVICE_ERROR_IGNORE, - szNull, - NULL, - NULL, - NULL, - NULL, - szNull); - */ - return TRUE; +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch(fdwReason) + { + case DLL_PROCESS_ATTACH: + msi_hInstance = hinstDLL; + DisableThreadLibraryCalls(hinstDLL); + msi_dialog_register_class(); + break; + case DLL_PROCESS_DETACH: + msi_dialog_unregister_class(); + /* FIXME: Cleanup */ + break; + } + return TRUE; } -typedef struct { - /* IUnknown fields */ - IClassFactoryVtbl *lpVtbl; - DWORD ref; +typedef struct tagIClassFactoryImpl +{ + IClassFactoryVtbl *lpVtbl; } IClassFactoryImpl; -static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - FIXME("(%p, %s, %p): stub\n",This,debugstr_guid(riid),ppobj); - return E_NOINTERFACE; +static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface, + REFIID riid,LPVOID *ppobj) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + FIXME("%p %s %p\n",This,debugstr_guid(riid),ppobj); + return E_NOINTERFACE; } -static ULONG WINAPI MsiCF_AddRef(LPCLASSFACTORY iface) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - return InterlockedIncrement(&This->ref); +static ULONG WINAPI MsiCF_AddRef(LPCLASSFACTORY iface) +{ + return 2; } -static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - /* static class, won't be freed */ - return InterlockedDecrement(&This->ref); +static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface) +{ + return 1; } -static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - FIXME ("(%p, %p, %s, %p): to implement\n", This, pOuter, debugstr_guid(riid), ppobj); - return 0; +static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface, + LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + FIXME("%p %p %s %p\n", This, pOuter, debugstr_guid(riid), ppobj); + return E_FAIL; } -static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - FIXME("(%p, %d): stub\n", This, dolock); - return S_OK; +static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface, BOOL dolock) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + FIXME("%p %d\n", This, dolock); + return S_OK; } -static IClassFactoryVtbl MsiCF_Vtbl = { - MsiCF_QueryInterface, - MsiCF_AddRef, - MsiCF_Release, - MsiCF_CreateInstance, - MsiCF_LockServer +static IClassFactoryVtbl MsiCF_Vtbl = +{ + MsiCF_QueryInterface, + MsiCF_AddRef, + MsiCF_Release, + MsiCF_CreateInstance, + MsiCF_LockServer }; -static IClassFactoryImpl Msi_CF = {&MsiCF_Vtbl, 1 }; +static IClassFactoryImpl Msi_CF = { &MsiCF_Vtbl }; /****************************************************************** - * DllGetClassObject (MSI.@) + * DllGetClassObject [MSI.@] */ -HRESULT WINAPI MSI_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) { - FIXME("(%s, %s, %p): almost a stub.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); - if (IsEqualCLSID (rclsid, &CLSID_IMsiServer)) { - *ppv = (LPVOID) &Msi_CF; - IClassFactory_AddRef((IClassFactory*)*ppv); - return S_OK; - } else if (IsEqualCLSID (rclsid, &CLSID_IMsiServerMessage)) { - *ppv = (LPVOID) &Msi_CF; - IClassFactory_AddRef((IClassFactory*)*ppv); - return S_OK; - } else if (IsEqualCLSID (rclsid, &CLSID_IMsiServerX1)) { - *ppv = (LPVOID) &Msi_CF; - IClassFactory_AddRef((IClassFactory*)*ppv); - return S_OK; - } else if (IsEqualCLSID (rclsid, &CLSID_IMsiServerX2)) { - *ppv = (LPVOID) &Msi_CF; - IClassFactory_AddRef((IClassFactory*)*ppv); - return S_OK; - } else if (IsEqualCLSID (rclsid, &CLSID_IMsiServerX3)) { - *ppv = (LPVOID) &Msi_CF; - IClassFactory_AddRef((IClassFactory*)*ppv); - return S_OK; - } - WARN("(%s, %s, %p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); - return CLASS_E_CLASSNOTAVAILABLE; +HRESULT WINAPI MSI_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +{ + TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + + if( IsEqualCLSID (rclsid, &CLSID_IMsiServer) || + IsEqualCLSID (rclsid, &CLSID_IMsiServerMessage) || + IsEqualCLSID (rclsid, &CLSID_IMsiServerX1) || + IsEqualCLSID (rclsid, &CLSID_IMsiServerX2) || + IsEqualCLSID (rclsid, &CLSID_IMsiServerX3) ) + { + *ppv = (LPVOID) &Msi_CF; + return S_OK; + } + return CLASS_E_CLASSNOTAVAILABLE; } /****************************************************************** - * DllGetVersion (MSI.@) + * DllGetVersion [MSI.@] */ HRESULT WINAPI MSI_DllGetVersion(DLLVERSIONINFO *pdvi) { - TRACE("%p\n",pdvi); + TRACE("%p\n",pdvi); - if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) - return E_INVALIDARG; + if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) + return E_INVALIDARG; - pdvi->dwMajorVersion = MSI_MAJORVERSION; - pdvi->dwMinorVersion = MSI_MINORVERSION; - pdvi->dwBuildNumber = MSI_BUILDNUMBER; - pdvi->dwPlatformID = 1; + pdvi->dwMajorVersion = MSI_MAJORVERSION; + pdvi->dwMinorVersion = MSI_MINORVERSION; + pdvi->dwBuildNumber = MSI_BUILDNUMBER; + pdvi->dwPlatformID = 1; - return S_OK; + return S_OK; } /****************************************************************** - * DllCanUnloadNow (MSI.@) + * DllCanUnloadNow [MSI.@] */ BOOL WINAPI MSI_DllCanUnloadNow(void) { - return S_FALSE; + return S_FALSE; } UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR szUpgradeCode, DWORD dwReserved, @@ -1637,3 +1686,80 @@ UINT WINAPI MsiGetFeatureUsageA(LPCSTR szProduct, LPCSTR szFeature, pdwUseCount, pwDateUsed); return ERROR_CALL_NOT_IMPLEMENTED; } + +UINT WINAPI MsiUseFeatureExW(LPCWSTR szProduct, LPCWSTR szFeature, + DWORD dwInstallMode, DWORD dwReserved) +{ + FIXME("%s %s %li %li\n", debugstr_w(szProduct), debugstr_w(szFeature), + dwInstallMode, dwReserved); + + return INSTALLSTATE_LOCAL; +} + +UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent, + LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct, + DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf, + DWORD* pcchPathBuf) +{ + FIXME("%s %s %li %s %li %li %p %p\n", debugstr_w(szComponent), + debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct), + Unused1, Unused2, lpPathBuf, pcchPathBuf); + + return ERROR_INDEX_ABSENT; +} + +USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct, LPWSTR lpUserNameBuf, + DWORD* pcchUserNameBuf, LPWSTR lpOrgNameBuf, + DWORD* pcchOrgNameBuf, LPWSTR lpSerialBuf, DWORD* pcchSerialBuf) +{ + FIXME("%s %p %p %p %p %p %p\n",debugstr_w(szProduct), lpUserNameBuf, + pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf, + pcchSerialBuf); + + return USERINFOSTATE_UNKNOWN; +} + +USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct, LPSTR lpUserNameBuf, + DWORD* pcchUserNameBuf, LPSTR lpOrgNameBuf, + DWORD* pcchOrgNameBuf, LPSTR lpSerialBuf, DWORD* pcchSerialBuf) +{ + FIXME("%s %p %p %p %p %p %p\n",debugstr_a(szProduct), lpUserNameBuf, + pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf, + pcchSerialBuf); + + return USERINFOSTATE_UNKNOWN; +} + +UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct) +{ + FIXME("%s\n",debugstr_w(szProduct)); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct) +{ + FIXME("%s\n",debugstr_a(szProduct)); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiCreateAndVerifyInstallerDirectory(void) +{ + FIXME("\n"); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget, + LPSTR szProductCode, LPSTR szFeatureId, + LPSTR szComponentCode) +{ + FIXME("\n"); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget, + LPWSTR szProductCode, LPWSTR szFeatureId, + LPWSTR szComponentCode) +{ + FIXME("\n"); + return ERROR_CALL_NOT_IMPLEMENTED; +} diff --git a/reactos/lib/msi/msi.rc b/reactos/lib/msi/msi.rc new file mode 100644 index 00000000000..adf5138d0e3 --- /dev/null +++ b/reactos/lib/msi/msi.rc @@ -0,0 +1,30 @@ +/* + * Resources for MSI + * + * Copyright 2005 Mike McCormack + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winnls.h" + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL + +#include "version.rc" + +#include "msi_En.rc" diff --git a/reactos/lib/msi/msi.spec b/reactos/lib/msi/msi.spec index 7b6029ae8f1..ad1cd0d0840 100644 --- a/reactos/lib/msi/msi.spec +++ b/reactos/lib/msi/msi.spec @@ -6,8 +6,8 @@ 6 stdcall MsiAdvertiseProductW(wstr wstr wstr long) 7 stdcall MsiCloseAllHandles() 8 stdcall MsiCloseHandle(long) -9 stub MsiCollectUserInfoA -10 stub MsiCollectUserInfoW +9 stdcall MsiCollectUserInfoA(str) +10 stdcall MsiCollectUserInfoW(wstr) 11 stub MsiConfigureFeatureA 12 stub MsiConfigureFeatureFromDescriptorA 13 stub MsiConfigureFeatureFromDescriptorW @@ -32,7 +32,7 @@ 32 stdcall MsiDatabaseOpenViewW(long wstr ptr) 33 stdcall MsiDoActionA(long str) 34 stdcall MsiDoActionW(long wstr) -35 stub MsiEnableUIPreview +35 stdcall MsiEnableUIPreview(long ptr) 36 stdcall MsiEnumClientsA(str long ptr) 37 stdcall MsiEnumClientsW(wstr long ptr) 38 stdcall MsiEnumComponentQualifiersA(str long str ptr str ptr) @@ -79,7 +79,7 @@ 79 stdcall MsiGetTargetPathA(long str ptr ptr) 80 stdcall MsiGetTargetPathW(long wstr ptr ptr) 81 stub MsiGetUserInfoA -82 stub MsiGetUserInfoW +82 stdcall MsiGetUserInfoW(wstr ptr ptr ptr ptr ptr ptr) 83 stub MsiInstallMissingComponentA 84 stub MsiInstallMissingComponentW 85 stub MsiInstallMissingFileA @@ -94,10 +94,10 @@ 94 stdcall MsiOpenPackageW(wstr ptr) 95 stdcall MsiOpenProductA(str ptr) 96 stdcall MsiOpenProductW(wstr ptr) -97 stub MsiPreviewBillboardA -98 stub MsiPreviewBillboardW -99 stub MsiPreviewDialogA -100 stub MsiPreviewDialogW +97 stdcall MsiPreviewBillboardA(long str str) +98 stdcall MsiPreviewBillboardW(long wstr wstr) +99 stdcall MsiPreviewDialogA(long str) +100 stdcall MsiPreviewDialogW(long wstr) 101 stub MsiProcessAdvertiseScriptA 102 stub MsiProcessAdvertiseScriptW 103 stdcall MsiProcessMessage(long long long) @@ -148,9 +148,9 @@ 148 stdcall MsiSummaryInfoGetPropertyA(long long ptr ptr ptr ptr ptr) 149 stdcall MsiSummaryInfoGetPropertyCount(long ptr) 150 stdcall MsiSummaryInfoGetPropertyW(long long ptr ptr ptr ptr ptr) -151 stub MsiSummaryInfoPersist -152 stub MsiSummaryInfoSetPropertyA -153 stub MsiSummaryInfoSetPropertyW +151 stdcall MsiSummaryInfoPersist(long) +152 stdcall MsiSummaryInfoSetPropertyA(long long long long ptr str) +153 stdcall MsiSummaryInfoSetPropertyW(long long long long ptr wstr) 154 stub MsiUseFeatureA 155 stub MsiUseFeatureW 156 stdcall MsiVerifyPackageA(str) @@ -186,21 +186,21 @@ 186 stub MsiCreateTransformSummaryInfoW 187 stub MsiQueryFeatureStateFromDescriptorA 188 stub MsiQueryFeatureStateFromDescriptorW -189 stub MsiConfigureProductExA -190 stub MsiConfigureProductExW +189 stdcall MsiConfigureProductExA(str long long str) +190 stdcall MsiConfigureProductExW(wstr long long wstr) 191 stub MsiInvalidateFeatureCache 192 stub MsiUseFeatureExA -193 stub MsiUseFeatureExW +193 stdcall MsiUseFeatureExW(wstr wstr long long) 194 stdcall MsiGetFileVersionA(str str ptr str ptr) 195 stdcall MsiGetFileVersionW(wstr wstr ptr wstr ptr) 196 stdcall MsiLoadStringA(long long long long long) 197 stdcall MsiLoadStringW(long long long long long) 198 stdcall MsiMessageBoxA(long long long long long long) 199 stdcall MsiMessageBoxW(long long long long long long) -200 stub MsiDecomposeDescriptorA -201 stub MsiDecomposeDescriptorW +200 stdcall MsiDecomposeDescriptorA(str ptr ptr ptr ptr) +201 stdcall MsiDecomposeDescriptorW(wstr ptr ptr ptr ptr) 202 stub MsiProvideQualifiedComponentExA -203 stub MsiProvideQualifiedComponentExW +203 stdcall MsiProvideQualifiedComponentExW(wstr wstr long wstr long long ptr ptr) 204 stdcall MsiEnumRelatedProductsA(str long long ptr) 205 stdcall MsiEnumRelatedProductsW(wstr long long ptr) 206 stub MsiSetFeatureAttributesA @@ -213,13 +213,13 @@ 213 stub MsiSourceListForceResolutionW 214 stub MsiIsProductElevatedA 215 stub MsiIsProductElevatedW -216 stub MsiGetShortcutTargetA -217 stub MsiGetShortcutTargetW +216 stdcall MsiGetShortcutTargetA(str ptr ptr ptr) +217 stdcall MsiGetShortcutTargetW(wstr ptr ptr ptr) 218 stub MsiGetFileHashA 219 stub MsiGetFileHashW 220 stub MsiEnumComponentCostsA 221 stub MsiEnumComponentCostsW -222 stub MsiCreateAndVerifyInstallerDirectory +222 stdcall MsiCreateAndVerifyInstallerDirectory() 223 stdcall MsiGetFileSignatureInformationA(str long ptr ptr ptr) 224 stdcall MsiGetFileSignatureInformationW(wstr long ptr ptr ptr) 225 stdcall MsiProvideAssemblyA(str str long long str ptr) diff --git a/reactos/lib/msi/msi_En.rc b/reactos/lib/msi/msi_En.rc new file mode 100644 index 00000000000..854b7a8cc8f --- /dev/null +++ b/reactos/lib/msi/msi_En.rc @@ -0,0 +1,33 @@ +/* + * English resources for MSI + * + * Copyright 2005 Mike McCormack + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + 5 "path %s not found" + 9 "insert disk %s" + 10 "bad parameters" + 11 "enter which folder contains %s" + 12 "install source for feature missing" + 13 "network drive for feature missing" + 14 "feature from:" + 15 "choose which folder contains %s" +} diff --git a/reactos/lib/msi/msipriv.h b/reactos/lib/msi/msipriv.h index 306feca76f8..98e735056fa 100644 --- a/reactos/lib/msi/msipriv.h +++ b/reactos/lib/msi/msipriv.h @@ -1,7 +1,7 @@ /* * Implementation of the Microsoft Installer (msi.dll) * - * Copyright 2002 Mike McCormack for CodeWeavers + * Copyright 2002-2005 Mike McCormack for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -53,7 +53,7 @@ struct tagMSIOBJECTHDR { UINT magic; UINT type; - UINT refcount; + DWORD refcount; msihandledestructor destructor; struct tagMSIOBJECTHDR *next; struct tagMSIOBJECTHDR *prev; @@ -161,7 +161,7 @@ typedef struct tagMSIVIEWOPS /* * modify - not yet implemented properly */ - UINT (*modify)( struct tagMSIVIEW *, MSIMODIFY, MSIHANDLE ); + UINT (*modify)( struct tagMSIVIEW *, MSIMODIFY, MSIRECORD * ); /* * delete - destroys the structure completely @@ -182,6 +182,9 @@ struct tagMSIVIEW MSIVIEWOPS *ops; }; +struct msi_dialog_tag; +typedef struct msi_dialog_tag msi_dialog; + typedef struct tagMSIPACKAGE { MSIOBJECTHDR hdr; @@ -196,14 +199,37 @@ typedef struct tagMSIPACKAGE UINT loaded_files; LPWSTR ActionFormat; LPWSTR LastAction; + + LPWSTR *DeferredAction; + UINT DeferredActionCount; + + LPWSTR *CommitAction; + UINT CommitActionCount; + + struct tagMSIRUNNINGACTION *RunningAction; + UINT RunningActionCount; + + LPWSTR PackagePath; + + UINT CurrentInstallState; + msi_dialog *dialog; + LPWSTR next_dialog; } MSIPACKAGE; +typedef struct tagMSIPREVIEW +{ + MSIOBJECTHDR hdr; + MSIPACKAGE *package; + msi_dialog *dialog; +} MSIPREVIEW; + #define MSIHANDLETYPE_ANY 0 #define MSIHANDLETYPE_DATABASE 1 #define MSIHANDLETYPE_SUMMARYINFO 2 #define MSIHANDLETYPE_VIEW 3 #define MSIHANDLETYPE_RECORD 4 #define MSIHANDLETYPE_PACKAGE 5 +#define MSIHANDLETYPE_PREVIEW 6 #define MSI_MAJORVERSION 2 #define MSI_MINORVERSION 0 @@ -212,7 +238,7 @@ typedef struct tagMSIPACKAGE #define GUID_SIZE 39 #define MSIHANDLE_MAGIC 0x4d434923 -#define MSIMAXHANDLES 0x80 +#define MSIMAXHANDLES 0xf0 #define MSISUMINFO_OFFSET 0x30LL @@ -271,9 +297,11 @@ extern BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name ); extern UINT read_raw_stream_data( MSIDATABASE*, LPCWSTR stname, USHORT **pdata, UINT *psz ); + +/* action internals */ extern UINT ACTION_DoTopLevelINSTALL( MSIPACKAGE *, LPCWSTR, LPCWSTR ); -extern void ACTION_remove_tracked_tempfiles( MSIPACKAGE* ); extern void ACTION_free_package_structures( MSIPACKAGE* ); +extern UINT ACTION_DialogBox( MSIPACKAGE*, LPCWSTR); /* record internals */ extern UINT MSI_RecordSetIStream( MSIRECORD *, unsigned int, IStream *); @@ -296,6 +324,9 @@ extern void enum_stream_names( IStorage *stg ); /* database internals */ 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 ); +extern UINT MSI_IterateRecords( MSIQUERY *, DWORD *, record_func, LPVOID ); /* view internals */ extern UINT MSI_ViewExecute( MSIQUERY*, MSIRECORD * ); @@ -303,26 +334,51 @@ extern UINT MSI_ViewFetch( MSIQUERY*, MSIRECORD ** ); extern UINT MSI_ViewClose( MSIQUERY* ); /* package internals */ -extern UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE ** ); -extern UINT MSI_SetTargetPathW( MSIPACKAGE *, LPCWSTR, LPCWSTR); +extern MSIPACKAGE *MSI_CreatePackage( MSIDATABASE * ); +extern UINT MSI_OpenPackageW( LPCWSTR szPackage, MSIPACKAGE ** ); +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 INT MSI_ProcessMessage( MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD * ); +extern UINT MSI_GetPropertyW( MSIPACKAGE *, LPCWSTR, LPWSTR, DWORD * ); extern MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *, LPCWSTR ); extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR ); -extern UINT MSI_GetComponentStateW(MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE *); -extern UINT MSI_GetFeatureStateW(MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE *); +extern UINT MSI_GetComponentStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE * ); +extern UINT MSI_GetFeatureStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE * ); +/* for deformating */ +extern UINT MSI_FormatRecordW(MSIPACKAGE* package, MSIRECORD* record, + LPWSTR buffer, DWORD *size); + /* registry data encoding/decoding functions */ -BOOL unsquash_guid(LPCWSTR in, LPWSTR out); -BOOL squash_guid(LPCWSTR in, LPWSTR out); -BOOL encode_base85_guid(GUID *,LPWSTR); -BOOL decode_base85_guid(LPCWSTR,GUID*); +extern BOOL unsquash_guid(LPCWSTR in, LPWSTR out); +extern BOOL squash_guid(LPCWSTR in, LPWSTR out); +extern BOOL encode_base85_guid(GUID *,LPWSTR); +extern BOOL decode_base85_guid(LPCWSTR,GUID*); +extern UINT MSIREG_OpenUninstallKey(LPCWSTR szProduct, HKEY* key, BOOL create); +extern UINT MSIREG_OpenUserProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create); +extern UINT MSIREG_OpenFeatures(HKEY* key); +extern UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create); +extern UINT MSIREG_OpenComponents(HKEY* key); +extern UINT MSIREG_OpenComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create); +extern UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create); +extern UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create); + +/* msi dialog interface */ +typedef VOID (*msi_dialog_event_handler)( MSIPACKAGE*, LPCWSTR, LPCWSTR, msi_dialog* ); +extern msi_dialog *msi_dialog_create( MSIPACKAGE*, LPCWSTR, msi_dialog_event_handler ); +extern UINT msi_dialog_run_message_loop( msi_dialog* ); +extern void msi_dialog_end_dialog( msi_dialog* ); +extern void msi_dialog_check_messages( msi_dialog*, HANDLE ); +extern void msi_dialog_do_preview( msi_dialog* ); +extern void msi_dialog_destroy( msi_dialog* ); +extern void msi_dialog_register_class( void ); +extern void msi_dialog_unregister_class( void ); /* UI globals */ extern INSTALLUILEVEL gUILevel; extern HWND gUIhwnd; -extern INSTALLUI_HANDLERA gUIHandler; +extern INSTALLUI_HANDLERA gUIHandlerA; +extern INSTALLUI_HANDLERW gUIHandlerW; extern DWORD gUIFilter; extern LPVOID gUIContext; extern WCHAR gszLogFile[MAX_PATH]; diff --git a/reactos/lib/msi/msiquery.c b/reactos/lib/msi/msiquery.c index f856626d024..29665bd6fa3 100644 --- a/reactos/lib/msi/msiquery.c +++ b/reactos/lib/msi/msiquery.c @@ -38,30 +38,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); -#if 0 -typedef struct tagMSIQUERY -{ - MSIOBJECTHDR hdr; - MSIVIEW *view; - UINT row; - MSIDATABASE *db; -} MSIQUERY; -#endif - -UINT WINAPI MsiDatabaseIsTablePersistentA( - MSIHANDLE hDatabase, LPSTR szTableName) -{ - FIXME("%lx %s\n", hDatabase, debugstr_a(szTableName)); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiDatabaseIsTablePersistentW( - MSIHANDLE hDatabase, LPWSTR szTableName) -{ - FIXME("%lx %s\n", hDatabase, debugstr_w(szTableName)); - return ERROR_CALL_NOT_IMPLEMENTED; -} - void MSI_CloseView( MSIOBJECTHDR *arg ) { MSIQUERY *query = (MSIQUERY*) arg; @@ -158,6 +134,87 @@ UINT MSI_DatabaseOpenViewW(MSIDATABASE *db, return r; } +UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) +{ + LPWSTR szQuery; + LPCWSTR p; + UINT sz, rc; + va_list va; + + /* figure out how much space we need to allocate */ + va_start(va, fmt); + sz = strlenW(fmt) + 1; + p = fmt; + while (*p) + { + p = strchrW(p, '%'); + if (!p) + break; + p++; + switch (*p) + { + case 's': /* a string */ + sz += strlenW(va_arg(va,LPCWSTR)); + break; + case 'd': + case 'i': /* an integer -2147483648 seems to be longest */ + sz += 3*sizeof(int); + (void)va_arg(va,int); + break; + case '%': /* a single % - leave it alone */ + break; + default: + FIXME("Unhandled character type %c\n",*p); + } + p++; + } + va_end(va); + + /* construct the string */ + szQuery = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR)); + va_start(va, fmt); + vsnprintfW(szQuery, sz, fmt, va); + va_end(va); + + /* perform the query */ + rc = MSI_DatabaseOpenViewW(db, szQuery, view); + HeapFree(GetProcessHeap(), 0, szQuery); + return rc; +} + +UINT MSI_IterateRecords( MSIQUERY *view, DWORD *count, + record_func func, LPVOID param ) +{ + MSIRECORD *rec = NULL; + UINT r, n = 0, max = 0; + + r = MSI_ViewExecute( view, NULL ); + if( r != ERROR_SUCCESS ) + return r; + + if( count ) + max = *count; + + /* iterate a query */ + for( n = 0; (max == 0) || (n < max); n++ ) + { + r = MSI_ViewFetch( view, &rec ); + if( r != ERROR_SUCCESS ) + break; + r = func( rec, param ); + msiobj_release( &rec->hdr ); + if( r != ERROR_SUCCESS ) + break; + } + + MSI_ViewClose( view ); + + if( count ) + *count = n; + + return r; +} + UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb, LPCWSTR szQuery, MSIHANDLE *phView) { @@ -358,7 +415,10 @@ UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec) } } + msiobj_lock( &rec->hdr ); ret = MSI_ViewExecute( query, rec ); + msiobj_unlock( &rec->hdr ); + out: if( query ) msiobj_release( &query->hdr ); @@ -370,10 +430,10 @@ out: UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec) { - MSIVIEW *view; - MSIQUERY *query; - MSIHANDLE handle; - UINT ret, i, count = 0, type; + MSIVIEW *view = NULL; + MSIQUERY *query = NULL; + MSIRECORD *rec = NULL; + UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type; LPWSTR name; TRACE("%ld %d %p\n", hView, info, hRec); @@ -384,34 +444,82 @@ UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hR view = query->view; if( !view ) - return ERROR_FUNCTION_FAILED; + goto out; if( !view->ops->get_dimensions ) - return ERROR_FUNCTION_FAILED; + goto out; - ret = view->ops->get_dimensions( view, NULL, &count ); - if( ret ) - return ret; + r = view->ops->get_dimensions( view, NULL, &count ); + if( r ) + goto out; if( !count ) - return ERROR_INVALID_PARAMETER; + { + r = ERROR_INVALID_PARAMETER; + goto out; + } - handle = MsiCreateRecord( count ); - if( !handle ) + rec = MSI_CreateRecord( count ); + if( !rec ) return ERROR_FUNCTION_FAILED; for( i=0; iops->get_column_info( view, i+1, &name, &type ); - if( ret != ERROR_SUCCESS ) + r = view->ops->get_column_info( view, i+1, &name, &type ); + if( r != ERROR_SUCCESS ) continue; - MsiRecordSetStringW( handle, i+1, name ); + MSI_RecordSetStringW( rec, i+1, name ); HeapFree( GetProcessHeap(), 0, name ); } - *hRec = handle; + *hRec = alloc_msihandle( &rec->hdr ); - return ERROR_SUCCESS; +out: + if( query ) + msiobj_release( &query->hdr ); + if( rec ) + msiobj_release( &rec->hdr ); + + return r; +} + +UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode, + MSIHANDLE hRecord) +{ + MSIVIEW *view = NULL; + MSIQUERY *query = NULL; + MSIRECORD *rec = NULL; + UINT r = ERROR_FUNCTION_FAILED; + + TRACE("%ld %x %ld\n", hView, eModifyMode, hRecord); + + query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); + if( !query ) + return ERROR_INVALID_HANDLE; + + view = query->view; + if( !view ) + goto out; + + if( !view->ops->modify ) + goto out; + + rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD ); + if( !rec ) + { + r = ERROR_INVALID_HANDLE; + goto out; + } + + r = view->ops->modify( view, eModifyMode, rec ); + +out: + if( query ) + msiobj_release( &query->hdr ); + if( rec ) + msiobj_release( &rec->hdr ); + + return r; } UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb, @@ -461,6 +569,8 @@ UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb ) /* FIXME: unlock the database */ + msiobj_release( &db->hdr ); + return r; } @@ -478,9 +588,16 @@ UINT WINAPI MsiDatabaseGetPrimaryKeysW(MSIHANDLE hdb, return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiViewModify(MSIHANDLE hView, MSIMODIFY eModifyMode, MSIHANDLE -hRecord) +UINT WINAPI MsiDatabaseIsTablePersistentA( + MSIHANDLE hDatabase, LPSTR szTableName) { - FIXME("%ld %x %ld\n",hView, eModifyMode, hRecord); + FIXME("%lx %s\n", hDatabase, debugstr_a(szTableName)); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiDatabaseIsTablePersistentW( + MSIHANDLE hDatabase, LPWSTR szTableName) +{ + FIXME("%lx %s\n", hDatabase, debugstr_w(szTableName)); return ERROR_CALL_NOT_IMPLEMENTED; } diff --git a/reactos/lib/msi/order.c b/reactos/lib/msi/order.c index f37bdf10972..c23b1ef89ef 100644 --- a/reactos/lib/msi/order.c +++ b/reactos/lib/msi/order.c @@ -187,8 +187,7 @@ static UINT ORDER_close( struct tagMSIVIEW *view ) if( !ov->table ) return ERROR_FUNCTION_FAILED; - if( ov->reorder ) - HeapFree( GetProcessHeap(), 0, ov->reorder ); + HeapFree( GetProcessHeap(), 0, ov->reorder ); ov->reorder = NULL; return ov->table->ops->close( ov->table ); @@ -219,16 +218,17 @@ static UINT ORDER_get_column_info( struct tagMSIVIEW *view, return ov->table->ops->get_column_info( ov->table, n, name, type ); } -static UINT ORDER_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec) +static UINT ORDER_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, + MSIRECORD *rec ) { MSIORDERVIEW *ov = (MSIORDERVIEW*)view; - TRACE("%p %d %ld\n", ov, eModifyMode, hrec ); + TRACE("%p %d %p\n", ov, eModifyMode, rec ); if( !ov->table ) return ERROR_FUNCTION_FAILED; - return ov->table->ops->modify( ov->table, eModifyMode, hrec ); + return ov->table->ops->modify( ov->table, eModifyMode, rec ); } static UINT ORDER_delete( struct tagMSIVIEW *view ) @@ -240,8 +240,7 @@ static UINT ORDER_delete( struct tagMSIVIEW *view ) if( ov->table ) ov->table->ops->delete( ov->table ); - if( ov->reorder ) - HeapFree( GetProcessHeap(), 0, ov->reorder ); + HeapFree( GetProcessHeap(), 0, ov->reorder ); ov->reorder = NULL; msiobj_release( &ov->db->hdr ); diff --git a/reactos/lib/msi/package.c b/reactos/lib/msi/package.c index 639af427eaa..72d1a8deda4 100644 --- a/reactos/lib/msi/package.c +++ b/reactos/lib/msi/package.c @@ -53,36 +53,13 @@ void MSI_FreePackage( MSIOBJECTHDR *arg) { MSIPACKAGE *package= (MSIPACKAGE*) arg; - ACTION_remove_tracked_tempfiles(package); + if( package->dialog ) + msi_dialog_destroy( package->dialog ); ACTION_free_package_structures(package); msiobj_release( &package->db->hdr ); } -UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage) -{ - LPWSTR szwPack = NULL; - UINT len, ret; - - TRACE("%s %p\n",debugstr_a(szPackage), phPackage); - - if( szPackage ) - { - len = MultiByteToWideChar( CP_ACP, 0, szPackage, -1, NULL, 0 ); - szwPack = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); - if( szwPack ) - MultiByteToWideChar( CP_ACP, 0, szPackage, -1, szwPack, len ); - } - - ret = MsiOpenPackageW( szwPack, phPackage ); - - if( szwPack ) - HeapFree( GetProcessHeap(), 0, szwPack ); - - return ret; -} - - static const UINT clone_properties(MSIDATABASE *db) { MSIQUERY * view = NULL; @@ -102,7 +79,7 @@ static const UINT clone_properties(MSIDATABASE *db) '`','_','P','r','o','p','e','r','t','y','`',' ', '(','`','_','P','r','o','p','e','r','t','y','`',',', '`','V','a','l','u','e','`',')',' ', - 'V','A','L','U','E','S',' ','(','?',')',0}; + 'V','A','L','U','E','S',' ','(','?',',','?',')',0}; /* create the temporary properties table */ rc = MSI_DatabaseOpenViewW(db, CreateSql, &view); @@ -377,39 +354,18 @@ Privileged ReleaseDC(0, dc); } -UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) +MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db ) { - UINT rc; - MSIDATABASE *db = NULL; + static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 }; + static const WCHAR szpi[] = {'%','i',0}; MSIPACKAGE *package = NULL; WCHAR uilevel[10]; - UINT ret = ERROR_FUNCTION_FAILED; - static const WCHAR OriginalDatabase[] = -{'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0}; - static const WCHAR Database[] = -{'D','A','T','A','B','A','S','E',0}; - static const WCHAR szpi[] = {'%','i',0}; - static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 }; - - TRACE("%s %p\n",debugstr_w(szPackage), pPackage); - - if (szPackage[0] == '#') - { - INT handle = atoiW(&szPackage[1]); - db = msihandle2msiinfo( handle , MSIHANDLETYPE_DATABASE); - } - else - { - rc = MSI_OpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db); - if (rc != ERROR_SUCCESS) - return ERROR_FUNCTION_FAILED; - } + TRACE("%p\n", db); package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE), MSI_FreePackage ); - - if (package) + if( package ) { msiobj_addref( &db->hdr ); @@ -424,35 +380,78 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) package->loaded_files = 0; package->ActionFormat = NULL; package->LastAction = NULL; + package->dialog = NULL; + package->next_dialog = NULL; /* OK, here is where we do a slew of things to the database to * prep for all that is to come as a package */ clone_properties(db); set_installer_properties(package); - MSI_SetPropertyW(package, OriginalDatabase, szPackage); - MSI_SetPropertyW(package, Database, szPackage); sprintfW(uilevel,szpi,gUILevel); MSI_SetPropertyW(package, szLevel, uilevel); - - msiobj_addref( &package->hdr ); - *pPackage = package; - ret = ERROR_SUCCESS; } - if( package ) - msiobj_release( &package->hdr ); - if( db ) - msiobj_release( &db->hdr ); - - return ret; + return package; } -UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage) +UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) +{ + MSIDATABASE *db = NULL; + MSIPACKAGE *package; + MSIHANDLE handle; + + TRACE("%s %p\n", debugstr_w(szPackage), pPackage); + + if( szPackage[0] == '#' ) + { + handle = atoiW(&szPackage[1]); + db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE ); + if( !db ) + return ERROR_INVALID_HANDLE; + } + else + { + UINT r = MSI_OpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db); + if( r != ERROR_SUCCESS ) + return r; + } + + package = MSI_CreatePackage( db ); + msiobj_release( &db->hdr ); + if( !package ) + return ERROR_FUNCTION_FAILED; + + /* + * FIXME: I don't think this is right. Maybe we should be storing the + * name of the database in the MSIDATABASE structure and fetching this + * info from there, or maybe this is only relevant to cached databases. + */ + if( szPackage[0] != '#' ) + { + static const WCHAR OriginalDatabase[] = + {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0}; + static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0}; + + MSI_SetPropertyW( package, OriginalDatabase, szPackage ); + MSI_SetPropertyW( package, Database, szPackage ); + } + + *pPackage = package; + + return ERROR_SUCCESS; +} + +UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage) { MSIPACKAGE *package = NULL; UINT ret; + TRACE("%s %08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage); + + if( dwOptions ) + FIXME("dwOptions %08lx not supported\n", dwOptions); + ret = MSI_OpenPackageW( szPackage, &package); if( ret == ERROR_SUCCESS ) { @@ -462,16 +461,34 @@ UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage) return ret; } -UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage) +UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage) { - FIXME("%s 0x%08lx %p\n",debugstr_a(szPackage), dwOptions, phPackage); - return ERROR_CALL_NOT_IMPLEMENTED; + return MsiOpenPackageExW( szPackage, 0, phPackage ); } -UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage) +UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage) { - FIXME("%s 0x%08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage); - return ERROR_CALL_NOT_IMPLEMENTED; + LPWSTR szwPack = NULL; + UINT len, ret; + + if( szPackage ) + { + len = MultiByteToWideChar( CP_ACP, 0, szPackage, -1, NULL, 0 ); + szwPack = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); + if( szwPack ) + MultiByteToWideChar( CP_ACP, 0, szPackage, -1, szwPack, len ); + } + + ret = MsiOpenPackageExW( szwPack, dwOptions, phPackage ); + + HeapFree( GetProcessHeap(), 0, szwPack ); + + return ret; +} + +UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage) +{ + return MsiOpenPackageExA( szPackage, 0, phPackage ); } MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall) @@ -555,7 +572,7 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType, HeapFree(GetProcessHeap(),0,tmp); } - TRACE("(%p %lx %lx %s)\n",gUIHandler, gUIFilter, log_type, + TRACE("(%p %lx %lx %s)\n",gUIHandlerA, gUIFilter, log_type, debugstr_w(message)); /* convert it to ASCII */ @@ -565,9 +582,9 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType, WideCharToMultiByte( CP_ACP, 0, message, -1, msg, len, NULL, NULL ); - if (gUIHandler && (gUIFilter & log_type)) + if (gUIHandlerA && (gUIFilter & log_type)) { - rc = gUIHandler(gUIContext,eMessageType,msg); + rc = gUIHandlerA(gUIContext,eMessageType,msg); } if ((!rc) && (gszLogFile[0]) && !((eMessageType & 0xff000000) == @@ -649,10 +666,8 @@ UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue) hr = MsiSetPropertyW( hInstall, szwName, szwValue); end: - if( szwName ) - HeapFree( GetProcessHeap(), 0, szwName ); - if( szwValue ) - HeapFree( GetProcessHeap(), 0, szwValue ); + HeapFree( GetProcessHeap(), 0, szwName ); + HeapFree( GetProcessHeap(), 0, szwValue ); return hr; } @@ -667,7 +682,7 @@ UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue) {'I','N','S','E','R','T',' ','i','n','t','o',' ','`','_','P','r','o','p' ,'e','r','t','y','`',' ','(','`','_','P','r','o','p','e','r','t','y','`' ,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S' -,' ','(','?',')',0}; +,' ','(','?',',','?',')',0}; static const WCHAR Update[]= {'U','P','D','A','T','E',' ','_','P','r','o','p','e' ,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','=' @@ -848,7 +863,12 @@ UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, return ERROR_INVALID_HANDLE; ret = MSI_GetPropertyA(package, szName, szValueBuf, pchValueBuf ); msiobj_release( &package->hdr ); - return ret; + + /* MsiGetProperty does not return error codes on missing properties */ + if (ret!= ERROR_MORE_DATA) + return ERROR_SUCCESS; + else + return ret; } @@ -870,5 +890,10 @@ UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, return ERROR_INVALID_HANDLE; ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf ); msiobj_release( &package->hdr ); - return ret; + + /* MsiGetProperty does not return error codes on missing properties */ + if (ret!= ERROR_MORE_DATA) + return ERROR_SUCCESS; + else + return ret; } diff --git a/reactos/lib/msi/preview.c b/reactos/lib/msi/preview.c new file mode 100644 index 00000000000..03c7436ddd2 --- /dev/null +++ b/reactos/lib/msi/preview.c @@ -0,0 +1,164 @@ +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2005 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "msi.h" +#include "msipriv.h" + +#include "wine/debug.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +static void MSI_ClosePreview( MSIOBJECTHDR *arg ) +{ + MSIPREVIEW *preview = (MSIPREVIEW *) arg; + + msiobj_release( &preview->package->hdr ); +} + +MSIPREVIEW *MSI_EnableUIPreview( MSIDATABASE *db ) +{ + MSIPREVIEW *preview = NULL; + MSIPACKAGE *package; + + package = MSI_CreatePackage( db ); + if( package ) + { + preview = alloc_msiobject( MSIHANDLETYPE_PREVIEW, sizeof (MSIPREVIEW), + MSI_ClosePreview ); + if( preview ) + { + preview->package = package; + preview->dialog = 0; + msiobj_addref( &package->hdr ); + } + msiobj_release( &package->hdr ); + } + return preview; +} + +UINT WINAPI MsiEnableUIPreview( MSIHANDLE hdb, MSIHANDLE* phPreview ) +{ + MSIDATABASE *db; + MSIPREVIEW *preview; + UINT r = ERROR_FUNCTION_FAILED; + + TRACE("%ld %p\n", hdb, phPreview); + + db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE ); + if( !db ) + return ERROR_INVALID_HANDLE; + preview = MSI_EnableUIPreview( db ); + if( preview ) + { + *phPreview = alloc_msihandle( &preview->hdr ); + msiobj_release( &preview->hdr ); + r = ERROR_SUCCESS; + } + + return r; +} + +static VOID 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 )); +} + +UINT MSI_PreviewDialogW( MSIPREVIEW *preview, LPCWSTR szDialogName ) +{ + msi_dialog *dialog = NULL; + UINT r = ERROR_SUCCESS; + + if( preview->dialog ) + msi_dialog_destroy( preview->dialog ); + + /* an empty name means we should just destroy the current preview dialog */ + if( szDialogName ) + { + dialog = msi_dialog_create( preview->package, szDialogName, + preview_event_handler ); + if( dialog ) + msi_dialog_do_preview( dialog ); + else + r = ERROR_FUNCTION_FAILED; + } + preview->dialog = dialog; + + return r; +} + +UINT WINAPI MsiPreviewDialogW( MSIHANDLE hPreview, LPCWSTR szDialogName ) +{ + MSIPREVIEW *preview; + UINT r; + + TRACE("%ld %s\n", hPreview, debugstr_w(szDialogName)); + + preview = msihandle2msiinfo( hPreview, MSIHANDLETYPE_PREVIEW ); + if( !preview ) + return ERROR_INVALID_HANDLE; + + r = MSI_PreviewDialogW( preview, szDialogName ); + + msiobj_release( &preview->hdr ); + + return r; +} + +UINT WINAPI MsiPreviewDialogA( MSIHANDLE hPreview, LPCSTR szDialogName ) +{ + UINT r, len; + LPWSTR strW = NULL; + + TRACE("%ld %s\n", hPreview, debugstr_a(szDialogName)); + + if( szDialogName ) + { + len = MultiByteToWideChar( CP_ACP, 0, szDialogName, -1, NULL, 0 ); + strW = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, szDialogName, -1, strW, len ); + } + r = MsiPreviewDialogW( hPreview, strW ); + HeapFree( GetProcessHeap(), 0, strW ); + return r; +} + +UINT WINAPI MsiPreviewBillboardW( MSIHANDLE hPreview, LPCWSTR szControlName, + LPCWSTR szBillboard) +{ + FIXME("%ld %s %s\n", hPreview, debugstr_w(szControlName), + debugstr_w(szBillboard)); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiPreviewBillboardA( MSIHANDLE hPreview, LPCSTR szControlName, + LPCSTR szBillboard) +{ + FIXME("%ld %s %s\n", hPreview, debugstr_a(szControlName), + debugstr_a(szBillboard)); + return ERROR_CALL_NOT_IMPLEMENTED; +} diff --git a/reactos/lib/msi/record.c b/reactos/lib/msi/record.c index 30cde0f80ef..967017cd5cc 100644 --- a/reactos/lib/msi/record.c +++ b/reactos/lib/msi/record.c @@ -454,12 +454,20 @@ UINT MSI_RecordSetStringA( MSIRECORD *rec, unsigned int iField, LPCSTR szValue ) if( iField > rec->count ) return ERROR_INVALID_FIELD; - len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 ); - str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, szValue, -1, str, len ); MSI_FreeField( &rec->fields[iField] ); - rec->fields[iField].type = MSIFIELD_WSTR; - rec->fields[iField].u.szwVal = str; + if( szValue && szValue[0] ) + { + len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 ); + str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, szValue, -1, str, len ); + rec->fields[iField].type = MSIFIELD_WSTR; + rec->fields[iField].u.szwVal = str; + } + else + { + rec->fields[iField].type = MSIFIELD_NULL; + rec->fields[iField].u.szwVal = NULL; + } return 0; } @@ -491,13 +499,22 @@ UINT MSI_RecordSetStringW( MSIRECORD *rec, unsigned int iField, LPCWSTR szValue if( iField > rec->count ) return ERROR_INVALID_FIELD; - len = lstrlenW(szValue) + 1; - str = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR)); - lstrcpyW( str, szValue ); - MSI_FreeField( &rec->fields[iField] ); - rec->fields[iField].type = MSIFIELD_WSTR; - rec->fields[iField].u.szwVal = str; + + if( szValue && szValue[0] ) + { + len = lstrlenW(szValue) + 1; + str = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR)); + lstrcpyW( str, szValue ); + + rec->fields[iField].type = MSIFIELD_WSTR; + rec->fields[iField].u.szwVal = str; + } + else + { + rec->fields[iField].type = MSIFIELD_NULL; + rec->fields[iField].u.szwVal = NULL; + } return 0; } @@ -520,18 +537,6 @@ UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, unsigned int iField, LPCWSTR return ret; } -UINT WINAPI MsiFormatRecordA(MSIHANDLE hInstall, MSIHANDLE hRecord, LPSTR szResult, DWORD *sz) -{ - FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiFormatRecordW(MSIHANDLE hInstall, MSIHANDLE hRecord, LPWSTR szResult, DWORD *sz) -{ - FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz); - return ERROR_CALL_NOT_IMPLEMENTED; -} - /* read the data in a file into an IStream */ UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm) { diff --git a/reactos/lib/msi/registry.c b/reactos/lib/msi/registry.c new file mode 100644 index 00000000000..61c03c63e5c --- /dev/null +++ b/reactos/lib/msi/registry.c @@ -0,0 +1,486 @@ +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2005 Mike McCormack for CodeWeavers + * 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 + */ + +#include + +#define COBJMACROS +#define NONAMELESSUNION + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winnls.h" +#include "shlwapi.h" +#include "wine/debug.h" +#include "msi.h" +#include "msipriv.h" +#include "wincrypt.h" +#include "wine/unicode.h" +#include "winver.h" +#include "winuser.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + + +/* + * This module will be all the helper functions for registry access by the + * installer bits. + */ +static const WCHAR szUserFeatures_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','\\', +'F','e','a','t','u','r','e','s','\\', +'%','s',0}; + +static const WCHAR szInstaller_Features[] = { +'S','o','f','t','w','a','r','e','\\', +'M','i','c','r','o','s','o','f','t','\\', +'W','i','n','d','o','w','s','\\', +'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', +'I','n','s','t','a','l','l','e','r','\\', +'F','e','a','t','u','r','e','s',0 }; + +static const WCHAR szInstaller_Features_fmt[] = { +'S','o','f','t','w','a','r','e','\\', +'M','i','c','r','o','s','o','f','t','\\', +'W','i','n','d','o','w','s','\\', +'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', +'I','n','s','t','a','l','l','e','r','\\', +'F','e','a','t','u','r','e','s','\\', +'%','s',0}; + +static const WCHAR szInstaller_Components[] = { +'S','o','f','t','w','a','r','e','\\', +'M','i','c','r','o','s','o','f','t','\\', +'W','i','n','d','o','w','s','\\', +'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', +'I','n','s','t','a','l','l','e','r','\\', +'C','o','m','p','o','n','e','n','t','s',0 }; + +static const WCHAR szInstaller_Components_fmt[] = { +'S','o','f','t','w','a','r','e','\\', +'M','i','c','r','o','s','o','f','t','\\', +'W','i','n','d','o','w','s','\\', +'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', +'I','n','s','t','a','l','l','e','r','\\', +'C','o','m','p','o','n','e','n','t','s','\\', +'%','s',0}; + +static const WCHAR szUninstall_fmt[] = { +'S','o','f','t','w','a','r','e','\\', +'M','i','c','r','o','s','o','f','t','\\', +'W','i','n','d','o','w','s','\\', +'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', +'U','n','i','n','s','t','a','l','l','\\', +'%','s',0 }; + +static const WCHAR szUserProduct_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','\\', +'P','r','o','d','u','c','t','s','\\', +'%','s',0}; + +static const WCHAR szInstaller_Products[] = { +'S','o','f','t','w','a','r','e','\\', +'M','i','c','r','o','s','o','f','t','\\', +'W','i','n','d','o','w','s','\\', +'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', +'I','n','s','t','a','l','l','e','r','\\', +'P','r','o','d','u','c','t','s',0}; + +static const WCHAR szInstaller_Products_fmt[] = { +'S','o','f','t','w','a','r','e','\\', +'M','i','c','r','o','s','o','f','t','\\', +'W','i','n','d','o','w','s','\\', +'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', +'I','n','s','t','a','l','l','e','r','\\', +'P','r','o','d','u','c','t','s','\\', +'%','s',0}; + +BOOL unsquash_guid(LPCWSTR in, LPWSTR out) +{ + DWORD i,n=0; + + out[n++]='{'; + for(i=0; i<8; i++) + out[n++] = in[7-i]; + out[n++]='-'; + for(i=0; i<4; i++) + out[n++] = in[11-i]; + out[n++]='-'; + for(i=0; i<4; i++) + out[n++] = in[15-i]; + out[n++]='-'; + for(i=0; i<2; i++) + { + out[n++] = in[17+i*2]; + out[n++] = in[16+i*2]; + } + out[n++]='-'; + for( ; i<8; i++) + { + out[n++] = in[17+i*2]; + out[n++] = in[16+i*2]; + } + out[n++]='}'; + out[n]=0; + return TRUE; +} + +BOOL squash_guid(LPCWSTR in, LPWSTR out) +{ + DWORD i,n=0; + + if(in[n++] != '{') + return FALSE; + for(i=0; i<8; i++) + out[7-i] = in[n++]; + if(in[n++] != '-') + return FALSE; + for(i=0; i<4; i++) + out[11-i] = in[n++]; + if(in[n++] != '-') + return FALSE; + for(i=0; i<4; i++) + out[15-i] = in[n++]; + if(in[n++] != '-') + return FALSE; + for(i=0; i<2; i++) + { + out[17+i*2] = in[n++]; + out[16+i*2] = in[n++]; + } + if(in[n++] != '-') + return FALSE; + for( ; i<8; i++) + { + out[17+i*2] = in[n++]; + out[16+i*2] = in[n++]; + } + out[32]=0; + if(in[n++] != '}') + return FALSE; + if(in[n]) + return FALSE; + return TRUE; +} + + +/* tables for encoding and decoding base85 */ +static const unsigned char table_dec85[0x80] = { +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, +0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff, +0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17, +0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, +0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36, +0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46, +0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff, +}; + +static const char table_enc85[] = +"!$%&'()*+,-.0123456789=?@ABCDEFGHIJKLMNO" +"PQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwx" +"yz{}~"; + +/* + * Converts a base85 encoded guid into a GUID pointer + * Base85 encoded GUIDs should be 20 characters long. + * + * returns TRUE if successful, FALSE if not + */ +BOOL decode_base85_guid( LPCWSTR str, GUID *guid ) +{ + DWORD i, val = 0, base = 1, *p; + + p = (DWORD*) guid; + for( i=0; i<20; i++ ) + { + if( (i%5) == 0 ) + { + val = 0; + base = 1; + } + val += table_dec85[str[i]] * base; + if( str[i] >= 0x80 ) + return FALSE; + if( table_dec85[str[i]] == 0xff ) + return FALSE; + if( (i%5) == 4 ) + p[i/5] = val; + base *= 85; + } + return TRUE; +} + +/* + * Encodes a base85 guid given a GUID pointer + * Caller should provide a 21 character buffer for the encoded string. + * + * returns TRUE if successful, FALSE if not + */ +BOOL encode_base85_guid( GUID *guid, LPWSTR str ) +{ + unsigned int x, *p, i; + + p = (unsigned int*) guid; + for( i=0; i<4; i++ ) + { + x = p[i]; + *str++ = table_enc85[x%85]; + x = x/85; + *str++ = table_enc85[x%85]; + x = x/85; + *str++ = table_enc85[x%85]; + x = x/85; + *str++ = table_enc85[x%85]; + x = x/85; + *str++ = table_enc85[x%85]; + } + *str = 0; + + return TRUE; +} + + +UINT MSIREG_OpenUninstallKey(LPCWSTR szProduct, HKEY* key, BOOL create) +{ + UINT rc; + WCHAR keypath[0x200]; + TRACE("%s\n",debugstr_w(szProduct)); + + sprintfW(keypath,szUninstall_fmt,szProduct); + + if (create) + rc = RegCreateKeyW(HKEY_LOCAL_MACHINE, keypath, key); + else + rc = RegOpenKeyW(HKEY_LOCAL_MACHINE, keypath, key); + + return rc; +} + +UINT MSIREG_OpenUserProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create) +{ + UINT rc; + WCHAR squished_pc[GUID_SIZE]; + WCHAR keypath[0x200]; + + TRACE("%s\n",debugstr_w(szProduct)); + squash_guid(szProduct,squished_pc); + TRACE("squished (%s)\n", debugstr_w(squished_pc)); + + sprintfW(keypath,szUserProduct_fmt,squished_pc); + + if (create) + rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key); + else + rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key); + + return rc; +} + +UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create) +{ + UINT rc; + WCHAR squished_pc[GUID_SIZE]; + WCHAR keypath[0x200]; + + TRACE("%s\n",debugstr_w(szProduct)); + squash_guid(szProduct,squished_pc); + TRACE("squished (%s)\n", debugstr_w(squished_pc)); + + sprintfW(keypath,szUserFeatures_fmt,squished_pc); + + if (create) + rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key); + else + rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key); + + return rc; +} + +UINT MSIREG_OpenFeatures(HKEY* key) +{ + return RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller_Features,key); +} + +UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create) +{ + UINT rc; + WCHAR squished_pc[GUID_SIZE]; + WCHAR keypath[0x200]; + + TRACE("%s\n",debugstr_w(szProduct)); + squash_guid(szProduct,squished_pc); + TRACE("squished (%s)\n", debugstr_w(squished_pc)); + + sprintfW(keypath,szInstaller_Features_fmt,squished_pc); + + if (create) + rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key); + else + rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key); + + return rc; +} + +UINT MSIREG_OpenComponents(HKEY* key) +{ + return RegCreateKeyW(HKEY_LOCAL_MACHINE,szInstaller_Components,key); +} + +UINT MSIREG_OpenComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create) +{ + UINT rc; + WCHAR squished_cc[GUID_SIZE]; + WCHAR keypath[0x200]; + + TRACE("%s\n",debugstr_w(szComponent)); + squash_guid(szComponent,squished_cc); + TRACE("squished (%s)\n", debugstr_w(squished_cc)); + + sprintfW(keypath,szInstaller_Components_fmt,squished_cc); + + if (create) + rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key); + else + rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key); + + return rc; +} + +UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create) +{ + UINT rc; + WCHAR squished_pc[GUID_SIZE]; + WCHAR keypath[0x200]; + + TRACE("%s\n",debugstr_w(szProduct)); + squash_guid(szProduct,squished_pc); + TRACE("squished (%s)\n", debugstr_w(squished_pc)); + + sprintfW(keypath,szInstaller_Products_fmt,squished_pc); + + if (create) + rc = RegCreateKeyW(HKEY_LOCAL_MACHINE,keypath,key); + else + rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,keypath,key); + + return rc; +} + +/************************************************************************* + * MsiDecomposeDescriptorW [MSI.@] + * + * Decomposes an MSI descriptor into product, feature and component parts. + * An MSI descriptor is a string of the form: + * [base 85 guid] [feature code] '>' [base 85 guid] + * + * PARAMS + * szDescriptor [I] the descriptor to decompose + * szProduct [O] buffer of MAX_FEATURE_CHARS for the product guid + * szFeature [O] buffer of MAX_FEATURE_CHARS for the feature code + * szComponent [O] buffer of MAX_FEATURE_CHARS for the component guid + * pUsed [O] the length of the descriptor + * + * RETURNS + * ERROR_SUCCESS if everything worked correctly + * ERROR_INVALID_PARAMETER if the descriptor was invalid + * + */ +UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct, + LPWSTR szFeature, LPWSTR szComponent, DWORD *pUsed ) +{ + UINT r, len; + LPWSTR p; + GUID product, component; + + TRACE("%s %p %p %p %p\n", debugstr_w(szDescriptor), szProduct, + szFeature, szComponent, pUsed); + + r = decode_base85_guid( szDescriptor, &product ); + if( !r ) + return ERROR_INVALID_PARAMETER; + + TRACE("product %s\n", debugstr_guid( &product )); + + p = strchrW(&szDescriptor[20],'>'); + if( !p ) + return ERROR_INVALID_PARAMETER; + + len = (p - &szDescriptor[20]); + if( len > MAX_FEATURE_CHARS ) + return ERROR_INVALID_PARAMETER; + memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) ); + szFeature[len] = 0; + + TRACE("feature %s\n", debugstr_w( szFeature )); + + r = decode_base85_guid( p+1, &component ); + if( !r ) + return ERROR_INVALID_PARAMETER; + + TRACE("component %s\n", debugstr_guid( &component )); + + StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 ); + StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 ); + len = ( &p[21] - szDescriptor ); + + TRACE("length = %d\n", len); + *pUsed = len; + + return ERROR_SUCCESS; +} + +UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct, + LPSTR szFeature, LPSTR szComponent, DWORD *pUsed ) +{ + WCHAR product[MAX_FEATURE_CHARS+1]; + WCHAR feature[MAX_FEATURE_CHARS+1]; + WCHAR component[MAX_FEATURE_CHARS+1]; + LPWSTR str = NULL; + UINT r, len; + + TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct, + szFeature, szComponent, pUsed); + + if( szDescriptor ) + { + len = MultiByteToWideChar( CP_ACP, 0, szDescriptor, -1, NULL, 0 ); + str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, szDescriptor, -1, str, len ); + } + + r = MsiDecomposeDescriptorW( str, product, feature, component, pUsed ); + + WideCharToMultiByte( CP_ACP, 0, product, MAX_FEATURE_CHARS+1, + szProduct, MAX_FEATURE_CHARS+1, NULL, NULL ); + WideCharToMultiByte( CP_ACP, 0, feature, MAX_FEATURE_CHARS+1, + szFeature, MAX_FEATURE_CHARS+1, NULL, NULL ); + WideCharToMultiByte( CP_ACP, 0, component, MAX_FEATURE_CHARS+1, + szComponent, MAX_FEATURE_CHARS+1, NULL, NULL ); + + HeapFree( GetProcessHeap(), 0, str ); + + return r; +} diff --git a/reactos/lib/msi/select.c b/reactos/lib/msi/select.c index d31ee8f32aa..69ec7c6b772 100644 --- a/reactos/lib/msi/select.c +++ b/reactos/lib/msi/select.c @@ -168,16 +168,17 @@ static UINT SELECT_get_column_info( struct tagMSIVIEW *view, return sv->table->ops->get_column_info( sv->table, n, name, type ); } -static UINT SELECT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec) +static UINT SELECT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, + MSIRECORD *rec ) { MSISELECTVIEW *sv = (MSISELECTVIEW*)view; - TRACE("%p %d %ld\n", sv, eModifyMode, hrec ); + TRACE("%p %d %p\n", sv, eModifyMode, rec ); if( !sv->table ) return ERROR_FUNCTION_FAILED; - return sv->table->ops->modify( sv->table, eModifyMode, hrec ); + return sv->table->ops->modify( sv->table, eModifyMode, rec ); } static UINT SELECT_delete( struct tagMSIVIEW *view ) diff --git a/reactos/lib/msi/sql.tab.c b/reactos/lib/msi/sql.tab.c index eb700d78e53..478856d6737 100644 --- a/reactos/lib/msi/sql.tab.c +++ b/reactos/lib/msi/sql.tab.c @@ -564,7 +564,7 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 23 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 125 +#define YYLAST 126 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 147 @@ -663,7 +663,7 @@ static const short yyrhs[] = -1, 168, 57, 163, -1, 168, 85, 163, -1, 168, 78, 163, -1, 168, 54, 163, -1, 168, 89, 163, -1, 168, 73, 92, -1, 168, 73, 90, 92, -1, - 168, -1, 167, -1, 167, -1, 164, 24, 167, -1, + 168, -1, 167, -1, 167, -1, 167, 24, 164, -1, 166, -1, 166, 24, 165, -1, 169, 45, 167, -1, 70, -1, 88, 70, -1, 120, -1, 138, -1, 169, -1, 170, 39, 171, -1, 171, -1, 171, -1, 66, @@ -678,8 +678,8 @@ static const unsigned short yyrline[] = 290, 294, 298, 302, 306, 313, 324, 335, 339, 353, 371, 384, 397, 404, 415, 434, 438, 442, 446, 450, 454, 458, 462, 466, 470, 474, 478, 485, 486, 490, - 502, 518, 519, 528, 544, 548, 552, 556, 563, 570, - 574, 581, 588, 592 + 502, 517, 518, 527, 543, 547, 551, 555, 562, 569, + 573, 580, 587, 591 }; #endif @@ -787,8 +787,8 @@ static const unsigned char yydefact[] = 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 12, 11, 25, 0, 17, 0, 35, 37, 38, 56, 39, 48, 36, 43, 47, 40, - 0, 45, 42, 41, 44, 19, 0, 49, 46, 0, - 6, 50, 7 + 0, 45, 42, 41, 44, 19, 0, 49, 46, 6, + 0, 7, 50 }; /* YYDEFGOTO[NTERM-NUM]. */ @@ -801,30 +801,30 @@ static const yysigned_char yydefgoto[] = /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -105 +#define YYPACT_NINF -104 static const yysigned_char yypact[] = { - -30, -104, -46, -34, -51, 21, -105, -105, -105, -105, - -77, -51, -51, -52, -105, -105, -105, -25, 7, -1, - 2, -79, -105, -105, 31, -33, -32, -25, -51, -105, - -52, -51, -51, -52, -51, -52, -105, -88, -105, -105, - -82, 33, 14, -105, -48, -15, -17, -43, -50, -50, - -51, -64, 13, -51, -2, -6, -105, -105, -105, -105, - -105, -105, 6, -9, -49, -50, -4, 26, -105, -4, - -105, -105, 24, -105, -105, -105, -105, -17, -52, 25, - -105, 9, 19, -7, -50, -50, -59, -59, -59, -44, - -59, -59, -59, -105, -105, -105, -105, -3, -105, -64, - -105, -4, -4, 73, -105, -105, -105, -105, -105, -105, - 22, -105, -105, -105, -105, -105, -19, -105, -105, -64, - 1, -105, -105 + -30, -103, -52, -34, -51, 21, -104, -104, -104, -104, + -70, -51, -51, -57, -104, -104, -104, -26, 11, -6, + -1, -69, -104, -104, 32, -25, -15, -26, -51, -104, + -57, -51, -51, -57, -51, -57, -104, -71, -104, -104, + -67, 47, 27, -104, -36, -19, -17, -29, -53, -53, + -51, -63, 26, -51, 17, -10, -104, -104, -104, -104, + -104, -104, 5, 7, -35, -53, -4, 35, -104, -4, + -104, -104, 37, -104, -104, -104, -104, -17, -57, 39, + -104, 18, 28, -7, -53, -53, -60, -60, -60, -73, + -60, -60, -60, -104, -104, -104, -104, 4, -104, -63, + -104, -4, -4, 77, -104, -104, -104, -104, -104, -104, + 25, -104, -104, -104, -104, -104, 8, 95, -104, 0, + -63, -104, -104 }; /* YYPGOTO[NTERM-NUM]. */ static const yysigned_char yypgoto[] = { - -105, -105, -105, -105, -105, -105, -105, 42, -105, -105, - -105, -105, -105, -5, 97, -31, 18, -105, 75, -105, - -41, 30, 10, 85, 8 + -104, -104, -104, -104, -104, -104, -104, 44, -104, -104, + -104, -104, -104, 1, 96, -38, 14, 6, 75, -104, + -43, -37, 9, 12, 84 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If @@ -834,36 +834,36 @@ static const yysigned_char yypgoto[] = #define YYTABLE_NINF -64 static const yysigned_char yytable[] = { - 84, 1, 55, 84, 13, 119, 71, 14, 27, 53, - 75, 71, 22, 18, 14, 14, 14, 11, 69, 22, - 22, 23, 24, 18, 72, 38, 12, 28, 43, 72, - 47, 30, 14, 65, 83, 32, 22, 2, 31, 39, - 18, -61, 42, 18, 46, 18, 110, 33, 111, 48, - 34, 35, 56, 101, 102, 49, 73, 50, 117, 51, - 42, 103, 52, 77, 57, 58, 15, 64, 16, 16, - 16, 86, 76, 95, 74, 78, 59, 79, 121, 74, - 87, 81, 3, 88, 15, 82, 16, 54, 18, 21, - 85, 120, 80, 85, 93, 96, 25, 26, 60, 89, - 4, 98, 99, 100, 90, 107, 109, 115, 112, 113, - 114, 91, -63, 37, 118, 92, 106, 108, 108, 94, - 108, 108, 108, 122, 36, 70 + 84, 1, 55, 84, 13, 53, 14, 71, 75, 14, + 71, 69, 18, 14, 27, 14, 21, 110, 11, 111, + 12, 23, 18, 25, 26, 72, 28, 83, 72, 24, + 65, 38, 14, 31, 43, 30, 47, 2, -61, 18, + 37, 42, 18, 46, 18, 32, 101, 102, 33, 106, + 108, 108, 56, 108, 108, 108, 117, 73, 34, 42, + 103, 15, 77, 16, 57, 58, 48, 16, 35, 16, + 49, 50, 51, 79, 52, 74, 59, 117, 74, 95, + 86, 64, 3, 54, 15, 76, 16, 18, 22, 87, + 85, 80, 88, 85, 78, 22, 22, 81, 60, 82, + 4, 107, 109, 100, 112, 113, 114, 93, 89, 96, + 98, 99, 22, 90, 115, 39, -63, 118, 119, 120, + 91, 94, 121, 36, 92, 70, 122 }; static const unsigned char yycheck[] = { - 7, 31, 19, 7, 38, 24, 70, 66, 13, 24, - 51, 70, 4, 3, 66, 66, 66, 121, 49, 11, - 12, 0, 99, 13, 88, 30, 72, 52, 33, 88, - 35, 24, 66, 83, 65, 114, 28, 67, 39, 31, - 30, 39, 32, 33, 34, 35, 90, 16, 92, 137, - 83, 83, 69, 84, 85, 137, 120, 24, 99, 45, - 50, 120, 110, 53, 81, 82, 118, 110, 120, 120, - 120, 45, 59, 78, 138, 77, 93, 83, 119, 138, - 54, 90, 112, 57, 118, 134, 120, 102, 78, 4, - 97, 110, 86, 97, 70, 70, 11, 12, 115, 73, - 130, 92, 83, 110, 78, 87, 88, 110, 90, 91, - 92, 85, 39, 28, 92, 89, 86, 87, 88, 77, - 90, 91, 92, 122, 27, 50 + 7, 31, 19, 7, 38, 24, 66, 70, 51, 66, + 70, 49, 3, 66, 13, 66, 4, 90, 121, 92, + 72, 0, 13, 11, 12, 88, 52, 65, 88, 99, + 83, 30, 66, 39, 33, 24, 35, 67, 39, 30, + 28, 32, 33, 34, 35, 114, 84, 85, 16, 86, + 87, 88, 69, 90, 91, 92, 99, 120, 83, 50, + 120, 118, 53, 120, 81, 82, 137, 120, 83, 120, + 137, 24, 45, 83, 110, 138, 93, 120, 138, 78, + 45, 110, 112, 102, 118, 59, 120, 78, 4, 54, + 97, 86, 57, 97, 77, 11, 12, 90, 115, 134, + 130, 87, 88, 110, 90, 91, 92, 70, 73, 70, + 92, 83, 28, 78, 110, 31, 39, 92, 110, 24, + 85, 77, 122, 27, 89, 50, 120 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -881,8 +881,8 @@ static const unsigned char yystos[] = 86, 90, 134, 162, 7, 97, 45, 54, 57, 73, 78, 85, 89, 70, 154, 160, 70, 157, 92, 83, 110, 162, 162, 120, 163, 167, 168, 163, 168, 163, - 90, 92, 163, 163, 163, 110, 164, 167, 92, 24, - 110, 167, 122 + 90, 92, 163, 163, 163, 110, 164, 167, 92, 110, + 24, 122, 164 }; #if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) @@ -1944,16 +1944,15 @@ yyreduce: vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals ); if( vals ) { - vals->val = yyvsp[0].expr; - vals->next = NULL; + vals->val = yyvsp[-2].expr; + vals->next = yyvsp[0].val_list; } - yyvsp[-2].val_list->next = vals; - yyval.val_list = yyvsp[-2].val_list; + yyval.val_list = vals; ;} break; case 52: -#line 520 "./sql.y" +#line 519 "./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; @@ -1962,7 +1961,7 @@ yyreduce: break; case 53: -#line 529 "./sql.y" +#line 528 "./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 ) @@ -1978,70 +1977,70 @@ yyreduce: break; case 54: -#line 545 "./sql.y" +#line 544 "./sql.y" { yyval.expr = EXPR_ival( &yyvsp[0].str, 1 ); ;} break; case 55: -#line 549 "./sql.y" +#line 548 "./sql.y" { yyval.expr = EXPR_ival( &yyvsp[0].str, -1 ); ;} break; case 56: -#line 553 "./sql.y" +#line 552 "./sql.y" { yyval.expr = EXPR_sval( &yyvsp[0].str ); ;} break; case 57: -#line 557 "./sql.y" +#line 556 "./sql.y" { yyval.expr = EXPR_wildcard(); ;} break; case 58: -#line 564 "./sql.y" +#line 563 "./sql.y" { yyval.expr = EXPR_column( yyvsp[0].string ); ;} break; case 59: -#line 571 "./sql.y" +#line 570 "./sql.y" { yyval.string = yyvsp[0].string; /* FIXME */ ;} break; case 60: -#line 575 "./sql.y" +#line 574 "./sql.y" { yyval.string = yyvsp[0].string; ;} break; case 61: -#line 582 "./sql.y" +#line 581 "./sql.y" { yyval.string = yyvsp[0].string; ;} break; case 62: -#line 589 "./sql.y" +#line 588 "./sql.y" { yyval.string = SQL_getstring( &yyvsp[0].str ); ;} break; case 63: -#line 593 "./sql.y" +#line 592 "./sql.y" { yyval.string = SQL_getstring( &yyvsp[0].str ); ;} @@ -2051,7 +2050,7 @@ yyreduce: } /* Line 999 of yacc.c. */ -#line 2055 "sql.tab.c" +#line 2054 "sql.tab.c" yyvsp -= yylen; yyssp -= yylen; @@ -2257,7 +2256,7 @@ yyreturn: } -#line 598 "./sql.y" +#line 597 "./sql.y" int SQL_lex( void *SQL_lval, SQL_input *sql) diff --git a/reactos/lib/msi/sql.y b/reactos/lib/msi/sql.y index 892dd9ad9e9..ca918500245 100644 --- a/reactos/lib/msi/sql.y +++ b/reactos/lib/msi/sql.y @@ -499,18 +499,17 @@ constlist: } $$ = vals; } - | constlist TK_COMMA const_val + | const_val TK_COMMA constlist { value_list *vals; vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals ); if( vals ) { - vals->val = $3; - vals->next = NULL; + vals->val = $1; + vals->next = $3; } - $1->next = vals; - $$ = $1; + $$ = vals; } ; diff --git a/reactos/lib/msi/string.c b/reactos/lib/msi/string.c index bec268fe11a..cf59b04b028 100644 --- a/reactos/lib/msi/string.c +++ b/reactos/lib/msi/string.c @@ -393,8 +393,7 @@ UINT msi_string2idA( string_table *st, LPCSTR buffer, UINT *id ) MultiByteToWideChar( st->codepage, 0, buffer, -1, str, sz ); r = msi_string2idW( st, str, id ); - if( str ) - HeapFree( GetProcessHeap(), 0, str ); + HeapFree( GetProcessHeap(), 0, str ); return r; } diff --git a/reactos/lib/msi/suminfo.c b/reactos/lib/msi/suminfo.c index e8c16c625b0..fbc39d0f598 100644 --- a/reactos/lib/msi/suminfo.c +++ b/reactos/lib/msi/suminfo.c @@ -67,8 +67,7 @@ UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase, ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, phSummaryInfo); - if( szwDatabase ) - HeapFree( GetProcessHeap(), 0, szwDatabase ); + HeapFree( GetProcessHeap(), 0, szwDatabase ); return ret; } @@ -225,9 +224,72 @@ UINT WINAPI MsiSummaryInfoGetPropertyW( MSIHANDLE hSummaryInfo, UINT uiProperty, UINT *puiDataType, INT *piValue, FILETIME *pftValue, LPWSTR szValueBuf, DWORD *pcchValueBuf) { - FIXME("%ld %d %p %p %p %p %p\n", + MSISUMMARYINFO *suminfo; + HRESULT r; + PROPSPEC spec; + PROPVARIANT var; + + TRACE("%ld %d %p %p %p %p %p\n", hSummaryInfo, uiProperty, puiDataType, piValue, pftValue, szValueBuf, pcchValueBuf); - + + suminfo = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO ); + if( !suminfo ) + return ERROR_INVALID_HANDLE; + + spec.ulKind = PRSPEC_PROPID; + spec.u.propid = uiProperty; + + r = IPropertyStorage_ReadMultiple( suminfo->propstg, 1, &spec, &var); + if( FAILED(r) ) + return ERROR_FUNCTION_FAILED; + + if( puiDataType ) + *puiDataType = var.vt; + + switch( var.vt ) + { + case VT_I4: + if( piValue ) + *piValue = var.u.lVal; + break; + case VT_LPSTR: + if( pcchValueBuf && szValueBuf ) + { + MultiByteToWideChar(CP_ACP, 0, var.u.pszVal, -1, szValueBuf, + *pcchValueBuf ); + *pcchValueBuf = lstrlenA( var.u.pszVal ); + } + break; + case VT_FILETIME: + if( pftValue ) + memcpy(pftValue, &var.u.filetime, sizeof (FILETIME) ); + break; + case VT_EMPTY: + break; + default: + FIXME("Unknown property variant type\n"); + break; + } + + return ERROR_SUCCESS; +} + +UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE hSummaryInfo, UINT uiProperty, + UINT uiDataType, INT iValue, + FILETIME* pftValue, LPSTR szValue) +{ + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE hSummaryInfo, UINT uiProperty, + UINT uiDataType, INT iValue, + FILETIME* pftValue, LPWSTR szValue) +{ + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiSummaryInfoPersist(MSIHANDLE hSummaryInfo) +{ return ERROR_CALL_NOT_IMPLEMENTED; } diff --git a/reactos/lib/msi/table.c b/reactos/lib/msi/table.c index 52a5f01652a..5e1891b04fd 100644 --- a/reactos/lib/msi/table.c +++ b/reactos/lib/msi/table.c @@ -196,8 +196,8 @@ void enum_stream_names( IStorage *stg ) if( FAILED( r ) || !count ) break; decode_streamname( stat.pwcsName, name ); - ERR("stream %2ld -> %s %s\n", n, - debugstr_w(stat.pwcsName), debugstr_w(name) ); + TRACE("stream %2ld -> %s %s\n", n, + debugstr_w(stat.pwcsName), debugstr_w(name) ); n++; } @@ -356,12 +356,12 @@ static UINT write_stream_data( IStorage *stg, LPCWSTR stname, encname = encode_streamname(TRUE, stname ); r = IStorage_OpenStream( stg, encname, NULL, STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &stm); - HeapFree( GetProcessHeap(), 0, encname ); if( FAILED(r) ) { r = IStorage_CreateStream( stg, encname, STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm); } + HeapFree( GetProcessHeap(), 0, encname ); if( FAILED( r ) ) { ERR("open stream failed r = %08lx\n",r); @@ -408,7 +408,7 @@ UINT read_table_from_storage( MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable) TRACE("%s\n",debugstr_w(name)); - /* non-existing tables should be interpretted as empty tables */ + /* nonexistent tables should be interpreted as empty tables */ t = HeapAlloc( GetProcessHeap(), 0, sizeof (MSITABLE) + lstrlenW(name)*sizeof (WCHAR) ); if( !t ) @@ -747,10 +747,8 @@ UINT load_string_table( MSIDATABASE *db ) ret = ERROR_SUCCESS; end: - if( pool ) - HeapFree( GetProcessHeap(), 0, pool ); - if( data ) - HeapFree( GetProcessHeap(), 0, data ); + HeapFree( GetProcessHeap(), 0, pool ); + HeapFree( GetProcessHeap(), 0, data ); return ret; } @@ -830,10 +828,8 @@ UINT save_string_table( MSIDATABASE *db ) ret = ERROR_SUCCESS; err: - if( data ) - HeapFree( GetProcessHeap(), 0, data ); - if( pool ) - HeapFree( GetProcessHeap(), 0, pool ); + HeapFree( GetProcessHeap(), 0, data ); + HeapFree( GetProcessHeap(), 0, pool ); return ret; } @@ -1288,9 +1284,10 @@ static UINT TABLE_get_column_info( struct tagMSIVIEW *view, return ERROR_SUCCESS; } -static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec) +static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, + MSIRECORD *rec) { - FIXME("%p %d %ld\n", view, eModifyMode, hrec ); + FIXME("%p %d %p\n", view, eModifyMode, rec ); return ERROR_CALL_NOT_IMPLEMENTED; } diff --git a/reactos/lib/msi/update.c b/reactos/lib/msi/update.c index 99e5f6b6667..39c19d8d154 100644 --- a/reactos/lib/msi/update.c +++ b/reactos/lib/msi/update.c @@ -151,11 +151,12 @@ static UINT UPDATE_get_column_info( struct tagMSIVIEW *view, return wv->ops->get_column_info( wv, n, name, type ); } -static UINT UPDATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec) +static UINT UPDATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, + MSIRECORD *rec ) { MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view; - TRACE("%p %d %ld\n", uv, eModifyMode, hrec ); + TRACE("%p %d %p\n", uv, eModifyMode, rec ); return ERROR_FUNCTION_FAILED; } diff --git a/reactos/lib/msi/where.c b/reactos/lib/msi/where.c index 9ae20480cb9..2754f996b5b 100644 --- a/reactos/lib/msi/where.c +++ b/reactos/lib/msi/where.c @@ -269,8 +269,7 @@ static UINT WHERE_close( struct tagMSIVIEW *view ) if( !wv->table ) return ERROR_FUNCTION_FAILED; - if( wv->reorder ) - HeapFree( GetProcessHeap(), 0, wv->reorder ); + HeapFree( GetProcessHeap(), 0, wv->reorder ); wv->reorder = NULL; return wv->table->ops->close( wv->table ); @@ -308,16 +307,17 @@ static UINT WHERE_get_column_info( struct tagMSIVIEW *view, return wv->table->ops->get_column_info( wv->table, n, name, type ); } -static UINT WHERE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec) +static UINT WHERE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, + MSIRECORD *rec ) { MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; - TRACE("%p %d %ld\n", wv, eModifyMode, hrec ); + TRACE("%p %d %p\n", wv, eModifyMode, rec ); if( !wv->table ) return ERROR_FUNCTION_FAILED; - return wv->table->ops->modify( wv->table, eModifyMode, hrec ); + return wv->table->ops->modify( wv->table, eModifyMode, rec ); } static UINT WHERE_delete( struct tagMSIVIEW *view ) @@ -329,8 +329,7 @@ static UINT WHERE_delete( struct tagMSIVIEW *view ) if( wv->table ) wv->table->ops->delete( wv->table ); - if( wv->reorder ) - HeapFree( GetProcessHeap(), 0, wv->reorder ); + HeapFree( GetProcessHeap(), 0, wv->reorder ); wv->reorder = NULL; wv->row_count = 0;