wez             Thu Aug 14 12:49:56 2003 EDT

  Added files:                 
    /php-src/ext/com_dotnet     README com_com.c com_dotnet.c 
                                com_extension.c com_handlers.c com_misc.c 
                                com_olechar.c com_typeinfo.c com_variant.c 
                                php_com_dotnet.h php_com_dotnet_internal.h 
    /php-src/ext/com_dotnet/tests       variants.phpt 

  Modified files:              
    /php-src/main       config.w32.h internal_functions_win32.c 
  Log:
  Add new COM (and .Net) extension for php5.
  Not yet complete, but should work for most people.
  
  
Index: php-src/main/config.w32.h
diff -u php-src/main/config.w32.h:1.75 php-src/main/config.w32.h:1.76
--- php-src/main/config.w32.h:1.75      Fri Jun 27 12:43:05 2003
+++ php-src/main/config.w32.h   Thu Aug 14 12:49:56 2003
@@ -2,7 +2,7 @@
        Build Configuration for Win32.
        This has only been tested with MS VisualC++ 6 (and later).
 
-       $Id: config.w32.h,v 1.75 2003/06/27 16:43:05 sebastian Exp $
+       $Id: config.w32.h,v 1.76 2003/08/14 16:49:56 wez Exp $
 */
 
 /* Default PHP / PEAR directories */
@@ -46,6 +46,10 @@
 /* #define HAVE_MBSTR_KR 0 */
 /* #define HAVE_MBSTR_RU 0 */
 /* #define HAVE_MBSTR_TW 0 */ 
+
+/* If you have the .Net SDK in your include path, define this
+ * to compile .Net support into your COM extension. */
+#define HAVE_MSCOREE_H 0
 
 /* Enable / Disable ODBC extension (default: enabled) */
 #define HAVE_UODBC 1
Index: php-src/main/internal_functions_win32.c
diff -u php-src/main/internal_functions_win32.c:1.78 
php-src/main/internal_functions_win32.c:1.79
--- php-src/main/internal_functions_win32.c:1.78        Fri Jun 27 10:32:59 2003
+++ php-src/main/internal_functions_win32.c     Thu Aug 14 12:49:56 2003
@@ -17,7 +17,7 @@
        +----------------------------------------------------------------------+
 */
 
-/* $Id: internal_functions_win32.c,v 1.78 2003/06/27 14:32:59 edink Exp $ */
+/* $Id: internal_functions_win32.c,v 1.79 2003/08/14 16:49:56 wez Exp $ */
 
 /* {{{ includes
  */
@@ -97,6 +97,7 @@
 #ifdef HAVE_SQLITE
 #include "ext/sqlite/php_sqlite.h"
 #endif
+#include "ext/com_dotnet/php_com_dotnet.h"
 /* }}} */
 
 /* {{{ php_builtin_extensions[]
@@ -109,6 +110,7 @@
 #if HAVE_CALENDAR
        ,phpext_calendar_ptr
 #endif
+       ,phpext_com_dotnet_ptr
 #if HAVE_CTYPE
        ,phpext_ctype_ptr
 #endif
@@ -135,14 +137,14 @@
 #endif
 #if HAVE_LIBXML
 #if HAVE_DOM
-       ,phpext_dom_ptr
+       phpext_dom_ptr
 #endif
 #if HAVE_SIMPLEXML
-       ,phpext_simplexml_ptr
+       phpext_simplexml_ptr
 #endif
 #endif
 #if HAVE_XML
-       ,phpext_xml_ptr
+       phpext_xml_ptr
 #endif
 #if HAVE_XML && HAVE_WDDX
        ,phpext_wddx_ptr

Index: php-src/ext/com_dotnet/com_com.c
+++ php-src/ext/com_dotnet/com_com.c
/*
   +----------------------------------------------------------------------+
   | PHP Version 4                                                        |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2003 The PHP Group                                |
   +----------------------------------------------------------------------+
   | This source file is subject to version 3.0 of the PHP license,       |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.php.net/license/3_0.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          |
   | [EMAIL PROTECTED] so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Author: Wez Furlong  <[EMAIL PROTECTED]>                          |
   +----------------------------------------------------------------------+
 */

/* $Id: com_com.c,v 1.1 2003/08/14 16:49:55 wez Exp $ */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_com_dotnet.h"
#include "php_com_dotnet_internal.h"
#include "Zend/zend_default_classes.h"

/* {{{ com_create_instance - ctor for COM class */
PHP_FUNCTION(com_create_instance)
{
        zval *object = getThis();
        zval *server_params = NULL;
        php_com_dotnet_object *obj;
        char *module_name, *typelib_name = NULL, *server_name = NULL;
        char *user_name = NULL, *domain_name = NULL, *password = NULL;
        long module_name_len, typelib_name_len, server_name_len,
                user_name_len, domain_name_len, password_len;
        OLECHAR *moniker;
        CLSID clsid;
        CLSCTX ctx = CLSCTX_SERVER;
        HRESULT res = E_FAIL;
        int mode = COMG(autoreg_case_sensitive) ? CONST_CS : 0;
        ITypeLib *TL = NULL;

        obj = CDNO_FETCH(object);

        if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
                        ZEND_NUM_ARGS() TSRMLS_CC, "s|s!ls",
                        &module_name, &module_name_len, &server_name, &server_name_len,
                        &obj->code_page, &typelib_name, &typelib_name_len) &&
                FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
                        ZEND_NUM_ARGS() TSRMLS_CC, "sa|ls",
                        &module_name, &module_name_len, &server_params, 
&obj->code_page,
                        &typelib_name, &typelib_name_len)) {

                php_com_throw_exception("Could not create COM object - invalid 
arguments!" TSRMLS_CC);
                ZVAL_NULL(object);
                return;
        }

        if (server_name) {
                ctx = CLSCTX_REMOTE_SERVER;
        } else if (server_params) {
                zval **tmp;

                /* decode the data from the array */

                if (SUCCESS == zend_hash_find(HASH_OF(server_params),
                                "Server", sizeof("Server"), (void**)&tmp)) {
                        convert_to_string_ex(tmp);
                        server_name = Z_STRVAL_PP(tmp);
                        server_name_len = Z_STRLEN_PP(tmp);
                        ctx = CLSCTX_REMOTE_SERVER;
                }

                if (SUCCESS == zend_hash_find(HASH_OF(server_params),
                                "Username", sizeof("Username"), (void**)&tmp)) {
                        convert_to_string_ex(tmp);
                        user_name = Z_STRVAL_PP(tmp);
                        user_name_len = Z_STRLEN_PP(tmp);
                }

                if (SUCCESS == zend_hash_find(HASH_OF(server_params),
                                "Password", sizeof("Password"), (void**)&tmp)) {
                        convert_to_string_ex(tmp);
                        password = Z_STRVAL_PP(tmp);
                        password_len = Z_STRLEN_PP(tmp);
                }

                if (SUCCESS == zend_hash_find(HASH_OF(server_params),
                                "Domain", sizeof("Domain"), (void**)&tmp)) {
                        convert_to_string_ex(tmp);
                        domain_name = Z_STRVAL_PP(tmp);
                        domain_name_len = Z_STRLEN_PP(tmp);
                }

                if (SUCCESS == zend_hash_find(HASH_OF(server_params),
                                "Flags", sizeof("Flags"), (void**)&tmp)) {
                        convert_to_long_ex(tmp);
                        ctx = (CLSCTX)Z_LVAL_PP(tmp);
                }
        }

        if (server_name && !COMG(allow_dcom)) {
                php_com_throw_exception("DCOM has been disabled by your administrator 
[com.allow_dcom=0]" TSRMLS_CC);
                return;
        }

        moniker = php_com_string_to_olestring(module_name, module_name_len, 
obj->code_page TSRMLS_CC);

        if (FAILED(CLSIDFromString(moniker, &clsid))) {
                /* try to use it as a moniker */
                IBindCtx *pBindCtx = NULL;
                IMoniker *pMoniker = NULL;
                ULONG ulEaten;

                if (server_name == NULL) {
                        res = MK_E_SYNTAX;
                } else if (SUCCEEDED(res = CreateBindCtx(0, &pBindCtx)) &&
                                SUCCEEDED(res = MkParseDisplayName(pBindCtx, moniker, 
&ulEaten, &pMoniker))) {
                        res = IMoniker_BindToObject(pMoniker, pBindCtx, NULL, 
&IID_IDispatch, (LPVOID*)&V_DISPATCH(&obj->v));
                        
                        if (SUCCEEDED(res)) {
                                V_VT(&obj->v) = VT_DISPATCH;
                        }

                        IMoniker_Release(pMoniker);
                }
                if (pBindCtx) {
                        IBindCtx_Release(pBindCtx);
                }
        } else if (server_name) {
                COSERVERINFO    info;
                MULTI_QI                qi;
                COAUTHIDENTITY  authid;
                COAUTHINFO              authinfo = {
                        RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
                        RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE,
                        &authid, EOAC_NONE
                };

                info.dwReserved1 = 0;
                info.dwReserved2 = 0;
                info.pwszName = php_com_string_to_olestring(server_name, 
server_name_len, obj->code_page TSRMLS_CC);

                if (user_name) {
                        authid.User = php_com_string_to_olestring(user_name, -1, 
obj->code_page TSRMLS_CC);
                        authid.UserLength = user_name_len;

                        if (password) {
                                authid.Password = (OLECHAR*)password;
                                authid.PasswordLength = password_len;
                        } else {
                                authid.Password = (OLECHAR*)"";
                                authid.PasswordLength = 0;
                        }

                        if (domain_name) {
                                authid.Domain = (OLECHAR*)domain_name;
                                authid.DomainLength = domain_name_len;
                        } else {
                                authid.Domain = (OLECHAR*)"";
                                authid.DomainLength = 0;
                        }
                        authid.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
                        info.pAuthInfo = &authinfo;
                } else {
                        info.pAuthInfo = NULL;
                }
                qi.pIID = &IID_IDispatch;
                qi.pItf = NULL;
                qi.hr = S_OK;

                res = CoCreateInstanceEx(&clsid, NULL, ctx, &info, 1, &qi);
                efree(info.pwszName);

                if (SUCCEEDED(res)) {
                        res = qi.hr;
                        V_DISPATCH(&obj->v) = (IDispatch*)qi.pItf;
                        V_VT(&obj->v) = VT_DISPATCH;
                }

        } else {
                res = CoCreateInstance(&clsid, NULL, CLSCTX_SERVER, &IID_IDispatch, 
(LPVOID*)&V_DISPATCH(&obj->v));
                if (SUCCEEDED(res)) {
                        V_VT(&obj->v) = VT_DISPATCH;
                }
        }

        efree(moniker);

        if (FAILED(res)) {
                char *werr, *msg;

                werr = php_win_err(res);
                spprintf(&msg, 0, "Failed to create COM object `%s': %s", module_name, 
werr);
                LocalFree(werr);

                php_com_throw_exception(msg TSRMLS_CC);
                efree(msg);
                ZVAL_NULL(object);
                return;
        }

        /* we got the object and it lives ! */

        /* see if it has TypeInfo available */
        if (FAILED(IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, LANG_NEUTRAL, 
&obj->typeinfo)) && typelib_name) {
                /* load up the library from the named file */
                int cached;

                TL = php_com_load_typelib_via_cache(typelib_name, mode, 
obj->code_page, &cached TSRMLS_CC);

                if (TL) {
                        if (COMG(autoreg_on) && !cached) {
                                php_com_import_typelib(TL, mode, obj->code_page 
TSRMLS_CC);
                        }

                        /* cross your fingers... there is no guarantee that this 
ITypeInfo
                         * instance has any relation to this IDispatch instance... */
                        ITypeLib_GetTypeInfo(TL, 0, &obj->typeinfo);
                        ITypeLib_Release(TL);
                }
        } else if (obj->typeinfo && COMG(autoreg_on)) {
                int idx;

                if (SUCCEEDED(ITypeInfo_GetContainingTypeLib(obj->typeinfo, &TL, 
&idx))) {
                        /* check if the library is already in the cache by getting its 
name */
                        BSTR name;

                        if (SUCCEEDED(ITypeLib_GetDocumentation(TL, -1, &name, NULL, 
NULL, NULL))) {
                                typelib_name = php_com_olestring_to_string(name, 
&typelib_name_len, obj->code_page TSRMLS_CC);

                                if (SUCCESS == 
zend_ts_hash_add(&php_com_typelibraries, typelib_name, typelib_name_len+1, (void*)&TL, 
sizeof(ITypeLib*), NULL)) {
                                        php_com_import_typelib(TL, mode, 
obj->code_page TSRMLS_CC);

                                        /* add a reference for the hash */
                                        ITypeLib_AddRef(TL);
                                }

                        } else {
                                /* try it anyway */
                                php_com_import_typelib(TL, mode, obj->code_page 
TSRMLS_CC);
                        }

                        ITypeLib_Release(TL);
                }
        }

}
/* }}} */

/* Performs an Invoke on the given com object.
 * returns a failure code and creates an exception if there was an error */
HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member,
                WORD flags, DISPPARAMS *disp_params, VARIANT *v TSRMLS_DC)
{
        HRESULT hr;
        unsigned int arg_err;
        EXCEPINFO e;

        if (obj->typeinfo) {
                hr = ITypeInfo_Invoke(obj->typeinfo, V_DISPATCH(&obj->v), id_member, 
flags, disp_params, v, &e, &arg_err);
                if (FAILED(hr) && (hr != DISP_E_EXCEPTION)) {
                        hr = IDispatch_Invoke(V_DISPATCH(&obj->v), id_member,
                                &IID_NULL, LOCALE_SYSTEM_DEFAULT, flags, disp_params, 
v, &e, &arg_err);
                        if (SUCCEEDED(hr)) {
                                /* fall back on using IDispatch directly */
                                ITypeInfo_Release(obj->typeinfo);
                                obj->typeinfo = NULL;
                        }
                }
        } else {
                hr = IDispatch_Invoke(V_DISPATCH(&obj->v), id_member,
                        &IID_NULL, LOCALE_SYSTEM_DEFAULT, flags, disp_params, v, &e, 
&arg_err);
        }

        if (FAILED(hr)) {
                char *source = NULL, *desc = NULL, *msg = NULL;
                int source_len, desc_len;

                switch (hr) {
                        case DISP_E_EXCEPTION:
                                if (e.bstrSource) {
                                        source = 
php_com_olestring_to_string(e.bstrSource, &source_len, obj->code_page TSRMLS_CC);
                                        SysFreeString(e.bstrSource);
                                }
                                if (e.bstrDescription) {
                                        desc = 
php_com_olestring_to_string(e.bstrDescription, &desc_len, obj->code_page TSRMLS_CC);
                                        SysFreeString(e.bstrDescription);
                                }
                                if (PG(html_errors)) {
                                        spprintf(&msg, 0, "<b>Source:</b> 
%s<br/><b>Description:</b> %s",
                                                source ? source : "Unknown",
                                                desc ? desc : "Unknown");
                                } else {
                                        spprintf(&msg, 0, "Source: %s\nDescription: 
%s",
                                                source ? source : "Unknown",
                                                desc ? desc : "Unknown");
                                }
                                if (desc) {
                                        efree(desc);
                                }
                                if (source) {
                                        efree(source);
                                }
                                if (e.bstrHelpFile) {
                                        SysFreeString(e.bstrHelpFile);
                                }
                                break;

                        case DISP_E_PARAMNOTFOUND:
                        case DISP_E_TYPEMISMATCH:
                                desc = php_win_err(hr);
                                spprintf(&msg, 0, "Parameter %d: %s", arg_err, desc);
                                LocalFree(desc);
                                break;
                        default:
                                desc = php_win_err(hr);
                                spprintf(&msg, 0, "Error %s", desc);
                                LocalFree(desc);
                                break;
                }

                if (msg) {
                        php_com_throw_exception(msg TSRMLS_CC);
                        efree(msg);
                }
        }

        return hr;
}

/* map an ID to a name */
HRESULT php_com_get_id_of_name(php_com_dotnet_object *obj, char *name,
                int namelen, DISPID *dispid TSRMLS_DC)
{
        OLECHAR *olename;
        HRESULT hr;

        olename = php_com_string_to_olestring(name, namelen, obj->code_page TSRMLS_CC);

        if (obj->typeinfo) {
                hr = ITypeInfo_GetIDsOfNames(obj->typeinfo, &olename, 1, dispid);
                if (FAILED(hr)) {
                        hr = IDispatch_GetIDsOfNames(V_DISPATCH(&obj->v), &IID_NULL, 
&olename, 1, LOCALE_SYSTEM_DEFAULT, dispid);
                        if (SUCCEEDED(hr)) {
                                /* fall back on IDispatch direct */
                                ITypeInfo_Release(obj->typeinfo);
                                obj->typeinfo = NULL;
                        }
                }
        } else {
                hr = IDispatch_GetIDsOfNames(V_DISPATCH(&obj->v), &IID_NULL, &olename, 
1, LOCALE_SYSTEM_DEFAULT, dispid);
        }
        efree(olename);

        return hr;
}

/* the core of COM */
int php_com_do_invoke_by_id(php_com_dotnet_object *obj, DISPID dispid,
                WORD flags,     VARIANT *v, int nargs, zval **args TSRMLS_DC)
{
        DISPID altdispid;
        DISPPARAMS disp_params;
        HRESULT hr;
        VARIANT *vargs = NULL;
        int i;

        if (nargs) {
                vargs = (VARIANT*)emalloc(sizeof(VARIANT) * nargs);
        }

        /* Invoke'd args are in reverse order */
        for (i = 0; i < nargs; i++) {
                php_com_variant_from_zval(&vargs[i], args[nargs - i - 1], 
obj->code_page TSRMLS_CC);
        }

        disp_params.cArgs = nargs;
        disp_params.cNamedArgs = 0;
        disp_params.rgvarg = vargs;
        disp_params.rgdispidNamedArgs = NULL;

        if (flags & DISPATCH_PROPERTYPUT) {
                altdispid = DISPID_PROPERTYPUT;
                disp_params.rgdispidNamedArgs = &altdispid;
                disp_params.cNamedArgs = 1;
        }

        /* this will create an exception if needed */
        hr = php_com_invoke_helper(obj, dispid, flags, &disp_params, v TSRMLS_CC);     
 

        /* release variants */
        if (vargs) {
                for (i = 0; i < nargs; i++) {
                        VariantClear(&vargs[i]);
                }
                efree(vargs);
        }

        return SUCCEEDED(hr) ? SUCCESS : FAILURE;
}

int php_com_do_invoke(php_com_dotnet_object *obj, char *name, int namelen,
                WORD flags,     VARIANT *v, int nargs, zval **args TSRMLS_DC)
{
        DISPID dispid;
        HRESULT hr;
        char *winerr = NULL;
        char *msg = NULL;

        hr = php_com_get_id_of_name(obj, name, namelen, &dispid TSRMLS_CC);

        if (FAILED(hr)) {
                winerr = php_win_err(hr);
                spprintf(&msg, 0, "Unable to lookup `%s': %s", name, winerr);
                LocalFree(winerr);
                php_com_throw_exception(msg TSRMLS_CC);
                efree(msg);
                return FAILURE;
        }

        return php_com_do_invoke_by_id(obj, dispid, flags, v, nargs, args TSRMLS_CC);
}

Index: php-src/ext/com_dotnet/com_dotnet.c
+++ php-src/ext/com_dotnet/com_dotnet.c
/*
   +----------------------------------------------------------------------+
   | PHP Version 4                                                        |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2003 The PHP Group                                |
   +----------------------------------------------------------------------+
   | This source file is subject to version 3.0 of the PHP license,       |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.php.net/license/3_0.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          |
   | [EMAIL PROTECTED] so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Author: Wez Furlong  <[EMAIL PROTECTED]>                          |
   +----------------------------------------------------------------------+
 */

/* $Id: com_dotnet.c,v 1.1 2003/08/14 16:49:55 wez Exp $ */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"

#if HAVE_MSCOREE_H
# include "php_ini.h"
# include "ext/standard/info.h"
# include "php_com_dotnet.h"
# include "php_com_dotnet_internal.h"
# include "Zend/zend_default_classes.h"
# include <mscoree.h>

struct dotnet_runtime_stuff {
        ICorRuntimeHost *dotnet_host;
        IDispatch *dotnet_domain;
        DISPID create_instance;
};

/* Since there is no official public mscorlib.h header file, and since
 * generating your own version from the binary .tlb file results in a 3MB
 * header file (!), we opt for the Dispatch-able approach.  This is slightly
 * slower for creating new objects, but not too bad */
static int dotnet_init(TSRMLS_D)
{
        HRESULT hr;
        struct dotnet_runtime_stuff *stuff;
        IUnknown *unk = NULL;
        OLECHAR *olename;

        stuff = emalloc(sizeof(*stuff));
        memset(stuff, 0, sizeof(*stuff));

        if (SUCCEEDED(CoCreateInstance(&CLSID_CorRuntimeHost, NULL, CLSCTX_ALL,
                        &IID_ICorRuntimeHost, (LPVOID*)&stuff->dotnet_host))) {

                /* fire up the host and get the domain object */
                if (SUCCEEDED(ICorRuntimeHost_Start(stuff->dotnet_host)) &&
                                
SUCCEEDED(ICorRuntimeHost_GetDefaultDomain(stuff->dotnet_host, &unk)) &&
                                SUCCEEDED(IUnknown_QueryInterface(unk, &IID_IDispatch, 
(LPVOID*)&stuff->dotnet_domain))) {

                        /* locate the create-instance member */
                        olename = php_com_string_to_olestring("CreateInstance", 
sizeof("CreateInstance")-1, CP_ACP TSRMLS_CC);
                        hr = IDispatch_GetIDsOfNames(stuff->dotnet_domain, &IID_NULL, 
&olename, 1, LOCALE_SYSTEM_DEFAULT, &stuff->create_instance);
                        efree(olename);

                        if (SUCCEEDED(hr)) {
                                COMG(dotnet_runtime_stuff) = stuff;
                        }
                }

                if (unk) {
                        IUnknown_Release(unk);
                }
        }

        if (COMG(dotnet_runtime_stuff) == NULL) {
                /* clean up */
                if (stuff->dotnet_domain) {
                        IDispatch_Release(stuff->dotnet_domain);
                }
                if (stuff->dotnet_host) {
                        ICorRuntimeHost_Stop(stuff->dotnet_host);
                        ICorRuntimeHost_Release(stuff->dotnet_host);
                }
                efree(stuff);

                return FAILURE;
        }

        return SUCCESS;
}

/* {{{ com_dotnet_create_instance - ctor for DOTNET class */
PHP_FUNCTION(com_dotnet_create_instance)
{
        zval *object = getThis();
        php_com_dotnet_object *obj;
        char *assembly_name, *datatype_name;
        long assembly_name_len, datatype_name_len;
        struct dotnet_runtime_stuff *stuff;
        IObjectHandle *handle;
        DISPPARAMS params;
        VARIANT vargs[2];
        VARIANT retval;
        HRESULT hr;
        int ret = FAILURE;

        if (COMG(dotnet_runtime_stuff) == NULL) {
                if (FAILURE == dotnet_init(TSRMLS_C)) {
                        com_throw_exception("Failed to initialize .Net runtime" 
TSRMLS_CC);
                        ZVAL_NULL(object);
                        return;
                }
        }

        stuff = (struct dotnet_runtime_stuff*)COMG(dotnet_runtime_stuff);

        obj = CDNO_FETCH(object);

        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l",
                        &assembly_name, &assembly_name_len,
                        &datatype_name, &datatype_name_len,
                        &obj->code_page)) {
                com_throw_exception("Could not create .Net object - invalid 
arguments!" TSRMLS_CC);
                ZVAL_NULL(object);
                return;
        }

        params.cArgs = 2;
        params.cNamedArgs = 0;
        params.rgdispidNamedArgs = NULL;
        params.rgvarg = vargs;

        VariantInit(&vargs[0]);
        VariantInit(&vargs[1]);
        VariantInit(&retval);

        V_VT(&vargs[0]) = VT_BSTR;
        V_BSTR(&vargs[0]) = php_com_string_to_olestring(datatype_name, 
datatype_name_len, obj->code_page TSRMLS_CC);

        V_VT(&vargs[1]) = VT_BSTR;
        V_BSTR(&vargs[1]) = php_com_string_to_olestring(assembly_name, 
assembly_name_len, obj->code_page TSRMLS_CC);

        hr = IDispatch_Invoke(stuff->dotnet_domain, stuff->create_instance, &IID_NULL, 
LOCALE_SYSTEM_DEFAULT,
                DISPATCH_METHOD, &params, &retval, NULL, NULL);

        if (SUCCEEDED(hr)) {
                /* retval should now be an IUnknown/IDispatch representation of an 
IObjectHandle interface */
                if ((V_VT(&retval) == VT_UNKNOWN || V_VT(&retval) == VT_DISPATCH) &&
                                SUCCEEDED(IUnknown_QueryInterface(V_UNKNOWN(&retval), 
&IID_IObjectHandle, &handle))) {
                        VARIANT unwrapped;

                        if (SUCCEEDED(IObjectHandle_Unwrap(handle, &unwrapped))) {
                                /* unwrapped is now the dispatch pointer we want */
                                V_DISPATCH(&obj->v) = V_DISPATCH(&unwrapped);
                                V_VT(&obj->v) = VT_DISPATCH;

                                /* get its type-info */
                                IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, 
LANG_NEUTRAL, &obj->typeinfo);

                                ret = SUCCESS;
                        }
                        IObjectHandle_Release(handle);
                }
                VariantClear(&retval);
        }

        VariantClear(&vargs[0]);
        VariantClear(&vargs[1]);

        if (ret == FAILURE) {
                com_throw_exception("Failed to instantiate .Net object" TSRMLS_CC);
                ZVAL_NULL(object);
                return;
        }
}
/* }}} */


void php_com_dotnet_rshutdown(TSRMLS_D)
{
        struct dotnet_runtime_stuff *stuff = COMG(dotnet_runtime_stuff);
        
        IDispatch_Release(stuff->dotnet_domain);
        ICorRuntimeHost_Stop(stuff->dotnet_host);
        ICorRuntimeHost_Release(stuff->dotnet_host);

        efree(stuff);

        COMG(dotnet_runtime_stuff) = NULL;
}

#endif /* HAVE_MSCOREE_H */

Index: php-src/ext/com_dotnet/com_extension.c
+++ php-src/ext/com_dotnet/com_extension.c
/*
   +----------------------------------------------------------------------+
   | PHP Version 4                                                        |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2003 The PHP Group                                |
   +----------------------------------------------------------------------+
   | This source file is subject to version 3.0 of the PHP license,       |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.php.net/license/3_0.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          |
   | [EMAIL PROTECTED] so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Author: Wez Furlong  <[EMAIL PROTECTED]>                          |
   +----------------------------------------------------------------------+
 */

/* $Id: com_extension.c,v 1.1 2003/08/14 16:49:55 wez Exp $ */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_com_dotnet.h"
#include "php_com_dotnet_internal.h"
#include "Zend/zend_default_classes.h"

