Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

API CommonDialogs

26 views
Skip to first unread message

Rob

unread,
Jul 25, 2001, 11:25:52 PM7/25/01
to
In a Class module, I have three dialogs - FileOpen, FileSave, and
ChooseColor. Some items of the dialog structure like Filters are
associated with a Property and can therefore be set from the routine
that calls the particular dialog. All this works as expected. I wanted
to next add a "Hook" procedure so that I could center the dialogs on
screen. I have previously accomplished this same project solely within
a BasModule. However, when I try to use this statement within the
Class, I get an "Invalid Use of AddressOf.." message.
lpfnHook = FARPROC(AddressOf dlgHookProc)

I found that if I associate lpfnHook to a property, place the "Hook"
procedures in a Module, and then use the above line in the calling
routine, the process works and the dialogs are centered.

What is not working:

In a Save dialog, there is usually a InitialFile specified, say,
"MyList.txt", which is displayed as the Filename when the dialog opens.
In most cases, when a user selects a different FileType, the Filename is
modified to reflect the selection. Selecting "*.doc" in this case
should result in the Filename changing to "MyList.doc". But, for the
life of me I can't find a way to do this. I can detect a specific
window message when File Types is selected, but that is a module outside
the Class module.

Any hints of suggestions would be appreciated.

Rob

Roger Abbott

unread,
Jul 26, 2001, 1:52:27 AM7/26/01
to

You can only pass procedures in a code module to the API because class
module procedures have extra parameters to handle the COM and class
instance aspect. I suggest putting a reference to the class instance you
want to call in a global variable in the code module. When your hook
function is called, call into your class using the global reference you
have saved.

Something along the lines, anywhere convenient-

Set CallMe = <Some MyClass instance>

In the code module-

Public CallMe As MyClass

In the hook procedure-

Call CallMe.Method(Parameters extracted from the callback parameters)

Roger Abbott,
RHA (Minisystems) Ltd.
http://www.rhaminisys.com
DDE ActiveX controls and FAQ
Other Freeware and Shareware

Asko Telinen

unread,
Jul 26, 2001, 4:11:14 AM7/26/01
to
"Rob" <ic...@abac.com> wrote in message news:3B5F8DC0...@abac.com...

> In a Class module, I have three dialogs - FileOpen, FileSave, and
> ChooseColor. Some items of the dialog structure like Filters are
> associated with a Property and can therefore be set from the routine
> that calls the particular dialog. All this works as expected. I wanted
> to next add a "Hook" procedure so that I could center the dialogs on
> screen. I have previously accomplished this same project solely within
> a BasModule. However, when I try to use this statement within the
> Class, I get an "Invalid Use of AddressOf.." message.
> lpfnHook = FARPROC(AddressOf dlgHookProc)
>
> I found that if I associate lpfnHook to a property, place the "Hook"
> procedures in a Module, and then use the above line in the calling
> routine, the process works and the dialogs are centered.

This is from MSDN:

Any code you write to call a function pointer from Visual Basic must be
placed in a standard .BAS module - you can't put the code in a class module
or attach it to a form. When you call a declared function using the
AddressOf keyword, you should be aware of the following conditions:

AddressOf can only be used immediately preceding an argument in an argument
list; that argument can be the name of a user-defined sub, function, or
property.

The sub, function, or property you call with AddressOf must be in the same
project as the related declarations and procedures.

You can only use AddressOf with user-defined subs, functions, or
properties - you cannot use it with external functions declared with the
Declare statement, or with functions referenced from type libraries.

You can pass a function pointer to an argument that is typed As Any or As
Long in a declared Sub, Function, or user-defined type definition.

> What is not working:
>
> In a Save dialog, there is usually a InitialFile specified, say,
> "MyList.txt", which is displayed as the Filename when the dialog opens.
> In most cases, when a user selects a different FileType, the Filename is
> modified to reflect the selection. Selecting "*.doc" in this case
> should result in the Filename changing to "MyList.doc". But, for the
> life of me I can't find a way to do this. I can detect a specific
> window message when File Types is selected, but that is a module outside
> the Class module.

I´m not sure did i understand your question completely but is the problem
you dealing with is how to find out which instance of your class called hook
procedure? You can pass a pointer to class instance in lCustData member of
Dialog structure and turn it
to class reference when you handling WM_INITDIALOG message. Like

Dim ofs as OPENFILENAME

ofs.lCustData = ObjPtr(Me)
Call GetOpenFileName(ofs)

And in Callback procedure:

