Back to index

php5  5.3.10
com_handlers.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Wez Furlong  <wez@thebrainroom.com>                          |
00016    +----------------------------------------------------------------------+
00017  */
00018 
00019 /* $Id: com_handlers.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024 
00025 #include "php.h"
00026 #include "php_ini.h"
00027 #include "ext/standard/info.h"
00028 #include "php_com_dotnet.h"
00029 #include "php_com_dotnet_internal.h"
00030 #include "Zend/zend_exceptions.h"
00031 
00032 static zval *com_property_read(zval *object, zval *member, int type TSRMLS_DC)
00033 {
00034        zval *return_value;
00035        php_com_dotnet_object *obj;
00036        VARIANT v;
00037        HRESULT res;
00038 
00039        MAKE_STD_ZVAL(return_value);
00040        ZVAL_NULL(return_value);
00041        Z_SET_REFCOUNT_P(return_value, 0);
00042        Z_UNSET_ISREF_P(return_value);
00043 
00044        obj = CDNO_FETCH(object);
00045 
00046        if (V_VT(&obj->v) == VT_DISPATCH) {
00047               VariantInit(&v);
00048 
00049               convert_to_string_ex(&member);
00050 
00051               res = php_com_do_invoke(obj, Z_STRVAL_P(member), Z_STRLEN_P(member),
00052                             DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, 0, NULL, 1 TSRMLS_CC);
00053 
00054               if (res == SUCCESS) {
00055                      php_com_zval_from_variant(return_value, &v, obj->code_page TSRMLS_CC);
00056                      VariantClear(&v);
00057               } else if (res == DISP_E_BADPARAMCOUNT) {
00058                      php_com_saproxy_create(object, return_value, member TSRMLS_CC);
00059               }
00060        } else {
00061               php_com_throw_exception(E_INVALIDARG, "this variant has no properties" TSRMLS_CC);
00062        }
00063 
00064        return return_value;
00065 }
00066 
00067 static void com_property_write(zval *object, zval *member, zval *value TSRMLS_DC)
00068 {
00069        php_com_dotnet_object *obj;
00070        VARIANT v;
00071 
00072        obj = CDNO_FETCH(object);
00073 
00074        if (V_VT(&obj->v) == VT_DISPATCH) {
00075               VariantInit(&v);
00076 
00077               convert_to_string_ex(&member);
00078               if (SUCCESS == php_com_do_invoke(obj, Z_STRVAL_P(member), Z_STRLEN_P(member),
00079                             DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF, &v, 1, &value, 0 TSRMLS_CC)) {
00080                      VariantClear(&v);
00081               }
00082        } else {
00083               php_com_throw_exception(E_INVALIDARG, "this variant has no properties" TSRMLS_CC);
00084        }
00085 }
00086 
00087 static zval *com_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
00088 {
00089        zval *return_value;
00090        php_com_dotnet_object *obj;
00091        VARIANT v;
00092 
00093        MAKE_STD_ZVAL(return_value);
00094        ZVAL_NULL(return_value);
00095        Z_SET_REFCOUNT_P(return_value, 0);
00096        Z_UNSET_ISREF_P(return_value);
00097 
00098        obj = CDNO_FETCH(object);
00099 
00100        if (V_VT(&obj->v) == VT_DISPATCH) {
00101               VariantInit(&v);
00102 
00103               if (SUCCESS == php_com_do_invoke_by_id(obj, DISPID_VALUE,
00104                             DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, 1, &offset, 0, 0 TSRMLS_CC)) {
00105                      php_com_zval_from_variant(return_value, &v, obj->code_page TSRMLS_CC);
00106                      VariantClear(&v);
00107               }
00108        } else if (V_ISARRAY(&obj->v)) {
00109               convert_to_long(offset);
00110 
00111               if (SafeArrayGetDim(V_ARRAY(&obj->v)) == 1) {    
00112                      if (php_com_safearray_get_elem(&obj->v, &v, Z_LVAL_P(offset) TSRMLS_CC)) {
00113                             php_com_wrap_variant(return_value, &v, obj->code_page TSRMLS_CC);
00114                             VariantClear(&v);
00115                      }
00116               } else {
00117                      php_com_saproxy_create(object, return_value, offset TSRMLS_CC);
00118               }
00119 
00120        } else {
00121               php_com_throw_exception(E_INVALIDARG, "this variant is not an array type" TSRMLS_CC);
00122        }
00123 
00124        return return_value;
00125 }
00126 
00127 static void com_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC)
00128 {
00129        php_com_dotnet_object *obj;
00130        zval *args[2];
00131        VARIANT v;
00132        HRESULT res;
00133 
00134        obj = CDNO_FETCH(object);
00135 
00136        if (V_VT(&obj->v) == VT_DISPATCH) {
00137               args[0] = offset;
00138               args[1] = value;
00139 
00140               VariantInit(&v);
00141 
00142               if (SUCCESS == php_com_do_invoke_by_id(obj, DISPID_VALUE,
00143                             DISPATCH_METHOD|DISPATCH_PROPERTYPUT, &v, 2, args, 0, 0 TSRMLS_CC)) {
00144                      VariantClear(&v);
00145               }
00146        } else if (V_ISARRAY(&obj->v)) {
00147               LONG indices = 0;
00148               VARTYPE vt;
00149               
00150               if (SafeArrayGetDim(V_ARRAY(&obj->v)) == 1) {    
00151                      if (FAILED(SafeArrayGetVartype(V_ARRAY(&obj->v), &vt)) || vt == VT_EMPTY) {
00152                             vt = V_VT(&obj->v) & ~VT_ARRAY;
00153                      }
00154 
00155                      convert_to_long(offset);
00156                      indices = Z_LVAL_P(offset);
00157 
00158                      VariantInit(&v);
00159                      php_com_variant_from_zval(&v, value, obj->code_page TSRMLS_CC);
00160 
00161                      if (V_VT(&v) != vt) {
00162                             VariantChangeType(&v, &v, 0, vt);
00163                      }
00164 
00165                      if (vt == VT_VARIANT) {
00166                             res = SafeArrayPutElement(V_ARRAY(&obj->v), &indices, &v);
00167                      } else {
00168                             res = SafeArrayPutElement(V_ARRAY(&obj->v), &indices, &v.lVal);
00169                      }
00170 
00171                      VariantClear(&v);
00172 
00173                      if (FAILED(res)) {
00174                             php_com_throw_exception(res, NULL TSRMLS_CC);
00175                      }
00176 
00177               } else {
00178                      php_com_throw_exception(DISP_E_BADINDEX, "this variant has multiple dimensions; you can't set a new value without specifying *all* dimensions" TSRMLS_CC);
00179               }
00180 
00181        } else {
00182               php_com_throw_exception(E_INVALIDARG, "this variant is not an array type" TSRMLS_CC);
00183        }
00184 }
00185 
00186 #if 0
00187 static void com_object_set(zval **property, zval *value TSRMLS_DC)
00188 {
00189        /* Not yet implemented in the engine */
00190 }
00191 
00192 static zval *com_object_get(zval *property TSRMLS_DC)
00193 {
00194        /* Not yet implemented in the engine */
00195        return NULL;
00196 }
00197 #endif
00198 
00199 static int com_property_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
00200 {
00201        DISPID dispid;
00202        php_com_dotnet_object *obj;
00203 
00204        obj = CDNO_FETCH(object);
00205 
00206        if (V_VT(&obj->v) == VT_DISPATCH) {
00207               convert_to_string_ex(&member);
00208               if (SUCCEEDED(php_com_get_id_of_name(obj, Z_STRVAL_P(member), Z_STRLEN_P(member), &dispid TSRMLS_CC))) {
00209                      /* TODO: distinguish between property and method! */
00210                      return 1;
00211               }
00212        } else {
00213               /* TODO: check for safearray */
00214        }
00215 
00216        return 0;
00217 }
00218 
00219 static int com_dimension_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
00220 {
00221        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Operation not yet supported on a COM object");
00222        return 0;
00223 }
00224 
00225 static void com_property_delete(zval *object, zval *member TSRMLS_DC)
00226 {
00227        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a COM object");
00228 }
00229 
00230 static void com_dimension_delete(zval *object, zval *offset TSRMLS_DC)
00231 {
00232        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a COM object");
00233 }
00234 
00235 static HashTable *com_properties_get(zval *object TSRMLS_DC)
00236 {
00237        /* TODO: use type-info to get all the names and values ?
00238         * DANGER: if we do that, there is a strong possibility for
00239         * infinite recursion when the hash is displayed via var_dump().
00240         * Perhaps it is best to leave it un-implemented.
00241         */
00242        return NULL;
00243 }
00244 
00245 static void function_dtor(void *pDest)
00246 {
00247        zend_internal_function *f = (zend_internal_function*)pDest;
00248 
00249        efree(f->function_name);
00250        if (f->arg_info) {
00251               efree(f->arg_info);
00252        }
00253 }
00254 
00255 static PHP_FUNCTION(com_method_handler)
00256 {
00257        Z_OBJ_HANDLER_P(getThis(), call_method)(
00258                      ((zend_internal_function*)EG(current_execute_data)->function_state.function)->function_name,
00259                      INTERNAL_FUNCTION_PARAM_PASSTHRU);
00260 }
00261 
00262 static union _zend_function *com_method_get(zval **object_ptr, char *name, int len TSRMLS_DC)
00263 {
00264        zend_internal_function f, *fptr = NULL;
00265        php_com_dotnet_object *obj;
00266        union _zend_function *func;
00267        DISPID dummy;
00268        zval *object = *object_ptr;
00269 
00270        obj = CDNO_FETCH(object);
00271 
00272        if (V_VT(&obj->v) != VT_DISPATCH) {
00273               return NULL;
00274        }
00275 
00276        if (FAILED(php_com_get_id_of_name(obj, name, len, &dummy TSRMLS_CC))) {
00277               return NULL;
00278        }
00279 
00280        /* check cache */
00281        if (obj->method_cache == NULL || FAILURE == zend_hash_find(obj->method_cache, name, len, (void**)&fptr)) {
00282               f.type = ZEND_OVERLOADED_FUNCTION;
00283               f.num_args = 0;
00284               f.arg_info = NULL;
00285               f.scope = obj->ce;
00286               f.fn_flags = 0;
00287               f.function_name = estrndup(name, len);
00288               f.handler = PHP_FN(com_method_handler);
00289 
00290               fptr = &f;
00291        
00292               if (obj->typeinfo) {
00293                      /* look for byref params */
00294                      ITypeComp *comp;
00295                      ITypeInfo *TI = NULL;
00296                      DESCKIND kind;
00297                      BINDPTR bindptr;
00298                      OLECHAR *olename;
00299                      ULONG lhash;
00300                      int i;
00301 
00302                      if (SUCCEEDED(ITypeInfo_GetTypeComp(obj->typeinfo, &comp))) {
00303                             olename = php_com_string_to_olestring(name, len, obj->code_page TSRMLS_CC);
00304                             lhash = LHashValOfNameSys(SYS_WIN32, LOCALE_SYSTEM_DEFAULT, olename);
00305 
00306                             if (SUCCEEDED(ITypeComp_Bind(comp, olename, lhash, INVOKE_FUNC, &TI, &kind, &bindptr))) {
00307                                    switch (kind) {
00308                                           case DESCKIND_FUNCDESC:
00309                                                  f.arg_info = ecalloc(bindptr.lpfuncdesc->cParams, sizeof(zend_arg_info));
00310 
00311                                                  for (i = 0; i < bindptr.lpfuncdesc->cParams; i++) {
00312                                                         f.arg_info[i].allow_null = 1;
00313                                                         if (bindptr.lpfuncdesc->lprgelemdescParam[i].paramdesc.wParamFlags & PARAMFLAG_FOUT) {
00314                                                                f.arg_info[i].pass_by_reference = 1;
00315                                                         }
00316                                                  }
00317 
00318                                                  f.num_args = bindptr.lpfuncdesc->cParams;
00319 
00320                                                  ITypeInfo_ReleaseFuncDesc(TI, bindptr.lpfuncdesc);
00321                                                  break;
00322 
00323                                                  /* these should not happen, but *might* happen if the user
00324                                                   * screws up; lets avoid a leak in that case */
00325                                           case DESCKIND_VARDESC:
00326                                                  ITypeInfo_ReleaseVarDesc(TI, bindptr.lpvardesc);
00327                                                  break;
00328                                           case DESCKIND_TYPECOMP:
00329                                                  ITypeComp_Release(bindptr.lptcomp);
00330                                                  break;
00331 
00332                                           case DESCKIND_NONE:
00333                                                  break;
00334                                    }
00335                                    if (TI) {
00336                                           ITypeInfo_Release(TI);
00337                                    }
00338                             }
00339                             ITypeComp_Release(comp);
00340                             efree(olename);
00341                      }
00342               }
00343 
00344               if (fptr) {
00345                      /* save this method in the cache */
00346                      if (!obj->method_cache) {
00347                             ALLOC_HASHTABLE(obj->method_cache);
00348                             zend_hash_init(obj->method_cache, 2, NULL, function_dtor, 0);
00349                      }
00350 
00351                      zend_hash_update(obj->method_cache, name, len, &f, sizeof(f), (void**)&fptr);
00352               }
00353        }
00354 
00355        if (fptr) {
00356               /* duplicate this into a new chunk of emalloc'd memory,
00357                * since the engine will efree it */
00358               func = emalloc(sizeof(*fptr));
00359               memcpy(func, fptr, sizeof(*fptr));
00360 
00361               return func;
00362        }
00363 
00364        return NULL;
00365 }
00366 
00367 static int com_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
00368 {
00369        zval ***args = NULL;
00370        php_com_dotnet_object *obj;
00371        int nargs;
00372        VARIANT v;
00373        int ret = FAILURE;
00374        
00375        obj = CDNO_FETCH(getThis());
00376 
00377        if (V_VT(&obj->v) != VT_DISPATCH) {
00378               return FAILURE;
00379        }
00380        
00381        nargs = ZEND_NUM_ARGS();
00382 
00383        if (nargs) {
00384               args = (zval ***)safe_emalloc(sizeof(zval *), nargs, 0);
00385               zend_get_parameters_array_ex(nargs, args);
00386        }
00387 
00388        VariantInit(&v);
00389 
00390        if (SUCCESS == php_com_do_invoke_byref(obj, method, -1, DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, nargs, args TSRMLS_CC)) {
00391               php_com_zval_from_variant(return_value, &v, obj->code_page TSRMLS_CC);
00392               ret = SUCCESS;
00393               VariantClear(&v);
00394        }
00395 
00396        if (args) {
00397               efree(args);
00398        }
00399 
00400        return ret;
00401 }
00402 
00403 static union _zend_function *com_constructor_get(zval *object TSRMLS_DC)
00404 {
00405        php_com_dotnet_object *obj;
00406        static zend_internal_function c, d, v;
00407 
00408        obj = CDNO_FETCH(object);
00409 
00410 #define POPULATE_CTOR(f, fn)       \
00411        f.type = ZEND_INTERNAL_FUNCTION; \
00412        f.function_name = obj->ce->name; \
00413        f.scope = obj->ce; \
00414        f.arg_info = NULL; \
00415        f.num_args = 0; \
00416        f.fn_flags = 0; \
00417        f.handler = ZEND_FN(fn); \
00418        return (union _zend_function*)&f;
00419        
00420        switch (obj->ce->name[0]) {
00421 #if HAVE_MSCOREE_H
00422               case 'd':
00423                      POPULATE_CTOR(d, com_dotnet_create_instance);
00424 #endif
00425               
00426               case 'c':
00427                      POPULATE_CTOR(c, com_create_instance);
00428               
00429               case 'v':
00430                      POPULATE_CTOR(v, com_variant_create_instance);
00431                      
00432               default:
00433                      return NULL;
00434        }
00435 }
00436 
00437 static zend_class_entry *com_class_entry_get(const zval *object TSRMLS_DC)
00438 {
00439        php_com_dotnet_object *obj;
00440        obj = CDNO_FETCH(object);
00441 
00442        return obj->ce;
00443 }
00444 
00445 static int com_class_name_get(const zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
00446 {
00447        php_com_dotnet_object *obj;
00448        obj = CDNO_FETCH(object);
00449 
00450        *class_name = estrndup(obj->ce->name, obj->ce->name_length);
00451        *class_name_len = obj->ce->name_length;
00452 
00453        return 0;
00454 }
00455 
00456 /* This compares two variants for equality */
00457 static int com_objects_compare(zval *object1, zval *object2 TSRMLS_DC)
00458 {
00459        php_com_dotnet_object *obja, *objb;
00460        int ret;
00461        /* strange header bug problem here... the headers define the proto without the
00462         * flags parameter.  However, the MSDN docs state that there is a flags parameter,
00463         * and my VC6 won't link unless the code uses the version with 4 parameters.
00464         * So, we have this declaration here to fix it */
00465        STDAPI VarCmp(LPVARIANT pvarLeft, LPVARIANT pvarRight, LCID lcid, DWORD flags);
00466 
00467        obja = CDNO_FETCH(object1);
00468        objb = CDNO_FETCH(object2);
00469 
00470        switch (VarCmp(&obja->v, &objb->v, LOCALE_SYSTEM_DEFAULT, 0)) {
00471               case VARCMP_LT:
00472                      ret = -1;
00473                      break;
00474               case VARCMP_GT:
00475                      ret = 1;
00476                      break;
00477               case VARCMP_EQ:
00478                      ret = 0;
00479                      break;
00480               default:
00481                      /* either or both operands are NULL...
00482                       * not 100% sure how to handle this */
00483                      ret = -2;
00484        }
00485 
00486        return ret;
00487 }
00488 
00489 static int com_object_cast(zval *readobj, zval *writeobj, int type TSRMLS_DC)
00490 {
00491        php_com_dotnet_object *obj;
00492        VARIANT v;
00493        VARTYPE vt = VT_EMPTY;
00494        HRESULT res = S_OK;
00495 
00496        obj = CDNO_FETCH(readobj);
00497        ZVAL_NULL(writeobj);
00498        VariantInit(&v);
00499 
00500        if (V_VT(&obj->v) == VT_DISPATCH) {
00501               if (SUCCESS != php_com_do_invoke_by_id(obj, DISPID_VALUE,
00502                             DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, 0, NULL, 1, 0 TSRMLS_CC)) {
00503                      VariantCopy(&v, &obj->v);
00504               }
00505        } else {
00506               VariantCopy(&v, &obj->v);
00507        }
00508 
00509        switch(type) {
00510               case IS_LONG:
00511                      vt = VT_INT;
00512                      break;
00513               case IS_DOUBLE:
00514                      vt = VT_R8;
00515                      break;
00516               case IS_BOOL:
00517                      vt = VT_BOOL;
00518                      break;
00519               case IS_STRING:
00520                      vt = VT_BSTR;
00521                      break;
00522               default:
00523                      ;
00524        }
00525 
00526        if (vt != VT_EMPTY && vt != V_VT(&v)) {
00527               res = VariantChangeType(&v, &v, 0, vt);
00528        }
00529 
00530        if (SUCCEEDED(res)) {
00531               php_com_zval_from_variant(writeobj, &v, obj->code_page TSRMLS_CC);
00532        }
00533 
00534        VariantClear(&v);
00535 
00536        if (SUCCEEDED(res)) {
00537               return SUCCESS;
00538        }
00539 
00540        return zend_std_cast_object_tostring(readobj, writeobj, type TSRMLS_CC);
00541 }
00542 
00543 static int com_object_count(zval *object, long *count TSRMLS_DC)
00544 {
00545        php_com_dotnet_object *obj;
00546        LONG ubound = 0, lbound = 0;
00547        
00548        obj = CDNO_FETCH(object);
00549        
00550        if (!V_ISARRAY(&obj->v)) {
00551               return FAILURE;
00552        }
00553 
00554        SafeArrayGetLBound(V_ARRAY(&obj->v), 1, &lbound);
00555        SafeArrayGetUBound(V_ARRAY(&obj->v), 1, &ubound);
00556 
00557        *count = ubound - lbound + 1;
00558 
00559        return SUCCESS;
00560 }
00561 
00562 zend_object_handlers php_com_object_handlers = {
00563        ZEND_OBJECTS_STORE_HANDLERS,
00564        com_property_read,
00565        com_property_write,
00566        com_read_dimension,
00567        com_write_dimension,
00568        NULL,
00569        NULL, /* com_object_get, */
00570        NULL, /* com_object_set, */
00571        com_property_exists,
00572        com_property_delete,
00573        com_dimension_exists,
00574        com_dimension_delete,
00575        com_properties_get,
00576        com_method_get,
00577        com_call_method,
00578        com_constructor_get,
00579        com_class_entry_get,
00580        com_class_name_get,
00581        com_objects_compare,
00582        com_object_cast,
00583        com_object_count
00584 };
00585 
00586 void php_com_object_enable_event_sink(php_com_dotnet_object *obj, int enable TSRMLS_DC)
00587 {
00588        if (obj->sink_dispatch) {
00589               IConnectionPointContainer *cont;
00590               IConnectionPoint *point;
00591               
00592               if (SUCCEEDED(IDispatch_QueryInterface(V_DISPATCH(&obj->v),
00593                             &IID_IConnectionPointContainer, (void**)&cont))) {
00594                      
00595                      if (SUCCEEDED(IConnectionPointContainer_FindConnectionPoint(cont,
00596                                    &obj->sink_id, &point))) {
00597 
00598                             if (enable) {
00599                                    IConnectionPoint_Advise(point, (IUnknown*)obj->sink_dispatch, &obj->sink_cookie);
00600                             } else {
00601                                    IConnectionPoint_Unadvise(point, obj->sink_cookie);
00602                             }
00603                             IConnectionPoint_Release(point);
00604                      }
00605                      IConnectionPointContainer_Release(cont);
00606               }
00607        }
00608 }
00609 
00610 void php_com_object_free_storage(void *object TSRMLS_DC)
00611 {
00612        php_com_dotnet_object *obj = (php_com_dotnet_object*)object;
00613 
00614        if (obj->typeinfo) {
00615               ITypeInfo_Release(obj->typeinfo);
00616               obj->typeinfo = NULL;
00617        }
00618 
00619        if (obj->sink_dispatch) {
00620               php_com_object_enable_event_sink(obj, FALSE TSRMLS_CC);
00621               IDispatch_Release(obj->sink_dispatch);
00622               obj->sink_dispatch = NULL;
00623        }
00624 
00625        VariantClear(&obj->v);
00626 
00627        if (obj->method_cache) {
00628               zend_hash_destroy(obj->method_cache);
00629               FREE_HASHTABLE(obj->method_cache);
00630        }
00631        if (obj->id_of_name_cache) {
00632               zend_hash_destroy(obj->id_of_name_cache);
00633               FREE_HASHTABLE(obj->id_of_name_cache);
00634        }
00635        efree(obj);
00636 }
00637 
00638 void php_com_object_clone(void *object, void **clone_ptr TSRMLS_DC)
00639 {
00640        php_com_dotnet_object *cloneobj, *origobject;
00641 
00642        origobject = (php_com_dotnet_object*)object;
00643        cloneobj = (php_com_dotnet_object*)emalloc(sizeof(php_com_dotnet_object));
00644        
00645        memcpy(cloneobj, origobject, sizeof(*cloneobj));
00646 
00647        /* VariantCopy will perform VariantClear; we don't want to clobber
00648         * the IDispatch that we memcpy'd, so we init a new variant in the
00649         * clone structure */
00650        VariantInit(&cloneobj->v);
00651        /* We use the Indirection-following version of the API since we
00652         * want to clone as much as possible */
00653        VariantCopyInd(&cloneobj->v, &origobject->v); 
00654 
00655        if (cloneobj->typeinfo) {
00656               ITypeInfo_AddRef(cloneobj->typeinfo);
00657        }
00658 
00659        *clone_ptr = cloneobj;
00660 }
00661 
00662 zend_object_value php_com_object_new(zend_class_entry *ce TSRMLS_DC)
00663 {
00664        php_com_dotnet_object *obj;
00665        zend_object_value retval;
00666 
00667        php_com_initialize(TSRMLS_C);
00668        obj = emalloc(sizeof(*obj));
00669        memset(obj, 0, sizeof(*obj));
00670 
00671        VariantInit(&obj->v);
00672        obj->code_page = CP_ACP;
00673        obj->ce = ce;
00674        obj->zo.ce = ce;
00675 
00676        retval.handle = zend_objects_store_put(obj, NULL, php_com_object_free_storage, php_com_object_clone TSRMLS_CC);
00677        retval.handlers = &php_com_object_handlers;
00678 
00679        return retval;
00680 }