NSIS/Contrib/System/System.txt
joostverburg 88956798f1 System plugin
git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@1130 212acab6-be3b-0410-9dea-997c60f758d6
2002-09-21 20:59:13 +00:00

163 lines
No EOL
6.7 KiB
Text

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.