Modula-2 home

  Home  
  Tutorial  
  Win32 API  
  Reference  
  Projects  
  Source code  
  Links  
Shows printer-friendly 
version in new window  

 

More on the Windows "Save as" common dialog box

For Stony Brook Modula-2

By Frank Schoonjans (frank.schoonjans@ugent.be)

 

Sizing grip

When, on our previous page on A customized Windows "Save as" common dialog box, we added the flags COMMDLG.OFN_EXPLORER and COMMDLG.OFN_ENABLEHOOK, our dialog box lost its sizing grip (in the lower right corner of the dialog box). To correct for this, we must add (using the BOR operator) the flag COMMDLG.OFN_ENABLESIZING

 

A Places Bar (Windows 2000 and XP)

In Windows 2000 and XP the Save As and Open dialog boxes contain a Places Bar which contains a list of shortcuts to locations where you are likely to save files, such as My Documents, Desktop and Web Folders.

We will, in short, describe how to obtain this new style dialog box.

Step 1: Get the Windows version

First we must know under which version of Windows our program is running. We have a little procedure for this:

PROCEDURE GetWindowsVersion(VAR major,minor,build : INTEGER): INTEGER;
VAR OsVersion : WIN32.OSVERSIONINFO;
BEGIN
    OsVersion.dwOSVersionInfoSize:=SIZE(OsVersion);
    FUNC WIN32.GetVersionEx(OsVersion);
    major:=OsVersion.dwMajorVersion;
    minor:=OsVersion.dwMinorVersion;
    build:=WINUSER.LOWORD(OsVersion.dwBuildNumber);
    RETURN OsVersion.dwMajorVersion;
END GetWindowsVersion;

This procedure will return the major, minor and build number of windows in the respective parameters of the procedure. For our convenience, we also let it return the major version number.

Step 2: Adding new fields to the OPENFILENAME structure.

For our purpose, we must revise the OPENFILENAME structure (as exported by the current SBM2 COMMDLG module) as follows:

TYPE OPENFILENAMEnew = RECORD
         OpenFileOld    : COMMDLG.OPENFILENAME;
         (* new fields follow *)
         pvReserved     : ADDRESS;
         dwReserved     : DWORD;
         FlagsEx        : DWORD;
     END;

The pvReserved field must be initialised with the value NIL and dwReserved and FlagsEx must be initialised with the value 0.

Making it work

The principle is that if we find the Windows version to be higher than or equal to 5 (meaning it is Windows 2000 or XP), we will ask Windows to use the new version of the OPENFILENAME structure OPENFILENAMEnew. If the Windows version is less than 5, we will ask Windows to ignore the new fields of the structure. How do we ask Windows this? By initialising the lStructSize member of the OPENFILENAME structure with the size of the new record, or with the size of the old record respectively. For the latter purpose, a constant is defined which is equal to the SIZE of the old structure.

In short, the code will eventually look like this:

CONST OPENFILENAME_SIZE_VERSION_400 = 76;

VAR OpenFile : OPENFILENAMEnew;

BEGIN
    WITH OpenFile DO
      WITH OpenFileOld DO
        IF GetWindowsVersion(dummy,dummy,dummy)>=5 THEN
           lStructSize    := SIZE(OpenFile);
        ELSE
           lStructSize    := OPENFILENAME_SIZE_VERSION_400;
        END;
        (* and also initialise the other members
           ...
        *)
        pvReserved        := NIL;
        dwReserved        := 0;
        FlagsEx           := 0;
      END;
    END;

 

Handling shortcuts

The normal behaviour for the Open and Save as dialog boxes when you click on a shortcut (for instance to another folder on the hard disk), is to -obviously- go to the place the shortcut points to, but also to display the shortcut as a *.lnk file in the file name box. The latter is not very user friendly and we would like to have this file name removed from the file name box.

For this, we insert the following code into the hook procedure described on the previous page A customized Windows "Save as" common dialog box.

CONST (* ... *)
      edt1    = 0480H;

BEGIN
	(* ... *)

	CASE uint OF
    (* ... *)
    | WM_NOTIFY     :
        lpnmhdr:=CAST(LPNMHDR,lparam);
        CASE lpnmhdr^.code OF
        (* ... *)
        | COMMDLG.CDN_FOLDERCHANGE :
            SendDlgItemMessage(hwndParent,edt1,WM_GETTEXT,SIZE(str)-1,CAST(LPARAM,ADR(str)));
            len:=Strings.Length(str);
            IF len>4 THEN
                Strings.Extract(str,len-4,4,str);
                Strings.Capitalize(str);
                IF Strings.Equal(str,".LNK") THEN
                    str:="";
                    SendDlgItemMessage(hwndParent,edt1,WM_SETTEXT,0,CAST(LPARAM,ADR(str)));
                END;
             END;
         ELSE
         END;
    (* ... *)

Feedback

So, I hope this code is usefull for some of you and I'm looking forwards to reading your comments.

Frank