📄 w32api.c
字号:
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -