Contents |
int wb_call_function (int address [, array args])
Returns an integer that may be a valid value or a pointer to one object, according to the library function called.
You must perform the following steps to use a foreign function with WinBinder:
The pack() function should be used to pass a structure to a foreign function. Similarly, the unpack() function can retrieve structure fields as an associative array. Some common Windows types and their corresponding format characters for pack() / unpack() are listed in the table below.
| Windows | ANSI C | pack() | bytes |
|---|---|---|---|
| BYTE | unsigned char | C | 1 |
| DWORD | unsigned long | V | 4 |
| HANDLE¹ | void * | V | 4 |
| LONG | long | l | 4 |
| LPARAM | long | l | 4 |
| LPTSTR, LPCTSTR | unsigned short * | V | 4 |
| LRESULT | long | l | 4 |
| UINT | unsigned int | I | 4 |
| WORD | unsigned short | v | 2 |
| WPARAM | unsigned int | I | 4 |
| ¹ Note: Most Windows and GDI handles, like HINSTANCE, HWND, HACCEL, HBITMAP, HICON etc. are 32-bit handles and should be packed identically. | |||
Up to three constants are needed for each structure. The best way is to define them in advance to improve code readability. For example, the Windows API documentation defines a MEMORYSTATUS structure that is passed to the GlobalMemoryStatus() function to retrieve information about the system memory. The definition is as follows:
typedef struct _MEMORYSTATUS {
DWORD dwLength; // sizeof(MEMORYSTATUS)
DWORD dwMemoryLoad; // percent of memory in use
DWORD dwTotalPhys; // bytes of physical memory
DWORD dwAvailPhys; // free physical memory bytes
DWORD dwTotalPageFile; // bytes of paging file
DWORD dwAvailPageFile; // free bytes of paging file
DWORD dwTotalVirtual; // user bytes of address space
DWORD dwAvailVirtual; // free user bytes
} MEMORYSTATUS;
Because the structure consists of eight DWORDs, we can create a constant to format the structure like this:
define("MEMORYSTATUS_RAW", "VVVVVVVV");
or
define("MEMORYSTATUS_RAW", "V8");
This is enough to pass the structure to the function. To retrieve the structure, however, we need a different structure so that unpack() function can return an associative array with the field names:
define("MEMORYSTATUS", "Vlen/Vmemload/Vphys/Vavailphys/Vpagefile/Vavailpagefile/Vvirtual/Vavailvirtual")
Finally, because we must also pass the size of the structure, we define another constant:
define("MEMORYSTATUS_SIZE", 8 * 4);
The mini-program below shows how to call a Windows function in a single PHP line.
<?
// Shows the current ANSI code-page identifier for the operating system.
include "../include/winbinder.php";
wb_message_box(0, "ANSI code-page identifier: " . wb_call_function(wb_get_function_address("GetACP", wb_load_library("KERNEL"))));
?>
The example below shows how to create a new PHP function that calls a Windows function.
<?
include "../include/winbinder.php"; // Location of WinBinder library
// STEP 1: Load the DLL that contains the function
$KERNEL = wb_load_library("KERNEL");
// STEP 2: Get function address
$fgms = wb_get_function_address("GlobalMemoryStatus", $KERNEL);
// STEP 3: Declare constants for all structures
define("MEMORYSTATUS", "Vlen/Vmemload/Vphys/Vavailphys/Vpagefile/Vavailpagefile/Vvirtual/Vavailvirtual");
define("MEMORYSTATUS_RAW", "V8");
define("MEMORYSTATUS_SIZE", 8 * 4);
// STEP 4: Create function that uses foreign function
function GlobalMemoryStatus()
{
global $KERNEL, $fgms;
$val = pack(MEMORYSTATUS_RAW, MEMORYSTATUS_SIZE,0,0,0,0,0,0,0);
wb_call_function($fgms, array($val));
return unpack(MEMORYSTATUS, $val);
}
// STEP 5: Use the newly declared PHP function as any other regular PHP function.
$mem = GlobalMemoryStatus();
$report = "Total RAM is " . sprintf("%.2f", ($mem["phys"] / (1024 * 1024))) . " MB, " . $mem["memload"] . "% used";
wb_message_box(null, $report);
?>
Parameters are passed in a array. In the following example we pass only one parameter. Our function simply returns the result from wb_call_function().
function GetSystemMetrics($what)
{
global $USER, $KERNEL, $GDI;
static $pfn = null;
if($pfn === null)
$pfn = wb_get_function_address("GetSystemMetrics", $USER);
return wb_call_function($pfn, array($what));
}
If our function returns a string pointer we need to wrap a wb_peek() around the wb_call_function() in order to read the returning memory address. That address contains the real value.
function GetCommandLine()
{
global $USER, $KERNEL, $GDI;
static $pfn = null;
if($pfn === null)
$pfn = wb_get_function_address("GetCommandLine", $KERNEL);
return wb_peek(wb_call_function($pfn));
}
If we going to get a structure in return we have to define it first.
define("SYSTEMTIME", "vyear/vmonth/vdayofweek/vday/vhour/vminute/vsecond/vms");
define("SYSTEMTIME_RAW", "v8");
define("SYSTEMTIME_SIZE", 8 * 2);
In this case we need to pass a large enough variable to the function (GetSystemTime) to hold the returning data. This can be done with str_repeat and the so called null-character (a backslash and a zero). From our definition we know the maximum size of the structure (see table above). We can now pass this variable as parameter as usual. The difference here is that we unpack the variable $val after wb_call_function() based on our definied structure 'SYSTEMTIME'.
function GetSystemTime()
{
global $USER, $KERNEL, $GDI;
static $pfn = null;
if($pfn === null)
$pfn = wb_get_function_address("GetSystemTime", $KERNEL);
$val = str_repeat("\0", SYSTEMTIME_SIZE); // create a large enough variable
wb_call_function($pfn, array($val));
return unpack(SYSTEMTIME, $val); // unpack it
}
The structure of MEMORYSTATUS consists of 8 values. The first value is the size of the structure according to the struct decleration. The other 7 values are zeros because they are supposed to be changed by the function. The variable $var now contains the struct we want to pass to the function. After we have called the function $val has most likely been changed and we then return it by using the unpack function as described above to get an array of all values the structure offers.
function GlobalMemoryStatus()
{
global $USER, $KERNEL, $GDI;
static $pfn = null;
if($pfn === null)
$pfn = wb_get_function_address("GlobalMemoryStatus", $KERNEL);
$val = pack(MEMORYSTATUS_RAW, MEMORYSTATUS_SIZE, 0, 0, 0, 0, 0, 0, 0);
wb_call_function($pfn, array($val));
return unpack(MEMORYSTATUS, $val);
}
Note: In this example only zeros are packed. This is requested by the function; Of course you could pack other values and variables if necessary. Sometimes values within a struct also act as parameters.