how to kill word session forcibly...

V

Veena

Hi,
We have a VB program which opens word documents and data source and
performs mailmerge programmatically.
Whenever there is a problem with mailmerge (eg: some mergefields are
missing) the word session hangs.
Can you please tell me a method wherein i can forcibly kill the word
session. I tried calling the Quit method on WordApplication object and
close method on the word docs which are open. Both the statements hang
as word itself has hanged.
How do i forcible kill the word session programmatically ....
Obviously, error traping to avoid the problem would be the best
solution, but we are catering to a generic solution for
troubleshooting.
We are using VB6 with word 2000

Any help would be greatly appreciated!!

Thanks & Regards,
Veena.
 
H

Harold

This VB6 sample will kill instances of Word.
To test the code sample you will need to open a new VB6 project with a Form
and 2 commandbuttons
Option Explicit

Private Declare Function TerminateProcess Lib "kernel32" ( _
ByVal hProcess As Long, ByVal uExitCode As Long) As Long

Private Declare Function Process32First Lib "kernel32" ( _
ByVal hSnapshot As Long, lppe As PROCESSENTRY32) As Long

Private Declare Function Process32Next Lib "kernel32" ( _
ByVal hSnapshot As Long, lppe As PROCESSENTRY32) As Long

Private Declare Function CloseHandle Lib "Kernel32.dll" _
(ByVal Handle As Long) As Long

Private Declare Function OpenProcess Lib "Kernel32.dll" _
(ByVal dwDesiredAccessas As Long, ByVal bInheritHandle As Long, _
ByVal dwProcId As Long) As Long

Private Declare Function EnumProcesses Lib "psapi.dll" _
(ByRef lpidProcess As Long, ByVal cb As Long, _
ByRef cbNeeded As Long) As Long

Private Declare Function GetModuleFileNameExA Lib "psapi.dll" _
(ByVal hProcess As Long, ByVal hModule As Long, _
ByVal ModuleName As String, ByVal nSize As Long) As Long

Private Declare Function EnumProcessModules Lib "psapi.dll" _
(ByVal hProcess As Long, ByRef lphModule As Long, _
ByVal cb As Long, ByRef cbNeeded As Long) As Long

Private Declare Function CreateToolhelp32Snapshot Lib "kernel32" ( _
ByVal dwFlags As Long, ByVal th32ProcessID As Long) As Long

Private Declare Function GetVersionExA Lib "kernel32" _
(lpVersionInformation As OSVERSIONINFO) As Integer

Private Type PROCESSENTRY32
dwSize As Long
cntUsage As Long
th32ProcessID As Long ' This process
th32DefaultHeapID As Long
th32ModuleID As Long ' Associated exe
cntThreads As Long
th32ParentProcessID As Long ' This process's parent process
pcPriClassBase As Long ' Base priority of process threads
dwFlags As Long
szExeFile As String * 260 ' MAX_PATH
End Type

Private Type OSVERSIONINFO
dwOSVersionInfoSize As Long
dwMajorVersion As Long
dwMinorVersion As Long
dwBuildNumber As Long
dwPlatformId As Long '1 = Windows 95.
'2 = Windows NT

szCSDVersion As String * 128
End Type

Private Const PROCESS_QUERY_INFORMATION = 1024
Private Const PROCESS_VM_READ = 16
Private Const MAX_PATH = 260
Private Const STANDARD_RIGHTS_REQUIRED = &HF0000
Private Const SYNCHRONIZE = &H100000
'STANDARD_RIGHTS_REQUIRED Or SYNCHRONIZE Or &HFFF
Private Const PROCESS_ALL_ACCESS = &H1F0FFF
Private Const TH32CS_SNAPPROCESS = &H2&
Private Const hNull = 0

Function StrZToStr(s As String) As String
StrZToStr = Left$(s, Len(s) - 1)
End Function

Private Function getVersion() As Long
Dim osinfo As OSVERSIONINFO
Dim retvalue As Integer
osinfo.dwOSVersionInfoSize = 148
osinfo.szCSDVersion = Space$(128)
retvalue = GetVersionExA(osinfo)
getVersion = osinfo.dwPlatformId
End Function

Private Sub TerminateWord()
Select Case getVersion()

Case 1 'Windows 95/98
Dim f As Long, sname As String
Dim hSnap As Long, proc As PROCESSENTRY32

'Take a snapshot of the running processes
hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
If hSnap = hNull Then Exit Sub

