#include <windows.h>
#include <stdio.h>
int XLVersionThatWroteFile(char *filename) {
// Translate filename to Unicode
WCHAR wcFilename[1024];
int i = mbstowcs(wcFilename, filename, strlen(filename));
wcFilename[i] = 0;
// Open the document as an OLE compound document
IStorage *pStorage;
HRESULT hr;
hr = ::StgOpenStorage(wcFilename, NULL,
STGM_READ | STGM_SHARE_EXCLUSIVE, NULL, 0, &pStorage);
if(FAILED(hr)) return 0;
// 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)) {
pStorage->Release();
return 0;
}
// Get rupBuild & rupYear
short rupBuild, rupYear;
LARGE_INTEGER off;
ULARGE_INTEGER newPos;
off.QuadPart = 8;
pStream->Seek(off, STREAM_SEEK_SET, &newPos);
DWORD bytesRead;
pStream->Read(&rupBuild, 2, &bytesRead);
pStream->Read(&rupYear, 2, &bytesRead);
// Let go of the IStorage pointer
pStorage->Release();
// Excel 8.0's rupyear = 1996
if(rupYear == 1996) return 8;
// Excel 9.0 comes after Excel 8.0...
if(rupYear > 1996) return 9;
// Excel 5.0's rupyear < 1994
if(
(rupYear < 1994) ||
// Excel 5.0 & 7.0 have rupYear=1994 for some versions...
(rupBuild == 2412) || (rupBuild == 3218) || (rupBuild == 3321)
) return 5;
// All that's left is Excel 7.0
return 7;
}
void main(int argc, char **argv) {
if(argc != 2) {
printf("Usage: XLVER filename.xls");
}
else {
printf("Excel version = %d", XLVersionThatWroteFile(argv[1]));
}
}