Enhanced File Save Dialog...

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Enhanced File Save Dialog...

Christopher J. Demers
I am posting this for two reasons.  It may be useful for others that might
need to implement related functionality, and to see if any Windows API gurus
can help me understand some interesting nuances and maybe improve the
approach.

I have two different file formats (ie: file.exa and file.exb) and want users
to choose which format they want to save via the file dialog type drop down
box.  The default behavior of the FileSaveDialog is to not change the
extension of the file when the type is changed.  I wanted the functionality
of the Word or Excel file save dialog where when the type is changed the
file extension is updated.  After some digging it seemed that this
functionality was only available via hooking some code in via a callback.
So that is what I did, and after quite a few image crashes I got it working.

The first thing I had to do was to edit the OPENFILENAME class
<<defineFields method to remove the beFiller message from the lpfnHook
field.  My first curiosity is why was this marked as filler?  Was this a
philosophical decision because OA had not tested that element, or was there
a technical reason for this?  It seems odd to properly define a known field
and then make it unusable.  After removing beFiller it seems to work fine.

This is the method that handles the callback (see further comments bellow):
=====================
callBackhWnd: hWnd uMsg: uMsg lp: lp pData: pData
"Private - cdemers - 11/14/2005"
| dialogView formatCb filenameTb fileName fileTypeIndex extension idFormat
idFilename nmHdr |
idFormat := 1136. "ID_FORMAT"
idFilename := 1152.
Transcript nextPutAll: (Array with: uMsg with: hWnd with: lp with: pData)
displayString; cr.
(uMsg = 78 "WM_NOTIFY") ifTrue: [ nmHdr := NMHDR fromAddress: pData.
Transcript nextPutAll: nmHdr displayString; cr.
nmHdr code = -607 "CDN_TYPECHANGE" ifTrue: [
"For some reason this message is sent twice, it does not seem to cause a
problem though."
dialogView := (View fromHandle: hWnd) creationParentView.
formatCb := dialogView getItem: idFormat.
fileTypeIndex := formatCb sendMessage: 327. "CB_GETCURSEL"
extension := (fileTypes at: fileTypeIndex + 1) last.
"If there is more than one extension specified for the type get the first."
"Since the extensions always start with '.' we skip it."
extension := (extension subStrings: $;) first copyFrom: 2.
filenameTb := dialogView getItem: idFilename.
fileName := filenameTb text.
fileName := File change: fileName extension: extension.
filenameTb text: fileName]].
^0
=====================

This is the logged text when run on Windows XP SP2:
===========
78, 16r1A09B4, 0, 12639608
a NMHDR(hwndFrom=4983232 idFrom=0 code=-607)
49263, 16r1A09B4, 1136, 1
78, 16r1A09B4, 0, 12639608
a NMHDR(hwndFrom=4983232 idFrom=0 code=-607)
49263, 16r1A09B4, 1136, 1
78, 16r1A09B4, 0, 12640988
a NMHDR(hwndFrom=4983232 idFrom=0 code=-602)
2, 16r1A09B4, 0, 0
130, 16r1A09B4, 0, 0
==============

My first attempt was to look for a uMsg of 49263 and an lp of 1136 because I
knew 1136 was the ID of the file type drop down box.  Unfortunately I did
not know what 49263 meant, and even more unfortunately on Windows 98 I got a
different uMsg of 50467.  Does anyone know what this message means?

I ultimately decided to look for a uMsg of 78, which I know is WM_NOTIFY and
then look for an NMHDR code of -607, which is CDN_TYPECHANGE.  However I
notice that message gets sent twice, so my code runs twice.  While not
ideal, it does not seem to be cause any real problems, so I left it that
way.

Another interesting nuance is that in MitSciEnhancedFileSaveDialog class
<<initialize I have to bitOr OFN_ENABLESIZING with the style to get a
resizable dialog.  For some reason this is not needed with the default
implementation.  Why?

I don't work with low-level Windows API's very often so I have cobbled
together a rather limited understanding.  If someone with a more
comprehensive understanding can suggest a more elegant implementation I am
receptive.

The package can be downloaded here (Only load this into a test image, it
will replace the OPENFILENAME class <<defineFields method, use and
experiment at your own risk.):
http://www.cjd77.com/smalltalk/temp/MitSciEnhancedFileSaveDialog.pac

Comments and suggestions are welcome.

Chris


Reply | Threaded
Open this post in threaded view
|

Re: Enhanced File Save Dialog...

Randy Coulman-2
Christopher J. Demers wrote:
> I am posting this for two reasons.  It may be useful for others that might
> need to implement related functionality, and to see if any Windows API gurus
> can help me understand some interesting nuances and maybe improve the
> approach.
>

I'm long past being a Windows API guru, but I'll try to help anyway.

