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:
Gé van Geldorp 2005-02-12 22:59:04 +00:00
parent b14fe2e98e
commit c4a2530191
35 changed files with 9583 additions and 3952 deletions

View file

@ -55,6 +55,15 @@ typedef enum tagINSTALLUILEVEL
INSTALLUILEVEL_SOURCERESONLY = 0x100
} INSTALLUILEVEL;
typedef enum tagUSERINFOSTATE
{
USERINFOSTATE_MOREDATA = -3,
USERINFOSTATE_INVALIDARG = -2,
USERINFOSTATE_UNKNOWN = -1,
USERINFOSTATE_ABSENT = 0,
USERINFOSTATE_PRESENT = 1,
} USERINFOSTATE;
typedef enum tagINSTALLLEVEL
{
INSTALLLEVEL_DEFAULT = 0,
@ -137,15 +146,17 @@ typedef enum tagINSTALLTYPE
#define MAX_FEATURE_CHARS 38
typedef INT (CALLBACK *INSTALLUI_HANDLERA)(LPVOID pvContext, UINT iMessageType,
LPCSTR szMessage);
typedef INT (CALLBACK *INSTALLUI_HANDLERW)(LPVOID pvContext, UINT iMessageType,
LPCWSTR szMessage);
typedef INT (CALLBACK *INSTALLUI_HANDLERA)(LPVOID, UINT, LPCSTR);
typedef INT (CALLBACK *INSTALLUI_HANDLERW)(LPVOID, UINT, LPCWSTR);
UINT WINAPI MsiAdvertiseProductA(LPCSTR, LPCSTR, LPCSTR, LANGID);
UINT WINAPI MsiAdvertiseProductW(LPCWSTR, LPCWSTR, LPCWSTR, LANGID);
#define MsiAdvertiseProduct WINELIB_NAME_AW(MsiAdvertiseProduct)
UINT WINAPI MsiAdvertiseProductExA(LPCSTR, LPCSTR, LPCSTR, LANGID, DWORD, DWORD);
UINT WINAPI MsiAdvertiseProductExW(LPCWSTR, LPCWSTR, LPCWSTR, LANGID, DWORD, DWORD);
#define MsiAdvertiseProductEx WINELIB_NAME_AW(MsiAdvertiseProductEx)
UINT WINAPI MsiInstallProductA(LPCSTR, LPCSTR);
UINT WINAPI MsiInstallProductW(LPCWSTR, LPCWSTR);
#define MsiInstallProduct WINELIB_NAME_AW(MsiInstallProduct)
@ -158,8 +169,8 @@ UINT WINAPI MsiApplyPatchA(LPCSTR, LPCSTR, INSTALLTYPE, LPCSTR);
UINT WINAPI MsiApplyPatchW(LPCWSTR, LPCWSTR, INSTALLTYPE, LPCWSTR);
#define MsiApplyPatch WINELIB_NAME_AW(MsiApplyPatch)
UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid);
UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid);
UINT WINAPI MsiEnumProductsA(DWORD, LPSTR);
UINT WINAPI MsiEnumProductsW(DWORD, LPWSTR);
#define MsiEnumProducts WINELIB_NAME_AW(MsiEnumProducts)
UINT WINAPI MsiEnumFeaturesA(LPCSTR, DWORD, LPSTR, LPSTR);
@ -198,6 +209,12 @@ UINT WINAPI MsiSummaryInfoGetPropertyA(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPSTR
UINT WINAPI MsiSummaryInfoGetPropertyW(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPWSTR,DWORD*);
#define MsiSummaryInfoGetProperty WINELIB_NAME_AW(MsiSummaryInfoGetProperty)
UINT WINAPI MsiSummaryInfoPersist(MSIHANDLE);
UINT WINAPI MsiSummaryInfoSetPropertyA(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPSTR);
UINT WINAPI MsiSummaryInfoSetPropertyW(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPWSTR);
#define MsiSummaryInfoSetProperty WINELIB_NAME_AW(MsiSummaryInfoSetProperty)
UINT WINAPI MsiProvideComponentFromDescriptorA(LPCSTR,LPSTR,DWORD*,DWORD*);
UINT WINAPI MsiProvideComponentFromDescriptorW(LPCWSTR,LPWSTR,DWORD*,DWORD*);
#define MsiProvideComponentFromDescriptor WINELIB_NAME_AW(MsiProvideComponentFromDescriptor)
@ -218,20 +235,24 @@ INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR);
INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR);
#define MsiQueryProductState WINELIB_NAME_AW(MsiQueryProductState)
UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState);
UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState);
UINT WINAPI MsiConfigureProductA(LPCSTR, int, INSTALLSTATE);
UINT WINAPI MsiConfigureProductW(LPCWSTR, int, INSTALLSTATE);
#define MsiConfigureProduct WINELIB_NAME_AW(MsiConfigureProduct);
UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer);
UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer);
UINT WINAPI MsiConfigureProductExA(LPCSTR, int, INSTALLSTATE, LPCSTR);
UINT WINAPI MsiConfigureProductExW(LPCWSTR, int, INSTALLSTATE, LPCWSTR);
#define MsiConfigureProductEx WINELIB_NAME_AW(MsiConfigureProductEx);
UINT WINAPI MsiGetProductCodeA(LPCSTR, LPSTR);
UINT WINAPI MsiGetProductCodeW(LPCWSTR, LPWSTR);
#define MsiGetProductCode WINELIB_NAME_AW(MsiGetProductCode)
UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, LPSTR szBuffer, DWORD *pcchValueBuf);
UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szBuffer, DWORD *pcchValueBuf);
UINT WINAPI MsiGetProductInfoA(LPCSTR, LPCSTR, LPSTR, DWORD *);
UINT WINAPI MsiGetProductInfoW(LPCWSTR, LPCWSTR, LPWSTR, DWORD *);
#define MsiGetProductInfo WINELIB_NAME_AW(MsiGetProductInfo)
UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes);
UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes);
UINT WINAPI MsiEnableLogA(DWORD, LPCSTR, DWORD);
UINT WINAPI MsiEnableLogW(DWORD, LPCWSTR, DWORD);
#define MsiEnableLog WINELIB_NAME_AW(MsiEnableLog)
INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA, DWORD, LPVOID);
@ -242,15 +263,53 @@ INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR, LPCSTR, LPSTR, DWORD*);
INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR, LPCWSTR, LPWSTR, DWORD*);
#define MsiGetComponentPath WINELIB_NAME_AW(MsiGetComponentPath)
INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature);
INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature);
INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR, LPCSTR);
INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR, LPCWSTR);
#define MsiQueryFeatureState WINELIB_NAME_AW(MsiQueryFeatureState)
/**
* Non Unicode
*/
UINT WINAPI MsiGetFeatureUsageA(LPCSTR, LPCSTR, DWORD*, WORD*);
UINT WINAPI MsiGetFeatureUsageW(LPCWSTR, LPCWSTR, DWORD*, WORD*);
#define MsiGetFeatureUsage WINELIB_NAME_AW(MsiGetFeatureUsage)
UINT WINAPI MsiEnumRelatedProductsA(LPCSTR, DWORD, DWORD, LPSTR);
UINT WINAPI MsiEnumRelatedProductsW(LPCWSTR, DWORD, DWORD, LPWSTR);
#define MsiEnumRelatedProducts WINELIB_NAME_AW(MsiEnumRelatedProducts)
UINT WINAPI MsiProvideAssemblyA(LPCSTR, LPCSTR, DWORD, DWORD, LPSTR, DWORD*);
UINT WINAPI MsiProvideAssemblyW(LPCWSTR, LPCWSTR, DWORD, DWORD, LPWSTR, DWORD*);
#define MsiProvideAssembly WINELIB_NAME_AW(MsiProvideAssembly)
UINT WINAPI MsiEnumComponentQualifiersA(LPSTR, DWORD, LPSTR, DWORD*, LPSTR, DWORD*);
UINT WINAPI MsiEnumComponentQualifiersW(LPWSTR, DWORD, LPWSTR, DWORD*, LPWSTR, DWORD*);
#define MsiEnumComponentQualifiers WINELIB_NAME_AW(MsiEnumComponentQualifiers)
UINT WINAPI MsiGetFileVersionA(LPCSTR, LPSTR, DWORD*, LPSTR, DWORD*);
UINT WINAPI MsiGetFileVersionW(LPCWSTR, LPWSTR, DWORD*, LPWSTR, DWORD*);
#define MsiGetFileVersion WINELIB_NAME_AW(MsiGetFileVersion)
UINT WINAPI MsiMessageBoxA(HWND, LPCSTR, LPCSTR, UINT, WORD, DWORD);
UINT WINAPI MsiMessageBoxW(HWND, LPCWSTR, LPCWSTR, UINT, WORD, DWORD);
#define MsiMessageBox WINELIB_NAME_AW(MsiMessageBox)
UINT WINAPI MsiProvideQualifiedComponentExA(LPCSTR, LPCSTR, DWORD, LPSTR, DWORD, DWORD, LPSTR, DWORD*);
UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR, LPCWSTR, DWORD, LPWSTR, DWORD, DWORD, LPWSTR, DWORD*);
#define MsiProvideQualifiedComponentEx WINELIB_NAME_AW(MsiProvideQualifiedComponentEx)
UINT WINAPI MsiProvideQualifiedComponentA(LPCSTR, LPCSTR, DWORD, LPSTR, DWORD*);
UINT WINAPI MsiProvideQualifiedComponentW(LPCWSTR, LPCWSTR, DWORD, LPWSTR, DWORD*);
#define MsiProvideQualifiedComponent WINELIB_NAME_AW(MsiProvideQualifiedComponent)
USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR, LPSTR, DWORD*, LPSTR, DWORD*, LPSTR, DWORD*);
USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR, LPWSTR, DWORD*, LPWSTR, DWORD*, LPWSTR, DWORD*);
#define MsiGetUserInfo WINELIB_NAME_AW(MsiGetUserInfo)
UINT WINAPI MsiCollectUserInfoA( LPCSTR );
UINT WINAPI MsiCollectUserInfoW( LPCWSTR );
#define MsiCollectUserInfo WINELIB_NAME_AW(MsiCollectUserInfo)
/* Non Unicode */
UINT WINAPI MsiCloseHandle(MSIHANDLE);
UINT WINAPI MsiCloseAllHandles();
UINT WINAPI MsiCloseAllHandles(void);
INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL, HWND*);
#ifdef __cplusplus

View 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 */

View file

@ -8,15 +8,21 @@ EXTRALIBS = -luuid $(LIBUNICODE)
C_SRCS = \
action.c \
appsearch.c \
create.c \
custom.c \
dialog.c \
distinct.c \
format.c \
handle.c \
insert.c \
msi.c \
msiquery.c \
order.c \
package.c \
preview.c \
record.c \
registry.c \
regsvr.c \
select.c \
string.c \
@ -26,7 +32,7 @@ C_SRCS = \
update.c \
where.c
RC_SRCS = version.rc
RC_SRCS = msi.rc
EXTRA_SRCS = sql.y cond.y
EXTRA_OBJS = sql.tab.o cond.tab.o

File diff suppressed because it is too large Load diff

151
reactos/lib/msi/action.h Normal file
View 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
View 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

View file

@ -1,40 +1,99 @@
#ifndef BISON_COND_TAB_H
# define BISON_COND_TAB_H
#ifndef YYSTYPE
typedef union
{
struct cond_str str;
LPWSTR string;
INT value;
comp_int fn_comp_int;
comp_str fn_comp_str;
comp_m1 fn_comp_m1;
comp_m2 fn_comp_m2;
} yystype;
# define YYSTYPE yystype
# define YYSTYPE_IS_TRIVIAL 1
#endif
# define COND_SPACE 257
# define COND_EOF 258
# define COND_OR 259
# define COND_AND 260
# define COND_NOT 261
# define COND_LT 262
# define COND_GT 263
# define COND_EQ 264
# define COND_LPAR 265
# define COND_RPAR 266
# define COND_TILDA 267
# define COND_PERCENT 268
# define COND_DOLLARS 269
# define COND_QUESTION 270
# define COND_AMPER 271
# define COND_EXCLAM 272
# define COND_IDENT 273
# define COND_NUMBER 274
# define COND_LITER 275
# define COND_ERROR 276
#endif /* not BISON_COND_TAB_H */
/* A Bison parser, made by GNU Bison 1.875b. */
/* Skeleton parser for Yacc-like parsing with Bison,
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* As a special exception, when this file is copied by Bison into a
Bison output file, you may use that output file without restriction.
This special exception was added by the Free Software Foundation
in version 1.24 of Bison. */
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
/* Put the tokens into the symbol table, so that GDB and other debuggers
know about them. */
enum yytokentype {
COND_SPACE = 258,
COND_EOF = 259,
COND_OR = 260,
COND_AND = 261,
COND_NOT = 262,
COND_LT = 263,
COND_GT = 264,
COND_EQ = 265,
COND_LPAR = 266,
COND_RPAR = 267,
COND_TILDA = 268,
COND_PERCENT = 269,
COND_DOLLARS = 270,
COND_QUESTION = 271,
COND_AMPER = 272,
COND_EXCLAM = 273,
COND_IDENT = 274,
COND_NUMBER = 275,
COND_LITER = 276,
COND_ERROR = 277
};
#endif
#define COND_SPACE 258
#define COND_EOF 259
#define COND_OR 260
#define COND_AND 261
#define COND_NOT 262
#define COND_LT 263
#define COND_GT 264
#define COND_EQ 265
#define COND_LPAR 266
#define COND_RPAR 267
#define COND_TILDA 268
#define COND_PERCENT 269
#define COND_DOLLARS 270
#define COND_QUESTION 271
#define COND_AMPER 272
#define COND_EXCLAM 273
#define COND_IDENT 274
#define COND_NUMBER 275
#define COND_LITER 276
#define COND_ERROR 277
#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
#line 106 "./cond.y"
typedef union YYSTYPE {
struct cond_str str;
LPWSTR string;
INT value;
comp_int fn_comp_int;
comp_str fn_comp_str;
comp_m1 fn_comp_m1;
comp_m2 fn_comp_m2;
} YYSTYPE;
/* Line 1252 of yacc.c. */
#line 91 "cond.tab.h"
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
# define YYSTYPE_IS_TRIVIAL 1
#endif

View file

@ -181,7 +181,7 @@ term:
}
| value_s
{
$$ = atoiW($1);
$$ = $1[0] ? MSICONDITION_TRUE : MSICONDITION_FALSE;
}
| value_i comp_op_i value_i
{
@ -448,14 +448,22 @@ symbol_s:
{
DWORD sz;
COND_input* cond = (COND_input*) info;
$$ = HeapAlloc( GetProcessHeap(), 0, 0x100*sizeof (WCHAR) );
/* Lookup the identifier */
sz=0x100;
if (MSI_GetPropertyW(cond->package,$1,$$,&sz) != ERROR_SUCCESS)
sz = 0;
MSI_GetPropertyW(cond->package, $1, NULL, &sz);
if (sz == 0)
{
$$[0]=0;
$$ = HeapAlloc( GetProcessHeap(), 0 ,sizeof(WCHAR));
$$[0] = 0;
}
else
{
sz ++;
$$ = HeapAlloc( GetProcessHeap(), 0, sz*sizeof (WCHAR) );
/* Lookup the identifier */
MSI_GetPropertyW(cond->package,$1,$$,&sz);
}
HeapFree( GetProcessHeap(), 0, $1 );
}
@ -731,7 +739,7 @@ MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition )
TRACE("Evaluating %s\n",debugstr_w(szCondition));
if( !COND_parse( &cond ) )
if( szCondition && !COND_parse( &cond ) )
r = cond.result;
else
r = MSICONDITION_ERROR;
@ -767,8 +775,7 @@ MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szConditio
r = MsiEvaluateConditionW( hInstall, szwCond );
if( szwCond )
HeapFree( GetProcessHeap(), 0, szwCond );
HeapFree( GetProcessHeap(), 0, szwCond );
return r;
}

View file

@ -188,11 +188,12 @@ static UINT CREATE_get_column_info( struct tagMSIVIEW *view,
return ERROR_FUNCTION_FAILED;
}
static UINT CREATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
static UINT CREATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
MSIRECORD *rec)
{
MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
TRACE("%p %d %ld\n", cv, eModifyMode, hrec );
TRACE("%p %d %p\n", cv, eModifyMode, rec );
return ERROR_FUNCTION_FAILED;
}

794
reactos/lib/msi/custom.c Normal file
View 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
View 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 );
}

View file

@ -178,8 +178,7 @@ static UINT DISTINCT_close( struct tagMSIVIEW *view )
if( !dv->table )
return ERROR_FUNCTION_FAILED;
if( dv->translation )
HeapFree( GetProcessHeap(), 0, dv->translation );
HeapFree( GetProcessHeap(), 0, dv->translation );
dv->translation = NULL;
dv->row_count = 0;
@ -218,16 +217,17 @@ static UINT DISTINCT_get_column_info( struct tagMSIVIEW *view,
return dv->table->ops->get_column_info( dv->table, n, name, type );
}
static UINT DISTINCT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
static UINT DISTINCT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
MSIRECORD *rec )
{
MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
TRACE("%p %d %ld\n", dv, eModifyMode, hrec );
TRACE("%p %d %p\n", dv, eModifyMode, rec );
if( !dv->table )
return ERROR_FUNCTION_FAILED;
return dv->table->ops->modify( dv->table, eModifyMode, hrec );
return dv->table->ops->modify( dv->table, eModifyMode, rec );
}
static UINT DISTINCT_delete( struct tagMSIVIEW *view )
@ -239,8 +239,7 @@ static UINT DISTINCT_delete( struct tagMSIVIEW *view )
if( dv->table )
dv->table->ops->delete( dv->table );
if( dv->translation )
HeapFree( GetProcessHeap(), 0, dv->translation );
HeapFree( GetProcessHeap(), 0, dv->translation );
msiobj_release( &dv->db->hdr );
HeapFree( GetProcessHeap(), 0, dv );

583
reactos/lib/msi/format.c Normal file
View 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;
}

View file

@ -157,7 +157,7 @@ void msiobj_addref( MSIOBJECTHDR *info )
return;
}
info->refcount++;
InterlockedIncrement(&info->refcount);
}
void msiobj_lock( MSIOBJECTHDR *info )
@ -185,12 +185,12 @@ int msiobj_release( MSIOBJECTHDR *info )
return -1;
}
ret = info->refcount--;
if (info->refcount == 0)
ret = InterlockedDecrement( &info->refcount );
if( ret==0 )
{
if( info->destructor )
if( info->destructor )
info->destructor( info );
HeapFree( GetProcessHeap(), 0, info );
HeapFree( GetProcessHeap(), 0, info );
TRACE("object %p destroyed\n", info);
}

