Welcome to MSDN Blogs Sign in | Join | Help

Microsoft Excel

The team blog for Microsoft Excel and Excel Services.
Use the VBA SaveAs Method in Excel 2007

Today’s author is Ron de Bruin , an Excel MVP. You can find more useful tips and links to Excel add-ins at his website: http://www.rondebruin.nl/

You see a lot of old SaveAs code that does not specify the FileFormat
parameter. In Excel versions before Excel 2007, code without this parameter
will not cause too many problems because Excel will use the current FileFormat
of the existing file -- and the default FileFormat for new files is a normal workbook. But because there are so many new file formats in Excel 2007, you shouldn't
use code that doesn’t specify the FileFormat parameter.

In Excel 2007, the SaveAs method requires you to provide both the FileFormat parameter and the correct file extension.

For example, in Excel 2007 this line of code will fail if the ActiveWorkbook is not an .xlsm file:

ActiveWorkbook.SaveAs "C:\ron.xlsm"

But this code will always work:

ActiveWorkbook.SaveAs "C:\ron.xlsm", fileformat:=52 
' 52 = xlOpenXMLWorkbookMacroEnabled = xlsm (workbook with macro's in 2007)

These are the main file formats in Excel 2007:

51 = xlOpenXMLWorkbook (without macro's in 2007, .xlsx)
52 = xlOpenXMLWorkbookMacroEnabled (with or without macro's in 2007, .xlsm)
50 = xlExcel12 (Excel Binary Workbook in 2007 with or without macro's, .xlsb)
56 = xlExcel8 (97-2003 format in Excel 2007, .xls)

Note: I always use the FileFormat numbers instead of the defined constants
in my code so that it will compile OK when I copy the code into an Excel
97-2003 workbook. (For example, Excel 97-2003 won't know what the
xlOpenXMLWorkbookMacroEnabled constant is.)

Example

At the end of this section is a basic VBA code example for a macro named Copy_ActiveSheet_New_Workbook() that copies the ActiveSheet to a new Workbook and then saves it in a format that matches the file extension of the parent workbook.
Note: You can use this macro in Excel 97-2007.

If you run the code in Excel 2007, it will look at the FileFormat of the parent workbook and save the new file in that format. However, if the parent workbook is an .xlsm file and there is no VBA code in the new workbook, the code will save the new file as an .xlsx file.
If the parent workbook is not an .xlsx, .xlsm or .xls file, then it will be saved as an .xlsb file.

If you always want to save in a certain format you can replace this part of the macro:

Select Case Sourcewb.FileFormat
Case 51: FileExtStr = ".xlsx": FileFormatNum = 51
Case 52:
    If .HasVBProject Then
        FileExtStr = ".xlsm": FileFormatNum = 52
    Else
        FileExtStr = ".xlsx": FileFormatNum = 51
    End If
Case 56: FileExtStr = ".xls": FileFormatNum = 56
Case Else: FileExtStr = ".xlsb": FileFormatNum = 50
End Select
With the single line of code from this list for the format you want to use:
FileExtStr = ".xlsb": FileFormatNum = 50 
FileExtStr = ".xlsx": FileFormatNum = 51
FileExtStr = ".xlsm": FileFormatNum = 52
FileExtStr = ".xls": FileFormatNum = 56

Or maybe you want to save the one sheet workbook to .csv, .txt, or .prn. (you can use this also if you run the macro in Excel 97-2003)

FileExtStr = ".csv": FileFormatNum = 6
FileExtStr = ".txt": FileFormatNum = -4158
FileExtStr = ".prn": FileFormatNum = 36

Here’s the full code example.

Sub Copy_ActiveSheet_New_Workbook()
'Working in Excel 97-2007
    Dim FileExtStr As String
    Dim FileFormatNum As Long
    Dim Sourcewb As Workbook
    Dim Destwb As Workbook
    Dim TempFilePath As String
    Dim TempFileName As String

    With Application
        .ScreenUpdating = False
        .EnableEvents = False
    End With

    Set Sourcewb = ActiveWorkbook

    'Copy the sheet to a new workbook
    ActiveSheet.Copy
    Set Destwb = ActiveWorkbook

    'Determine the Excel version and file extension/format
    With Destwb
        If Val(Application.Version) < 12 Then
            'You use Excel 97-2003
            FileExtStr = ".xls": FileFormatNum = -4143
        Else
            'You use Excel 2007
            'We exit the sub when your answer is NO in the security dialog that you
            'only see when you copy a sheet from a xlsm file with macro's disabled.
            If Sourcewb.Name = .Name Then
                With Application
                    .ScreenUpdating = True
                    .EnableEvents = True
                End With
                MsgBox "Your answer is NO in the security dialog"
                Exit Sub
            Else
                Select Case Sourcewb.FileFormat
                Case 51: FileExtStr = ".xlsx": FileFormatNum = 51
                Case 52:
                    If .HasVBProject Then
                        FileExtStr = ".xlsm": FileFormatNum = 52
                    Else
                        FileExtStr = ".xlsx": FileFormatNum = 51
                    End If
                Case 56: FileExtStr = ".xls": FileFormatNum = 56
                Case Else: FileExtStr = ".xlsb": FileFormatNum = 50
                End Select
            End If
        End If
    End With

    '    'If you want to change all cells in the worksheet to values, uncomment these lines.
    '    With Destwb.Sheets(1).UsedRange
    '        .Cells.Copy
    '        .Cells.PasteSpecial xlPasteValues
    '        .Cells(1).Select
    '    End With
    '    Application.CutCopyMode = False

    'Save the new workbook and close it
    TempFilePath = Application.DefaultFilePath & "\"
    TempFileName = "Part of " & Sourcewb.Name & " " & Format(Now, "yyyy-mm-dd hh-mm-ss")

    With Destwb
        .SaveAs TempFilePath & TempFileName & FileExtStr, FileFormat:=FileFormatNum
        .Close SaveChanges:=False
    End With

    MsgBox "You can find the new file in " & TempFilePath

    With Application
        .ScreenUpdating = True
        .EnableEvents = True
    End With
End Sub
Posted: Tuesday, July 07, 2009 8:39 PM by MRoberts

Comments

Andy said:

This works great! Thanks!

Except the worksheet that I am copying & saving has form controls on it, but I don't want them to be copied. How do I change the code to accommodate this?

Thanks,

Andy

andyngretch@Msn.com

# July 8, 2009 11:29 AM

Ron de Bruin said:

Hi Andy

See this page for code that you can add to the macro. If you need more help let me know.

http://www.rondebruin.nl/controlsobjectsworksheet.htm

# July 8, 2009 11:48 AM

Harlan Grove said:

Seems moderation kicked out my previous comments. I'll try again without code.

Your macro is gross overkill and could be tightened up considerably. However, there's a better way to handle the FileFormat parameter of the .SaveAs method call: use a private function. Pass that function a reference to the original workbook, and encapsulate the code to handle Excel 12+ file formats there rather than in the body of your macro.

Encapsulating picky details, especially those details necessary for handling differences between versions, is usually considered programming best practice. Dumping such details in ad hoc macros isn't programming best practice.

# July 10, 2009 3:02 PM

Ron de Bruin said:

Hi Harlan

I am sure there are better ways and please post them.

The problem with seperate functions is that readers from my site always forget to copy them in the module together with the macro.

So I like to add it to the macro so it is a copy/Paste for a user.

You will not now how many private many mails I get from people that forgot to copy the functions that i use on a few of my pages.

And remember Harlan I am a flower grower and no programmer.

Thanks for your reply

# July 10, 2009 3:32 PM

Weldon Dodd said:

The new file doesn't have any of the macro modules from the original workbook. Is there a way to pass modules to the new workbook? Ideally, I'd like to pass one module and not all of them.

Thanks!

# July 11, 2009 3:36 PM

Weldon Dodd said:

on re-reading I realized that my question is almost the opposite of Andy's. I am using a second worksheet (order history) to prepopulate the first worksheet (order sheet). I want the macros and buttons associated with the order sheet to continue to work in the new workbook that I save for each customer. I do not want the additional worksheets and the file generation macros from the original worksheet (which are all in a separate module from the user controls)

# July 11, 2009 3:43 PM

Ron de Bruin said:

Hi Weldon

Use a button of the control toolbox and add your code in the click event of this button.

This event is in the sheet module so your button will work

If you want to mail each sheet see also

http://www.rondebruin.nl/sendmail.htm

# July 11, 2009 4:31 PM

Rick Henderson said:

Interesting post Ron. Finally! I've found a VBA blog associated with Microsoft!

# July 16, 2009 10:14 AM

Jayson said:

One thing I've learned (the hard way of course) is that there are different FileFormatNum for an .xls created in xl2003 and xl2007.  If you are running xl2003 you should use -4143.  If you are running xl2007 then use 56.

I've used this bit of code before to take care of this.

If Val(Application.Version) < 12 Then

   'You use Excel 97-2003

   FileExtStr = ".xls": FileFormatNum = -4143

Else

   'you use excel 2007 or later

   FileExtStr = ".xls": FileFormatNum = 56

End If

# July 20, 2009 4:44 PM

Gary B said:

I liked your article, however, if the sheet that is being copied to a new file contains a chart, then "sometimes" the chart does not appear correctly (as if it has lost its data series) in the new file.

I have found it useful to save the file, with a new name (and a different fileformat), deleting any sheets taht are not required in the final workbook, and removing all vba as the original file has an "On Open" routine that is run, which i don't want run from the final file.

In other words, sometimes it is better to NOT copy a sheet to a new file, but rather copy the file and make changes to the new file.  Sometimes :-)

# July 23, 2009 2:19 AM

Ron de Bruin said:

Hi Gary

Thanks for you reply

I have this option also in my mail add-ins

http://www.rondebruin.nl/mail/add-in.htm

# July 23, 2009 10:58 AM
New Comments to this post are disabled
Page view tracker