> I have two different file formats (ie: file.exa and file.exb) and want users
> to choose which format they want to save via the file dialog type drop down
> box.  The default behavior of the FileSaveDialog is to not change the
> extension of the file when the type is changed.  I wanted the functionality
> of the Word or Excel file save dialog where when the type is changed the
> file extension is updated.  After some digging it seemed that this
> functionality was only available via hooking some code in via a callback.
> So that is what I did, and after quite a few image crashes I got it working.
>

This behavior doesn't sound like what I remember, so I went digging in
MSDN.  I found the following information, but haven't tested any of it,
so maybe the docs are incorrect in this case, or maybe your situation
doesn't fit what it says.

(Sorry for any link wrapping)

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/commondialogboxlibrary/aboutcommondialogboxes/openandsaveasdialogboxes.asp

says this:

"For Explorer-style dialog boxes, the default extension may change if
the user selects a different filter. If the user selects a filter whose
first pattern is of the form *. xxx (that is, the extension does not
include a wildcard character), the dialog box uses xxx as the default
extension. This occurs only if you specified a default extension in the
lpstrDefExt member of the OPENFILENAME structure. For example, if the
user selects the "Source\0*.C;*.CXX\0" filter, the default extension
changes to "C". However, if you had defined the filter as
"Source\0*.C*\0", the default extension would not change because the
extension includes a wildcard."

See also the docs for the lpstrDefExt member of the OPENFILENAME structure.

I think that if you added separate filter patterns for *.exa and *.exb,
set the lpstrDefExt member to 'exa', and set the nFilterIndex member to
1, you'd get the behavior you want.

Randy
--
Randy Coulman
NOTE: Reply-to: address is spam-guarded.  Reassemble the following to
reply directly:
rcoulman at charter dot net


Reply | Threaded
Open this post in threaded view
|

Re: Enhanced File Save Dialog...

Christopher J. Demers
"Randy Coulman" <[hidden email]> wrote in message
news:j6yff.29956$[hidden email]...
> Christopher J. Demers wrote:
...

>> I have two different file formats (ie: file.exa and file.exb) and want
>> users
>> to choose which format they want to save via the file dialog type drop
>> down
>> box.  The default behavior of the FileSaveDialog is to not change the
>> extension of the file when the type is changed.  I wanted the
>> functionality
>> of the Word or Excel file save dialog where when the type is changed the
>> file extension is updated.  After some digging it seemed that this
>> functionality was only available via hooking some code in via a callback.
>> So that is what I did, and after quite a few image crashes I got it
>> working.
>>
>
> This behavior doesn't sound like what I remember, so I went digging in
> MSDN.  I found the following information, but haven't tested any of it, so
> maybe the docs are incorrect in this case, or maybe your situation doesn't
> fit what it says.
>
> (Sorry for any link wrapping)
>
> http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/commondialogboxlibrary/aboutcommondialogboxes/openandsaveasdialogboxes.asp
>
...
> See also the docs for the lpstrDefExt member of the OPENFILENAME
> structure.
>
> I think that if you added separate filter patterns for *.exa and *.exb,
> set the lpstrDefExt member to 'exa', and set the nFilterIndex member to 1,
> you'd get the behavior you want.

Thanks for the info.  While I think the information you have found is
correct, I believe that it falls short of what I want.  It appears to only
change the default extension, not the extension of the actual file name
selected.  It seems that the default extension is only used when the entered
file name does not have an extension.

This is the code I tried, let me know if I have missed something.
==========
fsd := FileSaveDialog new.
fsd fileTypes: #(#('File exa (*.exa)' '*.exa') #('File exb (*.exb)'
'*.exb')).
fsd model: 'test.exa'.
fsd winStruct lpstrDefExt: 'exa'.
fsd winStruct nFilterIndex: 1.
fsd showModal.
==========

Notice that the file name defaults to 'test.exa'.  If the user selects the
*.exb filter I want the extension of the selected file to change to 'exb'.
Basically I want it to work the way it does in Word, if you change the
filter from *.doc to *.rtf the extension of the file name actually changes.
This is something I would have expected to be built into the control, but it
does not seem to be.  I am happy to be proved wrong though. ;)

Chris


Reply | Threaded
Open this post in threaded view
|

Widely used email [was: Enhanced File Save Dialog...]

Chris Uppal-3
> "Randy Coulman" <[hidden email]> wrote in message

This is completely off-topic.

Randy, I didn't see your message that Christopher's replying to.  After a bit
of digging I found that it's because I have "[hidden email]" in my killfile
(probably to block one of the bozos who dump garbarge in the Java newsgroups).
I'm not suggesting you should change your email to please me, but you should be
aware that you are using an email that is also used by thousands of other
people on Usenet.  (Google thinks there are over a million posts by "you"...)

    -- chris