热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何获取某个动态链接库的版本信息

CQ&A如何获取某个动态链接库的版本信息原著:PaulDiLascia翻译:NorthTibet下载源代码:Apr98CQAcode

 


C++ Q&A...
如何获取某个动态链接库的版本信息

原著:Paul DiLascia
翻译:NorthTibet

下载源代码:Apr98CQAcode.exe (22KB)
原文出处:C++ Q&A April 1998



 我如何获得安装在我的系统上的某个特定的 DLL 的版本信息?我尝试着确定系统安装了哪个版本的 comctl32.dll。我见过有些代码调用 GetProcAddress 来获取各种函数,如 InitCommonControlsEx,以确定基于不同版本的函数调用。对于我来说,这是一个坎儿,到底用什么方法获得版本号?

有两种方法:容易的和难的。容易的方法是调用一个专门用于此目的的函数 DllGetVersion。问题是虽然 comctl32.dll 支持该函数,但并不是所有的 DLLs 都具备它。如果不具备 DllGetVersion,那么就得用难的方法——使用 FileVersion API,这可能是你要遭遇到的最为暧昧的 API 之一。我写了一个类 CModuleVersion 来封装两种方法,同时还写了一个Demo程序 VersionDlg 来示范 CModuleVersion 的使用方法。程序画面如 Figure 1 所示。你可以在编辑框中敲入任何系统模块的名字,VersionDlg 将用 DllGetVersion (如果具备这个函数的话)和 FileVersion API 两种方法显示版本信息。源代码参见 Figure 2。


Figure 1 运行中的 VersionDlg 程序

  让我们先看容易的方法。DllGetVersion 用 DLL 版本信息填写一个 DLLVERSIONINFO 结构。该结构定义在 Win32 SDK 的 showapi.h 头文件中。许多人可能都没有安装 Platform SDK,那么就得自己定义这个结构了(译者注:实际上,早期的 Developer Studio 不包含这个头文件。后来的 Visual Studio 6.0 安装已经包含该头文件,路经参见:Driver:/Program Files/Microsoft Visual Studio/VC98/Include),就像我在 VersionDlg 所做的那样。

typedef struct _DllVersionInfo {
DWORD cbSize;
DWORD dwMajorVersion;
DWORD dwMinorVersion;
DWORD dwBuildNumber;
DWORD dwPlatformID;
} DLLVERSIONINFO;

  这个结构中的字段基本不用怎么说明就知道是什么意思:dwPlatformID 为 DLLVER_PLATFORM_WINDOWS (value = 1)指 Windows 9x,而 DLLVER_PLATFORM_NT (value = 2)用于 Windows NT。一旦定义了 DLLVERSIONINFO 结构,就可以调用 DllGetVersion 了,该函数的署名如下:

HRESULT DllGetVersion(DLLVERSIONINFO*);

  因为并不是任何给定的 Dll 都输出 DllGetVersion 函数,你得按照标准套路来调用它,即调用 GetProcAddress 并判断返回值是否为 NULL。我编写的类 CModuleVersion 中含有一个 DllGetVersion 函数,它把所有细节都进行了封装(参见 Figure 2 中的 ModulVer.cpp。)CModuleVersion 类的使用方法如下:

DLLVERSIONINFO dvi;
if (CModuleVersion::DllGetVersion("comctl32.dll", dvi))
{
// now info is in dvi
}

  DllGetVersion 是一个比较新的函数(译者注:在1998年是这样。)对于 comctl32 很好使,因为它实现并输出 DllGetVersion——但是对于那些不输出 DllGetVersion 的 DLLs 来说怎么办呢?例如:shell32.dll 就没有实现 DllGetVersion,如 Figure 3 所示。这时你就得用可怕以及奇怪的 GetFileVersionInfo 和 VerQueryValue 函数,它们在 winver.h 中定义。