' Iterate through the processes
proc.dwSize = Len(proc)
f = Process32First(hSnap, proc)
Do While f
sname = StrZToStr(proc.szExeFile)
'If the EXE name contains "WinWord.exe", we've found an instance
of Word
If (InStr(1, LCase(sname), "winword.exe", vbTextCompare) > 0)
Then

'Confirm that we want to terminate it
If (MsgBox("Found an instance of Word. Are you sure you
want to Terminate it?", vbOKCancel) = vbOK) Then
Dim lretprocesshandle As Long
lretprocesshandle = OpenProcess(PROCESS_ALL_ACCESS,
True, _
proc.th32ProcessID)

TerminateProcess lretprocesshandle, -1
DoEvents
End If
End If
f = Process32Next(hSnap, proc)
Loop

Case 2 'Windows NT

Dim cb As Long
Dim cbNeeded As Long
Dim NumElements As Long
Dim ProcessIDs() As Long
Dim cbNeeded2 As Long
Dim NumElements2 As Long
Dim Modules(1 To 200) As Long
Dim lRet As Long
Dim ModuleName As String
Dim nSize As Long
Dim hProcess As Long
Dim i As Long
'Get the array containing the process id's for each process object
cb = 8
cbNeeded = 96
Do While cb <= cbNeeded
cb = cb * 2
ReDim ProcessIDs(cb / 4) As Long
lRet = EnumProcesses(ProcessIDs(1), cb, cbNeeded)
Loop
NumElements = cbNeeded / 4

For i = 1 To NumElements
'Get a handle to the Process
hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, ProcessIDs(i))

'Got a Process handle
If hProcess <> 0 Then
'Get an array of the module handles for the specified
'process
lRet = EnumProcessModules(hProcess, Modules(1), 200, _
cbNeeded2)

'If the Module Array is retrieved, Get the ModuleFileName
If lRet <> 0 Then
ModuleName = Space(MAX_PATH)
nSize = 500
lRet = GetModuleFileNameExA(hProcess, Modules(1), _
ModuleName, nSize)

'If the EXE name contains "WinWord.exe", we've found an
instance of Word
If (InStr(1, LCase(ModuleName), "winword.exe",
vbTextCompare) > 0) Then

'Confirm that we want to terminate it
If (MsgBox("Found an instance of Word. Are you sure
you want to Terminate it?", vbOKCancel) = vbOK) Then

'If so, go ahead and kill it
TerminateProcess hProcess, -1
End If
End If
End If
End If
'Close the handle to the process
lRet = CloseHandle(hProcess)
Next

End Select

MsgBox "Done searching"
End Sub


Private Sub Command1_Click()
Dim x As Integer
Dim ow As Object

For x = 1 To 5

Set ow = CreateObject("Word.application")

Next

End Sub

Private Sub Command2_Click()
TerminateWord
End Sub

I've not tested this with Word in a hung state.
I agree error handling would be a better solution then forcing Word to quit.
Regards,
 
L

Lars-Eric Gisslén

Harold,

TerminateProcess can be dangerous to use as it does not cause a normal
termination of a process. See the following note from the API documentation:
----------------------------------------
Remarks

The TerminateProcess function is used to unconditionally cause a process to
exit. Use it only in extreme circumstances. The state of global data
maintained by dynamic-link libraries (DLLs) may be compromised if
TerminateProcess is used rather than ExitProcess.
TerminateProcess causes all threads within a process to terminate, and
causes a process to exit, but DLLs attached to the process are not notified
that the process is terminating.
 
V

Veena

Thanks a lot Harold ..it worked!!
Also, thanks Lars-Eric Gisslén...will keep your advice in mind!!1

-regards,
veena.
 
V

Veena

Hi,
asking for more help!!

I am able to kill the winword session sucessfully!
But, I have another problem.
I have 2 programs :
Program 1: which has the code to do the mailmerge
Program 2: which has the code to kill the winword session.

I kill the winword session after I call the mailmerge.execute with a
parameter of false. (infact when the mailmerge.execute is hung) ie,

<Word_object>.ActiveDocument.MailMerge.Execute (False)

After, the word session is killed, Program 1 throws up an error
"Overflow"
I feel this error is thrown from the mailmerge.execute function.

Do you any ideas how to avoid this.

I have tried
<Word_object>.ActiveDocument.MailMerge.Execute (True), but that does
not help.

Please help.

Thanks & Regards,
Veena.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top