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 LibraryLocal - used by the Library.nsh macros
Get the version of local DLL and TLB files Get the version of local DLL and TLB files
Written by Joost Verburg 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 <iostream>
#include <fstream> #include <fstream>
#include "../../../Source/BinInterop.h"
#include "../../../Source/util.h" #include "../../../Source/util.h"
#include "../../../Source/winchar.h" #include "../../../Source/winchar.h"
@ -22,139 +25,79 @@ using namespace std;
int g_noconfig=0; // TODO: Not used? int g_noconfig=0; // TODO: Not used?
NSISRT_DEFINEGLOBALS(); NSISRT_DEFINEGLOBALS();
int GetTLBVersion(tstring& filepath, DWORD& high, DWORD & low) enum {
{ EC_SUCCESS = 0,
#ifdef _WIN32 EC_NO_VERSION_PRESENT = 1,
EC_UNSUPPORTED_FORMAT = 10, // TODO: POSIX should return this for 16-bit NE files
int found = 0; EC_FILE_NOT_FOUND = 15,
EC_INVALID_PARAMETER = 20,
TCHAR fullpath[1024]; EC_FILE_IO_ERROR = 50,
TCHAR *p; EC_UNKNOWN_ERROR = 99
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
}
NSIS_ENTRYPOINT_TMAIN NSIS_ENTRYPOINT_TMAIN
int _tmain(int argc, TCHAR* argv[]) int _tmain(int argc, TCHAR* argv[])
{ {
if (!NSISRT_Initialize()) return 1; if (!NSISRT_Initialize()) return EC_UNKNOWN_ERROR;
// Parse the command line tstring appmode;
const TCHAR *filename;
tstring cmdline; int filefound = 0, exitcode = EC_INVALID_PARAMETER;
tstring mode;
tstring filename;
tstring filepath;
int filefound = 0;
if (argc != 4) if (argc != 4)
return 1; return EC_INVALID_PARAMETER;
// Get the full path of the local file appmode = argv[1];
mode = argv[1];
filename = argv[2]; filename = argv[2];
// Validate filename // Validate filename
FILE*fIn = FOPEN(filename, ("rb"));
FILE*fIn = FOPEN(filename.c_str(), ("rb"));
filefound = !!fIn; filefound = !!fIn;
if (fIn) if (fIn)
fclose(fIn); fclose(fIn);
// Work
int versionfound = 0; int versionfound = 0;
DWORD low = 0, high = 0; DWORD low = 0, high = 0;
if (filefound) if (filefound)
{ {
// DLL/EXE version
// Get version if (appmode.compare(_T("D")) == 0)
// DLL / EXE
if (mode.compare(_T("D")) == 0)
{ {
versionfound = GetDLLVersion(filename, high, low); versionfound = GetDLLVersion(filename, high, low);
} }
// TLB // TLB version
if (appmode.compare(_T("T")) == 0)
if (mode.compare(_T("T")) == 0)
{ {
versionfound = GetTLBVersion(filename, high, low); 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")); 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 // File content is always ASCII so we don't use TCHAR
if (!filefound) if (!filefound)
{ {
fputs("!define LIBRARY_VERSION_FILENOTFOUND\n", fHdr); fputs("!define LIBRARY_VERSION_FILENOTFOUND\n", fHdr);
exitcode = EC_FILE_NOT_FOUND;
} }
else if (!versionfound) else if (!versionfound)
{ {
fputs("!define LIBRARY_VERSION_NONE\n", fHdr); fputs("!define LIBRARY_VERSION_NONE\n", fHdr);
exitcode = EC_NO_VERSION_PRESENT;
} }
else else
{ {
fprintf(fHdr, "!define LIBRARY_VERSION_HIGH %lu\n", static_cast<unsigned long>(high)); 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)); fprintf(fHdr, "!define LIBRARY_VERSION_LOW %lu\n", static_cast<unsigned long>(low));
exitcode = EC_SUCCESS;
} }
fclose(fHdr); fclose(fHdr);
return 0; return exitcode;
} }

View file

@ -6,6 +6,7 @@ files = Split("""
required_files = Split(""" required_files = Split("""
#Source/ResourceEditor.cpp #Source/ResourceEditor.cpp
#Source/BinInterop.cpp
#Source/util.cpp #Source/util.cpp
#Source/winchar.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 \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 !getdllversion "$%WINDIR%\Explorer.exe" Expv_
\c !echo "Explorer.exe version is ${expv_1}.${expv_2}.${expv_3}.${expv_4}" \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 \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 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 \S2{} Minor Changes
\b Removed unused NSD_LB_Clear macro parameter \b Removed unused NSD_LB_Clear macro parameter

View file

@ -16,7 +16,8 @@ XPStyle on
RequestExecutionLevel user 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"' !define TestEXE '"${NSISDIR}\Contrib\UIs\default.exe"'
Section Section

View file

@ -149,28 +149,38 @@
### Get library version ### Get library version
!macro __InstallLib_Helper_GetVersion TYPE FILE !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 !else
!execute 'LibraryLocal "${TYPE}" "${FILE}" "${LIBRARY_TEMP_NSH}"' !if "${TYPE}" == "D"
!getdllversion /NoErrors /Packed "${FILE}" LIBRARY_VERSION_
!if ${TYPE} == 'T' !else if "${TYPE}" == "T"
!gettlbversion /NoErrors /Packed "${FILE}" LIBRARY_VERSION_
!warning "LibraryLocal currently supports TypeLibs version detection on Windows only" !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
!endif !endif
!include "${LIBRARY_TEMP_NSH}"
!delfile "${LIBRARY_TEMP_NSH}"
!undef LIBRARY_TEMP_NSH
!macroend !macroend
### Install library ### Install library

View file

@ -153,6 +153,22 @@ CResourceEditor::~CResourceEditor() {
// Methods // 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. // Adds/Replaces/Removes a resource.
// If lpData is 0 UpdateResource removes the resource. // If lpData is 0 UpdateResource removes the resource.
bool CResourceEditor::UpdateResourceW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize) { 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 a copy of the requested resource
// Returns 0 if the requested resource can't be found // Returns 0 if the requested resource can't be found
BYTE* CResourceEditor::GetResourceW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage) { BYTE* CResourceEditor::GetResourceW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage) {
if (!m_bKeepData) CResourceDataEntry* data = FindResource(szType, szName, wLanguage);
throw runtime_error("Can't GetResource() when bKeepData is false"); return DupData(data);
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;
} }
BYTE* CResourceEditor::GetResourceT(const TCHAR* szType, WORD szName, LANGID wLanguage) { 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 the size of the requested resource
// Returns -1 if the requested resource can't be found // Returns -1 if the requested resource can't be found
int CResourceEditor::GetResourceSizeW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage) { int CResourceEditor::GetResourceSizeW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage) {
CResourceDirectory* nameDir = 0; CResourceDataEntry* data = FindResource(szType, szName, wLanguage);
CResourceDirectory* langDir = 0; return data ? data->GetSize() : -1;
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;
} }
int CResourceEditor::GetResourceSizeT(const TCHAR* szType, WORD szName, LANGID wLanguage) { 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 the offset of the requested resource in the original PE
// Returns -1 if the requested resource can't be found // Returns -1 if the requested resource can't be found
DWORD CResourceEditor::GetResourceOffsetW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage) { DWORD CResourceEditor::GetResourceOffsetW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage) {
CResourceDirectory* nameDir = 0; CResourceDataEntry* data = FindResource(szType, szName, wLanguage);
CResourceDirectory* langDir = 0; return data ? data->GetOffset() : DWORD(-1);
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);
} }
DWORD CResourceEditor::GetResourceOffsetT(const TCHAR* szType, WORD szName, LANGID wLanguage) { DWORD CResourceEditor::GetResourceOffsetT(const TCHAR* szType, WORD szName, LANGID wLanguage) {
@ -372,6 +325,41 @@ DWORD CResourceEditor::GetResourceOffsetT(const TCHAR* szType, WORD szName, LANG
#endif #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) void CResourceEditor::FreeResource(BYTE* pbResource)
{ {
if (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 // 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) // 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) bool CResourceEditor::SetPESectionVirtualSize(const char* pszSectionName, DWORD newsize)
{ {
PIMAGE_SECTION_HEADER sectionHeadersArray = IMAGE_FIRST_SECTION(m_ntHeaders); PIMAGE_SECTION_HEADER sectionHeadersArray = IMAGE_FIRST_SECTION(m_ntHeaders);

View file

@ -121,51 +121,42 @@ class CResourceEditor {
public: public:
CResourceEditor(BYTE* pbPE, int iSize, bool bKeepData = true); CResourceEditor(BYTE* pbPE, int iSize, bool bKeepData = true);
virtual ~CResourceEditor(); 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. // 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... // 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) template<class T> bool UpdateResource(const T*Type, WORD Name, LANGID Lang, BYTE*Data, DWORD Size)
{ {
if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type)) if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type)) { assert(IS_INTRESOURCE(Type)); return false; }
{
assert(IS_INTRESOURCE(Type));
return false;
}
return UpdateResourceT((const TCHAR*) Type, Name, Lang, Data, Size); return UpdateResourceT((const TCHAR*) Type, Name, Lang, Data, Size);
} }
template<class T> BYTE* GetResource(const T*Type, WORD Name, LANGID Lang) template<class T> BYTE* GetResource(const T*Type, WORD Name, LANGID Lang)
{ {
if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type)) if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type)) { assert(IS_INTRESOURCE(Type)); return NULL; }
{
assert(IS_INTRESOURCE(Type));
return NULL;
}
return GetResourceT((const TCHAR*) Type, Name, Lang); return GetResourceT((const TCHAR*) Type, Name, Lang);
} }
template<class T> int GetResourceSize(const T*Type, WORD Name, LANGID Lang) template<class T> int GetResourceSize(const T*Type, WORD Name, LANGID Lang)
{ {
if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type)) if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type)) { assert(IS_INTRESOURCE(Type)); return -1; }
{
assert(IS_INTRESOURCE(Type));
return -1;
}
return GetResourceSizeT((const TCHAR*) Type, Name, Lang); return GetResourceSizeT((const TCHAR*) Type, Name, Lang);
} }
template<class T> DWORD GetResourceOffset(const T*Type, WORD Name, LANGID Lang) template<class T> DWORD GetResourceOffset(const T*Type, WORD Name, LANGID Lang)
{ {
if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type)) if (sizeof(T) != sizeof(TCHAR) && !IS_INTRESOURCE(Type)) { assert(IS_INTRESOURCE(Type)); return -1; }
{
assert(IS_INTRESOURCE(Type));
return -1;
}
return GetResourceOffsetT((const TCHAR*) Type, Name, Lang); 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); bool UpdateResourceT (const TCHAR* szType, WORD szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize);
BYTE* GetResourceT (const TCHAR* szType, WORD szName, LANGID wLanguage); BYTE* GetResourceT (const TCHAR* szType, WORD szName, LANGID wLanguage);
int GetResourceSizeT (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); DWORD GetResourceOffsetT(const TCHAR* szType, WORD szName, LANGID wLanguage);
BYTE* GetFirstResourceT (const TCHAR* szType, size_t&cbData);
void FreeResource(BYTE* pbResource); void FreeResource(BYTE* pbResource);
// The section name must be in ASCII. // The section name must be in ASCII.
@ -182,11 +173,21 @@ public:
DWORD *pdwResSecVA = NULL, DWORD *pdwResSecVA = NULL,
DWORD *pdwSectionIndex = NULL DWORD *pdwSectionIndex = NULL
); );
private: private:
bool UpdateResourceW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize); bool UpdateResourceW (const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage, BYTE* lpData, DWORD dwSize);
BYTE* GetResourceW(const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage); BYTE* GetResourceW (const WINWCHAR* szType, WINWCHAR* szName, LANGID wLanguage);
int GetResourceSizeW(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); 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: private:
BYTE* m_pbPE; BYTE* m_pbPE;
@ -197,16 +198,7 @@ private:
DWORD m_dwResourceSectionIndex; DWORD m_dwResourceSectionIndex;
DWORD m_dwResourceSectionVA; DWORD m_dwResourceSectionVA;
CResourceDirectory* m_cResDir; 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 { class CResourceDirectory {
@ -243,12 +235,9 @@ public:
bool HasName() const; bool HasName() const;
const WINWCHAR* GetName() const; const WINWCHAR* GetName() const;
int GetNameLength() const; int GetNameLength() const;
WORD GetId() const; WORD GetId() const;
bool IsDataDirectory() const; bool IsDataDirectory() const;
CResourceDirectory* GetSubDirectory() const; CResourceDirectory* GetSubDirectory() const;
CResourceDataEntry* GetDataEntry() const; CResourceDataEntry* GetDataEntry() const;
ULONG_PTR m_ulWrittenAt; ULONG_PTR m_ulWrittenAt;
@ -271,7 +260,6 @@ public:
~CResourceDataEntry(); ~CResourceDataEntry();
BYTE* GetData(); BYTE* GetData();
void SetData(BYTE* pbData, DWORD dwSize); void SetData(BYTE* pbData, DWORD dwSize);
void SetData(BYTE* pbData, DWORD dwSize, DWORD dwCodePage); void SetData(BYTE* pbData, DWORD dwSize, DWORD dwCodePage);

View file

@ -19,6 +19,7 @@ makensis_files = Split("""
Plugins.cpp Plugins.cpp
ResourceEditor.cpp ResourceEditor.cpp
ResourceVersionInfo.cpp ResourceVersionInfo.cpp
BinInterop.cpp
script.cpp script.cpp
scriptpp.cpp scriptpp.cpp
ShConstants.cpp ShConstants.cpp
@ -55,6 +56,7 @@ libs = Split("""
pthread pthread
iconv iconv
shlwapi shlwapi
oleaut32
""") """)
Import('env AddAvailableLibs AddZLib') 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); 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) if (line.gettoken_enum(1, _T("warning\0")) == -1)
return (warning_fl(DW_PP_PRAGMA_UNKNOWN, _T("Unknown pragma")), rvErr); 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_tempfile(LineParser&line);
int pp_delfile(LineParser&line); int pp_delfile(LineParser&line);
int pp_appendfile(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_searchreplacestring(LineParser&line);
int pp_searchparsestring(LineParser&line); int pp_searchparsestring(LineParser&line);
DefineList *searchParseString(const TCHAR *source_string, LineParser&line, int parmOffs, bool ignCase, bool noErrors, UINT*failParam = 0); 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: case TOK_P_APPENDFILE:
return pp_appendfile(line); return pp_appendfile(line);
case TOK_P_GETDLLVERSION: case TOK_P_GETDLLVERSION:
return pp_getdllversion(line); case TOK_P_GETTLBVERSION:
return pp_getversion(which_token, line);
// page ordering stuff // page ordering stuff
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -1996,7 +1997,7 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
// Search for required items // 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 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 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); #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 "build.h"
#include "utf.h" #include "utf.h"
#include "util.h" #include "util.h"
#include "BinInterop.h"
#include "dirreader.h" #include "dirreader.h"
#include <cassert> // for assert(3) #include <cassert> // for assert(3)
#include <time.h> #include <time.h>
@ -579,28 +580,63 @@ int CEXEBuild::pp_appendfile(LineParser&line)
return PS_OK; 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"); TCHAR *symbuf = m_templinebuf;
DWORD low, high; DWORD tlb = (flags & PPGVHF_TLB);
if (!GetDLLVersion(line.gettoken_str(1), high, low)) 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; return PS_ERROR;
} }
TCHAR *symbuf = m_templinebuf, numbuf[30], *basesymname = line.gettoken_str(2);
DWORD vals[] = { high >> 16, high & 0xffff, low >> 16, low & 0xffff }; if (flags & PPGVHF_PACKED)
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)
{ {
_stprintf(symbuf,_T("%") NPRIs _T("%u"), basesymname, i+1); SCRIPT_MSG(_T("%") NPRIs _T(": %") NPRIs _T(" (%lu.%lu)->(%") NPRIs _T("<HIGH/LOW>)\n"),
_stprintf(numbuf,_T("%lu"), vals[i]); cmdname, path, high, low, basesymname);
definedlist.add(symbuf, numbuf); _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; 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 CEXEBuild::pp_searchreplacestring(LineParser&line)
{ {
int ignoreCase = !_tcsicmp(line.gettoken_str(1), _T("/ignorecase")); 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) if (comp == 5)
{ {
_stprintf(buf,_T("%d"),ret); definedlist.set_si32(define,ret);
definedlist.set(define,buf);
} }
else if (!check_external_exitcode(ret,comp,cmpv)) 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); 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); 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) 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 add(const TCHAR *name, const TCHAR *value=_T(""));
int addn(const TCHAR *name, size_t maxvallen, const TCHAR *value); // maxvallen does not include \0 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 * 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_TEMPFILE,_T("!tempfile"),1,0,_T("symbol"),TP_ALL},
{TOK_P_DELFILE,_T("!delfile"),1,1,_T("[/nonfatal] file"),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_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_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}, {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_DELFILE,
TOK_P_APPENDFILE, TOK_P_APPENDFILE,
TOK_P_GETDLLVERSION, TOK_P_GETDLLVERSION,
TOK_P_GETTLBVERSION,
TOK_P_SEARCHPARSESTRING, TOK_P_SEARCHPARSESTRING,
TOK_P_SEARCHREPLACESTRING, 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; bool found = false;
LANGID anylangid = CResourceEditor::ANYLANGID;
FILE *fdll = FOPEN(filepath.c_str(), ("rb")); FILE *fdll = FOPEN(filepath, ("rb"));
if (!fdll) if (!fdll)
return 0; return 0;
@ -1232,12 +1233,12 @@ static bool GetDLLVersionUsingRE(const tstring& filepath, DWORD& high, DWORD & l
try try
{ {
CResourceEditor *dllre = new CResourceEditor(dll, len); CResourceEditor *dllre = new CResourceEditor(dll, len);
LPBYTE ver = dllre->GetResource(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, 0); size_t versize = (size_t) dllre->GetResourceSize(VS_FILE_INFO, VS_VERSION_INFO, anylangid);
if (ver) if (ver)
{ {
if ((size_t) versize > sizeof(WORD) * 3) if (versize > sizeof(WORD) * 3)
{ {
// get VS_FIXEDFILEINFO from VS_VERSIONINFO // get VS_FIXEDFILEINFO from VS_VERSIONINFO
WINWCHAR *szKey = (WINWCHAR *)(ver + sizeof(WORD) * 3); WINWCHAR *szKey = (WINWCHAR *)(ver + sizeof(WORD) * 3);
@ -1261,7 +1262,7 @@ static bool GetDLLVersionUsingRE(const tstring& filepath, DWORD& high, DWORD & l
return found; 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; bool found = false;
@ -1270,7 +1271,7 @@ static bool GetDLLVersionUsingAPI(const tstring& filepath, DWORD& high, DWORD& l
TCHAR *name; TCHAR *name;
path[0] = 0; path[0] = 0;
GetFullPathName(filepath.c_str(), 1024, path, &name); GetFullPathName(filepath, 1024, path, &name);
DWORD d; DWORD d;
DWORD verSize = GetFileVersionInfoSize(path, &d); DWORD verSize = GetFileVersionInfoSize(path, &d);
@ -1449,11 +1450,11 @@ static BOOL GetVxdVersionInfo( LPCTSTR szFile, DWORD dwLen, LPVOID lpData )
#endif //_WIN32 #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; bool found = false;
#ifdef _WIN32 #ifdef _WIN32
DWORD verSize = GetVxdVersionInfoSize(filepath.c_str()); DWORD verSize = GetVxdVersionInfoSize(filepath);
if (verSize) if (verSize)
{ {
void *buf = (void *) GlobalAlloc(GPTR, verSize); void *buf = (void *) GlobalAlloc(GPTR, verSize);
@ -1461,7 +1462,7 @@ static bool GetDLLVersionFromVXD(const tstring& filepath, DWORD& high, DWORD& lo
{ {
UINT uLen; UINT uLen;
VS_FIXEDFILEINFO *pvsf; 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; found = true, low = pvsf->dwFileVersionLS, high = pvsf->dwFileVersionMS;
} }
@ -1472,7 +1473,7 @@ static bool GetDLLVersionFromVXD(const tstring& filepath, DWORD& high, DWORD& lo
return found; 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 (GetDLLVersionUsingAPI(filepath, high, low)) return true;
if (GetDLLVersionUsingRE(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 // 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); 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_full_path(const tstring& path);
tstring get_dir_name(const tstring& path); tstring get_dir_name(const tstring& path);