]> granicus.if.org Git - php/commitdiff
@ added the possibility to specify typelibs by full name
authorHarald Radi <phanto@php.net>
Sun, 3 Jun 2001 15:33:41 +0000 (15:33 +0000)
committerHarald Radi <phanto@php.net>
Sun, 3 Jun 2001 15:33:41 +0000 (15:33 +0000)
@ in the typelib file (Alan Brown)

ext/com/COM.c
ext/rpc/com/com_wrapper.c

index b0be9e5f44ca06f14876b98f2c6667a058968096..04282284126994483889ea2f397d4b3851903394 100644 (file)
  * VARIANT datatype and pass_by_reference support
  */
 
+/*
+ * 03.6.2001
+ * Enhanced Typelib support to include a search by name
+ */
+
 #ifdef PHP_WIN32
 
 #define _WIN32_DCOM
@@ -68,6 +73,7 @@ PHP_FUNCTION(com_propget);
 PHP_FUNCTION(com_propput);
 
 PHPAPI int php_COM_get_le_idispatch();
+static ITypeLib *php_COM_find_typelib(char *search_string, int mode);
 static int php_COM_load_typelib(char *typelib_name, int mode);
 
 static int le_idispatch;
@@ -96,19 +102,37 @@ static PHP_MINFO_FUNCTION(COM)
 PHPAPI HRESULT php_COM_invoke(i_dispatch *obj, DISPID dispIdMember, WORD wFlags, DISPPARAMS FAR*  pDispParams, VARIANT FAR*  pVarResult)
 {
        HRESULT hr;
+       int failed = FALSE;
 
        if(obj->referenced)
        {
-               if(obj->typelib) {
+               if(obj->typelib)
+               {
                        hr = obj->i.typeinfo->lpVtbl->Invoke(obj->i.typeinfo, obj->i.dispatch, dispIdMember,
                                                                                                   wFlags, pDispParams, pVarResult, NULL, NULL);
-                       if(!FAILED(hr))
+                       if(FAILED(hr))
                        {
-                               return hr;
+                               hr = obj->i.dispatch->lpVtbl->Invoke(obj->i.dispatch, dispIdMember, &IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                                                                                                  wFlags, pDispParams, pVarResult, NULL, NULL);
+                               if(SUCCEEDED(hr))
+                               {
+                                       /*
+                                        * ITypLib doesn't work
+                                        * Release ITypeLib and fall back to IDispatch
+                                        */
+
+                                       obj->i.typeinfo->lpVtbl->Release(obj->i.typeinfo);
+                                       obj->typelib = FALSE;
+                               }
                        }
                }
-               return obj->i.dispatch->lpVtbl->Invoke(obj->i.dispatch, dispIdMember, &IID_NULL, LOCALE_SYSTEM_DEFAULT,
-                                                                                                  wFlags, pDispParams, pVarResult, NULL, NULL);
+               else
+               {
+                       hr = obj->i.dispatch->lpVtbl->Invoke(obj->i.dispatch, dispIdMember, &IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                                                                  wFlags, pDispParams, pVarResult, NULL, NULL);
+               }
+
+               return hr;
        }
        else
        {
@@ -122,14 +146,32 @@ PHPAPI HRESULT php_COM_get_ids_of_names(i_dispatch *obj, OLECHAR FAR* FAR* rgszN
 
        if(obj->referenced)
        {
-               if(obj->typelib) {
+               if(obj->typelib)
+               {
                        hr = obj->i.typeinfo->lpVtbl->GetIDsOfNames(obj->i.typeinfo, rgszNames, 1, rgDispId);
-                       if(!FAILED(hr))
+
+                       if(FAILED(hr))
                        {
-                               return hr;
+                               hr = obj->i.dispatch->lpVtbl->GetIDsOfNames(obj->i.dispatch, &IID_NULL, rgszNames, 1, LOCALE_SYSTEM_DEFAULT, rgDispId);
+
+                               if(SUCCEEDED(hr))
+                               {
+                                       /*
+                                        * ITypLib doesn't work
+                                        * Release ITypeLib and fall back to IDispatch
+                                        */
+
+                                       obj->i.typeinfo->lpVtbl->Release(obj->i.typeinfo);
+                                       obj->typelib = FALSE;
+                               }
                        }
                }
-               return obj->i.dispatch->lpVtbl->GetIDsOfNames(obj->i.dispatch, &IID_NULL, rgszNames, 1, LOCALE_SYSTEM_DEFAULT, rgDispId);
+               else
+               {
+                       hr = obj->i.dispatch->lpVtbl->GetIDsOfNames(obj->i.dispatch, &IID_NULL, rgszNames, 1, LOCALE_SYSTEM_DEFAULT, rgDispId);
+               }
+
+               return hr;
        }
        else
        {
@@ -172,7 +214,6 @@ PHPAPI HRESULT php_COM_set(i_dispatch *obj, IDispatch FAR* pDisp, int cleanup)
 
        obj->i.dispatch = pDisp;
        obj->referenced = 1;
-       
        obj->typelib = !FAILED(obj->i.dispatch->lpVtbl->GetTypeInfo(obj->i.dispatch, 0, LANG_NEUTRAL, &(obj->i.typeinfo)));
 
        if(!cleanup)
@@ -1012,7 +1053,6 @@ PHPAPI void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_pro
                PHP_FN(com_load)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
                if(!zend_is_true(return_value))
                {
-                       pval_destructor(&function_name->element);
                        var_reset(object);
                        return;
                }
@@ -1041,10 +1081,7 @@ PHPAPI void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_pro
 
        if(!obj || (type!=le_idispatch))
        {
-               if(property.refcount == 1)
-               {
-                       pval_destructor(&property);
-               }
+               pval_destructor(&property);
                pval_destructor(&function_name->element);
                return;
        }
@@ -1092,39 +1129,61 @@ PHPAPI void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_pro
        pval_destructor(&function_name->element);
 }
 
-
-static int php_COM_load_typelib(char *typelib_name, int mode)
+static ITypeLib *php_COM_find_typelib(char *search_string, int mode)
 {
-       ITypeLib *TypeLib;
-       ITypeComp *TypeComp;
-       OLECHAR *p;
-       CLSID clsid;
+       ITypeLib *TypeLib = NULL;
        char *strtok_buf, *major, *minor;
-       int i;
-       int interfaces;
-       ELS_FETCH();
-
-
-       typelib_name = php_strtok_r(typelib_name, ",", &strtok_buf);
+       CLSID clsid;
+       OLECHAR *p;
+       char *ptr;
+
+       /* Type Libraries:
+        * The string we have is 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"
+        * Searching for the name will be more expensive that the
+        * other two, so we will do that when both other attempts
+        * fail.
+        */
+       search_string = php_strtok_r(search_string, ",", &strtok_buf);
        major = php_strtok_r(NULL, ",", &strtok_buf);
        minor = php_strtok_r(NULL, ",", &strtok_buf);
 
-       p = php_char_to_OLECHAR(typelib_name, strlen(typelib_name), codepage);
+       /* Remove leading/training white spaces on search_string */
+       while (isspace(*search_string)) /* Ends on '\0' in worst case */
+       {
+               search_string ++;
+       }
+       ptr = search_string + strlen(search_string) - 1;
+       while ((ptr != search_string) && isspace(*ptr))
+       {
+               *ptr = '\0';
+               ptr--;
+       }
 
+       p = php_char_to_OLECHAR(search_string, strlen(search_string), codepage);
+       /* Is the string a GUID ? */
        if(!FAILED(CLSIDFromString(p, &clsid)))
        {
                HRESULT hr;
                WORD major_i = 1;
                WORD minor_i = 0;
 
+               /* We have a valid GUID, check to see if a major/minor */
+               /* version was specified otherwise assume 1,0 */
                if(major && minor)
                {
                        major_i = (WORD) atoi(major);
                        minor_i = (WORD) atoi(minor);
                }
 
+               /* The GUID will either be a typelibrary or a CLSID */
                hr = LoadRegTypeLib((REFGUID) &clsid, major_i, minor_i, LANG_NEUTRAL, &TypeLib);
 
+               /* If the LoadRegTypeLib fails, let's try to instantiate */
+               /* the class itself and then QI for the TypeInfo and */
+               /* retrieve the type info from that interface */
                if(FAILED(hr) && (!major || !minor))
                {
                        IDispatch *Dispatch;
@@ -1134,20 +1193,20 @@ static int php_COM_load_typelib(char *typelib_name, int mode)
                        if(FAILED(CoCreateInstance(&clsid, NULL, CLSCTX_SERVER, &IID_IDispatch, (LPVOID *) &Dispatch)))
                        {
                                efree(p);
-                               return FAILURE;
+                               return NULL;
                        }
                        if(FAILED(Dispatch->lpVtbl->GetTypeInfo(Dispatch, 0, LANG_NEUTRAL, &TypeInfo)))
                        {
                                Dispatch->lpVtbl->Release(Dispatch);
                                efree(p);
-                               return FAILURE;
+                               return NULL;
                        }
                        Dispatch->lpVtbl->Release(Dispatch);
                        if(FAILED(TypeInfo->lpVtbl->GetContainingTypeLib(TypeInfo, &TypeLib, &idx)))
                        {
                                TypeInfo->lpVtbl->Release(TypeInfo);
                                efree(p);
-                               return FAILURE;
+                               return NULL;
                        }
                        TypeInfo->lpVtbl->Release(TypeInfo);
                }
@@ -1156,10 +1215,126 @@ static int php_COM_load_typelib(char *typelib_name, int mode)
        {
                if(FAILED(LoadTypeLib(p, &TypeLib)))
                {
+                       /* Walk HKCR/TypeLib looking for the string */
+                       /* If that succeeds, call ourself recursively */
+                       /* using the CLSID found, else give up and bail */
+                       HKEY hkey, hsubkey;
+                       DWORD SubKeys, MaxSubKeyLength;
+                       char *keyname;
+                       register unsigned int ii, jj;
+                       DWORD VersionCount;
+                       char version[20]; /* All the version keys are 1.0, 4.6, ... */
+                       char *libname;
+                       DWORD libnamelen;
+
+                       /* No Need for Unicode version any more */
                        efree(p);
-                       return FAILURE;
+
+                       /* Starting at HKEY_CLASSES_ROOT/TypeLib */
+                       /* Walk all subkeys (Typelib GUIDs) looking */
+                       /* at each version for a string match to the */
+                       /* supplied argument */
+                       if (ERROR_SUCCESS != RegOpenKey(HKEY_CLASSES_ROOT, "TypeLib",&hkey))
+                       {
+                               /* This is pretty bad - better bail */
+                               return NULL;
+                       }
+                       if (ERROR_SUCCESS != RegQueryInfoKey(hkey, NULL, NULL, NULL, &SubKeys, &MaxSubKeyLength, NULL, NULL, NULL, NULL, NULL, NULL))
+                       {
+                               RegCloseKey(hkey);
+                               return NULL;
+                       }
+                       keyname = malloc(MaxSubKeyLength);
+                       libname = malloc(strlen(search_string)+1);
+                       for (ii=0;ii<SubKeys;ii++)
+                       {
+                               if (ERROR_SUCCESS != RegEnumKey(hkey, ii, keyname, MaxSubKeyLength))
+                               {
+                                       /* Failed - who cares */
+                                       continue;
+                               }
+                               if (ERROR_SUCCESS != RegOpenKey(hkey, keyname, &hsubkey))
+                               {
+                                       /* Failed - who cares */
+                                       continue;
+                               }
+                               if (ERROR_SUCCESS != RegQueryInfoKey(hsubkey, NULL, NULL, NULL, &VersionCount, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
+                               {
+                                       /* Failed - who cares */
+                                       RegCloseKey(hsubkey);
+                                       continue;
+                               }
+                               for (jj=0;jj<VersionCount;jj++)
+                               {
+                                       if (ERROR_SUCCESS != RegEnumKey(hsubkey, jj, version, sizeof(version)))
+                                       {
+                                               /* Failed - who cares */
+                                               continue;
+                                       }
+                                       /* OK we just need to retrieve the default */
+                                       /* value for this key and see if it matches */
+                                       libnamelen = strlen(search_string)+1;
+                                       if (ERROR_SUCCESS == RegQueryValue(hsubkey, version, libname, &libnamelen))
+                                       {
+                                               if ((mode & CONST_CS) ? (strcmp(libname, search_string) == 0) : (stricmp(libname, search_string) == 0))
+                                               {
+                                                       char *str;
+                                                       int major, minor;
+
+                                                       /* Found it */
+                                                       RegCloseKey(hkey);
+                                                       RegCloseKey(hsubkey);
+                                                       efree(libname);
+                                                       /* We can either open up the "win32" key and find the DLL name */
+                                                       /* Or just parse the version string and pass that in */
+                                                       /* The version string seems like a more portable solution */
+                                                       /* Given that there is a COM on Unix */
+                                                       if (2 != sscanf(version, "%d.%d", &major, &minor))
+                                                       {
+                                                               major = 1;
+                                                               minor = 0;
+                                                       }
+                                                       str = malloc(strlen(keyname)+strlen(version)+20); /* 18 == safety, 2 == extra comma and \0 */
+                                                       sprintf(str, "%s,%d,%d", keyname, major, minor);
+                                                       free(keyname);
+                                                       TypeLib = php_COM_find_typelib(str, mode);
+                                                       free(str);
+                                                       /* This is probbaly much harder to read and follow */
+                                                       /* But it is MUCH more effiecient than trying to */
+                                                       /* test for errors and leave through a single "return" */
+                                                       return TypeLib;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               /* Failed - perhaps too small abuffer */
+                                               /* But if too small, then the name does not match */
+                                       }
+                               }
+                               RegCloseKey(hsubkey);
+                       }
+                       free(keyname);
+                       free(libname);
+                       return NULL;
                }
        }
+       efree(p);
+       return TypeLib;
+}
+
+static int php_COM_load_typelib(char *typelib_name, int mode)
+{
+       ITypeLib *TypeLib;
+       ITypeComp *TypeComp;
+       int i;
+       int interfaces;
+       ELS_FETCH();
+
+       TypeLib = php_COM_find_typelib(typelib_name, mode);
+       if (NULL == TypeLib)
+       {
+               return FAILURE;
+       }
 
        interfaces = TypeLib->lpVtbl->GetTypeInfoCount(TypeLib);
 
@@ -1217,7 +1392,6 @@ static int php_COM_load_typelib(char *typelib_name, int mode)
 
 
        TypeLib->lpVtbl->Release(TypeLib);
-       efree(p);
        return SUCCESS;
 }
 
index b0be9e5f44ca06f14876b98f2c6667a058968096..04282284126994483889ea2f397d4b3851903394 100644 (file)
  * VARIANT datatype and pass_by_reference support
  */
 
+/*
+ * 03.6.2001
+ * Enhanced Typelib support to include a search by name
+ */
+
 #ifdef PHP_WIN32
 
 #define _WIN32_DCOM
@@ -68,6 +73,7 @@ PHP_FUNCTION(com_propget);
 PHP_FUNCTION(com_propput);
 
 PHPAPI int php_COM_get_le_idispatch();
+static ITypeLib *php_COM_find_typelib(char *search_string, int mode);
 static int php_COM_load_typelib(char *typelib_name, int mode);
 
 static int le_idispatch;
@@ -96,19 +102,37 @@ static PHP_MINFO_FUNCTION(COM)
 PHPAPI HRESULT php_COM_invoke(i_dispatch *obj, DISPID dispIdMember, WORD wFlags, DISPPARAMS FAR*  pDispParams, VARIANT FAR*  pVarResult)
 {
        HRESULT hr;
+       int failed = FALSE;
 
        if(obj->referenced)
        {
-               if(obj->typelib) {
+               if(obj->typelib)
+               {
                        hr = obj->i.typeinfo->lpVtbl->Invoke(obj->i.typeinfo, obj->i.dispatch, dispIdMember,
                                                                                                   wFlags, pDispParams, pVarResult, NULL, NULL);
-                       if(!FAILED(hr))
+                       if(FAILED(hr))
                        {
-                               return hr;
+                               hr = obj->i.dispatch->lpVtbl->Invoke(obj->i.dispatch, dispIdMember, &IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                                                                                                  wFlags, pDispParams, pVarResult, NULL, NULL);
+                               if(SUCCEEDED(hr))
+                               {
+                                       /*
+                                        * ITypLib doesn't work
+                                        * Release ITypeLib and fall back to IDispatch
+                                        */
+
+                                       obj->i.typeinfo->lpVtbl->Release(obj->i.typeinfo);
+                                       obj->typelib = FALSE;
+                               }
                        }
                }
-               return obj->i.dispatch->lpVtbl->Invoke(obj->i.dispatch, dispIdMember, &IID_NULL, LOCALE_SYSTEM_DEFAULT,
-                                                                                                  wFlags, pDispParams, pVarResult, NULL, NULL);
+               else
+               {
+                       hr = obj->i.dispatch->lpVtbl->Invoke(obj->i.dispatch, dispIdMember, &IID_NULL, LOCALE_SYSTEM_DEFAULT,
+                                                                  wFlags, pDispParams, pVarResult, NULL, NULL);
+               }
+
+               return hr;
        }
        else
        {
@@ -122,14 +146,32 @@ PHPAPI HRESULT php_COM_get_ids_of_names(i_dispatch *obj, OLECHAR FAR* FAR* rgszN
 
        if(obj->referenced)
        {
-               if(obj->typelib) {
+               if(obj->typelib)
+               {
                        hr = obj->i.typeinfo->lpVtbl->GetIDsOfNames(obj->i.typeinfo, rgszNames, 1, rgDispId);
-                       if(!FAILED(hr))
+
+                       if(FAILED(hr))
                        {
-                               return hr;
+                               hr = obj->i.dispatch->lpVtbl->GetIDsOfNames(obj->i.dispatch, &IID_NULL, rgszNames, 1, LOCALE_SYSTEM_DEFAULT, rgDispId);
+
+                               if(SUCCEEDED(hr))
+                               {
+                                       /*
+                                        * ITypLib doesn't work
+                                        * Release ITypeLib and fall back to IDispatch
+                                        */
+
+                                       obj->i.typeinfo->lpVtbl->Release(obj->i.typeinfo);
+                                       obj->typelib = FALSE;
+                               }
                        }
                }
-               return obj->i.dispatch->lpVtbl->GetIDsOfNames(obj->i.dispatch, &IID_NULL, rgszNames, 1, LOCALE_SYSTEM_DEFAULT, rgDispId);
+               else
+               {
+                       hr = obj->i.dispatch->lpVtbl->GetIDsOfNames(obj->i.dispatch, &IID_NULL, rgszNames, 1, LOCALE_SYSTEM_DEFAULT, rgDispId);
+               }
+
+               return hr;
        }
        else
        {
@@ -172,7 +214,6 @@ PHPAPI HRESULT php_COM_set(i_dispatch *obj, IDispatch FAR* pDisp, int cleanup)
 
        obj->i.dispatch = pDisp;
        obj->referenced = 1;
-       
        obj->typelib = !FAILED(obj->i.dispatch->lpVtbl->GetTypeInfo(obj->i.dispatch, 0, LANG_NEUTRAL, &(obj->i.typeinfo)));
 
        if(!cleanup)
@@ -1012,7 +1053,6 @@ PHPAPI void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_pro
                PHP_FN(com_load)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
                if(!zend_is_true(return_value))
                {
-                       pval_destructor(&function_name->element);
                        var_reset(object);
                        return;
                }
@@ -1041,10 +1081,7 @@ PHPAPI void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_pro
 
        if(!obj || (type!=le_idispatch))
        {
-               if(property.refcount == 1)
-               {
-                       pval_destructor(&property);
-               }
+               pval_destructor(&property);
                pval_destructor(&function_name->element);
                return;
        }
@@ -1092,39 +1129,61 @@ PHPAPI void php_COM_call_function_handler(INTERNAL_FUNCTION_PARAMETERS, zend_pro
        pval_destructor(&function_name->element);
 }
 
-
-static int php_COM_load_typelib(char *typelib_name, int mode)
+static ITypeLib *php_COM_find_typelib(char *search_string, int mode)
 {
-       ITypeLib *TypeLib;
-       ITypeComp *TypeComp;
-       OLECHAR *p;
-       CLSID clsid;
+       ITypeLib *TypeLib = NULL;
        char *strtok_buf, *major, *minor;
-       int i;
-       int interfaces;
-       ELS_FETCH();
-
-
-       typelib_name = php_strtok_r(typelib_name, ",", &strtok_buf);
+       CLSID clsid;
+       OLECHAR *p;
+       char *ptr;
+
+       /* Type Libraries:
+        * The string we have is 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"
+        * Searching for the name will be more expensive that the
+        * other two, so we will do that when both other attempts
+        * fail.
+        */
+       search_string = php_strtok_r(search_string, ",", &strtok_buf);
        major = php_strtok_r(NULL, ",", &strtok_buf);
        minor = php_strtok_r(NULL, ",", &strtok_buf);
 
-       p = php_char_to_OLECHAR(typelib_name, strlen(typelib_name), codepage);
+       /* Remove leading/training white spaces on search_string */
+       while (isspace(*search_string)) /* Ends on '\0' in worst case */
+       {
+               search_string ++;
+       }
+       ptr = search_string + strlen(search_string) - 1;
+       while ((ptr != search_string) && isspace(*ptr))
+       {
+               *ptr = '\0';
+               ptr--;
+       }
 
+       p = php_char_to_OLECHAR(search_string, strlen(search_string), codepage);
+       /* Is the string a GUID ? */
        if(!FAILED(CLSIDFromString(p, &clsid)))
        {
                HRESULT hr;
                WORD major_i = 1;
                WORD minor_i = 0;
 
+               /* We have a valid GUID, check to see if a major/minor */
+               /* version was specified otherwise assume 1,0 */
                if(major && minor)
                {
                        major_i = (WORD) atoi(major);
                        minor_i = (WORD) atoi(minor);
                }
 
+               /* The GUID will either be a typelibrary or a CLSID */
                hr = LoadRegTypeLib((REFGUID) &clsid, major_i, minor_i, LANG_NEUTRAL, &TypeLib);
 
+               /* If the LoadRegTypeLib fails, let's try to instantiate */
+               /* the class itself and then QI for the TypeInfo and */
+               /* retrieve the type info from that interface */
                if(FAILED(hr) && (!major || !minor))
                {
                        IDispatch *Dispatch;
@@ -1134,20 +1193,20 @@ static int php_COM_load_typelib(char *typelib_name, int mode)
                        if(FAILED(CoCreateInstance(&clsid, NULL, CLSCTX_SERVER, &IID_IDispatch, (LPVOID *) &Dispatch)))
                        {
                                efree(p);
-                               return FAILURE;
+                               return NULL;
                        }
                        if(FAILED(Dispatch->lpVtbl->GetTypeInfo(Dispatch, 0, LANG_NEUTRAL, &TypeInfo)))
                        {
                                Dispatch->lpVtbl->Release(Dispatch);
                                efree(p);
-                               return FAILURE;
+                               return NULL;
                        }
                        Dispatch->lpVtbl->Release(Dispatch);
                        if(FAILED(TypeInfo->lpVtbl->GetContainingTypeLib(TypeInfo, &TypeLib, &idx)))
                        {
                                TypeInfo->lpVtbl->Release(TypeInfo);
                                efree(p);
-                               return FAILURE;
+                               return NULL;
                        }
                        TypeInfo->lpVtbl->Release(TypeInfo);
                }
@@ -1156,10 +1215,126 @@ static int php_COM_load_typelib(char *typelib_name, int mode)
        {
                if(FAILED(LoadTypeLib(p, &TypeLib)))
                {
+                       /* Walk HKCR/TypeLib looking for the string */
+                       /* If that succeeds, call ourself recursively */
+                       /* using the CLSID found, else give up and bail */
+                       HKEY hkey, hsubkey;
+                       DWORD SubKeys, MaxSubKeyLength;
+                       char *keyname;
+                       register unsigned int ii, jj;
+                       DWORD VersionCount;
+                       char version[20]; /* All the version keys are 1.0, 4.6, ... */
+                       char *libname;
+                       DWORD libnamelen;
+
+                       /* No Need for Unicode version any more */
                        efree(p);
-                       return FAILURE;
+
+                       /* Starting at HKEY_CLASSES_ROOT/TypeLib */
+                       /* Walk all subkeys (Typelib GUIDs) looking */
+                       /* at each version for a string match to the */
+                       /* supplied argument */
+                       if (ERROR_SUCCESS != RegOpenKey(HKEY_CLASSES_ROOT, "TypeLib",&hkey))
+                       {
+                               /* This is pretty bad - better bail */
+                               return NULL;
+                       }
+                       if (ERROR_SUCCESS != RegQueryInfoKey(hkey, NULL, NULL, NULL, &SubKeys, &MaxSubKeyLength, NULL, NULL, NULL, NULL, NULL, NULL))
+                       {
+                               RegCloseKey(hkey);
+                               return NULL;
+                       }
+                       keyname = malloc(MaxSubKeyLength);
+                       libname = malloc(strlen(search_string)+1);
+                       for (ii=0;ii<SubKeys;ii++)
+                       {
+                               if (ERROR_SUCCESS != RegEnumKey(hkey, ii, keyname, MaxSubKeyLength))
+                               {
+                                       /* Failed - who cares */
+                                       continue;
+                               }
+                               if (ERROR_SUCCESS != RegOpenKey(hkey, keyname, &hsubkey))
+                               {
+                                       /* Failed - who cares */
+                                       continue;
+                               }
+                               if (ERROR_SUCCESS != RegQueryInfoKey(hsubkey, NULL, NULL, NULL, &VersionCount, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
+                               {
+                                       /* Failed - who cares */
+                                       RegCloseKey(hsubkey);
+                                       continue;
+                               }
+                               for (jj=0;jj<VersionCount;jj++)
+                               {
+                                       if (ERROR_SUCCESS != RegEnumKey(hsubkey, jj, version, sizeof(version)))
+                                       {
+                                               /* Failed - who cares */
+                                               continue;
+                                       }
+                                       /* OK we just need to retrieve the default */
+                                       /* value for this key and see if it matches */
+                                       libnamelen = strlen(search_string)+1;
+                                       if (ERROR_SUCCESS == RegQueryValue(hsubkey, version, libname, &libnamelen))
+                                       {
+                                               if ((mode & CONST_CS) ? (strcmp(libname, search_string) == 0) : (stricmp(libname, search_string) == 0))
+                                               {
+                                                       char *str;
+                                                       int major, minor;
+
+                                                       /* Found it */
+                                                       RegCloseKey(hkey);
+                                                       RegCloseKey(hsubkey);
+                                                       efree(libname);
+                                                       /* We can either open up the "win32" key and find the DLL name */
+                                                       /* Or just parse the version string and pass that in */
+                                                       /* The version string seems like a more portable solution */
+                                                       /* Given that there is a COM on Unix */
+                                                       if (2 != sscanf(version, "%d.%d", &major, &minor))
+                                                       {
+                                                               major = 1;
+                                                               minor = 0;
+                                                       }
+                                                       str = malloc(strlen(keyname)+strlen(version)+20); /* 18 == safety, 2 == extra comma and \0 */
+                                                       sprintf(str, "%s,%d,%d", keyname, major, minor);
+                                                       free(keyname);
+                                                       TypeLib = php_COM_find_typelib(str, mode);
+                                                       free(str);
+                                                       /* This is probbaly much harder to read and follow */
+                                                       /* But it is MUCH more effiecient than trying to */
+                                                       /* test for errors and leave through a single "return" */
+                                                       return TypeLib;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               /* Failed - perhaps too small abuffer */
+                                               /* But if too small, then the name does not match */
+                                       }
+                               }
+                               RegCloseKey(hsubkey);
+                       }
+                       free(keyname);
+                       free(libname);
+                       return NULL;
                }
        }
+       efree(p);
+       return TypeLib;
+}
+
+static int php_COM_load_typelib(char *typelib_name, int mode)
+{
+       ITypeLib *TypeLib;
+       ITypeComp *TypeComp;
+       int i;
+       int interfaces;
+       ELS_FETCH();
+
+       TypeLib = php_COM_find_typelib(typelib_name, mode);
+       if (NULL == TypeLib)
+       {
+               return FAILURE;
+       }
 
        interfaces = TypeLib->lpVtbl->GetTypeInfoCount(TypeLib);
 
@@ -1217,7 +1392,6 @@ static int php_COM_load_typelib(char *typelib_name, int mode)
 
 
        TypeLib->lpVtbl->Release(TypeLib);
-       efree(p);
        return SUCCESS;
 }