mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
Sync to Wine-20050628:
Mike McCormack <mike@codeweavers.com> - Repaint the area behind the "transparent" text control when it changes. - Implement transparency in the text control. - Make the MSI icon control work. - Make tabs work in msi dialogs. - Added support for the MSI MaskEdit control. - Use a richedit control for license text. - Fix radio button groups. Don't add the WS_GROUP style to every window. - Use standard lists in the event subscription code. - Take the dialog frame into account when calculating the dialog size. - Use MSI_QueryGetRecord in one more place. - Create a helper function to fetch a single record from a query. - More -Wmissing-declarations and -Wwrite-strings warning fixes. - Get rid of some redundant parser types. - Use the new helper function MSI_QueryGetRecord. - Use MSI_RecordGetString in more actions. - Use MSI_RecordGetString where possible. - Fixes for -Wmissing-declarations and -Wwrite-strings warnings. - Remove some unused code. - Add and correct some function declarations. - Improve number parsing and avoid unicode.h. - avoid unicode.h - add a missing function prototype - Create a stub implementation for MsiViewGetError. - Remove more types from the parser. - Test and fix the size of stream fields in a record. - Clean up headers and make some functions static. Marcus Meissner <meissner@suse.de> - Use a simpler expression for the "RichEdit20W" string to workaround compiler bug. - Remove cszbs from msi/action.h. Aric Stewart <aric@codeweavers.com> Mike McCormack <mike@codeweavers.com> - Allow dialog controls to subscribe to installer events. - Fix handling of checkbox properties. - Implement dialog events and hook up the dialog code. Aric Stewart <aric@codeweavers.com> - Break out all the file related actions and helper functions into files.c - Break out all the top level apis into install.c. - Break out all the class registration actions into classes.c. This includes RegisterClassInfo, RegisterProgIds, RegisterExtensions and RegisterMIMETypes. - Break out all the helper functions into helpers.c. - Added module upgrade.c and implemented FindRelatedProducts. - A long overdue fix to MSI_SetTargetPath. This should fix an error with some installers that where unable to change the target path. - Add functions to add the User UpgradeCodes. - A simple cleanup to only track the temp file if we need to have it laying around because the action is going on asynchronously. Otherwise clean up the temp file as the action finishes. - Introduce really basic scripting of actions. This is primarily to get the order of execution of the action correct since some custom actions can be scripted and others are run during the script building phase. - Perform ExecuteAction at UILevel 2. - Rework CreateShortcuts to use MSI_IterateRecords. - Properly handle -1 as a registry key root. - Rework SelfRegModules to use MSI_IterateRecords. - Rework component, feature and file loading to use MSI_IterateRecords. - Rework RegisterFonts to use MSI_IterateRecords. - Rework WriteIniValues to use MSI_IterateRecords. - Rework PublishProduct to use MSI_IterateRecords. - Rework RegisterTypeLibraries to use MSI_IterateR - Rework LaunchConditions to use MSI_IterateRecord - Rework CostFinalize to use MSI_IterateRecords. - Rework WriteRegistryValues to use MSI_IterateRecords. - Rework CreateFolders to use MSI_IterateRecords. - Use MSI_IterateRecords for processing actions. Some whitespace cleanup and replace a comment block I did not want to remove. - Flesh out the remaining keys in RegisterProduct. - Extending upon Mike McCormack's cleanup to use MSI_RecordGetString. - Register the Product Version also. Also help plug some memory leaks pointed out by Mike McCormack. - Avoid a loop where a parent's parent refers to itself as its parent. - Added module upgrade.c and implemented FindRelatedProducts. - Set the Preselected property if appropriate (relevant to MigrateFeatureStates when implemented). - Write out Product Language and Product Icon to the registry. - Write out UpgradeCodes to the registry to allow for future upgrades. - Don't get caught in loops on parent progids. - Since multiple progids can refer to 1 class we need to check if that class is isntalled instead of just relying on having it set the InstallMe variable. - Add install_on_demand for Extension servers also. currently defaulting to TRUE. - Extension need to have 1 verb to mark the given progid to be installed. - Do not loop if a ProgId's Parent Index it itself. - Add a VersionIndIndex for tracking version independent fields for the ProgIds properly. - Print a message for skipped actions in ProcessExecSequence like in the UISequence. - Do not change a features state to Advertise if it explicitly disallows it. - For typelibs index 1 do not add \\1 to the path. This cleans up registry diffs with native MSI. - Register the FileType and correct short vs long path problems with InprocServer32. Also add install_on_demand boolean for future expansion. - First pass at writing out CurVer keys for ProgIds. Also print a message for the actions we skip. Lines up with native MSI output logs for ease of comparison. - A big rewrite of the whole RegisterClass, RegisterProgId, RegisterExtension and RegisterMIME actions. We now handle verbs properly, handle dependancies and such properly and keep track of what we need to register and what we do not properly. - Allow control events to return codes to halt the processing of event. Needed for the SetTargetPath Event. - Fix situations where TARGETDIR is set to a non \ terminated path. Fixes a few installers. - Redo how we extract files from a cabinet in order to dramatically improve performance, especially if picking and choosing files out of the cabinet. - Duplicate files should not fail if unable to get Destination Directory. - Use MSI_IterateRecords for DuplicateFiles. - Add UI messages to FindRelatedProducts. - Reduce unneeded includes. - A "1" is returned not a 1 for AssignmentType. Also as a bit more to the FIXME message. - Add Language to the values we can query with MsiGetProductInfo. - Correct a crash if the length buffer is NULL. - Locate where a buffer size is not being set and correctly handle the buffer size conversion from W to A (with help from Robert Shearman). - Make sure the TRACE statements do not spew garbage by using debugstr_wn. - Restrict deformating of nested index keys [[1]]. - Introduce the beginning of group deformating {}. - Implement the [!file] format to produce the short filename. Stefan Huehner <stefan@huehner.org> - Fix more -Wstrict-prototypes warnings. Francois Gouget <fgouget@free.fr> - Assorted spelling fixes. Dmitry Timoshkov <dmitry@codeweavers.com> - Make more of the OLE interface vtables const. svn path=/trunk/; revision=17034
This commit is contained in:
parent
0f766beac3
commit
4e23c74418
42 changed files with 7931 additions and 5507 deletions
10
reactos/include/wine/msvcrt/fcntl.h
Normal file
10
reactos/include/wine/msvcrt/fcntl.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#ifndef __WINE_MSVCRT_FCNTL_H
|
||||
#define __WINE_MSVCRT_FCNTL_H
|
||||
|
||||
/*
|
||||
* Compatibility header
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#endif /* __WINE_MSVCRT_FCNTL_H */
|
|
@ -4,21 +4,26 @@ SRCDIR = @srcdir@
|
|||
VPATH = @srcdir@
|
||||
MODULE = msi.dll
|
||||
IMPORTLIB = libmsi.$(IMPLIBEXT)
|
||||
IMPORTS = shell32 cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32
|
||||
IMPORTS = shell32 shlwapi cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32
|
||||
EXTRALIBS = -luuid $(LIBUNICODE)
|
||||
|
||||
C_SRCS = \
|
||||
action.c \
|
||||
appsearch.c \
|
||||
classes.c \
|
||||
create.c \
|
||||
custom.c \
|
||||
database.c \
|
||||
delete.c \
|
||||
dialog.c \
|
||||
distinct.c \
|
||||
events.c \
|
||||
files.c \
|
||||
format.c \
|
||||
handle.c \
|
||||
helpers.c \
|
||||
insert.c \
|
||||
install.c \
|
||||
msi.c \
|
||||
msiquery.c \
|
||||
order.c \
|
||||
|
@ -33,6 +38,7 @@ C_SRCS = \
|
|||
table.c \
|
||||
tokenize.c \
|
||||
update.c \
|
||||
upgrade.c \
|
||||
where.c
|
||||
|
||||
RC_SRCS = msi.rc
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,15 +18,17 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define IDENTIFIER_SIZE 96
|
||||
|
||||
typedef struct tagMSIFEATURE
|
||||
{
|
||||
WCHAR Feature[96];
|
||||
WCHAR Feature_Parent[96];
|
||||
WCHAR Feature[IDENTIFIER_SIZE];
|
||||
WCHAR Feature_Parent[IDENTIFIER_SIZE];
|
||||
WCHAR Title[0x100];
|
||||
WCHAR Description[0x100];
|
||||
INT Display;
|
||||
INT Level;
|
||||
WCHAR Directory[96];
|
||||
WCHAR Directory[IDENTIFIER_SIZE];
|
||||
INT Attributes;
|
||||
|
||||
INSTALLSTATE Installed;
|
||||
|
@ -40,12 +42,12 @@ typedef struct tagMSIFEATURE
|
|||
|
||||
typedef struct tagMSICOMPONENT
|
||||
{
|
||||
WCHAR Component[96];
|
||||
WCHAR ComponentId[96];
|
||||
WCHAR Directory[96];
|
||||
WCHAR Component[IDENTIFIER_SIZE];
|
||||
WCHAR ComponentId[IDENTIFIER_SIZE];
|
||||
WCHAR Directory[IDENTIFIER_SIZE];
|
||||
INT Attributes;
|
||||
WCHAR Condition[0x100];
|
||||
WCHAR KeyPath[96];
|
||||
WCHAR KeyPath[IDENTIFIER_SIZE];
|
||||
|
||||
INSTALLSTATE Installed;
|
||||
INSTALLSTATE ActionRequest;
|
||||
|
@ -56,6 +58,7 @@ typedef struct tagMSICOMPONENT
|
|||
INT RefCount;
|
||||
|
||||
LPWSTR FullKeypath;
|
||||
LPWSTR AdvertiseString;
|
||||
} MSICOMPONENT;
|
||||
|
||||
typedef struct tagMSIFOLDER
|
||||
|
@ -100,14 +103,117 @@ typedef struct tagMSIFILE
|
|||
BOOL Temporary;
|
||||
}MSIFILE;
|
||||
|
||||
typedef struct tagMSICLASS
|
||||
{
|
||||
WCHAR CLSID[IDENTIFIER_SIZE]; /* Primary Key */
|
||||
WCHAR Context[IDENTIFIER_SIZE]; /* Primary Key */
|
||||
INT ComponentIndex; /* Primary Key */
|
||||
INT ProgIDIndex;
|
||||
LPWSTR ProgIDText;
|
||||
LPWSTR Description;
|
||||
INT AppIDIndex;
|
||||
LPWSTR FileTypeMask;
|
||||
LPWSTR IconPath;
|
||||
LPWSTR DefInprocHandler;
|
||||
LPWSTR DefInprocHandler32;
|
||||
LPWSTR Argument;
|
||||
INT FeatureIndex;
|
||||
INT Attributes;
|
||||
/* not in the table, set during installation */
|
||||
BOOL Installed;
|
||||
} MSICLASS;
|
||||
|
||||
UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action);
|
||||
typedef struct tagMSIEXTENSION
|
||||
{
|
||||
WCHAR Extension[256]; /* Primary Key */
|
||||
INT ComponentIndex; /* Primary Key */
|
||||
INT ProgIDIndex;
|
||||
LPWSTR ProgIDText;
|
||||
INT MIMEIndex;
|
||||
INT FeatureIndex;
|
||||
/* not in the table, set during installation */
|
||||
BOOL Installed;
|
||||
INT VerbCount;
|
||||
INT Verbs[100]; /* yes hard coded limit, but realistically 100 verbs??? */
|
||||
} MSIEXTENSION;
|
||||
|
||||
typedef struct tagMSIPROGID
|
||||
{
|
||||
LPWSTR ProgID; /* Primary Key */
|
||||
INT ParentIndex;
|
||||
INT ClassIndex;
|
||||
LPWSTR Description;
|
||||
LPWSTR IconPath;
|
||||
/* not in the table, set during installation */
|
||||
BOOL InstallMe;
|
||||
INT CurVerIndex;
|
||||
INT VersionIndIndex;
|
||||
} MSIPROGID;
|
||||
|
||||
typedef struct tagMSIVERB
|
||||
{
|
||||
INT ExtensionIndex;
|
||||
LPWSTR Verb;
|
||||
INT Sequence;
|
||||
LPWSTR Command;
|
||||
LPWSTR Argument;
|
||||
} MSIVERB;
|
||||
|
||||
typedef struct tagMSIMIME
|
||||
{
|
||||
LPWSTR ContentType; /* Primary Key */
|
||||
INT ExtensionIndex;
|
||||
WCHAR CLSID[IDENTIFIER_SIZE];
|
||||
INT ClassIndex;
|
||||
/* not in the table, set during installation */
|
||||
BOOL InstallMe;
|
||||
} MSIMIME;
|
||||
|
||||
typedef struct tagMSIAPPID
|
||||
{
|
||||
WCHAR AppID[IDENTIFIER_SIZE]; /* Primary key */
|
||||
LPWSTR RemoteServerName;
|
||||
LPWSTR LocalServer;
|
||||
LPWSTR ServiceParameters;
|
||||
LPWSTR DllSurrogate;
|
||||
BOOL ActivateAtStorage;
|
||||
BOOL RunAsInteractiveUser;
|
||||
} MSIAPPID;
|
||||
|
||||
enum SCRIPTS {
|
||||
INSTALL_SCRIPT = 0,
|
||||
COMMIT_SCRIPT = 1,
|
||||
ROLLBACK_SCRIPT = 2,
|
||||
TOTAL_SCRIPTS = 3
|
||||
};
|
||||
|
||||
typedef struct tagMSISCRIPT
|
||||
{
|
||||
LPWSTR *Actions[TOTAL_SCRIPTS];
|
||||
UINT ActionCount[TOTAL_SCRIPTS];
|
||||
BOOL ExecuteSequenceRun;
|
||||
BOOL FindRelatedProductsRun;
|
||||
BOOL CurrentlyScripting;
|
||||
}MSISCRIPT;
|
||||
|
||||
|
||||
UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force);
|
||||
UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action);
|
||||
void ACTION_FinishCustomActions( MSIPACKAGE* package);
|
||||
UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action, BOOL execute);
|
||||
void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature);
|
||||
UINT ACTION_AppSearch(MSIPACKAGE *package);
|
||||
|
||||
/* actions in other modules */
|
||||
UINT ACTION_AppSearch(MSIPACKAGE *package);
|
||||
UINT ACTION_FindRelatedProducts(MSIPACKAGE *package);
|
||||
UINT ACTION_InstallFiles(MSIPACKAGE *package);
|
||||
UINT ACTION_DuplicateFiles(MSIPACKAGE *package);
|
||||
UINT ACTION_RegisterClassInfo(MSIPACKAGE *package);
|
||||
UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package);
|
||||
UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package);
|
||||
UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package);
|
||||
|
||||
|
||||
/* Helpers */
|
||||
DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data );
|
||||
WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index);
|
||||
LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc);
|
||||
|
@ -117,3 +223,35 @@ int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component );
|
|||
int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature );
|
||||
int get_loaded_file(MSIPACKAGE* package, LPCWSTR file);
|
||||
int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path);
|
||||
UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action);
|
||||
UINT build_icon_path(MSIPACKAGE *, LPCWSTR, LPWSTR *);
|
||||
DWORD build_version_dword(LPCWSTR);
|
||||
LPWSTR build_directory_name(DWORD , ...);
|
||||
BOOL create_full_pathW(const WCHAR *path);
|
||||
BOOL ACTION_VerifyComponentForAction(MSIPACKAGE*, INT, INSTALLSTATE);
|
||||
BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE*, INT, INSTALLSTATE);
|
||||
void reduce_to_longfilename(WCHAR*);
|
||||
void reduce_to_shortfilename(WCHAR*);
|
||||
LPWSTR create_component_advertise_string(MSIPACKAGE*, MSICOMPONENT*, LPCWSTR);
|
||||
void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature);
|
||||
|
||||
|
||||
/* control event stuff */
|
||||
VOID ControlEvent_FireSubscribedEvent(MSIPACKAGE *package, LPCWSTR event,
|
||||
MSIRECORD *data);
|
||||
VOID ControlEvent_CleanupSubscriptions(MSIPACKAGE *package);
|
||||
VOID ControlEvent_SubscribeToEvent(MSIPACKAGE *package, LPCWSTR event,
|
||||
LPCWSTR control, LPCWSTR attribute);
|
||||
VOID ControlEvent_UnSubscribeToEvent( MSIPACKAGE *package, LPCWSTR event,
|
||||
LPCWSTR control, LPCWSTR attribute );
|
||||
|
||||
/* User Interface messages from the actions */
|
||||
void ui_progress(MSIPACKAGE *, int, int, int, int);
|
||||
void ui_actiondata(MSIPACKAGE *, LPCWSTR, MSIRECORD *);
|
||||
|
||||
|
||||
/* string consts use a number of places and defined in helpers.c*/
|
||||
extern const WCHAR cszSourceDir[];
|
||||
extern const WCHAR szProductCode[];
|
||||
extern const WCHAR cszRootDrive[];
|
||||
extern const WCHAR cszbs[];
|
||||
|
|
1602
reactos/lib/msi/classes.c
Normal file
1602
reactos/lib/msi/classes.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -72,7 +72,7 @@
|
|||
#define YYLEX_PARAM info
|
||||
#define YYPARSE_PARAM info
|
||||
|
||||
static int COND_error(char *str);
|
||||
static int COND_error(const char *str);
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
|
@ -1970,7 +1970,7 @@ static LPWSTR COND_GetLiteral( struct cond_str *str )
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int COND_error(char *str)
|
||||
static int COND_error(const char *str)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,83 +1,9 @@
|
|||
/* A Bison parser, made by GNU Bison 1.875c. */
|
||||
#ifndef BISON_COND_TAB_H
|
||||
# define BISON_COND_TAB_H
|
||||
|
||||
/* Skeleton parser for Yacc-like parsing with Bison,
|
||||
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* As a special exception, when this file is copied by Bison into a
|
||||
Bison output file, you may use that output file without restriction.
|
||||
This special exception was added by the Free Software Foundation
|
||||
in version 1.24 of Bison. */
|
||||
|
||||
/* Tokens. */
|
||||
#ifndef YYTOKENTYPE
|
||||
# define YYTOKENTYPE
|
||||
/* Put the tokens into the symbol table, so that GDB and other debuggers
|
||||
know about them. */
|
||||
enum yytokentype {
|
||||
COND_SPACE = 258,
|
||||
COND_EOF = 259,
|
||||
COND_OR = 260,
|
||||
COND_AND = 261,
|
||||
COND_NOT = 262,
|
||||
COND_LT = 263,
|
||||
COND_GT = 264,
|
||||
COND_EQ = 265,
|
||||
COND_LPAR = 266,
|
||||
COND_RPAR = 267,
|
||||
COND_TILDA = 268,
|
||||
COND_PERCENT = 269,
|
||||
COND_DOLLARS = 270,
|
||||
COND_QUESTION = 271,
|
||||
COND_AMPER = 272,
|
||||
COND_EXCLAM = 273,
|
||||
COND_IDENT = 274,
|
||||
COND_NUMBER = 275,
|
||||
COND_LITER = 276,
|
||||
COND_ERROR = 277
|
||||
};
|
||||
#endif
|
||||
#define COND_SPACE 258
|
||||
#define COND_EOF 259
|
||||
#define COND_OR 260
|
||||
#define COND_AND 261
|
||||
#define COND_NOT 262
|
||||
#define COND_LT 263
|
||||
#define COND_GT 264
|
||||
#define COND_EQ 265
|
||||
#define COND_LPAR 266
|
||||
#define COND_RPAR 267
|
||||
#define COND_TILDA 268
|
||||
#define COND_PERCENT 269
|
||||
#define COND_DOLLARS 270
|
||||
#define COND_QUESTION 271
|
||||
#define COND_AMPER 272
|
||||
#define COND_EXCLAM 273
|
||||
#define COND_IDENT 274
|
||||
#define COND_NUMBER 275
|
||||
#define COND_LITER 276
|
||||
#define COND_ERROR 277
|
||||
|
||||
|
||||
|
||||
|
||||
#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
|
||||
#line 106 "./cond.y"
|
||||
typedef union YYSTYPE {
|
||||
#ifndef YYSTYPE
|
||||
typedef union
|
||||
{
|
||||
struct cond_str str;
|
||||
LPWSTR string;
|
||||
INT value;
|
||||
|
@ -85,15 +11,30 @@ typedef union YYSTYPE {
|
|||
comp_str fn_comp_str;
|
||||
comp_m1 fn_comp_m1;
|
||||
comp_m2 fn_comp_m2;
|
||||
} YYSTYPE;
|
||||
/* Line 1275 of yacc.c. */
|
||||
#line 91 "cond.tab.h"
|
||||
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
} yystype;
|
||||
# define YYSTYPE yystype
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
#endif
|
||||
# define COND_SPACE 257
|
||||
# define COND_EOF 258
|
||||
# define COND_OR 259
|
||||
# define COND_AND 260
|
||||
# define COND_NOT 261
|
||||
# define COND_LT 262
|
||||
# define COND_GT 263
|
||||
# define COND_EQ 264
|
||||
# define COND_LPAR 265
|
||||
# define COND_RPAR 266
|
||||
# define COND_TILDA 267
|
||||
# define COND_PERCENT 268
|
||||
# define COND_DOLLARS 269
|
||||
# define COND_QUESTION 270
|
||||
# define COND_AMPER 271
|
||||
# define COND_EXCLAM 272
|
||||
# define COND_IDENT 273
|
||||
# define COND_NUMBER 274
|
||||
# define COND_LITER 275
|
||||
# define COND_ERROR 276
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* not BISON_COND_TAB_H */
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
#define YYLEX_PARAM info
|
||||
#define YYPARSE_PARAM info
|
||||
|
||||
static int COND_error(char *str);
|
||||
static int COND_error(const char *str);
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
|
@ -722,7 +722,7 @@ static LPWSTR COND_GetLiteral( struct cond_str *str )
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int COND_error(char *str)
|
||||
static int COND_error(const char *str)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ typedef struct tagMSICREATEVIEW
|
|||
MSIDATABASE *db;
|
||||
LPWSTR name;
|
||||
BOOL bIsTemp;
|
||||
create_col_info *col_info;
|
||||
column_info *col_info;
|
||||
} MSICREATEVIEW;
|
||||
|
||||
static UINT CREATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
|
||||
|
@ -59,7 +59,7 @@ static UINT CREATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT
|
|||
static UINT CREATE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
|
||||
{
|
||||
MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
|
||||
create_col_info *col;
|
||||
column_info *col;
|
||||
UINT r, nField, row, table_val, column_val;
|
||||
static const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 };
|
||||
static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 };
|
||||
|
@ -122,8 +122,8 @@ static UINT CREATE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
|
|||
if( r )
|
||||
goto err;
|
||||
|
||||
column_val = msi_addstringW( cv->db->strings, 0, col->colname, -1, 1 );
|
||||
TRACE("New string %s -> %d\n", debugstr_w( col->colname ), column_val );
|
||||
column_val = msi_addstringW( cv->db->strings, 0, col->column, -1, 1 );
|
||||
TRACE("New string %s -> %d\n", debugstr_w( col->column ), column_val );
|
||||
if( column_val < 0 )
|
||||
break;
|
||||
|
||||
|
@ -226,7 +226,7 @@ MSIVIEWOPS create_ops =
|
|||
};
|
||||
|
||||
UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
||||
create_col_info *col_info, BOOL temp )
|
||||
column_info *col_info, BOOL temp )
|
||||
{
|
||||
MSICREATEVIEW *cv = NULL;
|
||||
|
||||
|
|
|
@ -77,7 +77,6 @@ static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source,
|
|||
UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
|
||||
{
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
MSIQUERY * view;
|
||||
MSIRECORD * row = 0;
|
||||
static const WCHAR ExecSeqQuery[] =
|
||||
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
||||
|
@ -89,25 +88,9 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
|
|||
LPWSTR target;
|
||||
WCHAR *deformated=NULL;
|
||||
|
||||
rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, action);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return rc;
|
||||
|
||||
rc = MSI_ViewExecute(view, 0);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
MSI_ViewClose(view);
|
||||
msiobj_release(&view->hdr);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = MSI_ViewFetch(view,&row);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
MSI_ViewClose(view);
|
||||
msiobj_release(&view->hdr);
|
||||
row = MSI_QueryGetRecord( package->db, ExecSeqQuery, action );
|
||||
if (!row)
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
type = MSI_RecordGetInteger(row,2);
|
||||
|
||||
|
@ -123,53 +106,28 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
|
|||
if (type & 0x100)
|
||||
{
|
||||
FIXME("Rollback only action... rollbacks not supported yet\n");
|
||||
schedule_action(package, ROLLBACK_SCRIPT, action);
|
||||
HeapFree(GetProcessHeap(),0,source);
|
||||
HeapFree(GetProcessHeap(),0,target);
|
||||
msiobj_release(&row->hdr);
|
||||
MSI_ViewClose(view);
|
||||
msiobj_release(&view->hdr);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
if (!execute)
|
||||
{
|
||||
LPWSTR *newbuf = NULL;
|
||||
INT count;
|
||||
if (type & 0x200)
|
||||
{
|
||||
TRACE("Deferring Commit Action!\n");
|
||||
count = package->CommitActionCount;
|
||||
package->CommitActionCount++;
|
||||
if (count != 0)
|
||||
newbuf = HeapReAlloc(GetProcessHeap(),0,
|
||||
package->CommitAction,
|
||||
package->CommitActionCount * sizeof(LPWSTR));
|
||||
else
|
||||
newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
|
||||
|
||||
newbuf[count] = strdupW(action);
|
||||
package->CommitAction = newbuf;
|
||||
schedule_action(package, COMMIT_SCRIPT, action);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE("Deferring Action!\n");
|
||||
count = package->DeferredActionCount;
|
||||
package->DeferredActionCount++;
|
||||
if (count != 0)
|
||||
newbuf = HeapReAlloc(GetProcessHeap(),0,
|
||||
package->DeferredAction,
|
||||
package->DeferredActionCount * sizeof(LPWSTR));
|
||||
else
|
||||
newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
|
||||
|
||||
newbuf[count] = strdupW(action);
|
||||
package->DeferredAction = newbuf;
|
||||
schedule_action(package, INSTALL_SCRIPT, action);
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(),0,source);
|
||||
HeapFree(GetProcessHeap(),0,target);
|
||||
msiobj_release(&row->hdr);
|
||||
MSI_ViewClose(view);
|
||||
msiobj_release(&view->hdr);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
|
@ -223,8 +181,6 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
|
|||
HeapFree(GetProcessHeap(),0,source);
|
||||
HeapFree(GetProcessHeap(),0,target);
|
||||
msiobj_release(&row->hdr);
|
||||
MSI_ViewClose(view);
|
||||
msiobj_release(&view->hdr);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -249,7 +205,6 @@ static UINT store_binary_to_temp(MSIPACKAGE *package, LPCWSTR source,
|
|||
{
|
||||
/* write out the file */
|
||||
UINT rc;
|
||||
MSIQUERY * view;
|
||||
MSIRECORD * row = 0;
|
||||
static const WCHAR fmt[] =
|
||||
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
||||
|
@ -258,34 +213,15 @@ static UINT store_binary_to_temp(MSIPACKAGE *package, LPCWSTR source,
|
|||
HANDLE the_file;
|
||||
CHAR buffer[1024];
|
||||
|
||||
if (track_tempfile(package, tmp_file, tmp_file)!=0)
|
||||
FIXME("File Name in temp tracking collision\n");
|
||||
|
||||
the_file = CreateFileW(tmp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (the_file == INVALID_HANDLE_VALUE)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
rc = MSI_OpenQuery(package->db, &view, fmt, source);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return rc;
|
||||
|
||||
rc = MSI_ViewExecute(view, 0);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
MSI_ViewClose(view);
|
||||
msiobj_release(&view->hdr);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = MSI_ViewFetch(view,&row);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
MSI_ViewClose(view);
|
||||
msiobj_release(&view->hdr);
|
||||
return rc;
|
||||
}
|
||||
row = MSI_QueryGetRecord(package->db, fmt, source);
|
||||
if (!row)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -305,8 +241,6 @@ static UINT store_binary_to_temp(MSIPACKAGE *package, LPCWSTR source,
|
|||
CloseHandle(the_file);
|
||||
|
||||
msiobj_release(&row->hdr);
|
||||
MSI_ViewClose(view);
|
||||
msiobj_release(&view->hdr);
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
|
@ -366,7 +300,7 @@ static UINT process_action_return_value(UINT type, HANDLE ThreadHandle)
|
|||
|
||||
static UINT process_handle(MSIPACKAGE* package, UINT type,
|
||||
HANDLE ThreadHandle, HANDLE ProcessHandle,
|
||||
LPCWSTR Name)
|
||||
LPCWSTR Name, BOOL *finished)
|
||||
{
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
|
||||
|
@ -390,6 +324,8 @@ static UINT process_handle(MSIPACKAGE* package, UINT type,
|
|||
CloseHandle(ThreadHandle);
|
||||
if (ProcessHandle);
|
||||
CloseHandle(ProcessHandle);
|
||||
if (finished)
|
||||
*finished = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -411,6 +347,8 @@ static UINT process_handle(MSIPACKAGE* package, UINT type,
|
|||
if (ProcessHandle);
|
||||
CloseHandle(ProcessHandle);
|
||||
}
|
||||
if (finished)
|
||||
*finished = FALSE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
@ -496,6 +434,7 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source,
|
|||
DWORD ThreadId;
|
||||
HANDLE ThreadHandle;
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
BOOL finished = FALSE;
|
||||
|
||||
store_binary_to_temp(package, source, tmp_file);
|
||||
|
||||
|
@ -516,7 +455,12 @@ static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source,
|
|||
|
||||
ThreadHandle = CreateThread(NULL,0,DllThread,(LPVOID)info,0,&ThreadId);
|
||||
|
||||
rc = process_handle(package, type, ThreadHandle, NULL, action);
|
||||
rc = process_handle(package, type, ThreadHandle, NULL, action, &finished );
|
||||
|
||||
if (!finished)
|
||||
track_tempfile(package, tmp_file, tmp_file);
|
||||
else
|
||||
DeleteFileW(tmp_file);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -533,6 +477,7 @@ static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source,
|
|||
WCHAR *cmd;
|
||||
static const WCHAR spc[] = {' ',0};
|
||||
UINT prc = ERROR_SUCCESS;
|
||||
BOOL finished = FALSE;
|
||||
|
||||
memset(&si,0,sizeof(STARTUPINFOW));
|
||||
|
||||
|
@ -569,8 +514,14 @@ static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source,
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
prc = process_handle(package, type, info.hThread, info.hProcess, action);
|
||||
prc = process_handle(package, type, info.hThread, info.hProcess, action,
|
||||
&finished);
|
||||
|
||||
if (!finished)
|
||||
track_tempfile(package, tmp_file, tmp_file);
|
||||
else
|
||||
DeleteFileW(tmp_file);
|
||||
|
||||
return prc;
|
||||
}
|
||||
|
||||
|
@ -622,7 +573,8 @@ static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source,
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
prc = process_handle(package, type, info.hThread, info.hProcess, action);
|
||||
prc = process_handle(package, type, info.hThread, info.hProcess, action,
|
||||
NULL);
|
||||
|
||||
return prc;
|
||||
}
|
||||
|
@ -636,37 +588,23 @@ static UINT HANDLE_CustomType19(MSIPACKAGE *package, LPCWSTR source,
|
|||
'W','H','E','R','E',' ','`','E','r','r','o','r','`',' ','=',' ',
|
||||
'\'','%','s','\'',0
|
||||
};
|
||||
MSIQUERY *view = NULL;
|
||||
MSIRECORD *row = 0;
|
||||
UINT r;
|
||||
LPWSTR deformated = NULL;
|
||||
|
||||
deformat_string( package, target, &deformated );
|
||||
|
||||
/* first try treat the error as a number */
|
||||
r = MSI_OpenQuery( package->db, &view, query, deformated );
|
||||
if( r == ERROR_SUCCESS )
|
||||
row = MSI_QueryGetRecord( package->db, query, deformated );
|
||||
if( row )
|
||||
{
|
||||
r = MSI_ViewExecute( view, 0 );
|
||||
if( r == ERROR_SUCCESS )
|
||||
{
|
||||
r = MSI_ViewFetch( view, &row );
|
||||
if( r == ERROR_SUCCESS )
|
||||
{
|
||||
LPCWSTR error = MSI_RecordGetString( row, 1 );
|
||||
MessageBoxW( NULL, error, NULL, MB_OK );
|
||||
msiobj_release( &row->hdr );
|
||||
}
|
||||
}
|
||||
MSI_ViewClose( view );
|
||||
msiobj_release( &view->hdr );
|
||||
LPCWSTR error = MSI_RecordGetString( row, 1 );
|
||||
MessageBoxW( NULL, error, NULL, MB_OK );
|
||||
msiobj_release( &row->hdr );
|
||||
}
|
||||
|
||||
if (r != ERROR_SUCCESS )
|
||||
{
|
||||
else
|
||||
MessageBoxW( NULL, deformated, NULL, MB_OK );
|
||||
HeapFree( GetProcessHeap(), 0, deformated );
|
||||
}
|
||||
|
||||
HeapFree( GetProcessHeap(), 0, deformated );
|
||||
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
@ -720,7 +658,8 @@ static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source,
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
prc = process_handle(package, type, info.hThread, info.hProcess, action);
|
||||
prc = process_handle(package, type, info.hThread, info.hProcess, action,
|
||||
NULL);
|
||||
|
||||
return prc;
|
||||
}
|
||||
|
@ -761,7 +700,8 @@ static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source,
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
prc = process_handle(package, type, info.hThread, info.hProcess, action);
|
||||
prc = process_handle(package, type, info.hThread, info.hProcess, action,
|
||||
NULL);
|
||||
|
||||
return prc;
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ DEFINE_GUID( CLSID_MsiDatabase, 0x000c1084, 0x0000, 0x0000,
|
|||
* Any binary data in a table is a reference to a stream.
|
||||
*/
|
||||
|
||||
VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
|
||||
static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
|
||||
{
|
||||
MSIDATABASE *db = (MSIDATABASE *) arg;
|
||||
DWORD r;
|
||||
|
@ -77,7 +77,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
|
|||
HRESULT r;
|
||||
MSIDATABASE *db = NULL;
|
||||
UINT ret = ERROR_FUNCTION_FAILED;
|
||||
LPWSTR szMode;
|
||||
LPCWSTR szMode;
|
||||
STATSTG stat;
|
||||
|
||||
TRACE("%s %s\n",debugstr_w(szDBPath),debugstr_w(szPersist) );
|
||||
|
@ -85,7 +85,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
|
|||
if( !pdb )
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
szMode = (LPWSTR) szPersist;
|
||||
szMode = szPersist;
|
||||
if( HIWORD( szPersist ) )
|
||||
{
|
||||
/* UINT len = lstrlenW( szPerist ) + 1; */
|
||||
|
@ -209,7 +209,7 @@ UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB)
|
|||
goto end;
|
||||
}
|
||||
else
|
||||
szwPersist = (LPWSTR) szPersist;
|
||||
szwPersist = (LPWSTR)(DWORD)szPersist;
|
||||
|
||||
r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB );
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
396
reactos/lib/msi/events.c
Normal file
396
reactos/lib/msi/events.c
Normal file
|
@ -0,0 +1,396 @@
|
|||
/*
|
||||
* Implementation of the Microsoft Installer (msi.dll)
|
||||
*
|
||||
* Copyright 2005 Aric Stewart for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/controlevent_overview.asp
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "winreg.h"
|
||||
#include "msi.h"
|
||||
#include "msipriv.h"
|
||||
#include "action.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
typedef UINT (*EVENTHANDLER)(MSIPACKAGE*,LPCWSTR,msi_dialog *);
|
||||
|
||||
struct _events {
|
||||
LPCSTR event;
|
||||
EVENTHANDLER handler;
|
||||
};
|
||||
|
||||
struct subscriber {
|
||||
struct list entry;
|
||||
LPWSTR event;
|
||||
LPWSTR control;
|
||||
LPWSTR attribute;
|
||||
};
|
||||
|
||||
UINT ControlEvent_HandleControlEvent(MSIPACKAGE *, LPCWSTR, LPCWSTR, msi_dialog*);
|
||||
|
||||
/*
|
||||
* Create a dialog box and run it if it's modal
|
||||
*/
|
||||
static UINT event_do_dialog( MSIPACKAGE *package, LPCWSTR name )
|
||||
{
|
||||
msi_dialog *dialog;
|
||||
UINT r;
|
||||
|
||||
/* kill the current modeless dialog */
|
||||
if( package->dialog )
|
||||
msi_dialog_destroy( package->dialog );
|
||||
package->dialog = NULL;
|
||||
|
||||
/* create a new dialog */
|
||||
dialog = msi_dialog_create( package, name,
|
||||
ControlEvent_HandleControlEvent );
|
||||
if( dialog )
|
||||
{
|
||||
/* modeless dialogs return an error message */
|
||||
r = msi_dialog_run_message_loop( dialog );
|
||||
if( r == ERROR_SUCCESS )
|
||||
msi_dialog_destroy( dialog );
|
||||
else
|
||||
package->dialog = dialog;
|
||||
}
|
||||
else
|
||||
r = ERROR_FUNCTION_FAILED;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* End a modal dialog box
|
||||
*/
|
||||
static UINT ControlEvent_EndDialog(MSIPACKAGE* package, LPCWSTR argument,
|
||||
msi_dialog* dialog)
|
||||
{
|
||||
static const WCHAR szExit[] = {
|
||||
'E','x','i','t',0};
|
||||
static const WCHAR szRetry[] = {
|
||||
'R','e','t','r','y',0};
|
||||
static const WCHAR szIgnore[] = {
|
||||
'I','g','n','o','r','e',0};
|
||||
static const WCHAR szReturn[] = {
|
||||
'R','e','t','u','r','n',0};
|
||||
|
||||
if (lstrcmpW(argument,szExit)==0)
|
||||
package->CurrentInstallState = ERROR_INSTALL_USEREXIT;
|
||||
else if (lstrcmpW(argument, szRetry) == 0)
|
||||
package->CurrentInstallState = ERROR_INSTALL_SUSPEND;
|
||||
else if (lstrcmpW(argument, szIgnore) == 0)
|
||||
package->CurrentInstallState = -1;
|
||||
else if (lstrcmpW(argument, szReturn) == 0)
|
||||
package->CurrentInstallState = ERROR_SUCCESS;
|
||||
else
|
||||
{
|
||||
ERR("Unknown argument string %s\n",debugstr_w(argument));
|
||||
package->CurrentInstallState = ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
ControlEvent_CleanupSubscriptions(package);
|
||||
msi_dialog_end_dialog( dialog );
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* transition from one modal dialog to another modal dialog
|
||||
*/
|
||||
static UINT ControlEvent_NewDialog(MSIPACKAGE* package, LPCWSTR argument,
|
||||
msi_dialog *dialog)
|
||||
{
|
||||
/* store the name of the next dialog, and signal this one to end */
|
||||
package->next_dialog = strdupW(argument);
|
||||
ControlEvent_CleanupSubscriptions(package);
|
||||
msi_dialog_end_dialog( dialog );
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new child dialog of an existing modal dialog
|
||||
*/
|
||||
static UINT ControlEvent_SpawnDialog(MSIPACKAGE* package, LPCWSTR argument,
|
||||
msi_dialog *dialog)
|
||||
{
|
||||
event_do_dialog( package, argument );
|
||||
if( package->CurrentInstallState != ERROR_SUCCESS )
|
||||
msi_dialog_end_dialog( dialog );
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a dialog that remains up for a period of time
|
||||
* based on a condition
|
||||
*/
|
||||
static UINT ControlEvent_SpawnWaitDialog(MSIPACKAGE* package, LPCWSTR argument,
|
||||
msi_dialog* dialog)
|
||||
{
|
||||
FIXME("Doing Nothing\n");
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT ControlEvent_DoAction(MSIPACKAGE* package, LPCWSTR argument,
|
||||
msi_dialog* dialog)
|
||||
{
|
||||
ACTION_PerformAction(package,argument,TRUE);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT ControlEvent_AddLocal(MSIPACKAGE* package, LPCWSTR argument,
|
||||
msi_dialog* dialog)
|
||||
{
|
||||
static const WCHAR szAll[] = {'A','L','L',0};
|
||||
int i;
|
||||
|
||||
if (lstrcmpW(szAll,argument))
|
||||
{
|
||||
MSI_SetFeatureStateW(package,argument,INSTALLSTATE_LOCAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < package->loaded_features; i++)
|
||||
{
|
||||
package->features[i].ActionRequest = INSTALLSTATE_LOCAL;
|
||||
package->features[i].Action = INSTALLSTATE_LOCAL;
|
||||
}
|
||||
ACTION_UpdateComponentStates(package,argument);
|
||||
}
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT ControlEvent_Remove(MSIPACKAGE* package, LPCWSTR argument,
|
||||
msi_dialog* dialog)
|
||||
{
|
||||
static const WCHAR szAll[] = {'A','L','L',0};
|
||||
int i;
|
||||
|
||||
if (lstrcmpW(szAll,argument))
|
||||
{
|
||||
MSI_SetFeatureStateW(package,argument,INSTALLSTATE_ABSENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < package->loaded_features; i++)
|
||||
{
|
||||
package->features[i].ActionRequest = INSTALLSTATE_ABSENT;
|
||||
package->features[i].Action= INSTALLSTATE_ABSENT;
|
||||
}
|
||||
ACTION_UpdateComponentStates(package,argument);
|
||||
}
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT ControlEvent_AddSource(MSIPACKAGE* package, LPCWSTR argument,
|
||||
msi_dialog* dialog)
|
||||
{
|
||||
static const WCHAR szAll[] = {'A','L','L',0};
|
||||
int i;
|
||||
|
||||
if (lstrcmpW(szAll,argument))
|
||||
{
|
||||
MSI_SetFeatureStateW(package,argument,INSTALLSTATE_SOURCE);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < package->loaded_features; i++)
|
||||
{
|
||||
package->features[i].ActionRequest = INSTALLSTATE_SOURCE;
|
||||
package->features[i].Action = INSTALLSTATE_SOURCE;
|
||||
}
|
||||
ACTION_UpdateComponentStates(package,argument);
|
||||
}
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT ControlEvent_SetTargetPath(MSIPACKAGE* package, LPCWSTR argument,
|
||||
msi_dialog* dialog)
|
||||
{
|
||||
LPWSTR path = load_dynamic_property(package,argument, NULL);
|
||||
/* failure to set the path halts the executing of control events */
|
||||
return MSI_SetTargetPathW(package, argument, path);
|
||||
}
|
||||
|
||||
/*
|
||||
* Subscribed events
|
||||
*/
|
||||
static void free_subscriber( struct subscriber *sub )
|
||||
{
|
||||
HeapFree(GetProcessHeap(),0,sub->event);
|
||||
HeapFree(GetProcessHeap(),0,sub->control);
|
||||
HeapFree(GetProcessHeap(),0,sub->attribute);
|
||||
HeapFree(GetProcessHeap(),0,sub);
|
||||
}
|
||||
|
||||
VOID ControlEvent_SubscribeToEvent( MSIPACKAGE *package, LPCWSTR event,
|
||||
LPCWSTR control, LPCWSTR attribute )
|
||||
{
|
||||
struct subscriber *sub;
|
||||
|
||||
sub = HeapAlloc(GetProcessHeap(),0,sizeof (*sub));
|
||||
if( !sub )
|
||||
return;
|
||||
sub->event = strdupW(event);
|
||||
sub->control = strdupW(control);
|
||||
sub->attribute = strdupW(attribute);
|
||||
list_add_tail( &package->subscriptions, &sub->entry );
|
||||
}
|
||||
|
||||
VOID ControlEvent_UnSubscribeToEvent( MSIPACKAGE *package, LPCWSTR event,
|
||||
LPCWSTR control, LPCWSTR attribute )
|
||||
{
|
||||
struct list *i, *t;
|
||||
struct subscriber *sub;
|
||||
|
||||
LIST_FOR_EACH_SAFE( i, t, &package->subscriptions )
|
||||
{
|
||||
sub = LIST_ENTRY( i, struct subscriber, entry );
|
||||
|
||||
if( lstrcmpiW(sub->control,control) )
|
||||
continue;
|
||||
if( lstrcmpiW(sub->attribute,attribute) )
|
||||
continue;
|
||||
if( lstrcmpiW(sub->event,event) )
|
||||
continue;
|
||||
list_remove( &sub->entry );
|
||||
free_subscriber( sub );
|
||||
}
|
||||
}
|
||||
|
||||
VOID ControlEvent_FireSubscribedEvent( MSIPACKAGE *package, LPCWSTR event,
|
||||
MSIRECORD *rec )
|
||||
{
|
||||
struct subscriber *sub;
|
||||
|
||||
TRACE("Firing Event %s\n",debugstr_w(event));
|
||||
|
||||
if (!package->dialog)
|
||||
return;
|
||||
|
||||
LIST_FOR_EACH_ENTRY( sub, &package->subscriptions, struct subscriber, entry )
|
||||
{
|
||||
if (lstrcmpiW(sub->event, event))
|
||||
continue;
|
||||
msi_dialog_handle_event( package->dialog, sub->control,
|
||||
sub->attribute, rec );
|
||||
}
|
||||
}
|
||||
|
||||
VOID ControlEvent_CleanupSubscriptions(MSIPACKAGE *package)
|
||||
{
|
||||
struct list *i, *t;
|
||||
struct subscriber *sub;
|
||||
|
||||
LIST_FOR_EACH_SAFE( i, t, &package->subscriptions )
|
||||
{
|
||||
sub = LIST_ENTRY( i, struct subscriber, entry );
|
||||
|
||||
list_remove( &sub->entry );
|
||||
free_subscriber( sub );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ACTION_DialogBox()
|
||||
*
|
||||
* Return ERROR_SUCCESS if dialog is process and ERROR_FUNCTION_FAILED
|
||||
* if the given parameter is not a dialog box
|
||||
*/
|
||||
UINT ACTION_DialogBox( MSIPACKAGE* package, LPCWSTR szDialogName )
|
||||
{
|
||||
UINT r = ERROR_SUCCESS;
|
||||
|
||||
if( package->next_dialog )
|
||||
ERR("Already a next dialog... ignoring it\n");
|
||||
package->next_dialog = NULL;
|
||||
|
||||
/*
|
||||
* Dialogs are chained by filling in the next_dialog member
|
||||
* of the package structure, then terminating the current dialog.
|
||||
* The code below sees the next_dialog member set, and runs the
|
||||
* next dialog.
|
||||
* We fall out of the loop below if we come across a modeless
|
||||
* dialog, as it returns ERROR_IO_PENDING when we try to run
|
||||
* its message loop.
|
||||
*/
|
||||
r = event_do_dialog( package, szDialogName );
|
||||
while( r == ERROR_SUCCESS && package->next_dialog )
|
||||
{
|
||||
LPWSTR name = package->next_dialog;
|
||||
|
||||
package->next_dialog = NULL;
|
||||
r = event_do_dialog( package, name );
|
||||
HeapFree( GetProcessHeap(), 0, name );
|
||||
}
|
||||
|
||||
if( r == ERROR_IO_PENDING )
|
||||
r = ERROR_SUCCESS;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
struct _events Events[] = {
|
||||
{ "EndDialog",ControlEvent_EndDialog },
|
||||
{ "NewDialog",ControlEvent_NewDialog },
|
||||
{ "SpawnDialog",ControlEvent_SpawnDialog },
|
||||
{ "SpawnWaitDialog",ControlEvent_SpawnWaitDialog },
|
||||
{ "DoAction",ControlEvent_DoAction },
|
||||
{ "AddLocal",ControlEvent_AddLocal },
|
||||
{ "Remove",ControlEvent_Remove },
|
||||
{ "AddSource",ControlEvent_AddSource },
|
||||
{ "SetTargetPath",ControlEvent_SetTargetPath },
|
||||
{ NULL,NULL },
|
||||
};
|
||||
|
||||
UINT ControlEvent_HandleControlEvent(MSIPACKAGE *package, LPCWSTR event,
|
||||
LPCWSTR argument, msi_dialog* dialog)
|
||||
{
|
||||
int i = 0;
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
|
||||
TRACE("Handling Control Event %s\n",debugstr_w(event));
|
||||
if (!event)
|
||||
return rc;
|
||||
|
||||
while( Events[i].event != NULL)
|
||||
{
|
||||
LPWSTR wevent = strdupAtoW(Events[i].event);
|
||||
if (lstrcmpW(wevent,event)==0)
|
||||
{
|
||||
HeapFree(GetProcessHeap(),0,wevent);
|
||||
rc = Events[i].handler(package,argument,dialog);
|
||||
return rc;
|
||||
}
|
||||
HeapFree(GetProcessHeap(),0,wevent);
|
||||
i++;
|
||||
}
|
||||
FIXME("unhandled control event %s arg(%s)\n",
|
||||
debugstr_w(event), debugstr_w(argument));
|
||||
return rc;
|
||||
}
|
759
reactos/lib/msi/files.c
Normal file
759
reactos/lib/msi/files.c
Normal file
|
@ -0,0 +1,759 @@
|
|||
/*
|
||||
* Implementation of the Microsoft Installer (msi.dll)
|
||||
*
|
||||
* Copyright 2005 Aric Stewart for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Actions dealing with files These are
|
||||
*
|
||||
* InstallFiles
|
||||
* DuplicateFiles
|
||||
* MoveFiles (TODO)
|
||||
* PatchFiles (TODO)
|
||||
* RemoveDuplicateFiles(TODO)
|
||||
* RemoveFiles(TODO)
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "wine/debug.h"
|
||||
#include "fdi.h"
|
||||
#include "msidefs.h"
|
||||
#include "msvcrt/fcntl.h"
|
||||
#include "msipriv.h"
|
||||
#include "winuser.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "action.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
extern const WCHAR szInstallFiles[];
|
||||
extern const WCHAR szDuplicateFiles[];
|
||||
extern const WCHAR szMoveFiles[];
|
||||
extern const WCHAR szPatchFiles[];
|
||||
extern const WCHAR szRemoveDuplicateFiles[];
|
||||
extern const WCHAR szRemoveFiles[];
|
||||
|
||||
static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
|
||||
|
||||
inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)
|
||||
{
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
MSIFOLDER *folder;
|
||||
LPWSTR install_path;
|
||||
|
||||
install_path = resolve_folder(package, package->components[component].Directory,
|
||||
FALSE, FALSE, &folder);
|
||||
if (!install_path)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
/* create the path */
|
||||
if (folder->State == 0)
|
||||
{
|
||||
create_full_pathW(install_path);
|
||||
folder->State = 2;
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, install_path);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a helper function for handling embedded cabinet media
|
||||
*/
|
||||
static UINT writeout_cabinet_stream(MSIPACKAGE *package, LPCWSTR stream_name,
|
||||
WCHAR* source)
|
||||
{
|
||||
UINT rc;
|
||||
USHORT* data;
|
||||
UINT size;
|
||||
DWORD write;
|
||||
HANDLE the_file;
|
||||
WCHAR tmp[MAX_PATH];
|
||||
|
||||
rc = read_raw_stream_data(package->db,stream_name,&data,&size);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return rc;
|
||||
|
||||
write = MAX_PATH;
|
||||
if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))
|
||||
GetTempPathW(MAX_PATH,tmp);
|
||||
|
||||
GetTempFileNameW(tmp,stream_name,0,source);
|
||||
|
||||
track_tempfile(package,strrchrW(source,'\\'), source);
|
||||
the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (the_file == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ERR("Unable to create file %s\n",debugstr_w(source));
|
||||
rc = ERROR_FUNCTION_FAILED;
|
||||
goto end;
|
||||
}
|
||||
|
||||
WriteFile(the_file,data,size,&write,NULL);
|
||||
CloseHandle(the_file);
|
||||
TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
|
||||
end:
|
||||
HeapFree(GetProcessHeap(),0,data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Support functions for FDI functions */
|
||||
typedef struct
|
||||
{
|
||||
MSIPACKAGE* package;
|
||||
LPCSTR cab_path;
|
||||
} CabData;
|
||||
|
||||
static void * cabinet_alloc(ULONG cb)
|
||||
{
|
||||
return HeapAlloc(GetProcessHeap(), 0, cb);
|
||||
}
|
||||
|
||||
static void cabinet_free(void *pv)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, pv);
|
||||
}
|
||||
|
||||
static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
|
||||
{
|
||||
DWORD dwAccess = 0;
|
||||
DWORD dwShareMode = 0;
|
||||
DWORD dwCreateDisposition = OPEN_EXISTING;
|
||||
switch (oflag & _O_ACCMODE)
|
||||
{
|
||||
case _O_RDONLY:
|
||||
dwAccess = GENERIC_READ;
|
||||
dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _O_WRONLY:
|
||||
dwAccess = GENERIC_WRITE;
|
||||
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
break;
|
||||
case _O_RDWR:
|
||||
dwAccess = GENERIC_READ | GENERIC_WRITE;
|
||||
dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
break;
|
||||
}
|
||||
if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
|
||||
dwCreateDisposition = CREATE_NEW;
|
||||
else if (oflag & _O_CREAT)
|
||||
dwCreateDisposition = CREATE_ALWAYS;
|
||||
return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
|
||||
dwCreateDisposition, 0, NULL);
|
||||
}
|
||||
|
||||
static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)
|
||||
{
|
||||
DWORD dwRead;
|
||||
if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL))
|
||||
return dwRead;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)
|
||||
{
|
||||
DWORD dwWritten;
|
||||
if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL))
|
||||
return dwWritten;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cabinet_close(INT_PTR hf)
|
||||
{
|
||||
return CloseHandle((HANDLE)hf) ? 0 : -1;
|
||||
}
|
||||
|
||||
static long cabinet_seek(INT_PTR hf, long dist, int seektype)
|
||||
{
|
||||
/* flags are compatible and so are passed straight through */
|
||||
return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
|
||||
}
|
||||
|
||||
static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
|
||||
{
|
||||
switch (fdint)
|
||||
{
|
||||
case fdintCOPY_FILE:
|
||||
{
|
||||
CabData *data = (CabData*) pfdin->pv;
|
||||
ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
|
||||
char *file;
|
||||
|
||||
LPWSTR trackname;
|
||||
LPWSTR trackpath;
|
||||
LPWSTR tracknametmp;
|
||||
static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
|
||||
LPWSTR given_file;
|
||||
INT index;
|
||||
|
||||
MSIRECORD * uirow;
|
||||
LPWSTR uipath;
|
||||
|
||||
given_file = strdupAtoW(pfdin->psz1);
|
||||
index = get_loaded_file(data->package, given_file);
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
ERR("Unknown File in Cabinent (%s)\n",debugstr_w(given_file));
|
||||
HeapFree(GetProcessHeap(),0,given_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!((data->package->files[index].State == 1 ||
|
||||
data->package->files[index].State == 2)))
|
||||
{
|
||||
TRACE("Skipping extraction of %s\n",debugstr_w(given_file));
|
||||
HeapFree(GetProcessHeap(),0,given_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
file = cabinet_alloc((len+1)*sizeof(char));
|
||||
strcpy(file, data->cab_path);
|
||||
strcat(file, pfdin->psz1);
|
||||
|
||||
TRACE("file: %s\n", debugstr_a(file));
|
||||
|
||||
/* track this file so it can be deleted if not installed */
|
||||
trackpath=strdupAtoW(file);
|
||||
tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
|
||||
trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) +
|
||||
strlenW(tmpprefix)+1) * sizeof(WCHAR));
|
||||
|
||||
strcpyW(trackname,tmpprefix);
|
||||
strcatW(trackname,tracknametmp);
|
||||
|
||||
track_tempfile(data->package, trackname, trackpath);
|
||||
|
||||
HeapFree(GetProcessHeap(),0,trackpath);
|
||||
HeapFree(GetProcessHeap(),0,trackname);
|
||||
HeapFree(GetProcessHeap(),0,tracknametmp);
|
||||
|
||||
/* the UI chunk */
|
||||
uirow=MSI_CreateRecord(9);
|
||||
MSI_RecordSetStringW(uirow,1,data->package->files[index].File);
|
||||
uipath = strdupW(data->package->files[index].TargetPath);
|
||||
*(strrchrW(uipath,'\\')+1)=0;
|
||||
MSI_RecordSetStringW(uirow,9,uipath);
|
||||
MSI_RecordSetInteger(uirow,6,data->package->files[index].FileSize);
|
||||
ui_actiondata(data->package,szInstallFiles,uirow);
|
||||
msiobj_release( &uirow->hdr );
|
||||
HeapFree(GetProcessHeap(),0,uipath);
|
||||
|
||||
ui_progress(data->package,2,data->package->files[index].FileSize,0,0);
|
||||
|
||||
return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
|
||||
}
|
||||
case fdintCLOSE_FILE_INFO:
|
||||
{
|
||||
FILETIME ft;
|
||||
FILETIME ftLocal;
|
||||
if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
|
||||
return -1;
|
||||
if (!LocalFileTimeToFileTime(&ft, &ftLocal))
|
||||
return -1;
|
||||
if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal))
|
||||
return -1;
|
||||
|
||||
cabinet_close(pfdin->hf);
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* extract_cabinet_file
|
||||
*
|
||||
* Extract files from a cab file.
|
||||
*/
|
||||
static BOOL extract_cabinet_file(MSIPACKAGE* package, LPCWSTR source,
|
||||
LPCWSTR path)
|
||||
{
|
||||
HFDI hfdi;
|
||||
ERF erf;
|
||||
BOOL ret;
|
||||
char *cabinet;
|
||||
char *cab_path;
|
||||
CabData data;
|
||||
|
||||
TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path));
|
||||
|
||||
hfdi = FDICreate(cabinet_alloc,
|
||||
cabinet_free,
|
||||
cabinet_open,
|
||||
cabinet_read,
|
||||
cabinet_write,
|
||||
cabinet_close,
|
||||
cabinet_seek,
|
||||
0,
|
||||
&erf);
|
||||
if (!hfdi)
|
||||
{
|
||||
ERR("FDICreate failed\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!(cabinet = strdupWtoA( source )))
|
||||
{
|
||||
FDIDestroy(hfdi);
|
||||
return FALSE;
|
||||
}
|
||||
if (!(cab_path = strdupWtoA( path )))
|
||||
{
|
||||
FDIDestroy(hfdi);
|
||||
HeapFree(GetProcessHeap(), 0, cabinet);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
data.package = package;
|
||||
data.cab_path = cab_path;
|
||||
|
||||
ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
|
||||
|
||||
if (!ret)
|
||||
ERR("FDICopy failed\n");
|
||||
|
||||
FDIDestroy(hfdi);
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, cabinet);
|
||||
HeapFree(GetProcessHeap(), 0, cab_path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static VOID set_file_source(MSIPACKAGE* package, MSIFILE* file, MSICOMPONENT*
|
||||
comp, LPCWSTR path)
|
||||
{
|
||||
if (file->Attributes & msidbFileAttributesNoncompressed)
|
||||
{
|
||||
LPWSTR p;
|
||||
p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
|
||||
file->SourcePath = build_directory_name(2, p, file->ShortName);
|
||||
HeapFree(GetProcessHeap(),0,p);
|
||||
}
|
||||
else
|
||||
file->SourcePath = build_directory_name(2, path, file->File);
|
||||
}
|
||||
|
||||
static UINT ready_media_for_file(MSIPACKAGE *package, int fileindex,
|
||||
MSICOMPONENT* comp)
|
||||
{
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
MSIRECORD * row = 0;
|
||||
static WCHAR source[MAX_PATH];
|
||||
static const WCHAR ExecSeqQuery[] =
|
||||
{'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
|
||||
'`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
|
||||
'`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',
|
||||
' ','%', 'i',' ','O','R','D','E','R',' ','B','Y',' ',
|
||||
'`','L','a','s','t','S','e','q','u','e','n','c','e','`',0};
|
||||
LPCWSTR cab;
|
||||
DWORD sz;
|
||||
INT seq;
|
||||
static UINT last_sequence = 0;
|
||||
static LPWSTR last_path = NULL;
|
||||
MSIFILE* file = NULL;
|
||||
|
||||
/* cleanup signal */
|
||||
if (!package)
|
||||
{
|
||||
HeapFree(GetProcessHeap(),0,last_path);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
file = &package->files[fileindex];
|
||||
|
||||
if (file->Sequence <= last_sequence)
|
||||
{
|
||||
set_file_source(package,file,comp,last_path);
|
||||
TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence);
|
||||
if (!row)
|
||||
{
|
||||
TRACE("Unable to query row\n");
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
seq = MSI_RecordGetInteger(row,2);
|
||||
last_sequence = seq;
|
||||
|
||||
HeapFree(GetProcessHeap(),0,last_path);
|
||||
last_path = NULL;
|
||||
|
||||
if (file->Attributes & msidbFileAttributesNoncompressed)
|
||||
{
|
||||
last_path = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
|
||||
set_file_source(package,file,comp,last_path);
|
||||
msiobj_release(&row->hdr);
|
||||
return rc;
|
||||
}
|
||||
|
||||
cab = MSI_RecordGetString(row,4);
|
||||
if (cab)
|
||||
{
|
||||
TRACE("Source is CAB %s\n",debugstr_w(cab));
|
||||
/* the stream does not contain the # character */
|
||||
if (cab[0]=='#')
|
||||
{
|
||||
writeout_cabinet_stream(package,&cab[1],source);
|
||||
last_path = strdupW(source);
|
||||
*(strrchrW(last_path,'\\')+1)=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sz = MAX_PATH;
|
||||
last_path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR));
|
||||
if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
|
||||
{
|
||||
ERR("No Source dir defined \n");
|
||||
rc = ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpyW(last_path,source);
|
||||
strcatW(source,cab);
|
||||
/* extract the cab file into a folder in the temp folder */
|
||||
sz = MAX_PATH;
|
||||
if (MSI_GetPropertyW(package, cszTempFolder,last_path, &sz)
|
||||
!= ERROR_SUCCESS)
|
||||
GetTempPathW(MAX_PATH,last_path);
|
||||
}
|
||||
}
|
||||
rc = !extract_cabinet_file(package, source, last_path);
|
||||
/* reaquire file ptr */
|
||||
file = &package->files[fileindex];
|
||||
}
|
||||
else
|
||||
{
|
||||
sz = MAX_PATH;
|
||||
last_path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR));
|
||||
MSI_GetPropertyW(package,cszSourceDir,source,&sz);
|
||||
strcpyW(last_path,source);
|
||||
}
|
||||
set_file_source(package, file, comp, last_path);
|
||||
msiobj_release(&row->hdr);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
|
||||
LPWSTR* file_source)
|
||||
{
|
||||
DWORD index;
|
||||
|
||||
if (!package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
for (index = 0; index < package->loaded_files; index ++)
|
||||
{
|
||||
if (strcmpW(file_key,package->files[index].File)==0)
|
||||
{
|
||||
if (package->files[index].State >= 2)
|
||||
{
|
||||
*file_source = strdupW(package->files[index].TargetPath);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
return ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
/*
|
||||
* In order to make this work more effeciencly I am going to do this in 2
|
||||
* passes.
|
||||
* Pass 1) Correct all the TargetPaths and determin what files are to be
|
||||
* installed.
|
||||
* Pass 2) Extract Cabinents and copy files.
|
||||
*/
|
||||
UINT ACTION_InstallFiles(MSIPACKAGE *package)
|
||||
{
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
DWORD index;
|
||||
|
||||
if (!package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
/* increment progress bar each time action data is sent */
|
||||
ui_progress(package,1,1,0,0);
|
||||
|
||||
/* Pass 1 */
|
||||
for (index = 0; index < package->loaded_files; index++)
|
||||
{
|
||||
MSIFILE *file;
|
||||
MSICOMPONENT* comp = NULL;
|
||||
|
||||
file = &package->files[index];
|
||||
|
||||
if (file->Temporary)
|
||||
continue;
|
||||
|
||||
if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex,
|
||||
INSTALLSTATE_LOCAL))
|
||||
{
|
||||
ui_progress(package,2,file->FileSize,0,0);
|
||||
TRACE("File %s is not scheduled for install\n",
|
||||
debugstr_w(file->File));
|
||||
|
||||
file->State = 5;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((file->State == 1) || (file->State == 2))
|
||||
{
|
||||
LPWSTR p = NULL;
|
||||
|
||||
TRACE("Pass 1: %s\n",debugstr_w(file->File));
|
||||
|
||||
create_component_directory( package, file->ComponentIndex);
|
||||
|
||||
/* recalculate file paths because things may have changed */
|
||||
|
||||
if (file->ComponentIndex >= 0)
|
||||
comp = &package->components[file->ComponentIndex];
|
||||
else
|
||||
{
|
||||
ERR("No Component for file\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
|
||||
HeapFree(GetProcessHeap(),0,file->TargetPath);
|
||||
|
||||
file->TargetPath = build_directory_name(2, p, file->FileName);
|
||||
HeapFree(GetProcessHeap(),0,p);
|
||||
}
|
||||
}
|
||||
|
||||
/* Pass 2 */
|
||||
for (index = 0; index < package->loaded_files; index++)
|
||||
{
|
||||
MSIFILE *file;
|
||||
MSICOMPONENT* comp = NULL;
|
||||
|
||||
file = &package->files[index];
|
||||
|
||||
if (file->Temporary)
|
||||
continue;
|
||||
|
||||
if ((file->State == 1) || (file->State == 2))
|
||||
{
|
||||
TRACE("Pass 2: %s\n",debugstr_w(file->File));
|
||||
|
||||
if (file->ComponentIndex >= 0)
|
||||
comp = &package->components[file->ComponentIndex];
|
||||
|
||||
rc = ready_media_for_file(package, index, comp);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("Unable to ready media\n");
|
||||
rc = ERROR_FUNCTION_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* WARNING!
|
||||
* our file table could change here because a new temp file
|
||||
* may have been created. So reaquire our ptr.
|
||||
*/
|
||||
file = &package->files[index];
|
||||
|
||||
TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
|
||||
debugstr_w(file->TargetPath));
|
||||
|
||||
if (file->Attributes & msidbFileAttributesNoncompressed)
|
||||
rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
|
||||
else
|
||||
rc = MoveFileW(file->SourcePath, file->TargetPath);
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
rc = GetLastError();
|
||||
ERR("Unable to move/copy file (%s -> %s) (error %d)\n",
|
||||
debugstr_w(file->SourcePath), debugstr_w(file->TargetPath),
|
||||
rc);
|
||||
if (rc == ERROR_ALREADY_EXISTS && file->State == 2)
|
||||
{
|
||||
if (!CopyFileW(file->SourcePath,file->TargetPath,FALSE))
|
||||
ERR("Unable to copy file (%s -> %s) (error %ld)\n",
|
||||
debugstr_w(file->SourcePath),
|
||||
debugstr_w(file->TargetPath), GetLastError());
|
||||
if (!(file->Attributes & msidbFileAttributesNoncompressed))
|
||||
DeleteFileW(file->SourcePath);
|
||||
rc = 0;
|
||||
}
|
||||
else if (rc == ERROR_FILE_NOT_FOUND)
|
||||
{
|
||||
ERR("Source File Not Found! Continuing\n");
|
||||
rc = 0;
|
||||
}
|
||||
else if (file->Attributes & msidbFileAttributesVital)
|
||||
{
|
||||
ERR("Ignoring Error and continuing (nonvital file)...\n");
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
file->State = 4;
|
||||
rc = ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
ready_media_for_file(NULL, 0, NULL);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
|
||||
{
|
||||
MSIPACKAGE *package = (MSIPACKAGE*)param;
|
||||
WCHAR *file_source = NULL;
|
||||
WCHAR dest_name[0x100];
|
||||
LPWSTR dest_path, dest;
|
||||
LPCWSTR file_key, component;
|
||||
INT component_index;
|
||||
DWORD sz;
|
||||
DWORD rc;
|
||||
|
||||
component = MSI_RecordGetString(row,2);
|
||||
component_index = get_loaded_component(package,component);
|
||||
|
||||
if (!ACTION_VerifyComponentForAction(package, component_index,
|
||||
INSTALLSTATE_LOCAL))
|
||||
{
|
||||
TRACE("Skipping copy due to disabled component %s\n",
|
||||
debugstr_w(component));
|
||||
|
||||
/* the action taken was the same as the current install state */
|
||||
package->components[component_index].Action =
|
||||
package->components[component_index].Installed;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
package->components[component_index].Action = INSTALLSTATE_LOCAL;
|
||||
|
||||
file_key = MSI_RecordGetString(row,3);
|
||||
if (!file_key)
|
||||
{
|
||||
ERR("Unable to get file key\n");
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
rc = get_file_target(package,file_key,&file_source);
|
||||
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("Original file unknown %s\n",debugstr_w(file_key));
|
||||
HeapFree(GetProcessHeap(),0,file_source);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
if (MSI_RecordIsNull(row,4))
|
||||
strcpyW(dest_name,strrchrW(file_source,'\\')+1);
|
||||
else
|
||||
{
|
||||
sz=0x100;
|
||||
MSI_RecordGetStringW(row,4,dest_name,&sz);
|
||||
reduce_to_longfilename(dest_name);
|
||||
}
|
||||
|
||||
if (MSI_RecordIsNull(row,5))
|
||||
{
|
||||
LPWSTR p;
|
||||
dest_path = strdupW(file_source);
|
||||
p = strrchrW(dest_path,'\\');
|
||||
if (p)
|
||||
*p=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LPCWSTR destkey;
|
||||
destkey = MSI_RecordGetString(row,5);
|
||||
dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);
|
||||
if (!dest_path)
|
||||
{
|
||||
/* try a Property */
|
||||
dest_path = load_dynamic_property(package, destkey, NULL);
|
||||
if (!dest_path)
|
||||
{
|
||||
FIXME("Unable to get destination folder, try AppSearch properties\n");
|
||||
HeapFree(GetProcessHeap(),0,file_source);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dest = build_directory_name(2, dest_path, dest_name);
|
||||
|
||||
TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
|
||||
debugstr_w(dest));
|
||||
|
||||
if (strcmpW(file_source,dest))
|
||||
rc = !CopyFileW(file_source,dest,TRUE);
|
||||
else
|
||||
rc = ERROR_SUCCESS;
|
||||
|
||||
if (rc != ERROR_SUCCESS)
|
||||
ERR("Failed to copy file %s -> %s, last error %ld\n", debugstr_w(file_source), debugstr_w(dest_path), GetLastError());
|
||||
|
||||
FIXME("We should track these duplicate files as well\n");
|
||||
|
||||
HeapFree(GetProcessHeap(),0,dest_path);
|
||||
HeapFree(GetProcessHeap(),0,dest);
|
||||
HeapFree(GetProcessHeap(),0,file_source);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
|
||||
{
|
||||
UINT rc;
|
||||
MSIQUERY * view;
|
||||
static const WCHAR ExecSeqQuery[] =
|
||||
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
||||
'`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0};
|
||||
|
||||
if (!package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
rc = MSI_IterateRecords(view, NULL, ITERATE_DuplicateFiles, package);
|
||||
msiobj_release(&view->hdr);
|
||||
|
||||
return rc;
|
||||
}
|
|
@ -31,26 +31,22 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msifo
|
|||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "winreg.h"
|
||||
#include "wine/debug.h"
|
||||
#include "fdi.h"
|
||||
#include "msi.h"
|
||||
#include "msiquery.h"
|
||||
#include "fcntl.h"
|
||||
#include "objbase.h"
|
||||
#include "objidl.h"
|
||||
#include "msipriv.h"
|
||||
#include "winnls.h"
|
||||
#include "winuser.h"
|
||||
#include "shlobj.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "winver.h"
|
||||
#include "action.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
|
||||
LPWSTR build_default_format(MSIRECORD* record)
|
||||
static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
|
||||
WCHAR** data, DWORD len, MSIRECORD* record,
|
||||
BOOL* in_group);
|
||||
|
||||
|
||||
static LPWSTR build_default_format(MSIRECORD* record)
|
||||
{
|
||||
int i;
|
||||
int count;
|
||||
|
@ -101,7 +97,8 @@ static LPWSTR deformat_component(MSIPACKAGE* package, LPCWSTR key, DWORD* sz)
|
|||
return value;
|
||||
}
|
||||
|
||||
static LPWSTR deformat_file(MSIPACKAGE* package, LPCWSTR key, DWORD* sz)
|
||||
static LPWSTR deformat_file(MSIPACKAGE* package, LPCWSTR key, DWORD* sz,
|
||||
BOOL shortname)
|
||||
{
|
||||
LPWSTR value = NULL;
|
||||
INT index;
|
||||
|
@ -114,8 +111,32 @@ static LPWSTR deformat_file(MSIPACKAGE* package, LPCWSTR key, DWORD* sz)
|
|||
index = get_loaded_file(package,key);
|
||||
if (index >=0)
|
||||
{
|
||||
value = strdupW(package->files[index].TargetPath);
|
||||
*sz = (strlenW(value)) * sizeof(WCHAR);
|
||||
if (!shortname)
|
||||
{
|
||||
value = strdupW(package->files[index].TargetPath);
|
||||
*sz = (strlenW(value)) * sizeof(WCHAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD size = 0;
|
||||
size = GetShortPathNameW(package->files[index].TargetPath, NULL, 0);
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
*sz = (size-1) * sizeof (WCHAR);
|
||||
size ++;
|
||||
value = HeapAlloc(GetProcessHeap(),0,size * sizeof(WCHAR));
|
||||
GetShortPathNameW(package->files[index].TargetPath, value,
|
||||
size);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("Unable to get ShortPath size (%s)\n",
|
||||
debugstr_w(package->files[index].TargetPath));
|
||||
value = NULL;
|
||||
*sz = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
|
@ -214,6 +235,45 @@ static LPWSTR deformat_property(MSIPACKAGE* package, LPCWSTR key, DWORD* chunk)
|
|||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Groups cannot be nested. They are just treated as from { to next }
|
||||
*/
|
||||
static BOOL find_next_group(LPCWSTR source, DWORD len_remaining,
|
||||
LPWSTR *group, LPCWSTR *mark,
|
||||
LPCWSTR* mark2)
|
||||
{
|
||||
int i;
|
||||
BOOL found = FALSE;
|
||||
|
||||
*mark = scanW(source,'{',len_remaining);
|
||||
if (!*mark)
|
||||
return FALSE;
|
||||
|
||||
for (i = 1; (*mark - source) + i < len_remaining; i++)
|
||||
{
|
||||
if ((*mark)[i] == '}')
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! found)
|
||||
return FALSE;
|
||||
|
||||
*mark2 = &(*mark)[i];
|
||||
|
||||
i = *mark2 - *mark;
|
||||
*group = HeapAlloc(GetProcessHeap(),0,i*sizeof(WCHAR));
|
||||
|
||||
i -= 1;
|
||||
memcpy(*group,&(*mark)[1],i*sizeof(WCHAR));
|
||||
(*group)[i] = 0;
|
||||
|
||||
TRACE("Found group %s\n",debugstr_w(*group));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static BOOL find_next_outermost_key(LPCWSTR source, DWORD len_remaining,
|
||||
LPWSTR *key, LPCWSTR *mark, LPCWSTR* mark2,
|
||||
BOOL *nested)
|
||||
|
@ -259,13 +319,71 @@ static BOOL find_next_outermost_key(LPCWSTR source, DWORD len_remaining,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static LPWSTR deformat_group(MSIPACKAGE* package, LPWSTR group, DWORD len,
|
||||
MSIRECORD* record, DWORD* size)
|
||||
{
|
||||
LPWSTR value;
|
||||
LPCWSTR mark, mark2;
|
||||
LPWSTR key;
|
||||
BOOL nested;
|
||||
INT failcount;
|
||||
static const WCHAR fmt[] = {'{','%','s','}',0};
|
||||
UINT sz;
|
||||
|
||||
if (!group || group[0] == 0)
|
||||
{
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
/* if no [] then group is returned as is */
|
||||
|
||||
if (!find_next_outermost_key(group, len, &key, &mark, &mark2, &nested))
|
||||
{
|
||||
*size = (len+2)*sizeof(WCHAR);
|
||||
value = HeapAlloc(GetProcessHeap(),0,*size);
|
||||
sprintfW(value,fmt,group);
|
||||
/* do not return size of the null at the end */
|
||||
*size = (len+1)*sizeof(WCHAR);
|
||||
return value;
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(),0,key);
|
||||
failcount = 0;
|
||||
sz = deformat_string_internal(package, group, &value, strlenW(group),
|
||||
record, &failcount);
|
||||
if (failcount==0)
|
||||
{
|
||||
*size = sz * sizeof(WCHAR);
|
||||
return value;
|
||||
}
|
||||
else if (failcount < 0)
|
||||
{
|
||||
LPWSTR v2;
|
||||
|
||||
v2 = HeapAlloc(GetProcessHeap(),0,(sz+2)*sizeof(WCHAR));
|
||||
v2[0] = '{';
|
||||
memcpy(&v2[1],value,sz*sizeof(WCHAR));
|
||||
v2[sz+1]='}';
|
||||
HeapFree(GetProcessHeap(),0,value);
|
||||
|
||||
*size = (sz+2)*sizeof(WCHAR);
|
||||
return v2;
|
||||
}
|
||||
else
|
||||
{
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* len is in WCHARs
|
||||
* return is also in WCHARs
|
||||
*/
|
||||
static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
|
||||
WCHAR** data, DWORD len, MSIRECORD* record)
|
||||
WCHAR** data, DWORD len, MSIRECORD* record,
|
||||
INT* failcount)
|
||||
{
|
||||
LPCWSTR mark = NULL;
|
||||
LPCWSTR mark2 = NULL;
|
||||
|
@ -285,15 +403,16 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
TRACE("Starting with %s\n",debugstr_w(ptr));
|
||||
TRACE("Starting with %s\n",debugstr_wn(ptr,len));
|
||||
|
||||
/* scan for special characters... fast exit */
|
||||
if (!scanW(ptr,'[',len) || (scanW(ptr,'[',len) && !scanW(ptr,']',len)))
|
||||
if ((!scanW(ptr,'[',len) || (scanW(ptr,'[',len) && !scanW(ptr,']',len))) &&
|
||||
(scanW(ptr,'{',len) && !scanW(ptr,'}',len)))
|
||||
{
|
||||
/* not formatted */
|
||||
*data = HeapAlloc(GetProcessHeap(),0,(len*sizeof(WCHAR)));
|
||||
memcpy(*data,ptr,len*sizeof(WCHAR));
|
||||
TRACE("Returning %s\n",debugstr_w(*data));
|
||||
TRACE("Returning %s\n",debugstr_wn(*data,len));
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -301,14 +420,23 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
|
|||
|
||||
while (progress - ptr < len)
|
||||
{
|
||||
/* seek out first group if existing */
|
||||
if (find_next_group(progress, len - (progress - ptr), &key,
|
||||
&mark, &mark2))
|
||||
{
|
||||
value = deformat_group(package, key, strlenW(key)+1, record,
|
||||
&chunk);
|
||||
key = NULL;
|
||||
nested = FALSE;
|
||||
}
|
||||
/* formatted string located */
|
||||
if (!find_next_outermost_key(progress, len - (progress - ptr), &key,
|
||||
&mark, &mark2, &nested))
|
||||
else if (!find_next_outermost_key(progress, len - (progress - ptr),
|
||||
&key, &mark, &mark2, &nested))
|
||||
{
|
||||
LPBYTE nd2;
|
||||
|
||||
TRACE("after value %s .. %s\n",debugstr_w((LPWSTR)newdata),
|
||||
debugstr_w(mark));
|
||||
TRACE("after value %s \n",debugstr_wn((LPWSTR)newdata,
|
||||
size/sizeof(WCHAR)));
|
||||
chunk = (len - (progress - ptr)) * sizeof(WCHAR);
|
||||
TRACE("after chunk is %li + %li\n",size,chunk);
|
||||
if (size)
|
||||
|
@ -343,33 +471,43 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
|
|||
{
|
||||
TRACE("Nested key... %s\n",debugstr_w(key));
|
||||
deformat_string_internal(package, key, &value, strlenW(key)+1,
|
||||
record);
|
||||
record, failcount);
|
||||
|
||||
HeapFree(GetProcessHeap(),0,key);
|
||||
key = value;
|
||||
}
|
||||
|
||||
TRACE("Current %s .. %s\n",debugstr_w((LPWSTR)newdata),debugstr_w(key));
|
||||
TRACE("Current %s .. %s\n",debugstr_wn((LPWSTR)newdata,
|
||||
size/sizeof(WCHAR)),debugstr_w(key));
|
||||
|
||||
if (!package)
|
||||
{
|
||||
/* only deformat number indexs */
|
||||
if (is_key_number(key))
|
||||
if (key && is_key_number(key))
|
||||
{
|
||||
value = deformat_index(record,key,&chunk);
|
||||
if (!chunk && failcount && *failcount >= 0)
|
||||
(*failcount)++;
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD keylen = strlenW(key);
|
||||
chunk = (keylen + 2)*sizeof(WCHAR);
|
||||
value = HeapAlloc(GetProcessHeap(),0,chunk);
|
||||
value[0] = '[';
|
||||
memcpy(&value[1],key,keylen*sizeof(WCHAR));
|
||||
value[1+keylen] = ']';
|
||||
if (failcount)
|
||||
*failcount = -1;
|
||||
if(key)
|
||||
{
|
||||
DWORD keylen = strlenW(key);
|
||||
chunk = (keylen + 2)*sizeof(WCHAR);
|
||||
value = HeapAlloc(GetProcessHeap(),0,chunk);
|
||||
value[0] = '[';
|
||||
memcpy(&value[1],key,keylen*sizeof(WCHAR));
|
||||
value[1+keylen] = ']';
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sz = 0;
|
||||
switch (key[0])
|
||||
if (key) switch (key[0])
|
||||
{
|
||||
case '~':
|
||||
value = deformat_NULL(&chunk);
|
||||
|
@ -378,8 +516,10 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
|
|||
value = deformat_component(package,&key[1],&chunk);
|
||||
break;
|
||||
case '#':
|
||||
value = deformat_file(package,&key[1], &chunk, FALSE);
|
||||
break;
|
||||
case '!': /* should be short path */
|
||||
value = deformat_file(package,&key[1], &chunk);
|
||||
value = deformat_file(package,&key[1], &chunk, TRUE);
|
||||
break;
|
||||
case '\\':
|
||||
value = deformat_escape(&key[1],&chunk);
|
||||
|
@ -388,8 +528,17 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
|
|||
value = deformat_environment(package,&key[1],&chunk);
|
||||
break;
|
||||
default:
|
||||
/* index keys cannot be nested */
|
||||
if (is_key_number(key))
|
||||
value = deformat_index(record,key,&chunk);
|
||||
if (!nested)
|
||||
value = deformat_index(record,key,&chunk);
|
||||
else
|
||||
{
|
||||
static const WCHAR fmt[] = {'[','%','s',']',0};
|
||||
value = HeapAlloc(GetProcessHeap(),0,10);
|
||||
sprintfW(value,fmt,key);
|
||||
chunk = strlenW(value)*sizeof(WCHAR);
|
||||
}
|
||||
else
|
||||
value = deformat_property(package,key,&chunk);
|
||||
break;
|
||||
|
@ -412,11 +561,14 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
|
|||
size+=chunk;
|
||||
HeapFree(GetProcessHeap(),0,value);
|
||||
}
|
||||
else if (failcount && *failcount >=0 )
|
||||
(*failcount)++;
|
||||
|
||||
progress = mark2+1;
|
||||
}
|
||||
|
||||
TRACE("after everything %s\n",debugstr_w((LPWSTR)newdata));
|
||||
TRACE("after everything %s\n",debugstr_wn((LPWSTR)newdata,
|
||||
size/sizeof(WCHAR)));
|
||||
|
||||
*data = (LPWSTR)newdata;
|
||||
return size / sizeof(WCHAR);
|
||||
|
@ -440,7 +592,7 @@ UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer,
|
|||
TRACE("(%s)\n",debugstr_w(rec));
|
||||
|
||||
len = deformat_string_internal(package,rec,&deformated,strlenW(rec),
|
||||
record);
|
||||
record, NULL);
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
|
@ -487,7 +639,7 @@ UINT MSI_FormatRecordA( MSIPACKAGE* package, MSIRECORD* record, LPSTR buffer,
|
|||
TRACE("(%s)\n",debugstr_w(rec));
|
||||
|
||||
len = deformat_string_internal(package,rec,&deformated,strlenW(rec),
|
||||
record);
|
||||
record, NULL);
|
||||
lenA = WideCharToMultiByte(CP_ACP,0,deformated,len,NULL,0,NULL,NULL);
|
||||
|
||||
if (buffer)
|
||||
|
|
913
reactos/lib/msi/helpers.c
Normal file
913
reactos/lib/msi/helpers.c
Normal file
|
@ -0,0 +1,913 @@
|
|||
/*
|
||||
* Implementation of the Microsoft Installer (msi.dll)
|
||||
*
|
||||
* Copyright 2005 Aric Stewart for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Here are helper functions formally in action.c that are used by a variaty of
|
||||
* actions and functions.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "wine/debug.h"
|
||||
#include "msipriv.h"
|
||||
#include "winuser.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "action.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};
|
||||
static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0};
|
||||
|
||||
const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
|
||||
const WCHAR szProductCode[]= {'P','r','o','d','u','c','t','C','o','d','e',0};
|
||||
const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
|
||||
const WCHAR cszbs[]={'\\',0};
|
||||
|
||||
DWORD build_version_dword(LPCWSTR version_string)
|
||||
{
|
||||
SHORT major,minor;
|
||||
WORD build;
|
||||
DWORD rc = 0x00000000;
|
||||
LPCWSTR ptr1;
|
||||
|
||||
ptr1 = version_string;
|
||||
|
||||
if (!ptr1)
|
||||
return rc;
|
||||
else
|
||||
major = atoiW(ptr1);
|
||||
|
||||
|
||||
if(ptr1)
|
||||
ptr1 = strchrW(ptr1,'.');
|
||||
if (ptr1)
|
||||
{
|
||||
ptr1++;
|
||||
minor = atoiW(ptr1);
|
||||
}
|
||||
else
|
||||
minor = 0;
|
||||
|
||||
if (ptr1)
|
||||
ptr1 = strchrW(ptr1,'.');
|
||||
|
||||
if (ptr1)
|
||||
{
|
||||
ptr1++;
|
||||
build = atoiW(ptr1);
|
||||
}
|
||||
else
|
||||
build = 0;
|
||||
|
||||
rc = MAKELONG(build,MAKEWORD(minor,major));
|
||||
TRACE("%s -> 0x%lx\n",debugstr_w(version_string),rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name,
|
||||
LPWSTR *FilePath)
|
||||
{
|
||||
LPWSTR ProductCode;
|
||||
LPWSTR SystemFolder;
|
||||
LPWSTR dest;
|
||||
UINT rc;
|
||||
|
||||
static const WCHAR szInstaller[] =
|
||||
{'M','i','c','r','o','s','o','f','t','\\',
|
||||
'I','n','s','t','a','l','l','e','r','\\',0};
|
||||
static const WCHAR szFolder[] =
|
||||
{'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
|
||||
|
||||
ProductCode = load_dynamic_property(package,szProductCode,&rc);
|
||||
if (!ProductCode)
|
||||
return rc;
|
||||
|
||||
SystemFolder = load_dynamic_property(package,szFolder,NULL);
|
||||
|
||||
dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode);
|
||||
|
||||
create_full_pathW(dest);
|
||||
|
||||
*FilePath = build_directory_name(2, dest, icon_name);
|
||||
|
||||
HeapFree(GetProcessHeap(),0,SystemFolder);
|
||||
HeapFree(GetProcessHeap(),0,ProductCode);
|
||||
HeapFree(GetProcessHeap(),0,dest);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
|
||||
{
|
||||
UINT rc;
|
||||
DWORD sz;
|
||||
LPWSTR ret;
|
||||
|
||||
sz = 0;
|
||||
if (MSI_RecordIsNull(row,index))
|
||||
return NULL;
|
||||
|
||||
rc = MSI_RecordGetStringW(row,index,NULL,&sz);
|
||||
|
||||
/* having an empty string is different than NULL */
|
||||
if (sz == 0)
|
||||
{
|
||||
ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR));
|
||||
ret[0] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
sz ++;
|
||||
ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR));
|
||||
rc = MSI_RecordGetStringW(row,index,ret,&sz);
|
||||
if (rc!=ERROR_SUCCESS)
|
||||
{
|
||||
ERR("Unable to load dynamic string\n");
|
||||
HeapFree(GetProcessHeap(), 0, ret);
|
||||
ret = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc)
|
||||
{
|
||||
DWORD sz = 0;
|
||||
LPWSTR str;
|
||||
UINT r;
|
||||
|
||||
r = MSI_GetPropertyW(package, prop, NULL, &sz);
|
||||
if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
|
||||
{
|
||||
if (rc)
|
||||
*rc = r;
|
||||
return NULL;
|
||||
}
|
||||
sz++;
|
||||
str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
|
||||
r = MSI_GetPropertyW(package, prop, str, &sz);
|
||||
if (r != ERROR_SUCCESS)
|
||||
{
|
||||
HeapFree(GetProcessHeap(),0,str);
|
||||
str = NULL;
|
||||
}
|
||||
if (rc)
|
||||
*rc = r;
|
||||
return str;
|
||||
}
|
||||
|
||||
int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
|
||||
{
|
||||
int rc = -1;
|
||||
DWORD i;
|
||||
|
||||
for (i = 0; i < package->loaded_components; i++)
|
||||
{
|
||||
if (strcmpW(Component,package->components[i].Component)==0)
|
||||
{
|
||||
rc = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
|
||||
{
|
||||
int rc = -1;
|
||||
DWORD i;
|
||||
|
||||
for (i = 0; i < package->loaded_features; i++)
|
||||
{
|
||||
if (strcmpW(Feature,package->features[i].Feature)==0)
|
||||
{
|
||||
rc = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
|
||||
{
|
||||
int rc = -1;
|
||||
DWORD i;
|
||||
|
||||
for (i = 0; i < package->loaded_files; i++)
|
||||
{
|
||||
if (strcmpW(file,package->files[i].File)==0)
|
||||
{
|
||||
rc = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
|
||||
{
|
||||
DWORD i;
|
||||
DWORD index;
|
||||
|
||||
if (!package)
|
||||
return -2;
|
||||
|
||||
for (i=0; i < package->loaded_files; i++)
|
||||
if (strcmpW(package->files[i].File,name)==0)
|
||||
return -1;
|
||||
|
||||
index = package->loaded_files;
|
||||
package->loaded_files++;
|
||||
if (package->loaded_files== 1)
|
||||
package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
|
||||
else
|
||||
package->files = HeapReAlloc(GetProcessHeap(),0,
|
||||
package->files , package->loaded_files * sizeof(MSIFILE));
|
||||
|
||||
memset(&package->files[index],0,sizeof(MSIFILE));
|
||||
|
||||
package->files[index].File = strdupW(name);
|
||||
package->files[index].TargetPath = strdupW(path);
|
||||
package->files[index].Temporary = TRUE;
|
||||
|
||||
TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
|
||||
BOOL set_prop, MSIFOLDER **folder)
|
||||
{
|
||||
DWORD i;
|
||||
LPWSTR p, path = NULL;
|
||||
|
||||
TRACE("Working to resolve %s\n",debugstr_w(name));
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
/* special resolving for Target and Source root dir */
|
||||
if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
|
||||
{
|
||||
if (!source)
|
||||
{
|
||||
LPWSTR check_path;
|
||||
check_path = load_dynamic_property(package,cszTargetDir,NULL);
|
||||
if (!check_path)
|
||||
{
|
||||
check_path = load_dynamic_property(package,cszRootDrive,NULL);
|
||||
if (set_prop)
|
||||
MSI_SetPropertyW(package,cszTargetDir,check_path);
|
||||
}
|
||||
|
||||
/* correct misbuilt target dir */
|
||||
path = build_directory_name(2, check_path, NULL);
|
||||
if (strcmpiW(path,check_path)!=0)
|
||||
MSI_SetPropertyW(package,cszTargetDir,path);
|
||||
|
||||
if (folder)
|
||||
{
|
||||
for (i = 0; i < package->loaded_folders; i++)
|
||||
{
|
||||
if (strcmpW(package->folders[i].Directory,name)==0)
|
||||
break;
|
||||
}
|
||||
*folder = &(package->folders[i]);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
else
|
||||
{
|
||||
path = load_dynamic_property(package,cszSourceDir,NULL);
|
||||
if (!path)
|
||||
{
|
||||
path = load_dynamic_property(package,cszDatabase,NULL);
|
||||
if (path)
|
||||
{
|
||||
p = strrchrW(path,'\\');
|
||||
if (p)
|
||||
*(p+1) = 0;
|
||||
}
|
||||
}
|
||||
if (folder)
|
||||
{
|
||||
for (i = 0; i < package->loaded_folders; i++)
|
||||
{
|
||||
if (strcmpW(package->folders[i].Directory,name)==0)
|
||||
break;
|
||||
}
|
||||
*folder = &(package->folders[i]);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < package->loaded_folders; i++)
|
||||
{
|
||||
if (strcmpW(package->folders[i].Directory,name)==0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= package->loaded_folders)
|
||||
return NULL;
|
||||
|
||||
if (folder)
|
||||
*folder = &(package->folders[i]);
|
||||
|
||||
if (!source && package->folders[i].ResolvedTarget)
|
||||
{
|
||||
path = strdupW(package->folders[i].ResolvedTarget);
|
||||
TRACE(" already resolved to %s\n",debugstr_w(path));
|
||||
return path;
|
||||
}
|
||||
else if (source && package->folders[i].ResolvedSource)
|
||||
{
|
||||
path = strdupW(package->folders[i].ResolvedSource);
|
||||
TRACE(" (source)already resolved to %s\n",debugstr_w(path));
|
||||
return path;
|
||||
}
|
||||
else if (!source && package->folders[i].Property)
|
||||
{
|
||||
path = build_directory_name(2, package->folders[i].Property, NULL);
|
||||
|
||||
TRACE(" internally set to %s\n",debugstr_w(path));
|
||||
if (set_prop)
|
||||
MSI_SetPropertyW(package,name,path);
|
||||
return path;
|
||||
}
|
||||
|
||||
if (package->folders[i].ParentIndex >= 0)
|
||||
{
|
||||
LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory;
|
||||
|
||||
TRACE(" ! Parent is %s\n", debugstr_w(parent));
|
||||
|
||||
p = resolve_folder(package, parent, source, set_prop, NULL);
|
||||
if (!source)
|
||||
{
|
||||
TRACE(" TargetDefault = %s\n",
|
||||
debugstr_w(package->folders[i].TargetDefault));
|
||||
|
||||
path = build_directory_name(3, p,
|
||||
package->folders[i].TargetDefault, NULL);
|
||||
package->folders[i].ResolvedTarget = strdupW(path);
|
||||
TRACE(" resolved into %s\n",debugstr_w(path));
|
||||
if (set_prop)
|
||||
MSI_SetPropertyW(package,name,path);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (package->folders[i].SourceDefault &&
|
||||
package->folders[i].SourceDefault[0]!='.')
|
||||
path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL);
|
||||
else
|
||||
path = strdupW(p);
|
||||
TRACE(" (source)resolved into %s\n",debugstr_w(path));
|
||||
package->folders[i].ResolvedSource = strdupW(path);
|
||||
}
|
||||
HeapFree(GetProcessHeap(),0,p);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/* wrapper to resist a need for a full rewrite right now */
|
||||
DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data )
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
MSIRECORD *rec = MSI_CreateRecord(1);
|
||||
DWORD size = 0;
|
||||
|
||||
MSI_RecordSetStringW(rec,0,ptr);
|
||||
MSI_FormatRecordW(package,rec,NULL,&size);
|
||||
if (size >= 0)
|
||||
{
|
||||
size++;
|
||||
*data = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
|
||||
if (size > 1)
|
||||
MSI_FormatRecordW(package,rec,*data,&size);
|
||||
else
|
||||
*data[0] = 0;
|
||||
msiobj_release( &rec->hdr );
|
||||
return sizeof(WCHAR)*size;
|
||||
}
|
||||
msiobj_release( &rec->hdr );
|
||||
}
|
||||
|
||||
*data = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action)
|
||||
{
|
||||
UINT count;
|
||||
LPWSTR *newbuf = NULL;
|
||||
if (script >= TOTAL_SCRIPTS)
|
||||
{
|
||||
FIXME("Unknown script requested %i\n",script);
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
TRACE("Scheduling Action %s in script %i\n",debugstr_w(action), script);
|
||||
|
||||
count = package->script->ActionCount[script];
|
||||
package->script->ActionCount[script]++;
|
||||
if (count != 0)
|
||||
newbuf = HeapReAlloc(GetProcessHeap(),0,
|
||||
package->script->Actions[script],
|
||||
package->script->ActionCount[script]* sizeof(LPWSTR));
|
||||
else
|
||||
newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
|
||||
|
||||
newbuf[count] = strdupW(action);
|
||||
package->script->Actions[script] = newbuf;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static void remove_tracked_tempfiles(MSIPACKAGE* package)
|
||||
{
|
||||
DWORD i;
|
||||
|
||||
if (!package)
|
||||
return;
|
||||
|
||||
for (i = 0; i < package->loaded_files; i++)
|
||||
{
|
||||
if (package->files[i].Temporary)
|
||||
{
|
||||
TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath));
|
||||
DeleteFileW(package->files[i].TargetPath);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Called when the package is being closed */
|
||||
void ACTION_free_package_structures( MSIPACKAGE* package)
|
||||
{
|
||||
INT i;
|
||||
|
||||
TRACE("Freeing package action data\n");
|
||||
|
||||
remove_tracked_tempfiles(package);
|
||||
|
||||
/* No dynamic buffers in features */
|
||||
if (package->features && package->loaded_features > 0)
|
||||
HeapFree(GetProcessHeap(),0,package->features);
|
||||
|
||||
for (i = 0; i < package->loaded_folders; i++)
|
||||
{
|
||||
HeapFree(GetProcessHeap(),0,package->folders[i].Directory);
|
||||
HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault);
|
||||
HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault);
|
||||
HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
|
||||
HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource);
|
||||
HeapFree(GetProcessHeap(),0,package->folders[i].Property);
|
||||
}
|
||||
if (package->folders && package->loaded_folders > 0)
|
||||
HeapFree(GetProcessHeap(),0,package->folders);
|
||||
|
||||
for (i = 0; i < package->loaded_components; i++)
|
||||
HeapFree(GetProcessHeap(),0,package->components[i].FullKeypath);
|
||||
|
||||
if (package->components && package->loaded_components > 0)
|
||||
HeapFree(GetProcessHeap(),0,package->components);
|
||||
|
||||
for (i = 0; i < package->loaded_files; i++)
|
||||
{
|
||||
HeapFree(GetProcessHeap(),0,package->files[i].File);
|
||||
HeapFree(GetProcessHeap(),0,package->files[i].FileName);
|
||||
HeapFree(GetProcessHeap(),0,package->files[i].ShortName);
|
||||
HeapFree(GetProcessHeap(),0,package->files[i].Version);
|
||||
HeapFree(GetProcessHeap(),0,package->files[i].Language);
|
||||
HeapFree(GetProcessHeap(),0,package->files[i].SourcePath);
|
||||
HeapFree(GetProcessHeap(),0,package->files[i].TargetPath);
|
||||
}
|
||||
|
||||
if (package->files && package->loaded_files > 0)
|
||||
HeapFree(GetProcessHeap(),0,package->files);
|
||||
|
||||
/* clean up extension, progid, class and verb structures */
|
||||
for (i = 0; i < package->loaded_classes; i++)
|
||||
{
|
||||
HeapFree(GetProcessHeap(),0,package->classes[i].Description);
|
||||
HeapFree(GetProcessHeap(),0,package->classes[i].FileTypeMask);
|
||||
HeapFree(GetProcessHeap(),0,package->classes[i].IconPath);
|
||||
HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler);
|
||||
HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler32);
|
||||
HeapFree(GetProcessHeap(),0,package->classes[i].Argument);
|
||||
HeapFree(GetProcessHeap(),0,package->classes[i].ProgIDText);
|
||||
}
|
||||
|
||||
if (package->classes && package->loaded_classes > 0)
|
||||
HeapFree(GetProcessHeap(),0,package->classes);
|
||||
|
||||
for (i = 0; i < package->loaded_extensions; i++)
|
||||
{
|
||||
HeapFree(GetProcessHeap(),0,package->extensions[i].ProgIDText);
|
||||
}
|
||||
|
||||
if (package->extensions && package->loaded_extensions > 0)
|
||||
HeapFree(GetProcessHeap(),0,package->extensions);
|
||||
|
||||
for (i = 0; i < package->loaded_progids; i++)
|
||||
{
|
||||
HeapFree(GetProcessHeap(),0,package->progids[i].ProgID);
|
||||
HeapFree(GetProcessHeap(),0,package->progids[i].Description);
|
||||
HeapFree(GetProcessHeap(),0,package->progids[i].IconPath);
|
||||
}
|
||||
|
||||
if (package->progids && package->loaded_progids > 0)
|
||||
HeapFree(GetProcessHeap(),0,package->progids);
|
||||
|
||||
for (i = 0; i < package->loaded_verbs; i++)
|
||||
{
|
||||
HeapFree(GetProcessHeap(),0,package->verbs[i].Verb);
|
||||
HeapFree(GetProcessHeap(),0,package->verbs[i].Command);
|
||||
HeapFree(GetProcessHeap(),0,package->verbs[i].Argument);
|
||||
}
|
||||
|
||||
if (package->verbs && package->loaded_verbs > 0)
|
||||
HeapFree(GetProcessHeap(),0,package->verbs);
|
||||
|
||||
for (i = 0; i < package->loaded_mimes; i++)
|
||||
HeapFree(GetProcessHeap(),0,package->mimes[i].ContentType);
|
||||
|
||||
if (package->mimes && package->loaded_mimes > 0)
|
||||
HeapFree(GetProcessHeap(),0,package->mimes);
|
||||
|
||||
for (i = 0; i < package->loaded_appids; i++)
|
||||
{
|
||||
HeapFree(GetProcessHeap(),0,package->appids[i].RemoteServerName);
|
||||
HeapFree(GetProcessHeap(),0,package->appids[i].LocalServer);
|
||||
HeapFree(GetProcessHeap(),0,package->appids[i].ServiceParameters);
|
||||
HeapFree(GetProcessHeap(),0,package->appids[i].DllSurrogate);
|
||||
}
|
||||
|
||||
if (package->appids && package->loaded_appids > 0)
|
||||
HeapFree(GetProcessHeap(),0,package->appids);
|
||||
|
||||
if (package->script)
|
||||
{
|
||||
for (i = 0; i < TOTAL_SCRIPTS; i++)
|
||||
{
|
||||
int j;
|
||||
for (j = 0; j < package->script->ActionCount[i]; j++)
|
||||
HeapFree(GetProcessHeap(),0,package->script->Actions[i][j]);
|
||||
|
||||
HeapFree(GetProcessHeap(),0,package->script->Actions[i]);
|
||||
}
|
||||
HeapFree(GetProcessHeap(),0,package->script);
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(),0,package->PackagePath);
|
||||
|
||||
/* cleanup control event subscriptions */
|
||||
ControlEvent_CleanupSubscriptions(package);
|
||||
}
|
||||
|
||||
/*
|
||||
* build_directory_name()
|
||||
*
|
||||
* This function is to save messing round with directory names
|
||||
* It handles adding backslashes between path segments,
|
||||
* and can add \ at the end of the directory name if told to.
|
||||
*
|
||||
* It takes a variable number of arguments.
|
||||
* It always allocates a new string for the result, so make sure
|
||||
* to free the return value when finished with it.
|
||||
*
|
||||
* The first arg is the number of path segments that follow.
|
||||
* The arguments following count are a list of path segments.
|
||||
* A path segment may be NULL.
|
||||
*
|
||||
* Path segments will be added with a \ separating them.
|
||||
* A \ will not be added after the last segment, however if the
|
||||
* last segment is NULL, then the last character will be a \
|
||||
*
|
||||
*/
|
||||
LPWSTR build_directory_name(DWORD count, ...)
|
||||
{
|
||||
DWORD sz = 1, i;
|
||||
LPWSTR dir;
|
||||
va_list va;
|
||||
|
||||
va_start(va,count);
|
||||
for(i=0; i<count; i++)
|
||||
{
|
||||
LPCWSTR str = va_arg(va,LPCWSTR);
|
||||
if (str)
|
||||
sz += strlenW(str) + 1;
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
dir = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));
|
||||
dir[0]=0;
|
||||
|
||||
va_start(va,count);
|
||||
for(i=0; i<count; i++)
|
||||
{
|
||||
LPCWSTR str = va_arg(va,LPCWSTR);
|
||||
if (!str)
|
||||
continue;
|
||||
strcatW(dir, str);
|
||||
if( ((i+1)!=count) && dir[strlenW(dir)-1]!='\\')
|
||||
strcatW(dir, cszbs);
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* create_full_pathW
|
||||
*
|
||||
* Recursively create all directories in the path.
|
||||
*
|
||||
* shamelessly stolen from setupapi/queue.c
|
||||
*/
|
||||
BOOL create_full_pathW(const WCHAR *path)
|
||||
{
|
||||
BOOL ret = TRUE;
|
||||
int len;
|
||||
WCHAR *new_path;
|
||||
|
||||
new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) *
|
||||
sizeof(WCHAR));
|
||||
|
||||
strcpyW(new_path, path);
|
||||
|
||||
while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
|
||||
new_path[len - 1] = 0;
|
||||
|
||||
while(!CreateDirectoryW(new_path, NULL))
|
||||
{
|
||||
WCHAR *slash;
|
||||
DWORD last_error = GetLastError();
|
||||
if(last_error == ERROR_ALREADY_EXISTS)
|
||||
break;
|
||||
|
||||
if(last_error != ERROR_PATH_NOT_FOUND)
|
||||
{
|
||||
ret = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!(slash = strrchrW(new_path, '\\')))
|
||||
{
|
||||
ret = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
len = slash - new_path;
|
||||
new_path[len] = 0;
|
||||
if(!create_full_pathW(new_path))
|
||||
{
|
||||
ret = FALSE;
|
||||
break;
|
||||
}
|
||||
new_path[len] = '\\';
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, new_path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d )
|
||||
{
|
||||
MSIRECORD * row;
|
||||
|
||||
row = MSI_CreateRecord(4);
|
||||
MSI_RecordSetInteger(row,1,a);
|
||||
MSI_RecordSetInteger(row,2,b);
|
||||
MSI_RecordSetInteger(row,3,c);
|
||||
MSI_RecordSetInteger(row,4,d);
|
||||
MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row);
|
||||
msiobj_release(&row->hdr);
|
||||
|
||||
msi_dialog_check_messages(NULL);
|
||||
}
|
||||
|
||||
void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
|
||||
{
|
||||
static const WCHAR Query_t[] =
|
||||
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
|
||||
'`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
|
||||
'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',
|
||||
' ','\'','%','s','\'',0};
|
||||
WCHAR message[1024];
|
||||
MSIRECORD * row = 0;
|
||||
DWORD size;
|
||||
static const WCHAR szActionData[] =
|
||||
{'A','c','t','i','o','n','D','a','t','a',0};
|
||||
|
||||
if (!package->LastAction || strcmpW(package->LastAction,action))
|
||||
{
|
||||
row = MSI_QueryGetRecord(package->db, Query_t, action);
|
||||
if (!row)
|
||||
return;
|
||||
|
||||
if (MSI_RecordIsNull(row,3))
|
||||
{
|
||||
msiobj_release(&row->hdr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* update the cached actionformat */
|
||||
HeapFree(GetProcessHeap(),0,package->ActionFormat);
|
||||
package->ActionFormat = load_dynamic_stringW(row,3);
|
||||
|
||||
HeapFree(GetProcessHeap(),0,package->LastAction);
|
||||
package->LastAction = strdupW(action);
|
||||
|
||||
msiobj_release(&row->hdr);
|
||||
}
|
||||
|
||||
MSI_RecordSetStringW(record,0,package->ActionFormat);
|
||||
size = 1024;
|
||||
MSI_FormatRecordW(package,record,message,&size);
|
||||
|
||||
row = MSI_CreateRecord(1);
|
||||
MSI_RecordSetStringW(row,1,message);
|
||||
|
||||
MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
|
||||
|
||||
ControlEvent_FireSubscribedEvent(package,szActionData, row);
|
||||
|
||||
msiobj_release(&row->hdr);
|
||||
}
|
||||
|
||||
BOOL ACTION_VerifyComponentForAction(MSIPACKAGE* package, INT index,
|
||||
INSTALLSTATE check )
|
||||
{
|
||||
if (package->components[index].Installed == check)
|
||||
return FALSE;
|
||||
|
||||
if (package->components[index].ActionRequest == check)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE* package, INT index,
|
||||
INSTALLSTATE check )
|
||||
{
|
||||
if (package->features[index].Installed == check)
|
||||
return FALSE;
|
||||
|
||||
if (package->features[index].ActionRequest == check)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void reduce_to_longfilename(WCHAR* filename)
|
||||
{
|
||||
LPWSTR p = strchrW(filename,'|');
|
||||
if (p)
|
||||
memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR));
|
||||
}
|
||||
|
||||
void reduce_to_shortfilename(WCHAR* filename)
|
||||
{
|
||||
LPWSTR p = strchrW(filename,'|');
|
||||
if (p)
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
LPWSTR create_component_advertise_string(MSIPACKAGE* package,
|
||||
MSICOMPONENT* component, LPCWSTR feature)
|
||||
{
|
||||
LPWSTR productid=NULL;
|
||||
GUID clsid;
|
||||
WCHAR productid_85[21];
|
||||
WCHAR component_85[21];
|
||||
/*
|
||||
* I have a fair bit of confusion as to when a < is used and when a > is
|
||||
* used. I do not think i have it right...
|
||||
*
|
||||
* Ok it appears that the > is used if there is a guid for the compoenent
|
||||
* and the < is used if not.
|
||||
*/
|
||||
static WCHAR fmt1[] = {'%','s','%','s','<',0,0};
|
||||
static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0};
|
||||
LPWSTR output = NULL;
|
||||
DWORD sz = 0;
|
||||
|
||||
memset(productid_85,0,sizeof(productid_85));
|
||||
memset(component_85,0,sizeof(component_85));
|
||||
|
||||
productid = load_dynamic_property(package,szProductCode,NULL);
|
||||
CLSIDFromString(productid, &clsid);
|
||||
|
||||
encode_base85_guid(&clsid,productid_85);
|
||||
|
||||
CLSIDFromString(component->ComponentId, &clsid);
|
||||
encode_base85_guid(&clsid,component_85);
|
||||
|
||||
TRACE("Doing something with this... %s %s %s\n",
|
||||
debugstr_w(productid_85), debugstr_w(feature),
|
||||
debugstr_w(component_85));
|
||||
|
||||
sz = lstrlenW(productid_85) + lstrlenW(feature);
|
||||
if (component)
|
||||
sz += lstrlenW(component_85);
|
||||
|
||||
sz+=3;
|
||||
sz *= sizeof(WCHAR);
|
||||
|
||||
output = HeapAlloc(GetProcessHeap(),0,sz);
|
||||
memset(output,0,sz);
|
||||
|
||||
if (component)
|
||||
sprintfW(output,fmt2,productid_85,feature,component_85);
|
||||
else
|
||||
sprintfW(output,fmt1,productid_85,feature);
|
||||
|
||||
HeapFree(GetProcessHeap(),0,productid);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/* update compoennt state based on a feature change */
|
||||
void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
|
||||
{
|
||||
int i;
|
||||
INSTALLSTATE newstate;
|
||||
MSIFEATURE *feature;
|
||||
|
||||
i = get_loaded_feature(package,szFeature);
|
||||
if (i < 0)
|
||||
return;
|
||||
|
||||
feature = &package->features[i];
|
||||
newstate = feature->ActionRequest;
|
||||
|
||||
for( i = 0; i < feature->ComponentCount; i++)
|
||||
{
|
||||
MSICOMPONENT* component = &package->components[feature->Components[i]];
|
||||
|
||||
TRACE("MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)\n",
|
||||
newstate, debugstr_w(component->Component), component->Installed,
|
||||
component->Action, component->ActionRequest);
|
||||
|
||||
if (!component->Enabled)
|
||||
continue;
|
||||
else
|
||||
{
|
||||
if (newstate == INSTALLSTATE_LOCAL)
|
||||
{
|
||||
component->ActionRequest = INSTALLSTATE_LOCAL;
|
||||
component->Action = INSTALLSTATE_LOCAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
int j,k;
|
||||
|
||||
component->ActionRequest = newstate;
|
||||
component->Action = newstate;
|
||||
|
||||
/*if any other feature wants is local we need to set it local*/
|
||||
for (j = 0;
|
||||
j < package->loaded_features &&
|
||||
component->ActionRequest != INSTALLSTATE_LOCAL;
|
||||
j++)
|
||||
{
|
||||
for (k = 0; k < package->features[j].ComponentCount; k++)
|
||||
if ( package->features[j].Components[k] ==
|
||||
feature->Components[i] )
|
||||
{
|
||||
if (package->features[j].ActionRequest ==
|
||||
INSTALLSTATE_LOCAL)
|
||||
{
|
||||
TRACE("Saved by %s\n", debugstr_w(package->features[j].Feature));
|
||||
component->ActionRequest = INSTALLSTATE_LOCAL;
|
||||
component->Action = INSTALLSTATE_LOCAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TRACE("Result (%i): Component %s (Installed %i, Action %i, Request %i)\n",
|
||||
newstate, debugstr_w(component->Component), component->Installed,
|
||||
component->Action, component->ActionRequest);
|
||||
}
|
||||
}
|
|
@ -44,7 +44,7 @@ typedef struct tagMSIINSERTVIEW
|
|||
MSIDATABASE *db;
|
||||
BOOL bIsTemp;
|
||||
MSIVIEW *sv;
|
||||
value_list *vals;
|
||||
column_info *vals;
|
||||
} MSIINSERTVIEW;
|
||||
|
||||
static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
|
||||
|
@ -62,7 +62,7 @@ static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT
|
|||
* Merge a value_list and a record to create a second record.
|
||||
* Replace wildcard entries in the valuelist with values from the record
|
||||
*/
|
||||
static MSIRECORD *INSERT_merge_record( UINT fields, value_list *vl, MSIRECORD *rec )
|
||||
static MSIRECORD *INSERT_merge_record( UINT fields, column_info *vl, MSIRECORD *rec )
|
||||
{
|
||||
MSIRECORD *merged;
|
||||
DWORD wildcard_count = 1, i;
|
||||
|
@ -255,7 +255,7 @@ MSIVIEWOPS insert_ops =
|
|||
};
|
||||
|
||||
UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
||||
string_list *columns, value_list *values, BOOL temp )
|
||||
column_info *columns, column_info *values, BOOL temp )
|
||||
{
|
||||
MSIINSERTVIEW *iv = NULL;
|
||||
UINT r;
|
||||
|
|
587
reactos/lib/msi/install.c
Normal file
587
reactos/lib/msi/install.c
Normal file
|
@ -0,0 +1,587 @@
|
|||
/*
|
||||
* Implementation of the Microsoft Installer (msi.dll)
|
||||
*
|
||||
* Copyright 2005 Aric Stewart for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* Msi top level apis directly related to installs */
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "wine/debug.h"
|
||||
#include "msi.h"
|
||||
#include "msidefs.h"
|
||||
#include "msipriv.h"
|
||||
#include "winuser.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "action.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
/***********************************************************************
|
||||
* MsiDoActionA (MSI.@)
|
||||
*/
|
||||
UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
|
||||
{
|
||||
LPWSTR szwAction;
|
||||
UINT rc;
|
||||
|
||||
TRACE(" exteral attempt at action %s\n",szAction);
|
||||
|
||||
if (!szAction)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
if (hInstall == 0)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
szwAction = strdupAtoW(szAction);
|
||||
|
||||
if (!szwAction)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
|
||||
rc = MsiDoActionW(hInstall, szwAction);
|
||||
HeapFree(GetProcessHeap(),0,szwAction);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiDoActionW (MSI.@)
|
||||
*/
|
||||
UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
|
||||
{
|
||||
MSIPACKAGE *package;
|
||||
UINT ret = ERROR_INVALID_HANDLE;
|
||||
|
||||
TRACE(" external attempt at action %s \n",debugstr_w(szAction));
|
||||
|
||||
package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
|
||||
if( package )
|
||||
{
|
||||
ret = ACTION_PerformUIAction(package,szAction);
|
||||
msiobj_release( &package->hdr );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiGetTargetPathA (MSI.@)
|
||||
*/
|
||||
UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
|
||||
LPSTR szPathBuf, DWORD* pcchPathBuf)
|
||||
{
|
||||
LPWSTR szwFolder;
|
||||
LPWSTR szwPathBuf;
|
||||
UINT rc;
|
||||
|
||||
TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
|
||||
|
||||
if (!szFolder)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
if (hInstall == 0)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
szwFolder = strdupAtoW(szFolder);
|
||||
|
||||
if (!szwFolder)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
|
||||
|
||||
rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
|
||||
|
||||
WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
|
||||
*pcchPathBuf, NULL, NULL );
|
||||
|
||||
HeapFree(GetProcessHeap(),0,szwFolder);
|
||||
HeapFree(GetProcessHeap(),0,szwPathBuf);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiGetTargetPathW (MSI.@)
|
||||
*/
|
||||
UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
|
||||
szPathBuf, DWORD* pcchPathBuf)
|
||||
{
|
||||
LPWSTR path;
|
||||
UINT rc = ERROR_FUNCTION_FAILED;
|
||||
MSIPACKAGE *package;
|
||||
|
||||
TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
|
||||
|
||||
package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
|
||||
if (!package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
path = resolve_folder(package, szFolder, FALSE, FALSE, NULL);
|
||||
msiobj_release( &package->hdr );
|
||||
|
||||
if (path && (strlenW(path) > *pcchPathBuf))
|
||||
{
|
||||
*pcchPathBuf = strlenW(path)+1;
|
||||
rc = ERROR_MORE_DATA;
|
||||
}
|
||||
else if (path)
|
||||
{
|
||||
*pcchPathBuf = strlenW(path)+1;
|
||||
strcpyW(szPathBuf,path);
|
||||
TRACE("Returning Path %s\n",debugstr_w(path));
|
||||
rc = ERROR_SUCCESS;
|
||||
}
|
||||
HeapFree(GetProcessHeap(),0,path);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* MsiGetSourcePathA (MSI.@)
|
||||
*/
|
||||
UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder,
|
||||
LPSTR szPathBuf, DWORD* pcchPathBuf)
|
||||
{
|
||||
LPWSTR szwFolder;
|
||||
LPWSTR szwPathBuf;
|
||||
UINT rc;
|
||||
|
||||
TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
|
||||
|
||||
if (!szFolder)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
if (hInstall == 0)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
szwFolder = strdupAtoW(szFolder);
|
||||
if (!szwFolder)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
|
||||
|
||||
rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
|
||||
|
||||
WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
|
||||
*pcchPathBuf, NULL, NULL );
|
||||
|
||||
HeapFree(GetProcessHeap(),0,szwFolder);
|
||||
HeapFree(GetProcessHeap(),0,szwPathBuf);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiGetSourcePathW (MSI.@)
|
||||
*/
|
||||
UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
|
||||
szPathBuf, DWORD* pcchPathBuf)
|
||||
{
|
||||
LPWSTR path;
|
||||
UINT rc = ERROR_FUNCTION_FAILED;
|
||||
MSIPACKAGE *package;
|
||||
|
||||
TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
|
||||
|
||||
package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
|
||||
if( !package )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
path = resolve_folder(package, szFolder, TRUE, FALSE, NULL);
|
||||
msiobj_release( &package->hdr );
|
||||
|
||||
if (path && strlenW(path) > *pcchPathBuf)
|
||||
{
|
||||
*pcchPathBuf = strlenW(path)+1;
|
||||
rc = ERROR_MORE_DATA;
|
||||
}
|
||||
else if (path)
|
||||
{
|
||||
*pcchPathBuf = strlenW(path)+1;
|
||||
strcpyW(szPathBuf,path);
|
||||
TRACE("Returning Path %s\n",debugstr_w(path));
|
||||
rc = ERROR_SUCCESS;
|
||||
}
|
||||
HeapFree(GetProcessHeap(),0,path);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* MsiSetTargetPathA (MSI.@)
|
||||
*/
|
||||
UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder,
|
||||
LPCSTR szFolderPath)
|
||||
{
|
||||
LPWSTR szwFolder;
|
||||
LPWSTR szwFolderPath;
|
||||
UINT rc;
|
||||
|
||||
if (!szFolder)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
if (hInstall == 0)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
szwFolder = strdupAtoW(szFolder);
|
||||
if (!szwFolder)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
szwFolderPath = strdupAtoW(szFolderPath);
|
||||
if (!szwFolderPath)
|
||||
{
|
||||
HeapFree(GetProcessHeap(),0,szwFolder);
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);
|
||||
|
||||
HeapFree(GetProcessHeap(),0,szwFolder);
|
||||
HeapFree(GetProcessHeap(),0,szwFolderPath);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ok my original interpretation of this was wrong. And it looks like msdn has
|
||||
* changed a bit also. The given folder path does not have to actually already
|
||||
* exist, it just cannot be read only and must be a legal folder path.
|
||||
*/
|
||||
UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
|
||||
LPCWSTR szFolderPath)
|
||||
{
|
||||
DWORD i;
|
||||
DWORD attrib;
|
||||
LPWSTR path = NULL;
|
||||
LPWSTR path2 = NULL;
|
||||
MSIFOLDER *folder;
|
||||
|
||||
TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
|
||||
|
||||
if (package==NULL)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
if (szFolderPath[0]==0)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
attrib = GetFileAttributesW(szFolderPath);
|
||||
if ( attrib != INVALID_FILE_ATTRIBUTES &&
|
||||
(!(attrib & FILE_ATTRIBUTE_DIRECTORY) ||
|
||||
attrib & FILE_ATTRIBUTE_OFFLINE ||
|
||||
attrib & FILE_ATTRIBUTE_READONLY))
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
path = resolve_folder(package,szFolder,FALSE,FALSE,&folder);
|
||||
|
||||
if (!path)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (attrib == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
if (!CreateDirectoryW(szFolderPath,NULL))
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
RemoveDirectoryW(szFolderPath);
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(),0,folder->Property);
|
||||
folder->Property = build_directory_name(2, szFolderPath, NULL);
|
||||
|
||||
if (lstrcmpiW(path, folder->Property) == 0)
|
||||
{
|
||||
/*
|
||||
* Resolved Target has not really changed, so just
|
||||
* set this folder and do not recalculate everything.
|
||||
*/
|
||||
HeapFree(GetProcessHeap(),0,folder->ResolvedTarget);
|
||||
folder->ResolvedTarget = NULL;
|
||||
path2 = resolve_folder(package,szFolder,FALSE,TRUE,NULL);
|
||||
HeapFree(GetProcessHeap(),0,path2);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < package->loaded_folders; i++)
|
||||
{
|
||||
HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
|
||||
package->folders[i].ResolvedTarget=NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < package->loaded_folders; i++)
|
||||
{
|
||||
path2=resolve_folder(package, package->folders[i].Directory, FALSE,
|
||||
TRUE, NULL);
|
||||
HeapFree(GetProcessHeap(),0,path2);
|
||||
}
|
||||
}
|
||||
HeapFree(GetProcessHeap(),0,path);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiSetTargetPathW (MSI.@)
|
||||
*/
|
||||
UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
|
||||
LPCWSTR szFolderPath)
|
||||
{
|
||||
MSIPACKAGE *package;
|
||||
UINT ret;
|
||||
|
||||
TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
|
||||
|
||||
package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
|
||||
ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
|
||||
msiobj_release( &package->hdr );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiGetMode (MSI.@)
|
||||
*
|
||||
* Returns an internal installer state (if it is running in a mode iRunMode)
|
||||
*
|
||||
* PARAMS
|
||||
* hInstall [I] Handle to the installation
|
||||
* hRunMode [I] Checking run mode
|
||||
* MSIRUNMODE_ADMIN Administrative mode
|
||||
* MSIRUNMODE_ADVERTISE Advertisement mode
|
||||
* MSIRUNMODE_MAINTENANCE Maintenance mode
|
||||
* MSIRUNMODE_ROLLBACKENABLED Rollback is enabled
|
||||
* MSIRUNMODE_LOGENABLED Log file is writing
|
||||
* MSIRUNMODE_OPERATIONS Operations in progress??
|
||||
* MSIRUNMODE_REBOOTATEND We need to reboot after installation completed
|
||||
* MSIRUNMODE_REBOOTNOW We need to reboot to continue the installation
|
||||
* MSIRUNMODE_CABINET Files from cabinet are installed
|
||||
* MSIRUNMODE_SOURCESHORTNAMES Long names in source files is suppressed
|
||||
* MSIRUNMODE_TARGETSHORTNAMES Long names in destination files is suppressed
|
||||
* MSIRUNMODE_RESERVED11 Reserved
|
||||
* MSIRUNMODE_WINDOWS9X Running under Windows95/98
|
||||
* MSIRUNMODE_ZAWENABLED Demand installation is supported
|
||||
* MSIRUNMODE_RESERVED14 Reserved
|
||||
* MSIRUNMODE_RESERVED15 Reserved
|
||||
* MSIRUNMODE_SCHEDULED called from install script
|
||||
* MSIRUNMODE_ROLLBACK called from rollback script
|
||||
* MSIRUNMODE_COMMIT called from commit script
|
||||
*
|
||||
* RETURNS
|
||||
* In the state: TRUE
|
||||
* Not in the state: FALSE
|
||||
*
|
||||
*/
|
||||
|
||||
BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
|
||||
{
|
||||
FIXME("STUB (iRunMode=%i)\n",iRunMode);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiSetFeatureStateA (MSI.@)
|
||||
*
|
||||
* According to the docs, when this is called it immediately recalculates
|
||||
* all the component states as well
|
||||
*/
|
||||
UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
|
||||
INSTALLSTATE iState)
|
||||
{
|
||||
LPWSTR szwFeature = NULL;
|
||||
UINT rc;
|
||||
|
||||
szwFeature = strdupAtoW(szFeature);
|
||||
|
||||
if (!szwFeature)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
rc = MsiSetFeatureStateW(hInstall,szwFeature, iState);
|
||||
|
||||
HeapFree(GetProcessHeap(),0,szwFeature);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
|
||||
INSTALLSTATE iState)
|
||||
{
|
||||
INT index, i;
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
|
||||
TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
|
||||
|
||||
index = get_loaded_feature(package,szFeature);
|
||||
if (index < 0)
|
||||
return ERROR_UNKNOWN_FEATURE;
|
||||
|
||||
if (iState == INSTALLSTATE_ADVERTISED &&
|
||||
package->features[index].Attributes &
|
||||
msidbFeatureAttributesDisallowAdvertise)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
package->features[index].ActionRequest= iState;
|
||||
package->features[index].Action= iState;
|
||||
|
||||
ACTION_UpdateComponentStates(package,szFeature);
|
||||
|
||||
/* update all the features that are children of this feature */
|
||||
for (i = 0; i < package->loaded_features; i++)
|
||||
{
|
||||
if (strcmpW(szFeature, package->features[i].Feature_Parent) == 0)
|
||||
MSI_SetFeatureStateW(package, package->features[i].Feature, iState);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiSetFeatureStateW (MSI.@)
|
||||
*/
|
||||
UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
|
||||
INSTALLSTATE iState)
|
||||
{
|
||||
MSIPACKAGE* package;
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
|
||||
TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
|
||||
|
||||
package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
|
||||
if (!package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
rc = MSI_SetFeatureStateW(package,szFeature,iState);
|
||||
|
||||
msiobj_release( &package->hdr );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiGetFeatureStateA (MSI.@)
|
||||
*/
|
||||
UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature,
|
||||
INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
|
||||
{
|
||||
LPWSTR szwFeature = NULL;
|
||||
UINT rc;
|
||||
|
||||
szwFeature = strdupAtoW(szFeature);
|
||||
|
||||
rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
|
||||
|
||||
HeapFree( GetProcessHeap(), 0 , szwFeature);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
|
||||
INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
|
||||
{
|
||||
INT index;
|
||||
|
||||
index = get_loaded_feature(package,szFeature);
|
||||
if (index < 0)
|
||||
return ERROR_UNKNOWN_FEATURE;
|
||||
|
||||
if (piInstalled)
|
||||
*piInstalled = package->features[index].Installed;
|
||||
|
||||
if (piAction)
|
||||
*piAction = package->features[index].Action;
|
||||
|
||||
TRACE("returning %i %i\n",*piInstalled,*piAction);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiGetFeatureStateW (MSI.@)
|
||||
*/
|
||||
UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature,
|
||||
INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
|
||||
{
|
||||
MSIPACKAGE* package;
|
||||
UINT ret;
|
||||
|
||||
TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,
|
||||
piAction);
|
||||
|
||||
package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
|
||||
if (!package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
|
||||
msiobj_release( &package->hdr );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiGetComponentStateA (MSI.@)
|
||||
*/
|
||||
UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent,
|
||||
INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
|
||||
{
|
||||
LPWSTR szwComponent= NULL;
|
||||
UINT rc;
|
||||
|
||||
szwComponent= strdupAtoW(szComponent);
|
||||
|
||||
rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
|
||||
|
||||
HeapFree( GetProcessHeap(), 0 , szwComponent);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent,
|
||||
INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
|
||||
{
|
||||
INT index;
|
||||
|
||||
TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled,
|
||||
piAction);
|
||||
|
||||
index = get_loaded_component(package,szComponent);
|
||||
if (index < 0)
|
||||
return ERROR_UNKNOWN_COMPONENT;
|
||||
|
||||
if (piInstalled)
|
||||
*piInstalled = package->components[index].Installed;
|
||||
|
||||
if (piAction)
|
||||
*piAction = package->components[index].Action;
|
||||
|
||||
TRACE("states (%i, %i)\n",
|
||||
(piInstalled)?*piInstalled:-1,(piAction)?*piAction:-1);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiGetComponentStateW (MSI.@)
|
||||
*/
|
||||
UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent,
|
||||
INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
|
||||
{
|
||||
MSIPACKAGE* package;
|
||||
UINT ret;
|
||||
|
||||
TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
|
||||
piInstalled, piAction);
|
||||
|
||||
package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
|
||||
if (!package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
|
||||
msiobj_release( &package->hdr );
|
||||
return ret;
|
||||
}
|
|
@ -38,9 +38,6 @@
|
|||
#include "wine/unicode.h"
|
||||
#include "action.h"
|
||||
|
||||
UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf);
|
||||
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
/*
|
||||
|
@ -465,6 +462,7 @@ UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute,
|
|||
{
|
||||
LPWSTR szwProduct = NULL, szwAttribute = NULL, szwBuffer = NULL;
|
||||
UINT r = ERROR_OUTOFMEMORY;
|
||||
DWORD pcchwValueBuf = 0;
|
||||
|
||||
TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute),
|
||||
szBuffer, pcchValueBuf);
|
||||
|
@ -486,14 +484,17 @@ UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute,
|
|||
if( szBuffer )
|
||||
{
|
||||
szwBuffer = HeapAlloc( GetProcessHeap(), 0, (*pcchValueBuf) * sizeof(WCHAR) );
|
||||
pcchwValueBuf = *pcchValueBuf;
|
||||
if( !szwBuffer )
|
||||
goto end;
|
||||
}
|
||||
|
||||
r = MsiGetProductInfoW( szwProduct, szwAttribute, szwBuffer, pcchValueBuf );
|
||||
r = MsiGetProductInfoW( szwProduct, szwAttribute, szwBuffer,
|
||||
&pcchwValueBuf );
|
||||
|
||||
if( ERROR_SUCCESS == r )
|
||||
WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, *pcchValueBuf, NULL, NULL);
|
||||
*pcchValueBuf = WideCharToMultiByte(CP_ACP, 0, szwBuffer, pcchwValueBuf,
|
||||
szBuffer, *pcchValueBuf, NULL, NULL);
|
||||
|
||||
end:
|
||||
HeapFree( GetProcessHeap(), 0, szwProduct );
|
||||
|
@ -516,6 +517,10 @@ UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute,
|
|||
{'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
|
||||
static const WCHAR szAssignmentType[] =
|
||||
{'A','s','s','i','g','n','m','e','n','t','T','y','p','e',0};
|
||||
static const WCHAR szLanguage[] =
|
||||
{'L','a','n','g','u','a','g','e',0};
|
||||
static const WCHAR szProductLanguage[] =
|
||||
{'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
|
||||
|
||||
FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute),
|
||||
szBuffer, pcchValueBuf);
|
||||
|
@ -569,11 +574,25 @@ UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute,
|
|||
}
|
||||
else if (strcmpW(szAttribute, szAssignmentType)==0)
|
||||
{
|
||||
FIXME("0 (zero) if advertised, 1(one) if per machine.\n");
|
||||
FIXME("0 (zero) if advertised or per user , 1(one) if per machine.\n");
|
||||
if (szBuffer)
|
||||
szBuffer[0] = 1;
|
||||
{
|
||||
szBuffer[0] = '1';
|
||||
szBuffer[1] = 0;
|
||||
}
|
||||
if (pcchValueBuf)
|
||||
*pcchValueBuf = 1;
|
||||
r = ERROR_SUCCESS;
|
||||
}
|
||||
else if (strcmpW(szAttribute, szLanguage)==0)
|
||||
{
|
||||
r = MsiOpenProductW(szProduct, &hProduct);
|
||||
if (ERROR_SUCCESS != r)
|
||||
return r;
|
||||
|
||||
r = MsiGetPropertyW(hProduct, szProductLanguage, szBuffer, pcchValueBuf);
|
||||
MsiCloseHandle(hProduct);
|
||||
}
|
||||
else
|
||||
{
|
||||
r = MsiOpenProductW(szProduct, &hProduct);
|
||||
|
@ -820,7 +839,7 @@ INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf,
|
|||
return INSTALLSTATE_UNKNOWN;
|
||||
}
|
||||
|
||||
INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPSTR lpPathBuf,
|
||||
INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPWSTR lpPathBuf,
|
||||
DWORD *pcchBuf)
|
||||
{
|
||||
FIXME("%s %p %08lx\n", debugstr_w(szComponent), lpPathBuf, *pcchBuf);
|
||||
|
@ -968,11 +987,16 @@ INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent,
|
|||
}
|
||||
|
||||
if( pcchBuf && *pcchBuf > 0 )
|
||||
{
|
||||
lpwPathBuf = HeapAlloc( GetProcessHeap(), 0, *pcchBuf * sizeof(WCHAR));
|
||||
incoming_len = *pcchBuf;
|
||||
}
|
||||
else
|
||||
{
|
||||
lpwPathBuf = NULL;
|
||||
incoming_len = 0;
|
||||
}
|
||||
|
||||
incoming_len = *pcchBuf;
|
||||
rc = MsiGetComponentPathW(szwProduct, szwComponent, lpwPathBuf, pcchBuf);
|
||||
|
||||
HeapFree( GetProcessHeap(), 0, szwProduct);
|
||||
|
@ -1195,7 +1219,7 @@ UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
|
|||
lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0,
|
||||
lpLangBuf, pcchLangBuf?*pcchLangBuf:0);
|
||||
|
||||
dwVerLen = GetFileVersionInfoSizeW((LPWSTR)szFilePath, NULL);
|
||||
dwVerLen = GetFileVersionInfoSizeW(szFilePath, NULL);
|
||||
if( !dwVerLen )
|
||||
return GetLastError();
|
||||
|
||||
|
@ -1206,14 +1230,14 @@ UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
|
|||
goto end;
|
||||
}
|
||||
|
||||
if( !GetFileVersionInfoW((LPWSTR)szFilePath, 0, dwVerLen, lpVer) )
|
||||
if( !GetFileVersionInfoW(szFilePath, 0, dwVerLen, lpVer) )
|
||||
{
|
||||
ret = GetLastError();
|
||||
goto end;
|
||||
}
|
||||
if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf )
|
||||
{
|
||||
if( VerQueryValueW(lpVer, (LPWSTR)szVersionResource, (LPVOID*)&ffi, &puLen) &&
|
||||
if( VerQueryValueW(lpVer, szVersionResource, (LPVOID*)&ffi, &puLen) &&
|
||||
(puLen > 0) )
|
||||
{
|
||||
wsprintfW(tmp, szVersionFormat,
|
||||
|
@ -1267,7 +1291,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
|||
|
||||
typedef struct tagIClassFactoryImpl
|
||||
{
|
||||
IClassFactoryVtbl *lpVtbl;
|
||||
const IClassFactoryVtbl *lpVtbl;
|
||||
} IClassFactoryImpl;
|
||||
|
||||
static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface,
|
||||
|
@ -1305,7 +1329,7 @@ static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static IClassFactoryVtbl MsiCF_Vtbl =
|
||||
static const IClassFactoryVtbl MsiCF_Vtbl =
|
||||
{
|
||||
MsiCF_QueryInterface,
|
||||
MsiCF_AddRef,
|
||||
|
|
|
@ -158,8 +158,8 @@
|
|||
158 stdcall MsiViewClose(long)
|
||||
159 stdcall MsiViewExecute(long long)
|
||||
160 stdcall MsiViewFetch(long ptr)
|
||||
161 stub MsiViewGetErrorA
|
||||
162 stub MsiViewGetErrorW
|
||||
161 stdcall MsiViewGetErrorA(long ptr ptr)
|
||||
162 stdcall MsiViewGetErrorW(long ptr ptr)
|
||||
163 stdcall MsiViewModify(long long long)
|
||||
164 stdcall MsiDatabaseIsTablePersistentA(long str)
|
||||
165 stdcall MsiDatabaseIsTablePersistentW(long wstr)
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<library>gdi32</library>
|
||||
<library>advapi32</library>
|
||||
<library>shell32</library>
|
||||
<library>shlwapi</library>
|
||||
<library>winmm</library>
|
||||
<library>cabinet</library>
|
||||
<library>ole32</library>
|
||||
|
@ -22,6 +23,7 @@
|
|||
<library>version</library>
|
||||
<file>action.c</file>
|
||||
<file>appsearch.c</file>
|
||||
<file>classes.c</file>
|
||||
<file>cond.tab.c</file>
|
||||
<file>create.c</file>
|
||||
<file>custom.c</file>
|
||||
|
@ -29,9 +31,13 @@
|
|||
<file>delete.c</file>
|
||||
<file>dialog.c</file>
|
||||
<file>distinct.c</file>
|
||||
<file>events.c</file>
|
||||
<file>files.c</file>
|
||||
<file>format.c</file>
|
||||
<file>handle.c</file>
|
||||
<file>helpers.c</file>
|
||||
<file>insert.c</file>
|
||||
<file>install.c</file>
|
||||
<file>msi.c</file>
|
||||
<file>msiquery.c</file>
|
||||
<file>order.c</file>
|
||||
|
@ -47,6 +53,7 @@
|
|||
<file>table.c</file>
|
||||
<file>tokenize.c</file>
|
||||
<file>update.c</file>
|
||||
<file>upgrade.c</file>
|
||||
<file>where.c</file>
|
||||
<file>msi.spec</file>
|
||||
<file>msi.rc</file>
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include "msiquery.h"
|
||||
#include "objbase.h"
|
||||
#include "objidl.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "winnls.h"
|
||||
#include "wine/list.h"
|
||||
|
||||
#define MSI_DATASIZEMASK 0x00ff
|
||||
|
@ -66,7 +66,7 @@ typedef struct tagMSIDATABASE
|
|||
MSIOBJECTHDR hdr;
|
||||
IStorage *storage;
|
||||
string_table *strings;
|
||||
LPWSTR mode;
|
||||
LPCWSTR mode;
|
||||
MSITABLE *first_table, *last_table;
|
||||
} MSIDATABASE;
|
||||
|
||||
|
@ -197,11 +197,20 @@ typedef struct tagMSIPACKAGE
|
|||
LPWSTR ActionFormat;
|
||||
LPWSTR LastAction;
|
||||
|
||||
LPWSTR *DeferredAction;
|
||||
UINT DeferredActionCount;
|
||||
|
||||
LPWSTR *CommitAction;
|
||||
UINT CommitActionCount;
|
||||
struct tagMSICLASS *classes;
|
||||
UINT loaded_classes;
|
||||
struct tagMSIEXTENSION *extensions;
|
||||
UINT loaded_extensions;
|
||||
struct tagMSIPROGID *progids;
|
||||
UINT loaded_progids;
|
||||
struct tagMSIVERB *verbs;
|
||||
UINT loaded_verbs;
|
||||
struct tagMSIMIME *mimes;
|
||||
UINT loaded_mimes;
|
||||
struct tagMSIAPPID *appids;
|
||||
UINT loaded_appids;
|
||||
|
||||
struct tagMSISCRIPT *script;
|
||||
|
||||
struct tagMSIRUNNINGACTION *RunningAction;
|
||||
UINT RunningActionCount;
|
||||
|
@ -211,8 +220,8 @@ typedef struct tagMSIPACKAGE
|
|||
UINT CurrentInstallState;
|
||||
msi_dialog *dialog;
|
||||
LPWSTR next_dialog;
|
||||
|
||||
BOOL ExecuteSequenceRun;
|
||||
|
||||
struct list subscriptions;
|
||||
} MSIPACKAGE;
|
||||
|
||||
typedef struct tagMSIPREVIEW
|
||||
|
@ -309,12 +318,17 @@ extern const WCHAR *MSI_RecordGetString( MSIRECORD *, unsigned int );
|
|||
extern MSIRECORD *MSI_CreateRecord( unsigned int );
|
||||
extern UINT MSI_RecordSetInteger( MSIRECORD *, unsigned int, int );
|
||||
extern UINT MSI_RecordSetStringW( MSIRECORD *, unsigned int, LPCWSTR );
|
||||
extern UINT MSI_RecordSetStringA( MSIRECORD *, unsigned int, LPCSTR );
|
||||
extern BOOL MSI_RecordIsNull( MSIRECORD *, unsigned int );
|
||||
extern UINT MSI_RecordGetStringW( MSIRECORD * , unsigned int, LPWSTR, DWORD *);
|
||||
extern UINT MSI_RecordGetStringA( MSIRECORD *, unsigned int, LPSTR, DWORD *);
|
||||
extern int MSI_RecordGetInteger( MSIRECORD *, unsigned int );
|
||||
extern UINT MSI_RecordReadStream( MSIRECORD *, unsigned int, char *, DWORD *);
|
||||
extern unsigned int MSI_RecordGetFieldCount( MSIRECORD *rec );
|
||||
extern UINT MSI_RecordSetStreamW( MSIRECORD *, unsigned int, LPCWSTR );
|
||||
extern UINT MSI_RecordSetStreamA( MSIRECORD *, unsigned int, LPCSTR );
|
||||
extern UINT MSI_RecordDataSize( MSIRECORD *, unsigned int );
|
||||
extern UINT MSI_RecordStreamToFile( MSIRECORD *, unsigned int, LPCWSTR );
|
||||
|
||||
/* stream internals */
|
||||
extern UINT get_raw_stream( MSIHANDLE hdb, LPCWSTR stname, IStream **stm );
|
||||
|
@ -325,8 +339,12 @@ extern void enum_stream_names( IStorage *stg );
|
|||
extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** );
|
||||
extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** );
|
||||
extern UINT MSI_OpenQuery( MSIDATABASE *, MSIQUERY **, LPCWSTR, ... );
|
||||
typedef UINT (*record_func)( MSIRECORD *rec, LPVOID param );
|
||||
typedef UINT (*record_func)( MSIRECORD *, LPVOID );
|
||||
extern UINT MSI_IterateRecords( MSIQUERY *, DWORD *, record_func, LPVOID );
|
||||
extern MSIRECORD *MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR query, ... );
|
||||
extern UINT MSI_DatabaseImport( MSIDATABASE *, LPCWSTR, LPCWSTR );
|
||||
extern UINT MSI_DatabaseExport( MSIDATABASE *, LPCWSTR, LPCWSTR, LPCWSTR );
|
||||
extern UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *, LPCWSTR, MSIRECORD ** );
|
||||
|
||||
/* view internals */
|
||||
extern UINT MSI_ViewExecute( MSIQUERY*, MSIRECORD * );
|
||||
|
@ -340,6 +358,7 @@ extern UINT MSI_SetTargetPathW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
|
|||
extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
|
||||
extern INT MSI_ProcessMessage( MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD * );
|
||||
extern UINT MSI_GetPropertyW( MSIPACKAGE *, LPCWSTR, LPWSTR, DWORD * );
|
||||
extern UINT MSI_GetPropertyA(MSIPACKAGE *, LPCSTR, LPSTR, DWORD* );
|
||||
extern MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *, LPCWSTR );
|
||||
extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
|
||||
extern UINT MSI_GetComponentStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE * );
|
||||
|
@ -347,8 +366,8 @@ extern UINT MSI_GetFeatureStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLS
|
|||
extern UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE*, LPCWSTR, INSTALLSTATE );
|
||||
|
||||
/* for deformating */
|
||||
extern UINT MSI_FormatRecordW(MSIPACKAGE* package, MSIRECORD* record,
|
||||
LPWSTR buffer, DWORD *size);
|
||||
extern UINT MSI_FormatRecordW( MSIPACKAGE *, MSIRECORD *, LPWSTR, DWORD * );
|
||||
extern UINT MSI_FormatRecordA( MSIPACKAGE *, MSIRECORD *, LPSTR, DWORD * );
|
||||
|
||||
/* registry data encoding/decoding functions */
|
||||
extern BOOL unsquash_guid(LPCWSTR in, LPWSTR out);
|
||||
|
@ -364,10 +383,12 @@ extern UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL cr
|
|||
extern UINT MSIREG_OpenComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
|
||||
extern UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create);
|
||||
|
||||
/* msi dialog interface */
|
||||
typedef VOID (*msi_dialog_event_handler)( MSIPACKAGE*, LPCWSTR, LPCWSTR, msi_dialog* );
|
||||
typedef UINT (*msi_dialog_event_handler)( MSIPACKAGE*, LPCWSTR, LPCWSTR, msi_dialog* );
|
||||
extern msi_dialog *msi_dialog_create( MSIPACKAGE*, LPCWSTR, msi_dialog_event_handler );
|
||||
extern UINT msi_dialog_run_message_loop( msi_dialog* );
|
||||
extern void msi_dialog_end_dialog( msi_dialog* );
|
||||
|
@ -376,6 +397,23 @@ extern void msi_dialog_do_preview( msi_dialog* );
|
|||
extern void msi_dialog_destroy( msi_dialog* );
|
||||
extern BOOL msi_dialog_register_class( void );
|
||||
extern void msi_dialog_unregister_class( void );
|
||||
extern void msi_dialog_handle_event( msi_dialog*, LPCWSTR, LPCWSTR, MSIRECORD * );
|
||||
|
||||
/* preview */
|
||||
extern MSIPREVIEW *MSI_EnableUIPreview( MSIDATABASE * );
|
||||
extern UINT MSI_PreviewDialogW( MSIPREVIEW *, LPCWSTR );
|
||||
|
||||
/* undocumented functions */
|
||||
UINT WINAPI MsiCreateAndVerifyInstallerDirectory( DWORD );
|
||||
UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR, LPWSTR, LPWSTR, LPWSTR, DWORD * );
|
||||
UINT WINAPI MsiDecomposeDescriptorA( LPCSTR, LPSTR, LPSTR, LPSTR, DWORD * );
|
||||
LANGID WINAPI MsiLoadStringW( MSIHANDLE, UINT, LPWSTR, int, LANGID );
|
||||
LANGID WINAPI MsiLoadStringA( MSIHANDLE, UINT, LPSTR, int, LANGID );
|
||||
|
||||
HRESULT WINAPI MSI_DllGetClassObject( REFCLSID, REFIID, LPVOID * );
|
||||
HRESULT WINAPI MSI_DllRegisterServer( void );
|
||||
HRESULT WINAPI MSI_DllUnregisterServer( void );
|
||||
BOOL WINAPI MSI_DllCanUnloadNow( void );
|
||||
|
||||
/* UI globals */
|
||||
extern INSTALLUILEVEL gUILevel;
|
||||
|
@ -415,8 +453,8 @@ inline static LPWSTR strdupW( LPCWSTR src )
|
|||
{
|
||||
LPWSTR dest;
|
||||
if (!src) return NULL;
|
||||
dest = HeapAlloc(GetProcessHeap(), 0, (strlenW(src)+1)*sizeof(WCHAR));
|
||||
strcpyW(dest, src);
|
||||
dest = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(src)+1)*sizeof(WCHAR));
|
||||
lstrcpyW(dest, src);
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
void MSI_CloseView( MSIOBJECTHDR *arg )
|
||||
static void MSI_CloseView( MSIOBJECTHDR *arg )
|
||||
{
|
||||
MSIQUERY *query = (MSIQUERY*) arg;
|
||||
struct list *ptr, *t;
|
||||
|
@ -139,7 +139,8 @@ UINT MSI_DatabaseOpenViewW(MSIDATABASE *db,
|
|||
return r;
|
||||
}
|
||||
|
||||
UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
|
||||
static UINT MSI_OpenQueryV( MSIDATABASE *db, MSIQUERY **view,
|
||||
LPCWSTR fmt, va_list args )
|
||||
{
|
||||
LPWSTR szQuery;
|
||||
LPCWSTR p;
|
||||
|
@ -147,7 +148,7 @@ UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
|
|||
va_list va;
|
||||
|
||||
/* figure out how much space we need to allocate */
|
||||
va_start(va, fmt);
|
||||
va = args;
|
||||
sz = lstrlenW(fmt) + 1;
|
||||
p = fmt;
|
||||
while (*p)
|
||||
|
@ -173,13 +174,11 @@ UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
|
|||
}
|
||||
p++;
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
/* construct the string */
|
||||
szQuery = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));
|
||||
va_start(va, fmt);
|
||||
va = args;
|
||||
vsnprintfW(szQuery, sz, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
/* perform the query */
|
||||
rc = MSI_DatabaseOpenViewW(db, szQuery, view);
|
||||
|
@ -187,6 +186,18 @@ UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
|
|||
return rc;
|
||||
}
|
||||
|
||||
UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... )
|
||||
{
|
||||
UINT r;
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
r = MSI_OpenQueryV( db, view, fmt, va );
|
||||
va_end(va);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
UINT MSI_IterateRecords( MSIQUERY *view, DWORD *count,
|
||||
record_func func, LPVOID param )
|
||||
{
|
||||
|
@ -223,6 +234,28 @@ UINT MSI_IterateRecords( MSIQUERY *view, DWORD *count,
|
|||
return r;
|
||||
}
|
||||
|
||||
/* return a single record from a query */
|
||||
MSIRECORD *MSI_QueryGetRecord( MSIDATABASE *db, LPCWSTR fmt, ... )
|
||||
{
|
||||
MSIRECORD *rec = NULL;
|
||||
MSIQUERY *view = NULL;
|
||||
UINT r;
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
r = MSI_OpenQueryV( db, &view, fmt, va );
|
||||
va_end(va);
|
||||
|
||||
if( r == ERROR_SUCCESS )
|
||||
{
|
||||
MSI_ViewExecute( view, NULL );
|
||||
MSI_ViewFetch( view, &rec );
|
||||
MSI_ViewClose( view );
|
||||
msiobj_release( &view->hdr );
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
|
||||
LPCWSTR szQuery, MSIHANDLE *phView)
|
||||
{
|
||||
|
@ -530,6 +563,42 @@ out:
|
|||
return r;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiViewGetErrorW( MSIHANDLE handle, LPWSTR szColumnNameBuffer,
|
||||
DWORD *pcchBuf )
|
||||
{
|
||||
MSIQUERY *query = NULL;
|
||||
|
||||
FIXME("%ld %p %p\n", handle, szColumnNameBuffer, pcchBuf );
|
||||
|
||||
if( !pcchBuf )
|
||||
return MSIDBERROR_INVALIDARG;
|
||||
|
||||
query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
|
||||
if( !query )
|
||||
return MSIDBERROR_INVALIDARG;
|
||||
|
||||
msiobj_release( &query->hdr );
|
||||
return MSIDBERROR_NOERROR;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiViewGetErrorA( MSIHANDLE handle, LPSTR szColumnNameBuffer,
|
||||
DWORD *pcchBuf )
|
||||
{
|
||||
MSIQUERY *query = NULL;
|
||||
|
||||
FIXME("%ld %p %p\n", handle, szColumnNameBuffer, pcchBuf );
|
||||
|
||||
if( !pcchBuf )
|
||||
return MSIDBERROR_INVALIDARG;
|
||||
|
||||
query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
|
||||
if( !query )
|
||||
return MSIDBERROR_INVALIDARG;
|
||||
|
||||
msiobj_release( &query->hdr );
|
||||
return MSIDBERROR_NOERROR;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb,
|
||||
LPCSTR szTransformFile, int iErrorCond)
|
||||
{
|
||||
|
|
|
@ -302,11 +302,11 @@ static UINT ORDER_AddColumn( MSIORDERVIEW *ov, LPCWSTR name )
|
|||
}
|
||||
|
||||
UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
|
||||
string_list *columns )
|
||||
column_info *columns )
|
||||
{
|
||||
MSIORDERVIEW *ov = NULL;
|
||||
UINT count = 0, r;
|
||||
string_list *x;
|
||||
column_info *x;
|
||||
|
||||
TRACE("%p\n", ov );
|
||||
|
||||
|
@ -332,7 +332,7 @@ UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
|
|||
*view = (MSIVIEW*) ov;
|
||||
|
||||
for( x = columns; x ; x = x->next )
|
||||
ORDER_AddColumn( ov, x->string );
|
||||
ORDER_AddColumn( ov, x->column );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
|||
*/
|
||||
#define LPCTSTR LPCWSTR
|
||||
|
||||
void MSI_FreePackage( MSIOBJECTHDR *arg)
|
||||
static void MSI_FreePackage( MSIOBJECTHDR *arg)
|
||||
{
|
||||
MSIPACKAGE *package= (MSIPACKAGE*) arg;
|
||||
|
||||
|
@ -389,6 +389,7 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db )
|
|||
package->LastAction = NULL;
|
||||
package->dialog = NULL;
|
||||
package->next_dialog = NULL;
|
||||
list_init( &package->subscriptions );
|
||||
|
||||
/* OK, here is where we do a slew of things to the database to
|
||||
* prep for all that is to come as a package */
|
||||
|
|
|
@ -82,11 +82,12 @@ UINT WINAPI MsiEnableUIPreview( MSIHANDLE hdb, MSIHANDLE* phPreview )
|
|||
return r;
|
||||
}
|
||||
|
||||
static VOID preview_event_handler( MSIPACKAGE *package, LPCWSTR event,
|
||||
static UINT preview_event_handler( MSIPACKAGE *package, LPCWSTR event,
|
||||
LPCWSTR argument, msi_dialog *dialog )
|
||||
{
|
||||
MESSAGE("Preview dialog event '%s' (arg='%s')\n",
|
||||
debugstr_w( event ), debugstr_w( argument ));
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
UINT MSI_PreviewDialogW( MSIPREVIEW *preview, LPCWSTR szDialogName )
|
||||
|
|
|
@ -59,11 +59,14 @@ struct sql_str {
|
|||
INT len;
|
||||
};
|
||||
|
||||
typedef struct _string_list
|
||||
typedef struct _column_info
|
||||
{
|
||||
LPWSTR string;
|
||||
struct _string_list *next;
|
||||
} string_list;
|
||||
LPCWSTR table;
|
||||
LPCWSTR column;
|
||||
UINT type;
|
||||
struct expr *val;
|
||||
struct _column_info *next;
|
||||
} column_info;
|
||||
|
||||
struct complex_expr
|
||||
{
|
||||
|
@ -80,56 +83,36 @@ struct expr
|
|||
struct complex_expr expr;
|
||||
INT ival;
|
||||
UINT uval;
|
||||
LPWSTR sval;
|
||||
LPWSTR column;
|
||||
LPCWSTR sval;
|
||||
LPCWSTR column;
|
||||
UINT col_number;
|
||||
} u;
|
||||
};
|
||||
|
||||
typedef struct _create_col_info
|
||||
{
|
||||
LPWSTR colname;
|
||||
UINT type;
|
||||
struct _create_col_info *next;
|
||||
} create_col_info;
|
||||
|
||||
typedef struct _value_list
|
||||
{
|
||||
struct expr *val;
|
||||
struct _value_list *next;
|
||||
} value_list;
|
||||
|
||||
typedef struct _column_assignment
|
||||
{
|
||||
string_list *col_list;
|
||||
value_list *val_list;
|
||||
} column_assignment;
|
||||
|
||||
|
||||
UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview,
|
||||
struct list *mem );
|
||||
|
||||
UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view );
|
||||
|
||||
UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
|
||||
string_list *columns );
|
||||
column_info *columns );
|
||||
|
||||
UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table );
|
||||
|
||||
UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
|
||||
string_list *columns );
|
||||
column_info *columns );
|
||||
|
||||
UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
|
||||
struct expr *cond );
|
||||
|
||||
UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
||||
create_col_info *col_info, BOOL temp );
|
||||
column_info *col_info, BOOL temp );
|
||||
|
||||
UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
||||
string_list *columns, value_list *values, BOOL temp );
|
||||
column_info *columns, column_info *values, BOOL temp );
|
||||
|
||||
UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **, LPWSTR table,
|
||||
column_assignment *list, struct expr *expr );
|
||||
column_info *list, struct expr *expr );
|
||||
|
||||
UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table );
|
||||
|
||||
|
|
|
@ -34,6 +34,9 @@
|
|||
#include "winnls.h"
|
||||
#include "ole2.h"
|
||||
|
||||
#include "winreg.h"
|
||||
#include "shlwapi.h"
|
||||
|
||||
#include "query.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
@ -44,7 +47,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
|||
#define MSIFIELD_WSTR 3
|
||||
#define MSIFIELD_STREAM 4
|
||||
|
||||
void MSI_FreeField( MSIFIELD *field )
|
||||
static void MSI_FreeField( MSIFIELD *field )
|
||||
{
|
||||
switch( field->type )
|
||||
{
|
||||
|
@ -62,7 +65,7 @@ void MSI_FreeField( MSIFIELD *field )
|
|||
}
|
||||
}
|
||||
|
||||
void MSI_CloseRecord( MSIOBJECTHDR *arg )
|
||||
static void MSI_CloseRecord( MSIOBJECTHDR *arg )
|
||||
{
|
||||
MSIRECORD *rec = (MSIRECORD *) arg;
|
||||
UINT i;
|
||||
|
@ -410,6 +413,17 @@ UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, unsigned int iField,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static UINT msi_get_stream_size( IStream *stm )
|
||||
{
|
||||
STATSTG stat;
|
||||
HRESULT r;
|
||||
|
||||
r = IStream_Stat( stm, &stat, STATFLAG_NONAME );
|
||||
if( FAILED(r) )
|
||||
return 0;
|
||||
return stat.cbSize.QuadPart;
|
||||
}
|
||||
|
||||
UINT MSI_RecordDataSize(MSIRECORD *rec, unsigned int iField)
|
||||
{
|
||||
TRACE("%p %d\n", rec, iField);
|
||||
|
@ -425,6 +439,8 @@ UINT MSI_RecordDataSize(MSIRECORD *rec, unsigned int iField)
|
|||
return lstrlenW( rec->fields[iField].u.szwVal );
|
||||
case MSIFIELD_NULL:
|
||||
break;
|
||||
case MSIFIELD_STREAM:
|
||||
return msi_get_stream_size( rec->fields[iField].u.stream );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -533,7 +549,7 @@ UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, unsigned int iField, LPCWSTR
|
|||
}
|
||||
|
||||
/* read the data in a file into an IStream */
|
||||
UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
|
||||
static UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
|
||||
{
|
||||
DWORD sz, szHighWord = 0, read;
|
||||
HANDLE handle;
|
||||
|
@ -761,3 +777,56 @@ UINT MSI_RecordGetIStream( MSIRECORD *rec, unsigned int iField, IStream **pstm)
|
|||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT msi_dump_stream_to_file( IStream *stm, LPCWSTR name )
|
||||
{
|
||||
ULARGE_INTEGER size;
|
||||
LARGE_INTEGER pos;
|
||||
IStream *out;
|
||||
DWORD stgm;
|
||||
HRESULT r;
|
||||
|
||||
stgm = STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_FAILIFTHERE;
|
||||
r = SHCreateStreamOnFileW( name, stgm, &out );
|
||||
if( FAILED( r ) )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
pos.QuadPart = 0;
|
||||
r = IStream_Seek( stm, pos, STREAM_SEEK_END, &size );
|
||||
if( FAILED( r ) )
|
||||
goto end;
|
||||
|
||||
pos.QuadPart = 0;
|
||||
r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL );
|
||||
if( FAILED( r ) )
|
||||
goto end;
|
||||
|
||||
r = IStream_CopyTo( stm, out, size, NULL, NULL );
|
||||
|
||||
end:
|
||||
IStream_Release( out );
|
||||
if( FAILED( r ) )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
UINT MSI_RecordStreamToFile( MSIRECORD *rec, unsigned int iField, LPCWSTR name )
|
||||
{
|
||||
IStream *stm = NULL;
|
||||
UINT r;
|
||||
|
||||
TRACE("%p %u %s\n", rec, iField, debugstr_w(name));
|
||||
|
||||
msiobj_lock( &rec->hdr );
|
||||
|
||||
r = MSI_RecordGetIStream( rec, iField, &stm );
|
||||
if( r == ERROR_SUCCESS )
|
||||
{
|
||||
r = msi_dump_stream_to_file( stm, name );
|
||||
IStream_Release( stm );
|
||||
}
|
||||
|
||||
msiobj_unlock( &rec->hdr );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -141,6 +141,20 @@ static const WCHAR szInstaller_UpgradeCodes_fmt[] = {
|
|||
'U','p','g','r','a','d','e','C','o','d','e','s','\\',
|
||||
'%','s',0};
|
||||
|
||||
static const WCHAR szInstaller_UserUpgradeCodes[] = {
|
||||
'S','o','f','t','w','a','r','e','\\',
|
||||
'M','i','c','r','o','s','o','f','t','\\',
|
||||
'I','n','s','t','a','l','l','e','r','\\',
|
||||
'U','p','g','r','a','d','e','C','o','d','e','s',0};
|
||||
|
||||
static const WCHAR szInstaller_UserUpgradeCodes_fmt[] = {
|
||||
'S','o','f','t','w','a','r','e','\\',
|
||||
'M','i','c','r','o','s','o','f','t','\\',
|
||||
'I','n','s','t','a','l','l','e','r','\\',
|
||||
'U','p','g','r','a','d','e','C','o','d','e','s','\\',
|
||||
'%','s',0};
|
||||
|
||||
|
||||
#define SQUISH_GUID_SIZE 33
|
||||
|
||||
BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
|
||||
|
@ -455,6 +469,27 @@ UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
|
|||
return rc;
|
||||
}
|
||||
|
||||
UINT MSIREG_OpenUserUpgradeCodesKey(LPCWSTR szUpgradeCode, HKEY* key, BOOL create)
|
||||
{
|
||||
UINT rc;
|
||||
WCHAR squished_pc[GUID_SIZE];
|
||||
WCHAR keypath[0x200];
|
||||
|
||||
TRACE("%s\n",debugstr_w(szUpgradeCode));
|
||||
squash_guid(szUpgradeCode,squished_pc);
|
||||
TRACE("squished (%s)\n", debugstr_w(squished_pc));
|
||||
|
||||
sprintfW(keypath,szInstaller_UserUpgradeCodes_fmt,squished_pc);
|
||||
|
||||
if (create)
|
||||
rc = RegCreateKeyW(HKEY_CURRENT_USER,keypath,key);
|
||||
else
|
||||
rc = RegOpenKeyW(HKEY_CURRENT_USER,keypath,key);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* MsiDecomposeDescriptorW [MSI.@]
|
||||
*
|
||||
|
|
|
@ -210,7 +210,7 @@ MSIVIEWOPS select_ops =
|
|||
SELECT_delete
|
||||
};
|
||||
|
||||
static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPWSTR name )
|
||||
static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPCWSTR name )
|
||||
{
|
||||
UINT r, n=0;
|
||||
MSIVIEW *table;
|
||||
|
@ -245,7 +245,7 @@ static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPWSTR name )
|
|||
}
|
||||
|
||||
UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
|
||||
string_list *columns )
|
||||
column_info *columns )
|
||||
{
|
||||
MSISELECTVIEW *sv = NULL;
|
||||
UINT count = 0, r;
|
||||
|
@ -273,7 +273,7 @@ UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
|
|||
|
||||
while( columns )
|
||||
{
|
||||
r = SELECT_AddColumn( sv, columns->string );
|
||||
r = SELECT_AddColumn( sv, columns->column );
|
||||
if( r )
|
||||
break;
|
||||
columns = columns->next;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,347 +1,163 @@
|
|||
/* A Bison parser, made by GNU Bison 1.875b. */
|
||||
#ifndef BISON_SQL_TAB_H
|
||||
# define BISON_SQL_TAB_H
|
||||
|
||||
/* Skeleton parser for Yacc-like parsing with Bison,
|
||||
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* As a special exception, when this file is copied by Bison into a
|
||||
Bison output file, you may use that output file without restriction.
|
||||
This special exception was added by the Free Software Foundation
|
||||
in version 1.24 of Bison. */
|
||||
|
||||
/* Tokens. */
|
||||
#ifndef YYTOKENTYPE
|
||||
# define YYTOKENTYPE
|
||||
/* Put the tokens into the symbol table, so that GDB and other debuggers
|
||||
know about them. */
|
||||
enum yytokentype {
|
||||
TK_ABORT = 258,
|
||||
TK_AFTER = 259,
|
||||
TK_AGG_FUNCTION = 260,
|
||||
TK_ALL = 261,
|
||||
TK_AND = 262,
|
||||
TK_AS = 263,
|
||||
TK_ASC = 264,
|
||||
TK_BEFORE = 265,
|
||||
TK_BEGIN = 266,
|
||||
TK_BETWEEN = 267,
|
||||
TK_BITAND = 268,
|
||||
TK_BITNOT = 269,
|
||||
TK_BITOR = 270,
|
||||
TK_BY = 271,
|
||||
TK_CASCADE = 272,
|
||||
TK_CASE = 273,
|
||||
TK_CHAR = 274,
|
||||
TK_CHECK = 275,
|
||||
TK_CLUSTER = 276,
|
||||
TK_COLLATE = 277,
|
||||
TK_COLUMN = 278,
|
||||
TK_COMMA = 279,
|
||||
TK_COMMENT = 280,
|
||||
TK_COMMIT = 281,
|
||||
TK_CONCAT = 282,
|
||||
TK_CONFLICT = 283,
|
||||
TK_CONSTRAINT = 284,
|
||||
TK_COPY = 285,
|
||||
TK_CREATE = 286,
|
||||
TK_DEFAULT = 287,
|
||||
TK_DEFERRABLE = 288,
|
||||
TK_DEFERRED = 289,
|
||||
TK_DELETE = 290,
|
||||
TK_DELIMITERS = 291,
|
||||
TK_DESC = 292,
|
||||
TK_DISTINCT = 293,
|
||||
TK_DOT = 294,
|
||||
TK_DROP = 295,
|
||||
TK_EACH = 296,
|
||||
TK_ELSE = 297,
|
||||
TK_END = 298,
|
||||
TK_END_OF_FILE = 299,
|
||||
TK_EQ = 300,
|
||||
TK_EXCEPT = 301,
|
||||
TK_EXPLAIN = 302,
|
||||
TK_FAIL = 303,
|
||||
TK_FLOAT = 304,
|
||||
TK_FOR = 305,
|
||||
TK_FOREIGN = 306,
|
||||
TK_FROM = 307,
|
||||
TK_FUNCTION = 308,
|
||||
TK_GE = 309,
|
||||
TK_GLOB = 310,
|
||||
TK_GROUP = 311,
|
||||
TK_GT = 312,
|
||||
TK_HAVING = 313,
|
||||
TK_HOLD = 314,
|
||||
TK_IGNORE = 315,
|
||||
TK_ILLEGAL = 316,
|
||||
TK_IMMEDIATE = 317,
|
||||
TK_IN = 318,
|
||||
TK_INDEX = 319,
|
||||
TK_INITIALLY = 320,
|
||||
TK_ID = 321,
|
||||
TK_INSERT = 322,
|
||||
TK_INSTEAD = 323,
|
||||
TK_INT = 324,
|
||||
TK_INTEGER = 325,
|
||||
TK_INTERSECT = 326,
|
||||
TK_INTO = 327,
|
||||
TK_IS = 328,
|
||||
TK_ISNULL = 329,
|
||||
TK_JOIN = 330,
|
||||
TK_JOIN_KW = 331,
|
||||
TK_KEY = 332,
|
||||
TK_LE = 333,
|
||||
TK_LIKE = 334,
|
||||
TK_LIMIT = 335,
|
||||
TK_LONG = 336,
|
||||
TK_LONGCHAR = 337,
|
||||
TK_LP = 338,
|
||||
TK_LSHIFT = 339,
|
||||
TK_LT = 340,
|
||||
TK_LOCALIZABLE = 341,
|
||||
TK_MATCH = 342,
|
||||
TK_MINUS = 343,
|
||||
TK_NE = 344,
|
||||
TK_NOT = 345,
|
||||
TK_NOTNULL = 346,
|
||||
TK_NULL = 347,
|
||||
TK_OBJECT = 348,
|
||||
TK_OF = 349,
|
||||
TK_OFFSET = 350,
|
||||
TK_ON = 351,
|
||||
TK_OR = 352,
|
||||
TK_ORACLE_OUTER_JOIN = 353,
|
||||
TK_ORDER = 354,
|
||||
TK_PLUS = 355,
|
||||
TK_PRAGMA = 356,
|
||||
TK_PRIMARY = 357,
|
||||
TK_RAISE = 358,
|
||||
TK_REFERENCES = 359,
|
||||
TK_REM = 360,
|
||||
TK_REPLACE = 361,
|
||||
TK_RESTRICT = 362,
|
||||
TK_ROLLBACK = 363,
|
||||
TK_ROW = 364,
|
||||
TK_RP = 365,
|
||||
TK_RSHIFT = 366,
|
||||
TK_SELECT = 367,
|
||||
TK_SEMI = 368,
|
||||
TK_SET = 369,
|
||||
TK_SHORT = 370,
|
||||
TK_SLASH = 371,
|
||||
TK_SPACE = 372,
|
||||
TK_STAR = 373,
|
||||
TK_STATEMENT = 374,
|
||||
TK_STRING = 375,
|
||||
TK_TABLE = 376,
|
||||
TK_TEMP = 377,
|
||||
TK_THEN = 378,
|
||||
TK_TRANSACTION = 379,
|
||||
TK_TRIGGER = 380,
|
||||
TK_UMINUS = 381,
|
||||
TK_UNCLOSED_STRING = 382,
|
||||
TK_UNION = 383,
|
||||
TK_UNIQUE = 384,
|
||||
TK_UPDATE = 385,
|
||||
TK_UPLUS = 386,
|
||||
TK_USING = 387,
|
||||
TK_VACUUM = 388,
|
||||
TK_VALUES = 389,
|
||||
TK_VIEW = 390,
|
||||
TK_WHEN = 391,
|
||||
TK_WHERE = 392,
|
||||
TK_WILDCARD = 393,
|
||||
COLUMN = 395,
|
||||
FUNCTION = 396,
|
||||
COMMENT = 397,
|
||||
UNCLOSED_STRING = 398,
|
||||
SPACE = 399,
|
||||
ILLEGAL = 400,
|
||||
END_OF_FILE = 401
|
||||
};
|
||||
#endif
|
||||
#define TK_ABORT 258
|
||||
#define TK_AFTER 259
|
||||
#define TK_AGG_FUNCTION 260
|
||||
#define TK_ALL 261
|
||||
#define TK_AND 262
|
||||
#define TK_AS 263
|
||||
#define TK_ASC 264
|
||||
#define TK_BEFORE 265
|
||||
#define TK_BEGIN 266
|
||||
#define TK_BETWEEN 267
|
||||
#define TK_BITAND 268
|
||||
#define TK_BITNOT 269
|
||||
#define TK_BITOR 270
|
||||
#define TK_BY 271
|
||||
#define TK_CASCADE 272
|
||||
#define TK_CASE 273
|
||||
#define TK_CHAR 274
|
||||
#define TK_CHECK 275
|
||||
#define TK_CLUSTER 276
|
||||
#define TK_COLLATE 277
|
||||
#define TK_COLUMN 278
|
||||
#define TK_COMMA 279
|
||||
#define TK_COMMENT 280
|
||||
#define TK_COMMIT 281
|
||||
#define TK_CONCAT 282
|
||||
#define TK_CONFLICT 283
|
||||
#define TK_CONSTRAINT 284
|
||||
#define TK_COPY 285
|
||||
#define TK_CREATE 286
|
||||
#define TK_DEFAULT 287
|
||||
#define TK_DEFERRABLE 288
|
||||
#define TK_DEFERRED 289
|
||||
#define TK_DELETE 290
|
||||
#define TK_DELIMITERS 291
|
||||
#define TK_DESC 292
|
||||
#define TK_DISTINCT 293
|
||||
#define TK_DOT 294
|
||||
#define TK_DROP 295
|
||||
#define TK_EACH 296
|
||||
#define TK_ELSE 297
|
||||
#define TK_END 298
|
||||
#define TK_END_OF_FILE 299
|
||||
#define TK_EQ 300
|
||||
#define TK_EXCEPT 301
|
||||
#define TK_EXPLAIN 302
|
||||
#define TK_FAIL 303
|
||||
#define TK_FLOAT 304
|
||||
#define TK_FOR 305
|
||||
#define TK_FOREIGN 306
|
||||
#define TK_FROM 307
|
||||
#define TK_FUNCTION 308
|
||||
#define TK_GE 309
|
||||
#define TK_GLOB 310
|
||||
#define TK_GROUP 311
|
||||
#define TK_GT 312
|
||||
#define TK_HAVING 313
|
||||
#define TK_HOLD 314
|
||||
#define TK_IGNORE 315
|
||||
#define TK_ILLEGAL 316
|
||||
#define TK_IMMEDIATE 317
|
||||
#define TK_IN 318
|
||||
#define TK_INDEX 319
|
||||
#define TK_INITIALLY 320
|
||||
#define TK_ID 321
|
||||
#define TK_INSERT 322
|
||||
#define TK_INSTEAD 323
|
||||
#define TK_INT 324
|
||||
#define TK_INTEGER 325
|
||||
#define TK_INTERSECT 326
|
||||
#define TK_INTO 327
|
||||
#define TK_IS 328
|
||||
#define TK_ISNULL 329
|
||||
#define TK_JOIN 330
|
||||
#define TK_JOIN_KW 331
|
||||
#define TK_KEY 332
|
||||
#define TK_LE 333
|
||||
#define TK_LIKE 334
|
||||
#define TK_LIMIT 335
|
||||
#define TK_LONG 336
|
||||
#define TK_LONGCHAR 337
|
||||
#define TK_LP 338
|
||||
#define TK_LSHIFT 339
|
||||
#define TK_LT 340
|
||||
#define TK_LOCALIZABLE 341
|
||||
#define TK_MATCH 342
|
||||
#define TK_MINUS 343
|
||||
#define TK_NE 344
|
||||
#define TK_NOT 345
|
||||
#define TK_NOTNULL 346
|
||||
#define TK_NULL 347
|
||||
#define TK_OBJECT 348
|
||||
#define TK_OF 349
|
||||
#define TK_OFFSET 350
|
||||
#define TK_ON 351
|
||||
#define TK_OR 352
|
||||
#define TK_ORACLE_OUTER_JOIN 353
|
||||
#define TK_ORDER 354
|
||||
#define TK_PLUS 355
|
||||
#define TK_PRAGMA 356
|
||||
#define TK_PRIMARY 357
|
||||
#define TK_RAISE 358
|
||||
#define TK_REFERENCES 359
|
||||
#define TK_REM 360
|
||||
#define TK_REPLACE 361
|
||||
#define TK_RESTRICT 362
|
||||
#define TK_ROLLBACK 363
|
||||
#define TK_ROW 364
|
||||
#define TK_RP 365
|
||||
#define TK_RSHIFT 366
|
||||
#define TK_SELECT 367
|
||||
#define TK_SEMI 368
|
||||
#define TK_SET 369
|
||||
#define TK_SHORT 370
|
||||
#define TK_SLASH 371
|
||||
#define TK_SPACE 372
|
||||
#define TK_STAR 373
|
||||
#define TK_STATEMENT 374
|
||||
#define TK_STRING 375
|
||||
#define TK_TABLE 376
|
||||
#define TK_TEMP 377
|
||||
#define TK_THEN 378
|
||||
#define TK_TRANSACTION 379
|
||||
#define TK_TRIGGER 380
|
||||
#define TK_UMINUS 381
|
||||
#define TK_UNCLOSED_STRING 382
|
||||
#define TK_UNION 383
|
||||
#define TK_UNIQUE 384
|
||||
#define TK_UPDATE 385
|
||||
#define TK_UPLUS 386
|
||||
#define TK_USING 387
|
||||
#define TK_VACUUM 388
|
||||
#define TK_VALUES 389
|
||||
#define TK_VIEW 390
|
||||
#define TK_WHEN 391
|
||||
#define TK_WHERE 392
|
||||
#define TK_WILDCARD 393
|
||||
#define COLUMN 395
|
||||
#define FUNCTION 396
|
||||
#define COMMENT 397
|
||||
#define UNCLOSED_STRING 398
|
||||
#define SPACE 399
|
||||
#define ILLEGAL 400
|
||||
#define END_OF_FILE 401
|
||||
|
||||
|
||||
|
||||
|
||||
#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
|
||||
#line 74 "./sql.y"
|
||||
typedef union YYSTYPE {
|
||||
#ifndef YYSTYPE
|
||||
typedef union
|
||||
{
|
||||
struct sql_str str;
|
||||
LPWSTR string;
|
||||
string_list *column_list;
|
||||
value_list *val_list;
|
||||
column_info *column_list;
|
||||
MSIVIEW *query;
|
||||
struct expr *expr;
|
||||
USHORT column_type;
|
||||
create_col_info *column_info;
|
||||
column_assignment update_col_info;
|
||||
} YYSTYPE;
|
||||
/* Line 1252 of yacc.c. */
|
||||
#line 339 "sql.tab.h"
|
||||
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
int integer;
|
||||
} yystype;
|
||||
# define YYSTYPE yystype
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
#endif
|
||||
# define TK_ABORT 257
|
||||
# define TK_AFTER 258
|
||||
# define TK_AGG_FUNCTION 259
|
||||
# define TK_ALL 260
|
||||
# define TK_AND 261
|
||||
# define TK_AS 262
|
||||
# define TK_ASC 263
|
||||
# define TK_BEFORE 264
|
||||
# define TK_BEGIN 265
|
||||
# define TK_BETWEEN 266
|
||||
# define TK_BITAND 267
|
||||
# define TK_BITNOT 268
|
||||
# define TK_BITOR 269
|
||||
# define TK_BY 270
|
||||
# define TK_CASCADE 271
|
||||
# define TK_CASE 272
|
||||
# define TK_CHAR 273
|
||||
# define TK_CHECK 274
|
||||
# define TK_CLUSTER 275
|
||||
# define TK_COLLATE 276
|
||||
# define TK_COLUMN 277
|
||||
# define TK_COMMA 278
|
||||
# define TK_COMMENT 279
|
||||
# define TK_COMMIT 280
|
||||
# define TK_CONCAT 281
|
||||
# define TK_CONFLICT 282
|
||||
# define TK_CONSTRAINT 283
|
||||
# define TK_COPY 284
|
||||
# define TK_CREATE 285
|
||||
# define TK_DEFAULT 286
|
||||
# define TK_DEFERRABLE 287
|
||||
# define TK_DEFERRED 288
|
||||
# define TK_DELETE 289
|
||||
# define TK_DELIMITERS 290
|
||||
# define TK_DESC 291
|
||||
# define TK_DISTINCT 292
|
||||
# define TK_DOT 293
|
||||
# define TK_DROP 294
|
||||
# define TK_EACH 295
|
||||
# define TK_ELSE 296
|
||||
# define TK_END 297
|
||||
# define TK_END_OF_FILE 298
|
||||
# define TK_EQ 299
|
||||
# define TK_EXCEPT 300
|
||||
# define TK_EXPLAIN 301
|
||||
# define TK_FAIL 302
|
||||
# define TK_FLOAT 303
|
||||
# define TK_FOR 304
|
||||
# define TK_FOREIGN 305
|
||||
# define TK_FROM 306
|
||||
# define TK_FUNCTION 307
|
||||
# define TK_GE 308
|
||||
# define TK_GLOB 309
|
||||
# define TK_GROUP 310
|
||||
# define TK_GT 311
|
||||
# define TK_HAVING 312
|
||||
# define TK_HOLD 313
|
||||
# define TK_IGNORE 314
|
||||
# define TK_ILLEGAL 315
|
||||
# define TK_IMMEDIATE 316
|
||||
# define TK_IN 317
|
||||
# define TK_INDEX 318
|
||||
# define TK_INITIALLY 319
|
||||
# define TK_ID 320
|
||||
# define TK_INSERT 321
|
||||
# define TK_INSTEAD 322
|
||||
# define TK_INT 323
|
||||
# define TK_INTEGER 324
|
||||
# define TK_INTERSECT 325
|
||||
# define TK_INTO 326
|
||||
# define TK_IS 327
|
||||
# define TK_ISNULL 328
|
||||
# define TK_JOIN 329
|
||||
# define TK_JOIN_KW 330
|
||||
# define TK_KEY 331
|
||||
# define TK_LE 332
|
||||
# define TK_LIKE 333
|
||||
# define TK_LIMIT 334
|
||||
# define TK_LONG 335
|
||||
# define TK_LONGCHAR 336
|
||||
# define TK_LP 337
|
||||
# define TK_LSHIFT 338
|
||||
# define TK_LT 339
|
||||
# define TK_LOCALIZABLE 340
|
||||
# define TK_MATCH 341
|
||||
# define TK_MINUS 342
|
||||
# define TK_NE 343
|
||||
# define TK_NOT 344
|
||||
# define TK_NOTNULL 345
|
||||
# define TK_NULL 346
|
||||
# define TK_OBJECT 347
|
||||
# define TK_OF 348
|
||||
# define TK_OFFSET 349
|
||||
# define TK_ON 350
|
||||
# define TK_OR 351
|
||||
# define TK_ORACLE_OUTER_JOIN 352
|
||||
# define TK_ORDER 353
|
||||
# define TK_PLUS 354
|
||||
# define TK_PRAGMA 355
|
||||
# define TK_PRIMARY 356
|
||||
# define TK_RAISE 357
|
||||
# define TK_REFERENCES 358
|
||||
# define TK_REM 359
|
||||
# define TK_REPLACE 360
|
||||
# define TK_RESTRICT 361
|
||||
# define TK_ROLLBACK 362
|
||||
# define TK_ROW 363
|
||||
# define TK_RP 364
|
||||
# define TK_RSHIFT 365
|
||||
# define TK_SELECT 366
|
||||
# define TK_SEMI 367
|
||||
# define TK_SET 368
|
||||
# define TK_SHORT 369
|
||||
# define TK_SLASH 370
|
||||
# define TK_SPACE 371
|
||||
# define TK_STAR 372
|
||||
# define TK_STATEMENT 373
|
||||
# define TK_STRING 374
|
||||
# define TK_TABLE 375
|
||||
# define TK_TEMP 376
|
||||
# define TK_THEN 377
|
||||
# define TK_TRANSACTION 378
|
||||
# define TK_TRIGGER 379
|
||||
# define TK_UMINUS 380
|
||||
# define TK_UNCLOSED_STRING 381
|
||||
# define TK_UNION 382
|
||||
# define TK_UNIQUE 383
|
||||
# define TK_UPDATE 384
|
||||
# define TK_UPLUS 385
|
||||
# define TK_USING 386
|
||||
# define TK_VACUUM 387
|
||||
# define TK_VALUES 388
|
||||
# define TK_VIEW 389
|
||||
# define TK_WHEN 390
|
||||
# define TK_WHERE 391
|
||||
# define TK_WILDCARD 392
|
||||
# define END_OF_FILE 393
|
||||
# define ILLEGAL 394
|
||||
# define SPACE 395
|
||||
# define UNCLOSED_STRING 396
|
||||
# define COMMENT 397
|
||||
# define FUNCTION 398
|
||||
# define COLUMN 399
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* not BISON_SQL_TAB_H */
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "query.h"
|
||||
#include "wine/list.h"
|
||||
#include "wine/debug.h"
|
||||
#include "wine/unicode.h"
|
||||
|
||||
#define YYLEX_PARAM info
|
||||
#define YYPARSE_PARAM info
|
||||
|
@ -55,12 +54,13 @@ static INT SQL_getint( void *info );
|
|||
static int SQL_lex( void *SQL_lval, SQL_input *info );
|
||||
|
||||
static void *parser_alloc( void *info, unsigned int sz );
|
||||
static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column );
|
||||
|
||||
static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys);
|
||||
static BOOL SQL_MarkPrimaryKeys( column_info *cols, column_info *keys);
|
||||
|
||||
static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r );
|
||||
static struct expr * EXPR_column( void *info, LPWSTR column );
|
||||
static struct expr * EXPR_ival( void *info, struct sql_str *, int sign );
|
||||
static struct expr * EXPR_column( void *info, column_info *column );
|
||||
static struct expr * EXPR_ival( void *info, int val );
|
||||
static struct expr * EXPR_sval( void *info, struct sql_str * );
|
||||
static struct expr * EXPR_wildcard( void *info );
|
||||
|
||||
|
@ -72,13 +72,11 @@ static struct expr * EXPR_wildcard( void *info );
|
|||
{
|
||||
struct sql_str str;
|
||||
LPWSTR string;
|
||||
string_list *column_list;
|
||||
value_list *val_list;
|
||||
column_info *column_list;
|
||||
MSIVIEW *query;
|
||||
struct expr *expr;
|
||||
USHORT column_type;
|
||||
create_col_info *column_info;
|
||||
column_assignment update_col_info;
|
||||
int integer;
|
||||
}
|
||||
|
||||
%token TK_ABORT TK_AFTER TK_AGG_FUNCTION TK_ALL TK_AND TK_AS TK_ASC
|
||||
|
@ -125,15 +123,14 @@ static struct expr * EXPR_wildcard( void *info );
|
|||
%nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
|
||||
COLUMN AGG_FUNCTION.
|
||||
|
||||
%type <string> column table id
|
||||
%type <column_list> selcollist
|
||||
%type <query> query from fromtable unorderedsel selectfrom
|
||||
%type <string> table id
|
||||
%type <column_list> selcollist column column_and_type column_def table_def
|
||||
%type <column_list> column_assignment update_assign_list constlist
|
||||
%type <query> query from fromtable selectfrom unorderedsel
|
||||
%type <query> oneupdate onedelete oneselect onequery onecreate oneinsert
|
||||
%type <expr> expr val column_val const_val
|
||||
%type <column_type> column_type data_type data_type_l data_count
|
||||
%type <column_info> column_def table_def
|
||||
%type <val_list> constlist
|
||||
%type <update_col_info> column_assignment update_assign_list
|
||||
%type <integer> number
|
||||
|
||||
%%
|
||||
|
||||
|
@ -210,7 +207,7 @@ oneupdate:
|
|||
SQL_input* sql = (SQL_input*) info;
|
||||
MSIVIEW *update = NULL;
|
||||
|
||||
UPDATE_CreateView( sql->db, &update, $2, &$4, $6 );
|
||||
UPDATE_CreateView( sql->db, &update, $2, $4, $6 );
|
||||
if( !update )
|
||||
YYABORT;
|
||||
$$ = update;
|
||||
|
@ -241,33 +238,27 @@ table_def:
|
|||
;
|
||||
|
||||
column_def:
|
||||
column_def TK_COMMA column column_type
|
||||
column_def TK_COMMA column_and_type
|
||||
{
|
||||
create_col_info *ci;
|
||||
column_info *ci;
|
||||
|
||||
for( ci = $1; ci->next; ci = ci->next )
|
||||
;
|
||||
|
||||
ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
|
||||
if( !ci->next )
|
||||
{
|
||||
/* FIXME: free $1 */
|
||||
YYABORT;
|
||||
}
|
||||
ci->next->colname = $3;
|
||||
ci->next->type = $4;
|
||||
ci->next->next = NULL;
|
||||
|
||||
ci->next = $3;
|
||||
$$ = $1;
|
||||
}
|
||||
| column column_type
|
||||
| column_and_type
|
||||
{
|
||||
$$ = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
|
||||
if( ! $$ )
|
||||
YYABORT;
|
||||
$$->colname = $1;
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
column_and_type:
|
||||
column column_type
|
||||
{
|
||||
$$ = $1;
|
||||
$$->type = $2;
|
||||
$$->next = NULL;
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -326,13 +317,11 @@ data_type:
|
|||
;
|
||||
|
||||
data_count:
|
||||
TK_INTEGER
|
||||
number
|
||||
{
|
||||
SQL_input* sql = (SQL_input*) info;
|
||||
int val = SQL_getint(sql);
|
||||
if( ( val > 255 ) || ( val < 0 ) )
|
||||
if( ( $1 > 255 ) || ( $1 < 0 ) )
|
||||
YYABORT;
|
||||
$$ = val;
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -386,30 +375,9 @@ selectfrom:
|
|||
|
||||
selcollist:
|
||||
column
|
||||
{
|
||||
string_list *list;
|
||||
|
||||
list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
|
||||
if( !list )
|
||||
YYABORT;
|
||||
list->string = $1;
|
||||
list->next = NULL;
|
||||
|
||||
$$ = list;
|
||||
TRACE("Collist %s\n",debugstr_w($$->string));
|
||||
}
|
||||
| column TK_COMMA selcollist
|
||||
{
|
||||
string_list *list;
|
||||
|
||||
list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
|
||||
if( !list )
|
||||
YYABORT;
|
||||
list->string = $1;
|
||||
list->next = $3;
|
||||
|
||||
$$ = list;
|
||||
TRACE("From table: %s\n",debugstr_w($$->string));
|
||||
$1->next = $3;
|
||||
}
|
||||
| TK_STAR
|
||||
{
|
||||
|
@ -527,25 +495,18 @@ val:
|
|||
constlist:
|
||||
const_val
|
||||
{
|
||||
value_list *vals;
|
||||
|
||||
vals = parser_alloc( info, sizeof *vals );
|
||||
if( !vals )
|
||||
$$ = parser_alloc_column( info, NULL, NULL );
|
||||
if( !$$ )
|
||||
YYABORT;
|
||||
vals->val = $1;
|
||||
vals->next = NULL;
|
||||
$$ = vals;
|
||||
$$->val = $1;
|
||||
}
|
||||
| const_val TK_COMMA constlist
|
||||
{
|
||||
value_list *vals;
|
||||
|
||||
vals = parser_alloc( info, sizeof *vals );
|
||||
if( !vals )
|
||||
$$ = parser_alloc_column( info, NULL, NULL );
|
||||
if( !$$ )
|
||||
YYABORT;
|
||||
vals->val = $1;
|
||||
vals->next = $3;
|
||||
$$ = vals;
|
||||
$$->val = $1;
|
||||
$$->next = $3;
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -553,38 +514,29 @@ update_assign_list:
|
|||
column_assignment
|
||||
| column_assignment TK_COMMA update_assign_list
|
||||
{
|
||||
$1.col_list->next = $3.col_list;
|
||||
$1.val_list->next = $3.val_list;
|
||||
$$ = $1;
|
||||
$$->next = $3;
|
||||
}
|
||||
;
|
||||
|
||||
column_assignment:
|
||||
column TK_EQ const_val
|
||||
{
|
||||
$$.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.col_list );
|
||||
if( !$$.col_list )
|
||||
YYABORT;
|
||||
$$.col_list->string = $1;
|
||||
$$.col_list->next = NULL;
|
||||
$$.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.val_list );
|
||||
if( !$$.val_list )
|
||||
YYABORT;
|
||||
$$.val_list->val = $3;
|
||||
$$.val_list->next = 0;
|
||||
$$ = $1;
|
||||
$$->val = $3;
|
||||
}
|
||||
;
|
||||
|
||||
const_val:
|
||||
TK_INTEGER
|
||||
number
|
||||
{
|
||||
$$ = EXPR_ival( info, &$1, 1 );
|
||||
$$ = EXPR_ival( info, $1 );
|
||||
if( !$$ )
|
||||
YYABORT;
|
||||
}
|
||||
| TK_MINUS TK_INTEGER
|
||||
| TK_MINUS number
|
||||
{
|
||||
$$ = EXPR_ival( info, &$2, -1 );
|
||||
$$ = EXPR_ival( info, -$2 );
|
||||
if( !$$ )
|
||||
YYABORT;
|
||||
}
|
||||
|
@ -614,11 +566,15 @@ column_val:
|
|||
column:
|
||||
table TK_DOT id
|
||||
{
|
||||
$$ = $3; /* FIXME */
|
||||
$$ = parser_alloc_column( info, $1, $3 );
|
||||
if( !$$ )
|
||||
YYABORT;
|
||||
}
|
||||
| id
|
||||
{
|
||||
$$ = $1;
|
||||
$$ = parser_alloc_column( info, NULL, $1 );
|
||||
if( !$$ )
|
||||
YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -638,6 +594,13 @@ id:
|
|||
}
|
||||
;
|
||||
|
||||
number:
|
||||
TK_INTEGER
|
||||
{
|
||||
$$ = SQL_getint( info );
|
||||
}
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
static void *parser_alloc( void *info, unsigned int sz )
|
||||
|
@ -650,6 +613,23 @@ static void *parser_alloc( void *info, unsigned int sz )
|
|||
return &mem[1];
|
||||
}
|
||||
|
||||
static column_info *parser_alloc_column( void *info, LPCWSTR table, LPCWSTR column )
|
||||
{
|
||||
column_info *col;
|
||||
|
||||
col = parser_alloc( info, sizeof (*col) );
|
||||
if( col )
|
||||
{
|
||||
col->table = table;
|
||||
col->column = column;
|
||||
col->val = NULL;
|
||||
col->type = 0;
|
||||
col->next = NULL;
|
||||
}
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
int SQL_lex( void *SQL_lval, SQL_input *sql )
|
||||
{
|
||||
int token;
|
||||
|
@ -701,8 +681,19 @@ INT SQL_getint( void *info )
|
|||
{
|
||||
SQL_input* sql = (SQL_input*) info;
|
||||
LPCWSTR p = &sql->command[sql->n];
|
||||
INT i, r = 0;
|
||||
|
||||
return atoiW( p );
|
||||
for( i=0; i<sql->len; i++ )
|
||||
{
|
||||
if( '0' > p[i] || '9' < p[i] )
|
||||
{
|
||||
ERR("should only be numbers here!\n");
|
||||
break;
|
||||
}
|
||||
r = (p[i]-'0') + r*10;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int SQL_error( const char *str )
|
||||
|
@ -733,24 +724,24 @@ static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct e
|
|||
return e;
|
||||
}
|
||||
|
||||
static struct expr * EXPR_column( void *info, LPWSTR column )
|
||||
static struct expr * EXPR_column( void *info, column_info *column )
|
||||
{
|
||||
struct expr *e = parser_alloc( info, sizeof *e );
|
||||
if( e )
|
||||
{
|
||||
e->type = EXPR_COLUMN;
|
||||
e->u.sval = column;
|
||||
e->u.sval = column->column;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static struct expr * EXPR_ival( void *info, struct sql_str *str, int sign )
|
||||
static struct expr * EXPR_ival( void *info, int val )
|
||||
{
|
||||
struct expr *e = parser_alloc( info, sizeof *e );
|
||||
if( e )
|
||||
{
|
||||
e->type = EXPR_IVAL;
|
||||
e->u.ival = atoiW( str->data ) * sign;
|
||||
e->u.ival = val;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
@ -766,19 +757,20 @@ static struct expr * EXPR_sval( void *info, struct sql_str *str )
|
|||
return e;
|
||||
}
|
||||
|
||||
static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys)
|
||||
static BOOL SQL_MarkPrimaryKeys( column_info *cols,
|
||||
column_info *keys )
|
||||
{
|
||||
string_list *k;
|
||||
column_info *k;
|
||||
BOOL found = TRUE;
|
||||
|
||||
for( k = keys; k && found; k = k->next )
|
||||
{
|
||||
create_col_info *c;
|
||||
column_info *c;
|
||||
|
||||
found = FALSE;
|
||||
for( c = cols; c && !found; c = c->next )
|
||||
{
|
||||
if( lstrcmpW( k->string, c->colname ) )
|
||||
if( lstrcmpW( k->column, c->column ) )
|
||||
continue;
|
||||
c->type |= MSITYPE_KEY;
|
||||
found = TRUE;
|
||||
|
|
|
@ -91,6 +91,14 @@ typedef struct {
|
|||
} str;
|
||||
} awstring;
|
||||
|
||||
typedef struct {
|
||||
BOOL unicode;
|
||||
union {
|
||||
LPCSTR a;
|
||||
LPCWSTR w;
|
||||
} str;
|
||||
} awcstring;
|
||||
|
||||
typedef struct tagMSISUMMARYINFO
|
||||
{
|
||||
MSIOBJECTHDR hdr;
|
||||
|
@ -627,7 +635,7 @@ UINT WINAPI MsiSummaryInfoGetPropertyW(
|
|||
}
|
||||
|
||||
static UINT set_prop( MSIHANDLE handle, UINT uiProperty, UINT uiDataType,
|
||||
INT iValue, FILETIME* pftValue, awstring *str )
|
||||
INT iValue, FILETIME* pftValue, awcstring *str )
|
||||
{
|
||||
MSISUMMARYINFO *si;
|
||||
PROPVARIANT *prop;
|
||||
|
@ -701,9 +709,9 @@ end:
|
|||
}
|
||||
|
||||
UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty,
|
||||
UINT uiDataType, INT iValue, FILETIME* pftValue, LPWSTR szValue )
|
||||
UINT uiDataType, INT iValue, FILETIME* pftValue, LPCWSTR szValue )
|
||||
{
|
||||
awstring str;
|
||||
awcstring str;
|
||||
|
||||
TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType,
|
||||
iValue, pftValue, debugstr_w(szValue) );
|
||||
|
@ -714,9 +722,9 @@ UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty,
|
|||
}
|
||||
|
||||
UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty,
|
||||
UINT uiDataType, INT iValue, FILETIME* pftValue, LPSTR szValue )
|
||||
UINT uiDataType, INT iValue, FILETIME* pftValue, LPCSTR szValue )
|
||||
{
|
||||
awstring str;
|
||||
awcstring str;
|
||||
|
||||
TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType,
|
||||
iValue, pftValue, debugstr_a(szValue) );
|
||||
|
|
|
@ -397,7 +397,7 @@ end:
|
|||
return ret;
|
||||
}
|
||||
|
||||
UINT read_table_from_storage( MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable)
|
||||
static UINT read_table_from_storage( MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable)
|
||||
{
|
||||
MSITABLE *t;
|
||||
USHORT *rawdata = NULL;
|
||||
|
@ -507,7 +507,7 @@ void remove_table( MSIDATABASE *db, MSITABLE *table )
|
|||
table->prev = NULL;
|
||||
}
|
||||
|
||||
void release_table( MSIDATABASE *db, MSITABLE *table )
|
||||
static void release_table( MSIDATABASE *db, MSITABLE *table )
|
||||
{
|
||||
if( !table->ref_count )
|
||||
ERR("Trying to destroy table with refcount 0\n");
|
||||
|
@ -610,7 +610,7 @@ UINT get_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable)
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
UINT save_table( MSIDATABASE *db, MSITABLE *t )
|
||||
static UINT save_table( MSIDATABASE *db, MSITABLE *t )
|
||||
{
|
||||
USHORT *rawdata = NULL, *p;
|
||||
UINT rawsize, r, i, j, row_size, num_cols = 0;
|
||||
|
@ -751,7 +751,7 @@ end:
|
|||
return ret;
|
||||
}
|
||||
|
||||
UINT save_string_table( MSIDATABASE *db )
|
||||
static UINT save_string_table( MSIDATABASE *db )
|
||||
{
|
||||
UINT i, count, datasize, poolsize, sz, used, r, codepage;
|
||||
UINT ret = ERROR_FUNCTION_FAILED;
|
||||
|
@ -858,7 +858,7 @@ struct standard_table {
|
|||
#define STANDARD_TABLE_COUNT \
|
||||
(sizeof(MSI_standard_tables)/sizeof(struct standard_table))
|
||||
|
||||
UINT get_defaulttablecolumns( LPCWSTR szTable, MSICOLUMNINFO *colinfo, UINT *sz)
|
||||
static UINT get_defaulttablecolumns( LPCWSTR szTable, MSICOLUMNINFO *colinfo, UINT *sz)
|
||||
{
|
||||
DWORD i, n=0;
|
||||
|
||||
|
@ -1167,7 +1167,7 @@ static UINT TABLE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
UINT TABLE_insert_row( struct tagMSIVIEW *view, UINT *num )
|
||||
static UINT TABLE_insert_row( struct tagMSIVIEW *view, UINT *num )
|
||||
{
|
||||
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
|
||||
USHORT **p, *row;
|
||||
|
|
|
@ -158,7 +158,7 @@ static const Keyword aKeywordTable[] = {
|
|||
** keyword. If it is a keyword, the token code of that keyword is
|
||||
** returned. If the input is not a keyword, TK_ID is returned.
|
||||
*/
|
||||
int sqliteKeywordCode(const WCHAR *z, int n){
|
||||
static int sqliteKeywordCode(const WCHAR *z, int n){
|
||||
UINT i, len;
|
||||
char buffer[0x10];
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ typedef struct tagMSIUPDATEVIEW
|
|||
MSIVIEW view;
|
||||
MSIDATABASE *db;
|
||||
MSIVIEW *wv;
|
||||
value_list *vals;
|
||||
column_info *vals;
|
||||
} MSIUPDATEVIEW;
|
||||
|
||||
static UINT UPDATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
|
||||
|
@ -193,7 +193,7 @@ static MSIVIEWOPS update_ops =
|
|||
};
|
||||
|
||||
UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
||||
column_assignment *list, struct expr *expr )
|
||||
column_info *columns, struct expr *expr )
|
||||
{
|
||||
MSIUPDATEVIEW *uv = NULL;
|
||||
UINT r;
|
||||
|
@ -215,7 +215,7 @@ UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
|||
}
|
||||
|
||||
/* then select the columns we want */
|
||||
r = SELECT_CreateView( db, &sv, wv, list->col_list );
|
||||
r = SELECT_CreateView( db, &sv, wv, columns );
|
||||
if( r != ERROR_SUCCESS )
|
||||
{
|
||||
if( tv )
|
||||
|
@ -231,7 +231,7 @@ UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
|
|||
uv->view.ops = &update_ops;
|
||||
msiobj_addref( &db->hdr );
|
||||
uv->db = db;
|
||||
uv->vals = list->val_list;
|
||||
uv->vals = columns;
|
||||
uv->wv = sv;
|
||||
*view = (MSIVIEW*) uv;
|
||||
|
||||
|
|
228
reactos/lib/msi/upgrade.c
Normal file
228
reactos/lib/msi/upgrade.c
Normal file
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* Implementation of the Microsoft Installer (msi.dll)
|
||||
*
|
||||
* Copyright 2005 Aric Stewart for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Actions focused on in this module
|
||||
*
|
||||
* FindRelatedProducts
|
||||
* MigrateFeatureStates (TODO)
|
||||
* RemoveExistingProducts (TODO)
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "winreg.h"
|
||||
#include "wine/debug.h"
|
||||
#include "msidefs.h"
|
||||
#include "msipriv.h"
|
||||
#include "winuser.h"
|
||||
#include "action.h"
|
||||
#include "wine/unicode.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
extern const WCHAR szFindRelatedProducts[];
|
||||
extern const WCHAR szMigrateFeatureStates[];
|
||||
extern const WCHAR szRemoveExistingProducts[];
|
||||
|
||||
static BOOL check_language(DWORD lang1, LPCWSTR lang2, DWORD attributes)
|
||||
{
|
||||
DWORD langdword;
|
||||
|
||||
if (!lang2 || lang2[0]==0)
|
||||
return TRUE;
|
||||
|
||||
langdword = atoiW(lang2);
|
||||
|
||||
if (attributes & msidbUpgradeAttributesLanguagesExclusive)
|
||||
return (lang1 != langdword);
|
||||
else
|
||||
return (lang1 == langdword);
|
||||
}
|
||||
|
||||
static void append_productcode(MSIPACKAGE* package, LPCWSTR action_property,
|
||||
LPCWSTR productid)
|
||||
{
|
||||
LPWSTR prop;
|
||||
LPWSTR newprop;
|
||||
DWORD len;
|
||||
static const WCHAR separator[] = {';',0};
|
||||
|
||||
prop = load_dynamic_property(package, action_property, NULL);
|
||||
if (prop)
|
||||
len = strlenW(prop);
|
||||
else
|
||||
len = 0;
|
||||
|
||||
/*separator*/
|
||||
len ++;
|
||||
|
||||
len += strlenW(productid);
|
||||
|
||||
/*null*/
|
||||
len++;
|
||||
|
||||
newprop = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
|
||||
|
||||
if (prop)
|
||||
{
|
||||
strcpyW(newprop,prop);
|
||||
strcatW(newprop,separator);
|
||||
}
|
||||
else
|
||||
newprop[0] = 0;
|
||||
strcatW(newprop,productid);
|
||||
|
||||
MSI_SetPropertyW(package, action_property, newprop);
|
||||
TRACE("Found Related Product... %s now %s\n",debugstr_w(action_property),
|
||||
debugstr_w(newprop));
|
||||
HeapFree(GetProcessHeap(),0,prop);
|
||||
HeapFree(GetProcessHeap(),0,newprop);
|
||||
}
|
||||
|
||||
static UINT ITERATE_FindRelatedProducts(MSIRECORD *rec, LPVOID param)
|
||||
{
|
||||
MSIPACKAGE *package = (MSIPACKAGE*)param;
|
||||
WCHAR product[GUID_SIZE];
|
||||
DWORD index = 0;
|
||||
DWORD attributes = 0;
|
||||
DWORD sz = GUID_SIZE;
|
||||
LPCWSTR upgrade_code;
|
||||
HKEY hkey = 0;
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
MSIRECORD *uirow;
|
||||
|
||||
upgrade_code = MSI_RecordGetString(rec,1);
|
||||
|
||||
rc = MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey, FALSE);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
uirow = MSI_CreateRecord(1);
|
||||
attributes = MSI_RecordGetInteger(rec,5);
|
||||
|
||||
while (rc == ERROR_SUCCESS)
|
||||
{
|
||||
rc = RegEnumValueW(hkey, index, product, &sz, NULL, NULL, NULL, NULL);
|
||||
TRACE("Looking at (%li) %s\n",index,debugstr_w(product));
|
||||
if (rc == ERROR_SUCCESS)
|
||||
{
|
||||
WCHAR productid[GUID_SIZE];
|
||||
LPCWSTR ver;
|
||||
LPCWSTR language;
|
||||
LPCWSTR action_property;
|
||||
DWORD check = 0x00000000;
|
||||
DWORD comp_ver = 0x00000000;
|
||||
DWORD sz = 0x100;
|
||||
HKEY hukey;
|
||||
INT r;
|
||||
static const WCHAR szVersion[] =
|
||||
{'V','e','r','s','i','o','n',0};
|
||||
static const WCHAR szLanguage[] =
|
||||
{'L','a','n','g','u','a','g','e',0};
|
||||
|
||||
unsquash_guid(product,productid);
|
||||
rc = MSIREG_OpenUserProductsKey(productid, &hukey, FALSE);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
rc = ERROR_SUCCESS;
|
||||
index ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
sz = sizeof(DWORD);
|
||||
RegQueryValueExW(hukey, szVersion, NULL, NULL, (LPBYTE)&check,
|
||||
&sz);
|
||||
/* check min */
|
||||
ver = MSI_RecordGetString(rec,2);
|
||||
comp_ver = build_version_dword(ver);
|
||||
r = check - comp_ver;
|
||||
if (r < 0 || (r == 0 && !(attributes &
|
||||
msidbUpgradeAttributesVersionMinInclusive)))
|
||||
{
|
||||
RegCloseKey(hukey);
|
||||
index ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check max */
|
||||
ver = MSI_RecordGetString(rec,3);
|
||||
comp_ver = build_version_dword(ver);
|
||||
r = check - comp_ver;
|
||||
if (r > 0 || (r == 0 && !(attributes &
|
||||
msidbUpgradeAttributesVersionMaxInclusive)))
|
||||
{
|
||||
RegCloseKey(hukey);
|
||||
index ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* check language*/
|
||||
sz = sizeof(DWORD);
|
||||
RegQueryValueExW(hukey, szLanguage, NULL, NULL, (LPBYTE)&check,
|
||||
&sz);
|
||||
RegCloseKey(hukey);
|
||||
language = MSI_RecordGetString(rec,4);
|
||||
TRACE("Checking languages 0x%lx and %s\n", check,
|
||||
debugstr_w(language));
|
||||
if (!check_language(check, language, attributes))
|
||||
{
|
||||
index ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
action_property = MSI_RecordGetString(rec,7);
|
||||
append_productcode(package,action_property,productid);
|
||||
ui_actiondata(package,szFindRelatedProducts,uirow);
|
||||
}
|
||||
index ++;
|
||||
}
|
||||
RegCloseKey(hkey);
|
||||
msiobj_release( &uirow->hdr);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
UINT ACTION_FindRelatedProducts(MSIPACKAGE *package)
|
||||
{
|
||||
static const WCHAR Query[] =
|
||||
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',
|
||||
' ','`','U','p','g','r','a','d','e','`',0};
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
MSIQUERY *view;
|
||||
|
||||
if (package->script && package->script->FindRelatedProductsRun)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
if (package->script)
|
||||
package->script->FindRelatedProductsRun = TRUE;
|
||||
|
||||
rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
rc = MSI_IterateRecords(view, NULL, ITERATE_FindRelatedProducts, package);
|
||||
msiobj_release(&view->hdr);
|
||||
|
||||
return rc;
|
||||
}
|
|
@ -24,7 +24,6 @@
|
|||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "wine/debug.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "msi.h"
|
||||
#include "msiquery.h"
|
||||
#include "objbase.h"
|
||||
|
@ -171,7 +170,7 @@ static UINT STRCMP_Evaluate( string_table *st, MSIVIEW *table, UINT row,
|
|||
else if( r_str && ! l_str )
|
||||
sr = -1;
|
||||
else
|
||||
sr = strcmpW( l_str, r_str );
|
||||
sr = lstrcmpW( l_str, r_str );
|
||||
|
||||
*val = ( cond->u.expr.op == OP_EQ && ( sr == 0 ) ) ||
|
||||
( cond->u.expr.op == OP_LT && ( sr < 0 ) ) ||
|
||||
|
|
|
@ -23,6 +23,10 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef _MSI_NO_CRYPTO
|
||||
#include "wincrypt.h"
|
||||
#endif
|
||||
|
||||
typedef unsigned long MSIHANDLE;
|
||||
|
||||
typedef enum tagINSTALLSTATE
|
||||
|
@ -201,20 +205,6 @@ UINT WINAPI MsiOpenProductA(LPCSTR, MSIHANDLE*);
|
|||
UINT WINAPI MsiOpenProductW(LPCWSTR, MSIHANDLE*);
|
||||
#define MsiOpenProduct WINELIB_NAME_AW(MsiOpenProduct)
|
||||
|
||||
UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE, LPCSTR, UINT, MSIHANDLE *);
|
||||
UINT WINAPI MsiGetSummaryInformationW(MSIHANDLE, LPCWSTR, UINT, MSIHANDLE *);
|
||||
#define MsiGetSummaryInformation WINELIB_NAME_AW(MsiGetSummaryInformation)
|
||||
|
||||
UINT WINAPI MsiSummaryInfoGetPropertyA(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPSTR,DWORD*);
|
||||
UINT WINAPI MsiSummaryInfoGetPropertyW(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPWSTR,DWORD*);
|
||||
#define MsiSummaryInfoGetProperty WINELIB_NAME_AW(MsiSummaryInfoGetProperty)
|
||||
|
||||
UINT WINAPI MsiSummaryInfoPersist(MSIHANDLE);
|
||||
|
||||
UINT WINAPI MsiSummaryInfoSetPropertyA(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPSTR);
|
||||
UINT WINAPI MsiSummaryInfoSetPropertyW(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPWSTR);
|
||||
#define MsiSummaryInfoSetProperty WINELIB_NAME_AW(MsiSummaryInfoSetProperty)
|
||||
|
||||
UINT WINAPI MsiProvideComponentFromDescriptorA(LPCSTR,LPSTR,DWORD*,DWORD*);
|
||||
UINT WINAPI MsiProvideComponentFromDescriptorW(LPCWSTR,LPWSTR,DWORD*,DWORD*);
|
||||
#define MsiProvideComponentFromDescriptor WINELIB_NAME_AW(MsiProvideComponentFromDescriptor)
|
||||
|
@ -303,10 +293,34 @@ USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR, LPSTR, DWORD*, LPSTR, DWORD*, LPSTR
|
|||
USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR, LPWSTR, DWORD*, LPWSTR, DWORD*, LPWSTR, DWORD*);
|
||||
#define MsiGetUserInfo WINELIB_NAME_AW(MsiGetUserInfo)
|
||||
|
||||
UINT WINAPI MsiCollectUserInfoA( LPCSTR );
|
||||
UINT WINAPI MsiCollectUserInfoW( LPCWSTR );
|
||||
UINT WINAPI MsiCollectUserInfoA(LPCSTR);
|
||||
UINT WINAPI MsiCollectUserInfoW(LPCWSTR);
|
||||
#define MsiCollectUserInfo WINELIB_NAME_AW(MsiCollectUserInfo)
|
||||
|
||||
UINT WINAPI MsiReinstallFeatureA(LPCSTR, LPCSTR, DWORD);
|
||||
UINT WINAPI MsiReinstallFeatureW(LPCWSTR, LPCWSTR, DWORD);
|
||||
#define MsiReinstallFeature WINELIB_NAME_AW(MsiReinstallFeature)
|
||||
|
||||
UINT WINAPI MsiGetShortcutTargetA(LPCSTR, LPSTR, LPSTR, LPSTR);
|
||||
UINT WINAPI MsiGetShortcutTargetW(LPCWSTR, LPWSTR, LPWSTR, LPWSTR);
|
||||
#define MsiGetShortcutTarget WINELIB_NAME_AW(MsiGetShortcutTarget)
|
||||
|
||||
INSTALLSTATE WINAPI MsiUseFeatureW(LPCWSTR, LPCWSTR);
|
||||
INSTALLSTATE WINAPI MsiUseFeatureA(LPCSTR, LPCSTR);
|
||||
#define MsiUseFeature WINELIB_NAME_AW(MsiUseFeature)
|
||||
|
||||
INSTALLSTATE WINAPI MsiUseFeatureExW(LPCWSTR, LPCWSTR, DWORD, DWORD);
|
||||
INSTALLSTATE WINAPI MsiUseFeatureExA(LPCSTR, LPCSTR, DWORD, DWORD);
|
||||
#define MsiUseFeatureEx WINELIB_NAME_AW(MsiUseFeatureEx)
|
||||
|
||||
HRESULT WINAPI MsiGetFileSignatureInformationA(LPCSTR, DWORD, PCCERT_CONTEXT*, BYTE*, DWORD*);
|
||||
HRESULT WINAPI MsiGetFileSignatureInformationW(LPCWSTR, DWORD, PCCERT_CONTEXT*, BYTE*, DWORD*);
|
||||
#define MsiGetFileSignatureInformation WINELIB_NAME_AW(MsiGetFileSignatureInformation)
|
||||
|
||||
INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR, LPSTR, DWORD *);
|
||||
INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR, LPWSTR, DWORD *);
|
||||
#define MsiLocateComponent WINELIB_NAME_AW(MsiLocateComponent)
|
||||
|
||||
/* Non Unicode */
|
||||
UINT WINAPI MsiCloseHandle(MSIHANDLE);
|
||||
UINT WINAPI MsiCloseAllHandles(void);
|
||||
|
|
|
@ -23,6 +23,15 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum msidbUpgradeAttributes {
|
||||
msidbUpgradeAttributesMigrateFeatures = 0x0000001,
|
||||
msidbUpgradeAttributesOnlyDetect = 0x00000002,
|
||||
msidbUpgradeAttributesIgnoreRemoveFailure = 0x00000004,
|
||||
msidbUpgradeAttributesVersionMinInclusive = 0x00000100,
|
||||
msidbUpgradeAttributesVersionMaxInclusive = 0x00000200,
|
||||
msidbUpgradeAttributesLanguagesExclusive = 0x00000400
|
||||
};
|
||||
|
||||
enum msidbFileAttributes {
|
||||
msidbFileAttributesReadOnly = 0x00000001,
|
||||
msidbFileAttributesHidden = 0x00000002,
|
||||
|
@ -49,6 +58,51 @@ enum msidbDialogAttributes {
|
|||
msidbDialogAttributesError = 0x00010000
|
||||
};
|
||||
|
||||
enum msidbControlAttributes {
|
||||
msidbControlAttributesVisible = 0x00000001,
|
||||
msidbControlAttributesEnabled = 0x00000002,
|
||||
msidbControlAttributesSunken = 0x00000004,
|
||||
msidbControlAttributesIndirect = 0x00000008,
|
||||
msidbControlAttributesInteger = 0x00000010,
|
||||
msidbControlAttributesRTLRO = 0x00000020,
|
||||
msidbControlAttributesRightAligned = 0x00000040,
|
||||
msidbControlAttributesLeftScroll = 0x00000080,
|
||||
msidbControlAttributesBiDi = 0x000000c0,
|
||||
|
||||
msidbControlAttributesTransparent = 0x00010000,
|
||||
msidbControlAttributesNoPrefix = 0x00020000,
|
||||
msidbControlAttributesNoWrap = 0x00040000,
|
||||
msidbControlAttributesFormatSize = 0x00080000,
|
||||
msidbControlAttributesUsersLanguage = 0x00100000,
|
||||
|
||||
msidbControlAttributesMultiline = 0x00010000,
|
||||
msidbControlAttributesPasswordInput = 0x00200000,
|
||||
|
||||
msidbControlAttributesProgress95 = 0x00010000,
|
||||
|
||||
msidbControlAttributesRemovableVolume = 0x00010000,
|
||||
msidbControlAttributesFixedVolume = 0x00020000,
|
||||
msidbControlAttributesRemoteVolume = 0x00040000,
|
||||
msidbControlAttributesCDROMVolume = 0x00080000,
|
||||
msidbControlAttributesRAMdiskVolume = 0x00100000,
|
||||
msidbControlAttributesFloppyVolume = 0x00200000,
|
||||
msidbControlShowRollbackCost = 0x00400000,
|
||||
|
||||
msidbControlAttributesSorted = 0x00010000,
|
||||
msidbControlAttributesComboList = 0x00020000,
|
||||
|
||||
msidbControlAttributesImageHandle = 0x00010000,
|
||||
msidbControlAttributesPushLike = 0x00020000,
|
||||
msidbControlAttributesBitmap = 0x00040000,
|
||||
msidbControlAttributesIcon = 0x00080000,
|
||||
msidbControlAttributesFixedSize = 0x00100000,
|
||||
msidbControlAttributesIconSize16 = 0x00200000,
|
||||
msidbControlAttributesIconSize32 = 0x00400000,
|
||||
msidbControlAttributesIconSize48 = 0x00600000,
|
||||
|
||||
msidbControlAttributesHasBorder = 0x01000000,
|
||||
};
|
||||
|
||||
enum msidbTextStyleStyleBits
|
||||
{
|
||||
msidbTextStyleStyleBitsBold = 0x00000001,
|
||||
|
|
|
@ -53,8 +53,6 @@ typedef enum tagMSIMODIFY
|
|||
MSIMODIFY_VALIDATE_DELETE = 11
|
||||
} MSIMODIFY;
|
||||
|
||||
#define MSI_NULL_INTEGER 0x80000000
|
||||
|
||||
#define MSIDBOPEN_READONLY (LPCTSTR)0
|
||||
#define MSIDBOPEN_TRANSACT (LPCTSTR)1
|
||||
#define MSIDBOPEN_DIRECT (LPCTSTR)2
|
||||
|
@ -84,6 +82,43 @@ typedef enum tagMSIRUNMODE
|
|||
MSIRUNMODE_COMMIT = 18
|
||||
} MSIRUNMODE;
|
||||
|
||||
typedef enum tagMSIDBERROR
|
||||
{
|
||||
MSIDBERROR_INVALIDARG = -3,
|
||||
MSIDBERROR_MOREDATA = -2,
|
||||
MSIDBERROR_FUNCTIONERROR = -1,
|
||||
MSIDBERROR_NOERROR = 0,
|
||||
MSIDBERROR_DUPLICATEKEY = 1,
|
||||
MSIDBERROR_REQUIRED = 2,
|
||||
MSIDBERROR_BADLINK = 3,
|
||||
MSIDBERROR_OVERFLOW = 4,
|
||||
MSIDBERROR_UNDERFLOW = 5,
|
||||
MSIDBERROR_NOTINSET = 6,
|
||||
MSIDBERROR_BADVERSION = 7,
|
||||
MSIDBERROR_BADCASE = 8,
|
||||
MSIDBERROR_BADGUID = 9,
|
||||
MSIDBERROR_BADWILDCARD = 10,
|
||||
MSIDBERROR_BADIDENTIFIER = 11,
|
||||
MSIDBERROR_BADLANGUAGE = 12,
|
||||
MSIDBERROR_BADFILENAME = 13,
|
||||
MSIDBERROR_BADPATH = 14,
|
||||
MSIDBERROR_BADCONDITION = 15,
|
||||
MSIDBERROR_BADFORMATTED = 16,
|
||||
MSIDBERROR_BADTEMPLATE = 17,
|
||||
MSIDBERROR_BADDEFAULTDIR = 18,
|
||||
MSIDBERROR_BADREGPATH = 19,
|
||||
MSIDBERROR_BADCUSTOMSOURCE = 20,
|
||||
MSIDBERROR_BADPROPERTY = 21,
|
||||
MSIDBERROR_MISSINGDATA = 22,
|
||||
MSIDBERROR_BADCATEGORY = 23,
|
||||
MSIDBERROR_BADKEYTABLE = 24,
|
||||
MSIDBERROR_BADMAXMINVALUES = 25,
|
||||
MSIDBERROR_BADCABINET = 26,
|
||||
MSIDBERROR_BADSHORTCUT= 27,
|
||||
MSIDBERROR_STRINGOVERFLOW = 28,
|
||||
MSIDBERROR_BADLOCALIZEATTRIB = 29
|
||||
} MSIDBERROR;
|
||||
|
||||
/* view manipulation */
|
||||
UINT WINAPI MsiViewFetch(MSIHANDLE,MSIHANDLE*);
|
||||
UINT WINAPI MsiViewExecute(MSIHANDLE,MSIHANDLE);
|
||||
|
@ -91,6 +126,9 @@ UINT WINAPI MsiViewClose(MSIHANDLE);
|
|||
UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE,LPCSTR,MSIHANDLE*);
|
||||
UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE,LPCWSTR,MSIHANDLE*);
|
||||
#define MsiDatabaseOpenView WINELIB_NAME_AW(MsiDatabaseOpenView)
|
||||
UINT WINAPI MsiViewGetErrorA(MSIHANDLE,LPSTR,DWORD*);
|
||||
UINT WINAPI MsiViewGetErrorW(MSIHANDLE,LPWSTR,DWORD*);
|
||||
#define MsiViewGetError WINELIB_NAME_AW(MsiViewGetError)
|
||||
|
||||
/* record manipulation */
|
||||
MSIHANDLE WINAPI MsiCreateRecord(unsigned int);
|
||||
|
@ -175,6 +213,48 @@ UINT WINAPI MsiSetFeatureStateA(MSIHANDLE, LPCSTR, INSTALLSTATE);
|
|||
UINT WINAPI MsiSetFeatureStateW(MSIHANDLE, LPCWSTR, INSTALLSTATE);
|
||||
#define MsiSetFeatureState WINELIB_NAME_AW(MsiSetFeatureState)
|
||||
|
||||
UINT WINAPI MsiPreviewDialogA(MSIHANDLE, LPCSTR);
|
||||
UINT WINAPI MsiPreviewDialogW(MSIHANDLE, LPCWSTR);
|
||||
#define MsiPreviewDialog WINELIB_NAME_AW(MsiPreviewDialog)
|
||||
|
||||
UINT WINAPI MsiPreviewBillboardA(MSIHANDLE, LPCSTR, LPCSTR);
|
||||
UINT WINAPI MsiPreviewBillboardW(MSIHANDLE, LPCWSTR, LPCWSTR);
|
||||
#define MsiPreviewBillboard WINELIB_NAME_AW(MsiPreviewBillboard)
|
||||
|
||||
UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE, LPCSTR, UINT, MSIHANDLE *);
|
||||
UINT WINAPI MsiGetSummaryInformationW(MSIHANDLE, LPCWSTR, UINT, MSIHANDLE *);
|
||||
#define MsiGetSummaryInformation WINELIB_NAME_AW(MsiGetSummaryInformation)
|
||||
|
||||
UINT WINAPI MsiSummaryInfoGetPropertyA(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPSTR,DWORD*);
|
||||
UINT WINAPI MsiSummaryInfoGetPropertyW(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPWSTR,DWORD*);
|
||||
#define MsiSummaryInfoGetProperty WINELIB_NAME_AW(MsiSummaryInfoGetProperty)
|
||||
|
||||
UINT WINAPI MsiSummaryInfoSetPropertyA(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPCSTR);
|
||||
UINT WINAPI MsiSummaryInfoSetPropertyW(MSIHANDLE, UINT, UINT, INT, FILETIME*, LPCWSTR);
|
||||
#define MsiSummaryInfoSetProperty WINELIB_NAME_AW(MsiSummaryInfoSetProperty)
|
||||
|
||||
UINT WINAPI MsiDatabaseExportA(MSIHANDLE, LPCSTR, LPCSTR, LPCSTR);
|
||||
UINT WINAPI MsiDatabaseExportW(MSIHANDLE, LPCWSTR, LPCWSTR, LPCWSTR);
|
||||
#define MsiDatabaseExport WINELIB_NAME_AW(MsiDatabaseExport)
|
||||
|
||||
UINT WINAPI MsiDatabaseImportA(MSIHANDLE, LPCSTR, LPCSTR);
|
||||
UINT WINAPI MsiDatabaseImportW(MSIHANDLE, LPCWSTR, LPCWSTR);
|
||||
#define MsiDatabaseImport WINELIB_NAME_AW(MsiDatabaseImport)
|
||||
|
||||
UINT WINAPI MsiOpenDatabaseW(LPCWSTR, LPCWSTR, MSIHANDLE*);
|
||||
UINT WINAPI MsiOpenDatabaseA(LPCSTR, LPCSTR, MSIHANDLE*);
|
||||
#define MsiOpenDatabase WINELIB_NAME_AW(MsiOpenDatabase)
|
||||
|
||||
UINT WINAPI MsiDatabaseIsTablePersistentA(MSIHANDLE, LPSTR);
|
||||
UINT WINAPI MsiDatabaseIsTablePersistentW(MSIHANDLE, LPWSTR);
|
||||
#define MsiDatabaseIsTablePersistent WINELIB_NAME_AW(MsiDatabaseIsTablePersistent)
|
||||
|
||||
UINT WINAPI MsiSummaryInfoPersist(MSIHANDLE);
|
||||
UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE,UINT*);
|
||||
|
||||
UINT WINAPI MsiEnableUIPreview(MSIHANDLE, MSIHANDLE*);
|
||||
BOOL WINAPI MsiGetMode(MSIHANDLE, MSIRUNMODE);
|
||||
|
||||
UINT WINAPI MsiViewModify(MSIHANDLE, MSIMODIFY, MSIHANDLE);
|
||||
|
||||
#endif /* __WINE_MSIQUERY_H */
|
||||
|
|
Loading…
Reference in a new issue