--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP version 4.0 |
+ +----------------------------------------------------------------------+
+ | 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 |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_02.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: James Moore <jmoore@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if HAVE_W32API
+#include <stdio.h>
+#include <stdlib.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "ext/standard/php_string.h"
+#include "php_w32api.h"
+
+/* {{{ w32api_functions[]
+ */
+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)
+ {NULL, NULL, NULL}
+};
+/* }}} */
+
+/* {{{ w32api_module_entry
+ */
+zend_module_entry w32api_module_entry = {
+ STANDARD_MODULE_HEADER,
+ "w32api",
+ w32api_functions,
+ PHP_MINIT(w32api),
+ PHP_MSHUTDOWN(w32api),
+ NULL,
+ NULL,
+ PHP_MINFO(w32api),
+ "0.1", /* Replace with version number for your extension */
+ 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)
+{
+ 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))
+ {
+ FREE_HASHTABLE(W32_G(regfuncs));
+ }
+
+ if(W32_G(libraries))
+ {
+ php_w32api_unload_libraries();
+ FREE_HASHTABLE(W32_G(libraries));
+ }
+
+ if(W32_G(libraries))
+ {
+ FREE_HASHTABLE(W32_G(types));
+ }
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ DYNAPARM dtor */
+static void w32api_free_dynaparm(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ DYNAPARM *dparam;
+
+ dparam = (DYNAPARM *)rsrc->ptr;
+
+ if(dparam->pArg)
+ efree(dparam->pArg);
+
+ efree(dparam);
+}
+/* }}} */
+
+/* {{{ */
+static void php_w32api_unload_libraries()
+{
+ TSRMLS_FETCH();
+ zend_hash_destroy(W32_G(libraries));
+}
+/* }}} */
+
+/* {{{ */
+static void php_w32api_dtor_library(void *data)
+{
+ FreeLibrary((HINSTANCE)data);
+}
+/* }}} */
+
+/* {{{ */
+static void php_w32api_init_globals(zend_w32api_globals *w32api_globals)
+{
+ TSRMLS_FETCH();
+
+ w32api_globals->regfuncs = NULL;
+ w32api_globals->libraries = 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);
+
+ ALLOC_HASHTABLE(W32_G(libraries));
+ zend_hash_init(W32_G(libraries), 1, NULL, php_w32api_dtor_library, 1);
+
+ ALLOC_HASHTABLE(W32_G(types));
+ zend_hash_init(W32_G(types), 5, NULL, NULL, 1);
+
+}
+/* }}} */
+
+/* {{{ */
+static void register_constants(int module_number)
+{
+ TSRMLS_FETCH();
+
+ 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)
+
+}
+/* }}} */
+
+/* {{{ proto void w32api_set_call_method(int method)
+ Sets the calling method used */
+PHP_FUNCTION(w32api_set_call_method)
+{
+ zval **method;
+
+ if(zend_get_parameters_ex(1, &method) == FAILURE)
+ {
+ WRONG_PARAM_COUNT
+ }
+
+ switch((*method)->value.lval)
+ {
+ case DC_CALL_CDECL:
+ W32_G(call_type) = DC_CALL_CDECL;
+ break;
+ default:
+ W32_G(call_type) = DC_CALL_STD;
+ break;
+ }
+
+ RETURN_TRUE
+
+}
+/* }}} */
+
+/* {{{ proto bool w32api_register_function(string libary, string function_name)
+ Registers function function_name from library with PHP */
+PHP_FUNCTION(w32api_register_function)
+{
+ 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)
+ {
+ WRONG_PARAM_COUNT
+ }
+
+ convert_to_string_ex(libname);
+ convert_to_string_ex(funcname);
+ convert_to_string_ex(retval_type);
+
+ fe = (W32APIFE *)emalloc(sizeof(W32APIFE));
+ fe->retvaltype = 0;
+ //TODO: Check library isnt alreay loaded
+
+ hinstLib = LoadLibrary((*libname)->value.str.val);
+
+ if(hinstLib == NULL)
+ {
+ php_error(E_WARNING, "Could not load dynamic link library %s", (*libname)->value.str.val);
+ RETURN_FALSE
+ }
+
+ zend_hash_add(W32_G(libraries),
+ (*libname)->value.str.val,
+ strlen((*libname)->value.str.val),
+ &hinstLib,
+ sizeof(HINSTANCE),
+ NULL);
+
+ //TODO: Check function handle isnt already loaded
+
+ ProcAdd = (FARPROC) GetProcAddress(hinstLib, (*funcname)->value.str.val);
+
+ if(ProcAdd == NULL)
+ {
+ php_error(E_WARNING, "Could not get handle for function %s", (*funcname)->value.str.val);
+ RETURN_FALSE
+ }
+
+ fe->fp = ProcAdd;
+
+ 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"))
+ {
+ fe->rettype = malloc(4*sizeof(char));
+ fe->rettype = strdup("long\0");
+ }
+ else if (!strcmp((*retval_type)->value.str.val, "string"))
+ {
+ fe->rettype = malloc(7*sizeof(char));
+ fe->rettype = strdup("string\0");
+ }
+ else if (!strcmp((*retval_type)->value.str.val, "byte"))
+ {
+ fe->rettype = malloc(5*sizeof(char));
+ fe->rettype = strdup("byte\0");
+ }
+ else if (!strcmp((*retval_type)->value.str.val, "double"))
+ {
+ fe->rettype = malloc(7*sizeof(char));
+ fe->rettype = strdup("double\0");
+ }
+ else if (!strcmp((*retval_type)->value.str.val, "bool"))
+ {
+ fe->rettype = malloc(5*sizeof(char));
+ fe->rettype = strdup("bool\0");
+ }
+ else
+ {
+ /**
+ * 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;
+ }
+
+ 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
+ */
+ {
+ 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
+ }
+
+
+ }
+
+
+
+ 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)
+{
+ 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;
+
+ args = emalloc(argc * sizeof(zval **));
+ Param = (DYNAPARM *)emalloc((argc) * sizeof(DYNAPARM));
+
+ if(zend_get_parameters_array_ex(argc, args) == FAILURE)
+ {
+ WRONG_PARAM_COUNT
+ }
+
+ funcname = get_active_function_name(TSRMLS_C);
+
+ 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;
+ }
+
+ fe = (W32APIFE *)tmp;
+
+ // Build the DYNPARAM array.
+ for(i = 0; i < (argc); i++)
+ {
+ Param[i] = w32api_convert_zval_to_dynparam(args[(i)] TSRMLS_CC);
+ }
+
+
+ /**
+ * 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;
+ }
+
+ retval = php_w32api_dynamic_dll_call(W32_G(call_type), (ulong)(fe->fp), (argc), Param, pVParam, VParamsz);
+
+ if(!strcmp(fe->rettype, "long"))
+ {
+ RETURN_LONG(retval.Long);
+ }
+ else if (!strcmp(fe->rettype, "int"))
+ {
+ RETURN_LONG(retval.Int);
+ }
+ else if (!strcmp(fe->rettype, "string"))
+ {
+ RETURN_STRING(retval.Pointer, 1);
+ }
+ else if (!strcmp(fe->rettype, "byte"))
+ {
+ php_error(E_WARNING, "byte return values are not supported right now");
+ RETURN_FALSE;
+ }
+ else if (!strcmp(fe->rettype, "double"))
+ {
+ RETURN_DOUBLE(retval.Double);
+ }
+ else if (!strcmp(fe->rettype, "bool"))
+ {
+ if(retval.Int)
+ {
+ RETURN_TRUE;
+ }
+ else
+ {
+ RETURN_FALSE;
+ }
+ }
+ 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));
+ }
+
+}
+/* }}} */
+
+/* {{{ 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;
+}
+/* }}} */
+
+/* {{{ 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)
+ {
+ 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;
+ break;
+ case IS_LONG:
+ dparam.nWidth = sizeof(long);
+ dparam.dwArg = (*carg)->value.lval;
+ break;
+ case IS_DOUBLE:
+ dparam.nWidth = sizeof(float);
+ dparam.pArg = &(*carg)->value.dval;
+ dparam.dwFlags = DC_FLAG_ARGPTR;
+ break;
+ case IS_STRING:
+ dparam.nWidth = sizeof(char *);
+ dparam.pArg = (*carg)->value.str.val;
+ break;
+ case IS_BOOL:
+ dparam.nWidth = sizeof(BOOL);
+ dparam.dwArg = ((*carg)->value.lval == 0)?FALSE:TRUE;
+ break;
+ case IS_NULL:
+ dparam.nWidth = sizeof(void *);
+ dparam.pArg = NULL;
+ break;
+ default:
+ php_error(E_ERROR, "Cant convert variable to type dynparam");
+ }
+
+ 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
+ *
+ */
+
+/* {{{ 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)
+{
+ zval ***args;
+ int argc = ZEND_NUM_ARGS();
+ int i;
+ runtime_struct *rst, *orst;
+ void *tmp;
+ field *fields, *ptr;
+
+ args = (zval ***)emalloc(sizeof(zval **) * argc);
+ rst = malloc(sizeof(runtime_struct));
+
+ ptr = (field *)emalloc(sizeof(field) *((argc-1)/2));
+
+ fields = ptr;
+
+ if((zend_get_parameters_array_ex(argc, args) == FAILURE) || ((argc % 2) != 1))
+ {
+ WRONG_PARAM_COUNT
+ }
+
+ for(i=2; i<argc; i++)
+ {
+ convert_to_string_ex(args[i]);
+ }
+
+ convert_to_string_ex(args[0]);
+
+ rst->name = (*args[0])->value.str.val;
+ rst->size = 0;
+
+ /**
+ * We now take each parameter pair and fill out the field struct
+ * for each parameter pair.
+ */
+ 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);
+
+ 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;
+
+ 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 (!strcmp(ptr->type, "byte"))
+ {
+ ptr->fsize = 1;
+ }
+ else if (!strcmp(ptr->type, "double"))
+ {
+ ptr->fsize = sizeof(double);
+ }
+ else if (!strcmp(ptr->type, "bool"))
+ {
+ ptr->fsize = sizeof(BOOL);
+ }
+ else
+ {
+ /**
+ * 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;
+ }
+
+ rst->size += ptr->fsize;
+ ptr++;
+ }
+
+ rst->fields = fields;
+
+ if(zend_hash_add(W32_G(types), rst->name, strlen(rst->name), rst, sizeof(runtime_struct), NULL) == FAILURE)
+ {
+ php_error(E_WARNING, "Error registering type %s", rst->name);
+ RETURN_FALSE;
+ }
+
+ RETURN_TRUE;
+
+}
+/* }}} */
+
+/* {{{ 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)
+{
+ DYNAPARM *dparam, *tparam;
+ void *rtstruct, *tmp;
+ runtime_struct *rst;
+ field *ptr;
+ char *m;
+ zval ***args;
+ zval **curarg;
+ int i, j,argc = ZEND_NUM_ARGS();
+
+ args = emalloc(sizeof(zval **) * argc);
+ dparam = emalloc(sizeof(DYNAPARM));
+
+ if(zend_get_parameters_array_ex(argc, args) != SUCCESS)
+ {
+ WRONG_PARAM_COUNT
+ }
+
+ 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)
+ {
+ php_error(E_WARNING, "Unknown type %s",(*args[0])->value.str.val);
+ RETURN_FALSE
+ }
+
+ rst = (runtime_struct *)tmp;
+
+ rtstruct = emalloc(rst->size);
+ rtstruct = memset(rtstruct, 0, rst->size);
+ tmp = rtstruct;
+ curarg = args[1];
+ ptr = rst->fields;
+
+ i = 0;
+ j = (argc-1);
+
+ 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;
+
+ curarg++;
+ ptr++;
+ i++;
+ }
+
+ dparam->dwFlags = 0;
+ dparam->nWidth = rst->size;
+ dparam->pArg = rtstruct;
+
+ ZEND_REGISTER_RESOURCE(return_value, dparam, W32_G(le_dynaparm));
+
+}
+/* }}} */
+
+
+#endif /* HAVE_W32API */
\ No newline at end of file