View file

@ -44,7 +44,7 @@ typedef struct tagMSIINSERTVIEW
MSIDATABASE *db;
BOOL bIsTemp;
MSIVIEW *sv;
value_list *vals; /* looks like these may be ignored... */
value_list *vals;
} MSIINSERTVIEW;
static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
@ -56,11 +56,62 @@ static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT
return ERROR_FUNCTION_FAILED;
}
/*
* INSERT_merge_record
*
* Merge a value_list and a record to create a second record.
* Replace wildcard entries in the valuelist with values from the record
*/
static MSIRECORD *INSERT_merge_record( UINT fields, value_list *vl, MSIRECORD *rec )
{
MSIRECORD *merged;
DWORD wildcard_count = 1, i;
const WCHAR *str;
merged = MSI_CreateRecord( fields );
for( i=1; i <= fields; i++ )
{
if( !vl )
{
TRACE("Not enough elements in the list to insert\n");
goto err;
}
switch( vl->val->type )
{
case EXPR_SVAL:
TRACE("field %ld -> %s\n", i, debugstr_w(vl->val->u.sval));
MSI_RecordSetStringW( merged, i, vl->val->u.sval );
break;
case EXPR_IVAL:
MSI_RecordSetInteger( merged, i, vl->val->u.ival );
break;
case EXPR_WILDCARD:
if( !rec )
goto err;
if( MSI_RecordIsNull( rec, wildcard_count ) )
goto err;
str = MSI_RecordGetString( rec, wildcard_count );
MSI_RecordSetStringW( merged, i, str );
wildcard_count++;
break;
default:
ERR("Unknown expression type %d\n", vl->val->type);
}
vl = vl->next;
}
return merged;
err:
msiobj_release( &merged->hdr );
return NULL;
}
static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record )
{
MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
UINT n, type, val, r, row, col_count = 0;
MSIVIEW *sv;
MSIRECORD *values = NULL;
TRACE("%p %p\n", iv, record );
@ -77,12 +128,13 @@ static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record )
if( r )
goto err;
n = MSI_RecordGetFieldCount( record );
if( n != col_count )
{
ERR("Number of fields do not match\n");
/*
* Merge the wildcard values into the list of values provided
* in the query, and create a record containing both.
*/
values = INSERT_merge_record( col_count, iv->vals, record );
if( !values )
goto err;
}
row = -1;
r = sv->ops->insert_row( sv, &row );
@ -98,12 +150,12 @@ static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record )
if( type & MSITYPE_STRING )
{
const WCHAR *str = MSI_RecordGetString( record, n );
const WCHAR *str = MSI_RecordGetString( values, n );
val = msi_addstringW( iv->db->strings, 0, str, -1, 1 );
}
else
{
val = MSI_RecordGetInteger( record, n );
val = MSI_RecordGetInteger( values, n );
val |= 0x8000;
}
r = sv->ops->set_int( sv, row, n, val );
@ -112,6 +164,9 @@ static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record )
}
err:
if( values )
msiobj_release( &values->hdr );
return ERROR_SUCCESS;
}
@ -159,11 +214,11 @@ static UINT INSERT_get_column_info( struct tagMSIVIEW *view,
return sv->ops->get_column_info( sv, n, name, type );
}
static UINT INSERT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
static UINT INSERT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIRECORD *rec)
{
MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
TRACE("%p %d %ld\n", iv, eModifyMode, hrec );
TRACE("%p %d %p\n", iv, eModifyMode, rec );
return ERROR_FUNCTION_FAILED;
}

File diff suppressed because it is too large Load diff

30
reactos/lib/msi/msi.rc Normal file
View 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"

View file

@ -6,8 +6,8 @@
6 stdcall MsiAdvertiseProductW(wstr wstr wstr long)
7 stdcall MsiCloseAllHandles()
8 stdcall MsiCloseHandle(long)
9 stub MsiCollectUserInfoA
10 stub MsiCollectUserInfoW
9 stdcall MsiCollectUserInfoA(str)
10 stdcall MsiCollectUserInfoW(wstr)
11 stub MsiConfigureFeatureA
12 stub MsiConfigureFeatureFromDescriptorA
13 stub MsiConfigureFeatureFromDescriptorW
@ -32,7 +32,7 @@
32 stdcall MsiDatabaseOpenViewW(long wstr ptr)
33 stdcall MsiDoActionA(long str)
34 stdcall MsiDoActionW(long wstr)
35 stub MsiEnableUIPreview
35 stdcall MsiEnableUIPreview(long ptr)
36 stdcall MsiEnumClientsA(str long ptr)
37 stdcall MsiEnumClientsW(wstr long ptr)
38 stdcall MsiEnumComponentQualifiersA(str long str ptr str ptr)
@ -79,7 +79,7 @@
79 stdcall MsiGetTargetPathA(long str ptr ptr)
80 stdcall MsiGetTargetPathW(long wstr ptr ptr)
81 stub MsiGetUserInfoA
82 stub MsiGetUserInfoW
82 stdcall MsiGetUserInfoW(wstr ptr ptr ptr ptr ptr ptr)
83 stub MsiInstallMissingComponentA
84 stub MsiInstallMissingComponentW
85 stub MsiInstallMissingFileA
@ -94,10 +94,10 @@
94 stdcall MsiOpenPackageW(wstr ptr)
95 stdcall MsiOpenProductA(str ptr)
96 stdcall MsiOpenProductW(wstr ptr)
97 stub MsiPreviewBillboardA
98 stub MsiPreviewBillboardW
99 stub MsiPreviewDialogA
100 stub MsiPreviewDialogW
97 stdcall MsiPreviewBillboardA(long str str)
98 stdcall MsiPreviewBillboardW(long wstr wstr)
99 stdcall MsiPreviewDialogA(long str)
100 stdcall MsiPreviewDialogW(long wstr)
101 stub MsiProcessAdvertiseScriptA
102 stub MsiProcessAdvertiseScriptW
103 stdcall MsiProcessMessage(long long long)
@ -148,9 +148,9 @@
148 stdcall MsiSummaryInfoGetPropertyA(long long ptr ptr ptr ptr ptr)
149 stdcall MsiSummaryInfoGetPropertyCount(long ptr)
150 stdcall MsiSummaryInfoGetPropertyW(long long ptr ptr ptr ptr ptr)
151 stub MsiSummaryInfoPersist
152 stub MsiSummaryInfoSetPropertyA
153 stub MsiSummaryInfoSetPropertyW
151 stdcall MsiSummaryInfoPersist(long)
152 stdcall MsiSummaryInfoSetPropertyA(long long long long ptr str)
153 stdcall MsiSummaryInfoSetPropertyW(long long long long ptr wstr)
154 stub MsiUseFeatureA
155 stub MsiUseFeatureW
156 stdcall MsiVerifyPackageA(str)
@ -186,21 +186,21 @@
186 stub MsiCreateTransformSummaryInfoW
187 stub MsiQueryFeatureStateFromDescriptorA
188 stub MsiQueryFeatureStateFromDescriptorW
189 stub MsiConfigureProductExA
190 stub MsiConfigureProductExW
189 stdcall MsiConfigureProductExA(str long long str)
190 stdcall MsiConfigureProductExW(wstr long long wstr)
191 stub MsiInvalidateFeatureCache
192 stub MsiUseFeatureExA
193 stub MsiUseFeatureExW
193 stdcall MsiUseFeatureExW(wstr wstr long long)
194 stdcall MsiGetFileVersionA(str str ptr str ptr)
195 stdcall MsiGetFileVersionW(wstr wstr ptr wstr ptr)
196 stdcall MsiLoadStringA(long long long long long)
197 stdcall MsiLoadStringW(long long long long long)
198 stdcall MsiMessageBoxA(long long long long long long)
199 stdcall MsiMessageBoxW(long long long long long long)
200 stub MsiDecomposeDescriptorA
201 stub MsiDecomposeDescriptorW
200 stdcall MsiDecomposeDescriptorA(str ptr ptr ptr ptr)
201 stdcall MsiDecomposeDescriptorW(wstr ptr ptr ptr ptr)
202 stub MsiProvideQualifiedComponentExA
203 stub MsiProvideQualifiedComponentExW
203 stdcall MsiProvideQualifiedComponentExW(wstr wstr long wstr long long ptr ptr)
204 stdcall MsiEnumRelatedProductsA(str long long ptr)
205 stdcall MsiEnumRelatedProductsW(wstr long long ptr)
206 stub MsiSetFeatureAttributesA
@ -213,13 +213,13 @@
213 stub MsiSourceListForceResolutionW
214 stub MsiIsProductElevatedA
215 stub MsiIsProductElevatedW
216 stub MsiGetShortcutTargetA
217 stub MsiGetShortcutTargetW
216 stdcall MsiGetShortcutTargetA(str ptr ptr ptr)
217 stdcall MsiGetShortcutTargetW(wstr ptr ptr ptr)
218 stub MsiGetFileHashA
219 stub MsiGetFileHashW
220 stub MsiEnumComponentCostsA
221 stub MsiEnumComponentCostsW
222 stub MsiCreateAndVerifyInstallerDirectory
222 stdcall MsiCreateAndVerifyInstallerDirectory()
223 stdcall MsiGetFileSignatureInformationA(str long ptr ptr ptr)
224 stdcall MsiGetFileSignatureInformationW(wstr long ptr ptr ptr)
225 stdcall MsiProvideAssemblyA(str str long long str ptr)

