Satheesh
Satheesh

Reputation: 902

How to identify and close an instance of opened application in C#

I just load a PDF file in a WinForm using WebBrowser control. I have a PDF byte array and I used to write this in temporary folder of client machine when the user clicks on print preview in my application.

After preview when the user closes the form I need to delete the file. Before deleting I need to close the instance of Adobe Reader that was opened for preview.

I tried getting a list of processes using

Process[] processes = Process.GetProcessesByName("AcroRd32");

I can kill the process by this means and delete the file from temporary folder. Here comes the actual problem. Suppose the user already opened a PDF file for his own purpose then by finding the running instances and by closing them I will close his reader too.

Is there any way to find the instance of Adobe reader which is opened by my application. I need to check for Adobe reader only. Not any other.

UPDATE

I have opened adbobe reader manually which has filename or MainWindowTitle as Magazine.pdf first.Then i opened adobe reader by webbrowser control in my application.But it has MainWindowTitle as Empty.Also there shoul be two intance of adobe reader but in taskmanager it shows four instance and of them only one has MainWindowTitle as Magazine.pdf See the below images for reference

Four Process of reader

Last process with MainWindowTitle

Upvotes: 1

Views: 6179

Answers (4)

Filippo Bottega
Filippo Bottega

Reputation: 109

If you want to delete a PDF file opened in WebBrowser control you have to use this code:

WebBrowser.Navigate(YourPdfPath)
...
WebBrowser.Navigate("about:blank")
Application.DoEvents()
Dim millisecondsTimeout = 5000
While True
  Try
    File.Delete(YourPdfPath)
    Exit While 
  Catch ex As IOException
    If millisecondsTimeout < 0 Then Exit Sub
    millisecondsTimeout -= 100
    Thread.Sleep(100)
  End Try
End While

UPDATE:

I found an extension method to kill a children process of a process:

  <Extension>
  Public Sub KillChildren(process As Process, Optional processNameToKill As String = "", Optional recursive As Boolean = False)
      Static ProcessIDStack As List(Of Integer) = New List(Of Integer)
      If ProcessIDStack.Contains(process.Id) Then
          Exit Sub
      Else
          ProcessIDStack.Add(process.Id)
      End If

      Dim searcher = New ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" & process.Id) 'MLHIDE
      Dim moc As ManagementObjectCollection = searcher.Get
      For Each mo As ManagementObject In moc
          Try
              Dim ChildProcess = process.GetProcessById(Convert.ToInt32(mo("ProcessID"))) 'MLHIDE
              If recursive Then
                  ChildProcess.KillChildren(processNameToKill, recursive)
              End If
              If (Not ChildProcess.HasExited) AndAlso (processNameToKill = String.Empty OrElse ChildProcess.ProcessName = processNameToKill) Then
                  ChildProcess.Kill()
                  ChildProcess.WaitForExit(1000)
              End If
          Catch ex As ArgumentException
              ' process already exited 
          Catch ex As InvalidOperationException
              ' process already exited 
          Catch ex As ComponentModel.Win32Exception
              ' process already exited 
          End Try
      Next

      ProcessIDStack.Remove(process.Id)
  End Sub

...
    WebBrowser.Navigate("about:blank")
    Process.GetCurrentProcess.KillChildren("AcroRd32", True)
    Application.DoEvents()
...

I'm searching for a better way to check if a file is not in use avoiding to sleep inside a loop (Andrew Barber correctly says that is not a good code...) but I didn't found anything else, sorry...

(Thanks to Andrew Barber)

Upvotes: 0

jcibar
jcibar

Reputation: 275

I don't open the PDF using WebBrowser, but I have a similar problem to yours when I use Process.MainWindowTitle(). It seems that it only returns a value different from "" for the last opened instance of Acrobat.

The C# code I use to look for all processes of Acrobat is the following:

  Process[] myProcess = Process.GetProcessesByName("AcroRd32");
  for (int i = 0; i < procesoProg.Length; i++)
  {
    if (myProcess[i].MainWindowTitle.Contains("MyTitle"))
    {
      myProcess[i].CloseMainWindow();
      Thread.Sleep(300);
    }
  }

I tried using Process.Kill() instead of Process.MainWindow(), but it closes all instances of Acrobat, not only the one I want.

If you only want to close the document you opened from your application, you can store the process when you launch the PDF, and use CloseMainWindow() when you want to close it:

    private static Process myProcess = null;

    public void OpenPDF()
    {
        myProcess = new Process();
        myProcess.StartInfo.FileName = "AcroRd32.exe";
        myProcess.StartInfo.Arguments = " /n /A \"pagemode=bookmarks&nameddest=" + strND + "\" \"" + strPath + "\"";
        myProcess.Start();
    }

    public void ClosePDF()
    {
        // If there is 
        if (myProcess!= null)
        {
            myProcess.CloseMainWindow();
            Thread.Sleep(500);
        }
    }

I hope this code can help you.

Upvotes: 0

egrunin
egrunin

Reputation: 25053

Check the MainWindowTitle of each Acrobat process - the one you want will begin with the name of the temp file.

Upvotes: 1

animaonline
animaonline

Reputation: 3804

You might take a look at the Process's MainWindowHandle property.

Upvotes: 0

Related Questions