how to bypass dialog box

A

Alex Cheng

I think it's working in Word. Let me try again and let you know.

Thanks,

Alex
Karl E. Peterson said:
Alex said:
FYI:

It won't work. It will ignore the dialog box and move on. I
guess
it is because it's not the same thread.

If you moved it into Word, yes, of course it's the same thread! That's
the whole point of doing it there. But you also need to set the
parameters for SetWindowsHookEx back to how they were when we started. I
need to you to *think* along with me here, okay? <g>

This (kinda) works:

Option Explicit

Private Declare Function SetWindowsHookEx Lib "user32" Alias
"SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod
As Long, ByVal dwThreadId As Long) As Long
Private Declare Function GetCurrentThreadId Lib "kernel32" () As Long
Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook
As Long) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA"
(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal
lParam As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA"
(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As
Any) As Long
Private Declare Function GetClassname Lib "user32" Alias "GetClassNameA"
(ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long)
As Long
Private Declare Function GetWindowText Lib "user32" Alias
"GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal cch
As Long) As Long

Private Const WH_CBT = 5
Private Const WM_CLOSE = &H10
Private Const HCBT_ACTIVATE = 5

Private m_hHook As Long

Public Sub AvoidCorruptDoc()
' Set the CBT hook. (Parameters set to be used in-process, within
VBA!)
m_hHook = SetWindowsHookEx(WH_CBT, AddressOf CloseCorrupt, 0&,
GetCurrentThreadId())

' Take step(s) here to Open document
CreateDocument

' Hook no longer needed.
If m_hHook Then Call UnhookWindowsHookEx(m_hHook)
End Sub

Private Function CloseCorrupt(ByVal nCode As Long, ByVal wParam As Long,
ByVal lParam As Long) As Long
' We only want to react to activations.
If nCode = HCBT_ACTIVATE Then
' Handle to be activated window is in wParam.
' IMPORTANT: Need to test for specific dialog!
Debug.Print Hex$(wParam), """"; Classname(wParam); """", """";
WindowText(wParam); """"
If IsFileSaveDialog(wParam) Then
' Press the [X] button!
Call SendMessage(wParam, WM_CLOSE, 0&, ByVal 0&)
' Hook no longer needed.
Call UnhookWindowsHookEx(m_hHook)
m_hHook = 0
End If
End If
End Function

Private Function IsFileSaveDialog(ByVal hWnd As Long) As Boolean
If Classname(hWnd) = "#32770" Then
If WindowText(hWnd) = "Microsoft Office Word" Then
' Pretty good odds this is the File-Save dialog.
' Could also test button text?
IsFileSaveDialog = True
End If
End If
End Function

Private Function Classname(ByVal hWnd As Long) As String
Dim nRet As Long
Dim Class As String
Const MaxLen As Long = 256

' Retrieve classname of passed window.
Class = String$(MaxLen, 0)
nRet = GetClassname(hWnd, Class, MaxLen)
If nRet Then Classname = Left$(Class, nRet)
End Function

Private Function WindowText(ByVal hWnd As Long) As String
Dim nRet As Long
Dim Buffer As String
Const MaxLen As Long = 256
' Retrieve caption of passed window.
Buffer = String$(MaxLen, 0)
nRet = GetWindowText(hWnd, Buffer, MaxLen)
If nRet > 0 Then
WindowText = Left$(Buffer, nRet)
End If
End Function

Public Sub CreateDocument()
Documents.Open "c:\temp\test.doc"
Selection.Text = "test"
Documents.Close
End Sub

I say "kinda" because (again!) I don't have a corrupt document to test
against, and my knowledge of the Word object model is severely
constrained. The Documents.Close call is failing when I send it the
WM_CLOSE message. Yes, *that* part is working just fine! :)

I think if you figure out the proper parameters for the dialog test,
you'll be in business. But as I said, I can't do all the thinking for ya
here. You gotta become a real participant in the process!
 
A

Alex Cheng

Here is what I tried in Word. But for some reason, it goes to
CloseCorrupt after I click on the dialog box. Am I doing something wrong?

Public Sub AvoidCorruptDoc()

' Set the CBT hook.
m_hHook = SetWindowsHookEx(WH_CBT, AddressOf CloseCorrupt, 0&,
GetCurrentThreadId())

' Take step(s) here to Open document
' CreateDocument
Application.DisplayAlerts = wdAlertsNone
Documents.Open "c:\temp\test.doc", openandrepair:=True,
noencodingDialog:=True
Selection.Text = "test"
Application.Quit

' Hook no longer needed.
If m_hHook Then Call UnhookWindowsHookEx(m_hHook)


End Sub

Private Function CloseCorrupt(ByVal nCode As Long, ByVal wParam As Long,
ByVal lParam As Long) As Long
' We only want to react to activations.
If nCode = HCBT_ACTIVATE Then
' Handle to be activated window is in wParam.
' IMPORTANT: Need to test for specific dialog!
Debug.Print Hex$(wParam), """"; Classname(wParam); """", """";
WindowText(wParam); """"
If IsErrorDialog(wParam) Then
' Press the [X] button!
Call PostMessage(wParam, WM_CLOSE, 0&, 0&)
' Hook no longer needed.
Call UnhookWindowsHookEx(m_hHook)
m_hHook = 0
End If
End If
End Function