case WM_INITDIALOG:
dim ofs as OPENFILENAME, objInstance as MyClass
Call CopyMemory(ofs,lParam,Len(ofs))
Call CopyMemory(objInstance,ofs.lCustData,???)

The problem is how to calculate a right size of your class instance

procedure.


> Any hints of suggestions would be appreciated.
>
> Rob
>

--

-------------------------------------------

Asko Telinen

department of information technology
Jyväskylä University

asko.t...@kanetti.com

-------------------------------------------


Asko Telinen

unread,
Jul 26, 2001, 6:08:29 AM7/26/01
to
You can convert pointer to Class reference as follow:

(This is taken from msgBlaster bas-module)

' --------------------------------------------------------------------------
----
' VBRefFromPtr
' - constructs a valid reference from a pointer obtained by calling
' the VBA.ObjPtr function
' --------------------------------------------------------------------------
----
Public Function VBRefFromPtr( _
ByVal lPtr As Long) As IUnknown

' Create a reference from the pointer bypassing VB (i.e. without Set).
Dim pUnk As IUnknown
CopyRef pRefDest:=pUnk, pSrc:=VBA.VarPtr(lPtr), cb:=mcbLongSize

' Return the reference created.
Set VBRefFromPtr = pUnk

' Now we have two references, but AddRef was called only once. We have to
destroy
' the additional reference without calling AddRef.
Dim lNullPtr As Long
CopyRef pRefDest:=pUnk, pSrc:=VBA.VarPtr(lNullPtr), cb:=4&
End Function

and this function you can use in WM_INITDIALOG message handler

dim obj As MyClass,ofn As OPENFILENAME

Case WM_INITDIALOG
CopyMemory ofn, lParam, LenB(ofn)
Set obj = VBRefFromPtr(ofn.lCustData)
MsgBox obj.Name 'Now we got reference to calling object instance
Set obj = Nothing
--

-------------------------------------------

Asko Telinen

department of information technology
Jyväskylä University

asko.t...@kanetti.com

-------------------------------------------

"Asko Telinen" <asko.t...@kanetti.com> wrote in message
news:OxE7LqaFBHA.1324@tkmsftngp02...

Rob

unread,
Jul 27, 2001, 2:34:21 AM7/27/01
to
Roger and Asko:

Thanks for your replies. However, I think I need to restate, differently, what
I am after. Forget Class modules for the moment:

In a commercial app like PhotoShop, when you open the SaveAs dialog, the active
image's title appears in the dialog's File Name box (i.e. "MyPicture.bmp") - the
Initial File. While the dialog is open, you can select from a list of other
File Types from the File Type combo box. If you select, say, JPEG, the text in
the File Name box is changed to "MyPicture.jpg".

How, in VB, can you make the Common Dialog control and/or API CommonDialog do
the same?

Rob

Hercules Gunter

unread,
Jul 27, 2001, 9:17:38 AM7/27/01
to
Rob wrote:

> Roger and Asko:
>
> Thanks for your replies. However, I think I need to restate, differently, what
> I am after. Forget Class modules for the moment:
>
> In a commercial app like PhotoShop, when you open the SaveAs dialog, the active
> image's title appears in the dialog's File Name box (i.e. "MyPicture.bmp") - the
> Initial File. While the dialog is open, you can select from a list of other
> File Types from the File Type combo box. If you select, say, JPEG, the text in
> the File Name box is changed to "MyPicture.jpg".
>
> How, in VB, can you make the Common Dialog control and/or API CommonDialog do
> the same?

Just list the file types you want. The syntax, straight out of MSDN, is:
object.Filter [= description1 |filter1 |description2 |filter2...]
so you want things like
object.filter = "Text files|*.txt|Excel
spreadsheets|*.xls|Bitmaps|*.bmp,*.jpg,*.gif"


Rob

unread,
Jul 27, 2001, 1:38:33 PM7/27/01
to
Yes, I know how to include filters in the dialog. That is not what my question was
about.

Rob

Richard Jalbert

unread,
Jul 27, 2001, 4:49:44 PM7/27/01
to
On Fri, 27 Jul 2001 10:38:33 -0700, Rob <ic...@abac.com> wrote:

>Yes, I know how to include filters in the dialog. That is not what my question was
>about.

You have to detect the new extension and do some code that will output
your in-memory information to the new format and write that new format
to the disk.

Get thee hence to

www.wotsit.org

for the biggest collection of fileformat ever.

I practiced changing RAW files to BMPs and it works.