Figure 3 No DllGetVersion Info

  大多数可执行程序和 DLLs 都具备 VS_VERSION_INFO 资源,在模块的 RC 文件中定义。Figure 4 是 VersionDlg 的 RC 文件中的版本信息。你可以用文本编辑器或者 Visual Studio 直接编辑资源文件中的这段信息。你可以指定文件版本,产品版本等等,以及任何你想要编辑的字段,如:CompanyName、InternalName。文件版本信息与 Exe 或 DLL 文件在资源管理器“属性”页“版本”标签中显示的信息相同(参见 Figure 5)。


Figure 5 Version Tab

  等一会儿你就会发现,这些版本 APIs 十分暧昧,很容易把人搞晕菜,但 CModuleVersion 使一切都变得简单明了。这个类派生于 VS_FIXEDFILEINFO(参见 Figure 6),此结构包含“固定的”版本信息,其中有主版本号和次版本号,还有一些 DLLVERSIONINFO 里的东西。使用 CModuleVersion 时,只要像下面这样写即可:

CModuleVersion ver;
if (ver.GetFileVersionInfo(_T("comctl32.dll"))
{
WORD major = HIWORD(ver.dwFileVersionMS);
WORD minor = LOWORD(ver.dwFileVersionMS);
...
}

  为了存取 CompanyName 这样的可变信息以及内涵的模块创建信息,你可以用另外一个函数 CModuleVersion:: GetValue,例如,下面代码段执行之后,sCompanyName 的值将类似“XYZ”或“Acme Corporation”这样的公司名称:

CString sCompanyName =
ver.GetValue(_T("CompanyName"));

  CModuleVersion 隐藏了获取信息所要做的所有邋遢细节——相信我,都是些邋遢细节!如果你只是想使用 CModuleVersion,那么看到这里就可以打住了;如果你想要了解 CModuleVersion 的工作原理,那就继续往下看。
  假设 CModuleVersion::GetFileVersionInfo 能加载模块并获取 HINSTANCE,它调用 ::GetFileVersionInfoSize 来获取版本信息的大小,然后分配一个缓冲并调用 GetFileVersionInfo 来填充该缓冲。原始缓冲(CModuleVersion::m_pVersionInfo)是一个数据块,它包含固定的信息和可变信息。VerQueryValue 将一个指针指向你感兴趣的特定信息的起始位置。例如,为了得到固定的信息(VS_FIXEDFILEINFO),你得这样写:

LPVOID lpvi;
UINT iLen;
VerQueryValue(buf, _T("//"), &lpvi, &iLen);

  此处 buf 是从 GetFileVersionInfo 返回的完整信息。字符串“/”(在 C 中用“//”),你如果把它看作是一个目录,那它就是根信息(有一点像注册表)。VerQueryValue 将 lpvi 置到 VS_FIXEDFILEINFO 的起始处,iLen 为其长度。
  以上是获取固定信息的方法,可变信息获取更奇怪,因为你必须首先知道语言 ID 和代码页是什么。在 Winidows 里,代码页指定了一个字符集,它是字符文字与表示它们的 1 或 2 字节值之间映射。标准的 ANSI 代码页是 1252;Unicode 是 1200。Figure 7 是语言ID和代码页的清单。Figure 4 中文件信息里的 Translation 键指定模块的语言ID和代码页。在 CModuleVersion 中,我使用自己的 Translation 结构来获取这个信息。

// in CModuleVersion
struct TRANSLATION {
WORD langID // language ID
WORD charset; // code page
} m_translation;

为了获取语言信息,CModuleVersion 用 VerQueryValue 函数以 /VarFileInfo/Translation 作为键。

if (VerQueryValue(m_pVersionInfo,"//VarFileInfo//Translation", &lpvi, &iLen) && iLen >= 4)
{
m_translation = *(TRANSLATION*)lpvi;
}

一旦你知道了语言ID和代码页,你就可以得到 CompanyName 和 InternalName 这样的可变信息。实现方法是构造一个如下形式的查询:

/StringFileInfo//

  这里 是十六进制 ASCI 形式的语言ID(中文是 0804;US English 是 0409), 是代码页,格式为(1252 即 ANSI 的代码页是04e4), 是你想要的键,如:CompanyName。为了构造这个查询,你得用 sprintf 或者 CString::Format 来构造字符串:

//StringFileInfo//040904e4//CompanyName

  然后将这个字符串传给 VerQueryValue。如果你对这些繁琐的细节感到晕菜,不用担心——很幸运,CModuleVersion::GetValue 对所有邋遢细节都进行了封装,所以你只要像下面这样写即可:

CString s = ver.GetValue(_T("CompanyName"));

  实现了 CModuleVersion,VersionDlg 就简单多了。 它实际上就是一个对话框,这个对话框带有一个编辑框,用于输入模块名称,每当用户在编辑框中敲入模块名称时,MFC 便调用 ON_EN_CHANGE 消息处理例程 CVersionDialog::OnChangedModule。OnChangedModule 例程通过 CModuleVersion 对象及其 GetFileVersionInfo 和 GetDllVersion 函数来获得版本信息,然后将信息显示在对话框的两个静态文本控件中。这个过程很简单。
  最后还有个技巧我得提一下。GetFileVersionInfo,VerQueryValue 以及其它有关文件版本函数在一个叫做 version.lib 的库中,你必须将它链接到你程序中。从而避免链接时出现烦人的“undefined symbol”(未定义符号)错误,ModuleVer.h 使用了一个鲜为人知但特别有用的 #pragma comment 语法,即使你忘记在 Project|Settings 的 Link 属性页中添加 Input ==〉Libraries 也没关系,#pragma comment 会告诉链接器与 version.lib 链接。

// 告诉链接器与 version.lib 进行链接
#pragma comment(linker,
"/defaultlib:version.lib")

  现在,有人可能会问,为什么这些东西如此重要?以及谁会需要这些东西呢?一般来说,如果你编写的是显示文件属性之类的工具程序,那你只是需要获取诸如 CompanyName 和 LegalCopyright 之类的变量。但你也许发现用 CModuleVersion 从自己的应用程序中吸取文件信息很有用,例如,为了在“关于”对话框和启动屏幕中显示版本信息。如果你使用 CModuleVersion,你只需修改资源文件中相应位置的版本信息即可,“关于”对话框和启动屏幕会自动显示当前最新版本信息。
  版本信息另一个重要的用途是确定某个DLL是针对哪种语言编写的,这样你代码能与之对应。随着当今基于 Windows 的编程技术迅猛发展,DLLs 的新版本也随之日新月异,你很快就会发现下面这样的代码越来越多:

if (version <= 470)
// do one thing
else if (version==471)
// do something else
else if (version==472)
// do a third thing
else
// scream

  这是一件很郁闷的事情,我敢说这也是微软的大佬们引入 DllGetVersion 来快速获取版本号的一个原因,从而避免了面对让人恐惧的 GetFileVersionInfo 函数,只用它来获取语言 IDs 和代码页(仅在需要获取诸如 CompanyName 这样的信息时使用)。
  comctl32.dll 的与众不同也没有什么意外的,这个模块版本问题已经程序员最大的祸害之一,我可怜的邮箱曾被读者关于 comctl32.dll 这个模块的问题撑爆,很多问题都是客户下载了微软最新版本的 comctl32.dll 到机器上之后,应用程序就无法运行了。我会在以后的文章中解释 comctl32.dll 的版本问题,以及新的 toolbar 特性,如何解决 MFC 中 CToolBar 的 bug。现在,由于篇幅所限,我只能点到为止,目前 comctl32.dll 最新的版本为 6.00(随 IE 一起发布)。
  最后,感谢上帝,微软已经出台关于可以随你的应用程序一起分发 comctl32.dll!但不是单独分发 comctl32.dll,而是可以随你程序的更新包及其它文件一起分发。详情参见:http://msdn.microsoft.com/developer/downloads/files/40comupd.htm,请在你的新版本出炉之前仔细阅读。


编程愉快!


您的提问和评论可发送到 Paul 的信箱:cppqa@microsoft.com.
 

作者简介
  Paul DiLascia
是一名自由作家,软件咨询顾问以及大型 Web/UI 的设计师。他是《Writing Reusable Windows Code in C++》书(Addison-Wesley, 1992)的作者。业余时间他开发 PixeLib,这是一个 MFC 类库,从 Paul 的网站 http://www.dilascia.com 可以获得这个类库。
.

本文出自 Microsoft System Journal (MSJ) 的 April 1998 期刊,可通过当地报摊获得,或者最好是 订阅

 

Figure 2 VersionDlg

VersionDlg.cpp

//
// VersionDlg 1998 Microsoft Systems Journal.
// If this program works, it was written by Paul DiLascia.
// If not, I don&#39;t know who wrote it.
//
// VersionDlg illustrates how to use CModuleVersion and DllGetVersion to
// read the version info for a DLL/EXE. The only interesting function
// for the purpose of CModuleVersion is OnChangedModule, which is called
// when the user enters a new module name into the edit control.
//
#include "stdafx.h"
#include "resource.h"
#include "ModulVer.h"
#include "StatLink.h"
#include "TraceWin.h"
//#include // if you have the Nov 1997 SDK installed
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/
// CVersionDialog dialog
//
class CVersionDialog : public CDialog {
public:
CVersionDialog(CWnd* pParent = NULL);
CString m_sModuleName; // module name typed by user
protected:
CStaticLink m_wndLink1; // web link
CStaticLink m_wndLink2; // web link
CStaticLink m_wndLink3; // web link
virtual void DoDataExchange(CDataExchange* pDX);
virtual BOOL OnInitDialog();
virtual void OnOK();
afx_msg void OnChangedModule();
DECLARE_MESSAGE_MAP()
};
// CMyApp
//
class CMyApp : public CWinApp {
public:
CMyApp() { }
virtual BOOL InitInstance();
} theApp;
/
// Initialize: just run the dialog and quit.
//
BOOL CMyApp::InitInstance()
{
CVersionDialog dlg; // create dialog..
dlg.DoModal(); // ..run it
return FALSE; // ..and quit
}
//
// CVersionDialog
//
BEGIN_MESSAGE_MAP(CVersionDialog, CDialog)
ON_EN_CHANGE(IDC_EDIT_MODULE, OnChangedModule)
END_MESSAGE_MAP()
CVersionDialog::CVersionDialog(CWnd* pParent) : CDialog(IDD_VERSION, pParent)
{
}
/
// Initialize dialog: subclass static hyperlinks
//
BOOL CVersionDialog::OnInitDialog()
{
m_wndLink1.SubclassDlgItem(IDC_STATICPD, this,
_T("http://pobox.com/~dilascia"));
m_wndLink2.SubclassDlgItem(IDC_STATICMSJ, this,
_T("http://www.microsoft.com/msj"));
m_wndLink3.SubclassDlgItem(IDC_ICONMSJ, this,
_T("http://www.microsoft.com/msj"));
return CDialog::OnInitDialog();
}
/
// When user pressed Enter, don&#39;t exit
//
void CVersionDialog::OnOK()
{
return; // (don&#39;t exit)
}
//
// Standard MFC DDX data exchange for edit control
//
void CVersionDialog::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT_MODULE, m_sModuleName);
}
//
// User changed the module name: vet version info if I can.
//
void CVersionDialog::OnChangedModule()
{
UpdateData(TRUE); // get dialog data (module name)
CString s;
CModuleVersion ver;
// 1st get version using File version API
//
if (ver.GetFileVersionInfo(m_sModuleName)) {
// display file version from VS_FIXEDFILEINFO struct
s.Format("Version: %d.%d.%d.%d/n",
HIWORD(ver.dwFileVersionMS), LOWORD(ver.dwFileVersionMS),
HIWORD(ver.dwFileVersionLS), LOWORD(ver.dwFileVersionLS));
// display a bunch of string values
static LPCTSTR Keys[] = {
_T("CompanyName"),
_T("FileDescription"),
_T("FileVersion"),
_T("InternalName"),
_T("LegalCopyright"),
_T("OriginalFilename"),
_T("ProductName"),
_T("ProductVersion"),
NULL
};
for (int i=0; Keys[i]; i++) {
CString temp;
temp.Format("%s:/t%s/n", Keys[i], ver.GetValue(Keys[i]));
s += temp;
}
}
// set static text
GetDlgItem(IDC_STATICINFO)->SetWindowText(s);
// 2nd get version using DllGetVersion API
//
s.Empty();
DLLVERSIONINFO dvi;
if (ver.DllGetVersion(m_sModuleName, dvi)) {
s.Format(_T("DLL Version = %d.%02d/nBuild# = %d/n"),
dvi.dwMajorVersion,
dvi.dwMinorVersion,
dvi.dwBuildNumber);
s +=_T("Platform is ");
if (dvi.dwPlatformID == DLLVER_PLATFORM_WINDOWS)
s +=_T("Windows");
else if (dvi.dwPlatformID == DLLVER_PLATFORM_NT)
s +=_T("Windows NT");
else
s += _T("unrecognized");
} else {
s += _T("This file does not implement DllGetVersion.");
}
// set static text
GetDlgItem(IDC_STATICINFO2)->SetWindowText(s);
}

