PDA

Click to See Complete Forum and Search --> : Common Dialogs made easy


Joacim Andersson
May 22nd, 2001, 05:43 AM
Hi all!
I've written a wrapper class for the common dialogs that uses the API functions to bring upp all the dialogs.

It has a much smaller footprint then the Common Dialog Control provided with VB and it also includes an advanced printer properties dialog and the browse for folder dialog.

It has most of the usefull properties that the control has but it's much easier to use because of two importent things. It doesn't have a flags property but instead the most common flags are pre-set.
The second advantage is that all the ShowXXX methods returns a boolean which is false if the user has pressed the cancel button.

I attached the code which you all are free to use in any matter you might feel fit.

Best regards

alex_read
May 22nd, 2001, 06:10 AM
Cool, cheers Joacim , I'll check that out ;)

MerryVIP
May 22nd, 2001, 06:11 AM
Same here. Hope I remember to check it out :rolleyes:

crispin
May 22nd, 2001, 07:42 AM
Thanks Joacim!

Joacim Andersson
May 23rd, 2001, 07:24 AM

Sezna
May 23rd, 2001, 07:38 AM
Joacim, is the dialog modal and does it always show up at the left upper corner like the usual API dialog? I hated that, that's why I could not use it.

Joacim Andersson
May 23rd, 2001, 08:06 AM
Yes the dialogs are modal. You just have to call the Init method first and pass the form you want to be the owner of the dialog.

Best regard

ExcalibursZone
May 23rd, 2001, 08:45 AM
Thankee for the class, time and effort to write this, jocaim ;)

Sezna
May 23rd, 2001, 11:13 AM
Originally posted by Joacim Andersson
Yes the dialogs are modal. You just have to call the Init method first and pass the form you want to be the owner of the dialog.


Cool, I am getting it, thanks!

surfmstr
May 23rd, 2001, 11:32 AM
Thanks man! I'm going to try this out. It's one of those things that so many of "intend" to do and it just never gets done. Great to see somebody swimming upstream :D

Michael Woolsey
May 23rd, 2001, 12:12 PM
Joacim Andersson

Quick question, this code isn't compatible with VB5 is it? It seems to be using the Replace function which didn't exist in VB5...

I know I know, why am I using VB5? Heh don't have much choice at a new job. *crosses fingers* Hopefully we are upgrading soon...

Maybe I'll play with it with my own home grown version of Replace...

Michael

Jotaf98
May 23rd, 2001, 12:14 PM
Hey, nice class :)

I always wanted to know how to use the Browse For Folder dialog ;)

Michael Woolsey
May 23rd, 2001, 12:28 PM
Can someone post the "InStrRev" defination? I'm not near a vb6 box while I'm at work so I can't remake this function without knowing what it does. :cool: (I have an idea, but I don't want to get it wrong)

Thanks,
Michael

Michael Woolsey
May 23rd, 2001, 12:48 PM
Under the assumption that InStrRev is doing the same thing as InStr, just starting at then end and going to the start of the string.

I have added the following 2 functions to the class, and replaced all the offending functions with my own. *shrug* It seems to work, and I'm certain my two functions could be optimized more so than they are...
Private Function myReplace(ByVal strTheString As String, ByVal strToReplace As String, ByVal strReplaceWith As String) As String
Dim strNewString As String
Dim intIndex As Integer

'Finds ever instace of the sought string and replaces it.
strNewString = strTheString
Do While InStr(strNewString, strToReplace) > 0 'This could be modified so it doesn't have to call InStr twice.
intIndex = InStr(strNewString, strToReplace)

strNewString = Left$(strNewString, intIndex - 1) & strReplaceWith & Right$(strNewString, Len(strNewString) - Len(Left$(strNewString, intIndex)) - Len(strToReplace) + 1)
Loop

myReplace = strNewString
End Function

Private Function myInStrRev(ByVal strTheString As String, ByVal strSoughtString As String) As Long
Dim intCtr As Long