=====================================================
Did you know my cats can type by sitting *on* my
keyboard?
rich...@sympatico.ca.No.Spam
http://www3.sympatico.ca/richmann/
http://www.geocities.com/richmannsoft/index.html
=====================================================

Rob

unread,
Jul 27, 2001, 5:51:49 PM7/27/01
to
Amazing. I was in no way asking about how to actually save a particular file format.
That is already taken care of.

Thanks anyway. I'll just have to leave it as is and go on to something else.

If anyone has ThumbsPlus or PhotoShop have a look at their SaveAs Dialog. In ThumbsPlus,
for example, if I am viewing a file named "Marybeth.tif", the SaveAs dialog displays
"Marybeth.tif" as the Filename as it also does in VB. If I make a selection from the
File Type dropdown, say, ".jpg", in ThumbsPlus (or PhotoShop), the Filename in the
Filename box changes to "Marybeth.jpg" and, of course, the listview contents changes
accordingly. In VB the listview updates as expected, but the Filename does not - it
still shows the original Filename, 'Marybeth.tif". Yes, of course, you can ensure that
the correct format is used in the "Save" routine, but, it seems to be a bit of a 'Kludge'
approach.


Rob

Brad Martinez

unread,
Jul 27, 2001, 8:31:39 PM7/27/01
to

Rob

>In a commercial app like PhotoShop, when you open the SaveAs dialog, the active
>image's title appears in the dialog's File Name box (i.e. "MyPicture.bmp") - the
>Initial File. While the dialog is open, you can select from a list of other
>File Types from the File Type combo box. If you select, say, JPEG, the text in
>the File Name box is changed to "MyPicture.jpg".
>
>How, in VB, can you make the Common Dialog control and/or API CommonDialog do
>the same?

Though not trivial, this can be accomplished using the
GetSaveFileName API (it's also possible using the VB
CommonDialog control but would much more of a chore).
In a nutshell, you'd want to do something like the following:

- store your individual filter values (extensions, not descriptions)
in a one-based array that correspond to the filters you specify
for the OPENFILENAME.lpstrFilter member

- specify OFN_ENABLEHOOK Or OFN_EXPLORER for the
OPENFILENAME.flags member

- in OFNHookProc on WM_NOTIFY/CDN_TYPECHANGE,
first fill the OPENFILENAME struct from OFNOTIFY.pszFile
(make sure that you define a 2nd OPENFILENAME struct
whose String members [lpstr...] are changed to Long, i.e.
OPENFILENAMEPTR), then get the new filter index from
the nFilterIndex member, see:
http://msdn.microsoft.com/library/en-us/winui/hh/winui/commdlg3_4bs5.asp

- get the current filename string in the "File name:" edit
control with the CDM_GETSPEC message, see:
http://msdn.microsoft.com/library/en-us/winui/hh/winui/commdlg3_4nqb.asp

- parse the filename string for the previous filter (extension)
string from the filter array index (you'll have to cache the
index value either in a static or module level variable, make
sure that you set this to the value that you specify for
OPENFILENAME.nFilterIndex + 1 before calling GetSaveFileName)

- if found, replace the extension in the filename string with
the extension at the element in your extension array
corresponding to the current nFilterIndex value, if not
found, just append the extension to the filename.

- add the new filename back to the edit control (using the
edit control's window ID, it's &H480 (see FileOpen.dlg and
dlgs.h if you have access to the PSDK or VC include source
files) with CDM_SETCONTROLTEXT, see
http://msdn.microsoft.com/library/en-us/winui/hh/winui/commdlg3_4lf8.asp

Easier done than said... Though not exactly what you want
to do, for an example of doing similar things in the API
common dialog's hook procedure, see the first demo at:
http://www.mvps.org/btmtz/_misc Spend some time
researching this on MSDN, with some time you should
get it. If you get real hung up on something, post back
here and we'll try to get things going...

--
Brad Martinez, http://www.mvps.org
Please direct questions/replies to the newsgroup


Hercules Gunter

unread,
Jul 28, 2001, 9:23:05 AM7/28/01
to
Sorry, Rob, I abase myself - the specific nature of your query was in what you said,
although I confess I misunderstood; the extension-changing did not come across as the
focus of the question, multiple file types did. The functionality in VB doesn't give
you that kind of fine-grained control, and you probably need to research the API calls
required - as you obviously realise seeing where you posted the question. I'd suggest
the Windows Bible or similar reference.

Rob

unread,
Jul 28, 2001, 3:23:46 PM7/28/01
to
Brad:

Thanks for the info. I'll have to "digest" it all and see what I can come up with.

Rob

0 new messages