33
reactos/lib/msi/msi_En.rc Normal file
View 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"
}

View file

@ -1,7 +1,7 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002 Mike McCormack for CodeWeavers
* Copyright 2002-2005 Mike McCormack for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -53,7 +53,7 @@ struct tagMSIOBJECTHDR
{
UINT magic;
UINT type;
UINT refcount;
DWORD refcount;
msihandledestructor destructor;
struct tagMSIOBJECTHDR *next;
struct tagMSIOBJECTHDR *prev;
@ -161,7 +161,7 @@ typedef struct tagMSIVIEWOPS
/*
* modify - not yet implemented properly
*/
UINT (*modify)( struct tagMSIVIEW *, MSIMODIFY, MSIHANDLE );
UINT (*modify)( struct tagMSIVIEW *, MSIMODIFY, MSIRECORD * );
/*
* delete - destroys the structure completely
@ -182,6 +182,9 @@ struct tagMSIVIEW
MSIVIEWOPS *ops;
};
struct msi_dialog_tag;
typedef struct msi_dialog_tag msi_dialog;
typedef struct tagMSIPACKAGE
{
MSIOBJECTHDR hdr;
@ -196,14 +199,37 @@ typedef struct tagMSIPACKAGE
UINT loaded_files;
LPWSTR ActionFormat;
LPWSTR LastAction;
LPWSTR *DeferredAction;
UINT DeferredActionCount;
LPWSTR *CommitAction;
UINT CommitActionCount;
struct tagMSIRUNNINGACTION *RunningAction;
UINT RunningActionCount;
LPWSTR PackagePath;
UINT CurrentInstallState;
msi_dialog *dialog;
LPWSTR next_dialog;
} MSIPACKAGE;
typedef struct tagMSIPREVIEW
{
MSIOBJECTHDR hdr;
MSIPACKAGE *package;
msi_dialog *dialog;
} MSIPREVIEW;
#define MSIHANDLETYPE_ANY 0
#define MSIHANDLETYPE_DATABASE 1
#define MSIHANDLETYPE_SUMMARYINFO 2
#define MSIHANDLETYPE_VIEW 3
#define MSIHANDLETYPE_RECORD 4
#define MSIHANDLETYPE_PACKAGE 5
#define MSIHANDLETYPE_PREVIEW 6
#define MSI_MAJORVERSION 2
#define MSI_MINORVERSION 0
@ -212,7 +238,7 @@ typedef struct tagMSIPACKAGE
#define GUID_SIZE 39
#define MSIHANDLE_MAGIC 0x4d434923
#define MSIMAXHANDLES 0x80
#define MSIMAXHANDLES 0xf0
#define MSISUMINFO_OFFSET 0x30LL
@ -271,9 +297,11 @@ extern BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name );
extern UINT read_raw_stream_data( MSIDATABASE*, LPCWSTR stname,
USHORT **pdata, UINT *psz );
/* action internals */
extern UINT ACTION_DoTopLevelINSTALL( MSIPACKAGE *, LPCWSTR, LPCWSTR );
extern void ACTION_remove_tracked_tempfiles( MSIPACKAGE* );
extern void ACTION_free_package_structures( MSIPACKAGE* );
extern UINT ACTION_DialogBox( MSIPACKAGE*, LPCWSTR);
/* record internals */
extern UINT MSI_RecordSetIStream( MSIRECORD *, unsigned int, IStream *);
@ -296,6 +324,9 @@ extern void enum_stream_names( IStorage *stg );
/* database internals */
extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** );
extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** );
extern UINT MSI_OpenQuery( MSIDATABASE *, MSIQUERY **, LPCWSTR, ... );
typedef UINT (*record_func)( MSIRECORD *rec, LPVOID param );
extern UINT MSI_IterateRecords( MSIQUERY *, DWORD *, record_func, LPVOID );
/* view internals */
extern UINT MSI_ViewExecute( MSIQUERY*, MSIRECORD * );
@ -303,26 +334,51 @@ extern UINT MSI_ViewFetch( MSIQUERY*, MSIRECORD ** );
extern UINT MSI_ViewClose( MSIQUERY* );
/* package internals */
extern UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE ** );
extern UINT MSI_SetTargetPathW( MSIPACKAGE *, LPCWSTR, LPCWSTR);
extern MSIPACKAGE *MSI_CreatePackage( MSIDATABASE * );
extern UINT MSI_OpenPackageW( LPCWSTR szPackage, MSIPACKAGE ** );
extern UINT MSI_SetTargetPathW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
extern INT MSI_ProcessMessage( MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD* );
extern UINT MSI_GetPropertyW( MSIPACKAGE *, LPCWSTR, LPWSTR, DWORD*);
extern INT MSI_ProcessMessage( MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD * );
extern UINT MSI_GetPropertyW( MSIPACKAGE *, LPCWSTR, LPWSTR, DWORD * );
extern MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *, LPCWSTR );
extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
extern UINT MSI_GetComponentStateW(MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE *);
extern UINT MSI_GetFeatureStateW(MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE *);
extern UINT MSI_GetComponentStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE * );
extern UINT MSI_GetFeatureStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE * );
/* for deformating */
extern UINT MSI_FormatRecordW(MSIPACKAGE* package, MSIRECORD* record,
LPWSTR buffer, DWORD *size);
/* registry data encoding/decoding functions */
BOOL unsquash_guid(LPCWSTR in, LPWSTR out);
BOOL squash_guid(LPCWSTR in, LPWSTR out);
BOOL encode_base85_guid(GUID *,LPWSTR);
BOOL decode_base85_guid(LPCWSTR,GUID*);
extern BOOL unsquash_guid(LPCWSTR in, LPWSTR out);
extern BOOL squash_guid(LPCWSTR in, LPWSTR out);
extern BOOL encode_base85_guid(GUID *,LPWSTR);
extern BOOL decode_base85_guid(LPCWSTR,GUID*);
extern UINT MSIREG_OpenUninstallKey(LPCWSTR szProduct, HKEY* key, BOOL create);
extern UINT MSIREG_OpenUserProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create);
extern UINT MSIREG_OpenFeatures(HKEY* key);
extern UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
extern UINT MSIREG_OpenComponents(HKEY* key);
extern UINT MSIREG_OpenComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create);
extern UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create);
extern UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
/* msi dialog interface */
typedef VOID (*msi_dialog_event_handler)( MSIPACKAGE*, LPCWSTR, LPCWSTR, msi_dialog* );
extern msi_dialog *msi_dialog_create( MSIPACKAGE*, LPCWSTR, msi_dialog_event_handler );
extern UINT msi_dialog_run_message_loop( msi_dialog* );
extern void msi_dialog_end_dialog( msi_dialog* );
extern void msi_dialog_check_messages( msi_dialog*, HANDLE );
extern void msi_dialog_do_preview( msi_dialog* );
extern void msi_dialog_destroy( msi_dialog* );
extern void msi_dialog_register_class( void );
extern void msi_dialog_unregister_class( void );
/* UI globals */
extern INSTALLUILEVEL gUILevel;
extern HWND gUIhwnd;
extern INSTALLUI_HANDLERA gUIHandler;
extern INSTALLUI_HANDLERA gUIHandlerA;
extern INSTALLUI_HANDLERW gUIHandlerW;
extern DWORD gUIFilter;
extern LPVOID gUIContext;
extern WCHAR gszLogFile[MAX_PATH];

View file