For intCtr = Len(strTheString) To 0 Step -1
If Mid(strTheString, intCtr, 1) = strSoughtString Then
Exit For
End If
Next intCtr

myInStrRev = intCtr
End Function

If anyone has VB5 and wants to test it out or optimize my routines, by all means go ahead...

Regards,
Michael

Jotaf98
May 24th, 2001, 04:42 AM
For that code to work, you'll need to see the declaration of InStrRev (it's different from InStr). Otherwise, it won't work because the parameters you pass are out of place!

Joacim Andersson
May 24th, 2001, 07:29 PM
Originally posted by Jotaf98
For that code to work, you'll need to see the declaration of InStrRev (it's different from InStr).
Otherwise, it won't work because the parameters you pass are out of place!
It doesn't matter.
InStrRev do has two additinal optional arguments but they aren't used in this class.

Best regards

Joacim Andersson
May 27th, 2001, 05:12 PM
:)

Jotaf98
May 27th, 2001, 05:36 PM
Hey, I used your class in one of my projects, the Debugger. I left is as it was, with the comments and all :)

I know this has nothing to do with it, but I can't upload it to Planet-Source-Code.com! It says that I'm using GetRight or something :(

Any idea?

Joacim Andersson
May 28th, 2001, 11:41 AM
I don't have the slightest idea why you can't upload your project, but I doubt it has anything to do with the use of this class.

Gush
May 28th, 2001, 11:51 AM
Hello Joacim Andersson and All,

I downloaded the class and it worked just fine it's wonderful, thank you.

I still have one question. Can I make a template for the open dialog in vb?

Joacim Andersson
May 29th, 2001, 04:37 AM
Well yes it's possible but it's not easy.
First of all you need a resourse for the template and for that you need a much more advanced resource editor then the one shipped with VB.
For it to work with VB you'll also need a TLB file which you must build in C++.

I'll tried this a couple of times but the result wasn't that good and I got a GPF some of the times I tried to show the dialog.

Jotaf98
May 29th, 2001, 02:47 PM
Heh, sorry, I wasn't saying it was because of YOUR class, I just needed some help :p

I think I'll post it in a new thread.

Anyway, I've heard that you can use the API to get a handle to the dialog box and then create controls there!

Joacim Andersson
May 29th, 2001, 02:55 PM
No, you use a template, made with a resource editor, and send the template name to the API function.
You'll also create a call-back procedure that the dialog (or rather the API) will call to sink all the events in the dialog.

Best regards

rickm
May 29th, 2001, 03:35 PM
Originally posted by Jotaf98
Hey, I used your class in one of my projects, the Debugger. I left is as it was, with the comments and all :)

I know this has nothing to do with it, but I can't upload it to Planet-Source-Code.com! It says that I'm using GetRight or something :(

Any idea?

Sounds like you are using, (or it thinks you are using) a program that will allow you to resume broken downloads. These programs also tend to have a "leech" function where you can download all the documents off a particular site, including the HTML and whatnot. If you really wanted to get their code, you could anyhow, so i dont know why they are doing that, but it sounds like thats what they are looking for.

Gush
May 30th, 2001, 03:36 AM
Has anyone been able to use a template for common dialog boxes, if so I would appreciate some code or help.

Jotaf98
May 30th, 2001, 05:42 AM
Yeah, I know - I just found out that they're selling the whole site on CD :p

Anyway, I'm sure I've seen a demo on custom controls in common dialogs before... and it said "It's kinda hard because you must find the handle of the common dialog and then create the controls there, through API". That's why I didn't download it, it needed +20 lines of code for a simple button :)

Gush
May 30th, 2001, 07:06 AM
Originally posted by Jotaf98

Anyway, I'm sure I've seen a demo on custom controls in common dialogs before... and it said "It's kinda hard because you must find the handle of the common dialog and then create the controls there, through API". That's why I didn't download it, it needed +20 lines of code for a simple button :)

Can you remember where you've seen that demo?

