com_wrapper.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  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. /* This module exports a PHP object as a COM object by wrapping it
  20. * using IDispatchEx */
  21. #ifdef HAVE_CONFIG_H
  22. #include "config.h"
  23. #endif
  24. #include "php.h"
  25. #include "php_ini.h"
  26. #include "ext/standard/info.h"
  27. #include "php_com_dotnet.h"
  28. #include "php_com_dotnet_internal.h"
  29. typedef struct {
  30. /* This first part MUST match the declaration
  31. * of interface IDispatchEx */
  32. CONST_VTBL struct IDispatchExVtbl *lpVtbl;
  33. /* now the PHP stuff */
  34. DWORD engine_thread; /* for sanity checking */
  35. zval *object; /* the object exported */
  36. LONG refcount; /* COM reference count */
  37. HashTable *dispid_to_name; /* keep track of dispid -> name mappings */
  38. HashTable *name_to_dispid; /* keep track of name -> dispid mappings */
  39. GUID sinkid; /* iid that we "implement" for event sinking */
  40. int id;
  41. } php_dispatchex;
  42. static int le_dispatch;
  43. static void disp_destructor(php_dispatchex *disp TSRMLS_DC);
  44. static void dispatch_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
  45. {
  46. php_dispatchex *disp = (php_dispatchex *)rsrc->ptr;
  47. disp_destructor(disp TSRMLS_CC);
  48. }
  49. int php_com_wrapper_minit(INIT_FUNC_ARGS)
  50. {
  51. le_dispatch = zend_register_list_destructors_ex(dispatch_dtor,
  52. NULL, "com_dotnet_dispatch_wrapper", module_number);
  53. return le_dispatch;
  54. }
  55. /* {{{ trace */
  56. static inline void trace(char *fmt, ...)
  57. {
  58. va_list ap;
  59. char buf[4096];
  60. snprintf(buf, sizeof(buf), "T=%08x ", GetCurrentThreadId());
  61. OutputDebugString(buf);
  62. va_start(ap, fmt);
  63. vsnprintf(buf, sizeof(buf), fmt, ap);
  64. OutputDebugString(buf);
  65. va_end(ap);
  66. }
  67. /* }}} */
  68. #define FETCH_DISP(methname) \
  69. php_dispatchex *disp = (php_dispatchex*)This; \
  70. TSRMLS_FETCH(); \
  71. if (COMG(rshutdown_started)) { \
  72. trace(" PHP Object:%p (name:unknown) %s\n", disp->object, methname); \
  73. } else { \
  74. trace(" PHP Object:%p (name:%s) %s\n", disp->object, Z_OBJCE_P(disp->object)->name, methname); \
  75. } \
  76. if (GetCurrentThreadId() != disp->engine_thread) { \
  77. return RPC_E_WRONG_THREAD; \
  78. }
  79. static HRESULT STDMETHODCALLTYPE disp_queryinterface(
  80. IDispatchEx *This,
  81. /* [in] */ REFIID riid,
  82. /* [iid_is][out] */ void **ppvObject)
  83. {
  84. FETCH_DISP("QueryInterface");
  85. if (IsEqualGUID(&IID_IUnknown, riid) ||
  86. IsEqualGUID(&IID_IDispatch, riid) ||
  87. IsEqualGUID(&IID_IDispatchEx, riid) ||
  88. IsEqualGUID(&disp->sinkid, riid)) {
  89. *ppvObject = This;
  90. InterlockedIncrement(&disp->refcount);
  91. return S_OK;
  92. }
  93. *ppvObject = NULL;
  94. return E_NOINTERFACE;
  95. }
  96. static ULONG STDMETHODCALLTYPE disp_addref(IDispatchEx *This)
  97. {
  98. FETCH_DISP("AddRef");
  99. return InterlockedIncrement(&disp->refcount);
  100. }
  101. static ULONG STDMETHODCALLTYPE disp_release(IDispatchEx *This)
  102. {
  103. ULONG ret;
  104. FETCH_DISP("Release");
  105. ret = InterlockedDecrement(&disp->refcount);
  106. trace("-- refcount now %d\n", ret);
  107. if (ret == 0) {
  108. /* destroy it */
  109. if (disp->id)
  110. zend_list_delete(disp->id);
  111. }
  112. return ret;
  113. }
  114. static HRESULT STDMETHODCALLTYPE disp_gettypeinfocount(
  115. IDispatchEx *This,
  116. /* [out] */ UINT *pctinfo)
  117. {
  118. FETCH_DISP("GetTypeInfoCount");
  119. *pctinfo = 0;
  120. return S_OK;
  121. }
  122. static HRESULT STDMETHODCALLTYPE disp_gettypeinfo(
  123. IDispatchEx *This,
  124. /* [in] */ UINT iTInfo,
  125. /* [in] */ LCID lcid,
  126. /* [out] */ ITypeInfo **ppTInfo)
  127. {
  128. FETCH_DISP("GetTypeInfo");
  129. *ppTInfo = NULL;
  130. return DISP_E_BADINDEX;
  131. }
  132. static HRESULT STDMETHODCALLTYPE disp_getidsofnames(
  133. IDispatchEx *This,
  134. /* [in] */ REFIID riid,
  135. /* [size_is][in] */ LPOLESTR *rgszNames,
  136. /* [in] */ UINT cNames,
  137. /* [in] */ LCID lcid,
  138. /* [size_is][out] */ DISPID *rgDispId)
  139. {
  140. UINT i;
  141. HRESULT ret = S_OK;
  142. FETCH_DISP("GetIDsOfNames");
  143. for (i = 0; i < cNames; i++) {
  144. char *name;
  145. unsigned int namelen;
  146. zval **tmp;
  147. name = php_com_olestring_to_string(rgszNames[i], &namelen, COMG(code_page) TSRMLS_CC);
  148. /* Lookup the name in the hash */
  149. if (zend_hash_find(disp->name_to_dispid, name, namelen+1, (void**)&tmp) == FAILURE) {
  150. ret = DISP_E_UNKNOWNNAME;
  151. rgDispId[i] = 0;
  152. } else {
  153. rgDispId[i] = Z_LVAL_PP(tmp);
  154. }
  155. efree(name);
  156. }
  157. return ret;
  158. }
  159. static HRESULT STDMETHODCALLTYPE disp_invoke(
  160. IDispatchEx *This,
  161. /* [in] */ DISPID dispIdMember,
  162. /* [in] */ REFIID riid,
  163. /* [in] */ LCID lcid,
  164. /* [in] */ WORD wFlags,
  165. /* [out][in] */ DISPPARAMS *pDispParams,
  166. /* [out] */ VARIANT *pVarResult,
  167. /* [out] */ EXCEPINFO *pExcepInfo,
  168. /* [out] */ UINT *puArgErr)
  169. {
  170. return This->lpVtbl->InvokeEx(This, dispIdMember,
  171. lcid, wFlags, pDispParams,
  172. pVarResult, pExcepInfo, NULL);
  173. }
  174. static HRESULT STDMETHODCALLTYPE disp_getdispid(
  175. IDispatchEx *This,
  176. /* [in] */ BSTR bstrName,
  177. /* [in] */ DWORD grfdex,
  178. /* [out] */ DISPID *pid)
  179. {
  180. HRESULT ret = DISP_E_UNKNOWNNAME;
  181. char *name;
  182. unsigned int namelen;
  183. zval **tmp;
  184. FETCH_DISP("GetDispID");
  185. name = php_com_olestring_to_string(bstrName, &namelen, COMG(code_page) TSRMLS_CC);
  186. trace("Looking for %s, namelen=%d in %p\n", name, namelen, disp->name_to_dispid);
  187. /* Lookup the name in the hash */
  188. if (zend_hash_find(disp->name_to_dispid, name, namelen+1, (void**)&tmp) == SUCCESS) {
  189. trace("found it\n");
  190. *pid = Z_LVAL_PP(tmp);
  191. ret = S_OK;
  192. }
  193. efree(name);
  194. return ret;
  195. }
  196. static HRESULT STDMETHODCALLTYPE disp_invokeex(
  197. IDispatchEx *This,
  198. /* [in] */ DISPID id,
  199. /* [in] */ LCID lcid,
  200. /* [in] */ WORD wFlags,
  201. /* [in] */ DISPPARAMS *pdp,
  202. /* [out] */ VARIANT *pvarRes,
  203. /* [out] */ EXCEPINFO *pei,
  204. /* [unique][in] */ IServiceProvider *pspCaller)
  205. {
  206. zval **name;
  207. UINT i;
  208. zval *retval = NULL;
  209. zval ***params = NULL;
  210. HRESULT ret = DISP_E_MEMBERNOTFOUND;
  211. FETCH_DISP("InvokeEx");
  212. if (SUCCESS == zend_hash_index_find(disp->dispid_to_name, id, (void**)&name)) {
  213. /* TODO: add support for overloaded objects */
  214. trace("-- Invoke: %d %20s [%d] flags=%08x args=%d\n", id, Z_STRVAL_PP(name), Z_STRLEN_PP(name), wFlags, pdp->cArgs);
  215. /* convert args into zvals.
  216. * Args are in reverse order */
  217. if (pdp->cArgs) {
  218. params = (zval ***)safe_emalloc(sizeof(zval **), pdp->cArgs, 0);
  219. for (i = 0; i < pdp->cArgs; i++) {
  220. VARIANT *arg;
  221. zval *zarg;
  222. arg = &pdp->rgvarg[ pdp->cArgs - 1 - i];
  223. trace("alloc zval for arg %d VT=%08x\n", i, V_VT(arg));
  224. ALLOC_INIT_ZVAL(zarg);
  225. php_com_wrap_variant(zarg, arg, COMG(code_page) TSRMLS_CC);
  226. params[i] = (zval**)emalloc(sizeof(zval**));
  227. *params[i] = zarg;
  228. }
  229. }
  230. trace("arguments processed, prepare to do some work\n");
  231. /* TODO: if PHP raises an exception here, we should catch it
  232. * and expose it as a COM exception */
  233. if (wFlags & DISPATCH_PROPERTYGET) {
  234. retval = zend_read_property(Z_OBJCE_P(disp->object), disp->object, Z_STRVAL_PP(name), Z_STRLEN_PP(name)+1, 1 TSRMLS_CC);
  235. } else if (wFlags & DISPATCH_PROPERTYPUT) {
  236. zend_update_property(Z_OBJCE_P(disp->object), disp->object, Z_STRVAL_PP(name), Z_STRLEN_PP(name)+1, *params[0] TSRMLS_CC);
  237. } else if (wFlags & DISPATCH_METHOD) {
  238. zend_try {
  239. if (SUCCESS == call_user_function_ex(EG(function_table), &disp->object, *name,
  240. &retval, pdp->cArgs, params, 1, NULL TSRMLS_CC)) {
  241. ret = S_OK;
  242. trace("function called ok\n");
  243. /* Copy any modified values to callers copy of variant*/
  244. for (i = 0; i < pdp->cArgs; i++) {
  245. php_com_dotnet_object *obj = CDNO_FETCH(*params[i]);
  246. VARIANT *srcvar = &obj->v;
  247. VARIANT *dstvar = &pdp->rgvarg[ pdp->cArgs - 1 - i];
  248. if ((V_VT(dstvar) & VT_BYREF) && obj->modified ) {
  249. trace("percolate modified value for arg %d VT=%08x\n", i, V_VT(dstvar));
  250. php_com_copy_variant(dstvar, srcvar TSRMLS_CC);
  251. }
  252. }
  253. } else {
  254. trace("failed to call func\n");
  255. ret = DISP_E_EXCEPTION;
  256. }
  257. } zend_catch {
  258. trace("something blew up\n");
  259. ret = DISP_E_EXCEPTION;
  260. } zend_end_try();
  261. } else {
  262. trace("Don't know how to handle this invocation %08x\n", wFlags);
  263. }
  264. /* release arguments */
  265. if (params) {
  266. for (i = 0; i < pdp->cArgs; i++) {
  267. zval_ptr_dtor(params[i]);
  268. efree(params[i]);
  269. }
  270. efree(params);
  271. }
  272. /* return value */
  273. if (retval) {
  274. if (pvarRes) {
  275. VariantInit(pvarRes);
  276. php_com_variant_from_zval(pvarRes, retval, COMG(code_page) TSRMLS_CC);
  277. }
  278. zval_ptr_dtor(&retval);
  279. } else if (pvarRes) {
  280. VariantInit(pvarRes);
  281. }
  282. } else {
  283. trace("InvokeEx: I don't support DISPID=%d\n", id);
  284. }
  285. return ret;
  286. }
  287. static HRESULT STDMETHODCALLTYPE disp_deletememberbyname(
  288. IDispatchEx *This,
  289. /* [in] */ BSTR bstrName,
  290. /* [in] */ DWORD grfdex)
  291. {
  292. FETCH_DISP("DeleteMemberByName");
  293. /* TODO: unset */
  294. return S_FALSE;
  295. }
  296. static HRESULT STDMETHODCALLTYPE disp_deletememberbydispid(
  297. IDispatchEx *This,
  298. /* [in] */ DISPID id)
  299. {
  300. FETCH_DISP("DeleteMemberByDispID");
  301. /* TODO: unset */
  302. return S_FALSE;
  303. }
  304. static HRESULT STDMETHODCALLTYPE disp_getmemberproperties(
  305. IDispatchEx *This,
  306. /* [in] */ DISPID id,
  307. /* [in] */ DWORD grfdexFetch,
  308. /* [out] */ DWORD *pgrfdex)
  309. {
  310. FETCH_DISP("GetMemberProperties");
  311. return DISP_E_UNKNOWNNAME;
  312. }
  313. static HRESULT STDMETHODCALLTYPE disp_getmembername(
  314. IDispatchEx *This,
  315. /* [in] */ DISPID id,
  316. /* [out] */ BSTR *pbstrName)
  317. {
  318. zval *name;
  319. FETCH_DISP("GetMemberName");
  320. if (SUCCESS == zend_hash_index_find(disp->dispid_to_name, id, (void**)&name)) {
  321. OLECHAR *olestr = php_com_string_to_olestring(Z_STRVAL_P(name), Z_STRLEN_P(name), COMG(code_page) TSRMLS_CC);
  322. *pbstrName = SysAllocString(olestr);
  323. efree(olestr);
  324. return S_OK;
  325. } else {
  326. return DISP_E_UNKNOWNNAME;
  327. }
  328. }
  329. static HRESULT STDMETHODCALLTYPE disp_getnextdispid(
  330. IDispatchEx *This,
  331. /* [in] */ DWORD grfdex,
  332. /* [in] */ DISPID id,
  333. /* [out] */ DISPID *pid)
  334. {
  335. ulong next = id+1;
  336. FETCH_DISP("GetNextDispID");
  337. while(!zend_hash_index_exists(disp->dispid_to_name, next))
  338. next++;
  339. if (zend_hash_index_exists(disp->dispid_to_name, next)) {
  340. *pid = next;
  341. return S_OK;
  342. }
  343. return S_FALSE;
  344. }
  345. static HRESULT STDMETHODCALLTYPE disp_getnamespaceparent(
  346. IDispatchEx *This,
  347. /* [out] */ IUnknown **ppunk)
  348. {
  349. FETCH_DISP("GetNameSpaceParent");
  350. *ppunk = NULL;
  351. return E_NOTIMPL;
  352. }
  353. static struct IDispatchExVtbl php_dispatch_vtbl = {
  354. disp_queryinterface,
  355. disp_addref,
  356. disp_release,
  357. disp_gettypeinfocount,
  358. disp_gettypeinfo,
  359. disp_getidsofnames,
  360. disp_invoke,
  361. disp_getdispid,
  362. disp_invokeex,
  363. disp_deletememberbyname,
  364. disp_deletememberbydispid,
  365. disp_getmemberproperties,
  366. disp_getmembername,
  367. disp_getnextdispid,
  368. disp_getnamespaceparent
  369. };
  370. /* enumerate functions and properties of the object and assign
  371. * dispatch ids */
  372. static void generate_dispids(php_dispatchex *disp TSRMLS_DC)
  373. {
  374. HashPosition pos;
  375. char *name = NULL;
  376. zval *tmp;
  377. int namelen;
  378. int keytype;
  379. ulong pid;
  380. if (disp->dispid_to_name == NULL) {
  381. ALLOC_HASHTABLE(disp->dispid_to_name);
  382. ALLOC_HASHTABLE(disp->name_to_dispid);
  383. zend_hash_init(disp->name_to_dispid, 0, NULL, ZVAL_PTR_DTOR, 0);
  384. zend_hash_init(disp->dispid_to_name, 0, NULL, ZVAL_PTR_DTOR, 0);
  385. }
  386. /* properties */
  387. if (Z_OBJPROP_P(disp->object)) {
  388. zend_hash_internal_pointer_reset_ex(Z_OBJPROP_P(disp->object), &pos);
  389. while (HASH_KEY_NON_EXISTENT != (keytype =
  390. zend_hash_get_current_key_ex(Z_OBJPROP_P(disp->object), &name,
  391. &namelen, &pid, 0, &pos))) {
  392. char namebuf[32];
  393. if (keytype == HASH_KEY_IS_LONG) {
  394. snprintf(namebuf, sizeof(namebuf), "%d", pid);
  395. name = namebuf;
  396. namelen = strlen(namebuf)+1;
  397. }
  398. zend_hash_move_forward_ex(Z_OBJPROP_P(disp->object), &pos);
  399. /* Find the existing id */
  400. if (zend_hash_find(disp->name_to_dispid, name, namelen, (void**)&tmp) == SUCCESS)
  401. continue;
  402. /* add the mappings */
  403. MAKE_STD_ZVAL(tmp);
  404. ZVAL_STRINGL(tmp, name, namelen-1, 1);
  405. pid = zend_hash_next_free_element(disp->dispid_to_name);
  406. zend_hash_index_update(disp->dispid_to_name, pid, (void*)&tmp, sizeof(zval *), NULL);
  407. MAKE_STD_ZVAL(tmp);
  408. ZVAL_LONG(tmp, pid);
  409. zend_hash_update(disp->name_to_dispid, name, namelen, (void*)&tmp, sizeof(zval *), NULL);
  410. }
  411. }
  412. /* functions */
  413. if (Z_OBJCE_P(disp->object)) {
  414. zend_hash_internal_pointer_reset_ex(&Z_OBJCE_P(disp->object)->function_table, &pos);
  415. while (HASH_KEY_NON_EXISTENT != (keytype =
  416. zend_hash_get_current_key_ex(&Z_OBJCE_P(disp->object)->function_table,
  417. &name, &namelen, &pid, 0, &pos))) {
  418. char namebuf[32];
  419. if (keytype == HASH_KEY_IS_LONG) {
  420. snprintf(namebuf, sizeof(namebuf), "%d", pid);
  421. name = namebuf;
  422. namelen = strlen(namebuf) + 1;
  423. }
  424. zend_hash_move_forward_ex(Z_OBJPROP_P(disp->object), &pos);
  425. /* Find the existing id */
  426. if (zend_hash_find(disp->name_to_dispid, name, namelen, (void**)&tmp) == SUCCESS)
  427. continue;
  428. /* add the mappings */
  429. MAKE_STD_ZVAL(tmp);
  430. ZVAL_STRINGL(tmp, name, namelen-1, 1);
  431. pid = zend_hash_next_free_element(disp->dispid_to_name);
  432. zend_hash_index_update(disp->dispid_to_name, pid, (void*)&tmp, sizeof(zval *), NULL);
  433. MAKE_STD_ZVAL(tmp);
  434. ZVAL_LONG(tmp, pid);
  435. zend_hash_update(disp->name_to_dispid, name, namelen, (void*)&tmp, sizeof(zval *), NULL);
  436. }
  437. }
  438. }
  439. static php_dispatchex *disp_constructor(zval *object TSRMLS_DC)
  440. {
  441. php_dispatchex *disp = (php_dispatchex*)CoTaskMemAlloc(sizeof(php_dispatchex));
  442. trace("constructing a COM wrapper for PHP object %p (%s)\n", object, Z_OBJCE_P(object)->name);
  443. if (disp == NULL)
  444. return NULL;
  445. memset(disp, 0, sizeof(php_dispatchex));
  446. disp->engine_thread = GetCurrentThreadId();
  447. disp->lpVtbl = &php_dispatch_vtbl;
  448. disp->refcount = 1;
  449. if (object)
  450. Z_ADDREF_P(object);
  451. disp->object = object;
  452. disp->id = zend_list_insert(disp, le_dispatch TSRMLS_CC);
  453. return disp;
  454. }
  455. static void disp_destructor(php_dispatchex *disp TSRMLS_DC)
  456. {
  457. /* Object store not available during request shutdown */
  458. if (COMG(rshutdown_started)) {
  459. trace("destroying COM wrapper for PHP object %p (name:unknown)\n", disp->object);
  460. } else {
  461. trace("destroying COM wrapper for PHP object %p (name:%s)\n", disp->object, Z_OBJCE_P(disp->object)->name);
  462. }
  463. disp->id = 0;
  464. if (disp->refcount > 0)
  465. CoDisconnectObject((IUnknown*)disp, 0);
  466. zend_hash_destroy(disp->dispid_to_name);
  467. zend_hash_destroy(disp->name_to_dispid);
  468. FREE_HASHTABLE(disp->dispid_to_name);
  469. FREE_HASHTABLE(disp->name_to_dispid);
  470. if (disp->object)
  471. zval_ptr_dtor(&disp->object);
  472. CoTaskMemFree(disp);
  473. }
  474. PHP_COM_DOTNET_API IDispatch *php_com_wrapper_export_as_sink(zval *val, GUID *sinkid,
  475. HashTable *id_to_name TSRMLS_DC)
  476. {
  477. php_dispatchex *disp = disp_constructor(val TSRMLS_CC);
  478. HashPosition pos;
  479. char *name = NULL;
  480. zval *tmp, **ntmp;
  481. int namelen;
  482. int keytype;
  483. ulong pid;
  484. disp->dispid_to_name = id_to_name;
  485. memcpy(&disp->sinkid, sinkid, sizeof(disp->sinkid));
  486. /* build up the reverse mapping */
  487. ALLOC_HASHTABLE(disp->name_to_dispid);
  488. zend_hash_init(disp->name_to_dispid, 0, NULL, ZVAL_PTR_DTOR, 0);
  489. zend_hash_internal_pointer_reset_ex(id_to_name, &pos);
  490. while (HASH_KEY_NON_EXISTENT != (keytype =
  491. zend_hash_get_current_key_ex(id_to_name, &name, &namelen, &pid, 0, &pos))) {
  492. if (keytype == HASH_KEY_IS_LONG) {
  493. zend_hash_get_current_data_ex(id_to_name, (void**)&ntmp, &pos);
  494. MAKE_STD_ZVAL(tmp);
  495. ZVAL_LONG(tmp, pid);
  496. zend_hash_update(disp->name_to_dispid, Z_STRVAL_PP(ntmp),
  497. Z_STRLEN_PP(ntmp)+1, (void*)&tmp, sizeof(zval *), NULL);
  498. }
  499. zend_hash_move_forward_ex(id_to_name, &pos);
  500. }
  501. return (IDispatch*)disp;
  502. }
  503. PHP_COM_DOTNET_API IDispatch *php_com_wrapper_export(zval *val TSRMLS_DC)
  504. {
  505. php_dispatchex *disp = NULL;
  506. if (Z_TYPE_P(val) != IS_OBJECT) {
  507. return NULL;
  508. }
  509. if (php_com_is_valid_object(val TSRMLS_CC)) {
  510. /* pass back its IDispatch directly */
  511. php_com_dotnet_object *obj = CDNO_FETCH(val);
  512. if (obj == NULL)
  513. return NULL;
  514. if (V_VT(&obj->v) == VT_DISPATCH && V_DISPATCH(&obj->v)) {
  515. IDispatch_AddRef(V_DISPATCH(&obj->v));
  516. return V_DISPATCH(&obj->v);
  517. }
  518. return NULL;
  519. }
  520. disp = disp_constructor(val TSRMLS_CC);
  521. generate_dispids(disp TSRMLS_CC);
  522. return (IDispatch*)disp;
  523. }