Reputation: 902
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
Upvotes: 1
Views: 6179
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
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
Reputation: 25053
Check the MainWindowTitle of each Acrobat process - the one you want will begin with the name of the temp file.
Upvotes: 1
Reputation: 3804
You might take a look at the Process's MainWindowHandle property.
Upvotes: 0