summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWez Furlong <wez@php.net>2002-05-20 01:31:48 +0000
committerWez Furlong <wez@php.net>2002-05-20 01:31:48 +0000
commitfc964e88d36bc39ea51a12e5ad8496d469c0cc80 (patch)
treec0f98fba484cba676e7d7603410d6647303abbf2
parent3b97fe3657bce898017cc0c65ef654a74303d316 (diff)
downloadphp-git-fc964e88d36bc39ea51a12e5ad8496d469c0cc80.tar.gz
Added generic COM wrapper for PHP objects.
-rw-r--r--ext/com/COM.c39
-rw-r--r--ext/com/conversion.c19
-rw-r--r--ext/com/dispatch.c547
-rw-r--r--ext/com/php_COM.h18
-rw-r--r--ext/rpc/com/com_wrapper.c39
-rw-r--r--ext/rpc/com/conversion.c19
-rw-r--r--ext/rpc/com/dispatch.c547
-rw-r--r--ext/rpc/com/php_com.h18
8 files changed, 1234 insertions, 12 deletions
diff --git a/ext/com/COM.c b/ext/com/COM.c
index cb42bfc4f7..f8149faf7c 100644
--- a/ext/com/COM.c
+++ b/ext/com/COM.c
@@ -65,7 +65,6 @@
#include "php_VARIANT.h"
static ITypeLib *php_COM_find_typelib(char *search_string, int mode TSRMLS_DC);
-static int php_COM_load_typelib(ITypeLib *TypeLib, int mode TSRMLS_DC);
static int do_COM_offget(VARIANT *result, comval *array, pval *property, int cleanup TSRMLS_DC);
static int do_COM_propget(VARIANT *var_result, comval *obj, pval *arg_property, int cleanup TSRMLS_DC);
static void php_register_COM_class(TSRMLS_D);
@@ -1424,6 +1423,32 @@ PHPAPI int php_COM_set_property_handler(zend_property_reference *property_refere
return SUCCESS;
}
+/* create an overloaded COM object from a dispatch pointer */
+PHPAPI zval *php_COM_object_from_dispatch(IDispatch *disp, zval *val TSRMLS_DC)
+{
+ comval *obj;
+ long rid;
+ zval *zobj;
+
+ ALLOC_COM(obj);
+ C_DISPATCH(obj) = disp;
+ php_COM_set(obj, &C_DISPATCH(obj), FALSE TSRMLS_CC);
+
+ /* resource */
+ rid = zend_list_insert(obj, IS_COM);
+
+ if (val == NULL)
+ MAKE_STD_ZVAL(val);
+ ZVAL_RESOURCE(val, rid);
+
+ /* now we want an object */
+ MAKE_STD_ZVAL(zobj);
+ object_init_ex(zobj, &COM_class_entry);
+ zend_hash_index_update(Z_OBJPROP_P(zobj), 0, &val, sizeof(zval *), NULL);
+
+ return zobj;
+}
+
PHPAPI void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference)
{
@@ -1672,7 +1697,7 @@ static ITypeLib *php_COM_find_typelib(char *search_string, int mode TSRMLS_DC)
}
-static int php_COM_load_typelib(ITypeLib *TypeLib, int mode TSRMLS_DC)
+PHPAPI int php_COM_load_typelib(ITypeLib *TypeLib, int mode TSRMLS_DC)
{
ITypeComp *TypeComp;
int i;
@@ -1800,11 +1825,18 @@ static void php_COM_init(int module_number TSRMLS_DC)
php_register_COM_class(TSRMLS_C);
}
+PHPAPI ZEND_DECLARE_MODULE_GLOBALS(com)
+
+static void php_com_init_globals(zend_com_globals *com_globals)
+{
+}
PHP_MINIT_FUNCTION(COM)
{
+ ZEND_INIT_MODULE_GLOBALS(com, php_com_init_globals, NULL);
php_COM_init(module_number TSRMLS_CC);
php_VARIANT_init(module_number TSRMLS_CC);
+ php_COM_dispatch_init(module_number TSRMLS_CC);
REGISTER_LONG_CONSTANT("CLSCTX_INPROC_SERVER", CLSCTX_INPROC_SERVER, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("CLSCTX_INPROC_HANDLER", CLSCTX_INPROC_HANDLER, CONST_CS | CONST_PERSISTENT);
@@ -1818,7 +1850,6 @@ PHP_MINIT_FUNCTION(COM)
return SUCCESS;
}
-
PHP_MSHUTDOWN_FUNCTION(COM)
{
UNREGISTER_INI_ENTRIES();
@@ -1835,7 +1866,7 @@ zend_module_entry COM_module_entry = {
PHP_MSHUTDOWN(COM),
NULL,
NULL,
- PHP_MINFO(COM),
+ PHP_MINFO(COM),
NO_VERSION_YET,
STANDARD_MODULE_PROPERTIES
};
diff --git a/ext/com/conversion.c b/ext/com/conversion.c
index 0adcefdf47..130885edd9 100644
--- a/ext/com/conversion.c
+++ b/ext/com/conversion.c
@@ -58,6 +58,8 @@ PHPAPI void php_pval_to_variant(pval *pval_arg, VARIANT *var_arg, int codepage T
type = VT_VARIANT|VT_BYREF;
} else if (!strcmp(Z_OBJCE_P(pval_arg)->name, "COM")) {
type = VT_DISPATCH;
+ } else {
+ type = VT_DISPATCH;
}
break;
@@ -155,6 +157,12 @@ PHPAPI void php_pval_to_variant_ex2(pval *pval_arg, VARIANT *var_arg, int type,
}
} else {
switch (V_VT(var_arg)) {
+
+ case VT_NULL:
+ case VT_VOID:
+ ZVAL_NULL(pval_arg);
+ break;
+
case VT_UI1:
convert_to_long_ex(&pval_arg);
V_UI1(var_arg) = (unsigned char) Z_LVAL_P(pval_arg);
@@ -211,6 +219,7 @@ PHPAPI void php_pval_to_variant_ex2(pval *pval_arg, VARIANT *var_arg, int type,
/** @todo
case IS_STRING:
+ */
/* string representation of a time value */
default:
@@ -262,7 +271,13 @@ PHPAPI void php_pval_to_variant_ex2(pval *pval_arg, VARIANT *var_arg, int type,
break;
case VT_DISPATCH:
- comval_to_variant(pval_arg, var_arg TSRMLS_CC);
+ if (!strcmp(Z_OBJCE_P(pval_arg)->name, "COM")) {
+ comval_to_variant(pval_arg, var_arg TSRMLS_CC);
+ } else {
+ V_DISPATCH(var_arg) = php_COM_export_object(pval_arg TSRMLS_CC);
+ if (V_DISPATCH(var_arg))
+ V_VT(var_arg) = VT_DISPATCH;
+ }
if (V_VT(var_arg) != VT_DISPATCH) {
VariantInit(var_arg);
}
@@ -437,7 +452,7 @@ PHPAPI void php_pval_to_variant_ex2(pval *pval_arg, VARIANT *var_arg, int type,
break;
default:
- php_error(E_WARNING, "Type not supported or not yet implemented.");
+ php_error(E_WARNING,"Unsupported variant type: %d (0x%X)", V_VT(var_arg), V_VT(var_arg));
}
}
}
diff --git a/ext/com/dispatch.c b/ext/com/dispatch.c
new file mode 100644
index 0000000000..802c4f871e
--- /dev/null
+++ b/ext/com/dispatch.c
@@ -0,0 +1,547 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 4 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2002 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.02 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_02.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@thebrainroom.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+/*
+ * This module is used to export PHP objects to COM and DOTNET by exposing
+ * them as objects implementing IDispatch.
+ * */
+
+#include "php.h"
+#include "php_COM.h"
+#include "php_VARIANT.h"
+#include "conversion.h"
+#include "variant.h"
+
+#define COBJMACROS
+#include <unknwn.h> /* IDispatch */
+#include <dispex.h> /* IDispatchEx */
+
+
+typedef struct {
+ /* This first part MUST match the declaration
+ * of interface IDispatchEx */
+ CONST_VTBL struct IDispatchExVtbl *lpVtbl;
+
+ /* now the PHP stuff */
+
+ THREAD_T engine_thread; /* for sanity checking */
+ zval *object; /* the object exported */
+ LONG refcount; /* COM reference count */
+
+ HashTable dispid_to_name; /* keep track of dispid -> name mappings */
+ HashTable name_to_dispid; /* keep track of name -> dispid mappings */
+
+ int id;
+} php_dispatchex;
+
+static void disp_destructor(php_dispatchex *disp);
+
+static void dispatch_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ php_dispatchex *disp = (php_dispatchex *)rsrc->ptr;
+ disp_destructor(disp);
+}
+
+static int le_dispatch;
+int php_COM_dispatch_init(int module_number TSRMLS_DC)
+{
+ le_dispatch = zend_register_list_destructors_ex(dispatch_dtor, NULL, "COM:Dispatch", module_number);
+ return le_dispatch;
+}
+
+
+/* {{{ trace */
+static inline void trace(char *fmt, ...)
+{
+ va_list ap;
+ char buf[4096];
+
+ sprintf(buf, "T=%08x ", tsrm_thread_id());
+ OutputDebugString(buf);
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+
+ OutputDebugString(buf);
+
+ va_end(ap);
+}
+/* }}} */
+
+#define FETCH_DISP(methname) \
+ php_dispatchex *disp = (php_dispatchex*)This; \
+ trace(" PHP:%s %s\n", Z_OBJCE_P(disp->object)->name, methname); \
+ if (tsrm_thread_id() != disp->engine_thread) \
+ return E_UNEXPECTED;
+
+
+static HRESULT STDMETHODCALLTYPE disp_queryinterface(
+ IDispatchEx *This,
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ void **ppvObject)
+{
+ FETCH_DISP("QueryInterface");
+
+ if (IsEqualGUID(&IID_IUnknown, riid) ||
+ IsEqualGUID(&IID_IDispatch, riid) ||
+ IsEqualGUID(&IID_IDispatchEx, riid)) {
+ *ppvObject = This;
+ InterlockedIncrement(&disp->refcount);
+ return S_OK;
+ }
+
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE disp_addref(IDispatchEx *This)
+{
+ FETCH_DISP("AddRef");
+
+ return InterlockedIncrement(&disp->refcount);
+}
+
+static ULONG STDMETHODCALLTYPE disp_release(IDispatchEx *This)
+{
+ ULONG ret;
+ TSRMLS_FETCH();
+ FETCH_DISP("Release");
+
+ ret = InterlockedDecrement(&disp->refcount);
+ trace("-- refcount now %d\n", ret);
+ if (ret == 0) {
+ /* destroy it */
+ if (disp->id)
+ zend_list_delete(disp->id);
+ }
+ return ret;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_gettypeinfocount(
+ IDispatchEx *This,
+ /* [out] */ UINT *pctinfo)
+{
+ FETCH_DISP("GetTypeInfoCount");
+
+ *pctinfo = 0;
+ return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_gettypeinfo(
+ IDispatchEx *This,
+ /* [in] */ UINT iTInfo,
+ /* [in] */ LCID lcid,
+ /* [out] */ ITypeInfo **ppTInfo)
+{
+ FETCH_DISP("GetTypeInfo");
+
+ *ppTInfo = NULL;
+ return DISP_E_BADINDEX;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_getidsofnames(
+ IDispatchEx *This,
+ /* [in] */ REFIID riid,
+ /* [size_is][in] */ LPOLESTR *rgszNames,
+ /* [in] */ UINT cNames,
+ /* [in] */ LCID lcid,
+ /* [size_is][out] */ DISPID *rgDispId)
+{
+ UINT i;
+ HRESULT ret = S_OK;
+ TSRMLS_FETCH();
+ FETCH_DISP("GetIDsOfNames");
+
+ for (i = 0; i < cNames; i++) {
+ char *name;
+ unsigned int namelen;
+ zval *tmp;
+
+ name = php_OLECHAR_to_char(rgszNames[i], &namelen, CP_ACP TSRMLS_CC);
+
+ /* Lookup the name in the hash */
+ if (zend_hash_find(&disp->name_to_dispid, name, namelen+1, (void**)&tmp) == FAILURE) {
+ ret = DISP_E_UNKNOWNNAME;
+ rgDispId[i] = 0;
+ } else {
+ rgDispId[i] = Z_LVAL_P(tmp);
+ }
+
+ efree(name);
+
+ }
+
+ return ret;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_invoke(
+ IDispatchEx *This,
+ /* [in] */ DISPID dispIdMember,
+ /* [in] */ REFIID riid,
+ /* [in] */ LCID lcid,
+ /* [in] */ WORD wFlags,
+ /* [out][in] */ DISPPARAMS *pDispParams,
+ /* [out] */ VARIANT *pVarResult,
+ /* [out] */ EXCEPINFO *pExcepInfo,
+ /* [out] */ UINT *puArgErr)
+{
+ return This->lpVtbl->InvokeEx(This, dispIdMember,
+ lcid, wFlags, pDispParams,
+ pVarResult, pExcepInfo, NULL);
+}
+
+static HRESULT STDMETHODCALLTYPE disp_getdispid(
+ IDispatchEx *This,
+ /* [in] */ BSTR bstrName,
+ /* [in] */ DWORD grfdex,
+ /* [out] */ DISPID *pid)
+{
+ HRESULT ret = DISP_E_UNKNOWNNAME;
+ char *name;
+ unsigned int namelen;
+ zval *tmp;
+ TSRMLS_FETCH();
+ FETCH_DISP("GetDispID");
+
+ name = php_OLECHAR_to_char(bstrName, &namelen, CP_ACP TSRMLS_CC);
+
+ /* Lookup the name in the hash */
+ if (zend_hash_find(&disp->name_to_dispid, name, namelen+1, (void**)&tmp) == SUCCESS) {
+ *pid = Z_LVAL_P(tmp);
+ ret = S_OK;
+ }
+
+ efree(name);
+
+ return ret;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_invokeex(
+ IDispatchEx *This,
+ /* [in] */ DISPID id,
+ /* [in] */ LCID lcid,
+ /* [in] */ WORD wFlags,
+ /* [in] */ DISPPARAMS *pdp,
+ /* [out] */ VARIANT *pvarRes,
+ /* [out] */ EXCEPINFO *pei,
+ /* [unique][in] */ IServiceProvider *pspCaller)
+{
+ zval *name;
+ UINT i;
+ int codepage = CP_ACP;
+ zval **retval = NULL;
+ zval ***params = NULL;
+ TSRMLS_FETCH();
+ FETCH_DISP("InvokeEx");
+
+ if (SUCCESS == zend_hash_index_find(&disp->dispid_to_name, id, (void**)&name)) {
+ /* TODO: add support for overloaded objects */
+
+ trace("-- Invoke: %d %s\n", id, Z_STRVAL_P(name));
+
+ /* convert args into zvals.
+ * Args are in reverse order */
+ params = (zval ***)emalloc(sizeof(zval **) * pdp->cArgs);
+ for (i = 0; i < pdp->cArgs; i++) {
+ ALLOC_INIT_ZVAL(*params[i]);
+
+ if (V_VT(&pdp->rgvarg[pdp->cArgs-i]) == VT_DISPATCH) {
+ php_COM_object_from_dispatch(V_DISPATCH(&pdp->rgvarg[pdp->cArgs-i]), *params[i] TSRMLS_CC);
+ } else {
+ ZVAL_VARIANT(*params[i], &pdp->rgvarg[pdp->cArgs-i]);
+ }
+ }
+
+ if (wFlags & DISPATCH_PROPERTYGET) {
+ zend_hash_find(Z_OBJPROP_P(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name)+1, (void**)&retval);
+ } else if (wFlags & DISPATCH_PROPERTYPUT) {
+ add_property_zval(disp->object, Z_STRVAL_P(name), *params[0]);
+ } else if (wFlags & DISPATCH_METHOD) {
+
+ call_user_function_ex(EG(function_table), &disp->object, name,
+ retval, pdp->cArgs, params, 1, NULL TSRMLS_CC);
+ }
+
+ /* release arguments */
+ for (i = 0; i < pdp->cArgs; i++)
+ zval_ptr_dtor(params[i]);
+
+ /* return value */
+ if (retval) {
+ if (pvarRes) {
+ if (Z_TYPE_PP(retval) == IS_OBJECT) {
+ /* export the object using a dispatch like ourselves */
+ VariantInit(pvarRes);
+ V_VT(pvarRes) = VT_DISPATCH;
+ V_DISPATCH(pvarRes) = php_COM_export_object(*retval TSRMLS_CC);
+ } else {
+ php_pval_to_variant(*retval, pvarRes, codepage TSRMLS_CC);
+ }
+ }
+ zval_ptr_dtor(retval);
+ } else if (pvarRes) {
+ VariantInit(pvarRes);
+ }
+
+ return S_OK;
+ } else {
+ trace("InvokeEx: I don't support DISPID=%d\n", id);
+ }
+
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_deletememberbyname(
+ IDispatchEx *This,
+ /* [in] */ BSTR bstrName,
+ /* [in] */ DWORD grfdex)
+{
+ FETCH_DISP("DeleteMemberByName");
+
+ return S_FALSE;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_deletememberbydispid(
+ IDispatchEx *This,
+ /* [in] */ DISPID id)
+{
+ FETCH_DISP("DeleteMemberByDispID");
+
+ return S_FALSE;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_getmemberproperties(
+ IDispatchEx *This,
+ /* [in] */ DISPID id,
+ /* [in] */ DWORD grfdexFetch,
+ /* [out] */ DWORD *pgrfdex)
+{
+ FETCH_DISP("GetMemberProperties");
+
+ return DISP_E_UNKNOWNNAME;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_getmembername(
+ IDispatchEx *This,
+ /* [in] */ DISPID id,
+ /* [out] */ BSTR *pbstrName)
+{
+ zval *name;
+ TSRMLS_FETCH();
+ FETCH_DISP("GetMemberName");
+
+ if (SUCCESS == zend_hash_index_find(&disp->dispid_to_name, id, (void**)&name)) {
+ OLECHAR *olestr = php_char_to_OLECHAR(Z_STRVAL_P(name), Z_STRLEN_P(name), CP_ACP TSRMLS_CC);
+ *pbstrName = SysAllocString(olestr);
+ efree(olestr);
+ return S_OK;
+ } else {
+ return DISP_E_UNKNOWNNAME;
+ }
+}
+
+static HRESULT STDMETHODCALLTYPE disp_getnextdispid(
+ IDispatchEx *This,
+ /* [in] */ DWORD grfdex,
+ /* [in] */ DISPID id,
+ /* [out] */ DISPID *pid)
+{
+ ulong next = id+1;
+ FETCH_DISP("GetNextDispID");
+
+ while(!zend_hash_index_exists(&disp->dispid_to_name, next))
+ next++;
+
+ if (zend_hash_index_exists(&disp->dispid_to_name, next)) {
+ *pid = next;
+ return S_OK;
+ }
+ return S_FALSE;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_getnamespaceparent(
+ IDispatchEx *This,
+ /* [out] */ IUnknown **ppunk)
+{
+ FETCH_DISP("GetNameSpaceParent");
+
+ *ppunk = NULL;
+ return E_NOTIMPL;
+}
+
+static struct IDispatchExVtbl php_dispatch_vtbl = {
+ disp_queryinterface,
+ disp_addref,
+ disp_release,
+ disp_gettypeinfocount,
+ disp_gettypeinfo,
+ disp_getidsofnames,
+ disp_invoke,
+ disp_getdispid,
+ disp_invokeex,
+ disp_deletememberbyname,
+ disp_deletememberbydispid,
+ disp_getmemberproperties,
+ disp_getmembername,
+ disp_getnextdispid,
+ disp_getnamespaceparent
+};
+
+
+/* enumerate functions and properties of the object and assign
+ * dispatch ids */
+static void update_dispids(php_dispatchex *disp TSRMLS_DC)
+{
+ HashPosition pos;
+ char *name = NULL;
+ zval *tmp;
+ int namelen;
+ int keytype;
+ ulong pid;
+
+ /* properties */
+ zend_hash_internal_pointer_reset_ex(Z_OBJPROP_PP(&disp->object), &pos);
+ while (HASH_KEY_NON_EXISTANT != (keytype =
+ zend_hash_get_current_key_ex(Z_OBJPROP_PP(&disp->object), &name, &namelen, &pid, 0, &pos))) {
+ char namebuf[32];
+ if (keytype == HASH_KEY_IS_LONG) {
+ sprintf(namebuf, "%d", pid);
+ name = namebuf;
+ namelen = strlen(namebuf);
+ }
+
+ zend_hash_move_forward_ex(Z_OBJPROP_PP(&disp->object), &pos);
+
+ /* Find the existing id */
+ if (zend_hash_find(&disp->name_to_dispid, name, namelen+1, (void**)&tmp) == SUCCESS)
+ continue;
+
+ /* add the mappings */
+ MAKE_STD_ZVAL(tmp);
+ ZVAL_STRINGL(tmp, name, namelen, 1);
+ zend_hash_index_update(&disp->dispid_to_name, pid, (void*)&tmp, sizeof(zval *), NULL);
+
+ MAKE_STD_ZVAL(tmp);
+ ZVAL_LONG(tmp, pid);
+ zend_hash_update(&disp->name_to_dispid, name, namelen+1, (void*)&tmp, sizeof(zval *), NULL);
+
+ }
+
+ /* functions */
+ zend_hash_internal_pointer_reset_ex(&Z_OBJCE_PP(&disp->object)->function_table, &pos);
+ while (HASH_KEY_NON_EXISTANT != (keytype =
+ zend_hash_get_current_key_ex(&Z_OBJCE_PP(&disp->object)->function_table, &name, &namelen, &pid, 0, &pos))) {
+
+ char namebuf[32];
+ if (keytype == HASH_KEY_IS_LONG) {
+ sprintf(namebuf, "%d", pid);
+ name = namebuf;
+ namelen = strlen(namebuf);
+ }
+
+ zend_hash_move_forward_ex(Z_OBJPROP_PP(&disp->object), &pos);
+
+ /* Find the existing id */
+ if (zend_hash_find(&disp->name_to_dispid, name, namelen+1, (void**)&tmp) == SUCCESS)
+ continue;
+
+ /* add the mappings */
+ MAKE_STD_ZVAL(tmp);
+ ZVAL_STRINGL(tmp, name, namelen, 1);
+ zend_hash_index_update(&disp->dispid_to_name, pid, (void*)&tmp, sizeof(zval *), NULL);
+
+ MAKE_STD_ZVAL(tmp);
+ ZVAL_LONG(tmp, pid);
+ zend_hash_update(&disp->name_to_dispid, name, namelen+1, (void*)&tmp, sizeof(zval *), NULL);
+ }
+}
+
+static php_dispatchex *disp_constructor(zval *object TSRMLS_DC)
+{
+ php_dispatchex *disp = (php_dispatchex*)CoTaskMemAlloc(sizeof(php_dispatchex));
+
+ if (disp == NULL)
+ return NULL;
+
+ memset(disp, 0, sizeof(php_dispatchex));
+
+ disp->engine_thread = tsrm_thread_id();
+ disp->lpVtbl = &php_dispatch_vtbl;
+ disp->refcount = 1;
+
+ zend_hash_init(&disp->dispid_to_name, 0, NULL, NULL, TRUE);
+ zend_hash_init(&disp->name_to_dispid, 0, NULL, NULL, TRUE);
+
+ if (object)
+ ZVAL_ADDREF(object);
+ disp->object = object;
+
+ update_dispids(disp TSRMLS_CC);
+
+ disp->id = zend_list_insert(disp, le_dispatch);
+
+ return disp;
+}
+
+static void disp_destructor(php_dispatchex *disp)
+{
+ TSRMLS_FETCH();
+
+ trace("destroying COM wrapper for PHP object %s\n", Z_OBJCE_P(disp->object)->name);
+
+ disp->id = 0;
+
+ if (disp->refcount > 0)
+ CoDisconnectObject((IUnknown*)disp, 0);
+
+ zend_hash_destroy(&disp->dispid_to_name);
+ zend_hash_destroy(&disp->name_to_dispid);
+
+ if (disp->object)
+ zval_ptr_dtor(&disp->object);
+
+
+ CoTaskMemFree(disp);
+}
+
+
+PHPAPI IDispatch *php_COM_export_object(zval *val TSRMLS_DC)
+{
+ if (Z_TYPE_P(val) != IS_OBJECT)
+ return NULL;
+
+ if (Z_OBJCE_P(val) == &COM_class_entry) {
+ /* pass back it's IDispatch directly */
+ zval **tmp;
+ comval *obj;
+ int type;
+
+ zend_hash_index_find(Z_OBJPROP_P(val), 0, (void**)&tmp);
+ obj = (comval *)zend_list_find(Z_LVAL_PP(tmp), &type);
+ if (type != IS_COM)
+ return NULL;
+
+ C_DISPATCH(obj)->lpVtbl->AddRef(C_DISPATCH(obj));
+ return C_DISPATCH(obj);
+ }
+ return (IDispatch*)disp_constructor(val TSRMLS_CC);
+}
+
+
diff --git a/ext/com/php_COM.h b/ext/com/php_COM.h
index 5c0155515b..396df9c93c 100644
--- a/ext/com/php_COM.h
+++ b/ext/com/php_COM.h
@@ -31,6 +31,12 @@ PHPAPI int php_COM_get_le_comval();
PHPAPI int php_COM_set_property_handler(zend_property_reference *property_reference, pval *value);
PHPAPI pval php_COM_get_property_handler(zend_property_reference *property_reference);
PHPAPI void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference);
+PHPAPI zval *php_COM_object_from_dispatch(IDispatch *disp, zval *val TSRMLS_DC);
+PHPAPI int php_COM_load_typelib(ITypeLib *TypeLib, int mode TSRMLS_DC);
+
+/* dispatch.c */
+PHPAPI IDispatch *php_COM_export_object(zval *val TSRMLS_DC);
+int php_COM_dispatch_init(int module_number TSRMLS_DC);
zend_module_entry COM_module_entry;
zend_class_entry COM_class_entry;
@@ -43,6 +49,18 @@ END_EXTERN_C()
#define phpext_com_ptr &COM_module_entry
+ZEND_BEGIN_MODULE_GLOBALS(com)
+ int nothing;
+ZEND_END_MODULE_GLOBALS(com)
+
+PHPAPI ZEND_EXTERN_MODULE_GLOBALS(com);
+
+#ifdef ZTS
+#define COMG(v) TSRMG(com_globals_id, zend_com_globals *, v)
+#else
+#define COMG(v) (com_globals.v)
+#endif
+
#else
#define phpext_com_ptr NULL
diff --git a/ext/rpc/com/com_wrapper.c b/ext/rpc/com/com_wrapper.c
index cb42bfc4f7..f8149faf7c 100644
--- a/ext/rpc/com/com_wrapper.c
+++ b/ext/rpc/com/com_wrapper.c
@@ -65,7 +65,6 @@
#include "php_VARIANT.h"
static ITypeLib *php_COM_find_typelib(char *search_string, int mode TSRMLS_DC);
-static int php_COM_load_typelib(ITypeLib *TypeLib, int mode TSRMLS_DC);
static int do_COM_offget(VARIANT *result, comval *array, pval *property, int cleanup TSRMLS_DC);
static int do_COM_propget(VARIANT *var_result, comval *obj, pval *arg_property, int cleanup TSRMLS_DC);
static void php_register_COM_class(TSRMLS_D);
@@ -1424,6 +1423,32 @@ PHPAPI int php_COM_set_property_handler(zend_property_reference *property_refere
return SUCCESS;
}
+/* create an overloaded COM object from a dispatch pointer */
+PHPAPI zval *php_COM_object_from_dispatch(IDispatch *disp, zval *val TSRMLS_DC)
+{
+ comval *obj;
+ long rid;
+ zval *zobj;
+
+ ALLOC_COM(obj);
+ C_DISPATCH(obj) = disp;
+ php_COM_set(obj, &C_DISPATCH(obj), FALSE TSRMLS_CC);
+
+ /* resource */
+ rid = zend_list_insert(obj, IS_COM);
+
+ if (val == NULL)
+ MAKE_STD_ZVAL(val);
+ ZVAL_RESOURCE(val, rid);
+
+ /* now we want an object */
+ MAKE_STD_ZVAL(zobj);
+ object_init_ex(zobj, &COM_class_entry);
+ zend_hash_index_update(Z_OBJPROP_P(zobj), 0, &val, sizeof(zval *), NULL);
+
+ return zobj;
+}
+
PHPAPI void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference)
{
@@ -1672,7 +1697,7 @@ static ITypeLib *php_COM_find_typelib(char *search_string, int mode TSRMLS_DC)
}
-static int php_COM_load_typelib(ITypeLib *TypeLib, int mode TSRMLS_DC)
+PHPAPI int php_COM_load_typelib(ITypeLib *TypeLib, int mode TSRMLS_DC)
{
ITypeComp *TypeComp;
int i;
@@ -1800,11 +1825,18 @@ static void php_COM_init(int module_number TSRMLS_DC)
php_register_COM_class(TSRMLS_C);
}
+PHPAPI ZEND_DECLARE_MODULE_GLOBALS(com)
+
+static void php_com_init_globals(zend_com_globals *com_globals)
+{
+}
PHP_MINIT_FUNCTION(COM)
{
+ ZEND_INIT_MODULE_GLOBALS(com, php_com_init_globals, NULL);
php_COM_init(module_number TSRMLS_CC);
php_VARIANT_init(module_number TSRMLS_CC);
+ php_COM_dispatch_init(module_number TSRMLS_CC);
REGISTER_LONG_CONSTANT("CLSCTX_INPROC_SERVER", CLSCTX_INPROC_SERVER, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("CLSCTX_INPROC_HANDLER", CLSCTX_INPROC_HANDLER, CONST_CS | CONST_PERSISTENT);
@@ -1818,7 +1850,6 @@ PHP_MINIT_FUNCTION(COM)
return SUCCESS;
}
-
PHP_MSHUTDOWN_FUNCTION(COM)
{
UNREGISTER_INI_ENTRIES();
@@ -1835,7 +1866,7 @@ zend_module_entry COM_module_entry = {
PHP_MSHUTDOWN(COM),
NULL,
NULL,
- PHP_MINFO(COM),
+ PHP_MINFO(COM),
NO_VERSION_YET,
STANDARD_MODULE_PROPERTIES
};
diff --git a/ext/rpc/com/conversion.c b/ext/rpc/com/conversion.c
index 0adcefdf47..130885edd9 100644
--- a/ext/rpc/com/conversion.c
+++ b/ext/rpc/com/conversion.c
@@ -58,6 +58,8 @@ PHPAPI void php_pval_to_variant(pval *pval_arg, VARIANT *var_arg, int codepage T
type = VT_VARIANT|VT_BYREF;
} else if (!strcmp(Z_OBJCE_P(pval_arg)->name, "COM")) {
type = VT_DISPATCH;
+ } else {
+ type = VT_DISPATCH;
}
break;
@@ -155,6 +157,12 @@ PHPAPI void php_pval_to_variant_ex2(pval *pval_arg, VARIANT *var_arg, int type,
}
} else {
switch (V_VT(var_arg)) {
+
+ case VT_NULL:
+ case VT_VOID:
+ ZVAL_NULL(pval_arg);
+ break;
+
case VT_UI1:
convert_to_long_ex(&pval_arg);
V_UI1(var_arg) = (unsigned char) Z_LVAL_P(pval_arg);
@@ -211,6 +219,7 @@ PHPAPI void php_pval_to_variant_ex2(pval *pval_arg, VARIANT *var_arg, int type,
/** @todo
case IS_STRING:
+ */
/* string representation of a time value */
default:
@@ -262,7 +271,13 @@ PHPAPI void php_pval_to_variant_ex2(pval *pval_arg, VARIANT *var_arg, int type,
break;
case VT_DISPATCH:
- comval_to_variant(pval_arg, var_arg TSRMLS_CC);
+ if (!strcmp(Z_OBJCE_P(pval_arg)->name, "COM")) {
+ comval_to_variant(pval_arg, var_arg TSRMLS_CC);
+ } else {
+ V_DISPATCH(var_arg) = php_COM_export_object(pval_arg TSRMLS_CC);
+ if (V_DISPATCH(var_arg))
+ V_VT(var_arg) = VT_DISPATCH;
+ }
if (V_VT(var_arg) != VT_DISPATCH) {
VariantInit(var_arg);
}
@@ -437,7 +452,7 @@ PHPAPI void php_pval_to_variant_ex2(pval *pval_arg, VARIANT *var_arg, int type,
break;
default:
- php_error(E_WARNING, "Type not supported or not yet implemented.");
+ php_error(E_WARNING,"Unsupported variant type: %d (0x%X)", V_VT(var_arg), V_VT(var_arg));
}
}
}
diff --git a/ext/rpc/com/dispatch.c b/ext/rpc/com/dispatch.c
new file mode 100644
index 0000000000..802c4f871e
--- /dev/null
+++ b/ext/rpc/com/dispatch.c
@@ -0,0 +1,547 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 4 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2002 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 2.02 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at |
+ | http://www.php.net/license/2_02.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@thebrainroom.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+/*
+ * This module is used to export PHP objects to COM and DOTNET by exposing
+ * them as objects implementing IDispatch.
+ * */
+
+#include "php.h"
+#include "php_COM.h"
+#include "php_VARIANT.h"
+#include "conversion.h"
+#include "variant.h"
+
+#define COBJMACROS
+#include <unknwn.h> /* IDispatch */
+#include <dispex.h> /* IDispatchEx */
+
+
+typedef struct {
+ /* This first part MUST match the declaration
+ * of interface IDispatchEx */
+ CONST_VTBL struct IDispatchExVtbl *lpVtbl;
+
+ /* now the PHP stuff */
+
+ THREAD_T engine_thread; /* for sanity checking */
+ zval *object; /* the object exported */
+ LONG refcount; /* COM reference count */
+
+ HashTable dispid_to_name; /* keep track of dispid -> name mappings */
+ HashTable name_to_dispid; /* keep track of name -> dispid mappings */
+
+ int id;
+} php_dispatchex;
+
+static void disp_destructor(php_dispatchex *disp);
+
+static void dispatch_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ php_dispatchex *disp = (php_dispatchex *)rsrc->ptr;
+ disp_destructor(disp);
+}
+
+static int le_dispatch;
+int php_COM_dispatch_init(int module_number TSRMLS_DC)
+{
+ le_dispatch = zend_register_list_destructors_ex(dispatch_dtor, NULL, "COM:Dispatch", module_number);
+ return le_dispatch;
+}
+
+
+/* {{{ trace */
+static inline void trace(char *fmt, ...)
+{
+ va_list ap;
+ char buf[4096];
+
+ sprintf(buf, "T=%08x ", tsrm_thread_id());
+ OutputDebugString(buf);
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+
+ OutputDebugString(buf);
+
+ va_end(ap);
+}
+/* }}} */
+
+#define FETCH_DISP(methname) \
+ php_dispatchex *disp = (php_dispatchex*)This; \
+ trace(" PHP:%s %s\n", Z_OBJCE_P(disp->object)->name, methname); \
+ if (tsrm_thread_id() != disp->engine_thread) \
+ return E_UNEXPECTED;
+
+
+static HRESULT STDMETHODCALLTYPE disp_queryinterface(
+ IDispatchEx *This,
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ void **ppvObject)
+{
+ FETCH_DISP("QueryInterface");
+
+ if (IsEqualGUID(&IID_IUnknown, riid) ||
+ IsEqualGUID(&IID_IDispatch, riid) ||
+ IsEqualGUID(&IID_IDispatchEx, riid)) {
+ *ppvObject = This;
+ InterlockedIncrement(&disp->refcount);
+ return S_OK;
+ }
+
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE disp_addref(IDispatchEx *This)
+{
+ FETCH_DISP("AddRef");
+
+ return InterlockedIncrement(&disp->refcount);
+}
+
+static ULONG STDMETHODCALLTYPE disp_release(IDispatchEx *This)
+{
+ ULONG ret;
+ TSRMLS_FETCH();
+ FETCH_DISP("Release");
+
+ ret = InterlockedDecrement(&disp->refcount);
+ trace("-- refcount now %d\n", ret);
+ if (ret == 0) {
+ /* destroy it */
+ if (disp->id)
+ zend_list_delete(disp->id);
+ }
+ return ret;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_gettypeinfocount(
+ IDispatchEx *This,
+ /* [out] */ UINT *pctinfo)
+{
+ FETCH_DISP("GetTypeInfoCount");
+
+ *pctinfo = 0;
+ return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_gettypeinfo(
+ IDispatchEx *This,
+ /* [in] */ UINT iTInfo,
+ /* [in] */ LCID lcid,
+ /* [out] */ ITypeInfo **ppTInfo)
+{
+ FETCH_DISP("GetTypeInfo");
+
+ *ppTInfo = NULL;
+ return DISP_E_BADINDEX;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_getidsofnames(
+ IDispatchEx *This,
+ /* [in] */ REFIID riid,
+ /* [size_is][in] */ LPOLESTR *rgszNames,
+ /* [in] */ UINT cNames,
+ /* [in] */ LCID lcid,
+ /* [size_is][out] */ DISPID *rgDispId)
+{
+ UINT i;
+ HRESULT ret = S_OK;
+ TSRMLS_FETCH();
+ FETCH_DISP("GetIDsOfNames");
+
+ for (i = 0; i < cNames; i++) {
+ char *name;
+ unsigned int namelen;
+ zval *tmp;
+
+ name = php_OLECHAR_to_char(rgszNames[i], &namelen, CP_ACP TSRMLS_CC);
+
+ /* Lookup the name in the hash */
+ if (zend_hash_find(&disp->name_to_dispid, name, namelen+1, (void**)&tmp) == FAILURE) {
+ ret = DISP_E_UNKNOWNNAME;
+ rgDispId[i] = 0;
+ } else {
+ rgDispId[i] = Z_LVAL_P(tmp);
+ }
+
+ efree(name);
+
+ }
+
+ return ret;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_invoke(
+ IDispatchEx *This,
+ /* [in] */ DISPID dispIdMember,
+ /* [in] */ REFIID riid,
+ /* [in] */ LCID lcid,
+ /* [in] */ WORD wFlags,
+ /* [out][in] */ DISPPARAMS *pDispParams,
+ /* [out] */ VARIANT *pVarResult,
+ /* [out] */ EXCEPINFO *pExcepInfo,
+ /* [out] */ UINT *puArgErr)
+{
+ return This->lpVtbl->InvokeEx(This, dispIdMember,
+ lcid, wFlags, pDispParams,
+ pVarResult, pExcepInfo, NULL);
+}
+
+static HRESULT STDMETHODCALLTYPE disp_getdispid(
+ IDispatchEx *This,
+ /* [in] */ BSTR bstrName,
+ /* [in] */ DWORD grfdex,
+ /* [out] */ DISPID *pid)
+{
+ HRESULT ret = DISP_E_UNKNOWNNAME;
+ char *name;
+ unsigned int namelen;
+ zval *tmp;
+ TSRMLS_FETCH();
+ FETCH_DISP("GetDispID");
+
+ name = php_OLECHAR_to_char(bstrName, &namelen, CP_ACP TSRMLS_CC);
+
+ /* Lookup the name in the hash */
+ if (zend_hash_find(&disp->name_to_dispid, name, namelen+1, (void**)&tmp) == SUCCESS) {
+ *pid = Z_LVAL_P(tmp);
+ ret = S_OK;
+ }
+
+ efree(name);
+
+ return ret;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_invokeex(
+ IDispatchEx *This,
+ /* [in] */ DISPID id,
+ /* [in] */ LCID lcid,
+ /* [in] */ WORD wFlags,
+ /* [in] */ DISPPARAMS *pdp,
+ /* [out] */ VARIANT *pvarRes,
+ /* [out] */ EXCEPINFO *pei,
+ /* [unique][in] */ IServiceProvider *pspCaller)
+{
+ zval *name;
+ UINT i;
+ int codepage = CP_ACP;
+ zval **retval = NULL;
+ zval ***params = NULL;
+ TSRMLS_FETCH();
+ FETCH_DISP("InvokeEx");
+
+ if (SUCCESS == zend_hash_index_find(&disp->dispid_to_name, id, (void**)&name)) {
+ /* TODO: add support for overloaded objects */
+
+ trace("-- Invoke: %d %s\n", id, Z_STRVAL_P(name));
+
+ /* convert args into zvals.
+ * Args are in reverse order */
+ params = (zval ***)emalloc(sizeof(zval **) * pdp->cArgs);
+ for (i = 0; i < pdp->cArgs; i++) {
+ ALLOC_INIT_ZVAL(*params[i]);
+
+ if (V_VT(&pdp->rgvarg[pdp->cArgs-i]) == VT_DISPATCH) {
+ php_COM_object_from_dispatch(V_DISPATCH(&pdp->rgvarg[pdp->cArgs-i]), *params[i] TSRMLS_CC);
+ } else {
+ ZVAL_VARIANT(*params[i], &pdp->rgvarg[pdp->cArgs-i]);
+ }
+ }
+
+ if (wFlags & DISPATCH_PROPERTYGET) {
+ zend_hash_find(Z_OBJPROP_P(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name)+1, (void**)&retval);
+ } else if (wFlags & DISPATCH_PROPERTYPUT) {
+ add_property_zval(disp->object, Z_STRVAL_P(name), *params[0]);
+ } else if (wFlags & DISPATCH_METHOD) {
+
+ call_user_function_ex(EG(function_table), &disp->object, name,
+ retval, pdp->cArgs, params, 1, NULL TSRMLS_CC);
+ }
+
+ /* release arguments */
+ for (i = 0; i < pdp->cArgs; i++)
+ zval_ptr_dtor(params[i]);
+
+ /* return value */
+ if (retval) {
+ if (pvarRes) {
+ if (Z_TYPE_PP(retval) == IS_OBJECT) {
+ /* export the object using a dispatch like ourselves */
+ VariantInit(pvarRes);
+ V_VT(pvarRes) = VT_DISPATCH;
+ V_DISPATCH(pvarRes) = php_COM_export_object(*retval TSRMLS_CC);
+ } else {
+ php_pval_to_variant(*retval, pvarRes, codepage TSRMLS_CC);
+ }
+ }
+ zval_ptr_dtor(retval);
+ } else if (pvarRes) {
+ VariantInit(pvarRes);
+ }
+
+ return S_OK;
+ } else {
+ trace("InvokeEx: I don't support DISPID=%d\n", id);
+ }
+
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_deletememberbyname(
+ IDispatchEx *This,
+ /* [in] */ BSTR bstrName,
+ /* [in] */ DWORD grfdex)
+{
+ FETCH_DISP("DeleteMemberByName");
+
+ return S_FALSE;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_deletememberbydispid(
+ IDispatchEx *This,
+ /* [in] */ DISPID id)
+{
+ FETCH_DISP("DeleteMemberByDispID");
+
+ return S_FALSE;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_getmemberproperties(
+ IDispatchEx *This,
+ /* [in] */ DISPID id,
+ /* [in] */ DWORD grfdexFetch,
+ /* [out] */ DWORD *pgrfdex)
+{
+ FETCH_DISP("GetMemberProperties");
+
+ return DISP_E_UNKNOWNNAME;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_getmembername(
+ IDispatchEx *This,
+ /* [in] */ DISPID id,
+ /* [out] */ BSTR *pbstrName)
+{
+ zval *name;
+ TSRMLS_FETCH();
+ FETCH_DISP("GetMemberName");
+
+ if (SUCCESS == zend_hash_index_find(&disp->dispid_to_name, id, (void**)&name)) {
+ OLECHAR *olestr = php_char_to_OLECHAR(Z_STRVAL_P(name), Z_STRLEN_P(name), CP_ACP TSRMLS_CC);
+ *pbstrName = SysAllocString(olestr);
+ efree(olestr);
+ return S_OK;
+ } else {
+ return DISP_E_UNKNOWNNAME;
+ }
+}
+
+static HRESULT STDMETHODCALLTYPE disp_getnextdispid(
+ IDispatchEx *This,
+ /* [in] */ DWORD grfdex,
+ /* [in] */ DISPID id,
+ /* [out] */ DISPID *pid)
+{
+ ulong next = id+1;
+ FETCH_DISP("GetNextDispID");
+
+ while(!zend_hash_index_exists(&disp->dispid_to_name, next))
+ next++;
+
+ if (zend_hash_index_exists(&disp->dispid_to_name, next)) {
+ *pid = next;
+ return S_OK;
+ }
+ return S_FALSE;
+}
+
+static HRESULT STDMETHODCALLTYPE disp_getnamespaceparent(
+ IDispatchEx *This,
+ /* [out] */ IUnknown **ppunk)
+{
+ FETCH_DISP("GetNameSpaceParent");
+
+ *ppunk = NULL;
+ return E_NOTIMPL;
+}
+
+static struct IDispatchExVtbl php_dispatch_vtbl = {
+ disp_queryinterface,
+ disp_addref,
+ disp_release,
+ disp_gettypeinfocount,
+ disp_gettypeinfo,
+ disp_getidsofnames,
+ disp_invoke,
+ disp_getdispid,
+ disp_invokeex,
+ disp_deletememberbyname,
+ disp_deletememberbydispid,
+ disp_getmemberproperties,
+ disp_getmembername,
+ disp_getnextdispid,
+ disp_getnamespaceparent
+};
+
+
+/* enumerate functions and properties of the object and assign
+ * dispatch ids */
+static void update_dispids(php_dispatchex *disp TSRMLS_DC)
+{
+ HashPosition pos;
+ char *name = NULL;
+ zval *tmp;
+ int namelen;
+ int keytype;
+ ulong pid;
+
+ /* properties */
+ zend_hash_internal_pointer_reset_ex(Z_OBJPROP_PP(&disp->object), &pos);
+ while (HASH_KEY_NON_EXISTANT != (keytype =
+ zend_hash_get_current_key_ex(Z_OBJPROP_PP(&disp->object), &name, &namelen, &pid, 0, &pos))) {
+ char namebuf[32];
+ if (keytype == HASH_KEY_IS_LONG) {
+ sprintf(namebuf, "%d", pid);
+ name = namebuf;
+ namelen = strlen(namebuf);
+ }
+
+ zend_hash_move_forward_ex(Z_OBJPROP_PP(&disp->object), &pos);
+
+ /* Find the existing id */
+ if (zend_hash_find(&disp->name_to_dispid, name, namelen+1, (void**)&tmp) == SUCCESS)
+ continue;
+
+ /* add the mappings */
+ MAKE_STD_ZVAL(tmp);
+ ZVAL_STRINGL(tmp, name, namelen, 1);
+ zend_hash_index_update(&disp->dispid_to_name, pid, (void*)&tmp, sizeof(zval *), NULL);
+
+ MAKE_STD_ZVAL(tmp);
+ ZVAL_LONG(tmp, pid);
+ zend_hash_update(&disp->name_to_dispid, name, namelen+1, (void*)&tmp, sizeof(zval *), NULL);
+
+ }
+
+ /* functions */
+ zend_hash_internal_pointer_reset_ex(&Z_OBJCE_PP(&disp->object)->function_table, &pos);
+ while (HASH_KEY_NON_EXISTANT != (keytype =
+ zend_hash_get_current_key_ex(&Z_OBJCE_PP(&disp->object)->function_table, &name, &namelen, &pid, 0, &pos))) {
+
+ char namebuf[32];
+ if (keytype == HASH_KEY_IS_LONG) {
+ sprintf(namebuf, "%d", pid);
+ name = namebuf;
+ namelen = strlen(namebuf);
+ }
+
+ zend_hash_move_forward_ex(Z_OBJPROP_PP(&disp->object), &pos);
+
+ /* Find the existing id */
+ if (zend_hash_find(&disp->name_to_dispid, name, namelen+1, (void**)&tmp) == SUCCESS)
+ continue;
+
+ /* add the mappings */
+ MAKE_STD_ZVAL(tmp);
+ ZVAL_STRINGL(tmp, name, namelen, 1);
+ zend_hash_index_update(&disp->dispid_to_name, pid, (void*)&tmp, sizeof(zval *), NULL);
+
+ MAKE_STD_ZVAL(tmp);
+ ZVAL_LONG(tmp, pid);
+ zend_hash_update(&disp->name_to_dispid, name, namelen+1, (void*)&tmp, sizeof(zval *), NULL);
+ }
+}
+
+static php_dispatchex *disp_constructor(zval *object TSRMLS_DC)
+{
+ php_dispatchex *disp = (php_dispatchex*)CoTaskMemAlloc(sizeof(php_dispatchex));
+
+ if (disp == NULL)
+ return NULL;
+
+ memset(disp, 0, sizeof(php_dispatchex));
+
+ disp->engine_thread = tsrm_thread_id();
+ disp->lpVtbl = &php_dispatch_vtbl;
+ disp->refcount = 1;
+
+ zend_hash_init(&disp->dispid_to_name, 0, NULL, NULL, TRUE);
+ zend_hash_init(&disp->name_to_dispid, 0, NULL, NULL, TRUE);
+
+ if (object)
+ ZVAL_ADDREF(object);
+ disp->object = object;
+
+ update_dispids(disp TSRMLS_CC);
+
+ disp->id = zend_list_insert(disp, le_dispatch);
+
+ return disp;
+}
+
+static void disp_destructor(php_dispatchex *disp)
+{
+ TSRMLS_FETCH();
+
+ trace("destroying COM wrapper for PHP object %s\n", Z_OBJCE_P(disp->object)->name);
+
+ disp->id = 0;
+
+ if (disp->refcount > 0)
+ CoDisconnectObject((IUnknown*)disp, 0);
+
+ zend_hash_destroy(&disp->dispid_to_name);
+ zend_hash_destroy(&disp->name_to_dispid);
+
+ if (disp->object)
+ zval_ptr_dtor(&disp->object);
+
+
+ CoTaskMemFree(disp);
+}
+
+
+PHPAPI IDispatch *php_COM_export_object(zval *val TSRMLS_DC)
+{
+ if (Z_TYPE_P(val) != IS_OBJECT)
+ return NULL;
+
+ if (Z_OBJCE_P(val) == &COM_class_entry) {
+ /* pass back it's IDispatch directly */
+ zval **tmp;
+ comval *obj;
+ int type;
+
+ zend_hash_index_find(Z_OBJPROP_P(val), 0, (void**)&tmp);
+ obj = (comval *)zend_list_find(Z_LVAL_PP(tmp), &type);
+ if (type != IS_COM)
+ return NULL;
+
+ C_DISPATCH(obj)->lpVtbl->AddRef(C_DISPATCH(obj));
+ return C_DISPATCH(obj);
+ }
+ return (IDispatch*)disp_constructor(val TSRMLS_CC);
+}
+
+
diff --git a/ext/rpc/com/php_com.h b/ext/rpc/com/php_com.h
index 5c0155515b..396df9c93c 100644
--- a/ext/rpc/com/php_com.h
+++ b/ext/rpc/com/php_com.h
@@ -31,6 +31,12 @@ PHPAPI int php_COM_get_le_comval();
PHPAPI int php_COM_set_property_handler(zend_property_reference *property_reference, pval *value);
PHPAPI pval php_COM_get_property_handler(zend_property_reference *property_reference);
PHPAPI void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference);
+PHPAPI zval *php_COM_object_from_dispatch(IDispatch *disp, zval *val TSRMLS_DC);
+PHPAPI int php_COM_load_typelib(ITypeLib *TypeLib, int mode TSRMLS_DC);
+
+/* dispatch.c */
+PHPAPI IDispatch *php_COM_export_object(zval *val TSRMLS_DC);
+int php_COM_dispatch_init(int module_number TSRMLS_DC);
zend_module_entry COM_module_entry;
zend_class_entry COM_class_entry;
@@ -43,6 +49,18 @@ END_EXTERN_C()
#define phpext_com_ptr &COM_module_entry
+ZEND_BEGIN_MODULE_GLOBALS(com)
+ int nothing;
+ZEND_END_MODULE_GLOBALS(com)
+
+PHPAPI ZEND_EXTERN_MODULE_GLOBALS(com);
+
+#ifdef ZTS
+#define COMG(v) TSRMG(com_globals_id, zend_com_globals *, v)
+#else
+#define COMG(v) (com_globals.v)
+#endif
+
#else
#define phpext_com_ptr NULL