|
|
||
|
Using CBT Hooks to Centre API DialogsEnsure Common Dialogs and Message Boxes appear where you want them to.
Windows sometimes places Common Dialogs and Message Boxes at the "wrong" position on the screen. Whilst there are some ways of working around this for Common Dialogs, a more general solution which applies to any Windows dialog is to use a CBT (Computer-Based Training) Windows Hook. These Hooks provide notification when any Window in your process is created, activated, focused, moved or destroyed. Using a WH_CBT HookWH_CBT hooks are intended primarily for Computer-Based Training applications, but provide a significant amount of power in intercepting and modifying the way Windows works. Once you install a WH_CBT hook, you will start receiving these hook notifications for every window within the process you've installed the hook in:
As you can see, you can use the hook to detect any window that is created or destroyed as well as to substantively alter how the user interface works. In the case of centring dialogs, however, we only need to detect when the dialog is created. Note there are also three other HCBT_ codes associated with CBT applications which aren't covered here; these are only used in conjunction with a WH_JOURNALPLAYBACK hook. Centring Common Dialogs and Message BoxesTo centre a Common Dialog or Message Box, you need to be able to do two things:
In this sample the vbAccelerator Windows Hook library is used to detect the dialog handle as it is created, and the Subclassing and Timer Assistant to subclass the dialog and intercept the WM_INITDIALOG message. 1. Using the WH_CBT hookThe previous section described the many notifications supplied by this hook. In this case detection of the dialog being created is needed; however, the hook will also provide all sorts of other notifications, including those for every child control within the dialog and activation/sizing of any controls on the dialog or your application. Therefore you want to filter the messages you receive to get the correct one. Also, for best performance the hook should be installed for as short a time as possible. This is achieved in the demonstration by:
The code looks like this:
Private Function IWindowsHook_HookProc( _
ByVal eType As vbalWinHook.EHTHookTypeConstants, _
ByVal nCode As Long, _
ByVal wParam As Long, _
ByVal lParam As Long, _
bConsume As Boolean) As Long
If eType = WH_CBT Then
If nCode = HCBT_CREATEWND Then
InstallWinProc wParam
End If
End If
End Function
Private Function InstallWinProc(ByVal hwnd As Long)
Dim lProcOld As Long
Dim sClass As String
Dim iPos As Long
If IsValidLocalWindow(hwnd) Then
If (InStr(ClassName(hwnd), "#32770")) Then
AttachMessage Me, hwnd, WM_INITDIALOG
End If
End If
End Function
Private Function IsValidLocalWindow(ByVal hwnd As Long) As Boolean
If IsWindow(hwnd) Then
Dim idWnd As Long
Call GetWindowThreadProcessId(hwnd, idWnd)
IsValidLocalWindow = (idWnd = GetCurrentProcessId())
End If
End Function
Private Property Get ClassName(ByVal hwnd As Long) As String
Dim sBuf As String
Dim iPos As Long
sBuf = String$(255, 0)
GetClassName hwnd, sBuf, 255
iPos = InStr(sBuf, Chr$(0))
If iPos > 1 Then
ClassName = Left$(sBuf, iPos - 1)
End If
End Property
Responding to the WM_INITDIALOG messageOnce the window has been found and the subclass installed, its just a matter of waiting for it to finish initialising and then send the WM_INITDIALOG message. When this message is sent, the dialog has been completely set up and sized, so the code can determine the dialog size, centre it, and then remove the subclass and hook. The code in the demonstration will check for multiple monitors on your system whilst centring and attempt to place the dialog at the best position. In more recent versions of Windows File and Folder selection dialogs are resizable which means you can also specify the ideal width and height you'd like for the dialog. ConclusionUsing a WH_CBT hook, you can easily intercept the creation and destruction of any Window and obtain a handle to it even if that Window is not being created directly from your code (which of course is usually the case for VB applications.) Hooks of this type are particularly useful for modifying the behaviour of Windows which possibly weren't intended to be modified, particularly the Windows API dialogs.
|
|
|
|
||