HOWTO: Determine the Version of a Microsoft Excel Workbook

ID: Q178605


The information in this article applies to:
  • Microsoft Visual C++, 32-bit Editions, versions 5.0, 6.0
  • Microsoft Excel 97 for Windows
  • Microsoft Excel for Windows 95, versions 7.0, 7.0a
  • Microsoft Excel for Windows, versions 5.0, 5.0a, 5.0c


SUMMARY

This article demonstrates how to determine the version of a Microsoft Excel Workbook (.xls).


MORE INFORMATION

Microsoft Excel saves data using structured storage. In particular, it creates a data stream called "Workbook" (previously just "Book") where it saves the contents starting with a BOF (beginning of file) record. This record contains useful attributes of the workbook, as well as the version. The following Microsoft Visual C++ code demonstrates how to open the file, read it, and return the version number based on the BOF.

  1. Create a new "Win32 Console Application" in Microsoft Developer Studio.


  2. Add a C++ Source File (.cpp) to the project and add the following code to the source file:


  3. 
    #include <windows.h>
    #include <iostream.h>   // My additions
    
    // BOF record from Microsoft Excel
    typedef struct _xlbof
    {
       char bofMarker; // Should be 0x09
    
       char vers;  // Version indicator for biff2, biff3, and biff4
                   // = 0x00 -> Biff2
                   // = 0x02 -> Biff3
                   // = 0x04 -> Biff4
                   // = 0x08 -> Biff5/Biff7/Biff8
    
       char skip[2]; // Unspecified
    
       short int vers2;  // Version number
                         // 0x0500 -> Biff5/Biff7
                         // 0x0600 -> Biff8
    
       short int dt;     // Substream type (not used in this example)
    
       short int rupBuild;  // Internal build identifier
       short int rupYear;   // Internal Build year
    } XLBOF;
    
    
    //* XLVersionFromFile() ******************************************
    //* Returns
    //*        n for BiffN
    //*   i.e. 8 for Biff8 (Microsoft Excel 97)
    //*
    //*        Negative if an error occurs
    //****************************************************************
    
    int XLVersionFromFile(char *filename) {
       // Translate filename to Unicode
       WCHAR wcFilename[1024];
       int i = mbstowcs(wcFilename, filename, strlen(filename));
       wcFilename[i] = 0;
    
       IStorage *pStorage;
       HRESULT hr;
       XLBOF xlbof;
    
       // Open the document as an OLE compound document
       hr = ::StgOpenStorage(wcFilename, NULL,
                  STGM_READ | STGM_SHARE_EXCLUSIVE, NULL, 0, &pStorage);
    
       if(!FAILED(hr)) {
          // Open the data-stream where Microsoft Excel stores the data
          IStream *pStream;
          hr = pStorage->OpenStream(L"Workbook", NULL,
                  STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
    
          // If "Workbook" does not exist, try "Book"
          if(FAILED(hr)) {
             hr = pStorage->OpenStream(L"Book", NULL,
                  STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);
          }
          if(!FAILED(hr)) {
             // Read the relevant BOF information
             DWORD dwCount; // bytes read
             pStream->Read(&xlbof, sizeof(XLBOF), &dwCount);
    
             // Let go of the IStream pointer
             pStream->Release();
          }
          else return -2;
    
          // Let go of the IStorage pointer
          pStorage->Release();
        }
        else return -1;
    
        // Determine which version to return
        if(xlbof.vers != 0x08) return (xlbof.vers + 4) / 2;
        else {
           switch(xlbof.vers2) {
             case 0x0500:  // Either Biff5 or Biff7
                // Biff7's rupYear is at least 1994
                if(xlbof.rupYear < 1994) return 5;
    
                // Check for specific builds of Microsoft Excel 5
                switch(xlbof.rupBuild) {
                   case 2412: // XL5a
                   case 3218: // XL5c
                   case 3321: // NT XL5
                      return 5;
                   default:
                      return 7;
                }
    
           case 0x0600:  return 8;
           }
        }
    
        // Version not recognized. Perhaps there is a newer version.
        return -3;
    }
    
    void main()
    {
       int iretVal = 0;
       iretVal = XLVersionFromFile("C:\\Test.xls");
                                   //Adapt the filename to your example
       cout << "The Excel Version is " << iretVal << "\n\n\r";
       return;
    } 
  4. In the main()function, you may need to modify the path and filename of the Microsoft Excel workbook in the following line of code:


  5. 
     iretVal = XLVersionFromFile("C:\\Test.xls"); 


REFERENCES

Microsoft Visual C++ Help, version 5.0; search on "structured storage"

Microsoft Developers Network (MSDN); search on "structured storage", "Microsoft Excel file format", "BOF", "beginning of file"

Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2); search on "Microsoft Excel file format", "BOF", "beginning of file"

Additional query words: excel97 excel8 xl5en32

Keywords : kbole kbExcel kbVC500 kbVC600 kbSDKExcel kbExcel97 kbDSupport
Version : WINDOWS:5.0,5.0a,5.0c,7.0,7.0a; winnt:5.0,6.0
Platform : WINDOWS winnt
Issue type : kbhowto


Last Reviewed: October 30, 1999
© 2000 Microsoft Corporation. All rights reserved. Terms of Use.