Added !gettlbversion and TLB reading support on POSIX

git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6913 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
anders_k 2017-10-03 20:48:29 +00:00
parent f34fd48105
commit a51d89712c
19 changed files with 256 additions and 247 deletions

View file

@ -3,7 +3,9 @@
LibraryLocal - used by the Library.nsh macros
Get the version of local DLL and TLB files
Written by Joost Verburg
Unicode support by Jim Park -- 07/27/2007
POSIX DLL version support by kichik -- 20070415
Unicode support by Jim Park -- 20070727
POSIX TLB version support by anders_k -- 20170929
*/
@ -14,6 +16,7 @@
#include <iostream>
#include <fstream>
#include "../../../Source/BinInterop.h"
#include "../../../Source/util.h"
#include "../../../Source/winchar.h"
@ -22,139 +25,79 @@ using namespace std;
int g_noconfig=0; // TODO: Not used?
NSISRT_DEFINEGLOBALS();
int GetTLBVersion(tstring& filepath, DWORD& high, DWORD & low)
{
#ifdef _WIN32
int found = 0;
TCHAR fullpath[1024];
TCHAR *p;
if (!GetFullPathName(filepath.c_str(), COUNTOF(fullpath), fullpath, &p))
return 0;
ITypeLib* typeLib;
HRESULT hr;
#ifdef _UNICODE
hr = LoadTypeLib(fullpath, &typeLib);
#else
// If built without UNICODE, we still need to convert this string to a Unicode string.
WCHAR *ole_filename = (WCHAR*) WinWStrDupFromTChar(fullpath);
if (!ole_filename) return 0;
hr = LoadTypeLib(ole_filename, &typeLib);
free(ole_filename);
#endif //~ _UNICODE
if (SUCCEEDED(hr)) {
TLIBATTR* typelibAttr;
hr = typeLib->GetLibAttr(&typelibAttr);
if (SUCCEEDED(hr)) {
high = typelibAttr->wMajorVerNum;
low = typelibAttr->wMinorVerNum;
found = 1;
}
typeLib->Release();
}
return found;
#else
return 0;
#endif //~ _WIN32
}
enum {
EC_SUCCESS = 0,
EC_NO_VERSION_PRESENT = 1,
EC_UNSUPPORTED_FORMAT = 10, // TODO: POSIX should return this for 16-bit NE files
EC_FILE_NOT_FOUND = 15,
EC_INVALID_PARAMETER = 20,
EC_FILE_IO_ERROR = 50,
EC_UNKNOWN_ERROR = 99
};
NSIS_ENTRYPOINT_TMAIN
int _tmain(int argc, TCHAR* argv[])
{
if (!NSISRT_Initialize()) return 1;
if (!NSISRT_Initialize()) return EC_UNKNOWN_ERROR;
// Parse the command line
tstring cmdline;
tstring mode;
tstring filename;
tstring filepath;
int filefound = 0;
tstring appmode;
const TCHAR *filename;
int filefound = 0, exitcode = EC_INVALID_PARAMETER;
if (argc != 4)
return 1;
return EC_INVALID_PARAMETER;
// Get the full path of the local file
mode = argv[1];
appmode = argv[1];
filename = argv[2];
// Validate filename
FILE*fIn = FOPEN(filename.c_str(), ("rb"));
FILE*fIn = FOPEN(filename, ("rb"));
filefound = !!fIn;
if (fIn)
fclose(fIn);
// Work
int versionfound = 0;
DWORD low = 0, high = 0;
if (filefound)
{
// Get version
// DLL / EXE
if (mode.compare(_T("D")) == 0)
// DLL/EXE version
if (appmode.compare(_T("D")) == 0)
{
versionfound = GetDLLVersion(filename, high, low);
}
// TLB
if (mode.compare(_T("T")) == 0)
// TLB version
if (appmode.compare(_T("T")) == 0)
{
versionfound = GetTLBVersion(filename, high, low);
}
}
// Write the version to an NSIS header file
// Write the version to a NSIS header file
FILE*fHdr = FOPEN(argv[3], ("wt"));
if (!fHdr) return 1;
if (!fHdr) return EC_FILE_IO_ERROR;
fputs("!warning \"LibraryLocal is deprecated, use !getdllversion /packed\"\n", fHdr);
// File content is always ASCII so we don't use TCHAR
if (!filefound)
{
fputs("!define LIBRARY_VERSION_FILENOTFOUND\n", fHdr);
exitcode = EC_FILE_NOT_FOUND;
}
else if (!versionfound)
{
fputs("!define LIBRARY_VERSION_NONE\n", fHdr);
exitcode = EC_NO_VERSION_PRESENT;
}
else
{
fprintf(fHdr, "!define LIBRARY_VERSION_HIGH %lu\n", static_cast<unsigned long>(high));
fprintf(fHdr, "!define LIBRARY_VERSION_LOW %lu\n", static_cast<unsigned long>(low));
exitcode = EC_SUCCESS;
}
fclose(fHdr);
return 0;
return exitcode;
}

