@@ -23,7 +23,7 @@ namespace CalibreImport
2323 [ ClassInterface ( ClassInterfaceType . None ) ] //, ComVisible(true)]
2424 [ Guid ( "8E5CD5CA-64E0-479A-B62F-B1FC00FF0227" ) ]
2525 [ DisplayName ( "CalibreImport" ) ]
26- [ COMServerAssociation ( AssociationType . AllFiles ) ] //needed for Directory Opus, apparently.
26+ // [COMServerAssociation(AssociationType.AllFiles)] //needed for Directory Opus, apparently.
2727 [ COMServerAssociation ( AssociationType . ClassOfExtension , ".epub" , ".pdf" , ".mobi" , ".azw" , ".azw3" , ".fb2" , ".djvu" , ".lrf" , ".rtf" , ".txt" , ".doc" , ".docx" , ".odt" , ".htm" , ".html" , ".cbz" , ".cbr" , ".pdb" , ".snb" , ".tcr" , ".zip" , ".rar" ) ]
2828
2929 // Welcome to CalibreImport, the main class of this Shell Extension.
@@ -32,7 +32,8 @@ namespace CalibreImport
3232 // The class is decorated with various attributes to specify its COM visibility and associations with file types.
3333 public class CalibreImport : SharpContextMenu
3434 {
35- private List < string > _supportedExtensions = new List < string > ( ) ;
35+ // HashSet for supported extensions to improve lookup performance
36+ private HashSet < string > _supportedExtensions = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) ;
3637
3738 // variables from the Settings file and their defaults
3839 private string MenuText = ResourceStrings . MenuTextRes ;
@@ -43,7 +44,7 @@ public class CalibreImport : SharpContextMenu
4344 private string hiddenLibraries = CustomSettings . Config . AppSettings . Settings [ "hiddenLibraries" ] . Value ?? "" ;
4445 private bool skipSuccessMessage = bool . Parse ( CustomSettings . Config . AppSettings . Settings [ "skipSuccessMessage" ] . Value ?? "False" ) ;
4546 private bool autoCalibreOpen = bool . Parse ( CustomSettings . Config . AppSettings . Settings [ "autoCalibreOpen" ] . Value ?? "False" ) ;
46-
47+ private string savedCulture = CustomSettings . Config . AppSettings . Settings [ "language" ] . Value ;
4748
4849 // List of Calibre-related processes to check
4950 private static readonly string [ ] CalibreProcesses = new [ ]
@@ -57,25 +58,28 @@ public class CalibreImport : SharpContextMenu
5758 "calibre-smtp"
5859 } ;
5960
61+ // Time checks for retrieveing file types in CanShowMenu
62+ private DateTime _lastExtensionsUpdate = DateTime . MinValue ;
63+ private readonly TimeSpan _extensionCacheDuration = TimeSpan . FromMinutes ( 5 ) ;
64+
6065 // other variables
6166 private string dllDirectory ;
6267 private string calibredbPath ;
6368 private string calibrePath ;
6469
65- // Constructor: sets culture from settings ,
66- // and loads paths and supported file extensions
70+ // Constructor: calls on the CultureManager class to set culture ,
71+ // and loads paths and supported file extensions.
6772 public CalibreImport ( )
6873 {
69- // Load the saved language setting
70- var savedCulture = CustomSettings . Config . AppSettings . Settings [ "language" ] . Value ;
71- if ( ! string . IsNullOrEmpty ( savedCulture ) )
72- {
73- CultureInfo culture = new CultureInfo ( savedCulture ) ;
74- Thread . CurrentThread . CurrentUICulture = culture ;
75- Thread . CurrentThread . CurrentCulture = culture ;
76- }
74+ // Ensure the default application culture is set FIRST before any other initialization
75+ CultureManager . SetApplicationCulture ( ) ;
76+
77+ // Set default thread culture to ensure new threads use the correct culture
78+ CultureInfo culture = Thread . CurrentThread . CurrentUICulture ;
79+ CultureInfo . DefaultThreadCurrentCulture = culture ;
80+ CultureInfo . DefaultThreadCurrentUICulture = culture ;
7781
78- // Initialize other components or settings if needed
82+ // Initialize other components or settings
7983 InitializePaths ( ) ;
8084 LoadSupportedExtensions ( ) ;
8185 }
@@ -95,19 +99,23 @@ protected override bool CanShowMenu()
9599 {
96100 try
97101 {
98- InitializePaths ( ) ;
99- LoadSupportedExtensions ( ) ;
100-
102+ // Only reload extensions if needed
103+ if ( _supportedExtensions == null || _supportedExtensions . Count == 0 ||
104+ DateTime . Now - _lastExtensionsUpdate > _extensionCacheDuration )
105+ {
106+ InitializePaths ( ) ;
107+ LoadSupportedExtensions ( ) ;
108+ _lastExtensionsUpdate = DateTime . Now ;
109+ }
101110 // Log the selected item paths and supported extensions
102111 Logger . LogThis ( $ "SelectedItemPaths: { string . Join ( ", " , SelectedItemPaths ) } ", true ) ;
103- Logger . LogThis ( $ "SupportedExtensions: { string . Join ( ", " , _supportedExtensions ) } ", true ) ;
112+ // Logger.LogThis($"SupportedExtensions: {string.Join(", ", _supportedExtensions)}", true);
104113
105114 // Ensure all selected items have supported extensions
106115 bool allSupported = SelectedItemPaths . Any ( p => _supportedExtensions . Contains ( Path . GetExtension ( p ) . ToLower ( ) ) ) ;
107116 Logger . LogThis ( $ "AllSupported: { allSupported } ", true ) ;
108117
109118 return allSupported ;
110- //return true;
111119 }
112120 catch ( Exception ex )
113121 {
@@ -120,6 +128,9 @@ protected override bool CanShowMenu()
120128 // Handles both submenu and single menu item display modes based on user settings.
121129 protected override ContextMenuStrip CreateMenu ( )
122130 {
131+ // Make sure culture is set correctly before creating any UI text
132+ CultureManager . SetApplicationCulture ( ) ;
133+
123134 var menu = new ContextMenuStrip ( ) ;
124135 Logger . LogThis ( "Creating context menu." , true ) ;
125136
@@ -217,6 +228,9 @@ private void ExecuteImport(string selectedLibrary = null, ReportProgressDelegate
217228 {
218229 try
219230 {
231+ // Ensure culture is set correctly before displaying any messages
232+ CultureManager . SetApplicationCulture ( ) ;
233+
220234 Logger . LogThis ( "ExecuteImport method called." , true ) ;
221235
222236 InitializePaths ( ) ;
@@ -233,6 +247,7 @@ private void ExecuteImport(string selectedLibrary = null, ReportProgressDelegate
233247
234248 Logger . LogThis ( $ "Found { filePaths . Count } supported files.", true ) ;
235249
250+ // make sure calibredb.exe exists, otherwise bye-bye
236251 if ( ! File . Exists ( calibredbPath ) )
237252 {
238253 Logger . LogThis ( $ "Could not find calibredb.exe at { calibredbPath } . Please update the script with the correct path.") ;
@@ -243,13 +258,14 @@ private void ExecuteImport(string selectedLibrary = null, ReportProgressDelegate
243258
244259 Logger . LogThis ( "calibredb.exe found." , true ) ;
245260
261+ // What to do if Calibre is running
246262 if ( IsCalibreRunning ( ) )
247263 {
248264 Logger . LogThis ( "Calibre is running." , true ) ;
249265
250266 if ( autoKillCalibre )
251267 {
252- Logger . LogThis ( "Auto-killing Calibre." , true ) ;
268+ Logger . LogThis ( "Auto-killing Calibre without asking ." , true ) ;
253269 KillCalibre ( ) ;
254270 }
255271 else
@@ -299,11 +315,9 @@ private void ExecuteImport(string selectedLibrary = null, ReportProgressDelegate
299315 return allSuccessful ;
300316 } ;
301317
302- using ( var importForm = new ImportForm ( libraries , importFunction ) )
303- {
304- importForm . Show ( ) ;
305- // The form will handle success messages and opening Calibre
306- }
318+ var importForm = new ImportForm ( libraries , importFunction ) ;
319+ importForm . ShowDialog ( ) ;
320+
307321 }
308322 else
309323 {
@@ -386,7 +400,11 @@ private bool ImportSingleFile(string libraryPath, string filePath)
386400 process . WaitForExit ( ) ;
387401
388402 Logger . LogThis ( $ "Process output: { output } ", true ) ;
389- Logger . LogThis ( $ "Process error: { error } ", true ) ;
403+ // Only log error output if it's not empty
404+ if ( ! string . IsNullOrWhiteSpace ( error ) )
405+ {
406+ Logger . LogThis ( $ "Process error: { error } ", true ) ;
407+ }
390408
391409 if ( process . ExitCode == 0 )
392410 {
@@ -537,45 +555,18 @@ int CalculateProgress(int current) =>
537555 }
538556 }
539557
540- // Load ebook extensions supported by Calibre from Registry
558+ // Call on the SupportedFileTypes class
559+ // In order to rertrieve the list of supported file extensions
541560 private void LoadSupportedExtensions ( )
542561 {
543- using ( var key = Registry . LocalMachine . OpenSubKey ( @"SOFTWARE\calibre\calibre64bit\Capabilities\FileAssociations" ) )
544- {
545- if ( key != null )
546- {
547- _supportedExtensions = key . GetValueNames ( ) . ToList ( ) ;
548- return ;
549- }
550- }
562+ _supportedExtensions . Clear ( ) ;
551563
552- _supportedExtensions = new List < string >
553- {
554- ".epub" , ".pdf" , ".mobi" , ".azw" , ".azw3" , ".fb2" , ".djvu" ,
555- ".lrf" , ".rtf" , ".txt" , ".doc" , ".docx" , ".odt" , ".htm" , ".html" ,
556- ".cbz" , ".cbr" , ".pdb" , ".snb" , ".tcr" , ".zip" , ".rar"
557- } ;
558- }
564+ // Use the centralized file extensions manager with HashSet for performance
565+ _supportedExtensions = SupportedFileTypes . GetExtensionsHashSet ( ) ;
559566
560- // Get the list of supported eBook file extensions
561- private static List < string > GetFileExtensions ( )
562- {
563- var extensions = new List < string > ( ) ;
564- using ( var key = Registry . LocalMachine . OpenSubKey ( @"SOFTWARE\calibre\calibre64bit\Capabilities\FileAssociations" ) )
565- {
566- if ( key != null )
567- {
568- extensions = key . GetValueNames ( ) . ToList ( ) ;
569- return extensions ;
570- }
571- }
572-
573- return new List < string >
574- {
575- ".epub" , ".pdf" , ".mobi" , ".azw" , ".azw3" , ".fb2" , ".djvu" ,
576- ".lrf" , ".rtf" , ".txt" , ".doc" , ".docx" , ".odt" , ".htm" , ".html" ,
577- ".cbz" , ".cbr" , ".pdb" , ".snb" , ".tcr" , ".zip" , ".rar"
578- } ;
567+ Logger . LogThis ( $ "Loaded { _supportedExtensions . Count } supported extensions from " +
568+ ( _supportedExtensions . Count > SupportedFileTypes . DefaultExtensions . Length ?
569+ "registry." : "default list." ) , true ) ;
579570 }
580571
581572 // Check if any Calibre-related process is running
@@ -584,8 +575,7 @@ private bool IsCalibreRunning()
584575 return CalibreProcesses . Any ( processName => Process . GetProcessesByName ( processName ) . Any ( ) ) ;
585576 }
586577
587- // Attempts to terminate all Calibre-related processes
588- // Prompts for user confirmation unless auto-kill is enabled
578+ // Attempts to terminate all Calibre-related processes, if any.
589579 private void KillCalibre ( )
590580 {
591581 var runningProcesses = CalibreProcesses
@@ -595,20 +585,21 @@ private void KillCalibre()
595585 if ( runningProcesses . Any ( ) )
596586 {
597587 var processNames = runningProcesses . Select ( p => p . ProcessName ) . Distinct ( ) ;
598- var warningMessage = $ " { ResourceStrings . CalibreProcessesRunningRes } \n \n { string . Join ( "\n " , processNames ) } \n \n { ResourceStrings . DoYouWantToProceedRes } " ;
588+ Logger . LogThis ( $ "Terminating Calibre processes: { string . Join ( ", " , processNames ) } " , true ) ;
599589
600- if ( MessageBox . Show ( warningMessage , ResourceStrings . CalibreRunning2Res , MessageBoxButtons . YesNo , MessageBoxIcon . Warning ) == DialogResult . Yes )
590+ foreach ( var process in runningProcesses )
601591 {
602- foreach ( var process in runningProcesses )
592+ try
603593 {
604594 process . Kill ( ) ;
595+ process . WaitForExit ( 1000 ) ; // Wait up to 1 second for the process to exit
596+ }
597+ catch ( Exception ex )
598+ {
599+ Logger . LogThis ( $ "Error killing process { process . ProcessName } : { ex . Message } ", true ) ;
605600 }
606- Logger . LogThis ( "Calibre-related processes were running and have been terminated." , true ) ;
607- }
608- else
609- {
610- Logger . LogThis ( "User chose not to terminate Calibre-related processes." , true ) ;
611601 }
602+ Logger . LogThis ( "Calibre-related processes have been terminated." , true ) ;
612603 }
613604 else
614605 {
@@ -628,9 +619,14 @@ public void ShowSettingsForm()
628619 try
629620 {
630621 Logger . LogThis ( "Attempting to show Settings form." , true ) ;
622+
623+ // Make sure culture is set correctly before showing the form
624+ CultureManager . SetApplicationCulture ( ) ;
625+
631626 var form = new SettingsForm ( ) ;
632627 form . StartPosition = FormStartPosition . CenterScreen ;
633628 form . Show ( ) ;
629+
634630 Logger . LogThis ( "Settings form displayed successfully." , true ) ;
635631 }
636632 catch ( Exception ex )
@@ -666,8 +662,11 @@ public static void Register(Type t)
666662 {
667663 try
668664 {
665+ // Ensure culture is set correctly before displaying any messages
666+ CultureManager . SetApplicationCulture ( ) ;
667+
669668 Logger . LogThis ( "Registering shell extension..." , true ) ;
670- KeyRegistryExtensions . RegisterExtension ( t . GUID , "ImportToCalibre" , GetFileExtensions ( ) ) ;
669+ KeyRegistryExtensions . RegisterExtension ( t . GUID , "ImportToCalibre" , SupportedFileTypes . GetExtensions ( ) ) ;
671670 Logger . LogThis ( "Shell extension registered successfully." , true ) ;
672671 }
673672 catch ( Exception ex )
@@ -683,27 +682,30 @@ public static void Unregister(Type t)
683682 {
684683 try
685684 {
685+ // Ensure culture is set correctly before displaying any messages
686+ CultureManager . SetApplicationCulture ( ) ;
687+
686688 Logger . LogThis ( "Unregistering shell extension..." , true ) ;
687689
688- KeyRegistryExtensions . UnregisterExtension ( t . GUID , GetFileExtensions ( ) ) ;
690+ KeyRegistryExtensions . UnregisterExtension ( t . GUID , SupportedFileTypes . GetExtensions ( ) ) ;
689691 Logger . LogThis ( "Shell extension unregistered successfully." , true ) ;
690692 }
691693 catch ( Exception ex )
692694 {
693695 Logger . LogThis ( $ "Unregistration failed: { ex . Message } ") ;
694696 }
695697 }
696-
697698 }
698699
699- // Class to represent Calibre library
700+ // Class to represent Calibre library
700701 public class CalibreLibrary
701702 {
702703 public string Path { get ; set ; }
703704 public string Name { get ; set ; }
704705 }
705706
706- // Class to manage registry keys upon registration and unregistration
707+ // Class to manage registry keys upon registration and unregistration.
708+ // Called by [ComRegisterFunction] and [ComUnregisterFunction] in the main class.
707709 public static class KeyRegistryExtensions
708710 {
709711 public static void RegisterExtension ( Guid guid , string menuName , List < string > extensions )
0 commit comments