GetFileVersionInfo获取SqlOledB.dll文件版本返回错误值问题
简述
SqlOledB.dll的文件版本:
- 实际版本:
10.0.18362.1 - GetFileVersionInfo返回值:
6.2.18362.1
详细说明
我尝试获取Windows DLL C:\Program Files (x86)\Common Files\System\Ole DB\sqloledb.dll的文件版本:
在Windows资源管理器中可见:
- 文件版本:10.0.18362.1
- 产品版本:10.0.18362.1

使用PowerShell执行:
> [System.Diagnostics.FileVersionInfo]::GetVersionInfo("C:\Program Files (x86)\Common Files\System\Ole DB\sqloledb.dll") | Format-List -property *
得到文件版本:
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 :
查看该DLL的VersionInfo资源,文件版本与产品版本一致:
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 } }
使用PEView查看原始版本资源,文件和产品版本均为000A0000 47BA0001,同时文件信息字符串部分显示:
- "FileVersion": "10.0.18362.1 (WinBuild.160101.0800)"
- "ProductVersion": "10.0.183612.1"
使用Process Monitor可确认应用程序查询的是正确的DLL:
但通过代码查询时得到错误值!
我的32位应用程序调用以下API:
GetFileVersionInfoSizeW()GetFileVersionInfoW()VerQueryValueW()(查询"\")
查看返回的VS_FIXEDFILEINFO缓冲区内容:
- 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
将文件版本和产品版本值转换为十六进制:
| 字段 | 十进制 | 十六进制 |
|---|---|---|
| dwFileVersionMS | 393218 | 0x00060002 |
| dwFileVersionLS | 1203372033 | 0x47BA0001 |
| dwProductVersionMS | 655360 | 0x000A0000 |
| dwProductVersionLS | 1203372033 | 0x47BA0001 |
转换为十进制版本字符串:
- 文件版本:
6.2.18362.1 - 产品版本:
10.0.13621.1
产品版本正确,但文件版本完全错误。
由此产生以下疑问:
- 当DLL二进制文件中所有信息都显示版本为
10.0.x.x时,GetFileVersion()API为何会返回6.2.x.x版本? - 是否存在应用程序兼容性垫片(appcompat shim)篡改版本号,使其显示为Windows 6.2而非10.0?
- 是否需要更新程序集清单中的
SupportedOS条目?
核心问题:Windows为何返回一个二进制文件中不存在的版本值?
简化复现代码
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 := '?.?.?.?'; // 获取文件信息结构所需的字节数 dwHandle := 0; dwInfoLength := GetFileVersionInfoSizeW(PWideChar(Filename), {var}dwHandle); if dwInfoLength = 0 then Exit; // 分配存储文件信息所需的内存 GetMem(pInfoData, dwInfoLength); try // 将信息写入刚分配的缓冲区 if not GetFileVersionInfoW(PWideChar(Filename), 0, dwInfoLength, pInfoData) then Exit; // 从pInfoData中提取所需数据到FileInformation结构 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.
补充说明
我还尝试使用ANSI版本API(搭配ANSI字符串),怀疑旧版ANSI版本可能存在篡改版本号的兼容性特性。
已在Delphi 5和Delphi XE6中测试,均为32位应用程序。
参考资料
- GetFileVersionInfo() returns wrong file's version information
内容的提问来源于stack exchange,提问作者Ian Boyd
相关产品推荐
相关产品推荐

