/*
+----------------------------------------------------------------------+
- | PHP Version 4 |
+ | PHP version 4.0 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2002 The PHP Group |
+ | Copyright (c) 1997-2001 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 2.02 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
- | Author: James Moore <jmoore@php.net> |
+ | Authors: James Moore <jmoore@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+/*
+ * Win32 API Extension for PHP 4
+ * =============================
+ *
+ * This extension allows PHP Developers to access the underlying functions in the
+ * Win32 API Dll's in a generic way, it provides a mechanism for the user to load
+ * and register functions from dll's and then to call them, it also implements a
+ * generic callback handler which allows the user to pass a pointer to one of
+ * their PHP functions to act as a callback from the C function enabling the PHP
+ * programmer to handle callbacks in PHP seemlessly. Finally the extension marshalls
+ * from PHP types (Zvals) to C structures seemlessly once it has been told about them
+ *
+ * I would like to thank Ton Plooy for his article on a similar subject which gave me
+ * the initial idea for a generic dll caller and some good pointers on how to actaully
+ * implement it.
+ */
+
+/*
+ * Interface the PHP Programmer Sees
+ * ==================================
+ *
+ * To keep namespaces tidy the module will introduce two classes, the first is
+ * the win32 class which has several functions to load and register functions from
+ * the underlying DLL's. The Win32 class also has functions for informing the
+ * module about the C types we will be using so it can marshall and demarshall to and from
+ * the C Interface. . Our second class is the Type class. The type class is our container
+ * for complex C types which are registered and initiated using our win32 class functions.
+ *
+ * Win32 Class Functions
+ * =====================
+ *
+ * static int Win32::RegisterFunction( string Definition, long flags )
+ * -------------------------------------------------------------------
+ *
+ * This function is used for registering a dll function with the module. The Definition should take
+ * the form:
+ * Definition: <return_type> <function_name> [Alias <alias_name] (<argument_list>) From <some_dll>
+ *
+ * return_type :- Either a simple type or a type that has
+ * been registered with the module
+ *
+ * function_name :- The name of the function within the dll, if this is not found
+ * we append an A to the function name to check for a ASCII version,
+ * if this is not found we fail.
+ *
+ * alias_name :- If this is provided then we register the function under this name
+ * in the PHP Symbol table.
+ *
+ * argument_list :- A comma seperated list of arguments in the form <argument_type>
+ * [&]argument_name.
+ *
+ * argument_type :- Argument type is a type known to the module
+ *
+ * argument_name :- This is not currently used although if it is proceeded by an
+ * & (Ampersand) then a pointer is passed rather than the value.
+ *
+ * some_dll :- This is the name of the dll to find the function in.
+ *
+ * On success the function returns TRUE, on error FALSE, The function issues appropriate errors
+ * to allow the PHP Progammer to catch individual errors.
+ *
+ * static int Win32::UnregisterFunction(string FunctionName)
+ * ---------------------------------------------------------
+ *
+ * Allows the PHP programmer to force a funciton to be unregistered saving on memory resources. Can
+ * be useful in long running scripts.
+ *
+ * Returns TRUE on success, FALSE on error.
+ *
+ *
+ * static int Win32::DefineType( string Definition )
+ * -------------------------------------------------
+ *
+ * This function is used to register a C-Type which will be used when calling a function, it only
+ * supports the equivilent of C structures at this time so if you need to use a union you must use the
+ * largest member of that union as the type in the struct for this to work.
+ *
+ * The definition string takes the form:
+ *
+ * Definition: <type_name> { <type_list> }
+ *
+ * type_name :- A unique name for this type.
+ *
+ * type_list :- Takes for form <member_type> [&]<member_name>
+ *
+ * member_type :- The type of this member.
+ *
+ * member_name :- The name for this member, if an & (ampersand) preceeds
+ * the name it will be stripped and a pointer rather than
+ * the value will be used.
+ *
+ * Returns TRUE on success, FALSE on error.
+ *
+ *
+ * static int Win32::GetTypeSize(mixed TypeHandle)
+ * -----------------------------------------------
+ *
+ * This function returns the size of a type registered with the module. The parameter should
+ * either be the name of the type or an instance of it. The Function returns FALSE on error
+ * ***USE === to distinguish between this and a size of 0*** or the size of the type on success.
+ *
+ *
+ * static mixed Win32::InitType(String TypeName)
+ * ---------------------------------------------
+ *
+ * Creates an instance of the type so that the PHP Programmer can assign values and then pass
+ * it to a C Function. Returns NULL on error.
+ *
+ * static int Win32::DecRef(mixed var)
+ * -----------------------------------
+ * Decreases the reference count on a variable only if we incremented the refcount when passing
+ * the variable to a C function.
+ *
+ * TYPE Functions
+ * ==============
+ *
+ * mixed Type::Type(String TypeName)
+ * ---------------------------------
+ * See Win32::InitType,
+ *
+ * mixed Type::Clone()
+ * -------------------
+ *
+ * Allows you to make an exact copy of the class, this should be used rather than the &= syntax
+ * Due to the nesting within classes. This function WILL become redundant in PHP 5.
+ */
+
+/*
+ * Implementation Details
+ * ======================
+ *
+ * This module will only work on the Intel platform.
+ *
+ * We basically want to set up this structure:
+ *
+ * +-----------+
+ * | PHP |
+ * +-----------+
+ * Call | /|\
+ * \|/ | call_user_function_ex
+ * +------------------------+
+ * | Win 32 API Extension |
+ * +------------------------+
+ * | /|\
+ * \|/ | Callback
+ * +-------------+
+ * | C-Space |
+ * +-------------+
+ *
+ * Win32 Needs to then Marshall between zvals and
+ *
+ * Marshalling from ZVAL's to C Types.
+ * -----------------------------------
+ * For simple types this is very easy as we either just copy the value or a pointer
+ * to it onto the stack, if we copy a pointer then we must increase the refcount on
+ * the zval and must also make sure we get it passed to us by reference.
+ *
+ * The problem here is when to dereference the zval again as we may get into the following
+ * situation
+ *
+ * We call somefunction giving it an argument by reference (IE we pass a pointer to the value union of a zval)
+ * we must increase the ref count on the zval to avoid the possibility of a GPE (IE the zval is dtord and then
+ * the function uses the zval in some sort of callback we could end up with a GPE)
+ * But if we increase the zval's refcount without dtoring it anywhere it would cause a mem leak.
+ *
+ * Therefore we probably need to keep a local reference table so we can either allow the user to call
+ * Win32::DecRef($var) to decrement the reference count (We would want to keep a local table to avoid anyone
+ * breaking Zend's handling off it as well..))
+ *
+ * Then at MSHUTDOWN we free this hashtable decrementing the refcount as needed..
+ *
+ * Complex types are less clear cut on how to handle them. My prefered method is to always
+ * keep these in a C Format but to allow access to these via a wrapper object which calculates
+ * the offset of the data to allow access to it from PHP. This also allows us to do no conversion
+ * when dealing with C types coming to us allowing us to deal with pointers in a more clear way.
+ *
+ *
+ * Enabling C Code to call PHP Code in a generic fashion
+ * -----------------------------------------------------
+ * What we do here is we use _declspec(naked) to tell the compiler we will handle all stack operations
+ * ourself, we also then create (At runtime) function prologues which we place on the heap which push
+ * extra arguments onto the stack which tell us which php_function is being called back and the callback type
+ * which has been registered with us.
+ *
+ */
+
+#if HAVE_W32API
-#if HAVE_W32API
#include <stdio.h>
#include <stdlib.h>
-#define WIN32_LEAN_AND_MEAN
+
+#define WINDOWS_LEAN_AND_MEAN
#include <windows.h>
#include "php.h"
#include "ext/standard/php_string.h"
#include "php_w32api.h"
-/* {{{ w32api_functions[]
+
+/* =====================================================================================================
+ * PHP Module Startup, Shutdown & Info Code
+ * =====================================================================================================
*/
-function_entry w32api_functions[] = {
- PHP_FE(w32api_register_function, NULL)
- PHP_FE(w32api_deftype, NULL)
- PHP_FE(w32api_init_dtype, NULL)
- PHP_FE(w32api_set_call_method, NULL)
- PHP_FE(w32api_invoke_function, NULL)
- {NULL, NULL, NULL}
-};
-/* }}} */
+
+#ifdef COMPILE_DL_W32API
+ZEND_GET_MODULE(w32api)
+#endif
/* {{{ w32api_module_entry
*/
zend_module_entry w32api_module_entry = {
STANDARD_MODULE_HEADER,
- "w32api",
- w32api_functions,
+ "Win32 API",
+ NULL, /* We define no global functions */
PHP_MINIT(w32api),
PHP_MSHUTDOWN(w32api),
- NULL,
- NULL,
+ PHP_RINIT(w32api),
+ PHP_RSHUTDOWN(w32api),
PHP_MINFO(w32api),
- "0.1", /* Replace with version number for your extension */
+ "0.2",
STANDARD_MODULE_PROPERTIES
};
/* }}} */
-ZEND_DECLARE_MODULE_GLOBALS(w32api)
-
-#ifdef COMPILE_DL_W32API
-ZEND_GET_MODULE(w32api)
-#endif
-
-/* {{{ PHP_MINFO_FUNCTION
- */
-PHP_MINFO_FUNCTION(w32api)
-{
- php_info_print_table_start();
- php_info_print_table_row(2, "Win32 API Support", "enabled" );
- php_info_print_table_end();
-}
-/* }}} */
/* {{{ PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION(w32api)
{
+ /* Setup out module globals */
ZEND_INIT_MODULE_GLOBALS(w32api, php_w32api_init_globals, NULL);
- register_constants(module_number);
- W32_G(le_dynaparm) = zend_register_list_destructors_ex(w32api_free_dynaparm, NULL, "dynaparm", module_number);
-
- return SUCCESS;
-}
-/* }}} */
-/* {{{ PHP_MSHUTDOWN_FUNCTION
- */
-PHP_MSHUTDOWN_FUNCTION(w32api)
-{
- if(W32_G(regfuncs))
+ if(win32_class_init(TSRMLS_C) != SUCCESS)
{
- FREE_HASHTABLE(W32_G(regfuncs));
+ return FAILURE;
}
- if(W32_G(libraries))
+ if(type_class_init(TSRMLS_C) != SUCCESS)
{
- php_w32api_unload_libraries();
- FREE_HASHTABLE(W32_G(libraries));
+ return FAILURE;
}
- if(W32_G(libraries))
- {
- FREE_HASHTABLE(W32_G(types));
- }
+ WG(le_type_instance) = zend_register_list_destructors_ex(w32api_type_instance_dtor, NULL, "Type Instance", module_number);
+
+ /* Function Flags */
+ REGISTER_LONG_CONSTANT( "W32API_ARGPTR", W32API_ARGPTR, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT( "W32API_BORLAND", W32API_BORLAND, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT( "W32API_CDECL", W32API_CDECL, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT( "W32API_REAL4", W32API_REAL4, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT( "W32API_REAL8", W32API_REAL8, CONST_CS | CONST_PERSISTENT);
+
+
+ return SUCCESS;
+};
+/* }}} */
+
+/* {{{ PHP_MSHUTDOWN_FUNCTION
+ */
+PHP_MSHUTDOWN_FUNCTION(w32api)
+{
return SUCCESS;
}
/* }}} */
-/* {{{ DYNAPARM dtor */
-static void w32api_free_dynaparm(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+/* {{{ PHP_RINIT_FUNCTION
+ */
+PHP_RINIT_FUNCTION(w32api)
{
- DYNAPARM *dparam;
+ /* Allocate Request Specific HT's here
+ */
+ ALLOC_HASHTABLE(WG(funcs));
+ zend_hash_init(WG(funcs), 1, NULL, php_w32api_hash_func_dtor, 1);
- dparam = (DYNAPARM *)rsrc->ptr;
+ ALLOC_HASHTABLE(WG(libraries));
+ zend_hash_init(WG(libraries), 1, NULL, php_w32api_hash_lib_dtor, 1);
- if(dparam->pArg)
- efree(dparam->pArg);
+ ALLOC_HASHTABLE(WG(callbacks));
+ zend_hash_init(WG(callbacks), 1, NULL, php_w32api_hash_callback_dtor, 1);
- efree(dparam);
-}
+ ALLOC_HASHTABLE(WG(types));
+ zend_hash_init(WG(types), 1, NULL, php_w32api_hash_type_dtor, 1);
+
+
+ return SUCCESS;
+
+};
/* }}} */
-/* {{{ */
-static void php_w32api_unload_libraries()
+/* {{{ PHP_RSHUTDOWN_FUNCTION
+ */
+PHP_RSHUTDOWN_FUNCTION(w32api)
{
- TSRMLS_FETCH();
- zend_hash_destroy(W32_G(libraries));
+
+ win32_class_rshutdown(TSRMLS_C);
+
+ /* Must be dtor'd before libraries */
+ zend_hash_destroy(WG(funcs));
+ FREE_HASHTABLE(WG(funcs));
+
+ zend_hash_destroy(WG(libraries));
+ FREE_HASHTABLE(WG(libraries)); /* we may only want to do this on MSHUTDOWN but for now it can be here */
+
+ zend_hash_destroy(WG(callbacks));
+ FREE_HASHTABLE(WG(callbacks));
+
+ zend_hash_destroy(WG(types));
+ FREE_HASHTABLE(WG(types));
+
+
+ return SUCCESS;
}
/* }}} */
-/* {{{ */
-static void php_w32api_dtor_library(void *data)
+
+/* {{{ PHP_MINFO_FUNCTION
+ */
+PHP_MINFO_FUNCTION(w32api)
{
- FreeLibrary((HINSTANCE)data);
+ php_info_print_table_start();
+ php_info_print_table_row(2, "Win32 API Support", "enabled" );
+ php_info_print_table_end();
}
/* }}} */
-/* {{{ */
+/* {{{ php_w32api_init_globals
+ */
static void php_w32api_init_globals(zend_w32api_globals *w32api_globals)
{
- TSRMLS_FETCH();
-
- w32api_globals->regfuncs = NULL;
+ w32api_globals->win32_ce = NULL;
+ w32api_globals->type_ce = NULL;
+ w32api_globals->funcs = NULL;
w32api_globals->libraries = NULL;
+ w32api_globals->callbacks = NULL;
w32api_globals->types = NULL;
- w32api_globals->call_type = DC_CALL_STD;
+}
+/* }}} */
- ALLOC_HASHTABLE(W32_G(regfuncs));
- zend_hash_init(W32_G(regfuncs), 1, NULL, NULL, 1);
+/* {{{ php_w32api_hash_lib_dtor (void *data)
+ * Dtor function called when hash is destroied, unloads library
+ */
+static void php_w32api_hash_lib_dtor(void *data)
+{
+ w32api_lib_handle *lh; /* Library Handle */
+ TSRMLS_FETCH(); /* Get thread safe stuff */
+ lh = (w32api_lib_handle *)data;
- ALLOC_HASHTABLE(W32_G(libraries));
- zend_hash_init(W32_G(libraries), 1, NULL, php_w32api_dtor_library, 1);
+ FreeLibrary(lh->handle);
+ efree(lh->library_name);
+}
+/* }}} */
- ALLOC_HASHTABLE(W32_G(types));
- zend_hash_init(W32_G(types), 5, NULL, NULL, 1);
+/* {{{ php_w32api_hash_func_dtor (void *data)
+ * Dtor function called when hash is destroied, unloads function.
+ */
+static void php_w32api_hash_func_dtor(void *data)
+{
+ w32api_func_handle **fh; /* Function Handle */
+ TSRMLS_FETCH(); /* Get thread safe stuff */
+ fh = (w32api_func_handle **)data;
+ php_w32api_unload_function(fh TSRMLS_CC);
}
/* }}} */
-/* {{{ */
-static void register_constants(int module_number)
+/* {{{ php_w32api_hash_callback_dtor
+ * DTOR function called when hash is destroied, removes callback.
+ */
+static void php_w32api_hash_callback_dtor(void *data)
{
- TSRMLS_FETCH();
+ w32api_func_handle **fh;
+
+ fh = (w32api_func_handle **)data;
- W32_REG_CONST(DC_MICROSOFT)
- W32_REG_CONST(DC_BORLAND)
- W32_REG_CONST(DC_CALL_CDECL)
- W32_REG_CONST(DC_CALL_STD)
- W32_REG_CONST(DC_RETVAL_MATH4)
- W32_REG_CONST(DC_RETVAL_MATH8)
- W32_REG_CONST(DC_CALL_STD_BO)
- W32_REG_CONST(DC_CALL_STD_MS)
- W32_REG_CONST(DC_CALL_STD_M8)
- W32_REG_CONST(DC_FLAG_ARGPTR)
+ php_w32api_free_arguments((*fh)->argument_list);
+ efree((*fh)->function_name);
+
+ if((*fh)->return_type_name)
+ efree((*fh)->return_type_name);
+ efree(*fh);
+}
+
+/* {{{ php_w32api_hash_type_dtor
+ * DTOR function called when hash is destroied, removes callback.
+ */
+static void php_w32api_hash_type_dtor(void *data)
+{
+ w32api_type_handle **th;
+
+ th = (w32api_type_handle **)data;
+
+ php_w32api_free_members((*th)->member_list);
+ efree((*th)->type_name);
+ efree(*th);
}
-/* }}} */
-/* {{{ proto void w32api_set_call_method(int method)
- Sets the calling method used */
-PHP_FUNCTION(w32api_set_call_method)
+static void w32api_type_instance_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
- zval **method;
+ w32api_type_instance *ti;
+ int i = 0;
- if(zend_get_parameters_ex(1, &method) == FAILURE)
- {
- WRONG_PARAM_COUNT
- }
+ if(!rsrc || !rsrc->ptr)
+ return;
- switch((*method)->value.lval)
+ ti = (w32api_type_instance *)rsrc->ptr;
+
+ for(i = 0; i < ti->type->member_count; i++)
{
- case DC_CALL_CDECL:
- W32_G(call_type) = DC_CALL_CDECL;
- break;
- default:
- W32_G(call_type) = DC_CALL_STD;
- break;
+ if(ti->values[i])
+ zval_ptr_dtor(&ti->values[i]);
}
- RETURN_TRUE
-
+ efree(ti);
+
+ return;
}
-/* }}} */
+/* =====================================================================================================
+ * Utility Functions
+ * =====================================================================================================
+ */
-/* {{{ proto bool w32api_register_function(string libary, string function_name)
- Registers function function_name from library with PHP */
-PHP_FUNCTION(w32api_register_function)
+/* {{{ php_w32api_unload_library
+ * Expects two arguments, the first is the pointer to a w32api_lib_handle
+ * and the second is a flag, if the flag is 0 then the reference counter is
+ * use if it is one then the library is unloaded irrespective of the reference
+ * counter
+ */
+static void php_w32api_unload_library (w32api_lib_handle *lh, int flags TSRMLS_DC)
{
- HINSTANCE hinstLib;
- FARPROC ProcAdd;
- W32APIFE *fe;
- BOOL fRunTimeLinkSuccess = FALSE;
- zval **libname, **funcname, **retval_type;
- void *tmp;
- runtime_struct *rst;
- if(zend_get_parameters_ex(3, &libname, &funcname, &retval_type) == FAILURE)
+ if(flags == 0)
{
- WRONG_PARAM_COUNT
+ lh->ref_count--;
}
- convert_to_string_ex(libname);
- convert_to_string_ex(funcname);
- convert_to_string_ex(retval_type);
+ if((flags == 1) || (lh->ref_count == 0))
+ {
+ /* remove outselves from the hashtable */
+ zend_hash_del(WG(libraries), lh->library_name, strlen(lh->library_name) + 1);
+ }
+}
+/* }}} */
- fe = (W32APIFE *)emalloc(sizeof(W32APIFE));
- fe->retvaltype = 0;
- //TODO: Check library isnt alreay loaded
+/* {{{ php_w32api_unload_function
+ * Expects one argument, a pointer to a w32api_func_handle, unloads this
+ * function from both the function table internally and the PHP function
+ * table then it decrements the reference counter on the library.
+ */
+static void php_w32api_unload_function (w32api_func_handle **fh TSRMLS_DC)
+{
+ zend_function *function = NULL;
- hinstLib = LoadLibrary((*libname)->value.str.val);
+ efree((*fh)->return_type_name);
+ php_w32api_free_arguments((*fh)->argument_list);
- if(hinstLib == NULL)
+ /* If needs be we need to retrieve function ptr from hash table
+ * and free anything we allocate when creating them at runtime (most notably
+ * arg_types
+ */
+ if(zend_hash_find( &WG(win32_ce)->function_table,
+ (*fh)->function_name,
+ strlen((*fh)->function_name) + 1,
+ (void **)&function) == SUCCESS)
{
- php_error(E_WARNING, "Could not load dynamic link library %s", (*libname)->value.str.val);
- RETURN_FALSE
+ zend_internal_function *internal_function = (zend_internal_function *)function;
+ if(internal_function->arg_types)
+ efree(internal_function->arg_types);
}
- zend_hash_add(W32_G(libraries),
- (*libname)->value.str.val,
- strlen((*libname)->value.str.val),
- &hinstLib,
- sizeof(HINSTANCE),
- NULL);
+ /* Remove from Function Table */
+ zend_hash_del(&WG(win32_ce)->function_table, (*fh)->function_name, strlen((*fh)->function_name) + 1);
+ php_w32api_unload_library((*fh)->lib, 0 TSRMLS_CC);
+
+ efree((*fh)->function_name);
+ efree(*fh);
+
+}
+/* }}} */
- //TODO: Check function handle isnt already loaded
+/* {{{ php_w32api_load_function
+ * Expects three arguments, The definition of the function in string format, the definitions length
+ * and a pointer to a pointer to a function handle. returns SUCCESS or FAILURE.
+ */
+static int php_w32api_load_function (char *definition, int definition_len, int flags TSRMLS_DC)
+{
+ zend_function function;
+ zend_internal_function *internal_function = (zend_internal_function *)&function;
+ w32api_func_handle **fh;
+ w32api_func_handle_ptr hnd;
- ProcAdd = (FARPROC) GetProcAddress(hinstLib, (*funcname)->value.str.val);
+ fh = emalloc(sizeof(w32api_func_handle *));
+ *fh = NULL;
- if(ProcAdd == NULL)
+ /* Parse function */
+ w32api_function_definition_scan_bytes(definition, definition_len);
+ if((w32api_function_definition_parse((void *)&hnd) != 0))
{
- php_error(E_WARNING, "Could not get handle for function %s", (*funcname)->value.str.val);
- RETURN_FALSE
+ *fh = hnd.hnd;
+ if(*fh != NULL)
+ efree(*fh);
+
+ efree(fh);
+ return FAILURE;
}
+ *fh = hnd.hnd;
- fe->fp = ProcAdd;
+ if(!*fh)
+ return FAILURE;
- if(!strcmp((*retval_type)->value.str.val, "long"))
- {
- fe->rettype = malloc(5*sizeof(char));
- fe->rettype = strdup("long\0");
- }
- else if (!strcmp((*retval_type)->value.str.val, "int"))
+
+ if(zend_hash_exists(&WG(win32_ce)->function_table, (*fh)->function_name, strlen((*fh)->function_name) + 1))
{
- fe->rettype = malloc(4*sizeof(char));
- fe->rettype = strdup("long\0");
+ php_error( E_WARNING,
+ "A function by the name %s already has been registered, cannot redefine function",
+ (*fh)->function_name);
+
+ /* We dont want to unload function as it already exists so lets just free it ourselves */
+ php_w32api_unload_library((*fh)->lib, 0 TSRMLS_CC);
+ php_w32api_free_arguments((*fh)->argument_list);
+ efree((*fh)->return_type_name);
+ efree((*fh)->function_name);
+ efree(*fh);
+ efree(fh);
+
+ return FAILURE;
}
- else if (!strcmp((*retval_type)->value.str.val, "string"))
+
+ /* Insert it into our hash table */
+ if(zend_hash_add( WG(funcs),
+ (*fh)->function_name,
+ strlen((*fh)->function_name) + 1,
+ fh,
+ sizeof(w32api_func_handle),
+ NULL) != SUCCESS)
{
- fe->rettype = malloc(7*sizeof(char));
- fe->rettype = strdup("string\0");
+
+ php_error( E_WARNING,
+ "Loading of function %s failed: Could not insert function handle into hash",
+ (*fh)->function_name);
+
+ /* Tidy up */
+ zend_hash_del(WG(funcs), (*fh)->function_name, strlen((*fh)->function_name) +1);
+ return FAILURE;
}
- else if (!strcmp((*retval_type)->value.str.val, "byte"))
+
+ /* Insert function into win32_ce's function_table */
+ internal_function->type = ZEND_INTERNAL_FUNCTION;
+ internal_function->handler = W32API_CLASS_FN(win32, invokefunction);
+ internal_function->function_name = (*fh)->function_name;
+ internal_function->arg_types = php_w32api_do_arg_types(&(*fh)->argument_list);
+
+ if(zend_hash_add(&WG(win32_ce)->function_table, (*fh)->function_name,
+ strlen((*fh)->function_name) + 1, &function, sizeof(zend_function), NULL) == FAILURE)
{
- fe->rettype = malloc(5*sizeof(char));
- fe->rettype = strdup("byte\0");
+ php_error(E_ERROR, "Could not register funciton %s into function table", (*fh)->function_name);
+ zend_hash_del(WG(funcs), (*fh)->function_name, strlen((*fh)->function_name) +1);
+
+ return FAILURE;;
}
- else if (!strcmp((*retval_type)->value.str.val, "double"))
+
+ if(flags)
{
- fe->rettype = malloc(7*sizeof(char));
- fe->rettype = strdup("double\0");
+ (*fh)->flags = (*fh)->flags | flags;
}
- else if (!strcmp((*retval_type)->value.str.val, "bool"))
+
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ php_w32api_unload_type
+ * Expects one argument, a pointer to a w32api_type_handle, unloads this
+ * type.
+ */
+static void php_w32api_unload_type (w32api_type_handle **th TSRMLS_DC)
+{
+ php_w32api_free_members((*th)->member_list);
+
+ zend_hash_del(WG(types), (*th)->type_name, strlen((*th)->type_name) + 1);
+
+}
+/* }}} */
+
+/* {{{ php_w32api_register_type
+ */
+static int php_w32api_register_type(char *type_definition, int type_definition_len TSRMLS_DC)
+{
+ w32api_type_handle **th;
+ w32api_type_handle_ptr hnd;
+
+ th = emalloc(sizeof(w32api_type_handle *));
+ *th = NULL;
+
+ w32api_type_definition_scan_bytes(type_definition, type_definition_len);
+ if(w32api_type_definition_parse((void *)&hnd) != 0)
{
- fe->rettype = malloc(5*sizeof(char));
- fe->rettype = strdup("bool\0");
+ *th = hnd.hnd;
+
+ /* Leaks */
+ if(*th != NULL)
+ efree(*th);
+
+ efree(th);
+ return FAILURE;
}
- else
+
+ *th = hnd.hnd;
+
+ if(!*th)
+ return FAILURE;
+
+ if((zend_hash_exists(WG(callbacks), (*th)->type_name, strlen((*th)->type_name) +1)) ||
+ (zend_hash_exists(WG(types), (*th)->type_name, strlen((*th)->type_name) + 1)))
{
- /**
- * this could be a userdef'd type so lets
- * search the ht for that.
- */
- if(zend_hash_find(W32_G(types), (*retval_type)->value.str.val, (*retval_type)->value.str.len, (void **) &tmp) == FAILURE)
- {
- php_error(E_WARNING, "Unknown type %s", (*retval_type)->value.str.val);
- RETURN_FALSE;
- }
- rst = tmp;
- fe->rettype = malloc(sizeof(char) * strlen(rst->name) + 1);
- memcpy(fe->rettype, rst->name, strlen(rst->name) + 1);
- fe->retvaltype = 1;
+ php_error( E_WARNING,
+ "A type or callback by the name %s already has been registered, cannot redefine type or callback",
+ (*th)->type_name);
+
+ /* We dont want to unload function as it already exists so lets just free it ourselves */
+ php_w32api_free_members((*th)->member_list);
+ efree((*th)->type_name);
+ efree(*th);
+ efree(th);
+
+ return FAILURE;
}
-
- if(zend_hash_add(W32_G(regfuncs), php_strtolower((*funcname)->value.str.val, (*funcname)->value.str.len), (*funcname)->value.str.len, fe, sizeof(W32APIFE), NULL) == FAILURE)
- {
- php_error(E_WARNING, "Could not register function %s into hash");
- RETURN_FALSE;
- }
- /**
- * We now need to add the function into the global namespace, the best way to do this is
- * to register it as a new module then it will definatly be removed on shutdown
- */
+ /* Insert it into our hash table */
+ if(zend_hash_add( WG(types),
+ (*th)->type_name,
+ strlen((*th)->type_name) + 1,
+ th,
+ sizeof(w32api_type_handle *),
+ NULL) != SUCCESS)
{
- zend_module_entry *temp_module_entry;
- char *fname;
- function_entry *tmp_functions;
-
- tmp_functions = malloc(sizeof(function_entry) * 2);
- fname = malloc((*funcname)->value.str.len + 1);
- memcpy(fname, (*funcname)->value.str.val, (*funcname)->value.str.len + 1);
-
- tmp_functions[0].fname = php_strtolower(fname, (*funcname)->value.str.len);
- tmp_functions[0].handler = zif_w32api_invoke_function;
- tmp_functions[0].func_arg_types = NULL;
- tmp_functions[1].fname = NULL;
- tmp_functions[1].handler = NULL;
- tmp_functions[1].func_arg_types = NULL;
-
-
- temp_module_entry = malloc(sizeof(zend_module_entry));
- temp_module_entry->size = sizeof(zend_module_entry);
- temp_module_entry->zend_api = ZEND_MODULE_API_NO;
- temp_module_entry->zend_debug = ZEND_DEBUG;
- temp_module_entry->zts = USING_ZTS;
- temp_module_entry->name = fname;
- temp_module_entry->functions = tmp_functions;
- temp_module_entry->module_startup_func = temp_module_entry->module_shutdown_func =
- temp_module_entry->request_startup_func = temp_module_entry->request_shutdown_func = NULL;
- temp_module_entry->info_func = NULL;
- temp_module_entry->version = NULL;
- temp_module_entry->global_startup_func = temp_module_entry->global_shutdown_func = NULL;
- temp_module_entry->globals_id = 0;
- temp_module_entry->module_started = 0;
- temp_module_entry->type = 0;
- temp_module_entry->handle = NULL;
- temp_module_entry->module_number = 0;
-
- if(zend_register_module(temp_module_entry) != SUCCESS)
- {
- php_error(E_WARNING, "could not register function %s into the function table", (*funcname)->value.str.val);
- RETURN_FALSE
- }
+ php_error( E_WARNING,
+ "Loading of type %s failed: Could not insert type handle into hash",
+ (*th)->type_name);
+ /* Tidy up */
+ zend_hash_del(WG(types), (*th)->type_name, strlen((*th)->type_name) + 1);
+ return FAILURE;
}
+ return SUCCESS;
-
- RETURN_TRUE
-};
+}
/* }}} */
-/* {{{ proto mixed w32api_invoke_function(string funcname, ....)
- Invokes function funcname with the arguments passed after the function name */
-PHP_FUNCTION(w32api_invoke_function)
+
+/* {{{ php_w32api_register_callback
+ */
+static int php_w32api_register_callback(char *function_definition, int function_definition_len TSRMLS_DC)
{
- zval ***args = (zval ***)NULL;
- void *tmp;
- W32APIFE *fe;
- char *funcname;
- int argc = ZEND_NUM_ARGS();
- runtime_struct *rst;
- RESULT retval;
- DYNAPARM *Param, *drval;
- LPVOID pVParam;
- int VParamsz;
- int i;
+ w32api_func_handle **fh;
+ w32api_func_handle_ptr hnd;
- args = emalloc(argc * sizeof(zval **));
- Param = (DYNAPARM *)emalloc((argc) * sizeof(DYNAPARM));
+ char *new_definition = NULL;
- if(zend_get_parameters_array_ex(argc, args) == FAILURE)
- {
- WRONG_PARAM_COUNT
- }
+ fh = emalloc(sizeof(w32api_func_handle *));
+ *fh = NULL;
- funcname = get_active_function_name(TSRMLS_C);
+ new_definition = emalloc(function_definition_len + sizeof(" from cb.cb"));
- if(zend_hash_find(W32_G(regfuncs), funcname, strlen(funcname), (void **) &tmp) == FAILURE)
- {
- php_error(E_WARNING, "Could not find function handle for function %s", funcname);
- RETURN_FALSE;
- }
+ snprintf(new_definition, function_definition_len + sizeof(" from cb.cb"), "%s from cb.cb", function_definition);
- fe = (W32APIFE *)tmp;
- // Build the DYNPARAM array.
- for(i = 0; i < (argc); i++)
+ /* Parse function */
+ w32api_function_definition_scan_bytes(new_definition, function_definition_len + sizeof(" from cb.cb"));
+ if(w32api_function_definition_parse((void *)&hnd) != 0)
{
- Param[i] = w32api_convert_zval_to_dynparam(args[(i)] TSRMLS_CC);
- }
+ *fh = hnd.hnd;
+ /* Leaks */
+ if(*fh != NULL)
+ efree(*fh);
- /**
- * We need to check the return type, if its a complex return type then we need to sort out pVParam and
- * VParamsz and pass them as the last two parameters of the call to the invoke of the function.
- */
- if(fe->retvaltype) // Complex return type
- {
- tmp = NULL;
- if(zend_hash_find(W32_G(types), fe->rettype, strlen(fe->rettype), (void **) &tmp) == FAILURE)
- {
- php_error(E_WARNING, "Unknown type %s", fe->rettype);
- RETURN_FALSE;
- }
- rst = tmp;
- VParamsz = rst->size;
- pVParam = malloc(rst->size);
- }
- else
- {
- pVParam = NULL;
- VParamsz = 0;
+ efree(fh);
+ return FAILURE;
}
+ *fh = hnd.hnd;
- retval = php_w32api_dynamic_dll_call(W32_G(call_type), (ulong)(fe->fp), (argc), Param, pVParam, VParamsz);
+ if(!*fh)
+ return FAILURE;
- if(!strcmp(fe->rettype, "long"))
+
+ if(zend_hash_exists(WG(callbacks), (*fh)->function_name, strlen((*fh)->function_name) + 1))
{
- RETURN_LONG(retval.Long);
+ php_error( E_WARNING,
+ "A callback by the name %s already has been registered, cannot redefine type",
+ (*fh)->function_name);
+
+ /* We dont want to unload function as it already exists so lets just free it ourselves */
+ php_w32api_free_arguments((*fh)->argument_list);
+ efree((*fh)->return_type_name);
+ efree((*fh)->function_name);
+ efree(*fh);
+ efree(fh);
+
+ return FAILURE;
}
- else if (!strcmp(fe->rettype, "int"))
+
+ /* Insert it into our hash table */
+ if(zend_hash_add( WG(callbacks),
+ (*fh)->function_name,
+ strlen((*fh)->function_name) + 1,
+ fh,
+ sizeof(w32api_func_handle *),
+ NULL) != SUCCESS)
{
- RETURN_LONG(retval.Int);
+
+ php_error( E_WARNING,
+ "Loading of function %s failed: Could not insert function handle into hash",
+ (*fh)->function_name);
+
+ /* Tidy up */
+ zend_hash_del(WG(callbacks), (*fh)->function_name, strlen((*fh)->function_name) + 1);
+ return FAILURE;
}
- else if (!strcmp(fe->rettype, "string"))
+
+ return SUCCESS;
+
+
+
+}
+/* }}} */
+
+
+/* {{{ php_w32api_free_arguments
+ * Expects one argument, the head of a list of arguments to free
+ */
+static void php_w32api_free_arguments(arguments *argument_list)
+{
+ if(argument_list == NULL)
+ return;
+
+ efree(argument_list->arg->argument_name);
+ efree(argument_list->arg->type_name);
+ efree(argument_list->arg);
+
+ if(argument_list->next_arg != NULL)
{
- RETURN_STRING(retval.Pointer, 1);
+ php_w32api_free_arguments(argument_list->next_arg);
}
- else if (!strcmp(fe->rettype, "byte"))
- {
- php_error(E_WARNING, "byte return values are not supported right now");
+
+ efree(argument_list);
+
+ return;
+}
+/* }}} */
+
+/* {{{ php_w32api_free_members
+ * Expects one argument, the head of a list of members to free
+ */
+static void php_w32api_free_members(members *member_list)
+{
+ if(member_list == NULL)
+ return;
+
+ efree(member_list->member->member_name);
+
+ if(member_list->member->member_type_name != NULL)
+ efree(member_list->member->member_type_name);
+
+ efree(member_list->member);
+
+ php_w32api_free_members(member_list->next_member);
+ efree(member_list);
+ return;
+}
+/* }}} */
+
+/* {{{ php_w32api_load_library
+ * Expects two parameters, first is libraries name the second is a pointer
+ * to a pointer to w32api_lib_handle which will recieve the resultant handle.
+ * returns SUCCESS on success and FAILURE on failure.
+ */
+static int php_w32api_load_library (char *library_name, w32api_lib_handle **lh TSRMLS_DC)
+{
+ if(zend_hash_find(WG(libraries), library_name, strlen(library_name) + 1, (void **)lh) == SUCCESS)
+ {
+ (*lh)->ref_count++;
+ return SUCCESS;
+ }
+
+ *lh = (w32api_lib_handle *) emalloc( sizeof(w32api_lib_handle) );
+ (*lh)->ref_count = 1;
+ (*lh)->library_name = estrdup(library_name);
+
+ (*lh)->handle = LoadLibrary((*lh)->library_name);
+
+ if(!(*lh)->handle) /* Could not load library */
+ {
+ LPVOID message_buffer;
+ FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR)&message_buffer,
+ 0,
+ NULL);
+
+ /* Tidy up */
+ efree((*lh)->library_name);
+ efree(*lh);
+ efree(lh);
+
+ php_error(E_WARNING, "Loading of library failed: %s", message_buffer);
+ LocalFree(message_buffer);
+
+ return FAILURE;
+ }
+
+ /* Add to hash */
+ if(zend_hash_add( WG(libraries),
+ (*lh)->library_name,
+ strlen((*lh)->library_name) + 1,
+ *lh,
+ sizeof(w32api_lib_handle),
+ NULL) != SUCCESS)
+ {
+
+ php_error( E_WARNING,
+ "Loading of library %s failed: Could not insert library handle into hash",
+ (*lh)->library_name);
+
+ /* Tidy up */
+ efree((*lh)->library_name);
+ efree(*lh);
+ efree(lh);
+
+ return FAILURE;
+ }
+
+
+ return SUCCESS;
+
+}
+/* }}} */
+
+
+/* {{{ php_w32api_do_arg_types
+ */
+static unsigned char *php_w32api_do_arg_types(arguments **argument_list)
+{
+ int i = 0;
+ int j = 0;
+ arguments *curr_arg = NULL;
+ unsigned char *retval = NULL;
+
+ if(!(argument_list) || !(*argument_list))
+ return NULL;
+
+ curr_arg = *argument_list;
+
+ /* See how much room we need to emalloc */
+ while(curr_arg)
+ {
+ i++;
+
+ if(curr_arg->arg->flags & BYREF_FORCE)
+ {
+ j = i;
+ }
+
+ curr_arg = curr_arg->next_arg;
+ }
+
+ /* Check to see if any args are by ref */
+ if( j == 0 )
+ return NULL;
+
+ retval = (unsigned char *)emalloc(sizeof(unsigned char) * j + 1);
+ retval[0] = (unsigned char)j;
+
+ curr_arg = *argument_list;
+
+ for(i=1; i <= j; i++)
+ {
+
+ retval[i] = (unsigned char)curr_arg->arg->flags;
+ curr_arg = curr_arg->next_arg;
+
+ }
+
+ return retval;
+}
+/* }}} */
+
+static int php_w32api_get_type_size(int type_id, char *type_name, int flags)
+{
+ TSRMLS_FETCH();
+
+ if(flags & BYREF_FORCE)
+ {
+ return sizeof(void *); /* Pointers are always the same size */
+ }
+
+ switch(type_id)
+ {
+ case W32API_NULL:
+ return sizeof(void *);
+ case W32API_INT:
+ return sizeof(int);
+ case W32API_LONG:
+ return sizeof(long);
+ case W32API_DOUBLE:
+ return sizeof(double);
+ case W32API_FLOAT:
+ return sizeof(float);
+ case W32API_STRING:
+ return sizeof(char *);
+ case W32API_BYTE:
+ return sizeof(char);
+ case W32API_BOOL:
+ return sizeof(int);
+ case W32API_COMPLEX:
+ {
+ w32api_type_handle **th;
+
+ if(zend_hash_find(WG(types), type_name, strlen(type_name) +1, (void **)&th) != SUCCESS)
+ {
+ php_error(E_ERROR, "Unknown type %s", type_name);
+ return -1;
+ }
+
+ return (*th)->size;
+
+ }
+ break;
+ case W32API_UNKNOWN:
+ default:
+ php_error(E_ERROR, "Unknown type %s", type_name);
+ return -1;
+ }
+}
+
+static int php_w32api_get_type_id_from_name(char *type)
+{
+
+ TSRMLS_FETCH();
+
+ if(!strcmp(type, "long"))
+ {
+ return W32API_LONG;
+ }
+ else if(!strcmp(type, "int"))
+ {
+ return W32API_INT;
+ }
+ else if (!strcmp(type, "string"))
+ {
+ return W32API_STRING;
+ }
+ else if (!strcmp(type, "byte"))
+ {
+ return W32API_BYTE;
+ }
+ else if (!strcmp(type, "bool"))
+ {
+ return W32API_BOOL;
+ }
+ else if (!strcmp(type, "double"))
+ {
+ return W32API_DOUBLE;
+ }
+ else if (!strcmp(type, "float"))
+ {
+ return W32API_FLOAT;
+ }
+ else if (!strcmp(type, "void"))
+ {
+ return W32API_NULL;
+ }
+ else
+ {
+ if(zend_hash_exists(WG(types), type, strlen(type) +1))
+ {
+ return W32API_COMPLEX;
+ }
+ else
+ {
+ return W32API_UNKNOWN;
+ }
+ }
+}
+
+static void php_w32api_init_type(w32api_type_handle *th, zval *obj TSRMLS_DC)
+{
+ w32api_type_instance *ti;
+ zval *rsrc_handle = NULL;
+
+ ti = emalloc(sizeof(w32api_type_instance));
+
+ if(!obj)
+ MAKE_STD_ZVAL(obj);
+
+ object_init_ex(obj, WG(type_ce));
+
+ ti->type = th;
+ ti->values = emalloc(sizeof(zval *) * th->member_count);
+ memset(ti->values, '\0', sizeof(zval *) * th->member_count);
+
+ MAKE_STD_ZVAL(rsrc_handle);
+ ZEND_REGISTER_RESOURCE(rsrc_handle, ti, WG(le_type_instance));
+
+ zend_hash_index_update(Z_OBJPROP_P(obj), 0, &rsrc_handle, sizeof(zval *), NULL);
+}
+
+
+static int php_w32api_do_prop_get(zval *object, zval *return_value, zend_llist_element **element TSRMLS_DC)
+{
+ w32api_type_instance *th;
+ zval **type_instance_handle;
+ members *current_member;
+ char *property_name;
+ int i = 0;
+
+ zend_hash_index_find(Z_OBJPROP_P(object), 0, (void **) &type_instance_handle);
+
+ th = (w32api_type_instance *)zend_fetch_resource(type_instance_handle TSRMLS_CC,
+ -1, "Complex Type Instance", NULL,
+ 1, WG(le_type_instance));
+
+ if(!th)
+ return FAILURE;
+
+ property_name = Z_STRVAL(((zend_overloaded_element *)(*element)->data)->element);
+
+ current_member = th->type->member_list;
+
+ while(strcmp(current_member->member->member_name, property_name) != 0)
+ {
+ i++;
+
+ if(current_member->next_member != NULL)
+ current_member = current_member->next_member;
+ else
+ return FAILURE;
+ }
+
+ *return_value = *(th->values[i]);
+ zval_copy_ctor(return_value);
+
+ return SUCCESS;
+}
+
+static int php_w32api_do_prop_set(zval *object, zval *value, zend_llist_element **element TSRMLS_DC)
+{
+ w32api_type_instance *th;
+ zval **type_instance_handle;
+ zval *new_var;
+ members *current_member;
+ char *property_name;
+ int i = 0;
+
+ zend_hash_index_find(Z_OBJPROP_P(object), 0, (void **) &type_instance_handle);
+
+ th = (w32api_type_instance *)zend_fetch_resource(type_instance_handle TSRMLS_CC,
+ -1, "Complex Type Instance", NULL,
+ 1, WG(le_type_instance));
+
+ if(!th)
+ return FAILURE;
+
+ property_name = Z_STRVAL(((zend_overloaded_element *)(*element)->data)->element);
+
+ current_member = th->type->member_list;
+
+ while(strcmp(current_member->member->member_name, property_name) != 0)
+ {
+ i++;
+
+ if(current_member->next_member != NULL)
+ current_member = current_member->next_member;
+ else
+ return FAILURE;
+ }
+
+ if(current_member->member->flags & BYREF_FORCE)
+ {
+ if(th->values[i])
+ zval_ptr_dtor(&th->values[i]);
+
+ MAKE_STD_ZVAL(new_var);
+ *new_var = *value;
+ zval_copy_ctor(new_var);
+ th->values[i] = new_var;
+
+ }
+ else
+ {
+ th->values[i] = value;
+ zval_add_ref(&value);
+ }
+
+ return SUCCESS;
+}
+
+w32api_result php_w32api_do_dynamic_dll_call(w32api_func_handle *fh, int argc, w32api_dynamic_param *params, void *return_buffer, int return_buffer_size)
+{
+
+ /**
+ * Theory Behind Implementation
+ * ============================
+ * We have four main jobs:
+ * 1) Push arguments onto stach aligned at 4 bytes.
+ * 2) Call Function
+ * 3) Get Return Values
+ * 4) Perform any cleanup needed.
+ *
+ * Pushing arguments onto the stack is fairly simple, just push from right to left
+ * so for a function with the prototype int sum(int a, int b) we would push b and
+ * then a in that order.
+ *
+ * Calling the function is fine as we already have the pointer to the function which
+ * we can use with call [function_pointer] to make the actual call.
+ *
+ * Return values are where we begin to get complicated. Now for simple return values up
+ * to 8 bytes they are returned via the EAX/EDX register pair. This means we can just
+ * copy the EAX/EDX pair to the win32_result sturcture and be sure we get any simple
+ * return type. If the return type is more than 8 bytes then things get complicated.
+ * When calling we must pass a hidden argument on the stach which points to a tempory
+ * buffer with enough memory to hold the return value, this return value is then copied
+ * to the correct varaible by us. Microsoft being the nice bunnies they are, decided to
+ * copy an optimization Borland introduced under win16 which is to pass structs of under
+ * 8 bytes directly via EAX/EDX pair. One final notable exception is dealing with floating
+ * point return types where we need to retrive the floating point number of the systems
+ * math coprocessor stack using the fstp call.
+ *
+ * Finally if its a __cdecl call we have to clean up the stack, otherwise the callee does this.
+ *
+ */
+
+ w32api_result result = { 0 };
+ DWORD *stack_pointer, stack_size = 0, eaxv, edxv;
+ BYTE *arg_ptr = NULL;
+ int size = 0, i = 0;
+ FARPROC fp = fh->handle;
+
+ _asm mov stack_pointer, esp // Store stack pointer (esp) in stack_pointer
+ _asm sub esp, 0x100 // Give ourselves 256 bytes on the stack
+
+
+ for(i = (argc - 1); i >= 0; i--)
+ {
+ size = (params[i].width + 3)/4 * 4;
+ arg_ptr = (unsigned char *)params[i].argument_ptr + size - 4;
+ stack_size += (unsigned long)size;
+
+ while(size > 0)
+ {
+ stack_pointer--;
+ if(params[i].flags == W32API_ARGPTR)
+ {
+ *stack_pointer = *(unsigned long *)arg_ptr;
+ arg_ptr -= 4;
+ }
+ else
+ {
+ *stack_pointer = params[i].argument;
+ }
+
+ size -= 4;
+ }
+ }
+
+ if((return_buffer) && ((fh->flags & W32API_BORLAND) || (return_buffer_size > 8)))
+ {
+
+ stack_size += 4;
+ stack_pointer--;
+ *stack_pointer = (unsigned long)return_buffer;
+ }
+
+ _asm add esp, 0x100
+ _asm sub esp, stack_size
+ _asm call [fp]
+ _asm mov eaxv, eax
+ _asm mov edxv, edx
+
+ if(fh->flags & W32API_CDECL)
+ {
+ _asm add esp, stack_size
+ }
+
+ if(fh->flags & W32API_REAL4)
+ _asm fstp dword ptr [result]
+ else if (fh->flags & W32API_REAL8)
+ _asm fstp qword ptr [result]
+ else if (!return_buffer)
+ {
+ _asm mov eax, [eaxv]
+ _asm mov edx, [edxv]
+ _asm mov DWORD PTR [result], eax
+ _asm mov DWORD PTR [result + 4], edx
+ }
+ else if (!(fh->flags & W32API_BORLAND) && (return_buffer_size <= 8))
+ {
+ _asm mov ecx, DWORD PTR [return_buffer]
+ _asm mov eax, [eaxv]
+ _asm mov DWORD PTR [ecx], eax
+ _asm mov edx, [edxv]
+ _asm mov DWORD PTR [ecx + 4], edx
+ }
+
+ return result;
+}
+
+void php_w32api_marshall_zval_to_c(argument *arg, w32api_dynamic_param *dp, zval *pzval TSRMLS_DC)
+{
+ dp->flags = 0;
+
+ /* We should have been passed a write reference when
+ * BYREF_FORCE is Set so we just add a reference
+ * when we pass it to the function,
+ * TODO: register the reference internally for safe unreferencing
+ */
+
+ switch(arg->type_id)
+ {
+ case W32API_INT:
+ convert_to_long_ex(&pzval);
+ if(arg->flags & BYREF_FORCE)
+ {
+ dp->argument = (unsigned long)&pzval->value.lval;
+ dp->width = sizeof(int *);
+
+ }
+ else
+ {
+ dp->argument = (int)pzval->value.lval;
+ dp->width = sizeof(int);
+ }
+ break;
+ case W32API_LONG:
+ convert_to_long_ex(&pzval);
+
+ if(arg->flags & BYREF_FORCE)
+ {
+ dp->argument = (unsigned long)&pzval->value.lval;
+ dp->width = sizeof(int *);
+ zval_add_ref(&pzval);
+ }
+ else
+ {
+ dp->argument = pzval->value.lval;
+ dp->width = sizeof(int);
+ }
+ break;
+ case W32API_STRING:
+
+ convert_to_string_ex(&pzval);
+ if(!(arg->flags & BYREF_FORCE))
+ {
+ /* Need to free this when we demarshall */
+ dp->argument = (unsigned long)estrndup(Z_STRVAL_P(pzval), Z_STRLEN_P(pzval));
+ }
+ else
+ {
+ dp->argument = (unsigned long)Z_STRVAL_P(pzval);
+ zval_add_ref(&pzval);
+ }
+
+ dp->width = sizeof(char *);
+ break;
+
+ case W32API_DOUBLE:
+ convert_to_double_ex(&pzval);
+
+ if(arg->flags & BYREF_FORCE)
+ {
+ dp->argument = (unsigned long)&pzval->value.dval;
+ dp->width = sizeof(double *);
+ zval_add_ref(&pzval);
+ }
+ else
+ {
+ dp->argument_ptr = &pzval->value.dval;
+ dp->width = sizeof(double);
+ dp->flags = W32API_ARGPTR;
+ }
+ break;
+ case W32API_FLOAT:
+ convert_to_double_ex(&pzval);
+
+ if(arg->flags & BYREF_FORCE)
+ {
+ dp->argument = (unsigned long)&pzval->value.dval;
+ dp->width = sizeof(double *);
+ zval_add_ref(&pzval);
+ }
+ else
+ {
+ dp->argument_ptr = &pzval->value.dval;
+ dp->width = sizeof(float);
+ dp->flags = W32API_ARGPTR;
+ }
+ break;
+ case W32API_BYTE:
+ /* Thanks sterling */
+ convert_to_string_ex(&pzval);
+ if(arg->flags & BYREF_FORCE)
+ {
+ dp->argument = (unsigned long)&Z_STRVAL_P(pzval);
+ dp->width = sizeof(char *);
+ zval_add_ref(&pzval);
+ }
+ else
+ {
+ dp->argument = (char)Z_STRVAL_P(pzval)[0];
+ dp->width = sizeof(char);
+ }
+ break;
+ case W32API_BOOL:
+ convert_to_boolean_ex(&pzval);
+
+ if(arg->flags & BYREF_FORCE)
+ {
+ dp->argument = (unsigned long)&pzval->value.lval;
+ dp->width = sizeof(int *);
+ zval_add_ref(&pzval);
+ }
+ else
+ {
+ dp->argument = (int)pzval->value.lval;
+ dp->width = sizeof(int);
+ }
+ break;
+ case W32API_COMPLEX:
+ if(Z_TYPE_P(pzval) != IS_OBJECT)
+ {
+ php_error(E_ERROR, "Variable passed as complex value is not an object");
+ break;
+ }
+
+ if(arg->flags & BYREF_FORCE)
+ {
+ int width= 0;
+ void **ptr = NULL;
+ ptr = emalloc(sizeof(void *));
+ *ptr = php_w32api_complex_marshall_zval_to_c(pzval, &width, NULL TSRMLS_CC);
+ dp->argument = (unsigned long)ptr;
+ dp->width = width;
+ }
+ else
+ {
+ int width= 0;
+ dp->argument_ptr = php_w32api_complex_marshall_zval_to_c(pzval, &width, NULL TSRMLS_CC);
+ dp->width = width;
+ }
+ break;
+
+ case W32API_UNKNOWN:
+ php_error(E_ERROR, "Unknown type when calling function, marshalling failed");
+ break;
+ }
+
+}
+
+static void *php_w32api_complex_marshall_zval_to_c(zval *pzval, int *width, void *return_value TSRMLS_DC)
+{
+ w32api_type_instance *th;
+ zval **type_instance_handle;
+ members *current_member;
+ char *offset = return_value;
+ int i = 0;
+
+
+ if(return_value == NULL)
+ {
+ /* First call */
+/* return_value = emalloc(th->type->size);
+
+ zend_hash_index_find(Z_OBJPROP_P(object), 0, (void **) &type_instance_handle);
+ th = (w32api_type_instance *)zend_fetch_resource(type_instance_handle TSRMLS_CC,
+ -1, "Complex Type Instance", NULL,
+ 1, WG(le_type_instance));
+
+ if(!th)
+ return NULL;
+
+
+ for(i = 0; i < th->type->member_count; i++)
+ {
+
+
+ }
+*/ }
+
+
+}
+
+
+/* =====================================================================================================
+ * Win32 Class Code
+ * =====================================================================================================
+ */
+
+/* {{{ win32_class_functions[]
+ */
+function_entry win32_class_functions[] = {
+ W32API_CLASS_FE(win32, registerfunction, NULL)
+ W32API_CLASS_FE(win32, unregisterfunction, NULL)
+ W32API_CLASS_FE(win32, registercallback, NULL)
+ W32API_CLASS_FE(win32, definetype, NULL)
+ W32API_CLASS_FE(win32, gettypesize, NULL)
+ W32API_CLASS_FE(win32, inittype, NULL)
+ W32API_CLASS_FE(win32, decref, NULL)
+#ifndef NDEBUG
+ W32API_CLASS_FE(win32, dump_function_hash, NULL)
+ W32API_CLASS_FE(win32, dump_library_hash, NULL)
+ W32API_CLASS_FE(win32, dump_callback_hash, NULL)
+ W32API_CLASS_FE(win32, dump_type_hash, NULL)
+#endif
+ {NULL, NULL, NULL}
+};
+/* }}} */
+
+/* {{{ win32_class_init(TSRMLS_D)
+ */
+int win32_class_init(TSRMLS_D)
+{
+ zend_class_entry ce;
+
+ INIT_CLASS_ENTRY(ce,
+ "win32",
+ win32_class_functions);
+
+ WG(win32_ce) = zend_register_internal_class(&ce TSRMLS_CC);
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ win32_class_rshutdown(TSRMLS_D)
+ * Cleans up at the end of the shutdown removing and freeing anything we added to the function
+ * table.
+ */
+int win32_class_rshutdown(TSRMLS_D)
+{
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ proto: int Win32::RegisterFunction(string definition [, int flags])
+ * Registers and Loads a function from an underlying Dll
+ */
+W32API_CLASS_FUNCTION(win32, registerfunction)
+{
+ char *function_definition = NULL;
+ int function_definition_len;
+ long flags = 0;
+
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l",
+ &function_definition,
+ &function_definition_len,
+ &flags) == FAILURE)
+ {
+ return;
+ }
+
+ if(php_w32api_load_function(function_definition, function_definition_len, flags TSRMLS_CC) != SUCCESS)
+ {
+ php_error(E_ERROR, "Registering Function %s failed", function_definition);
+ RETURN_FALSE;
+ }
+
+ RETURN_TRUE;
+
+
+}
+/* }}} */
+
+/* {{{ proto: int Win32::UnregisterFunction(string function_name)
+ * Unregisters a previously loaded function
+ */
+W32API_CLASS_FUNCTION(win32, unregisterfunction)
+{
+ char *function_name = NULL;
+ int function_name_len;
+ w32api_func_handle **fh = NULL;
+
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l",
+ &function_name,
+ &function_name_len) == FAILURE)
+ {
+ return;
+ }
+
+ /* Our deleteor handler removes us from the WG(win32_ce)->function_table
+ * so no need to delete specifically from there
+ */
+ zend_hash_del(WG(funcs), function_name, strlen(function_name) + 1);
+
+ RETURN_TRUE;
+
+}
+/* }}} */
+
+/* {{{ proto: int Win32::RegisterCallback(string definition)
+ * Registers a callback type
+ */
+W32API_CLASS_FUNCTION(win32, registercallback)
+{
+ char *function_definition = NULL;
+ int function_definition_len;
+ w32api_func_handle **fh = NULL;
+
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l",
+ &function_definition,
+ &function_definition_len) == FAILURE)
+ {
+ return;
+ }
+
+ if(php_w32api_register_callback(function_definition, function_definition_len TSRMLS_CC) != SUCCESS)
+ {
+ RETURN_FALSE;
+ }
+
+ RETURN_TRUE;
+
+}
+/* }}} */
+
+
+/* {{{ proto: int Win32::DefineType(string definition)
+ * Defines a C Like Type for use.
+ */
+W32API_CLASS_FUNCTION(win32, definetype)
+{
+ char *type_definition = NULL;
+ int type_definition_len;
+
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
+ &type_definition,
+ &type_definition_len) == FAILURE)
+ {
+ return;
+ }
+
+ if(php_w32api_register_type(type_definition, type_definition_len TSRMLS_CC) != SUCCESS)
+ {
+ php_error(E_ERROR, "Registering Type %s failed", type_definition);
+ RETURN_FALSE;
+ }
+
+ RETURN_TRUE;
+
+}
+/* }}} */
+
+/* {{{ proto: int Win32::GetTypeSize(string type_name)
+ * Returns the size of a registered type
+ */
+W32API_CLASS_FUNCTION(win32, gettypesize)
+{
+ char *type = NULL;
+ int type_len;
+
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
+ &type,
+ &type_len) == FAILURE)
+ {
+ return;
+ }
+
+ RETURN_LONG(php_w32api_get_type_size(php_w32api_get_type_id_from_name(type), type, BYREF_NONE));
+
+
+}
+/* }}} */
+
+/* {{{ proto: int Win32::InitType(string TypeName)
+ * Creates an instance of type TypeName
+ */
+W32API_CLASS_FUNCTION(win32, inittype)
+{
+ char *type_name = NULL;
+ int type_name_len = 0;
+ w32api_type_handle **th = NULL;
+
+ if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
+ &type_name, &type_name_len) == FAILURE)
+ {
+ return;
+ }
+
+ if(zend_hash_find(WG(types), type_name, type_name_len +1, (void **)&th) == FAILURE)
+ {
+ php_error(E_ERROR, "Could not retrieve type handle for type %s from hash table", type_name);
RETURN_FALSE;
}
- else if (!strcmp(fe->rettype, "double"))
+
+ php_w32api_init_type(*th, return_value TSRMLS_CC);
+
+}
+/* }}} */
+
+/* {{{ proto: int Win32::DecRef(mixed Variable)
+ * Decreases the reference count on a variable
+ */
+W32API_CLASS_FUNCTION(win32, decref)
+{
+
+}
+/* }}} */
+
+/* {{{ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ * THIS FUNCTION IS NOT PUBLICALLY ACCESSABLE
+ * IT IS USED AS A GENERIC HANDLER FOR W32API
+ * CALLS.
+ */
+W32API_CLASS_FUNCTION(win32, invokefunction)
+{
+ char *function_name = get_active_function_name(TSRMLS_C);
+ int argc = ZEND_NUM_ARGS();
+ int i = 0;
+ w32api_dynamic_param *params = NULL;
+ w32api_dynamic_param *current_dynamic_param = NULL;
+ w32api_func_handle **fh = NULL;
+ w32api_result res = {0};
+ void *w32api_return_buffer = NULL;
+ int w32api_return_buffer_size = 0;
+ zval **func_arguments = NULL;
+ zval *current_zval = NULL;
+ arguments *curr_arg = NULL;
+ w32api_type_handle *th = NULL;
+
+ if(zend_hash_find(WG(funcs), function_name, strlen(function_name) +1, (void **)&fh) == FAILURE)
{
- RETURN_DOUBLE(retval.Double);
+ php_error(E_ERROR, "Could not retrieve function handle from hash table");
+ RETURN_FALSE;
}
- else if (!strcmp(fe->rettype, "bool"))
+
+ if(argc)
{
- if(retval.Int)
+ if(zend_get_parameters_array_ex(argc, &func_arguments) == FAILURE)
{
- RETURN_TRUE;
+ WRONG_PARAM_COUNT
}
- else
+
+ params = (w32api_dynamic_param *)emalloc(sizeof(w32api_dynamic_param) * argc);
+
+ curr_arg = (*fh)->argument_list;
+ current_dynamic_param = params;
+
+ for(i = 0; i < argc; i++)
{
- RETURN_FALSE;
+ current_zval = func_arguments[i];
+ php_w32api_marshall_zval_to_c(curr_arg->arg, current_dynamic_param, current_zval TSRMLS_CC);
+
+ current_dynamic_param++;
+ curr_arg = curr_arg->next_arg;
}
}
else
{
- /**
- * This is returned in pRet, we need to get type and build a DYNAPARM for
- * the return value and return the RESOURCE.
- */
-
- drval = malloc(sizeof(DYNAPARM));
- drval->pArg = pVParam;
- drval->nWidth = VParamsz;
- drval->dwFlags = 0;
- ZEND_REGISTER_RESOURCE(return_value, drval, W32_G(le_dynaparm));
+ params = NULL;
}
-}
-/* }}} */
+ if((*fh)->return_type_id == W32API_COMPLEX)
+ {
+ if(zend_hash_find(WG(types), (*fh)->return_type_name, strlen((*fh)->return_type_name) +1, (void **)&th) != SUCCESS)
+ php_error(E_ERROR, "Could not find type handle for type %s", (*fh)->return_type_name);
-/* {{{ Dynamic calling of dll functions by pushing onto the stack manually. */
-PHP_W32API_API RESULT php_w32api_dynamic_dll_call( int Flags, DWORD lpFunction,
- int nArgs, DYNAPARM Param[],
- LPVOID pRet, int nRetSize)
-{
- /**
- * Here we dont know the function we are calling or the arguments
- * it expects so we must do quite a lot of work, normally done by
- * the compiler ourselves, this is far easier to do it Assembly than
- * in C.. here goes (jmoore - 05/11/2001).
- *
- * Based on the code by Ton Plooy <tonp@xs4all.nl>
- * See Also MSFT KB Article ID: Q171729 for more background.
- *
- * We will support two calling mechanisms, __stdcall and __cdecl(WINAPIV).
- */
- RESULT Res = { 0 };
- int i, nInd, nSize;
- DWORD dwEAX, dwEDX, dwVal, *pStack, dwStSize = 0;
- BYTE *pArg;
-
- _asm {
- mov pStack, esp
- sub esp, 0x100
- }
-
- for (i = nArgs; i > 0; i--) {
- nInd = i - 1;
- nSize = (Param[nInd].nWidth + 3) / 4 * 4;
- pArg = (BYTE *)Param[nInd].pArg + nSize - 4;
- dwStSize += (DWORD)nSize;
- while (nSize > 0) {
- if (Param[nInd].dwFlags & DC_FLAG_ARGPTR) {
- dwVal = *(DWORD *)pArg;
- pArg -= 4;
- }
- else {
-
- dwVal = Param[nInd].dwArg;
- }
-
- pStack--;
- *pStack = dwVal;
- nSize -= 4;
- }
- }
-
- if((pRet != NULL) && ((Flags & DC_BORLAND) || (nRetSize > 8)))
- {
- dwStSize += 4;
- pStack--;
- *pStack = (DWORD)pRet;
- }
-
- _asm {
- add esp, 0x100
- sub esp, dwStSize
- call [lpFunction]
- mov dwEAX, eax
- mov dwEDX, edx
- }
-
- if (Flags & DC_CALL_CDECL) {
- _asm add esp, dwStSize
- }
-
- if (Flags & DC_RETVAL_MATH4) {
- _asm fstp dword ptr [Res]
- }
- else if (Flags & DC_RETVAL_MATH8) {
- _asm fstp qword ptr [Res]
- }
- else if (pRet == NULL) {
- _asm{
- mov eax, [dwEAX]
- mov DWORD PTR [Res], eax
- mov edx, [dwEDX]
- mov DWORD PTR [Res + 4], edx
- }
- }
- else if (((Flags & DC_BORLAND) == 0) && (nRetSize <= 8)) {
- // Microsoft optimized less than 8-bytes structure passing
- _asm {
- mov ecx, DWORD PTR [pRet]
- mov eax, [dwEAX]
- mov DWORD PTR [ecx], eax
- mov edx, [dwEDX]
- mov DWORD PTR [ecx + 4], edx
- }
- }
- return Res;
-}
-/* }}} */
+ w32api_return_buffer = emalloc(th->size);
+ w32api_return_buffer_size = th->size;
+ }
-/* {{{ Conversion function for zvals to dynparams */
-DYNAPARM w32api_convert_zval_to_dynparam(zval ** carg TSRMLS_DC)
-{
- DYNAPARM dparam, *tparam;
- dparam.dwFlags = 0;
- switch((*carg)->type)
+
+ res = php_w32api_do_dynamic_dll_call(*fh, argc, params, w32api_return_buffer, w32api_return_buffer_size);
+
+ if(argc)
+ /* We should demarshall here not just efree */
+ efree(params);
+
+ switch((*fh)->return_type_id)
{
- case IS_RESOURCE:
- tparam = (DYNAPARM *) zend_fetch_resource(carg TSRMLS_CC, -1, "dynaparm", NULL, 1, W32_G(le_dynaparm));
- if(!tparam)
- {
- php_error(E_ERROR, "Error when fetching argument");
- }
- dparam = *tparam;
+ case W32API_LONG:
+ RETURN_LONG(res.lval);
break;
- case IS_LONG:
- dparam.nWidth = sizeof(long);
- dparam.dwArg = (*carg)->value.lval;
+ case W32API_INT:
+ RETURN_LONG(res.ival);
break;
- case IS_DOUBLE:
- dparam.nWidth = sizeof(float);
- dparam.pArg = &(*carg)->value.dval;
- dparam.dwFlags = DC_FLAG_ARGPTR;
+ case W32API_STRING:
+ case W32API_BYTE:
+ RETURN_STRING(res.ptr, 1);
break;
- case IS_STRING:
- dparam.nWidth = sizeof(char *);
- dparam.pArg = (*carg)->value.str.val;
+ case W32API_DOUBLE:
+ RETURN_DOUBLE(res.dval);
break;
- case IS_BOOL:
- dparam.nWidth = sizeof(BOOL);
- dparam.dwArg = ((*carg)->value.lval == 0)?FALSE:TRUE;
+ case W32API_FLOAT:
+ RETURN_DOUBLE(res.fval);
+ break;
+ case W32API_BOOL:
+ if(res.ival)
+ {
+ RETURN_TRUE;
+ }
+ else
+ {
+ RETURN_FALSE;
+ }
break;
- case IS_NULL:
- dparam.nWidth = sizeof(void *);
- dparam.pArg = NULL;
+ case W32API_COMPLEX:
break;
default:
- php_error(E_ERROR, "Cant convert variable to type dynparam");
+ php_error(E_WARNING, "Unknown return type %s", (*fh)->return_type_name);
}
- return dparam;
}
/* }}} */
-/**
- * Typedef functions, We need to be flexible about what types we are going
- * to pass and retrive from functions in the win32 api. this means we need
- * to be able to create structs of any different type at runtime. We can do
- * this in asm. For example:
- *
- * typedef struct james {
- * char firstname[81];
- * char lastname[81];
- * }
- *
- * An instance of the above struct (lets call this instance iJames. iJames
- * is a pointer to the first letter of firstname (the base address), firstname
- * then fills the following 81 bytes (some of these may be empty), lastname is
- * at the offset iJames+81,
- *
- * |- 81 Bytes -|- 81 Bytes -|
- * +------//------+------//------+
- * | James\0 | Moore\0 |
- * +------//------+------//------+
- * ^ ^
- * iJames iJames[81]
- *
- * We could store a value in ax in this field by
- * the assembly command:
- *
- * move ac iJames[81]
- *
- * Unions are easy in asm as the length of memory they use is equal to the size
- * of their largest member. For example:
- *
- * typedef union foo {
- * int i;
- * char j;
- * }
- *
- * The length of an int might be 4 bytes, the length of a char might be 1 byte.
- * So if we create an instance of foo called bar then it would have the following
- * layout in memory:
- *
- * +---+------------+
- * | ¦ |
- * +---+------------+
- * ^^^^^
- * Memory area for char
- * ^^^^^^^^^^^^^^^^^^
- * Memory area for int
- *
- * Therefore even if there was only a char held in this section and the union was within
- * a struct the next offset would still be base address + 4 not +1 so we need to deal
- * with this too.
- *
- * When defining types the user can call the w32api_deftype() function, this takes 2n+1 args where
- * n is the number of members the type has. The first argument is the name of the struct struct
- * after that is the type of the member followed by the members name (in pairs).
- *
- *
- * James Moore <jmoore@php.net> 6/11/2001
- *
- */
+#ifndef NDEBUG
+W32API_CLASS_FUNCTION(win32, dump_library_hash)
+{
+ zend_hash_apply(WG(libraries), (apply_func_t)php_w32api_dump_library_hash_cb TSRMLS_CC);
+}
-/* {{{ proto int w32api_deftype(string typename, string member1_type, string member1_name, ...)
- Defines a type for use with other w32api_functions. */
-PHP_FUNCTION(w32api_deftype)
+W32API_CLASS_FUNCTION(win32, dump_function_hash)
{
- zval ***args;
- int argc = ZEND_NUM_ARGS();
- int i;
- runtime_struct *rst, *orst;
- void *tmp;
- field *fields, *ptr;
+ zend_hash_apply(WG(funcs), (apply_func_t)php_w32api_dump_function_hash_cb TSRMLS_CC);
+}
- args = (zval ***)emalloc(sizeof(zval **) * argc);
- rst = malloc(sizeof(runtime_struct));
+W32API_CLASS_FUNCTION(win32, dump_callback_hash)
+{
- ptr = (field *)emalloc(sizeof(field) *((argc-1)/2));
+ zend_hash_apply(WG(callbacks), (apply_func_t)php_w32api_dump_callback_hash_cb TSRMLS_CC);
+}
- fields = ptr;
- if((zend_get_parameters_array_ex(argc, args) == FAILURE) || ((argc % 2) != 1))
- {
- WRONG_PARAM_COUNT
- }
+W32API_CLASS_FUNCTION(win32, dump_type_hash)
+{
- for(i=2; i<argc; i++)
- {
- convert_to_string_ex(args[i]);
- }
+ zend_hash_apply(WG(types), (apply_func_t)php_w32api_dump_type_hash_cb TSRMLS_CC);
+}
+
+int php_w32api_dump_library_hash_cb(void *pData TSRMLS_DC)
+{
+ w32api_lib_handle *lh = pData;
- convert_to_string_ex(args[0]);
+ printf("=====================================================================\n");
+ printf("Library Name: \t\t%s\n", lh->library_name);
+ printf("Reference Count: \t\t%d\n", lh->ref_count);
+ printf("Library Handle: \t\t%p\n", lh->handle);
+ printf("Lib ptr loc \t\t%p\n", lh);
+ printf("ll n loc \t\t%p\n", &lh->ref_count);
- rst->name = (*args[0])->value.str.val;
- rst->size = 0;
+ printf("=====================================================================\n");
- /**
- * We now take each parameter pair and fill out the field struct
- * for each parameter pair.
+ return 0;
+}
+
+int php_w32api_dump_function_hash_cb(void *pData TSRMLS_DC)
+{
+ w32api_func_handle **fh = pData;
+
+ printf("=====================================================================\n");
+ printf("Function Name: \t\t%s\n", (*fh)->function_name);
+ printf("Return Type Name: \t\t%s\n", (*fh)->return_type_name);
+ printf("Library Name: \t\t%s\n", (*fh)->lib->library_name );
+ printf("Function Flags: \t\t%d\n", (*fh)->flags);
+ printf("Function Handle: \t\t%p\n", (*fh)->handle);
+ printf("Return Type ID: \t\t%d\n", (*fh)->return_type_id);
+ printf("Return Type Name: \t\t%s\n", (*fh)->return_type_name);
+ printf("## Arguments ##\n");
+ printf("---------------------------------------------------------------------\n");
+ php_w32api_print_arguments((*fh)->argument_list);
+ printf("=====================================================================\n\n");
+
+ return 0;
+}
+
+int php_w32api_dump_callback_hash_cb(void *pData TSRMLS_DC)
+{
+ w32api_func_handle **fh = pData;
+
+ printf("=====================================================================\n");
+ printf("Callback Name: \t\t%s\n", (*fh)->function_name);
+ printf("Return Type Name: \t\t%s\n", (*fh)->return_type_name);
+ printf("Callback Flags: \t\t%d\n", (*fh)->flags);
+ printf("Return Type ID: \t\t%d\n", (*fh)->return_type_id);
+ printf("Return Type Name: \t\t%s\n", (*fh)->return_type_name);
+ printf("## Arguments ##\n");
+ printf("---------------------------------------------------------------------\n");
+ php_w32api_print_arguments((*fh)->argument_list);
+ printf("=====================================================================\n\n");
+
+ return 0;
+}
+
+int php_w32api_dump_type_hash_cb(void *pData TSRMLS_DC)
+{
+ w32api_type_handle **th = pData;
+
+
+ printf("=====================================================================\n");
+ printf("Type Name: \t\t%s\n", (*th)->type_name);
+ printf("Type Size: \t\t%d\n", (*th)->size);
+ printf("Member Count: \t\t%d\n", (*th)->member_count);
+ printf("## Members ##\n");
+ printf("---------------------------------------------------------------------\n");
+ php_w32api_print_members((*th)->member_list);
+ printf("=====================================================================\n\n");
+
+ return 0;
+}
+
+void php_w32api_print_members(members *member_list)
+{
+ if(member_list == NULL)
+ return;
+
+ printf("\tMember Name: \t%s\n", member_list->member->member_name);
+ printf("\tMember Flags: \t%d\n", member_list->member->flags);
+ printf("\tMember Type ID: \t%d\n", member_list->member->member_type_id);
+ printf("\tMember Type Name:\t%s\n", member_list->member->member_type_name);
+ printf("\tMember Offset: \t%d\n", member_list->member->offset);
+ printf("---------------------------------------------------------------------\n");
+
+ php_w32api_print_members(member_list->next_member);
+
+}
+void php_w32api_print_arguments(arguments *argument_list)
+{
+ if(argument_list == NULL)
+ return;
+
+ printf("\tArgument Name: \t%s\n", argument_list->arg->argument_name);
+ printf("\tArgument Flags: \t%d\n", argument_list->arg->flags);
+ printf("\tArgument Type ID:\t%d\n", argument_list->arg->type_id);
+ printf("\tArg Type Name: \t%s\n", argument_list->arg->type_name);
+ printf("---------------------------------------------------------------------\n");
+
+ php_w32api_print_arguments(argument_list->next_arg);
+}
+#endif
+/* =====================================================================================================
+ * Type Class Code
+ * =====================================================================================================
+ */
+
+/* {{{ type_class_functions[]
+ */
+function_entry type_class_functions[] = {
+ W32API_CLASS_FE(type, clone, NULL)
+ {NULL, NULL, NULL}
+};
+/* }}} */
+
+
+/* {{{ type_class_init(TSRMLS_DC)
+ */
+int type_class_init(TSRMLS_D)
+{
+ zend_class_entry ce;
+
+ INIT_OVERLOADED_CLASS_ENTRY(ce,
+ "type",
+ type_class_functions,
+ NULL,
+ W32API_PROP_GET_FUNCTION_N(type),
+ W32API_PROP_SET_FUNCTION_N(type));
+
+ WG(type_ce) = zend_register_internal_class(&ce TSRMLS_CC);
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ W32API_PROP_SET_FUNCTION(type)
+ */
+/* Most of this code is borrowed from php-gtk. Thanks to Andrei and Zeev for their
+ * help with the prop-get/set functions
+ */
+W32API_PROP_SET_FUNCTION(type)
+{
+ zval result, temp;
+ zval *temp_ptr = &temp;
+ zval *new_val;
+ zend_overloaded_element *overloaded_property;
+ zend_llist_element *element;
+ zval **object = &property_reference->object;
+ int setter_retval, getter_retval;
+ TSRMLS_FETCH();
+
+
+ /* If we have $foo->bar->baz->boo->bin we have to do sucessive propgets
+ * Until we can do our prop set (thanks Zeev, Andrei)
*/
- for(i=1; i<argc; i += 2)
- {
- ptr->type = malloc((*args[i])->value.str.len + 1);
- memcpy(ptr->type, (*args[i])->value.str.val, (*args[i])->value.str.len + 1);
+ for (element=property_reference->elements_list->head; element != property_reference->elements_list->tail; element=element->next) {
+ overloaded_property = (zend_overloaded_element *)element->data;
+
+ getter_retval = FAILURE;
+ if (Z_TYPE_P(overloaded_property) == OE_IS_OBJECT) {
+ if (Z_TYPE_PP(object) == IS_NULL ||
+ (Z_TYPE_PP(object) == IS_BOOL && Z_LVAL_PP(object) == 0) ||
+ (Z_TYPE_PP(object) == IS_STRING && Z_STRLEN_PP(object) == 0)) {
+ object_init(*object);
+ }
- ptr->fname = malloc((*args[i+1])->value.str.len + 1);
- memcpy(ptr->fname, (*args[i+1])->value.str.val, (*args[i+1])->value.str.len + 1);
- ptr->fsize = 0;
+ /* Trying to access a property on a non-object. */
+ if (Z_TYPE_PP(object) != IS_OBJECT) {
+ return FAILURE;
+ }
+
+ getter_retval = php_w32api_do_prop_get(*object, &result, &element TSRMLS_CC);
+
+ if (getter_retval == SUCCESS) {
+ temp = result;
+ object = &temp_ptr;
+ } else {
+ if ((getter_retval = zend_hash_find(Z_OBJPROP_PP(object),
+ Z_STRVAL(overloaded_property->element),
+ Z_STRLEN(overloaded_property->element)+1,
+ (void **)&object)) == FAILURE) {
+ MAKE_STD_ZVAL(new_val);
+ ZVAL_NULL(new_val);
+ zend_hash_update(Z_OBJPROP_PP(object),
+ Z_STRVAL(overloaded_property->element),
+ Z_STRLEN(overloaded_property->element)+1,
+ &new_val, sizeof(void *), (void **)&object);
+ }
+ }
- if(!strcmp(ptr->type, "long"))
- {
- ptr->fsize = sizeof(long);
- }
- else if (!strcmp(ptr->type, "int"))
- {
- ptr->fsize = sizeof(int);
- }
- else if (!strcmp(ptr->type, "string"))
- {
- ptr->fsize = sizeof(char *);
+ } else if (Z_TYPE_P(overloaded_property) == OE_IS_ARRAY) {
+ if (Z_TYPE_PP(object) == IS_NULL ||
+ (Z_TYPE_PP(object) == IS_BOOL && Z_LVAL_PP(object) == 0) ||
+ (Z_TYPE_PP(object) == IS_STRING && Z_STRLEN_PP(object) == 0)) {
+ array_init(*object);
+ }
+
+ /* Trying to access index on a non-array. */
+ if (Z_TYPE_PP(object) != IS_ARRAY) {
+ return FAILURE;
+ }
+
+ if (Z_TYPE(overloaded_property->element) == IS_STRING) {
+ getter_retval = zend_hash_find(Z_ARRVAL_PP(object),
+ Z_STRVAL(overloaded_property->element),
+ Z_STRLEN(overloaded_property->element)+1,
+ (void **)&object);
+ } else if (Z_TYPE(overloaded_property->element) == IS_LONG) {
+ getter_retval = zend_hash_index_find(Z_ARRVAL_PP(object),
+ Z_LVAL(overloaded_property->element),
+ (void **)&object);
+ }
+
+ if (getter_retval == FAILURE) {
+ MAKE_STD_ZVAL(new_val);
+ ZVAL_NULL(new_val);
+
+ if (Z_TYPE(overloaded_property->element) == IS_STRING) {
+ zend_hash_update(Z_ARRVAL_PP(object),
+ Z_STRVAL(overloaded_property->element),
+ Z_STRLEN(overloaded_property->element)+1,
+ &new_val, sizeof(void *), (void **)&object);
+ } else if (Z_TYPE(overloaded_property->element) == IS_LONG) {
+ zend_hash_index_update(Z_ARRVAL_PP(object),
+ Z_LVAL(overloaded_property->element),
+ &new_val, sizeof(void *), (void **)&object);
+ }
+ }
}
- else if (!strcmp(ptr->type, "byte"))
- {
- ptr->fsize = 1;
+
+ zval_dtor(&overloaded_property->element);
+ }
+
+ /* object is now the object we want to set our property on */
+ overloaded_property = (zend_overloaded_element *) element->data;
+ setter_retval = php_w32api_do_prop_set(*object, value, &element TSRMLS_CC);
+ zval_dtor(&overloaded_property->element);
+
+ return setter_retval;
+
+}
+/* }}} */
+
+/* {{{ W32API_PROP_GET_FUNCTION(type)
+ */
+W32API_PROP_GET_FUNCTION(type)
+{
+ zval result;
+ zval *result_ptr = &result;
+ zval **prop_result;
+ zend_overloaded_element *overloaded_property;
+ zend_llist_element *element;
+ zval object = *property_reference->object;
+ int getter_retval;
+ TSRMLS_FETCH();
+
+ for (element=property_reference->elements_list->head; element; element=element->next) {
+ overloaded_property = (zend_overloaded_element *) element->data;
+
+ getter_retval = FAILURE;
+ ZVAL_NULL(&result);
+ if (Z_TYPE_P(overloaded_property) == OE_IS_OBJECT) {
+ /* Trying to access a property on a non-object. */
+ if (Z_TYPE(object) != IS_OBJECT ||
+ Z_TYPE(overloaded_property->element) != IS_STRING) {
+ return result;
+ }
+
+ if ((getter_retval = php_w32api_do_prop_get(&object, &result, &element TSRMLS_CC) == FAILURE)) {
+ if ((getter_retval = zend_hash_find(Z_OBJPROP(object),
+ Z_STRVAL(overloaded_property->element),
+ Z_STRLEN(overloaded_property->element)+1,
+ (void **)&prop_result)) == SUCCESS) {
+ result = **prop_result;
+ }
+ }
+ } else if (Z_TYPE_P(overloaded_property) == OE_IS_ARRAY) {
+ /* Trying to access index on a non-array. */
+ if (Z_TYPE(object) != IS_ARRAY) {
+ return result;
+ }
+
+ if (Z_TYPE(overloaded_property->element) == IS_STRING) {
+ getter_retval = zend_hash_find(Z_ARRVAL(object),
+ Z_STRVAL(overloaded_property->element),
+ Z_STRLEN(overloaded_property->element)+1,
+ (void **)&prop_result);
+ } else if (Z_TYPE(overloaded_property->element) == IS_LONG) {
+ getter_retval = zend_hash_index_find(Z_ARRVAL(object),
+ Z_LVAL(overloaded_property->element),
+ (void **)&prop_result);
+ }
+ if (getter_retval == SUCCESS)
+ result = **prop_result;
}
- else if (!strcmp(ptr->type, "double"))
- {
- ptr->fsize = sizeof(double);
+
+ zval_dtor(&overloaded_property->element);
+
+ object = result;
+
+ if (getter_retval == FAILURE) {
+ return result;
}
- else if (!strcmp(ptr->type, "bool"))
+ }
+
+ zval_add_ref(&result_ptr);
+ SEPARATE_ZVAL(&result_ptr);
+ return *result_ptr;
+}
+/* }}} */
+
+/* {{{ proto: Type Type::Clone()
+ * Creates an exact clone of the object.
+ */
+W32API_CLASS_FUNCTION(type, clone)
+{
+
+}
+/* }}} */
+
+/* =====================================================================================================
+ * Scanner & Parser Functions
+ * =====================================================================================================
+ */
+
+/* -----------------------------
+ * Function Definition Functions
+ * -----------------------------
+ */
+
+/* {{{ w32api_parser_load_function_ex
+ * Callback for the parser, if the library name is cb.cb we are registering a
+ * callback so the LoadLibary and GetProcAddress code is skipped
+ */
+w32api_func_handle *w32api_parser_load_function_ex(char *return_type, char *function_name, char *alias_name, arguments *argument_list, char *library_name)
+{
+ w32api_func_handle *return_value;
+ TSRMLS_FETCH();
+
+ return_value = (w32api_func_handle *)emalloc(sizeof(w32api_func_handle));
+ memset(return_value, '\0', sizeof(w32api_func_handle));
+
+ return_value->argument_list = argument_list;
+ return_value->flags = 0;
+ return_value->function_name = (alias_name)?alias_name:function_name; /* This is estrdup'd in the Scanner already!! */
+ return_value->return_type_name = return_type; /* This is estrdup'd in the Scanner already!! */
+ return_value->return_type_id = php_w32api_get_type_id_from_name(return_type);
+
+ if(strcmp("cb.cb", library_name)) /* Bit of a hack but we are registering a callback */
+ {
+ php_w32api_load_library(library_name, &return_value->lib TSRMLS_CC);
+
+ if(!return_value->lib)
{
- ptr->fsize = sizeof(BOOL);
+ /* php_w32api_load_library has already given error */
+ efree(return_value);
+ return NULL;
}
- else
+
+ return_value->handle = GetProcAddress(return_value->lib->handle, function_name);
+
+ if(!return_value->handle)
{
- /**
- * this could be a userdef'd type so lets
- * search the ht for that.
- */
- if(zend_hash_find(W32_G(types), ptr->type, strlen(ptr->type), (void **) &tmp) == FAILURE)
- {
- php_error(E_WARNING, "Unknown type %s", ptr->type);
- RETURN_FALSE;
- }
- orst = tmp;
- ptr->fsize = orst->size;
+ /* Check for variation ending with A */
+ char *ascii_name = NULL;
+
+ ascii_name = emalloc(strlen(function_name) + 2);
+ strcpy(ascii_name, function_name);
+ ascii_name[strlen(function_name)] = 'A';
+ ascii_name[strlen(function_name) + 1] = '\0';
+ return_value->handle = GetProcAddress(return_value->lib->handle, ascii_name);
+ efree(ascii_name);
+
+ if(!return_value->handle)
+ {
+ /* TODO: php_error_docref and GetLastError etc */
+ php_error(E_WARNING, "Could not load function %s", function_name);
+ efree(return_value);
+ return NULL;
+ }
}
-
- rst->size += ptr->fsize;
- ptr++;
}
- rst->fields = fields;
+ /* We want function_name in lowercase now */
+ php_strtolower(return_value->function_name, strlen(return_value->function_name));
+
+ /* Free it if we have a alias */
+ if(alias_name)
+ efree(function_name);
+
+ return return_value;
+}
+/* }}} */
+
+/* {{{ w32api_parser_make_argument
+ * Helper function for the parser
+ */
+arguments *w32api_parser_make_argument(char *arg_type, char *arg_name, int byref)
+{
+ arguments *return_value = NULL; /* Pointer to our return value */
+ argument *argument_value = NULL; /* Our actual argument */
+
+ argument_value = emalloc(sizeof(argument));
+ return_value = emalloc(sizeof(arguments));
+
+ return_value->arg = argument_value;
+ return_value->next_arg = return_value->prev_arg = NULL;
+
+ argument_value->flags = byref;
+ argument_value->argument_name = arg_name;
+ argument_value->type_name = arg_type;
+ argument_value->type_id = php_w32api_get_type_id_from_name(arg_type);
- if(zend_hash_add(W32_G(types), rst->name, strlen(rst->name), rst, sizeof(runtime_struct), NULL) == FAILURE)
+ if(argument_value->type_id == W32API_UNKNOWN)
{
- php_error(E_WARNING, "Error registering type %s", rst->name);
- RETURN_FALSE;
+ php_error(E_NOTICE, "Unknown type %s used as arugment type", arg_type);
}
- RETURN_TRUE;
+ return return_value;
+}
+/* }}} */
+
+/* {{{ w32api_parser_join_arguments
+ * Helper function for the parser
+ */
+arguments *w32api_parser_join_arguments(arguments *lval, arguments *rval)
+{
+ lval->next_arg = rval;
+ rval->prev_arg = lval;
+ return lval;
}
-/* }}} */
+/* }}} */
+
+/* {{{ w32api_function_definition_error
+ * Error function for the parser
+ */
+int w32api_function_definition_error(char *s)
+{
+ php_error(E_ERROR, "Function Definition Parse Error: %s", s);
+ return 0;
+}
+/* }}} */
-/* {{{ proto resource w32api_init_dtype(string typename, mixed val1, mixed val2);
- Creates an instance to the data type typename and fills it with the values val1, val2, the function
- then returns a DYNAPARM which can be passed when invoking a function as a parameter.*/
-PHP_FUNCTION(w32api_init_dtype)
+/* -------------------------
+ * Type Definition Functions
+ * -------------------------
+ */
+w32api_type_handle *w32api_parser_register_type(char *type_name, members *member_list)
{
- DYNAPARM *dparam, *tparam;
- void *rtstruct, *tmp;
- runtime_struct *rst;
- field *ptr;
- char *m;
- zval ***args;
- zval **curarg;
- int i, j,argc = ZEND_NUM_ARGS();
+ w32api_type_handle *return_value = NULL;
+ members *current_member;
+ int offset = 0;
+ int member_count = 0;
- args = emalloc(sizeof(zval **) * argc);
- dparam = emalloc(sizeof(DYNAPARM));
+ return_value = emalloc(sizeof(w32api_type_handle));
- if(zend_get_parameters_array_ex(argc, args) != SUCCESS)
- {
- WRONG_PARAM_COUNT
- }
+ return_value->member_list = member_list;
+ return_value->type_name = type_name; /* estrdup'd in parser */
+ return_value->member_count = 0;
+
+ current_member = return_value->member_list;
- convert_to_string_ex(args[0]);
- if(zend_hash_find(W32_G(types), (*args[0])->value.str.val, (*args[0])->value.str.len, (void **)&tmp) == FAILURE)
+ while(current_member != NULL)
{
- php_error(E_WARNING, "Unknown type %s",(*args[0])->value.str.val);
- RETURN_FALSE
+ return_value->member_count++;
+ current_member->member->offset = offset;
+ offset += php_w32api_get_type_size(current_member->member->member_type_id, current_member->member->member_type_name, current_member->member->flags);
+ current_member = current_member->next_member;
}
- rst = (runtime_struct *)tmp;
- rtstruct = emalloc(rst->size);
- rtstruct = memset(rtstruct, 0, rst->size);
- tmp = rtstruct;
- curarg = args[1];
- ptr = rst->fields;
+ return_value->size = offset;
- i = 0;
- j = (argc-1);
+ return return_value;
- while(i<j)
- {
- if(!strcmp(ptr->type, "long"))
- {
- convert_to_long_ex(curarg);
- memcpy(tmp, &(*curarg)->value.lval, ptr->fsize);
- }
- else if (!strcmp(ptr->type, "int"))
- {
- convert_to_long_ex(curarg);
- memcpy(tmp, &(*curarg)->value.lval, ptr->fsize);
- }
- else if (!strcmp(ptr->type, "string"))
- {
- convert_to_string_ex(curarg);
- m = emalloc(sizeof(char) * (*curarg)->value.str.len + 1);
- memcpy(m, (*curarg)->value.str.val, (*curarg)->value.str.len + 1);
- memcpy(tmp, &m, ptr->fsize);
- }
- else if (!strcmp(ptr->type, "byte"))
- {
- /* use Lower order bytes */
- convert_to_long_ex(curarg);
- memcpy(tmp, &(*curarg)->value.lval, ptr->fsize);
- }
- else if (!strcmp(ptr->type, "double"))
- {
- convert_to_double_ex(curarg);
- memcpy(tmp, &(*curarg)->value.dval, ptr->fsize);
- }
- else if (!strcmp(ptr->type, "bool"))
- {
- convert_to_boolean_ex(curarg);
- memcpy(tmp, &(*curarg)->value.lval, ptr->fsize);
- }
- else
- {
- /**
- * OK we have a user type here, we need to treat the param
- * as a resource and fetch the DYNAPARM its contained in
- * then copy the contents of its LPVOID pointer into our
- * memory space.
- */
- ZEND_FETCH_RESOURCE(tparam, DYNAPARM *, curarg, -1, "dynaparm", W32_G(le_dynaparm));
- memcpy(tmp, tparam->pArg, ptr->fsize);
- }
- /**
- * We need somthing that is 1 byte
- */
- (char)tmp += ptr->fsize;
- (void *)tmp;
+}
+
+members *w32api_parser_type_make_value(char *type_name, char *member_name, long flags)
+{
+ members *return_value = NULL; /* Pointer to our return value */
+ member *member_value = NULL; /* Our actual member */
- curarg++;
- ptr++;
- i++;
- }
+ member_value = emalloc(sizeof(member));
+ return_value = emalloc(sizeof(members));
- dparam->dwFlags = 0;
- dparam->nWidth = rst->size;
- dparam->pArg = rtstruct;
-
- ZEND_REGISTER_RESOURCE(return_value, dparam, W32_G(le_dynaparm));
+ return_value->member = member_value;
+ return_value->next_member = return_value->prev_member = NULL;
+
+ member_value->member_name = member_name; /* estrdup'd in parser */
+ member_value->member_type_name = type_name; /* estrdup'd in parser */
+ member_value->member_type_id = php_w32api_get_type_id_from_name(type_name);
+ member_value->flags = flags;
+ return return_value;
}
-/* }}} */
-#endif /* HAVE_W32API */
+members *w32api_parser_type_join_values(members *lval, members *rval)
+{
+ lval->next_member = rval;
+ rval->prev_member = lval;
+
+ return lval;
+}
+
+/* {{{ w32api_function_definition_error
+ * Error function for the parser
+ */
+int w32api_type_definition_error(char *s)
+{
+ php_error(E_ERROR, "Type Definition Parse Error: %s", s);
+ return 0;
+}
+/* }}} */
+
+
+#endif /* HAVE_W32API */
\ No newline at end of file