Jotaf98
May 31st, 2001, 04:42 AM
No, sorry :(

But I know it was based on another demo, that allowed you to create a button in the title bar of a form, trough API (creating a control trough API gives you a lot more options, VB just provides us with the default ones :D). The author of that code just had to find a handle to the common dialog to create controls there. I think it was at http://www.planet-source-code.com , but I'm not sure.

anizmohammed
May 31st, 2001, 05:08 AM
Option Explicit
Dim cdl As CCommonDialogs

Private Sub Form_Click()
Set cdl = New CCommonDialogs
Form2.Show
cdl.Init (Form2)
cdl.ShowFolder
End Sub


This is my code It shows error
Type mismatch while i call the init function
of your class file


can any one helpme how to use it

Jotaf98
May 31st, 2001, 05:14 AM
Look, there's another way to create classes:

Dim CD As New CCommonDialog

That's much easier than what you're using ;)

Joacim Andersson
Jun 1st, 2001, 10:05 AM
Originally posted by anizmohammed
Option Explicit
Dim cdl As CCommonDialogs

Private Sub Form_Click()
Set cdl = New CCommonDialogs
Form2.Show
cdl.Init (Form2)
cdl.ShowFolder
End Sub

This is my code It shows error
Type mismatch while i call the init function
of your class file can any one helpme how to use it
Don't use the paranteses when you call the Init method (or use a Call statement) because when you do you pass the form ByVal instead of ByRef.

Dim cdl As CCommonDialogs

Private Sub Form_Click()
Set cdl = New CCommonDialogs
Form2.Show
cdl.Init Form2 'or Call cdl.Init(Form2)
cdl.ShowFolder
End Sub

Originally posted by Jotaf98
Look, there's another way to create classes:

Dim CD As New CCommonDialog

That's much easier than what you're using.
That might be easier to type but it's not a better way to declare and use an object.
This is because how VB initilize an object.
When you declare and init an object in the following matter:

Dim obj As Class
Set obj = New Class

The object will be initilized on the second row. That is with the Set statement.
But if you do the following:

Dim obj As New Class

The object will not be initlized before it is first used.
That is when you first assign a value to a property or when you call a method.
But then VB has to check if the object already exist, that is if it already has been initilized, and that takes time.
Furthermore VB has to do that check every time you use the object!

Private cdl As New CCommonDialog 'object isn't created

Private Sub Form_Load()
Dim sFile As String
cdl.Init Me 'check if object is created, if not create it.
cdl.ShowOpen 'check if object is created, if not create it.
sFile = cdl.FileName 'check if object is created, if not create it.
'and so on
End Sub

So I always use the two liner to create an object!

Best regards

Jotaf98
Jun 1st, 2001, 12:47 PM
Heh, thanks, I didn't know that about classes - I just used them like that and they seemed fine to me :p

Joacim Andersson
Jun 7th, 2001, 04:08 AM
Well it's a common mistake. But use the two liner and your code will execute much faster.

Joacim Andersson
Jun 19th, 2001, 06:49 AM
:)

cinder829
Jul 10th, 2001, 03:42 AM
I need some help. I love this class! It does everything I need so far, but I'm having a problem. How can I retrieve the number of copies the user sets when I call ShowPrinter? I'm trying to print a form using Form1.PrintForm and when I tried printing multiple copies by changing the copies on the print dialog, it only printed one copy. Here's my code:

Private Sub Print_Click()
On Error GoTo ErrorHandler
NotCanceled = CommonDialog1.ShowPrinter
If NotCanceled = False Then Exit Sub
Form1.PrintForm
Exit Sub
ErrorHandler:
End Sub

When I used the comdlg32.ocx control to print the form, this code let me print multiple copies by changing the copies property at runtime:

Private Sub Print_Click()
On Error GoTo ErrorHandler
CommonDialog1.CancelError = True
CommonDialog1.Flags = cdlPDHidePrintToFile Or cdlPDNoSelection
CommonDialog1.ShowPrinter
Form1.PrintForm
Exit Sub
ErrorHandler:
End Sub

