Short Version
File version of SqlOledB.dll
:
- Actual:
10.0.18362.1
- GetFileVersionInfo:
6.2.18362.1
Long Version
I am trying to get the file version of the Windows dll "C:\Program Files (x86)\Common Files\System\Ole DB\sqloledb.dll"
In Windows Explorer, I can see:
- File version: 10.0.18362.1
- Product version: 10.0.18362.1
When I use Powershell:
> [System.Diagnostics.FileVersionInfo]::GetVersionInfo("C:\Program Files (x86)\Common Files\System\Ole DB\sqloledb.dll") | Format-List -property *
I can see the file version:
FileVersionRaw : 10.0.18362.1
ProductVersionRaw : 10.0.18362.1
Comments :
CompanyName : Microsoft Corporation
FileBuildPart : 18362
FileDescription : OLE DB Provider for SQL Server
FileMajorPart : 10
FileMinorPart : 0
FileName : C:\Program Files (x86)\Common Files\System\Ole DB\sqloledb.dll
FilePrivatePart : 1
FileVersion : 10.0.18362.1 (WinBuild.160101.0800)
InternalName : sqloledb.dll
IsDebug : False
IsPatched : False
IsPrivateBuild : False
IsPreRelease : False
IsSpecialBuild : False
Language : English (United States)
LegalCopyright : © Microsoft Corporation. All rights reserved.
LegalTrademarks :
OriginalFilename : sqloledb.dll
PrivateBuild :
ProductBuildPart : 18362
ProductMajorPart : 10
ProductMinorPart : 0
ProductName : Microsoft® Windows® Operating System
ProductPrivatePart : 1
ProductVersion : 10.0.18362.1
SpecialBuild :
When I look at the VersionInfo resource in the DLL, I see the file and product versions match:
1 VERSIONINFO
FILEVERSION 10,0,18362,1
PRODUCTVERSION 10,0,18362,1
FILEOS 0x40004
FILETYPE 0x2
{
BLOCK "StringFileInfo"
{
BLOCK "040904B0"
{
VALUE "CompanyName", "Microsoft Corporation"
VALUE "FileDescription", "OLE DB Provider for SQL Server"
VALUE "FileVersion", "10.0.18362.1 (WinBuild.160101.0800)"
VALUE "InternalName", "sqloledb.dll"
VALUE "LegalCopyright", "© Microsoft Corporation. All rights reserved."
VALUE "OriginalFilename", "sqloledb.dll"
VALUE "ProductName", "Microsoft® Windows® Operating System"
VALUE "ProductVersion", "10.0.18362.1"
}
}
BLOCK "VarFileInfo"
{
VALUE "Translation", 0x0409 0x04B0
}
}
When I use PEView to view the raw version resource, I see 000A0000 47BA0001
for both the file and product versions. I also see the file info string section that says:
- "FileVersion": "10.0.18362.1 (WinBuild.160101.0800)"
- "ProductVersion": "10.0.183612.1"
And when I use Process Monitor, I can see my application querying the correct DLL:
But, when I query it from code, I get the wrong value!
When my 32-bit application calls:
GetFileVersionInfoSizeW()
GetFileVersionInfoW()
VerQueryValueW()
(querying for"\"
)
and look at the contents of the returned VS_FIXEDFILEINFO
buffer, I see:
- dwSignature: 4277077181
- dwStrucVersion: 65536
- dwFileVersionMS: 393218
- dwFileVersionLS: 1203372033
- dwProductVersionMS: 655360
- dwProductVersionLS: 1203372033
- dwFileFlagsMask: 63
- dwFileFlags: 0
- dwFileOS: 262148
- dwFileType: 2
- dwFileSubtype: 0
- dwFileDateMS: 0
- dwFileDateLS: 0
If you look at the fileVersion and productVersion values, and convert them to hex:
Field | Decimal | Hex |
---|---|---|
dwFileVersionMS | 393218 | 0x00060002 |
dwFileVersionLS | 1203372033 | 0x47BA0001 |
dwProductVersionMS | 655360 | 0x000A0000 |
dwProductVersionLS | 1203372033 | 0x47BA0001 |
Which gives you the versions in hex of:
- File Version:
0x0006
,0x0002
,0x47BA
,0x0001
- Product Version:
0x000A
,0x0000
,0x47BA
,0x0001
We get the versions as decimal strings:
- File Version: 6.2.18362.1
- Product Version: 10.0.13621.1
The product version is correct, but the file version is completely wrong.
Which begs the questions:
- Where is the
GetFileVersion()
API function possibly getting version6.2.x.x
from; when everything about the DLL binary says10.0.x.x
? - Is there an appcompat shim kicking in; lying to me about the version number so that it's Windows 6.2 rather than Windows 10.0?
- Do I need to update my
SupportedOS
entries in my assembly manifest?
Short Version: How is Windows returning a version value that does not exist anywhere in the binary?
CRME for the lazy
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows;
function GetFileVersion(Filename: WideString): string;
var
dwHandle: Cardinal;
dwInfoLength: Cardinal;
pInfoData: Pointer;
lengthOfReturned: Cardinal;
value: Pointer;
fileInfo: PVSFixedFileInfo;
iMajor, iMinor, iBuild, iRelease: Integer;
begin
Result := '?.?.?.?';
// Get the number of bytes he have to allocate for the file information structure
dwHandle := 0;
dwInfoLength := GetFileVersionInfoSizeW(PWideChar(Filename), {var}dwHandle);
if dwInfoLength = 0 then
Exit;
// Allocate the memory needed to hold the file info
GetMem(pInfoData, dwInfoLength);
try
//Put the information into the buffer we just allocated
if not GetFileVersionInfoW(PWideChar(Filename), 0, dwInfoLength, pInfoData) then
Exit;
// Extract the desired data from pInfoData into the FileInformation structure
value := nil;
lengthOfReturned := 0;
if not VerQueryValueW(pInfoData, '\', {var}value, {var}lengthOfReturned) then
Exit;
fileInfo := PVSFixedFileInfo(value);
iMajor := fileInfo.dwFileVersionMS shr 16;
iMinor := fileInfo.dwFileVersionMS and $FFFF;
iRelease := fileInfo.dwFileVersionLS shr 16;
iBuild := fileInfo.dwFileVersionLS and $FFFF;
finally
FreeMem(pInfoData);
end;
Result := Format('%d.%d.%d.%d', [iMajor, iMinor, iRelease, iBuild]);
end;
procedure Main;
var
filename: string;
version: string;
begin
filename := 'C:\Program Files (x86)\Common Files\System\Ole DB\sqloledb.dll';
version := GetFileVersion(filename);
WriteLn('Filename: '+filename);
WriteLn('File version: '+version);
end;
begin
Main;
WriteLn('Press enter to close...');
ReadLn;
end.
Bonus Chatter
I also tried using the ANSI versions (with ANSI strings), in case the legacy ANSI version had some app-compat feature that lies about version numbers.
Tried in Delphi 5 and Delphi XE6 - both 32-bit apps.
Yes, it is an app-compat shim kicking in - lying to me about the version of the
.dll
i use.Adding the Windows 10 entry
to my
Assembly.manifest
fixes it.