Added experimental System plug-in v2 syntax option

git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6955 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
anders_k 2017-12-03 18:04:02 +00:00
parent ebfe3bf6d2
commit 9229c5df18
4 changed files with 243 additions and 122 deletions

View file

@ -42,7 +42,7 @@ const int ParamSizeByType[8] = {
0 // PAT_REGMEM //BUGBUG64? 0 // PAT_REGMEM //BUGBUG64?
}; };
// Thomas needs to look at this. // The size of the base type when used in a struct with the '&' syntax (multiply by (Option - PAO_ARRBASE) to get the real size)
static const int ByteSizeByType[8] = { static const int ByteSizeByType[8] = {
1, // PAT_VOID 1, // PAT_VOID
1, // PAT_INT 1, // PAT_INT
@ -66,15 +66,29 @@ HINSTANCE g_hInstance;
char retexpr[4]; //BUGBUG64? char retexpr[4]; //BUGBUG64?
HANDLE retaddr; HANDLE retaddr;
TCHAR *GetResultStr(SystemProc *proc) static TCHAR *MakeResultStr(SystemProc *proc, TCHAR *buf)
{ {
TCHAR *buf = AllocString(); if (proc->ProcResult == PR_OK)
if (proc->ProcResult == PR_OK) lstrcpy(buf, _T("ok")); lstrcpy(buf, _T("ok"));
else if (proc->ProcResult == PR_ERROR) lstrcpy(buf, _T("error")); else if (proc->ProcResult == PR_ERROR)
else if (proc->ProcResult == PR_CALLBACK) wsprintf(buf, _T("callback%d"), proc->CallbackIndex); lstrcpy(buf, _T("error"));
else if (proc->ProcResult == PR_CALLBACK)
{
INT_PTR id = proc->CallbackIndex;
#ifdef POPT_SYNTAX2
if (proc->Options & POPT_SYNTAX2)
id = (INT_PTR) GetAssociatedSysProcFromCallbackThunkPtr(proc->Proc);
#endif
wsprintf(buf, sizeof(void*) > 4 ? _T("callback%Id") : _T("callback%d"), id); // "%d" must match format used by system_pushintptr() in Get() because script will StrCmp!
}
return buf; return buf;
} }
TCHAR *AllocResultStr(SystemProc *proc)
{
return MakeResultStr(proc, AllocString());
}
#ifdef SYSTEM_LOG_DEBUG #ifdef SYSTEM_LOG_DEBUG
#ifndef COUNTOF #ifndef COUNTOF
@ -253,19 +267,20 @@ PLUGINFUNCTION(Get)
SYSTEM_LOG_ADD(proc->ProcName); SYSTEM_LOG_ADD(proc->ProcName);
//SYSTEM_LOG_ADD(_T("\n")); //SYSTEM_LOG_ADD(_T("\n"));
SYSTEM_LOG_POST; SYSTEM_LOG_POST;
if ((proc->Options & POPT_ALWRETURN) != 0) if (proc->Options & POPT_ALWRETURN)
{ {
// Always return flag set -> return separate proc and result // Always return flag set -> return separate proc and result
system_pushintptr((INT_PTR) proc); system_pushintptr((INT_PTR) proc);
GlobalFree(system_pushstring(GetResultStr(proc))); GlobalFree(system_pushstring(AllocResultStr(proc)));
} else }
else
{ {
if (proc->ProcResult != PR_OK) if (proc->ProcResult != PR_OK)
{ {
// No always return flag and error result - return result // No always return flag and error result - return result
GlobalFree(system_pushstring(GetResultStr(proc))); GlobalFree(system_pushstring(AllocResultStr(proc)));
// If proc is permanent? // If proc is permanent?
if ((proc->Options & POPT_PERMANENT) == 0) if (!(proc->Options & POPT_PERMANENT))
GlobalFree((HGLOBAL) proc); // No, free it GlobalFree((HGLOBAL) proc); // No, free it
} }
else // Ok result, return proc else // Ok result, return proc
@ -319,11 +334,11 @@ PLUGINFUNCTION(Call)
} }
// Process output // Process output
if ((proc->Options & POPT_ALWRETURN) != 0) if (proc->Options & POPT_ALWRETURN)
{ {
// Always return flag set - return separate return and result // Always return flag set - return separate return and result
ParamsOut(proc); ParamsOut(proc);
GlobalFree(system_pushstring(GetResultStr(proc))); GlobalFree(system_pushstring(AllocResultStr(proc)));
} }
else else
{ {
@ -332,8 +347,10 @@ PLUGINFUNCTION(Call)
ProcParameter pp = proc->Params[0]; // Save old return param ProcParameter pp = proc->Params[0]; // Save old return param
// Return result instead of return value // Return result instead of return value
proc->Params[0].Value = (INT_PTR) GetResultStr(proc); TCHAR resstr[50];
proc->Params[0].Value = (INT_PTR) MakeResultStr(proc, resstr);
proc->Params[0].Type = PAT_TSTRING; proc->Params[0].Type = PAT_TSTRING;
proc->Params[0].allocatedBlock = NULL;
ParamsOut(proc); // Return all params ParamsOut(proc); // Return all params
proc->Params[0] = pp; // Restore old return param proc->Params[0] = pp; // Restore old return param
@ -355,7 +372,7 @@ PLUGINFUNCTION(Call)
} }
// If proc is permanent? // If proc is permanent?
if ((proc->Options & POPT_PERMANENT) == 0) GlobalFree((HGLOBAL) proc); // No, free it if (!(proc->Options & POPT_PERMANENT)) GlobalFree((HGLOBAL) proc); // No, free it
} PLUGINFUNCTIONEND } PLUGINFUNCTIONEND
PLUGINFUNCTIONSHORT(Int64Op) PLUGINFUNCTIONSHORT(Int64Op)
@ -436,7 +453,12 @@ SystemProc *PrepareProc(BOOL NeedForCall)
BOOL param_defined = FALSE; BOOL param_defined = FALSE;
SystemProc *proc = NULL; SystemProc *proc = NULL;
TCHAR *ibuf, *ib, *sbuf, *cbuf, *cb; TCHAR *ibuf, *ib, *sbuf, *cbuf, *cb;
unsigned int UsedTString = 0; unsigned int UsedTString = 0, aligntype;
#ifdef POPT_SYNTAX2
const UINT alignflag = PAT_ALIGNFLAG;
#else
const UINT alignflag = 0;
#endif
#ifdef __GNUC__ #ifdef __GNUC__
temp3 = 0; // "warning: 'temp3' may be used uninitialized in this function": temp3 is set to 0 when we start parsing a new parameter temp3 = 0; // "warning: 'temp3' may be used uninitialized in this function": temp3 is set to 0 when we start parsing a new parameter
@ -472,7 +494,7 @@ SystemProc *PrepareProc(BOOL NeedForCall)
case _T('('): case _T('('):
SectionType = PST_PARAMS; SectionType = PST_PARAMS;
// fake-real parameter: for COM interfaces first param is Interface Pointer // fake-real parameter: for COM interfaces first param is Interface Pointer
ParamIndex = ((ProcType == PT_VTABLEPROC)?(2):(1)); ParamIndex = ((ProcType == PT_VTABLEPROC)?(2):(1));
temp3 = temp = 0; temp3 = temp = 0;
param_defined = FALSE; param_defined = FALSE;
break; break;
@ -526,13 +548,13 @@ SystemProc *PrepareProc(BOOL NeedForCall)
if (pr != NULL) pr->Clone = NULL; if (pr != NULL) pr->Clone = NULL;
// Never Redefine? // Never Redefine?
if ((proc->Options & POPT_NEVERREDEF) != 0) if (proc->Options & POPT_NEVERREDEF)
{ {
// Create new proc as copy proc = GlobalCopy(proc); // Create new proc as copy
proc = GlobalCopy(proc); proc->Options &= ~(POPT_NEVERREDEF|POPT_PERMANENT); // NeverRedef options is never inherited
// NeverRedef options is never inherited }
proc->Options &= (~POPT_NEVERREDEF) & (~POPT_PERMANENT); else
} else proc->Options |= POPT_PERMANENT; // Proc is old -> permanent proc->Options |= POPT_PERMANENT; // Proc is old -> permanent
} }
break; break;
case PT_PROC: case PT_PROC:
@ -601,6 +623,7 @@ SystemProc *PrepareProc(BOOL NeedForCall)
ParamIndex = 0; // Uses the same logic as PST_PARAMS section ParamIndex = 0; // Uses the same logic as PST_PARAMS section
case PST_PARAMS: case PST_PARAMS:
temp2 = -1; temp4 = 0; // Our type placeholder temp2 = -1; temp4 = 0; // Our type placeholder
aligntype = FALSE;
switch (*ib) switch (*ib)
{ {
case _T(' '): case _T(' '):
@ -623,41 +646,44 @@ SystemProc *PrepareProc(BOOL NeedForCall)
param_defined = TRUE; param_defined = TRUE;
break; break;
case _T('&'): case _T('&'):
temp = 1; break; // Special parameter option temp = PAO_ARRBASE; break; // Special parameter option
case _T('*'): case _T('*'):
temp = -1; break; // Pointer parameter option temp = PAO_PTRFLAG; break; // Pointer parameter option
// Types // Types
case _T('@'): temp2 = PAT_REGMEM; break; case _T('@'): temp2 = PAT_REGMEM; break;
case _T('v'): case _T('V'): // No extra alignment for void padding
case _T('V'): temp2 = PAT_VOID; break; case _T('v'): temp2 = PAT_VOID; break;
case 'B': // INT8/BYTE/BOOLEAN case 'B': aligntype += alignflag ? 1 : 0;
case 'b': temp2 = PAT_INT, temp = sizeof(BYTE) + 1; break; case 'b': temp2 = PAT_INT, temp = sizeof(BYTE) + 1; break; // INT8/BYTE/BOOLEAN alias for &1
case 'H': // INT16/WORD/SHORT: 'h' AKA printf type length specifier case 'H': aligntype += alignflag ? 1 : 0;
case 'h': temp2 = PAT_INT, temp = sizeof(WORD) + 1; break; case 'h': temp2 = PAT_INT, temp = sizeof(WORD) + 1; break; // INT16/WORD/SHORT alias for &2 with 'h' AKA printf type length specifier
#ifndef _WIN64
case _T('P'):
#endif
case _T('I'): aligntype += alignflag ? 1 : 0;
#ifndef _WIN64 #ifndef _WIN64
case _T('p'): case _T('p'):
#endif #endif
case _T('i'): case _T('i'): temp2 = PAT_INT; break; // INT32
case _T('I'): temp2 = PAT_INT; break; #ifdef _WIN64
case _T('P'):
#endif
case _T('L'): aligntype += alignflag ? 1 : 0;
#ifdef _WIN64 #ifdef _WIN64
case _T('p'): case _T('p'):
#endif #endif
case _T('l'): case _T('l'): temp2 = PAT_LONG; break; // INT64
case _T('L'): temp2 = PAT_LONG; break; case _T('M'): // 1 byte, no extra alignment
case _T('m'): case _T('m'): temp2 = PAT_STRING; break;
case _T('M'): temp2 = PAT_STRING; break; case _T('T'): aligntype += (alignflag && sizeof(TCHAR) > 1) ? 1 : 0;
case _T('t'): case _T('t'): temp2 = PAT_TSTRING, ++UsedTString; break;
case _T('T'): case _T('G'): aligntype += alignflag ? 1 : 0;
temp2 = PAT_TSTRING; case _T('g'): temp2 = PAT_GUID; break;
++UsedTString; case _T('W'): aligntype += alignflag ? 1 : 0;
break; case _T('w'): temp2 = PAT_WSTRING; break;
case _T('g'): case _T('K'): aligntype += alignflag ? 1 : 0;
case _T('G'): temp2 = PAT_GUID; break; case _T('k'): temp2 = PAT_CALLBACK; break;
case _T('w'):
case _T('W'): temp2 = PAT_WSTRING; break;
case _T('k'):
case _T('K'): temp2 = PAT_CALLBACK; break;
// Input output specifiers // Input output specifiers
case _T('.'): temp3++; break; // skip specifier case _T('.'): temp3++; break; // skip specifier
@ -716,11 +742,11 @@ SystemProc *PrepareProc(BOOL NeedForCall)
{ {
const int psbt = ParamSizeByType[temp2]; const int psbt = ParamSizeByType[temp2];
param_defined = TRUE; param_defined = TRUE;
proc->Params[ParamIndex].Type = temp2; proc->Params[ParamIndex].Type = temp2 | (alignflag && aligntype ? alignflag : 0);
proc->Params[ParamIndex].Size = // Pointer sized or from type proc->Params[ParamIndex].Size = // Pointer sized or from type
(temp == -1)?(PARAMSIZEBYTYPE_PTR):((psbt>0)?(psbt):(1)); //BUGBUG64: Is it safe to fallback to 1 for CALLBACK? ParamOptionIsPointer(temp) ? (PARAMSIZEBYTYPE_PTR) : ((psbt>0) ? (psbt) : (1)); //BUGBUG64: Is it safe to fallback to 1 for CALLBACK?
if (temp == 1) temp = // Get the parameter real special option value if (temp == PAO_ARRBASE) temp =
((int) GetIntFromString(&ib)) + 1; // Read '&' type size specification PAO_ARRBASE + ((int) GetIntFromString(&ib)); // Read '&' array count specification
proc->Params[ParamIndex].Option = temp; proc->Params[ParamIndex].Option = temp;
proc->Params[ParamIndex].Value = 0; proc->Params[ParamIndex].Value = 0;
proc->Params[ParamIndex].Input = IOT_NONE; proc->Params[ParamIndex].Input = IOT_NONE;
@ -752,36 +778,27 @@ SystemProc *PrepareProc(BOOL NeedForCall)
temp2 = 0; temp2 = 0;
switch (*ib) switch (*ib)
{ {
case _T(' '): case _T(' '): break;
break;
case _T('!'): temp = -temp; break; case _T('!'): temp = -temp; break;
case _T('c'): case _T('c'):
#ifndef _WIN64 #ifndef _WIN64
temp2 = POPT_CDECL; temp2 = POPT_CDECL; // Only x86 cares, just eat the option for everything else
#endif #endif
break; break;
case _T('r'): case _T('r'): temp2 = POPT_ALWRETURN; break;
temp2 = POPT_ALWRETURN; case _T('n'): temp2 = POPT_NEVERREDEF; break;
break; case _T('s'): temp2 = POPT_GENSTACK; break;
case _T('n'): case _T('e'): temp2 = POPT_ERROR; break;
temp2 = POPT_NEVERREDEF; case _T('u'): temp2 = POPT_UNLOAD; break;
break; #ifdef POPT_SYNTAX2
case _T('s'): case _T('2'): temp2 = POPT_SYNTAX2; break;
temp2 = POPT_GENSTACK; #endif
break;
case _T('e'):
temp2 = POPT_ERROR;
break;
case _T('u'):
temp2 = POPT_UNLOAD;
break;
} }
// New Options // New Options
if (temp2 != 0) if (temp2 != 0)
{ {
if (temp == 1) proc->Options |= temp2; if (temp == 1) proc->Options |= temp2; else proc->Options &= ~temp2;
else proc->Options &= ~temp2;
// Back to default (turn on nothing) state // Back to default (turn on nothing) state
temp = 1; temp2 = 0; temp = 1; temp2 = 0;
} }
@ -892,10 +909,10 @@ SystemProc *PrepareProc(BOOL NeedForCall)
void ParamAllocate(SystemProc *proc) void ParamAllocate(SystemProc *proc)
{ {
int i; UINT i, c;
for (i = 0; i <= proc->ParamCount; i++) for (i = 0, c = proc->ParamCount; i <= c; i++)
if (!proc->Params[i].Value && proc->Params[i].Option == -1) if (!proc->Params[i].Value && ParamIsPointer(proc->Params[i]))
proc->Params[i].Value = (INT_PTR) GlobalAlloc(GPTR, 4*ParamSizeByType[proc->Params[i].Type]); proc->Params[i].Value = (INT_PTR) GlobalAlloc(GPTR, ParamSizeByType[GetParamType(proc->Params[i])] * 4);
} }
void ParamsIn(SystemProc *proc) void ParamsIn(SystemProc *proc)
@ -913,6 +930,7 @@ void ParamsIn(SystemProc *proc)
while (TRUE) while (TRUE)
{ {
ProcParameter *par = &proc->Params[i]; ProcParameter *par = &proc->Params[i];
UINT partype;
// Step 1: retrive value // Step 1: retrive value
if ((par->Input == IOT_NONE) || (par->Input == IOT_INLINE)) if ((par->Input == IOT_NONE) || (par->Input == IOT_INLINE))
realbuf = AllocStr(_T("")); realbuf = AllocStr(_T(""));
@ -927,14 +945,13 @@ void ParamsIn(SystemProc *proc)
} }
// Retreive pointer to place // Retreive pointer to place
if (par->Option == -1) place = (HGLOBAL*) par->Value; place = ParamIsPointer(*par) ? (HGLOBAL*) par->Value : (HGLOBAL*) &(par->Value);
else place = (HGLOBAL*) &(par->Value);
// by default no blocks are allocated // by default no blocks are allocated
par->allocatedBlock = NULL; par->allocatedBlock = NULL;
// Step 2: place it // Step 2: place it
switch (par->Type) switch (partype = GetParamType(*par))
{ {
case PAT_VOID: case PAT_VOID:
par->Value = 0; par->Value = 0;
@ -965,7 +982,7 @@ void ParamsIn(SystemProc *proc)
case PAT_GUID: case PAT_GUID:
wstr = (LPWSTR) GlobalAlloc(GPTR, g_stringsize*sizeof(WCHAR)); wstr = (LPWSTR) GlobalAlloc(GPTR, g_stringsize*sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, realbuf, g_stringsize, wstr, g_stringsize); MultiByteToWideChar(CP_ACP, 0, realbuf, g_stringsize, wstr, g_stringsize);
if (par->Type == PAT_GUID) if (partype == PAT_GUID)
{ {
*place = par->allocatedBlock = GlobalAlloc(GPTR, 16); *place = par->allocatedBlock = GlobalAlloc(GPTR, 16);
CLSIDFromString(wstr, *(LPCLSID*)place); CLSIDFromString(wstr, *(LPCLSID*)place);
@ -997,7 +1014,7 @@ void ParamsIn(SystemProc *proc)
#ifndef _WIN64 #ifndef _WIN64
hi32 = par->_value; hi32 = par->_value;
#endif #endif
wsprintf(buf, _T("\t\t\tParam In %d:\tType=%d Value=")SYSFMT_HEXPTR _T(" hi32=0x%08X"), i, wsprintf(buf, _T("\t\t\tParam In %d:\tType=%#x Value=") SYSFMT_HEXPTR _T(" hi32=0x%08X"), i,
par->Type, par->Value, hi32); par->Type, par->Value, hi32);
SYSTEM_LOG_ADD(buf); SYSTEM_LOG_ADD(buf);
SYSTEM_LOG_POST; SYSTEM_LOG_POST;
@ -1013,36 +1030,36 @@ void ParamsDeAllocate(SystemProc *proc)
{ {
int i; int i;
for (i = proc->ParamCount; i >= 0; i--) for (i = proc->ParamCount; i >= 0; i--)
if (proc->Params[i].Value && proc->Params[i].Option == -1) if (proc->Params[i].Value && ParamIsPointer(proc->Params[i]))
{ {
GlobalFree((HGLOBAL) (proc->Params[i].Value)); GlobalFree((HGLOBAL) (proc->Params[i].Value));
proc->Params[i].Value = 0; proc->Params[i].Value = 0;
} }
} }
#define GetSpecialParamTypeSize(pPP) ( (((pPP)->Option)-1) * ByteSizeByType[(pPP)->Type] ) #define GetSpecialParamTypeSize(par) ( (((par).Option)-PAO_ARRBASE) * ByteSizeByType[GetParamType(par)] ) // Option must be > PAO_ARRBASE!
static const int g_intmask[4] = { 0xFFFFFFFF, 0x000000FF, 0x0000FFFF, 0x00FFFFFF }; static const int g_intmask[4] = { 0xFFFFFFFF, 0x000000FF, 0x0000FFFF, 0x00FFFFFF };
#define GetMaskedInt32Value(val, size) ( (val) & g_intmask[(((size) >= 0) && ((size) < 4))?((size)):(0)] ) #define GetMaskedInt32Value(val, size) ( (val) & g_intmask[((UINT)(size) < 4) ? (size) : (0)] )
#define GetSpecialParamInt32Value(pPP, size) GetMaskedInt32Value((pPP)->Value, (size)) #define GetSpecialParamInt32Value(par, size) GetMaskedInt32Value((par).Value, (size))
void ParamsOut(SystemProc *proc) void ParamsOut(SystemProc *proc)
{ {
INT_PTR *place; INT_PTR *place;
LPWSTR wstr; LPWSTR wstr;
int i, intval, typsiz; int i, partype, intval, typsiz;
TCHAR *realbuf = AllocString(); TCHAR *realbuf = AllocString();
i = proc->ParamCount; i = proc->ParamCount;
do do
{ {
// Retreive pointer to place // Retreive pointer to place
if (proc->Params[i].Option == -1) if (ParamIsPointer(proc->Params[i]))
place = (INT_PTR*) proc->Params[i].Value; place = (INT_PTR*) proc->Params[i].Value;
else else
place = (INT_PTR*) &(proc->Params[i].Value); place = (INT_PTR*) &(proc->Params[i].Value);
// Step 1: retrive value // Step 1: retrive value
switch (proc->Params[i].Type) switch (partype = GetParamType(proc->Params[i]))
{ {
case PAT_VOID: case PAT_VOID:
*realbuf = _T('\0'); *realbuf = _T('\0');
@ -1054,7 +1071,7 @@ void ParamsOut(SystemProc *proc)
intval = (int)(*((INT_PTR*) place)); intval = (int)(*((INT_PTR*) place));
if (proc->Params[i].Option > 0) // Note: We don't handle '*' pointers, "*h" and "*b" are not supported, use "*i" even on smaller types if (proc->Params[i].Option > 0) // Note: We don't handle '*' pointers, "*h" and "*b" are not supported, use "*i" even on smaller types
{ {
typsiz = GetSpecialParamTypeSize(&proc->Params[i]); typsiz = GetSpecialParamTypeSize(proc->Params[i]);
intval = GetMaskedInt32Value(intval, typsiz); intval = GetMaskedInt32Value(intval, typsiz);
} }
wsprintf(realbuf, _T("%d"), intval); wsprintf(realbuf, _T("%d"), intval);
@ -1099,8 +1116,9 @@ void ParamsOut(SystemProc *proc)
} }
// memory cleanup // memory cleanup
if ((proc->Params[i].allocatedBlock != NULL) && ((proc->ProcType != PT_STRUCT) if ((proc->Params[i].allocatedBlock != NULL)
|| (proc->Params[i].Option > 0))) && ((partype != PT_STRUCT) || ParamIsArray(proc->Params[i]))
)
GlobalFree(proc->Params[i].allocatedBlock); GlobalFree(proc->Params[i].allocatedBlock);
SYSTEM_LOG_ADD(_T("\t\t\tParam Out(")); SYSTEM_LOG_ADD(_T("\t\t\tParam Out("));
@ -1123,7 +1141,7 @@ void ParamsOut(SystemProc *proc)
#ifdef SYSTEM_LOG_DEBUG #ifdef SYSTEM_LOG_DEBUG
{ {
TCHAR dbgbuf[99]; TCHAR dbgbuf[99];
wsprintf(dbgbuf, _T(")\t%d:\tType=%d Optn=%d Size=%d Data="), wsprintf(dbgbuf, _T(")\t%d:\tType=%#x Optn=%d Size=%d Data="),
i, proc->Params[i].Type, proc->Params[i].Option, proc->Params[i].Size); i, proc->Params[i].Type, proc->Params[i].Option, proc->Params[i].Size);
SYSTEM_LOG_ADD(dbgbuf); SYSTEM_LOG_ADD(dbgbuf);
SYSTEM_LOG_ADD(realbuf); SYSTEM_LOG_ADD(realbuf);
@ -1174,36 +1192,61 @@ HANDLE CreateCallback(SystemProc *cbproc)
#endif #endif
} }
#ifdef POPT_SYNTAX2
static UINT GetStructParamAlignment(const ProcParameter *par)
{
int partype = GetParamType(*par);
int isarr = ParamIsArray(*par);
// &l is used to get the final struct size "*(p, &l.r0)"
// but it also allows you to write the struct size to the struct as a int<8|16|32|64> "*(p, &l4)"
// so we can't stop that with: if ((par->Type & PAT_ALIGNFLAG) && (!isarr || partype != PAT_LONG))
if (par->Type & PAT_ALIGNFLAG)
{
if ((partype == PAT_STRING) | (partype == PAT_WSTRING)) return ByteSizeByType[partype];
if (partype == PAT_GUID) return 16;
return !isarr ? (par->Size * 4) : GetSpecialParamTypeSize(*par);
}
return 0;
}
#endif
void CallStruct(SystemProc *proc) void CallStruct(SystemProc *proc)
{ {
BOOL ssflag; // "&l" struct size syntax BOOL ssflag; // "&l" struct size syntax
int i, structsize = 0, size = 0; UINT i, paramcount = proc->ParamCount, structsize = 0, size = 0, partype;
char *st, *ptr; char *st, *ptr;
#ifdef POPT_SYNTAX2
BOOL tryalign = proc->Options & POPT_SYNTAX2;
#endif
SYSTEM_LOG_ADD(_T("\t\tStruct...")); SYSTEM_LOG_ADD(_T("\t\tStruct..."));
// Calculate the structure size // Calculate the structure size
for (i = 1; i <= proc->ParamCount; i++) for (i = 1; i <= paramcount; i++)
{ {
partype = GetParamType(proc->Params[i]);
// Emulate g as &g16 // Emulate g as &g16
// (Changing ByteSizeByType would break compatibility with '*(&g16,i)i.s') // (Changing ByteSizeByType would break compatibility with '*(&g16,i)i.s')
if (PAT_GUID==proc->Params[i].Type && 0==proc->Params[i].Option) if (PAT_GUID==partype && ParamIsSimple(proc->Params[i]))
{ proc->Params[i].Option = PAO_ARRBASE + 16;
proc->Params[i].Option = 1 + 16;
}
if (proc->Params[i].Option < 1) if (!ParamIsArray(proc->Params[i]))
structsize += proc->Params[i].Size * 4; size = proc->Params[i].Size * 4;
else else
structsize += GetSpecialParamTypeSize(&proc->Params[i]); size = GetParamArrayTypeSize(proc->Params[i]);
#ifdef POPT_SYNTAX2
if (tryalign)
structsize = SYS_ALIGNON(structsize, GetStructParamAlignment(&proc->Params[i]));
#endif
structsize += size;
} }
// Struct exists? // Struct exists?
if (proc->Proc == NULL) if (proc->Proc == NULL) // No. Allocate struct memory
// No. Allocate struct memory
proc->Proc = (HANDLE) GlobalAlloc(GPTR, structsize); proc->Proc = (HANDLE) GlobalAlloc(GPTR, structsize);
else // In case of zero size defined structure use mapped size else if (structsize == 0) // In case of zero size defined structure use mapped size
if (structsize == 0) structsize = (int) GlobalSize((HGLOBAL) proc->Proc); structsize = (int) GlobalSize((HGLOBAL) proc->Proc);
#ifdef SYSTEM_LOG_DEBUG #ifdef SYSTEM_LOG_DEBUG
{ {
@ -1216,49 +1259,58 @@ void CallStruct(SystemProc *proc)
// Pointer to current data // Pointer to current data
st = (char*) proc->Proc; st = (char*) proc->Proc;
for (i = 1; i <= proc->ParamCount; i++) for (i = 1; i <= paramcount; i++)
{ {
ssflag = FALSE; ssflag = FALSE;
partype = GetParamType(proc->Params[i]);
// Normal or special block? // Normal or special block?
if (proc->Params[i].Option < 1) if (!ParamIsArray(proc->Params[i]))
{ {
// Normal // Normal
size = proc->Params[i].Size*4; size = proc->Params[i].Size * 4;
ptr = (char*) &(proc->Params[i].Value); ptr = (char*) &(proc->Params[i].Value);
} }
else else
{ {
// Special // Special
size = GetSpecialParamTypeSize(&proc->Params[i]); size = GetParamArrayTypeSize(proc->Params[i]);
ptr = NULL; ptr = NULL;
switch (proc->Params[i].Type) switch (partype)
{ {
case PAT_VOID: break; case PAT_VOID:
case PAT_LONG: break;
case PAT_LONG:
// real structure size // real structure size
proc->Params[i].Value = structsize; proc->Params[i].Value = structsize;
#ifndef _WIN64 #ifndef _WIN64
proc->Params[i]._value = 0; proc->Params[i]._value = 0;
#endif #endif
ssflag = TRUE; // System::Call '*(...,&l.r0)' ssflag = TRUE; // System::Call '*(...,&l.r0)'
// [[fallthrough]]
case PAT_INT: case PAT_INT:
proc->Params[i].Value = GetSpecialParamInt32Value(&proc->Params[i], size); // clears unused value bits proc->Params[i].Value = GetSpecialParamInt32Value(proc->Params[i], size); // clears unused value bits
// pointer // pointer
ptr = (char*) &(proc->Params[i].Value); ptr = (char*) &(proc->Params[i].Value);
break; break;
case PAT_STRING: case PAT_STRING:
case PAT_WSTRING: case PAT_WSTRING:
case PAT_GUID: case PAT_GUID:
// Jim Park: Pointer for memcopy, so keep as char* // Jim Park: Pointer for memcopy, so keep as char*
ptr = (char*) proc->Params[i].Value; break; ptr = (char*) proc->Params[i].Value;
break;
} }
} }
// Process them! // Process them!
if (ptr != NULL) if (ptr != NULL)
{ {
#ifdef POPT_SYNTAX2
if (tryalign)
st = (char*) SYS_ALIGNON((INT_PTR) st, GetStructParamAlignment(&proc->Params[i]));
#endif
// Input // Input
if ((proc->Params[i].Input != IOT_NONE) || (ssflag)) if ((proc->Params[i].Input != IOT_NONE) || (ssflag))
copymem(st, ptr, size); copymem(st, ptr, size);

View file

@ -31,6 +31,10 @@
# define SYSTEM_API __declspec(dllimport) // BUGBUG: This is a plugin, who is going to import the functions directly? # define SYSTEM_API __declspec(dllimport) // BUGBUG: This is a plugin, who is going to import the functions directly?
#endif #endif
#define SYS_ALIGNUP(num, al) ( ((num)+((al)-1)) & ~((al)-1) )
#define SYS_UNSAFEALIGNON(num, al) ( (num) % (al) == 0 ? (num) : SYS_ALIGNUP((num), (al)) ) // al CANNOT be 0!
#define SYS_ALIGNON(num, al) ( (al) ? SYS_UNSAFEALIGNON((num), (al)) : (num) )
#define NEW_STACK_SIZE 256*256 #define NEW_STACK_SIZE 256*256
// Proc types: // Proc types:
@ -59,6 +63,7 @@
#define PAT_TSTRING PAT_STRING #define PAT_TSTRING PAT_STRING
#endif #endif
#define PAT_PTR ( (4==sizeof(void*)) ? PAT_INT : PAT_LONG ) #define PAT_PTR ( (4==sizeof(void*)) ? PAT_INT : PAT_LONG )
#define PAT_ALIGNFLAG 0x8000 // Type is aligned to its natural alignment
// Input/Output Source/Destination // Input/Output Source/Destination
#define IOT_NONE 0 #define IOT_NONE 0
@ -75,13 +80,18 @@
#define POPT_GENSTACK 0x10 // Use general stack (non temporary for callback) #define POPT_GENSTACK 0x10 // Use general stack (non temporary for callback)
#define POPT_ERROR 0x20 // Call GetLastError after proc and push it to stack #define POPT_ERROR 0x20 // Call GetLastError after proc and push it to stack
#define POPT_UNLOAD 0x40 // unload dll after call #define POPT_UNLOAD 0x40 // unload dll after call
#define POPT_CLONE 0x80 // This is clone callback #define POPT_CLONE 0x80 // Callback clone
#define POPT_SYNTAX2 0x100 // "?2" syntax mode (direct callback ids and aligned uppercased types)
// Proc argument (ProcParameter) options
#define PAO_PTRFLAG -1 // Could be changed to 0x80000000 if we need to support "*&iN"
#define PAO_ARRBASE 1
#define ParamOptionIsPointer(opt) ( (opt) < 0 )
// Our single proc parameter
typedef struct typedef struct
{ {
int Type; int Type; // Can be ORed with PAT_ALIGNFLAG to request alignment in structs
int Option; // -1 -> Pointer, 1-... -> Special+1 int Option; // PAO_PTRFLAG -> Pointer, PAO_ARRBASE-... -> Special+PAO_ARRBASE
INT_PTR Value; // it can hold any pointer sized value INT_PTR Value; // it can hold any pointer sized value
#ifndef _WIN64 #ifndef _WIN64
int _value; // Upper 32 bits of Value when type is 64 bit (2 pushes) int _value; // Upper 32 bits of Value when type is 64 bit (2 pushes)
@ -92,6 +102,16 @@ typedef struct
HGLOBAL allocatedBlock; // block allocated for passing string, wstring or guid param HGLOBAL allocatedBlock; // block allocated for passing string, wstring or guid param
} ProcParameter; } ProcParameter;
#define ParamIsSimple(par) ( (par).Option == 0 )
#define ParamIsPointer(par) ParamOptionIsPointer((par).Option)
#define ParamIsArray(par) ( (par).Option > 0 ) // AKA special
#define GetParamArrayTypeSize GetSpecialParamTypeSize
#ifdef POPT_SYNTAX2
#define GetParamType(par) ( (BYTE) (par).Type )
#else
#define GetParamType(par) ( (par).Type )
#endif
// Our single proc (Since the user will free proc with GlobalFree, // Our single proc (Since the user will free proc with GlobalFree,
// I've declared all variables as statics) // I've declared all variables as statics)
typedef struct tag_SystemProc SystemProc; typedef struct tag_SystemProc SystemProc;

View file

@ -472,9 +472,20 @@ System::Free $0
<th>u</th> <th>u</th>
<td>Unload DLL after call (using FreeLibrary, so you'll be able to delete it for example).</td> <td>Unload DLL after call (using FreeLibrary, so you'll be able to delete it for example).</td>
</tr> </tr>
<tr>
<th>2</th>
<td>Experimental v2 syntax</td>
</tr>
</table> </table>
</blockquote> </blockquote>
<h4>Experimental v2 syntax</h4>
<ul>
<li>Struct types in <a href="#v2typealign">uppercase are aligned</a> to their natural alignment. Lowercased types are packed without alignment.
<li><a href="#v2callback">Callback id</a> based on the allocated callback
</ul>
<h4>Usage Examples</h4> <h4>Usage Examples</h4>
<blockquote><pre> <blockquote><pre>
@ -516,6 +527,19 @@ System::<b>Call</b> "*$0(i .r1)"
System::Free $0 System::Free $0
DetailPrint $1 DetailPrint $1
</pre></blockquote> </pre></blockquote>
<a name="structsize"></a><blockquote><pre>
System::Call '*0(p, <b>&l.r2,</b> &t2)' ; &l. is not part of the struct
DetailPrint "Struct size=$2"
</pre></blockquote>
<a name="structsizemember"></a><blockquote><pre>
System::Call '*(<b>&l4</b>,i,i,i,i,&t128)p.r1' ; Fills dwOSVersionInfoSize with the struct size as a int32
${If} $1 Z<> 0
System::Call 'kernel32::GetVersionEx(pr1)i.r0'
System::Call '*$1(i,i.R1,i.R2,i.R3)'
System::Free $1
${IfThen} $0 <> 0 ${|} DetailPrint "v$R1.$R2.$R3" ${|}
${EndIf}
</pre></blockquote>
<blockquote><pre> <blockquote><pre>
<a name="directvarmemparam"></a>System::<b>Call</b> "user32::GetClientRect(p $hwndparent, @ r0)" <a name="directvarmemparam"></a>System::<b>Call</b> "user32::GetClientRect(p $hwndparent, @ r0)"
System::<b>Call</b> "*$0(i,i,i.r1,i.r2)" System::<b>Call</b> "*$0(i,i,i.r1,i.r2)"
@ -564,6 +588,29 @@ loop:
done: done:
System::Free $R0 System::Free $R0
</pre></blockquote> </pre></blockquote>
<a name="v2callback"></a><blockquote><pre>
System::Get '(m.r1)ir2r0 <b>?2</b>' ; v2 syntax
Pop $9
System::Call 'kernel32::EnumSystemLocalesA(k r9, i 0)'
loop:
StrCmp <b>$0 "callback$9"</b> 0 done
DetailPrint "Locale: $1"
StrCpy $2 1 ; EnumLocalesProc return value
System::Call $9 ; return from EnumLocalesProc
Goto loop
done:
System::Free $9
</pre></blockquote>
<a name="v2typealign"></a><blockquote><pre>
System::Call '*(&t50 "!")p.r2' ; DecimalSep
System::Call '*(&t50 "`")p.r3' ; ThousandSep
System::Call '*(i 2, i 0, i 3, <b>P r2, P r3</b>, i 1)p.r1 <b>?2</b>'
System::Call 'kernel32::GetNumberFormat(i 0, i 0, t "1337.666" r4, p r1, t.r5, i ${NSIS_MAX_STRLEN})'
DetailPrint "Custom formated $4: $5"
System::Free $3
System::Free $2
System::Free $1
</pre></blockquote>
<blockquote><pre> <blockquote><pre>
<a name="repeat"></a>!define MB "user32::MessageBox(p$HWNDPARENT,t,t'NSIS System Plug-in',i0)" <a name="repeat"></a>!define MB "user32::MessageBox(p$HWNDPARENT,t,t'NSIS System Plug-in',i0)"
System::<b>Call</b> "${MB}(,'my message',,)" System::<b>Call</b> "${MB}(,'my message',,)"

View file

@ -20,6 +20,8 @@ Released on ??? ??rd, 20??
\S2{} Minor Changes \S2{} Minor Changes
\b Added System plug-in v2 syntax option
\b Added System plug-in B and H types \b Added System plug-in B and H types
\b Added \R{intptrcmp}{IntPtrCmp}, IntPtrCmpU, and \R{intptrop}{IntPtrOp} \b Added \R{intptrcmp}{IntPtrCmp}, IntPtrCmpU, and \R{intptrop}{IntPtrOp}