~ubuntu-branches/ubuntu/hardy/php5/hardy-updates

« back to all changes in this revision

Viewing changes to ext/com_dotnet/com_wrapper.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-10-09 03:14:32 UTC
  • Revision ID: james.westby@ubuntu.com-20051009031432-kspik3lobxstafv9
Tags: upstream-5.0.5
ImportĀ upstreamĀ versionĀ 5.0.5

Show diffs side-by-side

added added

removed removed

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