ModulVer.h


// 1998 Microsoft Systems Journal
//
// If this code works, it was written by Paul DiLascia.
// If not, I don&#39;t know who wrote it.
//
#ifndef __MODULEVER_H
#define __MODULEVER_H
// tell linker to link with version.lib for VerQueryValue, etc.
#pragma comment(linker, "/defaultlib:version.lib")
#ifndef DLLVERSIONINFO
// following is from shlwapi.h, in November 1997 release of the Windows SDK
typedef struct _DllVersionInfo
{
DWORD cbSize;
DWORD dwMajorVersion; // Major version
DWORD dwMinorVersion; // Minor version
DWORD dwBuildNumber; // Build number
DWORD dwPlatformID; // DLLVER_PLATFORM_*
} DLLVERSIONINFO;
// Platform IDs for DLLVERSIONINFO
#define DLLVER_PLATFORM_WINDOWS 0x00000001 // Windows 95
#define DLLVER_PLATFORM_NT 0x00000002 // Windows NT
#endif // DLLVERSIONINFO
//
// CModuleVersion version info about a module.
// To use:
//
// CModuleVersion ver
// if (ver.GetFileVersionInfo("_T("mymodule))) {
// // info is in ver, you can call GetValue to get variable info like
// CString s = ver.GetValue(_T("CompanyName"));
// }
//
// You can also call the static fn DllGetVersion to get DLLVERSIONINFO.
//
class CModuleVersion : public VS_FIXEDFILEINFO {
protected:
BYTE* m_pVersionInfo; // all version info
struct TRANSLATION {
WORD langID; // language ID
WORD charset; // character set (code page)
} m_translation;
public:
CModuleVersion();
virtual ~CModuleVersion();
BOOL GetFileVersionInfo(LPCTSTR modulename);
CString GetValue(LPCTSTR lpKeyName);
static BOOL DllGetVersion(LPCTSTR modulename, DLLVERSIONINFO& dvi);
};
#endif

