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