Skip to content

Kill SumatraPDF process on preview window close - #7

Merged
emako merged 3 commits into
masterfrom
copilot/fix-sumatra-pdf-background-process
Mar 25, 2026
Merged

emako merged 3 commits into
masterfrom
copilot/fix-sumatra-pdf-background-process

Conversation

Copilot AI commented Mar 24, 2026 •

Copy link
Copy Markdown
Contributor

Each preview open spawned a new SumatraPDF.exe that was never terminated — Dispose() only sent WM_DESTROY to the window but never killed the backing process.

Changes

  • SumatraPDFControl.Designer.cs — Add SumatraProcess.Kill() to Dispose(), guarded by HasExited check with specific exception handling (InvalidOperationException, Win32Exception):

    if (SumatraProcess != null && !SumatraProcess.HasExited)
        SumatraProcess.Kill();
  • SumatraPanel.cs — Store SumatraPDFControl as a field and wire up Unloaded to call Dispose() when the panel leaves the visual tree (window close / preview change). Also dispose any existing instance at the top of PreviewFile() to prevent leaks on re-entrant calls.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • www.oasis-open.org
    • Triggering command: /opt/hostedtoolcache/CodeQL/2.24.3/x64/codeql/tools/linux64/java/bin/java /opt/hostedtoolcache/CodeQL/2.24.3/x64/codeql/tools/linux64/java/bin/java -jar /opt/hostedtoolcache/CodeQL/2.24.3/x64/codeql/xml/tools/xml-extractor.jar --fileList=/tmp/codeql-scratch-b692a6f0cd709e3b/dbs/csharp/working/files-to-index16873092065553289612.list --sourceArchiveDir=/tmp/codeql-scratch-b692a6f0cd709e3b/dbs/csharp/src --outputDir=/tmp/codeql-scratch-b692a6f0cd709e3b/dbs/csharp/trap/csharp (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>SumatraPDF still run in background when preview window closed</issue_title>
<issue_description>When previewing same .cbz file 3 times (open preview window then close), SumatraPDF still run in background and increase every time previewing

Why not reuse already run in background SumatraPDF or kill process every time preview window closed?

Image

<agent_instructions>帮我修复问题,窗口关闭的时候把sumatrapdf.exe进程也关闭。</agent_instructions>

Comments on the Issue (you are @copilot in this section)


⌨️ Start Copilot coding agent tasks without leaving your editor — available in VS Code, Visual Studio, JetBrains IDEs and Eclipse.

Copilot AI changed the title [WIP] Fix SumatraPDF running in background after closing preview window Kill SumatraPDF process on preview window close Mar 24, 2026
Copilot AI requested a review from emako March 24, 2026 17:29
@emako
emako marked this pull request as ready for review March 25, 2026 15:17
Copilot AI review requested due to automatic review settings March 25, 2026 15:17
@emako
emako merged commit d991c65 into master Mar 25, 2026
1 check passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Prevents leaked/background SumatraPDF.exe instances by ensuring the embedded Sumatra process is terminated when the preview control/panel is disposed (e.g., preview window close or preview refresh).

Changes:

  • Dispose the hosted SumatraPDFControl when SumatraPanel unloads and before creating a new preview control.
  • Extend SumatraPDFControl.Dispose() to kill the backing SumatraPDF.exe process (with guarded checks and exception handling).

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 4 comments.

File Description
QuickLook.Plugin.SumatraPDFReader/SumatraPanel.cs Persists the hosted control as a field, disposes it on Unloaded, and disposes prior instances on repeated PreviewFile() calls.
QuickLook.Plugin.SumatraPDFReader/SumatraPDFControl.Designer.cs Adds process termination logic to Dispose() so SumatraPDF.exe doesn’t remain running after the preview is closed.
Files not reviewed (1)
  • QuickLook.Plugin.SumatraPDFReader/SumatraPDFControl.Designer.cs: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}

private void SumatraPanel_Unloaded(object sender, RoutedEventArgs e)
{

Copilot AI Mar 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SumatraPanel_Unloaded disposes the hosted WinForms control but leaves it assigned to presenter.Child. That can leave WindowsFormsHost holding a reference to a disposed control. Clear/detach the child (e.g., set presenter.Child = null) before/when disposing so the host doesn't reference a disposed instance.

Suggested change
{
{
presenter.Child = null;

Copilot uses AI. Check for mistakes.
Comment on lines +48 to 50
_sumatraPDFControl?.Dispose();
_sumatraPDFControl = new SumatraPDFControl();

Copilot AI Mar 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In PreviewFile, the existing control is disposed while it may still be attached as presenter.Child until the end of the method. Detach the previous child from presenter first (or set presenter.Child = null) before disposing it to avoid the host interacting with a disposed WinForms control during layout/handle recreation.

Copilot uses AI. Check for mistakes.
Comment on lines +40 to +54
try
{
if (SumatraProcess != null && !SumatraProcess.HasExited)
{
SumatraProcess.Kill();
}
}
catch (InvalidOperationException)
{
// Process may have already exited
}
catch (System.ComponentModel.Win32Exception)
{
// Access denied or process could not be terminated
}

Copilot AI Mar 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new SumatraProcess termination runs regardless of the disposing flag. In the finalizer path (disposing == false), accessing managed objects like Process is unsafe; this should be guarded by if (disposing) (or equivalent) so process cleanup only happens on explicit dispose.

Suggested change
try
{
if (SumatraProcess != null && !SumatraProcess.HasExited)
{
SumatraProcess.Kill();
}
}
catch (InvalidOperationException)
{
// Process may have already exited
}
catch (System.ComponentModel.Win32Exception)
{
// Access denied or process could not be terminated
}
if (disposing)
{
try
{
if (SumatraProcess != null && !SumatraProcess.HasExited)
{
SumatraProcess.Kill();
}
}
catch (InvalidOperationException)
{
// Process may have already exited
}
catch (System.ComponentModel.Win32Exception)
{
// Access denied or process could not be terminated
}
}

Copilot uses AI. Check for mistakes.
catch (System.ComponentModel.Win32Exception)
{
// Access denied or process could not be terminated
}

Copilot AI Mar 25, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After calling Kill(), the Process object itself is still kept alive and its OS handle isn’t released until GC. Consider disposing SumatraProcess (and setting the field to null) in Dispose() (ideally in a finally) to avoid leaking a process handle across repeated previews.

Suggested change
}
}
finally
{
if (SumatraProcess != null)
{
SumatraProcess.Dispose();
SumatraProcess = null;
}
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SumatraPDF still run in background when preview window closed

3 participants