mirror of
https://github.com/etlegacy/Update-Installer.git
synced 2024-11-22 03:41:11 +00:00
Show a useful product name and description in the UAC prompt under Windows Vista/7
Add a VERSION_INFO section to the executable's resource file specifying the product name and description. The organization is currently set as 'Mendeley Ltd' - other projects will want to customize this. When the produced executable is digitally signed, the product name and description are shown in the UAC prompt asking for admin permissions.
This commit is contained in:
parent
ea7fc49002
commit
2f89332824
23 changed files with 3099 additions and 0 deletions
225
external/verpatch/src/ReadMe.txt
vendored
Normal file
225
external/verpatch/src/ReadMe.txt
vendored
Normal file
|
@ -0,0 +1,225 @@
|
|||
Verpatch - a tool to patch win32 version resources on .exe or .dll files,
|
||||
|
||||
Version: 01-Nov-2009 (rev. #7 for CodeProject)
|
||||
|
||||
Verpatch is a command line tool for adding and editing the version information
|
||||
of Windows executable files (applications, DLLs, kernel drivers)
|
||||
without rebuilding the executable.
|
||||
|
||||
It can also add or replace Win32 (native) resources, and do some other
|
||||
modifications of executable files.
|
||||
|
||||
Verpatch sets ERRORLEVEL 0 on success, otherwise errorlevel is non-zero.
|
||||
Verpatch modifies files in place, so please make copies of precious files.
|
||||
|
||||
|
||||
Command line syntax
|
||||
===================
|
||||
|
||||
verpatch filename [version] [/options]
|
||||
|
||||
The filename is the executable file (exe, dll, sys, ocx...) to edit.
|
||||
NOTE: the file will be modified; please make backup copies of precious files.
|
||||
|
||||
The version argument is one to four decimal numbers, separated by dots.
|
||||
The version argument can also have additional text after the numbers; see examples below.
|
||||
|
||||
|
||||
Common Options:
|
||||
|
||||
/s name "value" - add any version resource string attribute
|
||||
The name can be either a full attribute name or alias; see below.
|
||||
/sc "comment" - add or replace Comments string (same as /s Comments "comment")
|
||||
/pv <version> - specify Product version
|
||||
where <version> arg has same form as the file version (1.2.3.4 or "1.2.3.4 text")
|
||||
/vft2 num - specify driver subtype (VFT2_xxx value, see winver.h)
|
||||
The application type (VFT_xxx) is retained from the existing version resource of the file,
|
||||
or filled automatically, based on the filename extension.
|
||||
/fn - preserves Original filename, Internal name in the existing version resource of the file.
|
||||
/va - creates a version resource. Use when the file has no version resource at all.
|
||||
If this option not specified, verpatch will read and parse the version resourse from the file.
|
||||
/vo - outputs the version info in RC format to stdout.
|
||||
This can be used with /xi to import a version resource from another file.
|
||||
Output of /vo (text from #ifdef RC_INVOKED to #endif) can be saved to a .rc file and compiled with rc.
|
||||
|
||||
Other options:
|
||||
|
||||
/xi- test mode. does all operations but does not modify the file
|
||||
/xlb - test mode. Re-parses the version resource after modification.
|
||||
/rpdb - remove path of the .pdb file in debug information.
|
||||
/rf #id file - add or replace a raw binary resource from file (see below)
|
||||
/noed - do not check for extra data appended to exe file
|
||||
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
verpatch d:\foo.dll 1.2.33.44
|
||||
- replaces only the file version, all 4 numbers,
|
||||
the Original file name and Internal name strings are set to "foo.dll".
|
||||
|
||||
verpatch d:\foo.dll 33.44 /sc "a comment"
|
||||
- replaces only two last numbers of the file version and adds a comment.
|
||||
|
||||
verpatch d:\foo.dll "33.44 special release" /sc "a comment"
|
||||
- same as previous, with additional text in the version argument.
|
||||
|
||||
verpatch d:\foo.dll "1.2.33.44" /va /s FileDescription "foo.dll"
|
||||
/s CompanyName "company" /s LegalCopyright "(c) 2009"
|
||||
- adds a version resource to foo.dll, specify several string values.
|
||||
( this should be one line)
|
||||
|
||||
verpatch d:\foo.dll /vo /xi
|
||||
- dumps the version resource in RC format, does not update the file.
|
||||
|
||||
|
||||
|
||||
Remarks
|
||||
=======
|
||||
|
||||
Verpatch replaces the version number in existing file version info resource
|
||||
with the values given on the command line.
|
||||
|
||||
In "patch" mode (no /va option), the PE file should have a version resource,
|
||||
which is parsed, and then parameters specified on the command line are applied.
|
||||
|
||||
If the file has no version resource, use /va to create it.
|
||||
All nesessary strings can be specified with the /s option.
|
||||
The command line can become very long, so you may want to use
|
||||
a batch file or script.
|
||||
See the example batch files, how to create a version resource and
|
||||
specify all parameters with /va.
|
||||
|
||||
Verpatch can be run on same PE file any number of times.
|
||||
|
||||
The Version argument can be specified as 1 to 4 dot separated decimal numbers,
|
||||
or as quoted string containing additional text after the numbers.
|
||||
If less than 4 numbers are given, they are considered as lower numbers.
|
||||
The higher version parts are retained from existing version resource.
|
||||
For example, if the existing version info has version number 1.2.3.4
|
||||
and 55.66 specified on the command line, the result will be 1.2.55.66.
|
||||
|
||||
The quotes surrounding string arguments are needed for the command line shell (cmd.exe),
|
||||
for any argument that contains spaces.
|
||||
|
||||
The program ensures that the version numbers in the binary part
|
||||
of the version structure and in the string part (as text) are same.
|
||||
|
||||
By default, Original File Name and Internal File Name are replaced to the actual filename.
|
||||
Use /fn to preserve existing values in the version resource.
|
||||
|
||||
For option /s, specify *invariant* string names, not translations
|
||||
( example: PrivateBuild, not "Private Build Description" ).
|
||||
See below for the list of known string names and aliases.
|
||||
Null values can be specified as "".
|
||||
|
||||
Strings for File version and Product version parameters are handled in a special way,
|
||||
the /s switch can not be used to set them:
|
||||
- File version can be specified as the 2nd positional argument of the command
|
||||
- Product version can be specified using /pv switch
|
||||
|
||||
The /rf switch adds a resource from a file, or replaces a resource with same type and id.
|
||||
The file is added as opaque binary chunk; the size is rounded up to 4 bytes.
|
||||
The argument "#id" is a 32-bit hex number, prefixed with #.
|
||||
Low 16 bits of this value are resource id; can not be 0.
|
||||
Next 8 bits are resource type: one of RT_xxx symbols in winuser.h, or user defined.
|
||||
High 8 bits of the #id arg are reserved0.
|
||||
If the type value is 0, RT_RCDATA (10) is assumed.
|
||||
The language code of resources added by this switch is 0 (Neutral).
|
||||
Named resource types and ids are not implemented.
|
||||
|
||||
The program detects extra data appended to executable files, saves it and appends
|
||||
again after modifying resources.
|
||||
Such extra data is used by some installers, self-extracting archives and other applications.
|
||||
However, the way we restore the data may be not compatible with these applications.
|
||||
Please, verify that executable files that contain extra data work correctly after modification.
|
||||
Command switch /noed disables checking for extra data.
|
||||
|
||||
|
||||
====================================================================
|
||||
Known string keys in VS_VERSION_INFO resource
|
||||
====================================================================
|
||||
|
||||
The aliases are for use with the /s switch (case insensitive).
|
||||
|
||||
-------------------+----+-------------------------------+------------
|
||||
Invariant name |note| English translation | Alias
|
||||
-------------------+----+-------------------------------+------------
|
||||
Comments Comments comment
|
||||
CompanyName E Company company
|
||||
FileDescription E Description description, desc
|
||||
FileVersion *1 File version
|
||||
InternalName Internal Name title
|
||||
*2 Language
|
||||
LegalCopyright E Copyright copyright, (c)
|
||||
LegalTrademarks E Legal Trademarks tm, (tm)
|
||||
OriginalFilename Original File Name
|
||||
ProductName Product Name product
|
||||
ProductVersion *1 Product Version productver, prodver
|
||||
PrivateBuild Private Build Description pb
|
||||
SpecialBuild Special Build Description sb, build
|
||||
OleSelfRegister A -
|
||||
AssemblyVersion N
|
||||
|
||||
Notes
|
||||
*1: FileVersion, ProductVersion values:
|
||||
Can be any text. Windows Explorer displays the version numbers from the binary header.
|
||||
To avoid confusion, should begin with same v1.v2.v3.v4 version number as in the binary header.
|
||||
|
||||
*2: The "Language" value is the name of the language code specified in the header of the string block
|
||||
of VS_VERSION_INFO resource. (or taken from VarFileInfo block?)
|
||||
It is not a string in the string version data.
|
||||
|
||||
E: Displayed by Windows Explorer in Vista+
|
||||
A: Intended for some API (OleSelfRegister is used in COM object registration)
|
||||
N: Added by some .NET compilers. This version number is not contained in the
|
||||
binary part of the version struct and can differ from the file version.
|
||||
To change it, just use switch /s AssemblyVersion [value]
|
||||
|
||||
====================================================================
|
||||
|
||||
|
||||
|
||||
Known issues and TO DO's:
|
||||
=========================
|
||||
|
||||
- Currenly implemented only US English and Language Neutral Unicode version resources.
|
||||
MUI resource configuration manifests not checked.
|
||||
New version resource will be created as Language Neutral.
|
||||
Version info in other languages will be erroneously rewritten as English or Language Neutral- TO DO
|
||||
|
||||
A second (language neutral) version resource may be added to a file
|
||||
that already has a version resource in other language. Switch /va won't help.
|
||||
TO DO: ensure that a file has only one version resource!
|
||||
|
||||
- When verpatch is invoked from command prompt, or batch file, the string
|
||||
arguments can contain only ANSI characters, because cmd.exe batch files cannot be
|
||||
in Uncode format. If you need to include characters not in current locale,
|
||||
use other shell languages that fully support Unicode (PowerShell, vbs, js).
|
||||
|
||||
- TO DO: In RC source output (/vo), special characters in strings are not quoted;
|
||||
so /vo may produce invalid RC input
|
||||
|
||||
- The parser of binary version resources handles only the most common type of structure.
|
||||
If the parser breaks because of unhandled structure format, try /va switch to
|
||||
skip reading existing version resource and re-create it from scratch.
|
||||
Consider using WINE or other open source implementations?
|
||||
|
||||
- option to add extra 0 after version strings : "string\0"
|
||||
(tentative, requiested by a reader for some old VB code)
|
||||
|
||||
- For files with extra data, checksum is not re-calculated. Revise.
|
||||
|
||||
|
||||
Source code
|
||||
============
|
||||
The source is provided as a Visual C++ 2005 project, it can be compiled with VC 2008 Express.
|
||||
It demonstrates use of the UpdateResource and imagehlp.dll API.
|
||||
It does not demonstrate use of c++, good coding manners or anything else.
|
||||
Dependencies on C++ libraries available only with the full Visual C 2008 have been removed.
|
||||
|
||||
|
||||
LICENSE TERMS: CPOL (CodeProject Open License)
|
||||
http://www.codeproject.com/info/licenses.aspx
|
||||
|
||||
~~
|
100
external/verpatch/src/peExtras.cpp
vendored
Normal file
100
external/verpatch/src/peExtras.cpp
vendored
Normal file
|
@ -0,0 +1,100 @@
|
|||
//
|
||||
// PE image related utils
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "peExtras.h"
|
||||
#include "relstamp.h"
|
||||
#include <imagehlp.h>
|
||||
#pragma comment(lib, "imagehlp")
|
||||
|
||||
#if UNICODE
|
||||
// only non-unicode form of MapAndLoad exists in imagehlp. Grr.
|
||||
BOOL MapAndLoadW(
|
||||
__in PCWSTR ImageName,
|
||||
__in_opt PCWSTR DllPath,
|
||||
__out PLOADED_IMAGE LoadedImage,
|
||||
__in BOOL DotDll,
|
||||
__in BOOL ReadOnly
|
||||
);
|
||||
#define MapAndLoadT MapAndLoadW
|
||||
#else
|
||||
#define MapAndLoadT MapAndLoad
|
||||
#endif
|
||||
|
||||
BOOL getFileExtraData(LPCTSTR fname, PVOID *extraData, LPDWORD dwSize)
|
||||
{
|
||||
*dwSize = 0;
|
||||
*extraData = NULL;
|
||||
|
||||
BOOL r;
|
||||
LOADED_IMAGE im;
|
||||
|
||||
r = ::MapAndLoadT(
|
||||
fname,
|
||||
_T("\\no-implicit-paths"),
|
||||
&im,
|
||||
FALSE, // .exe by default
|
||||
TRUE // readonly
|
||||
);
|
||||
|
||||
if (!r) {
|
||||
dprint("err open file for reading extra data %d\n", GetLastError() );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ULONG endOfImage = 0;
|
||||
|
||||
for (ULONG i = 0; i < im.NumberOfSections; i++)
|
||||
{
|
||||
if (endOfImage < im.Sections[i].PointerToRawData + im.Sections[i].SizeOfRawData)
|
||||
endOfImage = im.Sections[i].PointerToRawData + im.Sections[i].SizeOfRawData;
|
||||
}
|
||||
|
||||
if (im.SizeOfImage > endOfImage)
|
||||
{
|
||||
*dwSize = im.SizeOfImage - endOfImage;
|
||||
*extraData = malloc(*dwSize);
|
||||
ASSERT(*extraData);
|
||||
memcpy(*extraData, &im.MappedAddress[endOfImage], *dwSize);
|
||||
}
|
||||
|
||||
r = ::UnMapAndLoad( &im );
|
||||
if (!r) {
|
||||
dprint("err unloading file %d\n", GetLastError() );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL appendFileExtraData( PCTSTR fname, PVOID extraData, DWORD dwSize)
|
||||
{
|
||||
DWORD bytesWritten = 0;
|
||||
|
||||
if (extraData == NULL)
|
||||
return TRUE;
|
||||
|
||||
HANDLE fh = CreateFile(fname, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
if (INVALID_HANDLE_VALUE == fh ) {
|
||||
dtprint(_T("Error opening executable %s err=%d\n"), fname, GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD pos = SetFilePointer(fh, 0, NULL, FILE_END);
|
||||
if ( INVALID_SET_FILE_POINTER == pos ) {
|
||||
dtprint(_T("Error seeking executable %s err=%d\n"), fname, GetLastError());
|
||||
CloseHandle(fh);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !WriteFile(fh, extraData, dwSize, &bytesWritten, NULL) || (bytesWritten != dwSize) ) {
|
||||
dtprint(_T("Error writing extra data %s err=%d\n"), fname, GetLastError());
|
||||
CloseHandle(fh);
|
||||
return false;
|
||||
}
|
||||
|
||||
CloseHandle(fh);
|
||||
return TRUE;
|
||||
}
|
4
external/verpatch/src/peExtras.h
vendored
Normal file
4
external/verpatch/src/peExtras.h
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
|
||||
extern BOOL getFileExtraData(PCTSTR fname, PVOID *extraData, PDWORD dwSize);
|
||||
extern BOOL appendFileExtraData(PCTSTR fname, PVOID extraData, DWORD size);
|
234
external/verpatch/src/peutils.cpp
vendored
Normal file
234
external/verpatch/src/peutils.cpp
vendored
Normal file
|
@ -0,0 +1,234 @@
|
|||
//
|
||||
// PE image related utils
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "relstamp.h"
|
||||
#include <imagehlp.h>
|
||||
#pragma comment(lib, "imagehlp")
|
||||
|
||||
#if UNICODE
|
||||
// only non-unicode form of MapAndLoad exists in imagehlp. Grr.
|
||||
BOOL MapAndLoadW(
|
||||
__in PCWSTR ImageName,
|
||||
__in_opt PCWSTR DllPath,
|
||||
__out PLOADED_IMAGE LoadedImage,
|
||||
__in BOOL DotDll,
|
||||
__in BOOL ReadOnly
|
||||
);
|
||||
#define MapAndLoadT MapAndLoadW
|
||||
#else
|
||||
#define MapAndLoadT MapAndLoad
|
||||
#endif
|
||||
|
||||
|
||||
bool clearPdbPath( PLOADED_IMAGE pim )
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
__try {
|
||||
|
||||
PIMAGE_NT_HEADERS pnth = pim->FileHeader;
|
||||
PIMAGE_FILE_HEADER pfh = &(pnth->FileHeader);
|
||||
WORD mtype = pfh->Machine;
|
||||
PIMAGE_DEBUG_DIRECTORY pdebug;
|
||||
PIMAGE_DATA_DIRECTORY pd;
|
||||
|
||||
switch (mtype) {
|
||||
case IMAGE_FILE_MACHINE_I386: {
|
||||
PIMAGE_OPTIONAL_HEADER32 pih =
|
||||
&(((PIMAGE_NT_HEADERS32)pnth)->OptionalHeader);
|
||||
pd = pih->DataDirectory;
|
||||
break;
|
||||
}
|
||||
case IMAGE_FILE_MACHINE_AMD64: {
|
||||
// EXPERIMENTAL for x64 image mapped on x86 host:
|
||||
PIMAGE_OPTIONAL_HEADER64 pih =
|
||||
&(((PIMAGE_NT_HEADERS64)pnth)->OptionalHeader);
|
||||
pd = pih->DataDirectory;
|
||||
break;
|
||||
}
|
||||
case IMAGE_FILE_MACHINE_IA64:
|
||||
dprint("not tested for IA64\n"); return false;
|
||||
default:
|
||||
dprint("Unsupported arch\n"); return false;
|
||||
}
|
||||
|
||||
ULONG32 adebug = pd[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
|
||||
ULONG i;
|
||||
for ( i = 0; i < pim->NumberOfSections; i++ ) {
|
||||
PIMAGE_SECTION_HEADER sh = &pim->Sections[i];
|
||||
if ( (sh->VirtualAddress <= adebug) &&
|
||||
(sh->SizeOfRawData + sh->VirtualAddress > adebug) ) {
|
||||
adebug -= sh->VirtualAddress;
|
||||
adebug += sh->PointerToRawData;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( i >= pim->NumberOfSections ) {
|
||||
d2print("virt address %#x not found\n", adebug);
|
||||
__leave;
|
||||
}
|
||||
pdebug = (PIMAGE_DEBUG_DIRECTORY)( adebug + (PUCHAR)(pim->MappedAddress) );
|
||||
|
||||
if ( pdebug->Type != IMAGE_DEBUG_TYPE_CODEVIEW /*2*/ )
|
||||
__leave;
|
||||
char *pdd = pdebug->PointerToRawData + (char*)(pim->MappedAddress);
|
||||
if ( *((PULONG32)pdd) != 'SDSR' )
|
||||
__leave;
|
||||
|
||||
unsigned dsize = pdebug->SizeOfData;
|
||||
if ( dsize <= 0x18 ) //?
|
||||
__leave;
|
||||
pdd += 0x18; //skip header to the pdb name string
|
||||
dsize -= 0x18;
|
||||
unsigned dsize2 = strnlen( pdd, dsize );
|
||||
if ( dsize2 == 0 || dsize2 >= dsize )
|
||||
__leave;
|
||||
d2print("PDB path in image:[%hs]\n", pdd);
|
||||
|
||||
char * pdbname = strrchr( pdd, '\\' );
|
||||
|
||||
if ( !pdbname || (pdbname - pdd) <= 4 || strchr( pdd, '\\' ) == pdbname ) {
|
||||
d2print("PDB path too short, not changing\n");
|
||||
ret = true; __leave;
|
||||
}
|
||||
|
||||
memcpy( pdd, "\\x\\", 3 );
|
||||
strcpy_s( pdd + 3, dsize2 - 3, pdbname );
|
||||
char *t = pdd + strlen(pdd);
|
||||
SecureZeroMemory( t, dsize2 - (t - pdd) );
|
||||
|
||||
ret = true;
|
||||
|
||||
} __except( EXCEPTION_EXECUTE_HANDLER ) {
|
||||
ret = false;
|
||||
dprint("%s - exception\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL updFileChecksum( LPCTSTR fname, bool fRemovePdbPath )
|
||||
{
|
||||
BOOL r;
|
||||
LOADED_IMAGE im;
|
||||
|
||||
r = ::MapAndLoadT(
|
||||
fname,
|
||||
_T("\\no-implicit-paths"),
|
||||
&im,
|
||||
FALSE, // .exe by default
|
||||
FALSE // readonly
|
||||
);
|
||||
|
||||
if (!r) {
|
||||
dprint("err open file for rechecksum %d\n", GetLastError() );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( !(im.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) ) {
|
||||
dprint("error: the file not marked as executable (build errors?)\n");
|
||||
::UnMapAndLoad( &im );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// begin image patches
|
||||
if ( fRemovePdbPath && !clearPdbPath( &im ) ) {
|
||||
dprint("error while editing pdb path\n");
|
||||
::UnMapAndLoad( &im );
|
||||
return FALSE;
|
||||
}
|
||||
// end image patches
|
||||
|
||||
// Checksum offset is same for IMAGE_OPTIONAL_HEADER32 and 64.
|
||||
DWORD old_sum, new_sum;
|
||||
PIMAGE_NT_HEADERS pimh = ::CheckSumMappedFile( im.MappedAddress, im.SizeOfImage, &old_sum, &new_sum );
|
||||
if (!pimh ) {
|
||||
dprint( "err CheckSumMappedFile %d\n", GetLastError() );
|
||||
::UnMapAndLoad( &im );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// d3print( "old cksm=%4.4X new=%4.4X\n", old_sum, new_sum );
|
||||
pimh->OptionalHeader.CheckSum = new_sum;
|
||||
|
||||
r = ::UnMapAndLoad( &im );
|
||||
if (!r) {
|
||||
dprint("err writing file back after patching %d\n", GetLastError() );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if UNICODE
|
||||
|
||||
PSTR strFilePathDeUnicode( PCWSTR tstr );
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Only a non-unicode form of MapAndLoad exists in imagehlp. Grr.
|
||||
//---------------------------------------------------------------------------------
|
||||
BOOL
|
||||
MapAndLoadW(
|
||||
__in PCWSTR fname,
|
||||
__in_opt PCWSTR path,
|
||||
__out PLOADED_IMAGE LoadedImage,
|
||||
BOOL DotDll,
|
||||
BOOL Readonly )
|
||||
{
|
||||
BOOL r;
|
||||
UNREFERENCED_PARAMETER(path); // fake this arg to not search, and not deunicode
|
||||
// Convert PWSTR to something acceptable for CreateFileA
|
||||
// Another way: Require the file *name* only be ascii, then path can be gibberish.
|
||||
// => cd to the path and use ./filename form.
|
||||
PSTR a_fname = strFilePathDeUnicode(fname);
|
||||
if (!a_fname) {
|
||||
dprint("err opening file for rechecksum (unicode path)\n");
|
||||
return FALSE;
|
||||
}
|
||||
r = MapAndLoad( a_fname, "\\dont-search-path", LoadedImage, DotDll, Readonly );
|
||||
free( a_fname );
|
||||
return r;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Convert unicode file path to something acceptable for non-unicode file APIs.
|
||||
// Caller should free returned pointer with free()
|
||||
//---------------------------------------------------------------------------------
|
||||
PSTR strFilePathDeUnicode( __in PCWSTR tstr)
|
||||
{
|
||||
//- dprint("orig. path [%ws]\n", tstr );
|
||||
DWORD r;
|
||||
PWSTR p = (PWSTR)calloc( MAX_PATH + 1, sizeof(WCHAR) );
|
||||
if ( !p )
|
||||
return NULL;
|
||||
|
||||
r = ::GetShortPathName( tstr, p, MAX_PATH );
|
||||
if ( r == 0 || r >= MAX_PATH ) {
|
||||
dprint("err GetShortPathName, gle=%d\n", GetLastError() );
|
||||
free(p);
|
||||
return NULL;
|
||||
}
|
||||
// now convert to single bytes
|
||||
for (int i = 0; i < MAX_PATH; i++ ) {
|
||||
WCHAR w = p[i];
|
||||
if ( !w )
|
||||
break;
|
||||
if ( w > (WCHAR)0xFF ) {
|
||||
dprint("error: GetShortPathName returned unicode??\n");
|
||||
free(p);
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
return NULL;
|
||||
}
|
||||
p[i] = 0;
|
||||
((PUCHAR)p)[i] = w & 0xFF;
|
||||
}
|
||||
|
||||
d3print("de-unicoded name [%ws]=[%hs]\n", tstr, p );
|
||||
|
||||
return (PSTR)p;
|
||||
}
|
||||
#endif //UNICODE
|
||||
|
850
external/verpatch/src/relstamp.cpp
vendored
Normal file
850
external/verpatch/src/relstamp.cpp
vendored
Normal file
|
@ -0,0 +1,850 @@
|
|||
// relstamp.cpp
|
||||
//
|
||||
// pa04 fixed bug in productversion aliases (/pv)
|
||||
// pa03 fixed up for VC2008 Express
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "relstamp.h"
|
||||
#include "vs_version.h"
|
||||
#pragma comment(lib, "version")
|
||||
#include "peExtras.h"
|
||||
|
||||
// Options
|
||||
struct cmd_params {
|
||||
bool PatchMode; // true: patch version descr. of the input file. false: create and replace.
|
||||
bool DbgImportOnly; // debug: test import only, don't modify file
|
||||
bool DbgLoopbackTest; // reparse generated blob
|
||||
// For import & patch mode
|
||||
bool DumpImportVerAsRC; // dump input version info in RC format
|
||||
bool PreserveOriginalFilename; // false: set to actual filename
|
||||
bool PreserveInternalFilename; // false: set to actual filename
|
||||
bool PreserveStringVersionTail; // true: save appendix of fileversion, productversion strings
|
||||
|
||||
bool fClearPdbPath;
|
||||
bool fNoPreserveExtraAppendedData; // true = do not check for extra data appended to end of file
|
||||
|
||||
bool cmd_arg_parse( int argc, _TCHAR *argv[], PCTSTR *fname, struct file_ver_data_s *fvd );
|
||||
// cmd_params() {} // ctor
|
||||
} g_params;
|
||||
|
||||
// Struct to hold a resource:
|
||||
struct ResDesc
|
||||
{
|
||||
PUCHAR m_data;
|
||||
DWORD m_cbdata;
|
||||
ULONG_PTR m_type; // string ptr or numeric id
|
||||
ULONG_PTR m_name; // string ptr or numeric id
|
||||
WORD m_language;
|
||||
|
||||
ResDesc() : m_data(0), m_cbdata(0) {}
|
||||
|
||||
ResDesc( void *data, unsigned cbData, ULONG_PTR typeId,
|
||||
ULONG_PTR name_id, WORD langId = LANG_NEUTRAL )
|
||||
: m_data((PUCHAR)data), m_cbdata(cbData), m_type(typeId),
|
||||
m_name(name_id), m_language(langId) {}
|
||||
|
||||
friend bool addResourceFromFile( PCTSTR resfile, UINT32 id_flags );
|
||||
};
|
||||
|
||||
static
|
||||
ResDesc *aRes[_A_MAX_N_RES + 1];
|
||||
|
||||
static
|
||||
void addUpdRes( ResDesc *rd )
|
||||
{
|
||||
for (int i = 0; i < ARRAYSIZE(aRes) - 1; i++) {
|
||||
if ( NULL == aRes[i] ) {
|
||||
aRes[i] = rd;
|
||||
return;
|
||||
}
|
||||
}
|
||||
dprint("ERROR: Too many resources added\n");
|
||||
throw ":TooManyRes";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
BOOL fillCompanyInfo( __out file_ver_data_s *fvd )
|
||||
{
|
||||
// default
|
||||
fvd->addTwostr( L"CompanyName", DEF_COMPANY_NAME );
|
||||
fvd->addTwostr( L"LegalCopyright", DEF_COPYRGT ); //"Copyright (c) 2009"
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BOOL fillProductInfo( __out file_ver_data_s *fvd )
|
||||
{
|
||||
// default
|
||||
fvd->addTwostr( L"ProductName", DEF_PRODUCT_NAME );
|
||||
fvd->pv_1 = 1;
|
||||
fvd->pv_2 = 0;
|
||||
fvd->pv_3 = 0;
|
||||
fvd->pv_4 = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
// callback class for ParseBinaryVersionResource()
|
||||
class VerCallback1 : public IParseVerStrCallback
|
||||
{
|
||||
file_ver_data_s *m_vd;
|
||||
int m_numcalled;
|
||||
public:
|
||||
VerCallback1(file_ver_data_s *fvd) : m_numcalled(0), m_vd(fvd) {};
|
||||
void callback( PCWSTR name, PCWSTR value ) override;
|
||||
};
|
||||
|
||||
// Callback to import version strings
|
||||
void VerCallback1::callback( PCWSTR name, PCWSTR value )
|
||||
{
|
||||
d3print( "callback #%d [%ws]= [%ws]\n", m_numcalled, name, value );
|
||||
++m_numcalled;
|
||||
|
||||
// filter off FileVersion, Product Version. always take from FIXED_INFO.
|
||||
if ( 0 == _wcsicmp(name, L"FileVersion") ) {
|
||||
// Optional tail: "1.2.3.4 tail"
|
||||
PCTSTR tail = wcschr(value, _T(' '));
|
||||
if ( tail ) {
|
||||
while( *tail == _T(' ') ) tail++;
|
||||
if (*tail) m_vd->sFileVerTail = tail;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 0 == _wcsicmp(name, L"ProductVersion") ) {
|
||||
// Optional tail: "1.2.3.4 tail"
|
||||
PCTSTR tail = wcschr(value, _T(' '));
|
||||
if ( tail ) {
|
||||
while( *tail == _T(' ') ) tail++;
|
||||
if (*tail) m_vd->sProductVerTail = tail;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 0 == _wcsicmp(name, L"@LANG") ) {
|
||||
static const WCHAR sigLangNeutral[] = L"000004b0"; /* LANG_NEUTRAL */
|
||||
static const WCHAR sigLangEng[] = L"040904B0"; /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */
|
||||
|
||||
if ( 0 == _wcsicmp( value, sigLangEng ) )
|
||||
m_vd->langid = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
|
||||
else if ( 0 == _wcsicmp( value, sigLangNeutral ) )
|
||||
m_vd->langid = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
|
||||
else {
|
||||
dprint("Resource languages not supported yet! id=%ws", value);
|
||||
m_vd->langid = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
m_vd->addTwostr( name, value );
|
||||
}
|
||||
|
||||
BOOL fillFileInfo( __out file_ver_data_s *fvd, PCTSTR fpath )
|
||||
{
|
||||
UINT xname, xdot_ext;
|
||||
if ( !fileGetNameExtFromPath( fpath, &xname, &xdot_ext) ) {
|
||||
dtprint(_T("Error parsing the file name\n") );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PCTSTR pfilename = (PCTSTR)( (PUCHAR)fpath + xname );
|
||||
PCTSTR pdot_ext = (PCTSTR)( (PUCHAR)fpath + xdot_ext );
|
||||
|
||||
if ( g_params.PatchMode )
|
||||
{
|
||||
// Import version blob from the file
|
||||
PUCHAR verinfo = (PUCHAR)calloc( _MAX_VERS_SIZE_CB, 1 );
|
||||
ASSERT(verinfo);
|
||||
if ( !fileReadVersionInfo( fpath, verinfo, _MAX_VERS_SIZE_CB ) ) {
|
||||
dprint("error reading version info from the file, err=%d\n", GetLastError());
|
||||
if (ERROR_RESOURCE_TYPE_NOT_FOUND == GetLastError() )
|
||||
dprint("The file does not have a version resource\n");
|
||||
if (ERROR_RESOURCE_DATA_NOT_FOUND == GetLastError() )
|
||||
dprint("The file could not be found or is not executable/dll\n");
|
||||
free(verinfo);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VS_FIXEDFILEINFO *fxi = NULL;
|
||||
VerCallback1 mycb(fvd);
|
||||
if ( !ParseBinaryVersionResource( verinfo, _MAX_VERS_SIZE_CB,
|
||||
&fxi, &mycb, g_params.DumpImportVerAsRC ) ) {
|
||||
dprint("error parsing version info from the file\n");
|
||||
free(verinfo);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fvd->v_1 = HIWORD(fxi->dwFileVersionMS);
|
||||
fvd->v_2 = LOWORD(fxi->dwFileVersionMS);
|
||||
fvd->v_3 = HIWORD(fxi->dwFileVersionLS);
|
||||
fvd->v_4 = LOWORD(fxi->dwFileVersionLS);
|
||||
|
||||
fvd->pv_1 = HIWORD(fxi->dwProductVersionMS);
|
||||
fvd->pv_2 = LOWORD(fxi->dwProductVersionMS);
|
||||
fvd->pv_3 = HIWORD(fxi->dwProductVersionLS);
|
||||
fvd->pv_4 = LOWORD(fxi->dwProductVersionLS);
|
||||
|
||||
fvd->dwFileFlags = (fxi->dwFileFlags & fxi->dwFileFlagsMask);
|
||||
fvd->dwFileType = fxi->dwFileType;
|
||||
fvd->dwFileSubType = fxi->dwFileSubtype;
|
||||
|
||||
if (fxi->dwFileOS != VOS_NT_WINDOWS32 && fxi->dwFileOS != VOS__WINDOWS32 ) {
|
||||
dprint( "warning: imported dwFileOS not WINDOWS32 (=%#x)\n", fxi->dwFileOS);
|
||||
}
|
||||
|
||||
free(verinfo);
|
||||
} // patch mode
|
||||
|
||||
if ( !g_params.PreserveOriginalFilename ) {
|
||||
fvd->addTwostr(L"OriginalFilename", pfilename);
|
||||
}
|
||||
|
||||
if ( !g_params.PreserveInternalFilename ) {
|
||||
fvd->addTwostr(L"InternalName", pfilename);
|
||||
}
|
||||
|
||||
// Fill in per file info:
|
||||
if ( VFT_UNKNOWN == fvd->dwFileType ) {
|
||||
d3tprint(_T("file ext=%s\n"), pdot_ext);
|
||||
if ( 0 == _tcsicmp( pdot_ext, _T(".exe") ))
|
||||
fvd->dwFileType = VFT_APP;
|
||||
if ( 0 == _tcsicmp( pdot_ext, _T(".sys") ))
|
||||
fvd->dwFileType = VFT_DRV;
|
||||
if ( 0 == _tcsicmp( pdot_ext, _T(".dll") ))
|
||||
fvd->dwFileType = VFT_DLL;
|
||||
}
|
||||
|
||||
if ( !fvd->getValStr(L"FileDescription") ) {
|
||||
// Use filename as default FileDescription
|
||||
fvd->addTwostr( L"FileDescription", pfilename );
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL parseFileVer( __out file_ver_data_s *fvd, PCTSTR arg )
|
||||
{
|
||||
unsigned n1=0,n2=0,n3=0,n4=0;
|
||||
int nf = _stscanf_s( arg, _T("%d.%d.%d.%d"), &n1, &n2, &n3, &n4);
|
||||
|
||||
// if less than 4 numbers given, they are minor
|
||||
switch( nf ) {
|
||||
case 1:
|
||||
fvd->v_4 = n1;
|
||||
break;
|
||||
case 2:
|
||||
fvd->v_3 = n1; fvd->v_4 = n2;
|
||||
break;
|
||||
case 3:
|
||||
fvd->v_2 = n1; fvd->v_3 = n2; fvd->v_4 = n3;
|
||||
break;
|
||||
case 4:
|
||||
fvd->v_1 = n1; fvd->v_2 = n2; fvd->v_3 = n3; fvd->v_4 = n4;
|
||||
break;
|
||||
default:
|
||||
dprint("error parsing version arg\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Optional tail: "1.2.3.4 tail"
|
||||
// If no tail found, don't replace existing.
|
||||
PCTSTR tail = _tcschr(arg, _T(' '));
|
||||
if ( tail ) {
|
||||
while( *tail == _T(' ') ) tail++;
|
||||
fvd->sFileVerTail = (*tail) ? strUnEscape(tail) : NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL parseProductVer( __out file_ver_data_s *fvd, PCTSTR arg )
|
||||
{
|
||||
unsigned n1=0,n2=0,n3=0,n4=0;
|
||||
int nf = _stscanf_s( arg, _T("%d.%d.%d.%d"), &n1, &n2, &n3, &n4);
|
||||
|
||||
// if less than 4 numbers given, they are minor
|
||||
switch( nf ) {
|
||||
case 1:
|
||||
fvd->pv_4 = n1;
|
||||
break;
|
||||
case 2:
|
||||
fvd->pv_3 = n1; fvd->pv_4 = n2;
|
||||
break;
|
||||
case 3:
|
||||
fvd->pv_2 = n1; fvd->pv_3 = n2; fvd->pv_4 = n3;
|
||||
break;
|
||||
case 4:
|
||||
fvd->pv_1 = n1; fvd->pv_2 = n2; fvd->pv_3 = n3; fvd->pv_4 = n4;
|
||||
break;
|
||||
default:
|
||||
dprint("error parsing version arg\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Optional tail: "1.2.3.4 tail"
|
||||
// If no tail found, don't replace existing.
|
||||
PCTSTR tail = _tcschr(arg, _T(' '));
|
||||
if ( tail ) {
|
||||
while( *tail == _T(' ') ) tail++;
|
||||
fvd->sProductVerTail = (*tail) ? strUnEscape(tail) : NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BOOL updFileResources( LPCTSTR fname, __in ResDesc *ard[] )
|
||||
{
|
||||
if ( !ard[0] ) {
|
||||
d2print("No resources to update\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// open file, start update
|
||||
BOOL bDeleteExistingResources = FALSE;
|
||||
BOOL ok = FALSE;
|
||||
int n_updated = 0;
|
||||
HANDLE rhandle = ::BeginUpdateResource( fname, bDeleteExistingResources );
|
||||
if ( !rhandle ) {
|
||||
dprint( "Error opening file for update resources, err=%d\n", GetLastError() );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (int i = 0; ; i++) {
|
||||
ResDesc *rd = ard[i];
|
||||
if ( !rd )
|
||||
break;
|
||||
|
||||
ok = ::UpdateResource(
|
||||
rhandle,
|
||||
(LPCTSTR)rd->m_type,
|
||||
(LPCTSTR)rd->m_name,
|
||||
rd->m_language,
|
||||
(LPVOID)rd->m_data,
|
||||
rd->m_cbdata
|
||||
);
|
||||
|
||||
if (!ok) {
|
||||
dprint("UpdateResource #%d err=%d\n", i, GetLastError());
|
||||
break;
|
||||
}
|
||||
n_updated++;
|
||||
}
|
||||
|
||||
d2print("Resources updated: %d\n", n_updated);
|
||||
|
||||
BOOL r2 = ::EndUpdateResource( rhandle, !ok );
|
||||
if (!r2) {
|
||||
dprint("EndUpdateResource err=%d\n", GetLastError());
|
||||
ok = FALSE;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
long parseFileSubType( PCTSTR ap )
|
||||
{
|
||||
if ( isdigit(*ap) )
|
||||
return _tcstol( ap, NULL, 16 );
|
||||
if ( 0 == _tcsicmp(ap, _T("DRV_SYSTEM")) )
|
||||
return VFT2_DRV_SYSTEM;
|
||||
if ( 0 == _tcsicmp(ap, _T("DRV_NETWORK")) )
|
||||
return VFT2_DRV_NETWORK;
|
||||
if ( 0 == _tcsicmp(ap, _T("DRV_COMM")) )
|
||||
return VFT2_DRV_COMM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// main
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
int _tmain(int argc, _TCHAR* argv[])
|
||||
{
|
||||
static file_ver_data_s file_ver_data;
|
||||
PCTSTR fname;
|
||||
BOOL r;
|
||||
|
||||
SetErrorMode( SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX );
|
||||
r = SetThreadLocale( LOCALE_INVARIANT );
|
||||
|
||||
if ( !g_params.cmd_arg_parse( argc, argv, &fname, NULL ) ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
d2tprint(_T("relstamp file=[%s]\n"), fname );
|
||||
|
||||
r &= fillFileInfo( &file_ver_data, fname );
|
||||
|
||||
if ( !g_params.PatchMode ) { // if not patch mode, read from INI
|
||||
r &= fillCompanyInfo( &file_ver_data );
|
||||
r &= fillProductInfo( &file_ver_data );
|
||||
}
|
||||
|
||||
// Parse again, put the args into the data
|
||||
if ( !g_params.cmd_arg_parse( argc, argv, &fname, &file_ver_data ) ) {
|
||||
dprint("Error parsing command args 2 pass!\n");
|
||||
r = FALSE;
|
||||
}
|
||||
|
||||
if ( !r ) {
|
||||
dprint("Some of actions failed, exiting\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
PUCHAR verdata = NULL;
|
||||
r = makeVersionResource( &file_ver_data, &verdata );
|
||||
if ( !r ) return 1;
|
||||
|
||||
if ( g_params.DbgLoopbackTest )
|
||||
{ // loopback test for vers res parser
|
||||
VS_FIXEDFILEINFO *fxi = NULL;
|
||||
VerCallback1 mycb(&file_ver_data);
|
||||
dprint("dbg: begin reparse\n");
|
||||
r = ParseBinaryVersionResource( verdata, _MAX_VERS_SIZE_CB, &fxi, &mycb, g_params.DumpImportVerAsRC );
|
||||
dprint("dbg: end reparse\n");
|
||||
}
|
||||
|
||||
// Save extra data possibly appended to the exe file
|
||||
DWORD extrasSize = 0;
|
||||
void *extras;
|
||||
if ( !g_params.fNoPreserveExtraAppendedData ) {
|
||||
r = getFileExtraData(fname, &extras, &extrasSize);
|
||||
if ( !r ) {
|
||||
dprint("Failed to read extra data\n");
|
||||
return 2;
|
||||
}
|
||||
if ( extrasSize ) {
|
||||
d2print("Found extra %d bytes appended to the file\n", extrasSize);
|
||||
}
|
||||
}
|
||||
|
||||
if( g_params.DbgImportOnly ) {
|
||||
dprint("read only, exiting\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Add the version to resources update:
|
||||
addUpdRes(
|
||||
new ResDesc(
|
||||
(PVOID)verdata,
|
||||
*((PWORD)verdata),
|
||||
(ULONG_PTR)RT_VERSION,
|
||||
(ULONG_PTR)MAKEINTRESOURCE(VS_VERSION_INFO),
|
||||
file_ver_data.langid
|
||||
)
|
||||
);
|
||||
|
||||
r = updFileResources( fname, &aRes[0] );
|
||||
if ( !r ) {
|
||||
dprint("Update file resources failed, the file may be damaged\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if ( extrasSize ) {
|
||||
|
||||
// Restore extra data appended to end of exec
|
||||
r = appendFileExtraData(fname, extras, extrasSize);
|
||||
if ( !r ) {
|
||||
dprint("Failed to restore extra data, the file may be damaged\n");
|
||||
return 3;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Re-checksum
|
||||
r = updFileChecksum( fname, g_params.fClearPdbPath );
|
||||
if ( !r ) {
|
||||
dprint("Update file checksum failed, the file may be damaged\n");
|
||||
return 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
d2print("ok\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Check if the string key name is alias, return the correct invariant key name:
|
||||
// See ver-res.txt
|
||||
LPCTSTR aliasToStringKey( LPCTSTR key )
|
||||
{
|
||||
if ( 0 == _tcsicmp(key, _T("comment"))) return _T("Comments");
|
||||
if ( 0 == _tcsicmp(key, _T("company"))) return _T("CompanyName");
|
||||
if ( 0 == _tcsicmp(key, _T("description"))) return _T("FileDescription");
|
||||
if ( 0 == _tcsicmp(key, _T("desc"))) return _T("FileDescription");
|
||||
if ( 0 == _tcsicmp(key, _T("title"))) return _T("InternalName");
|
||||
if ( 0 == _tcsicmp(key, _T("copyright"))) return _T("LegalCopyright");
|
||||
if ( 0 == _tcsicmp(key, _T("(c)"))) return _T("LegalCopyright");
|
||||
if ( 0 == _tcsicmp(key, _T("trademarks"))) return _T("LegalTrademarks");
|
||||
if ( 0 == _tcsicmp(key, _T("(tm)"))) return _T("LegalTrademarks");
|
||||
if ( 0 == _tcsicmp(key, _T("tm"))) return _T("LegalTrademarks");
|
||||
if ( 0 == _tcsicmp(key, _T("product"))) return _T("ProductName");
|
||||
if ( 0 == _tcsicmp(key, _T("pb"))) return _T("PrivateBuild");
|
||||
if ( 0 == _tcsicmp(key, _T("sb"))) return _T("SpecialBuild");
|
||||
if ( 0 == _tcsicmp(key, _T("build"))) return _T("SpecialBuild");
|
||||
|
||||
if ( 0 == _tcsicmp(key, _T("fileversion"))) {
|
||||
dprint("do NOT use FileVersion with /s option, see usage!\n");
|
||||
}
|
||||
|
||||
if ( 0 == _tcsicmp(key, _T("language"))) {
|
||||
dprint("do NOT use Language with /s option, this won't work.\n");
|
||||
}
|
||||
|
||||
//d3tprint(_T("alias not found %s\n"), key);
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Command args
|
||||
//
|
||||
//TODO: handle escapes in strings passed on command line
|
||||
// mode without version res: only bin patches
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
bool cmd_params::cmd_arg_parse( int argc, _TCHAR *argv[], PCTSTR *fname,
|
||||
__out_opt struct file_ver_data_s *fvd )
|
||||
{
|
||||
bool firstPass = false;
|
||||
static file_ver_data_s my_fvd;
|
||||
if ( !fvd ) {
|
||||
firstPass = true;
|
||||
fvd = &my_fvd;
|
||||
}
|
||||
|
||||
int pos_args = 0;
|
||||
int patch_actions = 0;
|
||||
|
||||
PatchMode = true; //default mode -pa04
|
||||
|
||||
for( int i = 1; i < argc; i++ ) {
|
||||
PCTSTR ap = argv[i];
|
||||
if (!ap)
|
||||
break; //done
|
||||
|
||||
if ( *ap == _T('/') || *ap == _T('-') ) {
|
||||
ap++;
|
||||
|
||||
if ( argmatch(_T("?"), ap ) )
|
||||
{ showUsage(); return false; }
|
||||
else if ( argmatch(_T("fn"), ap) ) // keep original filename
|
||||
PreserveInternalFilename = PreserveOriginalFilename = true;
|
||||
else if ( argmatch(_T("vo"), ap) ) // dump input res. desc. as RC source
|
||||
DumpImportVerAsRC = true;
|
||||
else if ( argmatch(_T("xi"), ap) ) { // read only, don't patch
|
||||
DbgImportOnly = true; // dbg
|
||||
}
|
||||
else if ( argmatch(_T("xlb"), ap) ) // reparse created res.desc. (self test)
|
||||
DbgLoopbackTest = true; //dbg
|
||||
else if ( argmatch(_T("sc"), ap) ) { // /sc "comment"
|
||||
ap = argv[++i]; ASSERT(ap);
|
||||
patch_actions++;
|
||||
if( !fvd->addTwostr( _T("Comments"), strUnEscape(ap) ) ) {
|
||||
dtprint(_T("Error adding string:[%s]\n"), ap);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( argmatch(_T("s"), ap) ) {
|
||||
//Add a string to version res: /s name "comment"
|
||||
PCTSTR ns = argv[++i]; ASSERT(ns);
|
||||
ap = argv[++i]; ASSERT(ap);
|
||||
patch_actions++;
|
||||
|
||||
if( !fvd->addTwostr( aliasToStringKey(ns), strUnEscape(ap) ) ) {
|
||||
dtprint(_T("Error adding string:[%s]\n"), ap);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if( argmatch(_T("pv"), ap) ||
|
||||
argmatch(_T("prodver"), ap) ||
|
||||
argmatch(_T("productver"), ap) ||
|
||||
argmatch(_T("productversion"), ap) ) {
|
||||
// product version string has same form as the file version arg (positional)
|
||||
ap = argv[++i]; ASSERT(ap);
|
||||
if ( !parseProductVer( fvd, ap ) ) {
|
||||
dprint("bad product version arg, see usage (/?)\n");
|
||||
return false;
|
||||
}
|
||||
patch_actions++;
|
||||
}
|
||||
else if (argmatch(_T("vft2"), ap) ) { // version subtype
|
||||
ap = argv[++i]; ASSERT(ap);
|
||||
long n = parseFileSubType(ap);
|
||||
if ( !(n >= 0 && n <= 0xFFFF) ) {
|
||||
dtprint(_T("Bad subtype \"%s\". For usage: /?\n"), ap);
|
||||
return false;
|
||||
}
|
||||
fvd->dwFileSubType = (USHORT)n;
|
||||
patch_actions++;
|
||||
}
|
||||
else if ( argmatch(_T("rpdb"), ap) ) {
|
||||
g_params.fClearPdbPath = true;
|
||||
patch_actions++;
|
||||
}
|
||||
else if ( argmatch(_T("va"), ap) ) { // auto generate version desc.
|
||||
PatchMode = false;
|
||||
patch_actions++;
|
||||
}
|
||||
else if ( argmatch(_T("rf"), ap) ) {
|
||||
// Add a resource from file: /rf #<number> filename
|
||||
// For now, use numeric ids only. High 16 bits can be used for type, etc.
|
||||
ULONG res_id = 0;
|
||||
ap = argv[++i]; ASSERT(ap);
|
||||
if ( *ap++ != _T('#') || 0 == (res_id = _tcstol( ap, NULL, 16 )) ) {
|
||||
dtprint(_T("Resource id must be #hex_number\n"), ap);
|
||||
return false;
|
||||
}
|
||||
|
||||
ap = argv[++i]; ASSERT( ap && *ap != _T('/') && *ap != _T('-') );
|
||||
// only during 2nd pass:
|
||||
if ( !firstPass && !addResourceFromFile( ap, res_id ) ) {
|
||||
dtprint(_T("Error adding resource file [%s] id=%#X\n"), ap, res_id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( argmatch(_T("noed"), ap) ) {
|
||||
// Do not check for extra data appended to exe file
|
||||
g_params.fNoPreserveExtraAppendedData = true;
|
||||
}
|
||||
else {
|
||||
dtprint(_T("Unknown option \"%s\". For usage: /?\n"), ap);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// position args:
|
||||
switch(pos_args++) {
|
||||
case 0:
|
||||
*fname = ap; //ex d:/stuff/foo.sys
|
||||
break;
|
||||
case 1:
|
||||
if ( parseFileVer( fvd, ap ) ) {
|
||||
patch_actions++;
|
||||
break;
|
||||
}
|
||||
dprint("bad version arg, see usage (/?)\n");
|
||||
return false;
|
||||
default:
|
||||
dprint("Too many args, see usage (/?)\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( 0 == pos_args ) {
|
||||
showUsage();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( 0 == patch_actions )
|
||||
DbgImportOnly = true; //dbg
|
||||
|
||||
// flags: SpecialBuild fVerBeta fVerDebug?
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// misc. utils
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
LPWSTR stralloc( __in PCSTR s )
|
||||
{
|
||||
ASSERT(s);
|
||||
size_t n = strlen(s);
|
||||
ASSERT( n < (256));
|
||||
LPWSTR p = (LPWSTR)malloc( (n + 1) * sizeof(WCHAR) );
|
||||
ASSERT( p );
|
||||
for ( size_t i = 0; i <= n; i++ )
|
||||
p[i] = s[i];
|
||||
return p;
|
||||
}
|
||||
|
||||
LPWSTR stralloc( __in PCWSTR s )
|
||||
{
|
||||
ASSERT(s);
|
||||
PWSTR p = _wcsdup(s);
|
||||
ASSERT(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
// return byte offset to name and .ext parts of filename
|
||||
BOOL fileGetNameExtFromPath( __in PCTSTR path, __out PUINT pname, __out PUINT pext )
|
||||
{
|
||||
ASSERT(path);
|
||||
PTSTR name = (PTSTR)calloc( 2*MAX_PATH, sizeof(TCHAR));
|
||||
ASSERT(name);
|
||||
PTSTR ext = name + MAX_PATH;
|
||||
|
||||
errno_t e;
|
||||
e = _tsplitpath_s(path, NULL, 0 , NULL, 0, name, MAX_PATH, ext, 10);
|
||||
if ( e == ERROR_SUCCESS ) {
|
||||
size_t lname = _tcslen(name);
|
||||
size_t lext = _tcslen(ext);
|
||||
*pname = (UINT)(_tcslen(path) - lname - lext) * sizeof(TCHAR);
|
||||
*pext = *pname + (lname * sizeof(TCHAR));
|
||||
} else {
|
||||
dtprint(_T("Error parsing filename: err=%d path=[%s]\n"), e, path);
|
||||
}
|
||||
|
||||
if ( name ) free( name );
|
||||
|
||||
return e == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
// Read VS_VERSION resource blob from a file by name
|
||||
BOOL fileReadVersionInfo( __in PCTSTR fname, __out PUCHAR buf, __in unsigned size)
|
||||
{
|
||||
BOOL r;
|
||||
r = GetFileVersionInfo( fname, NULL /*reserved*/, (DWORD)size, (LPVOID)buf );
|
||||
return r;
|
||||
}
|
||||
|
||||
// Format a string escaped for RC: quotes, symbols (R) (C) and so on
|
||||
PCWSTR strEscape( __in PCWSTR ws )
|
||||
{
|
||||
if ( !ws || !*ws ) {
|
||||
return (PCWSTR)L"\\0";
|
||||
}
|
||||
return ws; //$$$ TODO. for now, unescaped text will be printed, edit manually
|
||||
}
|
||||
|
||||
// Unescape a string escaped for RC: quotes, symbols (R) (C) and so on
|
||||
PCWSTR strUnEscape( __in PCWSTR ws )
|
||||
{
|
||||
return ws; //$$$ TODO
|
||||
}
|
||||
|
||||
bool argmatch(PCTSTR sw, PCTSTR cmp )
|
||||
{
|
||||
if ( 0 == _tcsicmp(sw, cmp) ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Add raw binary resource from file.
|
||||
// Low 16 bit of id_flags = resource ID. Bitmask FF0000 = type (0=RCDATA). High byte reserved.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool addResourceFromFile( PCTSTR resfile, UINT32 id_flags )
|
||||
{
|
||||
UINT64 xFileSize;
|
||||
HANDLE fh = CreateFile(resfile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
if (INVALID_HANDLE_VALUE == fh ) {
|
||||
dtprint(_T("Error opening res. file %s err=%d\n"), resfile, GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !GetFileSizeEx( fh, (PLARGE_INTEGER)&xFileSize ) ) {
|
||||
dtprint(_T("Error get file size %s\n"), resfile);
|
||||
CloseHandle(fh);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( xFileSize > _A_MAX_RES_CB ) {
|
||||
dtprint(_T("Error: file size too large %s %I64d K\n"), resfile, (xFileSize/1024));
|
||||
CloseHandle(fh);
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD dwFileSize = (DWORD)xFileSize;
|
||||
PUCHAR dp = (PUCHAR)calloc( dwFileSize + 4, 1 ); // round up to 4 bytes
|
||||
ASSERT(dp);
|
||||
DWORD cbread;
|
||||
if ( !ReadFile( fh, (LPVOID)dp, dwFileSize, &cbread, NULL ) || cbread != dwFileSize ) {
|
||||
dtprint(_T("Error reading file %s\n"), resfile);
|
||||
CloseHandle(fh);
|
||||
free(dp);
|
||||
return false;
|
||||
}
|
||||
|
||||
CloseHandle(fh);
|
||||
|
||||
// round up to 4 bytes
|
||||
dwFileSize = (dwFileSize + 3) & ~3;
|
||||
|
||||
ULONG restype = (id_flags >> 16) & 0xFF;
|
||||
if ( 0 == restype ) restype = (ULONG)RT_RCDATA;
|
||||
|
||||
addUpdRes( new ResDesc( dp, dwFileSize, restype, id_flags & 0xFFFF ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#if 1
|
||||
// Get a resource (pointer and size)
|
||||
// hm: module handle. 0 is the exe file
|
||||
bool getResource( HMODULE hm, DWORD rtype, DWORD rid, __out LPCVOID *p, __out PDWORD size )
|
||||
{
|
||||
HRSRC hrs = FindResourceEx( hm, (LPCTSTR)rtype, (LPCTSTR)rid, 0 /*MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)*/ );
|
||||
if ( !hrs ) {
|
||||
d2print("cannot find res. %#x, err=%d\n", rid, GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD rsize = SizeofResource(hm, hrs);
|
||||
if ( rsize < sizeof (DWORD) ) {
|
||||
d2print("res. size = 0??\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
HGLOBAL hg = LoadResource( hm, hrs );
|
||||
if ( !hg ) {
|
||||
d2print("err LoadResource %d\n", GetLastError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
*p = LockResource( hg );
|
||||
*size = rsize;
|
||||
return !!(*p) ;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// USAGE
|
||||
// How to add the help text:
|
||||
// - Put the text in a file (ex. usage.txt)
|
||||
// - make a copy of this exe file
|
||||
// - use /rf #64 <file.txt> to attach this text file to the copy of the program
|
||||
// See ver-self.cmd for a working example (this is also a kind of unit test :)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void showUsage()
|
||||
{
|
||||
const ULONG usage_txt_id = 0x64; //100
|
||||
const ULONG usage_txt_type = (ULONG)(ULONG_PTR)RT_RCDATA;
|
||||
const void *p;
|
||||
DWORD len;
|
||||
if ( !getResource( 0, usage_txt_type, usage_txt_id, &p, &len ) ) {
|
||||
dprint("No usage text! See readme.txt for instructions how to add it.\n");
|
||||
return;
|
||||
}
|
||||
fwrite(p, len, 1, stderr);
|
||||
}
|
||||
|
||||
#else
|
||||
void showUsage()
|
||||
{
|
||||
dprint("verpatch r2 (2009/05/31)\n");
|
||||
dprint("Usage: verpatch filename [version] [/options]\n");
|
||||
dprint("\nOptions:\n");
|
||||
dprint(" /sc \"comment\"\t- add Comments string\n"); // todo: escapes
|
||||
dprint(" /s name \"value\"\t- add/replace any version resource string\n"); // todo: escapes
|
||||
dprint(" /va\t- create a default version resource\n");
|
||||
dprint(" /vft2 num\t- specify driver type (VFT2_xxx, see winver.h)\n");
|
||||
dprint(" /fn\t- preserve Original filename, Internal name in the file version info\n");
|
||||
dprint(" /vo\t- output the file version info in RC format\n");
|
||||
dprint(" /xi\t- test mode, do not patch the file\n");
|
||||
dprint(" /rpdb\t- remove path to .pdb in debug information\n");
|
||||
dprint(" /rf #hex-id file - add a resource from file (see readme)\n");
|
||||
dprint("\n\nExamples:\n");
|
||||
dprint(" verpatch d:\\foo.dll 1.2.33.44 /sc \"holy cow, it works!\"\n");
|
||||
dprint(" verpatch d:\\foo.sys \"33.44 release\" /fn\n");
|
||||
dprint(" verpatch d:\\foo.exe 1.2.3.4 /rf #9 driver.sys\n");
|
||||
}
|
||||
#endif
|
64
external/verpatch/src/relstamp.h
vendored
Normal file
64
external/verpatch/src/relstamp.h
vendored
Normal file
|
@ -0,0 +1,64 @@
|
|||
// relstamp R2
|
||||
|
||||
#pragma once
|
||||
|
||||
// Defs for Windows version resource
|
||||
// http://msdn.microsoft.com/en-us/library/ms646997(VS.85).aspx
|
||||
#define _MAX_VERS_SIZE_CB 4096
|
||||
#define _MAX_VER_STRING_LEN_CCH 255
|
||||
#define _MAX_VER_CUSTOM_STRINGS 16
|
||||
#define _A_MAX_N_RES 8
|
||||
#define _A_MAX_RES_CB (500*1024)
|
||||
|
||||
#if ( 1 && !defined(DEF_COMPANY_NAME) )
|
||||
#define DEF_COMPANY_NAME _T(" ")
|
||||
#define DEF_COPYRGT _T("Copyright (c) 2009")
|
||||
#define DEF_PRODUCT_NAME _T(" ")
|
||||
#endif
|
||||
|
||||
#define dprint(fmt, ...) printf(fmt, __VA_ARGS__)
|
||||
#define dtprint(tfmt, ...) _tprintf(tfmt, __VA_ARGS__)
|
||||
|
||||
#ifdef NDEBUG
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#define ASSERT assert
|
||||
|
||||
#ifndef _A_NOISE_DBG
|
||||
#define _A_NOISE_DBG 1
|
||||
#endif
|
||||
|
||||
#if _A_NOISE_DBG
|
||||
#define d2print(fmt, ...) dprint(fmt, __VA_ARGS__)
|
||||
#define d2tprint(tfmt, ...) dtprint(tfmt, __VA_ARGS__)
|
||||
#else
|
||||
#define d2print(fmt, ...) __noop(fmt, __VA_ARGS__)
|
||||
#define d2tprint(tfmt, ...) __noop(tfmt, __VA_ARGS__)
|
||||
#endif //_A_NOISE_DBG
|
||||
|
||||
#if ( _A_NOISE_DBG > 1 )
|
||||
#define d3print d2print
|
||||
#define d3tprint d2tprint
|
||||
#else
|
||||
#define d3print(fmt, ...) __noop(fmt, __VA_ARGS__)
|
||||
#define d3tprint(tfmt, ...) __noop(tfmt, __VA_ARGS__)
|
||||
#endif //_A_NOISE_DBG
|
||||
|
||||
// Format a string escaped for RC: quotes, (R), (C) and so on
|
||||
PCWSTR strEscape( __in PCWSTR ws );
|
||||
PCWSTR strUnEscape( __in PCWSTR ws );
|
||||
|
||||
// strdup likes:
|
||||
LPWSTR stralloc( __in PCSTR s );
|
||||
LPWSTR stralloc( __in PCWSTR s );
|
||||
// Get name, ext from full filename
|
||||
BOOL fileGetNameExtFromPath( __in PCTSTR path, __out PUINT pname, __out PUINT pext );
|
||||
BOOL fileReadVersionInfo( __in PCTSTR fname, __out PUCHAR buf, __in unsigned size);
|
||||
|
||||
// 3state flag:
|
||||
enum f3state { F3NOTSET, F3FALSE, F3TRUE };
|
||||
|
||||
void showUsage();
|
||||
bool argmatch(__in PCTSTR sw, __in PCTSTR cmp );
|
||||
|
||||
BOOL updFileChecksum( LPCTSTR fname, bool fRemovePdbPath = false );
|
8
external/verpatch/src/stdafx.cpp
vendored
Normal file
8
external/verpatch/src/stdafx.cpp
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// relstamp.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
22
external/verpatch/src/stdafx.h
vendored
Normal file
22
external/verpatch/src/stdafx.h
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "targetver.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <tchar.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
|
||||
// TODO: reference additional headers your program requires here
|
13
external/verpatch/src/targetver.h
vendored
Normal file
13
external/verpatch/src/targetver.h
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
// The following macros define the minimum required platform. The minimum required platform
|
||||
// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
|
||||
// your application. The macros work by enabling all features available on platform versions up to and
|
||||
// including the version specified.
|
||||
|
||||
// Modify the following defines if you have to target a platform prior to the ones specified below.
|
||||
// Refer to MSDN for the latest info on corresponding values for different platforms.
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0501 //XP
|
||||
#endif
|
||||
|
22
external/verpatch/src/usage.txt
vendored
Normal file
22
external/verpatch/src/usage.txt
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
verpatch r8 (2011-04-25)
|
||||
Usage: verpatch filename [version] [/options]
|
||||
Options:
|
||||
/s name "value" - add or replace any version resource string.
|
||||
name: a string attribute. See readme.txt for reference.
|
||||
/sc "comment" - add Comments string (same as /s comment "comment")
|
||||
/va - create the version resource (use when the file has no version info, or to replace it)
|
||||
/pv <version> - specify Product version
|
||||
/prodver, /productversion - same as /pv
|
||||
/fn - preserve Original Filename, Internal Name in the file version info
|
||||
/vo - output the file version info in RC format
|
||||
/xi - test mode, does not modify the file
|
||||
/vft2 num - specify driver type (one of VFT2_ values defined in winver.h)
|
||||
/rpdb - remove path to .pdb in debug information
|
||||
/rf #hex-id file - add a raw binary resource from file (see readme)
|
||||
/noed - discard any extra data attached at the end of file
|
||||
|
||||
Examples:
|
||||
verpatch d:\foo.dll 1.2.33.44 /s comment "fixed this and that"
|
||||
verpatch d:\foo.dll "33.44 released on %date%"
|
||||
verpatch d:\foo.exe /va 1.2.3.4 /s desc "my program"
|
||||
verpatch d:\foo.exe 1.2.3.4 /rf #9 embedded-dll.dll
|
19
external/verpatch/src/ver-self.cmd
vendored
Normal file
19
external/verpatch/src/ver-self.cmd
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
: Add version info resource with some strings and a resource file to verpatch.exe
|
||||
: (also kind of self test)
|
||||
|
||||
: Run this in Release or Debug dir
|
||||
:
|
||||
set _ver="1.0.1.9 [%date%]"
|
||||
set _s1=/s desc "Version patcher tool" /s copyright "(C) 1998-2011, pavel_a"
|
||||
set _s1=%_s1% /s pb "pa"
|
||||
set _s1=%_s1% /pv "1.0.0.1 (free)"
|
||||
|
||||
set _resfile=/rf #64 ..\usage.txt
|
||||
|
||||
: Run a copy of verpatch on itself:
|
||||
|
||||
copy verpatch.exe v.exe || exit /b 1
|
||||
|
||||
v.exe verpatch.exe /va %_ver% %_s1% %_s2% %_resfile%
|
||||
|
||||
@echo Errorlevel=%errorlevel%
|
234
external/verpatch/src/verpatch-ReadMe.txt
vendored
Normal file
234
external/verpatch/src/verpatch-ReadMe.txt
vendored
Normal file
|
@ -0,0 +1,234 @@
|
|||
|
||||
Verpatch - a tool to patch win32 version resources on .exe or .dll files,
|
||||
|
||||
Version: 01-Nov-2009 (rev. #7 for CodeProject) edited
|
||||
|
||||
Verpatch is a command line tool for adding and editing the version information
|
||||
of Windows executable files (applications, DLLs, kernel drivers)
|
||||
without rebuilding the executable.
|
||||
|
||||
It can also add or replace Win32 (native) resources, and do some other
|
||||
modifications of executable files.
|
||||
|
||||
Verpatch sets ERRORLEVEL 0 on success, otherwise errorlevel is non-zero.
|
||||
Verpatch modifies files in place, so please make copies of precious files.
|
||||
|
||||
|
||||
Command line syntax
|
||||
===================
|
||||
|
||||
verpatch filename [version] [/options]
|
||||
|
||||
Where
|
||||
- filename : any Windows PE file (exe, dll, sys, ocx...) that can have native resources
|
||||
- version : one to four decimal numbers, separated by dots, ex.: 1.2.3.4
|
||||
Additional text can follow the numbers; see examples below. Ex.: "1.2.3.4 extra text"
|
||||
- options: see below
|
||||
|
||||
Common Options:
|
||||
|
||||
/va - creates a version resource. Use when the file has no version resource at all,
|
||||
or existing version resource should be replaced.
|
||||
If this option not specified, verpatch will patch the version resourse found in the file.
|
||||
/s name "value" - add a version resource string attribute
|
||||
The name can be either a full attribute name or alias; see below.
|
||||
/sc "comment" - add or replace Comments string (shortcut for /s Comments "comment")
|
||||
/pv <version> - specify Product version
|
||||
where <version> arg has same form as the file version (1.2.3.4 or "1.2.3.4 text")
|
||||
/fn - preserves Original filename, Internal name in the existing version resource of the file.
|
||||
|
||||
|
||||
Other options:
|
||||
|
||||
/vo - outputs the version info in RC format to stdout.
|
||||
This can be used with /xi to import a version resource from another file.
|
||||
Output of /vo (text from #ifdef RC_INVOKED to #endif) can be saved to a .rc file and compiled with rc.
|
||||
/xi- test mode. does all operations but does not modify the file
|
||||
/xlb - test mode. Re-parses the version resource after modification.
|
||||
/rpdb - removes path to the .pdb file in debug information; leaves only file name.
|
||||
/rf #id file - add or replace a raw binary resource from file (see below)
|
||||
/noed - do not check for extra data appended to exe file
|
||||
/vft2 num - specify driver subtype (VFT2_xxx value, see winver.h)
|
||||
The application type (VFT_xxx) is retained from the existing version resource of the file,
|
||||
or filled automatically, based on the filename extension (exe->app, sys->driver, anything else->dll)
|
||||
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
verpatch d:\foo.dll 1.2.33.44
|
||||
- replaces only the file version, all 4 numbers,
|
||||
the Original file name and Internal name strings are set to "foo.dll".
|
||||
File foo.dll should already have a version resource.
|
||||
|
||||
verpatch d:\foo.dll 33.44 /s comment "a comment"
|
||||
- replaces only two last numbers of the file version and adds a comment.
|
||||
File foo.dll should already have a version resource.
|
||||
|
||||
verpatch d:\foo.dll "33.44 special release" /sc "a comment"
|
||||
- same as previous, with additional text in the version argument.
|
||||
|
||||
verpatch d:\foo.dll "1.2.33.44" /va /s description "foo.dll"
|
||||
/s company "My Company" /s copyright "(c) 2009"
|
||||
- adds or replaces version resource to foo.dll, with several string values.
|
||||
( all options should be one line)
|
||||
|
||||
verpatch d:\foo.dll /vo /xi
|
||||
- dumps the version resource in RC format, does not update the file.
|
||||
|
||||
|
||||
|
||||
Remarks
|
||||
=======
|
||||
|
||||
Verpatch replaces the version number in existing file version info resource
|
||||
with the values given on the command line.
|
||||
|
||||
In "patch" mode (no /va option), the PE file should have a version resource,
|
||||
which is parsed, and then parameters specified on the command line are applied.
|
||||
|
||||
If the file has no version resource, or you want to discard the existing resource, use /va switch.
|
||||
All nesessary strings can be specified with the /s option.
|
||||
|
||||
The command line can become very long, so you may want to use a batch file or script.
|
||||
See the example batch files, how to create a version resource and
|
||||
specify all parameters with /va.
|
||||
|
||||
Verpatch can be run on same PE file any number of times.
|
||||
|
||||
The Version argument can be specified as 1 to 4 dot separated decimal numbers,
|
||||
or as quoted string containing additional text after the numbers.
|
||||
If less than 4 numbers are given, they are considered as minor numbers.
|
||||
The higher version parts are retained from existing version resource.
|
||||
For example, if the existing version info has version number 1.2.3.4
|
||||
and 55.66 specified on the command line, the result will be 1.2.55.66.
|
||||
|
||||
The quotes surrounding string arguments are needed for the command shell (cmd.exe),
|
||||
for any argument that contains spaces.
|
||||
|
||||
The program ensures that the version numbers in the binary part
|
||||
of the version structure and in the string part (as text) are same.
|
||||
|
||||
By default, Original File Name and Internal File Name are replaced to the actual filename.
|
||||
Use /fn to preserve existing values in the version resource.
|
||||
|
||||
For option /s, specify language-neutral string names, not translations
|
||||
( example: PrivateBuild, not "Private Build Description" ).
|
||||
Null values can be specified as empty string ("").
|
||||
See below for the list of known string keys names and their aliases.
|
||||
The examples above use the aliases.
|
||||
|
||||
Strings for File version and Product version parameters are handled in a special way,
|
||||
the /s switch can not be used to set them:
|
||||
- File version can be specified only as the 2nd positional argument
|
||||
- Product version can be specified using /pv switch
|
||||
|
||||
The /rf switch adds a resource from a file, or replaces a resource with same type and id.
|
||||
The argument "#id" is a 32-bit hex number, prefixed with #.
|
||||
Low 16 bits of this value are resource id; can not be 0.
|
||||
Next 8 bits are resource type: one of RT_xxx symbols in winuser.h, or user defined.
|
||||
If the type value is 0, RT_RCDATA (10) is assumed.
|
||||
High 8 bits of the #id arg are reserved0.
|
||||
The language code of resources added by this switch is 0 (Neutral).
|
||||
Named resource types and ids are not implemented.
|
||||
The file is added as opaque binary chunk; the resource size is rounded up to 4 bytes
|
||||
and padded with zero bytes.
|
||||
|
||||
The program detects extra data appended to executable files, saves it and appends
|
||||
again after modifying resources.
|
||||
Such extra data is used by some installers, self-extracting archives and other applications.
|
||||
However, the way we restore the data may be not compatible with these applications.
|
||||
Please, verify that executable files that contain extra data work correctly after modification.
|
||||
Command switch /noed disables checking for extra data.
|
||||
|
||||
|
||||
====================================================================
|
||||
Known string keys in VS_VERSION_INFO resource
|
||||
====================================================================
|
||||
|
||||
The aliases are for use with the /s switch, and are not case sensitive.
|
||||
|
||||
-------------------+----+-------------------------------+------------
|
||||
Invariant(LN) name |note| English translation | Alias
|
||||
-------------------+----+-------------------------------+------------
|
||||
Comments Comments comment
|
||||
CompanyName E Company company
|
||||
FileDescription E Description description, desc
|
||||
FileVersion *1 File version
|
||||
InternalName Internal Name title
|
||||
*2 Language
|
||||
LegalCopyright E Copyright copyright, (c)
|
||||
LegalTrademarks E Legal Trademarks tm, (tm)
|
||||
OriginalFilename Original File Name
|
||||
ProductName Product Name product
|
||||
ProductVersion *1 Product Version productver, prodver
|
||||
PrivateBuild Private Build Description pb
|
||||
SpecialBuild Special Build Description sb, build
|
||||
OleSelfRegister A -
|
||||
AssemblyVersion N
|
||||
|
||||
Notes
|
||||
*1: FileVersion, ProductVersion values should begin with same 1.2.3.4 version number as in the binary header.
|
||||
Can be any text. Windows Explorer displays the version numbers from the binary header.
|
||||
|
||||
*2: The "Language" value is the name of the language code specified in the header of the string block of VS_VERSION_INFO resource.
|
||||
(or taken from VarFileInfo block?)
|
||||
It is displayed by Windows Explorer, but is not contained in the version data.
|
||||
|
||||
E: Displayed by Windows Explorer in Vista+
|
||||
A: Intended for some API (OleSelfRegister is used in COM object registration)
|
||||
N: Added by some .NET compilers. This version number is not contained in the
|
||||
binary part of the version struct and can differ from the file version.
|
||||
To change it, just use switch /s AssemblyVersion [value]
|
||||
|
||||
====================================================================
|
||||
|
||||
|
||||
|
||||
Known issues and TO DO's:
|
||||
=========================
|
||||
|
||||
- Does not work on old PE files that have link version 5.x (before VC6?)
|
||||
No known workaround; this seems to be limitation of Windows UpdateResource API.
|
||||
|
||||
- Does not work on signed files (TO DO)
|
||||
|
||||
- Currenly implemented only US English and Language Neutral Unicode version resources.
|
||||
MUI resource configuration manifests not checked.
|
||||
New version resource will be created as Language Neutral.
|
||||
Version info in other languages will be erroneously rewritten as English or Language Neutral- TO DO
|
||||
|
||||
A second (language neutral) version resource may be added to a file
|
||||
that already has a version resource in other language. Switch /va won't help.
|
||||
TO DO: ensure that a file has only one version resource!
|
||||
|
||||
- When verpatch is invoked from command prompt, or batch file, the string
|
||||
arguments can contain only ANSI characters, because cmd.exe batch files cannot be
|
||||
in Uncode format. If you need to use arbitrary character sets,
|
||||
use other shells that fully support Unicode (PowerShell, vbs, js).
|
||||
|
||||
- TO DO: In RC source output (/vo), special characters in strings are not quoted;
|
||||
so /vo may produce invalid RC input
|
||||
|
||||
- The parser of binary version resources handles only the most common type of structure.
|
||||
If the parser breaks because of unhandled structure format, try /va switch to
|
||||
skip reading existing version resource and re-create it from scratch.
|
||||
TODO: Consider using WINE or other open source implementations?
|
||||
|
||||
- option to add extra 0 after version strings : "string\0"
|
||||
(requiested by one reader for some old VB code)
|
||||
|
||||
|
||||
|
||||
Source code
|
||||
============
|
||||
The source is provided as a Visual C++ 2005 project, it can be compiled with VC 2008 Express.
|
||||
It demonstrates use of the UpdateResource and imagehlp.dll API.
|
||||
It does not demonstrate use of c++, good coding manners or anything else.
|
||||
Dependencies on C++ libraries available only with the full Visual C 2008 have been removed.
|
||||
|
||||
|
||||
LICENSE TERMS: CPOL (CodeProject Open License)
|
||||
http://www.codeproject.com/info/licenses.aspx
|
||||
|
||||
~~
|
BIN
external/verpatch/src/verpatch.ncb
vendored
Normal file
BIN
external/verpatch/src/verpatch.ncb
vendored
Normal file
Binary file not shown.
24
external/verpatch/src/verpatch.sln
vendored
Normal file
24
external/verpatch/src/verpatch.sln
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual C++ Express 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "verpatch", "verpatch.vcproj", "{E08F11BD-35BC-4496-82BB-1CFD56BB044C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{E08F11BD-35BC-4496-82BB-1CFD56BB044C}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{E08F11BD-35BC-4496-82BB-1CFD56BB044C}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{E08F11BD-35BC-4496-82BB-1CFD56BB044C}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{E08F11BD-35BC-4496-82BB-1CFD56BB044C}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(SubversionScc) = preSolution
|
||||
Svn-Managed = True
|
||||
Manager = AnkhSVN - Subversion Support for Visual Studio
|
||||
EndGlobalSection
|
||||
EndGlobal
|
BIN
external/verpatch/src/verpatch.suo
vendored
Normal file
BIN
external/verpatch/src/verpatch.suo
vendored
Normal file
Binary file not shown.
336
external/verpatch/src/verpatch.vcproj
vendored
Normal file
336
external/verpatch/src/verpatch.vcproj
vendored
Normal file
|
@ -0,0 +1,336 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="verpatch"
|
||||
ProjectGUID="{E08F11BD-35BC-4496-82BB-1CFD56BB044C}"
|
||||
RootNamespace="relstamp"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)\verpatch.exe"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
LargeAddressAware="1"
|
||||
TerminalServerAware="1"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_A_NOISE_DBG=0"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)\verpatch.exe"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
LargeAddressAware="1"
|
||||
TerminalServerAware="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\peExtras.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\peutils.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\relstamp.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stdafx.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="1"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\vs_version.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\peExtras.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\relstamp.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\stdafx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\targetver.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\vs_version.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Etc"
|
||||
UniqueIdentifier="DOCUM"
|
||||
ParseFiles="false"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\ReadMe.txt"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\usage.txt"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ver-self.cmd"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="CodeProjectFiles"
|
||||
ParseFiles="false"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\codeproj\codeproject_vp.html"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\codeproj\ver-vista.png"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\codeproj\ver-winxp.png"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\codeproj\verpatch-update.html"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
65
external/verpatch/src/verpatch.vcproj.BUILD-WINDOWS.build.user
vendored
Normal file
65
external/verpatch/src/verpatch.vcproj.BUILD-WINDOWS.build.user
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioUserFile
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
ShowAllFiles="false"
|
||||
>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<DebugSettings
|
||||
Command="$(TargetPath)"
|
||||
WorkingDirectory=""
|
||||
CommandArguments=""
|
||||
Attach="false"
|
||||
DebuggerType="3"
|
||||
Remote="1"
|
||||
RemoteMachine="BUILD-WINDOWS"
|
||||
RemoteCommand=""
|
||||
HttpUrl=""
|
||||
PDBPath=""
|
||||
SQLDebugging=""
|
||||
Environment=""
|
||||
EnvironmentMerge="true"
|
||||
DebuggerFlavor=""
|
||||
MPIRunCommand=""
|
||||
MPIRunArguments=""
|
||||
MPIRunWorkingDirectory=""
|
||||
ApplicationCommand=""
|
||||
ApplicationArguments=""
|
||||
ShimCommand=""
|
||||
MPIAcceptMode=""
|
||||
MPIAcceptFilter=""
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<DebugSettings
|
||||
Command="$(TargetPath)"
|
||||
WorkingDirectory=""
|
||||
CommandArguments=""
|
||||
Attach="false"
|
||||
DebuggerType="3"
|
||||
Remote="1"
|
||||
RemoteMachine="BUILD-WINDOWS"
|
||||
RemoteCommand=""
|
||||
HttpUrl=""
|
||||
PDBPath=""
|
||||
SQLDebugging=""
|
||||
Environment=""
|
||||
EnvironmentMerge="true"
|
||||
DebuggerFlavor=""
|
||||
MPIRunCommand=""
|
||||
MPIRunArguments=""
|
||||
MPIRunWorkingDirectory=""
|
||||
ApplicationCommand=""
|
||||
ApplicationArguments=""
|
||||
ShimCommand=""
|
||||
MPIAcceptMode=""
|
||||
MPIAcceptFilter=""
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
</VisualStudioUserFile>
|
295
external/verpatch/src/vs_version.cpp
vendored
Normal file
295
external/verpatch/src/vs_version.cpp
vendored
Normal file
|
@ -0,0 +1,295 @@
|
|||
//
|
||||
// Code for VS_VERSION resource
|
||||
//
|
||||
#include "stdafx.h"
|
||||
#include "relstamp.h"
|
||||
#include "vs_version.h"
|
||||
|
||||
/// Make version resource
|
||||
BOOL makeVersionResource( __in file_ver_data_s const * fvd, __out PUCHAR *retp )
|
||||
{
|
||||
PUCHAR palloc = (PUCHAR)calloc(_MAX_VERS_SIZE_CB, 1);
|
||||
yybuf vbuf( palloc, _MAX_VERS_SIZE_CB );
|
||||
unsigned cbWritten = 0;
|
||||
BOOL ok = FALSE;
|
||||
PCWSTR sigLang = L"040904B0"; /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */
|
||||
WORD vtransl[2] = {0x0409, 0x04B0};
|
||||
WCHAR temps[_MAX_VER_STRING_LEN_CCH + 1];
|
||||
|
||||
if ( fvd->langid == LANG_NEUTRAL ) {
|
||||
//TODO support any language. currently tested only with en or neutral
|
||||
vtransl[0] = LANG_NEUTRAL;
|
||||
sigLang = L"000004b0";
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
// Fill the res header
|
||||
// struct VS_VERSIONINFO {
|
||||
// WORD wLength;
|
||||
// WORD wValueLength;
|
||||
// WORD wType;
|
||||
// WCHAR szKey[];
|
||||
// WORD Padding1[];
|
||||
// VS_FIXEDFILEINFO Value;
|
||||
// WORD Padding2[];
|
||||
// WORD Children[];
|
||||
// };
|
||||
|
||||
PWORD pTotalLen = vbuf.marksize(); // FIXUP LATER
|
||||
vbuf.pushw(~0); // FIXUP LATER
|
||||
vbuf.pushw( sizeof(VS_FIXEDFILEINFO) ); //0x34
|
||||
vbuf.pushw( 0 ); //type
|
||||
vbuf.pushstr( L"VS_VERSION_INFO" );
|
||||
|
||||
// Fixed info
|
||||
VS_FIXEDFILEINFO *fxi = (VS_FIXEDFILEINFO *)vbuf.getptr();
|
||||
fxi->dwSignature = 0xfeef04bd; // magic
|
||||
fxi->dwStrucVersion = VS_FFI_STRUCVERSION; //0x00010000
|
||||
fxi->dwFileVersionMS = MAKELONG( fvd->v_2, fvd->v_1 );
|
||||
fxi->dwFileVersionLS = MAKELONG( fvd->v_4, fvd->v_3 );
|
||||
fxi->dwProductVersionMS = MAKELONG( fvd->pv_2, fvd->pv_1 );
|
||||
fxi->dwProductVersionLS = MAKELONG( fvd->pv_4, fvd->pv_3 );
|
||||
fxi->dwFileFlagsMask = VS_FFI_FILEFLAGSMASK; //0x3F;
|
||||
fxi->dwFileFlags = fvd->dwFileFlags;
|
||||
fxi->dwFileOS = VOS_NT_WINDOWS32;
|
||||
fxi->dwFileType = fvd->dwFileType;
|
||||
fxi->dwFileSubtype = fvd->dwFileSubType;
|
||||
if ( 0 == fxi->dwFileType && 0 != fxi->dwFileSubtype )
|
||||
fxi->dwFileType = VFT_DRV;
|
||||
fxi->dwFileDateLS = 0; //unused?
|
||||
fxi->dwFileDateMS = 0; //
|
||||
vbuf.incptr( sizeof(VS_FIXEDFILEINFO) );
|
||||
vbuf.align4();
|
||||
|
||||
// String File Info
|
||||
|
||||
PWORD stringStart = vbuf.marksize();
|
||||
vbuf.pushw(~0); //wLength FIXUP LATER
|
||||
vbuf.pushw(0); //wValueLength
|
||||
vbuf.pushw(1); //wType
|
||||
vbuf.pushstr( L"StringFileInfo" );
|
||||
|
||||
PWORD stringTableStart = vbuf.marksize();
|
||||
vbuf.pushw(~0); //wLength FIXUP LATER
|
||||
vbuf.pushw(0); // ?
|
||||
vbuf.pushw(1); //wType
|
||||
vbuf.pushstr( sigLang );
|
||||
|
||||
// File version as string. Not shown by Vista, Win7.
|
||||
HRESULT hr = ::StringCbPrintf( &temps[0], sizeof(temps), _T("%d.%d.%d.%d"),
|
||||
fvd->v_1, fvd->v_2, fvd->v_3, fvd->v_4 );
|
||||
if ( !SUCCEEDED(hr) ) temps[0] = 0;
|
||||
if ( fvd->sFileVerTail ) {
|
||||
hr = ::StringCbCatW(&temps[0], sizeof(temps), L" ");
|
||||
hr = ::StringCbCatW(&temps[0], sizeof(temps), fvd->sFileVerTail);
|
||||
if ( !SUCCEEDED(hr) ) temps[0] = 0;
|
||||
}
|
||||
vbuf.pushTwostr( L"FileVersion", &temps[0] );
|
||||
|
||||
hr = ::StringCbPrintf( &temps[0], sizeof(temps), _T("%d.%d.%d.%d"),
|
||||
fvd->pv_1, fvd->pv_2, fvd->pv_3, fvd->pv_4 );
|
||||
if ( !SUCCEEDED(hr) ) temps[0] = 0;
|
||||
if ( fvd->sProductVerTail ) {
|
||||
hr = ::StringCbCatW(&temps[0], sizeof(temps), L" ");
|
||||
hr = ::StringCbCatW(&temps[0], sizeof(temps), fvd->sProductVerTail);
|
||||
if ( !SUCCEEDED(hr) ) temps[0] = 0;
|
||||
}
|
||||
vbuf.pushTwostr( L"ProductVersion", &temps[0] );
|
||||
|
||||
// Strings
|
||||
for ( int k = 0; k < ARRAYSIZE(fvd->CustomStrNames); k++ ) {
|
||||
if ( fvd->CustomStrNames[k] != NULL ) {
|
||||
|
||||
vbuf.pushTwostr( fvd->CustomStrNames[k], fvd->CustomStrVals[k] );
|
||||
|
||||
if ( 0 == _wcsicmp( L"SpecialBuild", fvd->CustomStrNames[k] ) )
|
||||
fxi->dwFileFlags |= VS_FF_SPECIALBUILD;
|
||||
if ( 0 == _wcsicmp( L"PrivateBuild",fvd->CustomStrNames[k] ) )
|
||||
fxi->dwFileFlags |= VS_FF_PRIVATEBUILD;
|
||||
}
|
||||
}
|
||||
|
||||
vbuf.patchsize( stringTableStart );
|
||||
vbuf.patchsize( stringStart );
|
||||
vbuf.align4();
|
||||
|
||||
// Var info
|
||||
//struct VarFileInfo {
|
||||
// WORD wLength;
|
||||
// WORD wValueLength;
|
||||
// WORD wType;
|
||||
// WCHAR szKey[];
|
||||
// WORD Padding[];
|
||||
// Var Children[];
|
||||
PWORD varStart = vbuf.marksize();
|
||||
vbuf.pushw(~0); // size, patch
|
||||
vbuf.pushw(0);
|
||||
vbuf.pushw(1);
|
||||
vbuf.pushstr( L"VarFileInfo" );
|
||||
|
||||
vbuf.pushw(0x24);
|
||||
vbuf.pushw(0x04);
|
||||
vbuf.pushw(0x00);
|
||||
vbuf.pushstr( L"Translation" );
|
||||
vbuf.pushw( vtransl[0] );
|
||||
vbuf.pushw( vtransl[1] );
|
||||
vbuf.patchsize( varStart );
|
||||
|
||||
/////////////////////////////
|
||||
vbuf.patchsize(pTotalLen);
|
||||
vbuf.checkspace();
|
||||
|
||||
ok = TRUE;
|
||||
} catch(...) {
|
||||
ok = FALSE;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
d3print("ver size= %d\n", vbuf.cbwritten() );
|
||||
*retp = palloc;
|
||||
} else {
|
||||
dprint("error in %s\n", __FUNCTION__);
|
||||
free( palloc );
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Simple parser for binary version resource
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
BOOL ParseBinaryVersionResource(
|
||||
__in const PUCHAR verres,
|
||||
unsigned size,
|
||||
__out VS_FIXEDFILEINFO **pfxi,
|
||||
IParseVerStrCallback *strCallback,
|
||||
bool b_dump_rc
|
||||
)
|
||||
{
|
||||
BOOL ok = FALSE;
|
||||
xybuf vbuf( verres, size );
|
||||
WCHAR sigLang[8+1];
|
||||
|
||||
try {
|
||||
|
||||
// Res header
|
||||
PWORD pTotalLen = vbuf.marksize();
|
||||
|
||||
vbuf.chkword( sizeof(VS_FIXEDFILEINFO) ); //0x34
|
||||
vbuf.chkword(0); //type
|
||||
vbuf.chkstr(L"VS_VERSION_INFO");
|
||||
// Fixed info
|
||||
VS_FIXEDFILEINFO *fxi = (VS_FIXEDFILEINFO *)vbuf.getptr();
|
||||
if ( fxi->dwSignature != 0xfeef04bd )
|
||||
throw ":fxi.sig";
|
||||
if ( fxi->dwStrucVersion > 0x00010000 || (fxi->dwStrucVersion == 0) )
|
||||
throw ":fxi.version";
|
||||
|
||||
*pfxi = fxi;
|
||||
|
||||
if (b_dump_rc) {
|
||||
// Dump in RC format:
|
||||
dtprint( _T("#ifdef RC_INVOKED\n\n"));
|
||||
dtprint( _T("1\tVERSIONINFO\n"));
|
||||
dtprint( _T("FILEVERSION\t%u,%u,%u,%u\n"),
|
||||
HIWORD(fxi->dwFileVersionMS), LOWORD(fxi->dwFileVersionMS), HIWORD(fxi->dwFileVersionLS), LOWORD(fxi->dwFileVersionLS) );
|
||||
dtprint( _T("PRODUCTVERSION\t%u,%u,%u,%u\n"),
|
||||
HIWORD(fxi->dwProductVersionMS), LOWORD(fxi->dwProductVersionMS), HIWORD(fxi->dwProductVersionLS), LOWORD(fxi->dwProductVersionLS) );
|
||||
dtprint( _T("FILEFLAGSMASK\t%#XL\n"), fxi->dwFileFlagsMask);
|
||||
dtprint( _T("FILEFLAGS\t%#XL\n"), fxi->dwFileFlags);
|
||||
dtprint( _T("FILEOS\t\t%#XL\n"), fxi->dwFileOS);
|
||||
dtprint( _T("FILETYPE\t%#X\n"), fxi->dwFileType);
|
||||
dtprint( _T("FILESUBTYPE\t%#X\n"), fxi->dwFileSubtype);
|
||||
}
|
||||
|
||||
vbuf.incptr( sizeof(VS_FIXEDFILEINFO) );
|
||||
vbuf.align4();
|
||||
|
||||
// String File Info
|
||||
PWORD stringStart = vbuf.marksize();
|
||||
vbuf.chkword(0); //wValueLength
|
||||
vbuf.chkword(1); //wType
|
||||
|
||||
try {
|
||||
vbuf.chkstr(L"StringFileInfo");
|
||||
} catch( char *exs ) {
|
||||
// !!! VarFileInfo can go before StringFileInfo!
|
||||
vbuf.chkstr(L"VarFileInfo");
|
||||
// ok so here is "VarFileInfo". Skip it and resync at StringFileInfo
|
||||
vbuf.checkspace(0x40);
|
||||
PUCHAR q = (PUCHAR)memchr( vbuf.getptr(), 'S', 0x30 );
|
||||
if ( !q ) throw(":parse_err2");
|
||||
vbuf.incptr( q - vbuf.getptr() - 3 *sizeof(WORD));
|
||||
// Retry:
|
||||
stringStart = vbuf.marksize();
|
||||
vbuf.chkword(0); //wValueLength
|
||||
vbuf.chkword(1); //wType
|
||||
vbuf.chkstr(L"StringFileInfo");
|
||||
}
|
||||
|
||||
PWORD stringTableStart = vbuf.marksize();
|
||||
vbuf.chkword(0); // ?
|
||||
vbuf.chkword(1); //wType
|
||||
|
||||
// Language string: ex. "040904B0"
|
||||
vbuf.checkspace( 10 * sizeof(WCHAR) );
|
||||
WORD n = wcslen( (PCWSTR)vbuf.getptr() );
|
||||
if (n != 8)
|
||||
throw(":bad_lang_str");
|
||||
memcpy( sigLang, vbuf.getptr(), 9*sizeof(WCHAR) ); //incl term. 0
|
||||
vbuf.incptr( (n + 1) * sizeof(WCHAR) );
|
||||
vbuf.align4();
|
||||
|
||||
strCallback->callback( L"@LANG", sigLang ); // revise
|
||||
|
||||
if (b_dump_rc) {
|
||||
// Dump in RC format:
|
||||
dtprint(_T("BEGIN\n"));
|
||||
dtprint(_T("\tBLOCK \"StringFileInfo\"\n"));
|
||||
dtprint(_T("\tBEGIN\n"));
|
||||
dtprint(_T("\t\tBLOCK \"%ws\"\n"), sigLang);
|
||||
dtprint(_T("\t\tBEGIN\n"));
|
||||
}
|
||||
|
||||
// Loop for strings:
|
||||
int cntstrings = 0;
|
||||
do {
|
||||
PCWSTR wsname, wsval;
|
||||
vbuf.pullTwoStr( &wsname, &wsval );
|
||||
cntstrings++;
|
||||
//- dprint(" str#%d [%ws]=[%ws]\n", cntstrings, wsname, wsval);
|
||||
if (b_dump_rc) {
|
||||
dtprint(_T("\t\t\tVALUE \"%ws\", \"%ws\"\n"), wsname, strEscape(wsval));
|
||||
}
|
||||
strCallback->callback( wsname, wsval );
|
||||
} while( vbuf.getptr() < ((PUCHAR)stringStart + *stringStart) );
|
||||
|
||||
vbuf.align4();
|
||||
d3print("strings counted:%d\n", cntstrings);
|
||||
|
||||
if (b_dump_rc) {
|
||||
dtprint(_T("\t\tEND\n"));
|
||||
dtprint(_T("\tEND\n"));
|
||||
// VarFileInfo.....
|
||||
dtprint(_T("\tBLOCK \"VarFileInfo\"\n"));
|
||||
dtprint(_T("\tBEGIN\n"));
|
||||
dtprint(_T("\t\tVALUE \"Translation\", 0x%4.4ws, 0x%4.4ws\n"), &sigLang[0], &sigLang[4]);
|
||||
dtprint(_T("\tEND\n"));
|
||||
dtprint(_T("END\n\n"));
|
||||
dtprint( _T("#endif /*RC_INVOKED*/\n\n"));
|
||||
}
|
||||
|
||||
ok = TRUE;
|
||||
|
||||
} catch(...) {
|
||||
dprint("Exception in %s\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
if (!ok) dprint("Error in %s\n", __FUNCTION__);
|
||||
|
||||
return ok;
|
||||
}
|
313
external/verpatch/src/vs_version.h
vendored
Normal file
313
external/verpatch/src/vs_version.h
vendored
Normal file
|
@ -0,0 +1,313 @@
|
|||
//
|
||||
// Code for VS_VERSION resource
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// Stupid helper classes for the version struct
|
||||
class yybuf
|
||||
{
|
||||
PUCHAR m_startptr;
|
||||
PUCHAR m_curptr;
|
||||
int m_inisize;
|
||||
|
||||
public:
|
||||
yybuf( PUCHAR start, unsigned size )
|
||||
: m_startptr(start), m_inisize(size), m_curptr(start)
|
||||
{
|
||||
ASSERT(((ULONG_PTR)start & 3) == 0); // must be aligned on 4
|
||||
}
|
||||
|
||||
void align4() {
|
||||
PULONG_PTR x = (PULONG_PTR)&m_curptr;
|
||||
*x += 3;
|
||||
*x &= ~(ULONG_PTR)3;
|
||||
}
|
||||
|
||||
int cbwritten(void) { return m_curptr - m_startptr; }
|
||||
|
||||
void checkspace( int n = 8 ) {
|
||||
if ( cbwritten() + n > m_inisize )
|
||||
__debugbreak();
|
||||
}
|
||||
|
||||
void pushw( WORD v ) {
|
||||
*(PWORD)m_curptr = v;
|
||||
m_curptr += sizeof(WORD);
|
||||
}
|
||||
|
||||
void pushd( DWORD v ) {
|
||||
*(PDWORD)m_curptr = v;
|
||||
m_curptr += sizeof(DWORD);
|
||||
}
|
||||
|
||||
void pushstr( __in LPCWSTR ws, bool b_align = TRUE ) {
|
||||
if ( !ws ) return;
|
||||
WORD n = wcslen( ws );
|
||||
ASSERT( n < _MAX_VER_STRING_LEN_CCH );
|
||||
n = (n + 1) * sizeof(WCHAR);
|
||||
checkspace(n + sizeof(DWORD));
|
||||
memcpy( m_curptr, ws, n );
|
||||
m_curptr += n;
|
||||
if (b_align)
|
||||
align4();
|
||||
}
|
||||
|
||||
PUCHAR getptr() { return m_curptr;}
|
||||
|
||||
void incptr( int n ) { checkspace(n); m_curptr += n; }
|
||||
|
||||
PWORD marksize() { return (PWORD)m_curptr; }
|
||||
|
||||
void patchsize ( PWORD mp ) {
|
||||
WORD cb = getptr() - (PUCHAR)mp;
|
||||
*mp = cb;
|
||||
};
|
||||
|
||||
void yybuf::pushTwostr( __in LPCWSTR name, __in LPCWSTR val )
|
||||
{
|
||||
//struct String {
|
||||
// WORD wLength;
|
||||
// WORD wValueLength;
|
||||
// WORD wType;
|
||||
// WCHAR szKey[];
|
||||
// WORD Padding[];
|
||||
// WORD Value[];
|
||||
//};
|
||||
WORD wValueLength = val ? (WORD)wcslen(val) : 0;
|
||||
if (wValueLength)
|
||||
wValueLength = (wValueLength + 1) * sizeof(WCHAR);
|
||||
WORD wNameLength = (WORD)((wcslen(name) + 1 ) * sizeof(WCHAR));
|
||||
ASSERT(wNameLength > sizeof(WCHAR));
|
||||
|
||||
checkspace( wValueLength + wNameLength + 5*sizeof(WORD));
|
||||
|
||||
PUCHAR porig = m_curptr;
|
||||
pushw(-1); //length, patch
|
||||
pushw( wValueLength );
|
||||
pushw( 1 ); //type
|
||||
pushstr( name ); // with align
|
||||
if ( wValueLength )
|
||||
pushstr( val, false ); // don't align yet
|
||||
*(PWORD)porig = (WORD)(m_curptr - porig);
|
||||
align4();
|
||||
}
|
||||
|
||||
}; // class
|
||||
|
||||
class xybuf
|
||||
{
|
||||
PUCHAR m_startptr;
|
||||
PUCHAR m_curptr;
|
||||
int m_inisize;
|
||||
|
||||
public:
|
||||
xybuf( PUCHAR start, unsigned size )
|
||||
: m_startptr(start), m_inisize(size), m_curptr(start)
|
||||
{
|
||||
ASSERT(((ULONG_PTR)start & 3) == 0); // must be aligned on 4
|
||||
}
|
||||
|
||||
void align4() {
|
||||
PULONG_PTR x = (PULONG_PTR)&m_curptr;
|
||||
*x += 3;
|
||||
*x &= ~(ULONG_PTR)3;
|
||||
}
|
||||
|
||||
int cbread(void) { return m_curptr - m_startptr; }
|
||||
|
||||
void checkspace( int n = 8 ) {
|
||||
if ( cbread() + n > m_inisize )
|
||||
throw ":overrun read";
|
||||
}
|
||||
|
||||
PUCHAR getptr() { return m_curptr;}
|
||||
|
||||
void incptr( int n ) { checkspace(n); m_curptr += n; }
|
||||
|
||||
PWORD marksize() { PWORD p = (PWORD)m_curptr; m_curptr += sizeof(WORD); return p; }
|
||||
|
||||
BOOL chksize( PWORD mp, bool b_nothrow = false ) {
|
||||
// check size of block is correct
|
||||
WORD cb = getptr() - (PUCHAR)mp;
|
||||
if (*mp != cb ) {
|
||||
if ( !b_nothrow ) throw ":chksize";
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
};
|
||||
|
||||
void chkword( WORD v ) {
|
||||
if (*(PWORD)m_curptr != v)
|
||||
throw ":chkword";
|
||||
m_curptr += sizeof(WORD);
|
||||
}
|
||||
|
||||
void chkdword( DWORD v ) {
|
||||
if (*(PDWORD)m_curptr != v)
|
||||
throw ":chkdword";
|
||||
m_curptr += sizeof(DWORD);
|
||||
}
|
||||
|
||||
void chkstr( __in LPCWSTR ws, bool b_align = TRUE ) {
|
||||
WORD n = wcslen( ws );
|
||||
ASSERT ( n );
|
||||
ASSERT( n < _MAX_VER_STRING_LEN_CCH );
|
||||
checkspace((n + 1) * sizeof(WCHAR) + sizeof(DWORD));
|
||||
|
||||
for (int i = 0; i <= n; i++ ) { // incl. term. 0
|
||||
if ( *(PWCHAR)m_curptr != *ws &&
|
||||
*(PWCHAR)m_curptr != (*ws ^ 0x20) )
|
||||
throw ":chkstr";
|
||||
m_curptr += sizeof(WCHAR);
|
||||
ws++;
|
||||
}
|
||||
|
||||
if (b_align)
|
||||
align4();
|
||||
}
|
||||
|
||||
void pullTwoStr( __out LPCWSTR *wsname, __out LPCWSTR *wsval )
|
||||
{
|
||||
//struct String {
|
||||
// WORD wLength;
|
||||
// WORD wValueLength;
|
||||
// WORD wType;
|
||||
// WCHAR szKey[];
|
||||
// WORD Padding[];
|
||||
// WORD Value[];
|
||||
//};
|
||||
checkspace(5*sizeof(WORD));
|
||||
PWORD porig = marksize();
|
||||
|
||||
WORD wLength = *porig;
|
||||
if ( wLength > 1024 || wLength < 5*sizeof(WORD))
|
||||
throw ":string desc size bad";
|
||||
checkspace(5*sizeof(WORD) + wLength);
|
||||
WORD wValueLength = *((PWORD)m_curptr);
|
||||
incptr(2);
|
||||
chkword(1); //type
|
||||
|
||||
size_t nLength = wcsnlen( (LPWSTR)( getptr() ), wLength/sizeof(WCHAR) );
|
||||
if (nLength == 0 || nLength == (wLength/sizeof(WCHAR)) )
|
||||
throw ":string name len bad";
|
||||
*wsname = (LPCWSTR)getptr(); //should point to name
|
||||
unsigned bLength = (nLength + 1)*sizeof(WCHAR);
|
||||
incptr( bLength );
|
||||
align4(); //padding
|
||||
|
||||
if ( getptr() >= (PUCHAR)porig + *porig ) {
|
||||
// null value
|
||||
*wsval = L"";
|
||||
return;
|
||||
}
|
||||
|
||||
wLength -= bLength;
|
||||
nLength = wcsnlen( LPWSTR( getptr() ), wLength/sizeof(WCHAR) );
|
||||
if ( nLength == 0 || nLength == (wLength/sizeof(WCHAR)) )
|
||||
throw ":string val name len bad";
|
||||
|
||||
*wsval = (LPCWSTR)getptr(); //should point to value
|
||||
bLength = (nLength + 1)*sizeof(WCHAR);
|
||||
// can be padded after 0 term
|
||||
|
||||
m_curptr = (PUCHAR)porig + *porig;
|
||||
align4(); //padding
|
||||
}
|
||||
|
||||
}; //class
|
||||
|
||||
#if 1
|
||||
// a stupid string helper class.
|
||||
// this doesn't run 24*7, so allow memory leaks...
|
||||
class _xpwstr {
|
||||
PWSTR m_str;
|
||||
|
||||
public:
|
||||
void operator = (PCTSTR s ) {
|
||||
if ( m_str )
|
||||
free( m_str );
|
||||
m_str = NULL;
|
||||
if (s)
|
||||
m_str = stralloc( s );
|
||||
}
|
||||
|
||||
operator PCWSTR() const { return (PCWSTR)m_str; }
|
||||
|
||||
_xpwstr() : m_str(NULL) { }
|
||||
~_xpwstr() { if (m_str) free( m_str ); }
|
||||
};
|
||||
|
||||
typedef _xpwstr ASTR;
|
||||
#else
|
||||
typedef CString ASTR;
|
||||
#endif
|
||||
|
||||
// Data for a vs_version resource
|
||||
struct file_ver_data_s {
|
||||
USHORT v_1, v_2, v_3, v_4; // Version components 1-4
|
||||
USHORT pv_1, pv_2, pv_3, pv_4; // Product Version components 1-4
|
||||
UINT32 dwFileType, dwFileSubType;
|
||||
UINT32 dwFileFlags;
|
||||
WORD langid; // language
|
||||
ASTR sFileVerTail; // sometimes used - ex. WDK samples, common.ver
|
||||
ASTR sProductVerTail; // same for product ver.
|
||||
// Strings
|
||||
ASTR CustomStrNames[_MAX_VER_CUSTOM_STRINGS];
|
||||
ASTR CustomStrVals[_MAX_VER_CUSTOM_STRINGS];
|
||||
|
||||
bool addTwostr( __in_opt PCWSTR name, __in_opt PCWSTR val )
|
||||
{
|
||||
if ( !name )
|
||||
return false;
|
||||
|
||||
int index = -1;
|
||||
for (int i = 0; i < ARRAYSIZE(CustomStrNames); i++) {
|
||||
if ( !CustomStrNames[i] ) {
|
||||
if (index == -1) index = i;
|
||||
continue;
|
||||
}
|
||||
if ( 0 == _wcsicmp( name, CustomStrNames[i] ) ) {
|
||||
index = i;
|
||||
d3print("replacing dup string in ver resource: %ws\n", (PCWSTR)name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( index != -1 ) {
|
||||
CustomStrNames[index] = name;
|
||||
CustomStrVals[index] = val; // can be 0
|
||||
return true;
|
||||
}
|
||||
|
||||
dprint("Too many strings in ver resource! not added %ws\n", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
PCWSTR getValStr( __in PCWSTR name )
|
||||
{
|
||||
for (int i = 0; i < ARRAYSIZE(CustomStrNames); i++) {
|
||||
PCWSTR s = CustomStrNames[i];
|
||||
if ( s && (0 == _wcsicmp(name, s) ) )
|
||||
return CustomStrVals[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
// Interface for ParseBinaryVersionResource
|
||||
class IParseVerStrCallback
|
||||
{
|
||||
public:
|
||||
virtual void callback( __in PCWSTR name, __in_opt PCWSTR value ) = 0;
|
||||
};
|
||||
|
||||
BOOL makeVersionResource( __in file_ver_data_s const * fvd, __out PUCHAR *retp );
|
||||
|
||||
BOOL ParseBinaryVersionResource(
|
||||
__in const PUCHAR verres,
|
||||
unsigned size,
|
||||
__out VS_FIXEDFILEINFO **pfxi,
|
||||
IParseVerStrCallback *strCallback,
|
||||
bool b_dump_rc = false
|
||||
);
|
234
external/verpatch/verpatch-ReadMe.txt
vendored
Normal file
234
external/verpatch/verpatch-ReadMe.txt
vendored
Normal file
|
@ -0,0 +1,234 @@
|
|||
|
||||
Verpatch - a tool to patch win32 version resources on .exe or .dll files,
|
||||
|
||||
Version: 01-Nov-2009 (rev. #7 for CodeProject) edited
|
||||
|
||||
Verpatch is a command line tool for adding and editing the version information
|
||||
of Windows executable files (applications, DLLs, kernel drivers)
|
||||
without rebuilding the executable.
|
||||
|
||||
It can also add or replace Win32 (native) resources, and do some other
|
||||
modifications of executable files.
|
||||
|
||||
Verpatch sets ERRORLEVEL 0 on success, otherwise errorlevel is non-zero.
|
||||
Verpatch modifies files in place, so please make copies of precious files.
|
||||
|
||||
|
||||
Command line syntax
|
||||
===================
|
||||
|
||||
verpatch filename [version] [/options]
|
||||
|
||||
Where
|
||||
- filename : any Windows PE file (exe, dll, sys, ocx...) that can have native resources
|
||||
- version : one to four decimal numbers, separated by dots, ex.: 1.2.3.4
|
||||
Additional text can follow the numbers; see examples below. Ex.: "1.2.3.4 extra text"
|
||||
- options: see below
|
||||
|
||||
Common Options:
|
||||
|
||||
/va - creates a version resource. Use when the file has no version resource at all,
|
||||
or existing version resource should be replaced.
|
||||
If this option not specified, verpatch will patch the version resourse found in the file.
|
||||
/s name "value" - add a version resource string attribute
|
||||
The name can be either a full attribute name or alias; see below.
|
||||
/sc "comment" - add or replace Comments string (shortcut for /s Comments "comment")
|
||||
/pv <version> - specify Product version
|
||||
where <version> arg has same form as the file version (1.2.3.4 or "1.2.3.4 text")
|
||||
/fn - preserves Original filename, Internal name in the existing version resource of the file.
|
||||
|
||||
|
||||
Other options:
|
||||
|
||||
/vo - outputs the version info in RC format to stdout.
|
||||
This can be used with /xi to import a version resource from another file.
|
||||
Output of /vo (text from #ifdef RC_INVOKED to #endif) can be saved to a .rc file and compiled with rc.
|
||||
/xi- test mode. does all operations but does not modify the file
|
||||
/xlb - test mode. Re-parses the version resource after modification.
|
||||
/rpdb - removes path to the .pdb file in debug information; leaves only file name.
|
||||
/rf #id file - add or replace a raw binary resource from file (see below)
|
||||
/noed - do not check for extra data appended to exe file
|
||||
/vft2 num - specify driver subtype (VFT2_xxx value, see winver.h)
|
||||
The application type (VFT_xxx) is retained from the existing version resource of the file,
|
||||
or filled automatically, based on the filename extension (exe->app, sys->driver, anything else->dll)
|
||||
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
verpatch d:\foo.dll 1.2.33.44
|
||||
- replaces only the file version, all 4 numbers,
|
||||
the Original file name and Internal name strings are set to "foo.dll".
|
||||
File foo.dll should already have a version resource.
|
||||
|
||||
verpatch d:\foo.dll 33.44 /s comment "a comment"
|
||||
- replaces only two last numbers of the file version and adds a comment.
|
||||
File foo.dll should already have a version resource.
|
||||
|
||||
verpatch d:\foo.dll "33.44 special release" /sc "a comment"
|
||||
- same as previous, with additional text in the version argument.
|
||||
|
||||
verpatch d:\foo.dll "1.2.33.44" /va /s description "foo.dll"
|
||||
/s company "My Company" /s copyright "(c) 2009"
|
||||
- adds or replaces version resource to foo.dll, with several string values.
|
||||
( all options should be one line)
|
||||
|
||||
verpatch d:\foo.dll /vo /xi
|
||||
- dumps the version resource in RC format, does not update the file.
|
||||
|
||||
|
||||
|
||||
Remarks
|
||||
=======
|
||||
|
||||
Verpatch replaces the version number in existing file version info resource
|
||||
with the values given on the command line.
|
||||
|
||||
In "patch" mode (no /va option), the PE file should have a version resource,
|
||||
which is parsed, and then parameters specified on the command line are applied.
|
||||
|
||||
If the file has no version resource, or you want to discard the existing resource, use /va switch.
|
||||
All nesessary strings can be specified with the /s option.
|
||||
|
||||
The command line can become very long, so you may want to use a batch file or script.
|
||||
See the example batch files, how to create a version resource and
|
||||
specify all parameters with /va.
|
||||
|
||||
Verpatch can be run on same PE file any number of times.
|
||||
|
||||
The Version argument can be specified as 1 to 4 dot separated decimal numbers,
|
||||
or as quoted string containing additional text after the numbers.
|
||||
If less than 4 numbers are given, they are considered as minor numbers.
|
||||
The higher version parts are retained from existing version resource.
|
||||
For example, if the existing version info has version number 1.2.3.4
|
||||
and 55.66 specified on the command line, the result will be 1.2.55.66.
|
||||
|
||||
The quotes surrounding string arguments are needed for the command shell (cmd.exe),
|
||||
for any argument that contains spaces.
|
||||
|
||||
The program ensures that the version numbers in the binary part
|
||||
of the version structure and in the string part (as text) are same.
|
||||
|
||||
By default, Original File Name and Internal File Name are replaced to the actual filename.
|
||||
Use /fn to preserve existing values in the version resource.
|
||||
|
||||
For option /s, specify language-neutral string names, not translations
|
||||
( example: PrivateBuild, not "Private Build Description" ).
|
||||
Null values can be specified as empty string ("").
|
||||
See below for the list of known string keys names and their aliases.
|
||||
The examples above use the aliases.
|
||||
|
||||
Strings for File version and Product version parameters are handled in a special way,
|
||||
the /s switch can not be used to set them:
|
||||
- File version can be specified only as the 2nd positional argument
|
||||
- Product version can be specified using /pv switch
|
||||
|
||||
The /rf switch adds a resource from a file, or replaces a resource with same type and id.
|
||||
The argument "#id" is a 32-bit hex number, prefixed with #.
|
||||
Low 16 bits of this value are resource id; can not be 0.
|
||||
Next 8 bits are resource type: one of RT_xxx symbols in winuser.h, or user defined.
|
||||
If the type value is 0, RT_RCDATA (10) is assumed.
|
||||
High 8 bits of the #id arg are reserved0.
|
||||
The language code of resources added by this switch is 0 (Neutral).
|
||||
Named resource types and ids are not implemented.
|
||||
The file is added as opaque binary chunk; the resource size is rounded up to 4 bytes
|
||||
and padded with zero bytes.
|
||||
|
||||
The program detects extra data appended to executable files, saves it and appends
|
||||
again after modifying resources.
|
||||
Such extra data is used by some installers, self-extracting archives and other applications.
|
||||
However, the way we restore the data may be not compatible with these applications.
|
||||
Please, verify that executable files that contain extra data work correctly after modification.
|
||||
Command switch /noed disables checking for extra data.
|
||||
|
||||
|
||||
====================================================================
|
||||
Known string keys in VS_VERSION_INFO resource
|
||||
====================================================================
|
||||
|
||||
The aliases are for use with the /s switch, and are not case sensitive.
|
||||
|
||||
-------------------+----+-------------------------------+------------
|
||||
Invariant(LN) name |note| English translation | Alias
|
||||
-------------------+----+-------------------------------+------------
|
||||
Comments Comments comment
|
||||
CompanyName E Company company
|
||||
FileDescription E Description description, desc
|
||||
FileVersion *1 File version
|
||||
InternalName Internal Name title
|
||||
*2 Language
|
||||
LegalCopyright E Copyright copyright, (c)
|
||||
LegalTrademarks E Legal Trademarks tm, (tm)
|
||||
OriginalFilename Original File Name
|
||||
ProductName Product Name product
|
||||
ProductVersion *1 Product Version productver, prodver
|
||||
PrivateBuild Private Build Description pb
|
||||
SpecialBuild Special Build Description sb, build
|
||||
OleSelfRegister A -
|
||||
AssemblyVersion N
|
||||
|
||||
Notes
|
||||
*1: FileVersion, ProductVersion values should begin with same 1.2.3.4 version number as in the binary header.
|
||||
Can be any text. Windows Explorer displays the version numbers from the binary header.
|
||||
|
||||
*2: The "Language" value is the name of the language code specified in the header of the string block of VS_VERSION_INFO resource.
|
||||
(or taken from VarFileInfo block?)
|
||||
It is displayed by Windows Explorer, but is not contained in the version data.
|
||||
|
||||
E: Displayed by Windows Explorer in Vista+
|
||||
A: Intended for some API (OleSelfRegister is used in COM object registration)
|
||||
N: Added by some .NET compilers. This version number is not contained in the
|
||||
binary part of the version struct and can differ from the file version.
|
||||
To change it, just use switch /s AssemblyVersion [value]
|
||||
|
||||
====================================================================
|
||||
|
||||
|
||||
|
||||
Known issues and TO DO's:
|
||||
=========================
|
||||
|
||||
- Does not work on old PE files that have link version 5.x (before VC6?)
|
||||
No known workaround; this seems to be limitation of Windows UpdateResource API.
|
||||
|
||||
- Does not work on signed files (TO DO)
|
||||
|
||||
- Currenly implemented only US English and Language Neutral Unicode version resources.
|
||||
MUI resource configuration manifests not checked.
|
||||
New version resource will be created as Language Neutral.
|
||||
Version info in other languages will be erroneously rewritten as English or Language Neutral- TO DO
|
||||
|
||||
A second (language neutral) version resource may be added to a file
|
||||
that already has a version resource in other language. Switch /va won't help.
|
||||
TO DO: ensure that a file has only one version resource!
|
||||
|
||||
- When verpatch is invoked from command prompt, or batch file, the string
|
||||
arguments can contain only ANSI characters, because cmd.exe batch files cannot be
|
||||
in Uncode format. If you need to use arbitrary character sets,
|
||||
use other shells that fully support Unicode (PowerShell, vbs, js).
|
||||
|
||||
- TO DO: In RC source output (/vo), special characters in strings are not quoted;
|
||||
so /vo may produce invalid RC input
|
||||
|
||||
- The parser of binary version resources handles only the most common type of structure.
|
||||
If the parser breaks because of unhandled structure format, try /va switch to
|
||||
skip reading existing version resource and re-create it from scratch.
|
||||
TODO: Consider using WINE or other open source implementations?
|
||||
|
||||
- option to add extra 0 after version strings : "string\0"
|
||||
(requiested by one reader for some old VB code)
|
||||
|
||||
|
||||
|
||||
Source code
|
||||
============
|
||||
The source is provided as a Visual C++ 2005 project, it can be compiled with VC 2008 Express.
|
||||
It demonstrates use of the UpdateResource and imagehlp.dll API.
|
||||
It does not demonstrate use of c++, good coding manners or anything else.
|
||||
Dependencies on C++ libraries available only with the full Visual C 2008 have been removed.
|
||||
|
||||
|
||||
LICENSE TERMS: CPOL (CodeProject Open License)
|
||||
http://www.codeproject.com/info/licenses.aspx
|
||||
|
||||
~~
|
BIN
external/verpatch/verpatch.exe
vendored
Normal file
BIN
external/verpatch/verpatch.exe
vendored
Normal file
Binary file not shown.
7
src/resources/create-version-info.bat
Normal file
7
src/resources/create-version-info.bat
Normal file
|
@ -0,0 +1,7 @@
|
|||
set VERSION="1.0"
|
||||
set FILEDESCR=/s desc "Software update utility."
|
||||
set BUILDINFO=/s pb "Built by Robert Knight"
|
||||
set COMPINFO=/s company "Mendeley Ltd." /s (c) "(C) Mendeley Ltd. 2011"
|
||||
set PRODINFO=/s product "Mendeley Software Updater" /pv "1.0"
|
||||
|
||||
verpatch /vo /xi updater.exe %VERSION% %FILEDESCR% %COMPINFO% %PRODINFO% %BUILDINFO%
|
|
@ -1 +1,31 @@
|
|||
IDI_APPICON ICON DISCARDABLE "updater.ico"
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 0,0,1,0
|
||||
PRODUCTVERSION 1,0,1,0
|
||||
FILEFLAGSMASK 0X3FL
|
||||
FILEFLAGS 0X8L
|
||||
FILEOS 0X40004L
|
||||
FILETYPE 0X1
|
||||
FILESUBTYPE 0
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "000004b0"
|
||||
BEGIN
|
||||
VALUE "FileVersion", "0.0.1.0"
|
||||
VALUE "ProductVersion", "1.0.1.0"
|
||||
VALUE "OriginalFilename", "updater.exe"
|
||||
VALUE "InternalName", "updater.exe"
|
||||
VALUE "FileDescription", "Software Update Tool"
|
||||
VALUE "CompanyName", "Mendeley Ltd."
|
||||
VALUE "LegalCopyright", "(C) Mendeley Ltd. 2011"
|
||||
VALUE "ProductName", "Mendeley Software Updater"
|
||||
VALUE "PrivateBuild", "Built by Robert Knight"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x0000, 0x04b0
|
||||
END
|
||||
END
|
Loading…
Reference in a new issue