From a51d89712c33f89e36b376af32f57739a392460b Mon Sep 17 00:00:00 2001 From: anders_k Date: Tue, 3 Oct 2017 20:48:29 +0000 Subject: [PATCH] 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 --- Contrib/Library/LibraryLocal/LibraryLocal.cpp | 121 +++++------------ Contrib/Library/LibraryLocal/SConscript | 1 + Docs/src/compiler.but | 17 ++- Docs/src/history.but | 4 + Examples/Library.nsi | 3 +- Include/Library.nsh | 34 +++-- Source/ResourceEditor.cpp | 128 ++++++++---------- Source/ResourceEditor.h | 62 ++++----- Source/SConscript | 2 + Source/build.cpp | 7 + Source/build.h | 3 +- Source/script.cpp | 5 +- Source/scriptpp.cpp | 65 +++++++-- Source/strlist.cpp | 18 ++- Source/strlist.h | 4 +- Source/tokens.cpp | 3 +- Source/tokens.h | 1 + Source/util.cpp | 23 ++-- Source/util.h | 2 +- 19 files changed, 256 insertions(+), 247 deletions(-) diff --git a/Contrib/Library/LibraryLocal/LibraryLocal.cpp b/Contrib/Library/LibraryLocal/LibraryLocal.cpp index 1151a15a..d7847fe1 100644 --- a/Contrib/Library/LibraryLocal/LibraryLocal.cpp +++ b/Contrib/Library/LibraryLocal/LibraryLocal.cpp @@ -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 #include +#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(high)); fprintf(fHdr, "!define LIBRARY_VERSION_LOW %lu\n", static_cast(low)); + exitcode = EC_SUCCESS; } fclose(fHdr); - return 0; - + return exitcode; } diff --git a/Contrib/Library/LibraryLocal/SConscript b/Contrib/Library/LibraryLocal/SConscript index c2e732e4..cb315d60 100644 --- a/Contrib/Library/LibraryLocal/SConscript +++ b/Contrib/Library/LibraryLocal/SConscript @@ -6,6 +6,7 @@ files = Split(""" required_files = Split(""" #Source/ResourceEditor.cpp + #Source/BinInterop.cpp #Source/util.cpp #Source/winchar.cpp """) diff --git a/Docs/src/compiler.but b/Docs/src/compiler.but index a8be1423..9f7376d7 100644 --- a/Docs/src/compiler.but +++ b/Docs/src/compiler.but @@ -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 diff --git a/Docs/src/history.but b/Docs/src/history.but index ffef1332..41ba8bcc 100644 --- a/Docs/src/history.but +++ b/Docs/src/history.but @@ -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 diff --git a/Examples/Library.nsi b/Examples/Library.nsi index 974f4b9a..cffc973f 100644 --- a/Examples/Library.nsi +++ b/Examples/Library.nsi @@ -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 diff --git a/Include/Library.nsh b/Include/Library.nsh index ba554819..1d886563 100644 --- a/Include/Library.nsh +++ b/Include/Library.nsh @@ -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 diff --git a/Source/ResourceEditor.cpp b/Source/ResourceEditor.cpp index 1b28a4e3..b34ece63 100644 --- a/Source/ResourceEditor.cpp +++ b/Source/ResourceEditor.cpp @@ -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); diff --git a/Source/ResourceEditor.h b/Source/ResourceEditor.h index 23d809f9..4afaf0d9 100644 --- a/Source/ResourceEditor.h +++ b/Source/ResourceEditor.h @@ -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 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 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 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 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 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); diff --git a/Source/SConscript b/Source/SConscript index 75b75274..ffd6c7d0 100644 --- a/Source/SConscript +++ b/Source/SConscript @@ -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') diff --git a/Source/build.cpp b/Source/build.cpp index 59ecdf05..bd0c2f30 100644 --- a/Source/build.cpp +++ b/Source/build.cpp @@ -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); diff --git a/Source/build.h b/Source/build.h index b706d1bf..cb4853db 100644 --- a/Source/build.h +++ b/Source/build.h @@ -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); diff --git a/Source/script.cpp b/Source/script.cpp index 5944cde9..febcad9e 100644 --- a/Source/script.cpp +++ b/Source/script.cpp @@ -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); diff --git a/Source/scriptpp.cpp b/Source/scriptpp.cpp index 76742948..c6d36374 100644 --- a/Source/scriptpp.cpp +++ b/Source/scriptpp.cpp @@ -24,6 +24,7 @@ #include "build.h" #include "utf.h" #include "util.h" +#include "BinInterop.h" #include "dirreader.h" #include // for assert(3) #include @@ -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(")\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)) { diff --git a/Source/strlist.cpp b/Source/strlist.cpp index 4ef75450..8b3547ed 100644 --- a/Source/strlist.cpp +++ b/Source/strlist.cpp @@ -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) diff --git a/Source/strlist.h b/Source/strlist.h index 85f60817..72c5b148 100644 --- a/Source/strlist.h +++ b/Source/strlist.h @@ -477,7 +477,9 @@ class DefineList : public SortedStringList */ 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 diff --git a/Source/tokens.cpp b/Source/tokens.cpp index 32c25b00..6df45be4 100644 --- a/Source/tokens.cpp +++ b/Source/tokens.cpp @@ -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}, diff --git a/Source/tokens.h b/Source/tokens.h index 92b7e457..697add25 100644 --- a/Source/tokens.h +++ b/Source/tokens.h @@ -134,6 +134,7 @@ enum TOK_P_DELFILE, TOK_P_APPENDFILE, TOK_P_GETDLLVERSION, + TOK_P_GETTLBVERSION, TOK_P_SEARCHPARSESTRING, TOK_P_SEARCHREPLACESTRING, diff --git a/Source/util.cpp b/Source/util.cpp index 83be1ffc..f205a385 100644 --- a/Source/util.cpp +++ b/Source/util.cpp @@ -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; diff --git a/Source/util.h b/Source/util.h index 1ecde3f2..3879e67b 100644 --- a/Source/util.h +++ b/Source/util.h @@ -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);