Hooked Common Dialogs (vbAccelerator style)?
I was wondering if anyone had any experience with hooked dialogs. Particularly using this DLL from vbAccelerator.
It just isn't acting how I expect. I think its because I don't understand the code. Could someone post an hooked dialog example project?
Re: Hooked Common Dialogs (vbAccelerator style)?
The URL you posted has an example there down, and there is a demonstration app too:Here is.
(sorry if you've already seen that)
Re: Hooked Common Dialogs (vbAccelerator style)?
Well, the demo application only shows how to hook into one of the common dialogs and center it to either the owner form or to the screen. What is it you want to accomplish?
Re: Hooked Common Dialogs (vbAccelerator style)?
jcis,
I know there are examples there, but they confuse me.
JA,
I don't really understand the process because of the APIs used in the example. Does the (picture preview) example copy the picture box onto the common dialog or the common dialog onto the form?
What I THINK I want to do is copy the common dialog onto my form and then get its rectangle so I can move/size other objects around the common dialog? Could you post a (commented) example of how to do this?
Thanks as always JA. :)
Re: Hooked Common Dialogs (vbAccelerator style)?
Now you confuse me... Where did you see that picture preview example?
Re: Hooked Common Dialogs (vbAccelerator style)?
Re: Hooked Common Dialogs (vbAccelerator style)?
OK. I will not go into depth about the implementation of the CommonDialog/Direct component but rather look on this example how the preview is created. However the cCommonDialog class in that component will raise some events if you set the hook. An object of the cCommonDialog class is in this example declared in the frmPreview Form. This Form is loaded but not shown when you click on the button on the frmLaunch Form.
The cCommonDialog object is declared in frmPreview in this way:
VB Code:
Public WithEvents cD As cCommonDialog
So the object is simply called cD and is public. The click event of the button in frmLaunch looks like this (with some comments added by me).
VB Code:
Private Sub cmdPreview_Click()
'Load the preview form but do not show it
Load frmPreview
frmPreview.OwnerForm = Me
'Now create the cCommonDialog object in frmPreview
Set frmPreview.cD = New cCommonDialog
With frmPreview.cD
'Set some of the properties, most of these are well known
'from the regular VB Common Dialog Control
.InitDir = App.Path
'I changed the Filter assignment so the line would get so long in this post
.Filter = "Picture Files|*.JPG;*.GIF;*.BMP;*.ICO"
.flags = OFN_FILEMUSTEXIST Or OFN_PATHMUSTEXIST Or OFN_HIDEREADONLY
.FilterIndex = 1
.DefaultExt = "BMP"
'The below property is not exposed by the VB Common Dialog Control
'and this is the secret. Setting it to True will cause the
'cCommonDialog class to raise events while a Dialog is shown
.HookDialog = True
'Make Dialog owner Me
.hwnd = Me.hwnd
.ShowOpen
' Will be blank if cancelled:
lblFile.Caption = .FileName
If Not lblFile.Caption = "" Then
Set imgPicture.Picture = LoadPicture(lblFile.Caption)
Else
Set imgPicture.Picture = Nothing
End If
End With
'Now unload the preview Form since we don't need it anymore.
'Remember that the preview form itself has never been showed!
Unload frmPreview
Set frmPreview = Nothing
End Sub
OK, with the comments I added to that code I hope it's all pretty clear. Now since we have set the HookDialog property to True, the cCommonDialog class will raise a number of events which is sinked in the frmPreview class (that has declared the object).
The important code is in the InitDialog, FileChange, and DialogClose events. The InitDialog event is raised before the Dialog is shown so you can change some of its behaviours and placement. This event gets a dialog handle as an argument, the hDlg is not the hWnd of the whole dialog window but rather the "frame" inside it. To get the hWnd of the actual dialog window you pass this hDlg to the GetParent API function. Let's have a look at the code:
VB Code:
Private Sub cD_InitDialog(ByVal hDlg As Long)
Dim tR As RECT
Dim lBorderSize As Long
'Get the hWnd of the dialog window
m_hwnd = GetParent(hDlg)
'Now get the size of this window
GetWindowRect m_hwnd, tR
'Call GetSystemMetrics to get the size of the border
'for a dialog window
lBorderSize = GetSystemMetrics(SM_CXDLGFRAME)
'MoveWindow is called here to resize the dialog window
'so we can put the PictureBox on it.
MoveWindow m_hwnd, 0&, 0&, _
tR.right - tR.left + picScroll.Width \ Screen.TwipsPerPixelX + lBorderSize * 2, _
tR.bottom - tR.top, 1
'Now simply center the dialog
If m_fOwner Is Nothing Then
cD.CentreDialog hDlg, Screen
Else
cD.CentreDialog hDlg, m_fOwner
End If
'Call SetParent to move the picturebox from this Form to the
'dialog window
SetParent picScroll.hwnd, m_hwnd
'Move the PictureBox to the right hand side of our
'resized dialog box. Doing some calculations for the size of the
'scrollbars that this demo adds to the PictureBox
MoveWindow picScroll.hwnd, _
tR.right - tR.left - lBorderSize, _
4&, picScroll.Width \ Screen.TwipsPerPixelX, _
tR.bottom - tR.top - GetSystemMetrics(SM_CYCAPTION) - _
GetSystemMetrics(SM_CYDLGFRAME) * 2 - 6, 1
End Sub
I've added some comments here as well so I hope it explains what it does. But in short it simply change the size of the dialog box so that the PictureBox can fit inside it. It then use SetParent to put the PictureBox on the Dialog window.
The next event that is used is FileChange which is raised whenever you have selected a new file in an Open/Save dialog box. The code in that simply use LoadPicture to load the selected image into the picturebox, nothing special. The interesting part is how it gets the selected file name. But even that is pretty straight forward. It uses GetParent to get the hWnd of the dialog box, like above. It then just send the CDM_GETFILEPATH message to this window to get the file name.
The last event that is handled is the DialogClose event. In which simply SetParent is called to move back the PictureBox to our Form before the dialog box is closed.
Re: Hooked Common Dialogs (vbAccelerator style)?
Thanks a ton JA! You have always been exteremely helpful.
A few questions:
1) How are resize events for the picturebox called if it has been moved to another form? Does the code just come with it?
2) Is it possible to move the dialog to my form instead of moving the stuff on my form to the dialog? Or is the way this example does it the better way? How would I get the dialog inside a tab if I didn't move it to my own form?
The main part I was missing was that GetWindowRect was for the inner frame of the dialog and not the whole thing and that my picture box was being moved to the dialog and that my form wasn't even being shown.
Thanks a ton.
Re: Hooked Common Dialogs (vbAccelerator style)?
1) All events for a control is sinked where it was origionally placed regardless if you use SetParent to move it or not. So all event code you want would be placed in the origional Form.
2) It is possible to do so, but not "out-of-the-box". This code doesn't support it directly but it's not to hard to extend the code to do so. I've done it with Source Edit for example. I'm currently not sitting at my regular developer compie so I can't post any sample code for you right now... I'll get back to you on that :)
GetWindowRect was not for the inner part of the dialog... I never said that did I? The code used GetParent with the hDlg handle to get the hWnd of the whole thing, and the hWnd is passed to GetWindowRect. Your Form is not shown because there is no reason for that. The Form is just the origional container of the PictureBox (that also had an image control) and the place to sink events inside. The PictureBox is moved (with SetParent) to the Dialog window and the dialog window is the only thing the user is interested to see... Viewing your (now empty) Form is pretty pointless, don't you think? :)
Re: Hooked Common Dialogs (vbAccelerator style)?
Quote:
Originally Posted by Joacim Andersson
1) All events for a control is sinked where it was origionally placed regardless if you use SetParent to move it or not. So all event code you want would be placed in the origional Form.
Cool.
Quote:
Originally Posted by Joacim Andersson
2) It is possible to do so, but not "out-of-the-box". This code doesn't support it directly but it's not to hard to extend the code to do so. I've done it with Source Edit for example. I'm currently not sitting at my regular developer compie so I can't post any sample code for you right now... I'll get back to you on that :)
I'd really appriciate and example like this because it would allow me to code it that way and it would all make more sense (to me).
Quote:
Originally Posted by Joacim Andersson
GetWindowRect was not for the inner part of the dialog... I never said that did I? The code used GetParent with the hDlg handle to get the hWnd of the whole thing, and the hWnd is passed to GetWindowRect. Your Form is not shown because there is no reason for that. The Form is just the origional container of the PictureBox (that also had an image control) and the place to sink events inside. The PictureBox is moved (with SetParent) to the Dialog window and the dialog window is the only thing the user is interested to see... Viewing your (now empty) Form is pretty pointless, don't you think? :)
Sorry, you misunderstood what I meant. I didn't mean that I was missing my form showing and that it needed to show. I meant that I didn't understand that my form wasn't showing. I though it was when it really wasn't and when it didn't need to. My grammer wasn't clear.
Re: Hooked Common Dialogs (vbAccelerator style)?
JA, have you had a chance to find the example you mentioned above?