If anyone has any ideas or can tell me what I'm doing wrong (Joacim?), please respond soon. :D

Joacim Andersson
Jul 10th, 2001, 04:13 AM
You'll have to change the code a little bit to do that.
First add a private variable to hold a new property value.
(Add it at the beginning of the class where the rest of the member variables are)

Private m_PrintCopies As Long

Then you'll have to add a new property procedure:

Public Property Get PrintCopies() As Long
If m_PrintCopies = 0 Then
m_PrintCopies = 1
End If
PrintCopies = m_PrintCopies
End Property

Public Property Let PrintCopies(ByVal NewValue As Long)
m_PrintCopies = NewValue
End Property

You'll also has to do some changes in the ShowPrinter method.
(The changes are in bold text.)

Public Function ShowPrinter() As Boolean
Dim pd As PrintDlgStruct
Dim nRetVal As Long

pd.lpSetupTemplateName = ""
pd.lpPrintTemplateName = ""
pd.hwndOwner = m_Owner.hWnd
pd.nCopies = Me.PrintCopies
pd.flags = PD_HIDEPRINTTOFILE Or PD_NOPAGENUMS Or PD_NOSELECTION
pd.lStructSize = Len(pd)
nRetVal = PrintDlg(pd)
Me.PrintCopies = pd.nCopies
ShowPrinter = (nRetVal <> 0)
End Function

Now you still have to loop through the number of copies you want to print. So you'll have to make a small change in your code as well:

Private Sub Print_Click()
Dim i As Long
On Error GoTo ErrorHandler
If CommonDialog1.ShowPrinter = True Then
For i = 1 To CommonDialog1.PrintCopies
Form1.PrintForm
Next
End If
Exit Sub
ErrorHandler:
End Sub

Best regards

cinder829
Jul 10th, 2001, 04:56 AM
Awesome! Thanks a million! :D

cinder829
Jul 21st, 2001, 11:00 PM
Hey Joacim, I'm having a problem with your code. I thought the PrintCopies property was working, but it's not right now. Whenever I call Print_Click(), it displays the print dialog, but no matter what I set copies to in the print dialog, the PrintCopies property is set to 1 and it prints the amount of copies I have set in the printer properties dialog. So, for example, if I call ShowPrinterProperties and set copies to 2, then call ShowPrinter, the print dialog has copies set to 1. Then if I click ok (leaving copies on 1) it prints 2 copies. I'm confused, can you help? :confused:

Joacim Andersson
Jul 22nd, 2001, 01:37 PM
If you want to set the number of pages to be printer in the Printer Properties dialog you'll have to do some more changes to the code.
First add the following structure:

Private Type DEVMODE
dmDeviceName As String * 32
dmSpecVersion As Integer
dmDriverVersion As Integer
dmSize As Integer
dmDriverExtra As Integer
dmFields As Long
dmOrientation As Integer
dmPaperSize As Integer
dmPaperLength As Integer
dmPaperWidth As Integer
dmScale As Integer
dmCopies As Integer
dmDefaultSource As Integer
dmPrintQuality As Integer
dmColor As Integer
dmDuplex As Integer
dmYResolution As Integer
dmTTOption As Integer
dmCollate As Integer
dmFormName As String * 32
dmUnusedPadding As Integer
dmBitsPerPel As Long
dmPelsWidth As Long
dmPelsHeight As Long
dmDisplayFlags As Long
dmDisplayFrequency As Long
End Type

Then do the following changes to the ShowPrinterProperties method:

Public Function ShowPrinterProperties() As Boolean
Dim nRetval As Long, hPrinter As Long
Dim pd As PRINTER_DEFAULTS
Dim dm As DEVMODE

On Error Resume Next
dm.dmSize = Len(dm)
dm.dmCopies = m_PrintCopies

