diff options
Diffstat (limited to 'ruby_2_2/ext/win32ole/win32ole.c')
-rw-r--r-- | ruby_2_2/ext/win32ole/win32ole.c | 4060 |
1 files changed, 0 insertions, 4060 deletions
diff --git a/ruby_2_2/ext/win32ole/win32ole.c b/ruby_2_2/ext/win32ole/win32ole.c deleted file mode 100644 index 0b455c2ec3..0000000000 --- a/ruby_2_2/ext/win32ole/win32ole.c +++ /dev/null @@ -1,4060 +0,0 @@ -/* - * (c) 1995 Microsoft Corporation. All rights reserved. - * Developed by ActiveWare Internet Corp., http://www.ActiveWare.com - * - * Other modifications Copyright (c) 1997, 1998 by Gurusamy Sarathy - * <gsar@umich.edu> and Jan Dubois <jan.dubois@ibm.net> - * - * You may distribute under the terms of either the GNU General Public - * License or the Artistic License, as specified in the README file - * of the Perl distribution. - * - */ - -/* - modified for win32ole (ruby) by Masaki.Suketa <masaki.suketa@nifty.ne.jp> - */ - -#include "win32ole.h" - -/* - * unfortunately IID_IMultiLanguage2 is not included in any libXXX.a - * in Cygwin(mingw32). - */ -#if defined(__CYGWIN__) || defined(__MINGW32__) -#undef IID_IMultiLanguage2 -const IID IID_IMultiLanguage2 = {0xDCCFC164, 0x2B38, 0x11d2, {0xB7, 0xEC, 0x00, 0xC0, 0x4F, 0x8F, 0x5D, 0x9A}}; -#endif - -#define WIN32OLE_VERSION "1.8.4" - -typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX) - (REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*); - -typedef HWND (WINAPI FNHTMLHELP)(HWND hwndCaller, LPCSTR pszFile, - UINT uCommand, DWORD dwData); -typedef BOOL (FNENUMSYSEMCODEPAGES) (CODEPAGE_ENUMPROC, DWORD); -VALUE cWIN32OLE; - -#if defined(RB_THREAD_SPECIFIC) && (defined(__CYGWIN__) || defined(__MINGW32__)) -static RB_THREAD_SPECIFIC BOOL g_ole_initialized; -# define g_ole_initialized_init() ((void)0) -# define g_ole_initialized_set(val) (g_ole_initialized = (val)) -#else -static volatile DWORD g_ole_initialized_key = TLS_OUT_OF_INDEXES; -# define g_ole_initialized (BOOL)TlsGetValue(g_ole_initialized_key) -# 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; -static HINSTANCE ghhctrl = NULL; -static HINSTANCE gole32 = NULL; -static FNCOCREATEINSTANCEEX *gCoCreateInstanceEx = NULL; -static VALUE com_hash; -static VALUE enc2cp_hash; -static IDispatchVtbl com_vtbl; -static UINT cWIN32OLE_cp = CP_ACP; -static rb_encoding *cWIN32OLE_enc; -static UINT g_cp_to_check = CP_ACP; -static char g_lcid_to_check[8 + 1]; -static VARTYPE g_nil_to = VT_ERROR; -static IMessageFilterVtbl message_filter; -static IMessageFilter imessage_filter = { &message_filter }; -static IMessageFilter* previous_filter; - -#if defined(HAVE_TYPE_IMULTILANGUAGE2) -static IMultiLanguage2 *pIMultiLanguage = NULL; -#elif defined(HAVE_TYPE_IMULTILANGUAGE) -static IMultiLanguage *pIMultiLanguage = NULL; -#else -#define pIMultiLanguage NULL /* dummy */ -#endif - -struct oleparam { - DISPPARAMS dp; - OLECHAR** pNamedArgs; -}; - -static HRESULT ( STDMETHODCALLTYPE QueryInterface )(IDispatch __RPC_FAR *, REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject); -static ULONG ( STDMETHODCALLTYPE AddRef )(IDispatch __RPC_FAR * This); -static ULONG ( STDMETHODCALLTYPE Release )(IDispatch __RPC_FAR * This); -static HRESULT ( STDMETHODCALLTYPE GetTypeInfoCount )(IDispatch __RPC_FAR * This, UINT __RPC_FAR *pctinfo); -static HRESULT ( STDMETHODCALLTYPE GetTypeInfo )(IDispatch __RPC_FAR * This, UINT iTInfo, LCID lcid, ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo); -static HRESULT ( STDMETHODCALLTYPE GetIDsOfNames )(IDispatch __RPC_FAR * This, REFIID riid, LPOLESTR __RPC_FAR *rgszNames, UINT cNames, LCID lcid, DISPID __RPC_FAR *rgDispId); -static HRESULT ( STDMETHODCALLTYPE Invoke )( IDispatch __RPC_FAR * This, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS __RPC_FAR *pDispParams, VARIANT __RPC_FAR *pVarResult, EXCEPINFO __RPC_FAR *pExcepInfo, UINT __RPC_FAR *puArgErr); -static IDispatch* val2dispatch(VALUE val); -static double rbtime2vtdate(VALUE tmobj); -static VALUE vtdate2rbtime(double date); -static rb_encoding *ole_cp2encoding(UINT cp); -static UINT ole_encoding2cp(rb_encoding *enc); -NORETURN(static void failed_load_conv51932(void)); -#ifndef pIMultiLanguage -static void load_conv_function51932(void); -#endif -static UINT ole_init_cp(void); -static void ole_freeexceptinfo(EXCEPINFO *pExInfo); -static VALUE ole_excepinfo2msg(EXCEPINFO *pExInfo); -static void ole_free(void *ptr); -static size_t ole_size(const void *ptr); -static LPWSTR ole_mb2wc(char *pm, int len); -static VALUE ole_ary_m_entry(VALUE val, LONG *pid); -static VALUE is_all_index_under(LONG *pid, long *pub, long dim); -static void * get_ptr_of_variant(VARIANT *pvar); -static void ole_set_safe_array(long n, SAFEARRAY *psa, LONG *pid, long *pub, VALUE val, long dim, VARTYPE vt); -static long dimension(VALUE val); -static long ary_len_of_dim(VALUE ary, long dim); -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 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(VALUE self, VALUE ole, VALUE host, VALUE others); -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 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); -static HWND ole_show_help(VALUE helpfile, VALUE helpcontext); -static VALUE fole_s_show_help(int argc, VALUE *argv, VALUE self); -static VALUE fole_s_get_code_page(VALUE self); -static BOOL CALLBACK installed_code_page_proc(LPTSTR str); -static BOOL code_page_installed(UINT cp); -static VALUE fole_s_set_code_page(VALUE self, VALUE vcp); -static VALUE fole_s_get_locale(VALUE self); -static BOOL CALLBACK installed_lcid_proc(LPTSTR str); -static BOOL lcid_installed(LCID lcid); -static VALUE fole_s_set_locale(VALUE self, VALUE vlcid); -static VALUE fole_s_create_guid(VALUE self); -static VALUE fole_s_ole_initialize(VALUE self); -static VALUE fole_s_ole_uninitialize(VALUE self); -static VALUE fole_initialize(int argc, VALUE *argv, VALUE self); -static int hash2named_arg(VALUE key, VALUE val, VALUE pop); -static VALUE set_argv(VARIANTARG* realargs, unsigned int beg, unsigned int end); -static VALUE ole_invoke(int argc, VALUE *argv, VALUE self, USHORT wFlags, BOOL is_bracket); -static VALUE fole_invoke(int argc, VALUE *argv, VALUE self); -static VALUE ole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types, USHORT dispkind); -static VALUE fole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types); -static VALUE fole_getproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types); -static VALUE fole_setproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types); -static VALUE fole_setproperty_with_bracket(int argc, VALUE *argv, VALUE self); -static VALUE fole_setproperty(int argc, VALUE *argv, VALUE self); -static VALUE fole_getproperty_with_bracket(int argc, VALUE *argv, VALUE self); -static VALUE ole_propertyput(VALUE self, VALUE property, VALUE value); -static VALUE fole_free(VALUE self); -static VALUE ole_each_sub(VALUE pEnumV); -static VALUE ole_ienum_free(VALUE pEnumV); -static VALUE fole_each(VALUE self); -static VALUE fole_missing(int argc, VALUE *argv, VALUE self); -static HRESULT typeinfo_from_ole(struct oledata *pole, ITypeInfo **ppti); -static VALUE ole_methods(VALUE self, int mask); -static VALUE fole_methods(VALUE self); -static VALUE fole_get_methods(VALUE self); -static VALUE fole_put_methods(VALUE self); -static VALUE fole_func_methods(VALUE self); -static VALUE fole_type(VALUE self); -static VALUE fole_typelib(VALUE self); -static VALUE fole_query_interface(VALUE self, VALUE str_iid); -static VALUE fole_respond_to(VALUE self, VALUE method); -static VALUE ole_usertype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails); -static VALUE ole_ptrtype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails); -static VALUE fole_method_help(VALUE self, VALUE cmdname); -static VALUE fole_activex_initialize(VALUE self); - -static void com_hash_free(void *ptr); -static void com_hash_mark(void *ptr); -static size_t com_hash_size(const void *ptr); - -static const rb_data_type_t ole_datatype = { - "win32ole", - {NULL, ole_free, ole_size,}, - 0, 0, RUBY_TYPED_FREE_IMMEDIATELY -}; - -static const rb_data_type_t win32ole_hash_datatype = { - "win32ole_hash", - {com_hash_mark, com_hash_free, com_hash_size,}, - 0, 0, RUBY_TYPED_FREE_IMMEDIATELY -}; - -static HRESULT (STDMETHODCALLTYPE mf_QueryInterface)( - IMessageFilter __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) -{ - if (MEMCMP(riid, &IID_IUnknown, GUID, 1) == 0 - || MEMCMP(riid, &IID_IMessageFilter, GUID, 1) == 0) - { - *ppvObject = &message_filter; - return S_OK; - } - return E_NOINTERFACE; -} - -static ULONG (STDMETHODCALLTYPE mf_AddRef)( - IMessageFilter __RPC_FAR * This) -{ - return 1; -} - -static ULONG (STDMETHODCALLTYPE mf_Release)( - IMessageFilter __RPC_FAR * This) -{ - return 1; -} - -static DWORD (STDMETHODCALLTYPE mf_HandleInComingCall)( - IMessageFilter __RPC_FAR * pThis, - DWORD dwCallType, //Type of incoming call - HTASK threadIDCaller, //Task handle calling this task - DWORD dwTickCount, //Elapsed tick count - LPINTERFACEINFO lpInterfaceInfo //Pointer to INTERFACEINFO structure - ) -{ -#ifdef DEBUG_MESSAGEFILTER - printf("incoming %08X, %08X, %d\n", dwCallType, threadIDCaller, dwTickCount); - fflush(stdout); -#endif - switch (dwCallType) - { - case CALLTYPE_ASYNC: - case CALLTYPE_TOPLEVEL_CALLPENDING: - case CALLTYPE_ASYNC_CALLPENDING: - if (rb_during_gc()) { - return SERVERCALL_RETRYLATER; - } - break; - default: - break; - } - if (previous_filter) { - return previous_filter->lpVtbl->HandleInComingCall(previous_filter, - dwCallType, - threadIDCaller, - dwTickCount, - lpInterfaceInfo); - } - return SERVERCALL_ISHANDLED; -} - -static DWORD (STDMETHODCALLTYPE mf_RetryRejectedCall)( - IMessageFilter* pThis, - HTASK threadIDCallee, //Server task handle - DWORD dwTickCount, //Elapsed tick count - DWORD dwRejectType //Returned rejection message - ) -{ - if (previous_filter) { - return previous_filter->lpVtbl->RetryRejectedCall(previous_filter, - threadIDCallee, - dwTickCount, - dwRejectType); - } - return 1000; -} - -static DWORD (STDMETHODCALLTYPE mf_MessagePending)( - IMessageFilter* pThis, - HTASK threadIDCallee, //Called applications task handle - DWORD dwTickCount, //Elapsed tick count - DWORD dwPendingType //Call type - ) -{ - if (rb_during_gc()) { - return PENDINGMSG_WAITNOPROCESS; - } - if (previous_filter) { - return previous_filter->lpVtbl->MessagePending(previous_filter, - threadIDCallee, - dwTickCount, - dwPendingType); - } - return PENDINGMSG_WAITNOPROCESS; -} - -typedef struct _Win32OLEIDispatch -{ - IDispatch dispatch; - ULONG refcount; - VALUE obj; -} Win32OLEIDispatch; - -static HRESULT ( STDMETHODCALLTYPE QueryInterface )( - IDispatch __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) -{ - if (MEMCMP(riid, &IID_IUnknown, GUID, 1) == 0 - || MEMCMP(riid, &IID_IDispatch, GUID, 1) == 0) - { - Win32OLEIDispatch* p = (Win32OLEIDispatch*)This; - p->refcount++; - *ppvObject = This; - return S_OK; - } - return E_NOINTERFACE; -} - -static ULONG ( STDMETHODCALLTYPE AddRef )( - IDispatch __RPC_FAR * This) -{ - Win32OLEIDispatch* p = (Win32OLEIDispatch*)This; - return ++(p->refcount); -} - -static ULONG ( STDMETHODCALLTYPE Release )( - IDispatch __RPC_FAR * This) -{ - Win32OLEIDispatch* p = (Win32OLEIDispatch*)This; - ULONG u = --(p->refcount); - if (u == 0) { - st_data_t key = p->obj; - st_delete(DATA_PTR(com_hash), &key, 0); - free(p); - } - return u; -} - -static HRESULT ( STDMETHODCALLTYPE GetTypeInfoCount )( - IDispatch __RPC_FAR * This, - /* [out] */ UINT __RPC_FAR *pctinfo) -{ - return E_NOTIMPL; -} - -static HRESULT ( STDMETHODCALLTYPE GetTypeInfo )( - IDispatch __RPC_FAR * This, - /* [in] */ UINT iTInfo, - /* [in] */ LCID lcid, - /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo) -{ - return E_NOTIMPL; -} - - -static HRESULT ( STDMETHODCALLTYPE GetIDsOfNames )( - IDispatch __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [size_is][in] */ LPOLESTR __RPC_FAR *rgszNames, - /* [in] */ UINT cNames, - /* [in] */ LCID lcid, - /* [size_is][out] */ DISPID __RPC_FAR *rgDispId) -{ - /* - Win32OLEIDispatch* p = (Win32OLEIDispatch*)This; - */ - char* psz = ole_wc2mb(*rgszNames); // support only one method - ID nameid = rb_intern(psz); - free(psz); - if ((ID)(DISPID)nameid != nameid) return E_NOINTERFACE; - *rgDispId = (DISPID)nameid; - return S_OK; -} - -static /* [local] */ HRESULT ( STDMETHODCALLTYPE Invoke )( - IDispatch __RPC_FAR * This, - /* [in] */ DISPID dispIdMember, - /* [in] */ REFIID riid, - /* [in] */ LCID lcid, - /* [in] */ WORD wFlags, - /* [out][in] */ DISPPARAMS __RPC_FAR *pDispParams, - /* [out] */ VARIANT __RPC_FAR *pVarResult, - /* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo, - /* [out] */ UINT __RPC_FAR *puArgErr) -{ - VALUE v; - int i; - int args = pDispParams->cArgs; - Win32OLEIDispatch* p = (Win32OLEIDispatch*)This; - VALUE* parg = ALLOCA_N(VALUE, args); - ID mid = (ID)dispIdMember; - for (i = 0; i < args; i++) { - *(parg + i) = ole_variant2val(&pDispParams->rgvarg[args - i - 1]); - } - if (dispIdMember == DISPID_VALUE) { - if (wFlags == DISPATCH_METHOD) { - mid = rb_intern("call"); - } else if (wFlags & DISPATCH_PROPERTYGET) { - mid = rb_intern("value"); - } - } - v = rb_funcall2(p->obj, mid, args, parg); - ole_val2variant(v, pVarResult); - return S_OK; -} - -BOOL -ole_initialized(void) -{ - return g_ole_initialized; -} - -static IDispatch* -val2dispatch(VALUE val) -{ - struct st_table *tbl = DATA_PTR(com_hash); - Win32OLEIDispatch* pdisp; - st_data_t data; - if (st_lookup(tbl, val, &data)) { - pdisp = (Win32OLEIDispatch *)(data & ~FIXNUM_FLAG); - pdisp->refcount++; - } - else { - pdisp = ALLOC(Win32OLEIDispatch); - pdisp->dispatch.lpVtbl = &com_vtbl; - pdisp->refcount = 1; - pdisp->obj = val; - st_insert(tbl, val, (VALUE)pdisp | FIXNUM_FLAG); - } - return &pdisp->dispatch; -} - -static double -rbtime2vtdate(VALUE tmobj) -{ - SYSTEMTIME st; - double t; - double nsec; - - st.wYear = FIX2INT(rb_funcall(tmobj, rb_intern("year"), 0)); - st.wMonth = FIX2INT(rb_funcall(tmobj, rb_intern("month"), 0)); - st.wDay = FIX2INT(rb_funcall(tmobj, rb_intern("mday"), 0)); - st.wHour = FIX2INT(rb_funcall(tmobj, rb_intern("hour"), 0)); - st.wMinute = FIX2INT(rb_funcall(tmobj, rb_intern("min"), 0)); - st.wSecond = FIX2INT(rb_funcall(tmobj, rb_intern("sec"), 0)); - st.wMilliseconds = 0; - SystemTimeToVariantTime(&st, &t); - - /* - * Unfortunately SystemTimeToVariantTime function always ignores the - * wMilliseconds of SYSTEMTIME struct. - * So, we need to calculate milliseconds by ourselves. - */ - nsec = FIX2INT(rb_funcall(tmobj, rb_intern("nsec"), 0)); - nsec /= 1000000.0; - nsec /= (24.0 * 3600.0); - nsec /= 1000; - return t + nsec; -} - -static VALUE -vtdate2rbtime(double date) -{ - SYSTEMTIME st; - VALUE v; - double msec; - double sec; - VariantTimeToSystemTime(date, &st); - v = rb_funcall(rb_cTime, rb_intern("new"), 6, - INT2FIX(st.wYear), - INT2FIX(st.wMonth), - INT2FIX(st.wDay), - INT2FIX(st.wHour), - INT2FIX(st.wMinute), - INT2FIX(st.wSecond)); - st.wYear = FIX2INT(rb_funcall(v, rb_intern("year"), 0)); - st.wMonth = FIX2INT(rb_funcall(v, rb_intern("month"), 0)); - st.wDay = FIX2INT(rb_funcall(v, rb_intern("mday"), 0)); - st.wHour = FIX2INT(rb_funcall(v, rb_intern("hour"), 0)); - st.wMinute = FIX2INT(rb_funcall(v, rb_intern("min"), 0)); - st.wSecond = FIX2INT(rb_funcall(v, rb_intern("sec"), 0)); - st.wMilliseconds = 0; - SystemTimeToVariantTime(&st, &sec); - /* - * Unfortunately VariantTimeToSystemTime always ignores the - * wMilliseconds of SYSTEMTIME struct(The wMilliseconds is 0). - * So, we need to calculate milliseconds by ourselves. - */ - msec = date - sec; - msec *= 24 * 60; - msec -= floor(msec); - msec *= 60; - if (msec >= 59) { - msec -= 60; - } - if (msec != 0) { - return rb_funcall(v, rb_intern("+"), 1, rb_float_new(msec)); - } - return v; -} - -#define ENC_MACHING_CP(enc,encname,cp) if(strcasecmp(rb_enc_name((enc)),(encname)) == 0) return cp - -static UINT ole_encoding2cp(rb_encoding *enc) -{ - /* - * Is there any better solution to convert - * Ruby encoding to Windows codepage??? - */ - ENC_MACHING_CP(enc, "Big5", 950); - ENC_MACHING_CP(enc, "CP51932", 51932); - ENC_MACHING_CP(enc, "CP850", 850); - ENC_MACHING_CP(enc, "CP852", 852); - ENC_MACHING_CP(enc, "CP855", 855); - ENC_MACHING_CP(enc, "CP949", 949); - ENC_MACHING_CP(enc, "EUC-JP", 20932); - ENC_MACHING_CP(enc, "EUC-KR", 51949); - ENC_MACHING_CP(enc, "EUC-TW", 51950); - ENC_MACHING_CP(enc, "GB18030", 54936); - ENC_MACHING_CP(enc, "GB2312", 20936); - ENC_MACHING_CP(enc, "GBK", 936); - ENC_MACHING_CP(enc, "IBM437", 437); - ENC_MACHING_CP(enc, "IBM737", 737); - ENC_MACHING_CP(enc, "IBM775", 775); - ENC_MACHING_CP(enc, "IBM852", 852); - ENC_MACHING_CP(enc, "IBM855", 855); - ENC_MACHING_CP(enc, "IBM857", 857); - ENC_MACHING_CP(enc, "IBM860", 860); - ENC_MACHING_CP(enc, "IBM861", 861); - ENC_MACHING_CP(enc, "IBM862", 862); - ENC_MACHING_CP(enc, "IBM863", 863); - ENC_MACHING_CP(enc, "IBM864", 864); - ENC_MACHING_CP(enc, "IBM865", 865); - ENC_MACHING_CP(enc, "IBM866", 866); - ENC_MACHING_CP(enc, "IBM869", 869); - ENC_MACHING_CP(enc, "ISO-2022-JP", 50220); - ENC_MACHING_CP(enc, "ISO-8859-1", 28591); - ENC_MACHING_CP(enc, "ISO-8859-15", 28605); - ENC_MACHING_CP(enc, "ISO-8859-2", 28592); - ENC_MACHING_CP(enc, "ISO-8859-3", 28593); - ENC_MACHING_CP(enc, "ISO-8859-4", 28594); - ENC_MACHING_CP(enc, "ISO-8859-5", 28595); - ENC_MACHING_CP(enc, "ISO-8859-6", 28596); - ENC_MACHING_CP(enc, "ISO-8859-7", 28597); - ENC_MACHING_CP(enc, "ISO-8859-8", 28598); - ENC_MACHING_CP(enc, "ISO-8859-9", 28599); - ENC_MACHING_CP(enc, "KOI8-R", 20866); - ENC_MACHING_CP(enc, "KOI8-U", 21866); - ENC_MACHING_CP(enc, "Shift_JIS", 932); - ENC_MACHING_CP(enc, "UTF-16BE", 1201); - ENC_MACHING_CP(enc, "UTF-16LE", 1200); - ENC_MACHING_CP(enc, "UTF-7", 65000); - ENC_MACHING_CP(enc, "UTF-8", 65001); - ENC_MACHING_CP(enc, "Windows-1250", 1250); - ENC_MACHING_CP(enc, "Windows-1251", 1251); - ENC_MACHING_CP(enc, "Windows-1252", 1252); - ENC_MACHING_CP(enc, "Windows-1253", 1253); - ENC_MACHING_CP(enc, "Windows-1254", 1254); - ENC_MACHING_CP(enc, "Windows-1255", 1255); - ENC_MACHING_CP(enc, "Windows-1256", 1256); - ENC_MACHING_CP(enc, "Windows-1257", 1257); - ENC_MACHING_CP(enc, "Windows-1258", 1258); - ENC_MACHING_CP(enc, "Windows-31J", 932); - ENC_MACHING_CP(enc, "Windows-874", 874); - ENC_MACHING_CP(enc, "eucJP-ms", 20932); - return CP_ACP; -} - -static void -failed_load_conv51932(void) -{ - rb_raise(eWIN32OLERuntimeError, "fail to load convert function for CP51932"); -} - -#ifndef pIMultiLanguage -static void -load_conv_function51932(void) -{ - HRESULT hr = E_NOINTERFACE; - void *p; - if (!pIMultiLanguage) { -#if defined(HAVE_TYPE_IMULTILANGUAGE2) - hr = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, - &IID_IMultiLanguage2, &p); -#elif defined(HAVE_TYPE_IMULTILANGUAGE) - hr = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER, - &IID_IMultiLanguage, &p); -#endif - if (FAILED(hr)) { - failed_load_conv51932(); - } - pIMultiLanguage = p; - } -} -#else -#define load_conv_function51932() failed_load_conv51932() -#endif - -#define conv_51932(cp) ((cp) == 51932 && (load_conv_function51932(), 1)) - -static void -set_ole_codepage(UINT cp) -{ - if (code_page_installed(cp)) { - cWIN32OLE_cp = cp; - } else { - switch(cp) { - case CP_ACP: - case CP_OEMCP: - case CP_MACCP: - case CP_THREAD_ACP: - case CP_SYMBOL: - case CP_UTF7: - case CP_UTF8: - cWIN32OLE_cp = cp; - break; - case 51932: - cWIN32OLE_cp = cp; - load_conv_function51932(); - break; - default: - rb_raise(eWIN32OLERuntimeError, "codepage should be WIN32OLE::CP_ACP, WIN32OLE::CP_OEMCP, WIN32OLE::CP_MACCP, WIN32OLE::CP_THREAD_ACP, WIN32OLE::CP_SYMBOL, WIN32OLE::CP_UTF7, WIN32OLE::CP_UTF8, or installed codepage."); - break; - } - } - cWIN32OLE_enc = ole_cp2encoding(cWIN32OLE_cp); -} - - -static UINT -ole_init_cp(void) -{ - UINT cp; - rb_encoding *encdef; - encdef = rb_default_internal_encoding(); - if (!encdef) { - encdef = rb_default_external_encoding(); - } - cp = ole_encoding2cp(encdef); - set_ole_codepage(cp); - return cp; -} - -struct myCPINFOEX { - UINT MaxCharSize; - BYTE DefaultChar[2]; - BYTE LeadByte[12]; - WCHAR UnicodeDefaultChar; - UINT CodePage; - char CodePageName[MAX_PATH]; -}; - -static rb_encoding * -ole_cp2encoding(UINT cp) -{ - static BOOL (*pGetCPInfoEx)(UINT, DWORD, struct myCPINFOEX *) = NULL; - struct myCPINFOEX* buf; - VALUE enc_name; - char *enc_cstr; - int idx; - - if (!code_page_installed(cp)) { - switch(cp) { - case CP_ACP: - cp = GetACP(); - break; - case CP_OEMCP: - cp = GetOEMCP(); - break; - case CP_MACCP: - case CP_THREAD_ACP: - if (!pGetCPInfoEx) { - pGetCPInfoEx = (BOOL (*)(UINT, DWORD, struct myCPINFOEX *)) - GetProcAddress(GetModuleHandle("kernel32"), "GetCPInfoEx"); - if (!pGetCPInfoEx) { - pGetCPInfoEx = (void*)-1; - } - } - buf = ALLOCA_N(struct myCPINFOEX, 1); - ZeroMemory(buf, sizeof(struct myCPINFOEX)); - if (pGetCPInfoEx == (void*)-1 || !pGetCPInfoEx(cp, 0, buf)) { - rb_raise(eWIN32OLERuntimeError, "cannot map codepage to encoding."); - break; /* never reach here */ - } - cp = buf->CodePage; - break; - case CP_SYMBOL: - case CP_UTF7: - case CP_UTF8: - break; - case 51932: - load_conv_function51932(); - break; - default: - rb_raise(eWIN32OLERuntimeError, "codepage should be WIN32OLE::CP_ACP, WIN32OLE::CP_OEMCP, WIN32OLE::CP_MACCP, WIN32OLE::CP_THREAD_ACP, WIN32OLE::CP_SYMBOL, WIN32OLE::CP_UTF7, WIN32OLE::CP_UTF8, or installed codepage."); - break; - } - } - - enc_name = rb_sprintf("CP%d", cp); - idx = rb_enc_find_index(enc_cstr = StringValueCStr(enc_name)); - if (idx < 0) - idx = rb_define_dummy_encoding(enc_cstr); - return rb_enc_from_index(idx); -} - -static char * -ole_wc2mb_alloc(LPWSTR pw, char *(alloc)(UINT size, void *arg), void *arg) -{ - LPSTR pm; - UINT size = 0; - if (conv_51932(cWIN32OLE_cp)) { -#ifndef pIMultiLanguage - DWORD dw = 0; - HRESULT hr = pIMultiLanguage->lpVtbl->ConvertStringFromUnicode(pIMultiLanguage, - &dw, cWIN32OLE_cp, pw, NULL, NULL, &size); - if (FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, "fail to convert Unicode to CP%d", cWIN32OLE_cp); - } - pm = alloc(size, arg); - hr = pIMultiLanguage->lpVtbl->ConvertStringFromUnicode(pIMultiLanguage, - &dw, cWIN32OLE_cp, pw, NULL, pm, &size); - if (FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, "fail to convert Unicode to CP%d", cWIN32OLE_cp); - } - pm[size] = '\0'; -#endif - return pm; - } - size = WideCharToMultiByte(cWIN32OLE_cp, 0, pw, -1, NULL, 0, NULL, NULL); - if (size) { - pm = alloc(size, arg); - WideCharToMultiByte(cWIN32OLE_cp, 0, pw, -1, pm, size, NULL, NULL); - pm[size] = '\0'; - } - else { - pm = alloc(0, arg); - *pm = '\0'; - } - return pm; -} - -static char * -ole_alloc_str(UINT size, void *arg) -{ - return ALLOC_N(char, size + 1); -} - -char * -ole_wc2mb(LPWSTR pw) -{ - return ole_wc2mb_alloc(pw, ole_alloc_str, NULL); -} - -static void -ole_freeexceptinfo(EXCEPINFO *pExInfo) -{ - SysFreeString(pExInfo->bstrDescription); - SysFreeString(pExInfo->bstrSource); - SysFreeString(pExInfo->bstrHelpFile); -} - -static VALUE -ole_excepinfo2msg(EXCEPINFO *pExInfo) -{ - char error_code[40]; - char *pSource = NULL; - char *pDescription = NULL; - VALUE error_msg; - if(pExInfo->pfnDeferredFillIn != NULL) { - (*pExInfo->pfnDeferredFillIn)(pExInfo); - } - if (pExInfo->bstrSource != NULL) { - pSource = ole_wc2mb(pExInfo->bstrSource); - } - if (pExInfo->bstrDescription != NULL) { - pDescription = ole_wc2mb(pExInfo->bstrDescription); - } - if(pExInfo->wCode == 0) { - sprintf(error_code, "\n OLE error code:%lX in ", (unsigned long)pExInfo->scode); - } - else{ - sprintf(error_code, "\n OLE error code:%u in ", pExInfo->wCode); - } - error_msg = rb_str_new2(error_code); - if(pSource != NULL) { - rb_str_cat2(error_msg, pSource); - } - else { - rb_str_cat(error_msg, "<Unknown>", 9); - } - rb_str_cat2(error_msg, "\n "); - if(pDescription != NULL) { - rb_str_cat2(error_msg, pDescription); - } - else { - rb_str_cat2(error_msg, "<No Description>"); - } - if(pSource) free(pSource); - if(pDescription) free(pDescription); - ole_freeexceptinfo(pExInfo); - return error_msg; -} - -void -ole_uninitialize(void) -{ - if (!g_ole_initialized) return; - OleUninitialize(); - g_ole_initialized_set(FALSE); -} - -static void -ole_uninitialize_hook(rb_event_flag_t evflag, VALUE data, VALUE self, ID mid, VALUE klass) -{ - ole_uninitialize(); -} - -void -ole_initialize(void) -{ - HRESULT hr; - - if(!g_uninitialize_hooked) { - rb_add_event_hook(ole_uninitialize_hook, RUBY_EVENT_THREAD_END, Qnil); - g_uninitialize_hooked = TRUE; - } - - if(g_ole_initialized == FALSE) { - hr = OleInitialize(NULL); - if(FAILED(hr)) { - ole_raise(hr, rb_eRuntimeError, "fail: OLE initialize"); - } - g_ole_initialized_set(TRUE); - - hr = CoRegisterMessageFilter(&imessage_filter, &previous_filter); - if(FAILED(hr)) { - previous_filter = NULL; - ole_raise(hr, rb_eRuntimeError, "fail: install OLE MessageFilter"); - } - } -} - -static void -ole_free(void *ptr) -{ - struct oledata *pole = ptr; - OLE_FREE(pole->pDispatch); - free(pole); -} - -static size_t ole_size(const void *ptr) -{ - return ptr ? sizeof(struct oledata) : 0; -} - -struct oledata * -oledata_get_struct(VALUE ole) -{ - struct oledata *pole; - TypedData_Get_Struct(ole, struct oledata, &ole_datatype, pole); - return pole; -} - -LPWSTR -ole_vstr2wc(VALUE vstr) -{ - rb_encoding *enc; - int cp; - UINT size = 0; - LPWSTR pw; - st_data_t data; - struct st_table *tbl = DATA_PTR(enc2cp_hash); - enc = rb_enc_get(vstr); - - if (st_lookup(tbl, (VALUE)enc | FIXNUM_FLAG, &data)) { - cp = FIX2INT((VALUE)data); - } else { - cp = ole_encoding2cp(enc); - if (code_page_installed(cp) || - cp == CP_ACP || - cp == CP_OEMCP || - cp == CP_MACCP || - cp == CP_THREAD_ACP || - cp == CP_SYMBOL || - cp == CP_UTF7 || - cp == CP_UTF8 || - cp == 51932) { - st_insert(tbl, (VALUE)enc | FIXNUM_FLAG, INT2FIX(cp)); - } else { - rb_raise(eWIN32OLERuntimeError, "not installed Windows codepage(%d) according to `%s'", cp, rb_enc_name(enc)); - } - } - if (conv_51932(cp)) { -#ifndef pIMultiLanguage - DWORD dw = 0; - UINT len = RSTRING_LENINT(vstr); - HRESULT hr = pIMultiLanguage->lpVtbl->ConvertStringToUnicode(pIMultiLanguage, - &dw, cp, RSTRING_PTR(vstr), &len, NULL, &size); - if (FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, "fail to convert CP%d to Unicode", cp); - } - pw = SysAllocStringLen(NULL, size); - len = RSTRING_LEN(vstr); - hr = pIMultiLanguage->lpVtbl->ConvertStringToUnicode(pIMultiLanguage, - &dw, cp, RSTRING_PTR(vstr), &len, pw, &size); - if (FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, "fail to convert CP%d to Unicode", cp); - } -#endif - return pw; - } - size = MultiByteToWideChar(cp, 0, RSTRING_PTR(vstr), RSTRING_LEN(vstr), NULL, 0); - pw = SysAllocStringLen(NULL, size); - MultiByteToWideChar(cp, 0, RSTRING_PTR(vstr), RSTRING_LEN(vstr), pw, size); - return pw; -} - -static LPWSTR -ole_mb2wc(char *pm, int len) -{ - UINT size = 0; - LPWSTR pw; - - if (conv_51932(cWIN32OLE_cp)) { -#ifndef pIMultiLanguage - DWORD dw = 0; - UINT n = len; - HRESULT hr = pIMultiLanguage->lpVtbl->ConvertStringToUnicode(pIMultiLanguage, - &dw, cWIN32OLE_cp, pm, &n, NULL, &size); - if (FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, "fail to convert CP%d to Unicode", cWIN32OLE_cp); - } - pw = SysAllocStringLen(NULL, size); - hr = pIMultiLanguage->lpVtbl->ConvertStringToUnicode(pIMultiLanguage, - &dw, cWIN32OLE_cp, pm, &n, pw, &size); - if (FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, "fail to convert CP%d to Unicode", cWIN32OLE_cp); - } -#endif - return pw; - } - size = MultiByteToWideChar(cWIN32OLE_cp, 0, pm, len, NULL, 0); - pw = SysAllocStringLen(NULL, size - 1); - MultiByteToWideChar(cWIN32OLE_cp, 0, pm, len, pw, size); - return pw; -} - -static char * -ole_alloc_vstr(UINT size, void *arg) -{ - VALUE str = rb_enc_str_new(NULL, size, cWIN32OLE_enc); - *(VALUE *)arg = str; - return RSTRING_PTR(str); -} - -VALUE -ole_wc2vstr(LPWSTR pw, BOOL isfree) -{ - VALUE vstr; - ole_wc2mb_alloc(pw, ole_alloc_vstr, &vstr); - rb_str_set_len(vstr, (long)strlen(RSTRING_PTR(vstr))); - if(isfree) - SysFreeString(pw); - return vstr; -} - -static VALUE -ole_ary_m_entry(VALUE val, LONG *pid) -{ - VALUE obj = Qnil; - int i = 0; - obj = val; - while(RB_TYPE_P(obj, T_ARRAY)) { - obj = rb_ary_entry(obj, pid[i]); - i++; - } - return obj; -} - -static VALUE -is_all_index_under(LONG *pid, long *pub, long dim) -{ - long i = 0; - for (i = 0; i < dim; i++) { - if (pid[i] > pub[i]) { - return Qfalse; - } - } - return Qtrue; -} - -void -ole_val2variant_ex(VALUE val, VARIANT *var, VARTYPE vt) -{ - if (val == Qnil) { - if (vt == VT_VARIANT) { - ole_val2variant2(val, var); - } else { - V_VT(var) = (vt & ~VT_BYREF); - if (V_VT(var) == VT_DISPATCH) { - V_DISPATCH(var) = NULL; - } else if (V_VT(var) == VT_UNKNOWN) { - V_UNKNOWN(var) = NULL; - } - } - return; - } -#if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__) - switch(vt & ~VT_BYREF) { - case VT_I8: - V_VT(var) = VT_I8; - V_I8(var) = NUM2I8 (val); - break; - case VT_UI8: - V_VT(var) = VT_UI8; - V_UI8(var) = NUM2UI8(val); - break; - default: - ole_val2variant2(val, var); - break; - } -#else /* (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__) */ - ole_val2variant2(val, var); -#endif -} - -VOID * -val2variant_ptr(VALUE val, VARIANT *var, VARTYPE vt) -{ - VOID *p = NULL; - HRESULT hr = S_OK; - ole_val2variant_ex(val, var, vt); - if ((vt & ~VT_BYREF) == VT_VARIANT) { - p = var; - } else { - if ( (vt & ~VT_BYREF) != V_VT(var)) { - hr = VariantChangeTypeEx(var, var, - cWIN32OLE_lcid, 0, (VARTYPE)(vt & ~VT_BYREF)); - if (FAILED(hr)) { - ole_raise(hr, rb_eRuntimeError, "failed to change type"); - } - } - p = get_ptr_of_variant(var); - } - if (p == NULL) { - rb_raise(rb_eRuntimeError, "failed to get pointer of variant"); - } - return p; -} - -static void * -get_ptr_of_variant(VARIANT *pvar) -{ - switch(V_VT(pvar)) { - case VT_UI1: - return &V_UI1(pvar); - break; - case VT_I2: - return &V_I2(pvar); - break; - case VT_UI2: - return &V_UI2(pvar); - break; - case VT_I4: - return &V_I4(pvar); - break; - case VT_UI4: - return &V_UI4(pvar); - break; - case VT_R4: - return &V_R4(pvar); - break; - case VT_R8: - return &V_R8(pvar); - break; -#if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__) - case VT_I8: - return &V_I8(pvar); - break; - case VT_UI8: - return &V_UI8(pvar); - break; -#endif - case VT_INT: - return &V_INT(pvar); - break; - case VT_UINT: - return &V_UINT(pvar); - break; - case VT_CY: - return &V_CY(pvar); - break; - case VT_DATE: - return &V_DATE(pvar); - break; - case VT_BSTR: - return V_BSTR(pvar); - break; - case VT_DISPATCH: - return V_DISPATCH(pvar); - break; - case VT_ERROR: - return &V_ERROR(pvar); - break; - case VT_BOOL: - return &V_BOOL(pvar); - break; - case VT_UNKNOWN: - return V_UNKNOWN(pvar); - break; - case VT_ARRAY: - return &V_ARRAY(pvar); - break; - default: - return NULL; - break; - } -} - -static void -ole_set_safe_array(long n, SAFEARRAY *psa, LONG *pid, long *pub, VALUE val, long dim, VARTYPE vt) -{ - VALUE val1; - HRESULT hr = S_OK; - VARIANT var; - VOID *p = NULL; - long i = n; - while(i >= 0) { - val1 = ole_ary_m_entry(val, pid); - VariantInit(&var); - p = val2variant_ptr(val1, &var, vt); - if (is_all_index_under(pid, pub, dim) == Qtrue) { - if ((V_VT(&var) == VT_DISPATCH && V_DISPATCH(&var) == NULL) || - (V_VT(&var) == VT_UNKNOWN && V_UNKNOWN(&var) == NULL)) { - rb_raise(eWIN32OLERuntimeError, "element of array does not have IDispatch or IUnknown Interface"); - } - hr = SafeArrayPutElement(psa, pid, p); - } - if (FAILED(hr)) { - ole_raise(hr, rb_eRuntimeError, "failed to SafeArrayPutElement"); - } - pid[i] += 1; - if (pid[i] > pub[i]) { - pid[i] = 0; - i -= 1; - } else { - i = dim - 1; - } - } -} - -static long -dimension(VALUE val) { - long dim = 0; - long dim1 = 0; - long len = 0; - long i = 0; - if (RB_TYPE_P(val, T_ARRAY)) { - len = RARRAY_LEN(val); - for (i = 0; i < len; i++) { - dim1 = dimension(rb_ary_entry(val, i)); - if (dim < dim1) { - dim = dim1; - } - } - dim += 1; - } - return dim; -} - -static long -ary_len_of_dim(VALUE ary, long dim) { - long ary_len = 0; - long ary_len1 = 0; - long len = 0; - long i = 0; - VALUE val; - if (dim == 0) { - if (RB_TYPE_P(ary, T_ARRAY)) { - ary_len = RARRAY_LEN(ary); - } - } else { - if (RB_TYPE_P(ary, T_ARRAY)) { - len = RARRAY_LEN(ary); - for (i = 0; i < len; i++) { - val = rb_ary_entry(ary, i); - ary_len1 = ary_len_of_dim(val, dim-1); - if (ary_len < ary_len1) { - ary_len = ary_len1; - } - } - } - } - return ary_len; -} - -HRESULT -ole_val_ary2variant_ary(VALUE val, VARIANT *var, VARTYPE vt) -{ - long dim = 0; - int i = 0; - HRESULT hr = S_OK; - - SAFEARRAYBOUND *psab = NULL; - SAFEARRAY *psa = NULL; - long *pub; - LONG *pid; - - Check_Type(val, T_ARRAY); - - dim = dimension(val); - - psab = ALLOC_N(SAFEARRAYBOUND, dim); - pub = ALLOC_N(long, dim); - pid = ALLOC_N(LONG, dim); - - if(!psab || !pub || !pid) { - if(pub) free(pub); - if(psab) free(psab); - if(pid) free(pid); - rb_raise(rb_eRuntimeError, "memory allocation error"); - } - - for (i = 0; i < dim; i++) { - psab[i].cElements = ary_len_of_dim(val, i); - psab[i].lLbound = 0; - pub[i] = psab[i].cElements - 1; - pid[i] = 0; - } - /* Create and fill VARIANT array */ - if ((vt & ~VT_BYREF) == VT_ARRAY) { - vt = (vt | VT_VARIANT); - } - psa = SafeArrayCreate((VARTYPE)(vt & VT_TYPEMASK), dim, psab); - if (psa == NULL) - hr = E_OUTOFMEMORY; - else - hr = SafeArrayLock(psa); - if (SUCCEEDED(hr)) { - ole_set_safe_array(dim-1, psa, pid, pub, val, dim, (VARTYPE)(vt & VT_TYPEMASK)); - hr = SafeArrayUnlock(psa); - } - - if(pub) free(pub); - if(psab) free(psab); - if(pid) free(pid); - - if (SUCCEEDED(hr)) { - V_VT(var) = vt; - V_ARRAY(var) = psa; - } - else { - if (psa != NULL) - SafeArrayDestroy(psa); - } - return hr; -} - -void -ole_val2variant(VALUE val, VARIANT *var) -{ - struct oledata *pole = NULL; - if(rb_obj_is_kind_of(val, cWIN32OLE)) { - pole = oledata_get_struct(val); - OLE_ADDREF(pole->pDispatch); - V_VT(var) = VT_DISPATCH; - V_DISPATCH(var) = pole->pDispatch; - return; - } - if (rb_obj_is_kind_of(val, cWIN32OLE_VARIANT)) { - ole_variant2variant(val, var); - return; - } - if (rb_obj_is_kind_of(val, cWIN32OLE_RECORD)) { - ole_rec2variant(val, var); - return; - } - if (rb_obj_is_kind_of(val, rb_cTime)) { - V_VT(var) = VT_DATE; - V_DATE(var) = rbtime2vtdate(val); - return; - } - switch (TYPE(val)) { - case T_ARRAY: - ole_val_ary2variant_ary(val, var, VT_VARIANT|VT_ARRAY); - break; - case T_STRING: - V_VT(var) = VT_BSTR; - V_BSTR(var) = ole_vstr2wc(val); - break; - case T_FIXNUM: - V_VT(var) = VT_I4; - V_I4(var) = NUM2INT(val); - break; - case T_BIGNUM: - V_VT(var) = VT_R8; - V_R8(var) = rb_big2dbl(val); - break; - case T_FLOAT: - V_VT(var) = VT_R8; - V_R8(var) = NUM2DBL(val); - break; - case T_TRUE: - V_VT(var) = VT_BOOL; - V_BOOL(var) = VARIANT_TRUE; - break; - case T_FALSE: - V_VT(var) = VT_BOOL; - V_BOOL(var) = VARIANT_FALSE; - break; - case T_NIL: - if (g_nil_to == VT_ERROR) { - V_VT(var) = VT_ERROR; - V_ERROR(var) = DISP_E_PARAMNOTFOUND; - }else { - V_VT(var) = VT_EMPTY; - } - break; - default: - V_VT(var) = VT_DISPATCH; - V_DISPATCH(var) = val2dispatch(val); - break; - } -} - -void -ole_val2variant2(VALUE val, VARIANT *var) -{ - g_nil_to = VT_EMPTY; - ole_val2variant(val, var); - g_nil_to = VT_ERROR; -} - -VALUE -make_inspect(const char *class_name, VALUE detail) -{ - VALUE str; - str = rb_str_new2("#<"); - rb_str_cat2(str, class_name); - rb_str_cat2(str, ":"); - rb_str_concat(str, detail); - rb_str_cat2(str, ">"); - return str; -} - -VALUE -default_inspect(VALUE self, const char *class_name) -{ - VALUE detail = rb_funcall(self, rb_intern("to_s"), 0); - return make_inspect(class_name, detail); -} - -static VALUE -ole_set_member(VALUE self, IDispatch *dispatch) -{ - struct oledata *pole = NULL; - pole = oledata_get_struct(self); - if (pole->pDispatch) { - OLE_RELEASE(pole->pDispatch); - pole->pDispatch = NULL; - } - pole->pDispatch = dispatch; - return self; -} - - -static VALUE -fole_s_allocate(VALUE klass) -{ - struct oledata *pole; - VALUE obj; - ole_initialize(); - obj = TypedData_Make_Struct(klass, struct oledata, &ole_datatype, pole); - pole->pDispatch = NULL; - return obj; -} - -static VALUE -create_win32ole_object(VALUE klass, IDispatch *pDispatch, int argc, VALUE *argv) -{ - VALUE obj = fole_s_allocate(klass); - ole_set_member(obj, pDispatch); - return obj; -} - -static VALUE -ary_new_dim(VALUE myary, LONG *pid, LONG *plb, LONG dim) { - long i; - VALUE obj = Qnil; - VALUE pobj = Qnil; - long *ids = ALLOC_N(long, dim); - if (!ids) { - rb_raise(rb_eRuntimeError, "memory allocation error"); - } - for(i = 0; i < dim; i++) { - ids[i] = pid[i] - plb[i]; - } - obj = myary; - pobj = myary; - for(i = 0; i < dim-1; i++) { - obj = rb_ary_entry(pobj, ids[i]); - if (obj == Qnil) { - rb_ary_store(pobj, ids[i], rb_ary_new()); - } - obj = rb_ary_entry(pobj, ids[i]); - pobj = obj; - } - if (ids) free(ids); - return obj; -} - -static void -ary_store_dim(VALUE myary, LONG *pid, LONG *plb, LONG dim, VALUE val) { - long id = pid[dim - 1] - plb[dim - 1]; - VALUE obj = ary_new_dim(myary, pid, plb, dim); - rb_ary_store(obj, id, val); -} - -VALUE -ole_variant2val(VARIANT *pvar) -{ - VALUE obj = Qnil; - VARTYPE vt = V_VT(pvar); - HRESULT hr; - while ( vt == (VT_BYREF | VT_VARIANT) ) { - pvar = V_VARIANTREF(pvar); - vt = V_VT(pvar); - } - - if(V_ISARRAY(pvar)) { - VARTYPE vt_base = vt & VT_TYPEMASK; - SAFEARRAY *psa = V_ISBYREF(pvar) ? *V_ARRAYREF(pvar) : V_ARRAY(pvar); - UINT i = 0; - LONG *pid, *plb, *pub; - VARIANT variant; - VALUE val; - UINT dim = 0; - if (!psa) { - return obj; - } - dim = SafeArrayGetDim(psa); - pid = ALLOC_N(LONG, dim); - plb = ALLOC_N(LONG, dim); - pub = ALLOC_N(LONG, dim); - - if(!pid || !plb || !pub) { - if(pid) free(pid); - if(plb) free(plb); - if(pub) free(pub); - rb_raise(rb_eRuntimeError, "memory allocation error"); - } - - for(i = 0; i < dim; ++i) { - SafeArrayGetLBound(psa, i+1, &plb[i]); - SafeArrayGetLBound(psa, i+1, &pid[i]); - SafeArrayGetUBound(psa, i+1, &pub[i]); - } - hr = SafeArrayLock(psa); - if (SUCCEEDED(hr)) { - obj = rb_ary_new(); - i = 0; - VariantInit(&variant); - V_VT(&variant) = vt_base | VT_BYREF; - if (vt_base == VT_RECORD) { - hr = SafeArrayGetRecordInfo(psa, &V_RECORDINFO(&variant)); - if (SUCCEEDED(hr)) { - V_VT(&variant) = VT_RECORD; - } - } - while (i < dim) { - ary_new_dim(obj, pid, plb, dim); - if (vt_base == VT_RECORD) - hr = SafeArrayPtrOfIndex(psa, pid, &V_RECORD(&variant)); - else - hr = SafeArrayPtrOfIndex(psa, pid, &V_BYREF(&variant)); - if (SUCCEEDED(hr)) { - val = ole_variant2val(&variant); - ary_store_dim(obj, pid, plb, dim, val); - } - for (i = 0; i < dim; ++i) { - if (++pid[i] <= pub[i]) - break; - pid[i] = plb[i]; - } - } - SafeArrayUnlock(psa); - } - if(pid) free(pid); - if(plb) free(plb); - if(pub) free(pub); - return obj; - } - switch(V_VT(pvar) & ~VT_BYREF){ - case VT_EMPTY: - break; - case VT_NULL: - break; - case VT_I1: - if(V_ISBYREF(pvar)) - obj = INT2NUM((long)*V_I1REF(pvar)); - else - obj = INT2NUM((long)V_I1(pvar)); - break; - - case VT_UI1: - if(V_ISBYREF(pvar)) - obj = INT2NUM((long)*V_UI1REF(pvar)); - else - obj = INT2NUM((long)V_UI1(pvar)); - break; - - case VT_I2: - if(V_ISBYREF(pvar)) - obj = INT2NUM((long)*V_I2REF(pvar)); - else - obj = INT2NUM((long)V_I2(pvar)); - break; - - case VT_UI2: - if(V_ISBYREF(pvar)) - obj = INT2NUM((long)*V_UI2REF(pvar)); - else - obj = INT2NUM((long)V_UI2(pvar)); - break; - - case VT_I4: - if(V_ISBYREF(pvar)) - obj = INT2NUM((long)*V_I4REF(pvar)); - else - obj = INT2NUM((long)V_I4(pvar)); - break; - - case VT_UI4: - if(V_ISBYREF(pvar)) - obj = INT2NUM((long)*V_UI4REF(pvar)); - else - obj = INT2NUM((long)V_UI4(pvar)); - break; - - case VT_INT: - if(V_ISBYREF(pvar)) - obj = INT2NUM((long)*V_INTREF(pvar)); - else - obj = INT2NUM((long)V_INT(pvar)); - break; - - case VT_UINT: - if(V_ISBYREF(pvar)) - obj = INT2NUM((long)*V_UINTREF(pvar)); - else - obj = INT2NUM((long)V_UINT(pvar)); - break; - -#if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__) - case VT_I8: - if(V_ISBYREF(pvar)) -#if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__) -#ifdef V_I8REF - obj = I8_2_NUM(*V_I8REF(pvar)); -#endif -#else - obj = Qnil; -#endif - else - obj = I8_2_NUM(V_I8(pvar)); - break; - case VT_UI8: - if(V_ISBYREF(pvar)) -#if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__) -#ifdef V_UI8REF - obj = UI8_2_NUM(*V_UI8REF(pvar)); -#endif -#else - obj = Qnil; -#endif - else - obj = UI8_2_NUM(V_UI8(pvar)); - break; -#endif /* (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__) */ - - case VT_R4: - if(V_ISBYREF(pvar)) - obj = rb_float_new(*V_R4REF(pvar)); - else - obj = rb_float_new(V_R4(pvar)); - break; - - case VT_R8: - if(V_ISBYREF(pvar)) - obj = rb_float_new(*V_R8REF(pvar)); - else - obj = rb_float_new(V_R8(pvar)); - break; - - case VT_BSTR: - { - if(V_ISBYREF(pvar)) - obj = ole_wc2vstr(*V_BSTRREF(pvar), FALSE); - else - obj = ole_wc2vstr(V_BSTR(pvar), FALSE); - break; - } - - case VT_ERROR: - if(V_ISBYREF(pvar)) - obj = INT2NUM(*V_ERRORREF(pvar)); - else - obj = INT2NUM(V_ERROR(pvar)); - break; - - case VT_BOOL: - if (V_ISBYREF(pvar)) - obj = (*V_BOOLREF(pvar) ? Qtrue : Qfalse); - else - obj = (V_BOOL(pvar) ? Qtrue : Qfalse); - break; - - case VT_DISPATCH: - { - IDispatch *pDispatch; - - if (V_ISBYREF(pvar)) - pDispatch = *V_DISPATCHREF(pvar); - else - pDispatch = V_DISPATCH(pvar); - - if (pDispatch != NULL ) { - OLE_ADDREF(pDispatch); - obj = create_win32ole_object(cWIN32OLE, pDispatch, 0, 0); - } - break; - } - - case VT_UNKNOWN: - { - /* get IDispatch interface from IUnknown interface */ - IUnknown *punk; - IDispatch *pDispatch; - void *p; - HRESULT hr; - - if (V_ISBYREF(pvar)) - punk = *V_UNKNOWNREF(pvar); - else - punk = V_UNKNOWN(pvar); - - if(punk != NULL) { - hr = punk->lpVtbl->QueryInterface(punk, &IID_IDispatch, &p); - if(SUCCEEDED(hr)) { - pDispatch = p; - obj = create_win32ole_object(cWIN32OLE, pDispatch, 0, 0); - } - } - break; - } - - case VT_DATE: - { - DATE date; - if(V_ISBYREF(pvar)) - date = *V_DATEREF(pvar); - else - date = V_DATE(pvar); - - obj = vtdate2rbtime(date); - break; - } - - case VT_RECORD: - { - IRecordInfo *pri = V_RECORDINFO(pvar); - void *prec = V_RECORD(pvar); - obj = create_win32ole_record(pri, prec); - break; - } - - case VT_CY: - default: - { - HRESULT hr; - VARIANT variant; - VariantInit(&variant); - hr = VariantChangeTypeEx(&variant, pvar, - cWIN32OLE_lcid, 0, VT_BSTR); - if (SUCCEEDED(hr) && V_VT(&variant) == VT_BSTR) { - obj = ole_wc2vstr(V_BSTR(&variant), FALSE); - } - VariantClear(&variant); - break; - } - } - return obj; -} - -LONG -reg_open_key(HKEY hkey, const char *name, HKEY *phkey) -{ - return RegOpenKeyEx(hkey, name, 0, KEY_READ, phkey); -} - -LONG -reg_open_vkey(HKEY hkey, VALUE key, HKEY *phkey) -{ - return reg_open_key(hkey, StringValuePtr(key), phkey); -} - -VALUE -reg_enum_key(HKEY hkey, DWORD i) -{ - char buf[BUFSIZ + 1]; - DWORD size_buf = sizeof(buf); - FILETIME ft; - LONG err = RegEnumKeyEx(hkey, i, buf, &size_buf, - NULL, NULL, NULL, &ft); - if(err == ERROR_SUCCESS) { - buf[BUFSIZ] = '\0'; - return rb_str_new2(buf); - } - return Qnil; -} - -VALUE -reg_get_val(HKEY hkey, const char *subkey) -{ - char *pbuf; - DWORD dwtype = 0; - DWORD size = 0; - VALUE val = Qnil; - LONG err = RegQueryValueEx(hkey, subkey, NULL, &dwtype, NULL, &size); - - if (err == ERROR_SUCCESS) { - pbuf = ALLOC_N(char, size + 1); - err = RegQueryValueEx(hkey, subkey, NULL, &dwtype, (BYTE *)pbuf, &size); - if (err == ERROR_SUCCESS) { - pbuf[size] = '\0'; - if (dwtype == REG_EXPAND_SZ) { - char* pbuf2 = (char *)pbuf; - DWORD len = ExpandEnvironmentStrings(pbuf2, NULL, 0); - pbuf = ALLOC_N(char, len + 1); - ExpandEnvironmentStrings(pbuf2, pbuf, len + 1); - free(pbuf2); - } - val = rb_str_new2((char *)pbuf); - } - free(pbuf); - } - return val; -} - -VALUE -reg_get_val2(HKEY hkey, const char *subkey) -{ - HKEY hsubkey; - LONG err; - VALUE val = Qnil; - err = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &hsubkey); - if (err == ERROR_SUCCESS) { - val = reg_get_val(hsubkey, NULL); - RegCloseKey(hsubkey); - } - if (val == Qnil) { - val = reg_get_val(hkey, subkey); - } - return val; -} - -static void -ole_const_load(ITypeLib *pTypeLib, VALUE klass, VALUE self) -{ - unsigned int count; - unsigned int index; - int iVar; - ITypeInfo *pTypeInfo; - TYPEATTR *pTypeAttr; - VARDESC *pVarDesc; - HRESULT hr; - unsigned int len; - BSTR bstr; - char *pName = NULL; - VALUE val; - VALUE constant; - ID id; - constant = rb_hash_new(); - count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib); - for (index = 0; index < count; index++) { - hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, index, &pTypeInfo); - if (FAILED(hr)) - continue; - hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr); - if(FAILED(hr)) { - OLE_RELEASE(pTypeInfo); - continue; - } - for(iVar = 0; iVar < pTypeAttr->cVars; iVar++) { - hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, iVar, &pVarDesc); - if(FAILED(hr)) - continue; - if(pVarDesc->varkind == VAR_CONST && - !(pVarDesc->wVarFlags & (VARFLAG_FHIDDEN | - VARFLAG_FRESTRICTED | - VARFLAG_FNONBROWSABLE))) { - hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, pVarDesc->memid, &bstr, - 1, &len); - if(FAILED(hr) || len == 0 || !bstr) - continue; - pName = ole_wc2mb(bstr); - val = ole_variant2val(V_UNION1(pVarDesc, lpvarValue)); - *pName = toupper((int)*pName); - id = rb_intern(pName); - if (rb_is_const_id(id)) { - rb_define_const(klass, pName, val); - } - else { - rb_hash_aset(constant, rb_str_new2(pName), val); - } - SysFreeString(bstr); - if(pName) { - free(pName); - pName = NULL; - } - } - pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc); - } - pTypeInfo->lpVtbl->ReleaseTypeAttr(pTypeInfo, pTypeAttr); - OLE_RELEASE(pTypeInfo); - } - rb_define_const(klass, "CONSTANTS", constant); -} - -static HRESULT -clsid_from_remote(VALUE host, VALUE com, CLSID *pclsid) -{ - HKEY hlm; - HKEY hpid; - VALUE subkey; - LONG err; - char clsid[100]; - OLECHAR *pbuf; - DWORD len; - DWORD dwtype; - HRESULT hr = S_OK; - err = RegConnectRegistry(StringValuePtr(host), HKEY_LOCAL_MACHINE, &hlm); - if (err != ERROR_SUCCESS) - return HRESULT_FROM_WIN32(err); - subkey = rb_str_new2("SOFTWARE\\Classes\\"); - rb_str_concat(subkey, com); - rb_str_cat2(subkey, "\\CLSID"); - err = RegOpenKeyEx(hlm, StringValuePtr(subkey), 0, KEY_READ, &hpid); - if (err != ERROR_SUCCESS) - hr = HRESULT_FROM_WIN32(err); - else { - len = sizeof(clsid); - err = RegQueryValueEx(hpid, "", NULL, &dwtype, (BYTE *)clsid, &len); - if (err == ERROR_SUCCESS && dwtype == REG_SZ) { - pbuf = ole_mb2wc(clsid, -1); - hr = CLSIDFromString(pbuf, pclsid); - SysFreeString(pbuf); - } - else { - hr = HRESULT_FROM_WIN32(err); - } - RegCloseKey(hpid); - } - RegCloseKey(hlm); - return hr; -} - -static VALUE -ole_create_dcom(VALUE self, VALUE ole, VALUE host, VALUE others) -{ - HRESULT hr; - CLSID clsid; - OLECHAR *pbuf; - - COSERVERINFO serverinfo; - MULTI_QI multi_qi; - DWORD clsctx = CLSCTX_REMOTE_SERVER; - - if (!gole32) - gole32 = LoadLibrary("OLE32"); - if (!gole32) - rb_raise(rb_eRuntimeError, "failed to load OLE32"); - if (!gCoCreateInstanceEx) - gCoCreateInstanceEx = (FNCOCREATEINSTANCEEX*) - GetProcAddress(gole32, "CoCreateInstanceEx"); - if (!gCoCreateInstanceEx) - rb_raise(rb_eRuntimeError, "CoCreateInstanceEx is not supported in this environment"); - - pbuf = ole_vstr2wc(ole); - hr = CLSIDFromProgID(pbuf, &clsid); - if (FAILED(hr)) - hr = clsid_from_remote(host, ole, &clsid); - if (FAILED(hr)) - hr = CLSIDFromString(pbuf, &clsid); - SysFreeString(pbuf); - if (FAILED(hr)) - ole_raise(hr, eWIN32OLERuntimeError, - "unknown OLE server: `%s'", - StringValuePtr(ole)); - memset(&serverinfo, 0, sizeof(COSERVERINFO)); - serverinfo.pwszName = ole_vstr2wc(host); - memset(&multi_qi, 0, sizeof(MULTI_QI)); - multi_qi.pIID = &IID_IDispatch; - hr = gCoCreateInstanceEx(&clsid, NULL, clsctx, &serverinfo, 1, &multi_qi); - SysFreeString(serverinfo.pwszName); - if (FAILED(hr)) - ole_raise(hr, eWIN32OLERuntimeError, - "failed to create DCOM server `%s' in `%s'", - StringValuePtr(ole), - StringValuePtr(host)); - - ole_set_member(self, (IDispatch*)multi_qi.pItf); - return self; -} - -static VALUE -ole_bind_obj(VALUE moniker, int argc, VALUE *argv, VALUE self) -{ - IBindCtx *pBindCtx; - IMoniker *pMoniker; - IDispatch *pDispatch; - void *p; - HRESULT hr; - OLECHAR *pbuf; - ULONG eaten = 0; - - ole_initialize(); - - hr = CreateBindCtx(0, &pBindCtx); - if(FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, - "failed to create bind context"); - } - - pbuf = ole_vstr2wc(moniker); - hr = MkParseDisplayName(pBindCtx, pbuf, &eaten, &pMoniker); - SysFreeString(pbuf); - if(FAILED(hr)) { - OLE_RELEASE(pBindCtx); - ole_raise(hr, eWIN32OLERuntimeError, - "failed to parse display name of moniker `%s'", - StringValuePtr(moniker)); - } - hr = pMoniker->lpVtbl->BindToObject(pMoniker, pBindCtx, NULL, - &IID_IDispatch, &p); - pDispatch = p; - OLE_RELEASE(pMoniker); - OLE_RELEASE(pBindCtx); - - if(FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, - "failed to bind moniker `%s'", - StringValuePtr(moniker)); - } - return create_win32ole_object(self, pDispatch, argc, argv); -} - -/* - * call-seq: - * WIN32OLE.connect( ole ) --> aWIN32OLE - * - * Returns running OLE Automation object or WIN32OLE object from moniker. - * 1st argument should be OLE program id or class id or moniker. - * - * WIN32OLE.connect('Excel.Application') # => WIN32OLE object which represents running Excel. - */ -static VALUE -fole_s_connect(int argc, VALUE *argv, VALUE self) -{ - VALUE svr_name; - VALUE others; - HRESULT hr; - CLSID clsid; - OLECHAR *pBuf; - IDispatch *pDispatch; - void *p; - IUnknown *pUnknown; - - /* initialize to use OLE */ - ole_initialize(); - - rb_scan_args(argc, argv, "1*", &svr_name, &others); - StringValue(svr_name); - if (rb_safe_level() > 0 && OBJ_TAINTED(svr_name)) { - rb_raise(rb_eSecurityError, "insecure connection - `%s'", - StringValuePtr(svr_name)); - } - - /* get CLSID from OLE server name */ - pBuf = ole_vstr2wc(svr_name); - hr = CLSIDFromProgID(pBuf, &clsid); - if(FAILED(hr)) { - hr = CLSIDFromString(pBuf, &clsid); - } - SysFreeString(pBuf); - if(FAILED(hr)) { - return ole_bind_obj(svr_name, argc, argv, self); - } - - hr = GetActiveObject(&clsid, 0, &pUnknown); - if (FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, - "OLE server `%s' not running", StringValuePtr(svr_name)); - } - hr = pUnknown->lpVtbl->QueryInterface(pUnknown, &IID_IDispatch, &p); - pDispatch = p; - if(FAILED(hr)) { - OLE_RELEASE(pUnknown); - ole_raise(hr, eWIN32OLERuntimeError, - "failed to create WIN32OLE server `%s'", - StringValuePtr(svr_name)); - } - - OLE_RELEASE(pUnknown); - - return create_win32ole_object(self, pDispatch, argc, argv); -} - -/* - * call-seq: - * WIN32OLE.const_load( ole, mod = WIN32OLE) - * - * Defines the constants of OLE Automation server as mod's constants. - * The first argument is WIN32OLE object or type library name. - * If 2nd argument is omitted, the default is WIN32OLE. - * The first letter of Ruby's constant variable name is upper case, - * so constant variable name of WIN32OLE object is capitalized. - * For example, the 'xlTop' constant of Excel is changed to 'XlTop' - * in WIN32OLE. - * If the first letter of constant variable is not [A-Z], then - * the constant is defined as CONSTANTS hash element. - * - * module EXCEL_CONST - * end - * excel = WIN32OLE.new('Excel.Application') - * WIN32OLE.const_load(excel, EXCEL_CONST) - * puts EXCEL_CONST::XlTop # => -4160 - * puts EXCEL_CONST::CONSTANTS['_xlDialogChartSourceData'] # => 541 - * - * WIN32OLE.const_load(excel) - * puts WIN32OLE::XlTop # => -4160 - * - * module MSO - * end - * WIN32OLE.const_load('Microsoft Office 9.0 Object Library', MSO) - * puts MSO::MsoLineSingle # => 1 - */ -static VALUE -fole_s_const_load(int argc, VALUE *argv, VALUE self) -{ - VALUE ole; - VALUE klass; - struct oledata *pole = NULL; - ITypeInfo *pTypeInfo; - ITypeLib *pTypeLib; - unsigned int index; - HRESULT hr; - OLECHAR *pBuf; - VALUE file; - LCID lcid = cWIN32OLE_lcid; - - rb_scan_args(argc, argv, "11", &ole, &klass); - if (!RB_TYPE_P(klass, T_CLASS) && - !RB_TYPE_P(klass, T_MODULE) && - !RB_TYPE_P(klass, T_NIL)) { - rb_raise(rb_eTypeError, "2nd parameter must be Class or Module"); - } - if (rb_obj_is_kind_of(ole, cWIN32OLE)) { - pole = oledata_get_struct(ole); - hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch, - 0, lcid, &pTypeInfo); - if(FAILED(hr)) { - ole_raise(hr, rb_eRuntimeError, "failed to GetTypeInfo"); - } - hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &index); - if(FAILED(hr)) { - OLE_RELEASE(pTypeInfo); - ole_raise(hr, rb_eRuntimeError, "failed to GetContainingTypeLib"); - } - OLE_RELEASE(pTypeInfo); - if(!RB_TYPE_P(klass, T_NIL)) { - ole_const_load(pTypeLib, klass, self); - } - else { - ole_const_load(pTypeLib, cWIN32OLE, self); - } - OLE_RELEASE(pTypeLib); - } - else if(RB_TYPE_P(ole, T_STRING)) { - file = typelib_file(ole); - if (file == Qnil) { - file = ole; - } - pBuf = ole_vstr2wc(file); - hr = LoadTypeLibEx(pBuf, REGKIND_NONE, &pTypeLib); - SysFreeString(pBuf); - if (FAILED(hr)) - ole_raise(hr, eWIN32OLERuntimeError, "failed to LoadTypeLibEx"); - if(!RB_TYPE_P(klass, T_NIL)) { - ole_const_load(pTypeLib, klass, self); - } - else { - ole_const_load(pTypeLib, cWIN32OLE, self); - } - OLE_RELEASE(pTypeLib); - } - else { - rb_raise(rb_eTypeError, "1st parameter must be WIN32OLE instance"); - } - return Qnil; -} - -static ULONG -reference_count(struct oledata * pole) -{ - ULONG n = 0; - if(pole->pDispatch) { - OLE_ADDREF(pole->pDispatch); - n = OLE_RELEASE(pole->pDispatch); - } - return n; -} - -/* - * call-seq: - * WIN32OLE.ole_reference_count(aWIN32OLE) --> number - * - * Returns reference counter of Dispatch interface of WIN32OLE object. - * You should not use this method because this method - * exists only for debugging WIN32OLE. - */ -static VALUE -fole_s_reference_count(VALUE self, VALUE obj) -{ - struct oledata * pole = NULL; - pole = oledata_get_struct(obj); - return INT2NUM(reference_count(pole)); -} - -/* - * call-seq: - * WIN32OLE.ole_free(aWIN32OLE) --> number - * - * Invokes Release method of Dispatch interface of WIN32OLE object. - * You should not use this method because this method - * exists only for debugging WIN32OLE. - * The return value is reference counter of OLE object. - */ -static VALUE -fole_s_free(VALUE self, VALUE obj) -{ - ULONG n = 0; - struct oledata * pole = NULL; - pole = oledata_get_struct(obj); - if(pole->pDispatch) { - if (reference_count(pole) > 0) { - n = OLE_RELEASE(pole->pDispatch); - } - } - return INT2NUM(n); -} - -static HWND -ole_show_help(VALUE helpfile, VALUE helpcontext) -{ - FNHTMLHELP *pfnHtmlHelp; - HWND hwnd = 0; - - if(!ghhctrl) - ghhctrl = LoadLibrary("HHCTRL.OCX"); - if (!ghhctrl) - return hwnd; - pfnHtmlHelp = (FNHTMLHELP*)GetProcAddress(ghhctrl, "HtmlHelpA"); - if (!pfnHtmlHelp) - return hwnd; - hwnd = pfnHtmlHelp(GetDesktopWindow(), StringValuePtr(helpfile), - 0x0f, NUM2INT(helpcontext)); - if (hwnd == 0) - hwnd = pfnHtmlHelp(GetDesktopWindow(), StringValuePtr(helpfile), - 0, NUM2INT(helpcontext)); - return hwnd; -} - -/* - * call-seq: - * WIN32OLE.ole_show_help(obj [,helpcontext]) - * - * Displays helpfile. The 1st argument specifies WIN32OLE_TYPE - * object or WIN32OLE_METHOD object or helpfile. - * - * excel = WIN32OLE.new('Excel.Application') - * typeobj = excel.ole_type - * WIN32OLE.ole_show_help(typeobj) - */ -static VALUE -fole_s_show_help(int argc, VALUE *argv, VALUE self) -{ - VALUE target; - VALUE helpcontext; - VALUE helpfile; - VALUE name; - HWND hwnd; - rb_scan_args(argc, argv, "11", &target, &helpcontext); - if (rb_obj_is_kind_of(target, cWIN32OLE_TYPE) || - rb_obj_is_kind_of(target, cWIN32OLE_METHOD)) { - helpfile = rb_funcall(target, rb_intern("helpfile"), 0); - if(strlen(StringValuePtr(helpfile)) == 0) { - name = rb_ivar_get(target, rb_intern("name")); - rb_raise(rb_eRuntimeError, "no helpfile of `%s'", - StringValuePtr(name)); - } - helpcontext = rb_funcall(target, rb_intern("helpcontext"), 0); - } else { - helpfile = target; - } - if (!RB_TYPE_P(helpfile, T_STRING)) { - rb_raise(rb_eTypeError, "1st parameter must be (String|WIN32OLE_TYPE|WIN32OLE_METHOD)"); - } - hwnd = ole_show_help(helpfile, helpcontext); - if(hwnd == 0) { - rb_raise(rb_eRuntimeError, "failed to open help file `%s'", - StringValuePtr(helpfile)); - } - return Qnil; -} - -/* - * call-seq: - * WIN32OLE.codepage - * - * Returns current codepage. - * WIN32OLE.codepage # => WIN32OLE::CP_ACP - */ -static VALUE -fole_s_get_code_page(VALUE self) -{ - return INT2FIX(cWIN32OLE_cp); -} - -static BOOL CALLBACK -installed_code_page_proc(LPTSTR str) { - if (strtoul(str, NULL, 10) == g_cp_to_check) { - g_cp_installed = TRUE; - return FALSE; - } - return TRUE; -} - -static BOOL -code_page_installed(UINT cp) -{ - g_cp_installed = FALSE; - g_cp_to_check = cp; - EnumSystemCodePages(installed_code_page_proc, CP_INSTALLED); - return g_cp_installed; -} - -/* - * call-seq: - * WIN32OLE.codepage = CP - * - * Sets current codepage. - * The WIN32OLE.codepage is initialized according to - * Encoding.default_internal. - * If Encoding.default_internal is nil then WIN32OLE.codepage - * is initialized according to Encoding.default_external. - * - * WIN32OLE.codepage = WIN32OLE::CP_UTF8 - * WIN32OLE.codepage = 65001 - */ -static VALUE -fole_s_set_code_page(VALUE self, VALUE vcp) -{ - UINT cp = FIX2INT(vcp); - set_ole_codepage(cp); - /* - * Should this method return old codepage? - */ - return Qnil; -} - -/* - * call-seq: - * WIN32OLE.locale -> locale id. - * - * Returns current locale id (lcid). The default locale is - * WIN32OLE::LOCALE_SYSTEM_DEFAULT. - * - * lcid = WIN32OLE.locale - */ -static VALUE -fole_s_get_locale(VALUE self) -{ - return INT2FIX(cWIN32OLE_lcid); -} - -static BOOL -CALLBACK installed_lcid_proc(LPTSTR str) -{ - if (strcmp(str, g_lcid_to_check) == 0) { - g_lcid_installed = TRUE; - return FALSE; - } - return TRUE; -} - -static BOOL -lcid_installed(LCID lcid) -{ - g_lcid_installed = FALSE; - snprintf(g_lcid_to_check, sizeof(g_lcid_to_check), "%08lx", (unsigned long)lcid); - EnumSystemLocales(installed_lcid_proc, LCID_INSTALLED); - return g_lcid_installed; -} - -/* - * call-seq: - * WIN32OLE.locale = lcid - * - * Sets current locale id (lcid). - * - * WIN32OLE.locale = 1033 # set locale English(U.S) - * obj = WIN32OLE_VARIANT.new("$100,000", WIN32OLE::VARIANT::VT_CY) - * - */ -static VALUE -fole_s_set_locale(VALUE self, VALUE vlcid) -{ - LCID lcid = FIX2INT(vlcid); - if (lcid_installed(lcid)) { - cWIN32OLE_lcid = lcid; - } else { - switch (lcid) { - case LOCALE_SYSTEM_DEFAULT: - case LOCALE_USER_DEFAULT: - cWIN32OLE_lcid = lcid; - break; - default: - rb_raise(eWIN32OLERuntimeError, "not installed locale: %u", (unsigned int)lcid); - } - } - return Qnil; -} - -/* - * call-seq: - * WIN32OLE.create_guid - * - * Creates GUID. - * WIN32OLE.create_guid # => {1CB530F1-F6B1-404D-BCE6-1959BF91F4A8} - */ -static VALUE -fole_s_create_guid(VALUE self) -{ - GUID guid; - HRESULT hr; - OLECHAR bstr[80]; - int len = 0; - hr = CoCreateGuid(&guid); - if (FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, "failed to create GUID"); - } - len = StringFromGUID2(&guid, bstr, sizeof(bstr)/sizeof(OLECHAR)); - if (len == 0) { - rb_raise(rb_eRuntimeError, "failed to create GUID(buffer over)"); - } - return ole_wc2vstr(bstr, FALSE); -} - -/* - * WIN32OLE.ole_initialize and WIN32OLE.ole_uninitialize - * are used in win32ole.rb to fix the issue bug #2618 (ruby-core:27634). - * You must not use these method. - */ - -/* :nodoc: */ -static VALUE -fole_s_ole_initialize(VALUE self) -{ - ole_initialize(); - return Qnil; -} - -/* :nodoc: */ -static VALUE -fole_s_ole_uninitialize(VALUE self) -{ - ole_uninitialize(); - return Qnil; -} - -/* - * Document-class: WIN32OLE - * - * <code>WIN32OLE</code> objects represent OLE Automation object in Ruby. - * - * By using WIN32OLE, you can access OLE server like VBScript. - * - * Here is sample script. - * - * require 'win32ole' - * - * excel = WIN32OLE.new('Excel.Application') - * excel.visible = true - * workbook = excel.Workbooks.Add(); - * worksheet = workbook.Worksheets(1); - * worksheet.Range("A1:D1").value = ["North","South","East","West"]; - * worksheet.Range("A2:B2").value = [5.2, 10]; - * worksheet.Range("C2").value = 8; - * worksheet.Range("D2").value = 20; - * - * range = worksheet.Range("A1:D2"); - * range.select - * chart = workbook.Charts.Add; - * - * workbook.saved = true; - * - * excel.ActiveWorkbook.Close(0); - * excel.Quit(); - * - * Unfortunately, Win32OLE doesn't support the argument passed by - * reference directly. - * Instead, Win32OLE provides WIN32OLE::ARGV or WIN32OLE_VARIANT object. - * If you want to get the result value of argument passed by reference, - * you can use WIN32OLE::ARGV or WIN32OLE_VARIANT. - * - * oleobj.method(arg1, arg2, refargv3) - * puts WIN32OLE::ARGV[2] # the value of refargv3 after called oleobj.method - * - * or - * - * refargv3 = WIN32OLE_VARIANT.new(XXX, - * WIN32OLE::VARIANT::VT_BYREF|WIN32OLE::VARIANT::VT_XXX) - * oleobj.method(arg1, arg2, refargv3) - * p refargv3.value # the value of refargv3 after called oleobj.method. - * - */ - -/* - * call-seq: - * WIN32OLE.new(server, [host]) -> WIN32OLE object - * - * Returns a new WIN32OLE object(OLE Automation object). - * The first argument server specifies OLE Automation server. - * The first argument should be CLSID or PROGID. - * If second argument host specified, then returns OLE Automation - * object on host. - * - * WIN32OLE.new('Excel.Application') # => Excel OLE Automation WIN32OLE object. - * WIN32OLE.new('{00024500-0000-0000-C000-000000000046}') # => Excel OLE Automation WIN32OLE object. - */ -static VALUE -fole_initialize(int argc, VALUE *argv, VALUE self) -{ - VALUE svr_name; - VALUE host; - VALUE others; - HRESULT hr; - CLSID clsid; - OLECHAR *pBuf; - IDispatch *pDispatch; - void *p; - rb_call_super(0, 0); - rb_scan_args(argc, argv, "11*", &svr_name, &host, &others); - - StringValue(svr_name); - if (rb_safe_level() > 0 && OBJ_TAINTED(svr_name)) { - rb_raise(rb_eSecurityError, "insecure object creation - `%s'", - StringValuePtr(svr_name)); - } - if (!NIL_P(host)) { - StringValue(host); - if (rb_safe_level() > 0 && OBJ_TAINTED(host)) { - rb_raise(rb_eSecurityError, "insecure object creation - `%s'", - StringValuePtr(host)); - } - return ole_create_dcom(self, svr_name, host, others); - } - - /* get CLSID from OLE server name */ - pBuf = ole_vstr2wc(svr_name); - hr = CLSIDFromProgID(pBuf, &clsid); - if(FAILED(hr)) { - hr = CLSIDFromString(pBuf, &clsid); - } - SysFreeString(pBuf); - if(FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, - "unknown OLE server: `%s'", - StringValuePtr(svr_name)); - } - - /* get IDispatch interface */ - hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, - &IID_IDispatch, &p); - pDispatch = p; - if(FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, - "failed to create WIN32OLE object from `%s'", - StringValuePtr(svr_name)); - } - - ole_set_member(self, pDispatch); - return self; -} - -static int -hash2named_arg(VALUE key, VALUE val, VALUE pop) -{ - struct oleparam* pOp = (struct oleparam *)pop; - unsigned int index, i; - index = pOp->dp.cNamedArgs; - /*--------------------------------------------- - the data-type of key must be String or Symbol - -----------------------------------------------*/ - if(!RB_TYPE_P(key, T_STRING) && !RB_TYPE_P(key, T_SYMBOL)) { - /* clear name of dispatch parameters */ - for(i = 1; i < index + 1; i++) { - SysFreeString(pOp->pNamedArgs[i]); - } - /* clear dispatch parameters */ - for(i = 0; i < index; i++ ) { - VariantClear(&(pOp->dp.rgvarg[i])); - } - /* raise an exception */ - rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)"); - } - if (RB_TYPE_P(key, T_SYMBOL)) { - key = rb_sym_to_s(key); - } - - /* pNamedArgs[0] is <method name>, so "index + 1" */ - pOp->pNamedArgs[index + 1] = ole_vstr2wc(key); - - VariantInit(&(pOp->dp.rgvarg[index])); - ole_val2variant(val, &(pOp->dp.rgvarg[index])); - - pOp->dp.cNamedArgs += 1; - return ST_CONTINUE; -} - -static VALUE -set_argv(VARIANTARG* realargs, unsigned int beg, unsigned int end) -{ - VALUE argv = rb_const_get(cWIN32OLE, rb_intern("ARGV")); - - Check_Type(argv, T_ARRAY); - rb_ary_clear(argv); - while (end-- > beg) { - rb_ary_push(argv, ole_variant2val(&realargs[end])); - if (V_VT(&realargs[end]) != VT_RECORD) { - VariantClear(&realargs[end]); - } - } - return argv; -} - -static VALUE -ole_invoke(int argc, VALUE *argv, VALUE self, USHORT wFlags, BOOL is_bracket) -{ - LCID lcid = cWIN32OLE_lcid; - struct oledata *pole = NULL; - HRESULT hr; - VALUE cmd; - VALUE paramS; - VALUE param; - VALUE obj; - VALUE v; - - BSTR wcmdname; - - DISPID DispID; - DISPID* pDispID; - EXCEPINFO excepinfo; - VARIANT result; - VARIANTARG* realargs = NULL; - unsigned int argErr = 0; - unsigned int i; - unsigned int cNamedArgs; - int n; - struct oleparam op; - memset(&excepinfo, 0, sizeof(EXCEPINFO)); - - VariantInit(&result); - - op.dp.rgvarg = NULL; - op.dp.rgdispidNamedArgs = NULL; - op.dp.cNamedArgs = 0; - op.dp.cArgs = 0; - - rb_scan_args(argc, argv, "1*", &cmd, ¶mS); - if(!RB_TYPE_P(cmd, T_STRING) && !RB_TYPE_P(cmd, T_SYMBOL) && !is_bracket) { - rb_raise(rb_eTypeError, "method is wrong type (expected String or Symbol)"); - } - if (RB_TYPE_P(cmd, T_SYMBOL)) { - cmd = rb_sym_to_s(cmd); - } - pole = oledata_get_struct(self); - if(!pole->pDispatch) { - rb_raise(rb_eRuntimeError, "failed to get dispatch interface"); - } - if (is_bracket) { - DispID = DISPID_VALUE; - argc += 1; - rb_ary_unshift(paramS, cmd); - } else { - wcmdname = ole_vstr2wc(cmd); - hr = pole->pDispatch->lpVtbl->GetIDsOfNames( pole->pDispatch, &IID_NULL, - &wcmdname, 1, lcid, &DispID); - SysFreeString(wcmdname); - if(FAILED(hr)) { - ole_raise(hr, rb_eNoMethodError, - "unknown property or method: `%s'", - StringValuePtr(cmd)); - } - } - - /* pick up last argument of method */ - param = rb_ary_entry(paramS, argc-2); - - op.dp.cNamedArgs = 0; - - /* if last arg is hash object */ - if(RB_TYPE_P(param, T_HASH)) { - /*------------------------------------------ - hash object ==> named dispatch parameters - --------------------------------------------*/ - cNamedArgs = rb_long2int(RHASH_SIZE(param)); - op.dp.cArgs = cNamedArgs + argc - 2; - op.pNamedArgs = ALLOCA_N(OLECHAR*, cNamedArgs + 1); - op.dp.rgvarg = ALLOCA_N(VARIANTARG, op.dp.cArgs); - - rb_hash_foreach(param, hash2named_arg, (VALUE)&op); - - pDispID = ALLOCA_N(DISPID, cNamedArgs + 1); - op.pNamedArgs[0] = ole_vstr2wc(cmd); - hr = pole->pDispatch->lpVtbl->GetIDsOfNames(pole->pDispatch, - &IID_NULL, - op.pNamedArgs, - op.dp.cNamedArgs + 1, - lcid, pDispID); - for(i = 0; i < op.dp.cNamedArgs + 1; i++) { - SysFreeString(op.pNamedArgs[i]); - op.pNamedArgs[i] = NULL; - } - if(FAILED(hr)) { - /* clear dispatch parameters */ - for(i = 0; i < op.dp.cArgs; i++ ) { - VariantClear(&op.dp.rgvarg[i]); - } - ole_raise(hr, eWIN32OLERuntimeError, - "failed to get named argument info: `%s'", - StringValuePtr(cmd)); - } - op.dp.rgdispidNamedArgs = &(pDispID[1]); - } - else { - cNamedArgs = 0; - op.dp.cArgs = argc - 1; - op.pNamedArgs = ALLOCA_N(OLECHAR*, cNamedArgs + 1); - if (op.dp.cArgs > 0) { - op.dp.rgvarg = ALLOCA_N(VARIANTARG, op.dp.cArgs); - } - } - /*-------------------------------------- - non hash args ==> dispatch parameters - ----------------------------------------*/ - if(op.dp.cArgs > cNamedArgs) { - realargs = ALLOCA_N(VARIANTARG, op.dp.cArgs-cNamedArgs+1); - for(i = cNamedArgs; i < op.dp.cArgs; i++) { - n = op.dp.cArgs - i + cNamedArgs - 1; - VariantInit(&realargs[n]); - VariantInit(&op.dp.rgvarg[n]); - param = rb_ary_entry(paramS, i-cNamedArgs); - if (rb_obj_is_kind_of(param, cWIN32OLE_VARIANT)) { - ole_variant2variant(param, &op.dp.rgvarg[n]); - } else if (rb_obj_is_kind_of(param, cWIN32OLE_RECORD)) { - ole_val2variant(param, &realargs[n]); - op.dp.rgvarg[n] = realargs[n]; - V_VT(&op.dp.rgvarg[n]) = VT_RECORD | VT_BYREF; - } else { - ole_val2variant(param, &realargs[n]); - V_VT(&op.dp.rgvarg[n]) = VT_VARIANT | VT_BYREF; - V_VARIANTREF(&op.dp.rgvarg[n]) = &realargs[n]; - } - } - } - /* apparent you need to call propput, you need this */ - if (wFlags & DISPATCH_PROPERTYPUT) { - if (op.dp.cArgs == 0) - ole_raise(ResultFromScode(E_INVALIDARG), eWIN32OLERuntimeError, "argument error"); - - op.dp.cNamedArgs = 1; - op.dp.rgdispidNamedArgs = ALLOCA_N( DISPID, 1 ); - op.dp.rgdispidNamedArgs[0] = DISPID_PROPERTYPUT; - } - hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID, - &IID_NULL, lcid, wFlags, &op.dp, - &result, &excepinfo, &argErr); - - if (FAILED(hr)) { - /* retry to call args by value */ - if(op.dp.cArgs >= cNamedArgs) { - for(i = cNamedArgs; i < op.dp.cArgs; i++) { - n = op.dp.cArgs - i + cNamedArgs - 1; - param = rb_ary_entry(paramS, i-cNamedArgs); - ole_val2variant(param, &op.dp.rgvarg[n]); - } - if (hr == DISP_E_EXCEPTION) { - ole_freeexceptinfo(&excepinfo); - } - memset(&excepinfo, 0, sizeof(EXCEPINFO)); - VariantInit(&result); - hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID, - &IID_NULL, lcid, wFlags, - &op.dp, &result, - &excepinfo, &argErr); - - /* mega kludge. if a method in WORD is called and we ask - * for a result when one is not returned then - * hResult == DISP_E_EXCEPTION. this only happens on - * functions whose DISPID > 0x8000 */ - if ((hr == DISP_E_EXCEPTION || hr == DISP_E_MEMBERNOTFOUND) && DispID > 0x8000) { - if (hr == DISP_E_EXCEPTION) { - ole_freeexceptinfo(&excepinfo); - } - memset(&excepinfo, 0, sizeof(EXCEPINFO)); - hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID, - &IID_NULL, lcid, wFlags, - &op.dp, NULL, - &excepinfo, &argErr); - - } - for(i = cNamedArgs; i < op.dp.cArgs; i++) { - n = op.dp.cArgs - i + cNamedArgs - 1; - if (V_VT(&op.dp.rgvarg[n]) != VT_RECORD) { - VariantClear(&op.dp.rgvarg[n]); - } - } - } - - if (FAILED(hr)) { - /* retry after converting nil to VT_EMPTY */ - if (op.dp.cArgs > cNamedArgs) { - for(i = cNamedArgs; i < op.dp.cArgs; i++) { - n = op.dp.cArgs - i + cNamedArgs - 1; - param = rb_ary_entry(paramS, i-cNamedArgs); - ole_val2variant2(param, &op.dp.rgvarg[n]); - } - if (hr == DISP_E_EXCEPTION) { - ole_freeexceptinfo(&excepinfo); - } - memset(&excepinfo, 0, sizeof(EXCEPINFO)); - VariantInit(&result); - hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID, - &IID_NULL, lcid, wFlags, - &op.dp, &result, - &excepinfo, &argErr); - for(i = cNamedArgs; i < op.dp.cArgs; i++) { - n = op.dp.cArgs - i + cNamedArgs - 1; - if (V_VT(&op.dp.rgvarg[n]) != VT_RECORD) { - VariantClear(&op.dp.rgvarg[n]); - } - } - } - } - - } - /* clear dispatch parameter */ - if(op.dp.cArgs > cNamedArgs) { - for(i = cNamedArgs; i < op.dp.cArgs; i++) { - n = op.dp.cArgs - i + cNamedArgs - 1; - param = rb_ary_entry(paramS, i-cNamedArgs); - if (rb_obj_is_kind_of(param, cWIN32OLE_VARIANT)) { - ole_val2variant(param, &realargs[n]); - } else if ( rb_obj_is_kind_of(param, cWIN32OLE_RECORD) && - V_VT(&realargs[n]) == VT_RECORD ) { - olerecord_set_ivar(param, V_RECORDINFO(&realargs[n]), V_RECORD(&realargs[n])); - } - } - set_argv(realargs, cNamedArgs, op.dp.cArgs); - } - else { - for(i = 0; i < op.dp.cArgs; i++) { - VariantClear(&op.dp.rgvarg[i]); - } - } - - if (FAILED(hr)) { - v = ole_excepinfo2msg(&excepinfo); - ole_raise(hr, eWIN32OLERuntimeError, "(in OLE method `%s': )%s", - StringValuePtr(cmd), - StringValuePtr(v)); - } - obj = ole_variant2val(&result); - VariantClear(&result); - return obj; -} - -/* - * call-seq: - * WIN32OLE#invoke(method, [arg1,...]) => return value of method. - * - * Runs OLE method. - * The first argument specifies the method name of OLE Automation object. - * The others specify argument of the <i>method</i>. - * If you can not execute <i>method</i> directly, then use this method instead. - * - * excel = WIN32OLE.new('Excel.Application') - * excel.invoke('Quit') # => same as excel.Quit - * - */ -static VALUE -fole_invoke(int argc, VALUE *argv, VALUE self) -{ - return ole_invoke(argc, argv, self, DISPATCH_METHOD|DISPATCH_PROPERTYGET, FALSE); -} - -static VALUE -ole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types, USHORT dispkind) -{ - HRESULT hr; - struct oledata *pole = NULL; - unsigned int argErr = 0; - EXCEPINFO excepinfo; - VARIANT result; - DISPPARAMS dispParams; - VARIANTARG* realargs = NULL; - int i, j; - VALUE obj = Qnil; - VALUE tp, param; - VALUE v; - VARTYPE vt; - - Check_Type(args, T_ARRAY); - Check_Type(types, T_ARRAY); - - memset(&excepinfo, 0, sizeof(EXCEPINFO)); - memset(&dispParams, 0, sizeof(DISPPARAMS)); - VariantInit(&result); - pole = oledata_get_struct(self); - - dispParams.cArgs = RARRAY_LEN(args); - dispParams.rgvarg = ALLOCA_N(VARIANTARG, dispParams.cArgs); - realargs = ALLOCA_N(VARIANTARG, dispParams.cArgs); - for (i = 0, j = dispParams.cArgs - 1; i < (int)dispParams.cArgs; i++, j--) - { - VariantInit(&realargs[i]); - VariantInit(&dispParams.rgvarg[i]); - tp = rb_ary_entry(types, j); - vt = (VARTYPE)FIX2INT(tp); - V_VT(&dispParams.rgvarg[i]) = vt; - param = rb_ary_entry(args, j); - if (param == Qnil) - { - - V_VT(&dispParams.rgvarg[i]) = V_VT(&realargs[i]) = VT_ERROR; - V_ERROR(&dispParams.rgvarg[i]) = V_ERROR(&realargs[i]) = DISP_E_PARAMNOTFOUND; - } - else - { - if (vt & VT_ARRAY) - { - int ent; - LPBYTE pb; - short* ps; - LPLONG pl; - VARIANT* pv; - CY *py; - VARTYPE v; - SAFEARRAYBOUND rgsabound[1]; - Check_Type(param, T_ARRAY); - rgsabound[0].lLbound = 0; - rgsabound[0].cElements = RARRAY_LEN(param); - v = vt & ~(VT_ARRAY | VT_BYREF); - V_ARRAY(&realargs[i]) = SafeArrayCreate(v, 1, rgsabound); - V_VT(&realargs[i]) = VT_ARRAY | v; - SafeArrayLock(V_ARRAY(&realargs[i])); - pb = V_ARRAY(&realargs[i])->pvData; - ps = V_ARRAY(&realargs[i])->pvData; - pl = V_ARRAY(&realargs[i])->pvData; - py = V_ARRAY(&realargs[i])->pvData; - pv = V_ARRAY(&realargs[i])->pvData; - for (ent = 0; ent < (int)rgsabound[0].cElements; ent++) - { - VARIANT velem; - VALUE elem = rb_ary_entry(param, ent); - ole_val2variant(elem, &velem); - if (v != VT_VARIANT) - { - VariantChangeTypeEx(&velem, &velem, - cWIN32OLE_lcid, 0, v); - } - switch (v) - { - /* 128 bits */ - case VT_VARIANT: - *pv++ = velem; - break; - /* 64 bits */ - case VT_R8: - case VT_CY: - case VT_DATE: - *py++ = V_CY(&velem); - break; - /* 16 bits */ - case VT_BOOL: - case VT_I2: - case VT_UI2: - *ps++ = V_I2(&velem); - break; - /* 8 bites */ - case VT_UI1: - case VT_I1: - *pb++ = V_UI1(&velem); - break; - /* 32 bits */ - default: - *pl++ = V_I4(&velem); - break; - } - } - SafeArrayUnlock(V_ARRAY(&realargs[i])); - } - else - { - ole_val2variant(param, &realargs[i]); - if ((vt & (~VT_BYREF)) != VT_VARIANT) - { - hr = VariantChangeTypeEx(&realargs[i], &realargs[i], - cWIN32OLE_lcid, 0, - (VARTYPE)(vt & (~VT_BYREF))); - if (hr != S_OK) - { - rb_raise(rb_eTypeError, "not valid value"); - } - } - } - if ((vt & VT_BYREF) || vt == VT_VARIANT) - { - if (vt == VT_VARIANT) - V_VT(&dispParams.rgvarg[i]) = VT_VARIANT | VT_BYREF; - switch (vt & (~VT_BYREF)) - { - /* 128 bits */ - case VT_VARIANT: - V_VARIANTREF(&dispParams.rgvarg[i]) = &realargs[i]; - break; - /* 64 bits */ - case VT_R8: - case VT_CY: - case VT_DATE: - V_CYREF(&dispParams.rgvarg[i]) = &V_CY(&realargs[i]); - break; - /* 16 bits */ - case VT_BOOL: - case VT_I2: - case VT_UI2: - V_I2REF(&dispParams.rgvarg[i]) = &V_I2(&realargs[i]); - break; - /* 8 bites */ - case VT_UI1: - case VT_I1: - V_UI1REF(&dispParams.rgvarg[i]) = &V_UI1(&realargs[i]); - break; - /* 32 bits */ - default: - V_I4REF(&dispParams.rgvarg[i]) = &V_I4(&realargs[i]); - break; - } - } - else - { - /* copy 64 bits of data */ - V_CY(&dispParams.rgvarg[i]) = V_CY(&realargs[i]); - } - } - } - - if (dispkind & DISPATCH_PROPERTYPUT) { - dispParams.cNamedArgs = 1; - dispParams.rgdispidNamedArgs = ALLOCA_N( DISPID, 1 ); - dispParams.rgdispidNamedArgs[0] = DISPID_PROPERTYPUT; - } - - hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, NUM2INT(dispid), - &IID_NULL, cWIN32OLE_lcid, - dispkind, - &dispParams, &result, - &excepinfo, &argErr); - - if (FAILED(hr)) { - v = ole_excepinfo2msg(&excepinfo); - ole_raise(hr, eWIN32OLERuntimeError, "(in OLE method `<dispatch id:%d>': )%s", - NUM2INT(dispid), - StringValuePtr(v)); - } - - /* clear dispatch parameter */ - if(dispParams.cArgs > 0) { - set_argv(realargs, 0, dispParams.cArgs); - } - - obj = ole_variant2val(&result); - VariantClear(&result); - return obj; -} - -/* - * call-seq: - * WIN32OLE#_invoke(dispid, args, types) - * - * Runs the early binding method. - * The 1st argument specifies dispatch ID, - * the 2nd argument specifies the array of arguments, - * the 3rd argument specifies the array of the type of arguments. - * - * excel = WIN32OLE.new('Excel.Application') - * excel._invoke(302, [], []) # same effect as excel.Quit - */ -static VALUE -fole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types) -{ - return ole_invoke2(self, dispid, args, types, DISPATCH_METHOD); -} - -/* - * call-seq: - * WIN32OLE#_getproperty(dispid, args, types) - * - * Runs the early binding method to get property. - * The 1st argument specifies dispatch ID, - * the 2nd argument specifies the array of arguments, - * the 3rd argument specifies the array of the type of arguments. - * - * excel = WIN32OLE.new('Excel.Application') - * puts excel._getproperty(558, [], []) # same effect as puts excel.visible - */ -static VALUE -fole_getproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types) -{ - return ole_invoke2(self, dispid, args, types, DISPATCH_PROPERTYGET); -} - -/* - * call-seq: - * WIN32OLE#_setproperty(dispid, args, types) - * - * Runs the early binding method to set property. - * The 1st argument specifies dispatch ID, - * the 2nd argument specifies the array of arguments, - * the 3rd argument specifies the array of the type of arguments. - * - * excel = WIN32OLE.new('Excel.Application') - * excel._setproperty(558, [true], [WIN32OLE::VARIANT::VT_BOOL]) # same effect as excel.visible = true - */ -static VALUE -fole_setproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types) -{ - return ole_invoke2(self, dispid, args, types, DISPATCH_PROPERTYPUT); -} - -/* - * call-seq: - * WIN32OLE[a1, a2, ...]=val - * - * Sets the value to WIN32OLE object specified by a1, a2, ... - * - * dict = WIN32OLE.new('Scripting.Dictionary') - * dict.add('ruby', 'RUBY') - * dict['ruby'] = 'Ruby' - * puts dict['ruby'] # => 'Ruby' - * - * Remark: You can not use this method to set the property value. - * - * excel = WIN32OLE.new('Excel.Application') - * # excel['Visible'] = true # This is error !!! - * excel.Visible = true # You should to use this style to set the property. - * - */ -static VALUE -fole_setproperty_with_bracket(int argc, VALUE *argv, VALUE self) -{ - return ole_invoke(argc, argv, self, DISPATCH_PROPERTYPUT, TRUE); -} - -/* - * call-seq: - * WIN32OLE.setproperty('property', [arg1, arg2,...] val) - * - * Sets property of OLE object. - * When you want to set property with argument, you can use this method. - * - * excel = WIN32OLE.new('Excel.Application') - * excel.Visible = true - * book = excel.workbooks.add - * sheet = book.worksheets(1) - * sheet.setproperty('Cells', 1, 2, 10) # => The B1 cell value is 10. - */ -static VALUE -fole_setproperty(int argc, VALUE *argv, VALUE self) -{ - return ole_invoke(argc, argv, self, DISPATCH_PROPERTYPUT, FALSE); -} - -/* - * call-seq: - * WIN32OLE[a1,a2,...] - * - * Returns the value of Collection specified by a1, a2,.... - * - * dict = WIN32OLE.new('Scripting.Dictionary') - * dict.add('ruby', 'Ruby') - * puts dict['ruby'] # => 'Ruby' (same as `puts dict.item('ruby')') - * - * Remark: You can not use this method to get the property. - * excel = WIN32OLE.new('Excel.Application') - * # puts excel['Visible'] This is error !!! - * puts excel.Visible # You should to use this style to get the property. - * - */ -static VALUE -fole_getproperty_with_bracket(int argc, VALUE *argv, VALUE self) -{ - return ole_invoke(argc, argv, self, DISPATCH_PROPERTYGET, TRUE); -} - -static VALUE -ole_propertyput(VALUE self, VALUE property, VALUE value) -{ - struct oledata *pole = NULL; - unsigned argErr; - unsigned int index; - HRESULT hr; - EXCEPINFO excepinfo; - DISPID dispID = DISPID_VALUE; - DISPID dispIDParam = DISPID_PROPERTYPUT; - USHORT wFlags = DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF; - DISPPARAMS dispParams; - VARIANTARG propertyValue[2]; - OLECHAR* pBuf[1]; - VALUE v; - LCID lcid = cWIN32OLE_lcid; - dispParams.rgdispidNamedArgs = &dispIDParam; - dispParams.rgvarg = propertyValue; - dispParams.cNamedArgs = 1; - dispParams.cArgs = 1; - - VariantInit(&propertyValue[0]); - VariantInit(&propertyValue[1]); - memset(&excepinfo, 0, sizeof(excepinfo)); - - pole = oledata_get_struct(self); - - /* get ID from property name */ - pBuf[0] = ole_vstr2wc(property); - hr = pole->pDispatch->lpVtbl->GetIDsOfNames(pole->pDispatch, &IID_NULL, - pBuf, 1, lcid, &dispID); - SysFreeString(pBuf[0]); - pBuf[0] = NULL; - - if(FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, - "unknown property or method: `%s'", - StringValuePtr(property)); - } - /* set property value */ - ole_val2variant(value, &propertyValue[0]); - hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, dispID, &IID_NULL, - lcid, wFlags, &dispParams, - NULL, &excepinfo, &argErr); - - for(index = 0; index < dispParams.cArgs; ++index) { - VariantClear(&propertyValue[index]); - } - if (FAILED(hr)) { - v = ole_excepinfo2msg(&excepinfo); - ole_raise(hr, eWIN32OLERuntimeError, "(in setting property `%s': )%s", - StringValuePtr(property), - StringValuePtr(v)); - } - return Qnil; -} - -/* - * call-seq: - * WIN32OLE#ole_free - * - * invokes Release method of Dispatch interface of WIN32OLE object. - * Usually, you do not need to call this method because Release method - * called automatically when WIN32OLE object garbaged. - * - */ -static VALUE -fole_free(VALUE self) -{ - struct oledata *pole = NULL; - pole = oledata_get_struct(self); - OLE_FREE(pole->pDispatch); - pole->pDispatch = NULL; - return Qnil; -} - -static VALUE -ole_each_sub(VALUE pEnumV) -{ - VARIANT variant; - VALUE obj = Qnil; - IEnumVARIANT *pEnum = (IEnumVARIANT *)pEnumV; - VariantInit(&variant); - while(pEnum->lpVtbl->Next(pEnum, 1, &variant, NULL) == S_OK) { - obj = ole_variant2val(&variant); - VariantClear(&variant); - VariantInit(&variant); - rb_yield(obj); - } - return Qnil; -} - -static VALUE -ole_ienum_free(VALUE pEnumV) -{ - IEnumVARIANT *pEnum = (IEnumVARIANT *)pEnumV; - OLE_RELEASE(pEnum); - return Qnil; -} - -/* - * call-seq: - * WIN32OLE#each {|i|...} - * - * Iterates over each item of OLE collection which has IEnumVARIANT interface. - * - * excel = WIN32OLE.new('Excel.Application') - * book = excel.workbooks.add - * sheets = book.worksheets(1) - * cells = sheets.cells("A1:A5") - * cells.each do |cell| - * cell.value = 10 - * end - */ -static VALUE -fole_each(VALUE self) -{ - LCID lcid = cWIN32OLE_lcid; - - struct oledata *pole = NULL; - - unsigned int argErr; - EXCEPINFO excepinfo; - DISPPARAMS dispParams; - VARIANT result; - HRESULT hr; - IEnumVARIANT *pEnum = NULL; - void *p; - - RETURN_ENUMERATOR(self, 0, 0); - - VariantInit(&result); - dispParams.rgvarg = NULL; - dispParams.rgdispidNamedArgs = NULL; - dispParams.cNamedArgs = 0; - dispParams.cArgs = 0; - memset(&excepinfo, 0, sizeof(excepinfo)); - - pole = oledata_get_struct(self); - hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DISPID_NEWENUM, - &IID_NULL, lcid, - DISPATCH_METHOD | DISPATCH_PROPERTYGET, - &dispParams, &result, - &excepinfo, &argErr); - - if (FAILED(hr)) { - VariantClear(&result); - ole_raise(hr, eWIN32OLERuntimeError, "failed to get IEnum Interface"); - } - - if (V_VT(&result) == VT_UNKNOWN) { - hr = V_UNKNOWN(&result)->lpVtbl->QueryInterface(V_UNKNOWN(&result), - &IID_IEnumVARIANT, - &p); - pEnum = p; - } else if (V_VT(&result) == VT_DISPATCH) { - hr = V_DISPATCH(&result)->lpVtbl->QueryInterface(V_DISPATCH(&result), - &IID_IEnumVARIANT, - &p); - pEnum = p; - } - if (FAILED(hr) || !pEnum) { - VariantClear(&result); - ole_raise(hr, rb_eRuntimeError, "failed to get IEnum Interface"); - } - - VariantClear(&result); - rb_ensure(ole_each_sub, (VALUE)pEnum, ole_ienum_free, (VALUE)pEnum); - return Qnil; -} - -/* - * call-seq: - * WIN32OLE#method_missing(id [,arg1, arg2, ...]) - * - * Calls WIN32OLE#invoke method. - */ -static VALUE -fole_missing(int argc, VALUE *argv, VALUE self) -{ - ID id; - const char* mname; - size_t n; - rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); - id = rb_to_id(argv[0]); - mname = rb_id2name(id); - if(!mname) { - rb_raise(rb_eRuntimeError, "fail: unknown method or property"); - } - n = strlen(mname); -#if SIZEOF_SIZE_T > SIZEOF_LONG - if (n >= LONG_MAX) { - rb_raise(rb_eRuntimeError, "too long method or property name"); - } -#endif - if(mname[n-1] == '=') { - rb_check_arity(argc, 2, 2); - argv[0] = rb_enc_str_new(mname, (long)(n-1), cWIN32OLE_enc); - - return ole_propertyput(self, argv[0], argv[1]); - } - else { - argv[0] = rb_enc_str_new(mname, (long)n, cWIN32OLE_enc); - return ole_invoke(argc, argv, self, DISPATCH_METHOD|DISPATCH_PROPERTYGET, FALSE); - } -} - -static HRESULT -typeinfo_from_ole(struct oledata *pole, ITypeInfo **ppti) -{ - ITypeInfo *pTypeInfo; - ITypeLib *pTypeLib; - BSTR bstr; - VALUE type; - UINT i; - UINT count; - LCID lcid = cWIN32OLE_lcid; - HRESULT hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch, - 0, lcid, &pTypeInfo); - if(FAILED(hr)) { - ole_raise(hr, rb_eRuntimeError, "failed to GetTypeInfo"); - } - hr = pTypeInfo->lpVtbl->GetDocumentation(pTypeInfo, - -1, - &bstr, - NULL, NULL, NULL); - type = WC2VSTR(bstr); - hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &i); - OLE_RELEASE(pTypeInfo); - if (FAILED(hr)) { - ole_raise(hr, rb_eRuntimeError, "failed to GetContainingTypeLib"); - } - count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib); - for (i = 0; i < count; i++) { - hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i, - &bstr, NULL, NULL, NULL); - if (SUCCEEDED(hr) && rb_str_cmp(WC2VSTR(bstr), type) == 0) { - hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, i, &pTypeInfo); - if (SUCCEEDED(hr)) { - *ppti = pTypeInfo; - break; - } - } - } - OLE_RELEASE(pTypeLib); - return hr; -} - -static VALUE -ole_methods(VALUE self, int mask) -{ - ITypeInfo *pTypeInfo; - HRESULT hr; - VALUE methods; - struct oledata *pole = NULL; - - pole = oledata_get_struct(self); - methods = rb_ary_new(); - - hr = typeinfo_from_ole(pole, &pTypeInfo); - if(FAILED(hr)) - return methods; - rb_ary_concat(methods, ole_methods_from_typeinfo(pTypeInfo, mask)); - OLE_RELEASE(pTypeInfo); - return methods; -} - -/* - * call-seq: - * WIN32OLE#ole_methods - * - * Returns the array of WIN32OLE_METHOD object. - * The element is OLE method of WIN32OLE object. - * - * excel = WIN32OLE.new('Excel.Application') - * methods = excel.ole_methods - * - */ -static VALUE -fole_methods(VALUE self) -{ - return ole_methods( self, INVOKE_FUNC | INVOKE_PROPERTYGET | INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF); -} - -/* - * call-seq: - * WIN32OLE#ole_get_methods - * - * Returns the array of WIN32OLE_METHOD object . - * The element of the array is property (gettable) of WIN32OLE object. - * - * excel = WIN32OLE.new('Excel.Application') - * properties = excel.ole_get_methods - */ -static VALUE -fole_get_methods(VALUE self) -{ - return ole_methods( self, INVOKE_PROPERTYGET); -} - -/* - * call-seq: - * WIN32OLE#ole_put_methods - * - * Returns the array of WIN32OLE_METHOD object . - * The element of the array is property (settable) of WIN32OLE object. - * - * excel = WIN32OLE.new('Excel.Application') - * properties = excel.ole_put_methods - */ -static VALUE -fole_put_methods(VALUE self) -{ - return ole_methods( self, INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF); -} - -/* - * call-seq: - * WIN32OLE#ole_func_methods - * - * Returns the array of WIN32OLE_METHOD object . - * The element of the array is property (settable) of WIN32OLE object. - * - * excel = WIN32OLE.new('Excel.Application') - * properties = excel.ole_func_methods - * - */ -static VALUE -fole_func_methods(VALUE self) -{ - return ole_methods( self, INVOKE_FUNC); -} - -/* - * call-seq: - * WIN32OLE#ole_type - * - * Returns WIN32OLE_TYPE object. - * - * excel = WIN32OLE.new('Excel.Application') - * tobj = excel.ole_type - */ -static VALUE -fole_type(VALUE self) -{ - ITypeInfo *pTypeInfo; - HRESULT hr; - struct oledata *pole = NULL; - LCID lcid = cWIN32OLE_lcid; - VALUE type = Qnil; - - pole = oledata_get_struct(self); - - hr = pole->pDispatch->lpVtbl->GetTypeInfo( pole->pDispatch, 0, lcid, &pTypeInfo ); - if(FAILED(hr)) { - ole_raise(hr, rb_eRuntimeError, "failed to GetTypeInfo"); - } - type = ole_type_from_itypeinfo(pTypeInfo); - OLE_RELEASE(pTypeInfo); - if (type == Qnil) { - rb_raise(rb_eRuntimeError, "failed to create WIN32OLE_TYPE obj from ITypeInfo"); - } - return type; -} - -/* - * call-seq: - * WIN32OLE#ole_typelib -> The WIN32OLE_TYPELIB object - * - * Returns the WIN32OLE_TYPELIB object. The object represents the - * type library which contains the WIN32OLE object. - * - * excel = WIN32OLE.new('Excel.Application') - * tlib = excel.ole_typelib - * puts tlib.name # -> 'Microsoft Excel 9.0 Object Library' - */ -static VALUE -fole_typelib(VALUE self) -{ - struct oledata *pole = NULL; - HRESULT hr; - ITypeInfo *pTypeInfo; - LCID lcid = cWIN32OLE_lcid; - VALUE vtlib = Qnil; - - pole = oledata_get_struct(self); - hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch, - 0, lcid, &pTypeInfo); - if(FAILED(hr)) { - ole_raise(hr, rb_eRuntimeError, "failed to GetTypeInfo"); - } - vtlib = ole_typelib_from_itypeinfo(pTypeInfo); - OLE_RELEASE(pTypeInfo); - if (vtlib == Qnil) { - rb_raise(rb_eRuntimeError, "failed to get type library info."); - } - return vtlib; -} - -/* - * call-seq: - * WIN32OLE#ole_query_interface(iid) -> WIN32OLE object - * - * Returns WIN32OLE object for a specific dispatch or dual - * interface specified by iid. - * - * ie = WIN32OLE.new('InternetExplorer.Application') - * ie_web_app = ie.ole_query_interface('{0002DF05-0000-0000-C000-000000000046}') # => WIN32OLE object for dispinterface IWebBrowserApp - */ -static VALUE -fole_query_interface(VALUE self, VALUE str_iid) -{ - HRESULT hr; - OLECHAR *pBuf; - IID iid; - struct oledata *pole = NULL; - IDispatch *pDispatch; - void *p; - - pBuf = ole_vstr2wc(str_iid); - hr = CLSIDFromString(pBuf, &iid); - SysFreeString(pBuf); - if(FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, - "invalid iid: `%s'", - StringValuePtr(str_iid)); - } - - pole = oledata_get_struct(self); - if(!pole->pDispatch) { - rb_raise(rb_eRuntimeError, "failed to get dispatch interface"); - } - - hr = pole->pDispatch->lpVtbl->QueryInterface(pole->pDispatch, &iid, - &p); - if(FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, - "failed to get interface `%s'", - StringValuePtr(str_iid)); - } - - pDispatch = p; - return create_win32ole_object(cWIN32OLE, pDispatch, 0, 0); -} - -/* - * call-seq: - * WIN32OLE#ole_respond_to?(method) -> true or false - * - * Returns true when OLE object has OLE method, otherwise returns false. - * - * ie = WIN32OLE.new('InternetExplorer.Application') - * ie.ole_respond_to?("gohome") => true - */ -static VALUE -fole_respond_to(VALUE self, VALUE method) -{ - struct oledata *pole = NULL; - BSTR wcmdname; - DISPID DispID; - HRESULT hr; - if(!RB_TYPE_P(method, T_STRING) && !RB_TYPE_P(method, T_SYMBOL)) { - rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)"); - } - if (RB_TYPE_P(method, T_SYMBOL)) { - method = rb_sym_to_s(method); - } - pole = oledata_get_struct(self); - wcmdname = ole_vstr2wc(method); - hr = pole->pDispatch->lpVtbl->GetIDsOfNames( pole->pDispatch, &IID_NULL, - &wcmdname, 1, cWIN32OLE_lcid, &DispID); - SysFreeString(wcmdname); - return SUCCEEDED(hr) ? Qtrue : Qfalse; -} - -HRESULT -ole_docinfo_from_type(ITypeInfo *pTypeInfo, BSTR *name, BSTR *helpstr, DWORD *helpcontext, BSTR *helpfile) -{ - HRESULT hr; - ITypeLib *pTypeLib; - UINT i; - - hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &i); - if (FAILED(hr)) { - return hr; - } - - hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i, - name, helpstr, - helpcontext, helpfile); - if (FAILED(hr)) { - OLE_RELEASE(pTypeLib); - return hr; - } - OLE_RELEASE(pTypeLib); - return hr; -} - -static VALUE -ole_usertype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails) -{ - HRESULT hr; - BSTR bstr; - ITypeInfo *pRefTypeInfo; - VALUE type = Qnil; - - hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo, - V_UNION1(pTypeDesc, hreftype), - &pRefTypeInfo); - if(FAILED(hr)) - return Qnil; - hr = ole_docinfo_from_type(pRefTypeInfo, &bstr, NULL, NULL, NULL); - if(FAILED(hr)) { - OLE_RELEASE(pRefTypeInfo); - return Qnil; - } - OLE_RELEASE(pRefTypeInfo); - type = WC2VSTR(bstr); - if(typedetails != Qnil) - rb_ary_push(typedetails, type); - return type; -} - -static VALUE -ole_ptrtype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails) -{ - TYPEDESC *p = pTypeDesc; - VALUE type = rb_str_new2(""); - - if (p->vt == VT_PTR || p->vt == VT_SAFEARRAY) { - p = V_UNION1(p, lptdesc); - type = ole_typedesc2val(pTypeInfo, p, typedetails); - } - return type; -} - -VALUE -ole_typedesc2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails) -{ - VALUE str; - VALUE typestr = Qnil; - switch(pTypeDesc->vt) { - case VT_I2: - typestr = rb_str_new2("I2"); - break; - case VT_I4: - typestr = rb_str_new2("I4"); - break; - case VT_R4: - typestr = rb_str_new2("R4"); - break; - case VT_R8: - typestr = rb_str_new2("R8"); - break; - case VT_CY: - typestr = rb_str_new2("CY"); - break; - case VT_DATE: - typestr = rb_str_new2("DATE"); - break; - case VT_BSTR: - typestr = rb_str_new2("BSTR"); - break; - case VT_BOOL: - typestr = rb_str_new2("BOOL"); - break; - case VT_VARIANT: - typestr = rb_str_new2("VARIANT"); - break; - case VT_DECIMAL: - typestr = rb_str_new2("DECIMAL"); - break; - case VT_I1: - typestr = rb_str_new2("I1"); - break; - case VT_UI1: - typestr = rb_str_new2("UI1"); - break; - case VT_UI2: - typestr = rb_str_new2("UI2"); - break; - case VT_UI4: - typestr = rb_str_new2("UI4"); - break; -#if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__) - case VT_I8: - typestr = rb_str_new2("I8"); - break; - case VT_UI8: - typestr = rb_str_new2("UI8"); - break; -#endif - case VT_INT: - typestr = rb_str_new2("INT"); - break; - case VT_UINT: - typestr = rb_str_new2("UINT"); - break; - case VT_VOID: - typestr = rb_str_new2("VOID"); - break; - case VT_HRESULT: - typestr = rb_str_new2("HRESULT"); - break; - case VT_PTR: - typestr = rb_str_new2("PTR"); - if(typedetails != Qnil) - rb_ary_push(typedetails, typestr); - return ole_ptrtype2val(pTypeInfo, pTypeDesc, typedetails); - case VT_SAFEARRAY: - typestr = rb_str_new2("SAFEARRAY"); - if(typedetails != Qnil) - rb_ary_push(typedetails, typestr); - return ole_ptrtype2val(pTypeInfo, pTypeDesc, typedetails); - case VT_CARRAY: - typestr = rb_str_new2("CARRAY"); - break; - case VT_USERDEFINED: - typestr = rb_str_new2("USERDEFINED"); - if (typedetails != Qnil) - rb_ary_push(typedetails, typestr); - str = ole_usertype2val(pTypeInfo, pTypeDesc, typedetails); - if (str != Qnil) { - return str; - } - return typestr; - case VT_UNKNOWN: - typestr = rb_str_new2("UNKNOWN"); - break; - case VT_DISPATCH: - typestr = rb_str_new2("DISPATCH"); - break; - case VT_ERROR: - typestr = rb_str_new2("ERROR"); - break; - case VT_LPWSTR: - typestr = rb_str_new2("LPWSTR"); - break; - case VT_LPSTR: - typestr = rb_str_new2("LPSTR"); - break; - case VT_RECORD: - typestr = rb_str_new2("RECORD"); - break; - default: - typestr = rb_str_new2("Unknown Type "); - rb_str_concat(typestr, rb_fix2str(INT2FIX(pTypeDesc->vt), 10)); - break; - } - if (typedetails != Qnil) - rb_ary_push(typedetails, typestr); - return typestr; -} - -/* - * call-seq: - * WIN32OLE#ole_method_help(method) - * - * Returns WIN32OLE_METHOD object corresponding with method - * specified by 1st argument. - * - * excel = WIN32OLE.new('Excel.Application') - * method = excel.ole_method_help('Quit') - * - */ -static VALUE -fole_method_help(VALUE self, VALUE cmdname) -{ - ITypeInfo *pTypeInfo; - HRESULT hr; - struct oledata *pole = NULL; - VALUE obj; - - SafeStringValue(cmdname); - pole = oledata_get_struct(self); - hr = typeinfo_from_ole(pole, &pTypeInfo); - if(FAILED(hr)) - ole_raise(hr, rb_eRuntimeError, "failed to get ITypeInfo"); - - obj = create_win32ole_method(pTypeInfo, cmdname); - - OLE_RELEASE(pTypeInfo); - if (obj == Qnil) - rb_raise(eWIN32OLERuntimeError, "not found %s", - StringValuePtr(cmdname)); - return obj; -} - -/* - * call-seq: - * WIN32OLE#ole_activex_initialize() -> Qnil - * - * Initialize WIN32OLE object(ActiveX Control) by calling - * IPersistMemory::InitNew. - * - * Before calling OLE method, some kind of the ActiveX controls - * created with MFC should be initialized by calling - * IPersistXXX::InitNew. - * - * If and only if you received the exception "HRESULT error code: - * 0x8000ffff catastrophic failure", try this method before - * invoking any ole_method. - * - * obj = WIN32OLE.new("ProgID_or_GUID_of_ActiveX_Control") - * obj.ole_activex_initialize - * obj.method(...) - * - */ -static VALUE -fole_activex_initialize(VALUE self) -{ - struct oledata *pole = NULL; - IPersistMemory *pPersistMemory; - void *p; - - HRESULT hr = S_OK; - - pole = oledata_get_struct(self); - - hr = pole->pDispatch->lpVtbl->QueryInterface(pole->pDispatch, &IID_IPersistMemory, &p); - pPersistMemory = p; - if (SUCCEEDED(hr)) { - hr = pPersistMemory->lpVtbl->InitNew(pPersistMemory); - OLE_RELEASE(pPersistMemory); - if (SUCCEEDED(hr)) { - return Qnil; - } - } - - if (FAILED(hr)) { - ole_raise(hr, eWIN32OLERuntimeError, "fail to initialize ActiveX control"); - } - - return Qnil; -} - -HRESULT -typelib_from_val(VALUE obj, ITypeLib **pTypeLib) -{ - LCID lcid = cWIN32OLE_lcid; - HRESULT hr; - struct oledata *pole = NULL; - unsigned int index; - ITypeInfo *pTypeInfo; - pole = oledata_get_struct(obj); - hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch, - 0, lcid, &pTypeInfo); - if (FAILED(hr)) { - return hr; - } - hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, pTypeLib, &index); - OLE_RELEASE(pTypeInfo); - return hr; -} - -static void -com_hash_free(void *ptr) -{ - st_table *tbl = ptr; - st_free_table(tbl); -} - -static void -com_hash_mark(void *ptr) -{ - st_table *tbl = ptr; - rb_mark_hash(tbl); -} - -static size_t -com_hash_size(const void *ptr) -{ - const st_table *tbl = ptr; - return tbl ? st_memsize(tbl) : 0; -} - -void -Init_win32ole(void) -{ - cWIN32OLE_lcid = LOCALE_SYSTEM_DEFAULT; - g_ole_initialized_init(); - - com_vtbl.QueryInterface = QueryInterface; - com_vtbl.AddRef = AddRef; - com_vtbl.Release = Release; - com_vtbl.GetTypeInfoCount = GetTypeInfoCount; - com_vtbl.GetTypeInfo = GetTypeInfo; - com_vtbl.GetIDsOfNames = GetIDsOfNames; - com_vtbl.Invoke = Invoke; - - message_filter.QueryInterface = mf_QueryInterface; - message_filter.AddRef = mf_AddRef; - message_filter.Release = mf_Release; - message_filter.HandleInComingCall = mf_HandleInComingCall; - message_filter.RetryRejectedCall = mf_RetryRejectedCall; - message_filter.MessagePending = mf_MessagePending; - - enc2cp_hash = TypedData_Wrap_Struct(rb_cData, &win32ole_hash_datatype, st_init_numtable()); - rb_gc_register_mark_object(enc2cp_hash); - - com_hash = TypedData_Wrap_Struct(rb_cData, &win32ole_hash_datatype, st_init_numtable()); - rb_gc_register_mark_object(com_hash); - - cWIN32OLE = rb_define_class("WIN32OLE", rb_cObject); - - rb_define_alloc_func(cWIN32OLE, fole_s_allocate); - - rb_define_method(cWIN32OLE, "initialize", fole_initialize, -1); - - rb_define_singleton_method(cWIN32OLE, "connect", fole_s_connect, -1); - rb_define_singleton_method(cWIN32OLE, "const_load", fole_s_const_load, -1); - - rb_define_singleton_method(cWIN32OLE, "ole_free", fole_s_free, 1); - rb_define_singleton_method(cWIN32OLE, "ole_reference_count", fole_s_reference_count, 1); - rb_define_singleton_method(cWIN32OLE, "ole_show_help", fole_s_show_help, -1); - rb_define_singleton_method(cWIN32OLE, "codepage", fole_s_get_code_page, 0); - rb_define_singleton_method(cWIN32OLE, "codepage=", fole_s_set_code_page, 1); - rb_define_singleton_method(cWIN32OLE, "locale", fole_s_get_locale, 0); - rb_define_singleton_method(cWIN32OLE, "locale=", fole_s_set_locale, 1); - rb_define_singleton_method(cWIN32OLE, "create_guid", fole_s_create_guid, 0); - rb_define_singleton_method(cWIN32OLE, "ole_initialize", fole_s_ole_initialize, 0); - rb_define_singleton_method(cWIN32OLE, "ole_uninitialize", fole_s_ole_uninitialize, 0); - - rb_define_method(cWIN32OLE, "invoke", fole_invoke, -1); - rb_define_method(cWIN32OLE, "[]", fole_getproperty_with_bracket, -1); - rb_define_method(cWIN32OLE, "_invoke", fole_invoke2, 3); - rb_define_method(cWIN32OLE, "_getproperty", fole_getproperty2, 3); - rb_define_method(cWIN32OLE, "_setproperty", fole_setproperty2, 3); - - /* support propput method that takes an argument */ - rb_define_method(cWIN32OLE, "[]=", fole_setproperty_with_bracket, -1); - - rb_define_method(cWIN32OLE, "ole_free", fole_free, 0); - - rb_define_method(cWIN32OLE, "each", fole_each, 0); - rb_define_method(cWIN32OLE, "method_missing", fole_missing, -1); - - /* support setproperty method much like Perl ;-) */ - rb_define_method(cWIN32OLE, "setproperty", fole_setproperty, -1); - - rb_define_method(cWIN32OLE, "ole_methods", fole_methods, 0); - rb_define_method(cWIN32OLE, "ole_get_methods", fole_get_methods, 0); - rb_define_method(cWIN32OLE, "ole_put_methods", fole_put_methods, 0); - rb_define_method(cWIN32OLE, "ole_func_methods", fole_func_methods, 0); - - rb_define_method(cWIN32OLE, "ole_method", fole_method_help, 1); - rb_define_alias(cWIN32OLE, "ole_method_help", "ole_method"); - rb_define_method(cWIN32OLE, "ole_activex_initialize", fole_activex_initialize, 0); - rb_define_method(cWIN32OLE, "ole_type", fole_type, 0); - rb_define_alias(cWIN32OLE, "ole_obj_help", "ole_type"); - rb_define_method(cWIN32OLE, "ole_typelib", fole_typelib, 0); - rb_define_method(cWIN32OLE, "ole_query_interface", fole_query_interface, 1); - rb_define_method(cWIN32OLE, "ole_respond_to?", fole_respond_to, 1); - - /* Constants definition */ - - /* - * Version string of WIN32OLE. - */ - rb_define_const(cWIN32OLE, "VERSION", rb_str_new2(WIN32OLE_VERSION)); - - /* - * After invoking OLE methods with reference arguments, you can access - * the value of arguments by using ARGV. - * - * If the method of OLE(COM) server written by C#.NET is following: - * - * void calcsum(int a, int b, out int c) { - * c = a + b; - * } - * - * then, the Ruby OLE(COM) client script to retrieve the value of - * argument c after invoking calcsum method is following: - * - * a = 10 - * b = 20 - * c = 0 - * comserver.calcsum(a, b, c) - * p c # => 0 - * p WIN32OLE::ARGV # => [10, 20, 30] - * - * You can use WIN32OLE_VARIANT object to retrieve the value of reference - * arguments instead of refering WIN32OLE::ARGV. - * - */ - rb_define_const(cWIN32OLE, "ARGV", rb_ary_new()); - - /* - * 0: ANSI code page. See WIN32OLE.codepage and WIN32OLE.codepage=. - */ - rb_define_const(cWIN32OLE, "CP_ACP", INT2FIX(CP_ACP)); - - /* - * 1: OEM code page. See WIN32OLE.codepage and WIN32OLE.codepage=. - */ - rb_define_const(cWIN32OLE, "CP_OEMCP", INT2FIX(CP_OEMCP)); - - /* - * 2 - */ - rb_define_const(cWIN32OLE, "CP_MACCP", INT2FIX(CP_MACCP)); - - /* - * 3: current thread ANSI code page. See WIN32OLE.codepage and - * WIN32OLE.codepage=. - */ - rb_define_const(cWIN32OLE, "CP_THREAD_ACP", INT2FIX(CP_THREAD_ACP)); - - /* - * 42: symbol code page. See WIN32OLE.codepage and WIN32OLE.codepage=. - */ - rb_define_const(cWIN32OLE, "CP_SYMBOL", INT2FIX(CP_SYMBOL)); - - /* - * 65000: UTF-7 code page. See WIN32OLE.codepage and WIN32OLE.codepage=. - */ - rb_define_const(cWIN32OLE, "CP_UTF7", INT2FIX(CP_UTF7)); - - /* - * 65001: UTF-8 code page. See WIN32OLE.codepage and WIN32OLE.codepage=. - */ - rb_define_const(cWIN32OLE, "CP_UTF8", INT2FIX(CP_UTF8)); - - /* - * 0x0800: default locale for the operating system. See WIN32OLE.locale - * and WIN32OLE.locale=. - */ - rb_define_const(cWIN32OLE, "LOCALE_SYSTEM_DEFAULT", INT2FIX(LOCALE_SYSTEM_DEFAULT)); - - /* - * 0x0400: default locale for the user or process. See WIN32OLE.locale - * and WIN32OLE.locale=. - */ - rb_define_const(cWIN32OLE, "LOCALE_USER_DEFAULT", INT2FIX(LOCALE_USER_DEFAULT)); - - Init_win32ole_variant_m(); - Init_win32ole_typelib(); - Init_win32ole_type(); - Init_win32ole_variable(); - Init_win32ole_method(); - Init_win32ole_param(); - Init_win32ole_event(); - Init_win32ole_variant(); - Init_win32ole_record(); - Init_win32ole_error(); - - ole_init_cp(); -} |