private void HotKeyChanged( HotKeyData hkData, HotKey actualBefore, HotKey actualAfter) { if (actualBefore != null) { _hotKeyDataMap.TryRemove(actualBefore, out _); _userHotKeyMap.Reverse.Remove(actualBefore); if (hkData.IsGlobal) { _kbHookSvc.UnregisterHotKey(actualBefore); } } if (actualAfter != null) { if (_hotKeyDataMap.ContainsKey(actualAfter)) { throw new ArgumentException("Hotkey already used"); } // Remap hotkey _hotKeyDataMap[actualAfter] = hkData; // Remove ghost user hotkey if necessary, update hotkey _userHotKeyMap.Reverse.Remove(actualAfter); _userHotKeyMap[hkData.Id] = actualAfter; if (hkData.IsGlobal) { _kbHookSvc.RegisterHotKey(actualAfter, hkData.Callback); } } LogTo.Debug($"Hotkey {hkData.Id} is now bound to {actualAfter}."); _delayedTask.Trigger(1000); }
private void OnXamlChanged(XamlLayout xamlLayout, string before, string after) { _parseXamlTask.Trigger(500); }
private void PDFWindow_SizeChanged(object sender, SizeChangedEventArgs e) { _saveConfigDelayed.Trigger(ResizeSaveDelay); }
/// <summary> /// Start plugin <paramref name="pluginInstance"/> /// </summary> /// <param name="pluginInstance">The plugin to start</param> /// <param name="attachDebugger">Whether to attach the debugger to the plugin host on start</param> /// <returns>Success of operation</returns> public async Task <bool> StartPlugin(TPluginInstance pluginInstance, bool attachDebugger = false) { var pluginPackage = pluginInstance.Package; var packageName = pluginPackage.Id; try { // Make sure the plugin is stopped and can be started using (await pluginInstance.Lock.LockAsync()) { if (pluginInstance.Status != PluginStatus.Stopped) { return(true); } if (CanPluginStartOrPause(pluginInstance) == false) { throw new InvalidOperationException("A plugin with the same Package name is already running"); } OnPluginStarting(pluginInstance); } // Determine the plugin and its dependencies assemblies' information. This includes the assembly which contains the PluginHost type var packageRootFolder = Locations.PluginPackageDir.FullPathWin; var pluginAndDependenciesAssembliesPath = new List <string>(); var pluginHostTypeAssemblyName = GetPluginHostTypeAssemblyName(pluginInstance); var pluginHostTypeMinAssemblyVersion = GetPluginHostTypeAssemblyMinimumVersion(pluginInstance); if (pluginInstance.IsDevelopment == false) { using (await PMLock.ReaderLockAsync()) { var pluginAndDependenciesPackageFilePaths = new List <FilePath>(); var pluginPkg = PackageManager.FindInstalledPluginById(packageName); if (pluginPkg == null) { throw new InvalidOperationException($"Cannot find requested plugin package {packageName}"); } PackageManager.GetInstalledPluginAssembliesFilePath( pluginPkg.Identity, out var tmpPluginAssemblies, out var tmpDependenciesAssemblies); pluginAndDependenciesPackageFilePaths.AddRange(tmpPluginAssemblies); pluginAndDependenciesPackageFilePaths.AddRange(tmpDependenciesAssemblies); var pluginHostTypeAssemblyPath = pluginAndDependenciesPackageFilePaths.FirstOrDefault(a => a.FileNameWithoutExtension == pluginHostTypeAssemblyName); if (pluginHostTypeAssemblyPath == null) { OnPluginStartFailed( pluginInstance, PluginStartFailure.InteropAssemblyNotFound, $"{pluginInstance} failed to start: Unable to find the PluginHost type's \"{pluginHostTypeAssemblyName}\" dependency assembly's package"); return(false); } // Make sure the assembly version is equal or higher to the required minimum version if (pluginHostTypeMinAssemblyVersion != null) { var pluginHostTypeAssemblyInfo = FileVersionInfo.GetVersionInfo(pluginHostTypeAssemblyPath.FullPath); if (NuGetVersion.TryParse(pluginHostTypeAssemblyInfo.ProductVersion, out var pluginHostTypeAssemblyVersion) == false) { OnPluginStartFailed( pluginInstance, PluginStartFailure.InteropAssemblyNotFound, $"{pluginInstance} failed to start: Invalid interop version '{pluginHostTypeAssemblyInfo.ProductVersion}'"); return(false); } if (pluginHostTypeAssemblyVersion < pluginHostTypeMinAssemblyVersion) { OnPluginStartFailed( pluginInstance, PluginStartFailure.InteropAssemblyNotFound, $"{pluginInstance} failed to start: Outdated interop version '{pluginHostTypeAssemblyInfo.ProductVersion}'. Either update the plugin, downgrade SMA, or ask the plugin developer to publish a new version to fix the issue."); return(false); } } foreach (var pkgFilePath in pluginAndDependenciesPackageFilePaths) { string pkgRelativeFilePath = pkgFilePath.FullPathWin.After(packageRootFolder); if (string.IsNullOrWhiteSpace(pkgRelativeFilePath)) { LogTo.Warning( $"Package {pkgFilePath} isn't located underneath the package folder {packageRootFolder}. Skipping, this might cause issues with the plugin"); continue; } pluginAndDependenciesAssembliesPath.Add(pkgRelativeFilePath); } } } // Build command line var cmdLineParams = new PluginHostParameters { PackageRootFolder = packageRootFolder, PluginAndDependenciesAssembliesPath = string.Join(";", pluginAndDependenciesAssembliesPath), PluginHostTypeAssemblyName = pluginHostTypeAssemblyName, PluginHostTypeQualifiedName = GetPluginHostTypeQualifiedName(pluginInstance), PackageName = packageName, HomePath = pluginPackage.HomeDir.FullPath, SessionString = pluginInstance.Guid.ToString(), ChannelName = IpcServerChannelName, ManagerProcessId = Process.GetCurrentProcess().Id, IsDevelopment = pluginInstance.IsDevelopment, AttachDebugger = attachDebugger }; // Build process parameters var processArgs = Parser.Default.FormatCommandLine(cmdLineParams); pluginInstance.Process = new Process { StartInfo = new ProcessStartInfo( Locations.PluginHostExeFile.FullPath, processArgs) { UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, }, EnableRaisingEvents = true, }; // Setup error output logging { var pluginStr = pluginInstance.ToString(); // Avoids keeping a pointer to PluginInstance around StringBuilder pluginErrBuilder = new StringBuilder(); void LogPluginErrorOutput() { if (string.IsNullOrWhiteSpace(pluginErrBuilder.ToString())) { return; } lock (pluginErrBuilder) { LogTo.Warning($"{pluginStr} standard error output:\n--------------------------------------------\n{pluginErrBuilder.ToString().Trim()}\n--------------------------------------------"); pluginErrBuilder.Clear(); } } DelayedTask logTask = new DelayedTask(LogPluginErrorOutput, 200); void AggregatePluginErrorOutput(object _, DataReceivedEventArgs e) { lock (pluginErrBuilder) { pluginErrBuilder.AppendLine(e.Data); logTask.Trigger(750); } } pluginInstance.Process.ErrorDataReceived += AggregatePluginErrorOutput; } // Start plugin if (pluginInstance.Process.Start() == false) { OnPluginStartFailed( pluginInstance, PluginStartFailure.ProcessDidNotStart, $"{pluginInstance} failed to start: Failed to start process"); return(false); } OnPluginStarted(pluginInstance); pluginInstance.Process.EnableRaisingEvents = true; pluginInstance.Process.BeginErrorReadLine(); pluginInstance.Process.Exited += (o, e) => { UISynchronizationContext.Post(_ => { using (pluginInstance.Lock.Lock()) OnPluginStopped(pluginInstance); }, null); }; var connected = await pluginInstance.ConnectedEvent.WaitAsync(PluginConnectTimeout); if (connected && pluginInstance.Status == PluginStatus.Connected) { return(true); } if (pluginInstance.Status == PluginStatus.Stopped) { OnPluginStartFailed( pluginInstance, connected ? PluginStartFailure.ProcessDidNotConnect : PluginStartFailure.Unknown, $"{pluginInstance} failed to start: process stopped unexpectedly."); pluginInstance.ConnectedEvent.Set(); return(false); } } catch (Exception ex) { LogTo.Error(ex, $"{pluginInstance} failed to start: An unknown exception occured during startup"); return(false); } try { LogTo.Warning( $"{pluginInstance.ToString().CapitalizeFirst()} failed to connect under {PluginConnectTimeout}ms. Attempting to kill process"); pluginInstance.Process.Refresh(); if (pluginInstance.Process.HasExited) { LogTo.Warning($"{pluginInstance.ToString().CapitalizeFirst()} has already exited"); return(false); } pluginInstance.Process.Kill(); } catch (RemotingException ex) { LogTo.Warning(ex, $"StartPlugin '{pluginInstance} failed."); } catch (Exception ex) { LogTo.Error(ex, $"An error occured while starting {pluginInstance}"); } finally { try { using (await pluginInstance.Lock.LockAsync()) OnPluginStopped(pluginInstance); } catch (Exception ex) { LogTo.Error(ex, "Exception thrown while calling OnPluginStopped"); } } return(false); }