Solved

Common Dialog/Save -- Selected file format?

Posted on 1997-05-30
7
254 Views
Last Modified: 2008-07-03
In an application I'm making in VB 4 Pro, I use the CommonDialog's FileSave method to present a "save file" dialog box. The file type combo box has two choices, *.dwg and *.dxf.



Now, in Windows 95 the file type selection works as I thought it would; the appropriate (ie. the selected ) file suffix is added to the file name. But in Windows 3.1, it isn't. And I can't find any (other) way to check what file format the user selected. Can anyone help me out on this one?





Thanks in advance,



MacSverre
0
Comment
Question by:MacSverre
  • 3
  • 3
7 Comments
 
LVL 3

Expert Comment

by:ChrisLewis
ID: 1426645
The common dialog control is nto very restrictive.  You can basically enter any extention that you want into the dialog, and the dialog will just go on it's merry way, returning whatever the user typed.

Here's a solution.

After the Common dialog has been processed, use the FilterIndex to figure out what filter the user has selected.  Compare that with the FileTitle property to see if the user has indeed typed the same extention that they have selected.

+-----+
'set you Common dialog stuff here
CommonDlg1.SHowSave
Select case commondlg1.FilterIndex
  Case 0 'DWG
    strCompare = ".DWG"
  Case 1 'DXF
    strCompare = ".DXF"
  CASE ELSE
END SELECT
 
If RIGHT$(commondlg1.FileTitle,4) ,. strCompare THEN
  MSgbox "Invalid file name"
  'or fix the extention
  'Cancel Save
ENDIF
+-----+


Hope this helps

Chris
0
 
LVL 2

Author Comment

by:MacSverre
ID: 1426646
I'm afraid this doesn't work. The filterindex property is just there for setting the default file type in a list of file types. If you read it, it returns whatever you set it to in code (or in the properties window). If you haven't set it at all, it returns zero.



Anyone else?
0
 
LVL 1

Expert Comment

by:ywoedta
ID: 1426647
Why don't you just check the filename the dialog returns and check the terminal three characters?  cut them off with the "right" function, then you know which extension was chosen.  Hope this helps...
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 2

Author Comment

by:MacSverre
ID: 1426648
Sorry, but if you read my original question, you can see that my problem is that Win 3.1 doesn't add the extension of the selected file format. That makes it kinda hard to check the suffix...

Anyone else?
0
 
LVL 3

Expert Comment

by:ChrisLewis
ID: 1426649
Interesting.  This works in VB 5 with out any problems.  VB4's help file says that FilterIndex "Returns or sets a default filter"

I did try it in VB 4/16 and it doesn't work.  

You could try DefaultEXT.  DefaultEXT will set a default extension, but ignores the filter, so you only get one default.

Obviously, you cannot change to VB5 if you're in a Win 3.x environment.

This is what I turned up in the MS KB on FilterIndex:

Article ID: Q106682
PRB: Default Extension Ignores File Type in VB Common Dialog

Essentially, MS says that it screwed up, and that File type does not override DefaultExt, and it's not like anything else in Windows.

It suggests writing a DLL to wrap around the CommonDialog functions in COMMDLG.DLL.

From Q106682:
Workaround for Windows API Programmers

Visual Basic's common dialog custom controls for Open and Save As pass their FilterIndex property to the Windows API function GetOpenFileName. GetOpenFileName is located in the Windows COMMDLG.DLL file. However, Visual Basic ignores the nFilterIndex value that the GetOpenFileName function returns. By design, your Visual Basic program cannot access the structure returned by the GetOpenFileName function, even by calling API routines.

You can write your own DLL routine in C to call the Windows common dialog routines located in COMMDLG.DLL. Then call this DLL from Visual Basic. The following documentation from the Windows Software Development Kit (SDK) explains how to use the nFilterIndex element of the structure passed to GetOpenFileName:

   nFilterIndex:
   Specifies an index into the buffer pointed to by the lpstrFiler member.
   The system uses the index value to obtain a pair of strings to use as
   the initial filter description and filter pattern for the dialog box.
   The first pair of strings has an index value of 1. When the user chooses
   the OK button to close the dialog box, the system copies the index of
   the selected filter strings into this location. If the nFilterIndex
   member is 0, the filter in the buffer pointed to by the
   lpstrCustomFilter member is used. If the nFilterIndex member is 0 and
   the lpstrCustomFilter member is NULL, the system uses the first filter
   in the buffer pointed to by the lpstrFilter member. If each of the three
   members is either 0 or NULL, the system does not use any filters and
   does not show any files in the File Name list box of the dialog box.


0
 
LVL 3

Accepted Solution