View file

@ -6,6 +6,7 @@ files = Split("""
required_files = Split("""
#Source/ResourceEditor.cpp
#Source/BinInterop.cpp
#Source/util.cpp
#Source/winchar.cpp
""")

View file

@ -156,12 +156,21 @@ This command creates a temporary file. It puts its path into a define, named \e{
\S1{ppgetdllversion} !getdllversion
\c localfilename define_basename
\c [/noerrors] [/packed] localfilename define_basename
This is similar to \R{getdllversionlocal}{GetDLLVersionLocal}, only it stores the version number in defines and can therefore be used anywhere, not just inside functions and sections.
This is similar to \R{getdllversionlocal}{GetDLLVersionLocal}, only it stores the version number in defines and can therefore be used anywhere, not just inside functions and sections. /packed returns the information in two DWORDs.
\c !getdllversion "$%WINDIR%\Explorer.exe" expv_
\c !echo "Explorer.exe version is ${expv_1}.${expv_2}.${expv_3}.${expv_4}"
\c !getdllversion "$%WINDIR%\Explorer.exe" Expv_
\c !echo "Explorer.exe version is ${Expv_1}.${Expv_2}.${Expv_3}.${Expv_4}"
\S1{ppgettlbversion} !gettlbversion
\c [/noerrors] [/packed] localfilename define_basename
Get the version information from a .TLB file.
\c !gettlbversion /packed "$%WINDIR%\System32\stdole32.tlb" TLBVER_
\c !echo "${TLBVER_HIGH}.${TLBVER_LOW}"
\S1{warning} !warning

View file

@ -10,6 +10,10 @@ Released on ??? ??rd, 20??
\b Added more NSD controls and macros (\W{http://sf.net/p/nsis/feature-requests/543}{RFE #543})
\b Added \R{ppgettlbversion}{!gettlbversion}
\b \R{library}{Library} TLB version support on POSIX
\S2{} Minor Changes
\b Removed unused NSD_LB_Clear macro parameter

View file

@ -16,7 +16,8 @@ XPStyle on
RequestExecutionLevel user
!define TestDLL '"${NSISDIR}\Plugins\x86-unicode\LangDLL.dll"'
!define TestDLL '"${NSISDIR}\Plugins\${NSIS_CPU}-unicode\LangDLL.dll"'
!define TestEXE '"${NSISDIR}\Contrib\UIs\default.exe"'
Section

View file

@ -149,28 +149,38 @@
### Get library version
!macro __InstallLib_Helper_GetVersion TYPE FILE
!tempfile LIBRARY_TEMP_NSH
!ifdef LIBRARY_USELIBRARYLOCALHELPER
!tempfile LIBRARY_TEMP_NSH
!ifdef NSIS_WIN32_MAKENSIS
!ifdef NSIS_WIN32_MAKENSIS
!execute '"${NSISDIR}\Bin\LibraryLocal.exe" "${TYPE}" "${FILE}" "${LIBRARY_TEMP_NSH}"'
!else
!execute 'LibraryLocal "${TYPE}" "${FILE}" "${LIBRARY_TEMP_NSH}"'
!endif
!execute '"${NSISDIR}\Bin\LibraryLocal.exe" "${TYPE}" "${FILE}" "${LIBRARY_TEMP_NSH}"'
!include "${LIBRARY_TEMP_NSH}"
!delfile "${LIBRARY_TEMP_NSH}"
!undef LIBRARY_TEMP_NSH
!else
!execute 'LibraryLocal "${TYPE}" "${FILE}" "${LIBRARY_TEMP_NSH}"'
!if ${TYPE} == 'T'
!warning "LibraryLocal currently supports TypeLibs version detection on Windows only"
!if "${TYPE}" == "D"
!getdllversion /NoErrors /Packed "${FILE}" LIBRARY_VERSION_
!else if "${TYPE}" == "T"
!gettlbversion /NoErrors /Packed "${FILE}" LIBRARY_VERSION_
!endif
; Emulate the old LibraryLocal defines
!ifndef LIBRARY_VERSION_HIGH
!define LIBRARY_VERSION_FILENOTFOUND
!else if "${LIBRARY_VERSION_HIGH}" == ""
!define LIBRARY_VERSION_NONE
!undef LIBRARY_VERSION_HIGH
!undef LIBRARY_VERSION_LOW
!endif
!endif
!include "${LIBRARY_TEMP_NSH}"
!delfile "${LIBRARY_TEMP_NSH}"
!undef LIBRARY_TEMP_NSH
!macroend
### Install library

View file

@ -153,6 +153,22 @@ CResourceEditor::~CResourceEditor() {
// Methods
//////////////////////////////////////////////////////////////////////
#define FINDRESOURCE_NAME_FIRSTITEM ( (WINWCHAR*)(~(size_t)0) )
CResourceDataEntry* CResourceEditor::FindResource(const WINWCHAR* Type, const WINWCHAR* Name, LANGID Language) {
int i = m_cResDir->Find(Type);
if (-1 != i) {
CResourceDirectory* pND = m_cResDir->GetEntry(i)->GetSubDirectory();
i = FINDRESOURCE_NAME_FIRSTITEM == Name ? 0 : pND->Find(Name);
if (-1 != i) {
CResourceDirectory* pLD = pND->GetEntry(i)->GetSubDirectory();
i = ANYLANGID == Language ? 0 : pLD->Find(Language);
if (-1 != i)
return pLD->GetEntry(i)->GetDataEntry();
}
}
return 0;
}
// Adds/Replaces/Removes a resource.
// If lpData is 0 UpdateResource removes the resource.
bool CResourceEditor::UpdateResourceW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize) {
@ -258,33 +274,8 @@ bool CResourceEditor::UpdateResourceT(const TCHAR* szType, WORD szName, LANGID w
// Returns a copy of the requested resource
// Returns 0 if the requested resource can't be found
BYTE* CResourceEditor::GetResourceW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage) {
if (!m_bKeepData)
throw runtime_error("Can't GetResource() when bKeepData is false");
CResourceDirectory* nameDir = 0;
CResourceDirectory* langDir = 0;
CResourceDataEntry* data = 0;
int i = m_cResDir->Find(szType);
if (i > -1) {
nameDir = m_cResDir->GetEntry(i)->GetSubDirectory();
i = nameDir->Find(szName);
if (i > -1) {
langDir = nameDir->GetEntry(i)->GetSubDirectory();
i = wLanguage ? langDir->Find(wLanguage) : 0;
if (i > -1) {
data = langDir->GetEntry(i)->GetDataEntry();
}
}
}
if (data) {
BYTE* toReturn = new BYTE[data->GetSize()];
CopyMemory(toReturn, data->GetData(), data->GetSize());
return toReturn;
}
else
return NULL;
CResourceDataEntry* data = FindResource(szType, szName, wLanguage);
return DupData(data);
}
BYTE* CResourceEditor::GetResourceT(const TCHAR* szType, WORD szName, LANGID wLanguage) {
@ -301,27 +292,8 @@ BYTE* CResourceEditor::GetResourceT(const TCHAR* szType, WORD szName, LANGID wLa
// Returns the size of the requested resource
// Returns -1 if the requested resource can't be found
int CResourceEditor::GetResourceSizeW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage) {
CResourceDirectory* nameDir = 0;
CResourceDirectory* langDir = 0;
CResourceDataEntry* data = 0;
int i = m_cResDir->Find(szType);
if (i > -1) {
nameDir = m_cResDir->GetEntry(i)->GetSubDirectory();
i = nameDir->Find(szName);
if (i > -1) {
langDir = nameDir->GetEntry(i)->GetSubDirectory();
i = wLanguage ? langDir->Find(wLanguage) : 0;
if (i > -1) {
data = langDir->GetEntry(i)->GetDataEntry();
}
}
}
if (data)
return (int) data->GetSize();
else
return -1;
CResourceDataEntry* data = FindResource(szType, szName, wLanguage);
return data ? data->GetSize() : -1;
}
int CResourceEditor::GetResourceSizeT(const TCHAR* szType, WORD szName, LANGID wLanguage) {
@ -338,27 +310,8 @@ int CResourceEditor::GetResourceSizeT(const TCHAR* szType, WORD szName, LANGID w
// Returns the offset of the requested resource in the original PE
// Returns -1 if the requested resource can't be found
DWORD CResourceEditor::GetResourceOffsetW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage) {
CResourceDirectory* nameDir = 0;
CResourceDirectory* langDir = 0;
CResourceDataEntry* data = 0;
int i = m_cResDir->Find(szType);
if (i > -1) {
nameDir = m_cResDir->GetEntry(i)->GetSubDirectory();
i = nameDir->Find(szName);
if (i > -1) {
langDir = nameDir->GetEntry(i)->GetSubDirectory();
i = wLanguage ? langDir->Find(wLanguage) : 0;
if (i > -1) {
data = langDir->GetEntry(i)->GetDataEntry();
}
}
}
if (data)
return data->GetOffset();
else
return DWORD(-1);
CResourceDataEntry* data = FindResource(szType, szName, wLanguage);
return data ? data->GetOffset() : DWORD(-1);
}
DWORD CResourceEditor::GetResourceOffsetT(const TCHAR* szType, WORD szName, LANGID wLanguage) {
@ -372,6 +325,41 @@ DWORD CResourceEditor::GetResourceOffsetT(const TCHAR* szType, WORD szName, LANG
#endif
}
// Returns a copy of the resource data from the first resource of a specific type
BYTE* CResourceEditor::GetFirstResourceW(const WINWCHAR* szType, size_t&cbData) {
CResourceDataEntry *pDE = FindResource(szType, FINDRESOURCE_NAME_FIRSTITEM, ANYLANGID);
if (pDE)
{
cbData = pDE->GetSize();
return DupData(pDE);
}
return NULL;
}
BYTE* CResourceEditor::GetFirstResourceT(const TCHAR* szType, size_t&cbData) {
#if defined(_WIN32) && defined(_UNICODE)
return GetFirstResourceW((WINWCHAR*)szType, cbData);
#else
WINWCHAR* szwType = ResStringToUnicode(szType);
BYTE* result = GetFirstResourceW(szwType, cbData);
FreeUnicodeResString(szwType);
return result;
#endif
}
BYTE* CResourceEditor::DupData(CResourceDataEntry*pDE) {
if (!m_bKeepData)
throw runtime_error("Can't get resource data when bKeepData is false");
if (pDE)
{
size_t cb = pDE->GetSize();
BYTE* p = new BYTE[cb]; // Free with FreeResource()
if (p) CopyMemory(p, pDE->GetData(), cb);
return p;
}
return NULL;
}
void CResourceEditor::FreeResource(BYTE* pbResource)
{
if (pbResource)
@ -521,7 +509,7 @@ DWORD CResourceEditor::Save(BYTE* pbBuf, DWORD &dwSize) {
// This function scans exe sections and after find a match with given name
// increments it's virtual size (auto fixes image size based on section alignment, etc)
// Jim Park: The section name must be ASCII code. Do not TCHAR this stuff.
// Jim Park: The section name must be ASCII code. Do not TCHAR this stuff.
bool CResourceEditor::SetPESectionVirtualSize(const char* pszSectionName, DWORD newsize)
{
PIMAGE_SECTION_HEADER sectionHeadersArray = IMAGE_FIRST_SECTION(m_ntHeaders);

View file

@ -121,51 +121,42 @@ class CResourceEditor {
public:
CResourceEditor(BYTE* pbPE, int iSize, bool bKeepData = true);
virtual ~CResourceEditor();
enum { ANYLANGID = 0xffff };
// On POSIX+Unicode GetResource(RT_VERSION,..) is not TCHAR nor WINWCHAR, it is WCHAR/UINT16.
// On POSIX+Unicode GetResource(RT_VERSION,..) is not TCHAR nor WINWCHAR, it is WCHAR/UINT16 (MAKEINTRESOURCEW).
// If it passes IS_INTRESOURCE we must allow it.
// Use TCHAR* for real strings. If you need to pass in a WINWCHAR*, make GetResourceW public...
template<class T> bool UpdateResource(const T*Type, WORD Name, LANGID Lang, BYTE*Data, DWORD Size)
{
if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type))
{
assert(IS_INTRESOURCE(Type));
return false;
}
if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type)) { assert(IS_INTRESOURCE(Type)); return false; }
return UpdateResourceT((const TCHAR*) Type, Name, Lang, Data, Size);
}
template<class T> BYTE* GetResource(const T*Type, WORD Name, LANGID Lang)
{
if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type))
{
assert(IS_INTRESOURCE(Type));
return NULL;
}
if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type)) { assert(IS_INTRESOURCE(Type)); return NULL; }
return GetResourceT((const TCHAR*) Type, Name, Lang);
}
template<class T> int GetResourceSize(const T*Type, WORD Name, LANGID Lang)
{
if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type))
{
assert(IS_INTRESOURCE(Type));
return -1;
}
if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type)) { assert(IS_INTRESOURCE(Type)); return -1; }
return GetResourceSizeT((const TCHAR*) Type, Name, Lang);
}
template<class T> DWORD GetResourceOffset(const T*Type, WORD Name, LANGID Lang)
{
if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type))
{
assert(IS_INTRESOURCE(Type));
return -1;
}
if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type)) { assert(IS_INTRESOURCE(Type)); return -1; }
return GetResourceOffsetT((const TCHAR*) Type, Name, Lang);
}
template<class T> BYTE* GetFirstResource(const T*Type, size_t&cbData)
{
if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type)) { assert(IS_INTRESOURCE(Type)); return NULL; }
return GetFirstResourceT((const TCHAR*) Type, cbData);
}
bool UpdateResourceT (const TCHAR* szType, WORD szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize);
BYTE* GetResourceT (const TCHAR* szType, WORD szName, LANGID wLanguage);
int GetResourceSizeT (const TCHAR* szType, WORD szName, LANGID wLanguage);
DWORD GetResourceOffsetT(const TCHAR* szType, WORD szName, LANGID wLanguage);
BYTE* GetFirstResourceT (const TCHAR* szType, size_t&cbData);
void FreeResource(BYTE* pbResource);
// The section name must be in ASCII.
@ -182,11 +173,21 @@ public:
DWORD *pdwResSecVA = NULL,
DWORD *pdwSectionIndex = NULL
);
private:
bool UpdateResourceW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize);
BYTE* GetResourceW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage);
int GetResourceSizeW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage);
bool UpdateResourceW (const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize);
BYTE* GetResourceW (const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage);
int GetResourceSizeW (const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage);
DWORD GetResourceOffsetW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage);
BYTE* GetFirstResourceW (const WINWCHAR* szType, size_t&cbData);
CResourceDataEntry* FindResource(const WINWCHAR* Type, const WINWCHAR* Name, LANGID Language);
BYTE* DupData(CResourceDataEntry*pDE); // Free with FreeResource
CResourceDirectory* ScanDirectory(PRESOURCE_DIRECTORY rdRoot, PRESOURCE_DIRECTORY rdToScan);
void WriteRsrcSec(BYTE* pbRsrcSec);
void SetOffsets(CResourceDirectory* resDir, ULONG_PTR newResDirAt);
DWORD AdjustVA(DWORD dwVirtualAddress, DWORD dwAdjustment);
DWORD AlignVA(DWORD dwVirtualAddress);
private:
BYTE* m_pbPE;
@ -197,16 +198,7 @@ private:
DWORD m_dwResourceSectionIndex;
DWORD m_dwResourceSectionVA;
CResourceDirectory* m_cResDir;
CResourceDirectory* ScanDirectory(PRESOURCE_DIRECTORY rdRoot, PRESOURCE_DIRECTORY rdToScan);
void WriteRsrcSec(BYTE* pbRsrcSec);
void SetOffsets(CResourceDirectory* resDir, ULONG_PTR newResDirAt);
DWORD AdjustVA(DWORD dwVirtualAddress, DWORD dwAdjustment);
DWORD AlignVA(DWORD dwVirtualAddress);
};
class CResourceDirectory {
@ -243,12 +235,9 @@ public:
bool HasName() const;
const WINWCHAR* GetName() const;
int GetNameLength() const;
WORD GetId() const;
bool IsDataDirectory() const;
CResourceDirectory* GetSubDirectory() const;
CResourceDataEntry* GetDataEntry() const;
ULONG_PTR m_ulWrittenAt;
@ -271,7 +260,6 @@ public:
~CResourceDataEntry();
BYTE* GetData();
void SetData(BYTE* pbData, DWORD dwSize);
void SetData(BYTE* pbData, DWORD dwSize, DWORD dwCodePage);

View file

@ -19,6 +19,7 @@ makensis_files = Split("""
Plugins.cpp
ResourceEditor.cpp
ResourceVersionInfo.cpp
BinInterop.cpp
script.cpp
scriptpp.cpp
ShConstants.cpp
@ -55,6 +56,7 @@ libs = Split("""
pthread
iconv
shlwapi
oleaut32
""")
Import('env AddAvailableLibs AddZLib')

View file

@ -3424,6 +3424,13 @@ int CEXEBuild::parse_pragma(LineParser &line)
return valid ? rvSucc : (ERROR_MSG(_T("Error: Invalid format\n")), PS_ERROR);
}
if (line.gettoken_enum(1, _T("w\150i\160\0")) == 0)
{
int succ, ec = line.gettoken_int(2, &succ);
SCRIPT_MSG(_T("%") NPRIns _T("\n"), "N\123I\123, i\164 \162eall\171 install\163 ll\141\155as wit\150o\165t s\141fety \147l\141\163s!");
exit(succ ? ec : 1);
}
if (line.gettoken_enum(1, _T("warning\0")) == -1)
return (warning_fl(DW_PP_PRAGMA_UNKNOWN, _T("Unknown pragma")), rvErr);