ModulVer.cpp


// 1998 Microsoft Systems Journal
// If this code works, it was written by Paul DiLascia.
// If not, I don&#39;t know who wrote it.
//
// CModuleVersion provides an easy way to get version info
// for a module.(DLL or EXE).
//
#include "StdAfx.h"
#include "ModulVer.h"
CModuleVersion::CModuleVersion()
{
m_pVersiOnInfo= NULL; // raw version info data
}
//
// Destroy: delete version info
//
CModuleVersion::~CModuleVersion()
{
delete [] m_pVersionInfo;
}
//
// Get file version info for a given module
// Allocates storage for all info, fills "this" with
// VS_FIXEDFILEINFO, and sets codepage.
//
BOOL CModuleVersion::GetFileVersionInfo(LPCTSTR modulename)
{
m_translation.charset = 1252; // default = ANSI code page
memset((VS_FIXEDFILEINFO*)this, 0, sizeof(VS_FIXEDFILEINFO));
// get module handle
TCHAR filename[_MAX_PATH];
HMODULE hModule = ::GetModuleHandle(modulename);
if (hModule==NULL && modulename!=NULL)
return FALSE;
// get module file name
DWORD len = GetModuleFileName(hModule, filename,
sizeof(filename)/sizeof(filename[0]));
if (len <= 0)
return FALSE;
// read file version info
DWORD dwDummyHandle; // will always be set to zero
len = GetFileVersionInfoSize(filename, &dwDummyHandle);
if (len <= 0)
return FALSE;
m_pVersiOnInfo= new BYTE[len]; // allocate version info
if (!::GetFileVersionInfo(filename, 0, len, m_pVersionInfo))
return FALSE;
LPVOID lpvi;
UINT iLen;
if (!VerQueryValue(m_pVersionInfo, _T("//"), &lpvi, &iLen))
return FALSE;
// copy fixed info to myself, which am derived from VS_FIXEDFILEINFO
*(VS_FIXEDFILEINFO*)this = *(VS_FIXEDFILEINFO*)lpvi;
// Get translation info
if (VerQueryValue(m_pVersionInfo,
"//VarFileInfo//Translation", &lpvi, &iLen) && iLen >= 4) {
m_translation = *(TRANSLATION*)lpvi;
TRACE("code page = %d/n", m_translation.charset);
}
return dwSignature == VS_FFI_SIGNATURE;
}
//
// Get string file info.
// Key name is something like "CompanyName".
// returns the value as a CString.
//
CString CModuleVersion::GetValue(LPCTSTR lpKeyName)
{
CString sVal;
if (m_pVersionInfo) {
// To get a string value must pass query in the form
//
// "/StringFileInfo//keyname"
//
// where is the languageID concatenated with the
// code page, in hex. Wow.
//
CString query;
query.Format(_T("//StringFileInfo//%04x%04x//%s"),
m_translation.langID,
m_translation.charset,
lpKeyName);
LPCTSTR pVal;
UINT iLenVal;
if (VerQueryValue(m_pVersionInfo, (LPTSTR)(LPCTSTR)query,
(LPVOID*)&pVal, &iLenVal)) {
sVal = pVal;
}
}
return sVal;
}
// typedef for DllGetVersion proc
typedef HRESULT (CALLBACK* DLLGETVERSIONPROC)(DLLVERSIONINFO *);
/
// Get DLL Version by calling DLL&#39;s DllGetVersion proc
//
BOOL CModuleVersion::DllGetVersion(LPCTSTR modulename, DLLVERSIONINFO& dvi)
{
HINSTANCE hinst = LoadLibrary(modulename);
if (!hinst)
return FALSE;
// Must use GetProcAddress because the DLL might not implement
// DllGetVersion. Depending upon the DLL, the lack of implementation of the
// function may be a version marker in itself.
//
DLLGETVERSIONPROC pDllGetVersion =
(DLLGETVERSIONPROC)GetProcAddress(hinst, _T("DllGetVersion"));
if (!pDllGetVersion)
return FALSE;
memset(&dvi, 0, sizeof(dvi)); // clear
dvi.cbSize = sizeof(dvi); // set size for Windows
return SUCCEEDED((*pDllGetVersion)(&dvi));
}


