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, ¶ms, &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