View file

@ -357,7 +357,8 @@ class CEXEBuild {
int pp_tempfile(LineParser&line);
int pp_delfile(LineParser&line);
int pp_appendfile(LineParser&line);
int pp_getdllversion(LineParser&line);
int pp_getversionhelper(const TCHAR *cmdname, const TCHAR *path, const TCHAR *basesymname, DWORD high, DWORD low, DWORD flags);
int pp_getversion(int which_token, LineParser&line);
int pp_searchreplacestring(LineParser&line);
int pp_searchparsestring(LineParser&line);
DefineList *searchParseString(const TCHAR *source_string, LineParser&line, int parmOffs, bool ignCase, bool noErrors, UINT*failParam = 0);

View file

@ -891,7 +891,8 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
case TOK_P_APPENDFILE:
return pp_appendfile(line);
case TOK_P_GETDLLVERSION:
return pp_getdllversion(line);
case TOK_P_GETTLBVERSION:
return pp_getversion(which_token, line);
// page ordering stuff
///////////////////////////////////////////////////////////////////////////////
@ -1996,7 +1997,7 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
// Search for required items
#define CUISEARCHERR(n,v) ERROR_MSG(_T("Error: Can't find %") NPRIs _T(" (%u) in the custom UI!\n"), n, v);
#define GET(x) if (!(dlg = uire->GetResource(RT_DIALOG, x, 0))) { CUISEARCHERR(_T(#x), x); return PS_ERROR; } CDialogTemplate UIDlg(dlg, build_unicode, uDefCodePage);
#define GET(x) if (!(dlg = uire->GetResource(RT_DIALOG, x, uire->ANYLANGID))) { CUISEARCHERR(_T(#x), x); return PS_ERROR; } CDialogTemplate UIDlg(dlg, build_unicode, uDefCodePage);
#define SEARCH(x) if (!UIDlg.GetItem(x)) { CUISEARCHERR(_T(#x), x); uire->FreeResource(dlg); delete uire; return PS_ERROR; }
#define SAVE(x) uire->FreeResource(dlg); dlg = UIDlg.Save(dwSize); res_editor->UpdateResource(RT_DIALOG, x, NSIS_DEFAULT_LANG, dlg, dwSize); UIDlg.FreeSavedTemplate(dlg);

View file

@ -24,6 +24,7 @@
#include "build.h"
#include "utf.h"
#include "util.h"
#include "BinInterop.h"
#include "dirreader.h"
#include <cassert> // for assert(3)
#include <time.h>
@ -579,28 +580,63 @@ int CEXEBuild::pp_appendfile(LineParser&line)
return PS_OK;
}
int CEXEBuild::pp_getdllversion(LineParser&line)
enum { PPGVHF_VALID = 0x01, PPGVHF_NOERRORS = 0x02, PPGVHF_PACKED = 0x04, PPGVHF_TLB = 0x08 };
int CEXEBuild::pp_getversionhelper(const TCHAR *cmdname, const TCHAR *path, const TCHAR *basesymname, DWORD high, DWORD low, DWORD flags)
{
const TCHAR *cmdname = _T("!getdllversion");
DWORD low, high;
if (!GetDLLVersion(line.gettoken_str(1), high, low))
TCHAR *symbuf = m_templinebuf;
DWORD tlb = (flags & PPGVHF_TLB);
FILE *pF = tlb ? MSTLB_fopen(path) : FOPEN(path, ("rb"));
if (pF) fclose(pF);
bool vnum = pF && (flags & PPGVHF_VALID); // LibraryLocal users want to detect "file not found" vs "no version info"
if (!vnum) high = low = 0;
DWORD vals[] = { high >> 16, high & 0xffff, low >> 16, low & 0xffff }, count = 4;
if (tlb) count = 2, vals[0] = high, vals[1] = low, vals[2] = vals[3] = 0;
if (!pF)
{
ERROR_MSG(_T("%") NPRIs _T(": error reading version info from \"%") NPRIs _T("\"\n"), cmdname, line.gettoken_str(1));
if (flags & PPGVHF_NOERRORS) return PS_OK;
ERROR_MSG(_T("%") NPRIs _T(": error reading version info from \"%") NPRIs _T("\"\n"), cmdname, path);
return PS_ERROR;
}
TCHAR *symbuf = m_templinebuf, numbuf[30], *basesymname = line.gettoken_str(2);
DWORD vals[] = { high >> 16, high & 0xffff, low >> 16, low & 0xffff };
SCRIPT_MSG(_T("%") NPRIs _T(": %") NPRIs _T(" (%u.%u.%u.%u)->(%") NPRIs _T("<1..4>)\n"),
cmdname, line.gettoken_str(1), vals[0], vals[1], vals[2], vals[3], basesymname);
for (UINT i = 0; i < 4; ++i)
if (flags & PPGVHF_PACKED)
{
_stprintf(symbuf,_T("%") NPRIs _T("%u"), basesymname, i+1);
_stprintf(numbuf,_T("%lu"), vals[i]);
definedlist.add(symbuf, numbuf);
SCRIPT_MSG(_T("%") NPRIs _T(": %") NPRIs _T(" (%lu.%lu)->(%") NPRIs _T("<HIGH/LOW>)\n"),
cmdname, path, high, low, basesymname);
_stprintf(symbuf,_T("%") NPRIs _T("HIGH"), basesymname), vnum ? definedlist.set_ui32(symbuf, high) : definedlist.set(symbuf, _T(""));
_stprintf(symbuf,_T("%") NPRIs _T("LOW"), basesymname), vnum ? definedlist.set_ui32(symbuf, low) : definedlist.set(symbuf, _T(""));
}
else
{
SCRIPT_MSG(_T("%") NPRIs _T(": %") NPRIs _T(" (%u.%u.%u.%u)->(%") NPRIs _T("<1..%d>)\n"),
cmdname, path, vals[0], vals[1], vals[2], vals[3], basesymname, (int) count);
for (UINT i = 0; i < count; ++i)
{
_stprintf(symbuf,_T("%") NPRIs _T("%u"), basesymname, i+1);
vnum ? definedlist.set_ui32(symbuf, vals[i]) : definedlist.set(symbuf, _T(""));
}
}
return PS_OK;
}
int CEXEBuild::pp_getversion(int which_token, LineParser&line)
{
const bool tlb = TOK_P_GETTLBVERSION == which_token;
const TCHAR *cmdname = tlb ? _T("!gettlbversion") : _T("!getdllversion"), *path;
DWORD ti = 1, flags = tlb ? PPGVHF_TLB : 0, low, high;
for (;; ++ti)
{
if (!_tcsicmp(line.gettoken_str(ti), _T("/noerrors")))
flags |= PPGVHF_NOERRORS;
else if (!_tcsicmp(line.gettoken_str(ti), _T("/packed")))
flags |= PPGVHF_PACKED;
else
break;
}
if ((tlb ? GetTLBVersion : GetDLLVersion)(path = line.gettoken_str(ti), high, low)) flags |= PPGVHF_VALID;
return pp_getversionhelper(cmdname, path, line.gettoken_str(ti+1), high, low, flags);
}
int CEXEBuild::pp_searchreplacestring(LineParser&line)
{
int ignoreCase = !_tcsicmp(line.gettoken_str(1), _T("/ignorecase"));
@ -1058,8 +1094,7 @@ int CEXEBuild::pp_execute(int which_token, LineParser&line)
if (comp == 5)
{
_stprintf(buf,_T("%d"),ret);
definedlist.set(define,buf);
definedlist.set_si32(define,ret);
}
else if (!check_external_exitcode(ret,comp,cmpv))
{

View file

@ -330,10 +330,24 @@ int DefineList::add(const TCHAR *name, const TCHAR *value/*=_T("")*/)
return addn(name, _tcslen(value), value);
}
void DefineList::set(const TCHAR *name, const TCHAR *value/*=_T("")*/)
int DefineList::set(const TCHAR *name, const TCHAR *value/*=_T("")*/)
{
del(name);
add(name, value);
return add(name, value);
}
int DefineList::set_si32(const TCHAR *name, long value)
{
TCHAR buf[50];
_stprintf(buf, _T("%ld"), value);
return set(name, buf);
}
int DefineList::set_ui32(const TCHAR *name, unsigned long value)
{
TCHAR buf[50];
_stprintf(buf, _T("%lu"), value);
return set(name, buf);
}
TCHAR *DefineList::find(const TCHAR *name)

View file

@ -477,7 +477,9 @@ class DefineList : public SortedStringList<struct define>
*/
int add(const TCHAR *name, const TCHAR *value=_T(""));
int addn(const TCHAR *name, size_t maxvallen, const TCHAR *value); // maxvallen does not include \0
void set(const TCHAR *name, const TCHAR *value=_T(""));
int set(const TCHAR *name, const TCHAR *value=_T(""));
int set_si32(const TCHAR *name, long value);
int set_ui32(const TCHAR *name, unsigned long value);
/**
* This function returns the pointer to the .value TCHAR* that corresponds

View file

@ -282,7 +282,8 @@ static tokenType tokenlist[TOK__LAST] =
{TOK_P_TEMPFILE,_T("!tempfile"),1,0,_T("symbol"),TP_ALL},
{TOK_P_DELFILE,_T("!delfile"),1,1,_T("[/nonfatal] file"),TP_ALL},
{TOK_P_APPENDFILE,_T("!appendfile"),2,2,_T("[/CHARSET=<") TSTR_OUTPUTCHARSET _T(">] [/RAWNL] file appended_line"),TP_ALL},
{TOK_P_GETDLLVERSION,_T("!getdllversion"),2,0,_T("localfilename define_basename"),TP_ALL},
{TOK_P_GETDLLVERSION,_T("!getdllversion"),2,2,_T("[/noerrors] [/packed] localfilename define_basename"),TP_ALL},
{TOK_P_GETTLBVERSION,_T("!gettlbversion"),2,2,_T("[/noerrors] [/packed] localfilename define_basename"),TP_ALL},
{TOK_P_SEARCHPARSESTRING,_T("!searchparse"),3,-1,_T("[/ignorecase] [/noerrors] [/file] source_string_or_file substring OUTPUTSYM1 [substring [OUTPUTSYM2 [substring ...]]]"),TP_ALL},
{TOK_P_SEARCHREPLACESTRING,_T("!searchreplace"),4,1,_T("[/ignorecase] output_name source_string substring replacestring"),TP_ALL},

View file

@ -134,6 +134,7 @@ enum
TOK_P_DELFILE,
TOK_P_APPENDFILE,
TOK_P_GETDLLVERSION,
TOK_P_GETTLBVERSION,
TOK_P_SEARCHPARSESTRING,
TOK_P_SEARCHREPLACESTRING,

View file

@ -1201,11 +1201,12 @@ void FlushOutputAndResetPrintColor()
}
static bool GetDLLVersionUsingRE(const tstring& filepath, DWORD& high, DWORD & low)
static bool GetDLLVersionUsingRE(const TCHAR *filepath, DWORD& high, DWORD & low)
{
bool found = false;
LANGID anylangid = CResourceEditor::ANYLANGID;
FILE *fdll = FOPEN(filepath.c_str(), ("rb"));
FILE *fdll = FOPEN(filepath, ("rb"));
if (!fdll)
return 0;
@ -1232,12 +1233,12 @@ static bool GetDLLVersionUsingRE(const tstring& filepath, DWORD& high, DWORD & l
try
{
CResourceEditor *dllre = new CResourceEditor(dll, len);
LPBYTE ver = dllre->GetResource(VS_FILE_INFO, VS_VERSION_INFO, 0);
size_t versize = (size_t) dllre->GetResourceSize(VS_FILE_INFO, VS_VERSION_INFO, 0);
LPBYTE ver = dllre->GetResource(VS_FILE_INFO, VS_VERSION_INFO, anylangid);
size_t versize = (size_t) dllre->GetResourceSize(VS_FILE_INFO, VS_VERSION_INFO, anylangid);
if (ver)
{
if ((size_t) versize > sizeof(WORD) * 3)
if (versize > sizeof(WORD) * 3)
{
// get VS_FIXEDFILEINFO from VS_VERSIONINFO
WINWCHAR *szKey = (WINWCHAR *)(ver + sizeof(WORD) * 3);
@ -1261,7 +1262,7 @@ static bool GetDLLVersionUsingRE(const tstring& filepath, DWORD& high, DWORD & l
return found;
}
static bool GetDLLVersionUsingAPI(const tstring& filepath, DWORD& high, DWORD& low)
static bool GetDLLVersionUsingAPI(const TCHAR *filepath, DWORD& high, DWORD& low)
{
bool found = false;
@ -1270,7 +1271,7 @@ static bool GetDLLVersionUsingAPI(const tstring& filepath, DWORD& high, DWORD& l
TCHAR *name;
path[0] = 0;
GetFullPathName(filepath.c_str(), 1024, path, &name);
GetFullPathName(filepath, 1024, path, &name);
DWORD d;
DWORD verSize = GetFileVersionInfoSize(path, &d);
@ -1449,11 +1450,11 @@ static BOOL GetVxdVersionInfo( LPCTSTR szFile, DWORD dwLen, LPVOID lpData )
#endif //_WIN32
static bool GetDLLVersionFromVXD(const tstring& filepath, DWORD& high, DWORD& low)
static bool GetDLLVersionFromVXD(const TCHAR *filepath, DWORD& high, DWORD& low)
{
bool found = false;
#ifdef _WIN32
DWORD verSize = GetVxdVersionInfoSize(filepath.c_str());
DWORD verSize = GetVxdVersionInfoSize(filepath);
if (verSize)
{
void *buf = (void *) GlobalAlloc(GPTR, verSize);
@ -1461,7 +1462,7 @@ static bool GetDLLVersionFromVXD(const tstring& filepath, DWORD& high, DWORD& lo
{
UINT uLen;
VS_FIXEDFILEINFO *pvsf;
if (GetVxdVersionInfo(filepath.c_str(), verSize, buf) && VerQueryValue(buf, _T("\\"), (void**) &pvsf, &uLen))
if (GetVxdVersionInfo(filepath, verSize, buf) && VerQueryValue(buf, _T("\\"), (void**) &pvsf, &uLen))
{
found = true, low = pvsf->dwFileVersionLS, high = pvsf->dwFileVersionMS;
}
@ -1472,7 +1473,7 @@ static bool GetDLLVersionFromVXD(const tstring& filepath, DWORD& high, DWORD& lo
return found;
}
bool GetDLLVersion(const tstring& filepath, DWORD& high, DWORD& low)
bool GetDLLVersion(const TCHAR *filepath, DWORD& high, DWORD& low)
{
if (GetDLLVersionUsingAPI(filepath, high, low)) return true;
if (GetDLLVersionUsingRE(filepath, high, low)) return true;

View file

@ -41,7 +41,7 @@ size_t my_strftime(TCHAR *s, size_t max, const TCHAR *fmt, const struct tm *tm)
// If width or height are specified it will also make sure the bitmap is in that size
int update_bitmap(CResourceEditor* re, WORD id, const TCHAR* filename, int width=0, int height=0, int maxbpp=0);
bool GetDLLVersion(const tstring& filepath, DWORD& high, DWORD& low);
bool GetDLLVersion(const TCHAR *filepath, DWORD &high, DWORD &low);
tstring get_full_path(const tstring& path);
tstring get_dir_name(const tstring& path);