Private Function IsErrorDialog(ByVal wParam As Long) As Boolean
' TBD
If Hex$(wParam) = "1390CB0" Then
IsErrorDialog = True
Else
IsErrorDialog = False
End If

End Function



Karl E. Peterson said:
Alex said:
FYI:

It won't work. It will ignore the dialog box and move on. I
guess
it is because it's not the same thread.

If you moved it into Word, yes, of course it's the same thread! That's
the whole point of doing it there. But you also need to set the
parameters for SetWindowsHookEx back to how they were when we started. I
need to you to *think* along with me here, okay? <g>

This (kinda) works:

Option Explicit

Private Declare Function SetWindowsHookEx Lib "user32" Alias
"SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod
As Long, ByVal dwThreadId As Long) As Long
Private Declare Function GetCurrentThreadId Lib "kernel32" () As Long
Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook
As Long) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA"
(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal
lParam As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA"
(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As
Any) As Long
Private Declare Function GetClassname Lib "user32" Alias "GetClassNameA"
(ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long)
As Long
Private Declare Function GetWindowText Lib "user32" Alias
"GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal cch
As Long) As Long

Private Const WH_CBT = 5
Private Const WM_CLOSE = &H10
Private Const HCBT_ACTIVATE = 5

Private m_hHook As Long

Public Sub AvoidCorruptDoc()
' Set the CBT hook. (Parameters set to be used in-process, within
VBA!)
m_hHook = SetWindowsHookEx(WH_CBT, AddressOf CloseCorrupt, 0&,
GetCurrentThreadId())

' Take step(s) here to Open document
CreateDocument

' Hook no longer needed.
If m_hHook Then Call UnhookWindowsHookEx(m_hHook)
End Sub

Private Function CloseCorrupt(ByVal nCode As Long, ByVal wParam As Long,
ByVal lParam As Long) As Long
' We only want to react to activations.
If nCode = HCBT_ACTIVATE Then
' Handle to be activated window is in wParam.
' IMPORTANT: Need to test for specific dialog!
Debug.Print Hex$(wParam), """"; Classname(wParam); """", """";
WindowText(wParam); """"
If IsFileSaveDialog(wParam) Then
' Press the [X] button!
Call SendMessage(wParam, WM_CLOSE, 0&, ByVal 0&)
' Hook no longer needed.
Call UnhookWindowsHookEx(m_hHook)
m_hHook = 0
End If
End If
End Function

Private Function IsFileSaveDialog(ByVal hWnd As Long) As Boolean
If Classname(hWnd) = "#32770" Then
If WindowText(hWnd) = "Microsoft Office Word" Then
' Pretty good odds this is the File-Save dialog.
' Could also test button text?
IsFileSaveDialog = True
End If
End If
End Function

Private Function Classname(ByVal hWnd As Long) As String
Dim nRet As Long
Dim Class As String
Const MaxLen As Long = 256

' Retrieve classname of passed window.
Class = String$(MaxLen, 0)
nRet = GetClassname(hWnd, Class, MaxLen)
If nRet Then Classname = Left$(Class, nRet)
End Function

Private Function WindowText(ByVal hWnd As Long) As String
Dim nRet As Long
Dim Buffer As String
Const MaxLen As Long = 256
' Retrieve caption of passed window.
Buffer = String$(MaxLen, 0)
nRet = GetWindowText(hWnd, Buffer, MaxLen)
If nRet > 0 Then
WindowText = Left$(Buffer, nRet)
End If
End Function

Public Sub CreateDocument()
Documents.Open "c:\temp\test.doc"
Selection.Text = "test"
Documents.Close
End Sub

I say "kinda" because (again!) I don't have a corrupt document to test
against, and my knowledge of the Word object model is severely
constrained. The Documents.Close call is failing when I send it the
WM_CLOSE message. Yes, *that* part is working just fine! :)

I think if you figure out the proper parameters for the dialog test,
you'll be in business. But as I said, I can't do all the thinking for ya
here. You gotta become a real participant in the process!
 
K

Karl E. Peterson

Alex said:
Here is what I tried in Word. But for some reason, it goes to
CloseCorrupt after I click on the dialog box. Am I doing something wrong?

If it's working said:
Public Sub AvoidCorruptDoc()

' Set the CBT hook.
m_hHook = SetWindowsHookEx(WH_CBT, AddressOf CloseCorrupt, 0&,
GetCurrentThreadId())

' Take step(s) here to Open document
' CreateDocument
Application.DisplayAlerts = wdAlertsNone
Documents.Open "c:\temp\test.doc", openandrepair:=True,
noencodingDialog:=True
Selection.Text = "test"
Application.Quit

