Process does not terminate - Why?

  • Thread starter Thread starter Shashi
  • Start date Start date
S

Shashi

Hi,

The following program attempts to print a pdf file and then delete it.
I am using Process.start with the command
(AcroRd32.exe /t "pdf-file-name" "printer-name") to do it.
The file gets printed. But, the process does not terminate. I have
called the WaitForExit() method after Process.Start and it blocks the
execution infinitely. If I remove the WaitForExit method, I cannot
delete the file because I get an error message saying the file is in
use by another process ("AcroRd32.exe").

One option is to use WaitForExit(20000) and wait for 20 seconds before
killing the process using the Kill() method but that would result in
each print job taking atleast 20 seconds.

Here is what I have.

Any ideas/suggestions? Thanks in Advance.


' This is just the relevant part of the code

Dim printedFileName As String
Dim printedFileInfo As FileInfo

printedFileName = "c:\myfile.pdf"
printedFileInfo = New FileInfo(printedFileName)

' Print the first file in the queue
startProcess("AcroRd32.exe", " /t " + printedFileName + "
\\IAN-P4\HP3330", dirName)
Console.Writeline("Printed file :" + printedFileName)

Try
' Delete the file
printedFileInfo.Delete()

' File successfully deleted
Console.WriteLine("Deleted file :" + printedFileName)
Catch ex As Exception
Console.WriteLine("Could not delete the file " +
printedFileName + vbCrLf + ex.Message + vbCrLf + ex.StackTrace)
End Try


Public Function startProcess(ByVal strCommand As String, _
ByVal strArguments As String, _
ByVal strWd As String)

Dim psi As New ProcessStartInfo

' Initialize the ProcessStartInfo structure
psi.FileName = strCommand
psi.Arguments = strArguments
psi.WorkingDirectory = strWd
psi.RedirectStandardInput = False
psi.RedirectStandardOutput = False
psi.UseShellExecute = False
Dim proc As New Process

' Start the process
proc = proc.Start(psi)

proc.WaitForExit()

End Function
 
I encountered this a year ago, in the exact same situation you are in. While
Acrobat does accept command line parameters, they are, according to Adobe,
unsupported. I never found a way to reliable close the acrobat process when
accessed by command line. I eventually switched to sending DDE messages to
acrobat, as this allowed me more flexibility, and had a better end result.


Here is a sample of what I ended up doing (in VB6 unfortunately), the method
you will want to start with is PrintPDF (near the bottom of code listing)
PS, I Cheated and used a const named DEFAULT_ACROBAT_PATH (not declared
below) for the path to the executable, the proper method would be to use the
registry functions to find the app used to handle pdf files.

Private Declare Function DdeClientTransaction Lib "user32" (ByVal pData As
Long, ByVal cbData As Long, ByVal hConv As Long, ByVal hszItem As Long,
ByVal wFmt As Long, ByVal wType As Long, ByVal dwTimeout As Long, pdwResult
As Long) As Long
Private Declare Function DdeCreateDataHandle Lib "user32" (ByVal idInst As
Long, pSrc As Byte, ByVal cb As Long, ByVal cbOff As Long, ByVal hszItem As
Long, ByVal wFmt As Long, ByVal afCmd As Long) As Long
Private Declare Function DdeDisconnect Lib "user32" (ByVal hConv As Long) As
Long
Private Declare Function DdeInitialize Lib "user32" Alias "DdeInitializeA"
(pidInst As Long, ByVal pfnCallback As Long, ByVal afCmd As Long, ByVal
ulRes As Long) As Integer
Private Declare Function DdeCreateStringHandle Lib "user32" Alias
"DdeCreateStringHandleA" (ByVal idInst As Long, ByVal psz As String, ByVal
iCodePage As Long) As Long
Private Declare Function DdeConnect Lib "user32" (ByVal idInst As Long,
ByVal hszService As Long, ByVal hszTopic As Long, pCC As Any) As Long
Private Declare Function DdeFreeStringHandle Lib "user32" (ByVal idInst As
Long, ByVal hsz As Long) As Long
Private Declare Function DdeUninitialize Lib "user32" (ByVal idInst As Long)
As Long

Public Enum ExDdeErrors
ExDdeError_Success = 0
ExDdeError_InitFailed = 1
ExDdeError_ConnectFailed = 2
ExDdeError_GetStringHandleFailed = 3
ExDdeError_GetDataHandleFailed = 4
ExDdeError_ExecuteFailed = 5
ExDdeError_Unspecified = 99
End Enum

Private Const CBF_FAIL_ALLSVRXACTIONS = &H3F000
Private Const DMLERR_NO_ERROR = 0 ' must be 0
Private Const XCLASS_FLAGS = &H4000
Private Const XTYP_EXECUTE = (&H50 Or XCLASS_FLAGS)


Public Function SendDDEMessage(ByVal DDEServer As String, ByVal DDETopic As
String, ByVal DDECommand As String, Optional ByVal DDETimeOut As Long =
1000) As ExDdeErrors
Dim ui As Long
Dim hszServer As Long
Dim hszTopic As Long
Dim idInst As Long
Dim hConv As Long
Dim hExecData As Long
Dim CommandArray(0 To 1024) As Byte
Dim I As Integer

For I = 0 To Len(DDECommand) - 1
CommandArray(I) = Asc(Mid(DDECommand, I + 1))
Next I

SendDDEMessage = ExDdeError_Success

ui = DdeInitialize(idInst, AddressOf DDECallback,
CBF_FAIL_ALLSVRXACTIONS, 0)
If ui <> DMLERR_NO_ERROR Then
SendDDEMessage = ExDdeError_InitFailed
GoTo CleanUp
End If

hszServer = DdeCreateStringHandle(idInst, DDEServer, CP_WINANSI)
If hszServer = 0 Then
SendDDEMessage = ExDdeError_GetStringHandleFailed
GoTo CleanUp
End If

hszTopic = DdeCreateStringHandle(idInst, DDETopic, CP_WINANSI)
If hszTopic = 0 Then
SendDDEMessage = ExDdeError_GetStringHandleFailed
GoTo CleanUp
End If

hConv = DdeConnect(idInst, hszServer, hszTopic, ByVal 0&)
If hConv = 0 Then
SendDDEMessage = ExDdeError_ConnectFailed
GoTo CleanUp
End If

Call DdeFreeStringHandle(idInst, hszServer)
Call DdeFreeStringHandle(idInst, hszTopic)

hExecData = DdeCreateDataHandle(idInst, CommandArray(0), Len(DDECommand)
+ 1, 0, 0, 0, 0)
If hExecData = 0 Then
SendDDEMessage = ExDdeError_GetDataHandleFailed
GoTo CleanUp
End If

If DdeClientTransaction(hExecData, -1, hConv, 0, 0, XTYP_EXECUTE,
DDETimeOut, 0) = 0 Then
SendDDEMessage = ExDdeError_ExecuteFailed
GoTo CleanUp
End If

CleanUp:
If hConv Then DdeDisconnect (hConv)
If idInst Then DdeUninitialize (idInst)
End Function

Public Function DDECallback(ByVal uType As Long _
, ByVal uFmt As Long _
, ByVal hConv As Long _
, ByVal hszTopic As Long _
, ByVal hszItem As Long _
, ByVal hData As Long _
, ByVal dwData1 As Long _
, ByVal dwData2 As Long) As Long
End Function

Public Sub PrintPDF(ByVal PDFFileName As String, _
ByVal DeviceName As String, _
ByVal DriverName As String, _
ByVal PortName As String)
Dim Q As String
Dim cmd As String
Dim ServerTaskID As Double
Dim AcrobatLocation As String

On Error Resume Next

Q = Chr(34) 'Quotation mark

If Trim(PDFFileName) = "" Then 'There is no document to print
Exit Sub
End If

If SendDDEMessage("acroview", "control", "", 1000) Then 'Assume an error
means we were unable to connect to our dde server... so start a new one
AcrobatLocation = FindPDFExecutable()
If AcrobatLocation = "" Then AcrobatLocation = DEFAULT_ACROBAT_PATH
ServerTaskID = Shell(AcrobatLocation, vbHide)
End If

cmd = "" 'Make a DDE command list
cmd = cmd & "[FilePrintTo(" & Q & PDFFileName & Q & ", " & Q &
DeviceName & Q & ", " & Q & DriverName & Q & ", " & Q & PortName & Q & ")]"
'Print our document to the specified printer
If ServerTaskID > 0 Then cmd = cmd & "[AppExit()]" 'if we had to make an
acrobat, then ask it to exit

Call SendDDEMessage("acroview", "control", cmd, 1000)

End Sub


GL
 
the waitforexit process is waiting for the process housing the command
prompt to go away. It won't. just close the process by calling proc.Close()
and then you can do your clean up after that if you need to.
 
Back
Top