pd.pDatatype = 0
pd.pDesiredAccess = STANDARD_RIGHTS_REQUIRED Or PRINTER_ACCESS_USE
pd.pDevMode = VarPtr(dm)
nRetval = OpenPrinter(Printer.DeviceName, hPrinter, pd)
If nRetval <> 0 Then
nRetval = PrinterProperties(m_Owner.hwnd, hPrinter)
m_PrintCopies = dm.dmCopies
ClosePrinter hPrinter
End If
ShowPrinterProperties = (nRetval <> 0)
End Function

Best regards

cinder829
Jul 22nd, 2001, 04:03 PM
Nope, didn't fix it. I think I may know where the problem is, but I have no clue how to fix it... First of all, I have a Hewlett Packard Deskjet 720C, in case that matters. When I run my program and to to display the print properties dialog it shows the printer properties for my printer. From here I can change print options such as portrait or landscape, greyscale or color, etc... If I go into the printer properties dialog, I can also set the number of copies it should print. If I set the number of copies to print to 2, click ok, show the print dialog, set the number of copies there to 1 and click ok, it prints two copies. I got the program to display a messagebox telling me what the .PrintCopies property was set to before it prints, and no matter what I set the copies to on the print dialog or the printer properties dialog, the .PrintCopies property is always 1. This means that my program must loop one time, e.g. it tells the printer to print one time. However it always prints however many copies I set in the print properties dialog. I think for some reason, when you set the .PrintCopies property for the ccommondialogs.cls class, it doesn't remember, or it doesn't change the setting for the printer. I hope this is enough information to fix the problem. If this was confusing, tell me and I'll try to explain better. Thanks a million! :D

P.S. Source Edit is great! I'm trying out C++ and it's my editor of choice now.

cinder829
Jul 23rd, 2001, 03:56 AM
Joacim, I figured out what's not working. I got the class to display a msgbox by modifying the ShowPrinter dialog like this:

Public Function ShowPrinter() As Boolean
Dim pd As PrintDlgStruct
Dim nRetVal As Long

pd.lpSetupTemplateName = ""
pd.lpPrintTemplateName = ""
pd.hwndOwner = m_Owner.hwnd
pd.nCopies = Me.PrintCopies
pd.Flags = PD_HIDEPRINTTOFILE Or PD_NOPAGENUMS Or PD_NOSELECTION
pd.lStructSize = Len(pd)
nRetVal = PrintDlg(pd)
MsgBox pd.nCopies
Me.PrintCopies = pd.nCopies
ShowPrinter = (nRetVal <> 0)
End Function


What I found was that everytime the msgbox appeared, no matter what the number of copies was set to, pd.nCopies was always 1 for some reason. Do you know why it would do that? Is there a way to fix it? Please respond A.S.A.P. Thanks for all your help. :D

Joacim Andersson
Jul 23rd, 2001, 10:00 AM
Yes I know whats wrong.
When you call ShowPrinterProperties and you'll have the option to set the number of copies in that dialog (I can't do it on any of my printers)
the value is sent directly to the printer and is not (for some reason) saved in the structure (Why? -Ask Microsoft).
When this is stored in the printer the printer itself will print that number of copies without you needing to loop thru the PrintCopies property.

If you don't want this behaviour I can only suggest that you don't show the properties dialog but only call the ShowPrinter dialog.

Best regards

Skitchen8
Jul 23rd, 2001, 01:00 PM
ccommondialog.filename won't work.... I am doing openfolder in the commondialog class, but when i try to retrieve the filename it won't work, is there another way to do this??

Joacim Andersson
Jul 23rd, 2001, 02:40 PM
The FileName property can only be used when you pick a file (in the Open and Save As dialogs).
When you call the ShowFolder method use the Path property instead.

Best regards

PS.
To Cinder829,

Thanks for downloading Source Edit. I hope you enjoy it and please mail me any feedbacks you can think of.
And if you didn't download it, there is a version 1.2 update on http://www.sourceedit.cc