ZEND_DECLARE_MODULE_GLOBALS(com_dotnet)
TsHashTable php_com_typelibraries;
zend_class_entry *php_com_variant_class_entry;

function_entry com_dotnet_functions[] = {
        PHP_FE(variant_set, NULL)
        PHP_FE(variant_add, NULL)
        PHP_FE(variant_cat, NULL)
        PHP_FE(variant_sub, NULL)
        PHP_FE(variant_mul, NULL)
        PHP_FE(variant_and, NULL)
        PHP_FE(variant_div, NULL)
        PHP_FE(variant_eqv, NULL)
        PHP_FE(variant_idiv, NULL)
        PHP_FE(variant_imp, NULL)
        PHP_FE(variant_mod, NULL)
        PHP_FE(variant_or, NULL)
        PHP_FE(variant_pow, NULL)
        PHP_FE(variant_xor, NULL)
        PHP_FE(variant_abs, NULL)
        PHP_FE(variant_fix, NULL)
        PHP_FE(variant_int, NULL)
        PHP_FE(variant_neg, NULL)
        PHP_FE(variant_not, NULL)
        PHP_FE(variant_round, NULL)
        PHP_FE(variant_cmp, NULL)
        PHP_FE(variant_date_to_timestamp, NULL)
        PHP_FE(variant_date_from_timestamp, NULL)
        PHP_FE(variant_get_type, NULL)
        PHP_FE(variant_set_type, NULL)
        PHP_FE(variant_cast, NULL)
        { NULL, NULL, NULL }
};

/* {{{ com_dotnet_module_entry
 */
zend_module_entry com_dotnet_module_entry = {
        STANDARD_MODULE_HEADER,
        "com_dotnet",
        com_dotnet_functions,
        PHP_MINIT(com_dotnet),
        PHP_MSHUTDOWN(com_dotnet),
        PHP_RINIT(com_dotnet),
        PHP_RSHUTDOWN(com_dotnet),
        PHP_MINFO(com_dotnet),
        "0.1",
        STANDARD_MODULE_PROPERTIES
};
/* }}} */

#ifdef COMPILE_DL_COM_DOTNET
ZEND_GET_MODULE(com_dotnet)
#endif

/* {{{ PHP_INI
 */
PHP_INI_BEGIN()
    STD_PHP_INI_ENTRY("com.allow_dcom",                         "0", PHP_INI_SYSTEM, 
OnUpdateBool, allow_dcom, zend_com_dotnet_globals, com_dotnet_globals)
    STD_PHP_INI_ENTRY("com.autoregister_verbose",       "0", PHP_INI_ALL, 
OnUpdateBool, autoreg_verbose, zend_com_dotnet_globals, com_dotnet_globals)
    STD_PHP_INI_ENTRY("com.autoregister_typelib",       "0", PHP_INI_ALL, 
OnUpdateBool, autoreg_on, zend_com_dotnet_globals, com_dotnet_globals)
    STD_PHP_INI_ENTRY("com.autoregister_casesensitive", "0", PHP_INI_ALL, 
OnUpdateBool, autoreg_case_sensitive, zend_com_dotnet_globals, com_dotnet_globals)
PHP_INI_END()
/* }}} */

/* {{{ php_com_dotnet_init_globals
 */
static void php_com_dotnet_init_globals(zend_com_dotnet_globals *com_dotnet_globals)
{
        memset(com_dotnet_globals, 0, sizeof(*com_dotnet_globals));
}
/* }}} */

/* {{{ PHP_MINIT_FUNCTION
 */
PHP_MINIT_FUNCTION(com_dotnet)
{
        zend_class_entry ce;

        ZEND_INIT_MODULE_GLOBALS(com_dotnet, php_com_dotnet_init_globals, NULL);
        REGISTER_INI_ENTRIES();

        INIT_CLASS_ENTRY(ce, "variant", NULL);
        ce.create_object = php_com_object_new;
        php_com_variant_class_entry = zend_register_internal_class(&ce TSRMLS_CC);

        INIT_CLASS_ENTRY(ce, "com", NULL);
        ce.create_object = php_com_object_new;
        zend_register_internal_class_ex(&ce, php_com_variant_class_entry, "variant" 
TSRMLS_CC);

        zend_ts_hash_init(&php_com_typelibraries, 0, NULL, php_com_typelibrary_dtor, 
0);

#if HAVE_MSCOREE_H
        INIT_CLASS_ENTRY(ce, "dotnet", NULL);
        ce.create_object = php_com_object_new;
        zend_register_internal_class_ex(&ce, php_com_variant_class_entry, "variant" 
TSRMLS_CC);
#endif

#define COM_CONST(x) REGISTER_LONG_CONSTANT(#x, x, CONST_CS|CONST_PERSISTENT)
        
        COM_CONST(CLSCTX_INPROC_SERVER);
        COM_CONST(CLSCTX_INPROC_HANDLER);
        COM_CONST(CLSCTX_LOCAL_SERVER);
        COM_CONST(CLSCTX_REMOTE_SERVER);
        COM_CONST(CLSCTX_SERVER);
        COM_CONST(CLSCTX_ALL);

        COM_CONST(DISPATCH_METHOD);
        COM_CONST(DISPATCH_PROPERTYGET);
        COM_CONST(DISPATCH_PROPERTYPUT);

        COM_CONST(VT_NULL);
        COM_CONST(VT_EMPTY);
        COM_CONST(VT_UI1);
        COM_CONST(VT_I1);
        COM_CONST(VT_UI2);
        COM_CONST(VT_I2);
        COM_CONST(VT_UI4);
        COM_CONST(VT_I4);
        COM_CONST(VT_R4);
        COM_CONST(VT_R8);
        COM_CONST(VT_BOOL);
        COM_CONST(VT_ERROR);
        COM_CONST(VT_CY);
        COM_CONST(VT_DATE);
        COM_CONST(VT_BSTR);
        COM_CONST(VT_DECIMAL);
        COM_CONST(VT_UNKNOWN);
        COM_CONST(VT_DISPATCH);
        COM_CONST(VT_VARIANT);
        COM_CONST(VT_INT);
        COM_CONST(VT_UINT);
        COM_CONST(VT_ARRAY);
        COM_CONST(VT_BYREF);

        COM_CONST(CP_ACP);
        COM_CONST(CP_MACCP);
        COM_CONST(CP_OEMCP);
        COM_CONST(CP_UTF7);
        COM_CONST(CP_UTF8);
        COM_CONST(CP_SYMBOL);
        COM_CONST(CP_THREAD_ACP);

        COM_CONST(VARCMP_LT);
        COM_CONST(VARCMP_EQ);
        COM_CONST(VARCMP_GT);
        COM_CONST(VARCMP_NULL);

        return SUCCESS;
}
/* }}} */

/* {{{ PHP_MSHUTDOWN_FUNCTION
 */
PHP_MSHUTDOWN_FUNCTION(com_dotnet)
{
        UNREGISTER_INI_ENTRIES();
        zend_ts_hash_destroy(&php_com_typelibraries);
        return SUCCESS;
}
/* }}} */

/* {{{ PHP_RINIT_FUNCTION
 */
PHP_RINIT_FUNCTION(com_dotnet)
{
        return SUCCESS;
}
/* }}} */

/* {{{ PHP_RSHUTDOWN_FUNCTION
 */
PHP_RSHUTDOWN_FUNCTION(com_dotnet)
{
#if HAVE_MSCOREE_H
        if (COMG(dotnet_runtime_stuff)) {
                php_com_dotnet_rshutdown(TSRMLS_C);
        }
#endif
        return SUCCESS;
}
/* }}} */

/* {{{ PHP_MINFO_FUNCTION
 */
PHP_MINFO_FUNCTION(com_dotnet)
{
        php_info_print_table_start();

        php_info_print_table_header(2, "COM support", "enabled");
        php_info_print_table_header(2, "DCOM support", COMG(allow_dcom) ? "enabled" : 
"disabled");

#if HAVE_MSCOREE_H
        php_info_print_table_header(2, ".Net support", "enabled");
#else
        php_info_print_table_header(2, ".Net support", "not present in this build");
#endif

        php_info_print_table_end();

        DISPLAY_INI_ENTRIES();
}
/* }}} */

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */

Index: php-src/ext/com_dotnet/com_handlers.c
+++ php-src/ext/com_dotnet/com_handlers.c
/*
   +----------------------------------------------------------------------+
   | PHP Version 4                                                        |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2003 The PHP Group                                |
   +----------------------------------------------------------------------+
   | This source file is subject to version 3.0 of the PHP license,       |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.php.net/license/3_0.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          |
   | [EMAIL PROTECTED] so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Author: Wez Furlong  <[EMAIL PROTECTED]>                          |
   +----------------------------------------------------------------------+
 */

/* $Id: com_handlers.c,v 1.1 2003/08/14 16:49:55 wez Exp $ */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_com_dotnet.h"
#include "php_com_dotnet_internal.h"
#include "Zend/zend_default_classes.h"

static zval *com_property_read(zval *object, zval *member, zend_bool silent TSRMLS_DC)
{
        zval *return_value;
        php_com_dotnet_object *obj;
        VARIANT v;

        MAKE_STD_ZVAL(return_value);
        ZVAL_NULL(return_value);

        obj = CDNO_FETCH(object);

        if (V_VT(&obj->v) == VT_DISPATCH) {
                VariantInit(&v);

                convert_to_string_ex(&member);
                if (SUCCESS == php_com_do_invoke(obj, Z_STRVAL_P(member), 
Z_STRLEN_P(member),
                                DISPATCH_PROPERTYGET, &v, 0, NULL TSRMLS_CC)) {
                        php_com_zval_from_variant(return_value, &v, obj->code_page 
TSRMLS_CC);
                        VariantClear(&v);
                }
        } else {
                if (!silent) {
                        php_com_throw_exception("this variant has no properties" 
TSRMLS_CC);
                }
        }

        return return_value;
}

static void com_property_write(zval *object, zval *member, zval *value TSRMLS_DC)
{
        php_com_dotnet_object *obj;
        VARIANT v;

        obj = CDNO_FETCH(object);

        if (V_VT(&obj->v) == VT_DISPATCH) {
                VariantInit(&v);

                convert_to_string_ex(&member);
                if (SUCCESS == php_com_do_invoke(obj, Z_STRVAL_P(member), 
Z_STRLEN_P(member),
                                DISPATCH_PROPERTYPUT, &v, 1, &value TSRMLS_CC)) {
                        VariantClear(&v);
                }
        } else {
                php_com_throw_exception("this variant has no properties" TSRMLS_CC);
        }
}

static HRESULT com_get_default_binding(php_com_dotnet_object *obj TSRMLS_DC)
{
        VARDESC *vardesc;
        int i;

        if (!obj->typeinfo) {
                return FAILURE;
        }

        for (i = 0; !obj->have_default_bind; i++) {
                if (FAILED(ITypeInfo_GetVarDesc(obj->typeinfo, i, &vardesc))) {
                        return FAILURE;
                }

                if (vardesc->wVarFlags & VARFLAG_FDEFAULTBIND) {
                        obj->default_bind = (DISPID)vardesc->memid;
                        obj->have_default_bind = 1;
                }

                ITypeInfo_ReleaseVarDesc(obj->typeinfo, vardesc);
        }
        return obj->have_default_bind ? SUCCESS : FAILURE;
}

