wez             Sat Oct  9 09:10:38 2004 EDT

  Modified files:              (Branch: PHP_5_0)
    /php-src/ext/com_dotnet     com_dotnet.c 
  Log:
  MFH: dotnet init fixes
  
  
http://cvs.php.net/diff.php/php-src/ext/com_dotnet/com_dotnet.c?r1=1.7.2.1&r2=1.7.2.2&ty=u
Index: php-src/ext/com_dotnet/com_dotnet.c
diff -u php-src/ext/com_dotnet/com_dotnet.c:1.7.2.1 
php-src/ext/com_dotnet/com_dotnet.c:1.7.2.2
--- php-src/ext/com_dotnet/com_dotnet.c:1.7.2.1 Sat Aug  7 17:01:43 2004
+++ php-src/ext/com_dotnet/com_dotnet.c Sat Oct  9 09:10:37 2004
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: com_dotnet.c,v 1.7.2.1 2004/08/07 21:01:43 wez Exp $ */
+/* $Id: com_dotnet.c,v 1.7.2.2 2004/10/09 13:10:37 wez Exp $ */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -32,53 +32,139 @@
 # include "Zend/zend_exceptions.h"
 # include <mscoree.h>
 
+/* Since there is no official public mscorlib.h header file, and since
+ * generating your own version from the elusive binary .tlb file takes a lot of
+ * hacking and results in a 3MB header file (!), we opt for this slightly
+ * voodoo approach.  The following is just enough definition to be able to
+ * reach the _AppDomain::CreateInstance method that we need to use to be able
+ * to fire up .Net objects.  We used to use IDispatch for this, but it would
+ * not always work.
+ *
+ * The following info was obtained using OleView to export the IDL from
+ * mscorlib.tlb.  Note that OleView is unable to generate C headers for this
+ * particular tlb... hence this mess.
+ */
+
+const GUID IID_mscorlib_System_AppDomain = {
+0x05F696DC, 0x2B29, 0x3663, {0xAD, 0x8B, 0xC4, 0x38, 0x9C, 0xF2, 0xA7, 0x13 }};
+
+typedef struct _Imscorlib_System_AppDomain IAppDomain;
+
+struct _Imscorlib_System_AppDomainVtbl {
+       BEGIN_INTERFACE
+
+       HRESULT ( STDMETHODCALLTYPE *QueryInterface )( 
+               IAppDomain * This,
+               /* [in] */ REFIID riid,
+               /* [iid_is][out] */ void **ppvObject);
+        
+       ULONG ( STDMETHODCALLTYPE *AddRef )( 
+               IAppDomain * This);
+        
+       ULONG ( STDMETHODCALLTYPE *Release )( 
+               IAppDomain * This);
+        
+       /* this is padding to get CreateInstance into the correct position */
+#define DUMMY_METHOD(x)                HRESULT ( STDMETHODCALLTYPE *dummy_##x 
)(IAppDomain *This)
+
+       DUMMY_METHOD(GetTypeInfoCount);
+       DUMMY_METHOD(GetTypeInfo);
+       DUMMY_METHOD(GetIDsOfNames);
+       DUMMY_METHOD(Invoke);
+       DUMMY_METHOD(ToString);
+       DUMMY_METHOD(Equals);
+       DUMMY_METHOD(GetHashCode);
+       DUMMY_METHOD(GetType);
+       DUMMY_METHOD(InitializeLifetimeService);
+       DUMMY_METHOD(GetLifetimeService);
+       DUMMY_METHOD(Evidence);
+       DUMMY_METHOD(add_DomainUnload);
+       DUMMY_METHOD(remove_DomainUnload);
+       DUMMY_METHOD(add_AssemblyLoad);
+       DUMMY_METHOD(remove_AssemblyLoad);
+       DUMMY_METHOD(add_ProcessExit);
+       DUMMY_METHOD(remove_ProcessExit);
+       DUMMY_METHOD(add_TypeResolve);
+       DUMMY_METHOD(remove_TypeResolve);
+       DUMMY_METHOD(add_ResourceResolve);
+       DUMMY_METHOD(remove_ResourceResolve);
+       DUMMY_METHOD(add_AssemblyResolve);
+       DUMMY_METHOD(remove_AssemblyResolve);
+       DUMMY_METHOD(add_UnhandledException);
+       DUMMY_METHOD(remove_UnhandledException);
+       DUMMY_METHOD(DefineDynamicAssembly);
+       DUMMY_METHOD(DefineDynamicAssembly_2);
+       DUMMY_METHOD(DefineDynamicAssembly_3);
+       DUMMY_METHOD(DefineDynamicAssembly_4);
+       DUMMY_METHOD(DefineDynamicAssembly_5);
+       DUMMY_METHOD(DefineDynamicAssembly_6);
+       DUMMY_METHOD(DefineDynamicAssembly_7);
+       DUMMY_METHOD(DefineDynamicAssembly_8);
+       DUMMY_METHOD(DefineDynamicAssembly_9);
+
+       HRESULT ( STDMETHODCALLTYPE *CreateInstance )(IAppDomain * This, BSTR 
AssemblyName, BSTR typeName, IUnknown **pRetVal);
+       HRESULT ( STDMETHODCALLTYPE *CreateInstanceFrom )(IAppDomain * This, BSTR 
AssemblyFile, BSTR typeName, IUnknown **pRetVal);
+
+       /* more methods live here */
+
+       END_INTERFACE
+};
+
+struct _Imscorlib_System_AppDomain {
+       struct _Imscorlib_System_AppDomainVtbl *lpVtbl;
+};
+
+
 struct dotnet_runtime_stuff {
        ICorRuntimeHost *dotnet_host;
-       IDispatch *dotnet_domain;
+       IAppDomain              *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)
+static HRESULT dotnet_init(char **p_where TSRMLS_DC)
 {
        HRESULT hr;
        struct dotnet_runtime_stuff *stuff;
        IUnknown *unk = NULL;
-       OLECHAR *olename;
+       OLECHAR *olename, *oletmp;
+       char *where = "";
 
        stuff = malloc(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);
-               }
+       where = "CoCreateInstance";
+       hr = CoCreateInstance(&CLSID_CorRuntimeHost, NULL, CLSCTX_ALL,
+                       &IID_ICorRuntimeHost, (LPVOID*)&stuff->dotnet_host);
+
+       if (FAILED(hr))
+               goto out;
+
+       /* fire up the host and get the domain object */
+       where = "ICorRuntimeHost_Start\n";
+       hr = ICorRuntimeHost_Start(stuff->dotnet_host);
+       if (FAILED(hr))
+               goto out;
+       
+       where = "ICorRuntimeHost_GetDefaultDomain";
+       hr = ICorRuntimeHost_GetDefaultDomain(stuff->dotnet_host, &unk);
+       if (FAILED(hr))
+               goto out;
+
+       where = "QI: System._AppDomain";
+       hr = IUnknown_QueryInterface(unk, &IID_mscorlib_System_AppDomain, 
(LPVOID*)&stuff->dotnet_domain);
+       if (FAILED(hr))
+               goto out;
+               
+       COMG(dotnet_runtime_stuff) = stuff;
+
+out:
+       if (unk) {
+               IUnknown_Release(unk);
        }
