mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-09-02 19:26:32 +00:00
Sync to Wine-0_9_1:
Ivan Leo Puoti <[email protected]> - Fix some wrong prototypes. Thomas Weidenmueller <[email protected]> - Passing NULL as the last two parameters to ReadFile is illegal and actually causes a crash on windows. The attached patch fixes this. Aric Stewart <[email protected]> - Force files to install if the REINSTALL property is set. Mike McCormack <[email protected]> - Some installers don't call the CreateFolders action before the InstallFiles action as MSDN specifies, but it still seems to work, so make sure that we create component directories in the InstallFiles action anyway. - Create component folders in the CreateFolders action. - If an action fails, print out its name as well as the error code. Use %d for error codes so it's easy to match them up to something in winerror.h. - Rename load_dynamic_stringW to msi_dup_record_field to better describe what it does, and replace a few instances with MSI_RecordGetString to avoid allocating memory. - Tidy up the RegisterProduct action a little. - Create a stub function to apply a single table transform and call it where we need to apply transforms. - Enumerate the substorage transforms for any patches that are passed on the command line with PATCH=. Need to implement table_apply_transform() before this will do anything interesting. - Simplify register_progid() and remove a fixed length buffer. - Make enter and escape trigger the default and cancel buttons in dialogs. - Switch back to using IPicture to load images. LoadImage did the resizing for us, but doesn't handle jpeg files and requires us writing a temp file, whereas IPicture handles jpeg files and can load directly from a stream. - Remove unused package parameter of register_progid_base(). - Remove an incorrect comment and check for 0 being an invalid file handle. - Add missing semicolons that caused compile trouble on FreeBSD. - Extract file directly to their target location, bypassing the need to use temporary files and move files. - Put the UI update code for cabinet file into a separate function. - Translate INVALID_HANDLE_VALUE to zero for cabinet handles. - Fix a memory leak in the cabinet extracting code. - Fix passing of NULL pointers to MsiDecomposeDescriptor and add a test. - Fix parameter handling in MsiSetTargetPath, and add a test for it. - Deleted two buggy functions that incorrectly and inefficiently check whether a row already exists in a table, and replaced them with a call to an existing working function that does the same thing correctly. - Fix and test MsiGetProperty and MsiSetProperty. - Add a stub implementation of msi.MsiSetMode. - NULL and empty strings are the same in conditions. - Add a bunch of tests for MsiEvaluateCondition and make them pass. - Fix error handling in MsiEvaluateCondition. - Create the +msidb debug channel for msi database code. - Implement transforms. This still includes some debugging code which can be enabled by setting debug_transform to 1 in the relevant places. - Define NONAMELESSUNION and NONAMELESSSTRUCT for older compilers. - Remove some redundant null pointer checks. - Make sure to unregister all the classes that were registered when msi is unloaded, so we can register again cleanly. - Fix a memory leak. - Implement the RemoveFiles action. - Add a read-only implementation of the SelectionTree control. - Make sure we only CoUninitialize after successfully initializing. Fix the address of the returned IShellLinkDataList interface. - Use an enumeration for file states. - Handle MaskEdit masks containing dashes and other constant characters. - Stub implementation for MsiAdvertiseScriptA/W. - Add a stub for the AllocateRegistrySpace action. - Explicitly check for MSICONDITION_TRUE being returned from MsiEvaluateCondition. - Stub implementation for MsiGetFileHashA/W. - Define MSIDBOPEN_ constants using LPCWSTR when compiling Wine. - Improve MsiUseFeatureEx and MsiGetFeatureState a little, add some simple test cases. - Use msi_get_property_int() in a few more places. - Implement MsiGetFeatureUsageA and MsiUseFeature(Ex)A using their W versions. - Use "static const" rather than "const static" as gcc -W complains about the former. - Add an implementation for MsiGetShortcutTargetA/W. - Don't change the UI level during ExecuteAction. - Return an error in MsiGetComponentPathW if passed a null component. - Remove the unused 1st parameter of ACTION_VerifyComponentForAction. - Fix MsiGetPropertyA/W spec declarations. - Create an internal handle-free api for reading MSI database summary information. svn path=/trunk/; revision=19307
This commit is contained in:
+374
-214
File diff suppressed because it is too large
Load Diff
+14
-10
@@ -93,6 +93,15 @@ typedef struct tagMSIFOLDER
|
||||
INT Space;
|
||||
} MSIFOLDER;
|
||||
|
||||
typedef enum _msi_file_state {
|
||||
msifs_invalid,
|
||||
msifs_missing,
|
||||
msifs_overwrite,
|
||||
msifs_present,
|
||||
msifs_installed,
|
||||
msifs_skipped,
|
||||
} msi_file_state;
|
||||
|
||||
typedef struct tagMSIFILE
|
||||
{
|
||||
struct list entry;
|
||||
@@ -105,14 +114,7 @@ typedef struct tagMSIFILE
|
||||
LPWSTR Language;
|
||||
INT Attributes;
|
||||
INT Sequence;
|
||||
|
||||
INT State;
|
||||
/* 0 = uninitialize */
|
||||
/* 1 = not present */
|
||||
/* 2 = present but replace */
|
||||
/* 3 = present do not replace */
|
||||
/* 4 = Installed */
|
||||
/* 5 = Skipped */
|
||||
msi_file_state state;
|
||||
LPWSTR SourcePath;
|
||||
LPWSTR TargetPath;
|
||||
} MSIFILE;
|
||||
@@ -241,6 +243,7 @@ extern UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action, BOOL ex
|
||||
extern UINT ACTION_AppSearch(MSIPACKAGE *package);
|
||||
extern UINT ACTION_FindRelatedProducts(MSIPACKAGE *package);
|
||||
extern UINT ACTION_InstallFiles(MSIPACKAGE *package);
|
||||
extern UINT ACTION_RemoveFiles(MSIPACKAGE *package);
|
||||
extern UINT ACTION_DuplicateFiles(MSIPACKAGE *package);
|
||||
extern UINT ACTION_RegisterClassInfo(MSIPACKAGE *package);
|
||||
extern UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package);
|
||||
@@ -250,7 +253,7 @@ extern UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package);
|
||||
|
||||
/* Helpers */
|
||||
extern DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data );
|
||||
extern WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index);
|
||||
extern LPWSTR msi_dup_record_field(MSIRECORD *row, INT index);
|
||||
extern LPWSTR msi_dup_property(MSIPACKAGE *package, LPCWSTR prop);
|
||||
extern LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source,
|
||||
BOOL set_prop, MSIFOLDER **folder);
|
||||
@@ -264,7 +267,7 @@ extern LPWSTR build_icon_path(MSIPACKAGE *, LPCWSTR);
|
||||
extern DWORD build_version_dword(LPCWSTR);
|
||||
extern LPWSTR build_directory_name(DWORD , ...);
|
||||
extern BOOL create_full_pathW(const WCHAR *path);
|
||||
extern BOOL ACTION_VerifyComponentForAction(MSIPACKAGE*, MSICOMPONENT*, INSTALLSTATE);
|
||||
extern BOOL ACTION_VerifyComponentForAction(MSICOMPONENT*, INSTALLSTATE);
|
||||
extern BOOL ACTION_VerifyFeatureForAction(MSIFEATURE*, INSTALLSTATE);
|
||||
extern void reduce_to_longfilename(WCHAR*);
|
||||
extern void reduce_to_shortfilename(WCHAR*);
|
||||
@@ -273,6 +276,7 @@ extern void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
|
||||
extern UINT register_unique_action(MSIPACKAGE *, LPCWSTR);
|
||||
extern BOOL check_unique_action(MSIPACKAGE *, LPCWSTR);
|
||||
extern WCHAR* generate_error_string(MSIPACKAGE *, UINT, DWORD, ... );
|
||||
extern UINT msi_create_component_directories( MSIPACKAGE *package );
|
||||
|
||||
|
||||
/* control event stuff */
|
||||
|
||||
@@ -118,15 +118,15 @@ static UINT ACTION_AppSearchGetSignature(MSIPACKAGE *package, MSISIGNATURE *sig,
|
||||
}
|
||||
|
||||
/* get properties */
|
||||
sig->File = load_dynamic_stringW(row,2);
|
||||
minVersion = load_dynamic_stringW(row,3);
|
||||
sig->File = msi_dup_record_field(row,2);
|
||||
minVersion = msi_dup_record_field(row,3);
|
||||
if (minVersion)
|
||||
{
|
||||
ACTION_VerStrToInteger(minVersion, &sig->MinVersionMS,
|
||||
&sig->MinVersionLS);
|
||||
msi_free( minVersion);
|
||||
}
|
||||
maxVersion = load_dynamic_stringW(row,4);
|
||||
maxVersion = msi_dup_record_field(row,4);
|
||||
if (maxVersion)
|
||||
{
|
||||
ACTION_VerStrToInteger(maxVersion, &sig->MaxVersionMS,
|
||||
@@ -139,7 +139,7 @@ static UINT ACTION_AppSearchGetSignature(MSIPACKAGE *package, MSISIGNATURE *sig,
|
||||
sig->MaxSize = MSI_RecordGetInteger(row,6);
|
||||
if (sig->MaxSize == MSI_NULL_INTEGER)
|
||||
sig->MaxSize = 0;
|
||||
sig->Languages = load_dynamic_stringW(row,9);
|
||||
sig->Languages = msi_dup_record_field(row,9);
|
||||
time = MSI_RecordGetInteger(row,7);
|
||||
if (time != MSI_NULL_INTEGER)
|
||||
DosDateTimeToFileTime(HIWORD(time), LOWORD(time), &sig->MinTime);
|
||||
@@ -276,9 +276,9 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, BOOL *appFound,
|
||||
}
|
||||
|
||||
root = MSI_RecordGetInteger(row,2);
|
||||
keyPath = load_dynamic_stringW(row,3);
|
||||
keyPath = msi_dup_record_field(row,3);
|
||||
/* FIXME: keyPath needs to be expanded for properties */
|
||||
valueName = load_dynamic_stringW(row,4);
|
||||
valueName = msi_dup_record_field(row,4);
|
||||
/* FIXME: valueName probably does too */
|
||||
type = MSI_RecordGetInteger(row,5);
|
||||
|
||||
@@ -442,7 +442,7 @@ static UINT ACTION_AppSearchIni(MSIPACKAGE *package, BOOL *appFound,
|
||||
}
|
||||
|
||||
/* get file name */
|
||||
fileName = load_dynamic_stringW(row,2);
|
||||
fileName = msi_dup_record_field(row,2);
|
||||
FIXME("AppSearch unimplemented for IniLocator (ini file name %s)\n",
|
||||
debugstr_w(fileName));
|
||||
msi_free( fileName);
|
||||
@@ -549,7 +549,7 @@ static UINT ACTION_FileVersionMatches(MSISIGNATURE *sig, LPCWSTR filePath,
|
||||
|
||||
if (buf)
|
||||
{
|
||||
static const WCHAR rootW[] = { '\\',0 };
|
||||
static WCHAR rootW[] = { '\\',0 };
|
||||
UINT versionLen;
|
||||
LPVOID subBlock = NULL;
|
||||
|
||||
|
||||
+48
-93
@@ -65,15 +65,15 @@ static MSIAPPID *load_appid( MSIPACKAGE* package, MSIRECORD *row )
|
||||
if (!appid)
|
||||
return NULL;
|
||||
|
||||
appid->AppID = load_dynamic_stringW( row, 1 );
|
||||
appid->AppID = msi_dup_record_field( row, 1 );
|
||||
TRACE("loading appid %s\n", debugstr_w( appid->AppID ));
|
||||
|
||||
buffer = MSI_RecordGetString(row,2);
|
||||
deformat_string( package, buffer, &appid->RemoteServerName );
|
||||
|
||||
appid->LocalServer = load_dynamic_stringW(row,3);
|
||||
appid->ServiceParameters = load_dynamic_stringW(row,4);
|
||||
appid->DllSurrogate = load_dynamic_stringW(row,5);
|
||||
appid->LocalServer = msi_dup_record_field(row,3);
|
||||
appid->ServiceParameters = msi_dup_record_field(row,4);
|
||||
appid->DllSurrogate = msi_dup_record_field(row,5);
|
||||
|
||||
appid->ActivateAtStorage = !MSI_RecordIsNull(row,6);
|
||||
appid->RunAsInteractiveUser = !MSI_RecordIsNull(row,7);
|
||||
@@ -131,7 +131,7 @@ static MSIPROGID *load_progid( MSIPACKAGE* package, MSIRECORD *row )
|
||||
|
||||
list_add_tail( &package->progids, &progid->entry );
|
||||
|
||||
progid->ProgID = load_dynamic_stringW(row,1);
|
||||
progid->ProgID = msi_dup_record_field(row,1);
|
||||
TRACE("loading progid %s\n",debugstr_w(progid->ProgID));
|
||||
|
||||
buffer = MSI_RecordGetString(row,2);
|
||||
@@ -144,12 +144,12 @@ static MSIPROGID *load_progid( MSIPACKAGE* package, MSIRECORD *row )
|
||||
if (progid->Class == NULL && buffer)
|
||||
FIXME("Unknown class %s\n",debugstr_w(buffer));
|
||||
|
||||
progid->Description = load_dynamic_stringW(row,4);
|
||||
progid->Description = msi_dup_record_field(row,4);
|
||||
|
||||
if (!MSI_RecordIsNull(row,6))
|
||||
{
|
||||
INT icon_index = MSI_RecordGetInteger(row,6);
|
||||
LPWSTR FileName = load_dynamic_stringW(row,5);
|
||||
LPCWSTR FileName = MSI_RecordGetString(row,5);
|
||||
LPWSTR FilePath;
|
||||
static const WCHAR fmt[] = {'%','s',',','%','i',0};
|
||||
|
||||
@@ -160,7 +160,6 @@ static MSIPROGID *load_progid( MSIPACKAGE* package, MSIRECORD *row )
|
||||
sprintfW(progid->IconPath,fmt,FilePath,icon_index);
|
||||
|
||||
msi_free(FilePath);
|
||||
msi_free(FileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -180,7 +179,7 @@ static MSIPROGID *load_progid( MSIPACKAGE* package, MSIRECORD *row )
|
||||
while (parent->Parent && parent->Parent != parent)
|
||||
parent = parent->Parent;
|
||||
|
||||
FIXME("need to determing if we are really the CurVer\n");
|
||||
/* FIXME: need to determing if we are really the CurVer */
|
||||
|
||||
progid->CurVer = parent;
|
||||
parent->VersionInd = progid;
|
||||
@@ -235,28 +234,28 @@ static MSICLASS *load_class( MSIPACKAGE* package, MSIRECORD *row )
|
||||
|
||||
list_add_tail( &package->classes, &cls->entry );
|
||||
|
||||
cls->clsid = load_dynamic_stringW( row, 1 );
|
||||
cls->clsid = msi_dup_record_field( row, 1 );
|
||||
TRACE("loading class %s\n",debugstr_w(cls->clsid));
|
||||
cls->Context = load_dynamic_stringW( row, 2 );
|
||||
cls->Context = msi_dup_record_field( row, 2 );
|
||||
buffer = MSI_RecordGetString(row,3);
|
||||
cls->Component = get_loaded_component(package, buffer);
|
||||
|
||||
cls->ProgIDText = load_dynamic_stringW(row,4);
|
||||
cls->ProgIDText = msi_dup_record_field(row,4);
|
||||
cls->ProgID = load_given_progid(package, cls->ProgIDText);
|
||||
|
||||
cls->Description = load_dynamic_stringW(row,5);
|
||||
cls->Description = msi_dup_record_field(row,5);
|
||||
|
||||
buffer = MSI_RecordGetString(row,6);
|
||||
if (buffer)
|
||||
cls->AppID = load_given_appid(package, buffer);
|
||||
|
||||
cls->FileTypeMask = load_dynamic_stringW(row,7);
|
||||
cls->FileTypeMask = msi_dup_record_field(row,7);
|
||||
|
||||
if (!MSI_RecordIsNull(row,9))
|
||||
{
|
||||
|
||||
INT icon_index = MSI_RecordGetInteger(row,9);
|
||||
LPWSTR FileName = load_dynamic_stringW(row,8);
|
||||
LPCWSTR FileName = MSI_RecordGetString(row,8);
|
||||
LPWSTR FilePath;
|
||||
static const WCHAR fmt[] = {'%','s',',','%','i',0};
|
||||
|
||||
@@ -267,7 +266,6 @@ static MSICLASS *load_class( MSIPACKAGE* package, MSIRECORD *row )
|
||||
sprintfW(cls->IconPath,fmt,FilePath,icon_index);
|
||||
|
||||
msi_free(FilePath);
|
||||
msi_free(FileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -300,7 +298,7 @@ static MSICLASS *load_class( MSIPACKAGE* package, MSIRECORD *row )
|
||||
}
|
||||
else
|
||||
{
|
||||
cls->DefInprocHandler32 = load_dynamic_stringW( row, 10);
|
||||
cls->DefInprocHandler32 = msi_dup_record_field( row, 10);
|
||||
reduce_to_longfilename(cls->DefInprocHandler32);
|
||||
}
|
||||
}
|
||||
@@ -366,13 +364,13 @@ static MSIMIME *load_mime( MSIPACKAGE* package, MSIRECORD *row )
|
||||
if (!mt)
|
||||
return mt;
|
||||
|
||||
mt->ContentType = load_dynamic_stringW( row, 1 );
|
||||
mt->ContentType = msi_dup_record_field( row, 1 );
|
||||
TRACE("loading mime %s\n", debugstr_w(mt->ContentType));
|
||||
|
||||
buffer = MSI_RecordGetString( row, 2 );
|
||||
mt->Extension = load_given_extension( package, buffer );
|
||||
|
||||
mt->clsid = load_dynamic_stringW( row, 3 );
|
||||
mt->clsid = msi_dup_record_field( row, 3 );
|
||||
mt->Class = load_given_class( package, mt->clsid );
|
||||
|
||||
list_add_tail( &package->mimes, &mt->entry );
|
||||
@@ -428,13 +426,13 @@ static MSIEXTENSION *load_extension( MSIPACKAGE* package, MSIRECORD *row )
|
||||
|
||||
list_add_tail( &package->extensions, &ext->entry );
|
||||
|
||||
ext->Extension = load_dynamic_stringW( row, 1 );
|
||||
ext->Extension = msi_dup_record_field( row, 1 );
|
||||
TRACE("loading extension %s\n", debugstr_w(ext->Extension));
|
||||
|
||||
buffer = MSI_RecordGetString( row, 2 );
|
||||
ext->Component = get_loaded_component( package,buffer );
|
||||
|
||||
ext->ProgIDText = load_dynamic_stringW( row, 3 );
|
||||
ext->ProgIDText = msi_dup_record_field( row, 3 );
|
||||
ext->ProgID = load_given_progid( package, ext->ProgIDText );
|
||||
|
||||
buffer = MSI_RecordGetString( row, 4 );
|
||||
@@ -505,7 +503,7 @@ static UINT iterate_load_verb(MSIRECORD *row, LPVOID param)
|
||||
if (!verb)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
verb->Verb = load_dynamic_stringW(row,2);
|
||||
verb->Verb = msi_dup_record_field(row,2);
|
||||
TRACE("loading verb %s\n",debugstr_w(verb->Verb));
|
||||
verb->Sequence = MSI_RecordGetInteger(row,3);
|
||||
|
||||
@@ -837,9 +835,6 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
|
||||
BOOL install_on_demand = FALSE;
|
||||
MSICLASS *cls;
|
||||
|
||||
if (!package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
load_classes_and_such(package);
|
||||
rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
@@ -1043,68 +1038,36 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static UINT register_progid_base(MSIPACKAGE* package, MSIPROGID* progid,
|
||||
LPWSTR clsid)
|
||||
static LPCWSTR get_clsid_of_progid( MSIPROGID *progid )
|
||||
{
|
||||
while (progid)
|
||||
{
|
||||
if (progid->Class)
|
||||
return progid->Class->clsid;
|
||||
progid = progid->Parent;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static UINT register_progid( MSIPROGID* progid )
|
||||
{
|
||||
static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
|
||||
static const WCHAR szDefaultIcon[] =
|
||||
{'D','e','f','a','u','l','t','I','c','o','n',0};
|
||||
HKEY hkey;
|
||||
static const WCHAR szCurVer[] =
|
||||
{'C','u','r','V','e','r',0};
|
||||
HKEY hkey = 0;
|
||||
UINT rc;
|
||||
|
||||
RegCreateKeyW(HKEY_CLASSES_ROOT,progid->ProgID,&hkey);
|
||||
rc = RegCreateKeyW( HKEY_CLASSES_ROOT, progid->ProgID, &hkey );
|
||||
if (rc == ERROR_SUCCESS)
|
||||
{
|
||||
LPCWSTR clsid = get_clsid_of_progid( progid );
|
||||
|
||||
if (progid->Description)
|
||||
msi_reg_set_val_str( hkey, NULL, progid->Description );
|
||||
|
||||
if (progid->Class)
|
||||
{
|
||||
msi_reg_set_subkey_val( hkey, szCLSID, NULL, progid->Class->clsid );
|
||||
if (clsid)
|
||||
strcpyW( clsid, progid->Class->clsid );
|
||||
}
|
||||
else
|
||||
{
|
||||
FIXME("progid (%s) with null classid\n", debugstr_w(progid->ProgID));
|
||||
}
|
||||
|
||||
if (progid->IconPath)
|
||||
msi_reg_set_subkey_val( hkey, szDefaultIcon, NULL, progid->IconPath );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid,
|
||||
LPWSTR clsid)
|
||||
{
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
|
||||
if (progid->Parent == NULL)
|
||||
rc = register_progid_base(package, progid, clsid);
|
||||
else
|
||||
{
|
||||
DWORD disp;
|
||||
HKEY hkey;
|
||||
static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
|
||||
static const WCHAR szDefaultIcon[] =
|
||||
{'D','e','f','a','u','l','t','I','c','o','n',0};
|
||||
static const WCHAR szCurVer[] =
|
||||
{'C','u','r','V','e','r',0};
|
||||
|
||||
/* check if already registered */
|
||||
RegCreateKeyExW(HKEY_CLASSES_ROOT, progid->ProgID, 0, NULL, 0,
|
||||
KEY_ALL_ACCESS, NULL, &hkey, &disp );
|
||||
if (disp == REG_OPENED_EXISTING_KEY)
|
||||
{
|
||||
TRACE("Key already registered\n");
|
||||
RegCloseKey(hkey);
|
||||
return rc;
|
||||
}
|
||||
|
||||
TRACE("Registering Parent %s\n", debugstr_w(progid->Parent->ProgID) );
|
||||
rc = register_progid( package, progid->Parent, clsid );
|
||||
|
||||
/* clsid is same as parent */
|
||||
msi_reg_set_subkey_val( hkey, szCLSID, NULL, clsid );
|
||||
msi_reg_set_subkey_val( hkey, szCLSID, NULL, clsid );
|
||||
else
|
||||
ERR("%s has no class\n", debugstr_w( progid->ProgID ) );
|
||||
|
||||
if (progid->Description)
|
||||
msi_reg_set_val_str( hkey, NULL, progid->Description );
|
||||
@@ -1118,6 +1081,9 @@ static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid,
|
||||
|
||||
RegCloseKey(hkey);
|
||||
}
|
||||
else
|
||||
ERR("failed to create key %s\n", debugstr_w( progid->ProgID ) );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1126,15 +1092,10 @@ UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
|
||||
MSIPROGID *progid;
|
||||
MSIRECORD *uirow;
|
||||
|
||||
if (!package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
load_classes_and_such(package);
|
||||
|
||||
LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry )
|
||||
{
|
||||
WCHAR clsid[0x1000];
|
||||
|
||||
/* check if this progid is to be installed */
|
||||
if (progid->Class && progid->Class->Installed)
|
||||
progid->InstallMe = TRUE;
|
||||
@@ -1148,9 +1109,9 @@ UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
|
||||
|
||||
TRACE("Registering progid %s\n", debugstr_w(progid->ProgID));
|
||||
|
||||
register_progid( package, progid, clsid );
|
||||
register_progid( progid );
|
||||
|
||||
uirow = MSI_CreateRecord(1);
|
||||
uirow = MSI_CreateRecord( 1 );
|
||||
MSI_RecordSetStringW( uirow, 1, progid->ProgID );
|
||||
ui_actiondata( package, szRegisterProgIdInfo, uirow );
|
||||
msiobj_release( &uirow->hdr );
|
||||
@@ -1247,9 +1208,6 @@ UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
|
||||
MSIRECORD *uirow;
|
||||
BOOL install_on_demand = TRUE;
|
||||
|
||||
if (!package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
load_classes_and_such(package);
|
||||
|
||||
/* We need to set install_on_demand based on if the shell handles advertised
|
||||
@@ -1355,9 +1313,6 @@ UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
|
||||
MSIRECORD *uirow;
|
||||
MSIMIME *mt;
|
||||
|
||||
if (!package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
load_classes_and_such(package);
|
||||
|
||||
LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry )
|
||||
|
||||
+340
-413
@@ -28,12 +28,14 @@
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winuser.h"
|
||||
#include "wine/debug.h"
|
||||
#include "wine/unicode.h"
|
||||
|
||||
#include "msi.h"
|
||||
#include "msiquery.h"
|
||||
#include "msipriv.h"
|
||||
#include "action.h"
|
||||
|
||||
#define YYLEX_PARAM info
|
||||
#define YYPARSE_PARAM info
|
||||
@@ -58,45 +60,44 @@ struct cond_str {
|
||||
static LPWSTR COND_GetString( struct cond_str *str );
|
||||
static LPWSTR COND_GetLiteral( struct cond_str *str );
|
||||
static int COND_lex( void *COND_lval, COND_input *info);
|
||||
static const WCHAR szEmpty[] = { 0 };
|
||||
|
||||
typedef INT (*comp_int)(INT a, INT b);
|
||||
typedef INT (*comp_str)(LPWSTR a, LPWSTR b, BOOL caseless);
|
||||
typedef INT (*comp_m1)(LPWSTR a,int b);
|
||||
typedef INT (*comp_m2)(int a,LPWSTR b);
|
||||
static INT compare_int( INT a, INT operator, INT b );
|
||||
static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b );
|
||||
|
||||
static INT comp_lt_i(INT a, INT b);
|
||||
static INT comp_gt_i(INT a, INT b);
|
||||
static INT comp_le_i(INT a, INT b);
|
||||
static INT comp_ge_i(INT a, INT b);
|
||||
static INT comp_eq_i(INT a, INT b);
|
||||
static INT comp_ne_i(INT a, INT b);
|
||||
static INT comp_bitand(INT a, INT b);
|
||||
static INT comp_highcomp(INT a, INT b);
|
||||
static INT comp_lowcomp(INT a, INT b);
|
||||
static INT compare_and_free_strings( LPWSTR a, INT op, LPWSTR b )
|
||||
{
|
||||
INT r;
|
||||
|
||||
static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless);
|
||||
static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless);
|
||||
static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless);
|
||||
static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless);
|
||||
static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless);
|
||||
static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless);
|
||||
static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless);
|
||||
static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless);
|
||||
static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless);
|
||||
r = compare_string( a, op, b );
|
||||
msi_free( a );
|
||||
msi_free( b );
|
||||
return r;
|
||||
}
|
||||
|
||||
static INT comp_eq_m1(LPWSTR a, INT b);
|
||||
static INT comp_ne_m1(LPWSTR a, INT b);
|
||||
static INT comp_lt_m1(LPWSTR a, INT b);
|
||||
static INT comp_gt_m1(LPWSTR a, INT b);
|
||||
static INT comp_le_m1(LPWSTR a, INT b);
|
||||
static INT comp_ge_m1(LPWSTR a, INT b);
|
||||
static BOOL num_from_prop( LPCWSTR p, INT *val )
|
||||
{
|
||||
INT ret = 0, sign = 1;
|
||||
|
||||
static INT comp_eq_m2(INT a, LPWSTR b);
|
||||
static INT comp_ne_m2(INT a, LPWSTR b);
|
||||
static INT comp_lt_m2(INT a, LPWSTR b);
|
||||
static INT comp_gt_m2(INT a, LPWSTR b);
|
||||
static INT comp_le_m2(INT a, LPWSTR b);
|
||||
static INT comp_ge_m2(INT a, LPWSTR b);
|
||||
if (!p)
|
||||
return FALSE;
|
||||
if (*p == '-')
|
||||
{
|
||||
sign = -1;
|
||||
p++;
|
||||
}
|
||||
if (!*p)
|
||||
return FALSE;
|
||||
while (*p)
|
||||
{
|
||||
if( *p < '0' || *p > '9' )
|
||||
return FALSE;
|
||||
ret = ret*10 + (*p - '0');
|
||||
p++;
|
||||
}
|
||||
*val = ret*sign;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
@@ -107,37 +108,36 @@ static INT comp_ge_m2(INT a, LPWSTR b);
|
||||
struct cond_str str;
|
||||
LPWSTR string;
|
||||
INT value;
|
||||
comp_int fn_comp_int;
|
||||
comp_str fn_comp_str;
|
||||
comp_m1 fn_comp_m1;
|
||||
comp_m2 fn_comp_m2;
|
||||
}
|
||||
|
||||
%token COND_SPACE COND_EOF COND_SPACE
|
||||
%token COND_OR COND_AND COND_NOT
|
||||
%token COND_LT COND_GT COND_EQ
|
||||
%token COND_LPAR COND_RPAR COND_TILDA
|
||||
%token COND_OR COND_AND COND_NOT COND_XOR COND_IMP COND_EQV
|
||||
%token COND_LT COND_GT COND_EQ COND_NE COND_GE COND_LE
|
||||
%token COND_ILT COND_IGT COND_IEQ COND_INE COND_IGE COND_ILE
|
||||
%token COND_LPAR COND_RPAR COND_TILDA COND_SS COND_ISS
|
||||
%token COND_ILHS COND_IRHS COND_LHS COND_RHS
|
||||
%token COND_PERCENT COND_DOLLARS COND_QUESTION COND_AMPER COND_EXCLAM
|
||||
%token <str> COND_IDENT <str> COND_NUMBER <str> COND_LITER
|
||||
|
||||
%nonassoc COND_EOF COND_ERROR
|
||||
%nonassoc COND_ERROR COND_EOF
|
||||
|
||||
%type <value> expression boolean_term boolean_factor
|
||||
%type <value> term value_i symbol_i integer
|
||||
%type <string> identifier value_s symbol_s literal
|
||||
%type <fn_comp_int> comp_op_i
|
||||
%type <fn_comp_str> comp_op_s
|
||||
%type <fn_comp_m1> comp_op_m1
|
||||
%type <fn_comp_m2> comp_op_m2
|
||||
%type <value> value_i integer operator
|
||||
%type <string> identifier symbol_s value_s literal
|
||||
|
||||
%%
|
||||
|
||||
condition:
|
||||
expression
|
||||
expression
|
||||
{
|
||||
COND_input* cond = (COND_input*) info;
|
||||
cond->result = $1;
|
||||
}
|
||||
| /* empty */
|
||||
{
|
||||
COND_input* cond = (COND_input*) info;
|
||||
cond->result = MSICONDITION_NONE;
|
||||
}
|
||||
;
|
||||
|
||||
expression:
|
||||
@@ -145,10 +145,22 @@ expression:
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| boolean_term COND_OR expression
|
||||
| expression COND_OR boolean_term
|
||||
{
|
||||
$$ = $1 || $3;
|
||||
}
|
||||
| expression COND_IMP boolean_term
|
||||
{
|
||||
$$ = !$1 || $3;
|
||||
}
|
||||
| expression COND_XOR boolean_term
|
||||
{
|
||||
$$ = ( $1 || $3 ) && !( $1 && $3 );
|
||||
}
|
||||
| expression COND_EQV boolean_term
|
||||
{
|
||||
$$ = ( $1 && $3 ) || ( !$1 && !$3 );
|
||||
}
|
||||
;
|
||||
|
||||
boolean_term:
|
||||
@@ -156,59 +168,68 @@ boolean_term:
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| boolean_term COND_AND boolean_factor
|
||||
| boolean_term COND_AND boolean_factor
|
||||
{
|
||||
$$ = $1 && $3;
|
||||
}
|
||||
;
|
||||
|
||||
boolean_factor:
|
||||
term
|
||||
COND_NOT boolean_factor
|
||||
{
|
||||
$$ = $1;
|
||||
$$ = $2 ? 0 : 1;
|
||||
}
|
||||
| COND_NOT term
|
||||
| value_i
|
||||
{
|
||||
$$ = ! $2;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
term:
|
||||
value_i
|
||||
{
|
||||
$$ = $1;
|
||||
$$ = $1 ? 1 : 0;
|
||||
}
|
||||
| value_s
|
||||
{
|
||||
$$ = ($1 && $1[0]) ? MSICONDITION_TRUE : MSICONDITION_FALSE;
|
||||
msi_free( $1 );
|
||||
$$ = ($1 && $1[0]) ? 1 : 0;
|
||||
}
|
||||
| value_i comp_op_i value_i
|
||||
| value_i operator value_i
|
||||
{
|
||||
$$ = $2( $1, $3 );
|
||||
$$ = compare_int( $1, $2, $3 );
|
||||
}
|
||||
| value_s comp_op_s value_s
|
||||
| symbol_s operator value_i
|
||||
{
|
||||
$$ = $2( $1, $3, FALSE );
|
||||
msi_free( $1 );
|
||||
msi_free( $3 );
|
||||
int num;
|
||||
if (num_from_prop( $1, &num ))
|
||||
$$ = compare_int( num, $2, $3 );
|
||||
else
|
||||
$$ = ($2 == COND_NE || $2 == COND_INE );
|
||||
}
|
||||
| value_s COND_TILDA comp_op_s value_s
|
||||
| value_i operator symbol_s
|
||||
{
|
||||
$$ = $3( $1, $4, TRUE );
|
||||
msi_free( $1 );
|
||||
msi_free( $4 );
|
||||
int num;
|
||||
if (num_from_prop( $3, &num ))
|
||||
$$ = compare_int( $1, $2, num );
|
||||
else
|
||||
$$ = ($2 == COND_NE || $2 == COND_INE );
|
||||
}
|
||||
| value_s comp_op_m1 value_i
|
||||
| symbol_s operator symbol_s
|
||||
{
|
||||
$$ = $2( $1, $3 );
|
||||
msi_free( $1 );
|
||||
$$ = compare_and_free_strings( $1, $2, $3 );
|
||||
}
|
||||
| value_i comp_op_m2 value_s
|
||||
| symbol_s operator literal
|
||||
{
|
||||
$$ = $2( $1, $3 );
|
||||
msi_free( $3 );
|
||||
$$ = compare_and_free_strings( $1, $2, $3 );
|
||||
}
|
||||
| literal operator symbol_s
|
||||
{
|
||||
$$ = compare_and_free_strings( $1, $2, $3 );
|
||||
}
|
||||
| literal operator literal
|
||||
{
|
||||
$$ = compare_and_free_strings( $1, $2, $3 );
|
||||
}
|
||||
| literal operator value_i
|
||||
{
|
||||
$$ = 0;
|
||||
}
|
||||
| value_i operator literal
|
||||
{
|
||||
$$ = 0;
|
||||
}
|
||||
| COND_LPAR expression COND_RPAR
|
||||
{
|
||||
@@ -216,183 +237,30 @@ term:
|
||||
}
|
||||
;
|
||||
|
||||
comp_op_i:
|
||||
operator:
|
||||
/* common functions */
|
||||
COND_EQ
|
||||
{
|
||||
$$ = comp_eq_i;
|
||||
}
|
||||
| COND_LT COND_GT
|
||||
{
|
||||
$$ = comp_ne_i;
|
||||
}
|
||||
| COND_LT
|
||||
{
|
||||
$$ = comp_lt_i;
|
||||
}
|
||||
| COND_GT
|
||||
{
|
||||
$$ = comp_gt_i;
|
||||
}
|
||||
| COND_LT COND_EQ
|
||||
{
|
||||
$$ = comp_le_i;
|
||||
}
|
||||
| COND_GT COND_EQ
|
||||
{
|
||||
$$ = comp_ge_i;
|
||||
}
|
||||
/*Int only*/
|
||||
| COND_GT COND_LT
|
||||
{
|
||||
$$ = comp_bitand;
|
||||
}
|
||||
| COND_LT COND_LT
|
||||
{
|
||||
$$ = comp_highcomp;
|
||||
}
|
||||
| COND_GT COND_GT
|
||||
{
|
||||
$$ = comp_lowcomp;
|
||||
}
|
||||
;
|
||||
|
||||
comp_op_s:
|
||||
/* common functions */
|
||||
COND_EQ
|
||||
{
|
||||
$$ = comp_eq_s;
|
||||
}
|
||||
| COND_LT COND_GT
|
||||
{
|
||||
$$ = comp_ne_s;
|
||||
}
|
||||
| COND_LT
|
||||
{
|
||||
$$ = comp_lt_s;
|
||||
}
|
||||
| COND_GT
|
||||
{
|
||||
$$ = comp_gt_s;
|
||||
}
|
||||
| COND_LT COND_EQ
|
||||
{
|
||||
$$ = comp_le_s;
|
||||
}
|
||||
| COND_GT COND_EQ
|
||||
{
|
||||
$$ = comp_ge_s;
|
||||
}
|
||||
/*string only*/
|
||||
| COND_GT COND_LT
|
||||
{
|
||||
$$ = comp_substring;
|
||||
}
|
||||
| COND_LT COND_LT
|
||||
{
|
||||
$$ = comp_start;
|
||||
}
|
||||
| COND_GT COND_GT
|
||||
{
|
||||
$$ = comp_end;
|
||||
}
|
||||
;
|
||||
|
||||
comp_op_m1:
|
||||
/* common functions */
|
||||
COND_EQ
|
||||
{
|
||||
$$ = comp_eq_m1;
|
||||
}
|
||||
| COND_LT COND_GT
|
||||
{
|
||||
$$ = comp_ne_m1;
|
||||
}
|
||||
| COND_LT
|
||||
{
|
||||
$$ = comp_lt_m1;
|
||||
}
|
||||
| COND_GT
|
||||
{
|
||||
$$ = comp_gt_m1;
|
||||
}
|
||||
| COND_LT COND_EQ
|
||||
{
|
||||
$$ = comp_le_m1;
|
||||
}
|
||||
| COND_GT COND_EQ
|
||||
{
|
||||
$$ = comp_ge_m1;
|
||||
}
|
||||
/*Not valid for mixed compares*/
|
||||
| COND_GT COND_LT
|
||||
{
|
||||
$$ = 0;
|
||||
}
|
||||
| COND_LT COND_LT
|
||||
{
|
||||
$$ = 0;
|
||||
}
|
||||
| COND_GT COND_GT
|
||||
{
|
||||
$$ = 0;
|
||||
}
|
||||
;
|
||||
|
||||
comp_op_m2:
|
||||
/* common functions */
|
||||
COND_EQ
|
||||
{
|
||||
$$ = comp_eq_m2;
|
||||
}
|
||||
| COND_LT COND_GT
|
||||
{
|
||||
$$ = comp_ne_m2;
|
||||
}
|
||||
| COND_LT
|
||||
{
|
||||
$$ = comp_lt_m2;
|
||||
}
|
||||
| COND_GT
|
||||
{
|
||||
$$ = comp_gt_m2;
|
||||
}
|
||||
| COND_LT COND_EQ
|
||||
{
|
||||
$$ = comp_le_m2;
|
||||
}
|
||||
| COND_GT COND_EQ
|
||||
{
|
||||
$$ = comp_ge_m2;
|
||||
}
|
||||
/*Not valid for mixed compares*/
|
||||
| COND_GT COND_LT
|
||||
{
|
||||
$$ = 0;
|
||||
}
|
||||
| COND_LT COND_LT
|
||||
{
|
||||
$$ = 0;
|
||||
}
|
||||
| COND_GT COND_GT
|
||||
{
|
||||
$$ = 0;
|
||||
}
|
||||
;
|
||||
|
||||
value_i:
|
||||
symbol_i
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| integer
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
COND_EQ { $$ = COND_EQ; }
|
||||
| COND_NE { $$ = COND_NE; }
|
||||
| COND_LT { $$ = COND_LT; }
|
||||
| COND_GT { $$ = COND_GT; }
|
||||
| COND_LE { $$ = COND_LE; }
|
||||
| COND_GE { $$ = COND_GE; }
|
||||
| COND_SS { $$ = COND_SS; }
|
||||
| COND_IEQ { $$ = COND_IEQ; }
|
||||
| COND_INE { $$ = COND_INE; }
|
||||
| COND_ILT { $$ = COND_ILT; }
|
||||
| COND_IGT { $$ = COND_IGT; }
|
||||
| COND_ILE { $$ = COND_ILE; }
|
||||
| COND_IGE { $$ = COND_IGE; }
|
||||
| COND_ISS { $$ = COND_ISS; }
|
||||
| COND_LHS { $$ = COND_LHS; }
|
||||
| COND_RHS { $$ = COND_RHS; }
|
||||
| COND_ILHS { $$ = COND_ILHS; }
|
||||
| COND_IRHS { $$ = COND_IRHS; }
|
||||
;
|
||||
|
||||
value_s:
|
||||
symbol_s
|
||||
symbol_s
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
@@ -411,8 +279,12 @@ literal:
|
||||
}
|
||||
;
|
||||
|
||||
symbol_i:
|
||||
COND_DOLLARS identifier
|
||||
value_i:
|
||||
integer
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| COND_DOLLARS identifier
|
||||
{
|
||||
COND_input* cond = (COND_input*) info;
|
||||
INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
|
||||
@@ -453,35 +325,19 @@ symbol_i:
|
||||
symbol_s:
|
||||
identifier
|
||||
{
|
||||
DWORD sz;
|
||||
COND_input* cond = (COND_input*) info;
|
||||
|
||||
sz = 0;
|
||||
MSI_GetPropertyW(cond->package, $1, NULL, &sz);
|
||||
if (sz == 0)
|
||||
{
|
||||
$$ = msi_alloc( sizeof(WCHAR));
|
||||
$$[0] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sz ++;
|
||||
$$ = msi_alloc( sz*sizeof (WCHAR) );
|
||||
|
||||
/* Lookup the identifier */
|
||||
|
||||
MSI_GetPropertyW(cond->package,$1,$$,&sz);
|
||||
}
|
||||
$$ = msi_dup_property( cond->package, $1 );
|
||||
msi_free( $1 );
|
||||
}
|
||||
| COND_PERCENT identifier
|
||||
{
|
||||
UINT len = GetEnvironmentVariableW( $2, NULL, 0 );
|
||||
if( len++ )
|
||||
$$ = NULL;
|
||||
if (len++)
|
||||
{
|
||||
$$ = msi_alloc( len*sizeof (WCHAR) );
|
||||
if( $$ )
|
||||
GetEnvironmentVariableW( $2, $$, len );
|
||||
GetEnvironmentVariableW( $2, $$, len );
|
||||
}
|
||||
msi_free( $2 );
|
||||
}
|
||||
@@ -522,83 +378,105 @@ static int COND_IsNumber( WCHAR x )
|
||||
return( (( x >= '0' ) && ( x <= '9' )) || (x =='-') || (x =='.') );
|
||||
}
|
||||
|
||||
static WCHAR *strstriW( const WCHAR *str, const WCHAR *sub )
|
||||
{
|
||||
LPWSTR strlower, sublower, r;
|
||||
strlower = CharLowerW( strdupW( str ) );
|
||||
sublower = CharLowerW( strdupW( sub ) );
|
||||
r = strstrW( strlower, sublower );
|
||||
if (r)
|
||||
r = (LPWSTR)str + (r - strlower);
|
||||
msi_free( strlower );
|
||||
msi_free( sublower );
|
||||
return r;
|
||||
}
|
||||
|
||||
/* the mess of comparison functions */
|
||||
static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b )
|
||||
{
|
||||
/* null and empty string are equivalent */
|
||||
if (!a) a = szEmpty;
|
||||
if (!b) b = szEmpty;
|
||||
|
||||
static INT comp_lt_i(INT a, INT b)
|
||||
{ return (a < b); }
|
||||
static INT comp_gt_i(INT a, INT b)
|
||||
{ return (a > b); }
|
||||
static INT comp_le_i(INT a, INT b)
|
||||
{ return (a <= b); }
|
||||
static INT comp_ge_i(INT a, INT b)
|
||||
{ return (a >= b); }
|
||||
static INT comp_eq_i(INT a, INT b)
|
||||
{ return (a == b); }
|
||||
static INT comp_ne_i(INT a, INT b)
|
||||
{ return (a != b); }
|
||||
static INT comp_bitand(INT a, INT b)
|
||||
{ return a & b;}
|
||||
static INT comp_highcomp(INT a, INT b)
|
||||
{ return HIWORD(a)==b; }
|
||||
static INT comp_lowcomp(INT a, INT b)
|
||||
{ return LOWORD(a)==b; }
|
||||
|
||||
static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless)
|
||||
{ if (casless) return !strcmpiW(a,b); else return !strcmpW(a,b);}
|
||||
static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless)
|
||||
{ if (casless) return strcmpiW(a,b); else return strcmpW(a,b);}
|
||||
static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless)
|
||||
{ if (casless) return strcmpiW(a,b)<0; else return strcmpW(a,b)<0;}
|
||||
static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless)
|
||||
{ if (casless) return strcmpiW(a,b)>0; else return strcmpW(a,b)>0;}
|
||||
static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless)
|
||||
{ if (casless) return strcmpiW(a,b)<=0; else return strcmpW(a,b)<=0;}
|
||||
static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless)
|
||||
{ if (casless) return strcmpiW(a,b)>=0; else return strcmpW(a,b)>=0;}
|
||||
static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless)
|
||||
/* ERROR NOT WORKING REWRITE */
|
||||
{ if (casless) return strstrW(a,b)!=NULL; else return strstrW(a,b)!=NULL;}
|
||||
static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless)
|
||||
{ if (casless) return strncmpiW(a,b,strlenW(b))==0;
|
||||
else return strncmpW(a,b,strlenW(b))==0;}
|
||||
static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless)
|
||||
{
|
||||
int i = strlenW(a);
|
||||
int j = strlenW(b);
|
||||
if (j>i)
|
||||
/* a or b may be NULL */
|
||||
switch (operator)
|
||||
{
|
||||
case COND_LT:
|
||||
return -1 == lstrcmpW( a, b );
|
||||
case COND_GT:
|
||||
return 1 == lstrcmpW( a, b );
|
||||
case COND_EQ:
|
||||
return 0 == lstrcmpW( a, b );
|
||||
case COND_NE:
|
||||
return 0 != lstrcmpW( a, b );
|
||||
case COND_GE:
|
||||
return -1 != lstrcmpW( a, b );
|
||||
case COND_LE:
|
||||
return 1 != lstrcmpW( a, b );
|
||||
case COND_SS: /* substring */
|
||||
return strstrW( a, b ) ? 1 : 0;
|
||||
case COND_ILT:
|
||||
return -1 == lstrcmpiW( a, b );
|
||||
case COND_IGT:
|
||||
return 1 == lstrcmpiW( a, b );
|
||||
case COND_IEQ:
|
||||
return 0 == lstrcmpiW( a, b );
|
||||
case COND_INE:
|
||||
return 0 != lstrcmpiW( a, b );
|
||||
case COND_IGE:
|
||||
return -1 != lstrcmpiW( a, b );
|
||||
case COND_ILE:
|
||||
return 1 != lstrcmpiW( a, b );
|
||||
case COND_ISS:
|
||||
return strstriW( a, b ) ? 1 : 0;
|
||||
case COND_LHS:
|
||||
case COND_RHS:
|
||||
case COND_ILHS:
|
||||
case COND_IRHS:
|
||||
ERR("unimplemented string comparison\n");
|
||||
break;
|
||||
default:
|
||||
ERR("invalid integer operator\n");
|
||||
return 0;
|
||||
if (casless) return (!strcmpiW(&a[i-j-1],b));
|
||||
else return (!strcmpW(&a[i-j-1],b));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static INT comp_eq_m1(LPWSTR a, INT b)
|
||||
{ if (COND_IsNumber(a[0])) return atoiW(a)==b; else return 0;}
|
||||
static INT comp_ne_m1(LPWSTR a, INT b)
|
||||
{ if (COND_IsNumber(a[0])) return atoiW(a)!=b; else return 1;}
|
||||
static INT comp_lt_m1(LPWSTR a, INT b)
|
||||
{ if (COND_IsNumber(a[0])) return atoiW(a)<b; else return 0;}
|
||||
static INT comp_gt_m1(LPWSTR a, INT b)
|
||||
{ if (COND_IsNumber(a[0])) return atoiW(a)>b; else return 0;}
|
||||
static INT comp_le_m1(LPWSTR a, INT b)
|
||||
{ if (COND_IsNumber(a[0])) return atoiW(a)<=b; else return 0;}
|
||||
static INT comp_ge_m1(LPWSTR a, INT b)
|
||||
{ if (COND_IsNumber(a[0])) return atoiW(a)>=b; else return 0;}
|
||||
|
||||
static INT comp_eq_m2(INT a, LPWSTR b)
|
||||
{ if (COND_IsNumber(b[0])) return a == atoiW(b); else return 0;}
|
||||
static INT comp_ne_m2(INT a, LPWSTR b)
|
||||
{ if (COND_IsNumber(b[0])) return a != atoiW(b); else return 1;}
|
||||
static INT comp_lt_m2(INT a, LPWSTR b)
|
||||
{ if (COND_IsNumber(b[0])) return a < atoiW(b); else return 0;}
|
||||
static INT comp_gt_m2(INT a, LPWSTR b)
|
||||
{ if (COND_IsNumber(b[0])) return a > atoiW(b); else return 0;}
|
||||
static INT comp_le_m2(INT a, LPWSTR b)
|
||||
{ if (COND_IsNumber(b[0])) return a <= atoiW(b); else return 0;}
|
||||
static INT comp_ge_m2(INT a, LPWSTR b)
|
||||
{ if (COND_IsNumber(b[0])) return a >= atoiW(b); else return 0;}
|
||||
|
||||
static INT compare_int( INT a, INT operator, INT b )
|
||||
{
|
||||
switch (operator)
|
||||
{
|
||||
case COND_LT:
|
||||
case COND_ILT:
|
||||
return a < b;
|
||||
case COND_GT:
|
||||
case COND_IGT:
|
||||
return a > b;
|
||||
case COND_EQ:
|
||||
case COND_IEQ:
|
||||
return a == b;
|
||||
case COND_NE:
|
||||
case COND_INE:
|
||||
return a != b;
|
||||
case COND_GE:
|
||||
case COND_IGE:
|
||||
return a >= b;
|
||||
case COND_LE:
|
||||
case COND_ILE:
|
||||
return a >= b;
|
||||
case COND_SS:
|
||||
case COND_ISS:
|
||||
return ( a & b ) ? 1 : 0;
|
||||
case COND_RHS:
|
||||
return ( ( a & 0xffff ) == b ) ? 1 : 0;
|
||||
case COND_LHS:
|
||||
return ( ( (a>>16) & 0xffff ) == b ) ? 1 : 0;
|
||||
default:
|
||||
ERR("invalid integer operator\n");
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int COND_IsIdent( WCHAR x )
|
||||
@@ -607,17 +485,54 @@ static int COND_IsIdent( WCHAR x )
|
||||
|| ( x == '#' ) || (x == '.') );
|
||||
}
|
||||
|
||||
static int COND_GetOperator( COND_input *cond )
|
||||
{
|
||||
static const struct {
|
||||
const WCHAR str[4];
|
||||
int id;
|
||||
} table[] = {
|
||||
{ {'~','=',0}, COND_IEQ },
|
||||
{ {'~','>','=',0}, COND_ILE },
|
||||
{ {'~','>','<',0}, COND_ISS },
|
||||
{ {'~','>','>',0}, COND_IRHS },
|
||||
{ {'~','>',0}, COND_ILT },
|
||||
{ {'~','<','>',0}, COND_INE },
|
||||
{ {'~','<','=',0}, COND_IGE },
|
||||
{ {'~','<','<',0}, COND_ILHS },
|
||||
{ {'~','<',0}, COND_IGT },
|
||||
{ {'>','=',0}, COND_GE },
|
||||
{ {'>','<',0}, COND_SS },
|
||||
{ {'>','>',0}, COND_LHS },
|
||||
{ {'>',0}, COND_GT },
|
||||
{ {'<','>',0}, COND_NE },
|
||||
{ {'<','=',0}, COND_LE },
|
||||
{ {'<','<',0}, COND_RHS },
|
||||
{ {'<',0}, COND_LT },
|
||||
{ {0}, 0 }
|
||||
};
|
||||
LPCWSTR p = &cond->str[cond->n];
|
||||
int i = 0, len;
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
len = lstrlenW( table[i].str );
|
||||
if ( !len || 0 == strncmpW( table[i].str, p, len ) )
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
cond->n += len;
|
||||
return table[i].id;
|
||||
}
|
||||
|
||||
static int COND_GetOne( struct cond_str *str, COND_input *cond )
|
||||
{
|
||||
static const WCHAR szNot[] = {'N','O','T',0};
|
||||
static const WCHAR szAnd[] = {'A','N','D',0};
|
||||
static const WCHAR szOr[] = {'O','R',0};
|
||||
WCHAR ch;
|
||||
int rc, len = 1;
|
||||
WCHAR ch;
|
||||
|
||||
str->data = &cond->str[cond->n];
|
||||
|
||||
ch = str->data[0];
|
||||
|
||||
switch( ch )
|
||||
{
|
||||
case 0: return 0;
|
||||
@@ -630,58 +545,73 @@ static int COND_GetOne( struct cond_str *str, COND_input *cond )
|
||||
case '%': rc = COND_PERCENT; break;
|
||||
case ' ': rc = COND_SPACE; break;
|
||||
case '=': rc = COND_EQ; break;
|
||||
case '~': rc = COND_TILDA; break;
|
||||
case '<': rc = COND_LT; break;
|
||||
case '>': rc = COND_GT; break;
|
||||
case '"':
|
||||
{
|
||||
const WCHAR *ch2 = str->data + 1;
|
||||
|
||||
|
||||
while ( *ch2 && *ch2 != '"' )
|
||||
++ch2;
|
||||
if (*ch2 == '"')
|
||||
{
|
||||
len = ch2 - str->data + 1;
|
||||
rc = COND_LITER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ERR("Unterminated string\n");
|
||||
rc = COND_ERROR;
|
||||
break;
|
||||
default:
|
||||
if( COND_IsAlpha( ch ) )
|
||||
{
|
||||
while( COND_IsIdent( str->data[len] ) )
|
||||
len++;
|
||||
rc = COND_IDENT;
|
||||
break;
|
||||
}
|
||||
|
||||
if( COND_IsNumber( ch ) )
|
||||
{
|
||||
while( COND_IsNumber( str->data[len] ) )
|
||||
len++;
|
||||
rc = COND_NUMBER;
|
||||
break;
|
||||
}
|
||||
|
||||
ERR("Got unknown character %c(%x)\n",ch,ch);
|
||||
rc = COND_ERROR;
|
||||
break;
|
||||
|
||||
case '~':
|
||||
case '<':
|
||||
case '>':
|
||||
rc = COND_GetOperator( cond );
|
||||
if (!rc)
|
||||
rc = COND_ERROR;
|
||||
return rc;
|
||||
default:
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
/* keyword identifiers */
|
||||
if( rc == COND_IDENT )
|
||||
if ( rc )
|
||||
{
|
||||
if( (len==3) && (strncmpiW(str->data,szNot,len)==0) )
|
||||
rc = COND_NOT;
|
||||
else if( (len==3) && (strncmpiW(str->data,szAnd,len)==0) )
|
||||
rc = COND_AND;
|
||||
else if( (len==2) && (strncmpiW(str->data,szOr,len)==0) )
|
||||
cond->n += len;
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (ch == '"' )
|
||||
{
|
||||
LPCWSTR p = strchrW( str->data + 1, '"' );
|
||||
if (!p)
|
||||
return COND_ERROR;
|
||||
len = p - str->data + 1;
|
||||
rc = COND_LITER;
|
||||
}
|
||||
else if( COND_IsAlpha( ch ) )
|
||||
{
|
||||
static const WCHAR szNot[] = {'N','O','T',0};
|
||||
static const WCHAR szAnd[] = {'A','N','D',0};
|
||||
static const WCHAR szXor[] = {'X','O','R',0};
|
||||
static const WCHAR szEqv[] = {'E','Q','V',0};
|
||||
static const WCHAR szImp[] = {'I','M','P',0};
|
||||
static const WCHAR szOr[] = {'O','R',0};
|
||||
|
||||
while( COND_IsIdent( str->data[len] ) )
|
||||
len++;
|
||||
rc = COND_IDENT;
|
||||
|
||||
if ( len == 3 )
|
||||
{
|
||||
if ( !strncmpiW( str->data, szNot, len ) )
|
||||
rc = COND_NOT;
|
||||
else if( !strncmpiW( str->data, szAnd, len ) )
|
||||
rc = COND_AND;
|
||||
else if( !strncmpiW( str->data, szXor, len ) )
|
||||
rc = COND_XOR;
|
||||
else if( !strncmpiW( str->data, szEqv, len ) )
|
||||
rc = COND_EQV;
|
||||
else if( !strncmpiW( str->data, szImp, len ) )
|
||||
rc = COND_IMP;
|
||||
}
|
||||
else if( (len == 2) && !strncmpiW( str->data, szOr, len ) )
|
||||
rc = COND_OR;
|
||||
}
|
||||
else if( COND_IsNumber( ch ) )
|
||||
{
|
||||
while( COND_IsNumber( str->data[len] ) )
|
||||
len++;
|
||||
rc = COND_NUMBER;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("Got unknown character %c(%x)\n",ch,ch);
|
||||
return COND_ERROR;
|
||||
}
|
||||
|
||||
cond->n += len;
|
||||
str->len = len;
|
||||
@@ -731,6 +661,7 @@ static LPWSTR COND_GetLiteral( struct cond_str *str )
|
||||
|
||||
static int COND_error(const char *str)
|
||||
{
|
||||
TRACE("%s\n", str );
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -739,21 +670,22 @@ MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition )
|
||||
COND_input cond;
|
||||
MSICONDITION r;
|
||||
|
||||
TRACE("%s\n", debugstr_w( szCondition ) );
|
||||
|
||||
if ( szCondition == NULL )
|
||||
return MSICONDITION_NONE;
|
||||
|
||||
cond.package = package;
|
||||
cond.str = szCondition;
|
||||
cond.n = 0;
|
||||
cond.result = -1;
|
||||
cond.result = MSICONDITION_ERROR;
|
||||
|
||||
TRACE("Evaluating %s\n",debugstr_w(szCondition));
|
||||
|
||||
if ( szCondition == NULL || szCondition[0] == 0)
|
||||
r = MSICONDITION_NONE;
|
||||
else if ( !COND_parse( &cond ) )
|
||||
if ( !COND_parse( &cond ) )
|
||||
r = cond.result;
|
||||
else
|
||||
r = MSICONDITION_ERROR;
|
||||
|
||||
TRACE("Evaluates to %i\n",r);
|
||||
TRACE("%i <- %s\n", r, debugstr_w(szCondition));
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -764,7 +696,7 @@ MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szConditi
|
||||
|
||||
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
|
||||
if( !package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
return MSICONDITION_ERROR;
|
||||
ret = MSI_EvaluateConditionW( package, szCondition );
|
||||
msiobj_release( &package->hdr );
|
||||
return ret;
|
||||
@@ -775,16 +707,11 @@ MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szConditio
|
||||
LPWSTR szwCond = NULL;
|
||||
MSICONDITION r;
|
||||
|
||||
if( szCondition )
|
||||
{
|
||||
UINT len = MultiByteToWideChar( CP_ACP, 0, szCondition, -1, NULL, 0 );
|
||||
szwCond = msi_alloc( len * sizeof (WCHAR) );
|
||||
MultiByteToWideChar( CP_ACP, 0, szCondition, -1, szwCond, len );
|
||||
}
|
||||
szwCond = strdupAtoW( szCondition );
|
||||
if( szCondition && !szwCond )
|
||||
return MSICONDITION_ERROR;
|
||||
|
||||
r = MsiEvaluateConditionW( hInstall, szwCond );
|
||||
|
||||
msi_free( szwCond );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
#include "query.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||
|
||||
|
||||
/* below is the query interface to a table */
|
||||
|
||||
+18
-21
@@ -125,8 +125,7 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
|
||||
' ','W','H','E','R','E',' ','`','A','c','t','i' ,'o','n','`',' ',
|
||||
'=',' ','\'','%','s','\'',0};
|
||||
UINT type;
|
||||
LPWSTR source;
|
||||
LPWSTR target;
|
||||
LPCWSTR source, target;
|
||||
WCHAR *deformated=NULL;
|
||||
|
||||
row = MSI_QueryGetRecord( package->db, ExecSeqQuery, action );
|
||||
@@ -135,8 +134,8 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
|
||||
|
||||
type = MSI_RecordGetInteger(row,2);
|
||||
|
||||
source = load_dynamic_stringW(row,3);
|
||||
target = load_dynamic_stringW(row,4);
|
||||
source = MSI_RecordGetString(row,3);
|
||||
target = MSI_RecordGetString(row,4);
|
||||
|
||||
TRACE("Handling custom action %s (%x %s %s)\n",debugstr_w(action),type,
|
||||
debugstr_w(source), debugstr_w(target));
|
||||
@@ -231,8 +230,6 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
|
||||
}
|
||||
|
||||
end:
|
||||
msi_free(source);
|
||||
msi_free(target);
|
||||
msiobj_release(&row->hdr);
|
||||
return rc;
|
||||
}
|
||||
@@ -330,16 +327,16 @@ static UINT process_action_return_value(UINT type, HANDLE ThreadHandle)
|
||||
|
||||
switch (rc)
|
||||
{
|
||||
case ERROR_FUNCTION_NOT_CALLED:
|
||||
case ERROR_SUCCESS:
|
||||
case ERROR_INSTALL_USEREXIT:
|
||||
case ERROR_INSTALL_FAILURE:
|
||||
return rc;
|
||||
case ERROR_NO_MORE_ITEMS:
|
||||
return ERROR_SUCCESS;
|
||||
default:
|
||||
ERR("Invalid Return Code %lx\n",rc);
|
||||
return ERROR_INSTALL_FAILURE;
|
||||
case ERROR_FUNCTION_NOT_CALLED:
|
||||
case ERROR_SUCCESS:
|
||||
case ERROR_INSTALL_USEREXIT:
|
||||
case ERROR_INSTALL_FAILURE:
|
||||
return rc;
|
||||
case ERROR_NO_MORE_ITEMS:
|
||||
return ERROR_SUCCESS;
|
||||
default:
|
||||
ERR("Invalid Return Code %ld\n",rc);
|
||||
return ERROR_INSTALL_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,7 +413,7 @@ static DWORD WINAPI ACTION_CallDllFunction(thread_struct *stuff)
|
||||
CustomEntry *fn;
|
||||
DWORD rc = ERROR_SUCCESS;
|
||||
|
||||
TRACE("calling function (%s, %s) \n", debugstr_w(stuff->source),
|
||||
TRACE("calling function (%s, %s)\n", debugstr_w(stuff->source),
|
||||
debugstr_w(stuff->target));
|
||||
|
||||
hModule = LoadLibraryW(stuff->source);
|
||||
@@ -546,7 +543,7 @@ static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source,
|
||||
msi_free(deformated);
|
||||
}
|
||||
|
||||
TRACE("executing exe %s \n",debugstr_w(cmd));
|
||||
TRACE("executing exe %s\n", debugstr_w(cmd));
|
||||
|
||||
rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
|
||||
c_collen, &si, &info);
|
||||
@@ -607,7 +604,7 @@ static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source,
|
||||
msi_free(deformated);
|
||||
}
|
||||
|
||||
TRACE("executing exe %s \n",debugstr_w(cmd));
|
||||
TRACE("executing exe %s\n", debugstr_w(cmd));
|
||||
|
||||
rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
|
||||
c_collen, &si, &info);
|
||||
@@ -692,7 +689,7 @@ static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source,
|
||||
}
|
||||
msi_free(prop);
|
||||
|
||||
TRACE("executing exe %s \n",debugstr_w(cmd));
|
||||
TRACE("executing exe %s\n", debugstr_w(cmd));
|
||||
|
||||
rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
|
||||
c_collen, &si, &info);
|
||||
@@ -732,7 +729,7 @@ static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source,
|
||||
if (!deformated)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
TRACE("executing exe %s \n",debugstr_w(deformated));
|
||||
TRACE("executing exe %s\n", debugstr_w(deformated));
|
||||
|
||||
rc = CreateProcessW(NULL, deformated, NULL, NULL, FALSE, 0, NULL,
|
||||
c_collen, &si, &info);
|
||||
|
||||
@@ -38,14 +38,6 @@
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
/*
|
||||
* The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR,
|
||||
* which is a problem because LPCTSTR isn't defined when compiling wine.
|
||||
* To work around this problem, we need to define LPCTSTR as LPCWSTR here,
|
||||
* and make sure to only use it in W functions.
|
||||
*/
|
||||
#define LPCTSTR LPCWSTR
|
||||
|
||||
DEFINE_GUID( CLSID_MsiDatabase, 0x000c1084, 0x0000, 0x0000,
|
||||
0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
|
||||
DEFINE_GUID( CLSID_MsiPatch, 0x000c1086, 0x0000, 0x0000,
|
||||
@@ -67,6 +59,7 @@ static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
|
||||
DWORD r;
|
||||
|
||||
free_cached_tables( db );
|
||||
msi_free_transforms( db );
|
||||
msi_destroy_stringtable( db->strings );
|
||||
r = IStorage_Release( db->storage );
|
||||
if( r )
|
||||
@@ -156,6 +149,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
|
||||
db->storage = stg;
|
||||
db->mode = szMode;
|
||||
list_init( &db->tables );
|
||||
list_init( &db->transforms );
|
||||
|
||||
db->strings = load_string_table( stg );
|
||||
if( !db->strings )
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
#include "query.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||
|
||||
|
||||
/*
|
||||
|
||||
+192
-23
@@ -19,6 +19,8 @@
|
||||
*/
|
||||
|
||||
#define COBJMACROS
|
||||
#define NONAMELESSUNION
|
||||
#define NONAMELESSSTRUCT
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
@@ -80,6 +82,8 @@ struct msi_dialog_tag
|
||||
msi_font *font_list;
|
||||
struct list controls;
|
||||
HWND hWndFocus;
|
||||
LPWSTR control_default;
|
||||
LPWSTR control_cancel;
|
||||
WCHAR name[1];
|
||||
};
|
||||
|
||||
@@ -102,9 +106,9 @@ const WCHAR szMsiDialogClass[] = {
|
||||
};
|
||||
const WCHAR szMsiHiddenWindow[] = {
|
||||
'M','s','i','H','i','d','d','e','n','W','i','n','d','o','w',0 };
|
||||
const static WCHAR szStatic[] = { 'S','t','a','t','i','c',0 };
|
||||
const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 };
|
||||
const static WCHAR szButtonData[] = { 'M','S','I','D','A','T','A',0 };
|
||||
static const WCHAR szStatic[] = { 'S','t','a','t','i','c',0 };
|
||||
static const WCHAR szButton[] = { 'B','U','T','T','O','N', 0 };
|
||||
static const WCHAR szButtonData[] = { 'M','S','I','D','A','T','A',0 };
|
||||
static const WCHAR szText[] = { 'T','e','x','t',0 };
|
||||
static const WCHAR szPushButton[] = { 'P','u','s','h','B','u','t','t','o','n',0 };
|
||||
static const WCHAR szLine[] = { 'L','i','n','e',0 };
|
||||
@@ -121,6 +125,8 @@ static const WCHAR szProgressBar[] = {
|
||||
static const WCHAR szRadioButtonGroup[] = {
|
||||
'R','a','d','i','o','B','u','t','t','o','n','G','r','o','u','p',0 };
|
||||
static const WCHAR szIcon[] = { 'I','c','o','n',0 };
|
||||
static const WCHAR szSelectionTree[] = {
|
||||
'S','e','l','e','c','t','i','o','n','T','r','e','e',0 };
|
||||
|
||||
static UINT msi_dialog_checkbox_handler( msi_dialog *, msi_control *, WPARAM );
|
||||
static void msi_dialog_checkbox_sync_state( msi_dialog *, msi_control * );
|
||||
@@ -359,7 +365,7 @@ static msi_control *msi_dialog_create_window( msi_dialog *dialog,
|
||||
|
||||
static MSIRECORD *msi_get_binary_record( MSIDATABASE *db, LPCWSTR name )
|
||||
{
|
||||
const static WCHAR query[] = {
|
||||
static const WCHAR query[] = {
|
||||
's','e','l','e','c','t',' ','*',' ',
|
||||
'f','r','o','m',' ','B','i','n','a','r','y',' ',
|
||||
'w','h','e','r','e',' ',
|
||||
@@ -623,7 +629,7 @@ static UINT msi_dialog_button_control( msi_dialog *dialog, MSIRECORD *rec )
|
||||
|
||||
static LPWSTR msi_get_checkbox_value( msi_dialog *dialog, LPCWSTR prop )
|
||||
{
|
||||
const static WCHAR query[] = {
|
||||
static const WCHAR query[] = {
|
||||
'S','E','L','E','C','T',' ','*',' ',
|
||||
'F','R','O','M',' ','`','C','h','e','c','k','B','o','x',' ','`',
|
||||
'W','H','E','R','E',' ',
|
||||
@@ -714,7 +720,7 @@ msi_richedit_stream_in( DWORD_PTR arg, LPBYTE buffer, LONG count, LONG *pcb )
|
||||
|
||||
static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec )
|
||||
{
|
||||
const static WCHAR szRichEdit20W[] = {
|
||||
static const WCHAR szRichEdit20W[] = {
|
||||
'R','i','c','h','E','d','i','t','2','0','W',0
|
||||
};
|
||||
struct msi_streamin_info info;
|
||||
@@ -750,6 +756,73 @@ static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec )
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static HBITMAP msi_load_picture( MSIDATABASE *db, LPCWSTR name,
|
||||
INT cx, INT cy, DWORD flags )
|
||||
{
|
||||
HBITMAP hOleBitmap = 0, hBitmap = 0, hOldSrcBitmap, hOldDestBitmap;
|
||||
MSIRECORD *rec = NULL;
|
||||
IStream *stm = NULL;
|
||||
IPicture *pic = NULL;
|
||||
HDC srcdc, destdc;
|
||||
BITMAP bm;
|
||||
UINT r;
|
||||
|
||||
rec = msi_get_binary_record( db, name );
|
||||
if( !rec )
|
||||
goto end;
|
||||
|
||||
r = MSI_RecordGetIStream( rec, 2, &stm );
|
||||
msiobj_release( &rec->hdr );
|
||||
if( r != ERROR_SUCCESS )
|
||||
goto end;
|
||||
|
||||
r = OleLoadPicture( stm, 0, TRUE, &IID_IPicture, (LPVOID*) &pic );
|
||||
IStream_Release( stm );
|
||||
if( FAILED( r ) )
|
||||
{
|
||||
ERR("failed to load picture\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
r = IPicture_get_Handle( pic, (OLE_HANDLE*) &hOleBitmap );
|
||||
if( FAILED( r ) )
|
||||
{
|
||||
ERR("failed to get bitmap handle\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* make the bitmap the desired size */
|
||||
r = GetObjectW( hOleBitmap, sizeof bm, &bm );
|
||||
if (r != sizeof bm )
|
||||
{
|
||||
ERR("failed to get bitmap size\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (flags & LR_DEFAULTSIZE)
|
||||
{
|
||||
cx = bm.bmWidth;
|
||||
cy = bm.bmHeight;
|
||||
}
|
||||
|
||||
srcdc = CreateCompatibleDC( NULL );
|
||||
hOldSrcBitmap = SelectObject( srcdc, hOleBitmap );
|
||||
destdc = CreateCompatibleDC( NULL );
|
||||
hBitmap = CreateCompatibleBitmap( srcdc, cx, cy );
|
||||
hOldDestBitmap = SelectObject( destdc, hBitmap );
|
||||
StretchBlt( destdc, 0, 0, cx, cy,
|
||||
srcdc, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
|
||||
SelectObject( srcdc, hOldSrcBitmap );
|
||||
SelectObject( destdc, hOldDestBitmap );
|
||||
DeleteDC( srcdc );
|
||||
DeleteDC( destdc );
|
||||
|
||||
end:
|
||||
if ( pic )
|
||||
IPicture_Release( pic );
|
||||
return hBitmap;
|
||||
}
|
||||
|
||||
static UINT msi_dialog_bitmap_control( msi_dialog *dialog, MSIRECORD *rec )
|
||||
{
|
||||
UINT cx, cy, flags, style, attributes;
|
||||
@@ -773,8 +846,7 @@ static UINT msi_dialog_bitmap_control( msi_dialog *dialog, MSIRECORD *rec )
|
||||
cy = msi_dialog_scale_unit( dialog, cy );
|
||||
|
||||
text = msi_get_deformatted_field( dialog->package, rec, 10 );
|
||||
control->hBitmap = msi_load_image( dialog->package->db, text,
|
||||
IMAGE_BITMAP, cx, cy, flags );
|
||||
control->hBitmap = msi_load_picture( dialog->package->db, text, cx, cy, flags );
|
||||
if( control->hBitmap )
|
||||
SendMessageW( control->hwnd, STM_SETIMAGE,
|
||||
IMAGE_BITMAP, (LPARAM) control->hBitmap );
|
||||
@@ -858,6 +930,20 @@ struct msi_maskedit_info
|
||||
struct msi_mask_group group[MASK_MAX_GROUPS];
|
||||
};
|
||||
|
||||
static BOOL msi_mask_editable( WCHAR type )
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case '%':
|
||||
case '#':
|
||||
case '&':
|
||||
case '`':
|
||||
case '?':
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void msi_mask_control_change( struct msi_maskedit_info *info )
|
||||
{
|
||||
LPWSTR val;
|
||||
@@ -871,9 +957,18 @@ static void msi_mask_control_change( struct msi_maskedit_info *info )
|
||||
ERR("can't fit control %d text into template\n",i);
|
||||
break;
|
||||
}
|
||||
r = GetWindowTextW( info->group[i].hwnd, &val[n], info->group[i].len+1 );
|
||||
if( r != info->group[i].len )
|
||||
break;
|
||||
if (!msi_mask_editable(info->group[i].type))
|
||||
{
|
||||
for(r=0; r<info->group[i].len; r++)
|
||||
val[n+r] = info->group[i].type;
|
||||
val[n+r] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = GetWindowTextW( info->group[i].hwnd, &val[n], info->group[i].len+1 );
|
||||
if( r != info->group[i].len )
|
||||
break;
|
||||
}
|
||||
n += r;
|
||||
}
|
||||
|
||||
@@ -991,12 +1086,6 @@ static struct msi_maskedit_info * msi_dialog_parse_groups( LPCWSTR mask )
|
||||
p++;
|
||||
for( i=0; i<MASK_MAX_GROUPS; i++ )
|
||||
{
|
||||
while (*p=='-')
|
||||
{
|
||||
total++;
|
||||
p++;
|
||||
}
|
||||
|
||||
/* stop at the end of the string */
|
||||
if( p[0] == 0 || p[0] == '>' )
|
||||
break;
|
||||
@@ -1043,6 +1132,8 @@ msi_maskedit_create_children( struct msi_maskedit_info *info, LPCWSTR font )
|
||||
|
||||
for( i = 0; i < info->num_groups; i++ )
|
||||
{
|
||||
if (!msi_mask_editable( info->group[i].type ))
|
||||
continue;
|
||||
wx = (info->group[i].ofs * width) / info->num_chars;
|
||||
ww = (info->group[i].len * width) / info->num_chars;
|
||||
|
||||
@@ -1062,7 +1153,10 @@ msi_maskedit_create_children( struct msi_maskedit_info *info, LPCWSTR font )
|
||||
}
|
||||
}
|
||||
|
||||
/* office 2003 uses "73931<````=````=````=````=`````>@@@@@" */
|
||||
/*
|
||||
* office 2003 uses "73931<````=````=````=````=`````>@@@@@"
|
||||
* delphi 7 uses "<????-??????-??????-????>" and "<???-???>"
|
||||
*/
|
||||
static UINT msi_dialog_maskedit_control( msi_dialog *dialog, MSIRECORD *rec )
|
||||
{
|
||||
LPWSTR font_mask, val = NULL, font;
|
||||
@@ -1228,6 +1322,63 @@ static UINT msi_dialog_radiogroup_control( msi_dialog *dialog, MSIRECORD *rec )
|
||||
return r;
|
||||
}
|
||||
|
||||
/******************** Selection Tree ***************************************/
|
||||
|
||||
static void
|
||||
msi_dialog_tv_add_child_features( MSIPACKAGE *package, HWND hwnd,
|
||||
LPCWSTR parent, HTREEITEM hParent )
|
||||
{
|
||||
MSIFEATURE *feature;
|
||||
TVINSERTSTRUCTW tvis;
|
||||
HTREEITEM hitem;
|
||||
|
||||
LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
|
||||
{
|
||||
if ( lstrcmpW( parent, feature->Feature_Parent ) )
|
||||
continue;
|
||||
|
||||
if ( !feature->Title )
|
||||
continue;
|
||||
|
||||
memset( &tvis, 0, sizeof tvis );
|
||||
tvis.hParent = hParent;
|
||||
tvis.hInsertAfter = TVI_SORT;
|
||||
if (feature->Title)
|
||||
{
|
||||
tvis.u.item.mask = TVIF_TEXT;
|
||||
tvis.u.item.pszText = feature->Title;
|
||||
}
|
||||
tvis.u.item.lParam = (LPARAM) feature;
|
||||
hitem = (HTREEITEM) SendMessageW( hwnd, TVM_INSERTITEMW, 0, (LPARAM) &tvis );
|
||||
if (!hitem)
|
||||
continue;
|
||||
|
||||
msi_dialog_tv_add_child_features( package, hwnd,
|
||||
feature->Feature, hitem );
|
||||
}
|
||||
}
|
||||
|
||||
static UINT msi_dialog_selection_tree( msi_dialog *dialog, MSIRECORD *rec )
|
||||
{
|
||||
msi_control *control;
|
||||
LPCWSTR prop;
|
||||
LPWSTR val;
|
||||
MSIPACKAGE *package = dialog->package;
|
||||
|
||||
prop = MSI_RecordGetString( rec, 9 );
|
||||
val = msi_dup_property( package, prop );
|
||||
control = msi_dialog_add_control( dialog, rec, WC_TREEVIEWW,
|
||||
TVS_HASBUTTONS | WS_GROUP | WS_VSCROLL );
|
||||
if (!control)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
msi_dialog_tv_add_child_features( package, control->hwnd, NULL, NULL );
|
||||
|
||||
msi_free( val );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
struct control_handler msi_dialog_handler[] =
|
||||
{
|
||||
{ szText, msi_dialog_text_control },
|
||||
@@ -1243,6 +1394,7 @@ struct control_handler msi_dialog_handler[] =
|
||||
{ szProgressBar, msi_dialog_progress_bar },
|
||||
{ szRadioButtonGroup, msi_dialog_radiogroup_control },
|
||||
{ szIcon, msi_dialog_icon_control },
|
||||
{ szSelectionTree, msi_dialog_selection_tree },
|
||||
};
|
||||
|
||||
#define NUM_CONTROL_TYPES (sizeof msi_dialog_handler/sizeof msi_dialog_handler[0])
|
||||
@@ -1309,7 +1461,7 @@ static UINT msi_dialog_set_control_condition( MSIRECORD *rec, LPVOID param )
|
||||
condition = MSI_RecordGetString( rec, 4 );
|
||||
r = MSI_EvaluateConditionW( dialog->package, condition );
|
||||
control = msi_dialog_find_control( dialog, name );
|
||||
if( r && control )
|
||||
if( r == MSICONDITION_TRUE && control )
|
||||
{
|
||||
TRACE("%s control %s\n", debugstr_w(action), debugstr_w(name));
|
||||
|
||||
@@ -1558,7 +1710,7 @@ static UINT msi_dialog_control_event( MSIRECORD *rec, LPVOID param )
|
||||
|
||||
condition = MSI_RecordGetString( rec, 5 );
|
||||
r = MSI_EvaluateConditionW( dialog->package, condition );
|
||||
if( r )
|
||||
if( r == MSICONDITION_TRUE )
|
||||
{
|
||||
event = MSI_RecordGetString( rec, 3 );
|
||||
arg = MSI_RecordGetString( rec, 4 );
|
||||
@@ -1710,11 +1862,22 @@ static UINT msi_dialog_radiogroup_handler( msi_dialog *dialog,
|
||||
|
||||
static LRESULT msi_dialog_oncommand( msi_dialog *dialog, WPARAM param, HWND hwnd )
|
||||
{
|
||||
msi_control *control;
|
||||
msi_control *control = NULL;
|
||||
|
||||
TRACE("%p %p %08x\n", dialog, hwnd, param);
|
||||
|
||||
control = msi_dialog_find_control_by_hwnd( dialog, hwnd );
|
||||
switch (param)
|
||||
{
|
||||
case 1: /* enter */
|
||||
control = msi_dialog_find_control( dialog, dialog->control_default );
|
||||
break;
|
||||
case 2: /* escape */
|
||||
control = msi_dialog_find_control( dialog, dialog->control_cancel );
|
||||
break;
|
||||
default:
|
||||
control = msi_dialog_find_control_by_hwnd( dialog, hwnd );
|
||||
}
|
||||
|
||||
if( control )
|
||||
{
|
||||
if( control->handler )
|
||||
@@ -1724,7 +1887,7 @@ static LRESULT msi_dialog_oncommand( msi_dialog *dialog, WPARAM param, HWND hwnd
|
||||
}
|
||||
}
|
||||
else
|
||||
ERR("button click from nowhere\n");
|
||||
ERR("button click from nowhere %p %d %p\n", dialog, param, hwnd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1835,6 +1998,8 @@ msi_dialog *msi_dialog_create( MSIPACKAGE* package, LPCWSTR szDialogName,
|
||||
return NULL;
|
||||
}
|
||||
dialog->attributes = MSI_RecordGetInteger( rec, 6 );
|
||||
dialog->control_default = strdupW( MSI_RecordGetString( rec, 9 ) );
|
||||
dialog->control_cancel = strdupW( MSI_RecordGetString( rec, 10 ) );
|
||||
msiobj_release( &rec->hdr );
|
||||
|
||||
return dialog;
|
||||
@@ -1978,6 +2143,8 @@ void msi_dialog_destroy( msi_dialog *dialog )
|
||||
}
|
||||
msi_free( dialog->default_font );
|
||||
|
||||
msi_free( dialog->control_default );
|
||||
msi_free( dialog->control_cancel );
|
||||
msiobj_release( &dialog->package->hdr );
|
||||
dialog->package = NULL;
|
||||
msi_free( dialog );
|
||||
@@ -2018,6 +2185,8 @@ BOOL msi_dialog_register_class( void )
|
||||
void msi_dialog_unregister_class( void )
|
||||
{
|
||||
DestroyWindow( hMsiHiddenWindow );
|
||||
hMsiHiddenWindow = NULL;
|
||||
UnregisterClassW( szMsiDialogClass, NULL );
|
||||
UnregisterClassW( szMsiHiddenWindow, NULL );
|
||||
uiThreadId = 0;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
#include "query.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||
|
||||
typedef struct tagDISTINCTSET
|
||||
{
|
||||
|
||||
+154
-173
@@ -56,26 +56,6 @@ extern const WCHAR szRemoveFiles[];
|
||||
|
||||
static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
|
||||
|
||||
static UINT create_component_directory( MSIPACKAGE* package, MSICOMPONENT *comp )
|
||||
{
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
MSIFOLDER *folder;
|
||||
LPWSTR install_path;
|
||||
|
||||
install_path = resolve_folder(package, comp->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;
|
||||
}
|
||||
msi_free(install_path);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a helper function for handling embedded cabinet media
|
||||
@@ -139,6 +119,7 @@ static void cabinet_free(void *pv)
|
||||
|
||||
static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
|
||||
{
|
||||
HANDLE handle;
|
||||
DWORD dwAccess = 0;
|
||||
DWORD dwShareMode = 0;
|
||||
DWORD dwCreateDisposition = OPEN_EXISTING;
|
||||
@@ -161,35 +142,62 @@ static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
|
||||
dwCreateDisposition = CREATE_NEW;
|
||||
else if (oflag & _O_CREAT)
|
||||
dwCreateDisposition = CREATE_ALWAYS;
|
||||
return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
|
||||
dwCreateDisposition, 0, NULL);
|
||||
handle = CreateFileA( pszFile, dwAccess, dwShareMode, NULL,
|
||||
dwCreateDisposition, 0, NULL );
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
return (INT_PTR) handle;
|
||||
}
|
||||
|
||||
static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)
|
||||
{
|
||||
HANDLE handle = (HANDLE) hf;
|
||||
DWORD dwRead;
|
||||
if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL))
|
||||
if (ReadFile(handle, pv, cb, &dwRead, NULL))
|
||||
return dwRead;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)
|
||||
{
|
||||
HANDLE handle = (HANDLE) hf;
|
||||
DWORD dwWritten;
|
||||
if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL))
|
||||
if (WriteFile(handle, pv, cb, &dwWritten, NULL))
|
||||
return dwWritten;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cabinet_close(INT_PTR hf)
|
||||
{
|
||||
return CloseHandle((HANDLE)hf) ? 0 : -1;
|
||||
HANDLE handle = (HANDLE) hf;
|
||||
return CloseHandle(handle) ? 0 : -1;
|
||||
}
|
||||
|
||||
static long cabinet_seek(INT_PTR hf, long dist, int seektype)
|
||||
{
|
||||
HANDLE handle = (HANDLE) hf;
|
||||
/* flags are compatible and so are passed straight through */
|
||||
return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
|
||||
return SetFilePointer(handle, dist, NULL, seektype);
|
||||
}
|
||||
|
||||
static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f )
|
||||
{
|
||||
MSIRECORD *uirow;
|
||||
LPWSTR uipath, p;
|
||||
|
||||
/* the UI chunk */
|
||||
uirow = MSI_CreateRecord( 9 );
|
||||
MSI_RecordSetStringW( uirow, 1, f->FileName );
|
||||
uipath = strdupW( f->TargetPath );
|
||||
p = strrchrW(uipath,'\\');
|
||||
if (p)
|
||||
p[1]=0;
|
||||
MSI_RecordSetStringW( uirow, 9, uipath);
|
||||
MSI_RecordSetInteger( uirow, 6, f->FileSize );
|
||||
ui_actiondata( package, szInstallFiles, uirow);
|
||||
msiobj_release( &uirow->hdr );
|
||||
msi_free( uipath );
|
||||
ui_progress( package, 2, f->FileSize, 0, 0);
|
||||
}
|
||||
|
||||
static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
|
||||
@@ -199,22 +207,13 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
|
||||
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;
|
||||
|
||||
MSIRECORD * uirow;
|
||||
LPWSTR uipath;
|
||||
HANDLE handle;
|
||||
LPWSTR file;
|
||||
MSIFILE *f;
|
||||
|
||||
given_file = strdupAtoW(pfdin->psz1);
|
||||
f = get_loaded_file(data->package, given_file);
|
||||
msi_free(given_file);
|
||||
file = strdupAtoW(pfdin->psz1);
|
||||
f = get_loaded_file(data->package, file);
|
||||
msi_free(file);
|
||||
|
||||
if (!f)
|
||||
{
|
||||
@@ -222,60 +221,41 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!((f->State == 1 || f->State == 2)))
|
||||
if (f->state != msifs_missing && f->state != msifs_overwrite)
|
||||
{
|
||||
TRACE("Skipping extraction of %s\n",debugstr_a(pfdin->psz1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
file = cabinet_alloc((len+1)*sizeof(char));
|
||||
strcpy(file, data->cab_path);
|
||||
strcat(file, pfdin->psz1);
|
||||
msi_file_update_ui( data->package, f );
|
||||
|
||||
TRACE("file: %s\n", debugstr_a(file));
|
||||
TRACE("extracting %s\n", debugstr_w(f->TargetPath) );
|
||||
|
||||
/* track this file so it can be deleted if not installed */
|
||||
trackpath=strdupAtoW(file);
|
||||
tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
|
||||
trackname = msi_alloc((strlenW(tracknametmp) +
|
||||
strlenW(tmpprefix)+1) * sizeof(WCHAR));
|
||||
handle = CreateFileW( f->TargetPath, GENERIC_READ | GENERIC_WRITE, 0,
|
||||
NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
|
||||
if ( handle == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
ERR("failed to create %s (error %ld)\n",
|
||||
debugstr_w( f->TargetPath ), GetLastError() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
strcpyW(trackname,tmpprefix);
|
||||
strcatW(trackname,tracknametmp);
|
||||
|
||||
track_tempfile(data->package, trackname, trackpath);
|
||||
|
||||
msi_free(trackpath);
|
||||
msi_free(trackname);
|
||||
msi_free(tracknametmp);
|
||||
|
||||
/* the UI chunk */
|
||||
uirow=MSI_CreateRecord(9);
|
||||
MSI_RecordSetStringW( uirow, 1, f->FileName );
|
||||
uipath = strdupW( f->TargetPath );
|
||||
*(strrchrW(uipath,'\\')+1)=0;
|
||||
MSI_RecordSetStringW(uirow,9,uipath);
|
||||
MSI_RecordSetInteger( uirow, 6, f->FileSize );
|
||||
ui_actiondata(data->package,szInstallFiles,uirow);
|
||||
msiobj_release( &uirow->hdr );
|
||||
msi_free(uipath);
|
||||
|
||||
ui_progress( data->package, 2, f->FileSize, 0, 0);
|
||||
|
||||
return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
|
||||
f->state = msifs_installed;
|
||||
return (INT_PTR) handle;
|
||||
}
|
||||
case fdintCLOSE_FILE_INFO:
|
||||
{
|
||||
FILETIME ft;
|
||||
FILETIME ftLocal;
|
||||
FILETIME ftLocal;
|
||||
HANDLE handle = (HANDLE) pfdin->hf;
|
||||
|
||||
if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
|
||||
return -1;
|
||||
if (!LocalFileTimeToFileTime(&ft, &ftLocal))
|
||||
return -1;
|
||||
if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal))
|
||||
if (!SetFileTime(handle, &ftLocal, 0, &ftLocal))
|
||||
return -1;
|
||||
|
||||
cabinet_close(pfdin->hf);
|
||||
CloseHandle(handle);
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
@@ -400,7 +380,8 @@ static UINT ready_volume(MSIPACKAGE* package, LPCWSTR path, LPWSTR last_volume,
|
||||
LPCWSTR want_volume = MSI_RecordGetString(row, 5);
|
||||
BOOL ok = check_volume(path, want_volume, volume, type);
|
||||
|
||||
TRACE("Readying Volume for %s (%s, %s)\n",debugstr_w(path), debugstr_w(want_volume), debugstr_w(last_volume));
|
||||
TRACE("Readying Volume for %s (%s, %s)\n", debugstr_w(path),
|
||||
debugstr_w(want_volume), debugstr_w(last_volume));
|
||||
|
||||
if (check_for_sourcefile(path) && !ok)
|
||||
{
|
||||
@@ -463,7 +444,7 @@ static void free_media_info( struct media_info *mi )
|
||||
}
|
||||
|
||||
static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
|
||||
MSIFILE *file, MSICOMPONENT* comp )
|
||||
MSIFILE *file )
|
||||
{
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
MSIRECORD * row = 0;
|
||||
@@ -478,6 +459,7 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
|
||||
INT seq;
|
||||
UINT type;
|
||||
LPCWSTR prompt;
|
||||
MSICOMPONENT *comp = file->Component;
|
||||
|
||||
if (file->Sequence <= mi->last_sequence)
|
||||
{
|
||||
@@ -560,7 +542,7 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
|
||||
mi->last_path = msi_alloc(MAX_PATH*sizeof(WCHAR));
|
||||
if (MSI_GetPropertyW(package, cszSourceDir, mi->source, &sz))
|
||||
{
|
||||
ERR("No Source dir defined \n");
|
||||
ERR("No Source dir defined\n");
|
||||
rc = ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
else
|
||||
@@ -626,14 +608,11 @@ static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
|
||||
{
|
||||
MSIFILE *file;
|
||||
|
||||
if (!package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
|
||||
{
|
||||
if (lstrcmpW( file_key, file->File )==0)
|
||||
{
|
||||
if (file->State >= 2)
|
||||
if (file->state >= msifs_overwrite)
|
||||
{
|
||||
*file_source = strdupW( file->TargetPath );
|
||||
return ERROR_SUCCESS;
|
||||
@@ -647,11 +626,11 @@ static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key,
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* ACTION_InstallFiles()
|
||||
*
|
||||
* For efficiency, this is done in two passes:
|
||||
* 1) Correct all the TargetPaths and determine what files are to be installed.
|
||||
* 2) Extract Cabinets and copy files.
|
||||
*/
|
||||
UINT ACTION_InstallFiles(MSIPACKAGE *package)
|
||||
{
|
||||
@@ -660,13 +639,10 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
|
||||
LPWSTR ptr;
|
||||
MSIFILE *file;
|
||||
|
||||
if (!package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
/* increment progress bar each time action data is sent */
|
||||
ui_progress(package,1,1,0,0);
|
||||
|
||||
/* handle the keys for the SouceList */
|
||||
/* handle the keys for the SourceList */
|
||||
ptr = strrchrW(package->PackagePath,'\\');
|
||||
if (ptr)
|
||||
{
|
||||
@@ -676,107 +652,88 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
|
||||
MSICODE_PRODUCT,
|
||||
INSTALLPROPERTY_PACKAGENAMEW, ptr);
|
||||
}
|
||||
FIXME("Write DiskPrompt\n");
|
||||
/* FIXME("Write DiskPrompt\n"); */
|
||||
|
||||
/* Pass 1 */
|
||||
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
|
||||
{
|
||||
MSICOMPONENT* comp = NULL;
|
||||
|
||||
if (!ACTION_VerifyComponentForAction(package, file->Component,
|
||||
INSTALLSTATE_LOCAL))
|
||||
if (!ACTION_VerifyComponentForAction( file->Component, 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->Component );
|
||||
|
||||
/* recalculate file paths because things may have changed */
|
||||
|
||||
comp = file->Component;
|
||||
if (!comp)
|
||||
{
|
||||
ERR("No Component for file\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
|
||||
msi_free(file->TargetPath);
|
||||
|
||||
file->TargetPath = build_directory_name(2, p, file->FileName);
|
||||
msi_free(p);
|
||||
file->state = msifs_skipped;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Despite MSDN specifying that the CreateFolders action
|
||||
* should be called before InstallFiles, some installers don't
|
||||
* do that, and they seem to work correctly. We need to create
|
||||
* directories here to make sure that the files can be copied.
|
||||
*/
|
||||
msi_create_component_directories( package );
|
||||
|
||||
mi = create_media_info();
|
||||
|
||||
/* Pass 2 */
|
||||
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
|
||||
{
|
||||
if ((file->State == 1) || (file->State == 2))
|
||||
if (file->state != msifs_missing && file->state != msifs_overwrite)
|
||||
continue;
|
||||
|
||||
TRACE("Pass 2: %s\n",debugstr_w(file->File));
|
||||
|
||||
rc = ready_media_for_file( package, mi, file );
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
TRACE("Pass 2: %s\n",debugstr_w(file->File));
|
||||
ERR("Unable to ready media\n");
|
||||
rc = ERROR_FUNCTION_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = ready_media_for_file( package, mi, file, file->Component );
|
||||
if (rc != ERROR_SUCCESS)
|
||||
TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
|
||||
debugstr_w(file->TargetPath));
|
||||
|
||||
if (file->state != msifs_missing && file->state != msifs_overwrite)
|
||||
continue;
|
||||
|
||||
/* compressed files are extracted in ready_media_for_file */
|
||||
if (~file->Attributes & msidbFileAttributesNoncompressed)
|
||||
{
|
||||
if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(file->TargetPath))
|
||||
ERR("compressed file wasn't extracted (%s)\n",
|
||||
debugstr_w(file->TargetPath));
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
|
||||
if (!rc)
|
||||
{
|
||||
rc = GetLastError();
|
||||
ERR("Unable to copy file (%s -> %s) (error %d)\n",
|
||||
debugstr_w(file->SourcePath), debugstr_w(file->TargetPath), rc);
|
||||
if (rc == ERROR_ALREADY_EXISTS && file->state == msifs_overwrite)
|
||||
{
|
||||
ERR("Unable to ready media\n");
|
||||
rc = ERROR_FUNCTION_FAILED;
|
||||
break;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
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)
|
||||
else if (rc == ERROR_FILE_NOT_FOUND)
|
||||
{
|
||||
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;
|
||||
}
|
||||
ERR("Source File Not Found! Continuing\n");
|
||||
rc = 0;
|
||||
}
|
||||
else
|
||||
else if (file->Attributes & msidbFileAttributesVital)
|
||||
{
|
||||
file->State = 4;
|
||||
rc = ERROR_SUCCESS;
|
||||
ERR("Ignoring Error and continuing (nonvital file)...\n");
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
file->state = msifs_installed;
|
||||
rc = ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
@@ -798,7 +755,7 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
|
||||
component = MSI_RecordGetString(row,2);
|
||||
comp = get_loaded_component(package,component);
|
||||
|
||||
if (!ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_LOCAL))
|
||||
if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
|
||||
{
|
||||
TRACE("Skipping copy due to disabled component %s\n",
|
||||
debugstr_w(component));
|
||||
@@ -873,7 +830,8 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param)
|
||||
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());
|
||||
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");
|
||||
|
||||
@@ -892,9 +850,6 @@ UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
|
||||
{'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;
|
||||
@@ -904,3 +859,29 @@ UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
UINT ACTION_RemoveFiles( MSIPACKAGE *package )
|
||||
{
|
||||
MSIFILE *file;
|
||||
|
||||
LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
|
||||
{
|
||||
if ( !file->Component )
|
||||
continue;
|
||||
if ( file->Component->Installed == INSTALLSTATE_LOCAL )
|
||||
continue;
|
||||
|
||||
if ( file->state == msifs_installed )
|
||||
ERR("removing installed file %s\n", debugstr_w(file->TargetPath));
|
||||
|
||||
if ( file->state != msifs_present )
|
||||
continue;
|
||||
|
||||
TRACE("removing %s\n", debugstr_w(file->File) );
|
||||
if ( !DeleteFileW( file->TargetPath ) )
|
||||
ERR("failed to delete %s\n", debugstr_w(file->TargetPath) );
|
||||
file->state = msifs_missing;
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ static LPWSTR deformat_index(MSIRECORD* record, LPCWSTR key, DWORD* chunk )
|
||||
|
||||
index = atoiW(key);
|
||||
TRACE("record index %i\n",index);
|
||||
value = load_dynamic_stringW(record,index);
|
||||
value = msi_dup_record_field(record,index);
|
||||
if (value)
|
||||
*chunk = strlenW(value) * sizeof(WCHAR);
|
||||
else
|
||||
@@ -434,7 +434,7 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr,
|
||||
{
|
||||
LPBYTE nd2;
|
||||
|
||||
TRACE("after value %s \n",debugstr_wn((LPWSTR)newdata,
|
||||
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);
|
||||
@@ -584,7 +584,7 @@ UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer,
|
||||
|
||||
TRACE("%p %p %p %li\n",package, record ,buffer, *size);
|
||||
|
||||
rec = load_dynamic_stringW(record,0);
|
||||
rec = msi_dup_record_field(record,0);
|
||||
if (!rec)
|
||||
rec = build_default_format(record);
|
||||
|
||||
@@ -631,7 +631,7 @@ UINT MSI_FormatRecordA( MSIPACKAGE* package, MSIRECORD* record, LPSTR buffer,
|
||||
|
||||
TRACE("%p %p %p %li\n",package, record ,buffer, *size);
|
||||
|
||||
rec = load_dynamic_stringW(record,0);
|
||||
rec = msi_dup_record_field(record,0);
|
||||
if (!rec)
|
||||
rec = build_default_format(record);
|
||||
|
||||
|
||||
@@ -107,36 +107,9 @@ LPWSTR build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name )
|
||||
return FilePath;
|
||||
}
|
||||
|
||||
WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
|
||||
LPWSTR msi_dup_record_field( 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 = msi_alloc(sizeof(WCHAR));
|
||||
ret[0] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
sz ++;
|
||||
ret = msi_alloc(sz * sizeof (WCHAR));
|
||||
rc = MSI_RecordGetStringW(row,index,ret,&sz);
|
||||
if (rc!=ERROR_SUCCESS)
|
||||
{
|
||||
ERR("Unable to load dynamic string\n");
|
||||
msi_free(ret);
|
||||
ret = NULL;
|
||||
}
|
||||
return ret;
|
||||
return strdupW( MSI_RecordGetString(row,index) );
|
||||
}
|
||||
|
||||
LPWSTR msi_dup_property(MSIPACKAGE *package, LPCWSTR prop)
|
||||
@@ -200,9 +173,6 @@ int track_tempfile( MSIPACKAGE *package, LPCWSTR name, LPCWSTR path )
|
||||
{
|
||||
MSITEMPFILE *temp;
|
||||
|
||||
if (!package)
|
||||
return -1;
|
||||
|
||||
LIST_FOR_EACH_ENTRY( temp, &package->tempfiles, MSITEMPFILE, entry )
|
||||
{
|
||||
if (lstrcmpW( name, temp->File )==0)
|
||||
@@ -751,7 +721,7 @@ void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
|
||||
|
||||
/* update the cached actionformat */
|
||||
msi_free(package->ActionFormat);
|
||||
package->ActionFormat = load_dynamic_stringW(row,3);
|
||||
package->ActionFormat = msi_dup_record_field(row,3);
|
||||
|
||||
msi_free(package->LastAction);
|
||||
package->LastAction = strdupW(action);
|
||||
@@ -773,8 +743,7 @@ void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
|
||||
msiobj_release(&row->hdr);
|
||||
}
|
||||
|
||||
BOOL ACTION_VerifyComponentForAction(MSIPACKAGE* package, MSICOMPONENT* comp,
|
||||
INSTALLSTATE check )
|
||||
BOOL ACTION_VerifyComponentForAction( MSICOMPONENT* comp, INSTALLSTATE check )
|
||||
{
|
||||
if (!comp)
|
||||
return FALSE;
|
||||
@@ -935,7 +904,7 @@ UINT register_unique_action(MSIPACKAGE *package, LPCWSTR action)
|
||||
UINT count;
|
||||
LPWSTR *newbuf = NULL;
|
||||
|
||||
if (!package || !package->script)
|
||||
if (!package->script)
|
||||
return FALSE;
|
||||
|
||||
TRACE("Registering Action %s as having fun\n",debugstr_w(action));
|
||||
@@ -958,7 +927,7 @@ BOOL check_unique_action(MSIPACKAGE *package, LPCWSTR action)
|
||||
{
|
||||
INT i;
|
||||
|
||||
if (!package || !package->script)
|
||||
if (!package->script)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < package->script->UniqueActionsCount; i++)
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
#include "query.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||
|
||||
|
||||
/* below is the query interface to a table */
|
||||
|
||||
+46
-31
@@ -116,7 +116,7 @@ UINT WINAPI MsiSequenceW( MSIHANDLE hInstall, LPCWSTR szTable, INT iSequenceMode
|
||||
return ret;
|
||||
}
|
||||
|
||||
static UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz )
|
||||
UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz )
|
||||
{
|
||||
UINT len, r = ERROR_SUCCESS;
|
||||
|
||||
@@ -134,12 +134,15 @@ static UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz )
|
||||
}
|
||||
else
|
||||
{
|
||||
len = WideCharToMultiByte( CP_ACP, 0, str, -1,
|
||||
awbuf->str.a, *sz, NULL, NULL );
|
||||
len--;
|
||||
len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
|
||||
if (len)
|
||||
len--;
|
||||
WideCharToMultiByte( CP_ACP, 0, str, -1, awbuf->str.a, *sz, NULL, NULL );
|
||||
if ( *sz && (len >= *sz) )
|
||||
awbuf->str.a[*sz - 1] = 0;
|
||||
}
|
||||
|
||||
if (len >= *sz)
|
||||
if (awbuf->str.w && len >= *sz)
|
||||
r = ERROR_MORE_DATA;
|
||||
*sz = len;
|
||||
return r;
|
||||
@@ -293,31 +296,23 @@ UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder,
|
||||
/***********************************************************************
|
||||
* MsiSetTargetPathA (MSI.@)
|
||||
*/
|
||||
UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder,
|
||||
LPCSTR szFolderPath)
|
||||
UINT WINAPI MsiSetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
|
||||
LPCSTR szFolderPath )
|
||||
{
|
||||
LPWSTR szwFolder;
|
||||
LPWSTR szwFolderPath;
|
||||
UINT rc;
|
||||
LPWSTR szwFolder = NULL, szwFolderPath = NULL;
|
||||
UINT rc = ERROR_OUTOFMEMORY;
|
||||
|
||||
if (!szFolder)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
if (hInstall == 0)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
if ( !szFolder || !szFolderPath )
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
szwFolder = strdupAtoW(szFolder);
|
||||
if (!szwFolder)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
szwFolderPath = strdupAtoW(szFolderPath);
|
||||
if (!szwFolderPath)
|
||||
{
|
||||
msi_free(szwFolder);
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
if (!szwFolder || !szwFolderPath)
|
||||
goto end;
|
||||
|
||||
rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);
|
||||
rc = MsiSetTargetPathW( hInstall, szwFolder, szwFolderPath );
|
||||
|
||||
end:
|
||||
msi_free(szwFolder);
|
||||
msi_free(szwFolderPath);
|
||||
|
||||
@@ -339,12 +334,6 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
|
||||
|
||||
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) ||
|
||||
@@ -353,14 +342,16 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder,
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
path = resolve_folder(package,szFolder,FALSE,FALSE,&folder);
|
||||
|
||||
if (!path)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
return ERROR_DIRECTORY;
|
||||
|
||||
if (attrib == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
if (!CreateDirectoryW(szFolderPath,NULL))
|
||||
{
|
||||
msi_free( path );
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
RemoveDirectoryW(szFolderPath);
|
||||
}
|
||||
|
||||
@@ -410,7 +401,13 @@ UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
|
||||
|
||||
TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
|
||||
|
||||
if ( !szFolder || !szFolderPath )
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
|
||||
if (!package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
|
||||
msiobj_release( &package->hdr );
|
||||
return ret;
|
||||
@@ -456,6 +453,24 @@ BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiSetMode (MSI.@)
|
||||
*/
|
||||
BOOL WINAPI MsiSetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode, BOOL fState)
|
||||
{
|
||||
switch (iRunMode)
|
||||
{
|
||||
case MSIRUNMODE_RESERVED11:
|
||||
case MSIRUNMODE_WINDOWS9X:
|
||||
case MSIRUNMODE_RESERVED14:
|
||||
case MSIRUNMODE_RESERVED15:
|
||||
return FALSE;
|
||||
default:
|
||||
FIXME("%ld %d %d\n", hInstall, iRunMode, fState);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiSetFeatureStateA (MSI.@)
|
||||
*
|
||||
|
||||
+221
-84
@@ -35,19 +35,14 @@
|
||||
#include "wincrypt.h"
|
||||
#include "winver.h"
|
||||
#include "winuser.h"
|
||||
#include "shlobj.h"
|
||||
#include "shobjidl.h"
|
||||
#include "objidl.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "action.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
/*
|
||||
* The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR,
|
||||
* which is a problem because LPCTSTR isn't defined when compiling wine.
|
||||
* To work around this problem, we need to define LPCTSTR as LPCWSTR here,
|
||||
* and make sure to only use it in W functions.
|
||||
*/
|
||||
#define LPCTSTR LPCWSTR
|
||||
|
||||
/* the UI level */
|
||||
INSTALLUILEVEL gUILevel = INSTALLUILEVEL_BASIC;
|
||||
HWND gUIhwnd = 0;
|
||||
@@ -418,7 +413,7 @@ UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer)
|
||||
DWORD sz = GUID_SIZE;
|
||||
static const WCHAR szPermKey[] =
|
||||
{ '0','0','0','0','0','0','0','0','0','0','0','0',
|
||||
'0','0','0','0','0','0','0', '0','0','0','0','0',
|
||||
'0','0','0','0','0','0','0','0','0','0','0','0',
|
||||
'0','0','0','0','0','0','0','0',0};
|
||||
|
||||
TRACE("%s %p\n",debugstr_w(szComponent), szBuffer);
|
||||
@@ -839,7 +834,7 @@ UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uTyp
|
||||
{
|
||||
FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_a(lpText),debugstr_a(lpCaption),
|
||||
uType,wLanguageId,f);
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
return MessageBoxExA(hWnd,lpText,lpCaption,uType,wLanguageId);
|
||||
}
|
||||
|
||||
UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
|
||||
@@ -847,7 +842,7 @@ UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uT
|
||||
{
|
||||
FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_w(lpText),debugstr_w(lpCaption),
|
||||
uType,wLanguageId,f);
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId);
|
||||
}
|
||||
|
||||
UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext,
|
||||
@@ -1013,6 +1008,8 @@ INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent,
|
||||
TRACE("%s %s %p %p\n", debugstr_w(szProduct),
|
||||
debugstr_w(szComponent), lpPathBuf, pcchBuf);
|
||||
|
||||
if( !szComponent )
|
||||
return INSTALLSTATE_INVALIDARG;
|
||||
if( lpPathBuf && !pcchBuf )
|
||||
return INSTALLSTATE_INVALIDARG;
|
||||
|
||||
@@ -1081,29 +1078,20 @@ end:
|
||||
*/
|
||||
INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
|
||||
{
|
||||
INSTALLSTATE rc;
|
||||
LPWSTR szwProduct= NULL;
|
||||
LPWSTR szwFeature= NULL;
|
||||
LPWSTR szwProduct = NULL, szwFeature= NULL;
|
||||
INSTALLSTATE rc = INSTALLSTATE_UNKNOWN;
|
||||
|
||||
if( szProduct )
|
||||
{
|
||||
szwProduct = strdupAtoW( szProduct );
|
||||
if( !szwProduct)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
szwProduct = strdupAtoW( szProduct );
|
||||
if ( szProduct && !szwProduct )
|
||||
goto end;
|
||||
|
||||
if( szFeature )
|
||||
{
|
||||
szwFeature = strdupAtoW( szFeature );
|
||||
if( !szwFeature)
|
||||
{
|
||||
msi_free( szwProduct);
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
szwFeature = strdupAtoW( szFeature );
|
||||
if ( szFeature && !szwFeature )
|
||||
goto end;
|
||||
|
||||
rc = MsiQueryFeatureStateW(szwProduct, szwFeature);
|
||||
|
||||
end:
|
||||
msi_free( szwProduct);
|
||||
msi_free( szwFeature);
|
||||
|
||||
@@ -1119,12 +1107,19 @@ INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature)
|
||||
*/
|
||||
INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
|
||||
{
|
||||
WCHAR squishProduct[GUID_SIZE];
|
||||
UINT rc;
|
||||
DWORD sz = 0;
|
||||
HKEY hkey;
|
||||
|
||||
TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
|
||||
|
||||
if (!szProduct || !szFeature)
|
||||
return INSTALLSTATE_INVALIDARG;
|
||||
|
||||
if (!squash_guid( szProduct, squishProduct ))
|
||||
return INSTALLSTATE_INVALIDARG;
|
||||
|
||||
rc = MSIREG_OpenFeaturesKey(szProduct, &hkey, FALSE);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return INSTALLSTATE_UNKNOWN;
|
||||
@@ -1134,8 +1129,8 @@ INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature)
|
||||
|
||||
if (rc == ERROR_SUCCESS)
|
||||
return INSTALLSTATE_LOCAL;
|
||||
else
|
||||
return INSTALLSTATE_ABSENT;
|
||||
|
||||
return INSTALLSTATE_UNKNOWN;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
@@ -1192,7 +1187,7 @@ end:
|
||||
UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf,
|
||||
DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf)
|
||||
{
|
||||
static const WCHAR szVersionResource[] = {'\\',0};
|
||||
static WCHAR szVersionResource[] = {'\\',0};
|
||||
static const WCHAR szVersionFormat[] = {
|
||||
'%','d','.','%','d','.','%','d','.','%','d',0};
|
||||
static const WCHAR szLangFormat[] = {'%','d',0};
|
||||
@@ -1373,65 +1368,134 @@ HRESULT WINAPI DllCanUnloadNow(void)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiGetFeatureUsageW(LPCWSTR szProduct, LPCWSTR szFeature,
|
||||
DWORD* pdwUseCount, WORD* pwDateUsed)
|
||||
/***********************************************************************
|
||||
* MsiGetFeatureUsageW [MSI.@]
|
||||
*/
|
||||
UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature,
|
||||
DWORD* pdwUseCount, WORD* pwDateUsed )
|
||||
{
|
||||
FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature),
|
||||
pdwUseCount, pwDateUsed);
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiGetFeatureUsageA(LPCSTR szProduct, LPCSTR szFeature,
|
||||
DWORD* pdwUseCount, WORD* pwDateUsed)
|
||||
/***********************************************************************
|
||||
* MsiGetFeatureUsageA [MSI.@]
|
||||
*/
|
||||
UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature,
|
||||
DWORD* pdwUseCount, WORD* pwDateUsed )
|
||||
{
|
||||
FIXME("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
|
||||
LPWSTR prod = NULL, feat = NULL;
|
||||
UINT ret = ERROR_OUTOFMEMORY;
|
||||
|
||||
TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature),
|
||||
pdwUseCount, pwDateUsed);
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
|
||||
prod = strdupAtoW( szProduct );
|
||||
if (szProduct && !prod)
|
||||
goto end;
|
||||
|
||||
feat = strdupAtoW( szFeature );
|
||||
if (szFeature && !feat)
|
||||
goto end;
|
||||
|
||||
ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed );
|
||||
|
||||
end:
|
||||
msi_free( prod );
|
||||
msi_free( feat );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
INSTALLSTATE WINAPI MsiUseFeatureExW(LPCWSTR szProduct, LPCWSTR szFeature,
|
||||
DWORD dwInstallMode, DWORD dwReserved)
|
||||
/***********************************************************************
|
||||
* MsiUseFeatureExW [MSI.@]
|
||||
*/
|
||||
INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature,
|
||||
DWORD dwInstallMode, DWORD dwReserved )
|
||||
{
|
||||
FIXME("%s %s %li %li\n", debugstr_w(szProduct), debugstr_w(szFeature),
|
||||
INSTALLSTATE state;
|
||||
|
||||
TRACE("%s %s %li %li\n", debugstr_w(szProduct), debugstr_w(szFeature),
|
||||
dwInstallMode, dwReserved);
|
||||
|
||||
/*
|
||||
* Polls all the components of the feature to find install state and then
|
||||
* writes:
|
||||
* Software\\Microsoft\\Windows\\CurrentVersion\\
|
||||
* Installer\\Products\\<squishguid>\\<feature>
|
||||
* "Usage"=dword:........
|
||||
*/
|
||||
state = MsiQueryFeatureStateW( szProduct, szFeature );
|
||||
|
||||
return INSTALLSTATE_LOCAL;
|
||||
if (dwReserved)
|
||||
return INSTALLSTATE_INVALIDARG;
|
||||
|
||||
if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION)
|
||||
{
|
||||
FIXME("mark product %s feature %s as used\n",
|
||||
debugstr_w(szProduct), debugstr_w(szFeature) );
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiUseFeatureExA [MSI.@]
|
||||
*/
|
||||
INSTALLSTATE WINAPI MsiUseFeatureExA(LPCSTR szProduct, LPCSTR szFeature,
|
||||
DWORD dwInstallMode, DWORD dwReserved)
|
||||
INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature,
|
||||
DWORD dwInstallMode, DWORD dwReserved )
|
||||
{
|
||||
FIXME("%s %s %li %li\n", debugstr_a(szProduct), debugstr_a(szFeature),
|
||||
INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
|
||||
LPWSTR prod = NULL, feat = NULL;
|
||||
|
||||
TRACE("%s %s %li %li\n", debugstr_a(szProduct), debugstr_a(szFeature),
|
||||
dwInstallMode, dwReserved);
|
||||
|
||||
return INSTALLSTATE_LOCAL;
|
||||
prod = strdupAtoW( szProduct );
|
||||
if (szProduct && !prod)
|
||||
goto end;
|
||||
|
||||
feat = strdupAtoW( szFeature );
|
||||
if (szFeature && !feat)
|
||||
goto end;
|
||||
|
||||
ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved );
|
||||
|
||||
end:
|
||||
msi_free( prod );
|
||||
msi_free( feat );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
INSTALLSTATE WINAPI MsiUseFeatureW(LPCWSTR szProduct, LPCWSTR szFeature)
|
||||
INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature )
|
||||
{
|
||||
FIXME("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature));
|
||||
|
||||
return INSTALLSTATE_LOCAL;
|
||||
}
|
||||
|
||||
INSTALLSTATE WINAPI MsiUseFeatureA(LPCSTR szProduct, LPCSTR szFeature)
|
||||
INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature )
|
||||
{
|
||||
FIXME("%s %s\n", debugstr_a(szProduct), debugstr_a(szFeature));
|
||||
INSTALLSTATE ret = INSTALLSTATE_UNKNOWN;
|
||||
LPWSTR prod = NULL, feat = NULL;
|
||||
|
||||
return INSTALLSTATE_LOCAL;
|
||||
TRACE("%s %s\n", debugstr_a(szProduct), debugstr_a(szFeature) );
|
||||
|
||||
prod = strdupAtoW( szProduct );
|
||||
if (szProduct && !prod)
|
||||
goto end;
|
||||
|
||||
feat = strdupAtoW( szFeature );
|
||||
if (szFeature && !feat)
|
||||
goto end;
|
||||
|
||||
ret = MsiUseFeatureW( prod, feat );
|
||||
|
||||
end:
|
||||
msi_free( prod );
|
||||
msi_free( feat );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiProvideQualifiedComponentExW [MSI.@]
|
||||
*/
|
||||
UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
|
||||
LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct,
|
||||
DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf,
|
||||
@@ -1441,10 +1505,9 @@ UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
|
||||
UINT rc;
|
||||
LPWSTR info;
|
||||
DWORD sz;
|
||||
LPWSTR product = NULL;
|
||||
LPWSTR component = NULL;
|
||||
LPWSTR ptr;
|
||||
GUID clsid;
|
||||
WCHAR product[MAX_FEATURE_CHARS+1];
|
||||
WCHAR component[MAX_FEATURE_CHARS+1];
|
||||
WCHAR feature[MAX_FEATURE_CHARS+1];
|
||||
|
||||
TRACE("%s %s %li %s %li %li %p %p\n", debugstr_w(szComponent),
|
||||
debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct),
|
||||
@@ -1471,25 +1534,8 @@ UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
|
||||
return ERROR_INDEX_ABSENT;
|
||||
}
|
||||
|
||||
/* find the component */
|
||||
ptr = strchrW(&info[20],'>');
|
||||
if (ptr)
|
||||
ptr++;
|
||||
else
|
||||
{
|
||||
RegCloseKey(hkey);
|
||||
msi_free(info);
|
||||
return ERROR_INDEX_ABSENT;
|
||||
}
|
||||
|
||||
if (!szProduct)
|
||||
{
|
||||
decode_base85_guid(info,&clsid);
|
||||
StringFromCLSID(&clsid, &product);
|
||||
}
|
||||
decode_base85_guid(ptr,&clsid);
|
||||
StringFromCLSID(&clsid, &component);
|
||||
|
||||
MsiDecomposeDescriptorW(info, product, feature, component, &sz);
|
||||
|
||||
if (!szProduct)
|
||||
rc = MsiGetComponentPathW(product, component, lpPathBuf, pcchPathBuf);
|
||||
else
|
||||
@@ -1497,8 +1543,6 @@ UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent,
|
||||
|
||||
RegCloseKey(hkey);
|
||||
msi_free(info);
|
||||
msi_free(product);
|
||||
msi_free(component);
|
||||
|
||||
if (rc == INSTALLSTATE_LOCAL)
|
||||
return ERROR_SUCCESS;
|
||||
@@ -1720,6 +1764,9 @@ UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiGetShortcutTargetA [MSI.@]
|
||||
*/
|
||||
UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
|
||||
LPSTR szProductCode, LPSTR szFeatureId,
|
||||
LPSTR szComponentCode )
|
||||
@@ -1746,12 +1793,60 @@ UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
|
||||
return r;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiGetShortcutTargetW [MSI.@]
|
||||
*/
|
||||
UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget,
|
||||
LPWSTR szProductCode, LPWSTR szFeatureId,
|
||||
LPWSTR szComponentCode )
|
||||
{
|
||||
FIXME("%s\n", debugstr_w(szShortcutTarget));
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
IShellLinkDataList *dl = NULL;
|
||||
IPersistFile *pf = NULL;
|
||||
LPEXP_DARWIN_LINK darwin = NULL;
|
||||
HRESULT r, init;
|
||||
|
||||
TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget),
|
||||
szProductCode, szFeatureId, szComponentCode );
|
||||
|
||||
init = CoInitialize(NULL);
|
||||
|
||||
r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
|
||||
&IID_IPersistFile, (LPVOID*) &pf );
|
||||
if( SUCCEEDED( r ) )
|
||||
{
|
||||
r = IPersistFile_Load( pf, szShortcutTarget,
|
||||
STGM_READ | STGM_SHARE_DENY_WRITE );
|
||||
if( SUCCEEDED( r ) )
|
||||
{
|
||||
r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList,
|
||||
(LPVOID*) &dl );
|
||||
if( SUCCEEDED( r ) )
|
||||
{
|
||||
IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG,
|
||||
(LPVOID) &darwin );
|
||||
IShellLinkDataList_Release( dl );
|
||||
}
|
||||
}
|
||||
IPersistFile_Release( pf );
|
||||
}
|
||||
|
||||
if (SUCCEEDED(init))
|
||||
CoUninitialize();
|
||||
|
||||
TRACE("darwin = %p\n", darwin);
|
||||
|
||||
if (darwin)
|
||||
{
|
||||
DWORD sz;
|
||||
UINT ret;
|
||||
|
||||
ret = MsiDecomposeDescriptorW( darwin->szwDarwinID,
|
||||
szProductCode, szFeatureId, szComponentCode, &sz );
|
||||
LocalFree( darwin );
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature,
|
||||
@@ -1877,3 +1972,45 @@ UINT WINAPI MsiEnumPatchesW( LPCWSTR szProduct, DWORD iPatchIndex,
|
||||
iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf);
|
||||
return ERROR_NO_MORE_ITEMS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiGetFileHashW [MSI.@]
|
||||
*/
|
||||
UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions,
|
||||
PMSIFILEHASHINFO pHash )
|
||||
{
|
||||
FIXME("%s %08lx %p\n", debugstr_w(szFilePath), dwOptions, pHash );
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiGetFileHashA [MSI.@]
|
||||
*/
|
||||
UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions,
|
||||
PMSIFILEHASHINFO pHash )
|
||||
{
|
||||
FIXME("%s %08lx %p\n", debugstr_a(szFilePath), dwOptions, pHash );
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiAdvertiseScriptW [MSI.@]
|
||||
*/
|
||||
UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags,
|
||||
PHKEY phRegData, BOOL fRemoveItems )
|
||||
{
|
||||
FIXME("%s %08lx %p %d\n",
|
||||
debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems );
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiAdvertiseScriptA [MSI.@]
|
||||
*/
|
||||
UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags,
|
||||
PHKEY phRegData, BOOL fRemoveItems )
|
||||
{
|
||||
FIXME("%s %08lx %p %d\n",
|
||||
debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems );
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
||||
#include "msi_Es.rc"
|
||||
#include "msi_Fi.rc"
|
||||
#include "msi_Fr.rc"
|
||||
#include "msi_Ko.rc"
|
||||
#include "msi_Nl.rc"
|
||||
#include "msi_No.rc"
|
||||
#include "msi_Pt.rc"
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
35 stdcall MsiEnableUIPreview(long ptr)
|
||||
36 stdcall MsiEnumClientsA(str long ptr)
|
||||
37 stdcall MsiEnumClientsW(wstr long ptr)
|
||||
38 stdcall MsiEnumComponentQualifiersA(str long str ptr str ptr)
|
||||
39 stdcall MsiEnumComponentQualifiersW(wstr long wstr ptr wstr ptr)
|
||||
38 stdcall MsiEnumComponentQualifiersA(str long ptr ptr ptr ptr)
|
||||
39 stdcall MsiEnumComponentQualifiersW(wstr long ptr ptr ptr ptr)
|
||||
40 stdcall MsiEnumComponentsA(long ptr)
|
||||
41 stdcall MsiEnumComponentsW(long ptr)
|
||||
42 stdcall MsiEnumFeaturesA(str long ptr ptr)
|
||||
@@ -66,8 +66,8 @@
|
||||
70 stdcall MsiGetProductInfoW(wstr wstr wstr long)
|
||||
71 stdcall MsiGetProductPropertyA(long str ptr ptr)
|
||||
72 stdcall MsiGetProductPropertyW(long wstr ptr ptr)
|
||||
73 stdcall MsiGetPropertyA(ptr str str ptr)
|
||||
74 stdcall MsiGetPropertyW(ptr wstr wstr ptr)
|
||||
73 stdcall MsiGetPropertyA(ptr str ptr ptr)
|
||||
74 stdcall MsiGetPropertyW(ptr wstr ptr ptr)
|
||||
75 stdcall MsiGetSourcePathA(long str ptr ptr)
|
||||
76 stdcall MsiGetSourcePathW(long wstr ptr ptr)
|
||||
77 stdcall MsiGetSummaryInformationA(long str long ptr)
|
||||
@@ -136,7 +136,7 @@
|
||||
140 stub MsiSetInstallLevel
|
||||
141 stdcall MsiSetInternalUI(long ptr)
|
||||
142 stub MsiVerifyDiskSpace
|
||||
143 stub MsiSetMode
|
||||
143 stdcall MsiSetMode(long long long)
|
||||
144 stdcall MsiSetPropertyA(long str str)
|
||||
145 stdcall MsiSetPropertyW(long wstr wstr)
|
||||
146 stdcall MsiSetTargetPathA(long str str)
|
||||
@@ -169,8 +169,8 @@
|
||||
173 stdcall MsiGetComponentPathW(wstr wstr ptr ptr)
|
||||
174 stdcall MsiApplyPatchA(str str long str)
|
||||
175 stdcall MsiApplyPatchW(wstr wstr long wstr)
|
||||
176 stub MsiAdvertiseScriptA
|
||||
177 stub MsiAdvertiseScriptW
|
||||
176 stdcall MsiAdvertiseScriptA(str long ptr long)
|
||||
177 stdcall MsiAdvertiseScriptW(wstr long ptr long)
|
||||
178 stub MsiGetPatchInfoA
|
||||
179 stub MsiGetPatchInfoW
|
||||
180 stdcall MsiEnumPatchesA(str long ptr ptr ptr)
|
||||
@@ -211,8 +211,8 @@
|
||||
215 stub MsiIsProductElevatedW
|
||||
216 stdcall MsiGetShortcutTargetA(str ptr ptr ptr)
|
||||
217 stdcall MsiGetShortcutTargetW(wstr ptr ptr ptr)
|
||||
218 stub MsiGetFileHashA
|
||||
219 stub MsiGetFileHashW
|
||||
218 stdcall MsiGetFileHashA(str long ptr)
|
||||
219 stdcall MsiGetFileHashW(wstr long ptr)
|
||||
220 stub MsiEnumComponentCostsA
|
||||
221 stub MsiEnumComponentCostsW
|
||||
222 stdcall MsiCreateAndVerifyInstallerDirectory(long)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Korean resources for MSI
|
||||
*
|
||||
* Copyright 2005 YunSong Hwang
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT
|
||||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
5 "path %s not found"
|
||||
9 "디스크 %s 삽입"
|
||||
10 "절못된 매개변수"
|
||||
11 "enter which folder contains %s"
|
||||
12 "install source for feature missing"
|
||||
13 "network drive for feature missing"
|
||||
14 "feature from:"
|
||||
15 "choose which folder contains %s"
|
||||
}
|
||||
@@ -67,6 +67,7 @@ typedef struct tagMSIDATABASE
|
||||
string_table *strings;
|
||||
LPCWSTR mode;
|
||||
struct list tables;
|
||||
struct list transforms;
|
||||
} MSIDATABASE;
|
||||
|
||||
typedef struct tagMSIVIEW MSIVIEW;
|
||||
@@ -219,6 +220,16 @@ typedef struct tagMSIPREVIEW
|
||||
msi_dialog *dialog;
|
||||
} MSIPREVIEW;
|
||||
|
||||
#define MSI_MAX_PROPS 20
|
||||
|
||||
typedef struct tagMSISUMMARYINFO
|
||||
{
|
||||
MSIOBJECTHDR hdr;
|
||||
MSIDATABASE *db;
|
||||
DWORD update_count;
|
||||
PROPVARIANT property[MSI_MAX_PROPS];
|
||||
} MSISUMMARYINFO;
|
||||
|
||||
#define MSIHANDLETYPE_ANY 0
|
||||
#define MSIHANDLETYPE_DATABASE 1
|
||||
#define MSIHANDLETYPE_SUMMARYINFO 2
|
||||
@@ -243,6 +254,7 @@ DEFINE_GUID(CLSID_IMsiServerX3, 0x000C1094,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x0
|
||||
|
||||
DEFINE_GUID(CLSID_IMsiServerMessage, 0x000C101D,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
|
||||
|
||||
/* handle unicode/ascii output in the Msi* API functions */
|
||||
typedef struct {
|
||||
BOOL unicode;
|
||||
union {
|
||||
@@ -259,6 +271,8 @@ typedef struct {
|
||||
} str;
|
||||
} awcstring;
|
||||
|
||||
UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz );
|
||||
|
||||
/* handle functions */
|
||||
extern void *msihandle2msiinfo(MSIHANDLE handle, UINT type);
|
||||
extern MSIHANDLE alloc_msihandle( MSIOBJECTHDR * );
|
||||
@@ -269,6 +283,7 @@ extern void msiobj_lock(MSIOBJECTHDR *);
|
||||
extern void msiobj_unlock(MSIOBJECTHDR *);
|
||||
|
||||
extern void free_cached_tables( MSIDATABASE *db );
|
||||
extern void msi_free_transforms( MSIDATABASE *db );
|
||||
extern string_table *load_string_table( IStorage *stg );
|
||||
extern UINT MSI_CommitTables( MSIDATABASE *db );
|
||||
extern HRESULT init_string_table( IStorage *stg );
|
||||
@@ -300,6 +315,9 @@ extern BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name );
|
||||
extern UINT read_raw_stream_data( MSIDATABASE*, LPCWSTR stname,
|
||||
USHORT **pdata, UINT *psz );
|
||||
|
||||
/* transform functions */
|
||||
extern UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg );
|
||||
|
||||
/* action internals */
|
||||
extern UINT MSI_InstallPackage( MSIPACKAGE *, LPCWSTR, LPCWSTR );
|
||||
extern void ACTION_free_package_structures( MSIPACKAGE* );
|
||||
@@ -401,6 +419,10 @@ extern void msi_dialog_handle_event( msi_dialog*, LPCWSTR, LPCWSTR, MSIRECORD *
|
||||
extern MSIPREVIEW *MSI_EnableUIPreview( MSIDATABASE * );
|
||||
extern UINT MSI_PreviewDialogW( MSIPREVIEW *, LPCWSTR );
|
||||
|
||||
/* summary information */
|
||||
extern MSISUMMARYINFO *MSI_GetSummaryInformationW( MSIDATABASE *db, UINT uiUpdateCount );
|
||||
extern LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty );
|
||||
|
||||
/* undocumented functions */
|
||||
UINT WINAPI MsiCreateAndVerifyInstallerDirectory( DWORD );
|
||||
UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR, LPWSTR, LPWSTR, LPWSTR, DWORD * );
|
||||
|
||||
@@ -657,8 +657,7 @@ static UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db,
|
||||
if( TRACE_ON( msi ) )
|
||||
enum_stream_names( stg );
|
||||
|
||||
/* r = table_apply_transform( db, stg ); */
|
||||
FIXME("should apply transform %s\n", debugstr_w(szTransformFile) );
|
||||
r = msi_table_apply_transform( db, stg );
|
||||
|
||||
IStorage_Release( stg );
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
#include "query.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||
|
||||
|
||||
/* below is the query interface to a table */
|
||||
|
||||
+120
-183
@@ -31,7 +31,6 @@
|
||||
#include "wine/debug.h"
|
||||
#include "msi.h"
|
||||
#include "msiquery.h"
|
||||
#include "msipriv.h"
|
||||
#include "objidl.h"
|
||||
#include "wincrypt.h"
|
||||
#include "winuser.h"
|
||||
@@ -39,15 +38,10 @@
|
||||
#include "wine/unicode.h"
|
||||
#include "objbase.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
#include "msipriv.h"
|
||||
#include "action.h"
|
||||
|
||||
/*
|
||||
* The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR,
|
||||
* which is a problem because LPCTSTR isn't defined when compiling wine.
|
||||
* To work around this problem, we need to define LPCTSTR as LPCWSTR here,
|
||||
* and make sure to only use it in W functions.
|
||||
*/
|
||||
#define LPCTSTR LPCWSTR
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
static void MSI_FreePackage( MSIOBJECTHDR *arg)
|
||||
{
|
||||
@@ -128,6 +122,30 @@ static UINT clone_properties(MSIDATABASE *db)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* set_installed_prop
|
||||
*
|
||||
* Sets the "Installed" property to indicate that
|
||||
* the product is installed for the current user.
|
||||
*/
|
||||
static UINT set_installed_prop( MSIPACKAGE *package )
|
||||
{
|
||||
static const WCHAR szInstalled[] = {
|
||||
'I','n','s','t','a','l','l','e','d',0 };
|
||||
WCHAR val[2] = { '1', 0 };
|
||||
HKEY hkey = 0;
|
||||
UINT r;
|
||||
|
||||
r = MSIREG_OpenUninstallKey( package->ProductCode, &hkey, FALSE );
|
||||
if (r == ERROR_SUCCESS)
|
||||
{
|
||||
RegCloseKey( hkey );
|
||||
MSI_SetPropertyW( package, szInstalled, val );
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are a whole slew of these we need to set
|
||||
*
|
||||
@@ -211,29 +229,14 @@ static VOID set_installer_properties(MSIPACKAGE *package)
|
||||
static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0};
|
||||
static const WCHAR szScreenFormat[] = {'%','d',0};
|
||||
|
||||
/*
|
||||
* Other things I notice set
|
||||
*
|
||||
SystemLanguageID
|
||||
ComputerName
|
||||
UserLanguageID
|
||||
LogonUser
|
||||
VirtualMemory
|
||||
Intel
|
||||
ShellAdvSupport
|
||||
DefaultUIFont
|
||||
VersionDatabase
|
||||
PackagecodeChanging
|
||||
ProductState
|
||||
CaptionHeight
|
||||
BorderTop
|
||||
BorderSide
|
||||
TextHeight
|
||||
RedirectedDllSupport
|
||||
Time
|
||||
Date
|
||||
Privileged
|
||||
*/
|
||||
/*
|
||||
* Other things that probably should be set:
|
||||
*
|
||||
* SystemLanguageID ComputerName UserLanguageID LogonUser VirtualMemory
|
||||
* Intel ShellAdvSupport DefaultUIFont VersionDatabase PackagecodeChanging
|
||||
* ProductState CaptionHeight BorderTop BorderSide TextHeight
|
||||
* RedirectedDllSupport Time Date Privileged
|
||||
*/
|
||||
|
||||
SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
|
||||
strcatW(pth,cszbs);
|
||||
@@ -365,6 +368,8 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db )
|
||||
{
|
||||
static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
|
||||
static const WCHAR szpi[] = {'%','i',0};
|
||||
static const WCHAR szProductCode[] = {
|
||||
'P','r','o','d','u','c','t','C','o','d','e',0};
|
||||
MSIPACKAGE *package = NULL;
|
||||
WCHAR uilevel[10];
|
||||
|
||||
@@ -401,6 +406,9 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db )
|
||||
set_installer_properties(package);
|
||||
sprintfW(uilevel,szpi,gUILevel);
|
||||
MSI_SetPropertyW(package, szLevel, uilevel);
|
||||
|
||||
package->ProductCode = msi_dup_property( package, szProductCode );
|
||||
set_installed_prop( package );
|
||||
}
|
||||
|
||||
return package;
|
||||
@@ -439,8 +447,6 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
|
||||
MSIDATABASE *db = NULL;
|
||||
MSIPACKAGE *package;
|
||||
MSIHANDLE handle;
|
||||
DWORD size;
|
||||
static const WCHAR szProductCode[]= {'P','r','o','d','u','c','t','C','o','d','e',0};
|
||||
UINT r;
|
||||
|
||||
TRACE("%s %p\n", debugstr_w(szPackage), pPackage);
|
||||
@@ -486,13 +492,6 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
|
||||
MSI_SetPropertyW( package, Database, szPackage );
|
||||
}
|
||||
|
||||
/* this property must exist */
|
||||
size = 0;
|
||||
MSI_GetPropertyW(package,szProductCode,NULL,&size);
|
||||
size ++;
|
||||
package->ProductCode = msi_alloc(size * sizeof(WCHAR));
|
||||
MSI_GetPropertyW(package,szProductCode,package->ProductCode, &size);
|
||||
|
||||
*pPackage = package;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
@@ -577,7 +576,7 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
|
||||
char *msg;
|
||||
int len;
|
||||
|
||||
TRACE("%x \n",eMessageType);
|
||||
TRACE("%x\n", eMessageType);
|
||||
rc = 0;
|
||||
|
||||
if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
|
||||
@@ -605,8 +604,8 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
|
||||
{
|
||||
LPWSTR tmp;
|
||||
WCHAR number[3];
|
||||
const static WCHAR format[] = { '%','i',':',' ',0};
|
||||
const static WCHAR space[] = { ' ',0};
|
||||
static const WCHAR format[] = { '%','i',':',' ',0};
|
||||
static const WCHAR space[] = { ' ',0};
|
||||
sz = 0;
|
||||
MSI_RecordGetStringW(record,i,NULL,&sz);
|
||||
sz+=4;
|
||||
@@ -690,32 +689,26 @@ out:
|
||||
}
|
||||
|
||||
/* property code */
|
||||
UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
|
||||
UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue )
|
||||
{
|
||||
LPWSTR szwName = NULL, szwValue = NULL;
|
||||
UINT hr = ERROR_INSTALL_FAILURE;
|
||||
UINT r = ERROR_OUTOFMEMORY;
|
||||
|
||||
if( szName )
|
||||
{
|
||||
szwName = strdupAtoW( szName );
|
||||
if( !szwName )
|
||||
goto end;
|
||||
}
|
||||
szwName = strdupAtoW( szName );
|
||||
if( szName && !szwName )
|
||||
goto end;
|
||||
|
||||
if( szValue )
|
||||
{
|
||||
szwValue = strdupAtoW( szValue );
|
||||
if( !szwValue)
|
||||
goto end;
|
||||
}
|
||||
szwValue = strdupAtoW( szValue );
|
||||
if( szValue && !szwValue )
|
||||
goto end;
|
||||
|
||||
hr = MsiSetPropertyW( hInstall, szwName, szwValue);
|
||||
r = MsiSetPropertyW( hInstall, szwName, szwValue);
|
||||
|
||||
end:
|
||||
msi_free( szwName );
|
||||
msi_free( szwValue );
|
||||
|
||||
return hr;
|
||||
return r;
|
||||
}
|
||||
|
||||
UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
|
||||
@@ -736,8 +729,14 @@ UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
|
||||
,'e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
|
||||
WCHAR Query[1024];
|
||||
|
||||
TRACE("Setting property (%s %s)\n",debugstr_w(szName),
|
||||
debugstr_w(szValue));
|
||||
TRACE("%p %s %s\n", package, debugstr_w(szName), debugstr_w(szValue));
|
||||
|
||||
if (!szName)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
/* this one is weird... */
|
||||
if (!szName[0])
|
||||
return szValue ? ERROR_FUNCTION_FAILED : ERROR_SUCCESS;
|
||||
|
||||
rc = MSI_GetPropertyW(package,szName,0,&sz);
|
||||
if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS)
|
||||
@@ -775,11 +774,6 @@ UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue
|
||||
MSIPACKAGE *package;
|
||||
UINT ret;
|
||||
|
||||
if (NULL == szName)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
if (NULL == szValue)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
|
||||
if( !package )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
@@ -788,51 +782,33 @@ UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue
|
||||
return ret;
|
||||
}
|
||||
|
||||
static UINT MSI_GetPropertyRow(MSIPACKAGE *package, LPCWSTR szName, MSIRECORD **row)
|
||||
static MSIRECORD *MSI_GetPropertyRow( MSIPACKAGE *package, LPCWSTR name )
|
||||
{
|
||||
MSIQUERY *view;
|
||||
UINT rc, sz;
|
||||
static const WCHAR select[]=
|
||||
static const WCHAR query[]=
|
||||
{'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ',
|
||||
'F','R','O','M',' ' ,'`','_','P','r','o','p','e','r','t','y','`',
|
||||
' ','W','H','E','R','E',' ' ,'`','_','P','r','o','p','e','r','t','y','`',
|
||||
'=','\'','%','s','\'',0};
|
||||
LPWSTR query;
|
||||
|
||||
if (!szName)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
if (!name || !name[0])
|
||||
return NULL;
|
||||
|
||||
sz = sizeof select + strlenW(szName)*sizeof(WCHAR);
|
||||
query = msi_alloc( sz);
|
||||
sprintfW(query,select,szName);
|
||||
|
||||
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
|
||||
msi_free(query);
|
||||
if (rc == ERROR_SUCCESS)
|
||||
{
|
||||
rc = MSI_ViewExecute(view, 0);
|
||||
if (rc == ERROR_SUCCESS)
|
||||
rc = MSI_ViewFetch(view,row);
|
||||
|
||||
MSI_ViewClose(view);
|
||||
msiobj_release(&view->hdr);
|
||||
}
|
||||
|
||||
return rc;
|
||||
return MSI_QueryGetRecord( package->db, query, name );
|
||||
}
|
||||
|
||||
UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName,
|
||||
LPWSTR szValueBuf, DWORD* pchValueBuf)
|
||||
|
||||
/* internal function, not compatible with MsiGetPropertyW */
|
||||
UINT MSI_GetPropertyW( MSIPACKAGE *package, LPCWSTR szName,
|
||||
LPWSTR szValueBuf, DWORD* pchValueBuf )
|
||||
{
|
||||
MSIRECORD *row;
|
||||
UINT rc;
|
||||
UINT rc = ERROR_FUNCTION_FAILED;
|
||||
|
||||
rc = MSI_GetPropertyRow(package, szName, &row);
|
||||
row = MSI_GetPropertyRow( package, szName );
|
||||
|
||||
if (*pchValueBuf > 0)
|
||||
szValueBuf[0] = 0;
|
||||
|
||||
if (rc == ERROR_SUCCESS)
|
||||
if (row)
|
||||
{
|
||||
rc = MSI_RecordGetStringW(row,1,szValueBuf,pchValueBuf);
|
||||
msiobj_release(&row->hdr);
|
||||
@@ -853,106 +829,67 @@ UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName,
|
||||
return rc;
|
||||
}
|
||||
|
||||
UINT MSI_GetPropertyA(MSIPACKAGE *package, LPCSTR szName,
|
||||
LPSTR szValueBuf, DWORD* pchValueBuf)
|
||||
{
|
||||
MSIRECORD *row;
|
||||
UINT rc;
|
||||
LPWSTR szwName = NULL;
|
||||
|
||||
if (*pchValueBuf > 0)
|
||||
szValueBuf[0] = 0;
|
||||
|
||||
if( szName )
|
||||
{
|
||||
szwName = strdupAtoW( szName );
|
||||
if (!szwName)
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
rc = MSI_GetPropertyRow(package, szwName, &row);
|
||||
if (rc == ERROR_SUCCESS)
|
||||
{
|
||||
rc = MSI_RecordGetStringA(row,1,szValueBuf,pchValueBuf);
|
||||
msiobj_release(&row->hdr);
|
||||
}
|
||||
|
||||
if (rc == ERROR_SUCCESS)
|
||||
TRACE("returning %s for property %s\n", debugstr_a(szValueBuf),
|
||||
debugstr_a(szName));
|
||||
else if (rc == ERROR_MORE_DATA)
|
||||
TRACE("need %ld sized buffer for %s\n", *pchValueBuf,
|
||||
debugstr_a(szName));
|
||||
else
|
||||
{
|
||||
*pchValueBuf = 0;
|
||||
TRACE("property not found\n");
|
||||
}
|
||||
msi_free( szwName );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf)
|
||||
static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name,
|
||||
awstring *szValueBuf, DWORD* pchValueBuf )
|
||||
{
|
||||
static const WCHAR empty[] = {0};
|
||||
MSIPACKAGE *package;
|
||||
UINT ret;
|
||||
MSIRECORD *row = NULL;
|
||||
UINT r;
|
||||
LPCWSTR val = NULL;
|
||||
|
||||
TRACE("%lu %s %p\n", hInstall, debugstr_a(szName), pchValueBuf);
|
||||
TRACE("%lu %s %p %p\n", handle, debugstr_w(name),
|
||||
szValueBuf->str.w, pchValueBuf );
|
||||
|
||||
if (0 == hInstall)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
if (NULL == szName)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
if (NULL != szValueBuf && NULL == pchValueBuf)
|
||||
if (!name)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
/* This was tested against native msi */
|
||||
if (NULL == szValueBuf && NULL != pchValueBuf)
|
||||
*pchValueBuf = 0;
|
||||
|
||||
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
|
||||
package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE );
|
||||
if (!package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
ret = MSI_GetPropertyA(package, szName, szValueBuf, pchValueBuf );
|
||||
|
||||
row = MSI_GetPropertyRow( package, name );
|
||||
if (row)
|
||||
val = MSI_RecordGetString( row, 1 );
|
||||
|
||||
if (!val)
|
||||
val = empty;
|
||||
|
||||
r = msi_strcpy_to_awstring( val, szValueBuf, pchValueBuf );
|
||||
|
||||
if (row)
|
||||
msiobj_release( &row->hdr );
|
||||
msiobj_release( &package->hdr );
|
||||
|
||||
/* MsiGetProperty does not return error codes on missing properties */
|
||||
if (ret != ERROR_MORE_DATA)
|
||||
ret = ERROR_SUCCESS;
|
||||
|
||||
return ret;
|
||||
return r;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiGetPropertyA( MSIHANDLE hInstall, LPCSTR szName,
|
||||
LPSTR szValueBuf, DWORD* pchValueBuf )
|
||||
{
|
||||
awstring val;
|
||||
LPWSTR name;
|
||||
UINT r;
|
||||
|
||||
val.unicode = FALSE;
|
||||
val.str.a = szValueBuf;
|
||||
|
||||
name = strdupAtoW( szName );
|
||||
if (szName && !name)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
r = MSI_GetProperty( hInstall, name, &val, pchValueBuf );
|
||||
msi_free( name );
|
||||
return r;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName,
|
||||
LPWSTR szValueBuf, DWORD* pchValueBuf)
|
||||
UINT WINAPI MsiGetPropertyW( MSIHANDLE hInstall, LPCWSTR szName,
|
||||
LPWSTR szValueBuf, DWORD* pchValueBuf )
|
||||
{
|
||||
MSIPACKAGE *package;
|
||||
UINT ret;
|
||||
awstring val;
|
||||
|
||||
TRACE("%lu %s %p\n", hInstall, debugstr_w(szName), pchValueBuf);
|
||||
val.unicode = TRUE;
|
||||
val.str.w = szValueBuf;
|
||||
|
||||
if (0 == hInstall)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
if (NULL == szName)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
if (NULL != szValueBuf && NULL == pchValueBuf)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
/* This was tested against native msi */
|
||||
if (NULL == szValueBuf && NULL != pchValueBuf)
|
||||
*pchValueBuf = 0;
|
||||
|
||||
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
|
||||
if (!package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf );
|
||||
msiobj_release( &package->hdr );
|
||||
|
||||
/* MsiGetProperty does not return error codes on missing properties */
|
||||
if (ret != ERROR_MORE_DATA)
|
||||
ret = ERROR_SUCCESS;
|
||||
|
||||
return ret;
|
||||
return MSI_GetProperty( hInstall, szName, &val, pchValueBuf );
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
#include "query.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||
|
||||
#define MSIFIELD_NULL 0
|
||||
#define MSIFIELD_INT 1
|
||||
|
||||
+128
-139
@@ -253,6 +253,9 @@ BOOL decode_base85_guid( LPCWSTR str, GUID *guid )
|
||||
{
|
||||
DWORD i, val = 0, base = 1, *p;
|
||||
|
||||
if (!str)
|
||||
return FALSE;
|
||||
|
||||
p = (DWORD*) guid;
|
||||
for( i=0; i<20; i++ )
|
||||
{
|
||||
@@ -532,10 +535,13 @@ UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
|
||||
len = (p - &szDescriptor[20]);
|
||||
if( len > MAX_FEATURE_CHARS )
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
|
||||
szFeature[len] = 0;
|
||||
if (szFeature)
|
||||
{
|
||||
memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) );
|
||||
szFeature[len] = 0;
|
||||
}
|
||||
|
||||
TRACE("feature %s\n", debugstr_w( szFeature ));
|
||||
TRACE("feature %s\n", debugstr_w( &szDescriptor[20] ));
|
||||
|
||||
r = decode_base85_guid( p+1, &component );
|
||||
if( !r )
|
||||
@@ -543,8 +549,10 @@ UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct,
|
||||
|
||||
TRACE("component %s\n", debugstr_guid( &component ));
|
||||
|
||||
StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 );
|
||||
StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 );
|
||||
if (szProduct)
|
||||
StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 );
|
||||
if (szComponent)
|
||||
StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 );
|
||||
len = ( &p[21] - szDescriptor );
|
||||
|
||||
TRACE("length = %d\n", len);
|
||||
@@ -559,26 +567,30 @@ UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct,
|
||||
WCHAR product[MAX_FEATURE_CHARS+1];
|
||||
WCHAR feature[MAX_FEATURE_CHARS+1];
|
||||
WCHAR component[MAX_FEATURE_CHARS+1];
|
||||
LPWSTR str = NULL;
|
||||
LPWSTR str = NULL, p = NULL, f = NULL, c = NULL;
|
||||
UINT r;
|
||||
|
||||
TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct,
|
||||
szFeature, szComponent, pUsed);
|
||||
|
||||
if( szDescriptor )
|
||||
{
|
||||
str = strdupAtoW( szDescriptor );
|
||||
if( !str )
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
str = strdupAtoW( szDescriptor );
|
||||
if( szDescriptor && !str )
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
r = MsiDecomposeDescriptorW( str, product, feature, component, pUsed );
|
||||
if (szProduct)
|
||||
p = product;
|
||||
if (szFeature)
|
||||
f = feature;
|
||||
if (szComponent)
|
||||
c = component;
|
||||
|
||||
WideCharToMultiByte( CP_ACP, 0, product, MAX_FEATURE_CHARS+1,
|
||||
r = MsiDecomposeDescriptorW( str, p, f, c, pUsed );
|
||||
|
||||
WideCharToMultiByte( CP_ACP, 0, p, MAX_FEATURE_CHARS+1,
|
||||
szProduct, MAX_FEATURE_CHARS+1, NULL, NULL );
|
||||
WideCharToMultiByte( CP_ACP, 0, feature, MAX_FEATURE_CHARS+1,
|
||||
WideCharToMultiByte( CP_ACP, 0, f, MAX_FEATURE_CHARS+1,
|
||||
szFeature, MAX_FEATURE_CHARS+1, NULL, NULL );
|
||||
WideCharToMultiByte( CP_ACP, 0, component, MAX_FEATURE_CHARS+1,
|
||||
WideCharToMultiByte( CP_ACP, 0, c, MAX_FEATURE_CHARS+1,
|
||||
szComponent, MAX_FEATURE_CHARS+1, NULL, NULL );
|
||||
|
||||
msi_free( str );
|
||||
@@ -757,157 +769,134 @@ UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
|
||||
return r;
|
||||
}
|
||||
|
||||
UINT WINAPI MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex,
|
||||
awstring *lpQualBuf, DWORD* pcchQual,
|
||||
awstring *lpAppBuf, DWORD* pcchAppBuf )
|
||||
{
|
||||
DWORD name_sz, val_sz, type, ofs;
|
||||
LPWSTR name = NULL, val = NULL;
|
||||
UINT r, r2;
|
||||
HKEY key;
|
||||
|
||||
TRACE("%s %08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex,
|
||||
lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf);
|
||||
|
||||
if (!szComponent)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE );
|
||||
if (r != ERROR_SUCCESS)
|
||||
return ERROR_UNKNOWN_COMPONENT;
|
||||
|
||||
/* figure out how big the name is we want to return */
|
||||
name_sz = 0;
|
||||
if (pcchQual)
|
||||
{
|
||||
r = ERROR_OUTOFMEMORY;
|
||||
name_sz = *pcchQual * 4;
|
||||
name = msi_alloc( name_sz * sizeof(WCHAR) );
|
||||
if (!name)
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* figure out how big the value is */
|
||||
type = 0;
|
||||
val_sz = 0;
|
||||
r = RegEnumValueW( key, iIndex, NULL, NULL,
|
||||
NULL, &type, NULL, &val_sz );
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto end;
|
||||
|
||||
if (type != REG_MULTI_SZ)
|
||||
{
|
||||
ERR("component data has wrong type (%ld)\n", type);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* the value size is in bytes */
|
||||
val_sz += sizeof(WCHAR);
|
||||
val = msi_alloc( val_sz );
|
||||
if (!val)
|
||||
goto end;
|
||||
|
||||
r = RegEnumValueW( key, iIndex, name, &name_sz,
|
||||
NULL, &type, (LPBYTE)val, &val_sz );
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto end;
|
||||
|
||||
ofs = 0;
|
||||
r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs );
|
||||
if (r != ERROR_SUCCESS)
|
||||
goto end;
|
||||
|
||||
TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs));
|
||||
|
||||
r = msi_strcpy_to_awstring( name, lpQualBuf, pcchQual );
|
||||
r2 = msi_strcpy_to_awstring( val+ofs, lpAppBuf, pcchAppBuf );
|
||||
|
||||
if (r2 != ERROR_SUCCESS)
|
||||
r = r2;
|
||||
|
||||
end:
|
||||
msi_free(val);
|
||||
msi_free(name);
|
||||
RegCloseKey(key);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* MsiEnumComponentQualifiersA [MSI.@]
|
||||
*
|
||||
*/
|
||||
UINT WINAPI MsiEnumComponentQualifiersA( LPSTR szComponent, DWORD iIndex,
|
||||
UINT WINAPI MsiEnumComponentQualifiersA( LPCSTR szComponent, DWORD iIndex,
|
||||
LPSTR lpQualifierBuf, DWORD* pcchQualifierBuf,
|
||||
LPSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf)
|
||||
LPSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf )
|
||||
{
|
||||
LPWSTR szwComponent;
|
||||
LPWSTR lpwQualifierBuf;
|
||||
DWORD pcchwQualifierBuf;
|
||||
LPWSTR lpwApplicationDataBuf;
|
||||
DWORD pcchwApplicationDataBuf;
|
||||
DWORD rc;
|
||||
DWORD length;
|
||||
awstring qual, appdata;
|
||||
LPWSTR comp;
|
||||
UINT r;
|
||||
|
||||
TRACE("%s %08lx %p %p %p %p\n", debugstr_a(szComponent), iIndex,
|
||||
lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
|
||||
pcchApplicationDataBuf);
|
||||
|
||||
szwComponent = strdupAtoW(szComponent);
|
||||
comp = strdupAtoW( szComponent );
|
||||
if (szComponent && !comp)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
if (lpQualifierBuf)
|
||||
lpwQualifierBuf = msi_alloc( (*pcchQualifierBuf) * sizeof(WCHAR));
|
||||
else
|
||||
lpwQualifierBuf = NULL;
|
||||
qual.unicode = FALSE;
|
||||
qual.str.a = lpQualifierBuf;
|
||||
|
||||
if (pcchQualifierBuf)
|
||||
pcchwQualifierBuf = *pcchQualifierBuf;
|
||||
else
|
||||
pcchwQualifierBuf = 0;
|
||||
appdata.unicode = FALSE;
|
||||
appdata.str.a = lpApplicationDataBuf;
|
||||
|
||||
if (lpApplicationDataBuf)
|
||||
lpwApplicationDataBuf = msi_alloc( (*pcchApplicationDataBuf) * sizeof(WCHAR));
|
||||
else
|
||||
lpwApplicationDataBuf = NULL;
|
||||
|
||||
if (pcchApplicationDataBuf)
|
||||
pcchwApplicationDataBuf = *pcchApplicationDataBuf;
|
||||
else
|
||||
pcchwApplicationDataBuf = 0;
|
||||
|
||||
rc = MsiEnumComponentQualifiersW( szwComponent, iIndex, lpwQualifierBuf,
|
||||
&pcchwQualifierBuf, lpwApplicationDataBuf,
|
||||
&pcchwApplicationDataBuf);
|
||||
|
||||
/*
|
||||
* A bit of wizardry to report back the length without the null.
|
||||
* just in case the buffer is too small and is filled.
|
||||
*/
|
||||
if (lpQualifierBuf)
|
||||
{
|
||||
length = WideCharToMultiByte(CP_ACP, 0, lpwQualifierBuf, -1,
|
||||
lpQualifierBuf, *pcchQualifierBuf, NULL, NULL);
|
||||
|
||||
if (*pcchQualifierBuf == length && lpQualifierBuf[length-1])
|
||||
*pcchQualifierBuf = length;
|
||||
else
|
||||
*pcchQualifierBuf = length - 1;
|
||||
}
|
||||
if (lpApplicationDataBuf)
|
||||
{
|
||||
length = WideCharToMultiByte(CP_ACP, 0,
|
||||
lpwApplicationDataBuf, -1, lpApplicationDataBuf,
|
||||
*pcchApplicationDataBuf, NULL, NULL);
|
||||
|
||||
if (*pcchApplicationDataBuf == length && lpApplicationDataBuf[length-1])
|
||||
*pcchApplicationDataBuf = length;
|
||||
else
|
||||
*pcchApplicationDataBuf = length - 1;
|
||||
}
|
||||
|
||||
msi_free(lpwApplicationDataBuf);
|
||||
msi_free(lpwQualifierBuf);
|
||||
msi_free(szwComponent);
|
||||
|
||||
return rc;
|
||||
r = MSI_EnumComponentQualifiers( comp, iIndex,
|
||||
&qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
|
||||
msi_free( comp );
|
||||
return r;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* MsiEnumComponentQualifiersW [MSI.@]
|
||||
*
|
||||
*/
|
||||
UINT WINAPI MsiEnumComponentQualifiersW( LPWSTR szComponent, DWORD iIndex,
|
||||
UINT WINAPI MsiEnumComponentQualifiersW( LPCWSTR szComponent, DWORD iIndex,
|
||||
LPWSTR lpQualifierBuf, DWORD* pcchQualifierBuf,
|
||||
LPWSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf )
|
||||
{
|
||||
UINT rc;
|
||||
HKEY key;
|
||||
DWORD actual_pcchQualifierBuf = 0;
|
||||
DWORD actual_pcchApplicationDataBuf = 0;
|
||||
LPWSTR full_buffer = NULL;
|
||||
DWORD full_buffer_size = 0;
|
||||
LPWSTR ptr;
|
||||
awstring qual, appdata;
|
||||
|
||||
TRACE("%s %08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex,
|
||||
lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf,
|
||||
pcchApplicationDataBuf);
|
||||
|
||||
if (pcchQualifierBuf)
|
||||
actual_pcchQualifierBuf = *pcchQualifierBuf * sizeof(WCHAR);
|
||||
if (pcchApplicationDataBuf)
|
||||
actual_pcchApplicationDataBuf = *pcchApplicationDataBuf * sizeof(WCHAR);
|
||||
|
||||
rc = MSIREG_OpenUserComponentsKey(szComponent, &key, FALSE);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return ERROR_UNKNOWN_COMPONENT;
|
||||
qual.unicode = TRUE;
|
||||
qual.str.w = lpQualifierBuf;
|
||||
|
||||
full_buffer_size = (52 * sizeof(WCHAR)) + actual_pcchApplicationDataBuf;
|
||||
full_buffer = msi_alloc(full_buffer_size);
|
||||
|
||||
rc = RegEnumValueW(key, iIndex, lpQualifierBuf, pcchQualifierBuf, NULL,
|
||||
NULL, (LPBYTE)full_buffer, &full_buffer_size);
|
||||
appdata.unicode = TRUE;
|
||||
appdata.str.w = lpApplicationDataBuf;
|
||||
|
||||
if (rc == ERROR_MORE_DATA)
|
||||
{
|
||||
msi_free(full_buffer);
|
||||
full_buffer_size+=sizeof(WCHAR);
|
||||
full_buffer = msi_alloc(full_buffer_size);
|
||||
rc = RegEnumValueW(key, iIndex, lpQualifierBuf, pcchQualifierBuf, NULL,
|
||||
NULL, (LPBYTE)full_buffer, &full_buffer_size);
|
||||
}
|
||||
|
||||
RegCloseKey(key);
|
||||
|
||||
if (rc == ERROR_SUCCESS)
|
||||
{
|
||||
if (lpApplicationDataBuf && pcchApplicationDataBuf)
|
||||
{
|
||||
ptr = full_buffer;
|
||||
/* Skip the first guid */
|
||||
ptr += 21;
|
||||
|
||||
/* Skip the name and the component guid if it exists */
|
||||
if (strchrW(ptr,'<'))
|
||||
ptr = strchrW(ptr,'<');
|
||||
else
|
||||
ptr = strchrW(ptr,'>') + 21;
|
||||
|
||||
lstrcpynW(lpApplicationDataBuf,ptr,*pcchApplicationDataBuf);
|
||||
*pcchApplicationDataBuf = strlenW(ptr);
|
||||
}
|
||||
if (lpQualifierBuf && pcchQualifierBuf)
|
||||
*pcchQualifierBuf /= sizeof(WCHAR);
|
||||
TRACE("Providing %s and %s\n", debugstr_w(lpQualifierBuf),
|
||||
debugstr_w(lpApplicationDataBuf));
|
||||
}
|
||||
|
||||
msi_free(full_buffer);
|
||||
|
||||
return rc;
|
||||
return MSI_EnumComponentQualifiers( szComponent, iIndex,
|
||||
&qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf );
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
#include "query.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||
|
||||
|
||||
/* below is the query interface to a table */
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
#include "query.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||
|
||||
typedef struct _msistring
|
||||
{
|
||||
|
||||
+58
-46
@@ -39,8 +39,6 @@
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
#define MSI_MAX_PROPS 20
|
||||
|
||||
#include "pshpack1.h"
|
||||
|
||||
typedef struct {
|
||||
@@ -83,14 +81,6 @@ typedef struct {
|
||||
|
||||
#define SECT_HDR_SIZE (sizeof(PROPERTYSECTIONHEADER))
|
||||
|
||||
typedef struct tagMSISUMMARYINFO
|
||||
{
|
||||
MSIOBJECTHDR hdr;
|
||||
MSIDATABASE *db;
|
||||
DWORD update_count;
|
||||
PROPVARIANT property[MSI_MAX_PROPS];
|
||||
} MSISUMMARYINFO;
|
||||
|
||||
static const WCHAR szSumInfo[] = { 5 ,'S','u','m','m','a','r','y',
|
||||
'I','n','f','o','r','m','a','t','i','o','n',0 };
|
||||
|
||||
@@ -417,45 +407,19 @@ static UINT save_summary_info( MSISUMMARYINFO * si, IStream *stm )
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase,
|
||||
LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle )
|
||||
MSISUMMARYINFO *MSI_GetSummaryInformationW( MSIDATABASE *db, UINT uiUpdateCount )
|
||||
{
|
||||
UINT ret = ERROR_SUCCESS;
|
||||
IStream *stm = NULL;
|
||||
MSISUMMARYINFO *si;
|
||||
MSIHANDLE handle;
|
||||
MSIDATABASE *db;
|
||||
DWORD grfMode;
|
||||
HRESULT r;
|
||||
|
||||
TRACE("%ld %s %d %p\n", hDatabase, debugstr_w(szDatabase),
|
||||
uiUpdateCount, pHandle);
|
||||
|
||||
if( !pHandle )
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if( szDatabase )
|
||||
{
|
||||
UINT res;
|
||||
|
||||
res = MSI_OpenDatabaseW(szDatabase, NULL, &db);
|
||||
if( res != ERROR_SUCCESS )
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
db = msihandle2msiinfo(hDatabase, MSIHANDLETYPE_DATABASE);
|
||||
if( !db )
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
TRACE("%p %d\n", db, uiUpdateCount );
|
||||
|
||||
si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO,
|
||||
sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo );
|
||||
if( !si )
|
||||
{
|
||||
ret = ERROR_FUNCTION_FAILED;
|
||||
goto end;
|
||||
}
|
||||
return si;
|
||||
|
||||
msiobj_addref( &db->hdr );
|
||||
si->db = db;
|
||||
@@ -471,14 +435,44 @@ UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase,
|
||||
IStream_Release( stm );
|
||||
}
|
||||
|
||||
handle = alloc_msihandle( &si->hdr );
|
||||
if( handle )
|
||||
*pHandle = handle;
|
||||
else
|
||||
ret = ERROR_FUNCTION_FAILED;
|
||||
msiobj_release( &si->hdr );
|
||||
return si;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase,
|
||||
LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle )
|
||||
{
|
||||
MSISUMMARYINFO *si;
|
||||
MSIDATABASE *db;
|
||||
UINT ret = ERROR_FUNCTION_FAILED;
|
||||
|
||||
TRACE("%ld %s %d %p\n", hDatabase, debugstr_w(szDatabase),
|
||||
uiUpdateCount, pHandle);
|
||||
|
||||
if( !pHandle )
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if( szDatabase )
|
||||
{
|
||||
ret = MSI_OpenDatabaseW( szDatabase, NULL, &db );
|
||||
if( ret != ERROR_SUCCESS )
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE );
|
||||
if( !db )
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
si = MSI_GetSummaryInformationW( db, uiUpdateCount );
|
||||
if (si)
|
||||
{
|
||||
*pHandle = alloc_msihandle( &si->hdr );
|
||||
if( *pHandle )
|
||||
ret = ERROR_SUCCESS;
|
||||
msiobj_release( &si->hdr );
|
||||
}
|
||||
|
||||
end:
|
||||
if( db )
|
||||
msiobj_release( &db->hdr );
|
||||
|
||||
@@ -539,6 +533,12 @@ static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType,
|
||||
if( !si )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
if ( uiProperty >= MSI_MAX_PROPS )
|
||||
{
|
||||
*puiDataType = VT_EMPTY;
|
||||
return ret;
|
||||
}
|
||||
|
||||
prop = &si->property[uiProperty];
|
||||
|
||||
if( puiDataType )
|
||||
@@ -590,6 +590,18 @@ static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType,
|
||||
return ret;
|
||||
}
|
||||
|
||||
LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty )
|
||||
{
|
||||
PROPVARIANT *prop;
|
||||
|
||||
if ( uiProperty >= MSI_MAX_PROPS )
|
||||
return NULL;
|
||||
prop = &si->property[uiProperty];
|
||||
if( prop->vt != VT_LPSTR )
|
||||
return NULL;
|
||||
return strdupAtoW( prop->u.pszVal );
|
||||
}
|
||||
|
||||
UINT WINAPI MsiSummaryInfoGetPropertyA(
|
||||
MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue,
|
||||
FILETIME *pftValue, LPSTR szValueBuf, DWORD *pcchValueBuf)
|
||||
|
||||
+423
-96
@@ -37,7 +37,7 @@
|
||||
|
||||
#include "query.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||
|
||||
typedef struct tagMSICOLUMNINFO
|
||||
{
|
||||
@@ -56,6 +56,11 @@ struct tagMSITABLE
|
||||
WCHAR name[1];
|
||||
};
|
||||
|
||||
typedef struct tagMSITRANSFORM {
|
||||
struct list entry;
|
||||
IStorage *stg;
|
||||
} MSITRANSFORM;
|
||||
|
||||
#define MAX_STREAM_NAME 0x1f
|
||||
|
||||
static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name,
|
||||
@@ -276,14 +281,23 @@ UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm )
|
||||
|
||||
r = IStorage_OpenStream(db->storage, encname, NULL,
|
||||
STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm);
|
||||
msi_free( encname );
|
||||
if( FAILED( r ) )
|
||||
{
|
||||
WARN("open stream failed r = %08lx - empty table?\n",r);
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
MSITRANSFORM *transform;
|
||||
|
||||
LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry )
|
||||
{
|
||||
TRACE("looking for %s in transform storage\n", debugstr_w(stname) );
|
||||
r = IStorage_OpenStream( transform->stg, encname, NULL,
|
||||
STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
|
||||
if (SUCCEEDED(r))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
msi_free( encname );
|
||||
|
||||
return SUCCEEDED(r) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname,
|
||||
@@ -1050,7 +1064,7 @@ static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
/* TRACE("Data [%d][%d] = %d \n", row, col, *val ); */
|
||||
/* TRACE("Data [%d][%d] = %d\n", row, col, *val ); */
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
@@ -1246,113 +1260,44 @@ static UINT TABLE_get_column_info( struct tagMSIVIEW *view,
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT table_find_in_column( MSITABLEVIEW *tv, UINT col, UINT val, UINT *row )
|
||||
{
|
||||
UINT i, r, x;
|
||||
|
||||
for( i=0; i<tv->table->row_count; i++ )
|
||||
{
|
||||
r = TABLE_fetch_int( (struct tagMSIVIEW*) tv, i, col, &x );
|
||||
if ( r != ERROR_SUCCESS )
|
||||
{
|
||||
ERR("TABLE_fetch_int shouldn't fail here\n");
|
||||
break;
|
||||
}
|
||||
if ( x == val )
|
||||
{
|
||||
*row = i;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row );
|
||||
|
||||
static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec )
|
||||
{
|
||||
LPCWSTR str;
|
||||
UINT i, val, r, row;
|
||||
BOOL has_key = FALSE;
|
||||
UINT r, row;
|
||||
|
||||
/* FIXME: set the MsiViewGetError value */
|
||||
|
||||
for( i = 0; i<tv->num_cols; i++ )
|
||||
{
|
||||
/* check for duplicate keys */
|
||||
if( !( tv->columns[i].type & MSITYPE_KEY ) )
|
||||
continue;
|
||||
|
||||
has_key = TRUE;
|
||||
|
||||
TRACE("column %d (%s.%s)is a key\n", i,
|
||||
debugstr_w(tv->columns[i].tablename),
|
||||
debugstr_w(tv->columns[i].colname) );
|
||||
|
||||
val = 0;
|
||||
if( tv->columns[i].type & MSITYPE_STRING )
|
||||
{
|
||||
/* keys can't be null */
|
||||
str = MSI_RecordGetString( rec, i+1 );
|
||||
if( !str )
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
/* if the string doesn't exist in the string table yet, it's OK */
|
||||
r = msi_string2idW( tv->db->strings, str, &val );
|
||||
if( ERROR_SUCCESS != r )
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
val = MSI_RecordGetInteger( rec, i+1 );
|
||||
val ^= 0x8000;
|
||||
}
|
||||
|
||||
/* if we find the same value in the table, it's a duplicate */
|
||||
row = 0;
|
||||
r = table_find_in_column( tv, i+1, val, &row );
|
||||
if( ERROR_SUCCESS != r )
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
TRACE("found in row %d\n", row );
|
||||
}
|
||||
|
||||
if (has_key)
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
r = msi_table_find_row( tv, rec, &row );
|
||||
if (r != ERROR_SUCCESS)
|
||||
return ERROR_SUCCESS;
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec )
|
||||
static UINT msi_table_modify_row( MSITABLEVIEW *tv, MSIRECORD *rec,
|
||||
UINT row, UINT mask )
|
||||
{
|
||||
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
|
||||
UINT n, type, val, r, row, col_count = 0;
|
||||
UINT i, val, r = ERROR_SUCCESS;
|
||||
|
||||
r = TABLE_get_dimensions( view, NULL, &col_count );
|
||||
if( r )
|
||||
return r;
|
||||
TRACE("%p %p %u %08x\n", tv, rec, row, mask );
|
||||
|
||||
row = -1;
|
||||
r = table_create_new_row( view, &row );
|
||||
TRACE("insert_row returned %08x\n", r);
|
||||
if( r )
|
||||
return r;
|
||||
|
||||
for( n = 1; n <= col_count; n++ )
|
||||
for( i = 0; i < tv->num_cols; i++ )
|
||||
{
|
||||
r = TABLE_get_column_info( view, n, NULL, &type );
|
||||
if( r )
|
||||
break;
|
||||
/* set keys or values specified in the mask */
|
||||
if( (~tv->columns[i].type & MSITYPE_KEY) && (~mask & (1<<i)) )
|
||||
continue;
|
||||
|
||||
if( type & MSITYPE_STRING )
|
||||
if( (tv->columns[i].type & MSITYPE_STRING) &&
|
||||
! MSITYPE_IS_BINARY(tv->columns[i].type) )
|
||||
{
|
||||
const WCHAR *str = MSI_RecordGetString( rec, n );
|
||||
const WCHAR *str = MSI_RecordGetString( rec, i+1 );
|
||||
val = msi_addstringW( tv->db->strings, 0, str, -1, 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
val = MSI_RecordGetInteger( rec, n );
|
||||
val ^= 0x8000;
|
||||
val = MSI_RecordGetInteger( rec, i+1 );
|
||||
if ( 2 == bytes_per_column( &tv->columns[i] ) )
|
||||
val ^= 0x8000;
|
||||
}
|
||||
r = TABLE_set_int( view, row, n, val );
|
||||
r = TABLE_set_int( &tv->view, row, i+1, val );
|
||||
if( r )
|
||||
break;
|
||||
}
|
||||
@@ -1360,6 +1305,21 @@ static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec )
|
||||
return r;
|
||||
}
|
||||
|
||||
static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec )
|
||||
{
|
||||
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
|
||||
UINT r, row = -1;
|
||||
|
||||
TRACE("%p %p\n", tv, rec );
|
||||
|
||||
r = table_create_new_row( view, &row );
|
||||
TRACE("insert_row returned %08x\n", r);
|
||||
if( r != ERROR_SUCCESS )
|
||||
return r;
|
||||
|
||||
return msi_table_modify_row( tv, rec, row, ~0 );
|
||||
}
|
||||
|
||||
static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
|
||||
MSIRECORD *rec)
|
||||
{
|
||||
@@ -1532,3 +1492,370 @@ UINT MSI_CommitTables( MSIDATABASE *db )
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static MSIRECORD *msi_get_transform_record( MSITABLEVIEW *tv, string_table *st, USHORT *rawdata )
|
||||
{
|
||||
UINT i, val, ofs = 0;
|
||||
USHORT mask = *rawdata++;
|
||||
MSICOLUMNINFO *columns = tv->columns;
|
||||
MSIRECORD *rec;
|
||||
const int debug_transform = 0;
|
||||
|
||||
rec = MSI_CreateRecord( tv->num_cols );
|
||||
if( !rec )
|
||||
return rec;
|
||||
|
||||
if( debug_transform ) MESSAGE("row -> ");
|
||||
for( i=0; i<tv->num_cols; i++ )
|
||||
{
|
||||
UINT n = bytes_per_column( &columns[i] );
|
||||
|
||||
if ( (mask&1) && (i>=(mask>>8)) )
|
||||
break;
|
||||
/* all keys must be present */
|
||||
if ( (~mask&1) && (~columns[i].type & MSITYPE_KEY) && ((1<<i) & ~mask) )
|
||||
continue;
|
||||
|
||||
switch( n )
|
||||
{
|
||||
case 2:
|
||||
val = rawdata[ofs];
|
||||
if( (columns[i].type & MSITYPE_STRING) &&
|
||||
! MSITYPE_IS_BINARY(tv->columns[i].type) )
|
||||
{
|
||||
LPCWSTR sval = msi_string_lookup_id( st, val );
|
||||
MSI_RecordSetStringW( rec, i+1, sval );
|
||||
if( debug_transform ) MESSAGE("[%s]", debugstr_w(sval));
|
||||
}
|
||||
else
|
||||
{
|
||||
val ^= 0x8000;
|
||||
MSI_RecordSetInteger( rec, i+1, val );
|
||||
if( debug_transform) MESSAGE("[0x%04x]", val );
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
val = rawdata[ofs] + (rawdata[ofs + 1]<<16);
|
||||
/* val ^= 0x80000000; */
|
||||
MSI_RecordSetInteger( rec, i+1, val );
|
||||
if( debug_transform ) MESSAGE("[0x%08x]", val );
|
||||
break;
|
||||
default:
|
||||
ERR("oops - unknown column width %d\n", n);
|
||||
break;
|
||||
}
|
||||
ofs += n/2;
|
||||
}
|
||||
if( debug_transform) MESSAGE("\n");
|
||||
return rec;
|
||||
}
|
||||
|
||||
static void dump_record( MSIRECORD *rec )
|
||||
{
|
||||
UINT i, n;
|
||||
|
||||
MESSAGE("row -> ");
|
||||
n = MSI_RecordGetFieldCount( rec );
|
||||
for( i=1; i<=n; i++ )
|
||||
{
|
||||
LPCWSTR sval = MSI_RecordGetString( rec, i );
|
||||
|
||||
if( MSI_RecordIsNull( rec, i ) )
|
||||
MESSAGE("[]");
|
||||
else if( (sval = MSI_RecordGetString( rec, i )) )
|
||||
MESSAGE("[%s]", debugstr_w(sval));
|
||||
else
|
||||
MESSAGE("[0x%08x]", MSI_RecordGetInteger( rec, i ) );
|
||||
}
|
||||
MESSAGE("\n");
|
||||
}
|
||||
|
||||
static void dump_table( string_table *st, USHORT *rawdata, UINT rawsize )
|
||||
{
|
||||
LPCWSTR sval;
|
||||
UINT i;
|
||||
|
||||
for( i=0; i<(rawsize/2); i++ )
|
||||
{
|
||||
sval = msi_string_lookup_id( st, rawdata[i] );
|
||||
if( !sval ) sval = (WCHAR[]) {0};
|
||||
MESSAGE(" %04x %s\n", rawdata[i], debugstr_w(sval) );
|
||||
}
|
||||
}
|
||||
|
||||
static UINT* msi_record_to_row( MSITABLEVIEW *tv, MSIRECORD *rec )
|
||||
{
|
||||
LPCWSTR str;
|
||||
UINT i, r, *data;
|
||||
|
||||
data = msi_alloc( tv->num_cols *sizeof (UINT) );
|
||||
for( i=0; i<tv->num_cols; i++ )
|
||||
{
|
||||
data[i] = 0;
|
||||
|
||||
if ( ~tv->columns[i].type & MSITYPE_KEY )
|
||||
continue;
|
||||
|
||||
/* turn the transform column value into a row value */
|
||||
if ( ( tv->columns[i].type & MSITYPE_STRING ) &&
|
||||
! MSITYPE_IS_BINARY(tv->columns[i].type) )
|
||||
{
|
||||
str = MSI_RecordGetString( rec, i+1 );
|
||||
r = msi_string2idW( tv->db->strings, str, &data[i] );
|
||||
|
||||
/* if there's no matching string in the string table,
|
||||
these keys can't match any record, so fail now. */
|
||||
if( ERROR_SUCCESS != r )
|
||||
{
|
||||
msi_free( data );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
data[i] = MSI_RecordGetInteger( rec, i+1 );
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static UINT msi_row_matches( MSITABLEVIEW *tv, UINT row, UINT *data )
|
||||
{
|
||||
UINT i, r, x, ret = ERROR_FUNCTION_FAILED;
|
||||
|
||||
for( i=0; i<tv->num_cols; i++ )
|
||||
{
|
||||
if ( ~tv->columns[i].type & MSITYPE_KEY )
|
||||
continue;
|
||||
|
||||
/* turn the transform column value into a row value */
|
||||
r = TABLE_fetch_int( &tv->view, row, i+1, &x );
|
||||
if ( r != ERROR_SUCCESS )
|
||||
{
|
||||
ERR("TABLE_fetch_int shouldn't fail here\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* if this key matches, move to the next column */
|
||||
if ( x != data[i] )
|
||||
{
|
||||
ret = ERROR_FUNCTION_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row )
|
||||
{
|
||||
UINT i, r = ERROR_FUNCTION_FAILED, *data;
|
||||
|
||||
data = msi_record_to_row( tv, rec );
|
||||
if( !data )
|
||||
return r;
|
||||
for( i=0; i<tv->table->row_count; i++ )
|
||||
{
|
||||
r = msi_row_matches( tv, i, data );
|
||||
if( r == ERROR_SUCCESS )
|
||||
{
|
||||
*row = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
msi_free( data );
|
||||
return r;
|
||||
}
|
||||
|
||||
static UINT msi_delete_row( MSITABLEVIEW *tv, UINT row )
|
||||
{
|
||||
UINT i;
|
||||
for( i=1; i<=tv->num_cols; i++ )
|
||||
tv->view.ops->set_int( &tv->view, row, i, 0 );
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT msi_table_load_transform( MSIDATABASE *db, IStorage *stg,
|
||||
string_table *st, LPCWSTR name )
|
||||
{
|
||||
UINT rawsize = 0;
|
||||
USHORT *rawdata = NULL;
|
||||
MSITABLEVIEW *tv = NULL;
|
||||
UINT r, n, sz, i, mask;
|
||||
MSIRECORD *rec = NULL;
|
||||
const int debug_transform = 0;
|
||||
|
||||
TRACE("%p %p %p %s\n", db, stg, st, debugstr_w(name) );
|
||||
|
||||
/* create a table view */
|
||||
r = TABLE_CreateView( db, name, (MSIVIEW**) &tv );
|
||||
if( r != ERROR_SUCCESS )
|
||||
goto err;
|
||||
|
||||
r = tv->view.ops->execute( &tv->view, NULL );
|
||||
if( r != ERROR_SUCCESS )
|
||||
goto err;
|
||||
|
||||
/* read the transform data */
|
||||
r = ERROR_FUNCTION_FAILED;
|
||||
read_stream_data( stg, name, &rawdata, &rawsize );
|
||||
if( !rawdata || (rawsize < 2) )
|
||||
{
|
||||
ERR("odd sized transform for table %s\n", debugstr_w(name));
|
||||
goto err;
|
||||
}
|
||||
|
||||
TRACE("name = %s columns = %u row_size = %u raw size = %u\n",
|
||||
debugstr_w(name), tv->num_cols, tv->row_size, rawsize );
|
||||
|
||||
/* interpret the data */
|
||||
r = ERROR_SUCCESS;
|
||||
for( n=0; n < (rawsize/2); )
|
||||
{
|
||||
mask = rawdata[n];
|
||||
|
||||
if (mask&1)
|
||||
{
|
||||
/*
|
||||
* if the low bit is set, columns are continuous and
|
||||
* the number of columns is specified in the high byte
|
||||
*/
|
||||
sz = 2 + tv->row_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If the low bit is not set, rowdata[n] is a bitmask.
|
||||
* Excepting for key fields, which are always present,
|
||||
* each bit indicates that a field is present in the transform record.
|
||||
*
|
||||
* rawdata[n] == 0 is a special case ... only the keys will be present
|
||||
* and it means that this row should be deleted.
|
||||
*/
|
||||
sz = 2;
|
||||
for( i=0; i<tv->num_cols; i++ )
|
||||
{
|
||||
if( (tv->columns[i].type & MSITYPE_KEY) || ((1<<i)&mask))
|
||||
sz += bytes_per_column( &tv->columns[i] );
|
||||
}
|
||||
}
|
||||
|
||||
/* check we didn't run of the end of the table */
|
||||
if ( (n+sz) > rawsize )
|
||||
{
|
||||
ERR("borked.\n");
|
||||
dump_table( st, rawdata, rawsize );
|
||||
break;
|
||||
}
|
||||
|
||||
rec = msi_get_transform_record( tv, st, &rawdata[n] );
|
||||
if (rec)
|
||||
{
|
||||
UINT row = 0;
|
||||
|
||||
r = msi_table_find_row( tv, rec, &row );
|
||||
|
||||
if( rawdata[n] & 1)
|
||||
{
|
||||
if( debug_transform ) MESSAGE("insert [%d]: ", row);
|
||||
TABLE_insert_row( &tv->view, rec );
|
||||
}
|
||||
else if( mask & 0xff )
|
||||
{
|
||||
if( debug_transform ) MESSAGE("modify [%d]: ", row);
|
||||
msi_table_modify_row( tv, rec, row, mask );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( debug_transform ) MESSAGE("delete [%d]: ", row);
|
||||
msi_delete_row( tv, row );
|
||||
}
|
||||
if( debug_transform ) dump_record( rec );
|
||||
msiobj_release( &rec->hdr );
|
||||
}
|
||||
|
||||
n += sz/2;
|
||||
|
||||
}
|
||||
|
||||
err:
|
||||
/* no need to free the table, it's associated with the database */
|
||||
msi_free( rawdata );
|
||||
if( tv )
|
||||
tv->view.ops->delete( &tv->view );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* msi_table_apply_transform
|
||||
*
|
||||
* Enumerate the table transforms in a transform storage and apply each one.
|
||||
*/
|
||||
UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg )
|
||||
{
|
||||
IEnumSTATSTG *stgenum = NULL;
|
||||
HRESULT r;
|
||||
STATSTG stat;
|
||||
ULONG n, count;
|
||||
WCHAR name[0x40];
|
||||
string_table *strings;
|
||||
UINT ret = ERROR_FUNCTION_FAILED;
|
||||
|
||||
TRACE("%p %p\n", db, stg );
|
||||
|
||||
strings = load_string_table( stg );
|
||||
if( !strings )
|
||||
goto end;
|
||||
|
||||
r = IStorage_EnumElements( stg, 0, NULL, 0, &stgenum );
|
||||
if( FAILED( r ) )
|
||||
goto end;
|
||||
|
||||
n = 0;
|
||||
ret = ERROR_SUCCESS;
|
||||
|
||||
while( r == ERROR_SUCCESS )
|
||||
{
|
||||
count = 0;
|
||||
r = IEnumSTATSTG_Next( stgenum, 1, &stat, &count );
|
||||
if( FAILED( r ) || !count )
|
||||
break;
|
||||
decode_streamname( stat.pwcsName, name );
|
||||
if( ( name[0] == 0x4840 ) && ( name[1] != '_' ) )
|
||||
ret = msi_table_load_transform( db, stg, strings, name+1 );
|
||||
else
|
||||
TRACE("transform contains stream %s\n", debugstr_w(name));
|
||||
n++;
|
||||
}
|
||||
|
||||
if ( ret == ERROR_SUCCESS )
|
||||
{
|
||||
MSITRANSFORM *t;
|
||||
|
||||
t = msi_alloc( sizeof *t );
|
||||
t->stg = stg;
|
||||
IStorage_AddRef( stg );
|
||||
list_add_tail( &db->transforms, &t->entry );
|
||||
}
|
||||
|
||||
end:
|
||||
if ( stgenum )
|
||||
IEnumSTATSTG_Release( stgenum );
|
||||
if ( strings )
|
||||
msi_destroy_stringtable( strings );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void msi_free_transforms( MSIDATABASE *db )
|
||||
{
|
||||
while( !list_empty( &db->transforms ) )
|
||||
{
|
||||
MSITRANSFORM *t = LIST_ENTRY( list_head( &db->transforms ),
|
||||
MSITRANSFORM, entry );
|
||||
list_remove( &t->entry );
|
||||
IStorage_Release( t->stg );
|
||||
msi_free( t );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
#include "query.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||
|
||||
|
||||
/* below is the query interface to a table */
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
#include "query.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||
|
||||
|
||||
/* below is the query interface to a table */
|
||||
|
||||
@@ -31,6 +31,7 @@ typedef unsigned long MSIHANDLE;
|
||||
|
||||
typedef enum tagINSTALLSTATE
|
||||
{
|
||||
INSTALLSTATE_NOTUSED = -7,
|
||||
INSTALLSTATE_BADCONFIG = -6,
|
||||
INSTALLSTATE_INCOMPLETE = -5,
|
||||
INSTALLSTATE_SOURCEABSENT = -4,
|
||||
@@ -136,12 +137,33 @@ typedef enum tagINSTALLLOGATTRIBUTES
|
||||
INSTALLLOGATTRIBUTES_FLUSHEACHLINE = 0x00000002
|
||||
} INSTALLLOGATTRIBUTES;
|
||||
|
||||
typedef enum tagINSTALLMODE
|
||||
{
|
||||
INSTALLMODE_NODETECTION_ANY = -4,
|
||||
INSTALLMODE_NOSOURCERESOLUTION = -3,
|
||||
INSTALLMODE_NODETECTION = -2,
|
||||
INSTALLMODE_EXISTING = -1,
|
||||
INSTALLMODE_DEFAULT = 0
|
||||
} INSTALLMODE;
|
||||
|
||||
typedef enum tagADVERTISEFLAGS
|
||||
{
|
||||
ADVERTISEFLAGS_MACHINEASSIGN = 0,
|
||||
ADVERTISEFLAGS_USERASSIGN = 1
|
||||
} ADVERTISEFLAGS;
|
||||
|
||||
typedef enum tagSCRIPTFLAGS
|
||||
{
|
||||
SCRIPTFLAGS_CACHEINFO = 1,
|
||||
SCRIPTFLAGS_SHORTCUTS = 4,
|
||||
SCRIPTFLAGS_MACHINEASSIGN = 8,
|
||||
SCRIPTFLAGS_REGDATA_APPINFO = 0x10,
|
||||
SCRIPTFLAGS_REGDATA_CNFGINFO = 0x20,
|
||||
SCRIPTFLAGS_VALIDATE_TRANSFORMS_LIST = 0x40,
|
||||
SCRIPTFLAGS_REGDATA_CLASSINFO = 0x80,
|
||||
SCRIPTFLAGS_REGDATA_EXTENSIONINFO = 0x100,
|
||||
} SCRIPTFLAGS;
|
||||
|
||||
typedef enum tagINSTALLTYPE
|
||||
{
|
||||
INSTALLTYPE_DEFAULT = 0,
|
||||
@@ -173,6 +195,11 @@ typedef enum tagMSICODE
|
||||
MSICODE_PATCH = 0x40000000L
|
||||
} MSICODE;
|
||||
|
||||
typedef struct _MSIFILEHASHINFO {
|
||||
ULONG dwFileHashInfoSize;
|
||||
ULONG dwData[4];
|
||||
} MSIFILEHASHINFO, *PMSIFILEHASHINFO;
|
||||
|
||||
#define MAX_FEATURE_CHARS 38
|
||||
|
||||
/* Strings defined in msi.h */
|
||||
@@ -409,6 +436,10 @@ UINT WINAPI MsiConfigureProductExA(LPCSTR, int, INSTALLSTATE, LPCSTR);
|
||||
UINT WINAPI MsiConfigureProductExW(LPCWSTR, int, INSTALLSTATE, LPCWSTR);
|
||||
#define MsiConfigureProductEx WINELIB_NAME_AW(MsiConfigureProductEx);
|
||||
|
||||
UINT WINAPI MsiConfigureFeatureA(LPCSTR, LPCSTR, INSTALLSTATE);
|
||||
UINT WINAPI MsiConfigureFeatureW(LPCWSTR, LPCWSTR, INSTALLSTATE);
|
||||
#define MsiConfigureFeature WINELIB_NAME_AW(MsiConfigureFeature);
|
||||
|
||||
UINT WINAPI MsiGetProductCodeA(LPCSTR, LPSTR);
|
||||
UINT WINAPI MsiGetProductCodeW(LPCWSTR, LPWSTR);
|
||||
#define MsiGetProductCode WINELIB_NAME_AW(MsiGetProductCode)
|
||||
@@ -445,8 +476,8 @@ UINT WINAPI MsiProvideAssemblyA(LPCSTR, LPCSTR, DWORD, DWORD, LPSTR, DWORD*);
|
||||
UINT WINAPI MsiProvideAssemblyW(LPCWSTR, LPCWSTR, DWORD, DWORD, LPWSTR, DWORD*);
|
||||
#define MsiProvideAssembly WINELIB_NAME_AW(MsiProvideAssembly)
|
||||
|
||||
UINT WINAPI MsiEnumComponentQualifiersA(LPSTR, DWORD, LPSTR, DWORD*, LPSTR, DWORD*);
|
||||
UINT WINAPI MsiEnumComponentQualifiersW(LPWSTR, DWORD, LPWSTR, DWORD*, LPWSTR, DWORD*);
|
||||
UINT WINAPI MsiEnumComponentQualifiersA(LPCSTR, DWORD, LPSTR, DWORD*, LPSTR, DWORD*);
|
||||
UINT WINAPI MsiEnumComponentQualifiersW(LPCWSTR, DWORD, LPWSTR, DWORD*, LPWSTR, DWORD*);
|
||||
#define MsiEnumComponentQualifiers WINELIB_NAME_AW(MsiEnumComponentQualifiers)
|
||||
|
||||
UINT WINAPI MsiGetFileVersionA(LPCSTR, LPSTR, DWORD*, LPSTR, DWORD*);
|
||||
@@ -513,6 +544,18 @@ UINT WINAPI MsiSourceListAddMediaDiskA(LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD,
|
||||
UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR, LPCWSTR, MSIINSTALLCONTEXT, DWORD, DWORD, LPCWSTR, LPCWSTR);
|
||||
#define MsiSourceListAddMediaDisk WINELIB_NAME_AW(MsiSourceListAddMediaDisk)
|
||||
|
||||
UINT WINAPI MsiEnumPatchesA(LPCSTR, DWORD, LPSTR, LPSTR, DWORD*);
|
||||
UINT WINAPI MsiEnumPatchesW(LPCWSTR, DWORD, LPWSTR, LPWSTR, DWORD*);
|
||||
#define MsiEnumPatches WINELIB_NAME_AW(MsiEnumPatches)
|
||||
|
||||
UINT WINAPI MsiGetFileHashA(LPCSTR, DWORD, PMSIFILEHASHINFO);
|
||||
UINT WINAPI MsiGetFileHashW(LPCWSTR, DWORD, PMSIFILEHASHINFO);
|
||||
#define MsiGetFileHash WINELIB_NAME_AW(MsiGetFileHash)
|
||||
|
||||
UINT WINAPI MsiAdvertiseScriptA(LPCSTR, DWORD, PHKEY, BOOL);
|
||||
UINT WINAPI MsiAdvertiseScriptW(LPCWSTR, DWORD, PHKEY, BOOL);
|
||||
#define MsiAdvertiseScript WINELIB_NAME_AW(MsiAdvertiseScript)
|
||||
|
||||
/* Non Unicode */
|
||||
UINT WINAPI MsiCloseHandle(MSIHANDLE);
|
||||
UINT WINAPI MsiCloseAllHandles(void);
|
||||
|
||||
@@ -53,11 +53,19 @@ typedef enum tagMSIMODIFY
|
||||
MSIMODIFY_VALIDATE_DELETE = 11
|
||||
} MSIMODIFY;
|
||||
|
||||
#ifndef __WINESRC__
|
||||
#define MSIDBOPEN_READONLY (LPCTSTR)0
|
||||
#define MSIDBOPEN_TRANSACT (LPCTSTR)1
|
||||
#define MSIDBOPEN_DIRECT (LPCTSTR)2
|
||||
#define MSIDBOPEN_CREATE (LPCTSTR)3
|
||||
#define MSIDBOPEN_CREATEDIRECT (LPCTSTR)4
|
||||
#else
|
||||
#define MSIDBOPEN_READONLY (LPCWSTR)0
|
||||
#define MSIDBOPEN_TRANSACT (LPCWSTR)1
|
||||
#define MSIDBOPEN_DIRECT (LPCWSTR)2
|
||||
#define MSIDBOPEN_CREATE (LPCWSTR)3
|
||||
#define MSIDBOPEN_CREATEDIRECT (LPCWSTR)4
|
||||
#endif
|
||||
|
||||
typedef enum tagMSIRUNMODE
|
||||
{
|
||||
@@ -261,6 +269,7 @@ UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE,UINT*);
|
||||
|
||||
UINT WINAPI MsiEnableUIPreview(MSIHANDLE, MSIHANDLE*);
|
||||
BOOL WINAPI MsiGetMode(MSIHANDLE, MSIRUNMODE);
|
||||
BOOL WINAPI MsiSetMode(MSIHANDLE, MSIRUNMODE, BOOL);
|
||||
|
||||
UINT WINAPI MsiViewModify(MSIHANDLE, MSIMODIFY, MSIHANDLE);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user