@ -38,30 +38,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(msi);
#if 0
typedef struct tagMSIQUERY
{
MSIOBJECTHDR hdr;
MSIVIEW *view;
UINT row;
MSIDATABASE *db;
} MSIQUERY;
#endif
UINT WINAPI MsiDatabaseIsTablePersistentA(
MSIHANDLE hDatabase, LPSTR szTableName)
{
FIXME("%lx %s\n", hDatabase, debugstr_a(szTableName));
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiDatabaseIsTablePersistentW(
MSIHANDLE hDatabase, LPWSTR szTableName)
{
FIXME("%lx %s\n", hDatabase, debugstr_w(szTableName));
return ERROR_CALL_NOT_IMPLEMENTED;
}
void MSI_CloseView( MSIOBJECTHDR *arg )
{
MSIQUERY *query = (MSIQUERY*) arg;
@ -158,6 +134,87 @@ UINT MSI_DatabaseOpenViewW(MSIDATABASE *db,
return r;
}
UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
{
LPWSTR szQuery;
LPCWSTR p;
UINT sz, rc;
va_list va;
/* figure out how much space we need to allocate */
va_start(va, fmt);
sz = strlenW(fmt) + 1;
p = fmt;
while (*p)
{
p = strchrW(p, '%');
if (!p)
break;
p++;
switch (*p)
{
case 's': /* a string */
sz += strlenW(va_arg(va,LPCWSTR));
break;
case 'd':
case 'i': /* an integer -2147483648 seems to be longest */
sz += 3*sizeof(int);
(void)va_arg(va,int);
break;
case '%': /* a single % - leave it alone */
break;
default:
FIXME("Unhandled character type %c\n",*p);
}
p++;
}
va_end(va);
/* construct the string */
szQuery = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));
va_start(va, fmt);
vsnprintfW(szQuery, sz, fmt, va);
va_end(va);
/* perform the query */
rc = MSI_DatabaseOpenViewW(db, szQuery, view);
HeapFree(GetProcessHeap(), 0, szQuery);
return rc;
}
UINT MSI_IterateRecords( MSIQUERY *view, DWORD *count,
record_func func, LPVOID param )
{
MSIRECORD *rec = NULL;
UINT r, n = 0, max = 0;
r = MSI_ViewExecute( view, NULL );
if( r != ERROR_SUCCESS )
return r;
if( count )
max = *count;
/* iterate a query */
for( n = 0; (max == 0) || (n < max); n++ )
{
r = MSI_ViewFetch( view, &rec );
if( r != ERROR_SUCCESS )
break;
r = func( rec, param );
msiobj_release( &rec->hdr );
if( r != ERROR_SUCCESS )
break;
}
MSI_ViewClose( view );
if( count )
*count = n;
return r;
}
UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
LPCWSTR szQuery, MSIHANDLE *phView)
{
@ -358,7 +415,10 @@ UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
}
}
msiobj_lock( &rec->hdr );
ret = MSI_ViewExecute( query, rec );
msiobj_unlock( &rec->hdr );
out:
if( query )
msiobj_release( &query->hdr );
@ -370,10 +430,10 @@ out:
UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
{
MSIVIEW *view;
MSIQUERY *query;
MSIHANDLE handle;
UINT ret, i, count = 0, type;
MSIVIEW *view = NULL;
MSIQUERY *query = NULL;
MSIRECORD *rec = NULL;
UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type;
LPWSTR name;
TRACE("%ld %d %p\n", hView, info, hRec);
@ -384,34 +444,82 @@ UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hR
view = query->view;
if( !view )
return ERROR_FUNCTION_FAILED;
goto out;
if( !view->ops->get_dimensions )
return ERROR_FUNCTION_FAILED;
goto out;
ret = view->ops->get_dimensions( view, NULL, &count );
if( ret )
return ret;
r = view->ops->get_dimensions( view, NULL, &count );
if( r )
goto out;
if( !count )
return ERROR_INVALID_PARAMETER;
{
r = ERROR_INVALID_PARAMETER;
goto out;
}
handle = MsiCreateRecord( count );
if( !handle )
rec = MSI_CreateRecord( count );
if( !rec )
return ERROR_FUNCTION_FAILED;
for( i=0; i<count; i++ )
{
name = NULL;
ret = view->ops->get_column_info( view, i+1, &name, &type );
if( ret != ERROR_SUCCESS )
r = view->ops->get_column_info( view, i+1, &name, &type );
if( r != ERROR_SUCCESS )
continue;
MsiRecordSetStringW( handle, i+1, name );
MSI_RecordSetStringW( rec, i+1, name );
HeapFree( GetProcessHeap(), 0, name );
}
*hRec = handle;
*hRec = alloc_msihandle( &rec->hdr );
return ERROR_SUCCESS;
out:
if( query )
msiobj_release( &query->hdr );
if( rec )
msiobj_release( &rec->hdr );
return r;
}
UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode,
MSIHANDLE hRecord)
{
MSIVIEW *view = NULL;
MSIQUERY *query = NULL;
MSIRECORD *rec = NULL;
UINT r = ERROR_FUNCTION_FAILED;
TRACE("%ld %x %ld\n", hView, eModifyMode, hRecord);
query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
if( !query )
return ERROR_INVALID_HANDLE;
view = query->view;
if( !view )
goto out;
if( !view->ops->modify )
goto out;
rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
if( !rec )
{
r = ERROR_INVALID_HANDLE;
goto out;
}
r = view->ops->modify( view, eModifyMode, rec );
out:
if( query )
msiobj_release( &query->hdr );
if( rec )
msiobj_release( &rec->hdr );
return r;
}
UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb,
@ -461,6 +569,8 @@ UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
/* FIXME: unlock the database */
msiobj_release( &db->hdr );
return r;
}
@ -478,9 +588,16 @@ UINT WINAPI MsiDatabaseGetPrimaryKeysW(MSIHANDLE hdb,
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiViewModify(MSIHANDLE hView, MSIMODIFY eModifyMode, MSIHANDLE
hRecord)
UINT WINAPI MsiDatabaseIsTablePersistentA(
MSIHANDLE hDatabase, LPSTR szTableName)
{
FIXME("%ld %x %ld\n",hView, eModifyMode, hRecord);
FIXME("%lx %s\n", hDatabase, debugstr_a(szTableName));
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiDatabaseIsTablePersistentW(
MSIHANDLE hDatabase, LPWSTR szTableName)
{
FIXME("%lx %s\n", hDatabase, debugstr_w(szTableName));
return ERROR_CALL_NOT_IMPLEMENTED;
}

View file

@ -187,8 +187,7 @@ static UINT ORDER_close( struct tagMSIVIEW *view )
if( !ov->table )
return ERROR_FUNCTION_FAILED;
if( ov->reorder )
HeapFree( GetProcessHeap(), 0, ov->reorder );
HeapFree( GetProcessHeap(), 0, ov->reorder );
ov->reorder = NULL;
return ov->table->ops->close( ov->table );
@ -219,16 +218,17 @@ static UINT ORDER_get_column_info( struct tagMSIVIEW *view,
return ov->table->ops->get_column_info( ov->table, n, name, type );
}
static UINT ORDER_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
static UINT ORDER_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
MSIRECORD *rec )
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
TRACE("%p %d %ld\n", ov, eModifyMode, hrec );
TRACE("%p %d %p\n", ov, eModifyMode, rec );
if( !ov->table )
return ERROR_FUNCTION_FAILED;
return ov->table->ops->modify( ov->table, eModifyMode, hrec );
return ov->table->ops->modify( ov->table, eModifyMode, rec );
}
static UINT ORDER_delete( struct tagMSIVIEW *view )
@ -240,8 +240,7 @@ static UINT ORDER_delete( struct tagMSIVIEW *view )
if( ov->table )
ov->table->ops->delete( ov->table );
if( ov->reorder )
HeapFree( GetProcessHeap(), 0, ov->reorder );
HeapFree( GetProcessHeap(), 0, ov->reorder );
ov->reorder = NULL;
msiobj_release( &ov->db->hdr );

View file