cinder829
Jul 23rd, 2001, 05:31 PM
Well, I've gotten rid of the print properties dialog, but I still can't print multiple copies. Do you know why pd.nCopies wouldn't change when the user closed the print dialog? For some reason it's always 1. Is there a fix or a workaround? Here's the code I have right now.

Public Function ShowPrinter() As Boolean
Dim pd As PrintDlgStruct
Dim nRetVal As Long

pd.lpSetupTemplateName = ""
pd.lpPrintTemplateName = ""
pd.hwndOwner = m_Owner.hwnd
pd.nCopies = Me.PrintCopies
pd.Flags = m_Flags
pd.lStructSize = Len(pd)
nRetVal = PrintDlg(pd)
Me.PrintCopies = pd.nCopies
ShowPrinter = (nRetVal <> 0)
End Function


P.S. Joacim, I know that Source Edit probably wasn't really made to edit vb programs, but it would still be nice if it did a better job with visual basic form files, e.g. didn't display all of the form information at the top of the file. Other than that, it's great! Keep up the good work... :D

veebee
Oct 10th, 2001, 08:30 AM
Joacim,

I'm trying to use this class to show the color dialog, and I can't get it to set the focus on the correct box for the initial color. My code is as follows:

i_CommonDialog.Init Me
i_CommonDialog.Color = Me.BackColor
lb_Result = i_CommonDialog.ShowColor
If lb_Result = True Then Me.BackColor = i_CommonDialog.Color

When the color dialog appears, the first color box in the dialog has focus (which is a pink color box on mine) instead of the gray that is my form backcolor. If I click OK without clicking on any color boxes, the color does not change to the color in that first box, it does stay the same color as my form, which would be correct. But it should set focus on the initial display of the dialog box to the correct color box, shouldn't it?

I also noticed that the custom color boxes at the bottom are not always the same.

Thanks..... (this class is very helpful)

Joacim Andersson
Oct 10th, 2001, 09:31 AM
The problem is that you assign one of the system colors. In this case (probably) vbButtonFace which has a value of &H8000000F. Which isn't actually grey.
To change this behaviour add the following declaration to the classPrivate Declare Function GetSysColor _
Lib "user32" ( _
ByVal nIndex As Long) As Long Now change the Property Let Color procedure into the followingPublic Property Let Color(ByVal nNew As Long)
Dim sHex As String
m_Color = nNew
If m_Color < 0 Then
' A system color. Convert it to correct color
sHex = Right$(Hex(m_Color), 4)
m_Color = CLng("&H" & sHex)
m_Color = GetSysColor(m_Color)
End If
End Property You should now get the correct color.

Thank you so much for pointing this out.

bazzaar
Feb 25th, 2002, 12:23 PM
Does this class work in MS Word 97?

I have it running in VB6 but want to use it in VBA

I am declaring my class as following but I'm getting an error

Dim cdl As CCommonDialogs

Set cdl = New CCommonDialogs

cdl.Init Me
cdl.ShowFolder

Joacim Andersson
Feb 25th, 2002, 03:12 PM
You have to make some slight changes to the code to make it work in Word.
The Init method takes a VB Form as an argument. This form is then used as the parent window for the dialog boxes.
Remove the Init method and change all the code you find with m_Owner.hWnd to 0.

Best regards

bazzaar
Feb 26th, 2002, 05:30 AM
Thanks for the quick response. Unfortunately I didn't have any luck. I'm new to VBA and learning this as I go so it could be something quite simple that I'm doing wrong. I'm using the class in a template which I place in the startup folder for word. It wont let me step through the code to find the error so I feel a little helpless. Why is it not possible to run my macro when I'm editing the template. Why do I have to run the template in the startup folder in order to run the macro and then not be able to view the code behind the macro? Any help muchly appreciated!

rouzbeh_ziafati
May 10th, 2009, 03:58 PM
How I can show common dialog ( commondialog1.showfont for Example) in center of screen ?