summaryrefslogtreecommitdiffstats
path: root/src/common/windows/version.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/windows/version.c')
-rw-r--r--src/common/windows/version.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/src/common/windows/version.c b/src/common/windows/version.c
new file mode 100644
index 0000000..4d61c78
--- /dev/null
+++ b/src/common/windows/version.c
@@ -0,0 +1,77 @@
+#include "common/debug.h"
+#include "common/mallocHelper.h"
+#include "common/windows/version.h"
+#include "common/windows/unicode.h"
+
+#include <windows.h>
+
+bool ffGetFileVersion(const wchar_t* filePath, const wchar_t* stringName, FFstrbuf* version) {
+ FF_DEBUG("ffGetFileVersion: enter filePath=%ls stringName=%ls", filePath, stringName);
+
+ DWORD handle;
+ DWORD size = GetFileVersionInfoSizeW(filePath, &handle);
+ if (size == 0) {
+ FF_DEBUG("GetFileVersionInfoSizeW failed: %s", ffDebugWin32Error(GetLastError()));
+ return false;
+ }
+
+ FF_DEBUG("GetFileVersionInfoSizeW ok: size=%lu handle=%lu",
+ (unsigned long) size,
+ (unsigned long) handle);
+
+ FF_AUTO_FREE void* versionData = malloc(size);
+ if (!versionData) {
+ FF_DEBUG("malloc failed: size=%lu", (unsigned long) size);
+ return false;
+ }
+
+ if (!GetFileVersionInfoW(filePath, handle, size, versionData)) {
+ FF_DEBUG("GetFileVersionInfoW failed: %s", ffDebugWin32Error(GetLastError()));
+ return false;
+ }
+
+ FF_DEBUG("GetFileVersionInfoW ok");
+
+ if (!stringName) {
+ VS_FIXEDFILEINFO* verInfo;
+ UINT len;
+ if (VerQueryValueW(versionData, L"\\", (void**) &verInfo, &len) &&
+ len &&
+ verInfo->dwSignature == 0xFEEF04BD) {
+ ffStrbufSetF(version, "%u.%u.%u.%u", (unsigned) ((verInfo->dwProductVersionMS >> 16) & 0xffff), (unsigned) ((verInfo->dwProductVersionMS >> 0) & 0xffff), (unsigned) ((verInfo->dwProductVersionLS >> 16) & 0xffff), (unsigned) ((verInfo->dwProductVersionLS >> 0) & 0xffff));
+ FF_DEBUG("fixed version resolved: %s", version->chars);
+ return true;
+ }
+
+ FF_DEBUG("fixed version query failed or invalid signature");
+ return false;
+ }
+
+ struct {
+ WORD language;
+ WORD codePage;
+ }* translations;
+ UINT translationsLen;
+
+ if (VerQueryValueW(versionData, L"\\VarFileInfo\\Translation", (void**) &translations, &translationsLen) &&
+ translationsLen >= sizeof(*translations)) {
+ wchar_t subBlock[128];
+ snwprintf(subBlock, ARRAY_SIZE(subBlock), L"\\StringFileInfo\\%04x%04x\\%ls", translations[0].language, translations[0].codePage, stringName);
+ FF_DEBUG("query version string with translation: %ls", subBlock);
+
+ wchar_t* value;
+ UINT valueLen; // Number of characters, including null terminator
+ if (VerQueryValueW(versionData, subBlock, (void**) &value, &valueLen) && valueLen > 0) {
+ ffStrbufSetNWS(version, valueLen - 1, value);
+ FF_DEBUG("version string resolved (translation fallback): %s", version->chars);
+ return true;
+ }
+
+ FF_DEBUG("translation fallback query failed");
+ } else {
+ FF_DEBUG("no translation table found in version resource");
+ }
+
+ FF_DEBUG("ffGetFileVersion failed");
+ return false;
+}