by:
ChrisLewis earned 100 total points
ID: 1426650
OK, Just because I like to figure out things that MS says can't be done, here is a set of API calls that will do what you want to do.  Bastardized it from an Access 2.0 project that I was doing.  

Module:
'----------------------------------------+----------------------------------------'
'----------------------------------------+----------------------------------------'
Option Explicit

'----------------------------------------+----------------------------------------'
' Global Declaration Section
'----------------------------------------+----------------------------------------'
Type tagOPENFILENAME
     lStructSize As Long
     hwndOwner As Integer
     hInstance As Integer
     lpstrFilter As Long
     lpstrCustomFilter As Long
     nMaxCustFilter As Long
     nFilterIndex As Long
     lpstrFile As Long
     nMaxFile As Long
     lpstrFileTitle As Long
     nMaxFileTitle As Long
     lpstrInitialDir As Long
     lpstrTitle As Long
     Flags As Long
     nFileOffset As Integer
     nFileExtension As Integer
     lpstrDefExt As Long
     lCustData As Long
     lpfnHook As Long
     lpTemplateName As Long
End Type
Declare Function GetOpenFileName Lib "COMMDLG.DLL" (OPENFILENAME As tagOPENFILENAME) As Integer
Declare Function GetSaveFileName Lib "COMMDLG.DLL" (OPENFILENAME As tagOPENFILENAME) As Integer
Declare Function lstrcpy Lib "Kernel" (ByVal lpDestString As Any, ByVal lpSourceString As Any) As Long

Global OPENFILENAME As tagOPENFILENAME

'----------------------------------------+----------------------------------------'
' Open File Constants
'----------------------------------------+----------------------------------------'
Global Const OFN_READONLY = &H1
Global Const OFN_OVERWRITEPROMPT = &H2
Global Const OFN_HIDEREADONLY = &H4
Global Const OFN_NOCHANGEDIR = &H8
Global Const OFN_SHOWHELP = &H10
Global Const OFN_ENABLEHOOK = &H20
Global Const OFN_ENABLETEMPLATE = &H40
Global Const OFN_ENABLETEMPLATEHANDLE = &H80
Global Const OFN_NOVALIDATE = &H100
Global Const OFN_ALLOWMULTISELECT = &H200
Global Const OFN_EXTENSIONDIFFERENT = &H400
Global Const OFN_PATHMUSTEXIST = &H800
Global Const OFN_FILEMUSTEXIST = &H1000
Global Const OFN_CREATEPROMPT = &H2000
Global Const OFN_SHAREAWARE = &H4000
Global Const OFN_NOREADONLYRETURN = &H8000
Global Const OFN_NOTESTFILECREATE = &H10000
Global Const OFN_SHAREFALLTHROUGH = 2
Global Const OFN_SHARENOWARN = 1
Global Const OFN_SHAREWARN = 0
'----------------------------------------+----------------------------------------'
' SAveCommDlg - Save pen File Common Dialog Function - used to call the COMMDLG.DLL
'   to create a file for saving...that file.
'   Usage:
'  strFilter = "Ext 1" & chr$(0) & ".EX1" & chr$(0) & "Ext 2" & chr$(0) & ".EX2" & chr$(0) &
'     strString = SaveCommDlg(Title,Filter,DefaultFile, DefaultEXT, FilterIndex)
'     If Len(strString) = 0 Then
'       Error
'     Else
'       Do something with this file name
'     End if
'  Filterindex = 1,2 etc based off of FileType selected
'   creatively pilfered from MS tech net!
'----------------------------------------+----------------------------------------'
Function SaveCommDlg(strParmTitle As String, strParmFilter As String, strParmFileName As String, strParmDefaultEXT As String, ByRef nRetFilterIndex As Long) As String
  Dim strFilter As String, strFileName As String, strFileTitle As String, strDefExt As String
  Dim strTitle As String, strCurDir As String
  Dim APIResults As Integer

  On Error GoTo SaveCommDlg_Err
   
  SaveCommDlg = ""
  'Define the strFilter string and allocate space in the "c" string
  strFilter = strParmFilter
 
  'Allocate string space for the returned strings.
  strFileName = strParmFileName & Chr$(0) & Space$(255) & Chr$(0)
  strFileTitle = Space$(255) & Chr$(0)
 
  ' Give the dialog a caption title.
  strTitle = strParmTitle & Chr$(0)
 
  strDefExt = strParmDefaultEXT & Chr$(0)
 
  ' Set up the default directory
  strCurDir = CurDir & Chr$(0)
 
  ' Set up the data structure before you call the GetOpenFileName
  OPENFILENAME.lStructSize = Len(OPENFILENAME)
  'If the OpenFile Dialog box is linked to a form use this line.
  'It will pass the forms window handle.
  'OPENFILENAME.hwndOwner = Screen.ActiveForm.hWnd
  'If the OpenFile Dialog box is not linked to any form use this line.
  'It will pass a null pointer.
  'OPENFILENAME.hwndOwner = 0&
 
  'No... use this...
  'Get Window Handle
  '*** THIS NEEDS A VALID WINDOWHANDLE
  OPENFILENAME.hwndOwner = Form1.hWnd

  OPENFILENAME.lpstrFilter = lstrcpy(strFilter, strFilter)
  OPENFILENAME.nFilterIndex = 1
  OPENFILENAME.lpstrFile = lstrcpy(strFileName, strFileName)
  OPENFILENAME.nMaxFile = Len(strFileName)
  OPENFILENAME.lpstrFileTitle = lstrcpy(strFileTitle, strFileTitle)
  OPENFILENAME.nMaxFileTitle = Len(strFileTitle)
  OPENFILENAME.lpstrTitle = lstrcpy(strTitle, strTitle)
  "NOTE: These flags are set for the original OPENFILE calls, but they seem to work now...
  OPENFILENAME.Flags = OFN_FILEMUSTEXIST Or OFN_HIDEREADONLY Or OFN_PATHMUSTEXIST Or OFN_FILEMUSTEXIST
  OPENFILENAME.lpstrDefExt = lstrcpy(strDefExt, strDefExt)
  OPENFILENAME.hInstance = 0
  OPENFILENAME.lpstrCustomFilter = 0
  OPENFILENAME.nMaxCustFilter = 0
  OPENFILENAME.lpstrInitialDir = lstrcpy(strCurDir, strCurDir)
  OPENFILENAME.nFileOffset = 0
  OPENFILENAME.nFileExtension = 0
  OPENFILENAME.lCustData = 0
  OPENFILENAME.lpfnHook = 0
  OPENFILENAME.lpTemplateName = 0
 
  '* This will pass the desired data structure to the Windows API,
  '* which will in turn it uses to display the Open Dialog form.
  APIResults = GetSaveFileName(OPENFILENAME)
 
  If APIResults <> 0 Then
    ' Note that FileName$ will have an embedded Chr$(0) at the end.
    strFileName = Left$(strFileName, InStr(strFileName, Chr$(0)) - 1)
  Else
    strFileName = ""
  End If
  'Return Filter index  
  nRetFilterIndex = OPENFILENAME.nFilterIndex
  SaveCommDlg = strFileName