@ -53,36 +53,13 @@ void MSI_FreePackage( MSIOBJECTHDR *arg)
{
MSIPACKAGE *package= (MSIPACKAGE*) arg;
ACTION_remove_tracked_tempfiles(package);
if( package->dialog )
msi_dialog_destroy( package->dialog );
ACTION_free_package_structures(package);
msiobj_release( &package->db->hdr );
}
UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
{
LPWSTR szwPack = NULL;
UINT len, ret;
TRACE("%s %p\n",debugstr_a(szPackage), phPackage);
if( szPackage )
{
len = MultiByteToWideChar( CP_ACP, 0, szPackage, -1, NULL, 0 );
szwPack = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
if( szwPack )
MultiByteToWideChar( CP_ACP, 0, szPackage, -1, szwPack, len );
}
ret = MsiOpenPackageW( szwPack, phPackage );
if( szwPack )
HeapFree( GetProcessHeap(), 0, szwPack );
return ret;
}
static const UINT clone_properties(MSIDATABASE *db)
{
MSIQUERY * view = NULL;
@ -102,7 +79,7 @@ static const UINT clone_properties(MSIDATABASE *db)
'`','_','P','r','o','p','e','r','t','y','`',' ',
'(','`','_','P','r','o','p','e','r','t','y','`',',',
'`','V','a','l','u','e','`',')',' ',
'V','A','L','U','E','S',' ','(','?',')',0};
'V','A','L','U','E','S',' ','(','?',',','?',')',0};
/* create the temporary properties table */
rc = MSI_DatabaseOpenViewW(db, CreateSql, &view);
@ -377,39 +354,18 @@ Privileged
ReleaseDC(0, dc);
}
UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db )
{
UINT rc;
MSIDATABASE *db = NULL;
static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
static const WCHAR szpi[] = {'%','i',0};
MSIPACKAGE *package = NULL;
WCHAR uilevel[10];
UINT ret = ERROR_FUNCTION_FAILED;
static const WCHAR OriginalDatabase[] =
{'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
static const WCHAR Database[] =
{'D','A','T','A','B','A','S','E',0};
static const WCHAR szpi[] = {'%','i',0};
static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
TRACE("%s %p\n",debugstr_w(szPackage), pPackage);
if (szPackage[0] == '#')
{
INT handle = atoiW(&szPackage[1]);
db = msihandle2msiinfo( handle , MSIHANDLETYPE_DATABASE);
}
else
{
rc = MSI_OpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db);
if (rc != ERROR_SUCCESS)
return ERROR_FUNCTION_FAILED;
}
TRACE("%p\n", db);
package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
MSI_FreePackage );
if (package)
if( package )
{
msiobj_addref( &db->hdr );
@ -424,35 +380,78 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
package->loaded_files = 0;
package->ActionFormat = NULL;
package->LastAction = NULL;
package->dialog = NULL;
package->next_dialog = NULL;
/* OK, here is where we do a slew of things to the database to
* prep for all that is to come as a package */
clone_properties(db);
set_installer_properties(package);
MSI_SetPropertyW(package, OriginalDatabase, szPackage);
MSI_SetPropertyW(package, Database, szPackage);
sprintfW(uilevel,szpi,gUILevel);
MSI_SetPropertyW(package, szLevel, uilevel);
msiobj_addref( &package->hdr );
*pPackage = package;
ret = ERROR_SUCCESS;
}
if( package )
msiobj_release( &package->hdr );
if( db )
msiobj_release( &db->hdr );
return ret;
return package;
}
UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
{
MSIDATABASE *db = NULL;
MSIPACKAGE *package;
MSIHANDLE handle;
TRACE("%s %p\n", debugstr_w(szPackage), pPackage);
if( szPackage[0] == '#' )
{
handle = atoiW(&szPackage[1]);
db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
if( !db )
return ERROR_INVALID_HANDLE;
}
else
{
UINT r = MSI_OpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db);
if( r != ERROR_SUCCESS )
return r;
}
package = MSI_CreatePackage( db );
msiobj_release( &db->hdr );
if( !package )
return ERROR_FUNCTION_FAILED;
/*
* FIXME: I don't think this is right. Maybe we should be storing the
* name of the database in the MSIDATABASE structure and fetching this
* info from there, or maybe this is only relevant to cached databases.
*/
if( szPackage[0] != '#' )
{
static const WCHAR OriginalDatabase[] =
{'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0};
MSI_SetPropertyW( package, OriginalDatabase, szPackage );
MSI_SetPropertyW( package, Database, szPackage );
}
*pPackage = package;
return ERROR_SUCCESS;
}
UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
{
MSIPACKAGE *package = NULL;
UINT ret;
TRACE("%s %08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage);
if( dwOptions )
FIXME("dwOptions %08lx not supported\n", dwOptions);
ret = MSI_OpenPackageW( szPackage, &package);
if( ret == ERROR_SUCCESS )
{
@ -462,16 +461,34 @@ UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
return ret;
}
UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
{
FIXME("%s 0x%08lx %p\n",debugstr_a(szPackage), dwOptions, phPackage);
return ERROR_CALL_NOT_IMPLEMENTED;
return MsiOpenPackageExW( szPackage, 0, phPackage );
}
UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
{
FIXME("%s 0x%08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage);
return ERROR_CALL_NOT_IMPLEMENTED;
LPWSTR szwPack = NULL;
UINT len, ret;
if( szPackage )
{
len = MultiByteToWideChar( CP_ACP, 0, szPackage, -1, NULL, 0 );
szwPack = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
if( szwPack )
MultiByteToWideChar( CP_ACP, 0, szPackage, -1, szwPack, len );
}
ret = MsiOpenPackageExW( szwPack, dwOptions, phPackage );
HeapFree( GetProcessHeap(), 0, szwPack );
return ret;
}
UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
{
return MsiOpenPackageExA( szPackage, 0, phPackage );
}
MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
@ -555,7 +572,7 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
HeapFree(GetProcessHeap(),0,tmp);
}
TRACE("(%p %lx %lx %s)\n",gUIHandler, gUIFilter, log_type,
TRACE("(%p %lx %lx %s)\n",gUIHandlerA, gUIFilter, log_type,
debugstr_w(message));
/* convert it to ASCII */
@ -565,9 +582,9 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
WideCharToMultiByte( CP_ACP, 0, message, -1,
msg, len, NULL, NULL );
if (gUIHandler && (gUIFilter & log_type))
if (gUIHandlerA && (gUIFilter & log_type))
{
rc = gUIHandler(gUIContext,eMessageType,msg);
rc = gUIHandlerA(gUIContext,eMessageType,msg);
}
if ((!rc) && (gszLogFile[0]) && !((eMessageType & 0xff000000) ==
@ -649,10 +666,8 @@ UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
hr = MsiSetPropertyW( hInstall, szwName, szwValue);
end:
if( szwName )
HeapFree( GetProcessHeap(), 0, szwName );
if( szwValue )
HeapFree( GetProcessHeap(), 0, szwValue );
HeapFree( GetProcessHeap(), 0, szwName );
HeapFree( GetProcessHeap(), 0, szwValue );
return hr;
}
@ -667,7 +682,7 @@ UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
{'I','N','S','E','R','T',' ','i','n','t','o',' ','`','_','P','r','o','p'
,'e','r','t','y','`',' ','(','`','_','P','r','o','p','e','r','t','y','`'
,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S'
,' ','(','?',')',0};
,' ','(','?',',','?',')',0};
static const WCHAR Update[]=
{'U','P','D','A','T','E',' ','_','P','r','o','p','e'
,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','='
@ -848,7 +863,12 @@ UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf,
return ERROR_INVALID_HANDLE;
ret = MSI_GetPropertyA(package, szName, szValueBuf, pchValueBuf );
msiobj_release( &package->hdr );
return ret;
/* MsiGetProperty does not return error codes on missing properties */
if (ret!= ERROR_MORE_DATA)
return ERROR_SUCCESS;
else
return ret;
}
@ -870,5 +890,10 @@ UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName,
return ERROR_INVALID_HANDLE;
ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf );
msiobj_release( &package->hdr );
return ret;
/* MsiGetProperty does not return error codes on missing properties */
if (ret!= ERROR_MORE_DATA)
return ERROR_SUCCESS;
else
return ret;
}

164
reactos/lib/msi/preview.c Normal file
View 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;
}

View file

@ -454,12 +454,20 @@ UINT MSI_RecordSetStringA( MSIRECORD *rec, unsigned int iField, LPCSTR szValue )
if( iField > rec->count )
return ERROR_INVALID_FIELD;
len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
MultiByteToWideChar( CP_ACP, 0, szValue, -1, str, len );
MSI_FreeField( &rec->fields[iField] );
rec->fields[iField].type = MSIFIELD_WSTR;
rec->fields[iField].u.szwVal = str;
if( szValue && szValue[0] )
{
len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
MultiByteToWideChar( CP_ACP, 0, szValue, -1, str, len );
rec->fields[iField].type = MSIFIELD_WSTR;
rec->fields[iField].u.szwVal = str;
}
else
{
rec->fields[iField].type = MSIFIELD_NULL;
rec->fields[iField].u.szwVal = NULL;
}
return 0;
}
@ -491,13 +499,22 @@ UINT MSI_RecordSetStringW( MSIRECORD *rec, unsigned int iField, LPCWSTR szValue
if( iField > rec->count )
return ERROR_INVALID_FIELD;
len = lstrlenW(szValue) + 1;
str = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR));
lstrcpyW( str, szValue );
MSI_FreeField( &rec->fields[iField] );
rec->fields[iField].type = MSIFIELD_WSTR;
rec->fields[iField].u.szwVal = str;
if( szValue && szValue[0] )
{
len = lstrlenW(szValue) + 1;
str = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR));
lstrcpyW( str, szValue );
rec->fields[iField].type = MSIFIELD_WSTR;
rec->fields[iField].u.szwVal = str;
}
else
{
rec->fields[iField].type = MSIFIELD_NULL;
rec->fields[iField].u.szwVal = NULL;
}
return 0;
}
@ -520,18 +537,6 @@ UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, unsigned int iField, LPCWSTR
return ret;
}
UINT WINAPI MsiFormatRecordA(MSIHANDLE hInstall, MSIHANDLE hRecord, LPSTR szResult, DWORD *sz)
{
FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiFormatRecordW(MSIHANDLE hInstall, MSIHANDLE hRecord, LPWSTR szResult, DWORD *sz)
{
FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
return ERROR_CALL_NOT_IMPLEMENTED;
}
/* read the data in a file into an IStream */
UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
{

486
reactos/lib/msi/registry.c Normal file
View 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;
}

View file

@ -168,16 +168,17 @@ static UINT SELECT_get_column_info( struct tagMSIVIEW *view,
return sv->table->ops->get_column_info( sv->table, n, name, type );
}
static UINT SELECT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
static UINT SELECT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
MSIRECORD *rec )
{
MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
TRACE("%p %d %ld\n", sv, eModifyMode, hrec );
TRACE("%p %d %p\n", sv, eModifyMode, rec );
if( !sv->table )
return ERROR_FUNCTION_FAILED;
return sv->table->ops->modify( sv->table, eModifyMode, hrec );
return sv->table->ops->modify( sv->table, eModifyMode, rec );
}
static UINT SELECT_delete( struct tagMSIVIEW *view )

View file