static zval *com_read_dimension(zval *object, zval *offset TSRMLS_DC)
{
        zval *return_value;
        php_com_dotnet_object *obj;
        VARIANT v;

        MAKE_STD_ZVAL(return_value);
        ZVAL_NULL(return_value);

        obj = CDNO_FETCH(object);

        if (V_VT(&obj->v) == VT_DISPATCH) {
                if (!obj->have_default_bind && !com_get_default_binding(obj 
TSRMLS_CC)) {
                        php_com_throw_exception("this COM object has no default 
property" TSRMLS_CC);
                        return return_value;
                }

                VariantInit(&v);

                if (SUCCESS == php_com_do_invoke_by_id(obj, obj->default_bind,
                                DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, 1, &offset 
TSRMLS_CC)) {
                        php_com_zval_from_variant(return_value, &v, obj->code_page 
TSRMLS_CC);
                        VariantClear(&v);
                }
        } else if (V_ISARRAY(&obj->v)) {
                SAFEARRAY *sa = V_ARRAY(&obj->v);
                UINT dims;
                VARTYPE vt;
                LONG bound_low = 0, bound_high = 0;
                LONG indices[1];

                dims = SafeArrayGetDim(sa);

                if (dims != 1) {
                        php_com_throw_exception("can only handle single dimension 
arrays" TSRMLS_CC);
                        return return_value;
                }

                if (FAILED(SafeArrayGetVartype(sa, &vt)) || vt == VT_EMPTY) {
                        vt = V_VT(&obj->v) & ~VT_ARRAY;
                }
                SafeArrayGetUBound(sa, 1, &bound_high);
                SafeArrayGetLBound(sa, 1, &bound_low);

                convert_to_long(offset);

                /* check bounds */
                if (Z_LVAL_P(offset) < bound_low || Z_LVAL_P(offset) > bound_high) {
                        php_com_throw_exception("index out of bounds" TSRMLS_CC);
                        return return_value;
                }

                indices[0] = Z_LVAL_P(offset);

                VariantInit(&v);
                V_VT(&v) = vt;
                /* store the value into "lVal" member of the variant.
                 * This works because it is a union; since we know the variant
                 * type, we end up with a working variant */
                SafeArrayGetElement(sa, indices, &v.lVal);

                /* now we can set the return value from that element */
                php_com_wrap_variant(return_value, &v, obj->code_page TSRMLS_CC);

                VariantClear(&v);

        } else {
                php_com_throw_exception("this variant is not an array type" TSRMLS_CC);
        }

        return return_value;
}

static void com_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC)
{
        php_com_dotnet_object *obj;
        zval *args[2];
        VARIANT v;

        obj = CDNO_FETCH(object);

        if (V_VT(&obj->v) == VT_DISPATCH) {
                if (!obj->have_default_bind && !com_get_default_binding(obj 
TSRMLS_CC)) {
                        php_com_throw_exception("this COM object has no default 
property" TSRMLS_CC);
                        return;
                }

                args[0] = offset;
                args[1] = value;

                VariantInit(&v);

                if (SUCCESS == php_com_do_invoke_by_id(obj, obj->default_bind,
                                DISPATCH_METHOD|DISPATCH_PROPERTYPUT, &v, 2, args 
TSRMLS_CC)) {
                        VariantClear(&v);
                }
        } else {
                /* TODO: check for safearray */
                php_com_throw_exception("this variant is not an array type" TSRMLS_CC);
        }
}

static zval **com_property_get_ptr(zval *object, zval *member TSRMLS_DC)
{
        zval **prop_ptr;

        prop_ptr = emalloc(sizeof(zval **));
        *prop_ptr = com_property_read(object, member, 0 TSRMLS_CC);
        return prop_ptr;
}

static void com_object_set(zval **property, zval *value TSRMLS_DC)
{
        /* Not yet implemented in the engine */
}

static zval *com_object_get(zval *property TSRMLS_DC)
{
        /* Not yet implemented in the engine */
        return NULL;
}

static int com_property_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
{
        DISPID dispid;
        php_com_dotnet_object *obj;

        obj = CDNO_FETCH(object);

        if (V_VT(&obj->v) == VT_DISPATCH) {
                convert_to_string_ex(&member);
                if (SUCCEEDED(php_com_get_id_of_name(obj, Z_STRVAL_P(member), 
Z_STRLEN_P(member), &dispid TSRMLS_CC))) {
                        /* TODO: distinguish between property and method! */
                        return 1;
                }
        } else {
                /* TODO: check for safearray */
        }

        return 0;
}

static void com_property_delete(zval *object, zval *member TSRMLS_DC)
{
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a 
COM object");
}

static void com_dimension_delete(zval *object, zval *offset TSRMLS_DC)
{
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a 
COM object");
}

static HashTable *com_properties_get(zval *object TSRMLS_DC)
{
        /* TODO: use type-info to get all the names and values ?
         * DANGER: if we do that, there is a strong possibility for
         * infinite recursion when the hash is displayed via var_dump().
         * Perhaps it is best to leave it un-implemented.
         */
        return NULL;
}

static union _zend_function *com_method_get(zval *object, char *name, int len 
TSRMLS_DC)
{
        zend_internal_function *f;
        php_com_dotnet_object *obj;

        /* TODO: cache this */

        obj = CDNO_FETCH(object);

        if (V_VT(&obj->v) != VT_DISPATCH) {
                return NULL;
        }

        f = emalloc(sizeof(zend_internal_function));
        f->type = ZEND_OVERLOADED_FUNCTION;
        f->num_args = 0;
        f->arg_info = NULL;
        f->scope = obj->ce;
        f->fn_flags = 0;
        f->function_name = estrndup(name, len);

        if (obj->typeinfo) {
                /* look for byref params */
                ITypeComp *comp;
                ITypeInfo *TI = NULL;
                DESCKIND kind;
                BINDPTR bindptr;
                OLECHAR *olename;
                ULONG lhash;
                int i;

                if (SUCCEEDED(ITypeInfo_GetTypeComp(obj->typeinfo, &comp))) {
                        olename = php_com_string_to_olestring(name, len, 
obj->code_page TSRMLS_CC);
                        lhash = LHashValOfNameSys(SYS_WIN32, LOCALE_SYSTEM_DEFAULT, 
olename);

                        if (SUCCEEDED(ITypeComp_Bind(comp, olename, lhash, 
INVOKE_FUNC, &TI, &kind, &bindptr))) {
                                switch (kind) {
                                        case DESCKIND_FUNCDESC:
                                                f->arg_info = 
ecalloc(bindptr.lpfuncdesc->cParams, sizeof(zend_arg_info));

                                                for (i = 0; i < 
bindptr.lpfuncdesc->cParams; i++) {
                                                        f->arg_info[i].allow_null = 1;
                                                        if 
(bindptr.lpfuncdesc->lprgelemdescParam[i].paramdesc.wParamFlags & PARAMFLAG_FOUT) {
                                                                
f->arg_info[i].pass_by_reference = 1;
                                                        }
                                                }

                                                f->num_args = 
bindptr.lpfuncdesc->cParams;

                                                ITypeInfo_ReleaseFuncDesc(TI, 
bindptr.lpfuncdesc);
                                                break;

                                        /* these should not happen, but *might* happen 
if the user
                                         * screws up; lets avoid a leak in that case */
                                        case DESCKIND_VARDESC:
                                                ITypeInfo_ReleaseVarDesc(TI, 
bindptr.lpvardesc);
                                                break;
                                        case DESCKIND_TYPECOMP:
                                                ITypeComp_Release(bindptr.lptcomp);
                                                break;
                                }
                                ITypeInfo_Release(TI);
                        }
                        ITypeComp_Release(comp);
                        efree(olename);
                }
        }

        return (union _zend_function*)f;
}

static int com_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
{
        zval **args = NULL;
        php_com_dotnet_object *obj;
        int nargs;
        VARIANT v;
        int ret = FAILURE;

        obj = CDNO_FETCH(getThis());

        if (V_VT(&obj->v) != VT_DISPATCH) {
                //php_com_throw_exception("call to member function of non-object");
                return FAILURE;
        }
        
        nargs = ZEND_NUM_ARGS();

        if (nargs) {
                args = (zval **)emalloc(sizeof(zval *) * nargs);
                zend_get_parameters_array(ht, nargs, args);
        }

        VariantInit(&v);

        if (SUCCESS == php_com_do_invoke(obj, method, -1, 
DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, nargs, args TSRMLS_CC)) {
                php_com_zval_from_variant(return_value, &v, obj->code_page TSRMLS_CC);
                ret = SUCCESS;
                VariantClear(&v);
        }

        if (args) {
                efree(args);
        }

        return ret;
}

static union _zend_function *com_constructor_get(zval *object TSRMLS_DC)
{
        php_com_dotnet_object *obj;
        zend_internal_function *f;

        obj = CDNO_FETCH(object);

        /* TODO: this leaks */
        f = emalloc(sizeof(zend_internal_function));
        f->type = ZEND_INTERNAL_FUNCTION;

        f->function_name = obj->ce->name;
        f->scope = obj->ce;
        f->arg_info = NULL;
        f->num_args = 0;
        f->fn_flags = 0;
#if HAVE_MSCOREE_H
        if (f->function_name[0] == 'd') { /* 'd'otnet */
                f->handler = ZEND_FN(com_dotnet_create_instance);
        } else 
#endif
        if (f->function_name[0] == 'c') { /* 'c'om */
                f->handler = ZEND_FN(com_create_instance);
        } else { /* 'v'ariant */
                f->handler = ZEND_FN(com_variant_create_instance);
        }

        return (union _zend_function*)f;
}

static zend_class_entry *com_class_entry_get(zval *object TSRMLS_DC)
{
        php_com_dotnet_object *obj;
        obj = CDNO_FETCH(object);

        return obj->ce;
}

static int com_class_name_get(zval *object, char **class_name, zend_uint 
*class_name_len, int parent TSRMLS_DC)
{
        php_com_dotnet_object *obj;
        obj = CDNO_FETCH(object);

        *class_name = estrndup(obj->ce->name, obj->ce->name_length);
        *class_name_len = obj->ce->name_length;

        return 0;
}

/* This compares two variants for equality */
static int com_objects_compare(zval *object1, zval *object2 TSRMLS_DC)
{
        php_com_dotnet_object *obja, *objb;
        int ret;
        /* strange header bug problem here... the headers define the proto without the
         * flags parameter.  However, the MSDN docs state that there is a flags 
parameter,
         * and my VC6 won't link unless the code uses the version with 4 parameters.
         * So, we have this declaration here to fix it */
        STDAPI VarCmp(LPVARIANT pvarLeft, LPVARIANT pvarRight, LCID lcid, DWORD flags);

        obja = CDNO_FETCH(object1);
        objb = CDNO_FETCH(object2);

        switch (VarCmp(&obja->v, &objb->v, LOCALE_SYSTEM_DEFAULT, 0)) {
                case VARCMP_LT:
                        ret = -1;
                        break;
                case VARCMP_GT:
                        ret = 1;
                        break;
                case VARCMP_EQ:
                        ret = 0;
                        break;
                default:
                        /* either or both operands are NULL...
                         * not 100% sure how to handle this */
                        ret = -2;
        }

        return ret;
}

static void com_object_cast(zval *readobj, zval *writeobj, int type, int should_free 
TSRMLS_DC)
{
        php_com_dotnet_object *obj;
        VARIANT v;
        VARTYPE vt = VT_EMPTY;

        if (should_free) {
                zval_dtor(writeobj);
        }

        ZVAL_NULL(writeobj);

        obj = CDNO_FETCH(readobj);
        VariantInit(&v);

        if (V_VT(&obj->v) == VT_DISPATCH) {

                if (!obj->have_default_bind && !com_get_default_binding(obj 
TSRMLS_CC)) {
                        return;
                }

                if (FAILURE == php_com_do_invoke_by_id(obj, obj->default_bind,
                                DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, 0, NULL 
TSRMLS_CC)) {
                        return;
                }
        } else {
                VariantCopy(&v, &obj->v);
        }

        switch(type) {
                case IS_LONG:
                        vt = VT_INT;
                        break;
                case IS_DOUBLE:
                        vt = VT_R8;
                        break;
                case IS_BOOL:
                        vt = VT_BOOL;
                        break;
                case IS_STRING:
                        vt = VT_BSTR;
                        break;
        }

        if (vt != VT_EMPTY) {
                VariantChangeType(&v, &v, 0, vt);
        }

        php_com_zval_from_variant(writeobj, &v, obj->code_page TSRMLS_CC);
        VariantClear(&v);
}

zend_object_handlers php_com_object_handlers = {
        ZEND_OBJECTS_STORE_HANDLERS,
        com_property_read,
        com_property_write,
        com_read_dimension,
        com_write_dimension,
        com_property_get_ptr,
        com_property_get_ptr,
        com_object_get,
        com_object_set,
        com_property_exists,
        com_property_delete,
        com_dimension_delete,
        com_properties_get,
        com_method_get,
        com_call_method,
        com_constructor_get,
        com_class_entry_get,
        com_class_name_get,
        com_objects_compare,
        com_object_cast
};

void php_com_object_dtor(void *object, zend_object_handle handle TSRMLS_DC)
{
        php_com_dotnet_object *obj = (php_com_dotnet_object*)object;

        if (obj->typeinfo) {
                ITypeInfo_Release(obj->typeinfo);
                obj->typeinfo = NULL;
        }

        VariantClear(&obj->v);

        efree(obj);
}

void php_com_object_clone(void *object, void **clone_ptr TSRMLS_DC)
{
        php_com_dotnet_object *cloneobj, *origobject;

        origobject = (php_com_dotnet_object*)object;
        cloneobj = (php_com_dotnet_object*)emalloc(sizeof(php_com_dotnet_object));
        
        memcpy(cloneobj, origobject, sizeof(*cloneobj));

        /* VariantCopy will perform VariantClear; we don't want to clobber
         * the IDispatch that we memcpy'd, so we init a new variant in the
         * clone structure */
        VariantInit(&cloneobj->v);
        /* We use the Indirection-following version of the API since we
         * want to clone as much as possible */
        VariantCopyInd(&cloneobj->v, &origobject->v); 

        if (cloneobj->typeinfo) {
                ITypeInfo_AddRef(cloneobj->typeinfo);
        }

        *clone_ptr = cloneobj;
}

zend_object_value php_com_object_new(zend_class_entry *ce TSRMLS_DC)
{
        php_com_dotnet_object *obj;
        zend_object_value retval;

        obj = emalloc(sizeof(*obj));
        memset(obj, 0, sizeof(*obj));

        VariantInit(&obj->v);
        obj->code_page = CP_ACP;
        obj->ce = ce;

        retval.handle = zend_objects_store_put(obj, php_com_object_dtor, 
php_com_object_clone TSRMLS_CC);
        retval.handlers = &php_com_object_handlers;

        return retval;
}

Index: php-src/ext/com_dotnet/com_misc.c
+++ php-src/ext/com_dotnet/com_misc.c
/*
   +----------------------------------------------------------------------+
   | PHP Version 4                                                        |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2003 The PHP Group                                |
   +----------------------------------------------------------------------+
   | This source file is subject to version 3.0 of the PHP license,       |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.php.net/license/3_0.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          |
   | [EMAIL PROTECTED] so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Author: Wez Furlong  <[EMAIL PROTECTED]>                          |
   +----------------------------------------------------------------------+
 */

/* $Id: com_misc.c,v 1.1 2003/08/14 16:49:55 wez Exp $ */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_com_dotnet.h"
#include "php_com_dotnet_internal.h"
#include "Zend/zend_default_classes.h"

zval *php_com_throw_exception(char *message TSRMLS_DC)
{
        zval *e, *tmp;
        
        ALLOC_ZVAL(e);
        Z_TYPE_P(e) = IS_OBJECT;
        object_init_ex(e, zend_exception_get_default());
        e->refcount = 1;
        e->is_ref = 1;

        MAKE_STD_ZVAL(tmp);
        ZVAL_STRING(tmp, message, 1);
        zend_hash_update(Z_OBJPROP_P(e), "message", sizeof("message"), (void**)&tmp, 
sizeof(zval*), NULL);

        MAKE_STD_ZVAL(tmp);
        ZVAL_STRING(tmp, zend_get_executed_filename(TSRMLS_C), 1);
        zend_hash_update(Z_OBJPROP_P(e), "file", sizeof("file"), (void**)&tmp, 
sizeof(zval*), NULL);

        MAKE_STD_ZVAL(tmp);
        ZVAL_LONG(tmp, zend_get_executed_lineno(TSRMLS_C));
        zend_hash_update(Z_OBJPROP_P(e), "line", sizeof("line"), (void**)&tmp, 
sizeof(zval*), NULL);

        EG(exception) = e;

        return e;
}

PHPAPI void php_com_wrap_dispatch(zval *z, IDispatch *disp,
                int codepage TSRMLS_DC)
{
        php_com_dotnet_object *obj;

        obj = emalloc(sizeof(*obj));
        memset(obj, 0, sizeof(*obj));
        obj->code_page = codepage;
        obj->ce = php_com_variant_class_entry;

        VariantInit(&obj->v);
        V_VT(&obj->v) = VT_DISPATCH;
        V_DISPATCH(&obj->v) = disp;

        IDispatch_AddRef(V_DISPATCH(&obj->v));
        IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, LANG_NEUTRAL, &obj->typeinfo);

        Z_TYPE_P(z) = IS_OBJECT;
        z->value.obj.handle = zend_objects_store_put(obj, php_com_object_dtor, 
php_com_object_clone TSRMLS_CC);
        z->value.obj.handlers = &php_com_object_handlers;
}

PHPAPI void php_com_wrap_variant(zval *z, VARIANT *v,
                int codepage TSRMLS_DC)
{
        php_com_dotnet_object *obj;

        obj = emalloc(sizeof(*obj));
        memset(obj, 0, sizeof(*obj));
        obj->code_page = codepage;
        obj->ce = php_com_variant_class_entry;

        VariantInit(&obj->v);
        VariantCopy(&obj->v, v);

        if (V_VT(&obj->v) == VT_DISPATCH) {
                IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, LANG_NEUTRAL, 
&obj->typeinfo);
        }

        Z_TYPE_P(z) = IS_OBJECT;
        
        z->value.obj.handle = zend_objects_store_put(obj, php_com_object_dtor, 
php_com_object_clone TSRMLS_CC);
        z->value.obj.handlers = &php_com_object_handlers;
}