SaveCommDlg_Exit:
  Exit Function

SaveCommDlg_Err:
  MsgBox Error
  SaveCommDlg = ""
  Resume SaveCommDlg_Exit
End Function


'----------------------------------------+----------------------------------------'
'----------------------------------------+----------------------------------------'

Form with one Command button on it:
Private Sub Command1_Click()
  Dim strFile As String
  Dim strFilter As String
  Dim strCompare as String
  Dim lngFilterIndex As Long
   
  strFilter = "DWG Files" & Chr$(0) & "*.DWG" & Chr$(0) & "DXF Files" & Chr$(0) & "*.DXF" & Chr$(0)
 
  strFile = SaveCommDlg("Save file as...", strFilter, "TEST.DWG", "DWG", lngFilterIndex)

Select case lngFilterIndex
 Case 1 'DWG
  strCompare = ".DWG"
 Case 2 'DXF
  strCompare = ".DXF"
  CASE ELSE
END SELECT

If RIGHT$(strFile ,4) <> strCompare THEN
  MSgbox "File extention and File type do not match"
  'or fix the extention
  'Cancel Save
ENDIF

End Sub
'----------------------------------------+----------------------------------------'
'----------------------------------------+----------------------------------------'


This does work in VB 4/16 , but you're going to have to still check to see if the filterIndex and the ext are matching.  The CommonDialog DLL doesn't force the defaultExt and FileType to match. But you should be able to trap the filename and FilterIndex at this point and insure correctness.

Hope this helps, and sorry the first one didn't work

Chris
0
 
LVL 2

Author Comment

by:MacSverre
ID: 1426651
Thank you very much! I've done a "work-a-round" that I will use in my current project, but I _will_ use this in later projects.

About the extension: It doesn't really matter to me if the user types in a different extension, as long a I can check which file format was selected.

Again, thanks!



   MacSverre
0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

Introduction While answering a recent question about filtering a custom class collection, I realized that this could be accomplished with very little code by using the ScriptControl (SC) library.  This article will introduce you to the SC library a…
If you have ever used Microsoft Word then you know that it has a good spell checker and it may have occurred to you that the ability to check spelling might be a nice piece of functionality to add to certain applications of yours. Well the code that…
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…

759 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now