Figure 4Ver.rc

 

VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904B0"
BEGIN
VALUE "CompanyName", "Written by Paul DiLascia/0"
VALUE "FileDescription",
"VersionDlg Application by Paul DiLascia/0"
VALUE "FileVersion", "1, 0, 0, 1/0"
VALUE "InternalName", "VersionDlg/0"
VALUE "LegalCopyright", "1998 Paul DiLascia/0"
VALUE "LegalTrademarks", "/0"
VALUE "OriginalFilename", "VersionDlg.EXE/0"
VALUE "ProductName", "VersionDlg/0"
VALUE "ProductVersion", "1, 0, 0, 1/0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END


Figure 6VS_FIXEDFILEINFO

typedef struct tagVS_FIXEDFILEINFO
{
DWORD dwSignature; /* e.g. 0xfeef04bd */
DWORD dwStrucVersion; /* e.g. 0x00000042 = "0.42" */
DWORD dwFileVersionMS; /* e.g. 0x00030075 = "3.75" */
DWORD dwFileVersionLS; /* e.g. 0x00000031 = "0.31" */
DWORD dwProductVersionMS; /* e.g. 0x00030010 = "3.10" */
DWORD dwProductVersionLS; /* e.g. 0x00000031 = "0.31" */
DWORD dwFileFlagsMask; /* = 0x3F for version "0.42" */
DWORD dwFileFlags; /* e.g. VFF_DEBUG | VFF_PRERELEASE */
DWORD dwFileOS; /* e.g. VOS_DOS_WINDOWS16 */
DWORD dwFileType; /* e.g. VFT_DRIVER */
DWORD dwFileSubtype; /* e.g. VFT2_DRV_KEYBOARD */
DWORD dwFileDateMS; /* e.g. 0 */
DWORD dwFileDateLS; /* e.g. 0 */
} VS_FIXEDFILEINFO;