Index: php-src/ext/com_dotnet/com_olechar.c
+++ php-src/ext/com_dotnet/com_olechar.c
/*
   +----------------------------------------------------------------------+
   | PHP Version 4                                                        |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2003 The PHP Group                                |
   +----------------------------------------------------------------------+
   | This source file is subject to version 3.0 of the PHP license,       |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.php.net/license/3_0.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          |
   | [EMAIL PROTECTED] so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Author: Wez Furlong <[EMAIL PROTECTED]>                           |
   |         Harald Radi <[EMAIL PROTECTED]>                                  |
   +----------------------------------------------------------------------+
 */

/* $Id: com_olechar.c,v 1.1 2003/08/14 16:49:55 wez Exp $ */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_com_dotnet.h"
#include "php_com_dotnet_internal.h"


PHPAPI OLECHAR *php_com_string_to_olestring(char *string, uint string_len, int 
codepage TSRMLS_DC)
{
        OLECHAR *olestring = NULL;
        DWORD flags = codepage == CP_UTF8 ? 0 : MB_PRECOMPOSED | MB_ERR_INVALID_CHARS;
        BOOL ok;

        if (string_len == -1) {
                /* determine required length for the buffer (includes NUL terminator) 
*/
                string_len = MultiByteToWideChar(codepage, flags, string, -1, NULL, 0);
        } else {
                /* allow room for NUL terminator */
                string_len++;
        }

        if (strlen > 0) {
                olestring = (OLECHAR*)emalloc(sizeof(OLECHAR) * string_len);
                ok = MultiByteToWideChar(codepage, flags, string, string_len, 
olestring, string_len);
        } else {
                ok = FALSE;
                olestring = (OLECHAR*)emalloc(sizeof(OLECHAR));
                *olestring = 0;
        }

        if (!ok) {
                char *msg = php_win_err(GetLastError());

                php_error_docref(NULL TSRMLS_CC, E_WARNING,
                        "Could not convert string to unicode: `%s'", msg);

                LocalFree(msg);
        }

        return olestring;
}

PHPAPI char *php_com_olestring_to_string(OLECHAR *olestring, uint *string_len, int 
codepage TSRMLS_DC)
{
        char *string;
        uint length = 0;
        BOOL ok;
        LONG err;

        length = WideCharToMultiByte(codepage, 0, olestring, -1, NULL, 0, NULL, NULL);

        if (length) {
                string = (char*)emalloc(sizeof(char) * length);
                length = WideCharToMultiByte(codepage, 0, olestring, -1, string, 
length, NULL, NULL);
                ok = length > 0;
        } else {
                err = GetLastError();
                string = (char*)emalloc(sizeof(char));
                *string = '\0';
                ok = FALSE;
                length = 0;
        }

        if (!ok) {
                char *msg = php_win_err(err);

                php_error_docref(NULL TSRMLS_CC, E_WARNING,
                        "Could not convert string from unicode: `%s'", msg);

                LocalFree(msg);
        }

        if (string_len) {
                *string_len = length-1;
        }

        return string;
}
Index: php-src/ext/com_dotnet/com_typeinfo.c
+++ php-src/ext/com_dotnet/com_typeinfo.c
/*
   +----------------------------------------------------------------------+
   | PHP Version 4                                                        |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2003 The PHP Group                                |
   +----------------------------------------------------------------------+
   | This source file is subject to version 3.0 of the PHP license,       |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.php.net/license/3_0.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          |
   | [EMAIL PROTECTED] so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Author: Wez Furlong <[EMAIL PROTECTED]>                           |
   |         Harald Radi <[EMAIL PROTECTED]>                                  |
   +----------------------------------------------------------------------+
 */

/* $Id: com_typeinfo.c,v 1.1 2003/08/14 16:49:55 wez Exp $ */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_com_dotnet.h"
#include "php_com_dotnet_internal.h"


/* The search string can be either:
 * a) a file name
 * b) a CLSID, major, minor e.g. "{00000200-0000-0010-8000-00AA006D2EA4},2,0"
 * c) a Type Library name e.g. "Microsoft OLE DB ActiveX Data Objects 1.0 Library"
 */
PHPAPI ITypeLib *php_com_load_typelib(char *search_string, int mode,
                int codepage TSRMLS_DC)
{
        ITypeLib *TL = NULL;
        char *strtok_buf, *major, *minor;
        CLSID clsid;
        OLECHAR *p;
        HRESULT hr;

        search_string = php_strtok_r(search_string, ",", &strtok_buf);

        if (search_string == NULL) {
                return NULL;
        }

        major = php_strtok_r(NULL, ",", &strtok_buf);
        minor = php_strtok_r(NULL, ",", &strtok_buf);

        p = php_com_string_to_olestring(search_string, strlen(search_string), codepage 
TSRMLS_CC);

        if (SUCCEEDED(CLSIDFromString(p, &clsid))) {
                WORD major_i = 1, minor_i = 0;

                /* pick up the major/minor numbers; if none specified, default to 1,0 
*/
                if (major && minor) {
                        major_i = (WORD)atoi(major);
                        minor_i = (WORD)atoi(minor);
                }

                /* Load the TypeLib by GUID */
                hr = LoadRegTypeLib((REFGUID)&clsid, major_i, minor_i, LANG_NEUTRAL, 
&TL);

                /* if that failed, assumed that the GUID is actually a CLSID and
                 * attemp to get the library via an instance of that class */
                if (FAILED(hr) && (major == NULL || minor == NULL)) {
                        IDispatch *disp = NULL;
                        ITypeInfo *info = NULL;
                        int idx;

                        if (SUCCEEDED(hr = CoCreateInstance(&clsid, NULL, 
CLSCTX_SERVER, &IID_IDispatch, (LPVOID*)&disp)) &&
                                        SUCCEEDED(hr = IDispatch_GetTypeInfo(disp, 0, 
LANG_NEUTRAL, &info))) {
                                hr = ITypeInfo_GetContainingTypeLib(info, &TL, &idx);
                        }

                        if (info) {
                                ITypeInfo_Release(info);
                        }
                        if (disp) {
                                IDispatch_Release(disp);
                        }
                }
        } else {
                /* Try to load it from a file; if it fails, do a really painful search 
of
                 * the registry */
                if (FAILED(LoadTypeLib(p, &TL))) {
                        HKEY hkey, hsubkey;
                        DWORD SubKeys, MaxSubKeyLength;
                        char *keyname;
                        unsigned int i, j;
                        DWORD VersionCount;
                        char version[20];
                        char *libname;
                        DWORD libnamelen;

                        if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, 
"TypeLib", 0, KEY_READ, &hkey) &&
                                        ERROR_SUCCESS == RegQueryInfoKey(hkey, NULL, 
NULL, NULL, &SubKeys,
                                        &MaxSubKeyLength, NULL, NULL, NULL, NULL, 
NULL, NULL)) {

                                MaxSubKeyLength++; /* make room for NUL */
                                keyname = emalloc(MaxSubKeyLength);
                                libname = emalloc(strlen(search_string) + 1);

                                for (i = 0; i < SubKeys && TL == NULL; i++) {
                                        if (ERROR_SUCCESS == RegEnumKey(hkey, i, 
keyname, MaxSubKeyLength) &&
                                                        ERROR_SUCCESS == 
RegOpenKeyEx(hkey, keyname, 0, KEY_READ, &hsubkey)) {
                                                if (ERROR_SUCCESS == 
RegQueryInfoKey(hsubkey, NULL, NULL, NULL, &VersionCount,
                                                                NULL, NULL, NULL, 
NULL, NULL, NULL, NULL)) {
                                                        for (j = 0; j < VersionCount; 
j++) {
                                                                if (ERROR_SUCCESS != 
RegEnumKey(hsubkey, j, version, sizeof(version))) {
                                                                        continue;
                                                                }
                                                                /* get the default 
value for this key and compare */
                                                                libnamelen = 
strlen(search_string)+1;
                                                                if (ERROR_SUCCESS == 
RegQueryValue(hsubkey, version, libname, &libnamelen)) {
                                                                        if (0 == 
((mode & CONST_CS) ? strcmp(libname, search_string) : stricmp(libname, 
search_string))) {
                                                                                char 
*str = NULL;
                                                                                int 
major, minor;

                                                                                /* 
fetch the GUID and add the version numbers */
                                                                                if (2 
!= sscanf(version, "%d.%d", &major, &minor)) {
                                                                                       
 major = 1;
                                                                                       
 minor = 0;
                                                                                }
                                                                                
spprintf(&str, 0, "%s,%d,%d", keyname, major, minor);
                                                                                /* 
recurse */
                                                                                TL = 
php_com_load_typelib(str, mode, codepage TSRMLS_CC);

                                                                                
efree(str);
                                                                                break;
                                                                        }
                                                                }
                                                        }
                                                }
                                                RegCloseKey(hsubkey);
                                        }
                                }
                                RegCloseKey(hkey);
                                efree(keyname);
                                efree(libname);
                        }
                }
        }
        
        efree(p);

        return TL;
}

/* Given a type-library, merge it into the current engine state */
PHPAPI int php_com_import_typelib(ITypeLib *TL, int mode, int codepage TSRMLS_DC)
{
        int i, j, interfaces;
        TYPEKIND pTKind;
        ITypeInfo *TypeInfo;
        VARDESC *pVarDesc;
        UINT NameCount;
        BSTR bstr_ids;
        zend_constant c;
        zval exists, results, value;
        char *const_name;

        if (TL == NULL) {
                return FAILURE;
        }

        interfaces = ITypeLib_GetTypeInfoCount(TL);
        for (i = 0; i < interfaces; i++) {
                ITypeLib_GetTypeInfoType(TL, i, &pTKind);
                if (pTKind == TKIND_ENUM) {
                        ITypeLib_GetTypeInfo(TL, i, &TypeInfo);
                        for (j = 0; ; j++) {
                                if (FAILED(ITypeInfo_GetVarDesc(TypeInfo, j, 
&pVarDesc))) {
                                        break;
                                }
                                ITypeInfo_GetNames(TypeInfo, pVarDesc->memid, 
&bstr_ids, 1, &NameCount);
                                if (NameCount != 1) {
                                        ITypeInfo_ReleaseVarDesc(TypeInfo, pVarDesc);
                                        continue;
                                }

                                const_name = php_com_olestring_to_string(bstr_ids, 
&c.name_len, codepage TSRMLS_CC);
                                c.name = zend_strndup(const_name, c.name_len);
                                efree(const_name);
                                c.name_len++; /* include NUL */
                                SysFreeString(bstr_ids);

                                /* sanity check for the case where the constant is 
already defined */
                                if (zend_get_constant(c.name, c.name_len - 1, &exists 
TSRMLS_CC)) {
                                        if (COMG(autoreg_verbose) && 
!compare_function(&results, &c.value, &exists TSRMLS_CC)) {
                                                php_error_docref(NULL TSRMLS_CC, 
E_WARNING, "Type library constant %s is already defined", c.name);
                                        }
                                        free(c.name);
                                        ITypeInfo_ReleaseVarDesc(TypeInfo, pVarDesc);
                                        continue;
                                }

                                /* register the constant */
                                php_com_zval_from_variant(&value, 
pVarDesc->lpvarValue, codepage TSRMLS_CC);
                                if (Z_TYPE(value) == IS_LONG) {
                                        c.flags = mode;
                                        c.value.type = IS_LONG;
                                        c.value.value.lval = Z_LVAL(value);
                                        c.module_number = 0;
                                        zend_register_constant(&c TSRMLS_CC);
                                }
                                ITypeInfo_ReleaseVarDesc(TypeInfo, pVarDesc);
                        }
                        ITypeInfo_Release(TypeInfo);
                }
        }
        return SUCCESS;
}

