*/
static const WCHAR c_colon[] = {'C',':','\\',0};
-const static WCHAR szCreateFolders[] =
+static const WCHAR szCreateFolders[] =
{'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
-const static WCHAR szCostFinalize[] =
+static const WCHAR szCostFinalize[] =
{'C','o','s','t','F','i','n','a','l','i','z','e',0};
const WCHAR szInstallFiles[] =
{'I','n','s','t','a','l','l','F','i','l','e','s',0};
const WCHAR szDuplicateFiles[] =
{'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
-const static WCHAR szWriteRegistryValues[] =
+static const WCHAR szWriteRegistryValues[] =
{'W','r','i','t','e','R','e','g','i','s','t','r','y',
'V','a','l','u','e','s',0};
-const static WCHAR szCostInitialize[] =
+static const WCHAR szCostInitialize[] =
{'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
-const static WCHAR szFileCost[] =
+static const WCHAR szFileCost[] =
{'F','i','l','e','C','o','s','t',0};
-const static WCHAR szInstallInitialize[] =
+static const WCHAR szInstallInitialize[] =
{'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
-const static WCHAR szInstallValidate[] =
+static const WCHAR szInstallValidate[] =
{'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
-const static WCHAR szLaunchConditions[] =
+static const WCHAR szLaunchConditions[] =
{'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
-const static WCHAR szProcessComponents[] =
+static const WCHAR szProcessComponents[] =
{'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
-const static WCHAR szRegisterTypeLibraries[] =
+static const WCHAR szRegisterTypeLibraries[] =
{'R','e','g','i','s','t','e','r','T','y','p','e',
'L','i','b','r','a','r','i','e','s',0};
const WCHAR szRegisterClassInfo[] =
{'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
const WCHAR szRegisterProgIdInfo[] =
{'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
-const static WCHAR szCreateShortcuts[] =
+static const WCHAR szCreateShortcuts[] =
{'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
-const static WCHAR szPublishProduct[] =
+static const WCHAR szPublishProduct[] =
{'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
-const static WCHAR szWriteIniValues[] =
+static const WCHAR szWriteIniValues[] =
{'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
-const static WCHAR szSelfRegModules[] =
+static const WCHAR szSelfRegModules[] =
{'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
-const static WCHAR szPublishFeatures[] =
+static const WCHAR szPublishFeatures[] =
{'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
-const static WCHAR szRegisterProduct[] =
+static const WCHAR szRegisterProduct[] =
{'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
-const static WCHAR szInstallExecute[] =
+static const WCHAR szInstallExecute[] =
{'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
-const static WCHAR szInstallExecuteAgain[] =
+static const WCHAR szInstallExecuteAgain[] =
{'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
'A','g','a','i','n',0};
-const static WCHAR szInstallFinalize[] =
+static const WCHAR szInstallFinalize[] =
{'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
-const static WCHAR szForceReboot[] =
+static const WCHAR szForceReboot[] =
{'F','o','r','c','e','R','e','b','o','o','t',0};
-const static WCHAR szResolveSource[] =
+static const WCHAR szResolveSource[] =
{'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
const WCHAR szAppSearch[] =
{'A','p','p','S','e','a','r','c','h',0};
-const static WCHAR szAllocateRegistrySpace[] =
+static const WCHAR szAllocateRegistrySpace[] =
{'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
'S','p','a','c','e',0};
-const static WCHAR szBindImage[] =
+static const WCHAR szBindImage[] =
{'B','i','n','d','I','m','a','g','e',0};
-const static WCHAR szCCPSearch[] =
+static const WCHAR szCCPSearch[] =
{'C','C','P','S','e','a','r','c','h',0};
-const static WCHAR szDeleteServices[] =
+static const WCHAR szDeleteServices[] =
{'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
-const static WCHAR szDisableRollback[] =
+static const WCHAR szDisableRollback[] =
{'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
-const static WCHAR szExecuteAction[] =
+static const WCHAR szExecuteAction[] =
{'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
const WCHAR szFindRelatedProducts[] =
{'F','i','n','d','R','e','l','a','t','e','d',
'P','r','o','d','u','c','t','s',0};
-const static WCHAR szInstallAdminPackage[] =
+static const WCHAR szInstallAdminPackage[] =
{'I','n','s','t','a','l','l','A','d','m','i','n',
'P','a','c','k','a','g','e',0};
-const static WCHAR szInstallSFPCatalogFile[] =
+static const WCHAR szInstallSFPCatalogFile[] =
{'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
'F','i','l','e',0};
-const static WCHAR szIsolateComponents[] =
+static const WCHAR szIsolateComponents[] =
{'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
const WCHAR szMigrateFeatureStates[] =
{'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
'S','t','a','t','e','s',0};
const WCHAR szMoveFiles[] =
{'M','o','v','e','F','i','l','e','s',0};
-const static WCHAR szMsiPublishAssemblies[] =
+static const WCHAR szMsiPublishAssemblies[] =
{'M','s','i','P','u','b','l','i','s','h',
'A','s','s','e','m','b','l','i','e','s',0};
-const static WCHAR szMsiUnpublishAssemblies[] =
+static const WCHAR szMsiUnpublishAssemblies[] =
{'M','s','i','U','n','p','u','b','l','i','s','h',
'A','s','s','e','m','b','l','i','e','s',0};
-const static WCHAR szInstallODBC[] =
+static const WCHAR szInstallODBC[] =
{'I','n','s','t','a','l','l','O','D','B','C',0};
-const static WCHAR szInstallServices[] =
+static const WCHAR szInstallServices[] =
{'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
const WCHAR szPatchFiles[] =
{'P','a','t','c','h','F','i','l','e','s',0};
-const static WCHAR szPublishComponents[] =
+static const WCHAR szPublishComponents[] =
{'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
-const static WCHAR szRegisterComPlus[] =
+static const WCHAR szRegisterComPlus[] =
{'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
const WCHAR szRegisterExtensionInfo[] =
{'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
'I','n','f','o',0};
-const static WCHAR szRegisterFonts[] =
+static const WCHAR szRegisterFonts[] =
{'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
const WCHAR szRegisterMIMEInfo[] =
{'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
-const static WCHAR szRegisterUser[] =
+static const WCHAR szRegisterUser[] =
{'R','e','g','i','s','t','e','r','U','s','e','r',0};
const WCHAR szRemoveDuplicateFiles[] =
{'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
'F','i','l','e','s',0};
-const static WCHAR szRemoveEnvironmentStrings[] =
+static const WCHAR szRemoveEnvironmentStrings[] =
{'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
'S','t','r','i','n','g','s',0};
const WCHAR szRemoveExistingProducts[] =
'P','r','o','d','u','c','t','s',0};
const WCHAR szRemoveFiles[] =
{'R','e','m','o','v','e','F','i','l','e','s',0};
-const static WCHAR szRemoveFolders[] =
+static const WCHAR szRemoveFolders[] =
{'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
-const static WCHAR szRemoveIniValues[] =
+static const WCHAR szRemoveIniValues[] =
{'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
-const static WCHAR szRemoveODBC[] =
+static const WCHAR szRemoveODBC[] =
{'R','e','m','o','v','e','O','D','B','C',0};
-const static WCHAR szRemoveRegistryValues[] =
+static const WCHAR szRemoveRegistryValues[] =
{'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
'V','a','l','u','e','s',0};
-const static WCHAR szRemoveShortcuts[] =
+static const WCHAR szRemoveShortcuts[] =
{'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
-const static WCHAR szRMCCPSearch[] =
+static const WCHAR szRMCCPSearch[] =
{'R','M','C','C','P','S','e','a','r','c','h',0};
-const static WCHAR szScheduleReboot[] =
+static const WCHAR szScheduleReboot[] =
{'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
-const static WCHAR szSelfUnregModules[] =
+static const WCHAR szSelfUnregModules[] =
{'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
-const static WCHAR szSetODBCFolders[] =
+static const WCHAR szSetODBCFolders[] =
{'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
-const static WCHAR szStartServices[] =
+static const WCHAR szStartServices[] =
{'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
-const static WCHAR szStopServices[] =
+static const WCHAR szStopServices[] =
{'S','t','o','p','S','e','r','v','i','c','e','s',0};
-const static WCHAR szUnpublishComponents[] =
+static const WCHAR szUnpublishComponents[] =
{'U','n','p','u','b','l','i','s','h',
'C','o','m','p','o','n','e','n','t','s',0};
-const static WCHAR szUnpublishFeatures[] =
+static const WCHAR szUnpublishFeatures[] =
{'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
const WCHAR szUnregisterClassInfo[] =
{'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
'I','n','f','o',0};
-const static WCHAR szUnregisterComPlus[] =
+static const WCHAR szUnregisterComPlus[] =
{'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
const WCHAR szUnregisterExtensionInfo[] =
{'U','n','r','e','g','i','s','t','e','r',
'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
-const static WCHAR szUnregisterFonts[] =
+static const WCHAR szUnregisterFonts[] =
{'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
const WCHAR szUnregisterMIMEInfo[] =
{'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
const WCHAR szUnregisterProgIdInfo[] =
{'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
'I','n','f','o',0};
-const static WCHAR szUnregisterTypeLibraries[] =
+static const WCHAR szUnregisterTypeLibraries[] =
{'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
'L','i','b','r','a','r','i','e','s',0};
-const static WCHAR szValidateProductID[] =
+static const WCHAR szValidateProductID[] =
{'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
-const static WCHAR szWriteEnvironmentStrings[] =
+static const WCHAR szWriteEnvironmentStrings[] =
{'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
'S','t','r','i','n','g','s',0};
return ERROR_SUCCESS;
}
+
+static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
+{
+ LPWSTR p, *ret = NULL;
+ UINT count = 0;
+
+ if (!str)
+ return ret;
+
+ /* count the number of substrings */
+ for ( p = (LPWSTR)str, count = 0; p; count++ )
+ {
+ p = strchrW( p, sep );
+ if (p)
+ p++;
+ }
+
+ /* allocate space for an array of substring pointers and the substrings */
+ ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
+ (lstrlenW(str)+1) * sizeof(WCHAR) );
+ if (!ret)
+ return ret;
+
+ /* copy the string and set the pointers */
+ p = (LPWSTR) &ret[count+1];
+ lstrcpyW( p, str );
+ for( count = 0; (ret[count] = p); count++ )
+ {
+ p = strchrW( p, sep );
+ if (p)
+ *p++ = 0;
+ }
+
+ return ret;
+}
+
+static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
+ MSIDATABASE *patch_db, LPCWSTR name )
+{
+ UINT ret = ERROR_FUNCTION_FAILED;
+ IStorage *stg = NULL;
+ HRESULT r;
+
+ TRACE("%p %s\n", package, debugstr_w(name) );
+
+ if (*name++ != ':')
+ {
+ ERR("expected a colon in %s\n", debugstr_w(name));
+ return ERROR_FUNCTION_FAILED;
+ }
+
+ r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
+ if (SUCCEEDED(r))
+ {
+ ret = msi_table_apply_transform( package->db, stg );
+ IStorage_Release( stg );
+ ret = ERROR_SUCCESS;
+ }
+ else
+ ERR("failed to open substorage %s\n", debugstr_w(name));
+
+ return ret;
+}
+
+static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
+{
+ static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
+ LPWSTR guid_list, *guids, product_id;
+ UINT i, ret = ERROR_FUNCTION_FAILED;
+
+ product_id = msi_dup_property( package, szProdID );
+ if (!product_id)
+ {
+ /* FIXME: the property ProductID should be written into the DB somewhere */
+ ERR("no product ID to check\n");
+ return ERROR_SUCCESS;
+ }
+
+ guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
+ guids = msi_split_string( guid_list, ';' );
+ for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
+ {
+ if (!lstrcmpW( guids[i], product_id ))
+ ret = ERROR_SUCCESS;
+ }
+ msi_free( guids );
+ msi_free( guid_list );
+ msi_free( product_id );
+
+ return ret;
+}
+
+static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
+{
+ MSISUMMARYINFO *si;
+ LPWSTR str, *substorage;
+ UINT i, r = ERROR_SUCCESS;
+
+ si = MSI_GetSummaryInformationW( patch_db, 0 );
+ if (!si)
+ return ERROR_FUNCTION_FAILED;
+
+ msi_check_patch_applicable( package, si );
+
+ /* enumerate the substorage */
+ str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
+ substorage = msi_split_string( str, ';' );
+ for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
+ r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
+ msi_free( substorage );
+ msi_free( str );
+
+ /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
+
+ msiobj_release( &si->hdr );
+
+ return r;
+}
+
+static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
+{
+ MSIDATABASE *patch_db = NULL;
+ UINT r;
+
+ TRACE("%p %s\n", package, debugstr_w( file ) );
+
+ /* FIXME:
+ * We probably want to make sure we only open a patch collection here.
+ * Patch collections (.msp) and databases (.msi) have different GUIDs
+ * but currently MSI_OpenDatabaseW will accept both.
+ */
+ r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
+ if ( r != ERROR_SUCCESS )
+ {
+ ERR("failed to open patch collection %s\n", debugstr_w( file ) );
+ return r;
+ }
+
+ msi_parse_patch_summary( package, patch_db );
+ msiobj_release( &patch_db->hdr );
+
+ return ERROR_SUCCESS;
+}
+
+/* get the PATCH property, and apply all the patches it specifies */
+static UINT msi_apply_patches( MSIPACKAGE *package )
+{
+ static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
+ LPWSTR patch_list, *patches;
+ UINT i, r = ERROR_SUCCESS;
+
+ patch_list = msi_dup_property( package, szPatch );
+
+ TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
+
+ patches = msi_split_string( patch_list, ';' );
+ for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
+ r = msi_apply_patch_package( package, patches[i] );
+
+ msi_free( patches );
+ msi_free( patch_list );
+
+ return r;
+}
+
/****************************************************
* TOP level entry points
*****************************************************/
msi_parse_command_line( package, szCommandLine );
+ msi_apply_patches( package );
+
if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
{
package->script->InWhatSequence |= SEQUENCE_UI;
rc = ERROR_SUCCESS;
if (rc != ERROR_SUCCESS)
- ERR("Execution halted due to error (%i)\n",rc);
+ ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
return rc;
}
if (rc == ERROR_SUCCESS)
{
- TRACE("Running the actions \n");
+ TRACE("Running the actions\n");
rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
msiobj_release(&view->hdr);
BOOL run = force;
int i;
+ if (!package)
+ {
+ ERR("package was null!\n");
+ return FALSE;
+ }
+
if (!run && !package->script->CurrentlyScripting)
run = TRUE;
dir = MSI_RecordGetString(row,1);
if (!dir)
{
- ERR("Unable to get folder id \n");
+ ERR("Unable to get folder id\n");
return ERROR_SUCCESS;
}
return ERROR_SUCCESS;
}
+/* FIXME: probably should merge this with the above function */
+static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
+{
+ UINT rc = ERROR_SUCCESS;
+ MSIFOLDER *folder;
+ LPWSTR install_path;
+
+ install_path = resolve_folder(package, dir, 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;
+}
+
+UINT msi_create_component_directories( MSIPACKAGE *package )
+{
+ MSICOMPONENT *comp;
+
+ /* create all the folders required by the components are going to install */
+ LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
+ {
+ if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
+ continue;
+ msi_create_directory( package, comp->Directory );
+ }
+
+ return ERROR_SUCCESS;
+}
/*
* Also we cannot enable/disable components either, so for now I am just going
UINT rc;
MSIQUERY *view;
+ /* create all the empty folders specified in the CreateFolder table */
rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
msiobj_release(&view->hdr);
-
+
+ msi_create_component_directories( package );
+
return rc;
}
return comp;
/* fill in the data */
- comp->Component = load_dynamic_stringW( row, 1 );
+ comp->Component = msi_dup_record_field( row, 1 );
TRACE("Loading Component %s\n", debugstr_w(comp->Component));
- comp->ComponentId = load_dynamic_stringW( row, 2 );
- comp->Directory = load_dynamic_stringW( row, 3 );
+ comp->ComponentId = msi_dup_record_field( row, 2 );
+ comp->Directory = msi_dup_record_field( row, 3 );
comp->Attributes = MSI_RecordGetInteger(row,4);
- comp->Condition = load_dynamic_stringW( row, 5 );
- comp->KeyPath = load_dynamic_stringW( row, 6 );
+ comp->Condition = msi_dup_record_field( row, 5 );
+ comp->KeyPath = msi_dup_record_field( row, 6 );
comp->Installed = INSTALLSTATE_ABSENT;
comp->Action = INSTALLSTATE_UNKNOWN;
list_init( &feature->Components );
- feature->Feature = load_dynamic_stringW( row, 1 );
+ feature->Feature = msi_dup_record_field( row, 1 );
TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
- feature->Feature_Parent = load_dynamic_stringW( row, 2 );
- feature->Title = load_dynamic_stringW( row, 3 );
- feature->Description = load_dynamic_stringW( row, 4 );
+ feature->Feature_Parent = msi_dup_record_field( row, 2 );
+ feature->Title = msi_dup_record_field( row, 3 );
+ feature->Description = msi_dup_record_field( row, 4 );
if (!MSI_RecordIsNull(row,5))
feature->Display = MSI_RecordGetInteger(row,5);
feature->Level= MSI_RecordGetInteger(row,6);
- feature->Directory = load_dynamic_stringW( row, 7 );
+ feature->Directory = msi_dup_record_field( row, 7 );
feature->Attributes = MSI_RecordGetInteger(row,8);
feature->Installed = INSTALLSTATE_ABSENT;
if (!file)
return ERROR_NOT_ENOUGH_MEMORY;
- file->File = load_dynamic_stringW( row, 1 );
+ file->File = msi_dup_record_field( row, 1 );
component = MSI_RecordGetString( row, 2 );
file->Component = get_loaded_component( package, component );
if (!file->Component)
ERR("Unfound Component %s\n",debugstr_w(component));
- file->FileName = load_dynamic_stringW( row, 3 );
+ file->FileName = msi_dup_record_field( row, 3 );
reduce_to_longfilename( file->FileName );
- file->ShortName = load_dynamic_stringW( row, 3 );
+ file->ShortName = msi_dup_record_field( row, 3 );
reduce_to_shortfilename( file->ShortName );
file->FileSize = MSI_RecordGetInteger( row, 4 );
- file->Version = load_dynamic_stringW( row, 5 );
- file->Language = load_dynamic_stringW( row, 6 );
+ file->Version = msi_dup_record_field( row, 5 );
+ file->Language = msi_dup_record_field( row, 6 );
file->Attributes = MSI_RecordGetInteger( row, 7 );
file->Sequence = MSI_RecordGetInteger( row, 8 );
- file->State = 0;
+ file->state = msifs_invalid;
TRACE("File Loaded (%s)\n",debugstr_w(file->File));
static const WCHAR szCosting[] =
{'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
static const WCHAR szZero[] = { '0', 0 };
- WCHAR buffer[3];
- DWORD sz = 3;
- MSI_GetPropertyW(package, szCosting, buffer, &sz);
- if (buffer[0]=='1')
+ if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
return ERROR_SUCCESS;
MSI_SetPropertyW(package, szCosting, szZero);
if (!row)
return NULL;
- ptargetdir = targetdir = load_dynamic_stringW(row,3);
+ ptargetdir = targetdir = msi_dup_record_field(row,3);
/* split src and target dir */
if (strchrW(targetdir,':'))
{'A','D','D','L','O','C','A','L',0};
static const WCHAR szRemove[] =
{'R','E','M','O','V','E',0};
+ static const WCHAR szReinstall[] =
+ {'R','E','I','N','S','T','A','L','L',0};
BOOL override = FALSE;
MSICOMPONENT* component;
MSIFEATURE *feature;
*/
override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
+ override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
if (!override)
{
UINT rc;
MSIQUERY * view;
LPWSTR level;
- DWORD sz = 3;
- WCHAR buffer[3];
- MSI_GetPropertyW(package, szCosting, buffer, &sz);
- if (buffer[0]=='1')
+ if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
return ERROR_SUCCESS;
-
+
TRACE("Building Directory properties\n");
rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
{
- file->State = 1;
+ file->state = msifs_missing;
comp->Cost += file->FileSize;
continue;
}
DWORD versize;
UINT sz;
LPVOID version;
- static const WCHAR name[] =
- {'\\',0};
+ static WCHAR name[] = {'\\',0};
static const WCHAR name_fmt[] =
{'%','u','.','%','u','.','%','u','.','%','u',0};
WCHAR filever[0x100];
VS_FIXEDFILEINFO *lpVer;
- TRACE("Version comparison.. \n");
+ TRACE("Version comparison..\n");
versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
version = msi_alloc(versize);
GetFileVersionInfoW(file->TargetPath, 0, versize, version);
debugstr_w(filever));
if (strcmpiW(filever,file->Version)<0)
{
- file->State = 2;
- FIXME("cost should be diff in size\n");
+ file->state = msifs_overwrite;
+ /* FIXME: cost should be diff in size */
comp->Cost += file->FileSize;
}
else
- file->State = 3;
+ file->state = msifs_present;
msi_free(version);
}
else
- file->State = 3;
+ file->state = msifs_present;
}
TRACE("Evaluating Condition Table\n");
if (!comp)
return ERROR_SUCCESS;
- if (!ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_LOCAL))
+ if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
{
TRACE("Skipping write due to disabled component %s\n",
debugstr_w(component));
MSICOMPONENT *comp;
HKEY hkey=0,hkey2=0;
- if (!package)
- return ERROR_INVALID_HANDLE;
-
/* writes the Component and Features values to the registry */
rc = MSIREG_OpenComponents(&hkey);
* Write the keypath out if the component is to be registered
* and delete the key if the component is to be deregistered
*/
- if (ACTION_VerifyComponentForAction(package, comp,
- INSTALLSTATE_LOCAL))
+ if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
{
rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
if (rc != ERROR_SUCCESS)
msiobj_release( &uirow->hdr );
}
}
- else if (ACTION_VerifyComponentForAction(package, comp,
- INSTALLSTATE_ABSENT))
+ else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
{
DWORD res;
if (!comp)
return ERROR_SUCCESS;
- if (!ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_LOCAL))
+ if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
{
TRACE("Skipping typelib reg due to disabled component\n");
return ERROR_SUCCESS;
module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
- if (module != NULL)
+ if (module)
{
- LPWSTR guid;
- guid = load_dynamic_stringW(row,1);
- CLSIDFromString(guid, &tl_struct.clsid);
- msi_free(guid);
+ LPCWSTR guid;
+ guid = MSI_RecordGetString(row,1);
+ CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
tl_struct.source = strdupW( file->TargetPath );
tl_struct.path = NULL;
EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
(LONG_PTR)&tl_struct);
- if (tl_struct.path != NULL)
+ if (tl_struct.path)
{
LPWSTR help = NULL;
LPCWSTR helpid;
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
'`','T','y','p','e','L','i','b','`',0};
- if (!package)
- return ERROR_INVALID_HANDLE;
-
rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
if (!comp)
return ERROR_SUCCESS;
- if (!ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_LOCAL))
+ if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
{
TRACE("Skipping shortcut creation due to disabled component\n");
{'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
'`','S','h','o','r','t','c','u','t','`',0};
- if (!package)
- return ERROR_INVALID_HANDLE;
-
rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
if (rc != ERROR_SUCCESS)
return ERROR_SUCCESS;
DWORD size;
MSIHANDLE hDb, hSumInfo;
- if (!package)
- return ERROR_INVALID_HANDLE;
-
/* write out icon files */
rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
}
else
{
- ERR("Unable to query Revision_Number... \n");
+ ERR("Unable to query Revision_Number...\n");
rc = ERROR_SUCCESS;
}
MsiCloseHandle(hSumInfo);
component = MSI_RecordGetString(row, 8);
comp = get_loaded_component(package,component);
- if (!ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_LOCAL))
+ if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
{
TRACE("Skipping ini file due to disabled component %s\n",
debugstr_w(component));
HKEY hkey=0;
HKEY hukey=0;
- if (!package)
- return ERROR_INVALID_HANDLE;
-
rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
if (rc != ERROR_SUCCESS)
goto end;
return ERROR_SUCCESS;
}
+static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
+{
+ LPWSTR prop, val, key;
+ static const LPCSTR propval[] = {
+ "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
+ "ARPCONTACT", "Contact",
+ "ARPCOMMENTS", "Comments",
+ "ProductName", "DisplayName",
+ "ProductVersion", "DisplayVersion",
+ "ARPHELPLINK", "HelpLink",
+ "ARPHELPTELEPHONE", "HelpTelephone",
+ "ARPINSTALLLOCATION", "InstallLocation",
+ "SourceDir", "InstallSource",
+ "Manufacturer", "Publisher",
+ "ARPREADME", "Readme",
+ "ARPSIZE", "Size",
+ "ARPURLINFOABOUT", "URLInfoAbout",
+ "ARPURLUPDATEINFO", "URLUpdateInfo",
+ NULL,
+ };
+ const LPCSTR *p = propval;
+
+ while( *p )
+ {
+ prop = strdupAtoW( *p++ );
+ key = strdupAtoW( *p++ );
+ val = msi_dup_property( package, prop );
+ msi_reg_set_val_str( hkey, key, val );
+ msi_free(val);
+ msi_free(key);
+ msi_free(prop);
+ }
+ return ERROR_SUCCESS;
+}
+
static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
{
HKEY hkey=0;
LPWSTR buffer = NULL;
- UINT rc,i;
+ UINT rc;
DWORD size, langid;
static const WCHAR szWindowsInstaller[] =
- {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
- static const WCHAR szPropKeys[][80] =
- {
-{'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0},
-{'A','R','P','C','O','N','T','A','C','T',0},
-{'A','R','P','C','O','M','M','E','N','T','S',0},
-{'P','r','o','d','u','c','t','N','a','m','e',0},
-{'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0},
-{'A','R','P','H','E','L','P','L','I','N','K',0},
-{'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0},
-{'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0},
-{'S','o','u','r','c','e','D','i','r',0},
-{'M','a','n','u','f','a','c','t','u','r','e','r',0},
-{'A','R','P','R','E','A','D','M','E',0},
-{'A','R','P','S','I','Z','E',0},
-{'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0},
-{'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0},
-{0},
- };
-
- static const WCHAR szRegKeys[][80] =
- {
-{'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0},
-{'C','o','n','t','a','c','t',0},
-{'C','o','m','m','e','n','t','s',0},
-{'D','i','s','p','l','a','y','N','a','m','e',0},
-{'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0},
-{'H','e','l','p','L','i','n','k',0},
-{'H','e','l','p','T','e','l','e','p','h','o','n','e',0},
-{'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0},
-{'I','n','s','t','a','l','l','S','o','u','r','c','e',0},
-{'P','u','b','l','i','s','h','e','r',0},
-{'R','e','a','d','m','e',0},
-{'S','i','z','e',0},
-{'U','R','L','I','n','f','o','A','b','o','u','t',0},
-{'U','R','L','U','p','d','a','t','e','I','n','f','o',0},
-{0},
- };
+ {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
static const WCHAR szUpgradeCode[] =
{'U','p','g','r','a','d','e','C','o','d','e',0};
static const WCHAR modpath_fmt[] =
- {'M','s','i','E','x','e','c','.','e','x','e',' ','/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
+ {'M','s','i','E','x','e','c','.','e','x','e',' ',
+ '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
static const WCHAR szModifyPath[] =
{'M','o','d','i','f','y','P','a','t','h',0};
static const WCHAR szUninstallString[] =
SYSTEMTIME systime;
static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
LPWSTR upgrade_code;
-
- if (!package)
- return ERROR_INVALID_HANDLE;
+ WCHAR szDate[9];
rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
if (rc != ERROR_SUCCESS)
- goto end;
+ return rc;
/* dump all the info i can grab */
- FIXME("Flesh out more information \n");
+ FIXME("Flesh out more information\n");
- for( i=0; szPropKeys[i][0]; i++ )
- {
- buffer = msi_dup_property( package, szPropKeys[i] );
- msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
- msi_free(buffer);
- }
+ msi_write_uninstall_property_vals( package, hkey );
msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
GetLocalTime(&systime);
- size = 9*sizeof(WCHAR);
- buffer= msi_alloc(size);
- sprintfW(buffer,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
- msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, buffer );
- msi_free(buffer);
+ sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
+ msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
langid = msi_get_property_int( package, szProductLanguage, 0 );
msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
msi_free(upgrade_code);
}
-end:
RegCloseKey(hkey);
return ERROR_SUCCESS;
static UINT ACTION_InstallExecute(MSIPACKAGE *package)
{
- UINT rc;
-
- if (!package)
- return ERROR_INVALID_HANDLE;
-
- rc = execute_script(package,INSTALL_SCRIPT);
-
- return rc;
+ return execute_script(package,INSTALL_SCRIPT);
}
static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
{
UINT rc;
- if (!package)
- return ERROR_INVALID_HANDLE;
-
/* turn off scheduleing */
package->script->CurrentlyScripting= FALSE;
HKEY hkey;
WCHAR squished_pc[100];
- if (!package)
- return ERROR_INVALID_HANDLE;
-
squash_guid(package->ProductCode,squished_pc);
GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
{0},
};
- if (!package)
- return ERROR_INVALID_HANDLE;
-
productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
if (!productid)
return ERROR_SUCCESS;
static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
{
- static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
- static const WCHAR szTwo[] = {'2',0};
UINT rc;
- LPWSTR level;
- level = msi_dup_property( package, szUILevel );
- MSI_SetPropertyW(package,szUILevel,szTwo);
package->script->InWhatSequence |= SEQUENCE_EXEC;
rc = ACTION_ProcessExecSequence(package,FALSE);
- MSI_SetPropertyW(package,szUILevel,level);
- msi_free(level);
return rc;
}
}
/* check to make sure that component is installed */
- if (!ACTION_VerifyComponentForAction(package,
- file->Component, INSTALLSTATE_LOCAL))
+ if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL))
{
TRACE("Skipping: Component not scheduled for install\n");
return ERROR_SUCCESS;
if (MSI_RecordIsNull(row,2))
name = load_ttfname_from( file->TargetPath );
else
- name = load_dynamic_stringW(row,2);
+ name = msi_dup_record_field(row,2);
if (name)
{
component = MSI_RecordGetString(rec,3);
comp = get_loaded_component(package,component);
- if (!ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_LOCAL) &&
- !ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_SOURCE) &&
- !ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_ADVERTISED))
+ if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) &&
+ !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
+ !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
{
TRACE("Skipping: Component %s not scheduled for install\n",
debugstr_w(component));
return ERROR_SUCCESS;
}
+static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
+{
+ TRACE("%p\n", package);
+ return ERROR_SUCCESS;
+}
+
static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
{
static const WCHAR table[] =
}
static struct _actions StandardActions[] = {
- { szAllocateRegistrySpace, NULL},
+ { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
{ szAppSearch, ACTION_AppSearch },
{ szBindImage, ACTION_BindImage },
{ szCCPSearch, NULL},
{ szRemoveDuplicateFiles, NULL},
{ szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
{ szRemoveExistingProducts, NULL},
- { szRemoveFiles, NULL},
+ { szRemoveFiles, ACTION_RemoveFiles},
{ szRemoveFolders, NULL},
{ szRemoveIniValues, ACTION_RemoveIniValues },
{ szRemoveODBC, NULL},
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;
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;
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);
/* 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);
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*);
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 */
}
/* 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,
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);
}
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);
}
/* 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);
if (buf)
{
- static const WCHAR rootW[] = { '\\',0 };
+ static WCHAR rootW[] = { '\\',0 };
UINT versionLen;
LPVOID subBlock = NULL;
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);
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);
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};
sprintfW(progid->IconPath,fmt,FilePath,icon_index);
msi_free(FilePath);
- msi_free(FileName);
}
else
{
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;
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};
sprintfW(cls->IconPath,fmt,FilePath,icon_index);
msi_free(FilePath);
- msi_free(FileName);
}
else
{
}
else
{
- cls->DefInprocHandler32 = load_dynamic_stringW( row, 10);
+ cls->DefInprocHandler32 = msi_dup_record_field( row, 10);
reduce_to_longfilename(cls->DefInprocHandler32);
}
}
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 );
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 );
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);
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)
return rc;
}
-static UINT register_progid_base(MSIPACKAGE* package, MSIPROGID* progid,
- LPWSTR clsid)
+static LPCWSTR get_clsid_of_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;
-
- RegCreateKeyW(HKEY_CLASSES_ROOT,progid->ProgID,&hkey);
-
- 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
+ while (progid)
{
- FIXME("progid (%s) with null classid\n", debugstr_w(progid->ProgID));
+ if (progid->Class)
+ return progid->Class->clsid;
+ progid = progid->Parent;
}
-
- if (progid->IconPath)
- msi_reg_set_subkey_val( hkey, szDefaultIcon, NULL, progid->IconPath );
-
- return ERROR_SUCCESS;
+ return NULL;
}
-static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid,
- LPWSTR clsid)
+static UINT register_progid( MSIPROGID* progid )
{
- UINT rc = ERROR_SUCCESS;
+ 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};
+ HKEY hkey = 0;
+ UINT rc;
- if (progid->Parent == NULL)
- rc = register_progid_base(package, progid, clsid);
- else
+ rc = RegCreateKeyW( HKEY_CLASSES_ROOT, progid->ProgID, &hkey );
+ if (rc == ERROR_SUCCESS)
{
- 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 );
+ LPCWSTR clsid = get_clsid_of_progid( progid );
- /* clsid is same as parent */
- msi_reg_set_subkey_val( hkey, szCLSID, NULL, clsid );
+ if (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 );
RegCloseKey(hkey);
}
+ else
+ ERR("failed to create key %s\n", debugstr_w( progid->ProgID ) );
+
return rc;
}
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;
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 );
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
MSIRECORD *uirow;
MSIMIME *mt;
- if (!package)
- return ERROR_INVALID_HANDLE;
-
load_classes_and_such(package);
LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry )
#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
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 comp_lt_i(INT a, INT b);
-static INT comp_gt_i(INT a, INT b);
-static INT comp_le_i(INT a, INT b);
-static INT comp_ge_i(INT a, INT b);
-static INT comp_eq_i(INT a, INT b);
-static INT comp_ne_i(INT a, INT b);
-static INT comp_bitand(INT a, INT b);
-static INT comp_highcomp(INT a, INT b);
-static INT comp_lowcomp(INT a, INT b);
-
-static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless);
-static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless);
-static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless);
-static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless);
-static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless);
-static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless);
-static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless);
-static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless);
-static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless);
-
-static INT comp_eq_m1(LPWSTR a, INT b);
-static INT comp_ne_m1(LPWSTR a, INT b);
-static INT comp_lt_m1(LPWSTR a, INT b);
-static INT comp_gt_m1(LPWSTR a, INT b);
-static INT comp_le_m1(LPWSTR a, INT b);
-static INT comp_ge_m1(LPWSTR a, INT b);
-
-static INT comp_eq_m2(INT a, LPWSTR b);
-static INT comp_ne_m2(INT a, LPWSTR b);
-static INT comp_lt_m2(INT a, LPWSTR b);
-static INT comp_gt_m2(INT a, LPWSTR b);
-static INT comp_le_m2(INT a, LPWSTR b);
-static INT comp_ge_m2(INT a, LPWSTR b);
+static INT compare_int( INT a, INT operator, INT b );
+static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b );
+
+static INT compare_and_free_strings( LPWSTR a, INT op, LPWSTR b )
+{
+ INT r;
+
+ r = compare_string( a, op, b );
+ msi_free( a );
+ msi_free( b );
+ return r;
+}
+
+static BOOL num_from_prop( LPCWSTR p, INT *val )
+{
+ INT ret = 0, sign = 1;
+
+ 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;
+}
%}
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:
{
$$ = $1;
}
- | boolean_term COND_OR expression
+ | expression COND_OR boolean_term
{
$$ = $1 || $3;
}
- ;
-
-boolean_term:
- boolean_factor
- {
- $$ = $1;
- }
- | boolean_term COND_AND boolean_factor
+ | expression COND_IMP boolean_term
{
- $$ = $1 && $3;
+ $$ = !$1 || $3;
}
- ;
-
-boolean_factor:
- term
+ | expression COND_XOR boolean_term
{
- $$ = $1;
+ $$ = ( $1 || $3 ) && !( $1 && $3 );
}
- | COND_NOT term
+ | expression COND_EQV boolean_term
{
- $$ = ! $2;
+ $$ = ( $1 && $3 ) || ( !$1 && !$3 );
}
;
-
-term:
- value_i
+boolean_term:
+ boolean_factor
{
$$ = $1;
}
- | value_s
- {
- $$ = ($1 && $1[0]) ? MSICONDITION_TRUE : MSICONDITION_FALSE;
- msi_free( $1 );
- }
- | value_i comp_op_i value_i
- {
- $$ = $2( $1, $3 );
- }
- | value_s comp_op_s value_s
- {
- $$ = $2( $1, $3, FALSE );
- msi_free( $1 );
- msi_free( $3 );
- }
- | value_s COND_TILDA comp_op_s value_s
- {
- $$ = $3( $1, $4, TRUE );
- msi_free( $1 );
- msi_free( $4 );
- }
- | value_s comp_op_m1 value_i
- {
- $$ = $2( $1, $3 );
- msi_free( $1 );
- }
- | value_i comp_op_m2 value_s
+ | boolean_term COND_AND boolean_factor
{
- $$ = $2( $1, $3 );
- msi_free( $3 );
- }
- | COND_LPAR expression COND_RPAR
- {
- $$ = $2;
- }
- ;
-
-comp_op_i:
- /* 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;
+ $$ = $1 && $3;
}
;
-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
+boolean_factor:
+ COND_NOT boolean_factor
{
- $$ = comp_le_s;
+ $$ = $2 ? 0 : 1;
}
- | COND_GT COND_EQ
+ | value_i
{
- $$ = comp_ge_s;
+ $$ = $1 ? 1 : 0;
}
- /*string only*/
- | COND_GT COND_LT
+ | value_s
{
- $$ = comp_substring;
+ $$ = ($1 && $1[0]) ? 1 : 0;
}
- | COND_LT COND_LT
+ | value_i operator value_i
{
- $$ = comp_start;
+ $$ = compare_int( $1, $2, $3 );
}
- | COND_GT COND_GT
+ | symbol_s operator value_i
{
- $$ = comp_end;
+ int num;
+ if (num_from_prop( $1, &num ))
+ $$ = compare_int( num, $2, $3 );
+ else
+ $$ = ($2 == COND_NE || $2 == COND_INE );
}
- ;
-
-comp_op_m1:
- /* common functions */
- COND_EQ
+ | value_i operator symbol_s
{
- $$ = comp_eq_m1;
+ int num;
+ if (num_from_prop( $3, &num ))
+ $$ = compare_int( $1, $2, num );
+ else
+ $$ = ($2 == COND_NE || $2 == COND_INE );
}
- | COND_LT COND_GT
+ | symbol_s operator symbol_s
{
- $$ = comp_ne_m1;
+ $$ = compare_and_free_strings( $1, $2, $3 );
}
- | COND_LT
+ | symbol_s operator literal
{
- $$ = comp_lt_m1;
+ $$ = compare_and_free_strings( $1, $2, $3 );
}
- | COND_GT
+ | literal operator symbol_s
{
- $$ = comp_gt_m1;
+ $$ = compare_and_free_strings( $1, $2, $3 );
}
- | COND_LT COND_EQ
+ | literal operator literal
{
- $$ = comp_le_m1;
+ $$ = compare_and_free_strings( $1, $2, $3 );
}
- | COND_GT COND_EQ
- {
- $$ = comp_ge_m1;
- }
- /*Not valid for mixed compares*/
- | COND_GT COND_LT
+ | literal operator value_i
{
$$ = 0;
}
- | COND_LT COND_LT
+ | value_i operator literal
{
$$ = 0;
}
- | COND_GT COND_GT
+ | COND_LPAR expression COND_RPAR
{
- $$ = 0;
+ $$ = $2;
}
;
-comp_op_m2:
+operator:
/* 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;
}
}
;
-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;
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 );
}
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 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)
+static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b )
+{
+ /* null and empty string are equivalent */
+ if (!a) a = szEmpty;
+ if (!b) b = szEmpty;
+
+ /* 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 )
|| ( 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;
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;
- }
+ break;
- if( COND_IsNumber( ch ) )
- {
- while( COND_IsNumber( str->data[len] ) )
- len++;
- rc = COND_NUMBER;
- break;
- }
+ case '~':
+ case '<':
+ case '>':
+ rc = COND_GetOperator( cond );
+ if (!rc)
+ rc = COND_ERROR;
+ return rc;
+ default:
+ rc = 0;
+ }
- ERR("Got unknown character %c(%x)\n",ch,ch);
- rc = COND_ERROR;
- break;
+ if ( rc )
+ {
+ cond->n += len;
+ return rc;
}
- /* keyword identifiers */
- if( rc == COND_IDENT )
+ 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 ) )
{
- 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) )
+ 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;
static int COND_error(const char *str)
{
+ TRACE("%s\n", str );
return 0;
}
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;
}
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;
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;
}
#include "query.h"
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
/* below is the query interface to a table */
' ','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 );
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));
}
end:
- msi_free(source);
- msi_free(target);
msiobj_release(&row->hdr);
return rc;
}
switch (rc)
{
- case ERROR_FUNCTION_NOT_CALLED:
- case ERROR_SUCCESS:
- case ERROR_INSTALL_USEREXIT:
- case ERROR_INSTALL_FAILURE:
- return rc;
- case ERROR_NO_MORE_ITEMS:
- return ERROR_SUCCESS;
- default:
- 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;
}
}
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);
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);
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);
}
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);
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);
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,
DWORD r;
free_cached_tables( db );
+ msi_free_transforms( db );
msi_destroy_stringtable( db->strings );
r = IStorage_Release( db->storage );
if( r )
db->storage = stg;
db->mode = szMode;
list_init( &db->tables );
+ list_init( &db->transforms );
db->strings = load_string_table( stg );
if( !db->strings )
#include "query.h"
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
/*
*/
#define COBJMACROS
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
#include <stdarg.h>
msi_font *font_list;
struct list controls;
HWND hWndFocus;
+ LPWSTR control_default;
+ LPWSTR control_cancel;
WCHAR name[1];
};
};
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 };
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 * );
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',' ',
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',' ',
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;
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;
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 );
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;
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;
}
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;
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;
}
}
-/* 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;
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 },
{ 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])
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));
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 );
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 )
}
}
else
- ERR("button click from nowhere\n");
+ ERR("button click from nowhere %p %d %p\n", dialog, param, hwnd);
return 0;
}
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;
}
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 );
void msi_dialog_unregister_class( void )
{
DestroyWindow( hMsiHiddenWindow );
+ hMsiHiddenWindow = NULL;
UnregisterClassW( szMsiDialogClass, NULL );
+ UnregisterClassW( szMsiHiddenWindow, NULL );
uiThreadId = 0;
}
#include "query.h"
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
typedef struct tagDISTINCTSET
{
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
static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
{
+ HANDLE handle;
DWORD dwAccess = 0;
DWORD dwShareMode = 0;
DWORD dwCreateDisposition = OPEN_EXISTING;
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)
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)
{
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);
-
- TRACE("file: %s\n", debugstr_a(file));
-
- /* track this file so it can be deleted if not installed */
- trackpath=strdupAtoW(file);
- tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
- trackname = msi_alloc((strlenW(tracknametmp) +
- strlenW(tmpprefix)+1) * sizeof(WCHAR));
-
- strcpyW(trackname,tmpprefix);
- strcatW(trackname,tracknametmp);
-
- track_tempfile(data->package, trackname, trackpath);
-
- msi_free(trackpath);
- msi_free(trackname);
- msi_free(tracknametmp);
+ msi_file_update_ui( data->package, f );
- /* 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);
+ TRACE("extracting %s\n", debugstr_w(f->TargetPath) );
- ui_progress( data->package, 2, f->FileSize, 0, 0);
+ 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;
+ }
- 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:
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)
{
}
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;
INT seq;
UINT type;
LPCWSTR prompt;
+ MSICOMPONENT *comp = file->Component;
if (file->Sequence <= mi->last_sequence)
{
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
{
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;
}
/*
- * 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)
{
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)
{
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)
- {
- ERR("Unable to ready media\n");
- rc = ERROR_FUNCTION_FAILED;
- break;
- }
+ TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
+ debugstr_w(file->TargetPath));
- 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;
- if (file->Attributes & msidbFileAttributesNoncompressed)
- rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
- else
- rc = MoveFileW(file->SourcePath, file->TargetPath);
+ /* 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;
+ }
- if (!rc)
+ 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)
{
- 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;
- }
+ rc = 0;
}
- else
+ else if (rc == ERROR_FILE_NOT_FOUND)
+ {
+ ERR("Source File Not Found! Continuing\n");
+ rc = 0;
+ }
+ 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 */
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));
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");
{'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;
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;
+}
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
{
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);
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);
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);
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)
{
MSITEMPFILE *temp;
- if (!package)
- return -1;
-
LIST_FOR_EACH_ENTRY( temp, &package->tempfiles, MSITEMPFILE, entry )
{
if (lstrcmpW( name, temp->File )==0)
/* 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);
msiobj_release(&row->hdr);
}
-BOOL ACTION_VerifyComponentForAction(MSIPACKAGE* package, MSICOMPONENT* comp,
- INSTALLSTATE check )
+BOOL ACTION_VerifyComponentForAction( MSICOMPONENT* comp, INSTALLSTATE check )
{
if (!comp)
return FALSE;
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));
{
INT i;
- if (!package || !package->script)
+ if (!package->script)
return FALSE;
for (i = 0; i < package->script->UniqueActionsCount; i++)
#include "query.h"
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
/* below is the query interface to a table */
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;
}
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;
/***********************************************************************
* 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);
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) ||
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);
}
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;
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.@)
*
#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;
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);
{
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,
{
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,
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;
*/
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);
*/
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;
if (rc == ERROR_SUCCESS)
return INSTALLSTATE_LOCAL;
- else
- return INSTALLSTATE_ABSENT;
+
+ return INSTALLSTATE_UNKNOWN;
}
/******************************************************************
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};
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,
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),
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
RegCloseKey(hkey);
msi_free(info);
- msi_free(product);
- msi_free(component);
if (rc == INSTALLSTATE_LOCAL)
return ERROR_SUCCESS;
return 0;
}
+/***********************************************************************
+ * MsiGetShortcutTargetA [MSI.@]
+ */
UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget,
LPSTR szProductCode, LPSTR szFeatureId,
LPSTR szComponentCode )
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,
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;
+}
#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"
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)
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)
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)
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)
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)
--- /dev/null
+/*
+ * 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"
+}
string_table *strings;
LPCWSTR mode;
struct list tables;
+ struct list transforms;
} MSIDATABASE;
typedef struct tagMSIVIEW MSIVIEW;
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
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 {
} 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 * );
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 );
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* );
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 * );
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 );
#include "query.h"
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
/* below is the query interface to a table */
#include "wine/debug.h"
#include "msi.h"
#include "msiquery.h"
-#include "msipriv.h"
#include "objidl.h"
#include "wincrypt.h"
#include "winuser.h"
#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)
{
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
*
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);
{
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];
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;
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);
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;
char *msg;
int len;
- TRACE("%x \n",eMessageType);
+ TRACE("%x\n", eMessageType);
rc = 0;
if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
{
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;
}
/* 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)
,'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)
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;
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;
-
- 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);
- }
+ if (!name || !name[0])
+ return NULL;
- 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);
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 );
- msiobj_release( &package->hdr );
- /* MsiGetProperty does not return error codes on missing properties */
- if (ret != ERROR_MORE_DATA)
- ret = ERROR_SUCCESS;
+ row = MSI_GetPropertyRow( package, name );
+ if (row)
+ val = MSI_RecordGetString( row, 1 );
- return ret;
+ if (!val)
+ val = empty;
+
+ r = msi_strcpy_to_awstring( val, szValueBuf, pchValueBuf );
+
+ if (row)
+ msiobj_release( &row->hdr );
+ msiobj_release( &package->hdr );
+
+ return r;
}
-
-UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName,
- LPWSTR szValueBuf, DWORD* pchValueBuf)
+UINT WINAPI MsiGetPropertyA( MSIHANDLE hInstall, LPCSTR szName,
+ LPSTR szValueBuf, DWORD* pchValueBuf )
{
- MSIPACKAGE *package;
- UINT ret;
-
- TRACE("%lu %s %p\n", hInstall, debugstr_w(szName), pchValueBuf);
+ awstring val;
+ LPWSTR name;
+ UINT r;
- if (0 == hInstall)
- return ERROR_INVALID_HANDLE;
- if (NULL == szName)
- return ERROR_INVALID_PARAMETER;
- if (NULL != szValueBuf && NULL == pchValueBuf)
- return ERROR_INVALID_PARAMETER;
+ val.unicode = FALSE;
+ val.str.a = szValueBuf;
- /* This was tested against native msi */
- if (NULL == szValueBuf && NULL != pchValueBuf)
- *pchValueBuf = 0;
+ name = strdupAtoW( szName );
+ if (szName && !name)
+ return ERROR_OUTOFMEMORY;
- package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
- if (!package)
- return ERROR_INVALID_HANDLE;
- ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf );
- msiobj_release( &package->hdr );
+ r = MSI_GetProperty( hInstall, name, &val, pchValueBuf );
+ msi_free( name );
+ return r;
+}
+
+UINT WINAPI MsiGetPropertyW( MSIHANDLE hInstall, LPCWSTR szName,
+ LPWSTR szValueBuf, DWORD* pchValueBuf )
+{
+ awstring val;
- /* MsiGetProperty does not return error codes on missing properties */
- if (ret != ERROR_MORE_DATA)
- ret = ERROR_SUCCESS;
+ val.unicode = TRUE;
+ val.str.w = szValueBuf;
- return ret;
+ return MSI_GetProperty( hInstall, szName, &val, pchValueBuf );
}
#include "query.h"
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
#define MSIFIELD_NULL 0
#define MSIFIELD_INT 1
{
DWORD i, val = 0, base = 1, *p;
+ if (!str)
+ return FALSE;
+
p = (DWORD*) guid;
for( i=0; i<20; i++ )
{
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 )
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);
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;
+
+ if (szProduct)
+ p = product;
+ if (szFeature)
+ f = feature;
+ if (szComponent)
+ c = component;
- r = MsiDecomposeDescriptorW( str, product, feature, component, pUsed );
+ r = MsiDecomposeDescriptorW( str, p, f, c, pUsed );
- WideCharToMultiByte( CP_ACP, 0, product, MAX_FEATURE_CHARS+1,
+ 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 );
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);
-
- if (lpQualifierBuf)
- lpwQualifierBuf = msi_alloc( (*pcchQualifierBuf) * sizeof(WCHAR));
- else
- lpwQualifierBuf = NULL;
-
- if (pcchQualifierBuf)
- pcchwQualifierBuf = *pcchQualifierBuf;
- else
- pcchwQualifierBuf = 0;
+ comp = strdupAtoW( szComponent );
+ if (szComponent && !comp)
+ return ERROR_OUTOFMEMORY;
- if (lpApplicationDataBuf)
- lpwApplicationDataBuf = msi_alloc( (*pcchApplicationDataBuf) * sizeof(WCHAR));
- else
- lpwApplicationDataBuf = NULL;
-
- if (pcchApplicationDataBuf)
- pcchwApplicationDataBuf = *pcchApplicationDataBuf;
- else
- pcchwApplicationDataBuf = 0;
+ qual.unicode = FALSE;
+ qual.str.a = lpQualifierBuf;
- rc = MsiEnumComponentQualifiersW( szwComponent, iIndex, lpwQualifierBuf,
- &pcchwQualifierBuf, lpwApplicationDataBuf,
- &pcchwApplicationDataBuf);
+ appdata.unicode = FALSE;
+ appdata.str.a = lpApplicationDataBuf;
- /*
- * 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 );
}
/*************************************************************************
#include "query.h"
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
/* below is the query interface to a table */
#include "query.h"
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
typedef struct _msistring
{
WINE_DEFAULT_DEBUG_CHANNEL(msi);
-#define MSI_MAX_PROPS 20
-
#include "pshpack1.h"
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 };
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;
IStream_Release( stm );
}
- handle = alloc_msihandle( &si->hdr );
- if( handle )
- *pHandle = handle;
+ 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
- ret = ERROR_FUNCTION_FAILED;
- msiobj_release( &si->hdr );
+ {
+ 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 );
if( !si )
return ERROR_INVALID_HANDLE;
+ if ( uiProperty >= MSI_MAX_PROPS )
+ {
+ *puiDataType = VT_EMPTY;
+ return ret;
+ }
+
prop = &si->property[uiProperty];
if( 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)
#include "query.h"
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
typedef struct tagMSICOLUMNINFO
{
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,
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,
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;
}
return ERROR_SUCCESS;
}
-static UINT table_find_in_column( MSITABLEVIEW *tv, UINT col, UINT val, UINT *row )
+static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row );
+
+static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec )
{
- UINT i, r, x;
+ UINT r, row;
- 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;
+ r = msi_table_find_row( tv, rec, &row );
+ if (r != ERROR_SUCCESS)
+ return ERROR_SUCCESS;
+ return ERROR_INVALID_DATA;
}
-static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec )
+static UINT msi_table_modify_row( MSITABLEVIEW *tv, MSIRECORD *rec,
+ UINT row, UINT mask )
{
- LPCWSTR str;
- UINT i, val, r, row;
- BOOL has_key = FALSE;
+ UINT i, val, r = ERROR_SUCCESS;
- /* FIXME: set the MsiViewGetError value */
+ TRACE("%p %p %u %08x\n", tv, rec, row, mask );
- for( i = 0; i<tv->num_cols; i++ )
+ for( i = 0; i < tv->num_cols; i++ )
{
- /* check for duplicate keys */
- if( !( tv->columns[i].type & MSITYPE_KEY ) )
+ /* set keys or values specified in the mask */
+ if( (~tv->columns[i].type & MSITYPE_KEY) && (~mask & (1<<i)) )
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 )
+ if( (tv->columns[i].type & MSITYPE_STRING) &&
+ ! MSITYPE_IS_BINARY(tv->columns[i].type) )
{
- /* 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;
+ const WCHAR *str = MSI_RecordGetString( rec, i+1 );
+ val = msi_addstringW( tv->db->strings, 0, str, -1, 1 );
}
else
{
val = MSI_RecordGetInteger( rec, i+1 );
- val ^= 0x8000;
+ if ( 2 == bytes_per_column( &tv->columns[i] ) )
+ 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 );
+ r = TABLE_set_int( &tv->view, row, i+1, val );
+ if( r )
+ break;
}
- if (has_key)
- return ERROR_INVALID_DATA;
-
- return ERROR_SUCCESS;
+ return r;
}
static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
- UINT n, type, val, r, row, col_count = 0;
+ UINT r, row = -1;
- r = TABLE_get_dimensions( view, NULL, &col_count );
- if( r )
- return r;
+ TRACE("%p %p\n", tv, rec );
- row = -1;
r = table_create_new_row( view, &row );
TRACE("insert_row returned %08x\n", r);
- if( r )
+ if( r != ERROR_SUCCESS )
return r;
- for( n = 1; n <= col_count; n++ )
- {
- r = TABLE_get_column_info( view, n, NULL, &type );
- if( r )
- break;
-
- if( type & MSITYPE_STRING )
- {
- const WCHAR *str = MSI_RecordGetString( rec, n );
- val = msi_addstringW( tv->db->strings, 0, str, -1, 1 );
- }
- else
- {
- val = MSI_RecordGetInteger( rec, n );
- val ^= 0x8000;
- }
- r = TABLE_set_int( view, row, n, val );
- if( r )
- break;
- }
-
- return r;
+ return msi_table_modify_row( tv, rec, row, ~0 );
}
static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
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 );
+ }
+}
#include "query.h"
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
/* below is the query interface to a table */
#include "query.h"
-WINE_DEFAULT_DEBUG_CHANNEL(msi);
+WINE_DEFAULT_DEBUG_CHANNEL(msidb);
/* below is the query interface to a table */
typedef enum tagINSTALLSTATE
{
+ INSTALLSTATE_NOTUSED = -7,
INSTALLSTATE_BADCONFIG = -6,
INSTALLSTATE_INCOMPLETE = -5,
INSTALLSTATE_SOURCEABSENT = -4,
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,
MSICODE_PATCH = 0x40000000L
} MSICODE;
+typedef struct _MSIFILEHASHINFO {
+ ULONG dwFileHashInfoSize;
+ ULONG dwData[4];
+} MSIFILEHASHINFO, *PMSIFILEHASHINFO;
+
#define MAX_FEATURE_CHARS 38
/* Strings defined in msi.h */
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)
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*);
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);
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
{
UINT WINAPI MsiEnableUIPreview(MSIHANDLE, MSIHANDLE*);
BOOL WINAPI MsiGetMode(MSIHANDLE, MSIRUNMODE);
+BOOL WINAPI MsiSetMode(MSIHANDLE, MSIRUNMODE, BOOL);
UINT WINAPI MsiViewModify(MSIHANDLE, MSIMODIFY, MSIHANDLE);