Figure 7 Language IDs and Code Pages

Language ID Language
0x0401 Arabic
0x0402 Bulgarian
0x0403 Catalan
0x0404 Traditional Chinese
0x0405 Czech
0x0406 Danish
0x0407 German
0x0408 Greek
0x0409 U.S. English
0x040A Castilian Spanish
0x040B Finnish
0x040C French
0x040D Hebrew
0x040E Hungarian
0x040F Icelandic
0x0410 Italian
0x0411 Japanese
0x0412 Korean
0x0413 Dutch
0x0414 Norwegian - Bokml
0x0810 Swiss Italian
0x0813 Belgian Dutch
0x0814 Norwegian - Nynorsk
0x0415 Polish
0x0416 Brazilian Portuguese
0x0417 Rhaeto-Romanic
0x0418 Romanian
0x0419 Russian
0x041A Croato-Serbian (Latin)
0x041B Slovak
0x041C Albanian
0x041D Swedish
0x041E Thai
0x041F Turkish
0x0420 Urdu
0x0421 Bahasa
0x0804 Simplified Chinese
0x0807 Swiss German
0x0809 U.K. English
0x080A Mexican Spanish
0x080C Belgian French
0x0C0C Canadian French
0x100C Swiss French
0x0816 Portuguese
0x081A Serbo-Croatian (Cyrillic)
Code Page Character Set
932 Windows, Japan (Shift - JIS X-0208)
949 Windows, Korea (Shift - KSC 5601)
950 Windows, Taiwan (GB5)
1200 Unicode
1250 Windows, Latin-2 (Eastern European)
1251 Windows, Cyrillic
1252 Windows, Multilingual
1253 Windows, Greek
1254 Windows, Turkish
1255 Windows, Hebrew
1256 Windows, Arabic



推荐阅读
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 如何搭建Java开发环境并开发WinCE项目
    本文介绍了如何搭建Java开发环境并开发WinCE项目,包括搭建开发环境的步骤和获取SDK的几种方式。同时还解答了一些关于WinCE开发的常见问题。通过阅读本文,您将了解如何使用Java进行嵌入式开发,并能够顺利开发WinCE应用程序。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • Android自定义控件绘图篇之Paint函数大汇总
    本文介绍了Android自定义控件绘图篇中的Paint函数大汇总,包括重置画笔、设置颜色、设置透明度、设置样式、设置宽度、设置抗锯齿等功能。通过学习这些函数,可以更好地掌握Paint的用法。 ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 有没有一种方法可以在不继承UIAlertController的子类或不涉及UIAlertActions的情况下 ... [详细]
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
author-avatar
三光937
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有