/* Type-library stuff */
void php_com_typelibrary_dtor(void *pDest)
{
        ITypeLib *Lib = *(ITypeLib**)pDest;
        ITypeLib_Release(Lib);
}

PHPAPI ITypeLib *php_com_load_typelib_via_cache(char *search_string,
        int mode, int codepage, int *cached TSRMLS_DC)
{
        ITypeLib **TL;
        char *name_dup;
        int l;

        l = strlen(search_string);

        if (zend_ts_hash_find(&php_com_typelibraries, search_string, l+1,
                        (void**)&TL) == SUCCESS) {
                *cached = 1;
                /* add a reference for the caller */
                ITypeLib_AddRef(*TL);
                return *TL;
        }

        *cached = 0;
        name_dup = estrndup(search_string, l);
        *TL = php_com_load_typelib(name_dup, mode, codepage TSRMLS_CC);
        efree(name_dup);

        if (*TL) {
                if (SUCCESS == zend_ts_hash_update(&php_com_typelibraries,
                                search_string, l+1, (void*)*TL, sizeof(ITypeLib*), 
NULL)) {
                        /* add a reference for the hash table */
                        ITypeLib_AddRef(*TL);
                }
        }

        return *TL;
}

Index: php-src/ext/com_dotnet/com_variant.c
+++ php-src/ext/com_dotnet/com_variant.c
/*
   +----------------------------------------------------------------------+
   | PHP Version 4                                                        |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2003 The PHP Group                                |
   +----------------------------------------------------------------------+
   | This source file is subject to version 3.0 of the PHP license,       |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.php.net/license/3_0.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          |
   | [EMAIL PROTECTED] so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Author: Wez Furlong <[EMAIL PROTECTED]>                           |
   +----------------------------------------------------------------------+
 */

/* $Id: com_variant.c,v 1.1 2003/08/14 16:49:55 wez Exp $ */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_com_dotnet.h"
#include "php_com_dotnet_internal.h"

PHPAPI void php_com_variant_from_zval(VARIANT *v, zval *z, int codepage TSRMLS_DC)
{
        OLECHAR *olestring;
        php_com_dotnet_object *obj;
        
        switch (Z_TYPE_P(z)) {
                case IS_NULL:
                        V_VT(v) = VT_NULL;
                        break;

                case IS_BOOL:
                        V_VT(v) = VT_BOOL;
                        V_BOOL(v) = Z_BVAL_P(z) ? VARIANT_TRUE : VARIANT_FALSE;
                        break;

                case IS_OBJECT:
                        if (php_com_is_valid_object(z TSRMLS_CC)) {
                                obj = CDNO_FETCH(z);
                                if (V_VT(&obj->v) == VT_DISPATCH) {
                                        /* pass the underlying object */
                                        V_VT(v) = VT_DISPATCH;
                                        if (V_DISPATCH(&obj->v)) {
                                                IDispatch_AddRef(V_DISPATCH(&obj->v));
                                        }
                                        V_DISPATCH(v) = V_DISPATCH(&obj->v);
                                } else {
                                        /* pass the variant by reference */
                                        V_VT(v) = VT_VARIANT | VT_BYREF;
                                        V_VARIANTREF(v) = &obj->v;
                                }
                        } else {
                                /* TODO: export the object using our COM wrapper */
                                V_VT(v) = VT_NULL;
                        }
                        break;
                        
                case IS_ARRAY:
                        V_VT(v) = VT_NULL;
                        /* TODO: map as safe array ? */
                        break;

                case IS_LONG:
                        V_VT(v) = VT_I4;
                        V_I4(v) = Z_LVAL_P(z);
                        break;

                case IS_DOUBLE:
                        V_VT(v) = VT_R8;
                        V_R8(v) = Z_DVAL_P(z);
                        break;

                case IS_STRING:
                        V_VT(v) = VT_BSTR;
                        olestring = php_com_string_to_olestring(Z_STRVAL_P(z), 
Z_STRLEN_P(z), codepage TSRMLS_CC);
                        V_BSTR(v) = SysAllocStringByteLen((char*)olestring, 
Z_STRLEN_P(z) * sizeof(OLECHAR));
                        efree(olestring);
                        break;

                case IS_RESOURCE:
                case IS_CONSTANT:
                case IS_CONSTANT_ARRAY:
                default:
                        V_VT(v) = VT_NULL;
                        break;
        }
}

PHPAPI int php_com_zval_from_variant(zval *z, VARIANT *v, int codepage TSRMLS_DC)
{
        OLECHAR *olestring = NULL;
        int ret = SUCCESS;
        SYSTEMTIME systime;
        struct tm tmv;
        php_com_dotnet_object *obj;

        switch (V_VT(v)) {
                case VT_EMPTY:
                case VT_NULL:
                case VT_VOID:
                        ZVAL_NULL(z);
                        break;
                case VT_UI1:
                        ZVAL_LONG(z, (long)V_UI1(v));
                        break;
                case VT_I1:
                        ZVAL_LONG(z, (long)V_I1(v));
                        break;
                case VT_UI2:
                        ZVAL_LONG(z, (long)V_UI2(v));
                        break;
                case VT_I2:
                        ZVAL_LONG(z, (long)V_I2(v));
                        break;
                case VT_UI4:  /* TODO: promote to double if large? */
                        ZVAL_LONG(z, (long)V_UI4(v));
                        break;
                case VT_I4:
                        ZVAL_LONG(z, (long)V_I4(v));
                        break;
                case VT_INT:
                        ZVAL_LONG(z, V_INT(v));
                        break;
                case VT_UINT: /* TODO: promote to double if large? */
                        ZVAL_LONG(z, (long)V_UINT(v));
                        break;
                case VT_R4:
                        ZVAL_DOUBLE(z, (double)V_R4(v));
                        break;
                case VT_R8:
                        ZVAL_DOUBLE(z, V_R8(v));
                        break;
                case VT_BOOL:
                        ZVAL_BOOL(z, V_BOOL(v) ? 1 : 0);
                        break;
                case VT_BSTR:
                        olestring = V_BSTR(v);
                        if (olestring) {
                                Z_TYPE_P(z) = IS_STRING;
                                Z_STRVAL_P(z) = php_com_olestring_to_string(olestring,
                                        &Z_STRLEN_P(z), codepage TSRMLS_CC);
                                olestring = NULL;
                        }
                        break;
                case VT_UNKNOWN:
                        if (V_UNKNOWN(v) != NULL) {
                                IDispatch *disp;

                                if (SUCCEEDED(IUnknown_QueryInterface(V_UNKNOWN(v), 
&IID_IDispatch, &disp))) {
                                        php_com_wrap_dispatch(z, disp, codepage 
TSRMLS_CC);
                                        IDispatch_Release(disp);
                                } else {
                                        ret = FAILURE;
                                }
                        }
                        break;

                case VT_DISPATCH:
                        if (V_DISPATCH(v) != NULL) {
                                php_com_wrap_dispatch(z, V_DISPATCH(v), codepage 
TSRMLS_CC);
                        }
                        break;

                case VT_VARIANT:
                default:
                        php_com_wrap_variant(z, v, codepage TSRMLS_CC);
        }

        if (olestring) {
                efree(olestring);
        }

        if (ret == FAILURE) {
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "variant->zval: conversion 
from 0x%x ret=%d", V_VT(v), ret);
        }

        return ret;
}

/* {{{ com_variant_create_instance - ctor for new VARIANT() */
PHP_FUNCTION(com_variant_create_instance)
{
        VARTYPE vt = VT_EMPTY;
        long codepage = CP_ACP;
        zval *object = getThis();
        php_com_dotnet_object *obj;
        zval *zvalue = NULL;
        HRESULT res;

        if (ZEND_NUM_ARGS() == 0) {
                /* just leave things as-is - an empty variant */
                return;
        }
        
        obj = CDNO_FETCH(object);
        
        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
                "z!|ll", &zvalue, &vt, &codepage)) {
                        php_com_throw_exception("Invalid arguments" TSRMLS_CC);
                        return;
        }

        if (ZEND_NUM_ARGS() == 3) {
                obj->code_page = codepage;
        }

        php_com_variant_from_zval(&obj->v, zvalue, obj->code_page TSRMLS_CC);

        if (ZEND_NUM_ARGS() >= 2) {

                res = VariantChangeType(&obj->v, &obj->v, 0, vt);

                if (FAILED(res)) {
                        char *werr, *msg;

                        werr = php_win_err(res);
                        spprintf(&msg, 0, "Variant type conversion failed: %s", werr);
                        LocalFree(werr);

                        php_com_throw_exception(msg TSRMLS_CC);
                        efree(msg);
                }
        }

        if (V_VT(&obj->v) != VT_DISPATCH && obj->typeinfo) {
                ITypeInfo_Release(obj->typeinfo);
                obj->typeinfo = NULL;
        }
}
/* }}} */

/* {{{ proto void variant_set(object variant, mixed value)
   Assigns a new value for a variant object (like "set" in VB) */
PHP_FUNCTION(variant_set)
{
        zval *zobj, *zvalue = NULL;
        php_com_dotnet_object *obj;

        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
                        "Oz!", &zobj, php_com_variant_class_entry, &zvalue)) {
                return;
        }

        obj = CDNO_FETCH(zobj);

        /* dtor the old value */
        if (obj->typeinfo) {
                ITypeInfo_Release(obj->typeinfo);
                obj->typeinfo = NULL;
        }

        VariantClear(&obj->v);

        php_com_variant_from_zval(&obj->v, zvalue, obj->code_page TSRMLS_CC);
}
/* }}} */

enum variant_binary_opcode {
        VOP_ADD, VOP_CAT, VOP_SUB, VOP_MUL, VOP_AND, VOP_DIV,
        VOP_EQV, VOP_IDIV, VOP_IMP, VOP_MOD, VOP_OR, VOP_POW,
        VOP_XOR
};

enum variant_unary_opcode {
        VOP_ABS, VOP_FIX, VOP_INT, VOP_NEG, VOP_NOT
};

static void variant_binary_operation(enum variant_binary_opcode op, 
INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
{
        VARIANT vres;
        VARIANT left_val, right_val;
        VARIANT *vleft = NULL, *vright = NULL;
        zval *zleft = NULL, *zright = NULL;
        php_com_dotnet_object *obj;
        HRESULT result;
        int codepage = CP_ACP;

        VariantInit(&left_val);
        VariantInit(&right_val);
        VariantInit(&vres);

        if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
                        ZEND_NUM_ARGS() TSRMLS_CC, "OO", &zleft, 
php_com_variant_class_entry,
                        &zright, php_com_variant_class_entry)) {
                obj = CDNO_FETCH(zleft);
                vleft = &obj->v;
                obj = CDNO_FETCH(zright);
                vright = &obj->v;
        } else if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
                        ZEND_NUM_ARGS() TSRMLS_CC, "Oz!", &zleft, 
php_com_variant_class_entry,
                        &zright)) {
                obj = CDNO_FETCH(zleft);
                vleft = &obj->v;
                vright = &right_val;
                php_com_variant_from_zval(vright, zright, codepage TSRMLS_CC);
        } else if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
                        ZEND_NUM_ARGS() TSRMLS_CC, "z!O", &zleft, &zright, 
php_com_variant_class_entry)) {
                obj = CDNO_FETCH(zright);
                vright = &obj->v;
                vleft = &left_val;
                php_com_variant_from_zval(vleft, zleft, codepage TSRMLS_CC);
        } else if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
                        "z!z!", &zleft, &zright)) {

                vleft = &left_val;
                php_com_variant_from_zval(vleft, zleft, codepage TSRMLS_CC);

                vright = &right_val;
                php_com_variant_from_zval(vright, zright, codepage TSRMLS_CC);

        } else {
                return;
        }

        switch (op) {
                case VOP_ADD:
                        result = VarAdd(vleft, vright, &vres);
                        break;
                case VOP_CAT:
                        result = VarCat(vleft, vright, &vres);
                        break;
                case VOP_SUB:
                        result = VarSub(vleft, vright, &vres);
                        break;
                case VOP_MUL:
                        result = VarMul(vleft, vright, &vres);
                        break;
                case VOP_AND:
                        result = VarAnd(vleft, vright, &vres);
                        break;
                case VOP_DIV:
                        result = VarDiv(vleft, vright, &vres);
                        break;
                case VOP_EQV:
                        result = VarEqv(vleft, vright, &vres);
                        break;
                case VOP_IDIV:
                        result = VarIdiv(vleft, vright, &vres);
                        break;
                case VOP_IMP:
                        result = VarImp(vleft, vright, &vres);
                        break;
                case VOP_MOD:
                        result = VarMod(vleft, vright, &vres);
                        break;
                case VOP_OR:
                        result = VarOr(vleft, vright, &vres);
                        break;
                case VOP_POW:
                        result = VarPow(vleft, vright, &vres);
                        break;
                case VOP_XOR:
                        result = VarXor(vleft, vright, &vres);
                        break;
        }

        if (SUCCEEDED(result)) {
                php_com_wrap_variant(return_value, &vres, codepage TSRMLS_CC);
        }

        VariantClear(&vres);
        VariantClear(&left_val);
        VariantClear(&right_val);
}
/* }}} */

