From 0e2410f47e29b87f84d68b437130770d1d2cfc02 Mon Sep 17 00:00:00 2001 From: suke Date: Wed, 6 Aug 2014 12:00:09 +0000 Subject: * ext/win32ole/win32ole.c: separate src of WIN32OLE_TYPELIB from win32ole.c * ext/win32ole/win32ole.h: ditto. * ext/win32ole/win32ole_typelib.c: ditto. * ext/win32ole/win32ole_typelib.h: ditto. * ext/win32ole/depend: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47088 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/win32ole/depend | 1 + ext/win32ole/win32ole.c | 880 ++-------------------------------------- ext/win32ole/win32ole.h | 28 +- ext/win32ole/win32ole_typelib.c | 818 +++++++++++++++++++++++++++++++++++++ ext/win32ole/win32ole_typelib.h | 10 + 5 files changed, 894 insertions(+), 843 deletions(-) create mode 100644 ext/win32ole/win32ole_typelib.c create mode 100644 ext/win32ole/win32ole_typelib.h (limited to 'ext') diff --git a/ext/win32ole/depend b/ext/win32ole/depend index 0dec504505..58a0ea1f7c 100644 --- a/ext/win32ole/depend +++ b/ext/win32ole/depend @@ -2,3 +2,4 @@ WIN32OLE_HEADERS = $(HDRS) $(ruby_headers) win32ole.o : win32ole.c $(WIN32OLE_HEADERS) win32ole_variant_m.o : win32ole_variant_m.c $(WIN32OLE_HEADERS) win32ole_error.o : win32ole_error.c $(WIN32OLE_HEADERS) +win32ole_typelib.o : win32ole_typelib.c $(WIN32OLE_HEADERS) diff --git a/ext/win32ole/win32ole.c b/ext/win32ole/win32ole.c index 997de6569d..84d1195ae2 100644 --- a/ext/win32ole/win32ole.c +++ b/ext/win32ole/win32ole.c @@ -26,21 +26,12 @@ const IID IID_IMultiLanguage2 = {0xDCCFC164, 0x2B38, 0x11d2, {0xB7, 0xEC, 0x00, 0xC0, 0x4F, 0x8F, 0x5D, 0x9A}}; #endif -#define OLE_RELEASE(X) (X) ? ((X)->lpVtbl->Release(X)) : 0 #define OLE_ADDREF(X) (X) ? ((X)->lpVtbl->AddRef(X)) : 0 #define OLE_GET_TYPEATTR(X, Y) ((X)->lpVtbl->GetTypeAttr((X), (Y))) #define OLE_RELEASE_TYPEATTR(X, Y) ((X)->lpVtbl->ReleaseTypeAttr((X), (Y))) -#define OLE_FREE(x) {\ - if(g_ole_initialized == TRUE) {\ - if(x) {\ - OLE_RELEASE(x);\ - (x) = 0;\ - }\ - }\ -} #define OLEData_Get_Struct(obj, pole) {\ Data_Get_Struct(obj, struct oledata, pole);\ @@ -61,9 +52,7 @@ const IID IID_IMultiLanguage2 = {0xDCCFC164, 0x2B38, 0x11d2, {0xB7, 0xEC, 0x00, #define NUM2UI8 NUM2UINT #endif -#define WC2VSTR(x) ole_wc2vstr((x), TRUE) - -#define WIN32OLE_VERSION "1.7.4" +#define WIN32OLE_VERSION "1.7.6" typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX) (REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*); @@ -121,8 +110,6 @@ typedef struct tagIEVENTSINKOBJ { }IEVENTSINKOBJ, *PIEVENTSINKOBJ; VALUE cWIN32OLE; -VALUE cWIN32OLE_TYPELIB; -VALUE cWIN32OLE_TYPE; VALUE cWIN32OLE_VARIABLE; VALUE cWIN32OLE_METHOD; VALUE cWIN32OLE_PARAM; @@ -143,6 +130,7 @@ static volatile DWORD g_ole_initialized_key = TLS_OUT_OF_INDEXES; # define g_ole_initialized_init() (g_ole_initialized_key = TlsAlloc()) # define g_ole_initialized_set(val) TlsSetValue(g_ole_initialized_key, (void*)(val)) #endif + static BOOL g_uninitialize_hooked = FALSE; static BOOL g_cp_installed = FALSE; static BOOL g_lcid_installed = FALSE; @@ -173,10 +161,6 @@ struct oledata { IDispatch *pDispatch; }; -struct oletypelibdata { - ITypeLib *pTypeLib; -}; - struct oletypedata { ITypeInfo *pTypeInfo; }; @@ -239,17 +223,13 @@ static UINT ole_init_cp(void); static char *ole_wc2mb(LPWSTR pw); static void ole_freeexceptinfo(EXCEPINFO *pExInfo); static VALUE ole_excepinfo2msg(EXCEPINFO *pExInfo); -static void ole_initialize(void); static void ole_msg_loop(void); static void ole_free(struct oledata *pole); -static void oletypelib_free(struct oletypelibdata *poletypelib); static void oletype_free(struct oletypedata *poletype); static void olemethod_free(struct olemethoddata *polemethod); static void olevariable_free(struct olevariabledata *polevar); static void oleparam_free(struct oleparamdata *pole); -static LPWSTR ole_vstr2wc(VALUE vstr); static LPWSTR ole_mb2wc(char *pm, int len); -static VALUE ole_wc2vstr(LPWSTR pw, BOOL isfree); static VALUE ole_ary_m_entry(VALUE val, LONG *pid); static void * get_ptr_of_variant(VARIANT *pvar); static VALUE is_all_index_under(LONG *pid, long *pub, long dim); @@ -266,28 +246,18 @@ static void ole_set_byref(VARIANT *realvar, VARIANT *var, VARTYPE vt); static void ole_val2olevariantdata(VALUE val, VARTYPE vt, struct olevariantdata *pvar); static void ole_val2variant2(VALUE val, VARIANT *var); static VALUE make_inspect(const char *class_name, VALUE detail); -static VALUE default_inspect(VALUE self, const char *class_name); static VALUE ole_set_member(VALUE self, IDispatch *dispatch); static VALUE fole_s_allocate(VALUE klass); static VALUE create_win32ole_object(VALUE klass, IDispatch *pDispatch, int argc, VALUE *argv); static VALUE ary_new_dim(VALUE myary, LONG *pid, LONG *plb, LONG dim); static void ary_store_dim(VALUE myary, LONG *pid, LONG *plb, LONG dim, VALUE val); static VALUE ole_variant2val(VARIANT *pvar); -static LONG reg_open_key(HKEY hkey, const char *name, HKEY *phkey); -static LONG reg_open_vkey(HKEY hkey, VALUE key, HKEY *phkey); -static VALUE reg_enum_key(HKEY hkey, DWORD i); -static VALUE reg_get_val(HKEY hkey, const char *subkey); -static VALUE reg_get_typelib_file_path(HKEY hkey); -static VALUE typelib_file_from_clsid(VALUE ole); -static VALUE typelib_file_from_typelib(VALUE ole); -static VALUE typelib_file(VALUE ole); static void ole_const_load(ITypeLib *pTypeLib, VALUE klass, VALUE self); static HRESULT clsid_from_remote(VALUE host, VALUE com, CLSID *pclsid); static VALUE ole_create_dcom(int argc, VALUE *argv, VALUE self); static VALUE ole_bind_obj(VALUE moniker, int argc, VALUE *argv, VALUE self); static VALUE fole_s_connect(int argc, VALUE *argv, VALUE self); static VALUE fole_s_const_load(int argc, VALUE *argv, VALUE self); -static VALUE ole_types_from_typelib(ITypeLib *pTypeLib, VALUE classes); static ULONG reference_count(struct oledata * pole); static VALUE fole_s_reference_count(VALUE self, VALUE obj); static VALUE fole_s_free(VALUE self, VALUE obj); @@ -350,27 +320,6 @@ static VALUE foletype_s_progids(VALUE self); static VALUE foletype_s_allocate(VALUE klass); static VALUE oletype_set_member(VALUE self, ITypeInfo *pTypeInfo, VALUE name); static VALUE oleclass_from_typelib(VALUE self, ITypeLib *pTypeLib, VALUE oleclass); -static VALUE oletypelib_set_member(VALUE self, ITypeLib *pTypeLib); -static ITypeLib * oletypelib_get_typelib(VALUE self); -static void oletypelib_get_libattr(ITypeLib *pTypeLib, TLIBATTR **ppTLibAttr); -static VALUE foletypelib_s_typelibs(VALUE self); -static VALUE make_version_str(VALUE major, VALUE minor); -static VALUE oletypelib_search_registry2(VALUE self, VALUE args); -static VALUE oletypelib_search_registry(VALUE self, VALUE typelib); -static VALUE foletypelib_s_allocate(VALUE klass); -static VALUE foletypelib_initialize(VALUE self, VALUE args); -static VALUE foletypelib_guid(VALUE self); -static VALUE foletypelib_name(VALUE self); -static VALUE foletypelib_version(VALUE self); -static VALUE foletypelib_major_version(VALUE self); -static VALUE foletypelib_minor_version(VALUE self); -static VALUE oletypelib_path(VALUE guid, VALUE version); -static HRESULT oletypelib_from_guid(VALUE guid, VALUE version, ITypeLib **ppTypeLib); -static VALUE foletypelib_path(VALUE self); -static VALUE foletypelib_visible(VALUE self); -static VALUE foletypelib_library_name(VALUE self); -static VALUE foletypelib_ole_types(VALUE self); -static VALUE foletypelib_inspect(VALUE self); static VALUE foletype_initialize(VALUE self, VALUE typelib, VALUE oleclass); static VALUE foletype_name(VALUE self); static VALUE ole_ole_type(ITypeInfo *pTypeInfo); @@ -740,6 +689,12 @@ static /* [local] */ HRESULT ( STDMETHODCALLTYPE Invoke )( return S_OK; } +BOOL +ole_initialized() +{ + return g_ole_initialized; +} + static IDispatch* val2dispatch(VALUE val) { @@ -1115,7 +1070,7 @@ ole_uninitialize_hook(rb_event_flag_t evflag, VALUE data, VALUE self, ID mid, VA ole_uninitialize(); } -static void +void ole_initialize(void) { HRESULT hr; @@ -1156,13 +1111,6 @@ ole_free(struct oledata *pole) free(pole); } -static void -oletypelib_free(struct oletypelibdata *poletypelib) -{ - OLE_FREE(poletypelib->pTypeLib); - free(poletypelib); -} - static void oletype_free(struct oletypedata *poletype) { @@ -1193,7 +1141,7 @@ oleparam_free(struct oleparamdata *pole) } -static LPWSTR +LPWSTR ole_vstr2wc(VALUE vstr) { rb_encoding *enc; @@ -1284,7 +1232,7 @@ ole_alloc_vstr(UINT size, void *arg) return RSTRING_PTR(str); } -static VALUE +VALUE ole_wc2vstr(LPWSTR pw, BOOL isfree) { VALUE vstr; @@ -1965,7 +1913,7 @@ make_inspect(const char *class_name, VALUE detail) return str; } -static VALUE +VALUE default_inspect(VALUE self, const char *class_name) { VALUE detail = rb_funcall(self, rb_intern("to_s"), 0); @@ -2315,19 +2263,19 @@ ole_variant2val(VARIANT *pvar) return obj; } -static LONG +LONG reg_open_key(HKEY hkey, const char *name, HKEY *phkey) { return RegOpenKeyEx(hkey, name, 0, KEY_READ, phkey); } -static LONG +LONG reg_open_vkey(HKEY hkey, VALUE key, HKEY *phkey) { return reg_open_key(hkey, StringValuePtr(key), phkey); } -static VALUE +VALUE reg_enum_key(HKEY hkey, DWORD i) { char buf[BUFSIZ + 1]; @@ -2342,7 +2290,7 @@ reg_enum_key(HKEY hkey, DWORD i) return Qnil; } -static VALUE +VALUE reg_get_val(HKEY hkey, const char *subkey) { char *pbuf; @@ -2370,7 +2318,7 @@ reg_get_val(HKEY hkey, const char *subkey) return val; } -static VALUE +VALUE reg_get_val2(HKEY hkey, const char *subkey) { HKEY hsubkey; @@ -2387,118 +2335,6 @@ reg_get_val2(HKEY hkey, const char *subkey) return val; } -static VALUE -reg_get_typelib_file_path(HKEY hkey) -{ - VALUE path = Qnil; - path = reg_get_val2(hkey, "win64"); - if (path != Qnil) { - return path; - } - path = reg_get_val2(hkey, "win32"); - if (path != Qnil) { - return path; - } - path = reg_get_val2(hkey, "win16"); - return path; -} - -static VALUE -typelib_file_from_clsid(VALUE ole) -{ - HKEY hroot, hclsid; - LONG err; - VALUE typelib; - char path[MAX_PATH + 1]; - - err = reg_open_key(HKEY_CLASSES_ROOT, "CLSID", &hroot); - if (err != ERROR_SUCCESS) { - return Qnil; - } - err = reg_open_key(hroot, StringValuePtr(ole), &hclsid); - if (err != ERROR_SUCCESS) { - RegCloseKey(hroot); - return Qnil; - } - typelib = reg_get_val2(hclsid, "InprocServer32"); - RegCloseKey(hroot); - RegCloseKey(hclsid); - if (typelib != Qnil) { - ExpandEnvironmentStrings(StringValuePtr(typelib), path, sizeof(path)); - path[MAX_PATH] = '\0'; - typelib = rb_str_new2(path); - } - return typelib; -} - -static VALUE -typelib_file_from_typelib(VALUE ole) -{ - HKEY htypelib, hclsid, hversion, hlang; - double fver; - DWORD i, j, k; - LONG err; - BOOL found = FALSE; - VALUE typelib; - VALUE file = Qnil; - VALUE clsid; - VALUE ver; - VALUE lang; - - err = reg_open_key(HKEY_CLASSES_ROOT, "TypeLib", &htypelib); - if(err != ERROR_SUCCESS) { - return Qnil; - } - for(i = 0; !found; i++) { - clsid = reg_enum_key(htypelib, i); - if (clsid == Qnil) - break; - err = reg_open_vkey(htypelib, clsid, &hclsid); - if (err != ERROR_SUCCESS) - continue; - fver = 0; - for(j = 0; !found; j++) { - ver = reg_enum_key(hclsid, j); - if (ver == Qnil) - break; - err = reg_open_vkey(hclsid, ver, &hversion); - if (err != ERROR_SUCCESS || fver > atof(StringValuePtr(ver))) - continue; - fver = atof(StringValuePtr(ver)); - typelib = reg_get_val(hversion, NULL); - if (typelib == Qnil) - continue; - if (rb_str_cmp(typelib, ole) == 0) { - for(k = 0; !found; k++) { - lang = reg_enum_key(hversion, k); - if (lang == Qnil) - break; - err = reg_open_vkey(hversion, lang, &hlang); - if (err == ERROR_SUCCESS) { - if ((file = reg_get_typelib_file_path(hlang)) != Qnil) - found = TRUE; - RegCloseKey(hlang); - } - } - } - RegCloseKey(hversion); - } - RegCloseKey(hclsid); - } - RegCloseKey(htypelib); - return file; -} - -static VALUE -typelib_file(VALUE ole) -{ - VALUE file = typelib_file_from_clsid(ole); - if (file != Qnil) { - return file; - } - return typelib_file_from_typelib(ole); -} - static void ole_const_load(ITypeLib *pTypeLib, VALUE klass, VALUE self) { @@ -2847,37 +2683,6 @@ fole_s_const_load(int argc, VALUE *argv, VALUE self) return Qnil; } -static VALUE -ole_types_from_typelib(ITypeLib *pTypeLib, VALUE classes) -{ - - long count; - int i; - HRESULT hr; - BSTR bstr; - ITypeInfo *pTypeInfo; - VALUE type; - - count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib); - for (i = 0; i < count; i++) { - hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i, - &bstr, NULL, NULL, NULL); - if (FAILED(hr)) - continue; - - hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, i, &pTypeInfo); - if (FAILED(hr)) - continue; - - type = foletype_s_allocate(cWIN32OLE_TYPE); - oletype_set_member(type, pTypeInfo, WC2VSTR(bstr)); - - rb_ary_push(classes, type); - OLE_RELEASE(pTypeInfo); - } - return classes; -} - static ULONG reference_count(struct oledata * pole) { @@ -4427,8 +4232,7 @@ ole_typelib_from_itypeinfo(ITypeInfo *pTypeInfo) if(FAILED(hr)) { return Qnil; } - retval = rb_funcall(cWIN32OLE_TYPELIB, rb_intern("allocate"), 0); - oletypelib_set_member(retval, pTypeLib); + retval = create_win32ole_typelib(pTypeLib); return retval; } @@ -4901,6 +4705,14 @@ oletype_set_member(VALUE self, ITypeInfo *pTypeInfo, VALUE name) return self; } +VALUE +create_win32ole_type(ITypeInfo *pTypeInfo, VALUE name) +{ + VALUE obj = foletype_s_allocate(cWIN32OLE_TYPE); + oletype_set_member(obj, pTypeInfo, name); + return obj; +} + static VALUE oleclass_from_typelib(VALUE self, ITypeLib *pTypeLib, VALUE oleclass) { @@ -4933,616 +4745,6 @@ oleclass_from_typelib(VALUE self, ITypeLib *pTypeLib, VALUE oleclass) return found; } -/* - * Document-class: WIN32OLE_TYPELIB - * - * WIN32OLE_TYPELIB objects represent OLE tyblib information. - */ - -static VALUE -oletypelib_set_member(VALUE self, ITypeLib *pTypeLib) -{ - struct oletypelibdata *ptlib; - Data_Get_Struct(self, struct oletypelibdata, ptlib); - ptlib->pTypeLib = pTypeLib; - return self; -} - -static ITypeLib * -oletypelib_get_typelib(VALUE self) -{ - struct oletypelibdata *ptlib; - Data_Get_Struct(self, struct oletypelibdata, ptlib); - return ptlib->pTypeLib; -} - -static void -oletypelib_get_libattr(ITypeLib *pTypeLib, TLIBATTR **ppTLibAttr) -{ - HRESULT hr; - hr = pTypeLib->lpVtbl->GetLibAttr(pTypeLib, ppTLibAttr); - if (FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, - "failed to get library attribute(TLIBATTR) from ITypeLib"); - } -} - -/* - * call-seq: - * - * WIN32OLE_TYPELIB.typelibs - * - * Returns the array of WIN32OLE_TYPELIB object. - * - * tlibs = WIN32OLE_TYPELIB.typelibs - * - */ -static VALUE -foletypelib_s_typelibs(VALUE self) -{ - HKEY htypelib, hguid; - DWORD i, j; - LONG err; - VALUE guid; - VALUE version; - VALUE name = Qnil; - VALUE typelibs = rb_ary_new(); - VALUE typelib = Qnil; - HRESULT hr; - ITypeLib *pTypeLib; - - err = reg_open_key(HKEY_CLASSES_ROOT, "TypeLib", &htypelib); - if(err != ERROR_SUCCESS) { - return typelibs; - } - for(i = 0; ; i++) { - guid = reg_enum_key(htypelib, i); - if (guid == Qnil) - break; - err = reg_open_vkey(htypelib, guid, &hguid); - if (err != ERROR_SUCCESS) - continue; - for(j = 0; ; j++) { - version = reg_enum_key(hguid, j); - if (version == Qnil) - break; - if ( (name = reg_get_val2(hguid, StringValuePtr(version))) != Qnil ) { - hr = oletypelib_from_guid(guid, version, &pTypeLib); - if (SUCCEEDED(hr)) { - typelib = rb_funcall(cWIN32OLE_TYPELIB, rb_intern("allocate"), 0); - oletypelib_set_member(typelib, pTypeLib); - rb_ary_push(typelibs, typelib); - } - } - } - RegCloseKey(hguid); - } - RegCloseKey(htypelib); - return typelibs; -} - -static VALUE -make_version_str(VALUE major, VALUE minor) -{ - VALUE version_str = Qnil; - VALUE minor_str = Qnil; - if (major == Qnil) { - return Qnil; - } - version_str = rb_String(major); - if (minor != Qnil) { - minor_str = rb_String(minor); - rb_str_cat2(version_str, "."); - rb_str_append(version_str, minor_str); - } - return version_str; -} - -static VALUE -oletypelib_search_registry2(VALUE self, VALUE args) -{ - HKEY htypelib, hguid, hversion; - double fver; - DWORD j; - LONG err; - VALUE found = Qfalse; - VALUE tlib; - VALUE ver; - VALUE version_str; - VALUE version = Qnil; - VALUE typelib = Qnil; - HRESULT hr; - ITypeLib *pTypeLib; - - VALUE guid = rb_ary_entry(args, 0); - version_str = make_version_str(rb_ary_entry(args, 1), rb_ary_entry(args, 2)); - - err = reg_open_key(HKEY_CLASSES_ROOT, "TypeLib", &htypelib); - if(err != ERROR_SUCCESS) { - return Qfalse; - } - err = reg_open_vkey(htypelib, guid, &hguid); - if (err != ERROR_SUCCESS) { - RegCloseKey(htypelib); - return Qfalse; - } - if (version_str != Qnil) { - err = reg_open_vkey(hguid, version_str, &hversion); - if (err == ERROR_SUCCESS) { - tlib = reg_get_val(hversion, NULL); - if (tlib != Qnil) { - typelib = tlib; - version = version_str; - } - } - RegCloseKey(hversion); - } else { - fver = 0.0; - for(j = 0; ;j++) { - ver = reg_enum_key(hguid, j); - if (ver == Qnil) - break; - err = reg_open_vkey(hguid, ver, &hversion); - if (err != ERROR_SUCCESS) - continue; - tlib = reg_get_val(hversion, NULL); - if (tlib == Qnil) { - RegCloseKey(hversion); - continue; - } - if (fver < atof(StringValuePtr(ver))) { - fver = atof(StringValuePtr(ver)); - version = ver; - typelib = tlib; - } - RegCloseKey(hversion); - } - } - RegCloseKey(hguid); - RegCloseKey(htypelib); - if (typelib != Qnil) { - hr = oletypelib_from_guid(guid, version, &pTypeLib); - if (SUCCEEDED(hr)) { - found = Qtrue; - oletypelib_set_member(self, pTypeLib); - } - } - return found; -} - -static VALUE -oletypelib_search_registry(VALUE self, VALUE typelib) -{ - HKEY htypelib, hguid, hversion; - DWORD i, j; - LONG err; - VALUE found = Qfalse; - VALUE tlib; - VALUE guid; - VALUE ver; - HRESULT hr; - ITypeLib *pTypeLib; - - err = reg_open_key(HKEY_CLASSES_ROOT, "TypeLib", &htypelib); - if(err != ERROR_SUCCESS) { - return Qfalse; - } - for(i = 0; !found; i++) { - guid = reg_enum_key(htypelib, i); - if (guid == Qnil) - break; - err = reg_open_vkey(htypelib, guid, &hguid); - if (err != ERROR_SUCCESS) - continue; - for(j = 0; found == Qfalse; j++) { - ver = reg_enum_key(hguid, j); - if (ver == Qnil) - break; - err = reg_open_vkey(hguid, ver, &hversion); - if (err != ERROR_SUCCESS) - continue; - tlib = reg_get_val(hversion, NULL); - if (tlib == Qnil) { - RegCloseKey(hversion); - continue; - } - if (rb_str_cmp(typelib, tlib) == 0) { - hr = oletypelib_from_guid(guid, ver, &pTypeLib); - if (SUCCEEDED(hr)) { - oletypelib_set_member(self, pTypeLib); - found = Qtrue; - } - } - RegCloseKey(hversion); - } - RegCloseKey(hguid); - } - RegCloseKey(htypelib); - return found; -} - -static VALUE -foletypelib_s_allocate(VALUE klass) -{ - struct oletypelibdata *poletypelib; - VALUE obj; - ole_initialize(); - obj = Data_Make_Struct(klass, struct oletypelibdata, 0, oletypelib_free, poletypelib); - poletypelib->pTypeLib = NULL; - return obj; -} - -/* - * call-seq: - * WIN32OLE_TYPELIB.new(typelib [, version1, version2]) -> WIN32OLE_TYPELIB object - * - * Returns a new WIN32OLE_TYPELIB object. - * - * The first argument typelib specifies OLE type library name or GUID or - * OLE library file. - * The second argument is major version or version of the type library. - * The third argument is minor version. - * The second argument and third argument are optional. - * If the first argument is type library name, then the second and third argument - * are ignored. - * - * tlib1 = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') - * tlib2 = WIN32OLE_TYPELIB.new('{00020813-0000-0000-C000-000000000046}') - * tlib3 = WIN32OLE_TYPELIB.new('{00020813-0000-0000-C000-000000000046}', 1.3) - * tlib4 = WIN32OLE_TYPELIB.new('{00020813-0000-0000-C000-000000000046}', 1, 3) - * tlib5 = WIN32OLE_TYPELIB.new("C:\\WINNT\\SYSTEM32\\SHELL32.DLL") - * puts tlib1.name # -> 'Microsoft Excel 9.0 Object Library' - * puts tlib2.name # -> 'Microsoft Excel 9.0 Object Library' - * puts tlib3.name # -> 'Microsoft Excel 9.0 Object Library' - * puts tlib4.name # -> 'Microsoft Excel 9.0 Object Library' - * puts tlib5.name # -> 'Microsoft Shell Controls And Automation' - * - */ -static VALUE -foletypelib_initialize(VALUE self, VALUE args) -{ - VALUE found = Qfalse; - VALUE typelib = Qnil; - int len = 0; - OLECHAR * pbuf; - ITypeLib *pTypeLib; - HRESULT hr = S_OK; - - len = RARRAY_LEN(args); - if (len < 1 || len > 3) { - rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..3)", len); - } - - typelib = rb_ary_entry(args, 0); - - SafeStringValue(typelib); - - found = oletypelib_search_registry(self, typelib); - if (found == Qfalse) { - found = oletypelib_search_registry2(self, args); - } - if (found == Qfalse) { - pbuf = ole_vstr2wc(typelib); - hr = LoadTypeLibEx(pbuf, REGKIND_NONE, &pTypeLib); - SysFreeString(pbuf); - if (SUCCEEDED(hr)) { - found = Qtrue; - oletypelib_set_member(self, pTypeLib); - } - } - - if (found == Qfalse) { - rb_raise(eWIN32OLERuntimeError, "not found type library `%s`", - StringValuePtr(typelib)); - } - return self; -} - -/* - * call-seq: - * WIN32OLE_TYPELIB#guid -> The guid string. - * - * Returns guid string which specifies type library. - * - * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') - * guid = tlib.guid # -> '{00020813-0000-0000-C000-000000000046}' - */ -static VALUE -foletypelib_guid(VALUE self) -{ - ITypeLib *pTypeLib; - OLECHAR bstr[80]; - VALUE guid = Qnil; - int len; - TLIBATTR *pTLibAttr; - - pTypeLib = oletypelib_get_typelib(self); - oletypelib_get_libattr(pTypeLib, &pTLibAttr); - len = StringFromGUID2(&pTLibAttr->guid, bstr, sizeof(bstr)/sizeof(OLECHAR)); - if (len > 3) { - guid = ole_wc2vstr(bstr, FALSE); - } - pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr); - return guid; -} - -/* - * call-seq: - * WIN32OLE_TYPELIB#name -> The type library name - * - * Returns the type library name. - * - * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') - * name = tlib.name # -> 'Microsoft Excel 9.0 Object Library' - */ -static VALUE -foletypelib_name(VALUE self) -{ - ITypeLib *pTypeLib; - HRESULT hr; - BSTR bstr; - VALUE name; - pTypeLib = oletypelib_get_typelib(self); - hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, -1, - NULL, &bstr, NULL, NULL); - - if (FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, "failed to get name from ITypeLib"); - } - name = WC2VSTR(bstr); - return name; -} - -/* - * call-seq: - * WIN32OLE_TYPELIB#version -> The type library version. - * - * Returns the type library version. - * - * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') - * puts tlib.version #-> 1.3 - */ -static VALUE -foletypelib_version(VALUE self) -{ - TLIBATTR *pTLibAttr; - VALUE major; - VALUE minor; - ITypeLib *pTypeLib; - - pTypeLib = oletypelib_get_typelib(self); - oletypelib_get_libattr(pTypeLib, &pTLibAttr); - major = INT2NUM(pTLibAttr->wMajorVerNum); - minor = INT2NUM(pTLibAttr->wMinorVerNum); - pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr); - return rb_Float(make_version_str(major, minor)); -} - -/* - * call-seq: - * WIN32OLE_TYPELIB#major_version -> The type library major version. - * - * Returns the type library major version. - * - * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') - * puts tlib.major_version # -> 1 - */ -static VALUE -foletypelib_major_version(VALUE self) -{ - TLIBATTR *pTLibAttr; - VALUE major; - ITypeLib *pTypeLib; - pTypeLib = oletypelib_get_typelib(self); - oletypelib_get_libattr(pTypeLib, &pTLibAttr); - - major = INT2NUM(pTLibAttr->wMajorVerNum); - pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr); - return major; -} - -/* - * call-seq: - * WIN32OLE_TYPELIB#minor_version -> The type library minor version. - * - * Returns the type library minor version. - * - * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') - * puts tlib.minor_version # -> 3 - */ -static VALUE -foletypelib_minor_version(VALUE self) -{ - TLIBATTR *pTLibAttr; - VALUE minor; - ITypeLib *pTypeLib; - pTypeLib = oletypelib_get_typelib(self); - oletypelib_get_libattr(pTypeLib, &pTLibAttr); - minor = INT2NUM(pTLibAttr->wMinorVerNum); - pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr); - return minor; -} - -static VALUE -oletypelib_path(VALUE guid, VALUE version) -{ - int k; - LONG err; - HKEY hkey; - HKEY hlang; - VALUE lang; - VALUE path = Qnil; - - VALUE key = rb_str_new2("TypeLib\\"); - rb_str_concat(key, guid); - rb_str_cat2(key, "\\"); - rb_str_concat(key, version); - - err = reg_open_vkey(HKEY_CLASSES_ROOT, key, &hkey); - if (err != ERROR_SUCCESS) { - return Qnil; - } - for(k = 0; path == Qnil; k++) { - lang = reg_enum_key(hkey, k); - if (lang == Qnil) - break; - err = reg_open_vkey(hkey, lang, &hlang); - if (err == ERROR_SUCCESS) { - path = reg_get_typelib_file_path(hlang); - RegCloseKey(hlang); - } - } - RegCloseKey(hkey); - return path; -} - -static HRESULT -oletypelib_from_guid(VALUE guid, VALUE version, ITypeLib **ppTypeLib) -{ - VALUE path; - OLECHAR *pBuf; - HRESULT hr; - path = oletypelib_path(guid, version); - if (path == Qnil) { - return E_UNEXPECTED; - } - pBuf = ole_vstr2wc(path); - hr = LoadTypeLibEx(pBuf, REGKIND_NONE, ppTypeLib); - SysFreeString(pBuf); - return hr; -} - -/* - * call-seq: - * WIN32OLE_TYPELIB#path -> The type library file path. - * - * Returns the type library file path. - * - * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') - * puts tlib.path #-> 'C:\...\EXCEL9.OLB' - */ -static VALUE -foletypelib_path(VALUE self) -{ - TLIBATTR *pTLibAttr; - HRESULT hr = S_OK; - BSTR bstr; - LCID lcid = cWIN32OLE_lcid; - VALUE path; - ITypeLib *pTypeLib; - - pTypeLib = oletypelib_get_typelib(self); - oletypelib_get_libattr(pTypeLib, &pTLibAttr); - hr = QueryPathOfRegTypeLib(&pTLibAttr->guid, - pTLibAttr->wMajorVerNum, - pTLibAttr->wMinorVerNum, - lcid, - &bstr); - if (FAILED(hr)) { - pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr); - ole_raise(hr, eWIN32OLERuntimeError, "failed to QueryPathOfRegTypeTypeLib"); - } - - pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr); - path = WC2VSTR(bstr); - return path; -} - -/* - * call-seq: - * WIN32OLE_TYPELIB#visible? - * - * Returns true if the type library information is not hidden. - * If wLibFlags of TLIBATTR is 0 or LIBFLAG_FRESTRICTED or LIBFLAG_FHIDDEN, - * the method returns false, otherwise, returns true. - * If the method fails to access the TLIBATTR information, then - * WIN32OLERuntimeError is raised. - * - * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') - * tlib.visible? # => true - */ -static VALUE -foletypelib_visible(VALUE self) -{ - ITypeLib *pTypeLib = NULL; - VALUE visible = Qtrue; - TLIBATTR *pTLibAttr; - - pTypeLib = oletypelib_get_typelib(self); - oletypelib_get_libattr(pTypeLib, &pTLibAttr); - - if ((pTLibAttr->wLibFlags == 0) || - (pTLibAttr->wLibFlags & LIBFLAG_FRESTRICTED) || - (pTLibAttr->wLibFlags & LIBFLAG_FHIDDEN)) { - visible = Qfalse; - } - pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr); - return visible; -} - -/* - * call-seq: - * WIN32OLE_TYPELIB#library_name - * - * Returns library name. - * If the method fails to access library name, WIN32OLERuntimeError is raised. - * - * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') - * tlib.library_name # => Excel - */ -static VALUE -foletypelib_library_name(VALUE self) -{ - HRESULT hr; - ITypeLib *pTypeLib = NULL; - VALUE libname = Qnil; - BSTR bstr; - - pTypeLib = oletypelib_get_typelib(self); - hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, -1, - &bstr, NULL, NULL, NULL); - if (FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, "failed to get library name"); - } - libname = WC2VSTR(bstr); - return libname; -} - - -/* - * call-seq: - * WIN32OLE_TYPELIB#ole_types -> The array of WIN32OLE_TYPE object included the type library. - * - * Returns the type library file path. - * - * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') - * classes = tlib.ole_types.collect{|k| k.name} # -> ['AddIn', 'AddIns' ...] - */ -static VALUE -foletypelib_ole_types(VALUE self) -{ - ITypeLib *pTypeLib = NULL; - VALUE classes = rb_ary_new(); - pTypeLib = oletypelib_get_typelib(self); - ole_types_from_typelib(pTypeLib, classes); - return classes; -} - -/* - * call-seq: - * WIN32OLE_TYPELIB#inspect -> String - * - * Returns the type library name with class name. - * - * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') - * tlib.inspect # => "<#WIN32OLE_TYPELIB:Microsoft Excel 9.0 Object Library>" - */ -static VALUE -foletypelib_inspect(VALUE self) -{ - return default_inspect(self, "WIN32OLE_TYPELIB"); -} - /* * Document-class: WIN32OLE_TYPE * @@ -9313,7 +8515,7 @@ folerecord_initialize(VALUE self, VALUE typename, VALUE oleobj) { if(rb_obj_is_kind_of(oleobj, cWIN32OLE)) { hr = typelib_from_val(oleobj, &pTypeLib); } else if (rb_obj_is_kind_of(oleobj, cWIN32OLE_TYPELIB)) { - pTypeLib = oletypelib_get_typelib(oleobj); + pTypeLib = itypelib(oleobj); OLE_ADDREF(pTypeLib); if (pTypeLib) { hr = S_OK; @@ -9471,6 +8673,16 @@ folerecord_method_missing(int argc, VALUE *argv, VALUE self) VALUE name; rb_check_arity(argc, 1, 2); name = rb_sym_to_s(argv[0]); + +#if SIZEOF_SIZE_T > SIZEOF_LONG + { + size_t n = strlen(StringValueCStr(name)); + if (n >= LONG_MAX) { + rb_raise(rb_eRuntimeError, "too long member name"); + } + } +#endif + if (argc == 1) { return olerecord_ivar_get(self, name); } else if (argc == 2) { @@ -9769,23 +8981,7 @@ Init_win32ole(void) rb_define_const(cWIN32OLE, "LOCALE_USER_DEFAULT", INT2FIX(LOCALE_USER_DEFAULT)); Init_win32ole_variant_m(); - - cWIN32OLE_TYPELIB = rb_define_class("WIN32OLE_TYPELIB", rb_cObject); - rb_define_singleton_method(cWIN32OLE_TYPELIB, "typelibs", foletypelib_s_typelibs, 0); - rb_define_alloc_func(cWIN32OLE_TYPELIB, foletypelib_s_allocate); - rb_define_method(cWIN32OLE_TYPELIB, "initialize", foletypelib_initialize, -2); - rb_define_method(cWIN32OLE_TYPELIB, "guid", foletypelib_guid, 0); - rb_define_method(cWIN32OLE_TYPELIB, "name", foletypelib_name, 0); - rb_define_method(cWIN32OLE_TYPELIB, "version", foletypelib_version, 0); - rb_define_method(cWIN32OLE_TYPELIB, "major_version", foletypelib_major_version, 0); - rb_define_method(cWIN32OLE_TYPELIB, "minor_version", foletypelib_minor_version, 0); - rb_define_method(cWIN32OLE_TYPELIB, "path", foletypelib_path, 0); - rb_define_method(cWIN32OLE_TYPELIB, "ole_types", foletypelib_ole_types, 0); - rb_define_alias(cWIN32OLE_TYPELIB, "ole_classes", "ole_types"); - rb_define_method(cWIN32OLE_TYPELIB, "visible?", foletypelib_visible, 0); - rb_define_method(cWIN32OLE_TYPELIB, "library_name", foletypelib_library_name, 0); - rb_define_alias(cWIN32OLE_TYPELIB, "to_s", "name"); - rb_define_method(cWIN32OLE_TYPELIB, "inspect", foletypelib_inspect, 0); + Init_win32ole_typelib(); cWIN32OLE_TYPE = rb_define_class("WIN32OLE_TYPE", rb_cObject); rb_define_singleton_method(cWIN32OLE_TYPE, "ole_classes", foletype_s_ole_classes, 1); diff --git a/ext/win32ole/win32ole.h b/ext/win32ole/win32ole.h index 4b478392d3..2fc0a09107 100644 --- a/ext/win32ole/win32ole.h +++ b/ext/win32ole/win32ole.h @@ -82,12 +82,38 @@ #define V_UINTREF(X) V_UNION(X, puintVal) #endif +#define OLE_RELEASE(X) (X) ? ((X)->lpVtbl->Release(X)) : 0 +#define OLE_FREE(x) {\ + if(ole_initialized() == TRUE) {\ + if(x) {\ + OLE_RELEASE(x);\ + (x) = 0;\ + }\ + }\ +} VALUE cWIN32OLE; - +VALUE cWIN32OLE_TYPE; LCID cWIN32OLE_lcid; +LPWSTR ole_vstr2wc(VALUE vstr); +LONG reg_open_key(HKEY hkey, const char *name, HKEY *phkey); +LONG reg_open_vkey(HKEY hkey, VALUE key, HKEY *phkey); +VALUE reg_enum_key(HKEY hkey, DWORD i); +VALUE reg_get_val(HKEY hkey, const char *subkey); +VALUE reg_get_val2(HKEY hkey, const char *subkey); +void ole_initialize(void); +VALUE default_inspect(VALUE self, const char *class_name); +VALUE ole_wc2vstr(LPWSTR pw, BOOL isfree); + + +#define WC2VSTR(x) ole_wc2vstr((x), TRUE) + +BOOL ole_initialized(); +VALUE create_win32ole_type(ITypeInfo *pTypeInfo, VALUE name); + #include "win32ole_variant_m.h" +#include "win32ole_typelib.h" #include "win32ole_error.h" #endif diff --git a/ext/win32ole/win32ole_typelib.c b/ext/win32ole/win32ole_typelib.c new file mode 100644 index 0000000000..2becbfdf45 --- /dev/null +++ b/ext/win32ole/win32ole_typelib.c @@ -0,0 +1,818 @@ +#include "win32ole.h" + +struct oletypelibdata { + ITypeLib *pTypeLib; +}; + +static VALUE reg_get_typelib_file_path(HKEY hkey); +static VALUE oletypelib_path(VALUE guid, VALUE version); +static HRESULT oletypelib_from_guid(VALUE guid, VALUE version, ITypeLib **ppTypeLib); +static VALUE foletypelib_s_typelibs(VALUE self); +static VALUE oletypelib_set_member(VALUE self, ITypeLib *pTypeLib); +static void oletypelib_free(struct oletypelibdata *poletypelib); +static VALUE foletypelib_s_allocate(VALUE klass); +static VALUE oletypelib_search_registry(VALUE self, VALUE typelib); +static void oletypelib_get_libattr(ITypeLib *pTypeLib, TLIBATTR **ppTLibAttr); +static VALUE oletypelib_search_registry2(VALUE self, VALUE args); +static VALUE foletypelib_initialize(VALUE self, VALUE args); +static VALUE foletypelib_guid(VALUE self); +static VALUE foletypelib_name(VALUE self); +static VALUE make_version_str(VALUE major, VALUE minor); +static VALUE foletypelib_version(VALUE self); +static VALUE foletypelib_major_version(VALUE self); +static VALUE foletypelib_minor_version(VALUE self); +static VALUE foletypelib_path(VALUE self); +static VALUE foletypelib_visible(VALUE self); +static VALUE foletypelib_library_name(VALUE self); +static VALUE ole_types_from_typelib(ITypeLib *pTypeLib, VALUE classes); +static VALUE typelib_file_from_typelib(VALUE ole); +static VALUE typelib_file_from_clsid(VALUE ole); +static VALUE foletypelib_ole_types(VALUE self); +static VALUE foletypelib_inspect(VALUE self); + +static VALUE +reg_get_typelib_file_path(HKEY hkey) +{ + VALUE path = Qnil; + path = reg_get_val2(hkey, "win64"); + if (path != Qnil) { + return path; + } + path = reg_get_val2(hkey, "win32"); + if (path != Qnil) { + return path; + } + path = reg_get_val2(hkey, "win16"); + return path; +} + +static VALUE +oletypelib_path(VALUE guid, VALUE version) +{ + int k; + LONG err; + HKEY hkey; + HKEY hlang; + VALUE lang; + VALUE path = Qnil; + + VALUE key = rb_str_new2("TypeLib\\"); + rb_str_concat(key, guid); + rb_str_cat2(key, "\\"); + rb_str_concat(key, version); + + err = reg_open_vkey(HKEY_CLASSES_ROOT, key, &hkey); + if (err != ERROR_SUCCESS) { + return Qnil; + } + for(k = 0; path == Qnil; k++) { + lang = reg_enum_key(hkey, k); + if (lang == Qnil) + break; + err = reg_open_vkey(hkey, lang, &hlang); + if (err == ERROR_SUCCESS) { + path = reg_get_typelib_file_path(hlang); + RegCloseKey(hlang); + } + } + RegCloseKey(hkey); + return path; +} + +static HRESULT +oletypelib_from_guid(VALUE guid, VALUE version, ITypeLib **ppTypeLib) +{ + VALUE path; + OLECHAR *pBuf; + HRESULT hr; + path = oletypelib_path(guid, version); + if (path == Qnil) { + return E_UNEXPECTED; + } + pBuf = ole_vstr2wc(path); + hr = LoadTypeLibEx(pBuf, REGKIND_NONE, ppTypeLib); + SysFreeString(pBuf); + return hr; +} + +ITypeLib * +itypelib(VALUE self) +{ + struct oletypelibdata *ptlib; + Data_Get_Struct(self, struct oletypelibdata, ptlib); + return ptlib->pTypeLib; +} + +/* + * Document-class: WIN32OLE_TYPELIB + * + * WIN32OLE_TYPELIB objects represent OLE tyblib information. + */ + +/* + * call-seq: + * + * WIN32OLE_TYPELIB.typelibs + * + * Returns the array of WIN32OLE_TYPELIB object. + * + * tlibs = WIN32OLE_TYPELIB.typelibs + * + */ +static VALUE +foletypelib_s_typelibs(VALUE self) +{ + HKEY htypelib, hguid; + DWORD i, j; + LONG err; + VALUE guid; + VALUE version; + VALUE name = Qnil; + VALUE typelibs = rb_ary_new(); + VALUE typelib = Qnil; + HRESULT hr; + ITypeLib *pTypeLib; + + err = reg_open_key(HKEY_CLASSES_ROOT, "TypeLib", &htypelib); + if(err != ERROR_SUCCESS) { + return typelibs; + } + for(i = 0; ; i++) { + guid = reg_enum_key(htypelib, i); + if (guid == Qnil) + break; + err = reg_open_vkey(htypelib, guid, &hguid); + if (err != ERROR_SUCCESS) + continue; + for(j = 0; ; j++) { + version = reg_enum_key(hguid, j); + if (version == Qnil) + break; + if ( (name = reg_get_val2(hguid, StringValuePtr(version))) != Qnil ) { + hr = oletypelib_from_guid(guid, version, &pTypeLib); + if (SUCCEEDED(hr)) { + typelib = create_win32ole_typelib(pTypeLib); + rb_ary_push(typelibs, typelib); + } + } + } + RegCloseKey(hguid); + } + RegCloseKey(htypelib); + return typelibs; +} + +static VALUE +oletypelib_set_member(VALUE self, ITypeLib *pTypeLib) +{ + struct oletypelibdata *ptlib; + Data_Get_Struct(self, struct oletypelibdata, ptlib); + ptlib->pTypeLib = pTypeLib; + return self; +} + +static void +oletypelib_free(struct oletypelibdata *poletypelib) +{ + OLE_FREE(poletypelib->pTypeLib); + free(poletypelib); +} + +static VALUE +foletypelib_s_allocate(VALUE klass) +{ + struct oletypelibdata *poletypelib; + VALUE obj; + ole_initialize(); + obj = Data_Make_Struct(klass, struct oletypelibdata, 0, oletypelib_free, poletypelib); + poletypelib->pTypeLib = NULL; + return obj; +} + +VALUE +create_win32ole_typelib(ITypeLib *pTypeLib) +{ + VALUE obj = foletypelib_s_allocate(cWIN32OLE_TYPELIB); + oletypelib_set_member(obj, pTypeLib); + return obj; +} + +static VALUE +oletypelib_search_registry(VALUE self, VALUE typelib) +{ + HKEY htypelib, hguid, hversion; + DWORD i, j; + LONG err; + VALUE found = Qfalse; + VALUE tlib; + VALUE guid; + VALUE ver; + HRESULT hr; + ITypeLib *pTypeLib; + + err = reg_open_key(HKEY_CLASSES_ROOT, "TypeLib", &htypelib); + if(err != ERROR_SUCCESS) { + return Qfalse; + } + for(i = 0; !found; i++) { + guid = reg_enum_key(htypelib, i); + if (guid == Qnil) + break; + err = reg_open_vkey(htypelib, guid, &hguid); + if (err != ERROR_SUCCESS) + continue; + for(j = 0; found == Qfalse; j++) { + ver = reg_enum_key(hguid, j); + if (ver == Qnil) + break; + err = reg_open_vkey(hguid, ver, &hversion); + if (err != ERROR_SUCCESS) + continue; + tlib = reg_get_val(hversion, NULL); + if (tlib == Qnil) { + RegCloseKey(hversion); + continue; + } + if (rb_str_cmp(typelib, tlib) == 0) { + hr = oletypelib_from_guid(guid, ver, &pTypeLib); + if (SUCCEEDED(hr)) { + oletypelib_set_member(self, pTypeLib); + found = Qtrue; + } + } + RegCloseKey(hversion); + } + RegCloseKey(hguid); + } + RegCloseKey(htypelib); + return found; +} + +static void +oletypelib_get_libattr(ITypeLib *pTypeLib, TLIBATTR **ppTLibAttr) +{ + HRESULT hr; + hr = pTypeLib->lpVtbl->GetLibAttr(pTypeLib, ppTLibAttr); + if (FAILED(hr)) { + ole_raise(hr, eWIN32OLERuntimeError, + "failed to get library attribute(TLIBATTR) from ITypeLib"); + } +} + +static VALUE +oletypelib_search_registry2(VALUE self, VALUE args) +{ + HKEY htypelib, hguid, hversion; + double fver; + DWORD j; + LONG err; + VALUE found = Qfalse; + VALUE tlib; + VALUE ver; + VALUE version_str; + VALUE version = Qnil; + VALUE typelib = Qnil; + HRESULT hr; + ITypeLib *pTypeLib; + + VALUE guid = rb_ary_entry(args, 0); + version_str = make_version_str(rb_ary_entry(args, 1), rb_ary_entry(args, 2)); + + err = reg_open_key(HKEY_CLASSES_ROOT, "TypeLib", &htypelib); + if(err != ERROR_SUCCESS) { + return Qfalse; + } + err = reg_open_vkey(htypelib, guid, &hguid); + if (err != ERROR_SUCCESS) { + RegCloseKey(htypelib); + return Qfalse; + } + if (version_str != Qnil) { + err = reg_open_vkey(hguid, version_str, &hversion); + if (err == ERROR_SUCCESS) { + tlib = reg_get_val(hversion, NULL); + if (tlib != Qnil) { + typelib = tlib; + version = version_str; + } + } + RegCloseKey(hversion); + } else { + fver = 0.0; + for(j = 0; ;j++) { + ver = reg_enum_key(hguid, j); + if (ver == Qnil) + break; + err = reg_open_vkey(hguid, ver, &hversion); + if (err != ERROR_SUCCESS) + continue; + tlib = reg_get_val(hversion, NULL); + if (tlib == Qnil) { + RegCloseKey(hversion); + continue; + } + if (fver < atof(StringValuePtr(ver))) { + fver = atof(StringValuePtr(ver)); + version = ver; + typelib = tlib; + } + RegCloseKey(hversion); + } + } + RegCloseKey(hguid); + RegCloseKey(htypelib); + if (typelib != Qnil) { + hr = oletypelib_from_guid(guid, version, &pTypeLib); + if (SUCCEEDED(hr)) { + found = Qtrue; + oletypelib_set_member(self, pTypeLib); + } + } + return found; +} + + +/* + * call-seq: + * WIN32OLE_TYPELIB.new(typelib [, version1, version2]) -> WIN32OLE_TYPELIB object + * + * Returns a new WIN32OLE_TYPELIB object. + * + * The first argument typelib specifies OLE type library name or GUID or + * OLE library file. + * The second argument is major version or version of the type library. + * The third argument is minor version. + * The second argument and third argument are optional. + * If the first argument is type library name, then the second and third argument + * are ignored. + * + * tlib1 = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') + * tlib2 = WIN32OLE_TYPELIB.new('{00020813-0000-0000-C000-000000000046}') + * tlib3 = WIN32OLE_TYPELIB.new('{00020813-0000-0000-C000-000000000046}', 1.3) + * tlib4 = WIN32OLE_TYPELIB.new('{00020813-0000-0000-C000-000000000046}', 1, 3) + * tlib5 = WIN32OLE_TYPELIB.new("C:\\WINNT\\SYSTEM32\\SHELL32.DLL") + * puts tlib1.name # -> 'Microsoft Excel 9.0 Object Library' + * puts tlib2.name # -> 'Microsoft Excel 9.0 Object Library' + * puts tlib3.name # -> 'Microsoft Excel 9.0 Object Library' + * puts tlib4.name # -> 'Microsoft Excel 9.0 Object Library' + * puts tlib5.name # -> 'Microsoft Shell Controls And Automation' + * + */ +static VALUE +foletypelib_initialize(VALUE self, VALUE args) +{ + VALUE found = Qfalse; + VALUE typelib = Qnil; + int len = 0; + OLECHAR * pbuf; + ITypeLib *pTypeLib; + HRESULT hr = S_OK; + + len = RARRAY_LEN(args); + if (len < 1 || len > 3) { + rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..3)", len); + } + + typelib = rb_ary_entry(args, 0); + + SafeStringValue(typelib); + + found = oletypelib_search_registry(self, typelib); + if (found == Qfalse) { + found = oletypelib_search_registry2(self, args); + } + if (found == Qfalse) { + pbuf = ole_vstr2wc(typelib); + hr = LoadTypeLibEx(pbuf, REGKIND_NONE, &pTypeLib); + SysFreeString(pbuf); + if (SUCCEEDED(hr)) { + found = Qtrue; + oletypelib_set_member(self, pTypeLib); + } + } + + if (found == Qfalse) { + rb_raise(eWIN32OLERuntimeError, "not found type library `%s`", + StringValuePtr(typelib)); + } + return self; +} + +/* + * call-seq: + * WIN32OLE_TYPELIB#guid -> The guid string. + * + * Returns guid string which specifies type library. + * + * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') + * guid = tlib.guid # -> '{00020813-0000-0000-C000-000000000046}' + */ +static VALUE +foletypelib_guid(VALUE self) +{ + ITypeLib *pTypeLib; + OLECHAR bstr[80]; + VALUE guid = Qnil; + int len; + TLIBATTR *pTLibAttr; + + pTypeLib = itypelib(self); + oletypelib_get_libattr(pTypeLib, &pTLibAttr); + len = StringFromGUID2(&pTLibAttr->guid, bstr, sizeof(bstr)/sizeof(OLECHAR)); + if (len > 3) { + guid = ole_wc2vstr(bstr, FALSE); + } + pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr); + return guid; +} + +/* + * call-seq: + * WIN32OLE_TYPELIB#name -> The type library name + * + * Returns the type library name. + * + * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') + * name = tlib.name # -> 'Microsoft Excel 9.0 Object Library' + */ +static VALUE +foletypelib_name(VALUE self) +{ + ITypeLib *pTypeLib; + HRESULT hr; + BSTR bstr; + VALUE name; + pTypeLib = itypelib(self); + hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, -1, + NULL, &bstr, NULL, NULL); + + if (FAILED(hr)) { + ole_raise(hr, eWIN32OLERuntimeError, "failed to get name from ITypeLib"); + } + name = WC2VSTR(bstr); + return name; +} + +static VALUE +make_version_str(VALUE major, VALUE minor) +{ + VALUE version_str = Qnil; + VALUE minor_str = Qnil; + if (major == Qnil) { + return Qnil; + } + version_str = rb_String(major); + if (minor != Qnil) { + minor_str = rb_String(minor); + rb_str_cat2(version_str, "."); + rb_str_append(version_str, minor_str); + } + return version_str; +} + +/* + * call-seq: + * WIN32OLE_TYPELIB#version -> The type library version. + * + * Returns the type library version. + * + * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') + * puts tlib.version #-> 1.3 + */ +static VALUE +foletypelib_version(VALUE self) +{ + TLIBATTR *pTLibAttr; + VALUE major; + VALUE minor; + ITypeLib *pTypeLib; + + pTypeLib = itypelib(self); + oletypelib_get_libattr(pTypeLib, &pTLibAttr); + major = INT2NUM(pTLibAttr->wMajorVerNum); + minor = INT2NUM(pTLibAttr->wMinorVerNum); + pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr); + return rb_Float(make_version_str(major, minor)); +} + +/* + * call-seq: + * WIN32OLE_TYPELIB#major_version -> The type library major version. + * + * Returns the type library major version. + * + * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') + * puts tlib.major_version # -> 1 + */ +static VALUE +foletypelib_major_version(VALUE self) +{ + TLIBATTR *pTLibAttr; + VALUE major; + ITypeLib *pTypeLib; + pTypeLib = itypelib(self); + oletypelib_get_libattr(pTypeLib, &pTLibAttr); + + major = INT2NUM(pTLibAttr->wMajorVerNum); + pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr); + return major; +} + +/* + * call-seq: + * WIN32OLE_TYPELIB#minor_version -> The type library minor version. + * + * Returns the type library minor version. + * + * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') + * puts tlib.minor_version # -> 3 + */ +static VALUE +foletypelib_minor_version(VALUE self) +{ + TLIBATTR *pTLibAttr; + VALUE minor; + ITypeLib *pTypeLib; + pTypeLib = itypelib(self); + oletypelib_get_libattr(pTypeLib, &pTLibAttr); + minor = INT2NUM(pTLibAttr->wMinorVerNum); + pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr); + return minor; +} + +/* + * call-seq: + * WIN32OLE_TYPELIB#path -> The type library file path. + * + * Returns the type library file path. + * + * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') + * puts tlib.path #-> 'C:\...\EXCEL9.OLB' + */ +static VALUE +foletypelib_path(VALUE self) +{ + TLIBATTR *pTLibAttr; + HRESULT hr = S_OK; + BSTR bstr; + LCID lcid = cWIN32OLE_lcid; + VALUE path; + ITypeLib *pTypeLib; + + pTypeLib = itypelib(self); + oletypelib_get_libattr(pTypeLib, &pTLibAttr); + hr = QueryPathOfRegTypeLib(&pTLibAttr->guid, + pTLibAttr->wMajorVerNum, + pTLibAttr->wMinorVerNum, + lcid, + &bstr); + if (FAILED(hr)) { + pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr); + ole_raise(hr, eWIN32OLERuntimeError, "failed to QueryPathOfRegTypeTypeLib"); + } + + pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr); + path = WC2VSTR(bstr); + return path; +} + +/* + * call-seq: + * WIN32OLE_TYPELIB#visible? + * + * Returns true if the type library information is not hidden. + * If wLibFlags of TLIBATTR is 0 or LIBFLAG_FRESTRICTED or LIBFLAG_FHIDDEN, + * the method returns false, otherwise, returns true. + * If the method fails to access the TLIBATTR information, then + * WIN32OLERuntimeError is raised. + * + * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') + * tlib.visible? # => true + */ +static VALUE +foletypelib_visible(VALUE self) +{ + ITypeLib *pTypeLib = NULL; + VALUE visible = Qtrue; + TLIBATTR *pTLibAttr; + + pTypeLib = itypelib(self); + oletypelib_get_libattr(pTypeLib, &pTLibAttr); + + if ((pTLibAttr->wLibFlags == 0) || + (pTLibAttr->wLibFlags & LIBFLAG_FRESTRICTED) || + (pTLibAttr->wLibFlags & LIBFLAG_FHIDDEN)) { + visible = Qfalse; + } + pTypeLib->lpVtbl->ReleaseTLibAttr(pTypeLib, pTLibAttr); + return visible; +} + +/* + * call-seq: + * WIN32OLE_TYPELIB#library_name + * + * Returns library name. + * If the method fails to access library name, WIN32OLERuntimeError is raised. + * + * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') + * tlib.library_name # => Excel + */ +static VALUE +foletypelib_library_name(VALUE self) +{ + HRESULT hr; + ITypeLib *pTypeLib = NULL; + VALUE libname = Qnil; + BSTR bstr; + + pTypeLib = itypelib(self); + hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, -1, + &bstr, NULL, NULL, NULL); + if (FAILED(hr)) { + ole_raise(hr, eWIN32OLERuntimeError, "failed to get library name"); + } + libname = WC2VSTR(bstr); + return libname; +} + +static VALUE +ole_types_from_typelib(ITypeLib *pTypeLib, VALUE classes) +{ + long count; + int i; + HRESULT hr; + BSTR bstr; + ITypeInfo *pTypeInfo; + VALUE type; + + count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib); + for (i = 0; i < count; i++) { + hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i, + &bstr, NULL, NULL, NULL); + if (FAILED(hr)) + continue; + + hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, i, &pTypeInfo); + if (FAILED(hr)) + continue; + + type = create_win32ole_type(pTypeInfo, WC2VSTR(bstr)); + + rb_ary_push(classes, type); + OLE_RELEASE(pTypeInfo); + } + return classes; +} + +static VALUE +typelib_file_from_typelib(VALUE ole) +{ + HKEY htypelib, hclsid, hversion, hlang; + double fver; + DWORD i, j, k; + LONG err; + BOOL found = FALSE; + VALUE typelib; + VALUE file = Qnil; + VALUE clsid; + VALUE ver; + VALUE lang; + + err = reg_open_key(HKEY_CLASSES_ROOT, "TypeLib", &htypelib); + if(err != ERROR_SUCCESS) { + return Qnil; + } + for(i = 0; !found; i++) { + clsid = reg_enum_key(htypelib, i); + if (clsid == Qnil) + break; + err = reg_open_vkey(htypelib, clsid, &hclsid); + if (err != ERROR_SUCCESS) + continue; + fver = 0; + for(j = 0; !found; j++) { + ver = reg_enum_key(hclsid, j); + if (ver == Qnil) + break; + err = reg_open_vkey(hclsid, ver, &hversion); + if (err != ERROR_SUCCESS || fver > atof(StringValuePtr(ver))) + continue; + fver = atof(StringValuePtr(ver)); + typelib = reg_get_val(hversion, NULL); + if (typelib == Qnil) + continue; + if (rb_str_cmp(typelib, ole) == 0) { + for(k = 0; !found; k++) { + lang = reg_enum_key(hversion, k); + if (lang == Qnil) + break; + err = reg_open_vkey(hversion, lang, &hlang); + if (err == ERROR_SUCCESS) { + if ((file = reg_get_typelib_file_path(hlang)) != Qnil) + found = TRUE; + RegCloseKey(hlang); + } + } + } + RegCloseKey(hversion); + } + RegCloseKey(hclsid); + } + RegCloseKey(htypelib); + return file; +} + +static VALUE +typelib_file_from_clsid(VALUE ole) +{ + HKEY hroot, hclsid; + LONG err; + VALUE typelib; + char path[MAX_PATH + 1]; + + err = reg_open_key(HKEY_CLASSES_ROOT, "CLSID", &hroot); + if (err != ERROR_SUCCESS) { + return Qnil; + } + err = reg_open_key(hroot, StringValuePtr(ole), &hclsid); + if (err != ERROR_SUCCESS) { + RegCloseKey(hroot); + return Qnil; + } + typelib = reg_get_val2(hclsid, "InprocServer32"); + RegCloseKey(hroot); + RegCloseKey(hclsid); + if (typelib != Qnil) { + ExpandEnvironmentStrings(StringValuePtr(typelib), path, sizeof(path)); + path[MAX_PATH] = '\0'; + typelib = rb_str_new2(path); + } + return typelib; +} + +VALUE +typelib_file(VALUE ole) +{ + VALUE file = typelib_file_from_clsid(ole); + if (file != Qnil) { + return file; + } + return typelib_file_from_typelib(ole); +} + + +/* + * call-seq: + * WIN32OLE_TYPELIB#ole_types -> The array of WIN32OLE_TYPE object included the type library. + * + * Returns the type library file path. + * + * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') + * classes = tlib.ole_types.collect{|k| k.name} # -> ['AddIn', 'AddIns' ...] + */ +static VALUE +foletypelib_ole_types(VALUE self) +{ + ITypeLib *pTypeLib = NULL; + VALUE classes = rb_ary_new(); + pTypeLib = itypelib(self); + ole_types_from_typelib(pTypeLib, classes); + return classes; +} + +/* + * call-seq: + * WIN32OLE_TYPELIB#inspect -> String + * + * Returns the type library name with class name. + * + * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library') + * tlib.inspect # => "<#WIN32OLE_TYPELIB:Microsoft Excel 9.0 Object Library>" + */ +static VALUE +foletypelib_inspect(VALUE self) +{ + return default_inspect(self, "WIN32OLE_TYPELIB"); +} + +void +Init_win32ole_typelib() +{ + cWIN32OLE_TYPELIB = rb_define_class("WIN32OLE_TYPELIB", rb_cObject); + rb_define_singleton_method(cWIN32OLE_TYPELIB, "typelibs", foletypelib_s_typelibs, 0); + rb_define_alloc_func(cWIN32OLE_TYPELIB, foletypelib_s_allocate); + rb_define_method(cWIN32OLE_TYPELIB, "initialize", foletypelib_initialize, -2); + rb_define_method(cWIN32OLE_TYPELIB, "guid", foletypelib_guid, 0); + rb_define_method(cWIN32OLE_TYPELIB, "name", foletypelib_name, 0); + rb_define_method(cWIN32OLE_TYPELIB, "version", foletypelib_version, 0); + rb_define_method(cWIN32OLE_TYPELIB, "major_version", foletypelib_major_version, 0); + rb_define_method(cWIN32OLE_TYPELIB, "minor_version", foletypelib_minor_version, 0); + rb_define_method(cWIN32OLE_TYPELIB, "path", foletypelib_path, 0); + rb_define_method(cWIN32OLE_TYPELIB, "ole_types", foletypelib_ole_types, 0); + rb_define_alias(cWIN32OLE_TYPELIB, "ole_classes", "ole_types"); + rb_define_method(cWIN32OLE_TYPELIB, "visible?", foletypelib_visible, 0); + rb_define_method(cWIN32OLE_TYPELIB, "library_name", foletypelib_library_name, 0); + rb_define_alias(cWIN32OLE_TYPELIB, "to_s", "name"); + rb_define_method(cWIN32OLE_TYPELIB, "inspect", foletypelib_inspect, 0); +} diff --git a/ext/win32ole/win32ole_typelib.h b/ext/win32ole/win32ole_typelib.h new file mode 100644 index 0000000000..3d4169a740 --- /dev/null +++ b/ext/win32ole/win32ole_typelib.h @@ -0,0 +1,10 @@ +#ifndef WIN32OLE_TYPELIB_H +#define WIN32OLE_TYPELIB_H 1 + +VALUE cWIN32OLE_TYPELIB; + +void Init_win32ole_typelib(); +ITypeLib * itypelib(VALUE self); +VALUE typelib_file(VALUE ole); +VALUE create_win32ole_typelib(ITypeLib *pTypeLib); +#endif -- cgit v1.2.3