@@ -334,7 +334,7 @@ static void WatchProgramUpdate()
334334 }
335335 }
336336
337- public static async Task IndexWin32ProgramsAsync ( )
337+ public static async Task IndexWin32ProgramsAsync ( bool resetCache )
338338 {
339339 await _win32sLock . WaitAsync ( ) ;
340340 try
@@ -345,7 +345,10 @@ public static async Task IndexWin32ProgramsAsync()
345345 {
346346 _win32s . Add ( win32 ) ;
347347 }
348- ResetCache ( ) ;
348+ if ( resetCache )
349+ {
350+ ResetCache ( ) ;
351+ }
349352 await Context . API . SaveCacheBinaryStorageAsync < List < Win32 > > ( Win32CacheName , Context . CurrentPluginMetadata . PluginCacheDirectoryPath ) ;
350353 lock ( _lastIndexTimeLock )
351354 {
@@ -362,7 +365,7 @@ public static async Task IndexWin32ProgramsAsync()
362365 }
363366 }
364367
365- public static async Task IndexUwpProgramsAsync ( )
368+ public static async Task IndexUwpProgramsAsync ( bool resetCache )
366369 {
367370 await _uwpsLock . WaitAsync ( ) ;
368371 try
@@ -373,7 +376,10 @@ public static async Task IndexUwpProgramsAsync()
373376 {
374377 _uwps . Add ( uwp ) ;
375378 }
376- ResetCache ( ) ;
379+ if ( resetCache )
380+ {
381+ ResetCache ( ) ;
382+ }
377383 await Context . API . SaveCacheBinaryStorageAsync < List < UWPApp > > ( UwpCacheName , Context . CurrentPluginMetadata . PluginCacheDirectoryPath ) ;
378384 lock ( _lastIndexTimeLock )
379385 {
@@ -394,22 +400,34 @@ public static async Task IndexProgramsAsync()
394400 {
395401 var win32Task = Task . Run ( async ( ) =>
396402 {
397- await Context . API . StopwatchLogInfoAsync ( ClassName , "Win32Program index cost" , IndexWin32ProgramsAsync ) ;
403+ await Context . API . StopwatchLogInfoAsync ( ClassName , "Win32Program index cost" , ( ) => IndexWin32ProgramsAsync ( resetCache : true ) ) ;
398404 } ) ;
399405
400406 var uwpTask = Task . Run ( async ( ) =>
401407 {
402- await Context . API . StopwatchLogInfoAsync ( ClassName , "UWPProgram index cost" , IndexUwpProgramsAsync ) ;
408+ await Context . API . StopwatchLogInfoAsync ( ClassName , "UWPProgram index cost" , ( ) => IndexUwpProgramsAsync ( resetCache : true ) ) ;
403409 } ) ;
404410
405411 await Task . WhenAll ( win32Task , uwpTask ) . ConfigureAwait ( false ) ;
406412 }
407413
408414 internal static void ResetCache ( )
409415 {
410- var oldCache = cache ;
411- cache = new MemoryCache ( cacheOptions ) ;
412- oldCache . Dispose ( ) ;
416+ var newCache = new MemoryCache ( cacheOptions ) ;
417+
418+ // Atomically swap and get the previous cache instance, avoids double-dispose/lost-assignment race
419+ // where each caller receives a distinct prior instance to dispose.
420+ var oldCache = Interlocked . Exchange ( ref cache , newCache ) ;
421+
422+ // Dispose the previous instance (if any)- each caller gets a unique prior instance from above
423+ try
424+ {
425+ oldCache ? . Dispose ( ) ;
426+ }
427+ catch ( Exception e )
428+ {
429+ Context . API . LogException ( ClassName , "Failed to dispose old program cache" , e ) ;
430+ }
413431 }
414432
415433 public Control CreateSettingPanel ( )
@@ -442,12 +460,26 @@ public List<Result> LoadContextMenus(Result selectedResult)
442460 Title = Context . API . GetTranslation ( "flowlauncher_plugin_program_disable_program" ) ,
443461 Action = c =>
444462 {
445- _ = DisableProgramAsync ( program ) ;
446- Context . API . ShowMsg (
447- Context . API . GetTranslation ( "flowlauncher_plugin_program_disable_dlgtitle_success" ) ,
448- Context . API . GetTranslation (
449- "flowlauncher_plugin_program_disable_dlgtitle_success_message" ) ) ;
450- Context . API . ReQuery ( ) ;
463+ _ = Task . Run ( async ( ) =>
464+ {
465+ try
466+ {
467+ var disabled = await DisableProgramAsync ( program ) ;
468+ if ( disabled )
469+ {
470+ ResetCache ( ) ;
471+ Context . API . ShowMsg (
472+ Context . API . GetTranslation ( "flowlauncher_plugin_program_disable_dlgtitle_success" ) ,
473+ Context . API . GetTranslation (
474+ "flowlauncher_plugin_program_disable_dlgtitle_success_message" ) ) ;
475+ }
476+ Context . API . ReQuery ( ) ;
477+ }
478+ catch ( Exception e )
479+ {
480+ Context . API . LogException ( ClassName , "Failed to disable program" , e ) ;
481+ }
482+ } ) ;
451483 return false ;
452484 } ,
453485 IcoPath = "Images/disable.png" ,
@@ -458,52 +490,50 @@ public List<Result> LoadContextMenus(Result selectedResult)
458490 return menuOptions ;
459491 }
460492
461- private static async Task DisableProgramAsync ( IProgram programToDelete )
493+ private static async Task < bool > DisableProgramAsync ( IProgram programToDelete )
462494 {
463495 if ( _settings . DisabledProgramSources . Any ( x => x . UniqueIdentifier == programToDelete . UniqueIdentifier ) )
464- return ;
496+ {
497+ return false ;
498+ }
465499
466500 await _uwpsLock . WaitAsync ( ) ;
467- var reindexUwps = true ;
468501 try
469502 {
470- reindexUwps = _uwps . Any ( x => x . UniqueIdentifier == programToDelete . UniqueIdentifier ) ;
471- var program = _uwps . First ( x => x . UniqueIdentifier == programToDelete . UniqueIdentifier ) ;
472- program . Enabled = false ;
473- _settings . DisabledProgramSources . Add ( new ProgramSource ( program ) ) ;
503+ var program = _uwps . FirstOrDefault ( x => x . UniqueIdentifier == programToDelete . UniqueIdentifier ) ;
504+ if ( program != null )
505+ {
506+ program . Enabled = false ;
507+ _settings . DisabledProgramSources . Add ( new ProgramSource ( program ) ) ;
508+ // Reindex UWP programs
509+ _ = Task . Run ( ( ) => IndexUwpProgramsAsync ( resetCache : false ) ) ;
510+ return true ;
511+ }
474512 }
475513 finally
476514 {
477515 _uwpsLock . Release ( ) ;
478516 }
479517
480- // Reindex UWP programs
481- if ( reindexUwps )
482- {
483- _ = Task . Run ( IndexUwpProgramsAsync ) ;
484- return ;
485- }
486-
487518 await _win32sLock . WaitAsync ( ) ;
488- var reindexWin32s = true ;
489519 try
490520 {
491- reindexWin32s = _win32s . Any ( x => x . UniqueIdentifier == programToDelete . UniqueIdentifier ) ;
492- var program = _win32s . First ( x => x . UniqueIdentifier == programToDelete . UniqueIdentifier ) ;
493- program . Enabled = false ;
494- _settings . DisabledProgramSources . Add ( new ProgramSource ( program ) ) ;
521+ var program = _win32s . FirstOrDefault ( x => x . UniqueIdentifier == programToDelete . UniqueIdentifier ) ;
522+ if ( program != null )
523+ {
524+ program . Enabled = false ;
525+ _settings . DisabledProgramSources . Add ( new ProgramSource ( program ) ) ;
526+ // Reindex Win32 programs
527+ _ = Task . Run ( ( ) => IndexWin32ProgramsAsync ( resetCache : false ) ) ;
528+ return true ;
529+ }
495530 }
496531 finally
497532 {
498533 _win32sLock . Release ( ) ;
499534 }
500535
501- // Reindex Win32 programs
502- if ( reindexWin32s )
503- {
504- _ = Task . Run ( IndexWin32ProgramsAsync ) ;
505- return ;
506- }
536+ return false ;
507537 }
508538
509539 public static void StartProcess ( Func < ProcessStartInfo , Process > runProcess , ProcessStartInfo info )
0 commit comments