Allow makensis to use stubs and plugins of different bitness, based on patch #265

git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6619 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
anders_k 2015-10-01 17:32:56 +00:00
parent 8577c8e9ae
commit 12cab3f3db
8 changed files with 91 additions and 65 deletions

View file

@ -846,7 +846,7 @@ typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY,*PIMAGE_DATA_DIRECTORY;
typedef struct _IMAGE_OPTIONAL_HEADER {
typedef struct _IMAGE_OPTIONAL_HEADER32 {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
@ -911,25 +911,34 @@ typedef struct _IMAGE_OPTIONAL_HEADER64 {
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64,*PIMAGE_OPTIONAL_HEADER64;
typedef struct _IMAGE_NT_HEADERS32 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32,*PIMAGE_NT_HEADERS32;
typedef struct _IMAGE_NT_HEADERS64 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64,*PIMAGE_NT_HEADERS64;
#ifdef _WIN64
typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER;
typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER;
typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS;
typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS;
#else
typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER;
typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER;
typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER;
typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS;
typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS;
#endif
#ifndef __BIG_ENDIAN__
# define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
# define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
# define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x010b
# define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x020b
#else
# define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x0b01
# define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x0b02
#endif
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER OptionalHeader;
} IMAGE_NT_HEADERS,*PIMAGE_NT_HEADERS;
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
union {

View file

@ -86,7 +86,7 @@ static inline void PrintCommandSig(const tstring sig)
_ftprintf(g_output, _T(" + %") NPRIs _T("\n"), sig.c_str());
}
void Plugins::AddPluginsDir(const tstring &path, bool displayInfo)
void Plugins::AddPluginsDir(const tstring &path, bool pe64, bool displayInfo)
{
boost::scoped_ptr<dir_reader> dr( new_dir_reader() );
dr->read(path);
@ -99,7 +99,7 @@ void Plugins::AddPluginsDir(const tstring &path, bool displayInfo)
continue;
const tstring plugin = path + PLATFORM_PATH_SEPARATOR_C + *files_itr;
GetExports(plugin, displayInfo);
GetExports(plugin, pe64, displayInfo);
}
}
@ -136,38 +136,45 @@ void read_file(const tstring& filename, vector<unsigned char>& data)
}
}
void Plugins::GetExports(const tstring &pathToDll, bool displayInfo)
void Plugins::GetExports(const tstring &pathToDll, bool pe64, bool displayInfo)
{
vector<unsigned char> dlldata;
PIMAGE_NT_HEADERS NTHeaders;
PIMAGE_NT_HEADERS pNTHdrs;
try {
read_file(pathToDll, dlldata);
if (dlldata.empty()) return;
NTHeaders = CResourceEditor::GetNTHeaders(&dlldata[0]);
pNTHdrs = CResourceEditor::GetNTHeaders(&dlldata[0]);
} catch (std::runtime_error&) {
return;
}
const WORD reqohm = pe64 ? IMAGE_NT_OPTIONAL_HDR64_MAGIC : IMAGE_NT_OPTIONAL_HDR32_MAGIC;
if (*GetCommonMemberFromPEOptHdr(pNTHdrs->OptionalHeader, Magic) != reqohm)
{
// Ignore DLLs that don't match our target
return;
}
tstring dllName = remove_file_extension(get_file_name(pathToDll));
if (DllHasDataHandle(dllName))
{
m_dllname_conflicts.insert(dllName);
}
FIX_ENDIAN_INT16_INPLACE(NTHeaders->FileHeader.Characteristics);
if (NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL)
FIX_ENDIAN_INT16_INPLACE(pNTHdrs->FileHeader.Characteristics);
if (pNTHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL)
{
FIX_ENDIAN_INT32_INPLACE(NTHeaders->OptionalHeader.NumberOfRvaAndSizes);
if (NTHeaders->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_EXPORT) return;
DWORD numrvaandsiz = *GetMemberFromPEOptHdr(pNTHdrs->OptionalHeader, NumberOfRvaAndSizes);
FIX_ENDIAN_INT32_INPLACE(numrvaandsiz);
if (numrvaandsiz <= IMAGE_DIRECTORY_ENTRY_EXPORT) return;
DWORD ExportDirVA = NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
DWORD ExportDirSize = NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
PIMAGE_SECTION_HEADER sections = IMAGE_FIRST_SECTION(NTHeaders);
const IMAGE_DATA_DIRECTORY *pExportDir;
pExportDir = &(*GetMemberFromPEOptHdr(pNTHdrs->OptionalHeader, DataDirectory))[IMAGE_DIRECTORY_ENTRY_EXPORT];
const DWORD ExportDirVA = FIX_ENDIAN_INT32(pExportDir->VirtualAddress);
const DWORD ExportDirSize = FIX_ENDIAN_INT32(pExportDir->Size);
FIX_ENDIAN_INT32_INPLACE(ExportDirVA);
FIX_ENDIAN_INT32_INPLACE(ExportDirSize);
WORD num_sections = FIX_ENDIAN_INT16(NTHeaders->FileHeader.NumberOfSections);
PIMAGE_SECTION_HEADER sections = IMAGE_FIRST_SECTION(pNTHdrs);
const WORD num_sections = FIX_ENDIAN_INT16(pNTHdrs->FileHeader.NumberOfSections);
for (DWORD i = 0; i < num_sections; i++)
{
@ -223,12 +230,12 @@ bool Plugins::DllHasDataHandle(const tstring& dllnamelowercase) const
return -1 != h;
}
bool Plugins::Initialize(const TCHAR*arcsubdir, bool displayInfo)
bool Plugins::Initialize(const TCHAR*arcsubdir, bool pe64, bool displayInfo)
{
if (m_initialized) return true;
m_initialized = true;
AddPluginsDir(tstring(arcsubdir), displayInfo);
AddPluginsDir(tstring(arcsubdir), pe64, displayInfo);
return true;
}

View file

@ -48,8 +48,8 @@ class Plugins
Plugins() : m_initialized(false) {}
bool Initialize(const TCHAR*arcsubdir, bool displayInfo);
void AddPluginsDir(const tstring& path, bool displayInfo);
bool Initialize(const TCHAR*arcsubdir, bool pe64, bool displayInfo);
void AddPluginsDir(const tstring& path, bool pe64, bool displayInfo);
bool FindDllPath(const tstring filename, tstring&dllPath);
bool IsPluginCommand(const tstring& command) const;
bool IsKnownPlugin(const tstring& token) const;
@ -59,7 +59,7 @@ class Plugins
static bool IsPluginCallSyntax(const tstring& token);
private: // methods
void GetExports(const tstring &pathToDll, bool displayInfo);
void GetExports(const tstring &pathToDll, bool pe64, bool displayInfo);
bool DllHasDataHandle(const tstring& dllnamelowercase) const;
private: // data members

View file

@ -52,8 +52,8 @@ PIMAGE_NT_HEADERS CResourceEditor::GetNTHeaders(BYTE* pbPE) {
throw runtime_error("PE file missing NT signature");
// Make sure this is a supported PE format
if (ntHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
ntHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
const WORD ohm = *GetCommonMemberFromPEOptHdr(ntHeaders->OptionalHeader, Magic);
if (ohm != IMAGE_NT_OPTIONAL_HDR32_MAGIC && ohm != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
throw runtime_error("Unsupported PE format");
return ntHeaders;
@ -66,8 +66,8 @@ PRESOURCE_DIRECTORY CResourceEditor::GetResourceDirectory(
DWORD *pdwResSecVA /*=NULL*/,
DWORD *pdwSectionIndex /*=NULL*/
) {
PIMAGE_DATA_DIRECTORY dataDirectory = *GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, DataDirectory);
DWORD dwNumberOfRvaAndSizes = *GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, NumberOfRvaAndSizes);
PIMAGE_DATA_DIRECTORY dataDirectory = *GetMemberFromPEOptHdr(ntHeaders->OptionalHeader, DataDirectory);
DWORD dwNumberOfRvaAndSizes = *GetMemberFromPEOptHdr(ntHeaders->OptionalHeader, NumberOfRvaAndSizes);
if (ConvertEndianness(dwNumberOfRvaAndSizes) <= IMAGE_DIRECTORY_ENTRY_RESOURCE)
throw runtime_error("No resource section found");
@ -130,7 +130,7 @@ CResourceEditor::CResourceEditor(BYTE* pbPE, int iSize, bool bKeepData /*=true*/
m_ntHeaders = GetNTHeaders(m_pbPE);
// No check sum support yet...
DWORD* pdwCheckSum = GetMemberFromOptionalHeader(m_ntHeaders->OptionalHeader, CheckSum);
DWORD* pdwCheckSum = GetCommonMemberFromPEOptHdr(m_ntHeaders->OptionalHeader, CheckSum);
if (*pdwCheckSum)
{
// clear checksum (should be [re]calculated after all changes done)
@ -384,10 +384,12 @@ DWORD CResourceEditor::Save(BYTE* pbBuf, DWORD &dwSize) {
throw runtime_error("Can't Save() when bKeepData is false");
unsigned int i;
DWORD dwReqSize;
DWORD dwReqSize, temp32;
DWORD dwFileAlign = ConvertEndianness(m_ntHeaders->OptionalHeader.FileAlignment);
DWORD dwSecAlign = ConvertEndianness(m_ntHeaders->OptionalHeader.SectionAlignment);
temp32 = *GetCommonMemberFromPEOptHdr(m_ntHeaders->OptionalHeader, FileAlignment);
const DWORD dwFileAlign = ConvertEndianness(temp32);
temp32 = *GetCommonMemberFromPEOptHdr(m_ntHeaders->OptionalHeader, SectionAlignment);
const DWORD dwSecAlign = ConvertEndianness(temp32);
DWORD dwRsrcSize = m_cResDir->GetSize(); // Size of new resource section
DWORD dwRsrcSizeAligned = RALIGN(dwRsrcSize, dwFileAlign); // Align it to FileAlignment
@ -440,36 +442,36 @@ DWORD CResourceEditor::Save(BYTE* pbBuf, DWORD &dwSize) {
sectionHeadersArray[m_dwResourceSectionIndex].SizeOfRawData = ConvertEndianness(dwRsrcSizeAligned);
// Set the virtual size as well (in memory)
sectionHeadersArray[m_dwResourceSectionIndex].Misc.VirtualSize = ConvertEndianness(dwRsrcSize);
(*GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, DataDirectory))[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = ConvertEndianness(dwRsrcSize);
(*GetMemberFromPEOptHdr(ntHeaders->OptionalHeader, DataDirectory))[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = ConvertEndianness(dwRsrcSize);
// Set the new virtual size of the image
DWORD* pdwSizeOfImage = GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, SizeOfImage);
*pdwSizeOfImage = AlignVA(*GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, SizeOfHeaders));
DWORD* pdwSizeOfImage = GetCommonMemberFromPEOptHdr(ntHeaders->OptionalHeader, SizeOfImage);
*pdwSizeOfImage = AlignVA(*GetCommonMemberFromPEOptHdr(ntHeaders->OptionalHeader, SizeOfHeaders));
for (i = 0; i < wNumberOfSections; i++) {
DWORD dwSecSize = ConvertEndianness(sectionHeadersArray[i].Misc.VirtualSize);
*pdwSizeOfImage = AlignVA(AdjustVA(*pdwSizeOfImage, dwSecSize));
}
// Set the new AddressOfEntryPoint if needed
DWORD* pdwAddressOfEntryPoint = GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, AddressOfEntryPoint);
DWORD* pdwAddressOfEntryPoint = GetCommonMemberFromPEOptHdr(ntHeaders->OptionalHeader, AddressOfEntryPoint);
if (ConvertEndianness(*pdwAddressOfEntryPoint) > m_dwResourceSectionVA)
*pdwAddressOfEntryPoint = AdjustVA(*pdwAddressOfEntryPoint, dwVAAdjustment);
// Set the new BaseOfCode if needed
DWORD* pdwBaseOfCode = GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, BaseOfCode);
DWORD* pdwBaseOfCode = GetCommonMemberFromPEOptHdr(ntHeaders->OptionalHeader, BaseOfCode);
if (ConvertEndianness(*pdwBaseOfCode) > m_dwResourceSectionVA)
*pdwBaseOfCode = AdjustVA(*pdwBaseOfCode, dwVAAdjustment);
// Set the new BaseOfData if needed
if (ntHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
if (*GetCommonMemberFromPEOptHdr(ntHeaders->OptionalHeader, Magic) == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
DWORD* pdwBaseOfData = &((PIMAGE_OPTIONAL_HEADER32)&ntHeaders->OptionalHeader)->BaseOfData;
if (ConvertEndianness(*pdwBaseOfData) > m_dwResourceSectionVA)
*pdwBaseOfData = AdjustVA(*pdwBaseOfData, dwVAAdjustment);
}
// Refresh the headers of the sections that come after the resource section, and the data directory
DWORD dwNumberOfRvaAndSizes = *GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, NumberOfRvaAndSizes);
PIMAGE_DATA_DIRECTORY pDataDirectory = *GetMemberFromOptionalHeader(ntHeaders->OptionalHeader, DataDirectory);
DWORD dwNumberOfRvaAndSizes = *GetMemberFromPEOptHdr(ntHeaders->OptionalHeader, NumberOfRvaAndSizes);
PIMAGE_DATA_DIRECTORY pDataDirectory = *GetMemberFromPEOptHdr(ntHeaders->OptionalHeader, DataDirectory);
for (i = m_dwResourceSectionIndex + 1; i < wNumberOfSections; i++) {
if (sectionHeadersArray[i].PointerToRawData) {
AdjustVA(sectionHeadersArray[i].PointerToRawData, dwRsrcSizeAligned - dwOldRsrcSize);
@ -542,7 +544,7 @@ bool CResourceEditor::SetPESectionVirtualSize(const char* pszSectionName, DWORD
if (m_dwResourceSectionIndex == (DWORD) k)
{
// fix the resources virtual address if it changed
PIMAGE_DATA_DIRECTORY pDataDirectory = *GetMemberFromOptionalHeader(m_ntHeaders->OptionalHeader, DataDirectory);
PIMAGE_DATA_DIRECTORY pDataDirectory = *GetMemberFromPEOptHdr(m_ntHeaders->OptionalHeader, DataDirectory);
pDataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = dwSecVA;
m_dwResourceSectionVA = ConvertEndianness(dwSecVA);
}
@ -768,8 +770,8 @@ DWORD CResourceEditor::AdjustVA(DWORD dwVirtualAddress, DWORD dwAdjustment) {
// Aligns a virtual address to the section alignment
DWORD CResourceEditor::AlignVA(DWORD dwVirtualAddress) {
DWORD dwSectionAlignment = *GetMemberFromOptionalHeader(m_ntHeaders->OptionalHeader, SectionAlignment);
DWORD dwAlignment = ConvertEndianness(dwSectionAlignment);
DWORD temp32 = *GetCommonMemberFromPEOptHdr(m_ntHeaders->OptionalHeader, SectionAlignment);
DWORD dwAlignment = ConvertEndianness(temp32);
dwVirtualAddress = ConvertEndianness(dwVirtualAddress);
dwVirtualAddress = RALIGN(dwVirtualAddress, dwAlignment);

View file

@ -105,11 +105,18 @@ typedef struct RESOURCE_DIRECTORY {
MY_IMAGE_RESOURCE_DIRECTORY_ENTRY Entries[1];
} *PRESOURCE_DIRECTORY;
#define GetMemberFromOptionalHeader(optionalHeader, member) \
( (optionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) ? \
&((PIMAGE_OPTIONAL_HEADER32)&optionalHeader)->member : \
&((PIMAGE_OPTIONAL_HEADER64)&optionalHeader)->member \
)
#define GetCommonStructField(ref, s1, s2, fld) \
( (&((ref).fld))[(1 / ( 0 + !!(FIELD_OFFSET(s1, fld) == FIELD_OFFSET(s2, fld) && sizeof(((s1*)0)->fld) == sizeof(((s2*)0)->fld)) )) - 1] ) // Try to fail at compile-time if the field is not at the same offset in both structs or does not have the same size
#define GetCommonMemberFromPEOptHdr(OptHdr, Member) \
( &GetCommonStructField(OptHdr, IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Member) )
#define GetMemberFromPEOptHdrEx(OptHdr, Member, Sixtyfour) \
( (Sixtyfour) ? \
&((PIMAGE_OPTIONAL_HEADER64)&(OptHdr))->Member : \
&((PIMAGE_OPTIONAL_HEADER32)&(OptHdr))->Member \
)
#define GetMemberFromPEOptHdr(OptHdr, Member) \
( GetMemberFromPEOptHdrEx(OptHdr, Member, ((OptHdr).Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)) )
class CResourceEditor {
public:
CResourceEditor(BYTE* pbPE, int iSize, bool bKeepData = true);

View file

@ -2406,16 +2406,16 @@ int CEXEBuild::UpdatePEHeader()
try {
PIMAGE_NT_HEADERS headers = CResourceEditor::GetNTHeaders(m_exehead);
// workaround for bug #2697027, #2725883, #2803097
headers->OptionalHeader.MajorImageVersion = FIX_ENDIAN_INT16(6);
headers->OptionalHeader.MinorImageVersion = FIX_ENDIAN_INT16(0);
*GetCommonMemberFromPEOptHdr(headers->OptionalHeader, MajorImageVersion) = FIX_ENDIAN_INT16(6);
*GetCommonMemberFromPEOptHdr(headers->OptionalHeader, MinorImageVersion) = FIX_ENDIAN_INT16(0);
// Override SubsystemVersion?
if (PESubsysVerMaj != (WORD) -1)
{
headers->OptionalHeader.MajorSubsystemVersion = FIX_ENDIAN_INT16(PESubsysVerMaj);
headers->OptionalHeader.MinorSubsystemVersion = FIX_ENDIAN_INT16(PESubsysVerMin);
*GetCommonMemberFromPEOptHdr(headers->OptionalHeader, MajorSubsystemVersion) = FIX_ENDIAN_INT16(PESubsysVerMaj);
*GetCommonMemberFromPEOptHdr(headers->OptionalHeader, MinorSubsystemVersion) = FIX_ENDIAN_INT16(PESubsysVerMin);
}
// DllCharacteristics
headers->OptionalHeader.DllCharacteristics = FIX_ENDIAN_INT16(PEDllCharacteristics);
*GetCommonMemberFromPEOptHdr(headers->OptionalHeader, DllCharacteristics) = FIX_ENDIAN_INT16(PEDllCharacteristics);
} catch (std::runtime_error& err) {
ERROR_MSG(_T("Error updating PE headers: %") NPRIs _T("\n"), CtoTStrParam(err.what()));
return PS_ERROR;
@ -3542,7 +3542,7 @@ int CEXEBuild::initialize_default_plugins(bool newtargetarc)
searchPath += get_target_suffix();
SCRIPT_MSG(_T("Processing default plugins: \"%") NPRIs PLATFORM_PATH_SEPARATOR_STR _T("*.dll\"\n"), searchPath.c_str());
if (!m_pPlugins->Initialize(searchPath.c_str(), !!display_script))
if (!m_pPlugins->Initialize(searchPath.c_str(), is_target_64bit(), !!display_script))
{
ERROR_MSG(_T("Error initializing default plugins!\n"));
return PS_ERROR;

View file

@ -129,7 +129,8 @@ class CEXEBuild {
TARGETTYPE get_target_type(const TCHAR*s) const;
const TCHAR* get_target_suffix(CEXEBuild::TARGETTYPE tt, const TCHAR*defval = _T("?")) const;
const TCHAR* get_target_suffix() const {return get_target_suffix(m_target_type);}
bool is_target_64bit() const { return TARGET_AMD64 == m_target_type; }
static bool is_targettype_64bit(TARGETTYPE tt) { return TARGET_AMD64 == tt; }
bool is_target_64bit() const { return is_targettype_64bit(m_target_type); }
unsigned int get_header_size() const { return (unsigned int)sizeof(header) + (is_target_64bit() ? (4 * BLOCKS_NUM) : 0); }
void set_default_output_filename(const tstring& filename);

View file

@ -6119,7 +6119,7 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
const TCHAR *fmtstr = _T("%") NPRIs _T(": \"%") NPRIs _T("\"%") NPRIs _T("%") NPRIs _T("%") NPRIs _T("\n");
SCRIPT_MSG(fmtstr, cmdnam, path, arcstr ? _T(" (") : _T(""), arcstr ? arcstr : _T(""), arcstr ? _T(")") : _T(""));
PATH_CONVERT(path);
m_plugins[tt].AddPluginsDir(path, !!display_script);
m_plugins[tt].AddPluginsDir(path, is_targettype_64bit(tt), !!display_script);
return PS_OK;
}
}