Okay, excuse my ignorance, but can you *do* that in Word? I mean, if you quit the
app, what happens to the code that still needs to execute?
' Hook no longer needed.
If m_hHook Then Call UnhookWindowsHookEx(m_hHook)
End Sub

Private Function CloseCorrupt(ByVal nCode As Long, ByVal wParam As Long,
ByVal lParam As Long) As Long
' We only want to react to activations.
If nCode = HCBT_ACTIVATE Then
' Handle to be activated window is in wParam.
' IMPORTANT: Need to test for specific dialog!
Debug.Print Hex$(wParam), """"; Classname(wParam); """", """";
WindowText(wParam); """"
If IsErrorDialog(wParam) Then
' Press the [X] button!
Call PostMessage(wParam, WM_CLOSE, 0&, 0&)
' Hook no longer needed.
Call UnhookWindowsHookEx(m_hHook)
m_hHook = 0
End If
End If
End Function

Private Function IsErrorDialog(ByVal wParam As Long) As Boolean
' TBD
If Hex$(wParam) = "1390CB0" Then
IsErrorDialog = True
Else
IsErrorDialog = False
End If
End Function

Your test here is looking for a specific hWnd. It could (very likely) be different
each time. Not a good solution. I'd go after the windowtext and classname instead.
 
A

Alex Cheng

For some reason, it bypass the dialog box but it will keep
running the "CloseCorrupt" as infinite loop. It seems the
UnhookWindowsHookEx command is having some problem. Also, I've changed to
check with Classname like you suggested and it works well.

Thanks,

Alex



Karl E. Peterson said:
Alex said:
Here is what I tried in Word. But for some reason, it goes
to
CloseCorrupt after I click on the dialog box. Am I doing something wrong?

If it's working said:
Public Sub AvoidCorruptDoc()

' Set the CBT hook.
m_hHook = SetWindowsHookEx(WH_CBT, AddressOf CloseCorrupt, 0&,
GetCurrentThreadId())

' Take step(s) here to Open document
' CreateDocument
Application.DisplayAlerts = wdAlertsNone
Documents.Open "c:\temp\test.doc", openandrepair:=True,
noencodingDialog:=True
Selection.Text = "test"
Application.Quit

Okay, excuse my ignorance, but can you *do* that in Word? I mean, if you
quit the app, what happens to the code that still needs to execute?
' Hook no longer needed.
If m_hHook Then Call UnhookWindowsHookEx(m_hHook)
End Sub

Private Function CloseCorrupt(ByVal nCode As Long, ByVal wParam As
Long,
ByVal lParam As Long) As Long
' We only want to react to activations.
If nCode = HCBT_ACTIVATE Then
' Handle to be activated window is in wParam.
' IMPORTANT: Need to test for specific dialog!
Debug.Print Hex$(wParam), """"; Classname(wParam); """", """";
WindowText(wParam); """"
If IsErrorDialog(wParam) Then
' Press the [X] button!
Call PostMessage(wParam, WM_CLOSE, 0&, 0&)
' Hook no longer needed.
Call UnhookWindowsHookEx(m_hHook)
m_hHook = 0
End If
End If
End Function

Private Function IsErrorDialog(ByVal wParam As Long) As Boolean
' TBD
If Hex$(wParam) = "1390CB0" Then
IsErrorDialog = True
Else
IsErrorDialog = False
End If
End Function

Your test here is looking for a specific hWnd. It could (very likely) be
different each time. Not a good solution. I'd go after the windowtext
and classname instead.
 
K

Karl E. Peterson

Alex said:
For some reason, it bypass the dialog box but it will keep
running the "CloseCorrupt" as infinite loop.

You'll get a callback into CloseCorrupt everytime anything happens with any window
on that thread, yes. Not sure what you mean bout bypassing the dialog box, though?
It seems the UnhookWindowsHookEx command is having some problem.

That's unfortunate?
Also, I've changed to
check with Classname like you suggested and it works well.

Good.
 
A

Alex Cheng

It gets the expected dialog box and close it. But after the
UnhookWindowHookEx is called, it supposed to stop all the hook but it seems
it continue to do so and cannot get out of it.

Alex
 
K

Karl E. Peterson

Alex said:
It gets the expected dialog box and close it. But after the
UnhookWindowHookEx is called, it supposed to stop all the hook but it seems
it continue to do so and cannot get out of it.

Hmmmm, maybe check what UnhookWindowHookEx is returning, as well as
Err.LastDllError?
 
A

Alex Cheng

For some reason, the m_hHook is 0 when it try to call this
line "Call UnhookWindowsHookEx(m_hHook)". I can't figure out why the m_hHook
is changed before I called the Unhook function.

alex
 
A

Alex Cheng

Finally figure it out. Once the application.quit, the hook
is reset. So it works when it tried to open the corrupted file before
calling the application.quit. Thanks a lot.

Thanks,

Alex


Alex Cheng said:
For some reason, the m_hHook is 0 when it try to call this
line "Call UnhookWindowsHookEx(m_hHook)". I can't figure out why the
m_hHook is changed before I called the Unhook function.

alex
 

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