com_handlers.c 17 KB

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