/* {{{ proto mixed variant_add(mixed left, mixed right)
   "Adds" two variant values together and returns the result */
PHP_FUNCTION(variant_add)
{
        variant_binary_operation(VOP_ADD, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */

/* {{{ proto mixed variant_cat(mixed left, mixed right)
   concatenates two variant values together and returns the result */
PHP_FUNCTION(variant_cat)
{
        variant_binary_operation(VOP_CAT, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */

/* {{{ proto mixed variant_sub(mixed left, mixed right)
   subjects the value of the right variant from the left variant value and returns the 
result */
PHP_FUNCTION(variant_sub)
{
        variant_binary_operation(VOP_SUB, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */

/* {{{ proto mixed variant_mul(mixed left, mixed right)
   multiplies the values of the two variants and returns the result */
PHP_FUNCTION(variant_mul)
{
        variant_binary_operation(VOP_MUL, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */

/* {{{ proto mixed variant_and(mixed left, mixed right)
   performs a bitwise AND operation between two variants and returns the result */
PHP_FUNCTION(variant_and)
{
        variant_binary_operation(VOP_AND, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */

/* {{{ proto mixed variant_div(mixed left, mixed right)
   Returns the result from dividing two variants */
PHP_FUNCTION(variant_div)
{
        variant_binary_operation(VOP_DIV, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */

/* {{{ proto mixed variant_eqv(mixed left, mixed right)
   Performs a bitwise equivalence on two variants */
PHP_FUNCTION(variant_eqv)
{
        variant_binary_operation(VOP_EQV, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */

/* {{{ proto mixed variant_idiv(mixed left, mixed right)
   Converts variants to operands and then returns the result from dividing them */
PHP_FUNCTION(variant_idiv)
{
        variant_binary_operation(VOP_IDIV, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */

/* {{{ proto mixed variant_imp(mixed left, mixed right)
   Performs a bitwise implication on two variants */
PHP_FUNCTION(variant_imp)
{
        variant_binary_operation(VOP_IMP, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */

/* {{{ proto mixed variant_mod(mixed left, mixed right)
   Divides two variants and returns only the remainder */
PHP_FUNCTION(variant_mod)
{
        variant_binary_operation(VOP_MOD, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */

/* {{{ proto mixed variant_or(mixed left, mixed right)
   Performs a logical disjunction on two variants */
PHP_FUNCTION(variant_or)
{
        variant_binary_operation(VOP_OR, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */

/* {{{ proto mixed variant_pow(mixed left, mixed right)
   Returns the result of performing the power function with two variants */
PHP_FUNCTION(variant_pow)
{
        variant_binary_operation(VOP_POW, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */

/* {{{ proto mixed variant_xor(mixed left, mixed right)
   Performs a logical exclusion on two variants */
PHP_FUNCTION(variant_xor)
{
        variant_binary_operation(VOP_XOR, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */

static void variant_unary_operation(enum variant_unary_opcode op, 
INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
{
        VARIANT vres;
        VARIANT left_val;
        VARIANT *vleft = NULL;
        zval *zleft = NULL;
        php_com_dotnet_object *obj;
        HRESULT result;
        int codepage = CP_ACP;

        VariantInit(&left_val);
        VariantInit(&vres);

        if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
                        ZEND_NUM_ARGS() TSRMLS_CC, "O", &zleft, 
php_com_variant_class_entry)) {
                obj = CDNO_FETCH(zleft);
                vleft = &obj->v;
        } else if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
                        "z!", &zleft)) {
                vleft = &left_val;
                php_com_variant_from_zval(vleft, zleft, codepage TSRMLS_CC);
        } else {
                return;
        }

        switch (op) {
                case VOP_ABS:
                        result = VarAbs(vleft, &vres);
                        break;
                case VOP_FIX:
                        result = VarFix(vleft, &vres);
                        break;
                case VOP_INT:
                        result = VarInt(vleft, &vres);
                        break;
                case VOP_NEG:
                        result = VarNeg(vleft, &vres);
                        break;
                case VOP_NOT:
                        result = VarNot(vleft, &vres);
                        break;
        }

        if (SUCCEEDED(result)) {
                php_com_wrap_variant(return_value, &vres, codepage TSRMLS_CC);
        }

        VariantClear(&vres);
        VariantClear(&left_val);
}
/* }}} */

/* {{{ proto mixed variant_abs(mixed left)
   Returns the absolute value of a variant */
PHP_FUNCTION(variant_abs)
{
        variant_unary_operation(VOP_ABS, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */

/* {{{ proto mixed variant_fix(mixed left)
   Returns the ? of a variant */
PHP_FUNCTION(variant_fix)
{
        variant_unary_operation(VOP_FIX, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */

/* {{{ proto mixed variant_int(mixed left)
   Returns the integer portion of a variant */
PHP_FUNCTION(variant_int)
{
        variant_unary_operation(VOP_INT, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */

/* {{{ proto mixed variant_neg(mixed left)
   Performs logical negation on a variant */
PHP_FUNCTION(variant_neg)
{
        variant_unary_operation(VOP_NEG, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */

/* {{{ proto mixed variant_not(mixed left)
   Performs bitwise not negation on a variant */
PHP_FUNCTION(variant_not)
{
        variant_unary_operation(VOP_NOT, INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */

/* {{{ proto mixed variant_round(mixed left, int decimals)
   Rounds a variant to the specified number of decimal places */
PHP_FUNCTION(variant_round)
{
        VARIANT vres;
        VARIANT left_val;
        VARIANT *vleft = NULL;
        zval *zleft = NULL;
        php_com_dotnet_object *obj;
        HRESULT result;
        int codepage = CP_ACP;
        long decimals = 0;

        VariantInit(&left_val);
        VariantInit(&vres);

        if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
                        ZEND_NUM_ARGS() TSRMLS_CC, "Ol", &zleft, 
php_com_variant_class_entry, &decimals)) {
                obj = CDNO_FETCH(zleft);
                vleft = &obj->v;
        } else if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
                        "z!l", &zleft, &decimals)) {
                vleft = &left_val;
                php_com_variant_from_zval(vleft, zleft, codepage TSRMLS_CC);
        } else {
                return;
        }

        if (SUCCEEDED(VarRound(vleft, decimals, &vres))) {
                php_com_wrap_variant(return_value, &vres, codepage TSRMLS_CC);
        }

        VariantClear(&vres);
        VariantClear(&left_val);
}
/* }}} */

/* {{{ proto int variant_cmp(mixed left, mixed right [, int lcid [, int flags]])
   Compares two variants */
PHP_FUNCTION(variant_cmp)
{
        VARIANT left_val, right_val;
        VARIANT *vleft = NULL, *vright = NULL;
        zval *zleft = NULL, *zright = NULL;
        php_com_dotnet_object *obj;
        HRESULT result;
        int codepage = CP_ACP;
        long lcid = LOCALE_SYSTEM_DEFAULT;
        long flags = 0;
        /* it is safe to ignore the warning for this line; see the comments in 
com_handlers.c */
        STDAPI VarCmp(LPVARIANT pvarLeft, LPVARIANT pvarRight, LCID lcid, DWORD flags);

        VariantInit(&left_val);
        VariantInit(&right_val);

        if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
                        ZEND_NUM_ARGS() TSRMLS_CC, "OO|ll", &zleft, 
php_com_variant_class_entry,
                        &zright, php_com_variant_class_entry, &lcid, &flags)) {
                obj = CDNO_FETCH(zleft);
                vleft = &obj->v;
                obj = CDNO_FETCH(zright);
                vright = &obj->v;
        } else if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
                        ZEND_NUM_ARGS() TSRMLS_CC, "Oz!|ll", &zleft, 
php_com_variant_class_entry,
                        &zright, &lcid, &flags)) {
                obj = CDNO_FETCH(zleft);
                vleft = &obj->v;
                vright = &right_val;
                php_com_variant_from_zval(vright, zright, codepage TSRMLS_CC);
        } else if (SUCCESS == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
                        ZEND_NUM_ARGS() TSRMLS_CC, "z!O|ll", &zleft, &zright, 
php_com_variant_class_entry,
                        &lcid, &flags)) {
                obj = CDNO_FETCH(zright);
                vright = &obj->v;
                vleft = &left_val;
                php_com_variant_from_zval(vleft, zleft, codepage TSRMLS_CC);
        } else if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
                        "z!z!|ll", &zleft, &zright, &lcid, &flags)) {

                vleft = &left_val;
                php_com_variant_from_zval(vleft, zleft, codepage TSRMLS_CC);

                vright = &right_val;
                php_com_variant_from_zval(vright, zright, codepage TSRMLS_CC);

        } else {
                return;
        }

        ZVAL_LONG(return_value, VarCmp(vleft, vright, lcid, flags));

        VariantClear(&left_val);
        VariantClear(&right_val);
}
/* }}} */

/* {{{ proto int variant_date_to_timestamp(object variant)
   Converts a variant date/time value to unix timestamp */
PHP_FUNCTION(variant_date_to_timestamp)
{
        VARIANT vres;
        zval *zleft = NULL;
        php_com_dotnet_object *obj;

        VariantInit(&vres);

        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
                "O", &zleft, php_com_variant_class_entry)) {
                return;
        }
        obj = CDNO_FETCH(zleft);

        if (SUCCEEDED(VariantChangeType(&vres, &obj->v, 0, VT_DATE))) {
                SYSTEMTIME systime;
                struct tm tmv;

                VariantTimeToSystemTime(V_DATE(&vres), &systime);

                memset(&tmv, 0, sizeof(tmv));
                tmv.tm_year = systime.wYear - 1900;
                tmv.tm_mon = systime.wMonth - 1;
                tmv.tm_mday = systime.wDay;
                tmv.tm_hour = systime.wHour;
                tmv.tm_min = systime.wMinute;
                tmv.tm_sec = systime.wSecond;
                tmv.tm_isdst = -1;

                tzset();
                RETVAL_LONG(mktime(&tmv));
        }

        VariantClear(&vres);
}
/* }}} */

/* {{{ proto object variant_date_from_timestamp(int timestamp)
   Returns a variant date representation of a unix timestamp */
PHP_FUNCTION(variant_date_from_timestamp)
{
        int timestamp;
        SYSTEMTIME systime;
        struct tm *tmv;
        VARIANT res;

        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l",
                        &timestamp)) {
                return;
        }

        VariantInit(&res);
        tmv = gmtime(&timestamp);
        memset(&systime, 0, sizeof(systime));

        systime.wDay = tmv->tm_mday;
        systime.wHour = tmv->tm_hour;
        systime.wMinute = tmv->tm_min;
        systime.wMonth = tmv->tm_mon + 1;
        systime.wSecond = tmv->tm_sec;
        systime.wYear = tmv->tm_year + 1900;

        V_VT(&res) = VT_DATE;
        SystemTimeToVariantTime(&systime, &V_DATE(&res));

        php_com_wrap_variant(return_value, &res, CP_ACP TSRMLS_CC);

        VariantClear(&res);
}
/* }}} */

/* {{{ proto int variant_get_type(object variant)
   Returns the VT_XXX type code for a variant */
PHP_FUNCTION(variant_get_type)
{
        zval *zobj;
        php_com_dotnet_object *obj;

        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
                "O", &zobj, php_com_variant_class_entry)) {
                return;
        }
        obj = CDNO_FETCH(zobj);

        RETURN_LONG(V_VT(&obj->v));
}
/* }}} */

/* {{{ proto void variant_set_type(object variant, int type)
   Convert a variant into another type.  Variant is modified "in-place" */
PHP_FUNCTION(variant_set_type)
{
        zval *zobj;
        php_com_dotnet_object *obj;
        VARTYPE vt;
        HRESULT res;

        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
                "Ol", &zobj, php_com_variant_class_entry, &vt)) {
                return;
        }
        obj = CDNO_FETCH(zobj);

        res = VariantChangeType(&obj->v, &obj->v, 0, vt);

        if (SUCCEEDED(res)) {
                if (vt != VT_DISPATCH && obj->typeinfo) {
                        ITypeInfo_Release(obj->typeinfo);
                        obj->typeinfo = NULL;
                }
        } else {
                char *werr, *msg;

                werr = php_win_err(res);
                spprintf(&msg, 0, "Variant type conversion failed: %s", werr);
                LocalFree(werr);

                php_com_throw_exception(msg TSRMLS_CC);
                efree(msg);
        }
}
/* }}} */

/* {{{ proto object variant_cast(object variant, int type)
   Convert a variant into a new variant object of another type */
PHP_FUNCTION(variant_cast)
{
        zval *zobj;
        php_com_dotnet_object *obj;
        VARTYPE vt;
        VARIANT vres;
        HRESULT res;

        if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
                "Ol", &zobj, php_com_variant_class_entry, &vt)) {
                return;
        }
        obj = CDNO_FETCH(zobj);

        VariantInit(&vres);
        res = VariantChangeType(&vres, &obj->v, 0, vt);

        if (SUCCEEDED(res)) {
                php_com_wrap_variant(return_value, &vres, obj->code_page TSRMLS_CC);
        } else {
                char *werr, *msg;

                werr = php_win_err(res);
                spprintf(&msg, 0, "Variant type conversion failed: %s", werr);
                LocalFree(werr);

                php_com_throw_exception(msg TSRMLS_CC);
                efree(msg);
        }

        VariantClear(&vres);
}
/* }}} */

/* {{{ proto mixed variant_index_get(object variant, mixed index1 [, mixed index2 [, 
...]])
   Get the value of a multi dimensional array property */
PHP_FUNCTION(variant_index_get)
{
        zval *zobj;
        php_com_dotnet_object *obj;
        VARIANT vres;
        HRESULT res;

        if (FAILURE == zend_parse_parameters(1 TSRMLS_CC,
                "O", &zobj, php_com_variant_class_entry)) {
                return;
        }
        obj = CDNO_FETCH(zobj);

        /* TODO: finish... */
}
/* }}} */

Index: php-src/ext/com_dotnet/php_com_dotnet.h
+++ php-src/ext/com_dotnet/php_com_dotnet.h
/*
   +----------------------------------------------------------------------+
   | PHP Version 4                                                        |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2003 The PHP Group                                |
   +----------------------------------------------------------------------+
   | This source file is subject to version 3.0 of the PHP license,       |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.php.net/license/3_0.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          |
   | [EMAIL PROTECTED] so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Author: Wez Furlong <[EMAIL PROTECTED]>                           |
   +----------------------------------------------------------------------+
 */

/* $Id: php_com_dotnet.h,v 1.1 2003/08/14 16:49:55 wez Exp $ */

#ifndef PHP_COM_DOTNET_H
#define PHP_COM_DOTNET_H

extern zend_module_entry com_dotnet_module_entry;
#define phpext_com_dotnet_ptr &com_dotnet_module_entry

#ifdef PHP_WIN32
# define PHP_COM_DOTNET_API __declspec(dllexport)
#else
# define PHP_COM_DOTNET_API
#endif

#ifdef ZTS
#include "TSRM.h"
#endif

PHP_MINIT_FUNCTION(com_dotnet);
PHP_MSHUTDOWN_FUNCTION(com_dotnet);
PHP_RINIT_FUNCTION(com_dotnet);
PHP_RSHUTDOWN_FUNCTION(com_dotnet);
PHP_MINFO_FUNCTION(com_dotnet);

PHP_FUNCTION(confirm_com_dotnet_compiled);

ZEND_BEGIN_MODULE_GLOBALS(com_dotnet)
        zend_bool allow_dcom;
        zend_bool autoreg_verbose;
        zend_bool autoreg_on;
        zend_bool autoreg_case_sensitive;
        void *dotnet_runtime_stuff; /* opaque to avoid cluttering up other modules */
ZEND_END_MODULE_GLOBALS(com_dotnet)

#ifdef ZTS
# define COMG(v) TSRMG(com_dotnet_globals_id, zend_com_dotnet_globals *, v)
#else
# define COMG(v) (com_dotnet_globals.v)
#endif

extern ZEND_DECLARE_MODULE_GLOBALS(com_dotnet);

#endif  /* PHP_COM_DOTNET_H */

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */

Index: php-src/ext/com_dotnet/php_com_dotnet_internal.h
+++ php-src/ext/com_dotnet/php_com_dotnet_internal.h
/*
   +----------------------------------------------------------------------+
   | PHP Version 4                                                        |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2003 The PHP Group                                |
   +----------------------------------------------------------------------+
   | This source file is subject to version 3.0 of the PHP license,       |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.php.net/license/3_0.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          |
   | [EMAIL PROTECTED] so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Author: Wez Furlong <[EMAIL PROTECTED]>                           |
   +----------------------------------------------------------------------+
 */

/* $Id: php_com_dotnet_internal.h,v 1.1 2003/08/14 16:49:55 wez Exp $ */

#ifndef PHP_COM_DOTNET_INTERNAL_H
#define PHP_COM_DOTNET_INTERNAL_H

#define _WIN32_DCOM
#define COBJMACROS
#include <ocidl.h>
#include "oleauto.h"
#include "win32/winutil.h"

/* brain-death in winutil.h defines the macro to hide the useful function... */
#undef php_win_err

typedef struct _php_com_dotnet_object {
        VARIANT v;

        ITypeInfo *typeinfo;
        int code_page;
        unsigned int have_default_bind:1;

        zend_class_entry *ce;
        DISPID default_bind; /* default property for array accesses */
} php_com_dotnet_object;

static inline int php_com_is_valid_object(zval *zv TSRMLS_DC)
{
        zend_class_entry *ce = Z_OBJCE_P(zv);
        return strcmp("com", ce->name) == 0 ||
                strcmp("dotnet", ce->name) == 0 ||
                strcmp("variant", ce->name) == 0;
}

#define CDNO_FETCH(zv)                  
(php_com_dotnet_object*)zend_object_store_get_object(zv TSRMLS_CC)
#define CDNO_FETCH_VERIFY(obj, zv)      do { \
        if (!php_com_is_valid_object(zv TSRMLS_CC)) { \
                php_com_throw_exception("expected a variant object" TSRMLS_CC); \
                return; \
        } \
        obj = (php_com_dotnet_object*)zend_object_store_get_object(zv TSRMLS_CC); \
} while(0)

/* com_extension.c */
TsHashTable php_com_typelibraries;
zend_class_entry *php_com_variant_class_entry;

/* com_handlers.c */
zend_object_value php_com_object_new(zend_class_entry *ce TSRMLS_DC);
void php_com_object_clone(void *object, void **clone_ptr TSRMLS_DC);
void php_com_object_dtor(void *object, zend_object_handle handle TSRMLS_DC);
zend_object_handlers php_com_object_handlers;

/* com_olechar.c */
PHPAPI char *php_com_olestring_to_string(OLECHAR *olestring,
                uint *string_len, int codepage TSRMLS_DC);
PHPAPI OLECHAR *php_com_string_to_olestring(char *string,
                uint string_len, int codepage TSRMLS_DC);


/* com_com.c */
PHP_FUNCTION(com_create_instance);
HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member,
                WORD flags, DISPPARAMS *disp_params, VARIANT *v TSRMLS_DC);
HRESULT php_com_get_id_of_name(php_com_dotnet_object *obj, char *name,
                int namelen, DISPID *dispid TSRMLS_DC);
int php_com_do_invoke_by_id(php_com_dotnet_object *obj, DISPID dispid,
                WORD flags,     VARIANT *v, int nargs, zval **args TSRMLS_DC);
int php_com_do_invoke(php_com_dotnet_object *obj, char *name, int namelen,
                WORD flags,     VARIANT *v, int nargs, zval **args TSRMLS_DC);

/* com_variant.c */
PHP_FUNCTION(com_variant_create_instance);
PHP_FUNCTION(variant_set);
PHP_FUNCTION(variant_add);
PHP_FUNCTION(variant_cat);
PHP_FUNCTION(variant_sub);
PHP_FUNCTION(variant_mul);
PHP_FUNCTION(variant_and);
PHP_FUNCTION(variant_div);
PHP_FUNCTION(variant_eqv);
PHP_FUNCTION(variant_idiv);
PHP_FUNCTION(variant_imp);
PHP_FUNCTION(variant_mod);
PHP_FUNCTION(variant_or);
PHP_FUNCTION(variant_pow);
PHP_FUNCTION(variant_xor);
PHP_FUNCTION(variant_abs);
PHP_FUNCTION(variant_fix);
PHP_FUNCTION(variant_int);
PHP_FUNCTION(variant_neg);
PHP_FUNCTION(variant_not);
PHP_FUNCTION(variant_round);
PHP_FUNCTION(variant_cmp);
PHP_FUNCTION(variant_date_to_timestamp);
PHP_FUNCTION(variant_date_from_timestamp);
PHP_FUNCTION(variant_get_type);
PHP_FUNCTION(variant_set_type);
PHP_FUNCTION(variant_cast);

PHPAPI void php_com_variant_from_zval_with_type(VARIANT *v, zval *z, VARTYPE type, int 
codepage TSRMLS_DC);
PHPAPI void php_com_variant_from_zval(VARIANT *v, zval *z, int codepage TSRMLS_DC);
PHPAPI int php_com_zval_from_variant(zval *z, VARIANT *v, int codepage TSRMLS_DC);

/* com_dotnet.c */
PHP_FUNCTION(com_dotnet_create_instance);
void php_com_dotnet_rshutdown(TSRMLS_D);

/* com_misc.c */
zval *php_com_throw_exception(char *message TSRMLS_DC);
PHPAPI void php_com_wrap_dispatch(zval *z, IDispatch *disp,
                int codepage TSRMLS_DC);
PHPAPI void php_com_wrap_variant(zval *z, VARIANT *v,
                int codepage TSRMLS_DC);

/* com_typeinfo.c */
PHPAPI ITypeLib *php_com_load_typelib_via_cache(char *search_string,
                int mode, int codepage, int *cached TSRMLS_DC);
PHPAPI ITypeLib *php_com_load_typelib(char *search_string, int mode,
                int codepage TSRMLS_DC);
PHPAPI int php_com_import_typelib(ITypeLib *TL, int mode,
                int codepage TSRMLS_DC);
void php_com_typelibrary_dtor(void *pDest);


#endif

Index: php-src/ext/com_dotnet/tests/variants.phpt
+++ php-src/ext/com_dotnet/tests/variants.phpt
--TEST--
COM: General variant tests
--SKIPIF--
<?php # vim:ft=php
if (!extension_loaded("com_dotnet")) print "skip"; ?>
--FILE--
<?php // $Id: variants.phpt,v 1.1 2003/08/14 16:49:56 wez Exp $
error_reporting(E_ALL);

$v = new VARIANT();
if (VT_EMPTY != variant_get_type($v)) {
        echo "VT_EMPTY: bork\n";
}

$values = array(VT_I4 => 42, VT_R8 => 3.5, VT_BSTR => "hello", VT_BOOL => false);
$binary_ops = array('add', 'cat', 'sub', 'mul', 'and', 'div',
        'eqv', 'idiv', 'imp', 'mod', 'or', 'pow', 'xor');

foreach ($values as $t => $val) {
        $v = new VARIANT($val);
        if ($t != variant_get_type($v)) {
                printf("Bork: [%d] %d: %s\n", $t, variant_get_type($v), (string)$v);
        }
        $results = array();

        foreach ($values as $op2) {
                echo "--\n";
                foreach ($binary_ops as $op) {
                        echo "$op: " . call_user_func('variant_' . $op, $v, $op2) . 
"\n";
                }
        }
}
$a = new VARIANT('10.0', VT_DECIMAL);
var_dump($a);

echo "OK!";
?>
--EXPECT--
--
add: 84
cat: 4242
sub: 0
mul: 1764
and: 42
div: 1
eqv: -1
idiv: 1
imp: -1
mod: 0
or: 42
pow: 1.50130937545297E+68
xor: 0
--
add: 45.5
cat: 423.5
sub: 38.5
mul: 147
and: 0
div: 12
eqv: -47
idiv: 10
imp: -43
mod: 2
or: 46
pow: 480145.116863642
xor: 46
--
add: 
cat: 42hello
sub: 
mul: 
and: 
div: 
eqv: 
idiv: 
imp: 
mod: 
or: 
pow: 
xor: 
--
add: 42
cat: 42False
sub: 42
mul: 0
and: 0
div: 
eqv: -43
idiv: 
imp: -43
mod: 
or: 42
pow: 1
xor: 42
--
add: 45.5
cat: 3.542
sub: -38.5
mul: 147
and: 0
div: 8.33333333333333E-02
eqv: -47
idiv: 0
imp: -5
mod: 4
or: 46
pow: 7.09345573078604E+22
xor: 46
--
add: 7
cat: 3.53.5
sub: 0
mul: 12.25
and: 4
div: 1
eqv: -1
idiv: 1
imp: -1
mod: 0
or: 4
pow: 80.2117802289664
xor: 0
--
add: 
cat: 3.5hello
sub: 
mul: 
and: 
div: 
eqv: 
idiv: 
imp: 
mod: 
or: 
pow: 
xor: 
--
add: 3.5
cat: 3.5False
sub: 3.5
mul: 0
and: 0
div: 
eqv: -5
idiv: 
imp: -5
mod: 
or: 4
pow: 1
xor: 4
--
add: 
cat: hello42
sub: 
mul: 
and: 
div: 
eqv: 
idiv: 
imp: 
mod: 
or: 
pow: 
xor: 
--
add: 
cat: hello3.5
sub: 
mul: 
and: 
div: 
eqv: 
idiv: 
imp: 
mod: 
or: 
pow: 
xor: 
--
add: hellohello
cat: hellohello
sub: 
mul: 
and: 
div: 
eqv: 
idiv: 
imp: 
mod: 
or: 
pow: 
xor: 
--
add: 
cat: helloFalse
sub: 
mul: 
and: 
div: 
eqv: 
idiv: 
imp: 
mod: 
or: 
pow: 
xor: 
--
add: 42
cat: False42
sub: -42
mul: 0
and: 0
div: 0
eqv: -43
idiv: 0
imp: -1
mod: 0
or: 42
pow: 0
xor: 42
--
add: 3.5
cat: False3.5
sub: -3.5
mul: 0
and: 0
div: 0
eqv: -5
idiv: 0
imp: -1
mod: 0
or: 4
pow: 0
xor: 4
--
add: 
cat: Falsehello
sub: 
mul: 
and: 
div: 
eqv: 
idiv: 
imp: 
mod: 
or: 
pow: 
xor: 
--
add: 0
cat: FalseFalse
sub: 0
mul: 0
and: 0
div: 
eqv: -1
idiv: 
imp: -1
mod: 
or: 0
pow: 1
xor: 0
OK!

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to