]> granicus.if.org Git - php/commitdiff
@Using ITypeInfo instead of IDispatch if possible. This makes DCOM calls
authorHarald Radi <phanto@php.net>
Tue, 20 Mar 2001 22:35:30 +0000 (22:35 +0000)
committerHarald Radi <phanto@php.net>
Tue, 20 Mar 2001 22:35:30 +0000 (22:35 +0000)
@and even COM calls much faster.
@All ini settings are now prefixed by 'com.'.
@Now you need not provide a path to the file containing the typelib, you can
@also provide the GUID of the TypeLib - entry or an IID for preloading
@type - information. (phanto)
memory leak was reportet, i'm not sure that it is fixed by now, but it should be.

ext/com/COM.c
ext/com/VARIANT.c
ext/com/com.h [new file with mode: 0644]
ext/com/php_COM.h
ext/rpc/com/com_wrapper.c
ext/rpc/com/com_wrapper.h [new file with mode: 0644]
ext/rpc/com/php_com.h
ext/rpc/com/variant.c

index a95891324e47c1f8b12ceaaddbbbbf25a3f5387a..9ed09eb8d467f99bb4eccbde39580ed374e5c3a2 100644 (file)
 
 #define _WIN32_DCOM
 
-#ifdef CP_THREAD_ACP
-#define PHP_COM_CODEPAGE CP_THREAD_ACP
-#else
-#define PHP_COM_CODEPAGE CP_ACP
-#endif
-
 #include <iostream.h>
 #include <math.h>
 
 #include "php.h"
 #include "php_ini.h"
+#include "com.h"
 
 #include "conversion.h"
-#include "unknwn.h"
-
-BEGIN_EXTERN_C()
 
 zend_class_entry com_class_entry;
 
-END_EXTERN_C()
-
 PHP_FUNCTION(COM_load);
 PHP_FUNCTION(COM_invoke);
 PHP_FUNCTION(com_propget);
@@ -101,27 +91,94 @@ static PHP_MINFO_FUNCTION(COM)
 
 static int php_COM_load_typelib(char *typelib_name, int mode);
 
+PHPAPI HRESULT php_COM_invoke(i_dispatch *obj, DISPID dispIdMember, WORD wFlags, DISPPARAMS FAR*  pDispParams, VARIANT FAR*  pVarResult)
+{
+       if(obj->typelib) {
+               return obj->i.dispatch->lpVtbl->Invoke(obj->i.dispatch, dispIdMember, &IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                                                                                          wFlags, pDispParams, pVarResult, NULL, NULL);
+       } else {
+               return obj->i.typeinfo->lpVtbl->Invoke(obj->i.typeinfo, obj->i.dispatch, dispIdMember,
+                                                                                          wFlags, pDispParams, pVarResult, NULL, NULL);
+       }
+}
+
+PHPAPI HRESULT php_COM_get_ids_of_names(i_dispatch *obj, OLECHAR FAR* FAR* rgszNames, DISPID FAR* rgDispId)
+{
+       if(obj->typelib) {
+               return obj->i.dispatch->lpVtbl->GetIDsOfNames(obj->i.dispatch, &IID_NULL, rgszNames, 1, LOCALE_SYSTEM_DEFAULT, rgDispId);
+       } else {
+               return obj->i.typeinfo->lpVtbl->GetIDsOfNames(obj->i.typeinfo, rgszNames, 1, rgDispId);
+       }
+}
+
+PHPAPI HRESULT php_COM_release(i_dispatch *obj)
+{
+       HRESULT hr;
+       
+       hr = obj->i.dispatch->lpVtbl->Release(obj->i.dispatch);
+       obj->i.dispatch = NULL;
+       obj->i.typeinfo = NULL;
+       obj->typelib = FALSE;
+
+       return hr;
+}
+
+PHPAPI HRESULT php_COM_set(i_dispatch *obj, IDispatch FAR* pDisp, int cleanup)
+{
+       HRESULT hr;
+
+       obj->i.dispatch = pDisp;
+       obj->typelib = !FAILED(obj->i.dispatch->lpVtbl->GetTypeInfo(obj->i.dispatch, 0, LANG_NEUTRAL, &obj->i.typeinfo));
+
+       if(cleanup) {
+               pDisp = NULL;
+       } else {
+               hr = obj->i.dispatch->lpVtbl->AddRef(obj->i.dispatch);
+       }
+
+       return hr;
+}
+
+PHPAPI HRESULT php_COM_clone(i_dispatch *obj, i_dispatch *clone, int cleanup)
+{
+       HRESULT hr;
+
+       obj->typelib = clone->typelib;
+       obj->i.dispatch = clone->i.dispatch;
+       obj->i.typeinfo = clone->i.typeinfo;
+
+       if(cleanup) {
+               obj->i.dispatch = NULL;
+               obj->i.typeinfo = NULL;
+               obj->typelib = FALSE;
+       } else {
+               hr = obj->i.dispatch->lpVtbl->AddRef(obj->i.dispatch);
+       }
+
+       return hr;
+}
+
 PHPAPI char *php_COM_error_message(HRESULT hr)
 {
-       char *pMsgBuf;
+       void *pMsgBuf;
 
        if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
                hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pMsgBuf, 0, NULL)) {
                char error_string[] = "No description available";
                
-               pMsgBuf = (char *) LocalAlloc(LMEM_FIXED, sizeof(error_string));
+               pMsgBuf = LocalAlloc(LMEM_FIXED, sizeof(error_string));
                memcpy(pMsgBuf, error_string, sizeof(error_string));
        }
 
        return pMsgBuf;
 }
 