-
        if (COMG(dotnet_runtime_stuff) == NULL) {
                /* clean up */
                if (stuff->dotnet_domain) {
-                       IDispatch_Release(stuff->dotnet_domain);
+                       IUnknown_Release(stuff->dotnet_domain);
                }
                if (stuff->dotnet_host) {
                        ICorRuntimeHost_Stop(stuff->dotnet_host);
@@ -86,10 +172,12 @@
                }
                free(stuff);
 
-               return FAILURE;
+               *p_where = where;
+
+               return hr;
        }
 
-       return SUCCESS;
+       return S_OK;
 }
 
 /* {{{ com_dotnet_create_instance - ctor for DOTNET class */
@@ -100,17 +188,21 @@
        char *assembly_name, *datatype_name;
        int assembly_name_len, datatype_name_len;
        struct dotnet_runtime_stuff *stuff;
-       IObjectHandle *handle;
-       DISPPARAMS params;
-       OLECHAR *olestring;
-       VARIANT vargs[2];
-       VARIANT retval;
+       OLECHAR *olestring, *oleassembly, *oletype;
        HRESULT hr;
        int ret = FAILURE;
+       char *where = "";
+       IUnknown *unk = NULL;
 
        if (COMG(dotnet_runtime_stuff) == NULL) {
-               if (FAILURE == dotnet_init(TSRMLS_C)) {
-                       php_com_throw_exception(E_ERROR, "Failed to initialize .Net 
runtime" TSRMLS_CC);
+               hr = dotnet_init(&where TSRMLS_CC);
+               if (FAILED(hr)) {
+                       char buf[1024];
+                       char *err = php_win_err(hr);
+                       snprintf(buf, sizeof(buf), "Failed to init .Net runtime [%s] 
%s", where, err);
+                       if (err)
+                               LocalFree(err);
+                       php_com_throw_exception(hr, buf TSRMLS_CC);
                        ZVAL_NULL(object);
                        return;
                }
@@ -129,54 +221,63 @@
                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;
-       olestring = php_com_string_to_olestring(datatype_name, datatype_name_len, 
obj->code_page TSRMLS_CC);
-       V_BSTR(&vargs[0]) = SysAllocStringByteLen((char*)olestring, datatype_name_len 
* sizeof(OLECHAR));
-       efree(olestring);
-
-       V_VT(&vargs[1]) = VT_BSTR;
-       olestring = php_com_string_to_olestring(assembly_name, assembly_name_len, 
obj->code_page TSRMLS_CC);
-       V_BSTR(&vargs[1]) = SysAllocStringByteLen((char*)olestring, assembly_name_len 
* sizeof(OLECHAR));
-       efree(olestring);
-
-       hr = IDispatch_Invoke(stuff->dotnet_domain, stuff->create_instance, &IID_NULL, 
LOCALE_SYSTEM_DEFAULT,
-               DISPATCH_METHOD, &params, &retval, NULL, NULL);
+       oletype = php_com_string_to_olestring(datatype_name, datatype_name_len, 
obj->code_page TSRMLS_CC);
+       oleassembly = php_com_string_to_olestring(assembly_name, assembly_name_len, 
obj->code_page TSRMLS_CC);
+       where = "CreateInstance";
+       hr = stuff->dotnet_domain->lpVtbl->CreateInstance(stuff->dotnet_domain, 
oleassembly, oletype, &unk);
+       efree(oletype);
+       efree(oleassembly);
 
        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;
+               VARIANT unwrapped;
+               IObjectHandle *handle = NULL;
 
-                               /* get its type-info */
-                               IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, 
LANG_NEUTRAL, &obj->typeinfo);
+               where = "QI: IObjectHandle";
+               hr = IUnknown_QueryInterface(unk, &IID_IObjectHandle, &handle);
 
-                               ret = SUCCESS;
+               if (SUCCEEDED(hr)) {
+                       where = "IObjectHandle_Unwrap";
+                       hr = IObjectHandle_Unwrap(handle, &unwrapped);
+                       if (SUCCEEDED(hr)) {
+
+                               if (V_VT(&unwrapped) == VT_UNKNOWN) {
+                                       where = "Unwrapped, QI for IDispatch";
+                                       hr = 
IUnknown_QueryInterface(V_UNKNOWN(&unwrapped), &IID_IDispatch, &V_DISPATCH(&obj->v));
+
+                                       if (SUCCEEDED(hr)) {
+                                               V_VT(&obj->v) = VT_DISPATCH;
+
+                                               /* get its type-info */
+                                               
IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, LANG_NEUTRAL, &obj->typeinfo);
+                                               ret = SUCCESS;
+                                       }
+                               } else if (V_VT(&unwrapped) == VT_DISPATCH) {
+                                       /* 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;
+                               } else {
+                                       /* shouldn't happen, but let's be ready for it 
*/
+                                       VariantClear(&unwrapped);
+                                       hr = E_INVALIDARG;
+                               }
                        }
                        IObjectHandle_Release(handle);
                }
-               VariantClear(&retval);
+               IUnknown_Release(unk);
        }
 
-       VariantClear(&vargs[0]);
-       VariantClear(&vargs[1]);
-
        if (ret == FAILURE) {
-               php_com_throw_exception(hr, "Failed to instantiate .Net object" 
TSRMLS_CC);
+               char buf[1024];
+               char *err = php_win_err(hr);
+               snprintf(buf, sizeof(buf), "Failed to instantiate .Net object [%s] 
[0x%08x] %s", where, hr, err);
+               if (err)
+                       LocalFree(err);
+               php_com_throw_exception(hr, buf TSRMLS_CC);
                ZVAL_NULL(object);
                return;
        }

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

Reply via email to