1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2014 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Wez Furlong <wez@thebrainroom.com> |
16 +----------------------------------------------------------------------+
17 */
18
19 /* $Id$ */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "php.h"
26 #include "php_ini.h"
27 #include "ext/standard/info.h"
28 #include "php_com_dotnet.h"
29 #include "php_com_dotnet_internal.h"
30 #include "Zend/zend_exceptions.h"
31
com_property_read(zval * object,zval * member,int type,const zend_literal * key TSRMLS_DC)32 static zval *com_property_read(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
33 {
34 zval *return_value;
35 php_com_dotnet_object *obj;
36 VARIANT v;
37 HRESULT res;
38
39 MAKE_STD_ZVAL(return_value);
40 ZVAL_NULL(return_value);
41 Z_SET_REFCOUNT_P(return_value, 0);
42 Z_UNSET_ISREF_P(return_value);
43
44 obj = CDNO_FETCH(object);
45
46 if (V_VT(&obj->v) == VT_DISPATCH) {
47 VariantInit(&v);
48
49 convert_to_string_ex(&member);
50
51 res = php_com_do_invoke(obj, Z_STRVAL_P(member), Z_STRLEN_P(member),
52 DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, 0, NULL, 1 TSRMLS_CC);
53
54 if (res == SUCCESS) {
55 php_com_zval_from_variant(return_value, &v, obj->code_page TSRMLS_CC);
56 VariantClear(&v);
57 } else if (res == DISP_E_BADPARAMCOUNT) {
58 php_com_saproxy_create(object, return_value, member TSRMLS_CC);
59 }
60 } else {
61 php_com_throw_exception(E_INVALIDARG, "this variant has no properties" TSRMLS_CC);
62 }
63
64 return return_value;
65 }
66
com_property_write(zval * object,zval * member,zval * value,const zend_literal * key TSRMLS_DC)67 static void com_property_write(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
68 {
69 php_com_dotnet_object *obj;
70 VARIANT v;
71
72 obj = CDNO_FETCH(object);
73
74 if (V_VT(&obj->v) == VT_DISPATCH) {
75 VariantInit(&v);
76
77 convert_to_string_ex(&member);
78 if (SUCCESS == php_com_do_invoke(obj, Z_STRVAL_P(member), Z_STRLEN_P(member),
79 DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF, &v, 1, &value, 0 TSRMLS_CC)) {
80 VariantClear(&v);
81 }
82 } else {
83 php_com_throw_exception(E_INVALIDARG, "this variant has no properties" TSRMLS_CC);
84 }
85 }
86
com_read_dimension(zval * object,zval * offset,int type TSRMLS_DC)87 static zval *com_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
88 {
89 zval *return_value;
90 php_com_dotnet_object *obj;
91 VARIANT v;
92
93 MAKE_STD_ZVAL(return_value);
94 ZVAL_NULL(return_value);
95 Z_SET_REFCOUNT_P(return_value, 0);
96 Z_UNSET_ISREF_P(return_value);
97
98 obj = CDNO_FETCH(object);
99
100 if (V_VT(&obj->v) == VT_DISPATCH) {
101 VariantInit(&v);
102
103 if (SUCCESS == php_com_do_invoke_by_id(obj, DISPID_VALUE,
104 DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, 1, &offset, 0, 0 TSRMLS_CC)) {
105 php_com_zval_from_variant(return_value, &v, obj->code_page TSRMLS_CC);
106 VariantClear(&v);
107 }
108 } else if (V_ISARRAY(&obj->v)) {
109 convert_to_long(offset);
110
111 if (SafeArrayGetDim(V_ARRAY(&obj->v)) == 1) {
112 if (php_com_safearray_get_elem(&obj->v, &v, Z_LVAL_P(offset) TSRMLS_CC)) {
113 php_com_wrap_variant(return_value, &v, obj->code_page TSRMLS_CC);
114 VariantClear(&v);
115 }
116 } else {
117 php_com_saproxy_create(object, return_value, offset TSRMLS_CC);
118 }
119
120 } else {
121 php_com_throw_exception(E_INVALIDARG, "this variant is not an array type" TSRMLS_CC);
122 }
123
124 return return_value;
125 }
126
com_write_dimension(zval * object,zval * offset,zval * value TSRMLS_DC)127 static void com_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC)
128 {
129 php_com_dotnet_object *obj;
130 zval *args[2];
131 VARIANT v;
132 HRESULT res;
133
134 obj = CDNO_FETCH(object);
135
136 if (V_VT(&obj->v) == VT_DISPATCH) {
137 args[0] = offset;
138 args[1] = value;
139
140 VariantInit(&v);
141
142 if (SUCCESS == php_com_do_invoke_by_id(obj, DISPID_VALUE,
143 DISPATCH_METHOD|DISPATCH_PROPERTYPUT, &v, 2, args, 0, 0 TSRMLS_CC)) {
144 VariantClear(&v);
145 }
146 } else if (V_ISARRAY(&obj->v)) {
147 LONG indices = 0;
148 VARTYPE vt;
149
150 if (SafeArrayGetDim(V_ARRAY(&obj->v)) == 1) {
151 if (FAILED(SafeArrayGetVartype(V_ARRAY(&obj->v), &vt)) || vt == VT_EMPTY) {
152 vt = V_VT(&obj->v) & ~VT_ARRAY;
153 }
154
155 convert_to_long(offset);
156 indices = Z_LVAL_P(offset);
157
158 VariantInit(&v);
159 php_com_variant_from_zval(&v, value, obj->code_page TSRMLS_CC);
160
161 if (V_VT(&v) != vt) {
162 VariantChangeType(&v, &v, 0, vt);
163 }
164
165 if (vt == VT_VARIANT) {
166 res = SafeArrayPutElement(V_ARRAY(&obj->v), &indices, &v);
167 } else {
168 res = SafeArrayPutElement(V_ARRAY(&obj->v), &indices, &v.lVal);
169 }
170
171 VariantClear(&v);
172
173 if (FAILED(res)) {
174 php_com_throw_exception(res, NULL TSRMLS_CC);
175 }
176
177 } else {
178 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);
179 }
180
181 } else {
182 php_com_throw_exception(E_INVALIDARG, "this variant is not an array type" TSRMLS_CC);
183 }
184 }
185
186 #if 0
187 static void com_object_set(zval **property, zval *value TSRMLS_DC)
188 {
189 /* Not yet implemented in the engine */
190 }
191
192 static zval *com_object_get(zval *property TSRMLS_DC)
193 {
194 /* Not yet implemented in the engine */
195 return NULL;
196 }
197 #endif
198
com_property_exists(zval * object,zval * member,int check_empty,const zend_literal * key TSRMLS_DC)199 static int com_property_exists(zval *object, zval *member, int check_empty, const zend_literal *key TSRMLS_DC)
200 {
201 DISPID dispid;
202 php_com_dotnet_object *obj;
203
204 obj = CDNO_FETCH(object);
205
206 if (V_VT(&obj->v) == VT_DISPATCH) {
207 convert_to_string_ex(&member);
208 if (SUCCEEDED(php_com_get_id_of_name(obj, Z_STRVAL_P(member), Z_STRLEN_P(member), &dispid TSRMLS_CC))) {
209 /* TODO: distinguish between property and method! */
210 return 1;
211 }
212 } else {
213 /* TODO: check for safearray */
214 }
215
216 return 0;
217 }
218
com_dimension_exists(zval * object,zval * member,int check_empty TSRMLS_DC)219 static int com_dimension_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
220 {
221 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Operation not yet supported on a COM object");
222 return 0;
223 }
224
com_property_delete(zval * object,zval * member,const zend_literal * key TSRMLS_DC)225 static void com_property_delete(zval *object, zval *member, const zend_literal *key TSRMLS_DC)
226 {
227 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a COM object");
228 }
229
com_dimension_delete(zval * object,zval * offset TSRMLS_DC)230 static void com_dimension_delete(zval *object, zval *offset TSRMLS_DC)
231 {
232 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a COM object");
233 }
234
com_properties_get(zval * object TSRMLS_DC)235 static HashTable *com_properties_get(zval *object TSRMLS_DC)
236 {
237 /* TODO: use type-info to get all the names and values ?
238 * DANGER: if we do that, there is a strong possibility for
239 * infinite recursion when the hash is displayed via var_dump().
240 * Perhaps it is best to leave it un-implemented.
241 */
242 return NULL;
243 }
244
function_dtor(void * pDest)245 static void function_dtor(void *pDest)
246 {
247 zend_internal_function *f = (zend_internal_function*)pDest;
248
249 efree((char*)f->function_name);
250 if (f->arg_info) {
251 efree(f->arg_info);
252 }
253 }
254
PHP_FUNCTION(com_method_handler)255 static PHP_FUNCTION(com_method_handler)
256 {
257 Z_OBJ_HANDLER_P(getThis(), call_method)(
258 ((zend_internal_function*)EG(current_execute_data)->function_state.function)->function_name,
259 INTERNAL_FUNCTION_PARAM_PASSTHRU);
260 }
261
com_method_get(zval ** object_ptr,char * name,int len,const zend_literal * key TSRMLS_DC)262 static union _zend_function *com_method_get(zval **object_ptr, char *name, int len, const zend_literal *key TSRMLS_DC)
263 {
264 zend_internal_function f, *fptr = NULL;
265 php_com_dotnet_object *obj;
266 union _zend_function *func;
267 DISPID dummy;
268 zval *object = *object_ptr;
269
270 obj = CDNO_FETCH(object);
271
272 if (V_VT(&obj->v) != VT_DISPATCH) {
273 return NULL;
274 }
275
276 if (FAILED(php_com_get_id_of_name(obj, name, len, &dummy TSRMLS_CC))) {
277 return NULL;
278 }
279
280 /* check cache */
281 if (obj->method_cache == NULL || FAILURE == zend_hash_find(obj->method_cache, name, len, (void**)&fptr)) {
282 f.type = ZEND_OVERLOADED_FUNCTION;
283 f.num_args = 0;
284 f.arg_info = NULL;
285 f.scope = obj->ce;
286 f.fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
287 f.function_name = estrndup(name, len);
288 f.handler = PHP_FN(com_method_handler);
289
290 fptr = &f;
291
292 if (obj->typeinfo) {
293 /* look for byref params */
294 ITypeComp *comp;
295 ITypeInfo *TI = NULL;
296 DESCKIND kind;
297 BINDPTR bindptr;
298 OLECHAR *olename;
299 ULONG lhash;
300 int i;
301
302 if (SUCCEEDED(ITypeInfo_GetTypeComp(obj->typeinfo, &comp))) {
303 olename = php_com_string_to_olestring(name, len, obj->code_page TSRMLS_CC);
304 lhash = LHashValOfNameSys(SYS_WIN32, LOCALE_SYSTEM_DEFAULT, olename);
305
306 if (SUCCEEDED(ITypeComp_Bind(comp, olename, lhash, INVOKE_FUNC, &TI, &kind, &bindptr))) {
307 switch (kind) {
308 case DESCKIND_FUNCDESC:
309 f.arg_info = ecalloc(bindptr.lpfuncdesc->cParams, sizeof(zend_arg_info));
310
311 for (i = 0; i < bindptr.lpfuncdesc->cParams; i++) {
312 f.arg_info[i].allow_null = 1;
313 if (bindptr.lpfuncdesc->lprgelemdescParam[i].paramdesc.wParamFlags & PARAMFLAG_FOUT) {
314 f.arg_info[i].pass_by_reference = 1;
315 }
316 }
317
318 f.num_args = bindptr.lpfuncdesc->cParams;
319
320 ITypeInfo_ReleaseFuncDesc(TI, bindptr.lpfuncdesc);
321 break;
322
323 /* these should not happen, but *might* happen if the user
324 * screws up; lets avoid a leak in that case */
325 case DESCKIND_VARDESC:
326 ITypeInfo_ReleaseVarDesc(TI, bindptr.lpvardesc);
327 break;
328 case DESCKIND_TYPECOMP:
329 ITypeComp_Release(bindptr.lptcomp);
330 break;
331
332 case DESCKIND_NONE:
333 break;
334 }
335 if (TI) {
336 ITypeInfo_Release(TI);
337 }
338 }
339 ITypeComp_Release(comp);
340 efree(olename);
341 }
342 }
343
344 if (fptr) {
345 /* save this method in the cache */
346 if (!obj->method_cache) {
347 ALLOC_HASHTABLE(obj->method_cache);
348 zend_hash_init(obj->method_cache, 2, NULL, function_dtor, 0);
349 }
350
351 zend_hash_update(obj->method_cache, name, len, &f, sizeof(f), (void**)&fptr);
352 }
353 }
354
355 if (fptr) {
356 /* duplicate this into a new chunk of emalloc'd memory,
357 * since the engine will efree it */
358 func = emalloc(sizeof(*fptr));
359 memcpy(func, fptr, sizeof(*fptr));
360
361 return func;
362 }
363
364 return NULL;
365 }
366
com_call_method(const char * method,INTERNAL_FUNCTION_PARAMETERS)367 static int com_call_method(const char *method, INTERNAL_FUNCTION_PARAMETERS)
368 {
369 zval ***args = NULL;
370 php_com_dotnet_object *obj;
371 int nargs;
372 VARIANT v;
373 int ret = FAILURE;
374
375 obj = CDNO_FETCH(getThis());
376
377 if (V_VT(&obj->v) != VT_DISPATCH) {
378 return FAILURE;
379 }
380
381 nargs = ZEND_NUM_ARGS();
382
383 if (nargs) {
384 args = (zval ***)safe_emalloc(sizeof(zval *), nargs, 0);
385 zend_get_parameters_array_ex(nargs, args);
386 }
387
388 VariantInit(&v);
389
390 if (SUCCESS == php_com_do_invoke_byref(obj, (char*)method, -1, DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, nargs, args TSRMLS_CC)) {
391 php_com_zval_from_variant(return_value, &v, obj->code_page TSRMLS_CC);
392 ret = SUCCESS;
393 VariantClear(&v);
394 }
395
396 if (args) {
397 efree(args);
398 }
399
400 return ret;
401 }
402
com_constructor_get(zval * object TSRMLS_DC)403 static union _zend_function *com_constructor_get(zval *object TSRMLS_DC)
404 {
405 php_com_dotnet_object *obj;
406 static zend_internal_function c, d, v;
407
408 obj = CDNO_FETCH(object);
409
410 #define POPULATE_CTOR(f, fn) \
411 f.type = ZEND_INTERNAL_FUNCTION; \
412 f.function_name = (char *) obj->ce->name; \
413 f.scope = obj->ce; \
414 f.arg_info = NULL; \
415 f.num_args = 0; \
416 f.fn_flags = 0; \
417 f.handler = ZEND_FN(fn); \
418 return (union _zend_function*)&f;
419
420 switch (obj->ce->name[0]) {
421 #if HAVE_MSCOREE_H
422 case 'd':
423 POPULATE_CTOR(d, com_dotnet_create_instance);
424 #endif
425
426 case 'c':
427 POPULATE_CTOR(c, com_create_instance);
428
429 case 'v':
430 POPULATE_CTOR(v, com_variant_create_instance);
431
432 default:
433 return NULL;
434 }
435 }
436
com_class_entry_get(const zval * object TSRMLS_DC)437 static zend_class_entry *com_class_entry_get(const zval *object TSRMLS_DC)
438 {
439 php_com_dotnet_object *obj;
440 obj = CDNO_FETCH(object);
441
442 return obj->ce;
443 }
444
com_class_name_get(const zval * object,const char ** class_name,zend_uint * class_name_len,int parent TSRMLS_DC)445 static int com_class_name_get(const zval *object, const char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
446 {
447 php_com_dotnet_object *obj;
448 obj = CDNO_FETCH(object);
449
450 *class_name = estrndup(obj->ce->name, obj->ce->name_length);
451 *class_name_len = obj->ce->name_length;
452
453 return 0;
454 }
455
456 /* This compares two variants for equality */
com_objects_compare(zval * object1,zval * object2 TSRMLS_DC)457 static int com_objects_compare(zval *object1, zval *object2 TSRMLS_DC)
458 {
459 php_com_dotnet_object *obja, *objb;
460 int ret;
461 /* strange header bug problem here... the headers define the proto without the
462 * flags parameter. However, the MSDN docs state that there is a flags parameter,
463 * and my VC6 won't link unless the code uses the version with 4 parameters.
464 * So, we have this declaration here to fix it */
465 STDAPI VarCmp(LPVARIANT pvarLeft, LPVARIANT pvarRight, LCID lcid, DWORD flags);
466
467 obja = CDNO_FETCH(object1);
468 objb = CDNO_FETCH(object2);
469
470 switch (VarCmp(&obja->v, &objb->v, LOCALE_SYSTEM_DEFAULT, 0)) {
471 case VARCMP_LT:
472 ret = -1;
473 break;
474 case VARCMP_GT:
475 ret = 1;
476 break;
477 case VARCMP_EQ:
478 ret = 0;
479 break;
480 default:
481 /* either or both operands are NULL...
482 * not 100% sure how to handle this */
483 ret = -2;
484 }
485
486 return ret;
487 }
488
com_object_cast(zval * readobj,zval * writeobj,int type TSRMLS_DC)489 static int com_object_cast(zval *readobj, zval *writeobj, int type TSRMLS_DC)
490 {
491 php_com_dotnet_object *obj;
492 VARIANT v;
493 VARTYPE vt = VT_EMPTY;
494 HRESULT res = S_OK;
495
496 obj = CDNO_FETCH(readobj);
497 ZVAL_NULL(writeobj);
498 VariantInit(&v);
499
500 if (V_VT(&obj->v) == VT_DISPATCH) {
501 if (SUCCESS != php_com_do_invoke_by_id(obj, DISPID_VALUE,
502 DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, 0, NULL, 1, 0 TSRMLS_CC)) {
503 VariantCopy(&v, &obj->v);
504 }
505 } else {
506 VariantCopy(&v, &obj->v);
507 }
508
509 switch(type) {
510 case IS_LONG:
511 vt = VT_INT;
512 break;
513 case IS_DOUBLE:
514 vt = VT_R8;
515 break;
516 case IS_BOOL:
517 vt = VT_BOOL;
518 break;
519 case IS_STRING:
520 vt = VT_BSTR;
521 break;
522 default:
523 ;
524 }
525
526 if (vt != VT_EMPTY && vt != V_VT(&v)) {
527 res = VariantChangeType(&v, &v, 0, vt);
528 }
529
530 if (SUCCEEDED(res)) {
531 php_com_zval_from_variant(writeobj, &v, obj->code_page TSRMLS_CC);
532 }
533
534 VariantClear(&v);
535
536 if (SUCCEEDED(res)) {
537 return SUCCESS;
538 }
539
540 return zend_std_cast_object_tostring(readobj, writeobj, type TSRMLS_CC);
541 }
542
com_object_count(zval * object,long * count TSRMLS_DC)543 static int com_object_count(zval *object, long *count TSRMLS_DC)
544 {
545 php_com_dotnet_object *obj;
546 LONG ubound = 0, lbound = 0;
547
548 obj = CDNO_FETCH(object);
549
550 if (!V_ISARRAY(&obj->v)) {
551 return FAILURE;
552 }
553
554 SafeArrayGetLBound(V_ARRAY(&obj->v), 1, &lbound);
555 SafeArrayGetUBound(V_ARRAY(&obj->v), 1, &ubound);
556
557 *count = ubound - lbound + 1;
558
559 return SUCCESS;
560 }
561
562 zend_object_handlers php_com_object_handlers = {
563 ZEND_OBJECTS_STORE_HANDLERS,
564 com_property_read,
565 com_property_write,
566 com_read_dimension,
567 com_write_dimension,
568 NULL,
569 NULL, /* com_object_get, */
570 NULL, /* com_object_set, */
571 com_property_exists,
572 com_property_delete,
573 com_dimension_exists,
574 com_dimension_delete,
575 com_properties_get,
576 com_method_get,
577 com_call_method,
578 com_constructor_get,
579 com_class_entry_get,
580 com_class_name_get,
581 com_objects_compare,
582 com_object_cast,
583 com_object_count,
584 NULL, /* get_debug_info */
585 NULL, /* get_closure */
586 NULL, /* get_gc */
587 };
588
php_com_object_enable_event_sink(php_com_dotnet_object * obj,int enable TSRMLS_DC)589 void php_com_object_enable_event_sink(php_com_dotnet_object *obj, int enable TSRMLS_DC)
590 {
591 if (obj->sink_dispatch) {
592 IConnectionPointContainer *cont;
593 IConnectionPoint *point;
594
595 if (SUCCEEDED(IDispatch_QueryInterface(V_DISPATCH(&obj->v),
596 &IID_IConnectionPointContainer, (void**)&cont))) {
597
598 if (SUCCEEDED(IConnectionPointContainer_FindConnectionPoint(cont,
599 &obj->sink_id, &point))) {
600
601 if (enable) {
602 IConnectionPoint_Advise(point, (IUnknown*)obj->sink_dispatch, &obj->sink_cookie);
603 } else {
604 IConnectionPoint_Unadvise(point, obj->sink_cookie);
605 }
606 IConnectionPoint_Release(point);
607 }
608 IConnectionPointContainer_Release(cont);
609 }
610 }
611 }
612
php_com_object_free_storage(void * object TSRMLS_DC)613 void php_com_object_free_storage(void *object TSRMLS_DC)
614 {
615 php_com_dotnet_object *obj = (php_com_dotnet_object*)object;
616
617 if (obj->typeinfo) {
618 ITypeInfo_Release(obj->typeinfo);
619 obj->typeinfo = NULL;
620 }
621
622 if (obj->sink_dispatch) {
623 php_com_object_enable_event_sink(obj, FALSE TSRMLS_CC);
624 IDispatch_Release(obj->sink_dispatch);
625 obj->sink_dispatch = NULL;
626 }
627
628 VariantClear(&obj->v);
629
630 if (obj->method_cache) {
631 zend_hash_destroy(obj->method_cache);
632 FREE_HASHTABLE(obj->method_cache);
633 }
634 if (obj->id_of_name_cache) {
635 zend_hash_destroy(obj->id_of_name_cache);
636 FREE_HASHTABLE(obj->id_of_name_cache);
637 }
638 efree(obj);
639 }
640
php_com_object_clone(void * object,void ** clone_ptr TSRMLS_DC)641 void php_com_object_clone(void *object, void **clone_ptr TSRMLS_DC)
642 {
643 php_com_dotnet_object *cloneobj, *origobject;
644
645 origobject = (php_com_dotnet_object*)object;
646 cloneobj = (php_com_dotnet_object*)emalloc(sizeof(php_com_dotnet_object));
647
648 memcpy(cloneobj, origobject, sizeof(*cloneobj));
649
650 /* VariantCopy will perform VariantClear; we don't want to clobber
651 * the IDispatch that we memcpy'd, so we init a new variant in the
652 * clone structure */
653 VariantInit(&cloneobj->v);
654 /* We use the Indirection-following version of the API since we
655 * want to clone as much as possible */
656 VariantCopyInd(&cloneobj->v, &origobject->v);
657
658 if (cloneobj->typeinfo) {
659 ITypeInfo_AddRef(cloneobj->typeinfo);
660 }
661
662 *clone_ptr = cloneobj;
663 }
664
php_com_object_new(zend_class_entry * ce TSRMLS_DC)665 zend_object_value php_com_object_new(zend_class_entry *ce TSRMLS_DC)
666 {
667 php_com_dotnet_object *obj;
668 zend_object_value retval;
669
670 php_com_initialize(TSRMLS_C);
671 obj = emalloc(sizeof(*obj));
672 memset(obj, 0, sizeof(*obj));
673
674 VariantInit(&obj->v);
675 obj->code_page = CP_ACP;
676 obj->ce = ce;
677 obj->zo.ce = ce;
678
679 retval.handle = zend_objects_store_put(obj, NULL, php_com_object_free_storage, php_com_object_clone TSRMLS_CC);
680 retval.handlers = &php_com_object_handlers;
681
682 return retval;
683 }
684