mirror of
https://github.com/reactos/reactos.git
synced 2024-08-01 09:01:13 +00:00
Sync to Wine-20050211
Mike McCormack <mike@codeweavers.com> - add support for Edit boxes in MSI dialogs - run the message loop when waiting for threads or processes - fix the dialog font - allow waiting on a handle while running the message loop - implement checkboxes in dialogs - use TextStyle enumeration instead of numbers - fix MSI_IterateRecords to return the correct count - Add more dialog controls, do something when they're clicked on. - Implement MsiPreviewDialog. - Implement and document MsiLoadString. - Added stub implementations for MsiPreviewDialog and MsiPreviewBillboard. - Fix MsiModifyView and MsiViewGetColumnInfo to use MSIRECORD* not MSIHANDLE. - Implement, test and document MsiDecomposeDescriptor. - Handle a number as a parameter for custom action 19. - Move OpenQuery into msiquery.c and make it non-static. - Fix and test inserting records. - Fix refcounting, use Interlocked functions. - MsiEvaluateCondition returns an error when passed NULL as a condition. - Lock record in MsiViewExecute, move stubs to end. - Fix MsiRecordSetString for NULL strings and update test case. - Fix a bug caused by freeing memory too soon in the table code. - Update headers, add MsiGetUserInfoA stub implementation. - Fix a memory leak in MsiConfigureProductExW. - Indentation and style cleanup. - implement MsiOpenPackageEx, and forward MsiOpenPackage there - make a MSI_CreatePackage function and use it in MSI_OpenPackage - move MsiOpenPackageA down with the rest of the API functions Juan Lang <juan_lang@yahoo.com> - Partially implement AppSearch action. - If a full path isn't specified, search across all fixed drives. - Simplify AppSearch error checking. - Identifiers evaluate to true if they are non-empty, regardless of value. Aric Stewart <aric@codeweavers.com> - action.c is getting too big, so split out all the handling of CustomActions into custom.c. Cleaned up a lot of the handling of custom actions including scripting actions and processing return codes. - Mike McCormack pointed out that MsiFormatRecord is basically the same as internal function deformat_string. So broke deformat_string out and updated it to function as MsiFormatRecord and implemented MsiFormatRecord. - A number of random fixes to action.c including properly calculating the length for the LocalPackage name, not forcing a reboot when really we should just return ERROR_INSTALL_SUSPEND and handling REG_MULTI_SZ now that we can deformat the properly. - Move the guid squishing functions out of msi.c and make a new registry.c file. Also clean up all the various registry keys we need to open and create to this module and modify the functions for msi.c to call these functions. - Added a few more stub implementations. - Implement custom action type 19, Halt install and display error message. - Continued work to simplify the ProcessAction call, also split it into a ProcessAction and ProcessUIAction for future dialog box work. Also fix a bug in deformat_string where i was not freeing the created record. - Make a temp file for each dll saved for custom actions. This prevents name collisions from causing custom actions to fail. - Do not track the temp files for custom actions based on the name from the table because then we get conflicts and files not tracked or cleaned up. - Add the RegisterUser action. - Implement RegisterExtensionInfo and RegisterMIMEInfo. - Add logic to be able to resolve the SourceDir based on CurrentPath. Also add logic to get the source locations of a file if it is not in a cabinet. - Finish up the framework by stubbing out all the remaining Standard actions. - A fix to deformat_string so it only returns a null return if you provided a null buffer. - Eliminate the giant if.. else if block from ACTION_ProcessAction in favor of a table of handlers. - Return code of the install should not depend on the return code of the final action. - Update component installed states as they are installed so that conditions based on component states are at least a little more correct. - Add icon and argument when regestering clsids. - Add a stub for ResolveSource because we do that work just not in ResolveSource like we should. - When quering a Component state return the correct state. - Enable the updating of Feature and thus the resulting component states. - Run the end of install actions for suspend and user exit states as well. - Start putting in place a currently running state for future ui use. - Use the new registry functions in registry.c. - Do not force a reboot, just return ERROR_INSTALL_SUSPEND and write some keys to the registry. - Quite a few fixes: - Allow for the queing of custom actions to trigger on the InstallExecute or InstallExecuteAgain actions. - allow for the queing of custom actions to trigger on InstallFinalize. - Properly set the CustomActionData property for said queued actions. - Implement RegisterProduct. - Beginning implementation of ForceReboot. - Don't kill install if an item to be duplicated does not exist. - Write out SourceList and LastUsedSource for resuming installs. - Use regsvr32 to register self reg dlls. - Implementations for SelfRegModules and PublishFeatures. - Set default ACTION property for Install. - Deformat more than JUST properties properly. Allows for Files and Component paths in deformat. - Properly deformat a LaunchCondition failure dialog box. - Resolve and save registry Keypaths. - Write the Features published keys more correctly. Still some problems. - First implementation of the WriteIniValues action. - Custom actions can have null in their target parameters, handle that without crashing. Also enable deformating of lines greater than 256 characters. - Added some more suminfo stubs. - An implementation of MsiSummaryInfoGetPropertyW based off of MsiSummaryInfoGetPropertyA. - Added stubs for MsiGetShortcutTargetA/W. - Do a very basic first implementation of MsiConfigureProductExW for msiexec /@ when run as a reboot. - Also add a number of new stubs for the office xp and 2k3 install and startup process. - Fix a copy and paste error, check for a null value and discard unneeded errors. - Do not limit properties to 256 characters when evaluating them. - Setting a record to an empty string is the same as making it null. - First pass implement ion of MsiQueryProductState[A/W] as well as a few fixes for MsiGetComponentPath. - Actually start on an implemention for MsiGetComponentPathW that should handle all keypaths that are files. - A reworking of format.c to remove the recursion, clean things up and stabilize behavior to match windows. - Cleanup processing a bit more. - Allow for nested keys to work properly. - MsiGetProperty does not return any error on missing properties. - The new Insert fixes now properly require ?,? instead of just ? for the Insert call. This fix modifies the MSI_SetProperty query to be correct. Michael Stefaniuc <mstefani@redhat.de> - Do not check for non NULL pointer before HeapFree'ing it. It's redundant. Francois Gouget <fgouget@free.fr> - Assorted spelling fixes. Ulrich Czekalla <ulrich@codeweavers.com> - Handle 0 length buffers in MSI_FormatRecordW. - Remove unused buffer in deformat_string. Mike Hearn <mh@codeweavers.com> - Correctly ensure properties set from resolved directory paths are backslash terminated. Francois Gouget <fgouget@free.fr> - Assorted spelling fixes. Marcus Meissner <meissner@suse.de> - Initialize rc in create_component_directory(). Alexandre Julliard <julliard@winehq.org> - Avoid unnecessary run-time initializations. svn path=/trunk/; revision=13518
This commit is contained in:
parent
b14fe2e98e
commit
c4a2530191
|
@ -55,6 +55,15 @@ typedef enum tagINSTALLUILEVEL
|
||||||
INSTALLUILEVEL_SOURCERESONLY = 0x100
|
INSTALLUILEVEL_SOURCERESONLY = 0x100
|
||||||
} INSTALLUILEVEL;
|
} INSTALLUILEVEL;
|
||||||
|
|
||||||
|
typedef enum tagUSERINFOSTATE
|
||||||
|
{
|
||||||
|
USERINFOSTATE_MOREDATA = -3,
|
||||||
|
USERINFOSTATE_INVALIDARG = -2,
|
||||||
|
USERINFOSTATE_UNKNOWN = -1,
|
||||||
|
USERINFOSTATE_ABSENT = 0,
|
||||||
|
USERINFOSTATE_PRESENT = 1,
|
||||||
|
} USERINFOSTATE;
|
||||||
|
|
||||||
typedef enum tagINSTALLLEVEL
|
typedef enum tagINSTALLLEVEL
|
||||||
{
|
{
|
||||||
INSTALLLEVEL_DEFAULT = 0,
|
INSTALLLEVEL_DEFAULT = 0,
|
||||||
|
@ -137,15 +146,17 @@ typedef enum tagINSTALLTYPE
|
||||||
|
|
||||||
#define MAX_FEATURE_CHARS 38
|
#define MAX_FEATURE_CHARS 38
|
||||||
|
|
||||||
typedef INT (CALLBACK *INSTALLUI_HANDLERA)(LPVOID pvContext, UINT iMessageType,
|
typedef INT (CALLBACK *INSTALLUI_HANDLERA)(LPVOID, UINT, LPCSTR);
|
||||||
LPCSTR szMessage);
|
typedef INT (CALLBACK *INSTALLUI_HANDLERW)(LPVOID, UINT, LPCWSTR);
|
||||||
typedef INT (CALLBACK *INSTALLUI_HANDLERW)(LPVOID pvContext, UINT iMessageType,
|
|
||||||
LPCWSTR szMessage);
|
|
||||||
|
|
||||||
UINT WINAPI MsiAdvertiseProductA(LPCSTR, LPCSTR, LPCSTR, LANGID);
|
UINT WINAPI MsiAdvertiseProductA(LPCSTR, LPCSTR, LPCSTR, LANGID);
|
||||||
UINT WINAPI MsiAdvertiseProductW(LPCWSTR, LPCWSTR, LPCWSTR, LANGID);
|
UINT WINAPI MsiAdvertiseProductW(LPCWSTR, LPCWSTR, LPCWSTR, LANGID);
|
||||||
#define MsiAdvertiseProduct WINELIB_NAME_AW(MsiAdvertiseProduct)
|
#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 MsiInstallProductA(LPCSTR, LPCSTR);
|
||||||
UINT WINAPI MsiInstallProductW(LPCWSTR, LPCWSTR);
|
UINT WINAPI MsiInstallProductW(LPCWSTR, LPCWSTR);
|
||||||
#define MsiInstallProduct WINELIB_NAME_AW(MsiInstallProduct)
|
#define MsiInstallProduct WINELIB_NAME_AW(MsiInstallProduct)
|
||||||
|
@ -158,8 +169,8 @@ UINT WINAPI MsiApplyPatchA(LPCSTR, LPCSTR, INSTALLTYPE, LPCSTR);
|
||||||
UINT WINAPI MsiApplyPatchW(LPCWSTR, LPCWSTR, INSTALLTYPE, LPCWSTR);
|
UINT WINAPI MsiApplyPatchW(LPCWSTR, LPCWSTR, INSTALLTYPE, LPCWSTR);
|
||||||
#define MsiApplyPatch WINELIB_NAME_AW(MsiApplyPatch)
|
#define MsiApplyPatch WINELIB_NAME_AW(MsiApplyPatch)
|
||||||
|
|
||||||
UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid);
|
UINT WINAPI MsiEnumProductsA(DWORD, LPSTR);
|
||||||
UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid);
|
UINT WINAPI MsiEnumProductsW(DWORD, LPWSTR);
|
||||||
#define MsiEnumProducts WINELIB_NAME_AW(MsiEnumProducts)
|
#define MsiEnumProducts WINELIB_NAME_AW(MsiEnumProducts)
|
||||||
|
|
||||||
UINT WINAPI MsiEnumFeaturesA(LPCSTR, DWORD, LPSTR, LPSTR);
|
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*);
|
UINT WINAPI MsiSummaryInfoGetPropertyW(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPWSTR,DWORD*);
|
||||||
#define MsiSummaryInfoGetProperty WINELIB_NAME_AW(MsiSummaryInfoGetProperty)
|
#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 MsiProvideComponentFromDescriptorA(LPCSTR,LPSTR,DWORD*,DWORD*);
|
||||||
UINT WINAPI MsiProvideComponentFromDescriptorW(LPCWSTR,LPWSTR,DWORD*,DWORD*);
|
UINT WINAPI MsiProvideComponentFromDescriptorW(LPCWSTR,LPWSTR,DWORD*,DWORD*);
|
||||||
#define MsiProvideComponentFromDescriptor WINELIB_NAME_AW(MsiProvideComponentFromDescriptor)
|
#define MsiProvideComponentFromDescriptor WINELIB_NAME_AW(MsiProvideComponentFromDescriptor)
|
||||||
|
@ -218,20 +235,24 @@ INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR);
|
||||||
INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR);
|
INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR);
|
||||||
#define MsiQueryProductState WINELIB_NAME_AW(MsiQueryProductState)
|
#define MsiQueryProductState WINELIB_NAME_AW(MsiQueryProductState)
|
||||||
|
|
||||||
UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState);
|
UINT WINAPI MsiConfigureProductA(LPCSTR, int, INSTALLSTATE);
|
||||||
UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState);
|
UINT WINAPI MsiConfigureProductW(LPCWSTR, int, INSTALLSTATE);
|
||||||
#define MsiConfigureProduct WINELIB_NAME_AW(MsiConfigureProduct);
|
#define MsiConfigureProduct WINELIB_NAME_AW(MsiConfigureProduct);
|
||||||
|
|
||||||
UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer);
|
UINT WINAPI MsiConfigureProductExA(LPCSTR, int, INSTALLSTATE, LPCSTR);
|
||||||
UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer);
|
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)
|
#define MsiGetProductCode WINELIB_NAME_AW(MsiGetProductCode)
|
||||||
|
|
||||||
UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, LPSTR szBuffer, DWORD *pcchValueBuf);
|
UINT WINAPI MsiGetProductInfoA(LPCSTR, LPCSTR, LPSTR, DWORD *);
|
||||||
UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szBuffer, DWORD *pcchValueBuf);
|
UINT WINAPI MsiGetProductInfoW(LPCWSTR, LPCWSTR, LPWSTR, DWORD *);
|
||||||
#define MsiGetProductInfo WINELIB_NAME_AW(MsiGetProductInfo)
|
#define MsiGetProductInfo WINELIB_NAME_AW(MsiGetProductInfo)
|
||||||
|
|
||||||
UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes);
|
UINT WINAPI MsiEnableLogA(DWORD, LPCSTR, DWORD);
|
||||||
UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes);
|
UINT WINAPI MsiEnableLogW(DWORD, LPCWSTR, DWORD);
|
||||||
#define MsiEnableLog WINELIB_NAME_AW(MsiEnableLog)
|
#define MsiEnableLog WINELIB_NAME_AW(MsiEnableLog)
|
||||||
|
|
||||||
INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA, DWORD, LPVOID);
|
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*);
|
INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR, LPCWSTR, LPWSTR, DWORD*);
|
||||||
#define MsiGetComponentPath WINELIB_NAME_AW(MsiGetComponentPath)
|
#define MsiGetComponentPath WINELIB_NAME_AW(MsiGetComponentPath)
|
||||||
|
|
||||||
INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature);
|
INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR, LPCSTR);
|
||||||
INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature);
|
INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR, LPCWSTR);
|
||||||
#define MsiQueryFeatureState WINELIB_NAME_AW(MsiQueryFeatureState)
|
#define MsiQueryFeatureState WINELIB_NAME_AW(MsiQueryFeatureState)
|
||||||
|
|
||||||
/**
|
UINT WINAPI MsiGetFeatureUsageA(LPCSTR, LPCSTR, DWORD*, WORD*);
|
||||||
* Non Unicode
|
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 MsiCloseHandle(MSIHANDLE);
|
||||||
UINT WINAPI MsiCloseAllHandles();
|
UINT WINAPI MsiCloseAllHandles(void);
|
||||||
INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL, HWND*);
|
INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL, HWND*);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
96
reactos/include/wine/msidefs.h
Normal file
96
reactos/include/wine/msidefs.h
Normal file
|
@ -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 */
|
|
@ -8,15 +8,21 @@ EXTRALIBS = -luuid $(LIBUNICODE)
|
||||||
|
|
||||||
C_SRCS = \
|
C_SRCS = \
|
||||||
action.c \
|
action.c \
|
||||||
|
appsearch.c \
|
||||||
create.c \
|
create.c \
|
||||||
|
custom.c \
|
||||||
|
dialog.c \
|
||||||
distinct.c \
|
distinct.c \
|
||||||
|
format.c \
|
||||||
handle.c \
|
handle.c \
|
||||||
insert.c \
|
insert.c \
|
||||||
msi.c \
|
msi.c \
|
||||||
msiquery.c \
|
msiquery.c \
|
||||||
order.c \
|
order.c \
|
||||||
package.c \
|
package.c \
|
||||||
|
preview.c \
|
||||||
record.c \
|
record.c \
|
||||||
|
registry.c \
|
||||||
regsvr.c \
|
regsvr.c \
|
||||||
select.c \
|
select.c \
|
||||||
string.c \
|
string.c \
|
||||||
|
@ -26,7 +32,7 @@ C_SRCS = \
|
||||||
update.c \
|
update.c \
|
||||||
where.c
|
where.c
|
||||||
|
|
||||||
RC_SRCS = version.rc
|
RC_SRCS = msi.rc
|
||||||
|
|
||||||
EXTRA_SRCS = sql.y cond.y
|
EXTRA_SRCS = sql.y cond.y
|
||||||
EXTRA_OBJS = sql.tab.o cond.tab.o
|
EXTRA_OBJS = sql.tab.o cond.tab.o
|
||||||
|
|
File diff suppressed because it is too large
Load diff
151
reactos/lib/msi/action.h
Normal file
151
reactos/lib/msi/action.h
Normal file
|
@ -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;
|
||||||
|
}
|
855
reactos/lib/msi/appsearch.c
Normal file
855
reactos/lib/msi/appsearch.c
Normal file
|
@ -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 <stdarg.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,9 +1,83 @@
|
||||||
#ifndef BISON_COND_TAB_H
|
/* A Bison parser, made by GNU Bison 1.875b. */
|
||||||
# define BISON_COND_TAB_H
|
|
||||||
|
|
||||||
#ifndef YYSTYPE
|
/* Skeleton parser for Yacc-like parsing with Bison,
|
||||||
typedef union
|
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;
|
struct cond_str str;
|
||||||
LPWSTR string;
|
LPWSTR string;
|
||||||
INT value;
|
INT value;
|
||||||
|
@ -11,30 +85,15 @@ typedef union
|
||||||
comp_str fn_comp_str;
|
comp_str fn_comp_str;
|
||||||
comp_m1 fn_comp_m1;
|
comp_m1 fn_comp_m1;
|
||||||
comp_m2 fn_comp_m2;
|
comp_m2 fn_comp_m2;
|
||||||
} yystype;
|
} YYSTYPE;
|
||||||
# define YYSTYPE 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
|
# define YYSTYPE_IS_TRIVIAL 1
|
||||||
#endif
|
#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 */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -181,7 +181,7 @@ term:
|
||||||
}
|
}
|
||||||
| value_s
|
| value_s
|
||||||
{
|
{
|
||||||
$$ = atoiW($1);
|
$$ = $1[0] ? MSICONDITION_TRUE : MSICONDITION_FALSE;
|
||||||
}
|
}
|
||||||
| value_i comp_op_i value_i
|
| value_i comp_op_i value_i
|
||||||
{
|
{
|
||||||
|
@ -448,14 +448,22 @@ symbol_s:
|
||||||
{
|
{
|
||||||
DWORD sz;
|
DWORD sz;
|
||||||
COND_input* cond = (COND_input*) info;
|
COND_input* cond = (COND_input*) info;
|
||||||
$$ = HeapAlloc( GetProcessHeap(), 0, 0x100*sizeof (WCHAR) );
|
|
||||||
|
sz = 0;
|
||||||
|
MSI_GetPropertyW(cond->package, $1, NULL, &sz);
|
||||||
|
if (sz == 0)
|
||||||
|
{
|
||||||
|
$$ = HeapAlloc( GetProcessHeap(), 0 ,sizeof(WCHAR));
|
||||||
|
$$[0] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sz ++;
|
||||||
|
$$ = HeapAlloc( GetProcessHeap(), 0, sz*sizeof (WCHAR) );
|
||||||
|
|
||||||
/* Lookup the identifier */
|
/* Lookup the identifier */
|
||||||
|
|
||||||
sz=0x100;
|
MSI_GetPropertyW(cond->package,$1,$$,&sz);
|
||||||
if (MSI_GetPropertyW(cond->package,$1,$$,&sz) != ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
$$[0]=0;
|
|
||||||
}
|
}
|
||||||
HeapFree( GetProcessHeap(), 0, $1 );
|
HeapFree( GetProcessHeap(), 0, $1 );
|
||||||
}
|
}
|
||||||
|
@ -731,7 +739,7 @@ MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition )
|
||||||
|
|
||||||
TRACE("Evaluating %s\n",debugstr_w(szCondition));
|
TRACE("Evaluating %s\n",debugstr_w(szCondition));
|
||||||
|
|
||||||
if( !COND_parse( &cond ) )
|
if( szCondition && !COND_parse( &cond ) )
|
||||||
r = cond.result;
|
r = cond.result;
|
||||||
else
|
else
|
||||||
r = MSICONDITION_ERROR;
|
r = MSICONDITION_ERROR;
|
||||||
|
@ -767,7 +775,6 @@ MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szConditio
|
||||||
|
|
||||||
r = MsiEvaluateConditionW( hInstall, szwCond );
|
r = MsiEvaluateConditionW( hInstall, szwCond );
|
||||||
|
|
||||||
if( szwCond )
|
|
||||||
HeapFree( GetProcessHeap(), 0, szwCond );
|
HeapFree( GetProcessHeap(), 0, szwCond );
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
|
|
@ -188,11 +188,12 @@ static UINT CREATE_get_column_info( struct tagMSIVIEW *view,
|
||||||
return ERROR_FUNCTION_FAILED;
|
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;
|
MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
|
||||||
|
|
||||||
TRACE("%p %d %ld\n", cv, eModifyMode, hrec );
|
TRACE("%p %d %p\n", cv, eModifyMode, rec );
|
||||||
|
|
||||||
return ERROR_FUNCTION_FAILED;
|
return ERROR_FUNCTION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
794
reactos/lib/msi/custom.c
Normal file
794
reactos/lib/msi/custom.c
Normal file
|
@ -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 <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define COBJMACROS
|
||||||
|
|
||||||
|
#include "windef.h"
|
||||||
|
#include "winbase.h"
|
||||||
|
#include "winerror.h"
|
||||||
|
#include "winreg.h"
|
||||||
|
#include "wine/debug.h"
|
||||||
|
#include "fdi.h"
|
||||||
|
#include "msi.h"
|
||||||
|
#include "msiquery.h"
|
||||||
|
#include "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);
|
||||||
|
}
|
973
reactos/lib/msi/dialog.c
Normal file
973
reactos/lib/msi/dialog.c
Normal file
|
@ -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 <stdarg.h>
|
||||||
|
|
||||||
|
#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; i<NUM_CONTROL_TYPES; i++ )
|
||||||
|
if (!strcmpiW( msi_dialog_handler[i].control_type, control_type ))
|
||||||
|
break;
|
||||||
|
if( i != NUM_CONTROL_TYPES )
|
||||||
|
msi_dialog_handler[i].func( dialog, rec );
|
||||||
|
else
|
||||||
|
ERR("no handler for element type %s\n", debugstr_w(control_type));
|
||||||
|
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT msi_dialog_fill_controls( msi_dialog *dialog )
|
||||||
|
{
|
||||||
|
static const WCHAR query[] = {
|
||||||
|
'S','E','L','E','C','T',' ','*',' ',
|
||||||
|
'F','R','O','M',' ','C','o','n','t','r','o','l',' ',
|
||||||
|
'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_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 );
|
||||||
|
}
|
|
@ -178,7 +178,6 @@ static UINT DISTINCT_close( struct tagMSIVIEW *view )
|
||||||
if( !dv->table )
|
if( !dv->table )
|
||||||
return ERROR_FUNCTION_FAILED;
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
|
||||||
if( dv->translation )
|
|
||||||
HeapFree( GetProcessHeap(), 0, dv->translation );
|
HeapFree( GetProcessHeap(), 0, dv->translation );
|
||||||
dv->translation = NULL;
|
dv->translation = NULL;
|
||||||
dv->row_count = 0;
|
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 );
|
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;
|
MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
|
||||||
|
|
||||||
TRACE("%p %d %ld\n", dv, eModifyMode, hrec );
|
TRACE("%p %d %p\n", dv, eModifyMode, rec );
|
||||||
|
|
||||||
if( !dv->table )
|
if( !dv->table )
|
||||||
return ERROR_FUNCTION_FAILED;
|
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 )
|
static UINT DISTINCT_delete( struct tagMSIVIEW *view )
|
||||||
|
@ -239,7 +239,6 @@ static UINT DISTINCT_delete( struct tagMSIVIEW *view )
|
||||||
if( dv->table )
|
if( dv->table )
|
||||||
dv->table->ops->delete( 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 );
|
msiobj_release( &dv->db->hdr );
|
||||||
HeapFree( GetProcessHeap(), 0, dv );
|
HeapFree( GetProcessHeap(), 0, dv );
|
||||||
|
|
583
reactos/lib/msi/format.c
Normal file
583
reactos/lib/msi/format.c
Normal file
|
@ -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 <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define COBJMACROS
|
||||||
|
|
||||||
|
#include "windef.h"
|
||||||
|
#include "winbase.h"
|
||||||
|
#include "winerror.h"
|
||||||
|
#include "winreg.h"
|
||||||
|
#include "wine/debug.h"
|
||||||
|
#include "fdi.h"
|
||||||
|
#include "msi.h"
|
||||||
|
#include "msiquery.h"
|
||||||
|
#include "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;
|
||||||
|
}
|
|
@ -157,7 +157,7 @@ void msiobj_addref( MSIOBJECTHDR *info )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
info->refcount++;
|
InterlockedIncrement(&info->refcount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void msiobj_lock( MSIOBJECTHDR *info )
|
void msiobj_lock( MSIOBJECTHDR *info )
|
||||||
|
@ -185,8 +185,8 @@ int msiobj_release( MSIOBJECTHDR *info )
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = info->refcount--;
|
ret = InterlockedDecrement( &info->refcount );
|
||||||
if (info->refcount == 0)
|
if( ret==0 )
|
||||||
{
|
{
|
||||||
if( info->destructor )
|
if( info->destructor )
|
||||||
info->destructor( info );
|
info->destructor( info );
|
||||||
|
|
|
@ -44,7 +44,7 @@ typedef struct tagMSIINSERTVIEW
|
||||||
MSIDATABASE *db;
|
MSIDATABASE *db;
|
||||||
BOOL bIsTemp;
|
BOOL bIsTemp;
|
||||||
MSIVIEW *sv;
|
MSIVIEW *sv;
|
||||||
value_list *vals; /* looks like these may be ignored... */
|
value_list *vals;
|
||||||
} MSIINSERTVIEW;
|
} MSIINSERTVIEW;
|
||||||
|
|
||||||
static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
|
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;
|
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 )
|
static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record )
|
||||||
{
|
{
|
||||||
MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
|
MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
|
||||||
UINT n, type, val, r, row, col_count = 0;
|
UINT n, type, val, r, row, col_count = 0;
|
||||||
MSIVIEW *sv;
|
MSIVIEW *sv;
|
||||||
|
MSIRECORD *values = NULL;
|
||||||
|
|
||||||
TRACE("%p %p\n", iv, record );
|
TRACE("%p %p\n", iv, record );
|
||||||
|
|
||||||
|
@ -77,12 +128,13 @@ static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record )
|
||||||
if( r )
|
if( r )
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
n = MSI_RecordGetFieldCount( record );
|
/*
|
||||||
if( n != col_count )
|
* Merge the wildcard values into the list of values provided
|
||||||
{
|
* in the query, and create a record containing both.
|
||||||
ERR("Number of fields do not match\n");
|
*/
|
||||||
|
values = INSERT_merge_record( col_count, iv->vals, record );
|
||||||
|
if( !values )
|
||||||
goto err;
|
goto err;
|
||||||
}
|
|
||||||
|
|
||||||
row = -1;
|
row = -1;
|
||||||
r = sv->ops->insert_row( sv, &row );
|
r = sv->ops->insert_row( sv, &row );
|
||||||
|
@ -98,12 +150,12 @@ static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record )
|
||||||
|
|
||||||
if( type & MSITYPE_STRING )
|
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 );
|
val = msi_addstringW( iv->db->strings, 0, str, -1, 1 );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
val = MSI_RecordGetInteger( record, n );
|
val = MSI_RecordGetInteger( values, n );
|
||||||
val |= 0x8000;
|
val |= 0x8000;
|
||||||
}
|
}
|
||||||
r = sv->ops->set_int( sv, row, n, val );
|
r = sv->ops->set_int( sv, row, n, val );
|
||||||
|
@ -112,6 +164,9 @@ static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record )
|
||||||
}
|
}
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
if( values )
|
||||||
|
msiobj_release( &values->hdr );
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
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 );
|
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;
|
MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
|
||||||
|
|
||||||
TRACE("%p %d %ld\n", iv, eModifyMode, hrec );
|
TRACE("%p %d %p\n", iv, eModifyMode, rec );
|
||||||
|
|
||||||
return ERROR_FUNCTION_FAILED;
|
return ERROR_FUNCTION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
30
reactos/lib/msi/msi.rc
Normal file
30
reactos/lib/msi/msi.rc
Normal file
|
@ -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"
|
|
@ -6,8 +6,8 @@
|
||||||
6 stdcall MsiAdvertiseProductW(wstr wstr wstr long)
|
6 stdcall MsiAdvertiseProductW(wstr wstr wstr long)
|
||||||
7 stdcall MsiCloseAllHandles()
|
7 stdcall MsiCloseAllHandles()
|
||||||
8 stdcall MsiCloseHandle(long)
|
8 stdcall MsiCloseHandle(long)
|
||||||
9 stub MsiCollectUserInfoA
|
9 stdcall MsiCollectUserInfoA(str)
|
||||||
10 stub MsiCollectUserInfoW
|
10 stdcall MsiCollectUserInfoW(wstr)
|
||||||
11 stub MsiConfigureFeatureA
|
11 stub MsiConfigureFeatureA
|
||||||
12 stub MsiConfigureFeatureFromDescriptorA
|
12 stub MsiConfigureFeatureFromDescriptorA
|
||||||
13 stub MsiConfigureFeatureFromDescriptorW
|
13 stub MsiConfigureFeatureFromDescriptorW
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
32 stdcall MsiDatabaseOpenViewW(long wstr ptr)
|
32 stdcall MsiDatabaseOpenViewW(long wstr ptr)
|
||||||
33 stdcall MsiDoActionA(long str)
|
33 stdcall MsiDoActionA(long str)
|
||||||
34 stdcall MsiDoActionW(long wstr)
|
34 stdcall MsiDoActionW(long wstr)
|
||||||
35 stub MsiEnableUIPreview
|
35 stdcall MsiEnableUIPreview(long ptr)
|
||||||
36 stdcall MsiEnumClientsA(str long ptr)
|
36 stdcall MsiEnumClientsA(str long ptr)
|
||||||
37 stdcall MsiEnumClientsW(wstr long ptr)
|
37 stdcall MsiEnumClientsW(wstr long ptr)
|
||||||
38 stdcall MsiEnumComponentQualifiersA(str long str ptr str ptr)
|
38 stdcall MsiEnumComponentQualifiersA(str long str ptr str ptr)
|
||||||
|
@ -79,7 +79,7 @@
|
||||||
79 stdcall MsiGetTargetPathA(long str ptr ptr)
|
79 stdcall MsiGetTargetPathA(long str ptr ptr)
|
||||||
80 stdcall MsiGetTargetPathW(long wstr ptr ptr)
|
80 stdcall MsiGetTargetPathW(long wstr ptr ptr)
|
||||||
81 stub MsiGetUserInfoA
|
81 stub MsiGetUserInfoA
|
||||||
82 stub MsiGetUserInfoW
|
82 stdcall MsiGetUserInfoW(wstr ptr ptr ptr ptr ptr ptr)
|
||||||
83 stub MsiInstallMissingComponentA
|
83 stub MsiInstallMissingComponentA
|
||||||
84 stub MsiInstallMissingComponentW
|
84 stub MsiInstallMissingComponentW
|
||||||
85 stub MsiInstallMissingFileA
|
85 stub MsiInstallMissingFileA
|
||||||
|
@ -94,10 +94,10 @@
|
||||||
94 stdcall MsiOpenPackageW(wstr ptr)
|
94 stdcall MsiOpenPackageW(wstr ptr)
|
||||||
95 stdcall MsiOpenProductA(str ptr)
|
95 stdcall MsiOpenProductA(str ptr)
|
||||||
96 stdcall MsiOpenProductW(wstr ptr)
|
96 stdcall MsiOpenProductW(wstr ptr)
|
||||||
97 stub MsiPreviewBillboardA
|
97 stdcall MsiPreviewBillboardA(long str str)
|
||||||
98 stub MsiPreviewBillboardW
|
98 stdcall MsiPreviewBillboardW(long wstr wstr)
|
||||||
99 stub MsiPreviewDialogA
|
99 stdcall MsiPreviewDialogA(long str)
|
||||||
100 stub MsiPreviewDialogW
|
100 stdcall MsiPreviewDialogW(long wstr)
|
||||||
101 stub MsiProcessAdvertiseScriptA
|
101 stub MsiProcessAdvertiseScriptA
|
||||||
102 stub MsiProcessAdvertiseScriptW
|
102 stub MsiProcessAdvertiseScriptW
|
||||||
103 stdcall MsiProcessMessage(long long long)
|
103 stdcall MsiProcessMessage(long long long)
|
||||||
|
@ -148,9 +148,9 @@
|
||||||
148 stdcall MsiSummaryInfoGetPropertyA(long long ptr ptr ptr ptr ptr)
|
148 stdcall MsiSummaryInfoGetPropertyA(long long ptr ptr ptr ptr ptr)
|
||||||
149 stdcall MsiSummaryInfoGetPropertyCount(long ptr)
|
149 stdcall MsiSummaryInfoGetPropertyCount(long ptr)
|
||||||
150 stdcall MsiSummaryInfoGetPropertyW(long long ptr ptr ptr ptr ptr)
|
150 stdcall MsiSummaryInfoGetPropertyW(long long ptr ptr ptr ptr ptr)
|
||||||
151 stub MsiSummaryInfoPersist
|
151 stdcall MsiSummaryInfoPersist(long)
|
||||||
152 stub MsiSummaryInfoSetPropertyA
|
152 stdcall MsiSummaryInfoSetPropertyA(long long long long ptr str)
|
||||||
153 stub MsiSummaryInfoSetPropertyW
|
153 stdcall MsiSummaryInfoSetPropertyW(long long long long ptr wstr)
|
||||||
154 stub MsiUseFeatureA
|
154 stub MsiUseFeatureA
|
||||||
155 stub MsiUseFeatureW
|
155 stub MsiUseFeatureW
|
||||||
156 stdcall MsiVerifyPackageA(str)
|
156 stdcall MsiVerifyPackageA(str)
|
||||||
|
@ -186,21 +186,21 @@
|
||||||
186 stub MsiCreateTransformSummaryInfoW
|
186 stub MsiCreateTransformSummaryInfoW
|
||||||
187 stub MsiQueryFeatureStateFromDescriptorA
|
187 stub MsiQueryFeatureStateFromDescriptorA
|
||||||
188 stub MsiQueryFeatureStateFromDescriptorW
|
188 stub MsiQueryFeatureStateFromDescriptorW
|
||||||
189 stub MsiConfigureProductExA
|
189 stdcall MsiConfigureProductExA(str long long str)
|
||||||
190 stub MsiConfigureProductExW
|
190 stdcall MsiConfigureProductExW(wstr long long wstr)
|
||||||
191 stub MsiInvalidateFeatureCache
|
191 stub MsiInvalidateFeatureCache
|
||||||
192 stub MsiUseFeatureExA
|
192 stub MsiUseFeatureExA
|
||||||
193 stub MsiUseFeatureExW
|
193 stdcall MsiUseFeatureExW(wstr wstr long long)
|
||||||
194 stdcall MsiGetFileVersionA(str str ptr str ptr)
|
194 stdcall MsiGetFileVersionA(str str ptr str ptr)
|
||||||
195 stdcall MsiGetFileVersionW(wstr wstr ptr wstr ptr)
|
195 stdcall MsiGetFileVersionW(wstr wstr ptr wstr ptr)
|
||||||
196 stdcall MsiLoadStringA(long long long long long)
|
196 stdcall MsiLoadStringA(long long long long long)
|
||||||
197 stdcall MsiLoadStringW(long long long long long)
|
197 stdcall MsiLoadStringW(long long long long long)
|
||||||
198 stdcall MsiMessageBoxA(long long long long long long)
|
198 stdcall MsiMessageBoxA(long long long long long long)
|
||||||
199 stdcall MsiMessageBoxW(long long long long long long)
|
199 stdcall MsiMessageBoxW(long long long long long long)
|
||||||
200 stub MsiDecomposeDescriptorA
|
200 stdcall MsiDecomposeDescriptorA(str ptr ptr ptr ptr)
|
||||||
201 stub MsiDecomposeDescriptorW
|
201 stdcall MsiDecomposeDescriptorW(wstr ptr ptr ptr ptr)
|
||||||
202 stub MsiProvideQualifiedComponentExA
|
202 stub MsiProvideQualifiedComponentExA
|
||||||
203 stub MsiProvideQualifiedComponentExW
|
203 stdcall MsiProvideQualifiedComponentExW(wstr wstr long wstr long long ptr ptr)
|
||||||
204 stdcall MsiEnumRelatedProductsA(str long long ptr)
|
204 stdcall MsiEnumRelatedProductsA(str long long ptr)
|
||||||
205 stdcall MsiEnumRelatedProductsW(wstr long long ptr)
|
205 stdcall MsiEnumRelatedProductsW(wstr long long ptr)
|
||||||
206 stub MsiSetFeatureAttributesA
|
206 stub MsiSetFeatureAttributesA
|
||||||
|
@ -213,13 +213,13 @@
|
||||||
213 stub MsiSourceListForceResolutionW
|
213 stub MsiSourceListForceResolutionW
|
||||||
214 stub MsiIsProductElevatedA
|
214 stub MsiIsProductElevatedA
|
||||||
215 stub MsiIsProductElevatedW
|
215 stub MsiIsProductElevatedW
|
||||||
216 stub MsiGetShortcutTargetA
|
216 stdcall MsiGetShortcutTargetA(str ptr ptr ptr)
|
||||||
217 stub MsiGetShortcutTargetW
|
217 stdcall MsiGetShortcutTargetW(wstr ptr ptr ptr)
|
||||||
218 stub MsiGetFileHashA
|
218 stub MsiGetFileHashA
|
||||||
219 stub MsiGetFileHashW
|
219 stub MsiGetFileHashW
|
||||||
220 stub MsiEnumComponentCostsA
|
220 stub MsiEnumComponentCostsA
|
||||||
221 stub MsiEnumComponentCostsW
|
221 stub MsiEnumComponentCostsW
|
||||||
222 stub MsiCreateAndVerifyInstallerDirectory
|
222 stdcall MsiCreateAndVerifyInstallerDirectory()
|
||||||
223 stdcall MsiGetFileSignatureInformationA(str long ptr ptr ptr)
|
223 stdcall MsiGetFileSignatureInformationA(str long ptr ptr ptr)
|
||||||
224 stdcall MsiGetFileSignatureInformationW(wstr long ptr ptr ptr)
|
224 stdcall MsiGetFileSignatureInformationW(wstr long ptr ptr ptr)
|
||||||
225 stdcall MsiProvideAssemblyA(str str long long str ptr)
|
225 stdcall MsiProvideAssemblyA(str str long long str ptr)
|
||||||
|
|
33
reactos/lib/msi/msi_En.rc
Normal file
33
reactos/lib/msi/msi_En.rc
Normal file
|
@ -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"
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Implementation of the Microsoft Installer (msi.dll)
|
* 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
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -53,7 +53,7 @@ struct tagMSIOBJECTHDR
|
||||||
{
|
{
|
||||||
UINT magic;
|
UINT magic;
|
||||||
UINT type;
|
UINT type;
|
||||||
UINT refcount;
|
DWORD refcount;
|
||||||
msihandledestructor destructor;
|
msihandledestructor destructor;
|
||||||
struct tagMSIOBJECTHDR *next;
|
struct tagMSIOBJECTHDR *next;
|
||||||
struct tagMSIOBJECTHDR *prev;
|
struct tagMSIOBJECTHDR *prev;
|
||||||
|
@ -161,7 +161,7 @@ typedef struct tagMSIVIEWOPS
|
||||||
/*
|
/*
|
||||||
* modify - not yet implemented properly
|
* modify - not yet implemented properly
|
||||||
*/
|
*/
|
||||||
UINT (*modify)( struct tagMSIVIEW *, MSIMODIFY, MSIHANDLE );
|
UINT (*modify)( struct tagMSIVIEW *, MSIMODIFY, MSIRECORD * );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* delete - destroys the structure completely
|
* delete - destroys the structure completely
|
||||||
|
@ -182,6 +182,9 @@ struct tagMSIVIEW
|
||||||
MSIVIEWOPS *ops;
|
MSIVIEWOPS *ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct msi_dialog_tag;
|
||||||
|
typedef struct msi_dialog_tag msi_dialog;
|
||||||
|
|
||||||
typedef struct tagMSIPACKAGE
|
typedef struct tagMSIPACKAGE
|
||||||
{
|
{
|
||||||
MSIOBJECTHDR hdr;
|
MSIOBJECTHDR hdr;
|
||||||
|
@ -196,14 +199,37 @@ typedef struct tagMSIPACKAGE
|
||||||
UINT loaded_files;
|
UINT loaded_files;
|
||||||
LPWSTR ActionFormat;
|
LPWSTR ActionFormat;
|
||||||
LPWSTR LastAction;
|
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;
|
} MSIPACKAGE;
|
||||||
|
|
||||||
|
typedef struct tagMSIPREVIEW
|
||||||
|
{
|
||||||
|
MSIOBJECTHDR hdr;
|
||||||
|
MSIPACKAGE *package;
|
||||||
|
msi_dialog *dialog;
|
||||||
|
} MSIPREVIEW;
|
||||||
|
|
||||||
#define MSIHANDLETYPE_ANY 0
|
#define MSIHANDLETYPE_ANY 0
|
||||||
#define MSIHANDLETYPE_DATABASE 1
|
#define MSIHANDLETYPE_DATABASE 1
|
||||||
#define MSIHANDLETYPE_SUMMARYINFO 2
|
#define MSIHANDLETYPE_SUMMARYINFO 2
|
||||||
#define MSIHANDLETYPE_VIEW 3
|
#define MSIHANDLETYPE_VIEW 3
|
||||||
#define MSIHANDLETYPE_RECORD 4
|
#define MSIHANDLETYPE_RECORD 4
|
||||||
#define MSIHANDLETYPE_PACKAGE 5
|
#define MSIHANDLETYPE_PACKAGE 5
|
||||||
|
#define MSIHANDLETYPE_PREVIEW 6
|
||||||
|
|
||||||
#define MSI_MAJORVERSION 2
|
#define MSI_MAJORVERSION 2
|
||||||
#define MSI_MINORVERSION 0
|
#define MSI_MINORVERSION 0
|
||||||
|
@ -212,7 +238,7 @@ typedef struct tagMSIPACKAGE
|
||||||
#define GUID_SIZE 39
|
#define GUID_SIZE 39
|
||||||
|
|
||||||
#define MSIHANDLE_MAGIC 0x4d434923
|
#define MSIHANDLE_MAGIC 0x4d434923
|
||||||
#define MSIMAXHANDLES 0x80
|
#define MSIMAXHANDLES 0xf0
|
||||||
|
|
||||||
#define MSISUMINFO_OFFSET 0x30LL
|
#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,
|
extern UINT read_raw_stream_data( MSIDATABASE*, LPCWSTR stname,
|
||||||
USHORT **pdata, UINT *psz );
|
USHORT **pdata, UINT *psz );
|
||||||
|
|
||||||
|
/* action internals */
|
||||||
extern UINT ACTION_DoTopLevelINSTALL( MSIPACKAGE *, LPCWSTR, LPCWSTR );
|
extern UINT ACTION_DoTopLevelINSTALL( MSIPACKAGE *, LPCWSTR, LPCWSTR );
|
||||||
extern void ACTION_remove_tracked_tempfiles( MSIPACKAGE* );
|
|
||||||
extern void ACTION_free_package_structures( MSIPACKAGE* );
|
extern void ACTION_free_package_structures( MSIPACKAGE* );
|
||||||
|
extern UINT ACTION_DialogBox( MSIPACKAGE*, LPCWSTR);
|
||||||
|
|
||||||
/* record internals */
|
/* record internals */
|
||||||
extern UINT MSI_RecordSetIStream( MSIRECORD *, unsigned int, IStream *);
|
extern UINT MSI_RecordSetIStream( MSIRECORD *, unsigned int, IStream *);
|
||||||
|
@ -296,6 +324,9 @@ extern void enum_stream_names( IStorage *stg );
|
||||||
/* database internals */
|
/* database internals */
|
||||||
extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** );
|
extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** );
|
||||||
extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** );
|
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 */
|
/* view internals */
|
||||||
extern UINT MSI_ViewExecute( MSIQUERY*, MSIRECORD * );
|
extern UINT MSI_ViewExecute( MSIQUERY*, MSIRECORD * );
|
||||||
|
@ -303,26 +334,51 @@ extern UINT MSI_ViewFetch( MSIQUERY*, MSIRECORD ** );
|
||||||
extern UINT MSI_ViewClose( MSIQUERY* );
|
extern UINT MSI_ViewClose( MSIQUERY* );
|
||||||
|
|
||||||
/* package internals */
|
/* package internals */
|
||||||
extern UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE ** );
|
extern MSIPACKAGE *MSI_CreatePackage( MSIDATABASE * );
|
||||||
extern UINT MSI_SetTargetPathW( MSIPACKAGE *, LPCWSTR, LPCWSTR);
|
extern UINT MSI_OpenPackageW( LPCWSTR szPackage, MSIPACKAGE ** );
|
||||||
|
extern UINT MSI_SetTargetPathW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
|
||||||
extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
|
extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
|
||||||
extern INT MSI_ProcessMessage( MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD* );
|
extern INT MSI_ProcessMessage( MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD * );
|
||||||
extern UINT MSI_GetPropertyW( MSIPACKAGE *, LPCWSTR, LPWSTR, DWORD*);
|
extern UINT MSI_GetPropertyW( MSIPACKAGE *, LPCWSTR, LPWSTR, DWORD * );
|
||||||
extern MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *, LPCWSTR );
|
extern MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *, LPCWSTR );
|
||||||
extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
|
extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
|
||||||
extern UINT MSI_GetComponentStateW(MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE *);
|
extern UINT MSI_GetComponentStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE * );
|
||||||
extern UINT MSI_GetFeatureStateW(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 */
|
/* registry data encoding/decoding functions */
|
||||||
BOOL unsquash_guid(LPCWSTR in, LPWSTR out);
|
extern BOOL unsquash_guid(LPCWSTR in, LPWSTR out);
|
||||||
BOOL squash_guid(LPCWSTR in, LPWSTR out);
|
extern BOOL squash_guid(LPCWSTR in, LPWSTR out);
|
||||||
BOOL encode_base85_guid(GUID *,LPWSTR);
|
extern BOOL encode_base85_guid(GUID *,LPWSTR);
|
||||||
BOOL decode_base85_guid(LPCWSTR,GUID*);
|
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 */
|
/* UI globals */
|
||||||
extern INSTALLUILEVEL gUILevel;
|
extern INSTALLUILEVEL gUILevel;
|
||||||
extern HWND gUIhwnd;
|
extern HWND gUIhwnd;
|
||||||
extern INSTALLUI_HANDLERA gUIHandler;
|
extern INSTALLUI_HANDLERA gUIHandlerA;
|
||||||
|
extern INSTALLUI_HANDLERW gUIHandlerW;
|
||||||
extern DWORD gUIFilter;
|
extern DWORD gUIFilter;
|
||||||
extern LPVOID gUIContext;
|
extern LPVOID gUIContext;
|
||||||
extern WCHAR gszLogFile[MAX_PATH];
|
extern WCHAR gszLogFile[MAX_PATH];
|
||||||
|
|
|
@ -38,30 +38,6 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
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 )
|
void MSI_CloseView( MSIOBJECTHDR *arg )
|
||||||
{
|
{
|
||||||
MSIQUERY *query = (MSIQUERY*) arg;
|
MSIQUERY *query = (MSIQUERY*) arg;
|
||||||
|
@ -158,6 +134,87 @@ UINT MSI_DatabaseOpenViewW(MSIDATABASE *db,
|
||||||
return r;
|
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,
|
UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
|
||||||
LPCWSTR szQuery, MSIHANDLE *phView)
|
LPCWSTR szQuery, MSIHANDLE *phView)
|
||||||
{
|
{
|
||||||
|
@ -358,7 +415,10 @@ UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
msiobj_lock( &rec->hdr );
|
||||||
ret = MSI_ViewExecute( query, rec );
|
ret = MSI_ViewExecute( query, rec );
|
||||||
|
msiobj_unlock( &rec->hdr );
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if( query )
|
if( query )
|
||||||
msiobj_release( &query->hdr );
|
msiobj_release( &query->hdr );
|
||||||
|
@ -370,10 +430,10 @@ out:
|
||||||
|
|
||||||
UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
|
UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
|
||||||
{
|
{
|
||||||
MSIVIEW *view;
|
MSIVIEW *view = NULL;
|
||||||
MSIQUERY *query;
|
MSIQUERY *query = NULL;
|
||||||
MSIHANDLE handle;
|
MSIRECORD *rec = NULL;
|
||||||
UINT ret, i, count = 0, type;
|
UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type;
|
||||||
LPWSTR name;
|
LPWSTR name;
|
||||||
|
|
||||||
TRACE("%ld %d %p\n", hView, info, hRec);
|
TRACE("%ld %d %p\n", hView, info, hRec);
|
||||||
|
@ -384,34 +444,82 @@ UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hR
|
||||||
|
|
||||||
view = query->view;
|
view = query->view;
|
||||||
if( !view )
|
if( !view )
|
||||||
return ERROR_FUNCTION_FAILED;
|
goto out;
|
||||||
|
|
||||||
if( !view->ops->get_dimensions )
|
if( !view->ops->get_dimensions )
|
||||||
return ERROR_FUNCTION_FAILED;
|
goto out;
|
||||||
|
|
||||||
ret = view->ops->get_dimensions( view, NULL, &count );
|
r = view->ops->get_dimensions( view, NULL, &count );
|
||||||
if( ret )
|
if( r )
|
||||||
return ret;
|
goto out;
|
||||||
if( !count )
|
if( !count )
|
||||||
return ERROR_INVALID_PARAMETER;
|
{
|
||||||
|
r = ERROR_INVALID_PARAMETER;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
handle = MsiCreateRecord( count );
|
rec = MSI_CreateRecord( count );
|
||||||
if( !handle )
|
if( !rec )
|
||||||
return ERROR_FUNCTION_FAILED;
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
|
||||||
for( i=0; i<count; i++ )
|
for( i=0; i<count; i++ )
|
||||||
{
|
{
|
||||||
name = NULL;
|
name = NULL;
|
||||||
ret = view->ops->get_column_info( view, i+1, &name, &type );
|
r = view->ops->get_column_info( view, i+1, &name, &type );
|
||||||
if( ret != ERROR_SUCCESS )
|
if( r != ERROR_SUCCESS )
|
||||||
continue;
|
continue;
|
||||||
MsiRecordSetStringW( handle, i+1, name );
|
MSI_RecordSetStringW( rec, i+1, name );
|
||||||
HeapFree( GetProcessHeap(), 0, 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,
|
UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb,
|
||||||
|
@ -461,6 +569,8 @@ UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
|
||||||
|
|
||||||
/* FIXME: unlock the database */
|
/* FIXME: unlock the database */
|
||||||
|
|
||||||
|
msiobj_release( &db->hdr );
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,9 +588,16 @@ UINT WINAPI MsiDatabaseGetPrimaryKeysW(MSIHANDLE hdb,
|
||||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT WINAPI MsiViewModify(MSIHANDLE hView, MSIMODIFY eModifyMode, MSIHANDLE
|
UINT WINAPI MsiDatabaseIsTablePersistentA(
|
||||||
hRecord)
|
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;
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,7 +187,6 @@ static UINT ORDER_close( struct tagMSIVIEW *view )
|
||||||
if( !ov->table )
|
if( !ov->table )
|
||||||
return ERROR_FUNCTION_FAILED;
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
|
||||||
if( ov->reorder )
|
|
||||||
HeapFree( GetProcessHeap(), 0, ov->reorder );
|
HeapFree( GetProcessHeap(), 0, ov->reorder );
|
||||||
ov->reorder = NULL;
|
ov->reorder = NULL;
|
||||||
|
|
||||||
|
@ -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 );
|
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;
|
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
|
||||||
|
|
||||||
TRACE("%p %d %ld\n", ov, eModifyMode, hrec );
|
TRACE("%p %d %p\n", ov, eModifyMode, rec );
|
||||||
|
|
||||||
if( !ov->table )
|
if( !ov->table )
|
||||||
return ERROR_FUNCTION_FAILED;
|
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 )
|
static UINT ORDER_delete( struct tagMSIVIEW *view )
|
||||||
|
@ -240,7 +240,6 @@ static UINT ORDER_delete( struct tagMSIVIEW *view )
|
||||||
if( ov->table )
|
if( ov->table )
|
||||||
ov->table->ops->delete( ov->table );
|
ov->table->ops->delete( ov->table );
|
||||||
|
|
||||||
if( ov->reorder )
|
|
||||||
HeapFree( GetProcessHeap(), 0, ov->reorder );
|
HeapFree( GetProcessHeap(), 0, ov->reorder );
|
||||||
ov->reorder = NULL;
|
ov->reorder = NULL;
|
||||||
|
|
||||||
|
|
|
@ -53,36 +53,13 @@ void MSI_FreePackage( MSIOBJECTHDR *arg)
|
||||||
{
|
{
|
||||||
MSIPACKAGE *package= (MSIPACKAGE*) arg;
|
MSIPACKAGE *package= (MSIPACKAGE*) arg;
|
||||||
|
|
||||||
ACTION_remove_tracked_tempfiles(package);
|
if( package->dialog )
|
||||||
|
msi_dialog_destroy( package->dialog );
|
||||||
ACTION_free_package_structures(package);
|
ACTION_free_package_structures(package);
|
||||||
|
|
||||||
msiobj_release( &package->db->hdr );
|
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)
|
static const UINT clone_properties(MSIDATABASE *db)
|
||||||
{
|
{
|
||||||
MSIQUERY * view = NULL;
|
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','`',' ',
|
||||||
'(','`','_','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','`',')',' ',
|
||||||
'V','A','L','U','E','S',' ','(','?',')',0};
|
'V','A','L','U','E','S',' ','(','?',',','?',')',0};
|
||||||
|
|
||||||
/* create the temporary properties table */
|
/* create the temporary properties table */
|
||||||
rc = MSI_DatabaseOpenViewW(db, CreateSql, &view);
|
rc = MSI_DatabaseOpenViewW(db, CreateSql, &view);
|
||||||
|
@ -377,39 +354,18 @@ Privileged
|
||||||
ReleaseDC(0, dc);
|
ReleaseDC(0, dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
|
MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db )
|
||||||
{
|
{
|
||||||
UINT rc;
|
static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
|
||||||
MSIDATABASE *db = NULL;
|
static const WCHAR szpi[] = {'%','i',0};
|
||||||
MSIPACKAGE *package = NULL;
|
MSIPACKAGE *package = NULL;
|
||||||
WCHAR uilevel[10];
|
WCHAR uilevel[10];
|
||||||
UINT ret = ERROR_FUNCTION_FAILED;
|
|
||||||
|
|
||||||
static const WCHAR OriginalDatabase[] =
|
TRACE("%p\n", db);
|
||||||
{'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;
|
|
||||||
}
|
|
||||||
|
|
||||||
package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
|
package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
|
||||||
MSI_FreePackage );
|
MSI_FreePackage );
|
||||||
|
if( package )
|
||||||
if (package)
|
|
||||||
{
|
{
|
||||||
msiobj_addref( &db->hdr );
|
msiobj_addref( &db->hdr );
|
||||||
|
|
||||||
|
@ -424,35 +380,78 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
|
||||||
package->loaded_files = 0;
|
package->loaded_files = 0;
|
||||||
package->ActionFormat = NULL;
|
package->ActionFormat = NULL;
|
||||||
package->LastAction = 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
|
/* OK, here is where we do a slew of things to the database to
|
||||||
* prep for all that is to come as a package */
|
* prep for all that is to come as a package */
|
||||||
|
|
||||||
clone_properties(db);
|
clone_properties(db);
|
||||||
set_installer_properties(package);
|
set_installer_properties(package);
|
||||||
MSI_SetPropertyW(package, OriginalDatabase, szPackage);
|
|
||||||
MSI_SetPropertyW(package, Database, szPackage);
|
|
||||||
sprintfW(uilevel,szpi,gUILevel);
|
sprintfW(uilevel,szpi,gUILevel);
|
||||||
MSI_SetPropertyW(package, szLevel, uilevel);
|
MSI_SetPropertyW(package, szLevel, uilevel);
|
||||||
|
|
||||||
msiobj_addref( &package->hdr );
|
|
||||||
*pPackage = package;
|
|
||||||
ret = ERROR_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( package )
|
return package;
|
||||||
msiobj_release( &package->hdr );
|
|
||||||
if( db )
|
|
||||||
msiobj_release( &db->hdr );
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
MSIPACKAGE *package = NULL;
|
||||||
UINT ret;
|
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);
|
ret = MSI_OpenPackageW( szPackage, &package);
|
||||||
if( ret == ERROR_SUCCESS )
|
if( ret == ERROR_SUCCESS )
|
||||||
{
|
{
|
||||||
|
@ -462,16 +461,34 @@ UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
|
||||||
return ret;
|
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 MsiOpenPackageExW( szPackage, 0, phPackage );
|
||||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
LPWSTR szwPack = NULL;
|
||||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
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)
|
MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
|
||||||
|
@ -555,7 +572,7 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
|
||||||
HeapFree(GetProcessHeap(),0,tmp);
|
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));
|
debugstr_w(message));
|
||||||
|
|
||||||
/* convert it to ASCII */
|
/* convert it to ASCII */
|
||||||
|
@ -565,9 +582,9 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
|
||||||
WideCharToMultiByte( CP_ACP, 0, message, -1,
|
WideCharToMultiByte( CP_ACP, 0, message, -1,
|
||||||
msg, len, NULL, NULL );
|
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) ==
|
if ((!rc) && (gszLogFile[0]) && !((eMessageType & 0xff000000) ==
|
||||||
|
@ -649,9 +666,7 @@ UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
|
||||||
hr = MsiSetPropertyW( hInstall, szwName, szwValue);
|
hr = MsiSetPropertyW( hInstall, szwName, szwValue);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if( szwName )
|
|
||||||
HeapFree( GetProcessHeap(), 0, szwName );
|
HeapFree( GetProcessHeap(), 0, szwName );
|
||||||
if( szwValue )
|
|
||||||
HeapFree( GetProcessHeap(), 0, szwValue );
|
HeapFree( GetProcessHeap(), 0, szwValue );
|
||||||
|
|
||||||
return hr;
|
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'
|
{'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','`'
|
,'e','r','t','y','`',' ','(','`','_','P','r','o','p','e','r','t','y','`'
|
||||||
,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S'
|
,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S'
|
||||||
,' ','(','?',')',0};
|
,' ','(','?',',','?',')',0};
|
||||||
static const WCHAR Update[]=
|
static const WCHAR Update[]=
|
||||||
{'U','P','D','A','T','E',' ','_','P','r','o','p','e'
|
{'U','P','D','A','T','E',' ','_','P','r','o','p','e'
|
||||||
,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','='
|
,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','='
|
||||||
|
@ -848,6 +863,11 @@ UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf,
|
||||||
return ERROR_INVALID_HANDLE;
|
return ERROR_INVALID_HANDLE;
|
||||||
ret = MSI_GetPropertyA(package, szName, szValueBuf, pchValueBuf );
|
ret = MSI_GetPropertyA(package, szName, szValueBuf, pchValueBuf );
|
||||||
msiobj_release( &package->hdr );
|
msiobj_release( &package->hdr );
|
||||||
|
|
||||||
|
/* MsiGetProperty does not return error codes on missing properties */
|
||||||
|
if (ret!= ERROR_MORE_DATA)
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
else
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -870,5 +890,10 @@ UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName,
|
||||||
return ERROR_INVALID_HANDLE;
|
return ERROR_INVALID_HANDLE;
|
||||||
ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf );
|
ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf );
|
||||||
msiobj_release( &package->hdr );
|
msiobj_release( &package->hdr );
|
||||||
|
|
||||||
|
/* MsiGetProperty does not return error codes on missing properties */
|
||||||
|
if (ret!= ERROR_MORE_DATA)
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
else
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
164
reactos/lib/msi/preview.c
Normal file
164
reactos/lib/msi/preview.c
Normal file
|
@ -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 <stdarg.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
|
@ -454,12 +454,20 @@ UINT MSI_RecordSetStringA( MSIRECORD *rec, unsigned int iField, LPCSTR szValue )
|
||||||
if( iField > rec->count )
|
if( iField > rec->count )
|
||||||
return ERROR_INVALID_FIELD;
|
return ERROR_INVALID_FIELD;
|
||||||
|
|
||||||
|
MSI_FreeField( &rec->fields[iField] );
|
||||||
|
if( szValue && szValue[0] )
|
||||||
|
{
|
||||||
len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
|
len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
|
||||||
str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
|
str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
|
||||||
MultiByteToWideChar( CP_ACP, 0, szValue, -1, str, len );
|
MultiByteToWideChar( CP_ACP, 0, szValue, -1, str, len );
|
||||||
MSI_FreeField( &rec->fields[iField] );
|
|
||||||
rec->fields[iField].type = MSIFIELD_WSTR;
|
rec->fields[iField].type = MSIFIELD_WSTR;
|
||||||
rec->fields[iField].u.szwVal = str;
|
rec->fields[iField].u.szwVal = str;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rec->fields[iField].type = MSIFIELD_NULL;
|
||||||
|
rec->fields[iField].u.szwVal = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -491,13 +499,22 @@ UINT MSI_RecordSetStringW( MSIRECORD *rec, unsigned int iField, LPCWSTR szValue
|
||||||
if( iField > rec->count )
|
if( iField > rec->count )
|
||||||
return ERROR_INVALID_FIELD;
|
return ERROR_INVALID_FIELD;
|
||||||
|
|
||||||
|
MSI_FreeField( &rec->fields[iField] );
|
||||||
|
|
||||||
|
if( szValue && szValue[0] )
|
||||||
|
{
|
||||||
len = lstrlenW(szValue) + 1;
|
len = lstrlenW(szValue) + 1;
|
||||||
str = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR));
|
str = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR));
|
||||||
lstrcpyW( str, szValue );
|
lstrcpyW( str, szValue );
|
||||||
|
|
||||||
MSI_FreeField( &rec->fields[iField] );
|
|
||||||
rec->fields[iField].type = MSIFIELD_WSTR;
|
rec->fields[iField].type = MSIFIELD_WSTR;
|
||||||
rec->fields[iField].u.szwVal = str;
|
rec->fields[iField].u.szwVal = str;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rec->fields[iField].type = MSIFIELD_NULL;
|
||||||
|
rec->fields[iField].u.szwVal = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -520,18 +537,6 @@ UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, unsigned int iField, LPCWSTR
|
||||||
return ret;
|
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 */
|
/* read the data in a file into an IStream */
|
||||||
UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
|
UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
|
||||||
{
|
{
|
||||||
|
|
486
reactos/lib/msi/registry.c
Normal file
486
reactos/lib/msi/registry.c
Normal file
|
@ -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 <stdarg.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
|
@ -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 );
|
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;
|
MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
|
||||||
|
|
||||||
TRACE("%p %d %ld\n", sv, eModifyMode, hrec );
|
TRACE("%p %d %p\n", sv, eModifyMode, rec );
|
||||||
|
|
||||||
if( !sv->table )
|
if( !sv->table )
|
||||||
return ERROR_FUNCTION_FAILED;
|
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 )
|
static UINT SELECT_delete( struct tagMSIVIEW *view )
|
||||||
|
|
|
@ -564,7 +564,7 @@ union yyalloc
|
||||||
/* YYFINAL -- State number of the termination state. */
|
/* YYFINAL -- State number of the termination state. */
|
||||||
#define YYFINAL 23
|
#define YYFINAL 23
|
||||||
/* YYLAST -- Last index in YYTABLE. */
|
/* YYLAST -- Last index in YYTABLE. */
|
||||||
#define YYLAST 125
|
#define YYLAST 126
|
||||||
|
|
||||||
/* YYNTOKENS -- Number of terminals. */
|
/* YYNTOKENS -- Number of terminals. */
|
||||||
#define YYNTOKENS 147
|
#define YYNTOKENS 147
|
||||||
|
@ -663,7 +663,7 @@ static const short yyrhs[] =
|
||||||
-1, 168, 57, 163, -1, 168, 85, 163, -1, 168,
|
-1, 168, 57, 163, -1, 168, 85, 163, -1, 168,
|
||||||
78, 163, -1, 168, 54, 163, -1, 168, 89, 163,
|
78, 163, -1, 168, 54, 163, -1, 168, 89, 163,
|
||||||
-1, 168, 73, 92, -1, 168, 73, 90, 92, -1,
|
-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,
|
166, -1, 166, 24, 165, -1, 169, 45, 167, -1,
|
||||||
70, -1, 88, 70, -1, 120, -1, 138, -1, 169,
|
70, -1, 88, 70, -1, 120, -1, 138, -1, 169,
|
||||||
-1, 170, 39, 171, -1, 171, -1, 171, -1, 66,
|
-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,
|
290, 294, 298, 302, 306, 313, 324, 335, 339, 353,
|
||||||
371, 384, 397, 404, 415, 434, 438, 442, 446, 450,
|
371, 384, 397, 404, 415, 434, 438, 442, 446, 450,
|
||||||
454, 458, 462, 466, 470, 474, 478, 485, 486, 490,
|
454, 458, 462, 466, 470, 474, 478, 485, 486, 490,
|
||||||
502, 518, 519, 528, 544, 548, 552, 556, 563, 570,
|
502, 517, 518, 527, 543, 547, 551, 555, 562, 569,
|
||||||
574, 581, 588, 592
|
573, 580, 587, 591
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -787,8 +787,8 @@ static const unsigned char yydefact[] =
|
||||||
15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 55, 12, 11, 25, 0, 17, 0,
|
0, 0, 0, 55, 12, 11, 25, 0, 17, 0,
|
||||||
35, 37, 38, 56, 39, 48, 36, 43, 47, 40,
|
35, 37, 38, 56, 39, 48, 36, 43, 47, 40,
|
||||||
0, 45, 42, 41, 44, 19, 0, 49, 46, 0,
|
0, 45, 42, 41, 44, 19, 0, 49, 46, 6,
|
||||||
6, 50, 7
|
0, 7, 50
|
||||||
};
|
};
|
||||||
|
|
||||||
/* YYDEFGOTO[NTERM-NUM]. */
|
/* YYDEFGOTO[NTERM-NUM]. */
|
||||||
|
@ -801,30 +801,30 @@ static const yysigned_char yydefgoto[] =
|
||||||
|
|
||||||
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
|
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
|
||||||
STATE-NUM. */
|
STATE-NUM. */
|
||||||
#define YYPACT_NINF -105
|
#define YYPACT_NINF -104
|
||||||
static const yysigned_char yypact[] =
|
static const yysigned_char yypact[] =
|
||||||
{
|
{
|
||||||
-30, -104, -46, -34, -51, 21, -105, -105, -105, -105,
|
-30, -103, -52, -34, -51, 21, -104, -104, -104, -104,
|
||||||
-77, -51, -51, -52, -105, -105, -105, -25, 7, -1,
|
-70, -51, -51, -57, -104, -104, -104, -26, 11, -6,
|
||||||
2, -79, -105, -105, 31, -33, -32, -25, -51, -105,
|
-1, -69, -104, -104, 32, -25, -15, -26, -51, -104,
|
||||||
-52, -51, -51, -52, -51, -52, -105, -88, -105, -105,
|
-57, -51, -51, -57, -51, -57, -104, -71, -104, -104,
|
||||||
-82, 33, 14, -105, -48, -15, -17, -43, -50, -50,
|
-67, 47, 27, -104, -36, -19, -17, -29, -53, -53,
|
||||||
-51, -64, 13, -51, -2, -6, -105, -105, -105, -105,
|
-51, -63, 26, -51, 17, -10, -104, -104, -104, -104,
|
||||||
-105, -105, 6, -9, -49, -50, -4, 26, -105, -4,
|
-104, -104, 5, 7, -35, -53, -4, 35, -104, -4,
|
||||||
-105, -105, 24, -105, -105, -105, -105, -17, -52, 25,
|
-104, -104, 37, -104, -104, -104, -104, -17, -57, 39,
|
||||||
-105, 9, 19, -7, -50, -50, -59, -59, -59, -44,
|
-104, 18, 28, -7, -53, -53, -60, -60, -60, -73,
|
||||||
-59, -59, -59, -105, -105, -105, -105, -3, -105, -64,
|
-60, -60, -60, -104, -104, -104, -104, 4, -104, -63,
|
||||||
-105, -4, -4, 73, -105, -105, -105, -105, -105, -105,
|
-104, -4, -4, 77, -104, -104, -104, -104, -104, -104,
|
||||||
22, -105, -105, -105, -105, -105, -19, -105, -105, -64,
|
25, -104, -104, -104, -104, -104, 8, 95, -104, 0,
|
||||||
1, -105, -105
|
-63, -104, -104
|
||||||
};
|
};
|
||||||
|
|
||||||
/* YYPGOTO[NTERM-NUM]. */
|
/* YYPGOTO[NTERM-NUM]. */
|
||||||
static const yysigned_char yypgoto[] =
|
static const yysigned_char yypgoto[] =
|
||||||
{
|
{
|
||||||
-105, -105, -105, -105, -105, -105, -105, 42, -105, -105,
|
-104, -104, -104, -104, -104, -104, -104, 44, -104, -104,
|
||||||
-105, -105, -105, -5, 97, -31, 18, -105, 75, -105,
|
-104, -104, -104, 1, 96, -38, 14, 6, 75, -104,
|
||||||
-41, 30, 10, 85, 8
|
-43, -37, 9, 12, 84
|
||||||
};
|
};
|
||||||
|
|
||||||
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
|
/* 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
|
#define YYTABLE_NINF -64
|
||||||
static const yysigned_char yytable[] =
|
static const yysigned_char yytable[] =
|
||||||
{
|
{
|
||||||
84, 1, 55, 84, 13, 119, 71, 14, 27, 53,
|
84, 1, 55, 84, 13, 53, 14, 71, 75, 14,
|
||||||
75, 71, 22, 18, 14, 14, 14, 11, 69, 22,
|
71, 69, 18, 14, 27, 14, 21, 110, 11, 111,
|
||||||
22, 23, 24, 18, 72, 38, 12, 28, 43, 72,
|
12, 23, 18, 25, 26, 72, 28, 83, 72, 24,
|
||||||
47, 30, 14, 65, 83, 32, 22, 2, 31, 39,
|
65, 38, 14, 31, 43, 30, 47, 2, -61, 18,
|
||||||
18, -61, 42, 18, 46, 18, 110, 33, 111, 48,
|
37, 42, 18, 46, 18, 32, 101, 102, 33, 106,
|
||||||
34, 35, 56, 101, 102, 49, 73, 50, 117, 51,
|
108, 108, 56, 108, 108, 108, 117, 73, 34, 42,
|
||||||
42, 103, 52, 77, 57, 58, 15, 64, 16, 16,
|
103, 15, 77, 16, 57, 58, 48, 16, 35, 16,
|
||||||
16, 86, 76, 95, 74, 78, 59, 79, 121, 74,
|
49, 50, 51, 79, 52, 74, 59, 117, 74, 95,
|
||||||
87, 81, 3, 88, 15, 82, 16, 54, 18, 21,
|
86, 64, 3, 54, 15, 76, 16, 18, 22, 87,
|
||||||
85, 120, 80, 85, 93, 96, 25, 26, 60, 89,
|
85, 80, 88, 85, 78, 22, 22, 81, 60, 82,
|
||||||
4, 98, 99, 100, 90, 107, 109, 115, 112, 113,
|
4, 107, 109, 100, 112, 113, 114, 93, 89, 96,
|
||||||
114, 91, -63, 37, 118, 92, 106, 108, 108, 94,
|
98, 99, 22, 90, 115, 39, -63, 118, 119, 120,
|
||||||
108, 108, 108, 122, 36, 70
|
91, 94, 121, 36, 92, 70, 122
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned char yycheck[] =
|
static const unsigned char yycheck[] =
|
||||||
{
|
{
|
||||||
7, 31, 19, 7, 38, 24, 70, 66, 13, 24,
|
7, 31, 19, 7, 38, 24, 66, 70, 51, 66,
|
||||||
51, 70, 4, 3, 66, 66, 66, 121, 49, 11,
|
70, 49, 3, 66, 13, 66, 4, 90, 121, 92,
|
||||||
12, 0, 99, 13, 88, 30, 72, 52, 33, 88,
|
72, 0, 13, 11, 12, 88, 52, 65, 88, 99,
|
||||||
35, 24, 66, 83, 65, 114, 28, 67, 39, 31,
|
83, 30, 66, 39, 33, 24, 35, 67, 39, 30,
|
||||||
30, 39, 32, 33, 34, 35, 90, 16, 92, 137,
|
28, 32, 33, 34, 35, 114, 84, 85, 16, 86,
|
||||||
83, 83, 69, 84, 85, 137, 120, 24, 99, 45,
|
87, 88, 69, 90, 91, 92, 99, 120, 83, 50,
|
||||||
50, 120, 110, 53, 81, 82, 118, 110, 120, 120,
|
120, 118, 53, 120, 81, 82, 137, 120, 83, 120,
|
||||||
120, 45, 59, 78, 138, 77, 93, 83, 119, 138,
|
137, 24, 45, 83, 110, 138, 93, 120, 138, 78,
|
||||||
54, 90, 112, 57, 118, 134, 120, 102, 78, 4,
|
45, 110, 112, 102, 118, 59, 120, 78, 4, 54,
|
||||||
97, 110, 86, 97, 70, 70, 11, 12, 115, 73,
|
97, 86, 57, 97, 77, 11, 12, 90, 115, 134,
|
||||||
130, 92, 83, 110, 78, 87, 88, 110, 90, 91,
|
130, 87, 88, 110, 90, 91, 92, 70, 73, 70,
|
||||||
92, 85, 39, 28, 92, 89, 86, 87, 88, 77,
|
92, 83, 28, 78, 110, 31, 39, 92, 110, 24,
|
||||||
90, 91, 92, 122, 27, 50
|
85, 77, 122, 27, 89, 50, 120
|
||||||
};
|
};
|
||||||
|
|
||||||
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
|
/* 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,
|
86, 90, 134, 162, 7, 97, 45, 54, 57, 73,
|
||||||
78, 85, 89, 70, 154, 160, 70, 157, 92, 83,
|
78, 85, 89, 70, 154, 160, 70, 157, 92, 83,
|
||||||
110, 162, 162, 120, 163, 167, 168, 163, 168, 163,
|
110, 162, 162, 120, 163, 167, 168, 163, 168, 163,
|
||||||
90, 92, 163, 163, 163, 110, 164, 167, 92, 24,
|
90, 92, 163, 163, 163, 110, 164, 167, 92, 110,
|
||||||
110, 167, 122
|
24, 122, 164
|
||||||
};
|
};
|
||||||
|
|
||||||
#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
|
#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
|
||||||
|
@ -1944,16 +1944,15 @@ yyreduce:
|
||||||
vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
|
vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
|
||||||
if( vals )
|
if( vals )
|
||||||
{
|
{
|
||||||
vals->val = yyvsp[0].expr;
|
vals->val = yyvsp[-2].expr;
|
||||||
vals->next = NULL;
|
vals->next = yyvsp[0].val_list;
|
||||||
}
|
}
|
||||||
yyvsp[-2].val_list->next = vals;
|
yyval.val_list = vals;
|
||||||
yyval.val_list = yyvsp[-2].val_list;
|
|
||||||
;}
|
;}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 52:
|
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.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;
|
yyvsp[-2].update_col_info.val_list->next = yyvsp[0].update_col_info.val_list;
|
||||||
|
@ -1962,7 +1961,7 @@ yyreduce:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 53:
|
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 );
|
yyval.update_col_info.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.col_list );
|
||||||
if( !yyval.update_col_info.col_list )
|
if( !yyval.update_col_info.col_list )
|
||||||
|
@ -1978,70 +1977,70 @@ yyreduce:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 54:
|
case 54:
|
||||||
#line 545 "./sql.y"
|
#line 544 "./sql.y"
|
||||||
{
|
{
|
||||||
yyval.expr = EXPR_ival( &yyvsp[0].str, 1 );
|
yyval.expr = EXPR_ival( &yyvsp[0].str, 1 );
|
||||||
;}
|
;}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 55:
|
case 55:
|
||||||
#line 549 "./sql.y"
|
#line 548 "./sql.y"
|
||||||
{
|
{
|
||||||
yyval.expr = EXPR_ival( &yyvsp[0].str, -1 );
|
yyval.expr = EXPR_ival( &yyvsp[0].str, -1 );
|
||||||
;}
|
;}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 56:
|
case 56:
|
||||||
#line 553 "./sql.y"
|
#line 552 "./sql.y"
|
||||||
{
|
{
|
||||||
yyval.expr = EXPR_sval( &yyvsp[0].str );
|
yyval.expr = EXPR_sval( &yyvsp[0].str );
|
||||||
;}
|
;}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 57:
|
case 57:
|
||||||
#line 557 "./sql.y"
|
#line 556 "./sql.y"
|
||||||
{
|
{
|
||||||
yyval.expr = EXPR_wildcard();
|
yyval.expr = EXPR_wildcard();
|
||||||
;}
|
;}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 58:
|
case 58:
|
||||||
#line 564 "./sql.y"
|
#line 563 "./sql.y"
|
||||||
{
|
{
|
||||||
yyval.expr = EXPR_column( yyvsp[0].string );
|
yyval.expr = EXPR_column( yyvsp[0].string );
|
||||||
;}
|
;}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 59:
|
case 59:
|
||||||
#line 571 "./sql.y"
|
#line 570 "./sql.y"
|
||||||
{
|
{
|
||||||
yyval.string = yyvsp[0].string; /* FIXME */
|
yyval.string = yyvsp[0].string; /* FIXME */
|
||||||
;}
|
;}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 60:
|
case 60:
|
||||||
#line 575 "./sql.y"
|
#line 574 "./sql.y"
|
||||||
{
|
{
|
||||||
yyval.string = yyvsp[0].string;
|
yyval.string = yyvsp[0].string;
|
||||||
;}
|
;}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 61:
|
case 61:
|
||||||
#line 582 "./sql.y"
|
#line 581 "./sql.y"
|
||||||
{
|
{
|
||||||
yyval.string = yyvsp[0].string;
|
yyval.string = yyvsp[0].string;
|
||||||
;}
|
;}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 62:
|
case 62:
|
||||||
#line 589 "./sql.y"
|
#line 588 "./sql.y"
|
||||||
{
|
{
|
||||||
yyval.string = SQL_getstring( &yyvsp[0].str );
|
yyval.string = SQL_getstring( &yyvsp[0].str );
|
||||||
;}
|
;}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 63:
|
case 63:
|
||||||
#line 593 "./sql.y"
|
#line 592 "./sql.y"
|
||||||
{
|
{
|
||||||
yyval.string = SQL_getstring( &yyvsp[0].str );
|
yyval.string = SQL_getstring( &yyvsp[0].str );
|
||||||
;}
|
;}
|
||||||
|
@ -2051,7 +2050,7 @@ yyreduce:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Line 999 of yacc.c. */
|
/* Line 999 of yacc.c. */
|
||||||
#line 2055 "sql.tab.c"
|
#line 2054 "sql.tab.c"
|
||||||
|
|
||||||
yyvsp -= yylen;
|
yyvsp -= yylen;
|
||||||
yyssp -= 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)
|
int SQL_lex( void *SQL_lval, SQL_input *sql)
|
||||||
|
|
|
@ -499,18 +499,17 @@ constlist:
|
||||||
}
|
}
|
||||||
$$ = vals;
|
$$ = vals;
|
||||||
}
|
}
|
||||||
| constlist TK_COMMA const_val
|
| const_val TK_COMMA constlist
|
||||||
{
|
{
|
||||||
value_list *vals;
|
value_list *vals;
|
||||||
|
|
||||||
vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
|
vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
|
||||||
if( vals )
|
if( vals )
|
||||||
{
|
{
|
||||||
vals->val = $3;
|
vals->val = $1;
|
||||||
vals->next = NULL;
|
vals->next = $3;
|
||||||
}
|
}
|
||||||
$1->next = vals;
|
$$ = vals;
|
||||||
$$ = $1;
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -393,7 +393,6 @@ UINT msi_string2idA( string_table *st, LPCSTR buffer, UINT *id )
|
||||||
MultiByteToWideChar( st->codepage, 0, buffer, -1, str, sz );
|
MultiByteToWideChar( st->codepage, 0, buffer, -1, str, sz );
|
||||||
|
|
||||||
r = msi_string2idW( st, str, id );
|
r = msi_string2idW( st, str, id );
|
||||||
if( str )
|
|
||||||
HeapFree( GetProcessHeap(), 0, str );
|
HeapFree( GetProcessHeap(), 0, str );
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
|
|
@ -67,7 +67,6 @@ UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase,
|
||||||
|
|
||||||
ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, phSummaryInfo);
|
ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, phSummaryInfo);
|
||||||
|
|
||||||
if( szwDatabase )
|
|
||||||
HeapFree( GetProcessHeap(), 0, szwDatabase );
|
HeapFree( GetProcessHeap(), 0, szwDatabase );
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -225,9 +224,72 @@ UINT WINAPI MsiSummaryInfoGetPropertyW(
|
||||||
MSIHANDLE hSummaryInfo, UINT uiProperty, UINT *puiDataType, INT *piValue,
|
MSIHANDLE hSummaryInfo, UINT uiProperty, UINT *puiDataType, INT *piValue,
|
||||||
FILETIME *pftValue, LPWSTR szValueBuf, DWORD *pcchValueBuf)
|
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,
|
hSummaryInfo, uiProperty, puiDataType, piValue,
|
||||||
pftValue, szValueBuf, pcchValueBuf);
|
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;
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,7 +196,7 @@ void enum_stream_names( IStorage *stg )
|
||||||
if( FAILED( r ) || !count )
|
if( FAILED( r ) || !count )
|
||||||
break;
|
break;
|
||||||
decode_streamname( stat.pwcsName, name );
|
decode_streamname( stat.pwcsName, name );
|
||||||
ERR("stream %2ld -> %s %s\n", n,
|
TRACE("stream %2ld -> %s %s\n", n,
|
||||||
debugstr_w(stat.pwcsName), debugstr_w(name) );
|
debugstr_w(stat.pwcsName), debugstr_w(name) );
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
@ -356,12 +356,12 @@ static UINT write_stream_data( IStorage *stg, LPCWSTR stname,
|
||||||
encname = encode_streamname(TRUE, stname );
|
encname = encode_streamname(TRUE, stname );
|
||||||
r = IStorage_OpenStream( stg, encname, NULL,
|
r = IStorage_OpenStream( stg, encname, NULL,
|
||||||
STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
|
STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
|
||||||
HeapFree( GetProcessHeap(), 0, encname );
|
|
||||||
if( FAILED(r) )
|
if( FAILED(r) )
|
||||||
{
|
{
|
||||||
r = IStorage_CreateStream( stg, encname,
|
r = IStorage_CreateStream( stg, encname,
|
||||||
STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
|
STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
|
||||||
}
|
}
|
||||||
|
HeapFree( GetProcessHeap(), 0, encname );
|
||||||
if( FAILED( r ) )
|
if( FAILED( r ) )
|
||||||
{
|
{
|
||||||
ERR("open stream failed r = %08lx\n",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));
|
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,
|
t = HeapAlloc( GetProcessHeap(), 0,
|
||||||
sizeof (MSITABLE) + lstrlenW(name)*sizeof (WCHAR) );
|
sizeof (MSITABLE) + lstrlenW(name)*sizeof (WCHAR) );
|
||||||
if( !t )
|
if( !t )
|
||||||
|
@ -747,9 +747,7 @@ UINT load_string_table( MSIDATABASE *db )
|
||||||
ret = ERROR_SUCCESS;
|
ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if( pool )
|
|
||||||
HeapFree( GetProcessHeap(), 0, pool );
|
HeapFree( GetProcessHeap(), 0, pool );
|
||||||
if( data )
|
|
||||||
HeapFree( GetProcessHeap(), 0, data );
|
HeapFree( GetProcessHeap(), 0, data );
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -830,9 +828,7 @@ UINT save_string_table( MSIDATABASE *db )
|
||||||
ret = ERROR_SUCCESS;
|
ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
if( data )
|
|
||||||
HeapFree( GetProcessHeap(), 0, data );
|
HeapFree( GetProcessHeap(), 0, data );
|
||||||
if( pool )
|
|
||||||
HeapFree( GetProcessHeap(), 0, pool );
|
HeapFree( GetProcessHeap(), 0, pool );
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1288,9 +1284,10 @@ static UINT TABLE_get_column_info( struct tagMSIVIEW *view,
|
||||||
return ERROR_SUCCESS;
|
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;
|
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -151,11 +151,12 @@ static UINT UPDATE_get_column_info( struct tagMSIVIEW *view,
|
||||||
return wv->ops->get_column_info( wv, n, name, type );
|
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;
|
MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
|
||||||
|
|
||||||
TRACE("%p %d %ld\n", uv, eModifyMode, hrec );
|
TRACE("%p %d %p\n", uv, eModifyMode, rec );
|
||||||
|
|
||||||
return ERROR_FUNCTION_FAILED;
|
return ERROR_FUNCTION_FAILED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,7 +269,6 @@ static UINT WHERE_close( struct tagMSIVIEW *view )
|
||||||
if( !wv->table )
|
if( !wv->table )
|
||||||
return ERROR_FUNCTION_FAILED;
|
return ERROR_FUNCTION_FAILED;
|
||||||
|
|
||||||
if( wv->reorder )
|
|
||||||
HeapFree( GetProcessHeap(), 0, wv->reorder );
|
HeapFree( GetProcessHeap(), 0, wv->reorder );
|
||||||
wv->reorder = NULL;
|
wv->reorder = NULL;
|
||||||
|
|
||||||
|
@ -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 );
|
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;
|
MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
|
||||||
|
|
||||||
TRACE("%p %d %ld\n", wv, eModifyMode, hrec );
|
TRACE("%p %d %p\n", wv, eModifyMode, rec );
|
||||||
|
|
||||||
if( !wv->table )
|
if( !wv->table )
|
||||||
return ERROR_FUNCTION_FAILED;
|
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 )
|
static UINT WHERE_delete( struct tagMSIVIEW *view )
|
||||||
|
@ -329,7 +329,6 @@ static UINT WHERE_delete( struct tagMSIVIEW *view )
|
||||||
if( wv->table )
|
if( wv->table )
|
||||||
wv->table->ops->delete( 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->reorder = NULL;
|
||||||
wv->row_count = 0;
|
wv->row_count = 0;
|
||||||
|
|
Loading…
Reference in a new issue