-static char *php_string_from_clsid(const CLSID clsid)
+static char *php_string_from_clsid(const CLSID *clsid)
 {
        LPOLESTR ole_clsid;
        char *clsid_str;
 
-       StringFromCLSID(&clsid, &ole_clsid);
+       StringFromCLSID(clsid, &ole_clsid);
        clsid_str = php_OLECHAR_to_char(ole_clsid, NULL, 0, codepage);
        LocalFree(ole_clsid);
 
@@ -130,9 +187,9 @@ static char *php_string_from_clsid(const CLSID clsid)
 
 static void php_idispatch_destructor(zend_rsrc_list_entry *rsrc)
 {
-       IDispatch *i_dispatch = (IDispatch *)rsrc->ptr;
-
-       i_dispatch->lpVtbl->Release(i_dispatch);
+       i_dispatch *obj = (i_dispatch *)rsrc->ptr;
+       php_COM_release(obj);
+       efree(obj);
 }
 
 static PHP_INI_MH(OnTypelibFileChange)
@@ -199,12 +256,12 @@ static PHP_INI_MH(OnTypelibFileChange)
 
 
 PHP_INI_BEGIN()
-       PHP_INI_ENTRY1_EX("allow_dcom",         "0",            PHP_INI_SYSTEM,         NULL,                                   NULL,   php_ini_boolean_displayer_cb)
-       PHP_INI_ENTRY1("typelib_file",          NULL,           PHP_INI_SYSTEM,         OnTypelibFileChange,    NULL)
+       PHP_INI_ENTRY_EX("com.allow_dcom", "0", PHP_INI_SYSTEM, NULL, php_ini_boolean_displayer_cb)
+       PHP_INI_ENTRY("com.typelib_file", "", PHP_INI_SYSTEM, OnTypelibFileChange)
 PHP_INI_END()
 
 
-/* {{{ proto int com_load(string module_name)
+/* {{{ proto int com_load(string module_name [, string remote_host [, int codepage]])
    Loads a COM module */
 PHP_FUNCTION(COM_load)
 {
@@ -212,7 +269,7 @@ PHP_FUNCTION(COM_load)
        CLSID clsid;
        HRESULT hr;
        OLECHAR *ProgID;
-       IDispatch *i_dispatch;
+       i_dispatch *obj;
        char *error_message;
        char *clsid_str;
 
@@ -222,7 +279,7 @@ PHP_FUNCTION(COM_load)
                        codepage = CP_ACP;
                        break;
                case 2:
-                       if (!INI_INT("allow_dcom")) {
+                       if (!INI_INT("com.allow_dcom")) {
                                php_error(E_WARNING, "DCOM is disabled");
                                RETURN_FALSE;
                        }
@@ -237,7 +294,7 @@ PHP_FUNCTION(COM_load)
                                efree(server_name);
                                server_name = NULL;
                        } else {
-                               if (!INI_INT("allow_dcom")) {
+                               if (!INI_INT("com.allow_dcom")) {
                                        php_error(E_WARNING, "DCOM is disabled");
                                        RETURN_FALSE;
                                }
@@ -254,7 +311,7 @@ PHP_FUNCTION(COM_load)
 
        convert_to_string(module_name);
        ProgID = php_char_to_OLECHAR(module_name->value.str.val, module_name->value.str.len, codepage);
-       hr = CLSIDFromProgID(ProgID, &clsid);
+       hr=CLSIDFromProgID(ProgID, &clsid);
        efree(ProgID);
 
        /* obtain CLSID */
@@ -265,9 +322,12 @@ PHP_FUNCTION(COM_load)
                RETURN_FALSE;
        }
 
+       obj = (i_dispatch *) emalloc(sizeof(i_dispatch));
+
        /* obtain IDispatch */
        if (!server_name) {
-               hr = CoCreateInstance(&clsid, NULL, CLSCTX_SERVER, &IID_IDispatch, (LPVOID *) &i_dispatch);
+               hr = CoCreateInstance(&clsid, NULL, CLSCTX_SERVER, &IID_IDispatch, (LPVOID *) &(obj->i.dispatch));
+               php_COM_set(obj, obj->i.dispatch, TRUE);
        } else {
                COSERVERINFO server_info;
                MULTI_QI pResults;
@@ -283,27 +343,28 @@ PHP_FUNCTION(COM_load)
                hr=CoCreateInstanceEx(&clsid, NULL, CLSCTX_SERVER, &server_info, 1, &pResults);
                if (SUCCEEDED(hr)) {
                        hr = pResults.hr;
-                       i_dispatch = (IDispatch *) pResults.pItf;
+                       obj->i.dispatch = (IDispatch *) pResults.pItf;
+                       php_COM_set(obj, obj->i.dispatch, TRUE);
                }
                efree(server_info.pwszName);
        }
 
        if (FAILED(hr)) {
                error_message = php_COM_error_message(hr);
-               clsid_str = php_string_from_clsid(clsid);
+               clsid_str = php_string_from_clsid(&clsid);
                php_error(E_WARNING,"Unable to obtain IDispatch interface for CLSID %s:  %s",clsid_str,error_message);
                LocalFree(error_message);
                efree(clsid_str);
+               efree(obj);
                RETURN_FALSE;
        }
 
-
-       RETURN_LONG(zend_list_insert(i_dispatch,le_idispatch));
+       RETURN_LONG(zend_list_insert(obj, le_idispatch));
 }
 /* }}} */
 
 
-int do_COM_invoke(IDispatch *i_dispatch, pval *function_name, VARIANTARG *var_result, pval **arguments, int arg_count)
+int do_COM_invoke(i_dispatch *obj, pval *function_name, VARIANTARG *var_result, pval **arguments, int arg_count)
 {
        DISPID dispid;
        HRESULT hr;
@@ -315,7 +376,7 @@ int do_COM_invoke(IDispatch *i_dispatch, pval *function_name, VARIANTARG *var_re
 
        funcname = php_char_to_OLECHAR(function_name->value.str.val, function_name->value.str.len, codepage);
 
-       hr = i_dispatch->lpVtbl->GetIDsOfNames(i_dispatch, &IID_NULL, &funcname, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
+       hr = php_COM_get_ids_of_names(obj, &funcname, &dispid);
 
        if (FAILED(hr)) {
                error_message = php_COM_error_message(hr);
@@ -337,9 +398,7 @@ int do_COM_invoke(IDispatch *i_dispatch, pval *function_name, VARIANTARG *var_re
        dispparams.cArgs = arg_count;
        dispparams.cNamedArgs = 0;
 
-       hr = i_dispatch->lpVtbl->Invoke(i_dispatch, dispid, &IID_NULL,
-                                                       LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD|DISPATCH_PROPERTYGET,
-                                                       &dispparams, var_result, NULL, NULL);
+       hr = php_COM_invoke(obj, dispid, DISPATCH_METHOD|DISPATCH_PROPERTYGET, &dispparams, var_result);
 
        if (FAILED(hr)) {
                error_message = php_COM_error_message(hr);
@@ -362,7 +421,7 @@ PHP_FUNCTION(COM_invoke)
 {
        pval **arguments;
        pval *object, *function_name;
-       IDispatch *i_dispatch;
+       i_dispatch *obj;
        int type;
        int arg_count = ZEND_NUM_ARGS();
        VARIANTARG var_result;
@@ -378,10 +437,10 @@ PHP_FUNCTION(COM_invoke)
        object = arguments[0];
        function_name = arguments[1];
 
-       /* obtain i_dispatch interface */
+       /* obtain IDispatch interface */
        convert_to_long(object);
-       i_dispatch = (IDispatch *)zend_list_find(object->value.lval, &type);
-       if (!i_dispatch || (type!=le_idispatch)) {
+       obj = (i_dispatch *)zend_list_find(object->value.lval, &type);
+       if (!obj || (type!=le_idispatch)) {
                php_error(E_WARNING,"%d is not a COM object handler", function_name->value.str.val);
                RETURN_FALSE;
        }
@@ -389,7 +448,7 @@ PHP_FUNCTION(COM_invoke)
        /* obtain property/method handler */
        convert_to_string(function_name);
 
-       if (do_COM_invoke(i_dispatch, function_name, &var_result, arguments+2, arg_count-2)==FAILURE) {
+       if (do_COM_invoke(obj, function_name, &var_result, arguments+2, arg_count-2)==FAILURE) {
                RETURN_FALSE;
        }
        efree(arguments);
@@ -403,16 +462,21 @@ static int do_COM_offget(VARIANTARG *var_result, VARIANTARG *array, pval *arg_pr
        switch (array->vt) {
                case VT_DISPATCH:       {       /* a Collection, possibly */
                        pval function_name;
-                       IDispatch *i_dispatch = array->pdispVal;
+                       i_dispatch *obj;
                        int retval;
 
+                       obj = (i_dispatch *) emalloc(sizeof(i_dispatch));
+                       php_COM_set(obj, array->pdispVal, TRUE);
+
                        function_name.value.str.val = "Item";
                        function_name.value.str.len = 4;
                        function_name.type = IS_STRING;
-                       retval = do_COM_invoke(i_dispatch, &function_name, var_result, &arg_property, 1);
+                       retval = do_COM_invoke(obj, &function_name, var_result, &arg_property, 1);
                        if (cleanup) {
-                               i_dispatch->lpVtbl->Release(i_dispatch);
+                               php_COM_release(obj);
                        }
+                       efree(obj);
+
                        return retval;
                }
        }
@@ -420,7 +484,7 @@ static int do_COM_offget(VARIANTARG *var_result, VARIANTARG *array, pval *arg_pr
 }
 
 
-static int do_COM_propget(VARIANTARG *var_result, IDispatch *i_dispatch, pval *arg_property, int cleanup)
+static int do_COM_propget(VARIANTARG *var_result, i_dispatch *obj, pval *arg_property, int cleanup)
 {
        DISPID dispid;
        HRESULT hr;
@@ -432,7 +496,7 @@ static int do_COM_propget(VARIANTARG *var_result, IDispatch *i_dispatch, pval *a
        /* obtain property handler */
        propname = php_char_to_OLECHAR(arg_property->value.str.val, arg_property->value.str.len, codepage);
 
-       hr = i_dispatch->lpVtbl->GetIDsOfNames(i_dispatch, &IID_NULL, &propname, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
+       hr = php_COM_get_ids_of_names(obj, &propname, &dispid);
 
        if (FAILED(hr)) {
                error_message = php_COM_error_message(hr);
@@ -440,7 +504,7 @@ static int do_COM_propget(VARIANTARG *var_result, IDispatch *i_dispatch, pval *a
                LocalFree(error_message);
                efree(propname);
                if (cleanup) {
-                       i_dispatch->lpVtbl->Release(i_dispatch);
+                       php_COM_release(obj);
                }
                return FAILURE;
        }
@@ -448,7 +512,7 @@ static int do_COM_propget(VARIANTARG *var_result, IDispatch *i_dispatch, pval *a
        dispparams.cArgs = 0;
        dispparams.cNamedArgs = 0;
 
-       hr = i_dispatch->lpVtbl->Invoke(i_dispatch, dispid, &IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispparams, var_result, NULL, 0);
+       hr = php_COM_invoke(obj, dispid, DISPATCH_PROPERTYGET, &dispparams, var_result);
 
        if (FAILED(hr)) {
                error_message = php_COM_error_message(hr);
@@ -456,35 +520,37 @@ static int do_COM_propget(VARIANTARG *var_result, IDispatch *i_dispatch, pval *a
                LocalFree(error_message);
                efree(propname);
                if (cleanup) {
-                       i_dispatch->lpVtbl->Release(i_dispatch);
+                       php_COM_release(obj);
                }
                return FAILURE;
        }
 
        efree(propname);
        if (cleanup) {
-               i_dispatch->lpVtbl->Release(i_dispatch);
+               php_COM_release(obj);
        }
        return SUCCESS;
 }
 
 
-static void do_COM_propput(pval *return_value, IDispatch *i_dispatch, pval *arg_property, pval *value)
+static void do_COM_propput(pval *return_value, i_dispatch *obj, pval *arg_property, pval *value)
 {
        DISPID dispid;
        HRESULT hr;
        OLECHAR *propname;
        char *error_message;
-       VARIANTARG var_result;
+       VARIANT *var_result;
        DISPPARAMS dispparams;
        VARIANTARG new_value;
        DISPID mydispid = DISPID_PROPERTYPUT;
 
 
+       var_result = emalloc(sizeof(VARIANT));
+       
        /* obtain property handler */
        propname = php_char_to_OLECHAR(arg_property->value.str.val, arg_property->value.str.len, codepage);
 
-       hr = i_dispatch->lpVtbl->GetIDsOfNames(i_dispatch, &IID_NULL, &propname, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
+       hr = php_COM_get_ids_of_names(obj, &propname, &dispid);
 
        if (FAILED(hr)) {
                error_message = php_COM_error_message(hr);
@@ -494,16 +560,14 @@ static void do_COM_propput(pval *return_value, IDispatch *i_dispatch, pval *arg_
                RETURN_FALSE;
        }
 
-
        php_pval_to_variant(value, &new_value, codepage);
        dispparams.rgvarg = &new_value;
        dispparams.rgdispidNamedArgs = &mydispid;
        dispparams.cArgs = 1;
        dispparams.cNamedArgs = 1;
 
-       hr = i_dispatch->lpVtbl->Invoke(i_dispatch, dispid, &IID_NULL,
-                                                       LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT,
-                                                       &dispparams, NULL, NULL, 0);
+       hr = php_COM_invoke(obj, dispid, DISPATCH_PROPERTYPUT, &dispparams, NULL);
+
        if (FAILED(hr)) {
                error_message = php_COM_error_message(hr);
                php_error(E_WARNING,"PropPut() failed:  %s\n", error_message);
@@ -515,18 +579,16 @@ static void do_COM_propput(pval *return_value, IDispatch *i_dispatch, pval *arg_
        dispparams.cArgs = 0;
        dispparams.cNamedArgs = 0;
 
-       hr = i_dispatch->lpVtbl->Invoke(i_dispatch, dispid, &IID_NULL,
-                                                                       LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET,
-                                                                       &dispparams, &var_result, NULL, 0);
-
+       hr = php_COM_invoke(obj, dispid, DISPATCH_PROPERTYGET, &dispparams, var_result);
 
        if (SUCCEEDED(hr)) {
-               php_variant_to_pval(&var_result, return_value, 0, codepage);
+               php_variant_to_pval(var_result, return_value, 0, codepage);
        } else {
                *return_value = *value;
                zval_copy_ctor(return_value);
        }
 
+       efree(var_result);
        efree(propname);
 }
 
@@ -537,23 +599,22 @@ PHP_FUNCTION(com_propget)
 {
        pval *arg_idispatch, *arg_property;
        int type;
-       IDispatch *i_dispatch;
+       i_dispatch *obj;
        VARIANTARG var_result;
 
        if (ZEND_NUM_ARGS()!=2 || getParameters(ht, 2, &arg_idispatch, &arg_property)==FAILURE) {
                WRONG_PARAM_COUNT;
        }
 
-       /* obtain i_dispatch interface */
+       /* obtain IDispatch interface */
        convert_to_long(arg_idispatch);
-       /* obtain i_dispatch interface */
-       i_dispatch = (IDispatch *)zend_list_find(arg_idispatch->value.lval,&type);
-       if (!i_dispatch || (type!=le_idispatch)) {
+       obj = (i_dispatch *)zend_list_find(arg_idispatch->value.lval,&type);
+       if (!obj || (type!=le_idispatch)) {
                php_error(E_WARNING,"%d is not a COM object handler", arg_idispatch->value.lval);
        }       
        convert_to_string(arg_property);
 
-       if (do_COM_propget(&var_result, i_dispatch, arg_property, 0)==FAILURE) {
+       if (do_COM_propget(&var_result, obj, arg_property, 0)==FAILURE) {
                RETURN_FALSE;
        }
        php_variant_to_pval(&var_result, return_value, 0, codepage);
@@ -567,7 +628,7 @@ PHP_FUNCTION(com_propput)
 {
        pval *arg_idispatch, *arg_property, *arg_value;
        int type;
-       IDispatch *i_dispatch;
+       i_dispatch *obj;
 
        if (ZEND_NUM_ARGS()!=3 || getParameters(ht, 3, &arg_idispatch, &arg_property, &arg_value)==FAILURE) {
                WRONG_PARAM_COUNT;
@@ -576,62 +637,72 @@ PHP_FUNCTION(com_propput)
        /* obtain i_dispatch interface */
        convert_to_long(arg_idispatch);
        /* obtain i_dispatch interface */
-       i_dispatch = (IDispatch *)zend_list_find(arg_idispatch->value.lval,&type);
-       if (!i_dispatch || (type!=le_idispatch)) {
+       obj = (i_dispatch *)zend_list_find(arg_idispatch->value.lval,&type);
+       if (!obj || (type!=le_idispatch)) {
                php_error(E_WARNING,"%d is not a COM object handler", arg_idispatch->value.lval);
        }       
        convert_to_string(arg_property);
 
-       do_COM_propput(return_value, i_dispatch, arg_property, arg_value);
+       do_COM_propput(return_value, obj, arg_property, arg_value);
 }
 /* }}} */
 
 
-VARIANTARG _php_COM_get_property_handler(zend_property_reference *property_reference)
+VARIANT *_php_COM_get_property_handler(zend_property_reference *property_reference)
 {
        zend_overloaded_element *overloaded_property;
        zend_llist_element *element;
        pval **idispatch_handle;
        pval *object = property_reference->object;
-       IDispatch *i_dispatch;
        int type;
-       VARIANTARG var_result;
+       VARIANT *var_result;
+       i_dispatch *obj, *obj_prop;
 
 
        /* fetch the IDispatch interface */
        zend_hash_index_find(object->value.obj.properties, 0, (void **) &idispatch_handle);
-       i_dispatch = (IDispatch *)zend_list_find((*idispatch_handle)->value.lval,&type);
-       if (!i_dispatch || (type!=le_idispatch)) {
-               var_result.vt = VT_EMPTY;
-               return var_result;
+       obj = (i_dispatch *) zend_list_find((*idispatch_handle)->value.lval, &type);
+       if (!obj || (type!=le_idispatch)) {
+               return NULL;
        }
 
-       var_result.vt = VT_DISPATCH;
-       var_result.pdispVal = i_dispatch;
+       obj_prop = (i_dispatch *) emalloc(sizeof(i_dispatch));
+       php_COM_clone(obj_prop, obj, FALSE);
+       
+       var_result = (VARIANT *) emalloc(sizeof(VARIANT));
+       var_result->vt = VT_DISPATCH;
+       var_result->pdispVal = obj_prop->i.dispatch;
 
        for (element=property_reference->elements_list->head; element; element=element->next) {
                overloaded_property = (zend_overloaded_element *) element->data;
                switch (overloaded_property->type) {
                        case OE_IS_ARRAY:
-                               if (do_COM_offget(&var_result, &var_result, &overloaded_property->element, element!=property_reference->elements_list->head)==FAILURE) {
-                                       var_result.vt = VT_EMPTY;
+                               if (do_COM_offget(var_result, var_result, &overloaded_property->element, element!=property_reference->elements_list->head)==FAILURE) {
+                                       var_result->vt = VT_EMPTY;
+                                       efree(obj_prop);
                                        return var_result;
                                }
-                               /*printf("Array offset:  ");*/
                                break;
+
                        case OE_IS_OBJECT:
-                               if (var_result.vt != VT_DISPATCH) {
-                                       var_result.vt = VT_EMPTY;
+                               if (var_result->vt != VT_DISPATCH) {
+                                       var_result->vt = VT_EMPTY;
+                                       efree(obj_prop);
                                        return var_result;
                                } else {
-                                       if (do_COM_propget(&var_result, var_result.pdispVal, &overloaded_property->element, element!=property_reference->elements_list->head)==FAILURE) {
-                                               var_result.vt = VT_EMPTY;
+                                       php_COM_set(obj_prop, var_result->pdispVal, TRUE);
+                                       if (do_COM_propget(var_result, obj_prop, &overloaded_property->element, element!=property_reference->elements_list->head)==FAILURE) {
+                                               var_result->vt = VT_EMPTY;
+                                               efree(obj_prop);
                                                return var_result;
                                        }
-                                       /*printf("Object property:  ");*/
+                                       
                                }
                                break;
+
                        case OE_IS_METHOD:
+                               var_result->pdispVal = obj_prop->i.dispatch;
+                               efree(obj_prop);
                                return var_result;
                                break;
                }
@@ -647,15 +718,17 @@ VARIANTARG _php_COM_get_property_handler(zend_property_reference *property_refer
                */
                pval_destructor(&overloaded_property->element);
        }
+       efree(obj_prop);
        return var_result;
 }
 
 PHPAPI pval php_COM_get_property_handler(zend_property_reference *property_reference)
 {
        pval result;
-       VARIANTARG var_result = _php_COM_get_property_handler(property_reference);
+       VARIANT *var_result = _php_COM_get_property_handler(property_reference);
 
-       php_variant_to_pval(&var_result, &result, 0, codepage);
+       php_variant_to_pval(var_result, &result, 0, codepage);
+       efree(var_result);
        return result;
 }
 
@@ -667,19 +740,19 @@ PHPAPI int php_COM_set_property_handler(zend_property_reference *property_refere
        zend_llist_element *element;
        pval **idispatch_handle;
        pval *object = property_reference->object;
-       IDispatch *i_dispatch;
+       i_dispatch *obj;
        int type;
        VARIANTARG var_result;
 
 
        /* fetch the IDispatch interface */
        zend_hash_index_find(object->value.obj.properties, 0, (void **) &idispatch_handle);
-       i_dispatch = (IDispatch *)zend_list_find((*idispatch_handle)->value.lval,&type);
-       if (!i_dispatch || (type!=le_idispatch)) {
+       obj = (i_dispatch *)zend_list_find((*idispatch_handle)->value.lval,&type);
+       if (!obj || (type!=le_idispatch)) {
                return FAILURE;
        }
        var_result.vt = VT_DISPATCH;
-       var_result.pdispVal = i_dispatch;
+       var_result.pdispVal = obj->i.dispatch;
 
        for (element=property_reference->elements_list->head; element && element!=property_reference->elements_list->tail; element=element->next) {
                overloaded_property = (zend_overloaded_element *) element->data;
@@ -691,7 +764,8 @@ PHPAPI int php_COM_set_property_handler(zend_property_reference *property_refere
                                if (var_result.vt != VT_DISPATCH) {
                                        return FAILURE;
                                } else {
-                                       do_COM_propget(&var_result, i_dispatch, &overloaded_property->element, element!=property_reference->elements_list->head);
+                                       // ??????
+                                       do_COM_propget(&var_result, obj, &overloaded_property->element, element!=property_reference->elements_list->head);
                                        /*printf("Object property:  ");*/
                                }
                                break;
@@ -715,9 +789,15 @@ PHPAPI int php_COM_set_property_handler(zend_property_reference *property_refere
        if (var_result.vt != VT_DISPATCH) {
                return FAILURE;
        }
+       obj = (i_dispatch *) emalloc(sizeof(i_dispatch));
+       obj->typelib = FALSE;
+       obj->i.dispatch = var_result.pdispVal;
+
        overloaded_property = (zend_overloaded_element *) element->data;
-       do_COM_propput(&result, var_result.pdispVal, &overloaded_property->element, value);
+       do_COM_propput(&result, obj, &overloaded_property->element, value);
        pval_destructor(&overloaded_property->element);
+       efree(obj);
+
        return SUCCESS;
 }
 
@@ -745,24 +825,26 @@ PHPAPI void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_pro
                zend_hash_index_update(object->value.obj.properties, 0, &object_handle, sizeof(pval *), NULL);
                pval_destructor(&function_name->element);
        } else {
-               VARIANTARG object_handle = _php_COM_get_property_handler(property_reference);
+               i_dispatch *obj;
                pval **arguments;
                int arg_count = ZEND_NUM_ARGS();
                VARIANTARG var_result;
 
                var_result.vt = VT_EMPTY;
 
-               if (object_handle.vt != VT_DISPATCH) {
-                       /* that shouldn't happen */
-                       return;
-               }
+               obj = (i_dispatch *) emalloc(sizeof(i_dispatch));
+               php_COM_set(obj, _php_COM_get_property_handler(property_reference)->pdispVal, TRUE);
                arguments = (pval **) emalloc(sizeof(pval *)*arg_count);
                getParametersArray(ht, arg_count, arguments);
 
-               if (do_COM_invoke((IDispatch *) object_handle.pdispVal, &function_name->element, &var_result, arguments, arg_count)==FAILURE) {
+               if (do_COM_invoke(obj , &function_name->element, &var_result, arguments, arg_count)==FAILURE) {
                        RETVAL_FALSE;
                }
+               
                pval_destructor(&function_name->element);
+               php_COM_release(obj);
+               efree(obj);
                efree(arguments);
                php_variant_to_pval(&var_result, return_value, 0, codepage);
        }
@@ -788,18 +870,52 @@ static int php_COM_load_typelib(char *typelib_name, int mode)
        ITypeLib *TypeLib;
        ITypeComp *TypeComp;
        OLECHAR *p;
+       CLSID clsid;
+       char *strtok_buf, *major, *minor;
        int i;
        int interfaces;
        ELS_FETCH();
 
+
+       typelib_name = php_strtok_r(typelib_name, ",", &strtok_buf);
+       major = php_strtok_r(NULL, ",", &strtok_buf);
+       minor = php_strtok_r(NULL, ",", &strtok_buf);
+       
        p = php_char_to_OLECHAR(typelib_name, strlen(typelib_name), codepage);
 
-       if (FAILED(LoadTypeLib(p, &TypeLib))) {
-               efree(p);
-               return FAILURE;
+       if (!FAILED(CLSIDFromString(p, &clsid))) {
+               HRESULT hr;
+
+               if (major && minor) {
+                       hr = LoadRegTypeLib((REFGUID) &clsid, 1, 0, LANG_NEUTRAL, &TypeLib);
+               }
+               
+               if (!major || !minor || FAILED(hr)) {
+                       IDispatch *i_dispatch;
+                       ITypeInfo *TypeInfo;
+                       int idx;
+
+                       if (FAILED(CoCreateInstance(&clsid, NULL, CLSCTX_SERVER, &IID_IDispatch, (LPVOID *) &i_dispatch))) {
+                               efree(p);
+                               return FAILURE;
+                       }
+                       if (FAILED(i_dispatch->lpVtbl->GetTypeInfo(i_dispatch, 0, LANG_NEUTRAL, &TypeInfo))) {
+                               efree(p);
+                               return FAILURE;
+                       }
+                       if (FAILED(TypeInfo->lpVtbl->GetContainingTypeLib(TypeInfo, &TypeLib, &idx))) {
+                               efree(p);
+                               return FAILURE;
+                       }
+               }
+       } else {
+               if (FAILED(LoadTypeLib(p, &TypeLib))) {
+                       efree(p);
+                       return FAILURE;
+               }
        }
 
-       interfaces = TypeLib->lpVtbl->GetTypeInfoCount(TypeLib);
+       interfaces = TypeLib->lpVtbl->GetTypeInfoCount(TypeLib);
 
        TypeLib->lpVtbl->GetTypeComp(TypeLib, &TypeComp);
        for (i=0; i<interfaces; i++) {
@@ -865,7 +981,6 @@ void php_register_COM_class()
        zend_register_internal_class(&com_class_entry);
 }
 
-
 PHP_MINIT_FUNCTION(COM)
 {
        CoInitialize(NULL);
@@ -883,7 +998,6 @@ PHP_MSHUTDOWN_FUNCTION(COM)
        return SUCCESS;
 }
 
-BEGIN_EXTERN_C()
 // exports for external object creation
 
 zend_module_entry COM_module_entry = {
@@ -894,6 +1008,4 @@ PHPAPI int php_COM_get_le_idispatch() {
        return le_idispatch;
 }
 
-END_EXTERN_C()
-
 #endif
index 5bc772e20d936b7379821b854a395ce87360e5a9..4c4657b2a03aeaa0fc3dd686663a63539c902a20 100644 (file)
@@ -69,38 +69,38 @@ PHP_MINIT_FUNCTION(VARIANT)
        le_variant = zend_register_list_destructors_ex(php_variant_destructor, NULL, "VARIANT", module_number);
 
        /* variant datatypes */
-       REGISTER_LONG_CONSTANT("VT_NULL", VT_NULL, 0);
-       REGISTER_LONG_CONSTANT("VT_EMPTY", VT_EMPTY, 0);
-       REGISTER_LONG_CONSTANT("VT_UI1", VT_UI1, 0);
-       REGISTER_LONG_CONSTANT("VT_I2", VT_I2, 0);
-       REGISTER_LONG_CONSTANT("VT_I4", VT_I4, 0);
-       REGISTER_LONG_CONSTANT("VT_R4", VT_R4, 0);
-       REGISTER_LONG_CONSTANT("VT_R8", VT_R8, 0);
-       REGISTER_LONG_CONSTANT("VT_BOOL", VT_BOOL, 0);
-       REGISTER_LONG_CONSTANT("VT_ERROR", VT_ERROR, 0);
-       REGISTER_LONG_CONSTANT("VT_CY", VT_CY, 0);
-       REGISTER_LONG_CONSTANT("VT_DATE", VT_CY, 0);
-       REGISTER_LONG_CONSTANT("VT_BSTR", VT_BSTR, 0);
-       REGISTER_LONG_CONSTANT("VT_DECIMAL", VT_DECIMAL, 0);
-       REGISTER_LONG_CONSTANT("VT_UNKNOWN", VT_UNKNOWN, 0);
-       REGISTER_LONG_CONSTANT("VT_DISPATCH", VT_DISPATCH, 0);
-       REGISTER_LONG_CONSTANT("VT_VARIANT", VT_VARIANT, 0);
-       REGISTER_LONG_CONSTANT("VT_I1", VT_I1, 0);
-       REGISTER_LONG_CONSTANT("VT_UI2", VT_UI2, 0);
-       REGISTER_LONG_CONSTANT("VT_UI4", VT_UI4, 0);
-       REGISTER_LONG_CONSTANT("VT_INT", VT_INT, 0);
-       REGISTER_LONG_CONSTANT("VT_UINT", VT_UINT, 0);
-       REGISTER_LONG_CONSTANT("VT_ARRAY", VT_ARRAY, 0);
-       REGISTER_LONG_CONSTANT("VT_BYREF", VT_BYREF, 0);
+       REGISTER_LONG_CONSTANT("VT_NULL", VT_NULL, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_EMPTY", VT_EMPTY, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_UI1", VT_UI1, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_I2", VT_I2, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_I4", VT_I4, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_R4", VT_R4, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_R8", VT_R8, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_BOOL", VT_BOOL, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_ERROR", VT_ERROR, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_CY", VT_CY, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_DATE", VT_CY, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_BSTR", VT_BSTR, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_DECIMAL", VT_DECIMAL, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_UNKNOWN", VT_UNKNOWN, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_DISPATCH", VT_DISPATCH, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_VARIANT", VT_VARIANT, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_I1", VT_I1, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_UI2", VT_UI2, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_UI4", VT_UI4, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_INT", VT_INT, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_UINT", VT_UINT, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_ARRAY", VT_ARRAY, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_BYREF", VT_BYREF, CONST_CS | CONST_PERSISTENT);
  
        /* codepages */
-       REGISTER_LONG_CONSTANT("CP_ACP", CP_ACP, 0);
-       REGISTER_LONG_CONSTANT("CP_MACCP", CP_MACCP, 0);
-       REGISTER_LONG_CONSTANT("CP_OEMCP", CP_OEMCP, 0);
-       REGISTER_LONG_CONSTANT("CP_SYMBOL", CP_SYMBOL, 0);
-       REGISTER_LONG_CONSTANT("CP_THREAD_ACP", CP_THREAD_ACP, 0);
-       REGISTER_LONG_CONSTANT("CP_UTF7", CP_UTF7, 0);
-       REGISTER_LONG_CONSTANT("CP_UTF8", CP_UTF8, 0);
+       REGISTER_LONG_CONSTANT("CP_ACP", CP_ACP, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("CP_MACCP", CP_MACCP, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("CP_OEMCP", CP_OEMCP, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("CP_SYMBOL", CP_SYMBOL, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("CP_THREAD_ACP", CP_THREAD_ACP, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("CP_UTF7", CP_UTF7, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("CP_UTF8", CP_UTF8, CONST_CS | CONST_PERSISTENT);
 
        php_register_VARIANT_class();
        return SUCCESS;
diff --git a/ext/com/com.h b/ext/com/com.h
new file mode 100644 (file)
index 0000000..f111134
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef COM_H
+#define COM_H
+
+#if PHP_WIN32
+
+#include "unknwn.h"
+
+typedef struct i_dispatch_ {
+       int typelib;
+       struct {
+               IDispatch *dispatch;
+               ITypeInfo *typeinfo;
+       } i;
+} i_dispatch;
+
+PHPAPI HRESULT php_COM_invoke(i_dispatch *obj, DISPID dispIdMember, WORD wFlags, DISPPARAMS FAR*  pDispParams, VARIANT FAR*  pVarResult);
+PHPAPI HRESULT php_COM_get_ids_of_names(i_dispatch *obj, OLECHAR FAR* FAR* rgszNames, DISPID FAR* rgDispId);
+PHPAPI HRESULT php_COM_release(i_dispatch *obj);
+PHPAPI HRESULT php_COM_set(i_dispatch *obj, IDispatch FAR* pDisp, int cleanup);
+PHPAPI HRESULT php_COM_clone(i_dispatch *obj, i_dispatch *clone, int cleanup);
+
+#endif  /* PHP_WIN32 */
+
+#endif  /* COM_H */
index d2a680faff8b592372f78c952a20626e3cfc8437..84680523937356e6b460528f98433f29b8391206 100644 (file)
@@ -3,7 +3,7 @@
 
 #if PHP_WIN32
 
-BEGIN_EXTERN_C()
+#include "com.h"
 
 extern PHP_MINIT_FUNCTION(COM);
 extern PHP_MSHUTDOWN_FUNCTION(COM);
@@ -13,17 +13,11 @@ extern int php_COM_get_le_idispatch();
 extern zend_module_entry COM_module_entry;
 extern zend_class_entry com_class_entry;
 
-END_EXTERN_C()
-
-#ifdef __cplusplus
-
 extern pval php_COM_get_property_handler(zend_property_reference *property_reference);
 extern int php_COM_set_property_handler(zend_property_reference *property_reference, pval *value);
 extern char *php_COM_error_message(HRESULT hr);
 extern void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference);
 
-#endif
-
 #define COM_module_ptr &COM_module_entry
 
 #else
index a95891324e47c1f8b12ceaaddbbbbf25a3f5387a..9ed09eb8d467f99bb4eccbde39580ed374e5c3a2 100644 (file)
 
 #define _WIN32_DCOM
 
-#ifdef CP_THREAD_ACP
-#define PHP_COM_CODEPAGE CP_THREAD_ACP
-#else
-#define PHP_COM_CODEPAGE CP_ACP
-#endif
-
 #include <iostream.h>
 #include <math.h>
 
 #include "php.h"
 #include "php_ini.h"
+#include "com.h"
 
 #include "conversion.h"
-#include "unknwn.h"
-
-BEGIN_EXTERN_C()
 
 zend_class_entry com_class_entry;
 
-END_EXTERN_C()
-
 PHP_FUNCTION(COM_load);
 PHP_FUNCTION(COM_invoke);
 PHP_FUNCTION(com_propget);
@@ -101,27 +91,94 @@ static PHP_MINFO_FUNCTION(COM)
 
 static int php_COM_load_typelib(char *typelib_name, int mode);
 
+PHPAPI HRESULT php_COM_invoke(i_dispatch *obj, DISPID dispIdMember, WORD wFlags, DISPPARAMS FAR*  pDispParams, VARIANT FAR*  pVarResult)
+{
+       if(obj->typelib) {
+               return obj->i.dispatch->lpVtbl->Invoke(obj->i.dispatch, dispIdMember, &IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                                                                                          wFlags, pDispParams, pVarResult, NULL, NULL);
+       } else {
+               return obj->i.typeinfo->lpVtbl->Invoke(obj->i.typeinfo, obj->i.dispatch, dispIdMember,
+                                                                                          wFlags, pDispParams, pVarResult, NULL, NULL);
+       }
+}
+
+PHPAPI HRESULT php_COM_get_ids_of_names(i_dispatch *obj, OLECHAR FAR* FAR* rgszNames, DISPID FAR* rgDispId)
+{
+       if(obj->typelib) {
+               return obj->i.dispatch->lpVtbl->GetIDsOfNames(obj->i.dispatch, &IID_NULL, rgszNames, 1, LOCALE_SYSTEM_DEFAULT, rgDispId);
+       } else {
+               return obj->i.typeinfo->lpVtbl->GetIDsOfNames(obj->i.typeinfo, rgszNames, 1, rgDispId);
+       }
+}
+
+PHPAPI HRESULT php_COM_release(i_dispatch *obj)
+{
+       HRESULT hr;
+       
+       hr = obj->i.dispatch->lpVtbl->Release(obj->i.dispatch);
+       obj->i.dispatch = NULL;
+       obj->i.typeinfo = NULL;
+       obj->typelib = FALSE;
+
+       return hr;
+}
+
+PHPAPI HRESULT php_COM_set(i_dispatch *obj, IDispatch FAR* pDisp, int cleanup)
+{
+       HRESULT hr;
+
+       obj->i.dispatch = pDisp;
+       obj->typelib = !FAILED(obj->i.dispatch->lpVtbl->GetTypeInfo(obj->i.dispatch, 0, LANG_NEUTRAL, &obj->i.typeinfo));
+
+       if(cleanup) {
+               pDisp = NULL;
+       } else {
+               hr = obj->i.dispatch->lpVtbl->AddRef(obj->i.dispatch);
+       }
+
+       return hr;
+}
+
+PHPAPI HRESULT php_COM_clone(i_dispatch *obj, i_dispatch *clone, int cleanup)
+{
+       HRESULT hr;
+
+       obj->typelib = clone->typelib;
+       obj->i.dispatch = clone->i.dispatch;
+       obj->i.typeinfo = clone->i.typeinfo;
+
+       if(cleanup) {
+               obj->i.dispatch = NULL;
+               obj->i.typeinfo = NULL;
+               obj->typelib = FALSE;
+       } else {
+               hr = obj->i.dispatch->lpVtbl->AddRef(obj->i.dispatch);
+       }
+
+       return hr;
+}
+
 PHPAPI char *php_COM_error_message(HRESULT hr)
 {
-       char *pMsgBuf;
+       void *pMsgBuf;
 
        if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
                hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pMsgBuf, 0, NULL)) {
                char error_string[] = "No description available";
                
-               pMsgBuf = (char *) LocalAlloc(LMEM_FIXED, sizeof(error_string));
+               pMsgBuf = LocalAlloc(LMEM_FIXED, sizeof(error_string));
                memcpy(pMsgBuf, error_string, sizeof(error_string));
        }
 
        return pMsgBuf;
 }
 
-static char *php_string_from_clsid(const CLSID clsid)
+static char *php_string_from_clsid(const CLSID *clsid)
 {
        LPOLESTR ole_clsid;
        char *clsid_str;
 
-       StringFromCLSID(&clsid, &ole_clsid);
+       StringFromCLSID(clsid, &ole_clsid);
        clsid_str = php_OLECHAR_to_char(ole_clsid, NULL, 0, codepage);
        LocalFree(ole_clsid);
 
@@ -130,9 +187,9 @@ static char *php_string_from_clsid(const CLSID clsid)
 
 static void php_idispatch_destructor(zend_rsrc_list_entry *rsrc)
 {
-       IDispatch *i_dispatch = (IDispatch *)rsrc->ptr;
-
-       i_dispatch->lpVtbl->Release(i_dispatch);
+       i_dispatch *obj = (i_dispatch *)rsrc->ptr;
+       php_COM_release(obj);
+       efree(obj);
 }
 
 static PHP_INI_MH(OnTypelibFileChange)
@@ -199,12 +256,12 @@ static PHP_INI_MH(OnTypelibFileChange)
 
 
 PHP_INI_BEGIN()
-       PHP_INI_ENTRY1_EX("allow_dcom",         "0",            PHP_INI_SYSTEM,         NULL,                                   NULL,   php_ini_boolean_displayer_cb)
-       PHP_INI_ENTRY1("typelib_file",          NULL,           PHP_INI_SYSTEM,         OnTypelibFileChange,    NULL)
+       PHP_INI_ENTRY_EX("com.allow_dcom", "0", PHP_INI_SYSTEM, NULL, php_ini_boolean_displayer_cb)
+       PHP_INI_ENTRY("com.typelib_file", "", PHP_INI_SYSTEM, OnTypelibFileChange)
 PHP_INI_END()
 
 
-/* {{{ proto int com_load(string module_name)
+/* {{{ proto int com_load(string module_name [, string remote_host [, int codepage]])
    Loads a COM module */
 PHP_FUNCTION(COM_load)
 {
@@ -212,7 +269,7 @@ PHP_FUNCTION(COM_load)
        CLSID clsid;
        HRESULT hr;
        OLECHAR *ProgID;
-       IDispatch *i_dispatch;
+       i_dispatch *obj;
        char *error_message;
        char *clsid_str;
 
@@ -222,7 +279,7 @@ PHP_FUNCTION(COM_load)
                        codepage = CP_ACP;
                        break;
                case 2:
-                       if (!INI_INT("allow_dcom")) {
+                       if (!INI_INT("com.allow_dcom")) {
                                php_error(E_WARNING, "DCOM is disabled");
                                RETURN_FALSE;
                        }
@@ -237,7 +294,7 @@ PHP_FUNCTION(COM_load)
                                efree(server_name);
                                server_name = NULL;
                        } else {
-                               if (!INI_INT("allow_dcom")) {
+                               if (!INI_INT("com.allow_dcom")) {
                                        php_error(E_WARNING, "DCOM is disabled");
                                        RETURN_FALSE;
                                }
@@ -254,7 +311,7 @@ PHP_FUNCTION(COM_load)
 
        convert_to_string(module_name);
        ProgID = php_char_to_OLECHAR(module_name->value.str.val, module_name->value.str.len, codepage);
-       hr = CLSIDFromProgID(ProgID, &clsid);
+       hr=CLSIDFromProgID(ProgID, &clsid);
        efree(ProgID);
 
        /* obtain CLSID */
@@ -265,9 +322,12 @@ PHP_FUNCTION(COM_load)
                RETURN_FALSE;
        }
 
+       obj = (i_dispatch *) emalloc(sizeof(i_dispatch));
+
        /* obtain IDispatch */
        if (!server_name) {
-               hr = CoCreateInstance(&clsid, NULL, CLSCTX_SERVER, &IID_IDispatch, (LPVOID *) &i_dispatch);
+               hr = CoCreateInstance(&clsid, NULL, CLSCTX_SERVER, &IID_IDispatch, (LPVOID *) &(obj->i.dispatch));
+               php_COM_set(obj, obj->i.dispatch, TRUE);
        } else {
                COSERVERINFO server_info;
                MULTI_QI pResults;
@@ -283,27 +343,28 @@ PHP_FUNCTION(COM_load)
                hr=CoCreateInstanceEx(&clsid, NULL, CLSCTX_SERVER, &server_info, 1, &pResults);
                if (SUCCEEDED(hr)) {
                        hr = pResults.hr;
-                       i_dispatch = (IDispatch *) pResults.pItf;
+                       obj->i.dispatch = (IDispatch *) pResults.pItf;
+                       php_COM_set(obj, obj->i.dispatch, TRUE);
                }
                efree(server_info.pwszName);
        }
 
        if (FAILED(hr)) {
                error_message = php_COM_error_message(hr);
-               clsid_str = php_string_from_clsid(clsid);
+               clsid_str = php_string_from_clsid(&clsid);
                php_error(E_WARNING,"Unable to obtain IDispatch interface for CLSID %s:  %s",clsid_str,error_message);
                LocalFree(error_message);
                efree(clsid_str);
+               efree(obj);
                RETURN_FALSE;
        }
 
-
-       RETURN_LONG(zend_list_insert(i_dispatch,le_idispatch));
+       RETURN_LONG(zend_list_insert(obj, le_idispatch));
 }
 /* }}} */
 
 
-int do_COM_invoke(IDispatch *i_dispatch, pval *function_name, VARIANTARG *var_result, pval **arguments, int arg_count)
+int do_COM_invoke(i_dispatch *obj, pval *function_name, VARIANTARG *var_result, pval **arguments, int arg_count)
 {
        DISPID dispid;
        HRESULT hr;
@@ -315,7 +376,7 @@ int do_COM_invoke(IDispatch *i_dispatch, pval *function_name, VARIANTARG *var_re
 
        funcname = php_char_to_OLECHAR(function_name->value.str.val, function_name->value.str.len, codepage);
 
-       hr = i_dispatch->lpVtbl->GetIDsOfNames(i_dispatch, &IID_NULL, &funcname, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
+       hr = php_COM_get_ids_of_names(obj, &funcname, &dispid);
 
        if (FAILED(hr)) {
                error_message = php_COM_error_message(hr);
@@ -337,9 +398,7 @@ int do_COM_invoke(IDispatch *i_dispatch, pval *function_name, VARIANTARG *var_re
        dispparams.cArgs = arg_count;
        dispparams.cNamedArgs = 0;
 
-       hr = i_dispatch->lpVtbl->Invoke(i_dispatch, dispid, &IID_NULL,
-                                                       LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD|DISPATCH_PROPERTYGET,
-                                                       &dispparams, var_result, NULL, NULL);
+       hr = php_COM_invoke(obj, dispid, DISPATCH_METHOD|DISPATCH_PROPERTYGET, &dispparams, var_result);
 
        if (FAILED(hr)) {
                error_message = php_COM_error_message(hr);
@@ -362,7 +421,7 @@ PHP_FUNCTION(COM_invoke)
 {
        pval **arguments;
        pval *object, *function_name;
-       IDispatch *i_dispatch;
+       i_dispatch *obj;
        int type;
        int arg_count = ZEND_NUM_ARGS();
        VARIANTARG var_result;
@@ -378,10 +437,10 @@ PHP_FUNCTION(COM_invoke)
        object = arguments[0];
        function_name = arguments[1];
 
-       /* obtain i_dispatch interface */
+       /* obtain IDispatch interface */
        convert_to_long(object);
-       i_dispatch = (IDispatch *)zend_list_find(object->value.lval, &type);
-       if (!i_dispatch || (type!=le_idispatch)) {
+       obj = (i_dispatch *)zend_list_find(object->value.lval, &type);
+       if (!obj || (type!=le_idispatch)) {
                php_error(E_WARNING,"%d is not a COM object handler", function_name->value.str.val);
                RETURN_FALSE;
        }
@@ -389,7 +448,7 @@ PHP_FUNCTION(COM_invoke)
        /* obtain property/method handler */
        convert_to_string(function_name);
 
-       if (do_COM_invoke(i_dispatch, function_name, &var_result, arguments+2, arg_count-2)==FAILURE) {
+       if (do_COM_invoke(obj, function_name, &var_result, arguments+2, arg_count-2)==FAILURE) {
                RETURN_FALSE;
        }
        efree(arguments);
@@ -403,16 +462,21 @@ static int do_COM_offget(VARIANTARG *var_result, VARIANTARG *array, pval *arg_pr
        switch (array->vt) {
                case VT_DISPATCH:       {       /* a Collection, possibly */
                        pval function_name;
-                       IDispatch *i_dispatch = array->pdispVal;
+                       i_dispatch *obj;
                        int retval;
 
+                       obj = (i_dispatch *) emalloc(sizeof(i_dispatch));
+                       php_COM_set(obj, array->pdispVal, TRUE);
+
                        function_name.value.str.val = "Item";
                        function_name.value.str.len = 4;
                        function_name.type = IS_STRING;
-                       retval = do_COM_invoke(i_dispatch, &function_name, var_result, &arg_property, 1);
+                       retval = do_COM_invoke(obj, &function_name, var_result, &arg_property, 1);
                        if (cleanup) {
-                               i_dispatch->lpVtbl->Release(i_dispatch);
+                               php_COM_release(obj);
                        }
+                       efree(obj);
+
                        return retval;
                }
        }
@@ -420,7 +484,7 @@ static int do_COM_offget(VARIANTARG *var_result, VARIANTARG *array, pval *arg_pr
 }
 
 
-static int do_COM_propget(VARIANTARG *var_result, IDispatch *i_dispatch, pval *arg_property, int cleanup)
+static int do_COM_propget(VARIANTARG *var_result, i_dispatch *obj, pval *arg_property, int cleanup)
 {
        DISPID dispid;
        HRESULT hr;
@@ -432,7 +496,7 @@ static int do_COM_propget(VARIANTARG *var_result, IDispatch *i_dispatch, pval *a
        /* obtain property handler */
        propname = php_char_to_OLECHAR(arg_property->value.str.val, arg_property->value.str.len, codepage);
 
-       hr = i_dispatch->lpVtbl->GetIDsOfNames(i_dispatch, &IID_NULL, &propname, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
+       hr = php_COM_get_ids_of_names(obj, &propname, &dispid);
 
        if (FAILED(hr)) {
                error_message = php_COM_error_message(hr);
@@ -440,7 +504,7 @@ static int do_COM_propget(VARIANTARG *var_result, IDispatch *i_dispatch, pval *a
                LocalFree(error_message);
                efree(propname);
                if (cleanup) {
-                       i_dispatch->lpVtbl->Release(i_dispatch);
+                       php_COM_release(obj);
                }
                return FAILURE;
        }
@@ -448,7 +512,7 @@ static int do_COM_propget(VARIANTARG *var_result, IDispatch *i_dispatch, pval *a
        dispparams.cArgs = 0;
        dispparams.cNamedArgs = 0;
 
-       hr = i_dispatch->lpVtbl->Invoke(i_dispatch, dispid, &IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispparams, var_result, NULL, 0);
+       hr = php_COM_invoke(obj, dispid, DISPATCH_PROPERTYGET, &dispparams, var_result);
 
        if (FAILED(hr)) {
                error_message = php_COM_error_message(hr);
@@ -456,35 +520,37 @@ static int do_COM_propget(VARIANTARG *var_result, IDispatch *i_dispatch, pval *a
                LocalFree(error_message);
                efree(propname);
                if (cleanup) {
-                       i_dispatch->lpVtbl->Release(i_dispatch);
+                       php_COM_release(obj);
                }
                return FAILURE;
        }
 
        efree(propname);
        if (cleanup) {
-               i_dispatch->lpVtbl->Release(i_dispatch);
+               php_COM_release(obj);
        }
        return SUCCESS;
 }
 
 
-static void do_COM_propput(pval *return_value, IDispatch *i_dispatch, pval *arg_property, pval *value)
+static void do_COM_propput(pval *return_value, i_dispatch *obj, pval *arg_property, pval *value)
 {
        DISPID dispid;
        HRESULT hr;
        OLECHAR *propname;
        char *error_message;
-       VARIANTARG var_result;
+       VARIANT *var_result;
        DISPPARAMS dispparams;
        VARIANTARG new_value;
        DISPID mydispid = DISPID_PROPERTYPUT;
 
 
+       var_result = emalloc(sizeof(VARIANT));
+       
        /* obtain property handler */
        propname = php_char_to_OLECHAR(arg_property->value.str.val, arg_property->value.str.len, codepage);
 
-       hr = i_dispatch->lpVtbl->GetIDsOfNames(i_dispatch, &IID_NULL, &propname, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
+       hr = php_COM_get_ids_of_names(obj, &propname, &dispid);
 
        if (FAILED(hr)) {
                error_message = php_COM_error_message(hr);
@@ -494,16 +560,14 @@ static void do_COM_propput(pval *return_value, IDispatch *i_dispatch, pval *arg_
                RETURN_FALSE;
        }
 
-
        php_pval_to_variant(value, &new_value, codepage);
        dispparams.rgvarg = &new_value;
        dispparams.rgdispidNamedArgs = &mydispid;
        dispparams.cArgs = 1;
        dispparams.cNamedArgs = 1;
 
-       hr = i_dispatch->lpVtbl->Invoke(i_dispatch, dispid, &IID_NULL,
-                                                       LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT,
-                                                       &dispparams, NULL, NULL, 0);
+       hr = php_COM_invoke(obj, dispid, DISPATCH_PROPERTYPUT, &dispparams, NULL);
+
        if (FAILED(hr)) {
                error_message = php_COM_error_message(hr);
                php_error(E_WARNING,"PropPut() failed:  %s\n", error_message);
@@ -515,18 +579,16 @@ static void do_COM_propput(pval *return_value, IDispatch *i_dispatch, pval *arg_
        dispparams.cArgs = 0;
        dispparams.cNamedArgs = 0;
 
-       hr = i_dispatch->lpVtbl->Invoke(i_dispatch, dispid, &IID_NULL,
-                                                                       LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET,
-                                                                       &dispparams, &var_result, NULL, 0);
-
+       hr = php_COM_invoke(obj, dispid, DISPATCH_PROPERTYGET, &dispparams, var_result);
 
        if (SUCCEEDED(hr)) {
-               php_variant_to_pval(&var_result, return_value, 0, codepage);
+               php_variant_to_pval(var_result, return_value, 0, codepage);
        } else {
                *return_value = *value;
                zval_copy_ctor(return_value);
        }
 
+       efree(var_result);
        efree(propname);
 }
 
@@ -537,23 +599,22 @@ PHP_FUNCTION(com_propget)
 {
        pval *arg_idispatch, *arg_property;
        int type;
-       IDispatch *i_dispatch;
+       i_dispatch *obj;
        VARIANTARG var_result;
 
        if (ZEND_NUM_ARGS()!=2 || getParameters(ht, 2, &arg_idispatch, &arg_property)==FAILURE) {
                WRONG_PARAM_COUNT;
        }
 
-       /* obtain i_dispatch interface */
+       /* obtain IDispatch interface */
        convert_to_long(arg_idispatch);
-       /* obtain i_dispatch interface */
-       i_dispatch = (IDispatch *)zend_list_find(arg_idispatch->value.lval,&type);
-       if (!i_dispatch || (type!=le_idispatch)) {
+       obj = (i_dispatch *)zend_list_find(arg_idispatch->value.lval,&type);
+       if (!obj || (type!=le_idispatch)) {
                php_error(E_WARNING,"%d is not a COM object handler", arg_idispatch->value.lval);
        }       
        convert_to_string(arg_property);
 
-       if (do_COM_propget(&var_result, i_dispatch, arg_property, 0)==FAILURE) {
+       if (do_COM_propget(&var_result, obj, arg_property, 0)==FAILURE) {
                RETURN_FALSE;
        }
        php_variant_to_pval(&var_result, return_value, 0, codepage);
@@ -567,7 +628,7 @@ PHP_FUNCTION(com_propput)
 {
        pval *arg_idispatch, *arg_property, *arg_value;
        int type;
-       IDispatch *i_dispatch;
+       i_dispatch *obj;
 
        if (ZEND_NUM_ARGS()!=3 || getParameters(ht, 3, &arg_idispatch, &arg_property, &arg_value)==FAILURE) {
                WRONG_PARAM_COUNT;
@@ -576,62 +637,72 @@ PHP_FUNCTION(com_propput)
        /* obtain i_dispatch interface */
        convert_to_long(arg_idispatch);
        /* obtain i_dispatch interface */
-       i_dispatch = (IDispatch *)zend_list_find(arg_idispatch->value.lval,&type);
-       if (!i_dispatch || (type!=le_idispatch)) {
+       obj = (i_dispatch *)zend_list_find(arg_idispatch->value.lval,&type);
+       if (!obj || (type!=le_idispatch)) {
                php_error(E_WARNING,"%d is not a COM object handler", arg_idispatch->value.lval);
        }       
        convert_to_string(arg_property);
 
-       do_COM_propput(return_value, i_dispatch, arg_property, arg_value);
+       do_COM_propput(return_value, obj, arg_property, arg_value);
 }
 /* }}} */
 
 
-VARIANTARG _php_COM_get_property_handler(zend_property_reference *property_reference)
+VARIANT *_php_COM_get_property_handler(zend_property_reference *property_reference)
 {
        zend_overloaded_element *overloaded_property;
        zend_llist_element *element;
        pval **idispatch_handle;
        pval *object = property_reference->object;
-       IDispatch *i_dispatch;
        int type;
-       VARIANTARG var_result;
+       VARIANT *var_result;
+       i_dispatch *obj, *obj_prop;
 
 
        /* fetch the IDispatch interface */
        zend_hash_index_find(object->value.obj.properties, 0, (void **) &idispatch_handle);
-       i_dispatch = (IDispatch *)zend_list_find((*idispatch_handle)->value.lval,&type);
-       if (!i_dispatch || (type!=le_idispatch)) {
-               var_result.vt = VT_EMPTY;
-               return var_result;
+       obj = (i_dispatch *) zend_list_find((*idispatch_handle)->value.lval, &type);
+       if (!obj || (type!=le_idispatch)) {
+               return NULL;
        }
 
-       var_result.vt = VT_DISPATCH;
-       var_result.pdispVal = i_dispatch;
+       obj_prop = (i_dispatch *) emalloc(sizeof(i_dispatch));
+       php_COM_clone(obj_prop, obj, FALSE);
+       
+       var_result = (VARIANT *) emalloc(sizeof(VARIANT));
+       var_result->vt = VT_DISPATCH;
+       var_result->pdispVal = obj_prop->i.dispatch;
 
        for (element=property_reference->elements_list->head; element; element=element->next) {
                overloaded_property = (zend_overloaded_element *) element->data;
                switch (overloaded_property->type) {
                        case OE_IS_ARRAY:
-                               if (do_COM_offget(&var_result, &var_result, &overloaded_property->element, element!=property_reference->elements_list->head)==FAILURE) {
-                                       var_result.vt = VT_EMPTY;
+                               if (do_COM_offget(var_result, var_result, &overloaded_property->element, element!=property_reference->elements_list->head)==FAILURE) {
+                                       var_result->vt = VT_EMPTY;
+                                       efree(obj_prop);
                                        return var_result;
                                }
-                               /*printf("Array offset:  ");*/
                                break;
+
                        case OE_IS_OBJECT:
-                               if (var_result.vt != VT_DISPATCH) {
-                                       var_result.vt = VT_EMPTY;
+                               if (var_result->vt != VT_DISPATCH) {
+                                       var_result->vt = VT_EMPTY;
+                                       efree(obj_prop);
                                        return var_result;
                                } else {
-                                       if (do_COM_propget(&var_result, var_result.pdispVal, &overloaded_property->element, element!=property_reference->elements_list->head)==FAILURE) {
-                                               var_result.vt = VT_EMPTY;
+                                       php_COM_set(obj_prop, var_result->pdispVal, TRUE);
+                                       if (do_COM_propget(var_result, obj_prop, &overloaded_property->element, element!=property_reference->elements_list->head)==FAILURE) {
+                                               var_result->vt = VT_EMPTY;
+                                               efree(obj_prop);
                                                return var_result;
                                        }
-                                       /*printf("Object property:  ");*/
+                                       
                                }
                                break;
+
                        case OE_IS_METHOD:
+                               var_result->pdispVal = obj_prop->i.dispatch;
+                               efree(obj_prop);
                                return var_result;
                                break;
                }
@@ -647,15 +718,17 @@ VARIANTARG _php_COM_get_property_handler(zend_property_reference *property_refer
                */
                pval_destructor(&overloaded_property->element);
        }
+       efree(obj_prop);
        return var_result;
 }
 
 PHPAPI pval php_COM_get_property_handler(zend_property_reference *property_reference)
 {
        pval result;
-       VARIANTARG var_result = _php_COM_get_property_handler(property_reference);
+       VARIANT *var_result = _php_COM_get_property_handler(property_reference);
 
-       php_variant_to_pval(&var_result, &result, 0, codepage);
+       php_variant_to_pval(var_result, &result, 0, codepage);
+       efree(var_result);
        return result;
 }
 
@@ -667,19 +740,19 @@ PHPAPI int php_COM_set_property_handler(zend_property_reference *property_refere
        zend_llist_element *element;
        pval **idispatch_handle;
        pval *object = property_reference->object;
-       IDispatch *i_dispatch;
+       i_dispatch *obj;
        int type;
        VARIANTARG var_result;
 
 
        /* fetch the IDispatch interface */
        zend_hash_index_find(object->value.obj.properties, 0, (void **) &idispatch_handle);
-       i_dispatch = (IDispatch *)zend_list_find((*idispatch_handle)->value.lval,&type);
-       if (!i_dispatch || (type!=le_idispatch)) {
+       obj = (i_dispatch *)zend_list_find((*idispatch_handle)->value.lval,&type);
+       if (!obj || (type!=le_idispatch)) {
                return FAILURE;
        }
        var_result.vt = VT_DISPATCH;
-       var_result.pdispVal = i_dispatch;
+       var_result.pdispVal = obj->i.dispatch;
 
        for (element=property_reference->elements_list->head; element && element!=property_reference->elements_list->tail; element=element->next) {
                overloaded_property = (zend_overloaded_element *) element->data;
@@ -691,7 +764,8 @@ PHPAPI int php_COM_set_property_handler(zend_property_reference *property_refere
                                if (var_result.vt != VT_DISPATCH) {
                                        return FAILURE;
                                } else {
-                                       do_COM_propget(&var_result, i_dispatch, &overloaded_property->element, element!=property_reference->elements_list->head);
+                                       // ??????
+                                       do_COM_propget(&var_result, obj, &overloaded_property->element, element!=property_reference->elements_list->head);
                                        /*printf("Object property:  ");*/
                                }
                                break;
@@ -715,9 +789,15 @@ PHPAPI int php_COM_set_property_handler(zend_property_reference *property_refere
        if (var_result.vt != VT_DISPATCH) {
                return FAILURE;
        }
+       obj = (i_dispatch *) emalloc(sizeof(i_dispatch));
+       obj->typelib = FALSE;
+       obj->i.dispatch = var_result.pdispVal;
+
        overloaded_property = (zend_overloaded_element *) element->data;
-       do_COM_propput(&result, var_result.pdispVal, &overloaded_property->element, value);
+       do_COM_propput(&result, obj, &overloaded_property->element, value);
        pval_destructor(&overloaded_property->element);
+       efree(obj);
+
        return SUCCESS;
 }
 
@@ -745,24 +825,26 @@ PHPAPI void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_pro
                zend_hash_index_update(object->value.obj.properties, 0, &object_handle, sizeof(pval *), NULL);
                pval_destructor(&function_name->element);
        } else {
-               VARIANTARG object_handle = _php_COM_get_property_handler(property_reference);
+               i_dispatch *obj;
                pval **arguments;
                int arg_count = ZEND_NUM_ARGS();
                VARIANTARG var_result;
 
                var_result.vt = VT_EMPTY;
 
-               if (object_handle.vt != VT_DISPATCH) {
-                       /* that shouldn't happen */
-                       return;
-               }
+               obj = (i_dispatch *) emalloc(sizeof(i_dispatch));
+               php_COM_set(obj, _php_COM_get_property_handler(property_reference)->pdispVal, TRUE);
                arguments = (pval **) emalloc(sizeof(pval *)*arg_count);
                getParametersArray(ht, arg_count, arguments);
 
-               if (do_COM_invoke((IDispatch *) object_handle.pdispVal, &function_name->element, &var_result, arguments, arg_count)==FAILURE) {
+               if (do_COM_invoke(obj , &function_name->element, &var_result, arguments, arg_count)==FAILURE) {
                        RETVAL_FALSE;
                }
+               
                pval_destructor(&function_name->element);
+               php_COM_release(obj);
+               efree(obj);
                efree(arguments);
                php_variant_to_pval(&var_result, return_value, 0, codepage);
        }
@@ -788,18 +870,52 @@ static int php_COM_load_typelib(char *typelib_name, int mode)
        ITypeLib *TypeLib;
        ITypeComp *TypeComp;
        OLECHAR *p;
+       CLSID clsid;
+       char *strtok_buf, *major, *minor;
        int i;
        int interfaces;
        ELS_FETCH();
 
+
+       typelib_name = php_strtok_r(typelib_name, ",", &strtok_buf);
+       major = php_strtok_r(NULL, ",", &strtok_buf);
+       minor = php_strtok_r(NULL, ",", &strtok_buf);
+       
        p = php_char_to_OLECHAR(typelib_name, strlen(typelib_name), codepage);
 
-       if (FAILED(LoadTypeLib(p, &TypeLib))) {
-               efree(p);
-               return FAILURE;
+       if (!FAILED(CLSIDFromString(p, &clsid))) {
+               HRESULT hr;
+
+               if (major && minor) {
+                       hr = LoadRegTypeLib((REFGUID) &clsid, 1, 0, LANG_NEUTRAL, &TypeLib);
+               }
+               
+               if (!major || !minor || FAILED(hr)) {
+                       IDispatch *i_dispatch;
+                       ITypeInfo *TypeInfo;
+                       int idx;
+
+                       if (FAILED(CoCreateInstance(&clsid, NULL, CLSCTX_SERVER, &IID_IDispatch, (LPVOID *) &i_dispatch))) {
+                               efree(p);
+                               return FAILURE;
+                       }
+                       if (FAILED(i_dispatch->lpVtbl->GetTypeInfo(i_dispatch, 0, LANG_NEUTRAL, &TypeInfo))) {
+                               efree(p);
+                               return FAILURE;
+                       }
+                       if (FAILED(TypeInfo->lpVtbl->GetContainingTypeLib(TypeInfo, &TypeLib, &idx))) {
+                               efree(p);
+                               return FAILURE;
+                       }
+               }
+       } else {
+               if (FAILED(LoadTypeLib(p, &TypeLib))) {
+                       efree(p);
+                       return FAILURE;
+               }
        }
 
-       interfaces = TypeLib->lpVtbl->GetTypeInfoCount(TypeLib);
+       interfaces = TypeLib->lpVtbl->GetTypeInfoCount(TypeLib);
 
        TypeLib->lpVtbl->GetTypeComp(TypeLib, &TypeComp);
        for (i=0; i<interfaces; i++) {
@@ -865,7 +981,6 @@ void php_register_COM_class()
        zend_register_internal_class(&com_class_entry);
 }
 
-
 PHP_MINIT_FUNCTION(COM)
 {
        CoInitialize(NULL);
@@ -883,7 +998,6 @@ PHP_MSHUTDOWN_FUNCTION(COM)
        return SUCCESS;
 }
 
-BEGIN_EXTERN_C()
 // exports for external object creation
 
 zend_module_entry COM_module_entry = {
@@ -894,6 +1008,4 @@ PHPAPI int php_COM_get_le_idispatch() {
        return le_idispatch;
 }
 
-END_EXTERN_C()
-
 #endif
diff --git a/ext/rpc/com/com_wrapper.h b/ext/rpc/com/com_wrapper.h
new file mode 100644 (file)
index 0000000..f111134
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef COM_H
+#define COM_H
+
+#if PHP_WIN32
+
+#include "unknwn.h"
+
+typedef struct i_dispatch_ {
+       int typelib;
+       struct {
+               IDispatch *dispatch;
+               ITypeInfo *typeinfo;
+       } i;
+} i_dispatch;
+
+PHPAPI HRESULT php_COM_invoke(i_dispatch *obj, DISPID dispIdMember, WORD wFlags, DISPPARAMS FAR*  pDispParams, VARIANT FAR*  pVarResult);
+PHPAPI HRESULT php_COM_get_ids_of_names(i_dispatch *obj, OLECHAR FAR* FAR* rgszNames, DISPID FAR* rgDispId);
+PHPAPI HRESULT php_COM_release(i_dispatch *obj);
+PHPAPI HRESULT php_COM_set(i_dispatch *obj, IDispatch FAR* pDisp, int cleanup);
+PHPAPI HRESULT php_COM_clone(i_dispatch *obj, i_dispatch *clone, int cleanup);
+
+#endif  /* PHP_WIN32 */
+
+#endif  /* COM_H */
index d2a680faff8b592372f78c952a20626e3cfc8437..84680523937356e6b460528f98433f29b8391206 100644 (file)
@@ -3,7 +3,7 @@
 
 #if PHP_WIN32
 
-BEGIN_EXTERN_C()
+#include "com.h"
 
 extern PHP_MINIT_FUNCTION(COM);
 extern PHP_MSHUTDOWN_FUNCTION(COM);
@@ -13,17 +13,11 @@ extern int php_COM_get_le_idispatch();
 extern zend_module_entry COM_module_entry;
 extern zend_class_entry com_class_entry;
 
-END_EXTERN_C()
-
-#ifdef __cplusplus
-
 extern pval php_COM_get_property_handler(zend_property_reference *property_reference);
 extern int php_COM_set_property_handler(zend_property_reference *property_reference, pval *value);
 extern char *php_COM_error_message(HRESULT hr);
 extern void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference);
 
-#endif
-
 #define COM_module_ptr &COM_module_entry
 
 #else
index 5bc772e20d936b7379821b854a395ce87360e5a9..4c4657b2a03aeaa0fc3dd686663a63539c902a20 100644 (file)
@@ -69,38 +69,38 @@ PHP_MINIT_FUNCTION(VARIANT)
        le_variant = zend_register_list_destructors_ex(php_variant_destructor, NULL, "VARIANT", module_number);
 
        /* variant datatypes */
-       REGISTER_LONG_CONSTANT("VT_NULL", VT_NULL, 0);
-       REGISTER_LONG_CONSTANT("VT_EMPTY", VT_EMPTY, 0);
-       REGISTER_LONG_CONSTANT("VT_UI1", VT_UI1, 0);
-       REGISTER_LONG_CONSTANT("VT_I2", VT_I2, 0);
-       REGISTER_LONG_CONSTANT("VT_I4", VT_I4, 0);
-       REGISTER_LONG_CONSTANT("VT_R4", VT_R4, 0);
-       REGISTER_LONG_CONSTANT("VT_R8", VT_R8, 0);
-       REGISTER_LONG_CONSTANT("VT_BOOL", VT_BOOL, 0);
-       REGISTER_LONG_CONSTANT("VT_ERROR", VT_ERROR, 0);
-       REGISTER_LONG_CONSTANT("VT_CY", VT_CY, 0);
-       REGISTER_LONG_CONSTANT("VT_DATE", VT_CY, 0);
-       REGISTER_LONG_CONSTANT("VT_BSTR", VT_BSTR, 0);
-       REGISTER_LONG_CONSTANT("VT_DECIMAL", VT_DECIMAL, 0);
-       REGISTER_LONG_CONSTANT("VT_UNKNOWN", VT_UNKNOWN, 0);
-       REGISTER_LONG_CONSTANT("VT_DISPATCH", VT_DISPATCH, 0);
-       REGISTER_LONG_CONSTANT("VT_VARIANT", VT_VARIANT, 0);
-       REGISTER_LONG_CONSTANT("VT_I1", VT_I1, 0);
-       REGISTER_LONG_CONSTANT("VT_UI2", VT_UI2, 0);
-       REGISTER_LONG_CONSTANT("VT_UI4", VT_UI4, 0);
-       REGISTER_LONG_CONSTANT("VT_INT", VT_INT, 0);
-       REGISTER_LONG_CONSTANT("VT_UINT", VT_UINT, 0);
-       REGISTER_LONG_CONSTANT("VT_ARRAY", VT_ARRAY, 0);
-       REGISTER_LONG_CONSTANT("VT_BYREF", VT_BYREF, 0);
+       REGISTER_LONG_CONSTANT("VT_NULL", VT_NULL, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_EMPTY", VT_EMPTY, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_UI1", VT_UI1, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_I2", VT_I2, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_I4", VT_I4, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_R4", VT_R4, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_R8", VT_R8, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_BOOL", VT_BOOL, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_ERROR", VT_ERROR, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_CY", VT_CY, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_DATE", VT_CY, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_BSTR", VT_BSTR, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_DECIMAL", VT_DECIMAL, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_UNKNOWN", VT_UNKNOWN, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_DISPATCH", VT_DISPATCH, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_VARIANT", VT_VARIANT, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_I1", VT_I1, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_UI2", VT_UI2, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_UI4", VT_UI4, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_INT", VT_INT, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_UINT", VT_UINT, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_ARRAY", VT_ARRAY, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("VT_BYREF", VT_BYREF, CONST_CS | CONST_PERSISTENT);
  
        /* codepages */
-       REGISTER_LONG_CONSTANT("CP_ACP", CP_ACP, 0);
-       REGISTER_LONG_CONSTANT("CP_MACCP", CP_MACCP, 0);
-       REGISTER_LONG_CONSTANT("CP_OEMCP", CP_OEMCP, 0);
-       REGISTER_LONG_CONSTANT("CP_SYMBOL", CP_SYMBOL, 0);
-       REGISTER_LONG_CONSTANT("CP_THREAD_ACP", CP_THREAD_ACP, 0);
-       REGISTER_LONG_CONSTANT("CP_UTF7", CP_UTF7, 0);
-       REGISTER_LONG_CONSTANT("CP_UTF8", CP_UTF8, 0);
+       REGISTER_LONG_CONSTANT("CP_ACP", CP_ACP, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("CP_MACCP", CP_MACCP, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("CP_OEMCP", CP_OEMCP, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("CP_SYMBOL", CP_SYMBOL, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("CP_THREAD_ACP", CP_THREAD_ACP, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("CP_UTF7", CP_UTF7, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("CP_UTF8", CP_UTF8, CONST_CS | CONST_PERSISTENT);
 
        php_register_VARIANT_class();
        return SUCCESS;