@ -564,7 +564,7 @@ union yyalloc
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 23
/* YYLAST -- Last index in YYTABLE. */
#define YYLAST 125
#define YYLAST 126
/* YYNTOKENS -- Number of terminals. */
#define YYNTOKENS 147
@ -663,7 +663,7 @@ static const short yyrhs[] =
-1, 168, 57, 163, -1, 168, 85, 163, -1, 168,
78, 163, -1, 168, 54, 163, -1, 168, 89, 163,
-1, 168, 73, 92, -1, 168, 73, 90, 92, -1,
168, -1, 167, -1, 167, -1, 164, 24, 167, -1,
168, -1, 167, -1, 167, -1, 167, 24, 164, -1,
166, -1, 166, 24, 165, -1, 169, 45, 167, -1,
70, -1, 88, 70, -1, 120, -1, 138, -1, 169,
-1, 170, 39, 171, -1, 171, -1, 171, -1, 66,
@ -678,8 +678,8 @@ static const unsigned short yyrline[] =
290, 294, 298, 302, 306, 313, 324, 335, 339, 353,
371, 384, 397, 404, 415, 434, 438, 442, 446, 450,
454, 458, 462, 466, 470, 474, 478, 485, 486, 490,
502, 518, 519, 528, 544, 548, 552, 556, 563, 570,
574, 581, 588, 592
502, 517, 518, 527, 543, 547, 551, 555, 562, 569,
573, 580, 587, 591
};
#endif
@ -787,8 +787,8 @@ static const unsigned char yydefact[] =
15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 55, 12, 11, 25, 0, 17, 0,
35, 37, 38, 56, 39, 48, 36, 43, 47, 40,
0, 45, 42, 41, 44, 19, 0, 49, 46, 0,
6, 50, 7
0, 45, 42, 41, 44, 19, 0, 49, 46, 6,
0, 7, 50
};
/* YYDEFGOTO[NTERM-NUM]. */
@ -801,30 +801,30 @@ static const yysigned_char yydefgoto[] =
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
#define YYPACT_NINF -105
#define YYPACT_NINF -104
static const yysigned_char yypact[] =
{
-30, -104, -46, -34, -51, 21, -105, -105, -105, -105,
-77, -51, -51, -52, -105, -105, -105, -25, 7, -1,
2, -79, -105, -105, 31, -33, -32, -25, -51, -105,
-52, -51, -51, -52, -51, -52, -105, -88, -105, -105,
-82, 33, 14, -105, -48, -15, -17, -43, -50, -50,
-51, -64, 13, -51, -2, -6, -105, -105, -105, -105,
-105, -105, 6, -9, -49, -50, -4, 26, -105, -4,
-105, -105, 24, -105, -105, -105, -105, -17, -52, 25,
-105, 9, 19, -7, -50, -50, -59, -59, -59, -44,
-59, -59, -59, -105, -105, -105, -105, -3, -105, -64,
-105, -4, -4, 73, -105, -105, -105, -105, -105, -105,
22, -105, -105, -105, -105, -105, -19, -105, -105, -64,
1, -105, -105
-30, -103, -52, -34, -51, 21, -104, -104, -104, -104,
-70, -51, -51, -57, -104, -104, -104, -26, 11, -6,
-1, -69, -104, -104, 32, -25, -15, -26, -51, -104,
-57, -51, -51, -57, -51, -57, -104, -71, -104, -104,
-67, 47, 27, -104, -36, -19, -17, -29, -53, -53,
-51, -63, 26, -51, 17, -10, -104, -104, -104, -104,
-104, -104, 5, 7, -35, -53, -4, 35, -104, -4,
-104, -104, 37, -104, -104, -104, -104, -17, -57, 39,
-104, 18, 28, -7, -53, -53, -60, -60, -60, -73,
-60, -60, -60, -104, -104, -104, -104, 4, -104, -63,
-104, -4, -4, 77, -104, -104, -104, -104, -104, -104,
25, -104, -104, -104, -104, -104, 8, 95, -104, 0,
-63, -104, -104
};
/* YYPGOTO[NTERM-NUM]. */
static const yysigned_char yypgoto[] =
{
-105, -105, -105, -105, -105, -105, -105, 42, -105, -105,
-105, -105, -105, -5, 97, -31, 18, -105, 75, -105,
-41, 30, 10, 85, 8
-104, -104, -104, -104, -104, -104, -104, 44, -104, -104,
-104, -104, -104, 1, 96, -38, 14, 6, 75, -104,
-43, -37, 9, 12, 84
};
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
@ -834,36 +834,36 @@ static const yysigned_char yypgoto[] =
#define YYTABLE_NINF -64
static const yysigned_char yytable[] =
{
84, 1, 55, 84, 13, 119, 71, 14, 27, 53,
75, 71, 22, 18, 14, 14, 14, 11, 69, 22,
22, 23, 24, 18, 72, 38, 12, 28, 43, 72,
47, 30, 14, 65, 83, 32, 22, 2, 31, 39,
18, -61, 42, 18, 46, 18, 110, 33, 111, 48,
34, 35, 56, 101, 102, 49, 73, 50, 117, 51,
42, 103, 52, 77, 57, 58, 15, 64, 16, 16,
16, 86, 76, 95, 74, 78, 59, 79, 121, 74,
87, 81, 3, 88, 15, 82, 16, 54, 18, 21,
85, 120, 80, 85, 93, 96, 25, 26, 60, 89,
4, 98, 99, 100, 90, 107, 109, 115, 112, 113,
114, 91, -63, 37, 118, 92, 106, 108, 108, 94,
108, 108, 108, 122, 36, 70
84, 1, 55, 84, 13, 53, 14, 71, 75, 14,
71, 69, 18, 14, 27, 14, 21, 110, 11, 111,
12, 23, 18, 25, 26, 72, 28, 83, 72, 24,
65, 38, 14, 31, 43, 30, 47, 2, -61, 18,
37, 42, 18, 46, 18, 32, 101, 102, 33, 106,
108, 108, 56, 108, 108, 108, 117, 73, 34, 42,
103, 15, 77, 16, 57, 58, 48, 16, 35, 16,
49, 50, 51, 79, 52, 74, 59, 117, 74, 95,
86, 64, 3, 54, 15, 76, 16, 18, 22, 87,
85, 80, 88, 85, 78, 22, 22, 81, 60, 82,
4, 107, 109, 100, 112, 113, 114, 93, 89, 96,
98, 99, 22, 90, 115, 39, -63, 118, 119, 120,
91, 94, 121, 36, 92, 70, 122
};
static const unsigned char yycheck[] =
{
7, 31, 19, 7, 38, 24, 70, 66, 13, 24,
51, 70, 4, 3, 66, 66, 66, 121, 49, 11,
12, 0, 99, 13, 88, 30, 72, 52, 33, 88,
35, 24, 66, 83, 65, 114, 28, 67, 39, 31,
30, 39, 32, 33, 34, 35, 90, 16, 92, 137,
83, 83, 69, 84, 85, 137, 120, 24, 99, 45,
50, 120, 110, 53, 81, 82, 118, 110, 120, 120,
120, 45, 59, 78, 138, 77, 93, 83, 119, 138,
54, 90, 112, 57, 118, 134, 120, 102, 78, 4,
97, 110, 86, 97, 70, 70, 11, 12, 115, 73,
130, 92, 83, 110, 78, 87, 88, 110, 90, 91,
92, 85, 39, 28, 92, 89, 86, 87, 88, 77,
90, 91, 92, 122, 27, 50
7, 31, 19, 7, 38, 24, 66, 70, 51, 66,
70, 49, 3, 66, 13, 66, 4, 90, 121, 92,
72, 0, 13, 11, 12, 88, 52, 65, 88, 99,
83, 30, 66, 39, 33, 24, 35, 67, 39, 30,
28, 32, 33, 34, 35, 114, 84, 85, 16, 86,
87, 88, 69, 90, 91, 92, 99, 120, 83, 50,
120, 118, 53, 120, 81, 82, 137, 120, 83, 120,
137, 24, 45, 83, 110, 138, 93, 120, 138, 78,
45, 110, 112, 102, 118, 59, 120, 78, 4, 54,
97, 86, 57, 97, 77, 11, 12, 90, 115, 134,
130, 87, 88, 110, 90, 91, 92, 70, 73, 70,
92, 83, 28, 78, 110, 31, 39, 92, 110, 24,
85, 77, 122, 27, 89, 50, 120
};
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@ -881,8 +881,8 @@ static const unsigned char yystos[] =
86, 90, 134, 162, 7, 97, 45, 54, 57, 73,
78, 85, 89, 70, 154, 160, 70, 157, 92, 83,
110, 162, 162, 120, 163, 167, 168, 163, 168, 163,
90, 92, 163, 163, 163, 110, 164, 167, 92, 24,
110, 167, 122
90, 92, 163, 163, 163, 110, 164, 167, 92, 110,
24, 122, 164
};
#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
@ -1944,16 +1944,15 @@ yyreduce:
vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
if( vals )
{
vals->val = yyvsp[0].expr;
vals->next = NULL;
vals->val = yyvsp[-2].expr;
vals->next = yyvsp[0].val_list;
}
yyvsp[-2].val_list->next = vals;
yyval.val_list = yyvsp[-2].val_list;
yyval.val_list = vals;
;}
break;
case 52:
#line 520 "./sql.y"
#line 519 "./sql.y"
{
yyvsp[-2].update_col_info.col_list->next = yyvsp[0].update_col_info.col_list;
yyvsp[-2].update_col_info.val_list->next = yyvsp[0].update_col_info.val_list;
@ -1962,7 +1961,7 @@ yyreduce:
break;
case 53:
#line 529 "./sql.y"
#line 528 "./sql.y"
{
yyval.update_col_info.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.col_list );
if( !yyval.update_col_info.col_list )
@ -1978,70 +1977,70 @@ yyreduce:
break;
case 54:
#line 545 "./sql.y"
#line 544 "./sql.y"
{
yyval.expr = EXPR_ival( &yyvsp[0].str, 1 );
;}
break;
case 55:
#line 549 "./sql.y"
#line 548 "./sql.y"
{
yyval.expr = EXPR_ival( &yyvsp[0].str, -1 );
;}
break;
case 56:
#line 553 "./sql.y"
#line 552 "./sql.y"
{
yyval.expr = EXPR_sval( &yyvsp[0].str );
;}
break;
case 57:
#line 557 "./sql.y"
#line 556 "./sql.y"
{
yyval.expr = EXPR_wildcard();
;}
break;
case 58:
#line 564 "./sql.y"
#line 563 "./sql.y"
{
yyval.expr = EXPR_column( yyvsp[0].string );
;}
break;
case 59:
#line 571 "./sql.y"
#line 570 "./sql.y"
{
yyval.string = yyvsp[0].string; /* FIXME */
;}
break;
case 60:
#line 575 "./sql.y"
#line 574 "./sql.y"
{
yyval.string = yyvsp[0].string;
;}
break;
case 61:
#line 582 "./sql.y"
#line 581 "./sql.y"
{
yyval.string = yyvsp[0].string;
;}
break;
case 62:
#line 589 "./sql.y"
#line 588 "./sql.y"
{
yyval.string = SQL_getstring( &yyvsp[0].str );
;}
break;
case 63:
#line 593 "./sql.y"
#line 592 "./sql.y"
{
yyval.string = SQL_getstring( &yyvsp[0].str );
;}
@ -2051,7 +2050,7 @@ yyreduce:
}
/* Line 999 of yacc.c. */
#line 2055 "sql.tab.c"
#line 2054 "sql.tab.c"
yyvsp -= yylen;
yyssp -= yylen;
@ -2257,7 +2256,7 @@ yyreturn:
}
#line 598 "./sql.y"
#line 597 "./sql.y"
int SQL_lex( void *SQL_lval, SQL_input *sql)

