善意提醒

如果您打开本站很慢,布局排版混乱,并且看不到图片,那么可能是因为您还没有掌握用科学的方法上网的本领。
显示标签为“SDK”的博文。显示所有博文
显示标签为“SDK”的博文。显示所有博文

2017-05-21

正确地获取 Windows 的版本号

以前,想要获取 Windows 的版本号很简单,有个 Win32 API 函数名字叫做 GetVersion,望文生义,接下来要做的事情就是去 MSDN 上查下用法就可以了。

现在,GetVersion 会被报告成「过期函数」了。也许还能用,但(据 MSDN 说)起码在 Win10 上是别指望得到预期的结果了。道理也很简单,Win10 都搞滚动升级了,版本号规则肯定也和之前不一样了,你还指望这么老的函数能兼容么?

别痴心妄想了,GetVersionEx 也一样过期。那么,眼下有什么好办法吗?

一般来说,拿 Windows 版本号可能有两种用途:

  • 我想看看你 Windows 版本达到我要求没。
  • 我就是想知道你 Windows 版本号是多少。

对于前者,微软现在在 MSDN 上是这样推荐的:它做了一组 Version Helper functions,你如果想知道当前 Windows 的版本是不是某个特定的发行版,调这组函数就可以。我们来看看这组函数中三个典型:

  • IsWindowsXPOrGreater
  • IsWindowsXPSP3OrGreater
  • IsWindowsServer

不需要更多说明,我们从名字中就可以看出,这组函数可以用于判断 Windows 的大版本,Service Pack 的版本(结合大版本),以及能知道是不是服务器版操作系统。通常情况下,这些函数大概是够了。

但是,有的时候我们并不关心版本号高低,我们只是想要一个版本号(例如记录日志时)而已。微软对此的建议是:用 GetFileVersionInfo 去获取一个系统 DLL(例如 Kernel32.dll)的文件版本号(原文看 这里)。

相关的代码虽然能找到,MSDN 上也有官方例子(有点小 Bug),但比起一行 GetVersion 来代码量实在是不能算很少。由此可见,处理「过期函数」真的没有想象中那么容易。最后我还是提供一下我从项目代码中挖出来的一个实现吧。别照抄,如果你不想引入 STL 的话:

#include <windows.h>
#include <Strsafe.h>

#pragma comment(lib, "Version.lib")

// 获取文件版本
std::wstring GetFileVersionString(const std::wstring& strFilePath, bool bStrVer = false) {
    DWORD dwVerInfoSize = GetFileVersionInfoSize(strFilePath.c_str(), nullptr);
    if (dwVerInfoSize) {
        std::vector<BYTE> vecVerData(dwVerInfoSize);
        if (GetFileVersionInfo(strFilePath.c_str(), NULL, dwVerInfoSize, &vecVerData[0])) {
            LPCVOID pBlock = &vecVerData[0];

            UINT cbTranslate;
            TCHAR SubBlock[MAX_PATH];
            struct LANGANDCODEPAGE {
                WORD wLanguage;
                WORD wCodePage;
            } *lpTranslate;

            // 阅读语言和代码页列表
            VerQueryValue(pBlock,
                L"\\VarFileInfo\\Translation",
                (LPVOID*)&lpTranslate,
                &cbTranslate);

            if (bStrVer && lpTranslate) {
                // 读取第一种语言和代码页的文件版本
                for (size_t i = 0; i < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); ++i) {
                    StringCchPrintf(SubBlock, sizeof(SubBlock) / sizeof(TCHAR),
                        L"\\StringFileInfo\\%04x%04x\\ProductVersion",
                        lpTranslate[i].wLanguage,
                        lpTranslate[i].wCodePage);

                    LPVOID lpBuffer = nullptr;
                    UINT dwBytes;
                    if (VerQueryValue(pBlock, SubBlock, &lpBuffer, &dwBytes) && lpBuffer && dwBytes > 0) {
                        std::wstring strVersion(reinterpret_cast<TCHAR*>(lpBuffer));
                        return strVersion;
                    }
                }
            }

            // 未找到任何字符串版本
            VS_FIXEDFILEINFO* lpffi = nullptr;
            UINT uLen = 0;
            // 注意:这里的第二个参数 "\" 是固定写法,表示查询根块
            if (VerQueryValue(pBlock, L"\\", (LPVOID*)&lpffi, &uLen) && lpffi && uLen >= sizeof(VS_FIXEDFILEINFO)) {
                std::wstringstream wos;
                wos << HIWORD(lpffi->dwFileVersionMS) << L"." << LOWORD(lpffi->dwFileVersionMS) << L"."
                    << HIWORD(lpffi->dwFileVersionLS) << L"." << LOWORD(lpffi->dwFileVersionLS);
                return wos.str();
            }
        }
    }
    return L"";
}

// 获取 OS 版本信息
std::wstring GetOSVersion(const std::wstring& strWinSysDir, bool bStrVer) {
    std::wstring strWinSysFilePath = strWinSysDir;
    if (!strWinSysFilePath.empty() && strWinSysFilePath.back() != L'\\') {
        strWinSysFilePath += L'\\';
    }
    return GetFileVersionString(strWinSysFilePath + L"Kernel32.dll", bStrVer);
}

2013-01-25

VC6 最佳拍档,Platform SDK Feb 2003

很长一段时间内,一直用 Platform SDK Server 2003 SP1 来搭配 VC6 进行开发工作。但这个组合其实并不是很合适。这个版本的 Platform SDK 里面,有一些东西是 VC6 的 CRT 已经无法支持的,比如对 __time64_t 进行操作的那些时间函数。另外在链接到 shell32.lib 之类的库的时候,也会报错说调试信息的格式已经不匹配了。

最后一个支持 VC6 的 Platform SDK,是 Platform SDK Feb 2003,比我之前用的 SDK 版本要更旧一点。微软官网已经不提供下载了,目前给出的所有链接都是失效的。好在有网友通过 独立Blog 提供了 cab 包方式的下载。我把这些 cab 包中打包的文件提取出来后制作成了 ISO 光盘镜像,便于刻盘保存,也更方便下载。

以下下载链接来自于 Mega 网盘。下载无需注册,但国内下载速度不太好说,有快有慢,并且(从 Mega 的性质看来)随时可能被墙。可以尝试一下 ping mega.co.nz,如果 ping 值高于 600ms,建议通过 VPN 下载(GoAgent对于Mega不顶用),或者另寻它途。
Platform SDK Feb 2003.iso (346.8 MB)

值得一提的是,这个版本的 SDK 需要你的默认浏览器是 IE 才行。貌似通过 ActiveX 控件实现的安装向导,以后的版本没有继续采用,明显是一个失败的设计。