HOWTO: Determine the Version of a Microsoft Excel Workbook

Last reviewed: January 5, 1998
Article ID: Q178605
The information in this article applies to:
  • Microsoft Visual C++, 32-bit Editions, version 5.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:

          #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;
          }
    
    

  3. In the main()function, you may need to modify the path and filename of the Microsoft Excel workbook in the following line of code:

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

REFERENCES

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

Microsoft Developer’s 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 : VCGenIss kbcode
Technology : kbOle
Version : Win95:5.0,5.0a,5.0c,7.0,7.0a,97; winnt:5.0
Platform : Win95 winnt
Issue type : kbhowto


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: January 5, 1998
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.