View file

@ -499,18 +499,17 @@ constlist:
}
$$ = vals;
}
| constlist TK_COMMA const_val
| const_val TK_COMMA constlist
{
value_list *vals;
vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
if( vals )
{
vals->val = $3;
vals->next = NULL;
vals->val = $1;
vals->next = $3;
}
$1->next = vals;
$$ = $1;
$$ = vals;
}
;

View file

@ -393,8 +393,7 @@ UINT msi_string2idA( string_table *st, LPCSTR buffer, UINT *id )
MultiByteToWideChar( st->codepage, 0, buffer, -1, str, sz );
r = msi_string2idW( st, str, id );
if( str )
HeapFree( GetProcessHeap(), 0, str );
HeapFree( GetProcessHeap(), 0, str );
return r;
}

View file

@ -67,8 +67,7 @@ UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase,
ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, phSummaryInfo);
if( szwDatabase )
HeapFree( GetProcessHeap(), 0, szwDatabase );
HeapFree( GetProcessHeap(), 0, szwDatabase );
return ret;
}
@ -225,9 +224,72 @@ UINT WINAPI MsiSummaryInfoGetPropertyW(
MSIHANDLE hSummaryInfo, UINT uiProperty, UINT *puiDataType, INT *piValue,
FILETIME *pftValue, LPWSTR szValueBuf, DWORD *pcchValueBuf)
{
FIXME("%ld %d %p %p %p %p %p\n",
MSISUMMARYINFO *suminfo;
HRESULT r;
PROPSPEC spec;
PROPVARIANT var;
TRACE("%ld %d %p %p %p %p %p\n",
hSummaryInfo, uiProperty, puiDataType, piValue,
pftValue, szValueBuf, pcchValueBuf);
suminfo = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO );
if( !suminfo )
return ERROR_INVALID_HANDLE;
spec.ulKind = PRSPEC_PROPID;
spec.u.propid = uiProperty;
r = IPropertyStorage_ReadMultiple( suminfo->propstg, 1, &spec, &var);
if( FAILED(r) )
return ERROR_FUNCTION_FAILED;
if( puiDataType )
*puiDataType = var.vt;
switch( var.vt )
{
case VT_I4:
if( piValue )
*piValue = var.u.lVal;
break;
case VT_LPSTR:
if( pcchValueBuf && szValueBuf )
{
MultiByteToWideChar(CP_ACP, 0, var.u.pszVal, -1, szValueBuf,
*pcchValueBuf );
*pcchValueBuf = lstrlenA( var.u.pszVal );
}
break;
case VT_FILETIME:
if( pftValue )
memcpy(pftValue, &var.u.filetime, sizeof (FILETIME) );
break;
case VT_EMPTY:
break;
default:
FIXME("Unknown property variant type\n");
break;
}
return ERROR_SUCCESS;
}
UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE hSummaryInfo, UINT uiProperty,
UINT uiDataType, INT iValue,
FILETIME* pftValue, LPSTR szValue)
{
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE hSummaryInfo, UINT uiProperty,
UINT uiDataType, INT iValue,
FILETIME* pftValue, LPWSTR szValue)
{
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiSummaryInfoPersist(MSIHANDLE hSummaryInfo)
{
return ERROR_CALL_NOT_IMPLEMENTED;
}

View file

@ -196,8 +196,8 @@ void enum_stream_names( IStorage *stg )
if( FAILED( r ) || !count )
break;
decode_streamname( stat.pwcsName, name );
ERR("stream %2ld -> %s %s\n", n,
debugstr_w(stat.pwcsName), debugstr_w(name) );
TRACE("stream %2ld -> %s %s\n", n,
debugstr_w(stat.pwcsName), debugstr_w(name) );
n++;
}
@ -356,12 +356,12 @@ static UINT write_stream_data( IStorage *stg, LPCWSTR stname,
encname = encode_streamname(TRUE, stname );
r = IStorage_OpenStream( stg, encname, NULL,
STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &stm);
HeapFree( GetProcessHeap(), 0, encname );
if( FAILED(r) )
{
r = IStorage_CreateStream( stg, encname,
STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
}
HeapFree( GetProcessHeap(), 0, encname );
if( FAILED( r ) )
{
ERR("open stream failed r = %08lx\n",r);
@ -408,7 +408,7 @@ UINT read_table_from_storage( MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable)
TRACE("%s\n",debugstr_w(name));
/* non-existing tables should be interpretted as empty tables */
/* nonexistent tables should be interpreted as empty tables */
t = HeapAlloc( GetProcessHeap(), 0,
sizeof (MSITABLE) + lstrlenW(name)*sizeof (WCHAR) );
if( !t )
@ -747,10 +747,8 @@ UINT load_string_table( MSIDATABASE *db )
ret = ERROR_SUCCESS;
end:
if( pool )
HeapFree( GetProcessHeap(), 0, pool );
if( data )
HeapFree( GetProcessHeap(), 0, data );
HeapFree( GetProcessHeap(), 0, pool );
HeapFree( GetProcessHeap(), 0, data );
return ret;
}
@ -830,10 +828,8 @@ UINT save_string_table( MSIDATABASE *db )
ret = ERROR_SUCCESS;
err:
if( data )
HeapFree( GetProcessHeap(), 0, data );
if( pool )
HeapFree( GetProcessHeap(), 0, pool );
HeapFree( GetProcessHeap(), 0, data );
HeapFree( GetProcessHeap(), 0, pool );
return ret;
}
@ -1288,9 +1284,10 @@ static UINT TABLE_get_column_info( struct tagMSIVIEW *view,
return ERROR_SUCCESS;
}
static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
MSIRECORD *rec)
{
FIXME("%p %d %ld\n", view, eModifyMode, hrec );
FIXME("%p %d %p\n", view, eModifyMode, rec );
return ERROR_CALL_NOT_IMPLEMENTED;
}

View file

@ -151,11 +151,12 @@ static UINT UPDATE_get_column_info( struct tagMSIVIEW *view,
return wv->ops->get_column_info( wv, n, name, type );
}
static UINT UPDATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
static UINT UPDATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
MSIRECORD *rec )
{
MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
TRACE("%p %d %ld\n", uv, eModifyMode, hrec );
TRACE("%p %d %p\n", uv, eModifyMode, rec );
return ERROR_FUNCTION_FAILED;
}

View file

@ -269,8 +269,7 @@ static UINT WHERE_close( struct tagMSIVIEW *view )
if( !wv->table )
return ERROR_FUNCTION_FAILED;
if( wv->reorder )
HeapFree( GetProcessHeap(), 0, wv->reorder );
HeapFree( GetProcessHeap(), 0, wv->reorder );
wv->reorder = NULL;
return wv->table->ops->close( wv->table );
@ -308,16 +307,17 @@ static UINT WHERE_get_column_info( struct tagMSIVIEW *view,
return wv->table->ops->get_column_info( wv->table, n, name, type );
}
static UINT WHERE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
static UINT WHERE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
MSIRECORD *rec )
{
MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
TRACE("%p %d %ld\n", wv, eModifyMode, hrec );
TRACE("%p %d %p\n", wv, eModifyMode, rec );
if( !wv->table )
return ERROR_FUNCTION_FAILED;
return wv->table->ops->modify( wv->table, eModifyMode, hrec );
return wv->table->ops->modify( wv->table, eModifyMode, rec );
}
static UINT WHERE_delete( struct tagMSIVIEW *view )
@ -329,8 +329,7 @@ static UINT WHERE_delete( struct tagMSIVIEW *view )
if( wv->table )
wv->table->ops->delete( wv->table );
if( wv->reorder )
HeapFree( GetProcessHeap(), 0, wv->reorder );
HeapFree( GetProcessHeap(), 0, wv->reorder );
wv->reorder = NULL;
wv->row_count = 0;