diff --git a/reactos/dll/win32/msi/action.c b/reactos/dll/win32/msi/action.c index 79047704173..d94d842cae1 100644 --- a/reactos/dll/win32/msi/action.c +++ b/reactos/dll/win32/msi/action.c @@ -959,10 +959,6 @@ UINT msi_create_component_directories( MSIPACKAGE *package ) return ERROR_SUCCESS; } -/* - * Also we cannot enable/disable components either, so for now I am just going - * to do all the directories for all the components. - */ static UINT ACTION_CreateFolders(MSIPACKAGE *package) { static const WCHAR ExecSeqQuery[] = @@ -981,7 +977,60 @@ static UINT ACTION_CreateFolders(MSIPACKAGE *package) rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package); msiobj_release(&view->hdr); - msi_create_component_directories( package ); + return rc; +} + +static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param ) +{ + MSIPACKAGE *package = param; + LPCWSTR dir; + LPWSTR full_path; + MSIRECORD *uirow; + MSIFOLDER *folder; + + dir = MSI_RecordGetString( row, 1 ); + if (!dir) + { + ERR("Unable to get folder id\n"); + return ERROR_SUCCESS; + } + + full_path = resolve_folder( package, dir, FALSE, FALSE, TRUE, &folder ); + if (!full_path) + { + ERR("Unable to resolve folder id %s\n", debugstr_w(dir)); + return ERROR_SUCCESS; + } + + TRACE("folder is %s\n", debugstr_w(full_path)); + + uirow = MSI_CreateRecord( 1 ); + MSI_RecordSetStringW( uirow, 1, full_path ); + ui_actiondata( package, szRemoveFolders, uirow ); + msiobj_release( &uirow->hdr ); + + RemoveDirectoryW( full_path ); + folder->State = 0; + + msi_free( full_path ); + return ERROR_SUCCESS; +} + +static UINT ACTION_RemoveFolders( MSIPACKAGE *package ) +{ + static const WCHAR query[] = + {'S','E','L','E','C','T',' ', '`','D','i','r','e','c','t','o','r','y','_','`', + ' ','F','R','O','M',' ', '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0}; + + MSIQUERY *view; + UINT rc; + + rc = MSI_DatabaseOpenViewW( package->db, query, &view ); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package ); + msiobj_release( &view->hdr ); return rc; } @@ -1562,8 +1611,10 @@ static BOOL process_state_property(MSIPACKAGE* package, int level, while (ptr) { - if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0) - || (!ptr2 && strcmpW(ptr,feature->Feature)==0)) + int len = ptr2 - ptr; + + if ((ptr2 && strlenW(feature->Feature) == len && !strncmpW(ptr, feature->Feature, len)) + || (!ptr2 && !strcmpW(ptr, feature->Feature))) { msi_feature_set_state(package, feature, state); break; @@ -1583,55 +1634,57 @@ static BOOL process_state_property(MSIPACKAGE* package, int level, return TRUE; } -UINT MSI_SetFeatureStates(MSIPACKAGE *package) +static BOOL process_overrides( MSIPACKAGE *package, int level ) { - int level; - static const WCHAR szlevel[] = - {'I','N','S','T','A','L','L','L','E','V','E','L',0}; static const WCHAR szAddLocal[] = {'A','D','D','L','O','C','A','L',0}; static const WCHAR szAddSource[] = {'A','D','D','S','O','U','R','C','E',0}; static const WCHAR szAdvertise[] = {'A','D','V','E','R','T','I','S','E',0}; - BOOL override = FALSE; + BOOL ret = FALSE; + + /* all these activation/deactivation things happen in order and things + * later on the list override things earlier on the list. + * + * 0 INSTALLLEVEL processing + * 1 ADDLOCAL + * 2 REMOVE + * 3 ADDSOURCE + * 4 ADDDEFAULT + * 5 REINSTALL + * 6 ADVERTISE + * 7 COMPADDLOCAL + * 8 COMPADDSOURCE + * 9 FILEADDLOCAL + * 10 FILEADDSOURCE + * 11 FILEADDDEFAULT + */ + ret |= process_state_property( package, level, szAddLocal, INSTALLSTATE_LOCAL ); + ret |= process_state_property( package, level, szRemove, INSTALLSTATE_ABSENT ); + ret |= process_state_property( package, level, szAddSource, INSTALLSTATE_SOURCE ); + ret |= process_state_property( package, level, szReinstall, INSTALLSTATE_UNKNOWN ); + ret |= process_state_property( package, level, szAdvertise, INSTALLSTATE_ADVERTISED ); + + if (ret) + MSI_SetPropertyW( package, szPreselected, szOne ); + + return ret; +} + +UINT MSI_SetFeatureStates(MSIPACKAGE *package) +{ + int level; + static const WCHAR szlevel[] = + {'I','N','S','T','A','L','L','L','E','V','E','L',0}; MSICOMPONENT* component; MSIFEATURE *feature; - - /* I do not know if this is where it should happen.. but */ - TRACE("Checking Install Level\n"); level = msi_get_property_int(package, szlevel, 1); - /* ok here is the _real_ rub - * all these activation/deactivation things happen in order and things - * later on the list override things earlier on the list. - * 0) INSTALLLEVEL processing - * 1) ADDLOCAL - * 2) REMOVE - * 3) ADDSOURCE - * 4) ADDDEFAULT - * 5) REINSTALL - * 6) ADVERTISE - * 7) COMPADDLOCAL - * 8) COMPADDSOURCE - * 9) FILEADDLOCAL - * 10) FILEADDSOURCE - * 11) FILEADDDEFAULT - * - * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and - * REMOVE are the big ones, since we don't handle administrative installs - * yet anyway. - */ - override |= process_state_property(package, level, szAddLocal, INSTALLSTATE_LOCAL); - override |= process_state_property(package, level, szRemove, INSTALLSTATE_ABSENT); - override |= process_state_property(package, level, szAddSource, INSTALLSTATE_SOURCE); - override |= process_state_property(package, level, szReinstall, INSTALLSTATE_UNKNOWN); - override |= process_state_property(package, level, szAdvertise, INSTALLSTATE_ADVERTISED); - - if (!override) + if (!msi_get_property_int( package, szPreselected, 0 )) { LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry ) { @@ -1661,8 +1714,6 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package) msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN); } } - else - MSI_SetPropertyW(package, szPreselected, szOne); /* * now we want to enable or disable components base on feature @@ -1961,7 +2012,7 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) static const WCHAR szOutOfDiskSpace[] = {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0}; MSICOMPONENT *comp; - UINT rc; + UINT rc = ERROR_SUCCESS; MSIQUERY * view; LPWSTR level; @@ -1982,26 +2033,28 @@ static UINT ACTION_CostFinalize(MSIPACKAGE *package) TRACE("File calculations\n"); msi_check_file_install_states( package ); - TRACE("Evaluating Condition Table\n"); - - rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view); - if (rc == ERROR_SUCCESS) + if (!process_overrides( package, msi_get_property_int( package, szlevel, 1 ) )) { - rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions, - package); - msiobj_release(&view->hdr); - } + TRACE("Evaluating Condition Table\n"); - TRACE("Enabling or Disabling Components\n"); - LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) - { - if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE) + rc = MSI_DatabaseOpenViewW( package->db, ConditionQuery, &view ); + if (rc == ERROR_SUCCESS) { - TRACE("Disabling component %s\n", debugstr_w(comp->Component)); - comp->Enabled = FALSE; + rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package ); + msiobj_release( &view->hdr ); + } + + TRACE("Enabling or Disabling Components\n"); + LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry ) + { + if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE) + { + TRACE("Disabling component %s\n", debugstr_w(comp->Component)); + comp->Enabled = FALSE; + } + else + comp->Enabled = TRUE; } - else - comp->Enabled = TRUE; } MSI_SetPropertyW(package,szCosting,szOne); @@ -3652,6 +3705,89 @@ static UINT ACTION_SelfRegModules(MSIPACKAGE *package) return ERROR_SUCCESS; } +static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param ) +{ + static const WCHAR regsvr32[] = + {'r','e','g','s','v','r','3','2','.','e','x','e',' ','/','u',' ','\"',0}; + static const WCHAR close[] = {'\"',0}; + MSIPACKAGE *package = param; + LPCWSTR filename; + LPWSTR cmdline; + MSIFILE *file; + DWORD len; + STARTUPINFOW si; + PROCESS_INFORMATION pi; + BOOL ret; + MSIRECORD *uirow; + LPWSTR uipath, p; + + memset( &si, 0, sizeof(STARTUPINFOW) ); + + filename = MSI_RecordGetString( row, 1 ); + file = get_loaded_file( package, filename ); + + if (!file) + { + ERR("Unable to find file id %s\n", debugstr_w(filename)); + return ERROR_SUCCESS; + } + + len = strlenW( regsvr32 ) + strlenW( file->TargetPath ) + 2; + + cmdline = msi_alloc( len * sizeof(WCHAR) ); + strcpyW( cmdline, regsvr32 ); + strcatW( cmdline, file->TargetPath ); + strcatW( cmdline, close ); + + TRACE("Unregistering %s\n", debugstr_w(cmdline)); + + ret = CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, c_colon, &si, &pi ); + if (ret) + { + CloseHandle( pi.hThread ); + msi_dialog_check_messages( pi.hProcess ); + CloseHandle( pi.hProcess ); + } + + msi_free( cmdline ); + + uirow = MSI_CreateRecord( 2 ); + uipath = strdupW( file->TargetPath ); + if ((p = strrchrW( uipath, '\\' ))) + { + *p = 0; + MSI_RecordSetStringW( uirow, 1, ++p ); + } + MSI_RecordSetStringW( uirow, 2, uipath ); + ui_actiondata( package, szSelfUnregModules, uirow ); + msiobj_release( &uirow->hdr ); + msi_free( uipath ); + /* FIXME call ui_progress? */ + + return ERROR_SUCCESS; +} + +static UINT ACTION_SelfUnregModules( MSIPACKAGE *package ) +{ + UINT rc; + MSIQUERY *view; + static const WCHAR query[] = + {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + '`','S','e','l','f','R','e','g','`',0}; + + rc = MSI_DatabaseOpenViewW( package->db, query, &view ); + if (rc != ERROR_SUCCESS) + { + TRACE("no SelfReg table\n"); + return ERROR_SUCCESS; + } + + MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package ); + msiobj_release( &view->hdr ); + + return ERROR_SUCCESS; +} + static UINT ACTION_PublishFeatures(MSIPACKAGE *package) { MSIFEATURE *feature; @@ -4462,8 +4598,8 @@ static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param) MSIPACKAGE *package = param; MSICOMPONENT *comp; SC_HANDLE scm, service = NULL; - LPCWSTR name, *vector = NULL; - LPWSTR args; + LPCWSTR *vector = NULL; + LPWSTR name, args; DWORD event, numargs; UINT r = ERROR_FUNCTION_FAILED; @@ -4471,9 +4607,9 @@ static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param) if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT) return ERROR_SUCCESS; - name = MSI_RecordGetString(rec, 2); + deformat_string(package, MSI_RecordGetString(rec, 2), &name); + deformat_string(package, MSI_RecordGetString(rec, 4), &args); event = MSI_RecordGetInteger(rec, 3); - args = strdupW(MSI_RecordGetString(rec, 4)); if (!(event & msidbServiceControlEventStart)) return ERROR_SUCCESS; @@ -4488,15 +4624,16 @@ static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param) service = OpenServiceW(scm, name, SERVICE_START); if (!service) { - ERR("Failed to open service %s\n", debugstr_w(name)); + ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError()); goto done; } vector = msi_service_args_to_vector(args, &numargs); - if (!StartServiceW(service, numargs, vector)) + if (!StartServiceW(service, numargs, vector) && + GetLastError() != ERROR_SERVICE_ALREADY_RUNNING) { - ERR("Failed to start service %s\n", debugstr_w(name)); + ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError()); goto done; } @@ -4506,6 +4643,7 @@ done: CloseServiceHandle(service); CloseServiceHandle(scm); + msi_free(name); msi_free(args); msi_free(vector); return r; @@ -4570,27 +4708,12 @@ error: return FALSE; } -static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param) +static UINT stop_service( LPCWSTR name ) { - MSIPACKAGE *package = param; - MSICOMPONENT *comp; + SC_HANDLE scm = NULL, service = NULL; SERVICE_STATUS status; SERVICE_STATUS_PROCESS ssp; - SC_HANDLE scm = NULL, service = NULL; - LPWSTR name, args; - DWORD event, needed; - - event = MSI_RecordGetInteger(rec, 3); - if (!(event & msidbServiceControlEventStop)) - return ERROR_SUCCESS; - - comp = get_loaded_component(package, MSI_RecordGetString(rec, 6)); - if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT) - return ERROR_SUCCESS; - - deformat_string(package, MSI_RecordGetString(rec, 2), &name); - deformat_string(package, MSI_RecordGetString(rec, 4), &args); - args = strdupW(MSI_RecordGetString(rec, 4)); + DWORD needed; scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (!scm) @@ -4605,16 +4728,14 @@ static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param) SERVICE_ENUMERATE_DEPENDENTS); if (!service) { - WARN("Failed to open service (%s): %d\n", - debugstr_w(name), GetLastError()); + WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError()); goto done; } if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, sizeof(SERVICE_STATUS_PROCESS), &needed)) { - WARN("Failed to query service status (%s): %d\n", - debugstr_w(name), GetLastError()); + WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError()); goto done; } @@ -4629,8 +4750,28 @@ static UINT ITERATE_StopService(MSIRECORD *rec, LPVOID param) done: CloseServiceHandle(service); CloseServiceHandle(scm); - msi_free(name); - msi_free(args); + + return ERROR_SUCCESS; +} + +static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param ) +{ + MSIPACKAGE *package = param; + MSICOMPONENT *comp; + LPWSTR name; + DWORD event; + + event = MSI_RecordGetInteger( rec, 3 ); + if (!(event & msidbServiceControlEventStop)) + return ERROR_SUCCESS; + + comp = get_loaded_component( package, MSI_RecordGetString( rec, 6 ) ); + if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT) + return ERROR_SUCCESS; + + deformat_string( package, MSI_RecordGetString( rec, 2 ), &name ); + stop_service( name ); + msi_free( name ); return ERROR_SUCCESS; } @@ -4654,6 +4795,69 @@ static UINT ACTION_StopServices( MSIPACKAGE *package ) return rc; } +static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param ) +{ + MSIPACKAGE *package = param; + MSICOMPONENT *comp; + LPWSTR name = NULL; + DWORD event; + SC_HANDLE scm = NULL, service = NULL; + + event = MSI_RecordGetInteger( rec, 3 ); + if (!(event & msidbServiceControlEventDelete)) + return ERROR_SUCCESS; + + comp = get_loaded_component( package, MSI_RecordGetString(rec, 6) ); + if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT) + return ERROR_SUCCESS; + + deformat_string( package, MSI_RecordGetString(rec, 2), &name ); + stop_service( name ); + + scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS ); + if (!scm) + { + WARN("Failed to open the SCM: %d\n", GetLastError()); + goto done; + } + + service = OpenServiceW( scm, name, DELETE ); + if (!service) + { + WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError()); + goto done; + } + + if (!DeleteService( service )) + WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError()); + +done: + CloseServiceHandle( service ); + CloseServiceHandle( scm ); + msi_free( name ); + + return ERROR_SUCCESS; +} + +static UINT ACTION_DeleteServices( MSIPACKAGE *package ) +{ + UINT rc; + MSIQUERY *view; + + static const WCHAR query[] = { + 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 }; + + rc = MSI_DatabaseOpenViewW( package->db, query, &view ); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package ); + msiobj_release( &view->hdr ); + + return rc; +} + static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename ) { MSIFILE *file; @@ -4922,16 +5126,30 @@ static LONG env_set_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags ) LPCWSTR ptr = *value; if (!strncmpW(ptr, prefix, prefix_len)) { - *flags |= ENV_MOD_APPEND; - *value += lstrlenW(prefix); + if (ptr[prefix_len] == szSemiColon[0]) + { + *flags |= ENV_MOD_APPEND; + *value += lstrlenW(prefix); + } + else + { + *value = NULL; + } } else if (lstrlenW(*value) >= prefix_len) { ptr += lstrlenW(ptr) - prefix_len; if (!lstrcmpW(ptr, prefix)) { - *flags |= ENV_MOD_PREFIX; - /* the "[~]" will be removed by deformat_string */; + if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0]) + { + *flags |= ENV_MOD_PREFIX; + /* the "[~]" will be removed by deformat_string */; + } + else + { + *value = NULL; + } } } } @@ -4977,7 +5195,7 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param ) TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value)); res = env_set_flags(&name, &value, &flags); - if (res != ERROR_SUCCESS) + if (res != ERROR_SUCCESS || !value) goto done; if (value && !deformat_string(package, value, &deformatted)) @@ -5023,6 +5241,9 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param ) goto done; } + /* If we are appending but the string was empty, strip ; */ + if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++; + size = (lstrlenW(value) + 1) * sizeof(WCHAR); newval = strdupW(value); if (!newval) @@ -5033,7 +5254,8 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param ) } else { - if (flags & ENV_ACT_SETABSENT) + /* Contrary to MSDN, +-variable to [~];path works */ + if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK)) { res = ERROR_SUCCESS; goto done; @@ -5063,7 +5285,7 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param ) int multiplier = 0; if (flags & ENV_MOD_APPEND) multiplier++; if (flags & ENV_MOD_PREFIX) multiplier++; - mod_size = (lstrlenW(value) + 1) * multiplier; + mod_size = lstrlenW(value) * multiplier; size += mod_size * sizeof(WCHAR); } @@ -5078,26 +5300,18 @@ static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param ) if (flags & ENV_MOD_PREFIX) { lstrcpyW(newval, value); - lstrcatW(newval, szSemiColon); - ptr = newval + lstrlenW(value) + 1; + ptr = newval + lstrlenW(value); } lstrcpyW(ptr, data); if (flags & ENV_MOD_APPEND) { - lstrcatW(newval, szSemiColon); lstrcatW(newval, value); } } - - if (newval) - { - TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval)); - res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size); - } - else - res = ERROR_SUCCESS; + TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval)); + res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size); done: if (env) RegCloseKey(env); @@ -5911,6 +6125,13 @@ done: return r; } +static UINT ACTION_ScheduleReboot( MSIPACKAGE *package ) +{ + TRACE("\n"); + package->need_reboot = 1; + return ERROR_SUCCESS; +} + static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table ) { @@ -5973,18 +6194,6 @@ static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package ) return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table ); } -static UINT ACTION_SelfUnregModules( MSIPACKAGE *package ) -{ - static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 }; - return msi_unimplemented_action_stub( package, "SelfUnregModules", table ); -} - -static UINT ACTION_DeleteServices( MSIPACKAGE *package ) -{ - static const WCHAR table[] = { - 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 }; - return msi_unimplemented_action_stub( package, "DeleteServices", table ); -} static UINT ACTION_ValidateProductID( MSIPACKAGE *package ) { static const WCHAR table[] = { @@ -6048,12 +6257,6 @@ static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package ) return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table ); } -static UINT ACTION_RemoveFolders( MSIPACKAGE *package ) -{ - static const WCHAR table[] = { 'C','r','e','a','t','e','F','o','l','d','e','r',0 }; - return msi_unimplemented_action_stub( package, "RemoveFolders", table ); -} - static UINT ACTION_RemoveODBC( MSIPACKAGE *package ) { static const WCHAR table[] = { 'O','D','B','C','D','r','i','v','e','r',0 }; @@ -6072,6 +6275,12 @@ static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package ) return msi_unimplemented_action_stub( package, "RemoveShortcuts", table ); } +static UINT ACTION_SetODBCFolders( MSIPACKAGE *package ) +{ + static const WCHAR table[] = { 'D','i','r','e','c','t','o','r','y',0 }; + return msi_unimplemented_action_stub( package, "SetODBCFolders", table ); +} + static UINT ACTION_UnpublishComponents( MSIPACKAGE *package ) { static const WCHAR table[] = { 'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t',0 }; @@ -6173,10 +6382,10 @@ StandardActions[] = { szRemoveShortcuts, ACTION_RemoveShortcuts }, { szResolveSource, ACTION_ResolveSource }, { szRMCCPSearch, ACTION_RMCCPSearch }, - { szScheduleReboot, NULL }, + { szScheduleReboot, ACTION_ScheduleReboot }, { szSelfRegModules, ACTION_SelfRegModules }, { szSelfUnregModules, ACTION_SelfUnregModules }, - { szSetODBCFolders, NULL }, + { szSetODBCFolders, ACTION_SetODBCFolders }, { szStartServices, ACTION_StartServices }, { szStopServices, ACTION_StopServices }, { szUnpublishComponents, ACTION_UnpublishComponents }, diff --git a/reactos/dll/win32/msi/appsearch.c b/reactos/dll/win32/msi/appsearch.c index b99b4f52085..c4e4e588077 100644 --- a/reactos/dll/win32/msi/appsearch.c +++ b/reactos/dll/win32/msi/appsearch.c @@ -463,7 +463,7 @@ static UINT ACTION_AppSearchReg(MSIPACKAGE *package, LPWSTR *appValue, MSISIGNAT ACTION_ConvertRegValue(regType, value, sz, appValue); break; default: - FIXME("AppSearch unimplemented for type %d (key path %s, value %s)\n", + FIXME("unimplemented for type %d (key path %s, value %s)\n", type, debugstr_w(keyPath), debugstr_w(valueName)); } end: diff --git a/reactos/dll/win32/msi/automation.c b/reactos/dll/win32/msi/automation.c index 5305f9c9d47..f935a64397d 100644 --- a/reactos/dll/win32/msi/automation.c +++ b/reactos/dll/win32/msi/automation.c @@ -1138,6 +1138,21 @@ static HRESULT WINAPI ViewImpl_Invoke( return S_OK; } +static HRESULT DatabaseImpl_LastErrorRecord(WORD wFlags, + DISPPARAMS* pDispParams, + VARIANT* pVarResult, + EXCEPINFO* pExcepInfo, + UINT* puArgErr) +{ + if (!(wFlags & DISPATCH_METHOD)) + return DISP_E_MEMBERNOTFOUND; + + FIXME("\n"); + + VariantInit(pVarResult); + return S_OK; +} + static HRESULT WINAPI DatabaseImpl_Invoke( AutomationObject* This, DISPID dispIdMember, @@ -1208,6 +1223,11 @@ static HRESULT WINAPI DatabaseImpl_Invoke( else return DISP_E_MEMBERNOTFOUND; break; + case DISPID_INSTALLER_LASTERRORRECORD: + return DatabaseImpl_LastErrorRecord(wFlags, pDispParams, + pVarResult, pExcepInfo, + puArgErr); + default: return DISP_E_MEMBERNOTFOUND; } diff --git a/reactos/dll/win32/msi/cond.tab.c b/reactos/dll/win32/msi/cond.tab.c index a35bd98e5d6..5449d99fdab 100644 --- a/reactos/dll/win32/msi/cond.tab.c +++ b/reactos/dll/win32/msi/cond.tab.c @@ -119,6 +119,7 @@ #include "msiserver.h" #include "wine/debug.h" #include "wine/unicode.h" +#include "wine/list.h" #define YYLEX_PARAM info #define YYPARSE_PARAM info @@ -133,6 +134,7 @@ typedef struct tag_yyinput LPCWSTR str; INT n; MSICONDITION result; + struct list mem; } COND_input; struct cond_str { @@ -140,10 +142,14 @@ struct cond_str { INT len; }; -static LPWSTR COND_GetString( const struct cond_str *str ); -static LPWSTR COND_GetLiteral( const struct cond_str *str ); +static LPWSTR COND_GetString( COND_input *info, const struct cond_str *str ); +static LPWSTR COND_GetLiteral( COND_input *info, const struct cond_str *str ); static int cond_lex( void *COND_lval, COND_input *info); +static void *cond_alloc( COND_input *cond, unsigned int sz ); +static void *cond_track_mem( COND_input *cond, void *ptr, unsigned int sz ); +static void cond_free( void *ptr ); + static INT compare_int( INT a, INT operator, INT b ); static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b, BOOL convert ); @@ -152,8 +158,8 @@ static INT compare_and_free_strings( LPWSTR a, INT op, LPWSTR b, BOOL convert ) INT r; r = compare_string( a, op, b, convert ); - msi_free( a ); - msi_free( b ); + cond_free( a ); + cond_free( b ); return r; } @@ -184,7 +190,7 @@ static BOOL num_from_prop( LPCWSTR p, INT *val ) /* Line 189 of yacc.c */ -#line 188 "cond.tab.c" +#line 194 "cond.tab.c" /* Enabling traces. */ #ifndef YYDEBUG @@ -259,7 +265,7 @@ typedef union YYSTYPE { /* Line 214 of yacc.c */ -#line 110 "cond.y" +#line 116 "cond.y" struct cond_str str; LPWSTR string; @@ -268,7 +274,7 @@ typedef union YYSTYPE /* Line 214 of yacc.c */ -#line 272 "cond.tab.c" +#line 278 "cond.tab.c" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ @@ -280,7 +286,7 @@ typedef union YYSTYPE /* Line 264 of yacc.c */ -#line 284 "cond.tab.c" +#line 290 "cond.tab.c" #ifdef short # undef short @@ -584,12 +590,12 @@ static const yytype_int8 yyrhs[] = /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 134, 134, 140, 147, 151, 155, 159, 163, 170, - 174, 181, 185, 189, 194, 198, 207, 216, 220, 224, - 228, 232, 237, 242, 250, 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, - 266, 267, 271, 275, 282, 291, 295, 304, 313, 326, - 338, 345, 359, 368 + 0, 140, 140, 146, 153, 157, 161, 165, 169, 176, + 180, 187, 191, 195, 200, 204, 213, 222, 226, 230, + 234, 238, 243, 248, 256, 257, 258, 259, 260, 261, + 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, + 272, 273, 277, 281, 288, 298, 302, 311, 320, 333, + 345, 358, 375, 385 }; #endif @@ -1540,7 +1546,7 @@ yyreduce: case 2: /* Line 1455 of yacc.c */ -#line 135 "cond.y" +#line 141 "cond.y" { COND_input* cond = (COND_input*) info; cond->result = (yyvsp[(1) - (1)].value); @@ -1550,7 +1556,7 @@ yyreduce: case 3: /* Line 1455 of yacc.c */ -#line 140 "cond.y" +#line 146 "cond.y" { COND_input* cond = (COND_input*) info; cond->result = MSICONDITION_NONE; @@ -1560,7 +1566,7 @@ yyreduce: case 4: /* Line 1455 of yacc.c */ -#line 148 "cond.y" +#line 154 "cond.y" { (yyval.value) = (yyvsp[(1) - (1)].value); ;} @@ -1569,7 +1575,7 @@ yyreduce: case 5: /* Line 1455 of yacc.c */ -#line 152 "cond.y" +#line 158 "cond.y" { (yyval.value) = (yyvsp[(1) - (3)].value) || (yyvsp[(3) - (3)].value); ;} @@ -1578,7 +1584,7 @@ yyreduce: case 6: /* Line 1455 of yacc.c */ -#line 156 "cond.y" +#line 162 "cond.y" { (yyval.value) = !(yyvsp[(1) - (3)].value) || (yyvsp[(3) - (3)].value); ;} @@ -1587,7 +1593,7 @@ yyreduce: case 7: /* Line 1455 of yacc.c */ -#line 160 "cond.y" +#line 166 "cond.y" { (yyval.value) = ( (yyvsp[(1) - (3)].value) || (yyvsp[(3) - (3)].value) ) && !( (yyvsp[(1) - (3)].value) && (yyvsp[(3) - (3)].value) ); ;} @@ -1596,7 +1602,7 @@ yyreduce: case 8: /* Line 1455 of yacc.c */ -#line 164 "cond.y" +#line 170 "cond.y" { (yyval.value) = ( (yyvsp[(1) - (3)].value) && (yyvsp[(3) - (3)].value) ) || ( !(yyvsp[(1) - (3)].value) && !(yyvsp[(3) - (3)].value) ); ;} @@ -1605,7 +1611,7 @@ yyreduce: case 9: /* Line 1455 of yacc.c */ -#line 171 "cond.y" +#line 177 "cond.y" { (yyval.value) = (yyvsp[(1) - (1)].value); ;} @@ -1614,7 +1620,7 @@ yyreduce: case 10: /* Line 1455 of yacc.c */ -#line 175 "cond.y" +#line 181 "cond.y" { (yyval.value) = (yyvsp[(1) - (3)].value) && (yyvsp[(3) - (3)].value); ;} @@ -1623,7 +1629,7 @@ yyreduce: case 11: /* Line 1455 of yacc.c */ -#line 182 "cond.y" +#line 188 "cond.y" { (yyval.value) = (yyvsp[(2) - (2)].value) ? 0 : 1; ;} @@ -1632,7 +1638,7 @@ yyreduce: case 12: /* Line 1455 of yacc.c */ -#line 186 "cond.y" +#line 192 "cond.y" { (yyval.value) = (yyvsp[(1) - (1)].value) ? 1 : 0; ;} @@ -1641,17 +1647,17 @@ yyreduce: case 13: /* Line 1455 of yacc.c */ -#line 190 "cond.y" +#line 196 "cond.y" { (yyval.value) = ((yyvsp[(1) - (1)].string) && (yyvsp[(1) - (1)].string)[0]) ? 1 : 0; - msi_free((yyvsp[(1) - (1)].string)); + cond_free( (yyvsp[(1) - (1)].string) ); ;} break; case 14: /* Line 1455 of yacc.c */ -#line 195 "cond.y" +#line 201 "cond.y" { (yyval.value) = compare_int( (yyvsp[(1) - (3)].value), (yyvsp[(2) - (3)].value), (yyvsp[(3) - (3)].value) ); ;} @@ -1660,35 +1666,35 @@ yyreduce: case 15: /* Line 1455 of yacc.c */ -#line 199 "cond.y" +#line 205 "cond.y" { int num; if (num_from_prop( (yyvsp[(1) - (3)].string), &num )) (yyval.value) = compare_int( num, (yyvsp[(2) - (3)].value), (yyvsp[(3) - (3)].value) ); else (yyval.value) = ((yyvsp[(2) - (3)].value) == COND_NE || (yyvsp[(2) - (3)].value) == COND_INE ); - msi_free((yyvsp[(1) - (3)].string)); + cond_free( (yyvsp[(1) - (3)].string) ); ;} break; case 16: /* Line 1455 of yacc.c */ -#line 208 "cond.y" +#line 214 "cond.y" { int num; if (num_from_prop( (yyvsp[(3) - (3)].string), &num )) (yyval.value) = compare_int( (yyvsp[(1) - (3)].value), (yyvsp[(2) - (3)].value), num ); else (yyval.value) = ((yyvsp[(2) - (3)].value) == COND_NE || (yyvsp[(2) - (3)].value) == COND_INE ); - msi_free((yyvsp[(3) - (3)].string)); + cond_free( (yyvsp[(3) - (3)].string) ); ;} break; case 17: /* Line 1455 of yacc.c */ -#line 217 "cond.y" +#line 223 "cond.y" { (yyval.value) = compare_and_free_strings( (yyvsp[(1) - (3)].string), (yyvsp[(2) - (3)].value), (yyvsp[(3) - (3)].string), TRUE ); ;} @@ -1697,7 +1703,7 @@ yyreduce: case 18: /* Line 1455 of yacc.c */ -#line 221 "cond.y" +#line 227 "cond.y" { (yyval.value) = compare_and_free_strings( (yyvsp[(1) - (3)].string), (yyvsp[(2) - (3)].value), (yyvsp[(3) - (3)].string), TRUE ); ;} @@ -1706,7 +1712,7 @@ yyreduce: case 19: /* Line 1455 of yacc.c */ -#line 225 "cond.y" +#line 231 "cond.y" { (yyval.value) = compare_and_free_strings( (yyvsp[(1) - (3)].string), (yyvsp[(2) - (3)].value), (yyvsp[(3) - (3)].string), TRUE ); ;} @@ -1715,7 +1721,7 @@ yyreduce: case 20: /* Line 1455 of yacc.c */ -#line 229 "cond.y" +#line 235 "cond.y" { (yyval.value) = compare_and_free_strings( (yyvsp[(1) - (3)].string), (yyvsp[(2) - (3)].value), (yyvsp[(3) - (3)].string), FALSE ); ;} @@ -1724,27 +1730,27 @@ yyreduce: case 21: /* Line 1455 of yacc.c */ -#line 233 "cond.y" +#line 239 "cond.y" { (yyval.value) = 0; - msi_free((yyvsp[(1) - (3)].string)); + cond_free( (yyvsp[(1) - (3)].string) ); ;} break; case 22: /* Line 1455 of yacc.c */ -#line 238 "cond.y" +#line 244 "cond.y" { (yyval.value) = 0; - msi_free((yyvsp[(3) - (3)].string)); + cond_free( (yyvsp[(3) - (3)].string) ); ;} break; case 23: /* Line 1455 of yacc.c */ -#line 243 "cond.y" +#line 249 "cond.y" { (yyval.value) = (yyvsp[(2) - (3)].value); ;} @@ -1753,133 +1759,133 @@ yyreduce: case 24: /* Line 1455 of yacc.c */ -#line 250 "cond.y" +#line 256 "cond.y" { (yyval.value) = COND_EQ; ;} break; case 25: /* Line 1455 of yacc.c */ -#line 251 "cond.y" +#line 257 "cond.y" { (yyval.value) = COND_NE; ;} break; case 26: /* Line 1455 of yacc.c */ -#line 252 "cond.y" +#line 258 "cond.y" { (yyval.value) = COND_LT; ;} break; case 27: /* Line 1455 of yacc.c */ -#line 253 "cond.y" +#line 259 "cond.y" { (yyval.value) = COND_GT; ;} break; case 28: /* Line 1455 of yacc.c */ -#line 254 "cond.y" +#line 260 "cond.y" { (yyval.value) = COND_LE; ;} break; case 29: /* Line 1455 of yacc.c */ -#line 255 "cond.y" +#line 261 "cond.y" { (yyval.value) = COND_GE; ;} break; case 30: /* Line 1455 of yacc.c */ -#line 256 "cond.y" +#line 262 "cond.y" { (yyval.value) = COND_SS; ;} break; case 31: /* Line 1455 of yacc.c */ -#line 257 "cond.y" +#line 263 "cond.y" { (yyval.value) = COND_IEQ; ;} break; case 32: /* Line 1455 of yacc.c */ -#line 258 "cond.y" +#line 264 "cond.y" { (yyval.value) = COND_INE; ;} break; case 33: /* Line 1455 of yacc.c */ -#line 259 "cond.y" +#line 265 "cond.y" { (yyval.value) = COND_ILT; ;} break; case 34: /* Line 1455 of yacc.c */ -#line 260 "cond.y" +#line 266 "cond.y" { (yyval.value) = COND_IGT; ;} break; case 35: /* Line 1455 of yacc.c */ -#line 261 "cond.y" +#line 267 "cond.y" { (yyval.value) = COND_ILE; ;} break; case 36: /* Line 1455 of yacc.c */ -#line 262 "cond.y" +#line 268 "cond.y" { (yyval.value) = COND_IGE; ;} break; case 37: /* Line 1455 of yacc.c */ -#line 263 "cond.y" +#line 269 "cond.y" { (yyval.value) = COND_ISS; ;} break; case 38: /* Line 1455 of yacc.c */ -#line 264 "cond.y" +#line 270 "cond.y" { (yyval.value) = COND_LHS; ;} break; case 39: /* Line 1455 of yacc.c */ -#line 265 "cond.y" +#line 271 "cond.y" { (yyval.value) = COND_RHS; ;} break; case 40: /* Line 1455 of yacc.c */ -#line 266 "cond.y" +#line 272 "cond.y" { (yyval.value) = COND_ILHS; ;} break; case 41: /* Line 1455 of yacc.c */ -#line 267 "cond.y" +#line 273 "cond.y" { (yyval.value) = COND_IRHS; ;} break; case 42: /* Line 1455 of yacc.c */ -#line 272 "cond.y" +#line 278 "cond.y" { (yyval.string) = (yyvsp[(1) - (1)].string); ;} @@ -1888,7 +1894,7 @@ yyreduce: case 43: /* Line 1455 of yacc.c */ -#line 276 "cond.y" +#line 282 "cond.y" { (yyval.string) = (yyvsp[(1) - (1)].string); ;} @@ -1897,9 +1903,10 @@ yyreduce: case 44: /* Line 1455 of yacc.c */ -#line 283 "cond.y" +#line 289 "cond.y" { - (yyval.string) = COND_GetLiteral(&(yyvsp[(1) - (1)].str)); + COND_input* cond = (COND_input*) info; + (yyval.string) = COND_GetLiteral( cond, &(yyvsp[(1) - (1)].str) ); if( !(yyval.string) ) YYABORT; ;} @@ -1908,7 +1915,7 @@ yyreduce: case 45: /* Line 1455 of yacc.c */ -#line 292 "cond.y" +#line 299 "cond.y" { (yyval.value) = (yyvsp[(1) - (1)].value); ;} @@ -1917,35 +1924,35 @@ yyreduce: case 46: /* Line 1455 of yacc.c */ -#line 296 "cond.y" +#line 303 "cond.y" { COND_input* cond = (COND_input*) info; INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; MSI_GetComponentStateW(cond->package, (yyvsp[(2) - (2)].string), &install, &action ); (yyval.value) = action; - msi_free( (yyvsp[(2) - (2)].string) ); + cond_free( (yyvsp[(2) - (2)].string) ); ;} break; case 47: /* Line 1455 of yacc.c */ -#line 305 "cond.y" +#line 312 "cond.y" { COND_input* cond = (COND_input*) info; INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; MSI_GetComponentStateW(cond->package, (yyvsp[(2) - (2)].string), &install, &action ); (yyval.value) = install; - msi_free( (yyvsp[(2) - (2)].string) ); + cond_free( (yyvsp[(2) - (2)].string) ); ;} break; case 48: /* Line 1455 of yacc.c */ -#line 314 "cond.y" +#line 321 "cond.y" { COND_input* cond = (COND_input*) info; INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; @@ -1956,58 +1963,68 @@ yyreduce: else (yyval.value) = action; - msi_free( (yyvsp[(2) - (2)].string) ); + cond_free( (yyvsp[(2) - (2)].string) ); ;} break; case 49: /* Line 1455 of yacc.c */ -#line 327 "cond.y" +#line 334 "cond.y" { COND_input* cond = (COND_input*) info; INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; MSI_GetFeatureStateW(cond->package, (yyvsp[(2) - (2)].string), &install, &action ); (yyval.value) = install; - msi_free( (yyvsp[(2) - (2)].string) ); + cond_free( (yyvsp[(2) - (2)].string) ); ;} break; case 50: /* Line 1455 of yacc.c */ -#line 339 "cond.y" +#line 346 "cond.y" { COND_input* cond = (COND_input*) info; + UINT len; (yyval.string) = msi_dup_property( cond->package, (yyvsp[(1) - (1)].string) ); - msi_free( (yyvsp[(1) - (1)].string) ); + if ((yyval.string)) + { + len = (lstrlenW((yyval.string)) + 1) * sizeof (WCHAR); + (yyval.string) = cond_track_mem( cond, (yyval.string), len ); + } + cond_free( (yyvsp[(1) - (1)].string) ); ;} break; case 51: /* Line 1455 of yacc.c */ -#line 346 "cond.y" +#line 359 "cond.y" { + COND_input* cond = (COND_input*) info; UINT len = GetEnvironmentVariableW( (yyvsp[(2) - (2)].string), NULL, 0 ); (yyval.string) = NULL; if (len++) { - (yyval.string) = msi_alloc( len*sizeof (WCHAR) ); + (yyval.string) = cond_alloc( cond, len*sizeof (WCHAR) ); + if( !(yyval.string) ) + YYABORT; GetEnvironmentVariableW( (yyvsp[(2) - (2)].string), (yyval.string), len ); } - msi_free( (yyvsp[(2) - (2)].string) ); + cond_free( (yyvsp[(2) - (2)].string) ); ;} break; case 52: /* Line 1455 of yacc.c */ -#line 360 "cond.y" +#line 376 "cond.y" { - (yyval.string) = COND_GetString(&(yyvsp[(1) - (1)].str)); + COND_input* cond = (COND_input*) info; + (yyval.string) = COND_GetString( cond, &(yyvsp[(1) - (1)].str) ); if( !(yyval.string) ) YYABORT; ;} @@ -2016,20 +2033,21 @@ yyreduce: case 53: /* Line 1455 of yacc.c */ -#line 369 "cond.y" +#line 386 "cond.y" { - LPWSTR szNum = COND_GetString(&(yyvsp[(1) - (1)].str)); + COND_input* cond = (COND_input*) info; + LPWSTR szNum = COND_GetString( cond, &(yyvsp[(1) - (1)].str) ); if( !szNum ) YYABORT; (yyval.value) = atoiW( szNum ); - msi_free( szNum ); + cond_free( szNum ); ;} break; /* Line 1455 of yacc.c */ -#line 2033 "cond.tab.c" +#line 2051 "cond.tab.c" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); @@ -2241,7 +2259,7 @@ yyreturn: /* Line 1675 of yacc.c */ -#line 378 "cond.y" +#line 396 "cond.y" @@ -2558,11 +2576,11 @@ static int cond_lex( void *COND_lval, COND_input *cond ) return rc; } -static LPWSTR COND_GetString( const struct cond_str *str ) +static LPWSTR COND_GetString( COND_input *cond, const struct cond_str *str ) { LPWSTR ret; - ret = msi_alloc( (str->len+1) * sizeof (WCHAR) ); + ret = cond_alloc( cond, (str->len+1) * sizeof (WCHAR) ); if( ret ) { memcpy( ret, str->data, str->len * sizeof(WCHAR)); @@ -2572,11 +2590,11 @@ static LPWSTR COND_GetString( const struct cond_str *str ) return ret; } -static LPWSTR COND_GetLiteral( const struct cond_str *str ) +static LPWSTR COND_GetLiteral( COND_input *cond, const struct cond_str *str ) { LPWSTR ret; - ret = msi_alloc( (str->len-1) * sizeof (WCHAR) ); + ret = cond_alloc( cond, (str->len-1) * sizeof (WCHAR) ); if( ret ) { memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) ); @@ -2586,6 +2604,48 @@ static LPWSTR COND_GetLiteral( const struct cond_str *str ) return ret; } +static void *cond_alloc( COND_input *cond, unsigned int sz ) +{ + struct list *mem; + + mem = msi_alloc( sizeof (struct list) + sz ); + if( !mem ) + return NULL; + + list_add_head( &(cond->mem), mem ); + return mem + 1; +} + +static void *cond_track_mem( COND_input *cond, void *ptr, unsigned int sz ) +{ + void *new_ptr; + + if( !ptr ) + return ptr; + + new_ptr = cond_alloc( cond, sz ); + if( !new_ptr ) + { + msi_free( ptr ); + return NULL; + } + + memcpy( new_ptr, ptr, sz ); + msi_free( ptr ); + return new_ptr; +} + +static void cond_free( void *ptr ) +{ + struct list *mem = (struct list *)ptr - 1; + + if( ptr ) + { + list_remove( mem ); + msi_free( mem ); + } +} + static int cond_error(const char *str) { TRACE("%s\n", str ); @@ -2596,6 +2656,7 @@ MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition ) { COND_input cond; MSICONDITION r; + struct list *mem, *safety; TRACE("%s\n", debugstr_w( szCondition ) ); @@ -2606,12 +2667,23 @@ MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition ) cond.str = szCondition; cond.n = 0; cond.result = MSICONDITION_ERROR; - + + list_init( &cond.mem ); + if ( !cond_parse( &cond ) ) r = cond.result; else r = MSICONDITION_ERROR; + LIST_FOR_EACH_SAFE( mem, safety, &cond.mem ) + { + /* The tracked memory lives directly after the list struct */ + void *ptr = mem + 1; + if ( r != MSICONDITION_ERROR ) + WARN( "condition parser failed to free up some memory: %p\n", ptr ); + cond_free( ptr ); + } + TRACE("%i <- %s\n", r, debugstr_w(szCondition)); return r; } diff --git a/reactos/dll/win32/msi/cond.tab.h b/reactos/dll/win32/msi/cond.tab.h index ebc6e23ed3e..47f4816deb3 100644 --- a/reactos/dll/win32/msi/cond.tab.h +++ b/reactos/dll/win32/msi/cond.tab.h @@ -87,7 +87,7 @@ typedef union YYSTYPE { /* Line 1676 of yacc.c */ -#line 110 "cond.y" +#line 116 "cond.y" struct cond_str str; LPWSTR string; diff --git a/reactos/dll/win32/msi/cond.y b/reactos/dll/win32/msi/cond.y index c2a17376e29..f3db635a10a 100644 --- a/reactos/dll/win32/msi/cond.y +++ b/reactos/dll/win32/msi/cond.y @@ -40,6 +40,7 @@ #include "msiserver.h" #include "wine/debug.h" #include "wine/unicode.h" +#include "wine/list.h" #define YYLEX_PARAM info #define YYPARSE_PARAM info @@ -54,6 +55,7 @@ typedef struct tag_yyinput LPCWSTR str; INT n; MSICONDITION result; + struct list mem; } COND_input; struct cond_str { @@ -61,10 +63,14 @@ struct cond_str { INT len; }; -static LPWSTR COND_GetString( const struct cond_str *str ); -static LPWSTR COND_GetLiteral( const struct cond_str *str ); +static LPWSTR COND_GetString( COND_input *info, const struct cond_str *str ); +static LPWSTR COND_GetLiteral( COND_input *info, const struct cond_str *str ); static int cond_lex( void *COND_lval, COND_input *info); +static void *cond_alloc( COND_input *cond, unsigned int sz ); +static void *cond_track_mem( COND_input *cond, void *ptr, unsigned int sz ); +static void cond_free( void *ptr ); + static INT compare_int( INT a, INT operator, INT b ); static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b, BOOL convert ); @@ -73,8 +79,8 @@ static INT compare_and_free_strings( LPWSTR a, INT op, LPWSTR b, BOOL convert ) INT r; r = compare_string( a, op, b, convert ); - msi_free( a ); - msi_free( b ); + cond_free( a ); + cond_free( b ); return r; } @@ -189,7 +195,7 @@ boolean_factor: | value_s { $$ = ($1 && $1[0]) ? 1 : 0; - msi_free($1); + cond_free( $1 ); } | value_i operator value_i { @@ -202,7 +208,7 @@ boolean_factor: $$ = compare_int( num, $2, $3 ); else $$ = ($2 == COND_NE || $2 == COND_INE ); - msi_free($1); + cond_free( $1 ); } | value_i operator symbol_s { @@ -211,7 +217,7 @@ boolean_factor: $$ = compare_int( $1, $2, num ); else $$ = ($2 == COND_NE || $2 == COND_INE ); - msi_free($3); + cond_free( $3 ); } | symbol_s operator symbol_s { @@ -232,12 +238,12 @@ boolean_factor: | literal operator value_i { $$ = 0; - msi_free($1); + cond_free( $1 ); } | value_i operator literal { $$ = 0; - msi_free($3); + cond_free( $3 ); } | COND_LPAR expression COND_RPAR { @@ -281,7 +287,8 @@ value_s: literal: COND_LITER { - $$ = COND_GetLiteral(&$1); + COND_input* cond = (COND_input*) info; + $$ = COND_GetLiteral( cond, &$1 ); if( !$$ ) YYABORT; } @@ -299,7 +306,7 @@ value_i: MSI_GetComponentStateW(cond->package, $2, &install, &action ); $$ = action; - msi_free( $2 ); + cond_free( $2 ); } | COND_QUESTION identifier { @@ -308,7 +315,7 @@ value_i: MSI_GetComponentStateW(cond->package, $2, &install, &action ); $$ = install; - msi_free( $2 ); + cond_free( $2 ); } | COND_AMPER identifier { @@ -321,7 +328,7 @@ value_i: else $$ = action; - msi_free( $2 ); + cond_free( $2 ); } | COND_EXCLAM identifier { @@ -330,7 +337,7 @@ value_i: MSI_GetFeatureStateW(cond->package, $2, &install, &action ); $$ = install; - msi_free( $2 ); + cond_free( $2 ); } ; @@ -338,27 +345,37 @@ symbol_s: identifier { COND_input* cond = (COND_input*) info; + UINT len; $$ = msi_dup_property( cond->package, $1 ); - msi_free( $1 ); + if ($$) + { + len = (lstrlenW($$) + 1) * sizeof (WCHAR); + $$ = cond_track_mem( cond, $$, len ); + } + cond_free( $1 ); } | COND_PERCENT identifier { + COND_input* cond = (COND_input*) info; UINT len = GetEnvironmentVariableW( $2, NULL, 0 ); $$ = NULL; if (len++) { - $$ = msi_alloc( len*sizeof (WCHAR) ); + $$ = cond_alloc( cond, len*sizeof (WCHAR) ); + if( !$$ ) + YYABORT; GetEnvironmentVariableW( $2, $$, len ); } - msi_free( $2 ); + cond_free( $2 ); } ; identifier: COND_IDENT { - $$ = COND_GetString(&$1); + COND_input* cond = (COND_input*) info; + $$ = COND_GetString( cond, &$1 ); if( !$$ ) YYABORT; } @@ -367,11 +384,12 @@ identifier: integer: COND_NUMBER { - LPWSTR szNum = COND_GetString(&$1); + COND_input* cond = (COND_input*) info; + LPWSTR szNum = COND_GetString( cond, &$1 ); if( !szNum ) YYABORT; $$ = atoiW( szNum ); - msi_free( szNum ); + cond_free( szNum ); } ; @@ -691,11 +709,11 @@ static int cond_lex( void *COND_lval, COND_input *cond ) return rc; } -static LPWSTR COND_GetString( const struct cond_str *str ) +static LPWSTR COND_GetString( COND_input *cond, const struct cond_str *str ) { LPWSTR ret; - ret = msi_alloc( (str->len+1) * sizeof (WCHAR) ); + ret = cond_alloc( cond, (str->len+1) * sizeof (WCHAR) ); if( ret ) { memcpy( ret, str->data, str->len * sizeof(WCHAR)); @@ -705,11 +723,11 @@ static LPWSTR COND_GetString( const struct cond_str *str ) return ret; } -static LPWSTR COND_GetLiteral( const struct cond_str *str ) +static LPWSTR COND_GetLiteral( COND_input *cond, const struct cond_str *str ) { LPWSTR ret; - ret = msi_alloc( (str->len-1) * sizeof (WCHAR) ); + ret = cond_alloc( cond, (str->len-1) * sizeof (WCHAR) ); if( ret ) { memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) ); @@ -719,6 +737,48 @@ static LPWSTR COND_GetLiteral( const struct cond_str *str ) return ret; } +static void *cond_alloc( COND_input *cond, unsigned int sz ) +{ + struct list *mem; + + mem = msi_alloc( sizeof (struct list) + sz ); + if( !mem ) + return NULL; + + list_add_head( &(cond->mem), mem ); + return mem + 1; +} + +static void *cond_track_mem( COND_input *cond, void *ptr, unsigned int sz ) +{ + void *new_ptr; + + if( !ptr ) + return ptr; + + new_ptr = cond_alloc( cond, sz ); + if( !new_ptr ) + { + msi_free( ptr ); + return NULL; + } + + memcpy( new_ptr, ptr, sz ); + msi_free( ptr ); + return new_ptr; +} + +static void cond_free( void *ptr ) +{ + struct list *mem = (struct list *)ptr - 1; + + if( ptr ) + { + list_remove( mem ); + msi_free( mem ); + } +} + static int cond_error(const char *str) { TRACE("%s\n", str ); @@ -729,6 +789,7 @@ MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition ) { COND_input cond; MSICONDITION r; + struct list *mem, *safety; TRACE("%s\n", debugstr_w( szCondition ) ); @@ -739,12 +800,23 @@ MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition ) cond.str = szCondition; cond.n = 0; cond.result = MSICONDITION_ERROR; - + + list_init( &cond.mem ); + if ( !cond_parse( &cond ) ) r = cond.result; else r = MSICONDITION_ERROR; + LIST_FOR_EACH_SAFE( mem, safety, &cond.mem ) + { + /* The tracked memory lives directly after the list struct */ + void *ptr = mem + 1; + if ( r != MSICONDITION_ERROR ) + WARN( "condition parser failed to free up some memory: %p\n", ptr ); + cond_free( ptr ); + } + TRACE("%i <- %s\n", r, debugstr_w(szCondition)); return r; } diff --git a/reactos/dll/win32/msi/custom.c b/reactos/dll/win32/msi/custom.c index 508bf6b2b4d..2b2a3e1373f 100644 --- a/reactos/dll/win32/msi/custom.c +++ b/reactos/dll/win32/msi/custom.c @@ -647,6 +647,28 @@ static UINT get_action_info( const GUID *guid, INT *type, MSIHANDLE *handle, return ERROR_SUCCESS; } +#ifdef __i386__ +extern UINT CUSTOMPROC_wrapper( MsiCustomActionEntryPoint proc, MSIHANDLE handle ); +__ASM_GLOBAL_FUNC( CUSTOMPROC_wrapper, + "pushl %ebp\n\t" + __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") + __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") + "movl %esp,%ebp\n\t" + __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") + "pushl 12(%ebp)\n\t" + "movl 8(%ebp),%eax\n\t" + "call *%eax\n\t" + "leave\n\t" + __ASM_CFI(".cfi_def_cfa %esp,4\n\t") + __ASM_CFI(".cfi_same_value %ebp\n\t") + "ret" ) +#else +static inline UINT CUSTOMPROC_wrapper( MsiCustomActionEntryPoint proc, MSIHANDLE handle ) +{ + return proc(handle); +} +#endif + static DWORD ACTION_CallDllFunction( const GUID *guid ) { MsiCustomActionEntryPoint fn; @@ -685,7 +707,7 @@ static DWORD ACTION_CallDllFunction( const GUID *guid ) __TRY { - r = fn( hPackage ); + r = CUSTOMPROC_wrapper( fn, hPackage ); } __EXCEPT_PAGE_FAULT { diff --git a/reactos/dll/win32/msi/database.c b/reactos/dll/win32/msi/database.c index b0966a25cf3..7855fea9186 100644 --- a/reactos/dll/win32/msi/database.c +++ b/reactos/dll/win32/msi/database.c @@ -51,6 +51,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); * Any binary data in a table is a reference to a stream. */ +#define IS_INTMSIDBOPEN(x) (((ULONG_PTR)(x) >> 16) == 0) + typedef struct tagMSITRANSFORM { struct list entry; IStorage *stg; @@ -306,7 +308,7 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb) save_path = szDBPath; szMode = szPersist; - if( HIWORD( szPersist ) ) + if( !IS_INTMSIDBOPEN(szPersist) ) { if (!CopyFileW( szDBPath, szPersist, FALSE )) return ERROR_OPEN_FAILED; @@ -459,7 +461,7 @@ UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB) goto end; } - if( HIWORD(szPersist) ) + if( !IS_INTMSIDBOPEN(szPersist) ) { szwPersist = strdupAtoW( szPersist ); if( !szwPersist ) @@ -471,7 +473,7 @@ UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB) r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB ); end: - if( HIWORD(szPersist) ) + if( !IS_INTMSIDBOPEN(szPersist) ) msi_free( szwPersist ); msi_free( szwDBPath ); diff --git a/reactos/dll/win32/msi/dialog.c b/reactos/dll/win32/msi/dialog.c index a22091f95fa..5fd4bbd138b 100644 --- a/reactos/dll/win32/msi/dialog.c +++ b/reactos/dll/win32/msi/dialog.c @@ -166,6 +166,8 @@ static MSIFEATURE *msi_seltree_get_selected_feature( msi_control *control ); #define WM_MSI_DIALOG_CREATE (WM_USER+0x100) #define WM_MSI_DIALOG_DESTROY (WM_USER+0x101) +#define USER_INSTALLSTATE_ALL 0x1000 + static DWORD uiThreadId; static HWND hMsiHiddenWindow; @@ -1876,7 +1878,7 @@ msi_seltree_popup_menu( HWND hwnd, INT x, INT y ) /* FIXME: load strings from resources */ AppendMenuA( hMenu, MF_ENABLED, INSTALLSTATE_LOCAL, "Install feature locally"); - AppendMenuA( hMenu, MF_GRAYED, 0x1000, "Install entire feature"); + AppendMenuA( hMenu, MF_ENABLED, USER_INSTALLSTATE_ALL, "Install entire feature"); AppendMenuA( hMenu, MF_ENABLED, INSTALLSTATE_ADVERTISED, "Install on demand"); AppendMenuA( hMenu, MF_ENABLED, INSTALLSTATE_ABSENT, "Don't install"); r = TrackPopupMenu( hMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, @@ -1899,6 +1901,37 @@ msi_seltree_feature_from_item( HWND hwnd, HTREEITEM hItem ) return (MSIFEATURE*) tvi.lParam; } +static void +msi_seltree_update_feature_installstate( HWND hwnd, HTREEITEM hItem, + MSIPACKAGE *package, MSIFEATURE *feature, INSTALLSTATE state ) +{ + msi_feature_set_state( package, feature, state ); + msi_seltree_sync_item_state( hwnd, feature, hItem ); + ACTION_UpdateComponentStates( package, feature->Feature ); +} + +static void +msi_seltree_update_siblings_and_children_installstate( HWND hwnd, HTREEITEM curr, + MSIPACKAGE *package, INSTALLSTATE state) +{ + /* update all siblings */ + do + { + MSIFEATURE *feature; + HTREEITEM child; + + feature = msi_seltree_feature_from_item( hwnd, curr ); + msi_seltree_update_feature_installstate( hwnd, curr, package, feature, state ); + + /* update this sibling's children */ + child = (HTREEITEM)SendMessageW( hwnd, TVM_GETNEXTITEM, (WPARAM)TVGN_CHILD, (LPARAM)curr ); + if (child) + msi_seltree_update_siblings_and_children_installstate( hwnd, child, + package, state ); + } + while ((curr = (HTREEITEM)SendMessageW( hwnd, TVM_GETNEXTITEM, (WPARAM)TVGN_NEXT, (LPARAM)curr ))); +} + static LRESULT msi_seltree_menu( HWND hwnd, HTREEITEM hItem ) { @@ -1931,19 +1964,23 @@ msi_seltree_menu( HWND hwnd, HTREEITEM hItem ) switch (r) { - case INSTALLSTATE_LOCAL: + case USER_INSTALLSTATE_ALL: + r = INSTALLSTATE_LOCAL; + /* fall-through */ case INSTALLSTATE_ADVERTISED: case INSTALLSTATE_ABSENT: - msi_feature_set_state(package, feature, r); + { + HTREEITEM child; + child = (HTREEITEM)SendMessageW( hwnd, TVM_GETNEXTITEM, (WPARAM)TVGN_CHILD, (LPARAM)hItem ); + if (child) + msi_seltree_update_siblings_and_children_installstate( hwnd, child, package, r ); + } + /* fall-through */ + case INSTALLSTATE_LOCAL: + msi_seltree_update_feature_installstate( hwnd, hItem, package, feature, r ); break; - default: - FIXME("select feature and all children\n"); } - /* update */ - msi_seltree_sync_item_state( hwnd, feature, hItem ); - ACTION_UpdateComponentStates( package, feature->Feature ); - return 0; } diff --git a/reactos/dll/win32/msi/events.c b/reactos/dll/win32/msi/events.c index 6275a95e9c4..f4697dd0a34 100644 --- a/reactos/dll/win32/msi/events.c +++ b/reactos/dll/win32/msi/events.c @@ -383,6 +383,28 @@ static UINT ControlEvent_ReinstallMode(MSIPACKAGE *package, LPCWSTR argument, return MSI_SetPropertyW( package, szReinstallMode, argument ); } +static UINT ControlEvent_ValidateProductID(MSIPACKAGE *package, LPCWSTR argument, + msi_dialog *dialog) +{ + static const WCHAR szProductID[] = {'P','r','o','d','u','c','t','I','D',0}; + static const WCHAR szPIDTemplate[] = {'P','I','D','T','e','m','p','l','a','t','e',0}; + static const WCHAR szPIDKEY[] = {'P','I','D','K','E','Y',0}; + LPWSTR key, template; + UINT ret = ERROR_SUCCESS; + + template = msi_dup_property( package, szPIDTemplate ); + key = msi_dup_property( package, szPIDKEY ); + + if (key && template) + { + FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) ); + ret = MSI_SetPropertyW( package, szProductID, key ); + } + msi_free( template ); + msi_free( key ); + return ret; +} + static const struct _events Events[] = { { "EndDialog",ControlEvent_EndDialog }, { "NewDialog",ControlEvent_NewDialog }, @@ -398,6 +420,7 @@ static const struct _events Events[] = { { "DirectoryListUp",ControlEvent_DirectoryListUp }, { "SelectionBrowse",ControlEvent_SpawnDialog }, { "ReinstallMode",ControlEvent_ReinstallMode }, + { "ValidateProductID",ControlEvent_ValidateProductID }, { NULL,NULL }, }; diff --git a/reactos/dll/win32/msi/files.c b/reactos/dll/win32/msi/files.c index 7e74dca9696..b7af4d39416 100644 --- a/reactos/dll/win32/msi/files.c +++ b/reactos/dll/win32/msi/files.c @@ -365,7 +365,8 @@ static UINT ITERATE_DuplicateFiles(MSIRECORD *row, LPVOID param) debugstr_w(component)); /* the action taken was the same as the current install state */ - comp->Action = comp->Installed; + if (comp) + comp->Action = comp->Installed; return ERROR_SUCCESS; } diff --git a/reactos/dll/win32/msi/helpers.c b/reactos/dll/win32/msi/helpers.c index 83569231029..e3009f7bce7 100644 --- a/reactos/dll/win32/msi/helpers.c +++ b/reactos/dll/win32/msi/helpers.c @@ -440,238 +440,6 @@ void msi_free_action_script(MSIPACKAGE *package, UINT script) package->script->ActionCount[script] = 0; } -static void remove_tracked_tempfiles(MSIPACKAGE* package) -{ - struct list *item, *cursor; - - LIST_FOR_EACH_SAFE( item, cursor, &package->tempfiles ) - { - MSITEMPFILE *temp = LIST_ENTRY( item, MSITEMPFILE, entry ); - - list_remove( &temp->entry ); - TRACE("deleting temp file %s\n", debugstr_w( temp->Path )); - if (!DeleteFileW( temp->Path )) - ERR("failed to delete %s\n", debugstr_w( temp->Path )); - msi_free( temp->Path ); - msi_free( temp ); - } -} - -static void free_feature( MSIFEATURE *feature ) -{ - struct list *item, *cursor; - - LIST_FOR_EACH_SAFE( item, cursor, &feature->Children ) - { - FeatureList *fl = LIST_ENTRY( item, FeatureList, entry ); - list_remove( &fl->entry ); - msi_free( fl ); - } - - LIST_FOR_EACH_SAFE( item, cursor, &feature->Components ) - { - ComponentList *cl = LIST_ENTRY( item, ComponentList, entry ); - list_remove( &cl->entry ); - msi_free( cl ); - } - msi_free( feature->Feature ); - msi_free( feature->Feature_Parent ); - msi_free( feature->Directory ); - msi_free( feature->Description ); - msi_free( feature->Title ); - msi_free( feature ); -} - -static void free_extension( MSIEXTENSION *ext ) -{ - struct list *item, *cursor; - - LIST_FOR_EACH_SAFE( item, cursor, &ext->verbs ) - { - MSIVERB *verb = LIST_ENTRY( item, MSIVERB, entry ); - - list_remove( &verb->entry ); - msi_free( verb->Verb ); - msi_free( verb->Command ); - msi_free( verb->Argument ); - msi_free( verb ); - } - - msi_free( ext->Extension ); - msi_free( ext->ProgIDText ); - msi_free( ext ); -} - -/* Called when the package is being closed */ -void ACTION_free_package_structures( MSIPACKAGE* package) -{ - INT i; - struct list *item, *cursor; - - TRACE("Freeing package action data\n"); - - remove_tracked_tempfiles(package); - - LIST_FOR_EACH_SAFE( item, cursor, &package->features ) - { - MSIFEATURE *feature = LIST_ENTRY( item, MSIFEATURE, entry ); - list_remove( &feature->entry ); - free_feature( feature ); - } - - LIST_FOR_EACH_SAFE( item, cursor, &package->folders ) - { - MSIFOLDER *folder = LIST_ENTRY( item, MSIFOLDER, entry ); - - list_remove( &folder->entry ); - msi_free( folder->Parent ); - msi_free( folder->Directory ); - msi_free( folder->TargetDefault ); - msi_free( folder->SourceLongPath ); - msi_free( folder->SourceShortPath ); - msi_free( folder->ResolvedTarget ); - msi_free( folder->ResolvedSource ); - msi_free( folder->Property ); - msi_free( folder ); - } - - LIST_FOR_EACH_SAFE( item, cursor, &package->components ) - { - MSICOMPONENT *comp = LIST_ENTRY( item, MSICOMPONENT, entry ); - - list_remove( &comp->entry ); - msi_free( comp->Component ); - msi_free( comp->ComponentId ); - msi_free( comp->Directory ); - msi_free( comp->Condition ); - msi_free( comp->KeyPath ); - msi_free( comp->FullKeypath ); - msi_free( comp ); - } - - LIST_FOR_EACH_SAFE( item, cursor, &package->files ) - { - MSIFILE *file = LIST_ENTRY( item, MSIFILE, entry ); - - list_remove( &file->entry ); - msi_free( file->File ); - msi_free( file->FileName ); - msi_free( file->ShortName ); - msi_free( file->LongName ); - msi_free( file->Version ); - msi_free( file->Language ); - msi_free( file->TargetPath ); - msi_free( file ); - } - - /* clean up extension, progid, class and verb structures */ - LIST_FOR_EACH_SAFE( item, cursor, &package->classes ) - { - MSICLASS *cls = LIST_ENTRY( item, MSICLASS, entry ); - - list_remove( &cls->entry ); - msi_free( cls->clsid ); - msi_free( cls->Context ); - msi_free( cls->Description ); - msi_free( cls->FileTypeMask ); - msi_free( cls->IconPath ); - msi_free( cls->DefInprocHandler ); - msi_free( cls->DefInprocHandler32 ); - msi_free( cls->Argument ); - msi_free( cls->ProgIDText ); - msi_free( cls ); - } - - LIST_FOR_EACH_SAFE( item, cursor, &package->extensions ) - { - MSIEXTENSION *ext = LIST_ENTRY( item, MSIEXTENSION, entry ); - - list_remove( &ext->entry ); - free_extension( ext ); - } - - LIST_FOR_EACH_SAFE( item, cursor, &package->progids ) - { - MSIPROGID *progid = LIST_ENTRY( item, MSIPROGID, entry ); - - list_remove( &progid->entry ); - msi_free( progid->ProgID ); - msi_free( progid->Description ); - msi_free( progid->IconPath ); - msi_free( progid ); - } - - LIST_FOR_EACH_SAFE( item, cursor, &package->mimes ) - { - MSIMIME *mt = LIST_ENTRY( item, MSIMIME, entry ); - - list_remove( &mt->entry ); - msi_free( mt->clsid ); - msi_free( mt->ContentType ); - msi_free( mt ); - } - - LIST_FOR_EACH_SAFE( item, cursor, &package->appids ) - { - MSIAPPID *appid = LIST_ENTRY( item, MSIAPPID, entry ); - - list_remove( &appid->entry ); - msi_free( appid->AppID ); - msi_free( appid->RemoteServerName ); - msi_free( appid->LocalServer ); - msi_free( appid->ServiceParameters ); - msi_free( appid->DllSurrogate ); - msi_free( appid ); - } - - LIST_FOR_EACH_SAFE( item, cursor, &package->sourcelist_info ) - { - MSISOURCELISTINFO *info = LIST_ENTRY( item, MSISOURCELISTINFO, entry ); - - list_remove( &info->entry ); - msi_free( info->value ); - msi_free( info ); - } - - LIST_FOR_EACH_SAFE( item, cursor, &package->sourcelist_media ) - { - MSIMEDIADISK *info = LIST_ENTRY( item, MSIMEDIADISK, entry ); - - list_remove( &info->entry ); - msi_free( info->volume_label ); - msi_free( info->disk_prompt ); - msi_free( info ); - } - - if (package->script) - { - for (i = 0; i < TOTAL_SCRIPTS; i++) - msi_free_action_script(package, i); - - for (i = 0; i < package->script->UniqueActionsCount; i++) - msi_free(package->script->UniqueActions[i]); - - msi_free(package->script->UniqueActions); - msi_free(package->script); - } - - if (package->patch) - { - msi_free(package->patch->patchcode); - msi_free(package->patch->transforms); - msi_free(package->patch); - } - - msi_free(package->BaseURL); - msi_free(package->PackagePath); - msi_free(package->ProductCode); - msi_free(package->ActionFormat); - msi_free(package->LastAction); - - /* cleanup control event subscriptions */ - ControlEvent_CleanupSubscriptions(package); -} - /* * build_directory_name() * diff --git a/reactos/dll/win32/msi/join.c b/reactos/dll/win32/msi/join.c index 134c5698cd2..f787c309a41 100644 --- a/reactos/dll/win32/msi/join.c +++ b/reactos/dll/win32/msi/join.c @@ -117,8 +117,11 @@ static UINT JOIN_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStr static UINT JOIN_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec ) { - FIXME("(%p, %d, %p): stub!\n", view, row, rec); - return ERROR_FUNCTION_FAILED; + MSIJOINVIEW *jv = (MSIJOINVIEW*)view; + + TRACE("%p %d %p\n", jv, row, rec); + + return msi_view_get_row( jv->db, view, row, rec ); } static UINT JOIN_execute( struct tagMSIVIEW *view, MSIRECORD *record ) @@ -219,13 +222,119 @@ static UINT JOIN_get_column_info( struct tagMSIVIEW *view, return ERROR_FUNCTION_FAILED; } -static UINT JOIN_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, - MSIRECORD *rec, UINT row ) +static UINT join_find_row( MSIJOINVIEW *jv, MSIRECORD *rec, UINT *row ) { - TRACE("%p %d %p\n", view, eModifyMode, rec); + LPCWSTR str; + UINT i, id, data; + + str = MSI_RecordGetString( rec, 1 ); + msi_string2idW( jv->db->strings, str, &id ); + + for (i = 0; i < jv->rows; i++) + { + JOIN_fetch_int( &jv->view, i, 1, &data ); + + if (data == id) + { + *row = i; + return ERROR_SUCCESS; + } + } + return ERROR_FUNCTION_FAILED; } +static UINT JOIN_set_row( struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask ) +{ + MSIJOINVIEW *jv = (MSIJOINVIEW*)view; + JOINTABLE *table; + UINT i, reduced_mask = 0, r = ERROR_SUCCESS, offset = 0, col_count; + MSIRECORD *reduced; + + TRACE("%p %d %p %u %08x\n", jv, row, rec, rec->count, mask ); + + if (mask >= 1 << jv->columns) + return ERROR_INVALID_PARAMETER; + + LIST_FOR_EACH_ENTRY(table, &jv->tables, JOINTABLE, entry) + { + r = table->view->ops->get_dimensions( table->view, NULL, &col_count ); + if (r != ERROR_SUCCESS) + return r; + + reduced = MSI_CreateRecord( col_count ); + if (!reduced) + return ERROR_FUNCTION_FAILED; + + for (i = 0; i < col_count; i++) + { + r = MSI_RecordCopyField( rec, i + offset + 1, reduced, i + 1 ); + if (r != ERROR_SUCCESS) + break; + } + + offset += col_count; + reduced_mask = mask >> (jv->columns - offset) & ((1 << col_count) - 1); + + if (r == ERROR_SUCCESS) + r = table->view->ops->set_row( table->view, row, reduced, reduced_mask ); + + msiobj_release( &reduced->hdr ); + } + + return r; +} + +static UINT join_modify_update( struct tagMSIVIEW *view, MSIRECORD *rec ) +{ + MSIJOINVIEW *jv = (MSIJOINVIEW *)view; + UINT r, row; + + r = join_find_row( jv, rec, &row ); + if (r != ERROR_SUCCESS) + return r; + + return JOIN_set_row( view, row, rec, (1 << jv->columns) - 1 ); +} + +static UINT JOIN_modify( struct tagMSIVIEW *view, MSIMODIFY mode, MSIRECORD *rec, UINT row ) +{ + UINT r; + + TRACE("%p %d %p %u\n", view, mode, rec, row); + + switch (mode) + { + case MSIMODIFY_UPDATE: + return join_modify_update( view, rec ); + + case MSIMODIFY_ASSIGN: + case MSIMODIFY_DELETE: + case MSIMODIFY_INSERT: + case MSIMODIFY_INSERT_TEMPORARY: + case MSIMODIFY_MERGE: + case MSIMODIFY_REPLACE: + case MSIMODIFY_SEEK: + case MSIMODIFY_VALIDATE: + case MSIMODIFY_VALIDATE_DELETE: + case MSIMODIFY_VALIDATE_FIELD: + case MSIMODIFY_VALIDATE_NEW: + r = ERROR_FUNCTION_FAILED; + break; + + case MSIMODIFY_REFRESH: + r = ERROR_CALL_NOT_IMPLEMENTED; + break; + + default: + WARN("%p %d %p %u - unknown mode\n", view, mode, rec, row ); + r = ERROR_INVALID_PARAMETER; + break; + } + + return r; +} + static UINT JOIN_delete( struct tagMSIVIEW *view ) { MSIJOINVIEW *jv = (MSIJOINVIEW*)view; @@ -259,7 +368,7 @@ static UINT JOIN_find_matching_rows( struct tagMSIVIEW *view, UINT col, if (col == 0 || col > jv->columns) return ERROR_INVALID_PARAMETER; - for (i = (UINT)*handle; i < jv->rows; i++) + for (i = PtrToUlong(*handle); i < jv->rows; i++) { if (view->ops->fetch_int( view, i, col, &row_value ) != ERROR_SUCCESS) continue; diff --git a/reactos/dll/win32/msi/msi.rc b/reactos/dll/win32/msi/msi.rc index 89d524c18e1..dfccd08a9a3 100644 --- a/reactos/dll/win32/msi/msi.rc +++ b/reactos/dll/win32/msi/msi.rc @@ -48,6 +48,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL #include "msi_Si.rc" #include "msi_Sv.rc" #include "msi_Tr.rc" +#include "msi_Uk.rc" #include "msi_Zh.rc" LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL diff --git a/reactos/dll/win32/msi/msi_Uk.rc b/reactos/dll/win32/msi/msi_Uk.rc new file mode 100644 index 00000000000..4b7173e8d4a --- /dev/null +++ b/reactos/dll/win32/msi/msi_Uk.rc @@ -0,0 +1,41 @@ +/* + * Ukrainian resources for MSI + * + * Copyright 2005 Mike McCormack + * Copyright 2007 Artem Reznikov + * Copyright 2010 Igor Paliychuk + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "windef.h" + +/* UTF-8 */ +#pragma code_page(65001) + +LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + 4 "Не вдалося відкрити вказаний пакет інсталяції. Перевірте шлях до файлу та спробуйте знов." + 5 "шлях %s не знайдено" + 9 "вставте диск %s" + 10 "невірні параметри" + 11 "вкажіть папку, що містить %s" + 12 "джерело встановлення даної можливості не вказане" + 13 "мережевий диск для даної можливості не вказаний" + 14 "можливість з:" + 15 "виберіть папку, що містить %s" +} diff --git a/reactos/dll/win32/msi/msipriv.h b/reactos/dll/win32/msi/msipriv.h index ac247ac4548..43486e0a830 100644 --- a/reactos/dll/win32/msi/msipriv.h +++ b/reactos/dll/win32/msi/msipriv.h @@ -689,7 +689,6 @@ extern UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si /* action internals */ extern UINT MSI_InstallPackage( MSIPACKAGE *, LPCWSTR, LPCWSTR ); -extern void ACTION_free_package_structures( MSIPACKAGE* ); extern UINT ACTION_DialogBox( MSIPACKAGE*, LPCWSTR); extern UINT ACTION_ForceReboot(MSIPACKAGE *package); extern UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode ); diff --git a/reactos/dll/win32/msi/msiquery.c b/reactos/dll/win32/msi/msiquery.c index ddbb28d6496..b673832b0c4 100644 --- a/reactos/dll/win32/msi/msiquery.c +++ b/reactos/dll/win32/msi/msiquery.c @@ -831,7 +831,7 @@ UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb ) return ERROR_INVALID_HANDLE; IWineMsiRemoteDatabase_Release( remote_database ); - WARN("MsiDatabaseCommit not allowed during a custom action!\n"); + WARN("not allowed during a custom action!\n"); return ERROR_SUCCESS; } diff --git a/reactos/dll/win32/msi/package.c b/reactos/dll/win32/msi/package.c index 120972fdd07..53804e22e56 100644 --- a/reactos/dll/win32/msi/package.c +++ b/reactos/dll/win32/msi/package.c @@ -49,6 +49,237 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi); +static void remove_tracked_tempfiles( MSIPACKAGE *package ) +{ + struct list *item, *cursor; + + LIST_FOR_EACH_SAFE( item, cursor, &package->tempfiles ) + { + MSITEMPFILE *temp = LIST_ENTRY( item, MSITEMPFILE, entry ); + + list_remove( &temp->entry ); + TRACE("deleting temp file %s\n", debugstr_w( temp->Path )); + if (!DeleteFileW( temp->Path )) + ERR("failed to delete %s\n", debugstr_w( temp->Path )); + msi_free( temp->Path ); + msi_free( temp ); + } +} + +static void free_feature( MSIFEATURE *feature ) +{ + struct list *item, *cursor; + + LIST_FOR_EACH_SAFE( item, cursor, &feature->Children ) + { + FeatureList *fl = LIST_ENTRY( item, FeatureList, entry ); + list_remove( &fl->entry ); + msi_free( fl ); + } + + LIST_FOR_EACH_SAFE( item, cursor, &feature->Components ) + { + ComponentList *cl = LIST_ENTRY( item, ComponentList, entry ); + list_remove( &cl->entry ); + msi_free( cl ); + } + msi_free( feature->Feature ); + msi_free( feature->Feature_Parent ); + msi_free( feature->Directory ); + msi_free( feature->Description ); + msi_free( feature->Title ); + msi_free( feature ); +} + +static void free_extension( MSIEXTENSION *ext ) +{ + struct list *item, *cursor; + + LIST_FOR_EACH_SAFE( item, cursor, &ext->verbs ) + { + MSIVERB *verb = LIST_ENTRY( item, MSIVERB, entry ); + + list_remove( &verb->entry ); + msi_free( verb->Verb ); + msi_free( verb->Command ); + msi_free( verb->Argument ); + msi_free( verb ); + } + + msi_free( ext->Extension ); + msi_free( ext->ProgIDText ); + msi_free( ext ); +} + +static void free_package_structures( MSIPACKAGE *package ) +{ + INT i; + struct list *item, *cursor; + + TRACE("Freeing package action data\n"); + + remove_tracked_tempfiles(package); + + LIST_FOR_EACH_SAFE( item, cursor, &package->features ) + { + MSIFEATURE *feature = LIST_ENTRY( item, MSIFEATURE, entry ); + list_remove( &feature->entry ); + free_feature( feature ); + } + + LIST_FOR_EACH_SAFE( item, cursor, &package->folders ) + { + MSIFOLDER *folder = LIST_ENTRY( item, MSIFOLDER, entry ); + + list_remove( &folder->entry ); + msi_free( folder->Parent ); + msi_free( folder->Directory ); + msi_free( folder->TargetDefault ); + msi_free( folder->SourceLongPath ); + msi_free( folder->SourceShortPath ); + msi_free( folder->ResolvedTarget ); + msi_free( folder->ResolvedSource ); + msi_free( folder->Property ); + msi_free( folder ); + } + + LIST_FOR_EACH_SAFE( item, cursor, &package->components ) + { + MSICOMPONENT *comp = LIST_ENTRY( item, MSICOMPONENT, entry ); + + list_remove( &comp->entry ); + msi_free( comp->Component ); + msi_free( comp->ComponentId ); + msi_free( comp->Directory ); + msi_free( comp->Condition ); + msi_free( comp->KeyPath ); + msi_free( comp->FullKeypath ); + msi_free( comp ); + } + + LIST_FOR_EACH_SAFE( item, cursor, &package->files ) + { + MSIFILE *file = LIST_ENTRY( item, MSIFILE, entry ); + + list_remove( &file->entry ); + msi_free( file->File ); + msi_free( file->FileName ); + msi_free( file->ShortName ); + msi_free( file->LongName ); + msi_free( file->Version ); + msi_free( file->Language ); + msi_free( file->TargetPath ); + msi_free( file ); + } + + /* clean up extension, progid, class and verb structures */ + LIST_FOR_EACH_SAFE( item, cursor, &package->classes ) + { + MSICLASS *cls = LIST_ENTRY( item, MSICLASS, entry ); + + list_remove( &cls->entry ); + msi_free( cls->clsid ); + msi_free( cls->Context ); + msi_free( cls->Description ); + msi_free( cls->FileTypeMask ); + msi_free( cls->IconPath ); + msi_free( cls->DefInprocHandler ); + msi_free( cls->DefInprocHandler32 ); + msi_free( cls->Argument ); + msi_free( cls->ProgIDText ); + msi_free( cls ); + } + + LIST_FOR_EACH_SAFE( item, cursor, &package->extensions ) + { + MSIEXTENSION *ext = LIST_ENTRY( item, MSIEXTENSION, entry ); + + list_remove( &ext->entry ); + free_extension( ext ); + } + + LIST_FOR_EACH_SAFE( item, cursor, &package->progids ) + { + MSIPROGID *progid = LIST_ENTRY( item, MSIPROGID, entry ); + + list_remove( &progid->entry ); + msi_free( progid->ProgID ); + msi_free( progid->Description ); + msi_free( progid->IconPath ); + msi_free( progid ); + } + + LIST_FOR_EACH_SAFE( item, cursor, &package->mimes ) + { + MSIMIME *mt = LIST_ENTRY( item, MSIMIME, entry ); + + list_remove( &mt->entry ); + msi_free( mt->clsid ); + msi_free( mt->ContentType ); + msi_free( mt ); + } + + LIST_FOR_EACH_SAFE( item, cursor, &package->appids ) + { + MSIAPPID *appid = LIST_ENTRY( item, MSIAPPID, entry ); + + list_remove( &appid->entry ); + msi_free( appid->AppID ); + msi_free( appid->RemoteServerName ); + msi_free( appid->LocalServer ); + msi_free( appid->ServiceParameters ); + msi_free( appid->DllSurrogate ); + msi_free( appid ); + } + + LIST_FOR_EACH_SAFE( item, cursor, &package->sourcelist_info ) + { + MSISOURCELISTINFO *info = LIST_ENTRY( item, MSISOURCELISTINFO, entry ); + + list_remove( &info->entry ); + msi_free( info->value ); + msi_free( info ); + } + + LIST_FOR_EACH_SAFE( item, cursor, &package->sourcelist_media ) + { + MSIMEDIADISK *info = LIST_ENTRY( item, MSIMEDIADISK, entry ); + + list_remove( &info->entry ); + msi_free( info->volume_label ); + msi_free( info->disk_prompt ); + msi_free( info ); + } + + if (package->script) + { + for (i = 0; i < TOTAL_SCRIPTS; i++) + msi_free_action_script( package, i ); + + for (i = 0; i < package->script->UniqueActionsCount; i++) + msi_free( package->script->UniqueActions[i] ); + + msi_free( package->script->UniqueActions ); + msi_free( package->script ); + } + + if (package->patch) + { + msi_free( package->patch->patchcode ); + msi_free( package->patch->transforms ); + msi_free( package->patch ); + } + + msi_free( package->BaseURL ); + msi_free( package->PackagePath ); + msi_free( package->ProductCode ); + msi_free( package->ActionFormat ); + msi_free( package->LastAction ); + + /* cleanup control event subscriptions */ + ControlEvent_CleanupSubscriptions( package ); +} + static void MSI_FreePackage( MSIOBJECTHDR *arg) { MSIPACKAGE *package= (MSIPACKAGE*) arg; @@ -57,7 +288,7 @@ static void MSI_FreePackage( MSIOBJECTHDR *arg) msi_dialog_destroy( package->dialog ); msiobj_release( &package->db->hdr ); - ACTION_free_package_structures(package); + free_package_structures(package); } static UINT create_temp_property_table(MSIPACKAGE *package) diff --git a/reactos/dll/win32/msi/storages.c b/reactos/dll/win32/msi/storages.c index a54d46fc76e..6a8134b5627 100644 --- a/reactos/dll/win32/msi/storages.c +++ b/reactos/dll/win32/msi/storages.c @@ -452,7 +452,7 @@ static UINT STORAGES_find_matching_rows(struct tagMSIVIEW *view, UINT col, UINT val, UINT *row, MSIITERHANDLE *handle) { MSISTORAGESVIEW *sv = (MSISTORAGESVIEW *)view; - UINT index = (UINT)*handle; + UINT index = PtrToUlong(*handle); TRACE("(%d, %d): %d\n", *row, col, val); @@ -470,7 +470,7 @@ static UINT STORAGES_find_matching_rows(struct tagMSIVIEW *view, UINT col, index++; } - *handle = (MSIITERHANDLE)++index; + *handle = UlongToPtr(++index); if (index >= sv->num_rows) return ERROR_NO_MORE_ITEMS; diff --git a/reactos/dll/win32/msi/streams.c b/reactos/dll/win32/msi/streams.c index 4825ae67b18..8d2e748e64d 100644 --- a/reactos/dll/win32/msi/streams.c +++ b/reactos/dll/win32/msi/streams.c @@ -41,7 +41,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(msidb); typedef struct tabSTREAM { UINT str_index; - LPWSTR name; IStream *stream; } STREAM; @@ -72,7 +71,6 @@ static STREAM *create_stream(MSISTREAMSVIEW *sv, LPWSTR name, BOOL encoded, IStr { STREAM *stream; WCHAR decoded[MAX_STREAM_NAME_LEN]; - LPWSTR ptr = name; stream = msi_alloc(sizeof(STREAM)); if (!stream) @@ -81,18 +79,11 @@ static STREAM *create_stream(MSISTREAMSVIEW *sv, LPWSTR name, BOOL encoded, IStr if (encoded) { decode_streamname(name, decoded); - ptr = decoded; TRACE("stream -> %s %s\n", debugstr_w(name), debugstr_w(decoded)); + name = decoded; } - stream->name = strdupW(ptr); - if (!stream->name) - { - msi_free(stream); - return NULL; - } - - stream->str_index = msi_addstringW(sv->db->strings, 0, stream->name, -1, 1, StringNonPersistent); + stream->str_index = msi_addstringW(sv->db->strings, 0, name, -1, 1, StringNonPersistent); stream->stream = stm; return stream; } @@ -133,9 +124,9 @@ static UINT STREAMS_get_row( struct tagMSIVIEW *view, UINT row, MSIRECORD **rec { MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; - FIXME("%p %d %p\n", sv, row, rec); + TRACE("%p %d %p\n", sv, row, rec); - return ERROR_CALL_NOT_IMPLEMENTED; + return msi_view_get_row( sv->db, view, row, rec ); } static UINT STREAMS_set_row(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, UINT mask) @@ -144,13 +135,13 @@ static UINT STREAMS_set_row(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, U STREAM *stream; IStream *stm; STATSTG stat; - LPWSTR name = NULL; + LPWSTR encname = NULL, name = NULL; USHORT *data = NULL; HRESULT hr; ULONG count; UINT r = ERROR_FUNCTION_FAILED; - TRACE("(%p, %p)\n", view, rec); + TRACE("(%p, %d, %p, %08x)\n", view, row, rec, mask); if (row > sv->num_rows) return ERROR_FUNCTION_FAILED; @@ -167,7 +158,10 @@ static UINT STREAMS_set_row(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, U } if (stat.cbSize.QuadPart >> 32) + { + WARN("stream too large\n"); goto done; + } data = msi_alloc(stat.cbSize.QuadPart); if (!data) @@ -182,7 +176,13 @@ static UINT STREAMS_set_row(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, U name = strdupW(MSI_RecordGetString(rec, 1)); if (!name) + { + WARN("failed to retrieve stream name\n"); goto done; + } + + encname = encode_streamname(FALSE, name); + IStorage_DestroyElement(sv->db->storage, encname); r = write_stream_data(sv->db->storage, name, data, count, FALSE); if (r != ERROR_SUCCESS) @@ -195,14 +195,20 @@ static UINT STREAMS_set_row(struct tagMSIVIEW *view, UINT row, MSIRECORD *rec, U if (!stream) goto done; - IStorage_OpenStream(sv->db->storage, name, 0, - STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stream->stream); + hr = IStorage_OpenStream(sv->db->storage, encname, 0, + STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stream->stream); + if (FAILED(hr)) + { + WARN("failed to open stream: %08x\n", hr); + goto done; + } sv->streams[row] = stream; done: msi_free(name); msi_free(data); + msi_free(encname); IStream_Release(stm); @@ -212,6 +218,9 @@ done: static UINT STREAMS_insert_row(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row, BOOL temporary) { MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; + UINT i; + + TRACE("(%p, %p, %d, %d)\n", view, rec, row, temporary); if (!streams_set_table_size(sv, ++sv->num_rows)) return ERROR_FUNCTION_FAILED; @@ -219,7 +228,11 @@ static UINT STREAMS_insert_row(struct tagMSIVIEW *view, MSIRECORD *rec, UINT row if (row == -1) row = sv->num_rows - 1; - /* FIXME have to readjust rows */ + /* shift the rows to make room for the new row */ + for (i = sv->num_rows - 1; i > row; i--) + { + sv->streams[i] = sv->streams[i - 1]; + } return STREAMS_set_row(view, row, rec, 0); } @@ -274,7 +287,7 @@ static UINT STREAMS_get_column_info(struct tagMSIVIEW *view, UINT n, { case 1: name_ptr = Name; - if (type) *type = MSITYPE_STRING | MAX_STREAM_NAME_LEN; + if (type) *type = MSITYPE_STRING | MSITYPE_VALID | MAX_STREAM_NAME_LEN; break; case 2: @@ -404,8 +417,6 @@ static UINT STREAMS_delete(struct tagMSIVIEW *view) { if (sv->streams[i]->stream) IStream_Release(sv->streams[i]->stream); - - msi_free(sv->streams[i]->name); msi_free(sv->streams[i]); } } @@ -420,9 +431,9 @@ static UINT STREAMS_find_matching_rows(struct tagMSIVIEW *view, UINT col, UINT val, UINT *row, MSIITERHANDLE *handle) { MSISTREAMSVIEW *sv = (MSISTREAMSVIEW *)view; - UINT index = (UINT)*handle; + UINT index = PtrToUlong(*handle); - TRACE("(%d, %d): %d\n", *row, col, val); + TRACE("(%p, %d, %d, %p, %p)\n", view, col, val, row, handle); if (col == 0 || col > NUM_STREAMS_COLS) return ERROR_INVALID_PARAMETER; @@ -438,8 +449,9 @@ static UINT STREAMS_find_matching_rows(struct tagMSIVIEW *view, UINT col, index++; } - *handle = (MSIITERHANDLE)++index; - if (index >= sv->num_rows) + *handle = UlongToPtr(++index); + + if (index > sv->num_rows) return ERROR_NO_MORE_ITEMS; return ERROR_SUCCESS; @@ -510,10 +522,17 @@ static INT add_streams_to_table(MSISTREAMSVIEW *sv) break; } - IStorage_OpenStream(sv->db->storage, stat.pwcsName, 0, - STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stream->stream); + hr = IStorage_OpenStream(sv->db->storage, stat.pwcsName, 0, + STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stream->stream); CoTaskMemFree(stat.pwcsName); + if (FAILED(hr)) + { + WARN("failed to open stream: %08x\n", hr); + count = -1; + break; + } + if (!streams_set_table_size(sv, ++count)) { count = -1; diff --git a/reactos/include/psdk/msi.h b/reactos/include/psdk/msi.h index 2c0a37fe43b..5c2f38cc824 100644 --- a/reactos/include/psdk/msi.h +++ b/reactos/include/psdk/msi.h @@ -597,6 +597,10 @@ UINT WINAPI MsiSourceListEnumSourcesA(LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, UINT WINAPI MsiSourceListEnumSourcesW(LPCWSTR, LPCWSTR, MSIINSTALLCONTEXT, DWORD, DWORD, LPWSTR, LPDWORD); #define MsiSourceListEnumSources WINELIB_NAME_AW(MsiSourceListEnumSources) +UINT WINAPI MsiSourceListClearSourceA(LPCSTR, LPCSTR, MSIINSTALLCONTEXT, DWORD, LPCSTR); +UINT WINAPI MsiSourceListClearSourceW(LPCWSTR, LPCWSTR, MSIINSTALLCONTEXT, DWORD, LPCWSTR); +#define MsiSourceListClearSource WINELIB_NAME_AW(MsiSourceListClearSource) + UINT WINAPI MsiSourceListClearAllA(LPCSTR, LPCSTR, DWORD); UINT WINAPI MsiSourceListClearAllW(LPCWSTR, LPCWSTR, DWORD); #define MsiSourceListClearAll WINELIB_NAME_AW(MsiSourceListClearAll)