diff --git a/reactos/lib/msi/action.c b/reactos/lib/msi/action.c index 6a7eca67681..3559c88c7ad 100644 --- a/reactos/lib/msi/action.c +++ b/reactos/lib/msi/action.c @@ -60,119 +60,119 @@ static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI) */ 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[] = @@ -180,55 +180,55 @@ 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}; @@ -404,6 +404,171 @@ static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine ) 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 *****************************************************/ @@ -453,6 +618,8 @@ UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath, 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; @@ -593,7 +760,7 @@ static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param) 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; } @@ -708,7 +875,7 @@ static UINT ACTION_ProcessUISequence(MSIPACKAGE *package) 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); @@ -727,6 +894,12 @@ static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, BOOL run = force; int i; + if (!package) + { + ERR("package was null!\n"); + return FALSE; + } + if (!run && !package->script->CurrentlyScripting) run = TRUE; @@ -855,7 +1028,7 @@ static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param) dir = MSI_RecordGetString(row,1); if (!dir) { - ERR("Unable to get folder id \n"); + ERR("Unable to get folder id\n"); return ERROR_SUCCESS; } @@ -883,6 +1056,42 @@ static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param) 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 @@ -898,13 +1107,16 @@ static UINT ACTION_CreateFolders(MSIPACKAGE *package) 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; } @@ -917,15 +1129,15 @@ static MSICOMPONENT* load_component( MSIRECORD * row ) 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; @@ -1031,19 +1243,19 @@ static UINT load_feature(MSIRECORD * row, LPVOID param) 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; @@ -1079,7 +1291,7 @@ static UINT load_file(MSIRECORD *row, LPVOID param) 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 ); @@ -1087,19 +1299,19 @@ static UINT load_file(MSIRECORD *row, LPVOID param) 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)); @@ -1154,11 +1366,8 @@ static UINT ACTION_CostInitialize(MSIPACKAGE *package) 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); @@ -1239,7 +1448,7 @@ static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir ) 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,':')) @@ -1404,6 +1613,8 @@ static UINT SetFeatureStates(MSIPACKAGE *package) {'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; @@ -1439,6 +1650,7 @@ static UINT SetFeatureStates(MSIPACKAGE *package) */ 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) { @@ -1617,13 +1829,10 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) 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); @@ -1661,7 +1870,7 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES) { - file->State = 1; + file->state = msifs_missing; comp->Cost += file->FileSize; continue; } @@ -1672,14 +1881,13 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) 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); @@ -1696,16 +1904,16 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) 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"); @@ -1893,7 +2101,7 @@ static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param) 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)); @@ -2349,9 +2557,6 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) 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); @@ -2385,8 +2590,7 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) * 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) @@ -2417,8 +2621,7 @@ static UINT ACTION_ProcessComponents(MSIPACKAGE *package) msiobj_release( &uirow->hdr ); } } - else if (ACTION_VerifyComponentForAction(package, comp, - INSTALLSTATE_ABSENT)) + else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT)) { DWORD res; @@ -2523,7 +2726,7 @@ static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param) 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"); @@ -2539,19 +2742,18 @@ static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param) 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; @@ -2604,9 +2806,6 @@ static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package) {'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; @@ -2634,7 +2833,7 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param) 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"); @@ -2755,9 +2954,6 @@ static UINT ACTION_CreateShortcuts(MSIPACKAGE *package) {'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; @@ -2856,9 +3052,6 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) DWORD size; MSIHANDLE hDb, hSumInfo; - if (!package) - return ERROR_INVALID_HANDLE; - /* write out icon files */ rc = MSI_DatabaseOpenViewW(package->db, Query, &view); @@ -2925,7 +3118,7 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package) } else { - ERR("Unable to query Revision_Number... \n"); + ERR("Unable to query Revision_Number...\n"); rc = ERROR_SUCCESS; } MsiCloseHandle(hSumInfo); @@ -2959,7 +3152,7 @@ static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param) 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)); @@ -3133,9 +3326,6 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package) 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; @@ -3281,55 +3471,54 @@ static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey ) 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[] = @@ -3344,23 +3533,16 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) 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 ); @@ -3376,11 +3558,8 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) 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 ); @@ -3414,7 +3593,6 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) msi_free(upgrade_code); } -end: RegCloseKey(hkey); return ERROR_SUCCESS; @@ -3422,23 +3600,13 @@ end: 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; @@ -3481,9 +3649,6 @@ static UINT ACTION_ForceReboot(MSIPACKAGE *package) 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])); @@ -3579,9 +3744,6 @@ static UINT ACTION_RegisterUser(MSIPACKAGE *package) {0}, }; - if (!package) - return ERROR_INVALID_HANDLE; - productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW ); if (!productid) return ERROR_SUCCESS; @@ -3607,17 +3769,10 @@ end: 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; } @@ -3784,8 +3939,7 @@ static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param) } /* 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; @@ -3797,7 +3951,7 @@ static UINT ITERATE_RegisterFonts(MSIRECORD *row, LPVOID param) 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) { @@ -3850,9 +4004,9 @@ static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param) 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)); @@ -3944,6 +4098,12 @@ static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, 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[] = @@ -4051,7 +4211,7 @@ static UINT ACTION_UnregisterFonts( MSIPACKAGE *package ) } static struct _actions StandardActions[] = { - { szAllocateRegistrySpace, NULL}, + { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace }, { szAppSearch, ACTION_AppSearch }, { szBindImage, ACTION_BindImage }, { szCCPSearch, NULL}, @@ -4099,7 +4259,7 @@ static struct _actions StandardActions[] = { { szRemoveDuplicateFiles, NULL}, { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings }, { szRemoveExistingProducts, NULL}, - { szRemoveFiles, NULL}, + { szRemoveFiles, ACTION_RemoveFiles}, { szRemoveFolders, NULL}, { szRemoveIniValues, ACTION_RemoveIniValues }, { szRemoveODBC, NULL}, diff --git a/reactos/lib/msi/action.h b/reactos/lib/msi/action.h index d2e03e2af7f..9b3e58d5947 100644 --- a/reactos/lib/msi/action.h +++ b/reactos/lib/msi/action.h @@ -93,6 +93,15 @@ typedef struct tagMSIFOLDER INT Space; } MSIFOLDER; +typedef enum _msi_file_state { + msifs_invalid, + msifs_missing, + msifs_overwrite, + msifs_present, + msifs_installed, + msifs_skipped, +} msi_file_state; + typedef struct tagMSIFILE { struct list entry; @@ -105,14 +114,7 @@ typedef struct tagMSIFILE LPWSTR Language; INT Attributes; INT Sequence; - - INT State; - /* 0 = uninitialize */ - /* 1 = not present */ - /* 2 = present but replace */ - /* 3 = present do not replace */ - /* 4 = Installed */ - /* 5 = Skipped */ + msi_file_state state; LPWSTR SourcePath; LPWSTR TargetPath; } MSIFILE; @@ -241,6 +243,7 @@ extern UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action, BOOL ex extern UINT ACTION_AppSearch(MSIPACKAGE *package); extern UINT ACTION_FindRelatedProducts(MSIPACKAGE *package); extern UINT ACTION_InstallFiles(MSIPACKAGE *package); +extern UINT ACTION_RemoveFiles(MSIPACKAGE *package); extern UINT ACTION_DuplicateFiles(MSIPACKAGE *package); extern UINT ACTION_RegisterClassInfo(MSIPACKAGE *package); extern UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package); @@ -250,7 +253,7 @@ extern UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package); /* Helpers */ extern DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data ); -extern WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index); +extern LPWSTR msi_dup_record_field(MSIRECORD *row, INT index); extern LPWSTR msi_dup_property(MSIPACKAGE *package, LPCWSTR prop); extern LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, BOOL set_prop, MSIFOLDER **folder); @@ -264,7 +267,7 @@ extern LPWSTR build_icon_path(MSIPACKAGE *, LPCWSTR); extern DWORD build_version_dword(LPCWSTR); extern LPWSTR build_directory_name(DWORD , ...); extern BOOL create_full_pathW(const WCHAR *path); -extern BOOL ACTION_VerifyComponentForAction(MSIPACKAGE*, MSICOMPONENT*, INSTALLSTATE); +extern BOOL ACTION_VerifyComponentForAction(MSICOMPONENT*, INSTALLSTATE); extern BOOL ACTION_VerifyFeatureForAction(MSIFEATURE*, INSTALLSTATE); extern void reduce_to_longfilename(WCHAR*); extern void reduce_to_shortfilename(WCHAR*); @@ -273,6 +276,7 @@ extern void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature) extern UINT register_unique_action(MSIPACKAGE *, LPCWSTR); extern BOOL check_unique_action(MSIPACKAGE *, LPCWSTR); extern WCHAR* generate_error_string(MSIPACKAGE *, UINT, DWORD, ... ); +extern UINT msi_create_component_directories( MSIPACKAGE *package ); /* control event stuff */ diff --git a/reactos/lib/msi/appsearch.c b/reactos/lib/msi/appsearch.c index 91c41d5f126..4c59c1a0bbb 100644 --- a/reactos/lib/msi/appsearch.c +++ b/reactos/lib/msi/appsearch.c @@ -118,15 +118,15 @@ static UINT ACTION_AppSearchGetSignature(MSIPACKAGE *package, MSISIGNATURE *sig, } /* get properties */ - sig->File = load_dynamic_stringW(row,2); - minVersion = load_dynamic_stringW(row,3); + sig->File = msi_dup_record_field(row,2); + minVersion = msi_dup_record_field(row,3); if (minVersion) { ACTION_VerStrToInteger(minVersion, &sig->MinVersionMS, &sig->MinVersionLS); msi_free( minVersion); } - maxVersion = load_dynamic_stringW(row,4); + maxVersion = msi_dup_record_field(row,4); if (maxVersion) { ACTION_VerStrToInteger(maxVersion, &sig->MaxVersionMS, @@ -139,7 +139,7 @@ static UINT ACTION_AppSearchGetSignature(MSIPACKAGE *package, MSISIGNATURE *sig, sig->MaxSize = MSI_RecordGetInteger(row,6); if (sig->MaxSize == MSI_NULL_INTEGER) sig->MaxSize = 0; - sig->Languages = load_dynamic_stringW(row,9); + sig->Languages = msi_dup_record_field(row,9); time = MSI_RecordGetInteger(row,7); if (time != MSI_NULL_INTEGER) DosDateTimeToFileTime(HIWORD(time), LOWORD(time), &sig->MinTime); @@ -276,9 +276,9 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, BOOL *appFound, } root = MSI_RecordGetInteger(row,2); - keyPath = load_dynamic_stringW(row,3); + keyPath = msi_dup_record_field(row,3); /* FIXME: keyPath needs to be expanded for properties */ - valueName = load_dynamic_stringW(row,4); + valueName = msi_dup_record_field(row,4); /* FIXME: valueName probably does too */ type = MSI_RecordGetInteger(row,5); @@ -442,7 +442,7 @@ static UINT ACTION_AppSearchIni(MSIPACKAGE *package, BOOL *appFound, } /* get file name */ - fileName = load_dynamic_stringW(row,2); + fileName = msi_dup_record_field(row,2); FIXME("AppSearch unimplemented for IniLocator (ini file name %s)\n", debugstr_w(fileName)); msi_free( fileName); @@ -549,7 +549,7 @@ static UINT ACTION_FileVersionMatches(MSISIGNATURE *sig, LPCWSTR filePath, if (buf) { - static const WCHAR rootW[] = { '\\',0 }; + static WCHAR rootW[] = { '\\',0 }; UINT versionLen; LPVOID subBlock = NULL; diff --git a/reactos/lib/msi/classes.c b/reactos/lib/msi/classes.c index c83453131cd..b7799f38059 100644 --- a/reactos/lib/msi/classes.c +++ b/reactos/lib/msi/classes.c @@ -65,15 +65,15 @@ static MSIAPPID *load_appid( MSIPACKAGE* package, MSIRECORD *row ) if (!appid) return NULL; - appid->AppID = load_dynamic_stringW( row, 1 ); + appid->AppID = msi_dup_record_field( row, 1 ); TRACE("loading appid %s\n", debugstr_w( appid->AppID )); buffer = MSI_RecordGetString(row,2); deformat_string( package, buffer, &appid->RemoteServerName ); - appid->LocalServer = load_dynamic_stringW(row,3); - appid->ServiceParameters = load_dynamic_stringW(row,4); - appid->DllSurrogate = load_dynamic_stringW(row,5); + appid->LocalServer = msi_dup_record_field(row,3); + appid->ServiceParameters = msi_dup_record_field(row,4); + appid->DllSurrogate = msi_dup_record_field(row,5); appid->ActivateAtStorage = !MSI_RecordIsNull(row,6); appid->RunAsInteractiveUser = !MSI_RecordIsNull(row,7); @@ -131,7 +131,7 @@ static MSIPROGID *load_progid( MSIPACKAGE* package, MSIRECORD *row ) list_add_tail( &package->progids, &progid->entry ); - progid->ProgID = load_dynamic_stringW(row,1); + progid->ProgID = msi_dup_record_field(row,1); TRACE("loading progid %s\n",debugstr_w(progid->ProgID)); buffer = MSI_RecordGetString(row,2); @@ -144,12 +144,12 @@ static MSIPROGID *load_progid( MSIPACKAGE* package, MSIRECORD *row ) if (progid->Class == NULL && buffer) FIXME("Unknown class %s\n",debugstr_w(buffer)); - progid->Description = load_dynamic_stringW(row,4); + progid->Description = msi_dup_record_field(row,4); if (!MSI_RecordIsNull(row,6)) { INT icon_index = MSI_RecordGetInteger(row,6); - LPWSTR FileName = load_dynamic_stringW(row,5); + LPCWSTR FileName = MSI_RecordGetString(row,5); LPWSTR FilePath; static const WCHAR fmt[] = {'%','s',',','%','i',0}; @@ -160,7 +160,6 @@ static MSIPROGID *load_progid( MSIPACKAGE* package, MSIRECORD *row ) sprintfW(progid->IconPath,fmt,FilePath,icon_index); msi_free(FilePath); - msi_free(FileName); } else { @@ -180,7 +179,7 @@ static MSIPROGID *load_progid( MSIPACKAGE* package, MSIRECORD *row ) while (parent->Parent && parent->Parent != parent) parent = parent->Parent; - FIXME("need to determing if we are really the CurVer\n"); + /* FIXME: need to determing if we are really the CurVer */ progid->CurVer = parent; parent->VersionInd = progid; @@ -235,28 +234,28 @@ static MSICLASS *load_class( MSIPACKAGE* package, MSIRECORD *row ) list_add_tail( &package->classes, &cls->entry ); - cls->clsid = load_dynamic_stringW( row, 1 ); + cls->clsid = msi_dup_record_field( row, 1 ); TRACE("loading class %s\n",debugstr_w(cls->clsid)); - cls->Context = load_dynamic_stringW( row, 2 ); + cls->Context = msi_dup_record_field( row, 2 ); buffer = MSI_RecordGetString(row,3); cls->Component = get_loaded_component(package, buffer); - cls->ProgIDText = load_dynamic_stringW(row,4); + cls->ProgIDText = msi_dup_record_field(row,4); cls->ProgID = load_given_progid(package, cls->ProgIDText); - cls->Description = load_dynamic_stringW(row,5); + cls->Description = msi_dup_record_field(row,5); buffer = MSI_RecordGetString(row,6); if (buffer) cls->AppID = load_given_appid(package, buffer); - cls->FileTypeMask = load_dynamic_stringW(row,7); + cls->FileTypeMask = msi_dup_record_field(row,7); if (!MSI_RecordIsNull(row,9)) { INT icon_index = MSI_RecordGetInteger(row,9); - LPWSTR FileName = load_dynamic_stringW(row,8); + LPCWSTR FileName = MSI_RecordGetString(row,8); LPWSTR FilePath; static const WCHAR fmt[] = {'%','s',',','%','i',0}; @@ -267,7 +266,6 @@ static MSICLASS *load_class( MSIPACKAGE* package, MSIRECORD *row ) sprintfW(cls->IconPath,fmt,FilePath,icon_index); msi_free(FilePath); - msi_free(FileName); } else { @@ -300,7 +298,7 @@ static MSICLASS *load_class( MSIPACKAGE* package, MSIRECORD *row ) } else { - cls->DefInprocHandler32 = load_dynamic_stringW( row, 10); + cls->DefInprocHandler32 = msi_dup_record_field( row, 10); reduce_to_longfilename(cls->DefInprocHandler32); } } @@ -366,13 +364,13 @@ static MSIMIME *load_mime( MSIPACKAGE* package, MSIRECORD *row ) if (!mt) return mt; - mt->ContentType = load_dynamic_stringW( row, 1 ); + mt->ContentType = msi_dup_record_field( row, 1 ); TRACE("loading mime %s\n", debugstr_w(mt->ContentType)); buffer = MSI_RecordGetString( row, 2 ); mt->Extension = load_given_extension( package, buffer ); - mt->clsid = load_dynamic_stringW( row, 3 ); + mt->clsid = msi_dup_record_field( row, 3 ); mt->Class = load_given_class( package, mt->clsid ); list_add_tail( &package->mimes, &mt->entry ); @@ -428,13 +426,13 @@ static MSIEXTENSION *load_extension( MSIPACKAGE* package, MSIRECORD *row ) list_add_tail( &package->extensions, &ext->entry ); - ext->Extension = load_dynamic_stringW( row, 1 ); + ext->Extension = msi_dup_record_field( row, 1 ); TRACE("loading extension %s\n", debugstr_w(ext->Extension)); buffer = MSI_RecordGetString( row, 2 ); ext->Component = get_loaded_component( package,buffer ); - ext->ProgIDText = load_dynamic_stringW( row, 3 ); + ext->ProgIDText = msi_dup_record_field( row, 3 ); ext->ProgID = load_given_progid( package, ext->ProgIDText ); buffer = MSI_RecordGetString( row, 4 ); @@ -505,7 +503,7 @@ static UINT iterate_load_verb(MSIRECORD *row, LPVOID param) if (!verb) return ERROR_OUTOFMEMORY; - verb->Verb = load_dynamic_stringW(row,2); + verb->Verb = msi_dup_record_field(row,2); TRACE("loading verb %s\n",debugstr_w(verb->Verb)); verb->Sequence = MSI_RecordGetInteger(row,3); @@ -837,9 +835,6 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) BOOL install_on_demand = FALSE; MSICLASS *cls; - if (!package) - return ERROR_INVALID_HANDLE; - load_classes_and_such(package); rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey); if (rc != ERROR_SUCCESS) @@ -1043,68 +1038,36 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package) return rc; } -static UINT register_progid_base(MSIPACKAGE* package, MSIPROGID* progid, - LPWSTR clsid) +static LPCWSTR get_clsid_of_progid( MSIPROGID *progid ) +{ + while (progid) + { + if (progid->Class) + return progid->Class->clsid; + progid = progid->Parent; + } + return NULL; +} + +static UINT register_progid( MSIPROGID* progid ) { static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; static const WCHAR szDefaultIcon[] = {'D','e','f','a','u','l','t','I','c','o','n',0}; - HKEY hkey; + static const WCHAR szCurVer[] = + {'C','u','r','V','e','r',0}; + HKEY hkey = 0; + UINT rc; - RegCreateKeyW(HKEY_CLASSES_ROOT,progid->ProgID,&hkey); + rc = RegCreateKeyW( HKEY_CLASSES_ROOT, progid->ProgID, &hkey ); + if (rc == ERROR_SUCCESS) + { + LPCWSTR clsid = get_clsid_of_progid( progid ); - if (progid->Description) - msi_reg_set_val_str( hkey, NULL, progid->Description ); - - if (progid->Class) - { - msi_reg_set_subkey_val( hkey, szCLSID, NULL, progid->Class->clsid ); if (clsid) - strcpyW( clsid, progid->Class->clsid ); - } - else - { - FIXME("progid (%s) with null classid\n", debugstr_w(progid->ProgID)); - } - - if (progid->IconPath) - msi_reg_set_subkey_val( hkey, szDefaultIcon, NULL, progid->IconPath ); - - return ERROR_SUCCESS; -} - -static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid, - LPWSTR clsid) -{ - UINT rc = ERROR_SUCCESS; - - if (progid->Parent == NULL) - rc = register_progid_base(package, progid, clsid); - else - { - DWORD disp; - HKEY hkey; - static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 }; - static const WCHAR szDefaultIcon[] = - {'D','e','f','a','u','l','t','I','c','o','n',0}; - static const WCHAR szCurVer[] = - {'C','u','r','V','e','r',0}; - - /* check if already registered */ - RegCreateKeyExW(HKEY_CLASSES_ROOT, progid->ProgID, 0, NULL, 0, - KEY_ALL_ACCESS, NULL, &hkey, &disp ); - if (disp == REG_OPENED_EXISTING_KEY) - { - TRACE("Key already registered\n"); - RegCloseKey(hkey); - return rc; - } - - TRACE("Registering Parent %s\n", debugstr_w(progid->Parent->ProgID) ); - rc = register_progid( package, progid->Parent, clsid ); - - /* clsid is same as parent */ - msi_reg_set_subkey_val( hkey, szCLSID, NULL, clsid ); + msi_reg_set_subkey_val( hkey, szCLSID, NULL, clsid ); + else + ERR("%s has no class\n", debugstr_w( progid->ProgID ) ); if (progid->Description) msi_reg_set_val_str( hkey, NULL, progid->Description ); @@ -1118,6 +1081,9 @@ static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid, RegCloseKey(hkey); } + else + ERR("failed to create key %s\n", debugstr_w( progid->ProgID ) ); + return rc; } @@ -1126,15 +1092,10 @@ UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package) MSIPROGID *progid; MSIRECORD *uirow; - if (!package) - return ERROR_INVALID_HANDLE; - load_classes_and_such(package); LIST_FOR_EACH_ENTRY( progid, &package->progids, MSIPROGID, entry ) { - WCHAR clsid[0x1000]; - /* check if this progid is to be installed */ if (progid->Class && progid->Class->Installed) progid->InstallMe = TRUE; @@ -1148,9 +1109,9 @@ UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package) TRACE("Registering progid %s\n", debugstr_w(progid->ProgID)); - register_progid( package, progid, clsid ); + register_progid( progid ); - uirow = MSI_CreateRecord(1); + uirow = MSI_CreateRecord( 1 ); MSI_RecordSetStringW( uirow, 1, progid->ProgID ); ui_actiondata( package, szRegisterProgIdInfo, uirow ); msiobj_release( &uirow->hdr ); @@ -1247,9 +1208,6 @@ UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package) MSIRECORD *uirow; BOOL install_on_demand = TRUE; - if (!package) - return ERROR_INVALID_HANDLE; - load_classes_and_such(package); /* We need to set install_on_demand based on if the shell handles advertised @@ -1355,9 +1313,6 @@ UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package) MSIRECORD *uirow; MSIMIME *mt; - if (!package) - return ERROR_INVALID_HANDLE; - load_classes_and_such(package); LIST_FOR_EACH_ENTRY( mt, &package->mimes, MSIMIME, entry ) diff --git a/reactos/lib/msi/cond.y b/reactos/lib/msi/cond.y index 977f81afc70..7abf2d34757 100644 --- a/reactos/lib/msi/cond.y +++ b/reactos/lib/msi/cond.y @@ -28,12 +28,14 @@ #include "windef.h" #include "winbase.h" +#include "winuser.h" #include "wine/debug.h" #include "wine/unicode.h" #include "msi.h" #include "msiquery.h" #include "msipriv.h" +#include "action.h" #define YYLEX_PARAM info #define YYPARSE_PARAM info @@ -58,45 +60,44 @@ struct cond_str { static LPWSTR COND_GetString( struct cond_str *str ); static LPWSTR COND_GetLiteral( struct cond_str *str ); static int COND_lex( void *COND_lval, COND_input *info); +static const WCHAR szEmpty[] = { 0 }; -typedef INT (*comp_int)(INT a, INT b); -typedef INT (*comp_str)(LPWSTR a, LPWSTR b, BOOL caseless); -typedef INT (*comp_m1)(LPWSTR a,int b); -typedef INT (*comp_m2)(int a,LPWSTR b); +static INT compare_int( INT a, INT operator, INT b ); +static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b ); -static INT comp_lt_i(INT a, INT b); -static INT comp_gt_i(INT a, INT b); -static INT comp_le_i(INT a, INT b); -static INT comp_ge_i(INT a, INT b); -static INT comp_eq_i(INT a, INT b); -static INT comp_ne_i(INT a, INT b); -static INT comp_bitand(INT a, INT b); -static INT comp_highcomp(INT a, INT b); -static INT comp_lowcomp(INT a, INT b); +static INT compare_and_free_strings( LPWSTR a, INT op, LPWSTR b ) +{ + INT r; -static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless); + r = compare_string( a, op, b ); + msi_free( a ); + msi_free( b ); + return r; +} -static INT comp_eq_m1(LPWSTR a, INT b); -static INT comp_ne_m1(LPWSTR a, INT b); -static INT comp_lt_m1(LPWSTR a, INT b); -static INT comp_gt_m1(LPWSTR a, INT b); -static INT comp_le_m1(LPWSTR a, INT b); -static INT comp_ge_m1(LPWSTR a, INT b); +static BOOL num_from_prop( LPCWSTR p, INT *val ) +{ + INT ret = 0, sign = 1; -static INT comp_eq_m2(INT a, LPWSTR b); -static INT comp_ne_m2(INT a, LPWSTR b); -static INT comp_lt_m2(INT a, LPWSTR b); -static INT comp_gt_m2(INT a, LPWSTR b); -static INT comp_le_m2(INT a, LPWSTR b); -static INT comp_ge_m2(INT a, LPWSTR b); + if (!p) + return FALSE; + if (*p == '-') + { + sign = -1; + p++; + } + if (!*p) + return FALSE; + while (*p) + { + if( *p < '0' || *p > '9' ) + return FALSE; + ret = ret*10 + (*p - '0'); + p++; + } + *val = ret*sign; + return TRUE; +} %} @@ -107,37 +108,36 @@ static INT comp_ge_m2(INT a, LPWSTR b); struct cond_str str; LPWSTR string; INT value; - comp_int fn_comp_int; - comp_str fn_comp_str; - comp_m1 fn_comp_m1; - comp_m2 fn_comp_m2; } %token COND_SPACE COND_EOF COND_SPACE -%token COND_OR COND_AND COND_NOT -%token COND_LT COND_GT COND_EQ -%token COND_LPAR COND_RPAR COND_TILDA +%token COND_OR COND_AND COND_NOT COND_XOR COND_IMP COND_EQV +%token COND_LT COND_GT COND_EQ COND_NE COND_GE COND_LE +%token COND_ILT COND_IGT COND_IEQ COND_INE COND_IGE COND_ILE +%token COND_LPAR COND_RPAR COND_TILDA COND_SS COND_ISS +%token COND_ILHS COND_IRHS COND_LHS COND_RHS %token COND_PERCENT COND_DOLLARS COND_QUESTION COND_AMPER COND_EXCLAM %token COND_IDENT COND_NUMBER COND_LITER -%nonassoc COND_EOF COND_ERROR +%nonassoc COND_ERROR COND_EOF %type expression boolean_term boolean_factor -%type term value_i symbol_i integer -%type identifier value_s symbol_s literal -%type comp_op_i -%type comp_op_s -%type comp_op_m1 -%type comp_op_m2 +%type value_i integer operator +%type identifier symbol_s value_s literal %% condition: - expression + expression { COND_input* cond = (COND_input*) info; cond->result = $1; } + | /* empty */ + { + COND_input* cond = (COND_input*) info; + cond->result = MSICONDITION_NONE; + } ; expression: @@ -145,10 +145,22 @@ expression: { $$ = $1; } - | boolean_term COND_OR expression + | expression COND_OR boolean_term { $$ = $1 || $3; } + | expression COND_IMP boolean_term + { + $$ = !$1 || $3; + } + | expression COND_XOR boolean_term + { + $$ = ( $1 || $3 ) && !( $1 && $3 ); + } + | expression COND_EQV boolean_term + { + $$ = ( $1 && $3 ) || ( !$1 && !$3 ); + } ; boolean_term: @@ -156,59 +168,68 @@ boolean_term: { $$ = $1; } - | boolean_term COND_AND boolean_factor + | boolean_term COND_AND boolean_factor { $$ = $1 && $3; } ; boolean_factor: - term + COND_NOT boolean_factor { - $$ = $1; + $$ = $2 ? 0 : 1; } - | COND_NOT term + | value_i { - $$ = ! $2; - } - ; - - -term: - value_i - { - $$ = $1; + $$ = $1 ? 1 : 0; } | value_s { - $$ = ($1 && $1[0]) ? MSICONDITION_TRUE : MSICONDITION_FALSE; - msi_free( $1 ); + $$ = ($1 && $1[0]) ? 1 : 0; } - | value_i comp_op_i value_i + | value_i operator value_i { - $$ = $2( $1, $3 ); + $$ = compare_int( $1, $2, $3 ); } - | value_s comp_op_s value_s + | symbol_s operator value_i { - $$ = $2( $1, $3, FALSE ); - msi_free( $1 ); - msi_free( $3 ); + int num; + if (num_from_prop( $1, &num )) + $$ = compare_int( num, $2, $3 ); + else + $$ = ($2 == COND_NE || $2 == COND_INE ); } - | value_s COND_TILDA comp_op_s value_s + | value_i operator symbol_s { - $$ = $3( $1, $4, TRUE ); - msi_free( $1 ); - msi_free( $4 ); + int num; + if (num_from_prop( $3, &num )) + $$ = compare_int( $1, $2, num ); + else + $$ = ($2 == COND_NE || $2 == COND_INE ); } - | value_s comp_op_m1 value_i + | symbol_s operator symbol_s { - $$ = $2( $1, $3 ); - msi_free( $1 ); + $$ = compare_and_free_strings( $1, $2, $3 ); } - | value_i comp_op_m2 value_s + | symbol_s operator literal { - $$ = $2( $1, $3 ); - msi_free( $3 ); + $$ = compare_and_free_strings( $1, $2, $3 ); + } + | literal operator symbol_s + { + $$ = compare_and_free_strings( $1, $2, $3 ); + } + | literal operator literal + { + $$ = compare_and_free_strings( $1, $2, $3 ); + } + | literal operator value_i + { + $$ = 0; + } + | value_i operator literal + { + $$ = 0; } | COND_LPAR expression COND_RPAR { @@ -216,183 +237,30 @@ term: } ; -comp_op_i: +operator: /* common functions */ - COND_EQ - { - $$ = comp_eq_i; - } - | COND_LT COND_GT - { - $$ = comp_ne_i; - } - | COND_LT - { - $$ = comp_lt_i; - } - | COND_GT - { - $$ = comp_gt_i; - } - | COND_LT COND_EQ - { - $$ = comp_le_i; - } - | COND_GT COND_EQ - { - $$ = comp_ge_i; - } - /*Int only*/ - | COND_GT COND_LT - { - $$ = comp_bitand; - } - | COND_LT COND_LT - { - $$ = comp_highcomp; - } - | COND_GT COND_GT - { - $$ = comp_lowcomp; - } - ; - -comp_op_s: - /* common functions */ - COND_EQ - { - $$ = comp_eq_s; - } - | COND_LT COND_GT - { - $$ = comp_ne_s; - } - | COND_LT - { - $$ = comp_lt_s; - } - | COND_GT - { - $$ = comp_gt_s; - } - | COND_LT COND_EQ - { - $$ = comp_le_s; - } - | COND_GT COND_EQ - { - $$ = comp_ge_s; - } - /*string only*/ - | COND_GT COND_LT - { - $$ = comp_substring; - } - | COND_LT COND_LT - { - $$ = comp_start; - } - | COND_GT COND_GT - { - $$ = comp_end; - } - ; - -comp_op_m1: - /* common functions */ - COND_EQ - { - $$ = comp_eq_m1; - } - | COND_LT COND_GT - { - $$ = comp_ne_m1; - } - | COND_LT - { - $$ = comp_lt_m1; - } - | COND_GT - { - $$ = comp_gt_m1; - } - | COND_LT COND_EQ - { - $$ = comp_le_m1; - } - | COND_GT COND_EQ - { - $$ = comp_ge_m1; - } - /*Not valid for mixed compares*/ - | COND_GT COND_LT - { - $$ = 0; - } - | COND_LT COND_LT - { - $$ = 0; - } - | COND_GT COND_GT - { - $$ = 0; - } - ; - -comp_op_m2: - /* common functions */ - COND_EQ - { - $$ = comp_eq_m2; - } - | COND_LT COND_GT - { - $$ = comp_ne_m2; - } - | COND_LT - { - $$ = comp_lt_m2; - } - | COND_GT - { - $$ = comp_gt_m2; - } - | COND_LT COND_EQ - { - $$ = comp_le_m2; - } - | COND_GT COND_EQ - { - $$ = comp_ge_m2; - } - /*Not valid for mixed compares*/ - | COND_GT COND_LT - { - $$ = 0; - } - | COND_LT COND_LT - { - $$ = 0; - } - | COND_GT COND_GT - { - $$ = 0; - } - ; - -value_i: - symbol_i - { - $$ = $1; - } - | integer - { - $$ = $1; - } + COND_EQ { $$ = COND_EQ; } + | COND_NE { $$ = COND_NE; } + | COND_LT { $$ = COND_LT; } + | COND_GT { $$ = COND_GT; } + | COND_LE { $$ = COND_LE; } + | COND_GE { $$ = COND_GE; } + | COND_SS { $$ = COND_SS; } + | COND_IEQ { $$ = COND_IEQ; } + | COND_INE { $$ = COND_INE; } + | COND_ILT { $$ = COND_ILT; } + | COND_IGT { $$ = COND_IGT; } + | COND_ILE { $$ = COND_ILE; } + | COND_IGE { $$ = COND_IGE; } + | COND_ISS { $$ = COND_ISS; } + | COND_LHS { $$ = COND_LHS; } + | COND_RHS { $$ = COND_RHS; } + | COND_ILHS { $$ = COND_ILHS; } + | COND_IRHS { $$ = COND_IRHS; } ; value_s: - symbol_s + symbol_s { $$ = $1; } @@ -411,8 +279,12 @@ literal: } ; -symbol_i: - COND_DOLLARS identifier +value_i: + integer + { + $$ = $1; + } + | COND_DOLLARS identifier { COND_input* cond = (COND_input*) info; INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; @@ -453,35 +325,19 @@ symbol_i: symbol_s: identifier { - DWORD sz; COND_input* cond = (COND_input*) info; - sz = 0; - MSI_GetPropertyW(cond->package, $1, NULL, &sz); - if (sz == 0) - { - $$ = msi_alloc( sizeof(WCHAR)); - $$[0] = 0; - } - else - { - sz ++; - $$ = msi_alloc( sz*sizeof (WCHAR) ); - - /* Lookup the identifier */ - - MSI_GetPropertyW(cond->package,$1,$$,&sz); - } + $$ = msi_dup_property( cond->package, $1 ); msi_free( $1 ); } | COND_PERCENT identifier { UINT len = GetEnvironmentVariableW( $2, NULL, 0 ); - if( len++ ) + $$ = NULL; + if (len++) { $$ = msi_alloc( len*sizeof (WCHAR) ); - if( $$ ) - GetEnvironmentVariableW( $2, $$, len ); + GetEnvironmentVariableW( $2, $$, len ); } msi_free( $2 ); } @@ -522,83 +378,105 @@ static int COND_IsNumber( WCHAR x ) return( (( x >= '0' ) && ( x <= '9' )) || (x =='-') || (x =='.') ); } +static WCHAR *strstriW( const WCHAR *str, const WCHAR *sub ) +{ + LPWSTR strlower, sublower, r; + strlower = CharLowerW( strdupW( str ) ); + sublower = CharLowerW( strdupW( sub ) ); + r = strstrW( strlower, sublower ); + if (r) + r = (LPWSTR)str + (r - strlower); + msi_free( strlower ); + msi_free( sublower ); + return r; +} -/* the mess of comparison functions */ +static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b ) +{ + /* null and empty string are equivalent */ + if (!a) a = szEmpty; + if (!b) b = szEmpty; -static INT comp_lt_i(INT a, INT b) -{ return (a < b); } -static INT comp_gt_i(INT a, INT b) -{ return (a > b); } -static INT comp_le_i(INT a, INT b) -{ return (a <= b); } -static INT comp_ge_i(INT a, INT b) -{ return (a >= b); } -static INT comp_eq_i(INT a, INT b) -{ return (a == b); } -static INT comp_ne_i(INT a, INT b) -{ return (a != b); } -static INT comp_bitand(INT a, INT b) -{ return a & b;} -static INT comp_highcomp(INT a, INT b) -{ return HIWORD(a)==b; } -static INT comp_lowcomp(INT a, INT b) -{ return LOWORD(a)==b; } - -static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return !strcmpiW(a,b); else return !strcmpW(a,b);} -static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b); else return strcmpW(a,b);} -static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)<0; else return strcmpW(a,b)<0;} -static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)>0; else return strcmpW(a,b)>0;} -static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)<=0; else return strcmpW(a,b)<=0;} -static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)>=0; else return strcmpW(a,b)>=0;} -static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless) -/* ERROR NOT WORKING REWRITE */ -{ if (casless) return strstrW(a,b)!=NULL; else return strstrW(a,b)!=NULL;} -static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strncmpiW(a,b,strlenW(b))==0; - else return strncmpW(a,b,strlenW(b))==0;} -static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless) -{ - int i = strlenW(a); - int j = strlenW(b); - if (j>i) + /* a or b may be NULL */ + switch (operator) + { + case COND_LT: + return -1 == lstrcmpW( a, b ); + case COND_GT: + return 1 == lstrcmpW( a, b ); + case COND_EQ: + return 0 == lstrcmpW( a, b ); + case COND_NE: + return 0 != lstrcmpW( a, b ); + case COND_GE: + return -1 != lstrcmpW( a, b ); + case COND_LE: + return 1 != lstrcmpW( a, b ); + case COND_SS: /* substring */ + return strstrW( a, b ) ? 1 : 0; + case COND_ILT: + return -1 == lstrcmpiW( a, b ); + case COND_IGT: + return 1 == lstrcmpiW( a, b ); + case COND_IEQ: + return 0 == lstrcmpiW( a, b ); + case COND_INE: + return 0 != lstrcmpiW( a, b ); + case COND_IGE: + return -1 != lstrcmpiW( a, b ); + case COND_ILE: + return 1 != lstrcmpiW( a, b ); + case COND_ISS: + return strstriW( a, b ) ? 1 : 0; + case COND_LHS: + case COND_RHS: + case COND_ILHS: + case COND_IRHS: + ERR("unimplemented string comparison\n"); + break; + default: + ERR("invalid integer operator\n"); return 0; - if (casless) return (!strcmpiW(&a[i-j-1],b)); - else return (!strcmpW(&a[i-j-1],b)); + } + return 0; } -static INT comp_eq_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)==b; else return 0;} -static INT comp_ne_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)!=b; else return 1;} -static INT comp_lt_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)b; else return 0;} -static INT comp_le_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)<=b; else return 0;} -static INT comp_ge_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)>=b; else return 0;} - -static INT comp_eq_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a == atoiW(b); else return 0;} -static INT comp_ne_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a != atoiW(b); else return 1;} -static INT comp_lt_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a < atoiW(b); else return 0;} -static INT comp_gt_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a > atoiW(b); else return 0;} -static INT comp_le_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a <= atoiW(b); else return 0;} -static INT comp_ge_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a >= atoiW(b); else return 0;} - +static INT compare_int( INT a, INT operator, INT b ) +{ + switch (operator) + { + case COND_LT: + case COND_ILT: + return a < b; + case COND_GT: + case COND_IGT: + return a > b; + case COND_EQ: + case COND_IEQ: + return a == b; + case COND_NE: + case COND_INE: + return a != b; + case COND_GE: + case COND_IGE: + return a >= b; + case COND_LE: + case COND_ILE: + return a >= b; + case COND_SS: + case COND_ISS: + return ( a & b ) ? 1 : 0; + case COND_RHS: + return ( ( a & 0xffff ) == b ) ? 1 : 0; + case COND_LHS: + return ( ( (a>>16) & 0xffff ) == b ) ? 1 : 0; + default: + ERR("invalid integer operator\n"); + return 0; + } + return 0; +} static int COND_IsIdent( WCHAR x ) @@ -607,17 +485,54 @@ static int COND_IsIdent( WCHAR x ) || ( x == '#' ) || (x == '.') ); } +static int COND_GetOperator( COND_input *cond ) +{ + static const struct { + const WCHAR str[4]; + int id; + } table[] = { + { {'~','=',0}, COND_IEQ }, + { {'~','>','=',0}, COND_ILE }, + { {'~','>','<',0}, COND_ISS }, + { {'~','>','>',0}, COND_IRHS }, + { {'~','>',0}, COND_ILT }, + { {'~','<','>',0}, COND_INE }, + { {'~','<','=',0}, COND_IGE }, + { {'~','<','<',0}, COND_ILHS }, + { {'~','<',0}, COND_IGT }, + { {'>','=',0}, COND_GE }, + { {'>','<',0}, COND_SS }, + { {'>','>',0}, COND_LHS }, + { {'>',0}, COND_GT }, + { {'<','>',0}, COND_NE }, + { {'<','=',0}, COND_LE }, + { {'<','<',0}, COND_RHS }, + { {'<',0}, COND_LT }, + { {0}, 0 } + }; + LPCWSTR p = &cond->str[cond->n]; + int i = 0, len; + + while ( 1 ) + { + len = lstrlenW( table[i].str ); + if ( !len || 0 == strncmpW( table[i].str, p, len ) ) + break; + i++; + } + cond->n += len; + return table[i].id; +} + static int COND_GetOne( struct cond_str *str, COND_input *cond ) { - static const WCHAR szNot[] = {'N','O','T',0}; - static const WCHAR szAnd[] = {'A','N','D',0}; - static const WCHAR szOr[] = {'O','R',0}; - WCHAR ch; int rc, len = 1; + WCHAR ch; str->data = &cond->str[cond->n]; ch = str->data[0]; + switch( ch ) { case 0: return 0; @@ -630,58 +545,73 @@ static int COND_GetOne( struct cond_str *str, COND_input *cond ) case '%': rc = COND_PERCENT; break; case ' ': rc = COND_SPACE; break; case '=': rc = COND_EQ; break; - case '~': rc = COND_TILDA; break; - case '<': rc = COND_LT; break; - case '>': rc = COND_GT; break; - case '"': - { - const WCHAR *ch2 = str->data + 1; - - - while ( *ch2 && *ch2 != '"' ) - ++ch2; - if (*ch2 == '"') - { - len = ch2 - str->data + 1; - rc = COND_LITER; - break; - } - } - ERR("Unterminated string\n"); - rc = COND_ERROR; - break; - default: - if( COND_IsAlpha( ch ) ) - { - while( COND_IsIdent( str->data[len] ) ) - len++; - rc = COND_IDENT; - break; - } - - if( COND_IsNumber( ch ) ) - { - while( COND_IsNumber( str->data[len] ) ) - len++; - rc = COND_NUMBER; - break; - } - - ERR("Got unknown character %c(%x)\n",ch,ch); - rc = COND_ERROR; break; + + case '~': + case '<': + case '>': + rc = COND_GetOperator( cond ); + if (!rc) + rc = COND_ERROR; + return rc; + default: + rc = 0; } - /* keyword identifiers */ - if( rc == COND_IDENT ) + if ( rc ) { - if( (len==3) && (strncmpiW(str->data,szNot,len)==0) ) - rc = COND_NOT; - else if( (len==3) && (strncmpiW(str->data,szAnd,len)==0) ) - rc = COND_AND; - else if( (len==2) && (strncmpiW(str->data,szOr,len)==0) ) + cond->n += len; + return rc; + } + + if (ch == '"' ) + { + LPCWSTR p = strchrW( str->data + 1, '"' ); + if (!p) + return COND_ERROR; + len = p - str->data + 1; + rc = COND_LITER; + } + else if( COND_IsAlpha( ch ) ) + { + static const WCHAR szNot[] = {'N','O','T',0}; + static const WCHAR szAnd[] = {'A','N','D',0}; + static const WCHAR szXor[] = {'X','O','R',0}; + static const WCHAR szEqv[] = {'E','Q','V',0}; + static const WCHAR szImp[] = {'I','M','P',0}; + static const WCHAR szOr[] = {'O','R',0}; + + while( COND_IsIdent( str->data[len] ) ) + len++; + rc = COND_IDENT; + + if ( len == 3 ) + { + if ( !strncmpiW( str->data, szNot, len ) ) + rc = COND_NOT; + else if( !strncmpiW( str->data, szAnd, len ) ) + rc = COND_AND; + else if( !strncmpiW( str->data, szXor, len ) ) + rc = COND_XOR; + else if( !strncmpiW( str->data, szEqv, len ) ) + rc = COND_EQV; + else if( !strncmpiW( str->data, szImp, len ) ) + rc = COND_IMP; + } + else if( (len == 2) && !strncmpiW( str->data, szOr, len ) ) rc = COND_OR; } + else if( COND_IsNumber( ch ) ) + { + while( COND_IsNumber( str->data[len] ) ) + len++; + rc = COND_NUMBER; + } + else + { + ERR("Got unknown character %c(%x)\n",ch,ch); + return COND_ERROR; + } cond->n += len; str->len = len; @@ -731,6 +661,7 @@ static LPWSTR COND_GetLiteral( struct cond_str *str ) static int COND_error(const char *str) { + TRACE("%s\n", str ); return 0; } @@ -739,21 +670,22 @@ MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition ) COND_input cond; MSICONDITION r; + TRACE("%s\n", debugstr_w( szCondition ) ); + + if ( szCondition == NULL ) + return MSICONDITION_NONE; + cond.package = package; cond.str = szCondition; cond.n = 0; - cond.result = -1; + cond.result = MSICONDITION_ERROR; - TRACE("Evaluating %s\n",debugstr_w(szCondition)); - - if ( szCondition == NULL || szCondition[0] == 0) - r = MSICONDITION_NONE; - else if ( !COND_parse( &cond ) ) + if ( !COND_parse( &cond ) ) r = cond.result; else r = MSICONDITION_ERROR; - TRACE("Evaluates to %i\n",r); + TRACE("%i <- %s\n", r, debugstr_w(szCondition)); return r; } @@ -764,7 +696,7 @@ MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szConditi package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); if( !package) - return ERROR_INVALID_HANDLE; + return MSICONDITION_ERROR; ret = MSI_EvaluateConditionW( package, szCondition ); msiobj_release( &package->hdr ); return ret; @@ -775,16 +707,11 @@ MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szConditio LPWSTR szwCond = NULL; MSICONDITION r; - if( szCondition ) - { - UINT len = MultiByteToWideChar( CP_ACP, 0, szCondition, -1, NULL, 0 ); - szwCond = msi_alloc( len * sizeof (WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, szCondition, -1, szwCond, len ); - } + szwCond = strdupAtoW( szCondition ); + if( szCondition && !szwCond ) + return MSICONDITION_ERROR; r = MsiEvaluateConditionW( hInstall, szwCond ); - msi_free( szwCond ); - return r; } diff --git a/reactos/lib/msi/create.c b/reactos/lib/msi/create.c index 2e98a2cec1a..fb93c626bef 100644 --- a/reactos/lib/msi/create.c +++ b/reactos/lib/msi/create.c @@ -33,7 +33,7 @@ #include "query.h" -WINE_DEFAULT_DEBUG_CHANNEL(msi); +WINE_DEFAULT_DEBUG_CHANNEL(msidb); /* below is the query interface to a table */ diff --git a/reactos/lib/msi/custom.c b/reactos/lib/msi/custom.c index efb40c5777f..170e214e493 100644 --- a/reactos/lib/msi/custom.c +++ b/reactos/lib/msi/custom.c @@ -125,8 +125,7 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute) ' ','W','H','E','R','E',' ','`','A','c','t','i' ,'o','n','`',' ', '=',' ','\'','%','s','\'',0}; UINT type; - LPWSTR source; - LPWSTR target; + LPCWSTR source, target; WCHAR *deformated=NULL; row = MSI_QueryGetRecord( package->db, ExecSeqQuery, action ); @@ -135,8 +134,8 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute) type = MSI_RecordGetInteger(row,2); - source = load_dynamic_stringW(row,3); - target = load_dynamic_stringW(row,4); + source = MSI_RecordGetString(row,3); + target = MSI_RecordGetString(row,4); TRACE("Handling custom action %s (%x %s %s)\n",debugstr_w(action),type, debugstr_w(source), debugstr_w(target)); @@ -231,8 +230,6 @@ UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute) } end: - msi_free(source); - msi_free(target); msiobj_release(&row->hdr); return rc; } @@ -330,16 +327,16 @@ static UINT process_action_return_value(UINT type, HANDLE ThreadHandle) switch (rc) { - case ERROR_FUNCTION_NOT_CALLED: - case ERROR_SUCCESS: - case ERROR_INSTALL_USEREXIT: - case ERROR_INSTALL_FAILURE: - return rc; - case ERROR_NO_MORE_ITEMS: - return ERROR_SUCCESS; - default: - ERR("Invalid Return Code %lx\n",rc); - return ERROR_INSTALL_FAILURE; + case ERROR_FUNCTION_NOT_CALLED: + case ERROR_SUCCESS: + case ERROR_INSTALL_USEREXIT: + case ERROR_INSTALL_FAILURE: + return rc; + case ERROR_NO_MORE_ITEMS: + return ERROR_SUCCESS; + default: + ERR("Invalid Return Code %ld\n",rc); + return ERROR_INSTALL_FAILURE; } } @@ -416,7 +413,7 @@ static DWORD WINAPI ACTION_CallDllFunction(thread_struct *stuff) CustomEntry *fn; DWORD rc = ERROR_SUCCESS; - TRACE("calling function (%s, %s) \n", debugstr_w(stuff->source), + TRACE("calling function (%s, %s)\n", debugstr_w(stuff->source), debugstr_w(stuff->target)); hModule = LoadLibraryW(stuff->source); @@ -546,7 +543,7 @@ static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source, msi_free(deformated); } - TRACE("executing exe %s \n",debugstr_w(cmd)); + TRACE("executing exe %s\n", debugstr_w(cmd)); rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL, c_collen, &si, &info); @@ -607,7 +604,7 @@ static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source, msi_free(deformated); } - TRACE("executing exe %s \n",debugstr_w(cmd)); + TRACE("executing exe %s\n", debugstr_w(cmd)); rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL, c_collen, &si, &info); @@ -692,7 +689,7 @@ static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source, } msi_free(prop); - TRACE("executing exe %s \n",debugstr_w(cmd)); + TRACE("executing exe %s\n", debugstr_w(cmd)); rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL, c_collen, &si, &info); @@ -732,7 +729,7 @@ static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source, if (!deformated) return ERROR_FUNCTION_FAILED; - TRACE("executing exe %s \n",debugstr_w(deformated)); + TRACE("executing exe %s\n", debugstr_w(deformated)); rc = CreateProcessW(NULL, deformated, NULL, NULL, FALSE, 0, NULL, c_collen, &si, &info); diff --git a/reactos/lib/msi/database.c b/reactos/lib/msi/database.c index d4a965561d5..4da53381cf8 100644 --- a/reactos/lib/msi/database.c +++ b/reactos/lib/msi/database.c @@ -38,14 +38,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); -/* - * The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR, - * which is a problem because LPCTSTR isn't defined when compiling wine. - * To work around this problem, we need to define LPCTSTR as LPCWSTR here, - * and make sure to only use it in W functions. - */ -#define LPCTSTR LPCWSTR - DEFINE_GUID( CLSID_MsiDatabase, 0x000c1084, 0x0000, 0x0000, 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); DEFINE_GUID( CLSID_MsiPatch, 0x000c1086, 0x0000, 0x0000, @@ -67,6 +59,7 @@ static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg ) DWORD r; free_cached_tables( db ); + msi_free_transforms( db ); msi_destroy_stringtable( db->strings ); r = IStorage_Release( db->storage ); if( r ) @@ -156,6 +149,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb) db->storage = stg; db->mode = szMode; list_init( &db->tables ); + list_init( &db->transforms ); db->strings = load_string_table( stg ); if( !db->strings ) diff --git a/reactos/lib/msi/delete.c b/reactos/lib/msi/delete.c index d42bf600649..7f6675fe220 100644 --- a/reactos/lib/msi/delete.c +++ b/reactos/lib/msi/delete.c @@ -33,7 +33,7 @@ #include "query.h" -WINE_DEFAULT_DEBUG_CHANNEL(msi); +WINE_DEFAULT_DEBUG_CHANNEL(msidb); /* diff --git a/reactos/lib/msi/dialog.c b/reactos/lib/msi/dialog.c index 7a9c20d8974..3975891ec13 100644 --- a/reactos/lib/msi/dialog.c +++ b/reactos/lib/msi/dialog.c @@ -19,6 +19,8 @@ */ #define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT #include @@ -80,6 +82,8 @@ struct msi_dialog_tag msi_font *font_list; struct list controls; HWND hWndFocus; + LPWSTR control_default; + LPWSTR control_cancel; WCHAR name[1]; }; @@ -102,9 +106,9 @@ const WCHAR szMsiDialogClass[] = { }; const WCHAR szMsiHiddenWindow[] = { 'M','s','i','H','i','d','d','e','n','W','i','n','d','o','w',0 }; -const static WCHAR szStatic[] = { 'S','t','a','t','i','c',0 }; -const static WCHAR szButton[] = { 'B','U','T','T','O','N', 0 }; -const static WCHAR szButtonData[] = { 'M','S','I','D','A','T','A',0 }; +static const WCHAR szStatic[] = { 'S','t','a','t','i','c',0 }; +static const WCHAR szButton[] = { 'B','U','T','T','O','N', 0 }; +static const WCHAR szButtonData[] = { 'M','S','I','D','A','T','A',0 }; static const WCHAR szText[] = { 'T','e','x','t',0 }; static const WCHAR szPushButton[] = { 'P','u','s','h','B','u','t','t','o','n',0 }; static const WCHAR szLine[] = { 'L','i','n','e',0 }; @@ -121,6 +125,8 @@ static const WCHAR szProgressBar[] = { static const WCHAR szRadioButtonGroup[] = { 'R','a','d','i','o','B','u','t','t','o','n','G','r','o','u','p',0 }; static const WCHAR szIcon[] = { 'I','c','o','n',0 }; +static const WCHAR szSelectionTree[] = { + 'S','e','l','e','c','t','i','o','n','T','r','e','e',0 }; static UINT msi_dialog_checkbox_handler( msi_dialog *, msi_control *, WPARAM ); static void msi_dialog_checkbox_sync_state( msi_dialog *, msi_control * ); @@ -359,7 +365,7 @@ static msi_control *msi_dialog_create_window( msi_dialog *dialog, static MSIRECORD *msi_get_binary_record( MSIDATABASE *db, LPCWSTR name ) { - const static WCHAR query[] = { + static const WCHAR query[] = { 's','e','l','e','c','t',' ','*',' ', 'f','r','o','m',' ','B','i','n','a','r','y',' ', 'w','h','e','r','e',' ', @@ -623,7 +629,7 @@ static UINT msi_dialog_button_control( msi_dialog *dialog, MSIRECORD *rec ) static LPWSTR msi_get_checkbox_value( msi_dialog *dialog, LPCWSTR prop ) { - const static WCHAR query[] = { + static const WCHAR query[] = { 'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ','`','C','h','e','c','k','B','o','x',' ','`', 'W','H','E','R','E',' ', @@ -714,7 +720,7 @@ msi_richedit_stream_in( DWORD_PTR arg, LPBYTE buffer, LONG count, LONG *pcb ) static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec ) { - const static WCHAR szRichEdit20W[] = { + static const WCHAR szRichEdit20W[] = { 'R','i','c','h','E','d','i','t','2','0','W',0 }; struct msi_streamin_info info; @@ -750,6 +756,73 @@ static UINT msi_dialog_scrolltext_control( msi_dialog *dialog, MSIRECORD *rec ) return ERROR_SUCCESS; } +static HBITMAP msi_load_picture( MSIDATABASE *db, LPCWSTR name, + INT cx, INT cy, DWORD flags ) +{ + HBITMAP hOleBitmap = 0, hBitmap = 0, hOldSrcBitmap, hOldDestBitmap; + MSIRECORD *rec = NULL; + IStream *stm = NULL; + IPicture *pic = NULL; + HDC srcdc, destdc; + BITMAP bm; + UINT r; + + rec = msi_get_binary_record( db, name ); + if( !rec ) + goto end; + + r = MSI_RecordGetIStream( rec, 2, &stm ); + msiobj_release( &rec->hdr ); + if( r != ERROR_SUCCESS ) + goto end; + + r = OleLoadPicture( stm, 0, TRUE, &IID_IPicture, (LPVOID*) &pic ); + IStream_Release( stm ); + if( FAILED( r ) ) + { + ERR("failed to load picture\n"); + goto end; + } + + r = IPicture_get_Handle( pic, (OLE_HANDLE*) &hOleBitmap ); + if( FAILED( r ) ) + { + ERR("failed to get bitmap handle\n"); + goto end; + } + + /* make the bitmap the desired size */ + r = GetObjectW( hOleBitmap, sizeof bm, &bm ); + if (r != sizeof bm ) + { + ERR("failed to get bitmap size\n"); + goto end; + } + + if (flags & LR_DEFAULTSIZE) + { + cx = bm.bmWidth; + cy = bm.bmHeight; + } + + srcdc = CreateCompatibleDC( NULL ); + hOldSrcBitmap = SelectObject( srcdc, hOleBitmap ); + destdc = CreateCompatibleDC( NULL ); + hBitmap = CreateCompatibleBitmap( srcdc, cx, cy ); + hOldDestBitmap = SelectObject( destdc, hBitmap ); + StretchBlt( destdc, 0, 0, cx, cy, + srcdc, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); + SelectObject( srcdc, hOldSrcBitmap ); + SelectObject( destdc, hOldDestBitmap ); + DeleteDC( srcdc ); + DeleteDC( destdc ); + +end: + if ( pic ) + IPicture_Release( pic ); + return hBitmap; +} + static UINT msi_dialog_bitmap_control( msi_dialog *dialog, MSIRECORD *rec ) { UINT cx, cy, flags, style, attributes; @@ -773,8 +846,7 @@ static UINT msi_dialog_bitmap_control( msi_dialog *dialog, MSIRECORD *rec ) cy = msi_dialog_scale_unit( dialog, cy ); text = msi_get_deformatted_field( dialog->package, rec, 10 ); - control->hBitmap = msi_load_image( dialog->package->db, text, - IMAGE_BITMAP, cx, cy, flags ); + control->hBitmap = msi_load_picture( dialog->package->db, text, cx, cy, flags ); if( control->hBitmap ) SendMessageW( control->hwnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) control->hBitmap ); @@ -858,6 +930,20 @@ struct msi_maskedit_info struct msi_mask_group group[MASK_MAX_GROUPS]; }; +static BOOL msi_mask_editable( WCHAR type ) +{ + switch (type) + { + case '%': + case '#': + case '&': + case '`': + case '?': + return TRUE; + } + return FALSE; +} + static void msi_mask_control_change( struct msi_maskedit_info *info ) { LPWSTR val; @@ -871,9 +957,18 @@ static void msi_mask_control_change( struct msi_maskedit_info *info ) ERR("can't fit control %d text into template\n",i); break; } - r = GetWindowTextW( info->group[i].hwnd, &val[n], info->group[i].len+1 ); - if( r != info->group[i].len ) - break; + if (!msi_mask_editable(info->group[i].type)) + { + for(r=0; rgroup[i].len; r++) + val[n+r] = info->group[i].type; + val[n+r] = 0; + } + else + { + r = GetWindowTextW( info->group[i].hwnd, &val[n], info->group[i].len+1 ); + if( r != info->group[i].len ) + break; + } n += r; } @@ -991,12 +1086,6 @@ static struct msi_maskedit_info * msi_dialog_parse_groups( LPCWSTR mask ) p++; for( i=0; i' ) break; @@ -1043,6 +1132,8 @@ msi_maskedit_create_children( struct msi_maskedit_info *info, LPCWSTR font ) for( i = 0; i < info->num_groups; i++ ) { + if (!msi_mask_editable( info->group[i].type )) + continue; wx = (info->group[i].ofs * width) / info->num_chars; ww = (info->group[i].len * width) / info->num_chars; @@ -1062,7 +1153,10 @@ msi_maskedit_create_children( struct msi_maskedit_info *info, LPCWSTR font ) } } -/* office 2003 uses "73931<````=````=````=````=`````>@@@@@" */ +/* + * office 2003 uses "73931<````=````=````=````=`````>@@@@@" + * delphi 7 uses "" and "" + */ static UINT msi_dialog_maskedit_control( msi_dialog *dialog, MSIRECORD *rec ) { LPWSTR font_mask, val = NULL, font; @@ -1228,6 +1322,63 @@ static UINT msi_dialog_radiogroup_control( msi_dialog *dialog, MSIRECORD *rec ) return r; } +/******************** Selection Tree ***************************************/ + +static void +msi_dialog_tv_add_child_features( MSIPACKAGE *package, HWND hwnd, + LPCWSTR parent, HTREEITEM hParent ) +{ + MSIFEATURE *feature; + TVINSERTSTRUCTW tvis; + HTREEITEM hitem; + + LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) + { + if ( lstrcmpW( parent, feature->Feature_Parent ) ) + continue; + + if ( !feature->Title ) + continue; + + memset( &tvis, 0, sizeof tvis ); + tvis.hParent = hParent; + tvis.hInsertAfter = TVI_SORT; + if (feature->Title) + { + tvis.u.item.mask = TVIF_TEXT; + tvis.u.item.pszText = feature->Title; + } + tvis.u.item.lParam = (LPARAM) feature; + hitem = (HTREEITEM) SendMessageW( hwnd, TVM_INSERTITEMW, 0, (LPARAM) &tvis ); + if (!hitem) + continue; + + msi_dialog_tv_add_child_features( package, hwnd, + feature->Feature, hitem ); + } +} + +static UINT msi_dialog_selection_tree( msi_dialog *dialog, MSIRECORD *rec ) +{ + msi_control *control; + LPCWSTR prop; + LPWSTR val; + MSIPACKAGE *package = dialog->package; + + prop = MSI_RecordGetString( rec, 9 ); + val = msi_dup_property( package, prop ); + control = msi_dialog_add_control( dialog, rec, WC_TREEVIEWW, + TVS_HASBUTTONS | WS_GROUP | WS_VSCROLL ); + if (!control) + return ERROR_FUNCTION_FAILED; + + msi_dialog_tv_add_child_features( package, control->hwnd, NULL, NULL ); + + msi_free( val ); + + return ERROR_SUCCESS; +} + struct control_handler msi_dialog_handler[] = { { szText, msi_dialog_text_control }, @@ -1243,6 +1394,7 @@ struct control_handler msi_dialog_handler[] = { szProgressBar, msi_dialog_progress_bar }, { szRadioButtonGroup, msi_dialog_radiogroup_control }, { szIcon, msi_dialog_icon_control }, + { szSelectionTree, msi_dialog_selection_tree }, }; #define NUM_CONTROL_TYPES (sizeof msi_dialog_handler/sizeof msi_dialog_handler[0]) @@ -1309,7 +1461,7 @@ static UINT msi_dialog_set_control_condition( MSIRECORD *rec, LPVOID param ) condition = MSI_RecordGetString( rec, 4 ); r = MSI_EvaluateConditionW( dialog->package, condition ); control = msi_dialog_find_control( dialog, name ); - if( r && control ) + if( r == MSICONDITION_TRUE && control ) { TRACE("%s control %s\n", debugstr_w(action), debugstr_w(name)); @@ -1558,7 +1710,7 @@ static UINT msi_dialog_control_event( MSIRECORD *rec, LPVOID param ) condition = MSI_RecordGetString( rec, 5 ); r = MSI_EvaluateConditionW( dialog->package, condition ); - if( r ) + if( r == MSICONDITION_TRUE ) { event = MSI_RecordGetString( rec, 3 ); arg = MSI_RecordGetString( rec, 4 ); @@ -1710,11 +1862,22 @@ static UINT msi_dialog_radiogroup_handler( msi_dialog *dialog, static LRESULT msi_dialog_oncommand( msi_dialog *dialog, WPARAM param, HWND hwnd ) { - msi_control *control; + msi_control *control = NULL; TRACE("%p %p %08x\n", dialog, hwnd, param); - control = msi_dialog_find_control_by_hwnd( dialog, hwnd ); + switch (param) + { + case 1: /* enter */ + control = msi_dialog_find_control( dialog, dialog->control_default ); + break; + case 2: /* escape */ + control = msi_dialog_find_control( dialog, dialog->control_cancel ); + break; + default: + control = msi_dialog_find_control_by_hwnd( dialog, hwnd ); + } + if( control ) { if( control->handler ) @@ -1724,7 +1887,7 @@ static LRESULT msi_dialog_oncommand( msi_dialog *dialog, WPARAM param, HWND hwnd } } else - ERR("button click from nowhere\n"); + ERR("button click from nowhere %p %d %p\n", dialog, param, hwnd); return 0; } @@ -1835,6 +1998,8 @@ msi_dialog *msi_dialog_create( MSIPACKAGE* package, LPCWSTR szDialogName, return NULL; } dialog->attributes = MSI_RecordGetInteger( rec, 6 ); + dialog->control_default = strdupW( MSI_RecordGetString( rec, 9 ) ); + dialog->control_cancel = strdupW( MSI_RecordGetString( rec, 10 ) ); msiobj_release( &rec->hdr ); return dialog; @@ -1978,6 +2143,8 @@ void msi_dialog_destroy( msi_dialog *dialog ) } msi_free( dialog->default_font ); + msi_free( dialog->control_default ); + msi_free( dialog->control_cancel ); msiobj_release( &dialog->package->hdr ); dialog->package = NULL; msi_free( dialog ); @@ -2018,6 +2185,8 @@ BOOL msi_dialog_register_class( void ) void msi_dialog_unregister_class( void ) { DestroyWindow( hMsiHiddenWindow ); + hMsiHiddenWindow = NULL; UnregisterClassW( szMsiDialogClass, NULL ); + UnregisterClassW( szMsiHiddenWindow, NULL ); uiThreadId = 0; } diff --git a/reactos/lib/msi/distinct.c b/reactos/lib/msi/distinct.c index 7ecd48d20fa..f5b6bd225d8 100644 --- a/reactos/lib/msi/distinct.c +++ b/reactos/lib/msi/distinct.c @@ -33,7 +33,7 @@ #include "query.h" -WINE_DEFAULT_DEBUG_CHANNEL(msi); +WINE_DEFAULT_DEBUG_CHANNEL(msidb); typedef struct tagDISTINCTSET { diff --git a/reactos/lib/msi/files.c b/reactos/lib/msi/files.c index c292833191e..694f6d668a1 100644 --- a/reactos/lib/msi/files.c +++ b/reactos/lib/msi/files.c @@ -56,26 +56,6 @@ extern const WCHAR szRemoveFiles[]; static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0}; -static UINT create_component_directory( MSIPACKAGE* package, MSICOMPONENT *comp ) -{ - UINT rc = ERROR_SUCCESS; - MSIFOLDER *folder; - LPWSTR install_path; - - install_path = resolve_folder(package, comp->Directory, FALSE, FALSE, &folder); - if (!install_path) - return ERROR_FUNCTION_FAILED; - - /* create the path */ - if (folder->State == 0) - { - create_full_pathW(install_path); - folder->State = 2; - } - msi_free(install_path); - - return rc; -} /* * This is a helper function for handling embedded cabinet media @@ -139,6 +119,7 @@ static void cabinet_free(void *pv) static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode) { + HANDLE handle; DWORD dwAccess = 0; DWORD dwShareMode = 0; DWORD dwCreateDisposition = OPEN_EXISTING; @@ -161,35 +142,62 @@ static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode) dwCreateDisposition = CREATE_NEW; else if (oflag & _O_CREAT) dwCreateDisposition = CREATE_ALWAYS; - return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL, - dwCreateDisposition, 0, NULL); + handle = CreateFileA( pszFile, dwAccess, dwShareMode, NULL, + dwCreateDisposition, 0, NULL ); + if (handle == INVALID_HANDLE_VALUE) + return 0; + return (INT_PTR) handle; } static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb) { + HANDLE handle = (HANDLE) hf; DWORD dwRead; - if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL)) + if (ReadFile(handle, pv, cb, &dwRead, NULL)) return dwRead; return 0; } static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb) { + HANDLE handle = (HANDLE) hf; DWORD dwWritten; - if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL)) + if (WriteFile(handle, pv, cb, &dwWritten, NULL)) return dwWritten; return 0; } static int cabinet_close(INT_PTR hf) { - return CloseHandle((HANDLE)hf) ? 0 : -1; + HANDLE handle = (HANDLE) hf; + return CloseHandle(handle) ? 0 : -1; } static long cabinet_seek(INT_PTR hf, long dist, int seektype) { + HANDLE handle = (HANDLE) hf; /* flags are compatible and so are passed straight through */ - return SetFilePointer((HANDLE)hf, dist, NULL, seektype); + return SetFilePointer(handle, dist, NULL, seektype); +} + +static void msi_file_update_ui( MSIPACKAGE *package, MSIFILE *f ) +{ + MSIRECORD *uirow; + LPWSTR uipath, p; + + /* the UI chunk */ + uirow = MSI_CreateRecord( 9 ); + MSI_RecordSetStringW( uirow, 1, f->FileName ); + uipath = strdupW( f->TargetPath ); + p = strrchrW(uipath,'\\'); + if (p) + p[1]=0; + MSI_RecordSetStringW( uirow, 9, uipath); + MSI_RecordSetInteger( uirow, 6, f->FileSize ); + ui_actiondata( package, szInstallFiles, uirow); + msiobj_release( &uirow->hdr ); + msi_free( uipath ); + ui_progress( package, 2, f->FileSize, 0, 0); } static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) @@ -199,22 +207,13 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) case fdintCOPY_FILE: { CabData *data = (CabData*) pfdin->pv; - ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1); - char *file; - - LPWSTR trackname; - LPWSTR trackpath; - LPWSTR tracknametmp; - static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0}; - LPWSTR given_file; - - MSIRECORD * uirow; - LPWSTR uipath; + HANDLE handle; + LPWSTR file; MSIFILE *f; - given_file = strdupAtoW(pfdin->psz1); - f = get_loaded_file(data->package, given_file); - msi_free(given_file); + file = strdupAtoW(pfdin->psz1); + f = get_loaded_file(data->package, file); + msi_free(file); if (!f) { @@ -222,60 +221,41 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin) return 0; } - if (!((f->State == 1 || f->State == 2))) + if (f->state != msifs_missing && f->state != msifs_overwrite) { TRACE("Skipping extraction of %s\n",debugstr_a(pfdin->psz1)); return 0; } - file = cabinet_alloc((len+1)*sizeof(char)); - strcpy(file, data->cab_path); - strcat(file, pfdin->psz1); + msi_file_update_ui( data->package, f ); - TRACE("file: %s\n", debugstr_a(file)); + TRACE("extracting %s\n", debugstr_w(f->TargetPath) ); - /* track this file so it can be deleted if not installed */ - trackpath=strdupAtoW(file); - tracknametmp=strdupAtoW(strrchr(file,'\\')+1); - trackname = msi_alloc((strlenW(tracknametmp) + - strlenW(tmpprefix)+1) * sizeof(WCHAR)); + handle = CreateFileW( f->TargetPath, GENERIC_READ | GENERIC_WRITE, 0, + NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL ); + if ( handle == INVALID_HANDLE_VALUE ) + { + ERR("failed to create %s (error %ld)\n", + debugstr_w( f->TargetPath ), GetLastError() ); + return 0; + } - strcpyW(trackname,tmpprefix); - strcatW(trackname,tracknametmp); - - track_tempfile(data->package, trackname, trackpath); - - msi_free(trackpath); - msi_free(trackname); - msi_free(tracknametmp); - - /* the UI chunk */ - uirow=MSI_CreateRecord(9); - MSI_RecordSetStringW( uirow, 1, f->FileName ); - uipath = strdupW( f->TargetPath ); - *(strrchrW(uipath,'\\')+1)=0; - MSI_RecordSetStringW(uirow,9,uipath); - MSI_RecordSetInteger( uirow, 6, f->FileSize ); - ui_actiondata(data->package,szInstallFiles,uirow); - msiobj_release( &uirow->hdr ); - msi_free(uipath); - - ui_progress( data->package, 2, f->FileSize, 0, 0); - - return cabinet_open(file, _O_WRONLY | _O_CREAT, 0); + f->state = msifs_installed; + return (INT_PTR) handle; } case fdintCLOSE_FILE_INFO: { FILETIME ft; - FILETIME ftLocal; + FILETIME ftLocal; + HANDLE handle = (HANDLE) pfdin->hf; + if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft)) return -1; if (!LocalFileTimeToFileTime(&ft, &ftLocal)) return -1; - if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal)) + if (!SetFileTime(handle, &ftLocal, 0, &ftLocal)) return -1; - - cabinet_close(pfdin->hf); + CloseHandle(handle); return 1; } default: @@ -400,7 +380,8 @@ static UINT ready_volume(MSIPACKAGE* package, LPCWSTR path, LPWSTR last_volume, LPCWSTR want_volume = MSI_RecordGetString(row, 5); BOOL ok = check_volume(path, want_volume, volume, type); - TRACE("Readying Volume for %s (%s, %s)\n",debugstr_w(path), debugstr_w(want_volume), debugstr_w(last_volume)); + TRACE("Readying Volume for %s (%s, %s)\n", debugstr_w(path), + debugstr_w(want_volume), debugstr_w(last_volume)); if (check_for_sourcefile(path) && !ok) { @@ -463,7 +444,7 @@ static void free_media_info( struct media_info *mi ) } static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi, - MSIFILE *file, MSICOMPONENT* comp ) + MSIFILE *file ) { UINT rc = ERROR_SUCCESS; MSIRECORD * row = 0; @@ -478,6 +459,7 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi, INT seq; UINT type; LPCWSTR prompt; + MSICOMPONENT *comp = file->Component; if (file->Sequence <= mi->last_sequence) { @@ -560,7 +542,7 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi, mi->last_path = msi_alloc(MAX_PATH*sizeof(WCHAR)); if (MSI_GetPropertyW(package, cszSourceDir, mi->source, &sz)) { - ERR("No Source dir defined \n"); + ERR("No Source dir defined\n"); rc = ERROR_FUNCTION_FAILED; } else @@ -626,14 +608,11 @@ static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, { MSIFILE *file; - if (!package) - return ERROR_INVALID_HANDLE; - LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) { if (lstrcmpW( file_key, file->File )==0) { - if (file->State >= 2) + if (file->state >= msifs_overwrite) { *file_source = strdupW( file->TargetPath ); return ERROR_SUCCESS; @@ -647,11 +626,11 @@ static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, } /* - * In order to make this work more effeciencly I am going to do this in 2 - * passes. - * Pass 1) Correct all the TargetPaths and determin what files are to be - * installed. - * Pass 2) Extract Cabinents and copy files. + * ACTION_InstallFiles() + * + * For efficiency, this is done in two passes: + * 1) Correct all the TargetPaths and determine what files are to be installed. + * 2) Extract Cabinets and copy files. */ UINT ACTION_InstallFiles(MSIPACKAGE *package) { @@ -660,13 +639,10 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package) LPWSTR ptr; MSIFILE *file; - if (!package) - return ERROR_INVALID_HANDLE; - /* increment progress bar each time action data is sent */ ui_progress(package,1,1,0,0); - /* handle the keys for the SouceList */ + /* handle the keys for the SourceList */ ptr = strrchrW(package->PackagePath,'\\'); if (ptr) { @@ -676,107 +652,88 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package) MSICODE_PRODUCT, INSTALLPROPERTY_PACKAGENAMEW, ptr); } - FIXME("Write DiskPrompt\n"); + /* FIXME("Write DiskPrompt\n"); */ /* Pass 1 */ LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) { - MSICOMPONENT* comp = NULL; - - if (!ACTION_VerifyComponentForAction(package, file->Component, - INSTALLSTATE_LOCAL)) + if (!ACTION_VerifyComponentForAction( file->Component, INSTALLSTATE_LOCAL )) { ui_progress(package,2,file->FileSize,0,0); TRACE("File %s is not scheduled for install\n", debugstr_w(file->File)); - file->State = 5; - continue; - } - - if ((file->State == 1) || (file->State == 2)) - { - LPWSTR p = NULL; - - TRACE("Pass 1: %s\n",debugstr_w(file->File)); - - create_component_directory( package, file->Component ); - - /* recalculate file paths because things may have changed */ - - comp = file->Component; - if (!comp) - { - ERR("No Component for file\n"); - continue; - } - - p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL); - msi_free(file->TargetPath); - - file->TargetPath = build_directory_name(2, p, file->FileName); - msi_free(p); + file->state = msifs_skipped; } } + /* + * Despite MSDN specifying that the CreateFolders action + * should be called before InstallFiles, some installers don't + * do that, and they seem to work correctly. We need to create + * directories here to make sure that the files can be copied. + */ + msi_create_component_directories( package ); + mi = create_media_info(); /* Pass 2 */ LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) { - if ((file->State == 1) || (file->State == 2)) + if (file->state != msifs_missing && file->state != msifs_overwrite) + continue; + + TRACE("Pass 2: %s\n",debugstr_w(file->File)); + + rc = ready_media_for_file( package, mi, file ); + if (rc != ERROR_SUCCESS) { - TRACE("Pass 2: %s\n",debugstr_w(file->File)); + ERR("Unable to ready media\n"); + rc = ERROR_FUNCTION_FAILED; + break; + } - rc = ready_media_for_file( package, mi, file, file->Component ); - if (rc != ERROR_SUCCESS) + TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath), + debugstr_w(file->TargetPath)); + + if (file->state != msifs_missing && file->state != msifs_overwrite) + continue; + + /* compressed files are extracted in ready_media_for_file */ + if (~file->Attributes & msidbFileAttributesNoncompressed) + { + if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(file->TargetPath)) + ERR("compressed file wasn't extracted (%s)\n", + debugstr_w(file->TargetPath)); + continue; + } + + rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE); + if (!rc) + { + rc = GetLastError(); + ERR("Unable to copy file (%s -> %s) (error %d)\n", + debugstr_w(file->SourcePath), debugstr_w(file->TargetPath), rc); + if (rc == ERROR_ALREADY_EXISTS && file->state == msifs_overwrite) { - ERR("Unable to ready media\n"); - rc = ERROR_FUNCTION_FAILED; - break; + rc = 0; } - - TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath), - debugstr_w(file->TargetPath)); - - if (file->Attributes & msidbFileAttributesNoncompressed) - rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE); - else - rc = MoveFileW(file->SourcePath, file->TargetPath); - - if (!rc) + else if (rc == ERROR_FILE_NOT_FOUND) { - rc = GetLastError(); - ERR("Unable to move/copy file (%s -> %s) (error %d)\n", - debugstr_w(file->SourcePath), debugstr_w(file->TargetPath), - rc); - if (rc == ERROR_ALREADY_EXISTS && file->State == 2) - { - if (!CopyFileW(file->SourcePath,file->TargetPath,FALSE)) - ERR("Unable to copy file (%s -> %s) (error %ld)\n", - debugstr_w(file->SourcePath), - debugstr_w(file->TargetPath), GetLastError()); - if (!(file->Attributes & msidbFileAttributesNoncompressed)) - DeleteFileW(file->SourcePath); - rc = 0; - } - else if (rc == ERROR_FILE_NOT_FOUND) - { - ERR("Source File Not Found! Continuing\n"); - rc = 0; - } - else if (file->Attributes & msidbFileAttributesVital) - { - ERR("Ignoring Error and continuing (nonvital file)...\n"); - rc = 0; - } + ERR("Source File Not Found! Continuing\n"); + rc = 0; } - else + else if (file->Attributes & msidbFileAttributesVital) { - file->State = 4; - rc = ERROR_SUCCESS; + ERR("Ignoring Error and continuing (nonvital file)...\n"); + rc = 0; } } + else + { + file->state = msifs_installed; + rc = ERROR_SUCCESS; + } } /* cleanup */ @@ -798,7 +755,7 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param) component = MSI_RecordGetString(row,2); comp = get_loaded_component(package,component); - if (!ACTION_VerifyComponentForAction(package, comp, INSTALLSTATE_LOCAL)) + if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL )) { TRACE("Skipping copy due to disabled component %s\n", debugstr_w(component)); @@ -873,7 +830,8 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param) rc = ERROR_SUCCESS; if (rc != ERROR_SUCCESS) - ERR("Failed to copy file %s -> %s, last error %ld\n", debugstr_w(file_source), debugstr_w(dest_path), GetLastError()); + ERR("Failed to copy file %s -> %s, last error %ld\n", + debugstr_w(file_source), debugstr_w(dest_path), GetLastError()); FIXME("We should track these duplicate files as well\n"); @@ -892,9 +850,6 @@ UINT ACTION_DuplicateFiles(MSIPACKAGE *package) {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', '`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0}; - if (!package) - return ERROR_INVALID_HANDLE; - rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); if (rc != ERROR_SUCCESS) return ERROR_SUCCESS; @@ -904,3 +859,29 @@ UINT ACTION_DuplicateFiles(MSIPACKAGE *package) return rc; } + +UINT ACTION_RemoveFiles( MSIPACKAGE *package ) +{ + MSIFILE *file; + + LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry ) + { + if ( !file->Component ) + continue; + if ( file->Component->Installed == INSTALLSTATE_LOCAL ) + continue; + + if ( file->state == msifs_installed ) + ERR("removing installed file %s\n", debugstr_w(file->TargetPath)); + + if ( file->state != msifs_present ) + continue; + + TRACE("removing %s\n", debugstr_w(file->File) ); + if ( !DeleteFileW( file->TargetPath ) ) + ERR("failed to delete %s\n", debugstr_w(file->TargetPath) ); + file->state = msifs_missing; + } + + return ERROR_SUCCESS; +} diff --git a/reactos/lib/msi/format.c b/reactos/lib/msi/format.c index 9bcfc7f9cd2..2730433bb0a 100644 --- a/reactos/lib/msi/format.c +++ b/reactos/lib/msi/format.c @@ -206,7 +206,7 @@ static LPWSTR deformat_index(MSIRECORD* record, LPCWSTR key, DWORD* chunk ) index = atoiW(key); TRACE("record index %i\n",index); - value = load_dynamic_stringW(record,index); + value = msi_dup_record_field(record,index); if (value) *chunk = strlenW(value) * sizeof(WCHAR); else @@ -434,7 +434,7 @@ static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, { LPBYTE nd2; - TRACE("after value %s \n",debugstr_wn((LPWSTR)newdata, + TRACE("after value %s\n", debugstr_wn((LPWSTR)newdata, size/sizeof(WCHAR))); chunk = (len - (progress - ptr)) * sizeof(WCHAR); TRACE("after chunk is %li + %li\n",size,chunk); @@ -584,7 +584,7 @@ UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer, TRACE("%p %p %p %li\n",package, record ,buffer, *size); - rec = load_dynamic_stringW(record,0); + rec = msi_dup_record_field(record,0); if (!rec) rec = build_default_format(record); @@ -631,7 +631,7 @@ UINT MSI_FormatRecordA( MSIPACKAGE* package, MSIRECORD* record, LPSTR buffer, TRACE("%p %p %p %li\n",package, record ,buffer, *size); - rec = load_dynamic_stringW(record,0); + rec = msi_dup_record_field(record,0); if (!rec) rec = build_default_format(record); diff --git a/reactos/lib/msi/helpers.c b/reactos/lib/msi/helpers.c index fc466ba7a20..a47766b8a58 100644 --- a/reactos/lib/msi/helpers.c +++ b/reactos/lib/msi/helpers.c @@ -107,36 +107,9 @@ LPWSTR build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name ) return FilePath; } -WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index) +LPWSTR msi_dup_record_field( MSIRECORD *row, INT index ) { - UINT rc; - DWORD sz; - LPWSTR ret; - - sz = 0; - if (MSI_RecordIsNull(row,index)) - return NULL; - - rc = MSI_RecordGetStringW(row,index,NULL,&sz); - - /* having an empty string is different than NULL */ - if (sz == 0) - { - ret = msi_alloc(sizeof(WCHAR)); - ret[0] = 0; - return ret; - } - - sz ++; - ret = msi_alloc(sz * sizeof (WCHAR)); - rc = MSI_RecordGetStringW(row,index,ret,&sz); - if (rc!=ERROR_SUCCESS) - { - ERR("Unable to load dynamic string\n"); - msi_free(ret); - ret = NULL; - } - return ret; + return strdupW( MSI_RecordGetString(row,index) ); } LPWSTR msi_dup_property(MSIPACKAGE *package, LPCWSTR prop) @@ -200,9 +173,6 @@ int track_tempfile( MSIPACKAGE *package, LPCWSTR name, LPCWSTR path ) { MSITEMPFILE *temp; - if (!package) - return -1; - LIST_FOR_EACH_ENTRY( temp, &package->tempfiles, MSITEMPFILE, entry ) { if (lstrcmpW( name, temp->File )==0) @@ -751,7 +721,7 @@ void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record) /* update the cached actionformat */ msi_free(package->ActionFormat); - package->ActionFormat = load_dynamic_stringW(row,3); + package->ActionFormat = msi_dup_record_field(row,3); msi_free(package->LastAction); package->LastAction = strdupW(action); @@ -773,8 +743,7 @@ void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record) msiobj_release(&row->hdr); } -BOOL ACTION_VerifyComponentForAction(MSIPACKAGE* package, MSICOMPONENT* comp, - INSTALLSTATE check ) +BOOL ACTION_VerifyComponentForAction( MSICOMPONENT* comp, INSTALLSTATE check ) { if (!comp) return FALSE; @@ -935,7 +904,7 @@ UINT register_unique_action(MSIPACKAGE *package, LPCWSTR action) UINT count; LPWSTR *newbuf = NULL; - if (!package || !package->script) + if (!package->script) return FALSE; TRACE("Registering Action %s as having fun\n",debugstr_w(action)); @@ -958,7 +927,7 @@ BOOL check_unique_action(MSIPACKAGE *package, LPCWSTR action) { INT i; - if (!package || !package->script) + if (!package->script) return FALSE; for (i = 0; i < package->script->UniqueActionsCount; i++) diff --git a/reactos/lib/msi/insert.c b/reactos/lib/msi/insert.c index 5d9fcb90ebf..536daeac232 100644 --- a/reactos/lib/msi/insert.c +++ b/reactos/lib/msi/insert.c @@ -33,7 +33,7 @@ #include "query.h" -WINE_DEFAULT_DEBUG_CHANNEL(msi); +WINE_DEFAULT_DEBUG_CHANNEL(msidb); /* below is the query interface to a table */ diff --git a/reactos/lib/msi/install.c b/reactos/lib/msi/install.c index 2098cb2fc14..b74d244ddbd 100644 --- a/reactos/lib/msi/install.c +++ b/reactos/lib/msi/install.c @@ -116,7 +116,7 @@ UINT WINAPI MsiSequenceW( MSIHANDLE hInstall, LPCWSTR szTable, INT iSequenceMode return ret; } -static UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz ) +UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz ) { UINT len, r = ERROR_SUCCESS; @@ -134,12 +134,15 @@ static UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz ) } else { - len = WideCharToMultiByte( CP_ACP, 0, str, -1, - awbuf->str.a, *sz, NULL, NULL ); - len--; + len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL ); + if (len) + len--; + WideCharToMultiByte( CP_ACP, 0, str, -1, awbuf->str.a, *sz, NULL, NULL ); + if ( *sz && (len >= *sz) ) + awbuf->str.a[*sz - 1] = 0; } - if (len >= *sz) + if (awbuf->str.w && len >= *sz) r = ERROR_MORE_DATA; *sz = len; return r; @@ -293,31 +296,23 @@ UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, /*********************************************************************** * MsiSetTargetPathA (MSI.@) */ -UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder, - LPCSTR szFolderPath) +UINT WINAPI MsiSetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder, + LPCSTR szFolderPath ) { - LPWSTR szwFolder; - LPWSTR szwFolderPath; - UINT rc; + LPWSTR szwFolder = NULL, szwFolderPath = NULL; + UINT rc = ERROR_OUTOFMEMORY; - if (!szFolder) - return ERROR_FUNCTION_FAILED; - if (hInstall == 0) - return ERROR_FUNCTION_FAILED; + if ( !szFolder || !szFolderPath ) + return ERROR_INVALID_PARAMETER; szwFolder = strdupAtoW(szFolder); - if (!szwFolder) - return ERROR_FUNCTION_FAILED; - szwFolderPath = strdupAtoW(szFolderPath); - if (!szwFolderPath) - { - msi_free(szwFolder); - return ERROR_FUNCTION_FAILED; - } + if (!szwFolder || !szwFolderPath) + goto end; - rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath); + rc = MsiSetTargetPathW( hInstall, szwFolder, szwFolderPath ); +end: msi_free(szwFolder); msi_free(szwFolderPath); @@ -339,12 +334,6 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath)); - if (package==NULL) - return ERROR_INVALID_HANDLE; - - if (szFolderPath[0]==0) - return ERROR_FUNCTION_FAILED; - attrib = GetFileAttributesW(szFolderPath); if ( attrib != INVALID_FILE_ATTRIBUTES && (!(attrib & FILE_ATTRIBUTE_DIRECTORY) || @@ -353,14 +342,16 @@ UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, return ERROR_FUNCTION_FAILED; path = resolve_folder(package,szFolder,FALSE,FALSE,&folder); - if (!path) - return ERROR_INVALID_PARAMETER; + return ERROR_DIRECTORY; if (attrib == INVALID_FILE_ATTRIBUTES) { if (!CreateDirectoryW(szFolderPath,NULL)) + { + msi_free( path ); return ERROR_FUNCTION_FAILED; + } RemoveDirectoryW(szFolderPath); } @@ -410,7 +401,13 @@ UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath)); + if ( !szFolder || !szFolderPath ) + return ERROR_INVALID_PARAMETER; + package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE); + if (!package) + return ERROR_INVALID_HANDLE; + ret = MSI_SetTargetPathW( package, szFolder, szFolderPath ); msiobj_release( &package->hdr ); return ret; @@ -456,6 +453,24 @@ BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode) return TRUE; } +/*********************************************************************** + * MsiSetMode (MSI.@) + */ +BOOL WINAPI MsiSetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode, BOOL fState) +{ + switch (iRunMode) + { + case MSIRUNMODE_RESERVED11: + case MSIRUNMODE_WINDOWS9X: + case MSIRUNMODE_RESERVED14: + case MSIRUNMODE_RESERVED15: + return FALSE; + default: + FIXME("%ld %d %d\n", hInstall, iRunMode, fState); + } + return TRUE; +} + /*********************************************************************** * MsiSetFeatureStateA (MSI.@) * diff --git a/reactos/lib/msi/msi.c b/reactos/lib/msi/msi.c index bc52d1ab54a..bfbc3849299 100644 --- a/reactos/lib/msi/msi.c +++ b/reactos/lib/msi/msi.c @@ -35,19 +35,14 @@ #include "wincrypt.h" #include "winver.h" #include "winuser.h" +#include "shlobj.h" +#include "shobjidl.h" +#include "objidl.h" #include "wine/unicode.h" #include "action.h" WINE_DEFAULT_DEBUG_CHANNEL(msi); -/* - * The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR, - * which is a problem because LPCTSTR isn't defined when compiling wine. - * To work around this problem, we need to define LPCTSTR as LPCWSTR here, - * and make sure to only use it in W functions. - */ -#define LPCTSTR LPCWSTR - /* the UI level */ INSTALLUILEVEL gUILevel = INSTALLUILEVEL_BASIC; HWND gUIhwnd = 0; @@ -418,7 +413,7 @@ UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer) DWORD sz = GUID_SIZE; static const WCHAR szPermKey[] = { '0','0','0','0','0','0','0','0','0','0','0','0', - '0','0','0','0','0','0','0', '0','0','0','0','0', + '0','0','0','0','0','0','0','0','0','0','0','0', '0','0','0','0','0','0','0','0',0}; TRACE("%s %p\n",debugstr_w(szComponent), szBuffer); @@ -839,7 +834,7 @@ UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uTyp { FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_a(lpText),debugstr_a(lpCaption), uType,wLanguageId,f); - return ERROR_CALL_NOT_IMPLEMENTED; + return MessageBoxExA(hWnd,lpText,lpCaption,uType,wLanguageId); } UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType, @@ -847,7 +842,7 @@ UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uT { FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_w(lpText),debugstr_w(lpCaption), uType,wLanguageId,f); - return ERROR_CALL_NOT_IMPLEMENTED; + return MessageBoxExW(hWnd,lpText,lpCaption,uType,wLanguageId); } UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext, @@ -1013,6 +1008,8 @@ INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent, TRACE("%s %s %p %p\n", debugstr_w(szProduct), debugstr_w(szComponent), lpPathBuf, pcchBuf); + if( !szComponent ) + return INSTALLSTATE_INVALIDARG; if( lpPathBuf && !pcchBuf ) return INSTALLSTATE_INVALIDARG; @@ -1081,29 +1078,20 @@ end: */ INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature) { - INSTALLSTATE rc; - LPWSTR szwProduct= NULL; - LPWSTR szwFeature= NULL; + LPWSTR szwProduct = NULL, szwFeature= NULL; + INSTALLSTATE rc = INSTALLSTATE_UNKNOWN; - if( szProduct ) - { - szwProduct = strdupAtoW( szProduct ); - if( !szwProduct) - return ERROR_OUTOFMEMORY; - } + szwProduct = strdupAtoW( szProduct ); + if ( szProduct && !szwProduct ) + goto end; - if( szFeature ) - { - szwFeature = strdupAtoW( szFeature ); - if( !szwFeature) - { - msi_free( szwProduct); - return ERROR_OUTOFMEMORY; - } - } + szwFeature = strdupAtoW( szFeature ); + if ( szFeature && !szwFeature ) + goto end; rc = MsiQueryFeatureStateW(szwProduct, szwFeature); +end: msi_free( szwProduct); msi_free( szwFeature); @@ -1119,12 +1107,19 @@ INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature) */ INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature) { + WCHAR squishProduct[GUID_SIZE]; UINT rc; DWORD sz = 0; HKEY hkey; TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature)); + if (!szProduct || !szFeature) + return INSTALLSTATE_INVALIDARG; + + if (!squash_guid( szProduct, squishProduct )) + return INSTALLSTATE_INVALIDARG; + rc = MSIREG_OpenFeaturesKey(szProduct, &hkey, FALSE); if (rc != ERROR_SUCCESS) return INSTALLSTATE_UNKNOWN; @@ -1134,8 +1129,8 @@ INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature) if (rc == ERROR_SUCCESS) return INSTALLSTATE_LOCAL; - else - return INSTALLSTATE_ABSENT; + + return INSTALLSTATE_UNKNOWN; } /****************************************************************** @@ -1192,7 +1187,7 @@ end: UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf) { - static const WCHAR szVersionResource[] = {'\\',0}; + static WCHAR szVersionResource[] = {'\\',0}; static const WCHAR szVersionFormat[] = { '%','d','.','%','d','.','%','d','.','%','d',0}; static const WCHAR szLangFormat[] = {'%','d',0}; @@ -1373,65 +1368,134 @@ HRESULT WINAPI DllCanUnloadNow(void) return S_FALSE; } -UINT WINAPI MsiGetFeatureUsageW(LPCWSTR szProduct, LPCWSTR szFeature, - DWORD* pdwUseCount, WORD* pwDateUsed) +/*********************************************************************** + * MsiGetFeatureUsageW [MSI.@] + */ +UINT WINAPI MsiGetFeatureUsageW( LPCWSTR szProduct, LPCWSTR szFeature, + DWORD* pdwUseCount, WORD* pwDateUsed ) { FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature), pdwUseCount, pwDateUsed); return ERROR_CALL_NOT_IMPLEMENTED; } -UINT WINAPI MsiGetFeatureUsageA(LPCSTR szProduct, LPCSTR szFeature, - DWORD* pdwUseCount, WORD* pwDateUsed) +/*********************************************************************** + * MsiGetFeatureUsageA [MSI.@] + */ +UINT WINAPI MsiGetFeatureUsageA( LPCSTR szProduct, LPCSTR szFeature, + DWORD* pdwUseCount, WORD* pwDateUsed ) { - FIXME("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature), + LPWSTR prod = NULL, feat = NULL; + UINT ret = ERROR_OUTOFMEMORY; + + TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature), pdwUseCount, pwDateUsed); - return ERROR_CALL_NOT_IMPLEMENTED; + + prod = strdupAtoW( szProduct ); + if (szProduct && !prod) + goto end; + + feat = strdupAtoW( szFeature ); + if (szFeature && !feat) + goto end; + + ret = MsiGetFeatureUsageW( prod, feat, pdwUseCount, pwDateUsed ); + +end: + msi_free( prod ); + msi_free( feat ); + + return ret; } -INSTALLSTATE WINAPI MsiUseFeatureExW(LPCWSTR szProduct, LPCWSTR szFeature, - DWORD dwInstallMode, DWORD dwReserved) +/*********************************************************************** + * MsiUseFeatureExW [MSI.@] + */ +INSTALLSTATE WINAPI MsiUseFeatureExW( LPCWSTR szProduct, LPCWSTR szFeature, + DWORD dwInstallMode, DWORD dwReserved ) { - FIXME("%s %s %li %li\n", debugstr_w(szProduct), debugstr_w(szFeature), + INSTALLSTATE state; + + TRACE("%s %s %li %li\n", debugstr_w(szProduct), debugstr_w(szFeature), dwInstallMode, dwReserved); - /* - * Polls all the components of the feature to find install state and then - * writes: - * Software\\Microsoft\\Windows\\CurrentVersion\\ - * Installer\\Products\\\\ - * "Usage"=dword:........ - */ + state = MsiQueryFeatureStateW( szProduct, szFeature ); - return INSTALLSTATE_LOCAL; + if (dwReserved) + return INSTALLSTATE_INVALIDARG; + + if (state == INSTALLSTATE_LOCAL && dwInstallMode != INSTALLMODE_NODETECTION) + { + FIXME("mark product %s feature %s as used\n", + debugstr_w(szProduct), debugstr_w(szFeature) ); + } + + return state; } /*********************************************************************** * MsiUseFeatureExA [MSI.@] */ -INSTALLSTATE WINAPI MsiUseFeatureExA(LPCSTR szProduct, LPCSTR szFeature, - DWORD dwInstallMode, DWORD dwReserved) +INSTALLSTATE WINAPI MsiUseFeatureExA( LPCSTR szProduct, LPCSTR szFeature, + DWORD dwInstallMode, DWORD dwReserved ) { - FIXME("%s %s %li %li\n", debugstr_a(szProduct), debugstr_a(szFeature), + INSTALLSTATE ret = INSTALLSTATE_UNKNOWN; + LPWSTR prod = NULL, feat = NULL; + + TRACE("%s %s %li %li\n", debugstr_a(szProduct), debugstr_a(szFeature), dwInstallMode, dwReserved); - return INSTALLSTATE_LOCAL; + prod = strdupAtoW( szProduct ); + if (szProduct && !prod) + goto end; + + feat = strdupAtoW( szFeature ); + if (szFeature && !feat) + goto end; + + ret = MsiUseFeatureExW( prod, feat, dwInstallMode, dwReserved ); + +end: + msi_free( prod ); + msi_free( feat ); + + return ret; } -INSTALLSTATE WINAPI MsiUseFeatureW(LPCWSTR szProduct, LPCWSTR szFeature) +INSTALLSTATE WINAPI MsiUseFeatureW( LPCWSTR szProduct, LPCWSTR szFeature ) { FIXME("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature)); return INSTALLSTATE_LOCAL; } -INSTALLSTATE WINAPI MsiUseFeatureA(LPCSTR szProduct, LPCSTR szFeature) +INSTALLSTATE WINAPI MsiUseFeatureA( LPCSTR szProduct, LPCSTR szFeature ) { - FIXME("%s %s\n", debugstr_a(szProduct), debugstr_a(szFeature)); + INSTALLSTATE ret = INSTALLSTATE_UNKNOWN; + LPWSTR prod = NULL, feat = NULL; - return INSTALLSTATE_LOCAL; + TRACE("%s %s\n", debugstr_a(szProduct), debugstr_a(szFeature) ); + + prod = strdupAtoW( szProduct ); + if (szProduct && !prod) + goto end; + + feat = strdupAtoW( szFeature ); + if (szFeature && !feat) + goto end; + + ret = MsiUseFeatureW( prod, feat ); + +end: + msi_free( prod ); + msi_free( feat ); + + return ret; } +/*********************************************************************** + * MsiProvideQualifiedComponentExW [MSI.@] + */ UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent, LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct, DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf, @@ -1441,10 +1505,9 @@ UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent, UINT rc; LPWSTR info; DWORD sz; - LPWSTR product = NULL; - LPWSTR component = NULL; - LPWSTR ptr; - GUID clsid; + WCHAR product[MAX_FEATURE_CHARS+1]; + WCHAR component[MAX_FEATURE_CHARS+1]; + WCHAR feature[MAX_FEATURE_CHARS+1]; TRACE("%s %s %li %s %li %li %p %p\n", debugstr_w(szComponent), debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct), @@ -1471,25 +1534,8 @@ UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent, return ERROR_INDEX_ABSENT; } - /* find the component */ - ptr = strchrW(&info[20],'>'); - if (ptr) - ptr++; - else - { - RegCloseKey(hkey); - msi_free(info); - return ERROR_INDEX_ABSENT; - } - - if (!szProduct) - { - decode_base85_guid(info,&clsid); - StringFromCLSID(&clsid, &product); - } - decode_base85_guid(ptr,&clsid); - StringFromCLSID(&clsid, &component); - + MsiDecomposeDescriptorW(info, product, feature, component, &sz); + if (!szProduct) rc = MsiGetComponentPathW(product, component, lpPathBuf, pcchPathBuf); else @@ -1497,8 +1543,6 @@ UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent, RegCloseKey(hkey); msi_free(info); - msi_free(product); - msi_free(component); if (rc == INSTALLSTATE_LOCAL) return ERROR_SUCCESS; @@ -1720,6 +1764,9 @@ UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved) return 0; } +/*********************************************************************** + * MsiGetShortcutTargetA [MSI.@] + */ UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget, LPSTR szProductCode, LPSTR szFeatureId, LPSTR szComponentCode ) @@ -1746,12 +1793,60 @@ UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget, return r; } +/*********************************************************************** + * MsiGetShortcutTargetW [MSI.@] + */ UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget, LPWSTR szProductCode, LPWSTR szFeatureId, LPWSTR szComponentCode ) { - FIXME("%s\n", debugstr_w(szShortcutTarget)); - return ERROR_CALL_NOT_IMPLEMENTED; + IShellLinkDataList *dl = NULL; + IPersistFile *pf = NULL; + LPEXP_DARWIN_LINK darwin = NULL; + HRESULT r, init; + + TRACE("%s %p %p %p\n", debugstr_w(szShortcutTarget), + szProductCode, szFeatureId, szComponentCode ); + + init = CoInitialize(NULL); + + r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, + &IID_IPersistFile, (LPVOID*) &pf ); + if( SUCCEEDED( r ) ) + { + r = IPersistFile_Load( pf, szShortcutTarget, + STGM_READ | STGM_SHARE_DENY_WRITE ); + if( SUCCEEDED( r ) ) + { + r = IPersistFile_QueryInterface( pf, &IID_IShellLinkDataList, + (LPVOID*) &dl ); + if( SUCCEEDED( r ) ) + { + IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG, + (LPVOID) &darwin ); + IShellLinkDataList_Release( dl ); + } + } + IPersistFile_Release( pf ); + } + + if (SUCCEEDED(init)) + CoUninitialize(); + + TRACE("darwin = %p\n", darwin); + + if (darwin) + { + DWORD sz; + UINT ret; + + ret = MsiDecomposeDescriptorW( darwin->szwDarwinID, + szProductCode, szFeatureId, szComponentCode, &sz ); + LocalFree( darwin ); + return ret; + } + + return ERROR_FUNCTION_FAILED; } UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature, @@ -1877,3 +1972,45 @@ UINT WINAPI MsiEnumPatchesW( LPCWSTR szProduct, DWORD iPatchIndex, iPatchIndex, lpPatchBuf, lpTransformsBuf, pcchTransformsBuf); return ERROR_NO_MORE_ITEMS; } + +/*********************************************************************** + * MsiGetFileHashW [MSI.@] + */ +UINT WINAPI MsiGetFileHashW( LPCWSTR szFilePath, DWORD dwOptions, + PMSIFILEHASHINFO pHash ) +{ + FIXME("%s %08lx %p\n", debugstr_w(szFilePath), dwOptions, pHash ); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +/*********************************************************************** + * MsiGetFileHashA [MSI.@] + */ +UINT WINAPI MsiGetFileHashA( LPCSTR szFilePath, DWORD dwOptions, + PMSIFILEHASHINFO pHash ) +{ + FIXME("%s %08lx %p\n", debugstr_a(szFilePath), dwOptions, pHash ); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +/*********************************************************************** + * MsiAdvertiseScriptW [MSI.@] + */ +UINT WINAPI MsiAdvertiseScriptW( LPCWSTR szScriptFile, DWORD dwFlags, + PHKEY phRegData, BOOL fRemoveItems ) +{ + FIXME("%s %08lx %p %d\n", + debugstr_w( szScriptFile ), dwFlags, phRegData, fRemoveItems ); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +/*********************************************************************** + * MsiAdvertiseScriptA [MSI.@] + */ +UINT WINAPI MsiAdvertiseScriptA( LPCSTR szScriptFile, DWORD dwFlags, + PHKEY phRegData, BOOL fRemoveItems ) +{ + FIXME("%s %08lx %p %d\n", + debugstr_a( szScriptFile ), dwFlags, phRegData, fRemoveItems ); + return ERROR_CALL_NOT_IMPLEMENTED; +} diff --git a/reactos/lib/msi/msi.rc b/reactos/lib/msi/msi.rc index 551af287e5e..badc1651617 100644 --- a/reactos/lib/msi/msi.rc +++ b/reactos/lib/msi/msi.rc @@ -34,6 +34,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL #include "msi_Es.rc" #include "msi_Fi.rc" #include "msi_Fr.rc" +#include "msi_Ko.rc" #include "msi_Nl.rc" #include "msi_No.rc" #include "msi_Pt.rc" diff --git a/reactos/lib/msi/msi.spec b/reactos/lib/msi/msi.spec index 33f2db14641..28b26289ada 100644 --- a/reactos/lib/msi/msi.spec +++ b/reactos/lib/msi/msi.spec @@ -31,8 +31,8 @@ 35 stdcall MsiEnableUIPreview(long ptr) 36 stdcall MsiEnumClientsA(str long ptr) 37 stdcall MsiEnumClientsW(wstr long ptr) -38 stdcall MsiEnumComponentQualifiersA(str long str ptr str ptr) -39 stdcall MsiEnumComponentQualifiersW(wstr long wstr ptr wstr ptr) +38 stdcall MsiEnumComponentQualifiersA(str long ptr ptr ptr ptr) +39 stdcall MsiEnumComponentQualifiersW(wstr long ptr ptr ptr ptr) 40 stdcall MsiEnumComponentsA(long ptr) 41 stdcall MsiEnumComponentsW(long ptr) 42 stdcall MsiEnumFeaturesA(str long ptr ptr) @@ -66,8 +66,8 @@ 70 stdcall MsiGetProductInfoW(wstr wstr wstr long) 71 stdcall MsiGetProductPropertyA(long str ptr ptr) 72 stdcall MsiGetProductPropertyW(long wstr ptr ptr) -73 stdcall MsiGetPropertyA(ptr str str ptr) -74 stdcall MsiGetPropertyW(ptr wstr wstr ptr) +73 stdcall MsiGetPropertyA(ptr str ptr ptr) +74 stdcall MsiGetPropertyW(ptr wstr ptr ptr) 75 stdcall MsiGetSourcePathA(long str ptr ptr) 76 stdcall MsiGetSourcePathW(long wstr ptr ptr) 77 stdcall MsiGetSummaryInformationA(long str long ptr) @@ -136,7 +136,7 @@ 140 stub MsiSetInstallLevel 141 stdcall MsiSetInternalUI(long ptr) 142 stub MsiVerifyDiskSpace -143 stub MsiSetMode +143 stdcall MsiSetMode(long long long) 144 stdcall MsiSetPropertyA(long str str) 145 stdcall MsiSetPropertyW(long wstr wstr) 146 stdcall MsiSetTargetPathA(long str str) @@ -169,8 +169,8 @@ 173 stdcall MsiGetComponentPathW(wstr wstr ptr ptr) 174 stdcall MsiApplyPatchA(str str long str) 175 stdcall MsiApplyPatchW(wstr wstr long wstr) -176 stub MsiAdvertiseScriptA -177 stub MsiAdvertiseScriptW +176 stdcall MsiAdvertiseScriptA(str long ptr long) +177 stdcall MsiAdvertiseScriptW(wstr long ptr long) 178 stub MsiGetPatchInfoA 179 stub MsiGetPatchInfoW 180 stdcall MsiEnumPatchesA(str long ptr ptr ptr) @@ -211,8 +211,8 @@ 215 stub MsiIsProductElevatedW 216 stdcall MsiGetShortcutTargetA(str ptr ptr ptr) 217 stdcall MsiGetShortcutTargetW(wstr ptr ptr ptr) -218 stub MsiGetFileHashA -219 stub MsiGetFileHashW +218 stdcall MsiGetFileHashA(str long ptr) +219 stdcall MsiGetFileHashW(wstr long ptr) 220 stub MsiEnumComponentCostsA 221 stub MsiEnumComponentCostsW 222 stdcall MsiCreateAndVerifyInstallerDirectory(long) diff --git a/reactos/lib/msi/msi_Ko.rc b/reactos/lib/msi/msi_Ko.rc new file mode 100644 index 00000000000..0eabd0453b2 --- /dev/null +++ b/reactos/lib/msi/msi_Ko.rc @@ -0,0 +1,33 @@ +/* + * Korean resources for MSI + * + * Copyright 2005 YunSong Hwang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + 5 "path %s not found" + 9 "µð½ºÅ© %s »ðÀÔ" + 10 "Àý¸øµÈ ¸Å°³º¯¼ö" + 11 "enter which folder contains %s" + 12 "install source for feature missing" + 13 "network drive for feature missing" + 14 "feature from:" + 15 "choose which folder contains %s" +} diff --git a/reactos/lib/msi/msipriv.h b/reactos/lib/msi/msipriv.h index 9f4f644f17b..7649d39add7 100644 --- a/reactos/lib/msi/msipriv.h +++ b/reactos/lib/msi/msipriv.h @@ -67,6 +67,7 @@ typedef struct tagMSIDATABASE string_table *strings; LPCWSTR mode; struct list tables; + struct list transforms; } MSIDATABASE; typedef struct tagMSIVIEW MSIVIEW; @@ -219,6 +220,16 @@ typedef struct tagMSIPREVIEW msi_dialog *dialog; } MSIPREVIEW; +#define MSI_MAX_PROPS 20 + +typedef struct tagMSISUMMARYINFO +{ + MSIOBJECTHDR hdr; + MSIDATABASE *db; + DWORD update_count; + PROPVARIANT property[MSI_MAX_PROPS]; +} MSISUMMARYINFO; + #define MSIHANDLETYPE_ANY 0 #define MSIHANDLETYPE_DATABASE 1 #define MSIHANDLETYPE_SUMMARYINFO 2 @@ -243,6 +254,7 @@ DEFINE_GUID(CLSID_IMsiServerX3, 0x000C1094,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x0 DEFINE_GUID(CLSID_IMsiServerMessage, 0x000C101D,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); +/* handle unicode/ascii output in the Msi* API functions */ typedef struct { BOOL unicode; union { @@ -259,6 +271,8 @@ typedef struct { } str; } awcstring; +UINT msi_strcpy_to_awstring( LPCWSTR str, awstring *awbuf, DWORD *sz ); + /* handle functions */ extern void *msihandle2msiinfo(MSIHANDLE handle, UINT type); extern MSIHANDLE alloc_msihandle( MSIOBJECTHDR * ); @@ -269,6 +283,7 @@ extern void msiobj_lock(MSIOBJECTHDR *); extern void msiobj_unlock(MSIOBJECTHDR *); extern void free_cached_tables( MSIDATABASE *db ); +extern void msi_free_transforms( MSIDATABASE *db ); extern string_table *load_string_table( IStorage *stg ); extern UINT MSI_CommitTables( MSIDATABASE *db ); extern HRESULT init_string_table( IStorage *stg ); @@ -300,6 +315,9 @@ extern BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name ); extern UINT read_raw_stream_data( MSIDATABASE*, LPCWSTR stname, USHORT **pdata, UINT *psz ); +/* transform functions */ +extern UINT msi_table_apply_transform( MSIDATABASE *db, IStorage *stg ); + /* action internals */ extern UINT MSI_InstallPackage( MSIPACKAGE *, LPCWSTR, LPCWSTR ); extern void ACTION_free_package_structures( MSIPACKAGE* ); @@ -401,6 +419,10 @@ extern void msi_dialog_handle_event( msi_dialog*, LPCWSTR, LPCWSTR, MSIRECORD * extern MSIPREVIEW *MSI_EnableUIPreview( MSIDATABASE * ); extern UINT MSI_PreviewDialogW( MSIPREVIEW *, LPCWSTR ); +/* summary information */ +extern MSISUMMARYINFO *MSI_GetSummaryInformationW( MSIDATABASE *db, UINT uiUpdateCount ); +extern LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty ); + /* undocumented functions */ UINT WINAPI MsiCreateAndVerifyInstallerDirectory( DWORD ); UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR, LPWSTR, LPWSTR, LPWSTR, DWORD * ); diff --git a/reactos/lib/msi/msiquery.c b/reactos/lib/msi/msiquery.c index ed7d8ebfbe4..2cbfbeddbed 100644 --- a/reactos/lib/msi/msiquery.c +++ b/reactos/lib/msi/msiquery.c @@ -657,8 +657,7 @@ static UINT MSI_DatabaseApplyTransformW( MSIDATABASE *db, if( TRACE_ON( msi ) ) enum_stream_names( stg ); - /* r = table_apply_transform( db, stg ); */ - FIXME("should apply transform %s\n", debugstr_w(szTransformFile) ); + r = msi_table_apply_transform( db, stg ); IStorage_Release( stg ); diff --git a/reactos/lib/msi/order.c b/reactos/lib/msi/order.c index b17be99143d..27da7c64770 100644 --- a/reactos/lib/msi/order.c +++ b/reactos/lib/msi/order.c @@ -33,7 +33,7 @@ #include "query.h" -WINE_DEFAULT_DEBUG_CHANNEL(msi); +WINE_DEFAULT_DEBUG_CHANNEL(msidb); /* below is the query interface to a table */ diff --git a/reactos/lib/msi/package.c b/reactos/lib/msi/package.c index b37ce4de1c6..96bf46fc089 100644 --- a/reactos/lib/msi/package.c +++ b/reactos/lib/msi/package.c @@ -31,7 +31,6 @@ #include "wine/debug.h" #include "msi.h" #include "msiquery.h" -#include "msipriv.h" #include "objidl.h" #include "wincrypt.h" #include "winuser.h" @@ -39,15 +38,10 @@ #include "wine/unicode.h" #include "objbase.h" -WINE_DEFAULT_DEBUG_CHANNEL(msi); +#include "msipriv.h" +#include "action.h" -/* - * The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR, - * which is a problem because LPCTSTR isn't defined when compiling wine. - * To work around this problem, we need to define LPCTSTR as LPCWSTR here, - * and make sure to only use it in W functions. - */ -#define LPCTSTR LPCWSTR +WINE_DEFAULT_DEBUG_CHANNEL(msi); static void MSI_FreePackage( MSIOBJECTHDR *arg) { @@ -128,6 +122,30 @@ static UINT clone_properties(MSIDATABASE *db) return rc; } +/* + * set_installed_prop + * + * Sets the "Installed" property to indicate that + * the product is installed for the current user. + */ +static UINT set_installed_prop( MSIPACKAGE *package ) +{ + static const WCHAR szInstalled[] = { + 'I','n','s','t','a','l','l','e','d',0 }; + WCHAR val[2] = { '1', 0 }; + HKEY hkey = 0; + UINT r; + + r = MSIREG_OpenUninstallKey( package->ProductCode, &hkey, FALSE ); + if (r == ERROR_SUCCESS) + { + RegCloseKey( hkey ); + MSI_SetPropertyW( package, szInstalled, val ); + } + + return r; +} + /* * There are a whole slew of these we need to set * @@ -211,29 +229,14 @@ static VOID set_installer_properties(MSIPACKAGE *package) static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0}; static const WCHAR szScreenFormat[] = {'%','d',0}; -/* - * Other things I notice set - * -SystemLanguageID -ComputerName -UserLanguageID -LogonUser -VirtualMemory -Intel -ShellAdvSupport -DefaultUIFont -VersionDatabase -PackagecodeChanging -ProductState -CaptionHeight -BorderTop -BorderSide -TextHeight -RedirectedDllSupport -Time -Date -Privileged -*/ + /* + * Other things that probably should be set: + * + * SystemLanguageID ComputerName UserLanguageID LogonUser VirtualMemory + * Intel ShellAdvSupport DefaultUIFont VersionDatabase PackagecodeChanging + * ProductState CaptionHeight BorderTop BorderSide TextHeight + * RedirectedDllSupport Time Date Privileged + */ SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth); strcatW(pth,cszbs); @@ -365,6 +368,8 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db ) { static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 }; static const WCHAR szpi[] = {'%','i',0}; + static const WCHAR szProductCode[] = { + 'P','r','o','d','u','c','t','C','o','d','e',0}; MSIPACKAGE *package = NULL; WCHAR uilevel[10]; @@ -401,6 +406,9 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db ) set_installer_properties(package); sprintfW(uilevel,szpi,gUILevel); MSI_SetPropertyW(package, szLevel, uilevel); + + package->ProductCode = msi_dup_property( package, szProductCode ); + set_installed_prop( package ); } return package; @@ -439,8 +447,6 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) MSIDATABASE *db = NULL; MSIPACKAGE *package; MSIHANDLE handle; - DWORD size; - static const WCHAR szProductCode[]= {'P','r','o','d','u','c','t','C','o','d','e',0}; UINT r; TRACE("%s %p\n", debugstr_w(szPackage), pPackage); @@ -486,13 +492,6 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) MSI_SetPropertyW( package, Database, szPackage ); } - /* this property must exist */ - size = 0; - MSI_GetPropertyW(package,szProductCode,NULL,&size); - size ++; - package->ProductCode = msi_alloc(size * sizeof(WCHAR)); - MSI_GetPropertyW(package,szProductCode,package->ProductCode, &size); - *pPackage = package; return ERROR_SUCCESS; @@ -577,7 +576,7 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType, char *msg; int len; - TRACE("%x \n",eMessageType); + TRACE("%x\n", eMessageType); rc = 0; if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR) @@ -605,8 +604,8 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType, { LPWSTR tmp; WCHAR number[3]; - const static WCHAR format[] = { '%','i',':',' ',0}; - const static WCHAR space[] = { ' ',0}; + static const WCHAR format[] = { '%','i',':',' ',0}; + static const WCHAR space[] = { ' ',0}; sz = 0; MSI_RecordGetStringW(record,i,NULL,&sz); sz+=4; @@ -690,32 +689,26 @@ out: } /* property code */ -UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue) +UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue ) { LPWSTR szwName = NULL, szwValue = NULL; - UINT hr = ERROR_INSTALL_FAILURE; + UINT r = ERROR_OUTOFMEMORY; - if( szName ) - { - szwName = strdupAtoW( szName ); - if( !szwName ) - goto end; - } + szwName = strdupAtoW( szName ); + if( szName && !szwName ) + goto end; - if( szValue ) - { - szwValue = strdupAtoW( szValue ); - if( !szwValue) - goto end; - } + szwValue = strdupAtoW( szValue ); + if( szValue && !szwValue ) + goto end; - hr = MsiSetPropertyW( hInstall, szwName, szwValue); + r = MsiSetPropertyW( hInstall, szwName, szwValue); end: msi_free( szwName ); msi_free( szwValue ); - return hr; + return r; } UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue) @@ -736,8 +729,14 @@ UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue) ,'e','r','t','y','`',' ','=',' ','\'','%','s','\'',0}; WCHAR Query[1024]; - TRACE("Setting property (%s %s)\n",debugstr_w(szName), - debugstr_w(szValue)); + TRACE("%p %s %s\n", package, debugstr_w(szName), debugstr_w(szValue)); + + if (!szName) + return ERROR_INVALID_PARAMETER; + + /* this one is weird... */ + if (!szName[0]) + return szValue ? ERROR_FUNCTION_FAILED : ERROR_SUCCESS; rc = MSI_GetPropertyW(package,szName,0,&sz); if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS) @@ -775,11 +774,6 @@ UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue MSIPACKAGE *package; UINT ret; - if (NULL == szName) - return ERROR_INVALID_PARAMETER; - if (NULL == szValue) - return ERROR_INVALID_PARAMETER; - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); if( !package ) return ERROR_INVALID_HANDLE; @@ -788,51 +782,33 @@ UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue return ret; } -static UINT MSI_GetPropertyRow(MSIPACKAGE *package, LPCWSTR szName, MSIRECORD **row) +static MSIRECORD *MSI_GetPropertyRow( MSIPACKAGE *package, LPCWSTR name ) { - MSIQUERY *view; - UINT rc, sz; - static const WCHAR select[]= + static const WCHAR query[]= {'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ', 'F','R','O','M',' ' ,'`','_','P','r','o','p','e','r','t','y','`', ' ','W','H','E','R','E',' ' ,'`','_','P','r','o','p','e','r','t','y','`', '=','\'','%','s','\'',0}; - LPWSTR query; - if (!szName) - return ERROR_INVALID_PARAMETER; + if (!name || !name[0]) + return NULL; - sz = sizeof select + strlenW(szName)*sizeof(WCHAR); - query = msi_alloc( sz); - sprintfW(query,select,szName); - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - msi_free(query); - if (rc == ERROR_SUCCESS) - { - rc = MSI_ViewExecute(view, 0); - if (rc == ERROR_SUCCESS) - rc = MSI_ViewFetch(view,row); - - MSI_ViewClose(view); - msiobj_release(&view->hdr); - } - - return rc; + return MSI_QueryGetRecord( package->db, query, name ); } - -UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName, - LPWSTR szValueBuf, DWORD* pchValueBuf) + +/* internal function, not compatible with MsiGetPropertyW */ +UINT MSI_GetPropertyW( MSIPACKAGE *package, LPCWSTR szName, + LPWSTR szValueBuf, DWORD* pchValueBuf ) { MSIRECORD *row; - UINT rc; + UINT rc = ERROR_FUNCTION_FAILED; - rc = MSI_GetPropertyRow(package, szName, &row); + row = MSI_GetPropertyRow( package, szName ); if (*pchValueBuf > 0) szValueBuf[0] = 0; - if (rc == ERROR_SUCCESS) + if (row) { rc = MSI_RecordGetStringW(row,1,szValueBuf,pchValueBuf); msiobj_release(&row->hdr); @@ -853,106 +829,67 @@ UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName, return rc; } -UINT MSI_GetPropertyA(MSIPACKAGE *package, LPCSTR szName, - LPSTR szValueBuf, DWORD* pchValueBuf) -{ - MSIRECORD *row; - UINT rc; - LPWSTR szwName = NULL; - - if (*pchValueBuf > 0) - szValueBuf[0] = 0; - - if( szName ) - { - szwName = strdupAtoW( szName ); - if (!szwName) - return ERROR_NOT_ENOUGH_MEMORY; - } - - rc = MSI_GetPropertyRow(package, szwName, &row); - if (rc == ERROR_SUCCESS) - { - rc = MSI_RecordGetStringA(row,1,szValueBuf,pchValueBuf); - msiobj_release(&row->hdr); - } - - if (rc == ERROR_SUCCESS) - TRACE("returning %s for property %s\n", debugstr_a(szValueBuf), - debugstr_a(szName)); - else if (rc == ERROR_MORE_DATA) - TRACE("need %ld sized buffer for %s\n", *pchValueBuf, - debugstr_a(szName)); - else - { - *pchValueBuf = 0; - TRACE("property not found\n"); - } - msi_free( szwName ); - - return rc; -} - -UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf) +static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name, + awstring *szValueBuf, DWORD* pchValueBuf ) { + static const WCHAR empty[] = {0}; MSIPACKAGE *package; - UINT ret; + MSIRECORD *row = NULL; + UINT r; + LPCWSTR val = NULL; - TRACE("%lu %s %p\n", hInstall, debugstr_a(szName), pchValueBuf); + TRACE("%lu %s %p %p\n", handle, debugstr_w(name), + szValueBuf->str.w, pchValueBuf ); - if (0 == hInstall) - return ERROR_INVALID_HANDLE; - if (NULL == szName) - return ERROR_INVALID_PARAMETER; - if (NULL != szValueBuf && NULL == pchValueBuf) + if (!name) return ERROR_INVALID_PARAMETER; - /* This was tested against native msi */ - if (NULL == szValueBuf && NULL != pchValueBuf) - *pchValueBuf = 0; - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); + package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE ); if (!package) return ERROR_INVALID_HANDLE; - ret = MSI_GetPropertyA(package, szName, szValueBuf, pchValueBuf ); + + row = MSI_GetPropertyRow( package, name ); + if (row) + val = MSI_RecordGetString( row, 1 ); + + if (!val) + val = empty; + + r = msi_strcpy_to_awstring( val, szValueBuf, pchValueBuf ); + + if (row) + msiobj_release( &row->hdr ); msiobj_release( &package->hdr ); - /* MsiGetProperty does not return error codes on missing properties */ - if (ret != ERROR_MORE_DATA) - ret = ERROR_SUCCESS; - - return ret; + return r; } +UINT WINAPI MsiGetPropertyA( MSIHANDLE hInstall, LPCSTR szName, + LPSTR szValueBuf, DWORD* pchValueBuf ) +{ + awstring val; + LPWSTR name; + UINT r; + + val.unicode = FALSE; + val.str.a = szValueBuf; + + name = strdupAtoW( szName ); + if (szName && !name) + return ERROR_OUTOFMEMORY; + + r = MSI_GetProperty( hInstall, name, &val, pchValueBuf ); + msi_free( name ); + return r; +} -UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, - LPWSTR szValueBuf, DWORD* pchValueBuf) +UINT WINAPI MsiGetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, + LPWSTR szValueBuf, DWORD* pchValueBuf ) { - MSIPACKAGE *package; - UINT ret; + awstring val; - TRACE("%lu %s %p\n", hInstall, debugstr_w(szName), pchValueBuf); + val.unicode = TRUE; + val.str.w = szValueBuf; - if (0 == hInstall) - return ERROR_INVALID_HANDLE; - if (NULL == szName) - return ERROR_INVALID_PARAMETER; - if (NULL != szValueBuf && NULL == pchValueBuf) - return ERROR_INVALID_PARAMETER; - - /* This was tested against native msi */ - if (NULL == szValueBuf && NULL != pchValueBuf) - *pchValueBuf = 0; - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf ); - msiobj_release( &package->hdr ); - - /* MsiGetProperty does not return error codes on missing properties */ - if (ret != ERROR_MORE_DATA) - ret = ERROR_SUCCESS; - - return ret; + return MSI_GetProperty( hInstall, szName, &val, pchValueBuf ); } diff --git a/reactos/lib/msi/record.c b/reactos/lib/msi/record.c index 05f80967cc1..c1f6d1fe8c5 100644 --- a/reactos/lib/msi/record.c +++ b/reactos/lib/msi/record.c @@ -39,7 +39,7 @@ #include "query.h" -WINE_DEFAULT_DEBUG_CHANNEL(msi); +WINE_DEFAULT_DEBUG_CHANNEL(msidb); #define MSIFIELD_NULL 0 #define MSIFIELD_INT 1 diff --git a/reactos/lib/msi/registry.c b/reactos/lib/msi/registry.c index b8c206a0d53..941608c2f3d 100644 --- a/reactos/lib/msi/registry.c +++ b/reactos/lib/msi/registry.c @@ -253,6 +253,9 @@ BOOL decode_base85_guid( LPCWSTR str, GUID *guid ) { DWORD i, val = 0, base = 1, *p; + if (!str) + return FALSE; + p = (DWORD*) guid; for( i=0; i<20; i++ ) { @@ -532,10 +535,13 @@ UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct, len = (p - &szDescriptor[20]); if( len > MAX_FEATURE_CHARS ) return ERROR_INVALID_PARAMETER; - memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) ); - szFeature[len] = 0; + if (szFeature) + { + memcpy( szFeature, &szDescriptor[20], len*sizeof(WCHAR) ); + szFeature[len] = 0; + } - TRACE("feature %s\n", debugstr_w( szFeature )); + TRACE("feature %s\n", debugstr_w( &szDescriptor[20] )); r = decode_base85_guid( p+1, &component ); if( !r ) @@ -543,8 +549,10 @@ UINT WINAPI MsiDecomposeDescriptorW( LPCWSTR szDescriptor, LPWSTR szProduct, TRACE("component %s\n", debugstr_guid( &component )); - StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 ); - StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 ); + if (szProduct) + StringFromGUID2( &product, szProduct, MAX_FEATURE_CHARS+1 ); + if (szComponent) + StringFromGUID2( &component, szComponent, MAX_FEATURE_CHARS+1 ); len = ( &p[21] - szDescriptor ); TRACE("length = %d\n", len); @@ -559,26 +567,30 @@ UINT WINAPI MsiDecomposeDescriptorA( LPCSTR szDescriptor, LPSTR szProduct, WCHAR product[MAX_FEATURE_CHARS+1]; WCHAR feature[MAX_FEATURE_CHARS+1]; WCHAR component[MAX_FEATURE_CHARS+1]; - LPWSTR str = NULL; + LPWSTR str = NULL, p = NULL, f = NULL, c = NULL; UINT r; TRACE("%s %p %p %p %p\n", debugstr_a(szDescriptor), szProduct, szFeature, szComponent, pUsed); - if( szDescriptor ) - { - str = strdupAtoW( szDescriptor ); - if( !str ) - return ERROR_OUTOFMEMORY; - } + str = strdupAtoW( szDescriptor ); + if( szDescriptor && !str ) + return ERROR_OUTOFMEMORY; - r = MsiDecomposeDescriptorW( str, product, feature, component, pUsed ); + if (szProduct) + p = product; + if (szFeature) + f = feature; + if (szComponent) + c = component; - WideCharToMultiByte( CP_ACP, 0, product, MAX_FEATURE_CHARS+1, + r = MsiDecomposeDescriptorW( str, p, f, c, pUsed ); + + WideCharToMultiByte( CP_ACP, 0, p, MAX_FEATURE_CHARS+1, szProduct, MAX_FEATURE_CHARS+1, NULL, NULL ); - WideCharToMultiByte( CP_ACP, 0, feature, MAX_FEATURE_CHARS+1, + WideCharToMultiByte( CP_ACP, 0, f, MAX_FEATURE_CHARS+1, szFeature, MAX_FEATURE_CHARS+1, NULL, NULL ); - WideCharToMultiByte( CP_ACP, 0, component, MAX_FEATURE_CHARS+1, + WideCharToMultiByte( CP_ACP, 0, c, MAX_FEATURE_CHARS+1, szComponent, MAX_FEATURE_CHARS+1, NULL, NULL ); msi_free( str ); @@ -757,157 +769,134 @@ UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct) return r; } +UINT WINAPI MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex, + awstring *lpQualBuf, DWORD* pcchQual, + awstring *lpAppBuf, DWORD* pcchAppBuf ) +{ + DWORD name_sz, val_sz, type, ofs; + LPWSTR name = NULL, val = NULL; + UINT r, r2; + HKEY key; + + TRACE("%s %08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex, + lpQualBuf, pcchQual, lpAppBuf, pcchAppBuf); + + if (!szComponent) + return ERROR_INVALID_PARAMETER; + + r = MSIREG_OpenUserComponentsKey( szComponent, &key, FALSE ); + if (r != ERROR_SUCCESS) + return ERROR_UNKNOWN_COMPONENT; + + /* figure out how big the name is we want to return */ + name_sz = 0; + if (pcchQual) + { + r = ERROR_OUTOFMEMORY; + name_sz = *pcchQual * 4; + name = msi_alloc( name_sz * sizeof(WCHAR) ); + if (!name) + goto end; + } + + /* figure out how big the value is */ + type = 0; + val_sz = 0; + r = RegEnumValueW( key, iIndex, NULL, NULL, + NULL, &type, NULL, &val_sz ); + if (r != ERROR_SUCCESS) + goto end; + + if (type != REG_MULTI_SZ) + { + ERR("component data has wrong type (%ld)\n", type); + goto end; + } + + /* the value size is in bytes */ + val_sz += sizeof(WCHAR); + val = msi_alloc( val_sz ); + if (!val) + goto end; + + r = RegEnumValueW( key, iIndex, name, &name_sz, + NULL, &type, (LPBYTE)val, &val_sz ); + if (r != ERROR_SUCCESS) + goto end; + + ofs = 0; + r = MsiDecomposeDescriptorW( val, NULL, NULL, NULL, &ofs ); + if (r != ERROR_SUCCESS) + goto end; + + TRACE("Providing %s and %s\n", debugstr_w(name), debugstr_w(val+ofs)); + + r = msi_strcpy_to_awstring( name, lpQualBuf, pcchQual ); + r2 = msi_strcpy_to_awstring( val+ofs, lpAppBuf, pcchAppBuf ); + + if (r2 != ERROR_SUCCESS) + r = r2; + +end: + msi_free(val); + msi_free(name); + RegCloseKey(key); + + return r; +} + /************************************************************************* * MsiEnumComponentQualifiersA [MSI.@] - * */ -UINT WINAPI MsiEnumComponentQualifiersA( LPSTR szComponent, DWORD iIndex, +UINT WINAPI MsiEnumComponentQualifiersA( LPCSTR szComponent, DWORD iIndex, LPSTR lpQualifierBuf, DWORD* pcchQualifierBuf, - LPSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf) + LPSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf ) { - LPWSTR szwComponent; - LPWSTR lpwQualifierBuf; - DWORD pcchwQualifierBuf; - LPWSTR lpwApplicationDataBuf; - DWORD pcchwApplicationDataBuf; - DWORD rc; - DWORD length; + awstring qual, appdata; + LPWSTR comp; + UINT r; TRACE("%s %08lx %p %p %p %p\n", debugstr_a(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, pcchApplicationDataBuf); - szwComponent = strdupAtoW(szComponent); + comp = strdupAtoW( szComponent ); + if (szComponent && !comp) + return ERROR_OUTOFMEMORY; - if (lpQualifierBuf) - lpwQualifierBuf = msi_alloc( (*pcchQualifierBuf) * sizeof(WCHAR)); - else - lpwQualifierBuf = NULL; + qual.unicode = FALSE; + qual.str.a = lpQualifierBuf; - if (pcchQualifierBuf) - pcchwQualifierBuf = *pcchQualifierBuf; - else - pcchwQualifierBuf = 0; + appdata.unicode = FALSE; + appdata.str.a = lpApplicationDataBuf; - if (lpApplicationDataBuf) - lpwApplicationDataBuf = msi_alloc( (*pcchApplicationDataBuf) * sizeof(WCHAR)); - else - lpwApplicationDataBuf = NULL; - - if (pcchApplicationDataBuf) - pcchwApplicationDataBuf = *pcchApplicationDataBuf; - else - pcchwApplicationDataBuf = 0; - - rc = MsiEnumComponentQualifiersW( szwComponent, iIndex, lpwQualifierBuf, - &pcchwQualifierBuf, lpwApplicationDataBuf, - &pcchwApplicationDataBuf); - - /* - * A bit of wizardry to report back the length without the null. - * just in case the buffer is too small and is filled. - */ - if (lpQualifierBuf) - { - length = WideCharToMultiByte(CP_ACP, 0, lpwQualifierBuf, -1, - lpQualifierBuf, *pcchQualifierBuf, NULL, NULL); - - if (*pcchQualifierBuf == length && lpQualifierBuf[length-1]) - *pcchQualifierBuf = length; - else - *pcchQualifierBuf = length - 1; - } - if (lpApplicationDataBuf) - { - length = WideCharToMultiByte(CP_ACP, 0, - lpwApplicationDataBuf, -1, lpApplicationDataBuf, - *pcchApplicationDataBuf, NULL, NULL); - - if (*pcchApplicationDataBuf == length && lpApplicationDataBuf[length-1]) - *pcchApplicationDataBuf = length; - else - *pcchApplicationDataBuf = length - 1; - } - - msi_free(lpwApplicationDataBuf); - msi_free(lpwQualifierBuf); - msi_free(szwComponent); - - return rc; + r = MSI_EnumComponentQualifiers( comp, iIndex, + &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf ); + msi_free( comp ); + return r; } /************************************************************************* * MsiEnumComponentQualifiersW [MSI.@] - * */ -UINT WINAPI MsiEnumComponentQualifiersW( LPWSTR szComponent, DWORD iIndex, +UINT WINAPI MsiEnumComponentQualifiersW( LPCWSTR szComponent, DWORD iIndex, LPWSTR lpQualifierBuf, DWORD* pcchQualifierBuf, LPWSTR lpApplicationDataBuf, DWORD* pcchApplicationDataBuf ) { - UINT rc; - HKEY key; - DWORD actual_pcchQualifierBuf = 0; - DWORD actual_pcchApplicationDataBuf = 0; - LPWSTR full_buffer = NULL; - DWORD full_buffer_size = 0; - LPWSTR ptr; + awstring qual, appdata; TRACE("%s %08lx %p %p %p %p\n", debugstr_w(szComponent), iIndex, lpQualifierBuf, pcchQualifierBuf, lpApplicationDataBuf, pcchApplicationDataBuf); - if (pcchQualifierBuf) - actual_pcchQualifierBuf = *pcchQualifierBuf * sizeof(WCHAR); - if (pcchApplicationDataBuf) - actual_pcchApplicationDataBuf = *pcchApplicationDataBuf * sizeof(WCHAR); - - rc = MSIREG_OpenUserComponentsKey(szComponent, &key, FALSE); - if (rc != ERROR_SUCCESS) - return ERROR_UNKNOWN_COMPONENT; + qual.unicode = TRUE; + qual.str.w = lpQualifierBuf; - full_buffer_size = (52 * sizeof(WCHAR)) + actual_pcchApplicationDataBuf; - full_buffer = msi_alloc(full_buffer_size); - - rc = RegEnumValueW(key, iIndex, lpQualifierBuf, pcchQualifierBuf, NULL, - NULL, (LPBYTE)full_buffer, &full_buffer_size); + appdata.unicode = TRUE; + appdata.str.w = lpApplicationDataBuf; - if (rc == ERROR_MORE_DATA) - { - msi_free(full_buffer); - full_buffer_size+=sizeof(WCHAR); - full_buffer = msi_alloc(full_buffer_size); - rc = RegEnumValueW(key, iIndex, lpQualifierBuf, pcchQualifierBuf, NULL, - NULL, (LPBYTE)full_buffer, &full_buffer_size); - } - - RegCloseKey(key); - - if (rc == ERROR_SUCCESS) - { - if (lpApplicationDataBuf && pcchApplicationDataBuf) - { - ptr = full_buffer; - /* Skip the first guid */ - ptr += 21; - - /* Skip the name and the component guid if it exists */ - if (strchrW(ptr,'<')) - ptr = strchrW(ptr,'<'); - else - ptr = strchrW(ptr,'>') + 21; - - lstrcpynW(lpApplicationDataBuf,ptr,*pcchApplicationDataBuf); - *pcchApplicationDataBuf = strlenW(ptr); - } - if (lpQualifierBuf && pcchQualifierBuf) - *pcchQualifierBuf /= sizeof(WCHAR); - TRACE("Providing %s and %s\n", debugstr_w(lpQualifierBuf), - debugstr_w(lpApplicationDataBuf)); - } - - msi_free(full_buffer); - - return rc; + return MSI_EnumComponentQualifiers( szComponent, iIndex, + &qual, pcchQualifierBuf, &appdata, pcchApplicationDataBuf ); } /************************************************************************* diff --git a/reactos/lib/msi/select.c b/reactos/lib/msi/select.c index 7345c1777fa..9bc2b964d37 100644 --- a/reactos/lib/msi/select.c +++ b/reactos/lib/msi/select.c @@ -33,7 +33,7 @@ #include "query.h" -WINE_DEFAULT_DEBUG_CHANNEL(msi); +WINE_DEFAULT_DEBUG_CHANNEL(msidb); /* below is the query interface to a table */ diff --git a/reactos/lib/msi/string.c b/reactos/lib/msi/string.c index 815d808188c..a5ec138b987 100644 --- a/reactos/lib/msi/string.c +++ b/reactos/lib/msi/string.c @@ -35,7 +35,7 @@ #include "query.h" -WINE_DEFAULT_DEBUG_CHANNEL(msi); +WINE_DEFAULT_DEBUG_CHANNEL(msidb); typedef struct _msistring { diff --git a/reactos/lib/msi/suminfo.c b/reactos/lib/msi/suminfo.c index 323da5c9e77..8a5d973a306 100644 --- a/reactos/lib/msi/suminfo.c +++ b/reactos/lib/msi/suminfo.c @@ -39,8 +39,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); -#define MSI_MAX_PROPS 20 - #include "pshpack1.h" typedef struct { @@ -83,14 +81,6 @@ typedef struct { #define SECT_HDR_SIZE (sizeof(PROPERTYSECTIONHEADER)) -typedef struct tagMSISUMMARYINFO -{ - MSIOBJECTHDR hdr; - MSIDATABASE *db; - DWORD update_count; - PROPVARIANT property[MSI_MAX_PROPS]; -} MSISUMMARYINFO; - static const WCHAR szSumInfo[] = { 5 ,'S','u','m','m','a','r','y', 'I','n','f','o','r','m','a','t','i','o','n',0 }; @@ -417,45 +407,19 @@ static UINT save_summary_info( MSISUMMARYINFO * si, IStream *stm ) return ERROR_SUCCESS; } -UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase, - LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle ) +MSISUMMARYINFO *MSI_GetSummaryInformationW( MSIDATABASE *db, UINT uiUpdateCount ) { - UINT ret = ERROR_SUCCESS; IStream *stm = NULL; MSISUMMARYINFO *si; - MSIHANDLE handle; - MSIDATABASE *db; DWORD grfMode; HRESULT r; - TRACE("%ld %s %d %p\n", hDatabase, debugstr_w(szDatabase), - uiUpdateCount, pHandle); - - if( !pHandle ) - return ERROR_INVALID_PARAMETER; - - if( szDatabase ) - { - UINT res; - - res = MSI_OpenDatabaseW(szDatabase, NULL, &db); - if( res != ERROR_SUCCESS ) - return res; - } - else - { - db = msihandle2msiinfo(hDatabase, MSIHANDLETYPE_DATABASE); - if( !db ) - return ERROR_INVALID_PARAMETER; - } + TRACE("%p %d\n", db, uiUpdateCount ); si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo ); if( !si ) - { - ret = ERROR_FUNCTION_FAILED; - goto end; - } + return si; msiobj_addref( &db->hdr ); si->db = db; @@ -471,14 +435,44 @@ UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase, IStream_Release( stm ); } - handle = alloc_msihandle( &si->hdr ); - if( handle ) - *pHandle = handle; - else - ret = ERROR_FUNCTION_FAILED; - msiobj_release( &si->hdr ); + return si; +} + +UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase, + LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle ) +{ + MSISUMMARYINFO *si; + MSIDATABASE *db; + UINT ret = ERROR_FUNCTION_FAILED; + + TRACE("%ld %s %d %p\n", hDatabase, debugstr_w(szDatabase), + uiUpdateCount, pHandle); + + if( !pHandle ) + return ERROR_INVALID_PARAMETER; + + if( szDatabase ) + { + ret = MSI_OpenDatabaseW( szDatabase, NULL, &db ); + if( ret != ERROR_SUCCESS ) + return ret; + } + else + { + db = msihandle2msiinfo( hDatabase, MSIHANDLETYPE_DATABASE ); + if( !db ) + return ERROR_INVALID_PARAMETER; + } + + si = MSI_GetSummaryInformationW( db, uiUpdateCount ); + if (si) + { + *pHandle = alloc_msihandle( &si->hdr ); + if( *pHandle ) + ret = ERROR_SUCCESS; + msiobj_release( &si->hdr ); + } -end: if( db ) msiobj_release( &db->hdr ); @@ -539,6 +533,12 @@ static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, if( !si ) return ERROR_INVALID_HANDLE; + if ( uiProperty >= MSI_MAX_PROPS ) + { + *puiDataType = VT_EMPTY; + return ret; + } + prop = &si->property[uiProperty]; if( puiDataType ) @@ -590,6 +590,18 @@ static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, return ret; } +LPWSTR msi_suminfo_dup_string( MSISUMMARYINFO *si, UINT uiProperty ) +{ + PROPVARIANT *prop; + + if ( uiProperty >= MSI_MAX_PROPS ) + return NULL; + prop = &si->property[uiProperty]; + if( prop->vt != VT_LPSTR ) + return NULL; + return strdupAtoW( prop->u.pszVal ); +} + UINT WINAPI MsiSummaryInfoGetPropertyA( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue, FILETIME *pftValue, LPSTR szValueBuf, DWORD *pcchValueBuf) diff --git a/reactos/lib/msi/table.c b/reactos/lib/msi/table.c index b3b110ae989..a3becc6770e 100644 --- a/reactos/lib/msi/table.c +++ b/reactos/lib/msi/table.c @@ -37,7 +37,7 @@ #include "query.h" -WINE_DEFAULT_DEBUG_CHANNEL(msi); +WINE_DEFAULT_DEBUG_CHANNEL(msidb); typedef struct tagMSICOLUMNINFO { @@ -56,6 +56,11 @@ struct tagMSITABLE WCHAR name[1]; }; +typedef struct tagMSITRANSFORM { + struct list entry; + IStorage *stg; +} MSITRANSFORM; + #define MAX_STREAM_NAME 0x1f static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, @@ -276,14 +281,23 @@ UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm ) r = IStorage_OpenStream(db->storage, encname, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm); - msi_free( encname ); if( FAILED( r ) ) { - WARN("open stream failed r = %08lx - empty table?\n",r); - return ERROR_FUNCTION_FAILED; + MSITRANSFORM *transform; + + LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry ) + { + TRACE("looking for %s in transform storage\n", debugstr_w(stname) ); + r = IStorage_OpenStream( transform->stg, encname, NULL, + STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm ); + if (SUCCEEDED(r)) + break; + } } - return ERROR_SUCCESS; + msi_free( encname ); + + return SUCCEEDED(r) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED; } UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname, @@ -1050,7 +1064,7 @@ static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT * return ERROR_FUNCTION_FAILED; } - /* TRACE("Data [%d][%d] = %d \n", row, col, *val ); */ + /* TRACE("Data [%d][%d] = %d\n", row, col, *val ); */ return ERROR_SUCCESS; } @@ -1246,113 +1260,44 @@ static UINT TABLE_get_column_info( struct tagMSIVIEW *view, return ERROR_SUCCESS; } -static UINT table_find_in_column( MSITABLEVIEW *tv, UINT col, UINT val, UINT *row ) -{ - UINT i, r, x; - - for( i=0; itable->row_count; i++ ) - { - r = TABLE_fetch_int( (struct tagMSIVIEW*) tv, i, col, &x ); - if ( r != ERROR_SUCCESS ) - { - ERR("TABLE_fetch_int shouldn't fail here\n"); - break; - } - if ( x == val ) - { - *row = i; - return ERROR_SUCCESS; - } - } - return ERROR_FUNCTION_FAILED; -} +static UINT msi_table_find_row( MSITABLEVIEW *tv, MSIRECORD *rec, UINT *row ); static UINT table_validate_new( MSITABLEVIEW *tv, MSIRECORD *rec ) { - LPCWSTR str; - UINT i, val, r, row; - BOOL has_key = FALSE; + UINT r, row; - /* FIXME: set the MsiViewGetError value */ - - for( i = 0; inum_cols; i++ ) - { - /* check for duplicate keys */ - if( !( tv->columns[i].type & MSITYPE_KEY ) ) - continue; - - has_key = TRUE; - - TRACE("column %d (%s.%s)is a key\n", i, - debugstr_w(tv->columns[i].tablename), - debugstr_w(tv->columns[i].colname) ); - - val = 0; - if( tv->columns[i].type & MSITYPE_STRING ) - { - /* keys can't be null */ - str = MSI_RecordGetString( rec, i+1 ); - if( !str ) - return ERROR_INVALID_DATA; - - /* if the string doesn't exist in the string table yet, it's OK */ - r = msi_string2idW( tv->db->strings, str, &val ); - if( ERROR_SUCCESS != r ) - return ERROR_SUCCESS; - } - else - { - val = MSI_RecordGetInteger( rec, i+1 ); - val ^= 0x8000; - } - - /* if we find the same value in the table, it's a duplicate */ - row = 0; - r = table_find_in_column( tv, i+1, val, &row ); - if( ERROR_SUCCESS != r ) - return ERROR_SUCCESS; - - TRACE("found in row %d\n", row ); - } - - if (has_key) - return ERROR_INVALID_DATA; - - return ERROR_SUCCESS; + r = msi_table_find_row( tv, rec, &row ); + if (r != ERROR_SUCCESS) + return ERROR_SUCCESS; + return ERROR_INVALID_DATA; } -static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec ) +static UINT msi_table_modify_row( MSITABLEVIEW *tv, MSIRECORD *rec, + UINT row, UINT mask ) { - MSITABLEVIEW *tv = (MSITABLEVIEW*)view; - UINT n, type, val, r, row, col_count = 0; + UINT i, val, r = ERROR_SUCCESS; - r = TABLE_get_dimensions( view, NULL, &col_count ); - if( r ) - return r; + TRACE("%p %p %u %08x\n", tv, rec, row, mask ); - row = -1; - r = table_create_new_row( view, &row ); - TRACE("insert_row returned %08x\n", r); - if( r ) - return r; - - for( n = 1; n <= col_count; n++ ) + for( i = 0; i < tv->num_cols; i++ ) { - r = TABLE_get_column_info( view, n, NULL, &type ); - if( r ) - break; + /* set keys or values specified in the mask */ + if( (~tv->columns[i].type & MSITYPE_KEY) && (~mask & (1<columns[i].type & MSITYPE_STRING) && + ! MSITYPE_IS_BINARY(tv->columns[i].type) ) { - const WCHAR *str = MSI_RecordGetString( rec, n ); + const WCHAR *str = MSI_RecordGetString( rec, i+1 ); val = msi_addstringW( tv->db->strings, 0, str, -1, 1 ); } else { - val = MSI_RecordGetInteger( rec, n ); - val ^= 0x8000; + val = MSI_RecordGetInteger( rec, i+1 ); + if ( 2 == bytes_per_column( &tv->columns[i] ) ) + val ^= 0x8000; } - r = TABLE_set_int( view, row, n, val ); + r = TABLE_set_int( &tv->view, row, i+1, val ); if( r ) break; } @@ -1360,6 +1305,21 @@ static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec ) return r; } +static UINT TABLE_insert_row( struct tagMSIVIEW *view, MSIRECORD *rec ) +{ + MSITABLEVIEW *tv = (MSITABLEVIEW*)view; + UINT r, row = -1; + + TRACE("%p %p\n", tv, rec ); + + r = table_create_new_row( view, &row ); + TRACE("insert_row returned %08x\n", r); + if( r != ERROR_SUCCESS ) + return r; + + return msi_table_modify_row( tv, rec, row, ~0 ); +} + static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIRECORD *rec) { @@ -1532,3 +1492,370 @@ UINT MSI_CommitTables( MSIDATABASE *db ) return ERROR_SUCCESS; } + +static MSIRECORD *msi_get_transform_record( MSITABLEVIEW *tv, string_table *st, USHORT *rawdata ) +{ + UINT i, val, ofs = 0; + USHORT mask = *rawdata++; + MSICOLUMNINFO *columns = tv->columns; + MSIRECORD *rec; + const int debug_transform = 0; + + rec = MSI_CreateRecord( tv->num_cols ); + if( !rec ) + return rec; + + if( debug_transform ) MESSAGE("row -> "); + for( i=0; inum_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<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; inum_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; inum_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; itable->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; inum_cols; i++ ) + { + if( (tv->columns[i].type & MSITYPE_KEY) || ((1<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 ); + } +} diff --git a/reactos/lib/msi/update.c b/reactos/lib/msi/update.c index 6a5791297a0..a36c5196483 100644 --- a/reactos/lib/msi/update.c +++ b/reactos/lib/msi/update.c @@ -33,7 +33,7 @@ #include "query.h" -WINE_DEFAULT_DEBUG_CHANNEL(msi); +WINE_DEFAULT_DEBUG_CHANNEL(msidb); /* below is the query interface to a table */ diff --git a/reactos/lib/msi/where.c b/reactos/lib/msi/where.c index cf54e4a05af..b11ebe79f13 100644 --- a/reactos/lib/msi/where.c +++ b/reactos/lib/msi/where.c @@ -33,7 +33,7 @@ #include "query.h" -WINE_DEFAULT_DEBUG_CHANNEL(msi); +WINE_DEFAULT_DEBUG_CHANNEL(msidb); /* below is the query interface to a table */ diff --git a/reactos/w32api/include/msi.h b/reactos/w32api/include/msi.h index 7dfb69e3fbe..0e2a14f35d7 100644 --- a/reactos/w32api/include/msi.h +++ b/reactos/w32api/include/msi.h @@ -31,6 +31,7 @@ typedef unsigned long MSIHANDLE; typedef enum tagINSTALLSTATE { + INSTALLSTATE_NOTUSED = -7, INSTALLSTATE_BADCONFIG = -6, INSTALLSTATE_INCOMPLETE = -5, INSTALLSTATE_SOURCEABSENT = -4, @@ -136,12 +137,33 @@ typedef enum tagINSTALLLOGATTRIBUTES INSTALLLOGATTRIBUTES_FLUSHEACHLINE = 0x00000002 } INSTALLLOGATTRIBUTES; +typedef enum tagINSTALLMODE +{ + INSTALLMODE_NODETECTION_ANY = -4, + INSTALLMODE_NOSOURCERESOLUTION = -3, + INSTALLMODE_NODETECTION = -2, + INSTALLMODE_EXISTING = -1, + INSTALLMODE_DEFAULT = 0 +} INSTALLMODE; + typedef enum tagADVERTISEFLAGS { ADVERTISEFLAGS_MACHINEASSIGN = 0, ADVERTISEFLAGS_USERASSIGN = 1 } ADVERTISEFLAGS; +typedef enum tagSCRIPTFLAGS +{ + SCRIPTFLAGS_CACHEINFO = 1, + SCRIPTFLAGS_SHORTCUTS = 4, + SCRIPTFLAGS_MACHINEASSIGN = 8, + SCRIPTFLAGS_REGDATA_APPINFO = 0x10, + SCRIPTFLAGS_REGDATA_CNFGINFO = 0x20, + SCRIPTFLAGS_VALIDATE_TRANSFORMS_LIST = 0x40, + SCRIPTFLAGS_REGDATA_CLASSINFO = 0x80, + SCRIPTFLAGS_REGDATA_EXTENSIONINFO = 0x100, +} SCRIPTFLAGS; + typedef enum tagINSTALLTYPE { INSTALLTYPE_DEFAULT = 0, @@ -173,6 +195,11 @@ typedef enum tagMSICODE MSICODE_PATCH = 0x40000000L } MSICODE; +typedef struct _MSIFILEHASHINFO { + ULONG dwFileHashInfoSize; + ULONG dwData[4]; +} MSIFILEHASHINFO, *PMSIFILEHASHINFO; + #define MAX_FEATURE_CHARS 38 /* Strings defined in msi.h */ @@ -409,6 +436,10 @@ UINT WINAPI MsiConfigureProductExA(LPCSTR, int, INSTALLSTATE, LPCSTR); UINT WINAPI MsiConfigureProductExW(LPCWSTR, int, INSTALLSTATE, LPCWSTR); #define MsiConfigureProductEx WINELIB_NAME_AW(MsiConfigureProductEx); +UINT WINAPI MsiConfigureFeatureA(LPCSTR, LPCSTR, INSTALLSTATE); +UINT WINAPI MsiConfigureFeatureW(LPCWSTR, LPCWSTR, INSTALLSTATE); +#define MsiConfigureFeature WINELIB_NAME_AW(MsiConfigureFeature); + UINT WINAPI MsiGetProductCodeA(LPCSTR, LPSTR); UINT WINAPI MsiGetProductCodeW(LPCWSTR, LPWSTR); #define MsiGetProductCode WINELIB_NAME_AW(MsiGetProductCode) @@ -445,8 +476,8 @@ UINT WINAPI MsiProvideAssemblyA(LPCSTR, LPCSTR, DWORD, DWORD, LPSTR, DWORD*); UINT WINAPI MsiProvideAssemblyW(LPCWSTR, LPCWSTR, DWORD, DWORD, LPWSTR, DWORD*); #define MsiProvideAssembly WINELIB_NAME_AW(MsiProvideAssembly) -UINT WINAPI MsiEnumComponentQualifiersA(LPSTR, DWORD, LPSTR, DWORD*, LPSTR, DWORD*); -UINT WINAPI MsiEnumComponentQualifiersW(LPWSTR, DWORD, LPWSTR, DWORD*, LPWSTR, DWORD*); +UINT WINAPI MsiEnumComponentQualifiersA(LPCSTR, DWORD, LPSTR, DWORD*, LPSTR, DWORD*); +UINT WINAPI MsiEnumComponentQualifiersW(LPCWSTR, DWORD, LPWSTR, DWORD*, LPWSTR, DWORD*); #define MsiEnumComponentQualifiers WINELIB_NAME_AW(MsiEnumComponentQualifiers) UINT WINAPI MsiGetFileVersionA(LPCSTR, LPSTR, DWORD*, LPSTR, DWORD*); @@ -513,6 +544,18 @@ UINT WINAPI MsiSourceListAddMediaDiskA(LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR, LPCWSTR, MSIINSTALLCONTEXT, DWORD, DWORD, LPCWSTR, LPCWSTR); #define MsiSourceListAddMediaDisk WINELIB_NAME_AW(MsiSourceListAddMediaDisk) +UINT WINAPI MsiEnumPatchesA(LPCSTR, DWORD, LPSTR, LPSTR, DWORD*); +UINT WINAPI MsiEnumPatchesW(LPCWSTR, DWORD, LPWSTR, LPWSTR, DWORD*); +#define MsiEnumPatches WINELIB_NAME_AW(MsiEnumPatches) + +UINT WINAPI MsiGetFileHashA(LPCSTR, DWORD, PMSIFILEHASHINFO); +UINT WINAPI MsiGetFileHashW(LPCWSTR, DWORD, PMSIFILEHASHINFO); +#define MsiGetFileHash WINELIB_NAME_AW(MsiGetFileHash) + +UINT WINAPI MsiAdvertiseScriptA(LPCSTR, DWORD, PHKEY, BOOL); +UINT WINAPI MsiAdvertiseScriptW(LPCWSTR, DWORD, PHKEY, BOOL); +#define MsiAdvertiseScript WINELIB_NAME_AW(MsiAdvertiseScript) + /* Non Unicode */ UINT WINAPI MsiCloseHandle(MSIHANDLE); UINT WINAPI MsiCloseAllHandles(void); diff --git a/reactos/w32api/include/msiquery.h b/reactos/w32api/include/msiquery.h index ab70681cb69..c98c30f51f7 100644 --- a/reactos/w32api/include/msiquery.h +++ b/reactos/w32api/include/msiquery.h @@ -53,11 +53,19 @@ typedef enum tagMSIMODIFY MSIMODIFY_VALIDATE_DELETE = 11 } MSIMODIFY; +#ifndef __WINESRC__ #define MSIDBOPEN_READONLY (LPCTSTR)0 #define MSIDBOPEN_TRANSACT (LPCTSTR)1 #define MSIDBOPEN_DIRECT (LPCTSTR)2 #define MSIDBOPEN_CREATE (LPCTSTR)3 #define MSIDBOPEN_CREATEDIRECT (LPCTSTR)4 +#else +#define MSIDBOPEN_READONLY (LPCWSTR)0 +#define MSIDBOPEN_TRANSACT (LPCWSTR)1 +#define MSIDBOPEN_DIRECT (LPCWSTR)2 +#define MSIDBOPEN_CREATE (LPCWSTR)3 +#define MSIDBOPEN_CREATEDIRECT (LPCWSTR)4 +#endif typedef enum tagMSIRUNMODE { @@ -261,6 +269,7 @@ UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE,UINT*); UINT WINAPI MsiEnableUIPreview(MSIHANDLE, MSIHANDLE*); BOOL WINAPI MsiGetMode(MSIHANDLE, MSIRUNMODE); +BOOL WINAPI MsiSetMode(MSIHANDLE, MSIRUNMODE, BOOL); UINT WINAPI MsiViewModify(MSIHANDLE, MSIMODIFY, MSIHANDLE);