📄 w32api.c
字号:
/* +----------------------------------------------------------------------+ | PHP version 4.0 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2007 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.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: w32api.c,v 1.5.2.4.2.2 2007/01/01 09:46:49 sebastian Exp $ *//* * 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 function 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#include <stdio.h>#include <stdlib.h>#define WINDOWS_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"/* ===================================================================================================== * PHP Module Startup, Shutdown & Info Code * ===================================================================================================== */#ifdef COMPILE_DL_W32APIZEND_GET_MODULE(w32api)#endif/* {{{ w32api_module_entry */zend_module_entry w32api_module_entry = { STANDARD_MODULE_HEADER, "Win32 API", NULL, /* We define no global functions */ PHP_MINIT(w32api), PHP_MSHUTDOWN(w32api), PHP_RINIT(w32api), PHP_RSHUTDOWN(w32api), PHP_MINFO(w32api), "0.2", STANDARD_MODULE_PROPERTIES};/* }}} *//* {{{ PHP_MINIT_FUNCTION */PHP_MINIT_FUNCTION(w32api){ /* Setup out module globals */ ZEND_INIT_MODULE_GLOBALS(w32api, php_w32api_init_globals, NULL); if(win32_class_init(TSRMLS_C) != SUCCESS) { return FAILURE; } if(type_class_init(TSRMLS_C) != SUCCESS) { return FAILURE; } 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;}/* }}} *//* {{{ PHP_RINIT_FUNCTION */PHP_RINIT_FUNCTION(w32api){ HashTable *tmp; WG(funcs) = WG(libraries) = WG(callbacks) = WG(types) = NULL; /* Allocate Request Specific HT's here */ ALLOC_HASHTABLE(tmp); zend_hash_init(tmp, 1, NULL, php_w32api_hash_func_dtor, 1); WG(funcs) = tmp; ALLOC_HASHTABLE(tmp); zend_hash_init(tmp, 1, NULL, php_w32api_hash_lib_dtor, 1); WG(libraries) = tmp; ALLOC_HASHTABLE(tmp); zend_hash_init(tmp, 1, NULL, php_w32api_hash_callback_dtor, 1); WG(callbacks) = tmp; ALLOC_HASHTABLE(tmp); zend_hash_init(tmp, 1, NULL, php_w32api_hash_type_dtor, 1); WG(types) = tmp; return SUCCESS;};/* }}} *//* {{{ PHP_RSHUTDOWN_FUNCTION */PHP_RSHUTDOWN_FUNCTION(w32api){ 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)); WG(funcs) = WG(libraries) = WG(callbacks) = WG(types) = NULL; return SUCCESS;}/* }}} *//* {{{ 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_w32api_init_globals */static void php_w32api_init_globals(zend_w32api_globals *w32api_globals){ 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;}/* }}} *//* {{{ 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; FreeLibrary(lh->handle); efree(lh->library_name);}/* }}} *//* {{{ 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);}/* }}} *//* {{{ php_w32api_hash_callback_dtor * DTOR function called when hash is destroied, removes callback. */static void php_w32api_hash_callback_dtor(void *data){ w32api_func_handle **fh; fh = (w32api_func_handle **)data; 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);}static void w32api_type_instance_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC){ w32api_type_instance *ti; int i = 0; if(!rsrc || !rsrc->ptr) return; ti = (w32api_type_instance *)rsrc->ptr; for(i = 0; i < ti->type->member_count; i++) { if(ti->values[i]) zval_ptr_dtor(&ti->values[i]); } efree(ti); return;}/* ===================================================================================================== * Utility Functions * ===================================================================================================== *//* {{{ 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -