diff --git a/Contrib/System/Buffers.c b/Contrib/System/Buffers.c
new file mode 100644
index 00000000..d373d8e9
--- /dev/null
+++ b/Contrib/System/Buffers.c
@@ -0,0 +1,93 @@
+#include "stdafx.h"
+#include "Plugin.h"
+#include "System.h"
+#include "Buffers.h"
+
+PLUGINFUNCTION(AllocCopy)
+ int mem;
+
+ if (popint(&mem) == 0)
+ {
+ pushint(0);
+ return;
+ }
+
+ mem = (int) GlobalCopy((HANDLE) mem);
+ pushint(mem);
+PLUGINFUNCTIONEND
+
+PLUGINFUNCTION(Alloc)
+ int size;
+ int mem;
+
+ if (popint(&size) == 0)
+ {
+ pushint(0);
+ return;
+ }
+
+ mem = (int) GlobalAlloc(GPTR, size);
+ pushint(mem);
+PLUGINFUNCTIONEND
+
+PLUGINFUNCTION(Free)
+ int mem;
+
+ if ((popint(&mem) == 0) || (mem == 0))
+ {
+ pushstring("false");
+ return;
+ }
+ if ((GlobalFree((HANDLE) mem) == NULL)) pushstring("true");
+ else pushstring("false");
+PLUGINFUNCTIONEND
+
+/*typedef BOOL (__stdcall *GetDiskSpace)
+(
+ LPCTSTR lpDirectoryName, // directory name
+ PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller
+ PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk
+ PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk
+);*/
+
+/*PLUGINFUNCTION(MyFunction)
+ GetDiskSpace proc;
+ ULARGE_INTEGER i1, i2, i3;
+ BOOL check;
+
+ proc = (GetDiskSpace) GetProcAddress(GetModuleHandle("kernel32.dll"), "GetDiskFreeSpaceExA");
+ check = proc(NULL, &i1, &i2, &i3);
+
+ _asm
+ {
+ push ecx
+ lea ecx, i3
+ push ecx
+ lea ecx, i2
+ push ecx
+ lea ecx, i1
+ push ecx
+ push 0
+
+ call proc
+
+ mov check, eax
+// add esp, 16
+ pop ecx
+ }
+
+ char buf[1024];
+ wsprintf(buf,"$0=%s\n",getuservariable(INST_0));
+ MessageBox(g_hwndParent,buf,0,MB_OK);
+PLUGINFUNCTIONEND*/
+
+HANDLE GlobalCopy(HANDLE Old)
+{
+ SIZE_T size;
+ HANDLE n;
+
+ size = GlobalSize(Old);
+ n = GlobalAlloc(GPTR, size);
+ CopyMemory(n, Old, size);
+ return n;
+}
\ No newline at end of file
diff --git a/Contrib/System/Buffers.h b/Contrib/System/Buffers.h
new file mode 100644
index 00000000..538c481b
--- /dev/null
+++ b/Contrib/System/Buffers.h
@@ -0,0 +1,3 @@
+#pragma once
+
+extern HANDLE GlobalCopy(HANDLE Old);
\ No newline at end of file
diff --git a/Contrib/System/Last Comments.txt b/Contrib/System/Last Comments.txt
new file mode 100644
index 00000000..acd135cc
--- /dev/null
+++ b/Contrib/System/Last Comments.txt
@@ -0,0 +1,23 @@
+I'm just finished and going to sleep, so a few words only.
+This is alpha release, just for testing. Report bugs please.
+
+That version limits:
+
+0. I've not noticed the NSIS team inverted the 'calling convention', arguments
+are passing to stack from left to right during d::p call, so you should invert
+system.txt arguments order. See SystemEx.nsi for examples.
+
+1. PT_VOID and PT_BOOLEAN are unsupported.
+2. PT_LONG without Pointer specifier is not allowed.
+3. NSIS->Call PT_LONG converts as 32 bits. Back conversion bit-width is unknown.
+By the way NSIS doesn't support int64 operations, so you can process received
+long values as strings only...
+4. Generaly untested :)
+5. Requires MSVC++ 7.0 to compile :) Sorry....
+
+Todo (will be done in a few days):
+1. Structures work (thru functions).
+2. Callbacks.
+3. Arg-lists
+4. Cdecl convention
+5. Optimizations and so on...
\ No newline at end of file
diff --git a/Contrib/System/Plugin.c b/Contrib/System/Plugin.c
new file mode 100644
index 00000000..1e0d2174
--- /dev/null
+++ b/Contrib/System/Plugin.c
@@ -0,0 +1,109 @@
+#include "stdafx.h"
+#include "Plugin.h"
+#include "System.h"
+
+HWND g_hwndParent;
+int g_stringsize;
+stack_t **g_stacktop;
+char *g_variables;
+
+int popstring(char *str)
+{
+ stack_t *th;
+ if (!g_stacktop || !*g_stacktop) return 0;
+ th=(*g_stacktop);
+ lstrcpy(str,th->text);
+ *g_stacktop = th->next;
+ GlobalFree((HGLOBAL)th);
+ return 1;
+}
+
+void pushstring(char *str)
+{
+ stack_t *th;
+ if (!g_stacktop) return;
+ th=(stack_t*)GlobalAlloc(GPTR,sizeof(stack_t)+g_stringsize);
+ lstrcpyn(th->text,str,g_stringsize);
+ th->next=*g_stacktop;
+ *g_stacktop=th;
+}
+
+char *getuservariable(int varnum)
+{
+ if (varnum < 0 || varnum >= __INST_LAST) return NULL;
+ return g_variables+varnum*g_stringsize;
+}
+
+void setuservariable(int varnum, char *var)
+{
+ if (var != NULL && varnum >= 0 && varnum < __INST_LAST) {
+ lstrcpy (g_variables + varnum*g_stringsize, var);
+
+ }
+}
+
+int myatoi(char *s)
+{
+ unsigned int v=0;
+ if (*s == '0' && (s[1] == 'x' || s[1] == 'X'))
+ {
+ s+=2;
+ for (;;)
+ {
+ int c=*s++;
+ if (c >= '0' && c <= '9') c-='0';
+ else if (c >= 'a' && c <= 'f') c-='a'-10;
+ else if (c >= 'A' && c <= 'F') c-='A'-10;
+ else break;
+ v<<=4;
+ v+=c;
+ }
+ }
+ else if (*s == '0' && s[1] <= '7' && s[1] >= '0')
+ {
+ s++;
+ for (;;)
+ {
+ int c=*s++;
+ if (c >= '0' && c <= '7') c-='0';
+ else break;
+ v<<=3;
+ v+=c;
+ }
+ }
+ else
+ {
+ int sign=0;
+ if (*s == '-') { s++; sign++; }
+ for (;;)
+ {
+ int c=*s++ - '0';
+ if (c < 0 || c > 9) break;
+ v*=10;
+ v+=c;
+ }
+ if (sign) return -(int) v;
+ }
+ return (int)v;
+}
+
+int popint(int *value)
+{
+ char buffer[1024];
+ if (popstring(buffer) == 0) return FALSE;
+ *value = myatoi(buffer);
+ return TRUE;
+}
+
+void pushint(int value)
+{
+ char buffer[1024];
+ wsprintf(buffer, "%d", value);
+ pushstring(buffer);
+}
+
+#ifdef _DEBUG
+void main()
+{
+}
+#endif
\ No newline at end of file
diff --git a/Contrib/System/Plugin.h b/Contrib/System/Plugin.h
new file mode 100644
index 00000000..d8e84626
--- /dev/null
+++ b/Contrib/System/Plugin.h
@@ -0,0 +1,56 @@
+#pragma once
+
+typedef struct _stack_t {
+ struct _stack_t *next;
+ char text[1]; // this should be the length of string_size
+} stack_t;
+
+enum
+{
+INST_0, // $0
+INST_1, // $1
+INST_2, // $2
+INST_3, // $3
+INST_4, // $4
+INST_5, // $5
+INST_6, // $6
+INST_7, // $7
+INST_8, // $8
+INST_9, // $9
+INST_R0, // $R0
+INST_R1, // $R1
+INST_R2, // $R2
+INST_R3, // $R3
+INST_R4, // $R4
+INST_R5, // $R5
+INST_R6, // $R6
+INST_R7, // $R7
+INST_R8, // $R8
+INST_R9, // $R9
+INST_CMDLINE, // $CMDLINE
+INST_INSTDIR, // $INSTDIR
+INST_OUTDIR, // $OUTDIR
+INST_EXEDIR, // $EXEDIR
+INST_LANG, // $LANGUAGE
+__INST_LAST
+};
+
+#define PLUGINFUNCTION(name) void __declspec(dllexport) name(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) { \
+ g_hwndParent=hwndParent; \
+ g_stringsize=string_size; \
+ g_stacktop=stacktop; \
+ g_variables=variables; {
+#define PLUGINFUNCTIONEND }}
+
+extern char *getuservariable(int varnum);
+extern void setuservariable(int varnum, char *var);
+extern int popstring(char *str); // 0 on empty stack
+extern void pushstring(char *str);
+extern int myatoi(char *s);
+extern int popint(int *value); // 0 on empty stack
+extern void pushint(int value);
+
+extern HWND g_hwndParent;
+extern int g_stringsize;
+extern stack_t **g_stacktop;
+extern char *g_variables;
diff --git a/Contrib/System/System.c b/Contrib/System/System.c
new file mode 100644
index 00000000..56efb3c4
--- /dev/null
+++ b/Contrib/System/System.c
@@ -0,0 +1,390 @@
+// System.cpp : Defines the entry point for the DLL application.
+//
+
+#include "stdafx.h"
+#include "Plugin.h"
+#include "System.h"
+
+HINSTANCE g_hInstance;
+
+#define PT_STRING_SIZE 2048
+#define PARAMOKCHECK(expr) if (expr) { pushint(0); return; }
+
+PLUGINFUNCTION(PartAddr)
+ char buffer[1024];
+ SystemProc *proc;
+
+ // Retrieve ProcID
+ PARAMOKCHECK(popstring(buffer) == 0);
+ // Try to initialize proc ...
+ proc = ParseProc(buffer);
+ // ... and return it to nsis!
+ pushint((int) proc);
+PLUGINFUNCTIONEND
+
+PLUGINFUNCTION(FullAddr)
+ char procid[1024], paramid[1024];
+ SystemProc *proc;
+
+ // Retrieve ProcID and ParamId
+ PARAMOKCHECK((popstring(procid) == 0) || (popstring(paramid) == 0))
+ // Try to initialize proc ...
+ proc = ParseProc(procid);
+ PARAMOKCHECK(proc == NULL)
+ // Try to initialize params ...
+ PARAMOKCHECK(ParseParam(proc, paramid) == FALSE)
+ // ... and return it to nsis!
+ pushint((int) proc);
+PLUGINFUNCTIONEND
+
+PLUGINFUNCTION(ShortAddr)
+ char paramid[1024];
+ SystemProc *proc;
+
+ // Retrieve Proc and ParamId
+ PARAMOKCHECK((popint(&((int)proc)) == 0) || (popstring(paramid) == 0))
+ // Try to initialize params ...
+ PARAMOKCHECK(ParseParam(proc, paramid) == FALSE)
+ // ... and return it to nsis!
+ pushint((int) proc);
+PLUGINFUNCTIONEND
+
+PLUGINFUNCTION(Call)
+ SystemProc *proc;
+
+ // Retrieve Proc
+ PARAMOKCHECK(popint(&((int)proc)) == 0)
+
+ // Run the proc
+ SystemCall(proc);
+PLUGINFUNCTIONEND
+
+PLUGINFUNCTION(ShortCall)
+ char paramid[1024];
+ SystemProc *proc;
+
+ // Retrieve Proc and ParamId
+ PARAMOKCHECK((popint(&((int)proc)) == 0) || (popstring(paramid) == 0))
+ // Try to initialize params ...
+ PARAMOKCHECK(ParseParam(proc, paramid) == FALSE)
+
+ // Run the proc
+ SystemCall(proc);
+PLUGINFUNCTIONEND
+
+PLUGINFUNCTION(FullCall)
+ char procid[1024], paramid[1024];
+ SystemProc *proc;
+
+ // Retrieve ProcID and ParamId
+ PARAMOKCHECK((popstring(procid) == 0) || (popstring(paramid) == 0))
+ // Try to initialize proc ...
+ proc = ParseProc(procid);
+ PARAMOKCHECK(proc == NULL)
+ // Try to initialize params ...
+ PARAMOKCHECK(ParseParam(proc, paramid) == FALSE)
+ // ... and return it to nsis!
+
+ // Run the proc
+ SystemCall(proc);
+
+ // We've created it, we've to destroyit
+ GlobalFree(proc);
+PLUGINFUNCTIONEND
+
+SystemProc *ParseProc(char *ProcID)
+{
+ SystemProc *proc;
+ char dllname[1024], procname[256], *p1, *p2;
+
+ // Extract dllname
+ p1 = ProcID;
+ p2 = dllname;
+ while (*p1 && (*p1 != '?')) *(p2++) = *(p1++);
+ *p2 = 0;
+ if ((lstrlen(dllname) == 0) || (*p1 == 0)) return NULL;
+
+ // Extract procname
+ p1++;
+ p2 = procname;
+ while (*p1 && (*p1 != '?')) *(p2++) = *(p1++);
+ *p2 = 0;
+ if ((lstrlen(procname) == 0) || (*p1 == 0)) return NULL;
+
+ // Ok, check If there is at least 1 param
+ p1++;
+ if (*p1 == 0) return NULL;
+
+ // Allocate memory for new Proc
+ proc = (SystemProc*) GlobalAlloc(GPTR, sizeof(SystemProc));
+
+ // Ok, retrieve dll handle
+ proc->dll = GetModuleHandle(dllname);
+ if (proc->dll == NULL)
+ {
+ // Dll is not loaded already
+ proc->dll = LoadLibrary(dllname);
+ if (proc->dll == NULL)
+ {
+ // Dll not found
+ GlobalFree(proc);
+ return NULL;
+ }
+ }
+
+ // Dll succesfully loaded, now we should Get Proc Address
+ proc->proc = GetProcAddress(proc->dll, procname);
+ if (proc->proc == NULL)
+ {
+ // Proc is not loaded succesfully
+ GlobalFree(proc);
+ return NULL;
+ }
+
+ // Allright, lets parse parameters
+ proc->ParamCount = 0;
+ while (*p1 && (*p1 != '?'))
+ {
+ // Memory is initialized to zeros with GlobalAlloc, so we don't need
+ // to set defaults for Parameters
+
+ // We should check for pointer
+ if ((*p1 == 'p') || (*p1 == 'P'))
+ {
+ proc->Params[proc->ParamCount].IsPointer = TRUE;
+ // Check for next character to be valid
+ p1++;
+ if ((*p1 == 0) || (*p1 == '?')) break;
+ }
+
+ switch(*p1)
+ {
+ case 'v':
+ case 'V':
+ proc->Params[proc->ParamCount].Type = PT_VOID;
+ break;
+ case 'i':
+ case 'I':
+ proc->Params[proc->ParamCount].Type = PT_INT;
+ break;
+ case 'l':
+ case 'L':
+ proc->Params[proc->ParamCount].Type = PT_LONG;
+ break;
+ case 's':
+ case 'S':
+ proc->Params[proc->ParamCount].Type = PT_STRING;
+ break;
+ case 'b':
+ case 'B':
+ proc->Params[proc->ParamCount].Type = PT_BOOLEAN;
+ break;
+ };
+
+ // Move to next character
+ proc->ParamCount++;
+ p1++;
+ }
+ return proc;
+}
+
+BOOL ParseParam(SystemProc *proc, char *ParamID)
+{
+ char *p1;
+ ProcParameter *par;
+
+ par = proc->Params + 1;
+ p1 = ParamID;
+
+ // Allright, lets parse input parameters
+ while (*p1 && (*p1 != '?'))
+ {
+ if ((*p1 == 's') || (*p1 == 'S')) par->Input = IOT_STACK;
+ else if ((*p1 == 'n') || (*p1 == 'N')) par->Input = IOT_NONE;
+ else if ((*p1 >= '0') && (*p1 <= '9')) par->Input = (*p1-'0')+1;
+ else if ((*p1 >= 'a') && (*p1 <= 'o')) par->Input = (*p1-'a')+11;
+ else if ((*p1 >= 'A') && (*p1 <= 'O')) par->Input = (*p1-'A')+11;
+
+ // Move to next param & character
+ par++;
+ p1++;
+ }
+
+ if (*p1++ == 0) return TRUE;
+ par = proc->Params;
+
+ // Allright, lets parse output parameters
+ while (*p1)
+ {
+ if ((*p1 == 's') || (*p1 == 'S')) par->Output = IOT_STACK;
+ else if ((*p1 == 'n') || (*p1 == 'N')) par->Output = IOT_NONE;
+ else if ((*p1 >= '0') && (*p1 <= '9')) par->Output = (*p1-'0')+1;
+ else if ((*p1 >= 'a') && (*p1 <= 'o')) par->Output = (*p1-'a')+11;
+ else if ((*p1 >= 'A') && (*p1 <= 'O')) par->Output = (*p1-'A')+11;
+
+ // Move to next param & character
+ par++;
+ p1++;
+ }
+
+ return TRUE;
+}
+
+void ParamsInput(SystemProc *proc)
+{
+ int i;
+ ProcParameter *par;
+ char buffer[PT_STRING_SIZE], *realbuf;
+
+ par = proc->Params + 1;
+ for (i = 1; i < proc->ParamCount; i++, par++)
+ {
+ // Step 1: retrive value
+ if (par->Input == IOT_STACK) popstring(realbuf = buffer);
+ else if (par->Input > 0) realbuf = getuservariable(par->Input - 1);
+ else *(realbuf = buffer) = 0;
+
+ // Step 2: place it
+ switch (par->Type)
+ {
+ // TODO: PT_VOID input????
+ //case PT_VOID:
+ case PT_INT:
+ {
+ if (par->IsPointer)
+ {
+ par->Value = (int) GlobalAlloc(GPTR, sizeof(int));
+ *((int*) par->Value) = myatoi(realbuf);
+ } else par->Value = myatoi(realbuf);
+ }
+ break;
+ case PT_LONG:
+ {
+ if (par->IsPointer)
+ {
+ par->Value = (int) GlobalAlloc(GPTR, sizeof(ULARGE_INTEGER));
+ ((ULARGE_INTEGER*) par->Value)->LowPart = myatoi(realbuf);
+ ((ULARGE_INTEGER*) par->Value)->HighPart = 0; // TODO: 64 bit atoi conversion
+ } else; // TODO: PT_LONG direct input????
+ }
+ break;
+ case PT_STRING:
+ {
+ if (par->IsPointer)
+ {
+ par->Value = (int) GlobalAlloc(GPTR, sizeof(int));
+ *((int*)par->Value) = GlobalAlloc(GPTR, PT_STRING_SIZE);
+ lstrcpy(*((LPCSTR*) par->Value), realbuf);
+ } else
+ {
+ par->Value = (int) GlobalAlloc(GPTR, PT_STRING_SIZE);
+ lstrcpy(par->Value, realbuf);
+ }
+ }
+ break;
+ // TODO: PT_BOOLEAN support ???
+ //case PT_BOLEAN: ;
+ }
+ }
+}
+
+void ParamsOutput(SystemProc *proc)
+{
+ int i;
+ ProcParameter *par;
+ char buffer[PT_STRING_SIZE];
+
+ par = proc->Params;
+ for (i = 0; i < proc->ParamCount; i++, par++)
+ {
+ // Step 1: retrieve value
+ switch (par->Type)
+ {
+ case PT_VOID:
+ {
+ if (par->IsPointer); // TODO: Pointer To Void Output
+ else *buffer = 0;
+ }
+ break;
+ case PT_INT:
+ {
+ if (par->IsPointer)
+ {
+ wsprintf(buffer, "%d", *((int*) par->Value));
+ GlobalFree(par->Value);
+ } else wsprintf(buffer, "%d", par->Value);
+ }
+ break;
+ case PT_LONG:
+ {
+ if (par->IsPointer)
+ {
+ wsprintf(buffer, "%ld", *((ULARGE_INTEGER*) par->Value));
+ GlobalFree(par->Value);
+ } else; // TODO: PT_LONG direct output????
+ }
+ break;
+ case PT_STRING:
+ {
+ if (par->IsPointer)
+ {
+ lstrcpy(buffer, *((LPCSTR*) par->Value));
+ GlobalFree(*((int*)par->Value));
+ GlobalFree(par->Value);
+ } else
+ {
+ lstrcpy(buffer, par->Value);
+ GlobalFree((HANDLE) par->Value);
+ }
+ }
+ break;
+ // TODO: PT_BOOLEAN support ???
+ //case PT_BOLEAN: ;
+ }
+
+ // Step 2: place it
+ if (par->Output == IOT_STACK) pushstring(buffer);
+ else if (par->Output > 0) setuservariable(par->Output - 1, buffer);
+ }
+}
+
+void SystemCall(SystemProc *proc)
+{
+ int z;
+ ProcParameter *par;
+
+ // Prepare input arguments
+ ParamsInput(proc);
+
+ // Push arguments to stack
+ par = proc->Params+proc->ParamCount-1;
+ while (par > proc->Params)
+ {
+ z = par->Value;
+ _asm
+ {
+ push z
+ }
+ par--;
+ }
+
+ // Call the proc and save return
+ z = proc->proc;
+ _asm
+ {
+ call z
+ mov z, eax
+ }
+ proc->Params[0].Value = z;
+
+ // Prepare output parameters
+ ParamsOutput(proc);
+}
+
+BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
+{
+ g_hInstance=hInst;
+
+ return TRUE;
+}
+
diff --git a/Contrib/System/System.h b/Contrib/System/System.h
new file mode 100644
index 00000000..55db95be
--- /dev/null
+++ b/Contrib/System/System.h
@@ -0,0 +1,50 @@
+// The following ifdef block is the standard way of creating macros which make exporting
+// from a DLL simpler. All files within this DLL are compiled with the SYSTEM_EXPORTS
+// symbol defined on the command line. this symbol should not be defined on any project
+// that uses this DLL. This way any other project whose source files include this file see
+// SYSTEM_API functions as being imported from a DLL, whereas this DLL sees symbols
+// defined with this macro as being exported.
+#pragma once
+
+#ifdef SYSTEM_EXPORTS
+#define SYSTEM_API __declspec(dllexport)
+#else
+#define SYSTEM_API __declspec(dllimport)
+#endif
+
+// Real world types
+#define PT_VOID 0
+#define PT_INT 1
+#define PT_LONG 2
+#define PT_STRING 3
+#define PT_BOOLEAN 4
+
+// Input/Output Source/Destination
+#define IOT_NONE 0
+#define IOT_STACK -1
+#define IOT_REG 1
+
+// Our single proc parameter
+typedef struct
+{
+ int Type;
+ BOOL IsPointer;
+ int Value; // it can hold any value
+ int Input;
+ int Output;
+} ProcParameter;
+
+// Our single proc
+typedef struct
+{
+ HANDLE dll;
+ HANDLE proc;
+ int ParamCount;
+ ProcParameter Params[20]; // I hope nobody will use more than 20 params
+} SystemProc;
+
+extern SystemProc *ParseProc(char *ProcID);
+extern BOOL ParseParam(SystemProc *proc, char *ParamID);
+extern void ParamsInput(SystemProc *proc);
+extern void ParamsOutput(SystemProc *proc);
+extern void SystemCall(SystemProc *proc);
diff --git a/Contrib/System/System.ncb b/Contrib/System/System.ncb
new file mode 100644
index 00000000..9057ebac
--- /dev/null
+++ b/Contrib/System/System.ncb
@@ -0,0 +1 @@
+Microsoft C/C++ MSF 7.00
diff --git a/Contrib/System/System.sln b/Contrib/System/System.sln
new file mode 100644
index 00000000..9268efc2
--- /dev/null
+++ b/Contrib/System/System.sln
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 7.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "System", "System.vcproj", "{2FB013AB-6FD4-4239-9974-C999F4DFD70C}"
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ ConfigName.0 = Debug
+ ConfigName.1 = Release
+ EndGlobalSection
+ GlobalSection(ProjectDependencies) = postSolution
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {2FB013AB-6FD4-4239-9974-C999F4DFD70C}.Debug.ActiveCfg = Debug|Win32
+ {2FB013AB-6FD4-4239-9974-C999F4DFD70C}.Debug.Build.0 = Debug|Win32
+ {2FB013AB-6FD4-4239-9974-C999F4DFD70C}.Release.ActiveCfg = Release|Win32
+ {2FB013AB-6FD4-4239-9974-C999F4DFD70C}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/Contrib/System/System.txt b/Contrib/System/System.txt
new file mode 100644
index 00000000..f6e7d037
--- /dev/null
+++ b/Contrib/System/System.txt
@@ -0,0 +1,163 @@
+ System: NSIS Plugin
+
+* - I'm a lazy bitch, for *(N) - see comment N at the end of the file.
+
+I. Introduction.
+----------------
+
+ That plugin will make you virtually unstopable. Now you could call any
+DLL procedure or function, i.e. you gain full control over the system.
+
+ If you want to call some proc, you should prepare two proc IDs: the
+ProcId and ParamID. Since the System plugin couldn't know the dll proc
+parameters and return type, you should find the proc description somewhere (the
+best will be .h files, for example from Platform SDK in case of system dlls).
+After that you should specify the ProcID: it contains the DLL and proc name,
+proc parameters, and proc calling options.
+ Since the parameters format of proc in DLL never changes (in general),
+that ProcID can be defined ones for all times (in include file for example, and
+I'm thinking about automatic conversion of some windows headers (winbase.h,
+winuser.h ...) to ProcID defines).
+
+ When you want to call the proc, you should prepare the second id,
+ParamID. It specifies where the System plugin should find your input values
+(registers, stack, etc) and where it should place proc output values. You can
+define this id once for installation, or you can use separate declaration at
+each call.
+
+II. ProcID.
+-----------
+
+ Ok. Let's learn how to convert function declaration to ProcID. Below
+the ProcID format is specified (You can read here *(1) why I'm using '?' as
+delimeter):
+
+"dll?proc?params?options", where:
+
+ - dll - the path (or name) of DLL containing proc (for ex: "kernel32",
+"c:\test\super.dll", etc.).
+ - proc - the proc name itself (warning: the proc name must be specified
+in the way it mentioned at dll, for example it may look like "_MyFunction@16".
+Other examples: "GetDiskFreeSpaceExA", "GetProcAddress", etc.).
+ - params - the proc parameters, described below.
+ - options - the proc options *(2) (for those, who don't want to read my
+comments - Currently Unavailable). At least two will be defined later: 'c' & 's'
+-> CDECL and STDCALL calling conventions. Should be completly (including
+question mark) ommited now.
+
+ Ok, each proc parameter (and return) is presented by single chararacter
+(there is only one exception - p character), these character are:
+
+ v - void (generaly for return)
+ i - int (includes char, byte, short, handles, pointers and so on)
+ l - long & large integer (know as int64)
+ s - string (LPCSTR, pointer to first character)
+ b - boolean (needs/returns 'true':'false') - by the fact this type is
+ senseless -> usual integer can be used ('0':'1')
+
+ p - pointer specifier -> the proc needs the pointer to type, affects
+ next char (parameter) [ex: 'pi' - pointer to int]
+
+ Huh, I think that is easily understandable, but there is one IMPORTANT
+HINT: the first parameter is RETURN type!
+ And at last: the pointers. You should remember that if you specify
+pointer parameter with 'p' specifier, the System Plugin waits from you and will
+return to you BASE TYPE, i.e. for 'pi' it will wait for and return to you
+INTEGER.
+ As I wrote above the options (including calling conventions are
+unsupported now), the System Plugin will always call DLL function with STDCALL
+(this convention is default for windows procs, for example for procs specified
+with WINAPI. CDECL is usually used with WINAPIV declared procs. This V char
+stands for variable, or arguments-list -> with CDECL convention the stack after
+the function call is cleared by caller, and with STDCALL it is cleared by called
+proc ('calee') -> all procs with arguments-lists (such as wsprintf) must use
+CDECL).
+
+IIa. ProcID examples.
+---------------------
+
+ Let's transform some real procs defenitions to ProcIDs:
+
+1) WINBASEAPI FARPROC WINAPI GetProcAddress(IN HMODULE hModule,
+ IN LPCSTR lpProcName);
+ For the start: proc defined with WINAPI - stdcall and thats allright.
+Proc return type FARPROC is just another name for proc handle (or address), so
+we could use integer type. This proc defined at kernel32.dll, but '.dll' could
+be ommited. So...
+
+"kernel32?GetProcAddress?iis"
+
+ Params: i - return, i - hModule, s - lpProcName.
+ Simple, huh?
+
+2) WINBASEAPI BOOL WINAPI GetDiskFreeSpaceExA( IN LPCSTR lpDirectoryName,
+ OUT PULARGE_INTEGER lpFreeBytesAvailableToCaller,
+ OUT PULARGE_INTEGER lpTotalNumberOfBytes,
+ OUT PULARGE_INTEGER lpTotalNumberOfFreeBytes
+ );
+
+ At first, If you'll look at MSDN, you will find GetDiskFreeSpaceEx
+function, but not with trailing 'A'. This is default Microsoft behaviour for
+functions, which have two variants: for ANSI (trailing 'A') and UNICODE
+(trailing 'W') respectively. You can meet such functions sometimes, and since
+neither NSIS or System Plugin support unicode you should always use version with
+trailing 'A'. PULARGE_INTEGER can be represented as (int64*) [pointer to long],
+so we will code this ProcID as:
+
+"kernel32.dll?GetDiskFreeSpaceExA?bsplplpl"
+
+ Params: b - return (boolean); pl, pl, pl - three pointer to long.
+
+ See other examples at System.nsh.
+
+III. ParamID.
+-------------
+
+ Ok, here is ParamID format:
+
+"input?output"
+
+Input/Output -> describes places (from where to take and where to put), encoded
+by single character too. The first character of output describes the place for
+function return.
+
+Input sources / Output destinations:
+ Registers $0-$9 -> 0..9
+ Registers $R0-$R9 -> a(0) b(1) c(2) d(3) e(4) f(5) g(6) h(7) i(8) j(9)
+ Additional regs -> k(CmdLine) l(InstDir) m(OutDir) n(ExeDir) o(Lang)
+ Stack -> s (parameters are poped/pushed in default, right-to-left order)
+ None -> n (0 (null) for input / specifies no output is required)
+
+VI. Functions.
+--------------
+
+Default return - on stack.
+
+handle = Alloc(bytes)
+ok? = Free(handle)
+handle = AllocCopy(handle) -> creates a copy
+
+----------
+
+addr = FullAddr(ProcID, ParamID) -> retrieve address for use with Call
+Call = FullCall(ProcID, ParamID) -> Direct call
+
+addr = PartAddr(ProcID)
+Call = Call(addr)
+
+----------
+
+Hint: These two change the passed proc, so if you want to preserve original
+proc use AllocCopy...
+
+addr = ShortAddr(addr, ParamID) -> For use if you half defined the proc
+Call = ShortCall(addr, ParamID) -> by PartAddr
+
+----------
+
+Comments (don't forget the * meaning :):
+ 1. I'm using '?' as delimiter just because I need some character to use
+as :). The other reason: '?' can't be spotted at dll paths and proc names.
+ 2. Currently unsupported. Some features, like buffers/structures,
+callbacks, different calling conventions, arg-lists, etc should become available
+at future releases.
\ No newline at end of file
diff --git a/Contrib/System/System.vcproj b/Contrib/System/System.vcproj
new file mode 100644
index 00000000..37af6d34
--- /dev/null
+++ b/Contrib/System/System.vcproj
@@ -0,0 +1,166 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Contrib/System/SystemEx.nsi b/Contrib/System/SystemEx.nsi
new file mode 100644
index 00000000..41350f16
--- /dev/null
+++ b/Contrib/System/SystemEx.nsi
@@ -0,0 +1,48 @@
+; This is just an example of System Plugin
+;
+; Read LastComments.txt and System.txt (unfinished)
+;
+; (c) BSForce, 2002
+
+Name "System Plugin Example"
+OutFile "SystemEx.exe"
+
+Function .onInit
+
+ ; First example: Message box, uses PartAddr, ShortAddr, Call
+
+ System::PartAddr "user32.dll?MessageBoxA?iissi"
+ Pop $0
+ System::ShortAddr "ssss?1nssn" $0
+ Pop $0
+ System::Call 33 "Example 1" "Just something" 0 $0
+ Pop $3
+ Pop $2
+ MessageBox MB_OK "Result: $1, strings '$2' and '$3'"
+ System::Free $0
+ Pop $0
+
+ ; Second example: uses FullAddr, Call, incorpotates int64, returns to $INSTDIR
+
+ System::FullAddr "snnn?s1al2" "kernel32.dll?GetDiskFreeSpaceExA?isplplpl"
+ Pop $0
+ System::Call "c:\" $0
+ Pop $3
+ MessageBox MB_OK "Path '$1', Free '$R0', Total '$INSTDIR', FreeUser '$2', Result $3"
+ System::Free $0
+ Pop $0
+
+ ; Third example: uses FullCall
+
+ System::FullCall "?9" "kernel32.dll?GetVersion?i"
+ ; Version aquired, but we wonna built number for example
+ IntOp $8 $9 / 65536
+ MessageBox MB_OK "Aquired windows version: $9 (Build $8)"
+
+ Quit
+FunctionEnd
+
+Section "ThisNameIsIgnoredSoWhyBother?"
+SectionEnd
+
+; eof
diff --git a/Contrib/System/stdafx.c b/Contrib/System/stdafx.c
new file mode 100644
index 00000000..5c6abfe6
--- /dev/null
+++ b/Contrib/System/stdafx.c
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes
+// AnyDLL.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/Contrib/System/stdafx.h b/Contrib/System/stdafx.h
new file mode 100644
index 00000000..1f363ded
--- /dev/null
+++ b/Contrib/System/stdafx.h
@@ -0,0 +1,12 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files:
+#include
+
+// TODO: reference additional headers your program requires here
diff --git a/Plugins/System.dll b/Plugins/System.dll
new file mode 100644
index 00000000..230a9c35
Binary files /dev/null and b/Plugins/System.dll differ