2006-04-12 01:59:08 +02:00
|
|
|
/**
|
|
|
|
* =========================================================================
|
|
|
|
* File : dll_ver.cpp
|
|
|
|
* Project : 0 A.D.
|
|
|
|
* Description : return DLL version information.
|
|
|
|
* =========================================================================
|
|
|
|
*/
|
|
|
|
|
2007-05-07 18:33:24 +02:00
|
|
|
// license: GPL; see lib/license.txt
|
2006-04-11 03:45:07 +02:00
|
|
|
|
|
|
|
#include "precompiled.h"
|
2007-01-01 22:25:47 +01:00
|
|
|
#include "dll_ver.h"
|
2006-04-11 03:45:07 +02:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2006-04-22 18:26:16 +02:00
|
|
|
#include "lib/path_util.h"
|
2007-05-08 17:11:53 +02:00
|
|
|
#include "win.h"
|
2007-05-04 19:30:32 +02:00
|
|
|
#include "wutil.h"
|
2007-05-24 04:32:53 +02:00
|
|
|
#include "winit.h"
|
2006-04-11 03:45:07 +02:00
|
|
|
|
|
|
|
#if MSC_VERSION
|
|
|
|
#pragma comment(lib, "version.lib") // DLL version
|
|
|
|
#endif
|
|
|
|
|
2007-05-24 04:32:53 +02:00
|
|
|
|
|
|
|
#pragma SECTION_PRE_LIBC(B)
|
|
|
|
WIN_REGISTER_FUNC(dll_ver_PreLibcInit);
|
|
|
|
#pragma FORCE_INCLUDE(dll_ver_PreLibcInit)
|
|
|
|
#pragma SECTION_RESTORE
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// temporarily disable and re-enable Wow64 file redirection.
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// Wow64 'helpfully' redirects all 32-bit apps' accesses of
|
|
|
|
// %windir\\system32\\drivers to %windir\\system32\\drivers\\SysWOW64.
|
|
|
|
// that's bad, because the actual drivers are not in the subdirectory. to
|
|
|
|
// work around this, we disable redirection over the duration of get_ver.
|
|
|
|
|
|
|
|
static BOOL (WINAPI *pWow64DisableWow64FsRedirection)(PVOID*) = 0;
|
|
|
|
static BOOL (WINAPI *pWow64RevertWow64FsRedirection)(PVOID) = 0;
|
|
|
|
|
|
|
|
static void ImportWow64Functions()
|
|
|
|
{
|
|
|
|
HMODULE hKernel32Dll = LoadLibrary("kernel32.dll");
|
|
|
|
*(void**)&pWow64DisableWow64FsRedirection = GetProcAddress(hKernel32Dll, "Wow64DisableWow64FsRedirection");
|
|
|
|
*(void**)&pWow64RevertWow64FsRedirection = GetProcAddress(hKernel32Dll, "Wow64RevertWow64FsRedirection");
|
|
|
|
FreeLibrary(hKernel32Dll);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void DisableRedirection(PVOID& wasRedirectionEnabled)
|
|
|
|
{
|
|
|
|
// note: don't just check if the function pointers are valid. 32-bit
|
|
|
|
// Vista includes them but isn't running Wow64, so calling the functions
|
|
|
|
// would fail. since we have to check if actually on Wow64, there's no
|
|
|
|
// more need to verify the pointers (their existence is implied).
|
|
|
|
if(!wutil_IsWow64())
|
|
|
|
return;
|
|
|
|
BOOL ok = pWow64DisableWow64FsRedirection(&wasRedirectionEnabled);
|
|
|
|
WARN_IF_FALSE(ok);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void RevertRedirection(PVOID wasRedirectionEnabled)
|
|
|
|
{
|
|
|
|
if(!wutil_IsWow64())
|
|
|
|
return;
|
|
|
|
BOOL ok = pWow64RevertWow64FsRedirection(wasRedirectionEnabled);
|
|
|
|
WARN_IF_FALSE(ok);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2006-10-20 22:33:38 +02:00
|
|
|
// helper function that does all the work; caller wraps it and takes care of
|
|
|
|
// undoing various operations if we fail midway.
|
|
|
|
static LibError get_ver_impl(const char* module_path, char* out_ver, size_t out_ver_len, void*& mem)
|
2006-04-11 03:45:07 +02:00
|
|
|
{
|
|
|
|
// determine size of and allocate memory for version information.
|
|
|
|
DWORD unused;
|
|
|
|
const DWORD ver_size = GetFileVersionInfoSize(module_path, &unused);
|
|
|
|
if(!ver_size)
|
2006-10-20 22:33:38 +02:00
|
|
|
WARN_RETURN(ERR::FAIL);
|
|
|
|
mem = malloc(ver_size);
|
|
|
|
if(!mem)
|
|
|
|
WARN_RETURN(ERR::NO_MEM);
|
|
|
|
|
|
|
|
if(!GetFileVersionInfo(module_path, 0, ver_size, mem))
|
|
|
|
WARN_RETURN(ERR::FAIL);
|
|
|
|
|
|
|
|
u16* lang; // -> 16 bit language ID, 16 bit codepage
|
|
|
|
uint lang_len;
|
|
|
|
const BOOL ok = VerQueryValue(mem, "\\VarFileInfo\\Translation", (void**)&lang, &lang_len);
|
|
|
|
if(!ok || !lang || lang_len != 4)
|
|
|
|
WARN_RETURN(ERR::FAIL);
|
|
|
|
|
|
|
|
char subblock[64];
|
|
|
|
sprintf(subblock, "\\StringFileInfo\\%04X%04X\\FileVersion", lang[0], lang[1]);
|
|
|
|
const char* in_ver;
|
|
|
|
uint in_ver_len;
|
|
|
|
if(!VerQueryValue(mem, subblock, (void**)&in_ver, &in_ver_len))
|
|
|
|
WARN_RETURN(ERR::FAIL);
|
|
|
|
|
|
|
|
strcpy_s(out_ver, out_ver_len, in_ver);
|
|
|
|
return INFO::OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get version information for the specified DLL.
|
|
|
|
static LibError get_ver(const char* module_path, char* out_ver, size_t out_ver_len)
|
|
|
|
{
|
2007-05-24 04:32:53 +02:00
|
|
|
LibError ret;
|
2006-04-11 03:45:07 +02:00
|
|
|
|
2007-05-24 04:32:53 +02:00
|
|
|
WIN_SAVE_LAST_ERROR; // GetFileVersion*, Ver*
|
2006-04-11 03:45:07 +02:00
|
|
|
{
|
2007-05-24 04:32:53 +02:00
|
|
|
PVOID wasRedirectionEnabled;
|
|
|
|
DisableRedirection(wasRedirectionEnabled);
|
|
|
|
{
|
|
|
|
void* mem = NULL;
|
|
|
|
ret = get_ver_impl(module_path, out_ver, out_ver_len, mem);
|
|
|
|
free(mem);
|
|
|
|
}
|
|
|
|
RevertRedirection(wasRedirectionEnabled);
|
2006-04-11 03:45:07 +02:00
|
|
|
}
|
|
|
|
WIN_RESTORE_LAST_ERROR;
|
|
|
|
|
2006-10-20 22:33:38 +02:00
|
|
|
if(ret != INFO::OK)
|
|
|
|
out_ver[0] = '\0';
|
2006-04-11 03:45:07 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// build a string containing DLL filename(s) and their version info.
|
|
|
|
//
|
|
|
|
|
|
|
|
static char* dll_list_buf;
|
|
|
|
static size_t dll_list_chars;
|
|
|
|
static char* dll_list_pos;
|
|
|
|
|
|
|
|
// set output buffer into which DLL names and their versions will be written.
|
|
|
|
void dll_list_init(char* buf, size_t chars)
|
|
|
|
{
|
|
|
|
dll_list_pos = dll_list_buf = buf;
|
|
|
|
dll_list_chars = chars;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// read DLL file version and append that and its name to the list.
|
|
|
|
//
|
|
|
|
// name should preferably be the complete path to DLL, to make sure
|
|
|
|
// we don't inadvertently load another one on the library search path.
|
|
|
|
// we add the .dll extension if necessary.
|
|
|
|
LibError dll_list_add(const char* name)
|
|
|
|
{
|
|
|
|
// not be called before dll_list_init or after failure
|
|
|
|
if(!dll_list_pos)
|
2006-09-22 15:19:40 +02:00
|
|
|
WARN_RETURN(ERR::LOGIC);
|
2006-04-11 03:45:07 +02:00
|
|
|
|
|
|
|
// some driver names are stored in the registry without .dll extension.
|
|
|
|
// if necessary, copy to new buffer and add it there.
|
|
|
|
// note: do not change extension if present; some drivers have a
|
|
|
|
// ".sys" extension, so always appending ".dll" is incorrect.
|
|
|
|
char buf[MAX_PATH];
|
|
|
|
const char* dll_name = name;
|
2006-04-22 18:26:16 +02:00
|
|
|
const char* ext = path_extension(name);
|
|
|
|
if(ext[0] == '\0') // no extension
|
2006-04-11 03:45:07 +02:00
|
|
|
{
|
|
|
|
snprintf(buf, ARRAY_SIZE(buf), "%s.dll", name);
|
|
|
|
dll_name = buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
// read file version.
|
|
|
|
char dll_ver[128] = "unknown"; // enclosed in () below
|
|
|
|
(void)get_ver(dll_name, dll_ver, sizeof(dll_ver));
|
|
|
|
// if this fails, default is already set and we don't want to abort.
|
|
|
|
|
|
|
|
const ssize_t max_chars_to_write = (ssize_t)dll_list_chars - (dll_list_pos-dll_list_buf) - 10;
|
|
|
|
// reserves enough room for subsequent comma and "..." strings.
|
|
|
|
|
|
|
|
// not first time: prepend comma to string (room was reserved above).
|
|
|
|
if(dll_list_pos != dll_list_buf)
|
|
|
|
dll_list_pos += sprintf(dll_list_pos, ", ");
|
|
|
|
|
|
|
|
// extract filename.
|
2006-04-22 18:26:16 +02:00
|
|
|
const char* dll_fn = path_name_only(dll_name);
|
2006-04-11 03:45:07 +02:00
|
|
|
|
|
|
|
int len = snprintf(dll_list_pos, max_chars_to_write, "%s (%s)", dll_fn, dll_ver);
|
|
|
|
// success
|
|
|
|
if(len > 0)
|
|
|
|
{
|
|
|
|
dll_list_pos += len;
|
2006-09-22 15:19:40 +02:00
|
|
|
return INFO::OK;
|
2006-04-11 03:45:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// didn't fit; complain
|
|
|
|
sprintf(dll_list_pos, "..."); // (room was reserved above)
|
|
|
|
dll_list_pos = 0; // poison pill, prevent further calls
|
2006-09-22 15:19:40 +02:00
|
|
|
WARN_RETURN(ERR::BUF_SIZE);
|
2006-04-11 03:45:07 +02:00
|
|
|
}
|
2007-05-24 04:32:53 +02:00
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
static LibError dll_ver_PreLibcInit()
|
|
|
|
{
|
|
|
|
ImportWow64Functions();
|
|
|
|
|
|
|
|
return INFO::OK;
|
|
|
|
}
|