summaryrefslogtreecommitdiff
path: root/jni/ruby/ext/win32ole/win32ole.c
diff options
context:
space:
mode:
Diffstat (limited to 'jni/ruby/ext/win32ole/win32ole.c')
-rw-r--r--jni/ruby/ext/win32ole/win32ole.c4073
1 files changed, 4073 insertions, 0 deletions
diff --git a/jni/ruby/ext/win32ole/win32ole.c b/jni/ruby/ext/win32ole/win32ole.c
new file mode 100644
index 0000000..4d664e8
--- /dev/null
+++ b/jni/ruby/ext/win32ole/win32ole.c
@@ -0,0 +1,4073 @@
+/*
+ * (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.3"
+
+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 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 st_table *enc2cp_table;
+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 init_enc2cp(void);
+static void free_enc2cp(void);
+
+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 com_hash_datatype = {
+ "com_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;
+ enc = rb_enc_get(vstr);
+
+ if (st_lookup(enc2cp_table, (st_data_t)enc, &data)) {
+ cp = (int)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(enc2cp_table, (st_data_t)enc, (st_data_t)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, &paramS);
+ 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
+init_enc2cp(void)
+{
+ enc2cp_table = st_init_numtable();
+}
+
+static void
+free_enc2cp(void)
+{
+ st_free_table(enc2cp_table);
+}
+
+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;
+
+ com_hash = TypedData_Wrap_Struct(rb_cData, &com_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();
+
+ init_enc2cp();
+ atexit((void (*)(void))free_enc2cp);
+ ole_init_cp();
+}