Ruby  2.7.1p83(2020-03-31revisiona0c7c23c9cec0d0ffcba012279cd652d28ad5bf3)
win32ole.c
Go to the documentation of this file.
1 /*
2  * (c) 1995 Microsoft Corporation. All rights reserved.
3  * Developed by ActiveWare Internet Corp., now known as
4  * ActiveState Tool Corp., http://www.ActiveState.com
5  *
6  * Other modifications Copyright (c) 1997, 1998 by Gurusamy Sarathy
7  * <gsar@umich.edu> and Jan Dubois <jan.dubois@ibm.net>
8  *
9  * You may distribute under the terms of either the GNU General Public
10  * License or the Artistic License, as specified in the README file
11  * of the Perl distribution.
12  *
13  */
14 
15 /*
16  modified for win32ole (ruby) by Masaki.Suketa <masaki.suketa@nifty.ne.jp>
17  */
18 
19 #include "win32ole.h"
20 
21 /*
22  * unfortunately IID_IMultiLanguage2 is not included in any libXXX.a
23  * in Cygwin(mingw32).
24  */
25 #if defined(__CYGWIN__) || defined(__MINGW32__)
26 #undef IID_IMultiLanguage2
27 const IID IID_IMultiLanguage2 = {0xDCCFC164, 0x2B38, 0x11d2, {0xB7, 0xEC, 0x00, 0xC0, 0x4F, 0x8F, 0x5D, 0x9A}};
28 #endif
29 
30 #define WIN32OLE_VERSION "1.8.8"
31 
32 typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX)
33  (REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*);
34 
35 typedef HWND (WINAPI FNHTMLHELP)(HWND hwndCaller, LPCSTR pszFile,
37 typedef BOOL (FNENUMSYSEMCODEPAGES) (CODEPAGE_ENUMPROC, DWORD);
39 
40 #if defined(RB_THREAD_SPECIFIC) && (defined(__CYGWIN__))
41 static RB_THREAD_SPECIFIC BOOL g_ole_initialized;
42 # define g_ole_initialized_init() ((void)0)
43 # define g_ole_initialized_set(val) (g_ole_initialized = (val))
44 #else
45 static volatile DWORD g_ole_initialized_key = TLS_OUT_OF_INDEXES;
46 # define g_ole_initialized (TlsGetValue(g_ole_initialized_key)!=0)
47 # define g_ole_initialized_init() (g_ole_initialized_key = TlsAlloc())
48 # define g_ole_initialized_set(val) TlsSetValue(g_ole_initialized_key, (void*)(val))
49 #endif
50 
51 static BOOL g_uninitialize_hooked = FALSE;
52 static BOOL g_cp_installed = FALSE;
53 static BOOL g_lcid_installed = FALSE;
54 static BOOL g_running_nano = FALSE;
55 static HINSTANCE ghhctrl = NULL;
56 static HINSTANCE gole32 = NULL;
57 static FNCOCREATEINSTANCEEX *gCoCreateInstanceEx = NULL;
58 static VALUE com_hash;
59 static VALUE enc2cp_hash;
60 static IDispatchVtbl com_vtbl;
61 static UINT cWIN32OLE_cp = CP_ACP;
62 static rb_encoding *cWIN32OLE_enc;
63 static UINT g_cp_to_check = CP_ACP;
64 static char g_lcid_to_check[8 + 1];
65 static VARTYPE g_nil_to = VT_ERROR;
66 static IMessageFilterVtbl message_filter;
67 static IMessageFilter imessage_filter = { &message_filter };
68 static IMessageFilter* previous_filter;
69 
70 #if defined(HAVE_TYPE_IMULTILANGUAGE2)
71 static IMultiLanguage2 *pIMultiLanguage = NULL;
72 #elif defined(HAVE_TYPE_IMULTILANGUAGE)
73 static IMultiLanguage *pIMultiLanguage = NULL;
74 #else
75 #define pIMultiLanguage NULL /* dummy */
76 #endif
77 
78 struct oleparam {
79  DISPPARAMS dp;
80  OLECHAR** pNamedArgs;
81 };
82 
83 static HRESULT ( STDMETHODCALLTYPE QueryInterface )(IDispatch __RPC_FAR *, REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject);
84 static ULONG ( STDMETHODCALLTYPE AddRef )(IDispatch __RPC_FAR * This);
85 static ULONG ( STDMETHODCALLTYPE Release )(IDispatch __RPC_FAR * This);
86 static HRESULT ( STDMETHODCALLTYPE GetTypeInfoCount )(IDispatch __RPC_FAR * This, UINT __RPC_FAR *pctinfo);
87 static HRESULT ( STDMETHODCALLTYPE GetTypeInfo )(IDispatch __RPC_FAR * This, UINT iTInfo, LCID lcid, ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo);
88 static HRESULT ( STDMETHODCALLTYPE GetIDsOfNames )(IDispatch __RPC_FAR * This, REFIID riid, LPOLESTR __RPC_FAR *rgszNames, UINT cNames, LCID lcid, DISPID __RPC_FAR *rgDispId);
89 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);
90 static IDispatch* val2dispatch(VALUE val);
91 static double rbtime2vtdate(VALUE tmobj);
92 static VALUE vtdate2rbtime(double date);
93 static rb_encoding *ole_cp2encoding(UINT cp);
94 static UINT ole_encoding2cp(rb_encoding *enc);
95 NORETURN(static void failed_load_conv51932(void));
96 #ifndef pIMultiLanguage
97 static void load_conv_function51932(void);
98 #endif
99 static UINT ole_init_cp(void);
100 static void ole_freeexceptinfo(EXCEPINFO *pExInfo);
101 static VALUE ole_excepinfo2msg(EXCEPINFO *pExInfo);
102 static void ole_free(void *ptr);
103 static size_t ole_size(const void *ptr);
104 static LPWSTR ole_mb2wc(char *pm, int len, UINT cp);
105 static VALUE ole_ary_m_entry(VALUE val, LONG *pid);
106 static VALUE is_all_index_under(LONG *pid, long *pub, long dim);
107 static void * get_ptr_of_variant(VARIANT *pvar);
108 static void ole_set_safe_array(long n, SAFEARRAY *psa, LONG *pid, long *pub, VALUE val, long dim, VARTYPE vt);
109 static long dimension(VALUE val);
110 static long ary_len_of_dim(VALUE ary, long dim);
111 static VALUE ole_set_member(VALUE self, IDispatch *dispatch);
112 static VALUE fole_s_allocate(VALUE klass);
113 static VALUE create_win32ole_object(VALUE klass, IDispatch *pDispatch, int argc, VALUE *argv);
114 static VALUE ary_new_dim(VALUE myary, LONG *pid, LONG *plb, LONG dim);
115 static void ary_store_dim(VALUE myary, LONG *pid, LONG *plb, LONG dim, VALUE val);
116 static void ole_const_load(ITypeLib *pTypeLib, VALUE klass, VALUE self);
117 static HRESULT clsid_from_remote(VALUE host, VALUE com, CLSID *pclsid);
118 static VALUE ole_create_dcom(VALUE self, VALUE ole, VALUE host, VALUE others);
119 static VALUE ole_bind_obj(VALUE moniker, int argc, VALUE *argv, VALUE self);
120 static VALUE fole_s_connect(int argc, VALUE *argv, VALUE self);
121 static VALUE fole_s_const_load(int argc, VALUE *argv, VALUE self);
122 static ULONG reference_count(struct oledata * pole);
123 static VALUE fole_s_reference_count(VALUE self, VALUE obj);
124 static VALUE fole_s_free(VALUE self, VALUE obj);
125 static HWND ole_show_help(VALUE helpfile, VALUE helpcontext);
126 static VALUE fole_s_show_help(int argc, VALUE *argv, VALUE self);
127 static VALUE fole_s_get_code_page(VALUE self);
128 static BOOL CALLBACK installed_code_page_proc(LPTSTR str);
129 static BOOL code_page_installed(UINT cp);
130 static VALUE fole_s_set_code_page(VALUE self, VALUE vcp);
131 static VALUE fole_s_get_locale(VALUE self);
132 static BOOL CALLBACK installed_lcid_proc(LPTSTR str);
133 static BOOL lcid_installed(LCID lcid);
134 static VALUE fole_s_set_locale(VALUE self, VALUE vlcid);
135 static VALUE fole_s_create_guid(VALUE self);
136 static VALUE fole_s_ole_initialize(VALUE self);
137 static VALUE fole_s_ole_uninitialize(VALUE self);
138 static VALUE fole_initialize(int argc, VALUE *argv, VALUE self);
139 static int hash2named_arg(VALUE key, VALUE val, VALUE pop);
140 static VALUE set_argv(VARIANTARG* realargs, unsigned int beg, unsigned int end);
141 static VALUE ole_invoke(int argc, VALUE *argv, VALUE self, USHORT wFlags, BOOL is_bracket);
142 static VALUE fole_invoke(int argc, VALUE *argv, VALUE self);
143 static VALUE ole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types, USHORT dispkind);
144 static VALUE fole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types);
145 static VALUE fole_getproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types);
146 static VALUE fole_setproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types);
147 static VALUE fole_setproperty_with_bracket(int argc, VALUE *argv, VALUE self);
148 static VALUE fole_setproperty(int argc, VALUE *argv, VALUE self);
149 static VALUE fole_getproperty_with_bracket(int argc, VALUE *argv, VALUE self);
150 static VALUE ole_propertyput(VALUE self, VALUE property, VALUE value);
151 static VALUE fole_free(VALUE self);
152 static VALUE ole_each_sub(VALUE pEnumV);
153 static VALUE ole_ienum_free(VALUE pEnumV);
154 static VALUE fole_each(VALUE self);
155 static VALUE fole_missing(int argc, VALUE *argv, VALUE self);
156 static HRESULT typeinfo_from_ole(struct oledata *pole, ITypeInfo **ppti);
157 static VALUE ole_methods(VALUE self, int mask);
158 static VALUE fole_methods(VALUE self);
159 static VALUE fole_get_methods(VALUE self);
160 static VALUE fole_put_methods(VALUE self);
161 static VALUE fole_func_methods(VALUE self);
162 static VALUE fole_type(VALUE self);
163 static VALUE fole_typelib(VALUE self);
164 static VALUE fole_query_interface(VALUE self, VALUE str_iid);
165 static VALUE fole_respond_to(VALUE self, VALUE method);
166 static VALUE ole_usertype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails);
167 static VALUE ole_ptrtype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails);
168 static VALUE fole_method_help(VALUE self, VALUE cmdname);
169 static VALUE fole_activex_initialize(VALUE self);
170 
171 static void com_hash_free(void *ptr);
172 static void com_hash_mark(void *ptr);
173 static size_t com_hash_size(const void *ptr);
174 static void check_nano_server(void);
175 
176 static const rb_data_type_t ole_datatype = {
177  "win32ole",
178  {NULL, ole_free, ole_size,},
180 };
181 
182 static const rb_data_type_t win32ole_hash_datatype = {
183  "win32ole_hash",
184  {com_hash_mark, com_hash_free, com_hash_size,},
186 };
187 
188 static HRESULT (STDMETHODCALLTYPE mf_QueryInterface)(
189  IMessageFilter __RPC_FAR * This,
190  /* [in] */ REFIID riid,
191  /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
192 {
193  if (MEMCMP(riid, &IID_IUnknown, GUID, 1) == 0
194  || MEMCMP(riid, &IID_IMessageFilter, GUID, 1) == 0)
195  {
196  *ppvObject = &message_filter;
197  return S_OK;
198  }
199  return E_NOINTERFACE;
200 }
201 
202 static ULONG (STDMETHODCALLTYPE mf_AddRef)(
203  IMessageFilter __RPC_FAR * This)
204 {
205  return 1;
206 }
207 
208 static ULONG (STDMETHODCALLTYPE mf_Release)(
209  IMessageFilter __RPC_FAR * This)
210 {
211  return 1;
212 }
213 
214 static DWORD (STDMETHODCALLTYPE mf_HandleInComingCall)(
215  IMessageFilter __RPC_FAR * pThis,
216  DWORD dwCallType, //Type of incoming call
217  HTASK threadIDCaller, //Task handle calling this task
218  DWORD dwTickCount, //Elapsed tick count
219  LPINTERFACEINFO lpInterfaceInfo //Pointer to INTERFACEINFO structure
220  )
221 {
222 #ifdef DEBUG_MESSAGEFILTER
223  printf("incoming %08X, %08X, %d\n", dwCallType, threadIDCaller, dwTickCount);
224  fflush(stdout);
225 #endif
226  switch (dwCallType)
227  {
228  case CALLTYPE_ASYNC:
229  case CALLTYPE_TOPLEVEL_CALLPENDING:
230  case CALLTYPE_ASYNC_CALLPENDING:
231  if (rb_during_gc()) {
232  return SERVERCALL_RETRYLATER;
233  }
234  break;
235  default:
236  break;
237  }
238  if (previous_filter) {
239  return previous_filter->lpVtbl->HandleInComingCall(previous_filter,
240  dwCallType,
242  dwTickCount,
244  }
245  return SERVERCALL_ISHANDLED;
246 }
247 
248 static DWORD (STDMETHODCALLTYPE mf_RetryRejectedCall)(
249  IMessageFilter* pThis,
250  HTASK threadIDCallee, //Server task handle
251  DWORD dwTickCount, //Elapsed tick count
252  DWORD dwRejectType //Returned rejection message
253  )
254 {
255  if (previous_filter) {
256  return previous_filter->lpVtbl->RetryRejectedCall(previous_filter,
258  dwTickCount,
259  dwRejectType);
260  }
261  return 1000;
262 }
263 
264 static DWORD (STDMETHODCALLTYPE mf_MessagePending)(
265  IMessageFilter* pThis,
266  HTASK threadIDCallee, //Called applications task handle
267  DWORD dwTickCount, //Elapsed tick count
268  DWORD dwPendingType //Call type
269  )
270 {
271  if (rb_during_gc()) {
272  return PENDINGMSG_WAITNOPROCESS;
273  }
274  if (previous_filter) {
275  return previous_filter->lpVtbl->MessagePending(previous_filter,
277  dwTickCount,
278  dwPendingType);
279  }
280  return PENDINGMSG_WAITNOPROCESS;
281 }
282 
283 typedef struct _Win32OLEIDispatch
284 {
285  IDispatch dispatch;
286  ULONG refcount;
289 
290 static HRESULT ( STDMETHODCALLTYPE QueryInterface )(
291  IDispatch __RPC_FAR * This,
292  /* [in] */ REFIID riid,
293  /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
294 {
295  if (MEMCMP(riid, &IID_IUnknown, GUID, 1) == 0
296  || MEMCMP(riid, &IID_IDispatch, GUID, 1) == 0)
297  {
299  p->refcount++;
300  *ppvObject = This;
301  return S_OK;
302  }
303  return E_NOINTERFACE;
304 }
305 
306 static ULONG ( STDMETHODCALLTYPE AddRef )(
307  IDispatch __RPC_FAR * This)
308 {
310  return ++(p->refcount);
311 }
312 
313 static ULONG ( STDMETHODCALLTYPE Release )(
314  IDispatch __RPC_FAR * This)
315 {
317  ULONG u = --(p->refcount);
318  if (u == 0) {
319  st_data_t key = p->obj;
320  st_delete(DATA_PTR(com_hash), &key, 0);
321  free(p);
322  }
323  return u;
324 }
325 
326 static HRESULT ( STDMETHODCALLTYPE GetTypeInfoCount )(
327  IDispatch __RPC_FAR * This,
328  /* [out] */ UINT __RPC_FAR *pctinfo)
329 {
330  return E_NOTIMPL;
331 }
332 
333 static HRESULT ( STDMETHODCALLTYPE GetTypeInfo )(
334  IDispatch __RPC_FAR * This,
335  /* [in] */ UINT iTInfo,
336  /* [in] */ LCID lcid,
337  /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo)
338 {
339  return E_NOTIMPL;
340 }
341 
342 
343 static HRESULT ( STDMETHODCALLTYPE GetIDsOfNames )(
344  IDispatch __RPC_FAR * This,
345  /* [in] */ REFIID riid,
346  /* [size_is][in] */ LPOLESTR __RPC_FAR *rgszNames,
347  /* [in] */ UINT cNames,
348  /* [in] */ LCID lcid,
349  /* [size_is][out] */ DISPID __RPC_FAR *rgDispId)
350 {
351  /*
352  Win32OLEIDispatch* p = (Win32OLEIDispatch*)This;
353  */
354  char* psz = ole_wc2mb(*rgszNames); // support only one method
355  ID nameid = rb_check_id_cstr(psz, (long)strlen(psz), cWIN32OLE_enc);
356  free(psz);
357  if ((ID)(DISPID)nameid != nameid) return E_NOINTERFACE;
358  *rgDispId = (DISPID)nameid;
359  return S_OK;
360 }
361 
362 static /* [local] */ HRESULT ( STDMETHODCALLTYPE Invoke )(
363  IDispatch __RPC_FAR * This,
364  /* [in] */ DISPID dispIdMember,
365  /* [in] */ REFIID riid,
366  /* [in] */ LCID lcid,
367  /* [in] */ WORD wFlags,
368  /* [out][in] */ DISPPARAMS __RPC_FAR *pDispParams,
369  /* [out] */ VARIANT __RPC_FAR *pVarResult,
370  /* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo,
371  /* [out] */ UINT __RPC_FAR *puArgErr)
372 {
373  VALUE v;
374  int i;
375  int args = pDispParams->cArgs;
377  VALUE* parg = ALLOCA_N(VALUE, args);
378  ID mid = (ID)dispIdMember;
379  for (i = 0; i < args; i++) {
380  *(parg + i) = ole_variant2val(&pDispParams->rgvarg[args - i - 1]);
381  }
382  if (dispIdMember == DISPID_VALUE) {
383  if (wFlags == DISPATCH_METHOD) {
384  mid = rb_intern("call");
385  } else if (wFlags & DISPATCH_PROPERTYGET) {
386  mid = rb_intern("value");
387  }
388  }
389  v = rb_funcallv(p->obj, mid, args, parg);
391  return S_OK;
392 }
393 
394 BOOL
396 {
397  return g_ole_initialized;
398 }
399 
400 static IDispatch*
401 val2dispatch(VALUE val)
402 {
403  struct st_table *tbl = DATA_PTR(com_hash);
404  Win32OLEIDispatch* pdisp;
405  st_data_t data;
406  if (st_lookup(tbl, val, &data)) {
407  pdisp = (Win32OLEIDispatch *)(data & ~FIXNUM_FLAG);
408  pdisp->refcount++;
409  }
410  else {
411  pdisp = ALLOC(Win32OLEIDispatch);
412  pdisp->dispatch.lpVtbl = &com_vtbl;
413  pdisp->refcount = 1;
414  pdisp->obj = val;
415  st_insert(tbl, val, (VALUE)pdisp | FIXNUM_FLAG);
416  }
417  return &pdisp->dispatch;
418 }
419 
420 static double
421 rbtime2vtdate(VALUE tmobj)
422 {
423  SYSTEMTIME st;
424  double t;
425  double nsec;
426 
427  st.wYear = RB_FIX2INT(rb_funcall(tmobj, rb_intern("year"), 0));
428  st.wMonth = RB_FIX2INT(rb_funcall(tmobj, rb_intern("month"), 0));
429  st.wDay = RB_FIX2INT(rb_funcall(tmobj, rb_intern("mday"), 0));
430  st.wHour = RB_FIX2INT(rb_funcall(tmobj, rb_intern("hour"), 0));
431  st.wMinute = RB_FIX2INT(rb_funcall(tmobj, rb_intern("min"), 0));
432  st.wSecond = RB_FIX2INT(rb_funcall(tmobj, rb_intern("sec"), 0));
433  st.wMilliseconds = 0;
434  SystemTimeToVariantTime(&st, &t);
435 
436  /*
437  * Unfortunately SystemTimeToVariantTime function always ignores the
438  * wMilliseconds of SYSTEMTIME struct.
439  * So, we need to calculate milliseconds by ourselves.
440  */
441  nsec = RB_FIX2INT(rb_funcall(tmobj, rb_intern("nsec"), 0));
442  nsec /= 1000000.0;
443  nsec /= (24.0 * 3600.0);
444  nsec /= 1000;
445  return t + nsec;
446 }
447 
448 static VALUE
449 vtdate2rbtime(double date)
450 {
451  SYSTEMTIME st;
452  VALUE v;
453  double msec;
454  double sec;
455  VariantTimeToSystemTime(date, &st);
456  v = rb_funcall(rb_cTime, rb_intern("new"), 6,
457  RB_INT2FIX(st.wYear),
458  RB_INT2FIX(st.wMonth),
459  RB_INT2FIX(st.wDay),
460  RB_INT2FIX(st.wHour),
461  RB_INT2FIX(st.wMinute),
462  RB_INT2FIX(st.wSecond));
463  st.wYear = RB_FIX2INT(rb_funcall(v, rb_intern("year"), 0));
464  st.wMonth = RB_FIX2INT(rb_funcall(v, rb_intern("month"), 0));
465  st.wDay = RB_FIX2INT(rb_funcall(v, rb_intern("mday"), 0));
466  st.wHour = RB_FIX2INT(rb_funcall(v, rb_intern("hour"), 0));
467  st.wMinute = RB_FIX2INT(rb_funcall(v, rb_intern("min"), 0));
468  st.wSecond = RB_FIX2INT(rb_funcall(v, rb_intern("sec"), 0));
469  st.wMilliseconds = 0;
470  SystemTimeToVariantTime(&st, &sec);
471  /*
472  * Unfortunately VariantTimeToSystemTime always ignores the
473  * wMilliseconds of SYSTEMTIME struct(The wMilliseconds is 0).
474  * So, we need to calculate milliseconds by ourselves.
475  */
476  msec = date - sec;
477  msec *= 24 * 60;
478  msec -= floor(msec);
479  msec *= 60;
480  if (msec >= 59) {
481  msec -= 60;
482  }
483  if (msec != 0) {
484  return rb_funcall(v, rb_intern("+"), 1, rb_float_new(msec));
485  }
486  return v;
487 }
488 
489 #define ENC_MACHING_CP(enc,encname,cp) if(strcasecmp(rb_enc_name((enc)),(encname)) == 0) return cp
490 
491 static UINT ole_encoding2cp(rb_encoding *enc)
492 {
493  /*
494  * Is there any better solution to convert
495  * Ruby encoding to Windows codepage???
496  */
497  ENC_MACHING_CP(enc, "Big5", 950);
498  ENC_MACHING_CP(enc, "CP51932", 51932);
499  ENC_MACHING_CP(enc, "CP850", 850);
500  ENC_MACHING_CP(enc, "CP852", 852);
501  ENC_MACHING_CP(enc, "CP855", 855);
502  ENC_MACHING_CP(enc, "CP949", 949);
503  ENC_MACHING_CP(enc, "EUC-JP", 20932);
504  ENC_MACHING_CP(enc, "EUC-KR", 51949);
505  ENC_MACHING_CP(enc, "EUC-TW", 51950);
506  ENC_MACHING_CP(enc, "GB18030", 54936);
507  ENC_MACHING_CP(enc, "GB2312", 20936);
508  ENC_MACHING_CP(enc, "GBK", 936);
509  ENC_MACHING_CP(enc, "IBM437", 437);
510  ENC_MACHING_CP(enc, "IBM737", 737);
511  ENC_MACHING_CP(enc, "IBM775", 775);
512  ENC_MACHING_CP(enc, "IBM852", 852);
513  ENC_MACHING_CP(enc, "IBM855", 855);
514  ENC_MACHING_CP(enc, "IBM857", 857);
515  ENC_MACHING_CP(enc, "IBM860", 860);
516  ENC_MACHING_CP(enc, "IBM861", 861);
517  ENC_MACHING_CP(enc, "IBM862", 862);
518  ENC_MACHING_CP(enc, "IBM863", 863);
519  ENC_MACHING_CP(enc, "IBM864", 864);
520  ENC_MACHING_CP(enc, "IBM865", 865);
521  ENC_MACHING_CP(enc, "IBM866", 866);
522  ENC_MACHING_CP(enc, "IBM869", 869);
523  ENC_MACHING_CP(enc, "ISO-2022-JP", 50220);
524  ENC_MACHING_CP(enc, "ISO-8859-1", 28591);
525  ENC_MACHING_CP(enc, "ISO-8859-15", 28605);
526  ENC_MACHING_CP(enc, "ISO-8859-2", 28592);
527  ENC_MACHING_CP(enc, "ISO-8859-3", 28593);
528  ENC_MACHING_CP(enc, "ISO-8859-4", 28594);
529  ENC_MACHING_CP(enc, "ISO-8859-5", 28595);
530  ENC_MACHING_CP(enc, "ISO-8859-6", 28596);
531  ENC_MACHING_CP(enc, "ISO-8859-7", 28597);
532  ENC_MACHING_CP(enc, "ISO-8859-8", 28598);
533  ENC_MACHING_CP(enc, "ISO-8859-9", 28599);
534  ENC_MACHING_CP(enc, "KOI8-R", 20866);
535  ENC_MACHING_CP(enc, "KOI8-U", 21866);
536  ENC_MACHING_CP(enc, "Shift_JIS", 932);
537  ENC_MACHING_CP(enc, "UTF-16BE", 1201);
538  ENC_MACHING_CP(enc, "UTF-16LE", 1200);
539  ENC_MACHING_CP(enc, "UTF-7", 65000);
540  ENC_MACHING_CP(enc, "UTF-8", 65001);
541  ENC_MACHING_CP(enc, "Windows-1250", 1250);
542  ENC_MACHING_CP(enc, "Windows-1251", 1251);
543  ENC_MACHING_CP(enc, "Windows-1252", 1252);
544  ENC_MACHING_CP(enc, "Windows-1253", 1253);
545  ENC_MACHING_CP(enc, "Windows-1254", 1254);
546  ENC_MACHING_CP(enc, "Windows-1255", 1255);
547  ENC_MACHING_CP(enc, "Windows-1256", 1256);
548  ENC_MACHING_CP(enc, "Windows-1257", 1257);
549  ENC_MACHING_CP(enc, "Windows-1258", 1258);
550  ENC_MACHING_CP(enc, "Windows-31J", 932);
551  ENC_MACHING_CP(enc, "Windows-874", 874);
552  ENC_MACHING_CP(enc, "eucJP-ms", 20932);
553  return CP_ACP;
554 }
555 
556 static void
557 failed_load_conv51932(void)
558 {
559  rb_raise(eWIN32OLERuntimeError, "fail to load convert function for CP51932");
560 }
561 
562 #ifndef pIMultiLanguage
563 static void
565 {
566  HRESULT hr = E_NOINTERFACE;
567  void *p;
568  if (!pIMultiLanguage) {
569 #if defined(HAVE_TYPE_IMULTILANGUAGE2)
570  hr = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
571  &IID_IMultiLanguage2, &p);
572 #elif defined(HAVE_TYPE_IMULTILANGUAGE)
573  hr = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,
574  &IID_IMultiLanguage, &p);
575 #endif
576  if (FAILED(hr)) {
577  failed_load_conv51932();
578  }
579  pIMultiLanguage = p;
580  }
581 }
582 #define need_conv_function51932() (load_conv_function51932(), 1)
583 #else
584 #define load_conv_function51932() failed_load_conv51932()
585 #define need_conv_function51932() (failed_load_conv51932(), 0)
586 #endif
587 
588 #define conv_51932(cp) ((cp) == 51932 && need_conv_function51932())
589 
590 static void
591 set_ole_codepage(UINT cp)
592 {
593  if (code_page_installed(cp)) {
594  cWIN32OLE_cp = cp;
595  } else {
596  switch(cp) {
597  case CP_ACP:
598  case CP_OEMCP:
599  case CP_MACCP:
600  case CP_THREAD_ACP:
601  case CP_SYMBOL:
602  case CP_UTF7:
603  case CP_UTF8:
604  cWIN32OLE_cp = cp;
605  break;
606  case 51932:
607  cWIN32OLE_cp = cp;
609  break;
610  default:
611  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.");
612  break;
613  }
614  }
615  cWIN32OLE_enc = ole_cp2encoding(cWIN32OLE_cp);
616 }
617 
618 
619 static UINT
620 ole_init_cp(void)
621 {
622  UINT cp;
623  rb_encoding *encdef;
624  encdef = rb_default_internal_encoding();
625  if (!encdef) {
626  encdef = rb_default_external_encoding();
627  }
628  cp = ole_encoding2cp(encdef);
629  set_ole_codepage(cp);
630  return cp;
631 }
632 
633 struct myCPINFOEX {
635  BYTE DefaultChar[2];
636  BYTE LeadByte[12];
638  UINT CodePage;
639  char CodePageName[MAX_PATH];
640 };
641 
642 static rb_encoding *
643 ole_cp2encoding(UINT cp)
644 {
645  static BOOL (*pGetCPInfoEx)(UINT, DWORD, struct myCPINFOEX *) = NULL;
646  struct myCPINFOEX* buf;
647  VALUE enc_name;
648  char *enc_cstr;
649  int idx;
650 
651  if (!code_page_installed(cp)) {
652  switch(cp) {
653  case CP_ACP:
654  cp = GetACP();
655  break;
656  case CP_OEMCP:
657  cp = GetOEMCP();
658  break;
659  case CP_MACCP:
660  case CP_THREAD_ACP:
661  if (!pGetCPInfoEx) {
662  pGetCPInfoEx = (BOOL (*)(UINT, DWORD, struct myCPINFOEX *))
663  GetProcAddress(GetModuleHandle("kernel32"), "GetCPInfoEx");
664  if (!pGetCPInfoEx) {
665  pGetCPInfoEx = (void*)-1;
666  }
667  }
668  buf = ALLOCA_N(struct myCPINFOEX, 1);
669  ZeroMemory(buf, sizeof(struct myCPINFOEX));
670  if (pGetCPInfoEx == (void*)-1 || !pGetCPInfoEx(cp, 0, buf)) {
671  rb_raise(eWIN32OLERuntimeError, "cannot map codepage to encoding.");
672  break; /* never reach here */
673  }
674  cp = buf->CodePage;
675  break;
676  case CP_SYMBOL:
677  case CP_UTF7:
678  case CP_UTF8:
679  break;
680  case 51932:
682  break;
683  default:
684  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.");
685  break;
686  }
687  }
688 
689  enc_name = rb_sprintf("CP%d", cp);
690  idx = rb_enc_find_index(enc_cstr = StringValueCStr(enc_name));
691  if (idx < 0)
692  idx = rb_define_dummy_encoding(enc_cstr);
693  return rb_enc_from_index(idx);
694 }
695 
696 #ifndef pIMultiLanguage
697 static HRESULT
698 ole_ml_wc2mb_conv0(LPWSTR pw, LPSTR pm, UINT *size)
699 {
700  DWORD dw = 0;
701  return pIMultiLanguage->lpVtbl->ConvertStringFromUnicode(pIMultiLanguage,
702  &dw, cWIN32OLE_cp, pw, NULL, pm, size);
703 }
704 #define ole_ml_wc2mb_conv(pw, pm, size, onfailure) do { \
705  HRESULT hr = ole_ml_wc2mb_conv0(pw, pm, &size); \
706  if (FAILED(hr)) { \
707  onfailure; \
708  ole_raise(hr, eWIN32OLERuntimeError, "fail to convert Unicode to CP%d", cWIN32OLE_cp); \
709  } \
710  } while (0)
711 #endif
712 
713 #define ole_wc2mb_conv(pw, pm, size) WideCharToMultiByte(cWIN32OLE_cp, 0, (pw), -1, (pm), (size), NULL, NULL)
714 
715 static char *
716 ole_wc2mb_alloc(LPWSTR pw, char *(alloc)(UINT size, void *arg), void *arg)
717 {
718  LPSTR pm;
719  UINT size = 0;
720  if (conv_51932(cWIN32OLE_cp)) {
721 #ifndef pIMultiLanguage
722  ole_ml_wc2mb_conv(pw, NULL, size, {});
723  pm = alloc(size, arg);
724  if (size) ole_ml_wc2mb_conv(pw, pm, size, xfree(pm));
725  pm[size] = '\0';
726  return pm;
727 #endif
728  }
729  size = ole_wc2mb_conv(pw, NULL, 0);
730  pm = alloc(size, arg);
731  if (size) ole_wc2mb_conv(pw, pm, size);
732  pm[size] = '\0';
733  return pm;
734 }
735 
736 static char *
737 ole_alloc_str(UINT size, void *arg)
738 {
739  return ALLOC_N(char, size + 1);
740 }
741 
742 char *
743 ole_wc2mb(LPWSTR pw)
744 {
745  return ole_wc2mb_alloc(pw, ole_alloc_str, NULL);
746 }
747 
748 static void
749 ole_freeexceptinfo(EXCEPINFO *pExInfo)
750 {
751  SysFreeString(pExInfo->bstrDescription);
752  SysFreeString(pExInfo->bstrSource);
753  SysFreeString(pExInfo->bstrHelpFile);
754 }
755 
756 static VALUE
757 ole_excepinfo2msg(EXCEPINFO *pExInfo)
758 {
759  char error_code[40];
760  char *pSource = NULL;
761  char *pDescription = NULL;
762  VALUE error_msg;
763  if(pExInfo->pfnDeferredFillIn != NULL) {
764  (*pExInfo->pfnDeferredFillIn)(pExInfo);
765  }
766  if (pExInfo->bstrSource != NULL) {
767  pSource = ole_wc2mb(pExInfo->bstrSource);
768  }
769  if (pExInfo->bstrDescription != NULL) {
770  pDescription = ole_wc2mb(pExInfo->bstrDescription);
771  }
772  if(pExInfo->wCode == 0) {
773  sprintf(error_code, "\n OLE error code:%lX in ", (unsigned long)pExInfo->scode);
774  }
775  else{
776  sprintf(error_code, "\n OLE error code:%u in ", pExInfo->wCode);
777  }
778  error_msg = rb_str_new2(error_code);
779  if(pSource != NULL) {
780  rb_str_cat2(error_msg, pSource);
781  }
782  else {
783  rb_str_cat(error_msg, "<Unknown>", 9);
784  }
785  rb_str_cat2(error_msg, "\n ");
786  if(pDescription != NULL) {
787  rb_str_cat2(error_msg, pDescription);
788  }
789  else {
790  rb_str_cat2(error_msg, "<No Description>");
791  }
792  if(pSource) free(pSource);
793  if(pDescription) free(pDescription);
794  ole_freeexceptinfo(pExInfo);
795  return error_msg;
796 }
797 
798 void
800 {
801  if (!g_ole_initialized) return;
802  OleUninitialize();
804 }
805 
806 static void
807 ole_uninitialize_hook(rb_event_flag_t evflag, VALUE data, VALUE self, ID mid, VALUE klass)
808 {
810 }
811 
812 void
814 {
815  HRESULT hr;
816 
817  if(!g_uninitialize_hooked) {
818  rb_add_event_hook(ole_uninitialize_hook, RUBY_EVENT_THREAD_END, Qnil);
819  g_uninitialize_hooked = TRUE;
820  }
821 
822  if(g_ole_initialized == FALSE) {
823  if(g_running_nano) {
824  hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
825  } else {
826  hr = OleInitialize(NULL);
827  }
828  if(FAILED(hr)) {
829  ole_raise(hr, rb_eRuntimeError, "fail: OLE initialize");
830  }
832 
833  if (g_running_nano == FALSE) {
834  hr = CoRegisterMessageFilter(&imessage_filter, &previous_filter);
835  if(FAILED(hr)) {
836  previous_filter = NULL;
837  ole_raise(hr, rb_eRuntimeError, "fail: install OLE MessageFilter");
838  }
839  }
840  }
841 }
842 
843 static void
844 ole_free(void *ptr)
845 {
846  struct oledata *pole = ptr;
847  OLE_FREE(pole->pDispatch);
848  free(pole);
849 }
850 
851 static size_t ole_size(const void *ptr)
852 {
853  return ptr ? sizeof(struct oledata) : 0;
854 }
855 
856 struct oledata *
858 {
859  struct oledata *pole;
860  TypedData_Get_Struct(ole, struct oledata, &ole_datatype, pole);
861  return pole;
862 }
863 
864 LPWSTR
866 {
867  rb_encoding *enc;
868  int cp;
869  LPWSTR pw;
870  st_data_t data;
871  struct st_table *tbl = DATA_PTR(enc2cp_hash);
872 
873  /* do not type-conversion here to prevent from other arguments
874  * changing (if exist) */
875  Check_Type(vstr, T_STRING);
876  if (RSTRING_LEN(vstr) == 0) {
877  return NULL;
878  }
879 
880  enc = rb_enc_get(vstr);
881 
882  if (st_lookup(tbl, (VALUE)enc | FIXNUM_FLAG, &data)) {
883  cp = RB_FIX2INT((VALUE)data);
884  } else {
885  cp = ole_encoding2cp(enc);
886  if (code_page_installed(cp) ||
887  cp == CP_ACP ||
888  cp == CP_OEMCP ||
889  cp == CP_MACCP ||
890  cp == CP_THREAD_ACP ||
891  cp == CP_SYMBOL ||
892  cp == CP_UTF7 ||
893  cp == CP_UTF8 ||
894  cp == 51932) {
895  st_insert(tbl, (VALUE)enc | FIXNUM_FLAG, RB_INT2FIX(cp));
896  } else {
897  rb_raise(eWIN32OLERuntimeError, "not installed Windows codepage(%d) according to `%s'", cp, rb_enc_name(enc));
898  }
899  }
900  pw = ole_mb2wc(RSTRING_PTR(vstr), RSTRING_LENINT(vstr), cp);
901  RB_GC_GUARD(vstr);
902  return pw;
903 }
904 
905 static LPWSTR
906 ole_mb2wc(char *pm, int len, UINT cp)
907 {
908  UINT size = 0;
909  LPWSTR pw;
910 
911  if (conv_51932(cp)) {
912 #ifndef pIMultiLanguage
913  DWORD dw = 0;
914  UINT n = len;
915  HRESULT hr = pIMultiLanguage->lpVtbl->ConvertStringToUnicode(pIMultiLanguage,
916  &dw, cp, pm, &n, NULL, &size);
917  if (FAILED(hr)) {
918  ole_raise(hr, eWIN32OLERuntimeError, "fail to convert CP%d to Unicode", cp);
919  }
920  pw = SysAllocStringLen(NULL, size);
921  n = len;
922  hr = pIMultiLanguage->lpVtbl->ConvertStringToUnicode(pIMultiLanguage,
923  &dw, cp, pm, &n, pw, &size);
924  if (FAILED(hr)) {
925  ole_raise(hr, eWIN32OLERuntimeError, "fail to convert CP%d to Unicode", cp);
926  }
927  return pw;
928 #endif
929  }
930  size = MultiByteToWideChar(cp, 0, pm, len, NULL, 0);
931  pw = SysAllocStringLen(NULL, size);
932  pw[size-1] = 0;
933  MultiByteToWideChar(cp, 0, pm, len, pw, size);
934  return pw;
935 }
936 
937 static char *
938 ole_alloc_vstr(UINT size, void *arg)
939 {
940  VALUE str = rb_enc_str_new(NULL, size, cWIN32OLE_enc);
941  *(VALUE *)arg = str;
942  return RSTRING_PTR(str);
943 }
944 
945 VALUE
946 ole_wc2vstr(LPWSTR pw, BOOL isfree)
947 {
948  VALUE vstr;
949  ole_wc2mb_alloc(pw, ole_alloc_vstr, &vstr);
950  rb_str_set_len(vstr, (long)strlen(RSTRING_PTR(vstr)));
951  if(isfree)
952  SysFreeString(pw);
953  return vstr;
954 }
955 
956 static VALUE
957 ole_ary_m_entry(VALUE val, LONG *pid)
958 {
959  VALUE obj = Qnil;
960  int i = 0;
961  obj = val;
962  while(RB_TYPE_P(obj, T_ARRAY)) {
963  obj = rb_ary_entry(obj, pid[i]);
964  i++;
965  }
966  return obj;
967 }
968 
969 static VALUE
970 is_all_index_under(LONG *pid, long *pub, long dim)
971 {
972  long i = 0;
973  for (i = 0; i < dim; i++) {
974  if (pid[i] > pub[i]) {
975  return Qfalse;
976  }
977  }
978  return Qtrue;
979 }
980 
981 void
982 ole_val2variant_ex(VALUE val, VARIANT *var, VARTYPE vt)
983 {
984  if (val == Qnil) {
985  if (vt == VT_VARIANT) {
986  ole_val2variant2(val, var);
987  } else {
988  V_VT(var) = (vt & ~VT_BYREF);
989  if (V_VT(var) == VT_DISPATCH) {
990  V_DISPATCH(var) = NULL;
991  } else if (V_VT(var) == VT_UNKNOWN) {
992  V_UNKNOWN(var) = NULL;
993  }
994  }
995  return;
996  }
997 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
998  switch(vt & ~VT_BYREF) {
999  case VT_I8:
1000  V_VT(var) = VT_I8;
1001  V_I8(var) = NUM2I8 (val);
1002  break;
1003  case VT_UI8:
1004  V_VT(var) = VT_UI8;
1005  V_UI8(var) = NUM2UI8(val);
1006  break;
1007  default:
1008  ole_val2variant2(val, var);
1009  break;
1010  }
1011 #else /* (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__) */
1012  ole_val2variant2(val, var);
1013 #endif
1014 }
1015 
1016 VOID *
1017 val2variant_ptr(VALUE val, VARIANT *var, VARTYPE vt)
1018 {
1019  VOID *p = NULL;
1020  HRESULT hr = S_OK;
1021  ole_val2variant_ex(val, var, vt);
1022  if ((vt & ~VT_BYREF) == VT_VARIANT) {
1023  p = var;
1024  } else {
1025  if ( (vt & ~VT_BYREF) != V_VT(var)) {
1026  hr = VariantChangeTypeEx(var, var,
1027  cWIN32OLE_lcid, 0, (VARTYPE)(vt & ~VT_BYREF));
1028  if (FAILED(hr)) {
1029  ole_raise(hr, rb_eRuntimeError, "failed to change type");
1030  }
1031  }
1032  p = get_ptr_of_variant(var);
1033  }
1034  if (p == NULL) {
1035  rb_raise(rb_eRuntimeError, "failed to get pointer of variant");
1036  }
1037  return p;
1038 }
1039 
1040 static void *
1041 get_ptr_of_variant(VARIANT *pvar)
1042 {
1043  switch(V_VT(pvar)) {
1044  case VT_UI1:
1045  return &V_UI1(pvar);
1046  break;
1047  case VT_I2:
1048  return &V_I2(pvar);
1049  break;
1050  case VT_UI2:
1051  return &V_UI2(pvar);
1052  break;
1053  case VT_I4:
1054  return &V_I4(pvar);
1055  break;
1056  case VT_UI4:
1057  return &V_UI4(pvar);
1058  break;
1059  case VT_R4:
1060  return &V_R4(pvar);
1061  break;
1062  case VT_R8:
1063  return &V_R8(pvar);
1064  break;
1065 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
1066  case VT_I8:
1067  return &V_I8(pvar);
1068  break;
1069  case VT_UI8:
1070  return &V_UI8(pvar);
1071  break;
1072 #endif
1073  case VT_INT:
1074  return &V_INT(pvar);
1075  break;
1076  case VT_UINT:
1077  return &V_UINT(pvar);
1078  break;
1079  case VT_CY:
1080  return &V_CY(pvar);
1081  break;
1082  case VT_DATE:
1083  return &V_DATE(pvar);
1084  break;
1085  case VT_BSTR:
1086  return V_BSTR(pvar);
1087  break;
1088  case VT_DISPATCH:
1089  return V_DISPATCH(pvar);
1090  break;
1091  case VT_ERROR:
1092  return &V_ERROR(pvar);
1093  break;
1094  case VT_BOOL:
1095  return &V_BOOL(pvar);
1096  break;
1097  case VT_UNKNOWN:
1098  return V_UNKNOWN(pvar);
1099  break;
1100  case VT_ARRAY:
1101  return &V_ARRAY(pvar);
1102  break;
1103  default:
1104  return NULL;
1105  break;
1106  }
1107 }
1108 
1109 static void
1110 ole_set_safe_array(long n, SAFEARRAY *psa, LONG *pid, long *pub, VALUE val, long dim, VARTYPE vt)
1111 {
1112  VALUE val1;
1113  HRESULT hr = S_OK;
1114  VARIANT var;
1115  VOID *p = NULL;
1116  long i = n;
1117  while(i >= 0) {
1118  val1 = ole_ary_m_entry(val, pid);
1119  VariantInit(&var);
1120  p = val2variant_ptr(val1, &var, vt);
1121  if (is_all_index_under(pid, pub, dim) == Qtrue) {
1122  if ((V_VT(&var) == VT_DISPATCH && V_DISPATCH(&var) == NULL) ||
1123  (V_VT(&var) == VT_UNKNOWN && V_UNKNOWN(&var) == NULL)) {
1124  rb_raise(eWIN32OLERuntimeError, "element of array does not have IDispatch or IUnknown Interface");
1125  }
1126  hr = SafeArrayPutElement(psa, pid, p);
1127  }
1128  if (FAILED(hr)) {
1129  ole_raise(hr, rb_eRuntimeError, "failed to SafeArrayPutElement");
1130  }
1131  pid[i] += 1;
1132  if (pid[i] > pub[i]) {
1133  pid[i] = 0;
1134  i -= 1;
1135  } else {
1136  i = dim - 1;
1137  }
1138  }
1139 }
1140 
1141 static long
1142 dimension(VALUE val) {
1143  long dim = 0;
1144  long dim1 = 0;
1145  long len = 0;
1146  long i = 0;
1147  if (RB_TYPE_P(val, T_ARRAY)) {
1148  len = RARRAY_LEN(val);
1149  for (i = 0; i < len; i++) {
1150  dim1 = dimension(rb_ary_entry(val, i));
1151  if (dim < dim1) {
1152  dim = dim1;
1153  }
1154  }
1155  dim += 1;
1156  }
1157  return dim;
1158 }
1159 
1160 static long
1161 ary_len_of_dim(VALUE ary, long dim) {
1162  long ary_len = 0;
1163  long ary_len1 = 0;
1164  long len = 0;
1165  long i = 0;
1166  VALUE val;
1167  if (dim == 0) {
1168  if (RB_TYPE_P(ary, T_ARRAY)) {
1169  ary_len = RARRAY_LEN(ary);
1170  }
1171  } else {
1172  if (RB_TYPE_P(ary, T_ARRAY)) {
1173  len = RARRAY_LEN(ary);
1174  for (i = 0; i < len; i++) {
1175  val = rb_ary_entry(ary, i);
1176  ary_len1 = ary_len_of_dim(val, dim-1);
1177  if (ary_len < ary_len1) {
1178  ary_len = ary_len1;
1179  }
1180  }
1181  }
1182  }
1183  return ary_len;
1184 }
1185 
1186 HRESULT
1187 ole_val_ary2variant_ary(VALUE val, VARIANT *var, VARTYPE vt)
1188 {
1189  long dim = 0;
1190  int i = 0;
1191  HRESULT hr = S_OK;
1192 
1193  SAFEARRAYBOUND *psab = NULL;
1194  SAFEARRAY *psa = NULL;
1195  long *pub;
1196  LONG *pid;
1197 
1198  Check_Type(val, T_ARRAY);
1199 
1200  dim = dimension(val);
1201 
1202  psab = ALLOC_N(SAFEARRAYBOUND, dim);
1203  pub = ALLOC_N(long, dim);
1204  pid = ALLOC_N(LONG, dim);
1205 
1206  if(!psab || !pub || !pid) {
1207  if(pub) free(pub);
1208  if(psab) free(psab);
1209  if(pid) free(pid);
1210  rb_raise(rb_eRuntimeError, "memory allocation error");
1211  }
1212 
1213  for (i = 0; i < dim; i++) {
1214  psab[i].cElements = ary_len_of_dim(val, i);
1215  psab[i].lLbound = 0;
1216  pub[i] = psab[i].cElements - 1;
1217  pid[i] = 0;
1218  }
1219  /* Create and fill VARIANT array */
1220  if ((vt & ~VT_BYREF) == VT_ARRAY) {
1221  vt = (vt | VT_VARIANT);
1222  }
1223  psa = SafeArrayCreate((VARTYPE)(vt & VT_TYPEMASK), dim, psab);
1224  if (psa == NULL)
1225  hr = E_OUTOFMEMORY;
1226  else
1227  hr = SafeArrayLock(psa);
1228  if (SUCCEEDED(hr)) {
1229  ole_set_safe_array(dim-1, psa, pid, pub, val, dim, (VARTYPE)(vt & VT_TYPEMASK));
1230  hr = SafeArrayUnlock(psa);
1231  }
1232 
1233  if(pub) free(pub);
1234  if(psab) free(psab);
1235  if(pid) free(pid);
1236 
1237  if (SUCCEEDED(hr)) {
1238  V_VT(var) = vt;
1239  V_ARRAY(var) = psa;
1240  }
1241  else {
1242  if (psa != NULL)
1243  SafeArrayDestroy(psa);
1244  }
1245  return hr;
1246 }
1247 
1248 void
1249 ole_val2variant(VALUE val, VARIANT *var)
1250 {
1251  struct oledata *pole = NULL;
1252  if(rb_obj_is_kind_of(val, cWIN32OLE)) {
1253  pole = oledata_get_struct(val);
1254  OLE_ADDREF(pole->pDispatch);
1255  V_VT(var) = VT_DISPATCH;
1256  V_DISPATCH(var) = pole->pDispatch;
1257  return;
1258  }
1260  ole_variant2variant(val, var);
1261  return;
1262  }
1263  if (rb_obj_is_kind_of(val, cWIN32OLE_RECORD)) {
1264  ole_rec2variant(val, var);
1265  return;
1266  }
1267  if (rb_obj_is_kind_of(val, rb_cTime)) {
1268  V_VT(var) = VT_DATE;
1269  V_DATE(var) = rbtime2vtdate(val);
1270  return;
1271  }
1272  switch (TYPE(val)) {
1273  case T_ARRAY:
1274  ole_val_ary2variant_ary(val, var, VT_VARIANT|VT_ARRAY);
1275  break;
1276  case T_STRING:
1277  V_VT(var) = VT_BSTR;
1278  V_BSTR(var) = ole_vstr2wc(val);
1279  break;
1280  case T_FIXNUM:
1281  V_VT(var) = VT_I4;
1282  {
1283  long v = RB_NUM2LONG(val);
1284  V_I4(var) = (LONG)v;
1285 #if SIZEOF_LONG > 4
1286  if (V_I4(var) != v) {
1287  V_I8(var) = v;
1288  V_VT(var) = VT_I8;
1289  }
1290 #endif
1291  }
1292  break;
1293  case T_BIGNUM:
1294  V_VT(var) = VT_R8;
1295  V_R8(var) = rb_big2dbl(val);
1296  break;
1297  case T_FLOAT:
1298  V_VT(var) = VT_R8;
1299  V_R8(var) = NUM2DBL(val);
1300  break;
1301  case T_TRUE:
1302  V_VT(var) = VT_BOOL;
1303  V_BOOL(var) = VARIANT_TRUE;
1304  break;
1305  case T_FALSE:
1306  V_VT(var) = VT_BOOL;
1307  V_BOOL(var) = VARIANT_FALSE;
1308  break;
1309  case T_NIL:
1310  if (g_nil_to == VT_ERROR) {
1311  V_VT(var) = VT_ERROR;
1312  V_ERROR(var) = DISP_E_PARAMNOTFOUND;
1313  }else {
1314  V_VT(var) = VT_EMPTY;
1315  }
1316  break;
1317  default:
1318  V_VT(var) = VT_DISPATCH;
1319  V_DISPATCH(var) = val2dispatch(val);
1320  break;
1321  }
1322 }
1323 
1324 void
1325 ole_val2variant2(VALUE val, VARIANT *var)
1326 {
1327  g_nil_to = VT_EMPTY;
1328  ole_val2variant(val, var);
1329  g_nil_to = VT_ERROR;
1330 }
1331 
1332 VALUE
1333 make_inspect(const char *class_name, VALUE detail)
1334 {
1335  VALUE str;
1336  str = rb_str_new2("#<");
1337  rb_str_cat2(str, class_name);
1338  rb_str_cat2(str, ":");
1339  rb_str_concat(str, detail);
1340  rb_str_cat2(str, ">");
1341  return str;
1342 }
1343 
1344 VALUE
1345 default_inspect(VALUE self, const char *class_name)
1346 {
1347  VALUE detail = rb_funcall(self, rb_intern("to_s"), 0);
1348  return make_inspect(class_name, detail);
1349 }
1350 
1351 static VALUE
1352 ole_set_member(VALUE self, IDispatch *dispatch)
1353 {
1354  struct oledata *pole = NULL;
1355  pole = oledata_get_struct(self);
1356  if (pole->pDispatch) {
1357  OLE_RELEASE(pole->pDispatch);
1358  pole->pDispatch = NULL;
1359  }
1360  pole->pDispatch = dispatch;
1361  return self;
1362 }
1363 
1364 
1365 static VALUE
1366 fole_s_allocate(VALUE klass)
1367 {
1368  struct oledata *pole;
1369  VALUE obj;
1370  ole_initialize();
1371  obj = TypedData_Make_Struct(klass, struct oledata, &ole_datatype, pole);
1372  pole->pDispatch = NULL;
1373  return obj;
1374 }
1375 
1376 static VALUE
1377 create_win32ole_object(VALUE klass, IDispatch *pDispatch, int argc, VALUE *argv)
1378 {
1379  VALUE obj = fole_s_allocate(klass);
1380  ole_set_member(obj, pDispatch);
1381  return obj;
1382 }
1383 
1384 static VALUE
1385 ary_new_dim(VALUE myary, LONG *pid, LONG *plb, LONG dim) {
1386  long i;
1387  VALUE obj = Qnil;
1388  VALUE pobj = Qnil;
1389  long *ids = ALLOC_N(long, dim);
1390  if (!ids) {
1391  rb_raise(rb_eRuntimeError, "memory allocation error");
1392  }
1393  for(i = 0; i < dim; i++) {
1394  ids[i] = pid[i] - plb[i];
1395  }
1396  obj = myary;
1397  pobj = myary;
1398  for(i = 0; i < dim-1; i++) {
1399  obj = rb_ary_entry(pobj, ids[i]);
1400  if (obj == Qnil) {
1401  rb_ary_store(pobj, ids[i], rb_ary_new());
1402  }
1403  obj = rb_ary_entry(pobj, ids[i]);
1404  pobj = obj;
1405  }
1406  if (ids) free(ids);
1407  return obj;
1408 }
1409 
1410 static void
1411 ary_store_dim(VALUE myary, LONG *pid, LONG *plb, LONG dim, VALUE val) {
1412  long id = pid[dim - 1] - plb[dim - 1];
1413  VALUE obj = ary_new_dim(myary, pid, plb, dim);
1414  rb_ary_store(obj, id, val);
1415 }
1416 
1417 VALUE
1418 ole_variant2val(VARIANT *pvar)
1419 {
1420  VALUE obj = Qnil;
1421  VARTYPE vt = V_VT(pvar);
1422  HRESULT hr;
1423  while ( vt == (VT_BYREF | VT_VARIANT) ) {
1424  pvar = V_VARIANTREF(pvar);
1425  vt = V_VT(pvar);
1426  }
1427 
1428  if(V_ISARRAY(pvar)) {
1429  VARTYPE vt_base = vt & VT_TYPEMASK;
1430  SAFEARRAY *psa = V_ISBYREF(pvar) ? *V_ARRAYREF(pvar) : V_ARRAY(pvar);
1431  UINT i = 0;
1432  LONG *pid, *plb, *pub;
1433  VARIANT variant;
1434  VALUE val;
1435  UINT dim = 0;
1436  if (!psa) {
1437  return obj;
1438  }
1439  dim = SafeArrayGetDim(psa);
1440  pid = ALLOC_N(LONG, dim);
1441  plb = ALLOC_N(LONG, dim);
1442  pub = ALLOC_N(LONG, dim);
1443 
1444  if(!pid || !plb || !pub) {
1445  if(pid) free(pid);
1446  if(plb) free(plb);
1447  if(pub) free(pub);
1448  rb_raise(rb_eRuntimeError, "memory allocation error");
1449  }
1450 
1451  for(i = 0; i < dim; ++i) {
1452  SafeArrayGetLBound(psa, i+1, &plb[i]);
1453  SafeArrayGetLBound(psa, i+1, &pid[i]);
1454  SafeArrayGetUBound(psa, i+1, &pub[i]);
1455  }
1456  hr = SafeArrayLock(psa);
1457  if (SUCCEEDED(hr)) {
1458  obj = rb_ary_new();
1459  i = 0;
1460  VariantInit(&variant);
1461  V_VT(&variant) = vt_base | VT_BYREF;
1462  if (vt_base == VT_RECORD) {
1463  hr = SafeArrayGetRecordInfo(psa, &V_RECORDINFO(&variant));
1464  if (SUCCEEDED(hr)) {
1465  V_VT(&variant) = VT_RECORD;
1466  }
1467  }
1468  while (i < dim) {
1469  ary_new_dim(obj, pid, plb, dim);
1470  if (vt_base == VT_RECORD)
1471  hr = SafeArrayPtrOfIndex(psa, pid, &V_RECORD(&variant));
1472  else
1473  hr = SafeArrayPtrOfIndex(psa, pid, &V_BYREF(&variant));
1474  if (SUCCEEDED(hr)) {
1475  val = ole_variant2val(&variant);
1476  ary_store_dim(obj, pid, plb, dim, val);
1477  }
1478  for (i = 0; i < dim; ++i) {
1479  if (++pid[i] <= pub[i])
1480  break;
1481  pid[i] = plb[i];
1482  }
1483  }
1484  SafeArrayUnlock(psa);
1485  }
1486  if(pid) free(pid);
1487  if(plb) free(plb);
1488  if(pub) free(pub);
1489  return obj;
1490  }
1491  switch(V_VT(pvar) & ~VT_BYREF){
1492  case VT_EMPTY:
1493  break;
1494  case VT_NULL:
1495  break;
1496  case VT_I1:
1497  if(V_ISBYREF(pvar))
1498  obj = RB_INT2NUM((long)*V_I1REF(pvar));
1499  else
1500  obj = RB_INT2NUM((long)V_I1(pvar));
1501  break;
1502 
1503  case VT_UI1:
1504  if(V_ISBYREF(pvar))
1505  obj = RB_INT2NUM((long)*V_UI1REF(pvar));
1506  else
1507  obj = RB_INT2NUM((long)V_UI1(pvar));
1508  break;
1509 
1510  case VT_I2:
1511  if(V_ISBYREF(pvar))
1512  obj = RB_INT2NUM((long)*V_I2REF(pvar));
1513  else
1514  obj = RB_INT2NUM((long)V_I2(pvar));
1515  break;
1516 
1517  case VT_UI2:
1518  if(V_ISBYREF(pvar))
1519  obj = RB_INT2NUM((long)*V_UI2REF(pvar));
1520  else
1521  obj = RB_INT2NUM((long)V_UI2(pvar));
1522  break;
1523 
1524  case VT_I4:
1525  if(V_ISBYREF(pvar))
1526  obj = RB_INT2NUM((long)*V_I4REF(pvar));
1527  else
1528  obj = RB_INT2NUM((long)V_I4(pvar));
1529  break;
1530 
1531  case VT_UI4:
1532  if(V_ISBYREF(pvar))
1533  obj = RB_INT2NUM((long)*V_UI4REF(pvar));
1534  else
1535  obj = RB_INT2NUM((long)V_UI4(pvar));
1536  break;
1537 
1538  case VT_INT:
1539  if(V_ISBYREF(pvar))
1540  obj = RB_INT2NUM((long)*V_INTREF(pvar));
1541  else
1542  obj = RB_INT2NUM((long)V_INT(pvar));
1543  break;
1544 
1545  case VT_UINT:
1546  if(V_ISBYREF(pvar))
1547  obj = RB_INT2NUM((long)*V_UINTREF(pvar));
1548  else
1549  obj = RB_INT2NUM((long)V_UINT(pvar));
1550  break;
1551 
1552 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
1553  case VT_I8:
1554  if(V_ISBYREF(pvar))
1555 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
1556 #ifdef V_I8REF
1557  obj = I8_2_NUM(*V_I8REF(pvar));
1558 #endif
1559 #else
1560  obj = Qnil;
1561 #endif
1562  else
1563  obj = I8_2_NUM(V_I8(pvar));
1564  break;
1565  case VT_UI8:
1566  if(V_ISBYREF(pvar))
1567 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
1568 #ifdef V_UI8REF
1569  obj = UI8_2_NUM(*V_UI8REF(pvar));
1570 #endif
1571 #else
1572  obj = Qnil;
1573 #endif
1574  else
1575  obj = UI8_2_NUM(V_UI8(pvar));
1576  break;
1577 #endif /* (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__) */
1578 
1579  case VT_R4:
1580  if(V_ISBYREF(pvar))
1581  obj = rb_float_new(*V_R4REF(pvar));
1582  else
1583  obj = rb_float_new(V_R4(pvar));
1584  break;
1585 
1586  case VT_R8:
1587  if(V_ISBYREF(pvar))
1588  obj = rb_float_new(*V_R8REF(pvar));
1589  else
1590  obj = rb_float_new(V_R8(pvar));
1591  break;
1592 
1593  case VT_BSTR:
1594  {
1595  BSTR bstr;
1596  if(V_ISBYREF(pvar))
1597  bstr = *V_BSTRREF(pvar);
1598  else
1599  bstr = V_BSTR(pvar);
1600  obj = (SysStringLen(bstr) == 0)
1601  ? rb_str_new2("")
1602  : ole_wc2vstr(bstr, FALSE);
1603  break;
1604  }
1605 
1606  case VT_ERROR:
1607  if(V_ISBYREF(pvar))
1608  obj = RB_INT2NUM(*V_ERRORREF(pvar));
1609  else
1610  obj = RB_INT2NUM(V_ERROR(pvar));
1611  break;
1612 
1613  case VT_BOOL:
1614  if (V_ISBYREF(pvar))
1615  obj = (*V_BOOLREF(pvar) ? Qtrue : Qfalse);
1616  else
1617  obj = (V_BOOL(pvar) ? Qtrue : Qfalse);
1618  break;
1619 
1620  case VT_DISPATCH:
1621  {
1622  IDispatch *pDispatch;
1623 
1624  if (V_ISBYREF(pvar))
1625  pDispatch = *V_DISPATCHREF(pvar);
1626  else
1627  pDispatch = V_DISPATCH(pvar);
1628 
1629  if (pDispatch != NULL ) {
1631  obj = create_win32ole_object(cWIN32OLE, pDispatch, 0, 0);
1632  }
1633  break;
1634  }
1635 
1636  case VT_UNKNOWN:
1637  {
1638  /* get IDispatch interface from IUnknown interface */
1639  IUnknown *punk;
1640  IDispatch *pDispatch;
1641  void *p;
1642  HRESULT hr;
1643 
1644  if (V_ISBYREF(pvar))
1645  punk = *V_UNKNOWNREF(pvar);
1646  else
1647  punk = V_UNKNOWN(pvar);
1648 
1649  if(punk != NULL) {
1650  hr = punk->lpVtbl->QueryInterface(punk, &IID_IDispatch, &p);
1651  if(SUCCEEDED(hr)) {
1652  pDispatch = p;
1653  obj = create_win32ole_object(cWIN32OLE, pDispatch, 0, 0);
1654  }
1655  }
1656  break;
1657  }
1658 
1659  case VT_DATE:
1660  {
1661  DATE date;
1662  if(V_ISBYREF(pvar))
1663  date = *V_DATEREF(pvar);
1664  else
1665  date = V_DATE(pvar);
1666 
1667  obj = vtdate2rbtime(date);
1668  break;
1669  }
1670 
1671  case VT_RECORD:
1672  {
1673  IRecordInfo *pri = V_RECORDINFO(pvar);
1674  void *prec = V_RECORD(pvar);
1675  obj = create_win32ole_record(pri, prec);
1676  break;
1677  }
1678 
1679  case VT_CY:
1680  default:
1681  {
1682  HRESULT hr;
1683  VARIANT variant;
1684  VariantInit(&variant);
1685  hr = VariantChangeTypeEx(&variant, pvar,
1686  cWIN32OLE_lcid, 0, VT_BSTR);
1687  if (SUCCEEDED(hr) && V_VT(&variant) == VT_BSTR) {
1688  obj = ole_wc2vstr(V_BSTR(&variant), FALSE);
1689  }
1690  VariantClear(&variant);
1691  break;
1692  }
1693  }
1694  return obj;
1695 }
1696 
1697 LONG
1698 reg_open_key(HKEY hkey, const char *name, HKEY *phkey)
1699 {
1700  return RegOpenKeyEx(hkey, name, 0, KEY_READ, phkey);
1701 }
1702 
1703 LONG
1704 reg_open_vkey(HKEY hkey, VALUE key, HKEY *phkey)
1705 {
1706  return reg_open_key(hkey, StringValuePtr(key), phkey);
1707 }
1708 
1709 VALUE
1710 reg_enum_key(HKEY hkey, DWORD i)
1711 {
1712  char buf[BUFSIZ + 1];
1713  DWORD size_buf = sizeof(buf);
1714  FILETIME ft;
1715  LONG err = RegEnumKeyEx(hkey, i, buf, &size_buf,
1716  NULL, NULL, NULL, &ft);
1717  if(err == ERROR_SUCCESS) {
1718  buf[BUFSIZ] = '\0';
1719  return rb_str_new2(buf);
1720  }
1721  return Qnil;
1722 }
1723 
1724 VALUE
1725 reg_get_val(HKEY hkey, const char *subkey)
1726 {
1727  char *pbuf;
1728  DWORD dwtype = 0;
1729  DWORD size = 0;
1730  VALUE val = Qnil;
1731  LONG err = RegQueryValueEx(hkey, subkey, NULL, &dwtype, NULL, &size);
1732 
1733  if (err == ERROR_SUCCESS) {
1734  pbuf = ALLOC_N(char, size + 1);
1735  err = RegQueryValueEx(hkey, subkey, NULL, &dwtype, (BYTE *)pbuf, &size);
1736  if (err == ERROR_SUCCESS) {
1737  pbuf[size] = '\0';
1738  if (dwtype == REG_EXPAND_SZ) {
1739  char* pbuf2 = (char *)pbuf;
1740  DWORD len = ExpandEnvironmentStrings(pbuf2, NULL, 0);
1741  pbuf = ALLOC_N(char, len + 1);
1742  ExpandEnvironmentStrings(pbuf2, pbuf, len + 1);
1743  free(pbuf2);
1744  }
1745  val = rb_str_new2((char *)pbuf);
1746  }
1747  free(pbuf);
1748  }
1749  return val;
1750 }
1751 
1752 VALUE
1753 reg_get_val2(HKEY hkey, const char *subkey)
1754 {
1755  HKEY hsubkey;
1756  LONG err;
1757  VALUE val = Qnil;
1758  err = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &hsubkey);
1759  if (err == ERROR_SUCCESS) {
1760  val = reg_get_val(hsubkey, NULL);
1761  RegCloseKey(hsubkey);
1762  }
1763  if (val == Qnil) {
1764  val = reg_get_val(hkey, subkey);
1765  }
1766  return val;
1767 }
1768 
1769 static void
1770 ole_const_load(ITypeLib *pTypeLib, VALUE klass, VALUE self)
1771 {
1772  unsigned int count;
1773  unsigned int index;
1774  int iVar;
1775  ITypeInfo *pTypeInfo;
1776  TYPEATTR *pTypeAttr;
1777  VARDESC *pVarDesc;
1778  HRESULT hr;
1779  unsigned int len;
1780  BSTR bstr;
1781  char *pName = NULL;
1782  VALUE val;
1783  VALUE constant;
1784  ID id;
1785  constant = rb_hash_new();
1786  count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
1787  for (index = 0; index < count; index++) {
1788  hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, index, &pTypeInfo);
1789  if (FAILED(hr))
1790  continue;
1791  hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
1792  if(FAILED(hr)) {
1793  OLE_RELEASE(pTypeInfo);
1794  continue;
1795  }
1796  for(iVar = 0; iVar < pTypeAttr->cVars; iVar++) {
1797  hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, iVar, &pVarDesc);
1798  if(FAILED(hr))
1799  continue;
1800  if(pVarDesc->varkind == VAR_CONST &&
1801  !(pVarDesc->wVarFlags & (VARFLAG_FHIDDEN |
1802  VARFLAG_FRESTRICTED |
1803  VARFLAG_FNONBROWSABLE))) {
1804  hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, pVarDesc->memid, &bstr,
1805  1, &len);
1806  if(FAILED(hr) || len == 0 || !bstr)
1807  continue;
1808  pName = ole_wc2mb(bstr);
1809  val = ole_variant2val(V_UNION1(pVarDesc, lpvarValue));
1810  *pName = toupper((int)*pName);
1811  id = rb_intern(pName);
1812  if (rb_is_const_id(id)) {
1813  if(!rb_const_defined_at(klass, id)) {
1814  rb_define_const(klass, pName, val);
1815  }
1816  }
1817  else {
1818  rb_hash_aset(constant, rb_str_new2(pName), val);
1819  }
1820  SysFreeString(bstr);
1821  if(pName) {
1822  free(pName);
1823  pName = NULL;
1824  }
1825  }
1826  pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
1827  }
1828  pTypeInfo->lpVtbl->ReleaseTypeAttr(pTypeInfo, pTypeAttr);
1829  OLE_RELEASE(pTypeInfo);
1830  }
1831  rb_define_const(klass, "CONSTANTS", constant);
1832 }
1833 
1834 static HRESULT
1835 clsid_from_remote(VALUE host, VALUE com, CLSID *pclsid)
1836 {
1837  HKEY hlm;
1838  HKEY hpid;
1839  VALUE subkey;
1840  LONG err;
1841  char clsid[100];
1842  OLECHAR *pbuf;
1843  DWORD len;
1844  DWORD dwtype;
1845  HRESULT hr = S_OK;
1846  err = RegConnectRegistry(StringValuePtr(host), HKEY_LOCAL_MACHINE, &hlm);
1847  if (err != ERROR_SUCCESS)
1848  return HRESULT_FROM_WIN32(err);
1849  subkey = rb_str_new2("SOFTWARE\\Classes\\");
1850  rb_str_concat(subkey, com);
1851  rb_str_cat2(subkey, "\\CLSID");
1852  err = RegOpenKeyEx(hlm, StringValuePtr(subkey), 0, KEY_READ, &hpid);
1853  if (err != ERROR_SUCCESS)
1854  hr = HRESULT_FROM_WIN32(err);
1855  else {
1856  len = sizeof(clsid);
1857  err = RegQueryValueEx(hpid, "", NULL, &dwtype, (BYTE *)clsid, &len);
1858  if (err == ERROR_SUCCESS && dwtype == REG_SZ) {
1859  pbuf = ole_mb2wc(clsid, -1, cWIN32OLE_cp);
1860  hr = CLSIDFromString(pbuf, pclsid);
1861  SysFreeString(pbuf);
1862  }
1863  else {
1864  hr = HRESULT_FROM_WIN32(err);
1865  }
1866  RegCloseKey(hpid);
1867  }
1868  RegCloseKey(hlm);
1869  return hr;
1870 }
1871 
1872 static VALUE
1873 ole_create_dcom(VALUE self, VALUE ole, VALUE host, VALUE others)
1874 {
1875  HRESULT hr;
1876  CLSID clsid;
1877  OLECHAR *pbuf;
1878 
1879  COSERVERINFO serverinfo;
1880  MULTI_QI multi_qi;
1881  DWORD clsctx = CLSCTX_REMOTE_SERVER;
1882 
1883  if (!gole32)
1884  gole32 = LoadLibrary("OLE32");
1885  if (!gole32)
1886  rb_raise(rb_eRuntimeError, "failed to load OLE32");
1887  if (!gCoCreateInstanceEx)
1888  gCoCreateInstanceEx = (FNCOCREATEINSTANCEEX*)
1889  GetProcAddress(gole32, "CoCreateInstanceEx");
1890  if (!gCoCreateInstanceEx)
1891  rb_raise(rb_eRuntimeError, "CoCreateInstanceEx is not supported in this environment");
1892 
1893  pbuf = ole_vstr2wc(ole);
1894  hr = CLSIDFromProgID(pbuf, &clsid);
1895  if (FAILED(hr))
1896  hr = clsid_from_remote(host, ole, &clsid);
1897  if (FAILED(hr))
1898  hr = CLSIDFromString(pbuf, &clsid);
1899  SysFreeString(pbuf);
1900  if (FAILED(hr))
1902  "unknown OLE server: `%s'",
1903  StringValuePtr(ole));
1904  memset(&serverinfo, 0, sizeof(COSERVERINFO));
1905  serverinfo.pwszName = ole_vstr2wc(host);
1906  memset(&multi_qi, 0, sizeof(MULTI_QI));
1907  multi_qi.pIID = &IID_IDispatch;
1908  hr = gCoCreateInstanceEx(&clsid, NULL, clsctx, &serverinfo, 1, &multi_qi);
1909  SysFreeString(serverinfo.pwszName);
1910  if (FAILED(hr))
1912  "failed to create DCOM server `%s' in `%s'",
1913  StringValuePtr(ole),
1914  StringValuePtr(host));
1915 
1916  ole_set_member(self, (IDispatch*)multi_qi.pItf);
1917  return self;
1918 }
1919 
1920 static VALUE
1921 ole_bind_obj(VALUE moniker, int argc, VALUE *argv, VALUE self)
1922 {
1923  IBindCtx *pBindCtx;
1924  IMoniker *pMoniker;
1925  IDispatch *pDispatch;
1926  void *p;
1927  HRESULT hr;
1928  OLECHAR *pbuf;
1929  ULONG eaten = 0;
1930 
1931  ole_initialize();
1932 
1933  hr = CreateBindCtx(0, &pBindCtx);
1934  if(FAILED(hr)) {
1936  "failed to create bind context");
1937  }
1938 
1939  pbuf = ole_vstr2wc(moniker);
1940  hr = MkParseDisplayName(pBindCtx, pbuf, &eaten, &pMoniker);
1941  SysFreeString(pbuf);
1942  if(FAILED(hr)) {
1943  OLE_RELEASE(pBindCtx);
1945  "failed to parse display name of moniker `%s'",
1946  StringValuePtr(moniker));
1947  }
1948  hr = pMoniker->lpVtbl->BindToObject(pMoniker, pBindCtx, NULL,
1949  &IID_IDispatch, &p);
1950  pDispatch = p;
1951  OLE_RELEASE(pMoniker);
1952  OLE_RELEASE(pBindCtx);
1953 
1954  if(FAILED(hr)) {
1956  "failed to bind moniker `%s'",
1957  StringValuePtr(moniker));
1958  }
1959  return create_win32ole_object(self, pDispatch, argc, argv);
1960 }
1961 
1962 /*
1963  * call-seq:
1964  * WIN32OLE.connect( ole ) --> aWIN32OLE
1965  *
1966  * Returns running OLE Automation object or WIN32OLE object from moniker.
1967  * 1st argument should be OLE program id or class id or moniker.
1968  *
1969  * WIN32OLE.connect('Excel.Application') # => WIN32OLE object which represents running Excel.
1970  */
1971 static VALUE
1972 fole_s_connect(int argc, VALUE *argv, VALUE self)
1973 {
1974  VALUE svr_name;
1975  VALUE others;
1976  HRESULT hr;
1977  CLSID clsid;
1978  OLECHAR *pBuf;
1979  IDispatch *pDispatch;
1980  void *p;
1981  IUnknown *pUnknown;
1982 
1983  /* initialize to use OLE */
1984  ole_initialize();
1985 
1986  rb_scan_args(argc, argv, "1*", &svr_name, &others);
1987  StringValue(svr_name);
1988 
1989  /* get CLSID from OLE server name */
1990  pBuf = ole_vstr2wc(svr_name);
1991  hr = CLSIDFromProgID(pBuf, &clsid);
1992  if(FAILED(hr)) {
1993  hr = CLSIDFromString(pBuf, &clsid);
1994  }
1995  SysFreeString(pBuf);
1996  if(FAILED(hr)) {
1997  return ole_bind_obj(svr_name, argc, argv, self);
1998  }
1999 
2000  hr = GetActiveObject(&clsid, 0, &pUnknown);
2001  if (FAILED(hr)) {
2003  "OLE server `%s' not running", StringValuePtr(svr_name));
2004  }
2005  hr = pUnknown->lpVtbl->QueryInterface(pUnknown, &IID_IDispatch, &p);
2006  pDispatch = p;
2007  if(FAILED(hr)) {
2008  OLE_RELEASE(pUnknown);
2010  "failed to create WIN32OLE server `%s'",
2011  StringValuePtr(svr_name));
2012  }
2013 
2014  OLE_RELEASE(pUnknown);
2015 
2016  return create_win32ole_object(self, pDispatch, argc, argv);
2017 }
2018 
2019 /*
2020  * call-seq:
2021  * WIN32OLE.const_load( ole, mod = WIN32OLE)
2022  *
2023  * Defines the constants of OLE Automation server as mod's constants.
2024  * The first argument is WIN32OLE object or type library name.
2025  * If 2nd argument is omitted, the default is WIN32OLE.
2026  * The first letter of Ruby's constant variable name is upper case,
2027  * so constant variable name of WIN32OLE object is capitalized.
2028  * For example, the 'xlTop' constant of Excel is changed to 'XlTop'
2029  * in WIN32OLE.
2030  * If the first letter of constant variable is not [A-Z], then
2031  * the constant is defined as CONSTANTS hash element.
2032  *
2033  * module EXCEL_CONST
2034  * end
2035  * excel = WIN32OLE.new('Excel.Application')
2036  * WIN32OLE.const_load(excel, EXCEL_CONST)
2037  * puts EXCEL_CONST::XlTop # => -4160
2038  * puts EXCEL_CONST::CONSTANTS['_xlDialogChartSourceData'] # => 541
2039  *
2040  * WIN32OLE.const_load(excel)
2041  * puts WIN32OLE::XlTop # => -4160
2042  *
2043  * module MSO
2044  * end
2045  * WIN32OLE.const_load('Microsoft Office 9.0 Object Library', MSO)
2046  * puts MSO::MsoLineSingle # => 1
2047  */
2048 static VALUE
2049 fole_s_const_load(int argc, VALUE *argv, VALUE self)
2050 {
2051  VALUE ole;
2052  VALUE klass;
2053  struct oledata *pole = NULL;
2054  ITypeInfo *pTypeInfo;
2055  ITypeLib *pTypeLib;
2056  unsigned int index;
2057  HRESULT hr;
2058  OLECHAR *pBuf;
2059  VALUE file;
2060  LCID lcid = cWIN32OLE_lcid;
2061 
2062  rb_scan_args(argc, argv, "11", &ole, &klass);
2063  if (!RB_TYPE_P(klass, T_CLASS) &&
2064  !RB_TYPE_P(klass, T_MODULE) &&
2065  !RB_TYPE_P(klass, T_NIL)) {
2066  rb_raise(rb_eTypeError, "2nd parameter must be Class or Module");
2067  }
2068  if (rb_obj_is_kind_of(ole, cWIN32OLE)) {
2069  pole = oledata_get_struct(ole);
2070  hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch,
2071  0, lcid, &pTypeInfo);
2072  if(FAILED(hr)) {
2073  ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to GetTypeInfo");
2074  }
2075  hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &index);
2076  if(FAILED(hr)) {
2077  OLE_RELEASE(pTypeInfo);
2078  ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to GetContainingTypeLib");
2079  }
2080  OLE_RELEASE(pTypeInfo);
2081  if(!RB_TYPE_P(klass, T_NIL)) {
2082  ole_const_load(pTypeLib, klass, self);
2083  }
2084  else {
2085  ole_const_load(pTypeLib, cWIN32OLE, self);
2086  }
2087  OLE_RELEASE(pTypeLib);
2088  }
2089  else if(RB_TYPE_P(ole, T_STRING)) {
2090  file = typelib_file(ole);
2091  if (file == Qnil) {
2092  file = ole;
2093  }
2094  pBuf = ole_vstr2wc(file);
2095  hr = LoadTypeLibEx(pBuf, REGKIND_NONE, &pTypeLib);
2096  SysFreeString(pBuf);
2097  if (FAILED(hr))
2098  ole_raise(hr, eWIN32OLERuntimeError, "failed to LoadTypeLibEx");
2099  if(!RB_TYPE_P(klass, T_NIL)) {
2100  ole_const_load(pTypeLib, klass, self);
2101  }
2102  else {
2103  ole_const_load(pTypeLib, cWIN32OLE, self);
2104  }
2105  OLE_RELEASE(pTypeLib);
2106  }
2107  else {
2108  rb_raise(rb_eTypeError, "1st parameter must be WIN32OLE instance");
2109  }
2110  return Qnil;
2111 }
2112 
2113 static ULONG
2114 reference_count(struct oledata * pole)
2115 {
2116  ULONG n = 0;
2117  if(pole->pDispatch) {
2118  OLE_ADDREF(pole->pDispatch);
2119  n = OLE_RELEASE(pole->pDispatch);
2120  }
2121  return n;
2122 }
2123 
2124 /*
2125  * call-seq:
2126  * WIN32OLE.ole_reference_count(aWIN32OLE) --> number
2127  *
2128  * Returns reference counter of Dispatch interface of WIN32OLE object.
2129  * You should not use this method because this method
2130  * exists only for debugging WIN32OLE.
2131  */
2132 static VALUE
2133 fole_s_reference_count(VALUE self, VALUE obj)
2134 {
2135  struct oledata * pole = NULL;
2136  pole = oledata_get_struct(obj);
2137  return RB_INT2NUM(reference_count(pole));
2138 }
2139 
2140 /*
2141  * call-seq:
2142  * WIN32OLE.ole_free(aWIN32OLE) --> number
2143  *
2144  * Invokes Release method of Dispatch interface of WIN32OLE object.
2145  * You should not use this method because this method
2146  * exists only for debugging WIN32OLE.
2147  * The return value is reference counter of OLE object.
2148  */
2149 static VALUE
2150 fole_s_free(VALUE self, VALUE obj)
2151 {
2152  ULONG n = 0;
2153  struct oledata * pole = NULL;
2154  pole = oledata_get_struct(obj);
2155  if(pole->pDispatch) {
2156  if (reference_count(pole) > 0) {
2157  n = OLE_RELEASE(pole->pDispatch);
2158  }
2159  }
2160  return RB_INT2NUM(n);
2161 }
2162 
2163 static HWND
2164 ole_show_help(VALUE helpfile, VALUE helpcontext)
2165 {
2166  FNHTMLHELP *pfnHtmlHelp;
2167  HWND hwnd = 0;
2168 
2169  if(!ghhctrl)
2170  ghhctrl = LoadLibrary("HHCTRL.OCX");
2171  if (!ghhctrl)
2172  return hwnd;
2173  pfnHtmlHelp = (FNHTMLHELP*)GetProcAddress(ghhctrl, "HtmlHelpA");
2174  if (!pfnHtmlHelp)
2175  return hwnd;
2176  hwnd = pfnHtmlHelp(GetDesktopWindow(), StringValuePtr(helpfile),
2177  0x0f, RB_NUM2INT(helpcontext));
2178  if (hwnd == 0)
2179  hwnd = pfnHtmlHelp(GetDesktopWindow(), StringValuePtr(helpfile),
2180  0, RB_NUM2INT(helpcontext));
2181  return hwnd;
2182 }
2183 
2184 /*
2185  * call-seq:
2186  * WIN32OLE.ole_show_help(obj [,helpcontext])
2187  *
2188  * Displays helpfile. The 1st argument specifies WIN32OLE_TYPE
2189  * object or WIN32OLE_METHOD object or helpfile.
2190  *
2191  * excel = WIN32OLE.new('Excel.Application')
2192  * typeobj = excel.ole_type
2193  * WIN32OLE.ole_show_help(typeobj)
2194  */
2195 static VALUE
2196 fole_s_show_help(int argc, VALUE *argv, VALUE self)
2197 {
2198  VALUE target;
2199  VALUE helpcontext;
2200  VALUE helpfile;
2201  VALUE name;
2202  HWND hwnd;
2203  rb_scan_args(argc, argv, "11", &target, &helpcontext);
2204  if (rb_obj_is_kind_of(target, cWIN32OLE_TYPE) ||
2206  helpfile = rb_funcall(target, rb_intern("helpfile"), 0);
2207  if(strlen(StringValuePtr(helpfile)) == 0) {
2208  name = rb_ivar_get(target, rb_intern("name"));
2209  rb_raise(rb_eRuntimeError, "no helpfile of `%s'",
2210  StringValuePtr(name));
2211  }
2212  helpcontext = rb_funcall(target, rb_intern("helpcontext"), 0);
2213  } else {
2214  helpfile = target;
2215  }
2216  if (!RB_TYPE_P(helpfile, T_STRING)) {
2217  rb_raise(rb_eTypeError, "1st parameter must be (String|WIN32OLE_TYPE|WIN32OLE_METHOD)");
2218  }
2219  hwnd = ole_show_help(helpfile, helpcontext);
2220  if(hwnd == 0) {
2221  rb_raise(rb_eRuntimeError, "failed to open help file `%s'",
2222  StringValuePtr(helpfile));
2223  }
2224  return Qnil;
2225 }
2226 
2227 /*
2228  * call-seq:
2229  * WIN32OLE.codepage
2230  *
2231  * Returns current codepage.
2232  * WIN32OLE.codepage # => WIN32OLE::CP_ACP
2233  */
2234 static VALUE
2235 fole_s_get_code_page(VALUE self)
2236 {
2237  return RB_INT2FIX(cWIN32OLE_cp);
2238 }
2239 
2240 static BOOL CALLBACK
2241 installed_code_page_proc(LPTSTR str) {
2242  if (strtoul(str, NULL, 10) == g_cp_to_check) {
2243  g_cp_installed = TRUE;
2244  return FALSE;
2245  }
2246  return TRUE;
2247 }
2248 
2249 static BOOL
2250 code_page_installed(UINT cp)
2251 {
2252  g_cp_installed = FALSE;
2253  g_cp_to_check = cp;
2254  EnumSystemCodePages(installed_code_page_proc, CP_INSTALLED);
2255  return g_cp_installed;
2256 }
2257 
2258 /*
2259  * call-seq:
2260  * WIN32OLE.codepage = CP
2261  *
2262  * Sets current codepage.
2263  * The WIN32OLE.codepage is initialized according to
2264  * Encoding.default_internal.
2265  * If Encoding.default_internal is nil then WIN32OLE.codepage
2266  * is initialized according to Encoding.default_external.
2267  *
2268  * WIN32OLE.codepage = WIN32OLE::CP_UTF8
2269  * WIN32OLE.codepage = 65001
2270  */
2271 static VALUE
2272 fole_s_set_code_page(VALUE self, VALUE vcp)
2273 {
2274  UINT cp = RB_FIX2INT(vcp);
2275  set_ole_codepage(cp);
2276  /*
2277  * Should this method return old codepage?
2278  */
2279  return Qnil;
2280 }
2281 
2282 /*
2283  * call-seq:
2284  * WIN32OLE.locale -> locale id.
2285  *
2286  * Returns current locale id (lcid). The default locale is
2287  * WIN32OLE::LOCALE_SYSTEM_DEFAULT.
2288  *
2289  * lcid = WIN32OLE.locale
2290  */
2291 static VALUE
2292 fole_s_get_locale(VALUE self)
2293 {
2294  return RB_INT2FIX(cWIN32OLE_lcid);
2295 }
2296 
2297 static BOOL
2298 CALLBACK installed_lcid_proc(LPTSTR str)
2299 {
2300  if (strcmp(str, g_lcid_to_check) == 0) {
2301  g_lcid_installed = TRUE;
2302  return FALSE;
2303  }
2304  return TRUE;
2305 }
2306 
2307 static BOOL
2308 lcid_installed(LCID lcid)
2309 {
2310  g_lcid_installed = FALSE;
2311  snprintf(g_lcid_to_check, sizeof(g_lcid_to_check), "%08lx", (unsigned long)lcid);
2312  EnumSystemLocales(installed_lcid_proc, LCID_INSTALLED);
2313  return g_lcid_installed;
2314 }
2315 
2316 /*
2317  * call-seq:
2318  * WIN32OLE.locale = lcid
2319  *
2320  * Sets current locale id (lcid).
2321  *
2322  * WIN32OLE.locale = 1033 # set locale English(U.S)
2323  * obj = WIN32OLE_VARIANT.new("$100,000", WIN32OLE::VARIANT::VT_CY)
2324  *
2325  */
2326 static VALUE
2327 fole_s_set_locale(VALUE self, VALUE vlcid)
2328 {
2329  LCID lcid = RB_FIX2INT(vlcid);
2330  if (lcid_installed(lcid)) {
2331  cWIN32OLE_lcid = lcid;
2332  } else {
2333  switch (lcid) {
2334  case LOCALE_SYSTEM_DEFAULT:
2335  case LOCALE_USER_DEFAULT:
2336  cWIN32OLE_lcid = lcid;
2337  break;
2338  default:
2339  rb_raise(eWIN32OLERuntimeError, "not installed locale: %u", (unsigned int)lcid);
2340  }
2341  }
2342  return Qnil;
2343 }
2344 
2345 /*
2346  * call-seq:
2347  * WIN32OLE.create_guid
2348  *
2349  * Creates GUID.
2350  * WIN32OLE.create_guid # => {1CB530F1-F6B1-404D-BCE6-1959BF91F4A8}
2351  */
2352 static VALUE
2353 fole_s_create_guid(VALUE self)
2354 {
2355  GUID guid;
2356  HRESULT hr;
2357  OLECHAR bstr[80];
2358  int len = 0;
2359  hr = CoCreateGuid(&guid);
2360  if (FAILED(hr)) {
2361  ole_raise(hr, eWIN32OLERuntimeError, "failed to create GUID");
2362  }
2363  len = StringFromGUID2(&guid, bstr, sizeof(bstr)/sizeof(OLECHAR));
2364  if (len == 0) {
2365  rb_raise(rb_eRuntimeError, "failed to create GUID(buffer over)");
2366  }
2367  return ole_wc2vstr(bstr, FALSE);
2368 }
2369 
2370 /*
2371  * WIN32OLE.ole_initialize and WIN32OLE.ole_uninitialize
2372  * are used in win32ole.rb to fix the issue bug #2618 (ruby-core:27634).
2373  * You must not use these method.
2374  */
2375 
2376 /* :nodoc: */
2377 static VALUE
2378 fole_s_ole_initialize(VALUE self)
2379 {
2380  ole_initialize();
2381  return Qnil;
2382 }
2383 
2384 /* :nodoc: */
2385 static VALUE
2386 fole_s_ole_uninitialize(VALUE self)
2387 {
2388  ole_uninitialize();
2389  return Qnil;
2390 }
2391 
2392 /*
2393  * Document-class: WIN32OLE
2394  *
2395  * <code>WIN32OLE</code> objects represent OLE Automation object in Ruby.
2396  *
2397  * By using WIN32OLE, you can access OLE server like VBScript.
2398  *
2399  * Here is sample script.
2400  *
2401  * require 'win32ole'
2402  *
2403  * excel = WIN32OLE.new('Excel.Application')
2404  * excel.visible = true
2405  * workbook = excel.Workbooks.Add();
2406  * worksheet = workbook.Worksheets(1);
2407  * worksheet.Range("A1:D1").value = ["North","South","East","West"];
2408  * worksheet.Range("A2:B2").value = [5.2, 10];
2409  * worksheet.Range("C2").value = 8;
2410  * worksheet.Range("D2").value = 20;
2411  *
2412  * range = worksheet.Range("A1:D2");
2413  * range.select
2414  * chart = workbook.Charts.Add;
2415  *
2416  * workbook.saved = true;
2417  *
2418  * excel.ActiveWorkbook.Close(0);
2419  * excel.Quit();
2420  *
2421  * Unfortunately, Win32OLE doesn't support the argument passed by
2422  * reference directly.
2423  * Instead, Win32OLE provides WIN32OLE::ARGV or WIN32OLE_VARIANT object.
2424  * If you want to get the result value of argument passed by reference,
2425  * you can use WIN32OLE::ARGV or WIN32OLE_VARIANT.
2426  *
2427  * oleobj.method(arg1, arg2, refargv3)
2428  * puts WIN32OLE::ARGV[2] # the value of refargv3 after called oleobj.method
2429  *
2430  * or
2431  *
2432  * refargv3 = WIN32OLE_VARIANT.new(XXX,
2433  * WIN32OLE::VARIANT::VT_BYREF|WIN32OLE::VARIANT::VT_XXX)
2434  * oleobj.method(arg1, arg2, refargv3)
2435  * p refargv3.value # the value of refargv3 after called oleobj.method.
2436  *
2437  */
2438 
2439 /*
2440  * call-seq:
2441  * WIN32OLE.new(server, [host]) -> WIN32OLE object
2442  * WIN32OLE.new(server, license: 'key') -> WIN32OLE object
2443  *
2444  * Returns a new WIN32OLE object(OLE Automation object).
2445  * The first argument server specifies OLE Automation server.
2446  * The first argument should be CLSID or PROGID.
2447  * If second argument host specified, then returns OLE Automation
2448  * object on host.
2449  * If :license keyword argument is provided,
2450  * IClassFactory2::CreateInstanceLic is used to create instance of
2451  * licensed server.
2452  *
2453  * WIN32OLE.new('Excel.Application') # => Excel OLE Automation WIN32OLE object.
2454  * WIN32OLE.new('{00024500-0000-0000-C000-000000000046}') # => Excel OLE Automation WIN32OLE object.
2455  */
2456 static VALUE
2457 fole_initialize(int argc, VALUE *argv, VALUE self)
2458 {
2459  VALUE svr_name;
2460  VALUE host;
2461  VALUE others;
2462  VALUE opts;
2463  HRESULT hr;
2464  CLSID clsid;
2465  OLECHAR *pBuf;
2466  OLECHAR *key_buf;
2467  IDispatch *pDispatch;
2468  IClassFactory2 * pIClassFactory2;
2469  void *p;
2470  static ID keyword_ids[1];
2471  VALUE kwargs[1];
2472 
2473  rb_call_super(0, 0);
2474  rb_scan_args(argc, argv, "11*:", &svr_name, &host, &others, &opts);
2475 
2476  StringValue(svr_name);
2477  if (!NIL_P(host)) {
2478  StringValue(host);
2479  return ole_create_dcom(self, svr_name, host, others);
2480  }
2481 
2482  /* get CLSID from OLE server name */
2483  pBuf = ole_vstr2wc(svr_name);
2484  hr = CLSIDFromProgID(pBuf, &clsid);
2485  if(FAILED(hr)) {
2486  hr = CLSIDFromString(pBuf, &clsid);
2487  }
2488  SysFreeString(pBuf);
2489  if(FAILED(hr)) {
2491  "unknown OLE server: `%s'",
2492  StringValuePtr(svr_name));
2493  }
2494 
2495  if (!keyword_ids[0]) {
2496  keyword_ids[0] = rb_intern_const("license");
2497  }
2498  rb_get_kwargs(opts, keyword_ids, 0, 1, kwargs);
2499 
2500  if (kwargs[0] == Qundef) {
2501  /* get IDispatch interface */
2502  hr = CoCreateInstance(
2503  &clsid,
2504  NULL,
2505  CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
2506  &IID_IDispatch,
2507  &p
2508  );
2509  } else {
2510  hr = CoGetClassObject(
2511  &clsid,
2512  CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
2513  NULL,
2514  &IID_IClassFactory2,
2515  (LPVOID)&pIClassFactory2
2516  );
2517  if (hr == S_OK) {
2518  key_buf = ole_vstr2wc(kwargs[0]);
2519  hr = pIClassFactory2->lpVtbl->CreateInstanceLic(pIClassFactory2, NULL, NULL, &IID_IDispatch, key_buf, &p);
2520  SysFreeString(key_buf);
2521  OLE_RELEASE(pIClassFactory2);
2522  }
2523  }
2524  pDispatch = p;
2525  if(FAILED(hr)) {
2527  "failed to create WIN32OLE object from `%s'",
2528  StringValuePtr(svr_name));
2529  }
2530 
2531  ole_set_member(self, pDispatch);
2532  return self;
2533 }
2534 
2535 static int
2536 hash2named_arg(VALUE key, VALUE val, VALUE pop)
2537 {
2538  struct oleparam* pOp = (struct oleparam *)pop;
2539  unsigned int index, i;
2540  index = pOp->dp.cNamedArgs;
2541  /*---------------------------------------------
2542  the data-type of key must be String or Symbol
2543  -----------------------------------------------*/
2544  if(!RB_TYPE_P(key, T_STRING) && !RB_TYPE_P(key, T_SYMBOL)) {
2545  /* clear name of dispatch parameters */
2546  for(i = 1; i < index + 1; i++) {
2547  SysFreeString(pOp->pNamedArgs[i]);
2548  }
2549  /* clear dispatch parameters */
2550  for(i = 0; i < index; i++ ) {
2551  VariantClear(&(pOp->dp.rgvarg[i]));
2552  }
2553  /* raise an exception */
2554  rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)");
2555  }
2556  if (RB_TYPE_P(key, T_SYMBOL)) {
2557  key = rb_sym2str(key);
2558  }
2559 
2560  /* pNamedArgs[0] is <method name>, so "index + 1" */
2561  pOp->pNamedArgs[index + 1] = ole_vstr2wc(key);
2562 
2563  VariantInit(&(pOp->dp.rgvarg[index]));
2564  ole_val2variant(val, &(pOp->dp.rgvarg[index]));
2565 
2566  pOp->dp.cNamedArgs += 1;
2567  return ST_CONTINUE;
2568 }
2569 
2570 static VALUE
2571 set_argv(VARIANTARG* realargs, unsigned int beg, unsigned int end)
2572 {
2574 
2576  rb_ary_clear(argv);
2577  while (end-- > beg) {
2578  rb_ary_push(argv, ole_variant2val(&realargs[end]));
2579  if (V_VT(&realargs[end]) != VT_RECORD) {
2580  VariantClear(&realargs[end]);
2581  }
2582  }
2583  return argv;
2584 }
2585 
2586 static VALUE
2587 ole_invoke(int argc, VALUE *argv, VALUE self, USHORT wFlags, BOOL is_bracket)
2588 {
2589  LCID lcid = cWIN32OLE_lcid;
2590  struct oledata *pole = NULL;
2591  HRESULT hr;
2592  VALUE cmd;
2593  VALUE paramS;
2594  VALUE param;
2595  VALUE obj;
2596  VALUE v;
2597 
2598  BSTR wcmdname;
2599 
2600  DISPID DispID;
2601  DISPID* pDispID;
2602  EXCEPINFO excepinfo;
2603  VARIANT result;
2604  VARIANTARG* realargs = NULL;
2605  unsigned int argErr = 0;
2606  unsigned int i;
2607  unsigned int cNamedArgs;
2608  int n;
2609  struct oleparam op;
2610  memset(&excepinfo, 0, sizeof(EXCEPINFO));
2611 
2612  VariantInit(&result);
2613 
2614  op.dp.rgvarg = NULL;
2615  op.dp.rgdispidNamedArgs = NULL;
2616  op.dp.cNamedArgs = 0;
2617  op.dp.cArgs = 0;
2618 
2619  rb_scan_args(argc, argv, "1*", &cmd, &paramS);
2620  if(!RB_TYPE_P(cmd, T_STRING) && !RB_TYPE_P(cmd, T_SYMBOL) && !is_bracket) {
2621  rb_raise(rb_eTypeError, "method is wrong type (expected String or Symbol)");
2622  }
2623  if (RB_TYPE_P(cmd, T_SYMBOL)) {
2624  cmd = rb_sym2str(cmd);
2625  }
2626  pole = oledata_get_struct(self);
2627  if(!pole->pDispatch) {
2628  rb_raise(rb_eRuntimeError, "failed to get dispatch interface");
2629  }
2630  if (is_bracket) {
2631  DispID = DISPID_VALUE;
2632  argc += 1;
2633  rb_ary_unshift(paramS, cmd);
2634  } else {
2635  wcmdname = ole_vstr2wc(cmd);
2636  hr = pole->pDispatch->lpVtbl->GetIDsOfNames( pole->pDispatch, &IID_NULL,
2637  &wcmdname, 1, lcid, &DispID);
2638  SysFreeString(wcmdname);
2639  if(FAILED(hr)) {
2640  return rb_eNoMethodError;
2641  }
2642  }
2643 
2644  /* pick up last argument of method */
2645  param = rb_ary_entry(paramS, argc-2);
2646 
2647  op.dp.cNamedArgs = 0;
2648 
2649  /* if last arg is hash object */
2650  if(RB_TYPE_P(param, T_HASH)) {
2651  /*------------------------------------------
2652  hash object ==> named dispatch parameters
2653  --------------------------------------------*/
2654  cNamedArgs = rb_long2int(RHASH_SIZE(param));
2655  op.dp.cArgs = cNamedArgs + argc - 2;
2656  op.pNamedArgs = ALLOCA_N(OLECHAR*, cNamedArgs + 1);
2657  op.dp.rgvarg = ALLOCA_N(VARIANTARG, op.dp.cArgs);
2658 
2659  rb_hash_foreach(param, hash2named_arg, (VALUE)&op);
2660 
2661  pDispID = ALLOCA_N(DISPID, cNamedArgs + 1);
2662  op.pNamedArgs[0] = ole_vstr2wc(cmd);
2663  hr = pole->pDispatch->lpVtbl->GetIDsOfNames(pole->pDispatch,
2664  &IID_NULL,
2665  op.pNamedArgs,
2666  op.dp.cNamedArgs + 1,
2667  lcid, pDispID);
2668  for(i = 0; i < op.dp.cNamedArgs + 1; i++) {
2669  SysFreeString(op.pNamedArgs[i]);
2670  op.pNamedArgs[i] = NULL;
2671  }
2672  if(FAILED(hr)) {
2673  /* clear dispatch parameters */
2674  for(i = 0; i < op.dp.cArgs; i++ ) {
2675  VariantClear(&op.dp.rgvarg[i]);
2676  }
2678  "failed to get named argument info: `%s'",
2679  StringValuePtr(cmd));
2680  }
2681  op.dp.rgdispidNamedArgs = &(pDispID[1]);
2682  }
2683  else {
2684  cNamedArgs = 0;
2685  op.dp.cArgs = argc - 1;
2686  op.pNamedArgs = ALLOCA_N(OLECHAR*, cNamedArgs + 1);
2687  if (op.dp.cArgs > 0) {
2688  op.dp.rgvarg = ALLOCA_N(VARIANTARG, op.dp.cArgs);
2689  }
2690  }
2691  /*--------------------------------------
2692  non hash args ==> dispatch parameters
2693  ----------------------------------------*/
2694  if(op.dp.cArgs > cNamedArgs) {
2695  realargs = ALLOCA_N(VARIANTARG, op.dp.cArgs-cNamedArgs+1);
2696  for(i = cNamedArgs; i < op.dp.cArgs; i++) {
2697  n = op.dp.cArgs - i + cNamedArgs - 1;
2698  VariantInit(&realargs[n]);
2699  VariantInit(&op.dp.rgvarg[n]);
2700  param = rb_ary_entry(paramS, i-cNamedArgs);
2701  if (rb_obj_is_kind_of(param, cWIN32OLE_VARIANT)) {
2702  ole_variant2variant(param, &op.dp.rgvarg[n]);
2703  } else if (rb_obj_is_kind_of(param, cWIN32OLE_RECORD)) {
2704  ole_val2variant(param, &realargs[n]);
2705  op.dp.rgvarg[n] = realargs[n];
2706  V_VT(&op.dp.rgvarg[n]) = VT_RECORD | VT_BYREF;
2707  } else {
2708  ole_val2variant(param, &realargs[n]);
2709  V_VT(&op.dp.rgvarg[n]) = VT_VARIANT | VT_BYREF;
2710  V_VARIANTREF(&op.dp.rgvarg[n]) = &realargs[n];
2711  }
2712  }
2713  }
2714  /* apparent you need to call propput, you need this */
2715  if (wFlags & DISPATCH_PROPERTYPUT) {
2716  if (op.dp.cArgs == 0)
2717  ole_raise(ResultFromScode(E_INVALIDARG), eWIN32OLERuntimeError, "argument error");
2718 
2719  op.dp.cNamedArgs = 1;
2720  op.dp.rgdispidNamedArgs = ALLOCA_N( DISPID, 1 );
2721  op.dp.rgdispidNamedArgs[0] = DISPID_PROPERTYPUT;
2722  }
2723  hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
2724  &IID_NULL, lcid, wFlags, &op.dp,
2725  &result, &excepinfo, &argErr);
2726 
2727  if (FAILED(hr)) {
2728  /* retry to call args by value */
2729  if(op.dp.cArgs >= cNamedArgs) {
2730  for(i = cNamedArgs; i < op.dp.cArgs; i++) {
2731  n = op.dp.cArgs - i + cNamedArgs - 1;
2732  param = rb_ary_entry(paramS, i-cNamedArgs);
2733  ole_val2variant(param, &op.dp.rgvarg[n]);
2734  }
2735  if (hr == DISP_E_EXCEPTION) {
2736  ole_freeexceptinfo(&excepinfo);
2737  }
2738  memset(&excepinfo, 0, sizeof(EXCEPINFO));
2739  VariantInit(&result);
2740  hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
2741  &IID_NULL, lcid, wFlags,
2742  &op.dp, &result,
2743  &excepinfo, &argErr);
2744 
2745  /* mega kludge. if a method in WORD is called and we ask
2746  * for a result when one is not returned then
2747  * hResult == DISP_E_EXCEPTION. this only happens on
2748  * functions whose DISPID > 0x8000 */
2749  if ((hr == DISP_E_EXCEPTION || hr == DISP_E_MEMBERNOTFOUND) && DispID > 0x8000) {
2750  if (hr == DISP_E_EXCEPTION) {
2751  ole_freeexceptinfo(&excepinfo);
2752  }
2753  memset(&excepinfo, 0, sizeof(EXCEPINFO));
2754  hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
2755  &IID_NULL, lcid, wFlags,
2756  &op.dp, NULL,
2757  &excepinfo, &argErr);
2758 
2759  }
2760  for(i = cNamedArgs; i < op.dp.cArgs; i++) {
2761  n = op.dp.cArgs - i + cNamedArgs - 1;
2762  if (V_VT(&op.dp.rgvarg[n]) != VT_RECORD) {
2763  VariantClear(&op.dp.rgvarg[n]);
2764  }
2765  }
2766  }
2767 
2768  if (FAILED(hr)) {
2769  /* retry after converting nil to VT_EMPTY */
2770  if (op.dp.cArgs > cNamedArgs) {
2771  for(i = cNamedArgs; i < op.dp.cArgs; i++) {
2772  n = op.dp.cArgs - i + cNamedArgs - 1;
2773  param = rb_ary_entry(paramS, i-cNamedArgs);
2774  ole_val2variant2(param, &op.dp.rgvarg[n]);
2775  }
2776  if (hr == DISP_E_EXCEPTION) {
2777  ole_freeexceptinfo(&excepinfo);
2778  }
2779  memset(&excepinfo, 0, sizeof(EXCEPINFO));
2780  VariantInit(&result);
2781  hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID,
2782  &IID_NULL, lcid, wFlags,
2783  &op.dp, &result,
2784  &excepinfo, &argErr);
2785  for(i = cNamedArgs; i < op.dp.cArgs; i++) {
2786  n = op.dp.cArgs - i + cNamedArgs - 1;
2787  if (V_VT(&op.dp.rgvarg[n]) != VT_RECORD) {
2788  VariantClear(&op.dp.rgvarg[n]);
2789  }
2790  }
2791  }
2792  }
2793 
2794  }
2795  /* clear dispatch parameter */
2796  if(op.dp.cArgs > cNamedArgs) {
2797  for(i = cNamedArgs; i < op.dp.cArgs; i++) {
2798  n = op.dp.cArgs - i + cNamedArgs - 1;
2799  param = rb_ary_entry(paramS, i-cNamedArgs);
2800  if (rb_obj_is_kind_of(param, cWIN32OLE_VARIANT)) {
2801  ole_val2variant(param, &realargs[n]);
2802  } else if ( rb_obj_is_kind_of(param, cWIN32OLE_RECORD) &&
2803  V_VT(&realargs[n]) == VT_RECORD ) {
2804  olerecord_set_ivar(param, V_RECORDINFO(&realargs[n]), V_RECORD(&realargs[n]));
2805  }
2806  }
2807  set_argv(realargs, cNamedArgs, op.dp.cArgs);
2808  }
2809  else {
2810  for(i = 0; i < op.dp.cArgs; i++) {
2811  VariantClear(&op.dp.rgvarg[i]);
2812  }
2813  }
2814 
2815  if (FAILED(hr)) {
2816  v = ole_excepinfo2msg(&excepinfo);
2817  ole_raise(hr, eWIN32OLERuntimeError, "(in OLE method `%s': )%s",
2818  StringValuePtr(cmd),
2819  StringValuePtr(v));
2820  }
2821  obj = ole_variant2val(&result);
2822  VariantClear(&result);
2823  return obj;
2824 }
2825 
2826 /*
2827  * call-seq:
2828  * WIN32OLE#invoke(method, [arg1,...]) => return value of method.
2829  *
2830  * Runs OLE method.
2831  * The first argument specifies the method name of OLE Automation object.
2832  * The others specify argument of the <i>method</i>.
2833  * If you can not execute <i>method</i> directly, then use this method instead.
2834  *
2835  * excel = WIN32OLE.new('Excel.Application')
2836  * excel.invoke('Quit') # => same as excel.Quit
2837  *
2838  */
2839 static VALUE
2840 fole_invoke(int argc, VALUE *argv, VALUE self)
2841 {
2842  VALUE v = ole_invoke(argc, argv, self, DISPATCH_METHOD|DISPATCH_PROPERTYGET, FALSE);
2843  if (v == rb_eNoMethodError) {
2844  return rb_call_super(argc, argv);
2845  }
2846  return v;
2847 }
2848 
2849 static VALUE
2850 ole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types, USHORT dispkind)
2851 {
2852  HRESULT hr;
2853  struct oledata *pole = NULL;
2854  unsigned int argErr = 0;
2855  EXCEPINFO excepinfo;
2856  VARIANT result;
2857  DISPPARAMS dispParams;
2858  VARIANTARG* realargs = NULL;
2859  int i, j; VALUE obj = Qnil;
2860  VALUE tp, param;
2861  VALUE v;
2862  VARTYPE vt;
2863 
2864  Check_Type(args, T_ARRAY);
2866 
2867  memset(&excepinfo, 0, sizeof(EXCEPINFO));
2868  memset(&dispParams, 0, sizeof(DISPPARAMS));
2869  VariantInit(&result);
2870  pole = oledata_get_struct(self);
2871 
2872  dispParams.cArgs = RARRAY_LEN(args);
2873  dispParams.rgvarg = ALLOCA_N(VARIANTARG, dispParams.cArgs);
2874  realargs = ALLOCA_N(VARIANTARG, dispParams.cArgs);
2875  for (i = 0, j = dispParams.cArgs - 1; i < (int)dispParams.cArgs; i++, j--)
2876  {
2877  VariantInit(&realargs[i]);
2878  VariantInit(&dispParams.rgvarg[i]);
2879  tp = rb_ary_entry(types, j);
2880  vt = (VARTYPE)RB_FIX2INT(tp);
2881  V_VT(&dispParams.rgvarg[i]) = vt;
2882  param = rb_ary_entry(args, j);
2883  if (param == Qnil)
2884  {
2885 
2886  V_VT(&dispParams.rgvarg[i]) = V_VT(&realargs[i]) = VT_ERROR;
2887  V_ERROR(&dispParams.rgvarg[i]) = V_ERROR(&realargs[i]) = DISP_E_PARAMNOTFOUND;
2888  }
2889  else
2890  {
2891  if (vt & VT_ARRAY)
2892  {
2893  int ent;
2894  LPBYTE pb;
2895  short* ps;
2896  LPLONG pl;
2897  VARIANT* pv;
2898  CY *py;
2899  VARTYPE v;
2900  SAFEARRAYBOUND rgsabound[1];
2901  Check_Type(param, T_ARRAY);
2902  rgsabound[0].lLbound = 0;
2903  rgsabound[0].cElements = RARRAY_LEN(param);
2904  v = vt & ~(VT_ARRAY | VT_BYREF);
2905  V_ARRAY(&realargs[i]) = SafeArrayCreate(v, 1, rgsabound);
2906  V_VT(&realargs[i]) = VT_ARRAY | v;
2907  SafeArrayLock(V_ARRAY(&realargs[i]));
2908  pb = V_ARRAY(&realargs[i])->pvData;
2909  ps = V_ARRAY(&realargs[i])->pvData;
2910  pl = V_ARRAY(&realargs[i])->pvData;
2911  py = V_ARRAY(&realargs[i])->pvData;
2912  pv = V_ARRAY(&realargs[i])->pvData;
2913  for (ent = 0; ent < (int)rgsabound[0].cElements; ent++)
2914  {
2915  VARIANT velem;
2916  VALUE elem = rb_ary_entry(param, ent);
2917  ole_val2variant(elem, &velem);
2918  if (v != VT_VARIANT)
2919  {
2920  VariantChangeTypeEx(&velem, &velem,
2921  cWIN32OLE_lcid, 0, v);
2922  }
2923  switch (v)
2924  {
2925  /* 128 bits */
2926  case VT_VARIANT:
2927  *pv++ = velem;
2928  break;
2929  /* 64 bits */
2930  case VT_R8:
2931  case VT_CY:
2932  case VT_DATE:
2933  *py++ = V_CY(&velem);
2934  break;
2935  /* 16 bits */
2936  case VT_BOOL:
2937  case VT_I2:
2938  case VT_UI2:
2939  *ps++ = V_I2(&velem);
2940  break;
2941  /* 8 bites */
2942  case VT_UI1:
2943  case VT_I1:
2944  *pb++ = V_UI1(&velem);
2945  break;
2946  /* 32 bits */
2947  default:
2948  *pl++ = V_I4(&velem);
2949  break;
2950  }
2951  }
2952  SafeArrayUnlock(V_ARRAY(&realargs[i]));
2953  }
2954  else
2955  {
2956  ole_val2variant(param, &realargs[i]);
2957  if ((vt & (~VT_BYREF)) != VT_VARIANT)
2958  {
2959  hr = VariantChangeTypeEx(&realargs[i], &realargs[i],
2960  cWIN32OLE_lcid, 0,
2961  (VARTYPE)(vt & (~VT_BYREF)));
2962  if (hr != S_OK)
2963  {
2964  rb_raise(rb_eTypeError, "not valid value");
2965  }
2966  }
2967  }
2968  if ((vt & VT_BYREF) || vt == VT_VARIANT)
2969  {
2970  if (vt == VT_VARIANT)
2971  V_VT(&dispParams.rgvarg[i]) = VT_VARIANT | VT_BYREF;
2972  switch (vt & (~VT_BYREF))
2973  {
2974  /* 128 bits */
2975  case VT_VARIANT:
2976  V_VARIANTREF(&dispParams.rgvarg[i]) = &realargs[i];
2977  break;
2978  /* 64 bits */
2979  case VT_R8:
2980  case VT_CY:
2981  case VT_DATE:
2982  V_CYREF(&dispParams.rgvarg[i]) = &V_CY(&realargs[i]);
2983  break;
2984  /* 16 bits */
2985  case VT_BOOL:
2986  case VT_I2:
2987  case VT_UI2:
2988  V_I2REF(&dispParams.rgvarg[i]) = &V_I2(&realargs[i]);
2989  break;
2990  /* 8 bites */
2991  case VT_UI1:
2992  case VT_I1:
2993  V_UI1REF(&dispParams.rgvarg[i]) = &V_UI1(&realargs[i]);
2994  break;
2995  /* 32 bits */
2996  default:
2997  V_I4REF(&dispParams.rgvarg[i]) = &V_I4(&realargs[i]);
2998  break;
2999  }
3000  }
3001  else
3002  {
3003  /* copy 64 bits of data */
3004  V_CY(&dispParams.rgvarg[i]) = V_CY(&realargs[i]);
3005  }
3006  }
3007  }
3008 
3009  if (dispkind & DISPATCH_PROPERTYPUT) {
3010  dispParams.cNamedArgs = 1;
3011  dispParams.rgdispidNamedArgs = ALLOCA_N( DISPID, 1 );
3012  dispParams.rgdispidNamedArgs[0] = DISPID_PROPERTYPUT;
3013  }
3014 
3015  hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, RB_NUM2INT(dispid),
3016  &IID_NULL, cWIN32OLE_lcid,
3017  dispkind,
3018  &dispParams, &result,
3019  &excepinfo, &argErr);
3020 
3021  if (FAILED(hr)) {
3022  v = ole_excepinfo2msg(&excepinfo);
3023  ole_raise(hr, eWIN32OLERuntimeError, "(in OLE method `<dispatch id:%d>': )%s",
3024  RB_NUM2INT(dispid),
3025  StringValuePtr(v));
3026  }
3027 
3028  /* clear dispatch parameter */
3029  if(dispParams.cArgs > 0) {
3030  set_argv(realargs, 0, dispParams.cArgs);
3031  }
3032 
3033  obj = ole_variant2val(&result);
3034  VariantClear(&result);
3035  return obj;
3036 }
3037 
3038 /*
3039  * call-seq:
3040  * WIN32OLE#_invoke(dispid, args, types)
3041  *
3042  * Runs the early binding method.
3043  * The 1st argument specifies dispatch ID,
3044  * the 2nd argument specifies the array of arguments,
3045  * the 3rd argument specifies the array of the type of arguments.
3046  *
3047  * excel = WIN32OLE.new('Excel.Application')
3048  * excel._invoke(302, [], []) # same effect as excel.Quit
3049  */
3050 static VALUE
3051 fole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types)
3052 {
3053  return ole_invoke2(self, dispid, args, types, DISPATCH_METHOD);
3054 }
3055 
3056 /*
3057  * call-seq:
3058  * WIN32OLE#_getproperty(dispid, args, types)
3059  *
3060  * Runs the early binding method to get property.
3061  * The 1st argument specifies dispatch ID,
3062  * the 2nd argument specifies the array of arguments,
3063  * the 3rd argument specifies the array of the type of arguments.
3064  *
3065  * excel = WIN32OLE.new('Excel.Application')
3066  * puts excel._getproperty(558, [], []) # same effect as puts excel.visible
3067  */
3068 static VALUE
3069 fole_getproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types)
3070 {
3071  return ole_invoke2(self, dispid, args, types, DISPATCH_PROPERTYGET);
3072 }
3073 
3074 /*
3075  * call-seq:
3076  * WIN32OLE#_setproperty(dispid, args, types)
3077  *
3078  * Runs the early binding method to set property.
3079  * The 1st argument specifies dispatch ID,
3080  * the 2nd argument specifies the array of arguments,
3081  * the 3rd argument specifies the array of the type of arguments.
3082  *
3083  * excel = WIN32OLE.new('Excel.Application')
3084  * excel._setproperty(558, [true], [WIN32OLE::VARIANT::VT_BOOL]) # same effect as excel.visible = true
3085  */
3086 static VALUE
3087 fole_setproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types)
3088 {
3089  return ole_invoke2(self, dispid, args, types, DISPATCH_PROPERTYPUT);
3090 }
3091 
3092 /*
3093  * call-seq:
3094  * WIN32OLE[a1, a2, ...]=val
3095  *
3096  * Sets the value to WIN32OLE object specified by a1, a2, ...
3097  *
3098  * dict = WIN32OLE.new('Scripting.Dictionary')
3099  * dict.add('ruby', 'RUBY')
3100  * dict['ruby'] = 'Ruby'
3101  * puts dict['ruby'] # => 'Ruby'
3102  *
3103  * Remark: You can not use this method to set the property value.
3104  *
3105  * excel = WIN32OLE.new('Excel.Application')
3106  * # excel['Visible'] = true # This is error !!!
3107  * excel.Visible = true # You should to use this style to set the property.
3108  *
3109  */
3110 static VALUE
3111 fole_setproperty_with_bracket(int argc, VALUE *argv, VALUE self)
3112 {
3113  VALUE v = ole_invoke(argc, argv, self, DISPATCH_PROPERTYPUT, TRUE);
3114  if (v == rb_eNoMethodError) {
3115  return rb_call_super(argc, argv);
3116  }
3117  return v;
3118 }
3119 
3120 /*
3121  * call-seq:
3122  * WIN32OLE.setproperty('property', [arg1, arg2,...] val)
3123  *
3124  * Sets property of OLE object.
3125  * When you want to set property with argument, you can use this method.
3126  *
3127  * excel = WIN32OLE.new('Excel.Application')
3128  * excel.Visible = true
3129  * book = excel.workbooks.add
3130  * sheet = book.worksheets(1)
3131  * sheet.setproperty('Cells', 1, 2, 10) # => The B1 cell value is 10.
3132  */
3133 static VALUE
3134 fole_setproperty(int argc, VALUE *argv, VALUE self)
3135 {
3136  VALUE v = ole_invoke(argc, argv, self, DISPATCH_PROPERTYPUT, FALSE);
3137  if (v == rb_eNoMethodError) {
3138  return rb_call_super(argc, argv);
3139  }
3140  return v;
3141 }
3142 
3143 /*
3144  * call-seq:
3145  * WIN32OLE[a1,a2,...]
3146  *
3147  * Returns the value of Collection specified by a1, a2,....
3148  *
3149  * dict = WIN32OLE.new('Scripting.Dictionary')
3150  * dict.add('ruby', 'Ruby')
3151  * puts dict['ruby'] # => 'Ruby' (same as `puts dict.item('ruby')')
3152  *
3153  * Remark: You can not use this method to get the property.
3154  * excel = WIN32OLE.new('Excel.Application')
3155  * # puts excel['Visible'] This is error !!!
3156  * puts excel.Visible # You should to use this style to get the property.
3157  *
3158  */
3159 static VALUE
3160 fole_getproperty_with_bracket(int argc, VALUE *argv, VALUE self)
3161 {
3162  VALUE v = ole_invoke(argc, argv, self, DISPATCH_PROPERTYGET, TRUE);
3163  if (v == rb_eNoMethodError) {
3164  return rb_call_super(argc, argv);
3165  }
3166  return v;
3167 }
3168 
3169 static VALUE
3170 ole_propertyput(VALUE self, VALUE property, VALUE value)
3171 {
3172  struct oledata *pole = NULL;
3173  unsigned argErr;
3174  unsigned int index;
3175  HRESULT hr;
3176  EXCEPINFO excepinfo;
3177  DISPID dispID = DISPID_VALUE;
3178  DISPID dispIDParam = DISPID_PROPERTYPUT;
3179  USHORT wFlags = DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF;
3180  DISPPARAMS dispParams;
3181  VARIANTARG propertyValue[2];
3182  OLECHAR* pBuf[1];
3183  VALUE v;
3184  LCID lcid = cWIN32OLE_lcid;
3185  dispParams.rgdispidNamedArgs = &dispIDParam;
3186  dispParams.rgvarg = propertyValue;
3187  dispParams.cNamedArgs = 1;
3188  dispParams.cArgs = 1;
3189 
3190  VariantInit(&propertyValue[0]);
3191  VariantInit(&propertyValue[1]);
3192  memset(&excepinfo, 0, sizeof(excepinfo));
3193 
3194  pole = oledata_get_struct(self);
3195 
3196  /* get ID from property name */
3197  pBuf[0] = ole_vstr2wc(property);
3198  hr = pole->pDispatch->lpVtbl->GetIDsOfNames(pole->pDispatch, &IID_NULL,
3199  pBuf, 1, lcid, &dispID);
3200  SysFreeString(pBuf[0]);
3201  pBuf[0] = NULL;
3202 
3203  if(FAILED(hr)) {
3205  "unknown property or method: `%s'",
3206  StringValuePtr(property));
3207  }
3208  /* set property value */
3209  ole_val2variant(value, &propertyValue[0]);
3210  hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, dispID, &IID_NULL,
3211  lcid, wFlags, &dispParams,
3212  NULL, &excepinfo, &argErr);
3213 
3214  for(index = 0; index < dispParams.cArgs; ++index) {
3215  VariantClear(&propertyValue[index]);
3216  }
3217  if (FAILED(hr)) {
3218  v = ole_excepinfo2msg(&excepinfo);
3219  ole_raise(hr, eWIN32OLERuntimeError, "(in setting property `%s': )%s",
3220  StringValuePtr(property),
3221  StringValuePtr(v));
3222  }
3223  return Qnil;
3224 }
3225 
3226 /*
3227  * call-seq:
3228  * WIN32OLE#ole_free
3229  *
3230  * invokes Release method of Dispatch interface of WIN32OLE object.
3231  * Usually, you do not need to call this method because Release method
3232  * called automatically when WIN32OLE object garbaged.
3233  *
3234  */
3235 static VALUE
3236 fole_free(VALUE self)
3237 {
3238  struct oledata *pole = NULL;
3239  pole = oledata_get_struct(self);
3240  OLE_FREE(pole->pDispatch);
3241  pole->pDispatch = NULL;
3242  return Qnil;
3243 }
3244 
3245 static VALUE
3246 ole_each_sub(VALUE pEnumV)
3247 {
3248  VARIANT variant;
3249  VALUE obj = Qnil;
3250  IEnumVARIANT *pEnum = (IEnumVARIANT *)pEnumV;
3251  VariantInit(&variant);
3252  while(pEnum->lpVtbl->Next(pEnum, 1, &variant, NULL) == S_OK) {
3253  obj = ole_variant2val(&variant);
3254  VariantClear(&variant);
3255  VariantInit(&variant);
3256  rb_yield(obj);
3257  }
3258  return Qnil;
3259 }
3260 
3261 static VALUE
3262 ole_ienum_free(VALUE pEnumV)
3263 {
3264  IEnumVARIANT *pEnum = (IEnumVARIANT *)pEnumV;
3265  OLE_RELEASE(pEnum);
3266  return Qnil;
3267 }
3268 
3269 /*
3270  * call-seq:
3271  * WIN32OLE#each {|i|...}
3272  *
3273  * Iterates over each item of OLE collection which has IEnumVARIANT interface.
3274  *
3275  * excel = WIN32OLE.new('Excel.Application')
3276  * book = excel.workbooks.add
3277  * sheets = book.worksheets(1)
3278  * cells = sheets.cells("A1:A5")
3279  * cells.each do |cell|
3280  * cell.value = 10
3281  * end
3282  */
3283 static VALUE
3284 fole_each(VALUE self)
3285 {
3286  LCID lcid = cWIN32OLE_lcid;
3287 
3288  struct oledata *pole = NULL;
3289 
3290  unsigned int argErr;
3291  EXCEPINFO excepinfo;
3292  DISPPARAMS dispParams;
3293  VARIANT result;
3294  HRESULT hr;
3295  IEnumVARIANT *pEnum = NULL;
3296  void *p;
3297 
3298  RETURN_ENUMERATOR(self, 0, 0);
3299 
3300  VariantInit(&result);
3301  dispParams.rgvarg = NULL;
3302  dispParams.rgdispidNamedArgs = NULL;
3303  dispParams.cNamedArgs = 0;
3304  dispParams.cArgs = 0;
3305  memset(&excepinfo, 0, sizeof(excepinfo));
3306 
3307  pole = oledata_get_struct(self);
3308  hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DISPID_NEWENUM,
3309  &IID_NULL, lcid,
3310  DISPATCH_METHOD | DISPATCH_PROPERTYGET,
3311  &dispParams, &result,
3312  &excepinfo, &argErr);
3313 
3314  if (FAILED(hr)) {
3315  VariantClear(&result);
3316  ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to get IEnum Interface");
3317  }
3318 
3319  if (V_VT(&result) == VT_UNKNOWN) {
3320  hr = V_UNKNOWN(&result)->lpVtbl->QueryInterface(V_UNKNOWN(&result),
3321  &IID_IEnumVARIANT,
3322  &p);
3323  pEnum = p;
3324  } else if (V_VT(&result) == VT_DISPATCH) {
3325  hr = V_DISPATCH(&result)->lpVtbl->QueryInterface(V_DISPATCH(&result),
3326  &IID_IEnumVARIANT,
3327  &p);
3328  pEnum = p;
3329  }
3330  if (FAILED(hr) || !pEnum) {
3331  VariantClear(&result);
3332  ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to get IEnum Interface");
3333  }
3334 
3335  VariantClear(&result);
3336  rb_ensure(ole_each_sub, (VALUE)pEnum, ole_ienum_free, (VALUE)pEnum);
3337  return Qnil;
3338 }
3339 
3340 /*
3341  * call-seq:
3342  * WIN32OLE#method_missing(id [,arg1, arg2, ...])
3343  *
3344  * Calls WIN32OLE#invoke method.
3345  */
3346 static VALUE
3347 fole_missing(int argc, VALUE *argv, VALUE self)
3348 {
3349  VALUE mid, org_mid, sym, v;
3350  const char* mname;
3351  long n;
3353  mid = org_mid = argv[0];
3354  sym = rb_check_symbol(&mid);
3355  if (!NIL_P(sym)) mid = rb_sym2str(sym);
3356  mname = StringValueCStr(mid);
3357  if(!mname) {
3358  rb_raise(rb_eRuntimeError, "fail: unknown method or property");
3359  }
3360  n = RSTRING_LEN(mid);
3361  if(mname[n-1] == '=') {
3362  rb_check_arity(argc, 2, 2);
3363  argv[0] = rb_enc_associate(rb_str_subseq(mid, 0, n-1), cWIN32OLE_enc);
3364 
3365  return ole_propertyput(self, argv[0], argv[1]);
3366  }
3367  else {
3368  argv[0] = rb_enc_associate(rb_str_dup(mid), cWIN32OLE_enc);
3369  v = ole_invoke(argc, argv, self, DISPATCH_METHOD|DISPATCH_PROPERTYGET, FALSE);
3370  if (v == rb_eNoMethodError) {
3371  argv[0] = org_mid;
3372  return rb_call_super(argc, argv);
3373  }
3374  return v;
3375  }
3376 }
3377 
3378 static HRESULT
3379 typeinfo_from_ole(struct oledata *pole, ITypeInfo **ppti)
3380 {
3381  ITypeInfo *pTypeInfo;
3382  ITypeLib *pTypeLib;
3383  BSTR bstr;
3384  VALUE type;
3385  UINT i;
3386  UINT count;
3387  LCID lcid = cWIN32OLE_lcid;
3388  HRESULT hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch,
3389  0, lcid, &pTypeInfo);
3390  if(FAILED(hr)) {
3391  ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to GetTypeInfo");
3392  }
3393  hr = pTypeInfo->lpVtbl->GetDocumentation(pTypeInfo,
3394  -1,
3395  &bstr,
3396  NULL, NULL, NULL);
3397  type = WC2VSTR(bstr);
3398  hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &i);
3399  OLE_RELEASE(pTypeInfo);
3400  if (FAILED(hr)) {
3401  ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to GetContainingTypeLib");
3402  }
3403  count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
3404  for (i = 0; i < count; i++) {
3405  hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i,
3406  &bstr, NULL, NULL, NULL);
3407  if (SUCCEEDED(hr) && rb_str_cmp(WC2VSTR(bstr), type) == 0) {
3408  hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, i, &pTypeInfo);
3409  if (SUCCEEDED(hr)) {
3410  *ppti = pTypeInfo;
3411  break;
3412  }
3413  }
3414  }
3415  OLE_RELEASE(pTypeLib);
3416  return hr;
3417 }
3418 
3419 static VALUE
3420 ole_methods(VALUE self, int mask)
3421 {
3422  ITypeInfo *pTypeInfo;
3423  HRESULT hr;
3424  VALUE methods;
3425  struct oledata *pole = NULL;
3426 
3427  pole = oledata_get_struct(self);
3428  methods = rb_ary_new();
3429 
3430  hr = typeinfo_from_ole(pole, &pTypeInfo);
3431  if(FAILED(hr))
3432  return methods;
3433  rb_ary_concat(methods, ole_methods_from_typeinfo(pTypeInfo, mask));
3434  OLE_RELEASE(pTypeInfo);
3435  return methods;
3436 }
3437 
3438 /*
3439  * call-seq:
3440  * WIN32OLE#ole_methods
3441  *
3442  * Returns the array of WIN32OLE_METHOD object.
3443  * The element is OLE method of WIN32OLE object.
3444  *
3445  * excel = WIN32OLE.new('Excel.Application')
3446  * methods = excel.ole_methods
3447  *
3448  */
3449 static VALUE
3450 fole_methods(VALUE self)
3451 {
3452  return ole_methods( self, INVOKE_FUNC | INVOKE_PROPERTYGET | INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF);
3453 }
3454 
3455 /*
3456  * call-seq:
3457  * WIN32OLE#ole_get_methods
3458  *
3459  * Returns the array of WIN32OLE_METHOD object .
3460  * The element of the array is property (gettable) of WIN32OLE object.
3461  *
3462  * excel = WIN32OLE.new('Excel.Application')
3463  * properties = excel.ole_get_methods
3464  */
3465 static VALUE
3466 fole_get_methods(VALUE self)
3467 {
3468  return ole_methods( self, INVOKE_PROPERTYGET);
3469 }
3470 
3471 /*
3472  * call-seq:
3473  * WIN32OLE#ole_put_methods
3474  *
3475  * Returns the array of WIN32OLE_METHOD object .
3476  * The element of the array is property (settable) of WIN32OLE object.
3477  *
3478  * excel = WIN32OLE.new('Excel.Application')
3479  * properties = excel.ole_put_methods
3480  */
3481 static VALUE
3482 fole_put_methods(VALUE self)
3483 {
3484  return ole_methods( self, INVOKE_PROPERTYPUT|INVOKE_PROPERTYPUTREF);
3485 }
3486 
3487 /*
3488  * call-seq:
3489  * WIN32OLE#ole_func_methods
3490  *
3491  * Returns the array of WIN32OLE_METHOD object .
3492  * The element of the array is property (settable) of WIN32OLE object.
3493  *
3494  * excel = WIN32OLE.new('Excel.Application')
3495  * properties = excel.ole_func_methods
3496  *
3497  */
3498 static VALUE
3499 fole_func_methods(VALUE self)
3500 {
3501  return ole_methods( self, INVOKE_FUNC);
3502 }
3503 
3504 /*
3505  * call-seq:
3506  * WIN32OLE#ole_type
3507  *
3508  * Returns WIN32OLE_TYPE object.
3509  *
3510  * excel = WIN32OLE.new('Excel.Application')
3511  * tobj = excel.ole_type
3512  */
3513 static VALUE
3514 fole_type(VALUE self)
3515 {
3516  ITypeInfo *pTypeInfo;
3517  HRESULT hr;
3518  struct oledata *pole = NULL;
3519  LCID lcid = cWIN32OLE_lcid;
3520  VALUE type = Qnil;
3521 
3522  pole = oledata_get_struct(self);
3523 
3524  hr = pole->pDispatch->lpVtbl->GetTypeInfo( pole->pDispatch, 0, lcid, &pTypeInfo );
3525  if(FAILED(hr)) {
3526  ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to GetTypeInfo");
3527  }
3528  type = ole_type_from_itypeinfo(pTypeInfo);
3529  OLE_RELEASE(pTypeInfo);
3530  if (type == Qnil) {
3531  rb_raise(rb_eRuntimeError, "failed to create WIN32OLE_TYPE obj from ITypeInfo");
3532  }
3533  return type;
3534 }
3535 
3536 /*
3537  * call-seq:
3538  * WIN32OLE#ole_typelib -> The WIN32OLE_TYPELIB object
3539  *
3540  * Returns the WIN32OLE_TYPELIB object. The object represents the
3541  * type library which contains the WIN32OLE object.
3542  *
3543  * excel = WIN32OLE.new('Excel.Application')
3544  * tlib = excel.ole_typelib
3545  * puts tlib.name # -> 'Microsoft Excel 9.0 Object Library'
3546  */
3547 static VALUE
3548 fole_typelib(VALUE self)
3549 {
3550  struct oledata *pole = NULL;
3551  HRESULT hr;
3552  ITypeInfo *pTypeInfo;
3553  LCID lcid = cWIN32OLE_lcid;
3554  VALUE vtlib = Qnil;
3555 
3556  pole = oledata_get_struct(self);
3557  hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch,
3558  0, lcid, &pTypeInfo);
3559  if(FAILED(hr)) {
3560  ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to GetTypeInfo");
3561  }
3562  vtlib = ole_typelib_from_itypeinfo(pTypeInfo);
3563  OLE_RELEASE(pTypeInfo);
3564  if (vtlib == Qnil) {
3565  rb_raise(rb_eRuntimeError, "failed to get type library info.");
3566  }
3567  return vtlib;
3568 }
3569 
3570 /*
3571  * call-seq:
3572  * WIN32OLE#ole_query_interface(iid) -> WIN32OLE object
3573  *
3574  * Returns WIN32OLE object for a specific dispatch or dual
3575  * interface specified by iid.
3576  *
3577  * ie = WIN32OLE.new('InternetExplorer.Application')
3578  * ie_web_app = ie.ole_query_interface('{0002DF05-0000-0000-C000-000000000046}') # => WIN32OLE object for dispinterface IWebBrowserApp
3579  */
3580 static VALUE
3581 fole_query_interface(VALUE self, VALUE str_iid)
3582 {
3583  HRESULT hr;
3584  OLECHAR *pBuf;
3585  IID iid;
3586  struct oledata *pole = NULL;
3587  IDispatch *pDispatch;
3588  void *p;
3589 
3590  pBuf = ole_vstr2wc(str_iid);
3591  hr = CLSIDFromString(pBuf, &iid);
3592  SysFreeString(pBuf);
3593  if(FAILED(hr)) {
3595  "invalid iid: `%s'",
3596  StringValuePtr(str_iid));
3597  }
3598 
3599  pole = oledata_get_struct(self);
3600  if(!pole->pDispatch) {
3601  rb_raise(rb_eRuntimeError, "failed to get dispatch interface");
3602  }
3603 
3604  hr = pole->pDispatch->lpVtbl->QueryInterface(pole->pDispatch, &iid,
3605  &p);
3606  if(FAILED(hr)) {
3608  "failed to get interface `%s'",
3609  StringValuePtr(str_iid));
3610  }
3611 
3612  pDispatch = p;
3613  return create_win32ole_object(cWIN32OLE, pDispatch, 0, 0);
3614 }
3615 
3616 /*
3617  * call-seq:
3618  * WIN32OLE#ole_respond_to?(method) -> true or false
3619  *
3620  * Returns true when OLE object has OLE method, otherwise returns false.
3621  *
3622  * ie = WIN32OLE.new('InternetExplorer.Application')
3623  * ie.ole_respond_to?("gohome") => true
3624  */
3625 static VALUE
3626 fole_respond_to(VALUE self, VALUE method)
3627 {
3628  struct oledata *pole = NULL;
3629  BSTR wcmdname;
3630  DISPID DispID;
3631  HRESULT hr;
3632  if(!RB_TYPE_P(method, T_STRING) && !RB_TYPE_P(method, T_SYMBOL)) {
3633  rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)");
3634  }
3635  if (RB_TYPE_P(method, T_SYMBOL)) {
3636  method = rb_sym2str(method);
3637  }
3638  pole = oledata_get_struct(self);
3639  wcmdname = ole_vstr2wc(method);
3640  hr = pole->pDispatch->lpVtbl->GetIDsOfNames( pole->pDispatch, &IID_NULL,
3641  &wcmdname, 1, cWIN32OLE_lcid, &DispID);
3642  SysFreeString(wcmdname);
3643  return SUCCEEDED(hr) ? Qtrue : Qfalse;
3644 }
3645 
3646 HRESULT
3647 ole_docinfo_from_type(ITypeInfo *pTypeInfo, BSTR *name, BSTR *helpstr, DWORD *helpcontext, BSTR *helpfile)
3648 {
3649  HRESULT hr;
3650  ITypeLib *pTypeLib;
3651  UINT i;
3652 
3653  hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &i);
3654  if (FAILED(hr)) {
3655  return hr;
3656  }
3657 
3658  hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i,
3659  name, helpstr,
3660  helpcontext, helpfile);
3661  if (FAILED(hr)) {
3662  OLE_RELEASE(pTypeLib);
3663  return hr;
3664  }
3665  OLE_RELEASE(pTypeLib);
3666  return hr;
3667 }
3668 
3669 static VALUE
3670 ole_usertype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails)
3671 {
3672  HRESULT hr;
3673  BSTR bstr;
3674  ITypeInfo *pRefTypeInfo;
3675  VALUE type = Qnil;
3676 
3677  hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo,
3678  V_UNION1(pTypeDesc, hreftype),
3679  &pRefTypeInfo);
3680  if(FAILED(hr))
3681  return Qnil;
3682  hr = ole_docinfo_from_type(pRefTypeInfo, &bstr, NULL, NULL, NULL);
3683  if(FAILED(hr)) {
3684  OLE_RELEASE(pRefTypeInfo);
3685  return Qnil;
3686  }
3687  OLE_RELEASE(pRefTypeInfo);
3688  type = WC2VSTR(bstr);
3689  if(typedetails != Qnil)
3690  rb_ary_push(typedetails, type);
3691  return type;
3692 }
3693 
3694 static VALUE
3695 ole_ptrtype2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails)
3696 {
3697  TYPEDESC *p = pTypeDesc;
3698  VALUE type = rb_str_new2("");
3699 
3700  if (p->vt == VT_PTR || p->vt == VT_SAFEARRAY) {
3701  p = V_UNION1(p, lptdesc);
3702  type = ole_typedesc2val(pTypeInfo, p, typedetails);
3703  }
3704  return type;
3705 }
3706 
3707 VALUE
3708 ole_typedesc2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails)
3709 {
3710  VALUE str;
3711  VALUE typestr = Qnil;
3712  switch(pTypeDesc->vt) {
3713  case VT_I2:
3714  typestr = rb_str_new2("I2");
3715  break;
3716  case VT_I4:
3717  typestr = rb_str_new2("I4");
3718  break;
3719  case VT_R4:
3720  typestr = rb_str_new2("R4");
3721  break;
3722  case VT_R8:
3723  typestr = rb_str_new2("R8");
3724  break;
3725  case VT_CY:
3726  typestr = rb_str_new2("CY");
3727  break;
3728  case VT_DATE:
3729  typestr = rb_str_new2("DATE");
3730  break;
3731  case VT_BSTR:
3732  typestr = rb_str_new2("BSTR");
3733  break;
3734  case VT_BOOL:
3735  typestr = rb_str_new2("BOOL");
3736  break;
3737  case VT_VARIANT:
3738  typestr = rb_str_new2("VARIANT");
3739  break;
3740  case VT_DECIMAL:
3741  typestr = rb_str_new2("DECIMAL");
3742  break;
3743  case VT_I1:
3744  typestr = rb_str_new2("I1");
3745  break;
3746  case VT_UI1:
3747  typestr = rb_str_new2("UI1");
3748  break;
3749  case VT_UI2:
3750  typestr = rb_str_new2("UI2");
3751  break;
3752  case VT_UI4:
3753  typestr = rb_str_new2("UI4");
3754  break;
3755 #if (_MSC_VER >= 1300) || defined(__CYGWIN__) || defined(__MINGW32__)
3756  case VT_I8:
3757  typestr = rb_str_new2("I8");
3758  break;
3759  case VT_UI8:
3760  typestr = rb_str_new2("UI8");
3761  break;
3762 #endif
3763  case VT_INT:
3764  typestr = rb_str_new2("INT");
3765  break;
3766  case VT_UINT:
3767  typestr = rb_str_new2("UINT");
3768  break;
3769  case VT_VOID:
3770  typestr = rb_str_new2("VOID");
3771  break;
3772  case VT_HRESULT:
3773  typestr = rb_str_new2("HRESULT");
3774  break;
3775  case VT_PTR:
3776  typestr = rb_str_new2("PTR");
3777  if(typedetails != Qnil)
3778  rb_ary_push(typedetails, typestr);
3779  return ole_ptrtype2val(pTypeInfo, pTypeDesc, typedetails);
3780  case VT_SAFEARRAY:
3781  typestr = rb_str_new2("SAFEARRAY");
3782  if(typedetails != Qnil)
3783  rb_ary_push(typedetails, typestr);
3784  return ole_ptrtype2val(pTypeInfo, pTypeDesc, typedetails);
3785  case VT_CARRAY:
3786  typestr = rb_str_new2("CARRAY");
3787  break;
3788  case VT_USERDEFINED:
3789  typestr = rb_str_new2("USERDEFINED");
3790  if (typedetails != Qnil)
3791  rb_ary_push(typedetails, typestr);
3792  str = ole_usertype2val(pTypeInfo, pTypeDesc, typedetails);
3793  if (str != Qnil) {
3794  return str;
3795  }
3796  return typestr;
3797  case VT_UNKNOWN:
3798  typestr = rb_str_new2("UNKNOWN");
3799  break;
3800  case VT_DISPATCH:
3801  typestr = rb_str_new2("DISPATCH");
3802  break;
3803  case VT_ERROR:
3804  typestr = rb_str_new2("ERROR");
3805  break;
3806  case VT_LPWSTR:
3807  typestr = rb_str_new2("LPWSTR");
3808  break;
3809  case VT_LPSTR:
3810  typestr = rb_str_new2("LPSTR");
3811  break;
3812  case VT_RECORD:
3813  typestr = rb_str_new2("RECORD");
3814  break;
3815  default:
3816  typestr = rb_str_new2("Unknown Type ");
3817  rb_str_concat(typestr, rb_fix2str(RB_INT2FIX(pTypeDesc->vt), 10));
3818  break;
3819  }
3820  if (typedetails != Qnil)
3821  rb_ary_push(typedetails, typestr);
3822  return typestr;
3823 }
3824 
3825 /*
3826  * call-seq:
3827  * WIN32OLE#ole_method_help(method)
3828  *
3829  * Returns WIN32OLE_METHOD object corresponding with method
3830  * specified by 1st argument.
3831  *
3832  * excel = WIN32OLE.new('Excel.Application')
3833  * method = excel.ole_method_help('Quit')
3834  *
3835  */
3836 static VALUE
3837 fole_method_help(VALUE self, VALUE cmdname)
3838 {
3839  ITypeInfo *pTypeInfo;
3840  HRESULT hr;
3841  struct oledata *pole = NULL;
3842  VALUE obj;
3843 
3844  SafeStringValue(cmdname);
3845  pole = oledata_get_struct(self);
3846  hr = typeinfo_from_ole(pole, &pTypeInfo);
3847  if(FAILED(hr))
3848  ole_raise(hr, eWIN32OLEQueryInterfaceError, "failed to get ITypeInfo");
3849 
3850  obj = create_win32ole_method(pTypeInfo, cmdname);
3851 
3852  OLE_RELEASE(pTypeInfo);
3853  if (obj == Qnil)
3854  rb_raise(eWIN32OLERuntimeError, "not found %s",
3855  StringValuePtr(cmdname));
3856  return obj;
3857 }
3858 
3859 /*
3860  * call-seq:
3861  * WIN32OLE#ole_activex_initialize() -> Qnil
3862  *
3863  * Initialize WIN32OLE object(ActiveX Control) by calling
3864  * IPersistMemory::InitNew.
3865  *
3866  * Before calling OLE method, some kind of the ActiveX controls
3867  * created with MFC should be initialized by calling
3868  * IPersistXXX::InitNew.
3869  *
3870  * If and only if you received the exception "HRESULT error code:
3871  * 0x8000ffff catastrophic failure", try this method before
3872  * invoking any ole_method.
3873  *
3874  * obj = WIN32OLE.new("ProgID_or_GUID_of_ActiveX_Control")
3875  * obj.ole_activex_initialize
3876  * obj.method(...)
3877  *
3878  */
3879 static VALUE
3880 fole_activex_initialize(VALUE self)
3881 {
3882  struct oledata *pole = NULL;
3883  IPersistMemory *pPersistMemory;
3884  void *p;
3885 
3886  HRESULT hr = S_OK;
3887 
3888  pole = oledata_get_struct(self);
3889 
3890  hr = pole->pDispatch->lpVtbl->QueryInterface(pole->pDispatch, &IID_IPersistMemory, &p);
3891  pPersistMemory = p;
3892  if (SUCCEEDED(hr)) {
3893  hr = pPersistMemory->lpVtbl->InitNew(pPersistMemory);
3894  OLE_RELEASE(pPersistMemory);
3895  if (SUCCEEDED(hr)) {
3896  return Qnil;
3897  }
3898  }
3899 
3900  if (FAILED(hr)) {
3901  ole_raise(hr, eWIN32OLERuntimeError, "fail to initialize ActiveX control");
3902  }
3903 
3904  return Qnil;
3905 }
3906 
3907 HRESULT
3908 typelib_from_val(VALUE obj, ITypeLib **pTypeLib)
3909 {
3910  LCID lcid = cWIN32OLE_lcid;
3911  HRESULT hr;
3912  struct oledata *pole = NULL;
3913  unsigned int index;
3914  ITypeInfo *pTypeInfo;
3915  pole = oledata_get_struct(obj);
3916  hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch,
3917  0, lcid, &pTypeInfo);
3918  if (FAILED(hr)) {
3919  return hr;
3920  }
3921  hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, pTypeLib, &index);
3922  OLE_RELEASE(pTypeInfo);
3923  return hr;
3924 }
3925 
3926 static void
3927 com_hash_free(void *ptr)
3928 {
3929  st_table *tbl = ptr;
3930  st_free_table(tbl);
3931 }
3932 
3933 static void
3934 com_hash_mark(void *ptr)
3935 {
3936  st_table *tbl = ptr;
3937  rb_mark_hash(tbl);
3938 }
3939 
3940 static size_t
3941 com_hash_size(const void *ptr)
3942 {
3943  const st_table *tbl = ptr;
3944  return st_memsize(tbl);
3945 }
3946 
3947 static void
3948 check_nano_server(void)
3949 {
3950  HKEY hsubkey;
3951  LONG err;
3952  const char * subkey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Server\\ServerLevels";
3953  const char * regval = "NanoServer";
3954 
3955  err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, subkey, 0, KEY_READ, &hsubkey);
3956  if (err == ERROR_SUCCESS) {
3957  err = RegQueryValueEx(hsubkey, regval, NULL, NULL, NULL, NULL);
3958  if (err == ERROR_SUCCESS) {
3959  g_running_nano = TRUE;
3960  }
3961  RegCloseKey(hsubkey);
3962  }
3963 }
3964 
3965 
3966 void
3968 {
3969  cWIN32OLE_lcid = LOCALE_SYSTEM_DEFAULT;
3971  check_nano_server();
3972 
3973  com_vtbl.QueryInterface = QueryInterface;
3974  com_vtbl.AddRef = AddRef;
3975  com_vtbl.Release = Release;
3976  com_vtbl.GetTypeInfoCount = GetTypeInfoCount;
3977  com_vtbl.GetTypeInfo = GetTypeInfo;
3978  com_vtbl.GetIDsOfNames = GetIDsOfNames;
3979  com_vtbl.Invoke = Invoke;
3980 
3981  message_filter.QueryInterface = mf_QueryInterface;
3982  message_filter.AddRef = mf_AddRef;
3983  message_filter.Release = mf_Release;
3984  message_filter.HandleInComingCall = mf_HandleInComingCall;
3985  message_filter.RetryRejectedCall = mf_RetryRejectedCall;
3986  message_filter.MessagePending = mf_MessagePending;
3987 
3988  enc2cp_hash = TypedData_Wrap_Struct(0, &win32ole_hash_datatype, 0);
3989  RTYPEDDATA_DATA(enc2cp_hash) = st_init_numtable();
3990  rb_gc_register_mark_object(enc2cp_hash);
3991 
3992  com_hash = TypedData_Wrap_Struct(0, &win32ole_hash_datatype, 0);
3993  RTYPEDDATA_DATA(com_hash) = st_init_numtable();
3994  rb_gc_register_mark_object(com_hash);
3995 
3996  cWIN32OLE = rb_define_class("WIN32OLE", rb_cObject);
3997 
3998  rb_define_alloc_func(cWIN32OLE, fole_s_allocate);
3999 
4000  rb_define_method(cWIN32OLE, "initialize", fole_initialize, -1);
4001 
4002  rb_define_singleton_method(cWIN32OLE, "connect", fole_s_connect, -1);
4003  rb_define_singleton_method(cWIN32OLE, "const_load", fole_s_const_load, -1);
4004 
4005  rb_define_singleton_method(cWIN32OLE, "ole_free", fole_s_free, 1);
4006  rb_define_singleton_method(cWIN32OLE, "ole_reference_count", fole_s_reference_count, 1);
4007  rb_define_singleton_method(cWIN32OLE, "ole_show_help", fole_s_show_help, -1);
4008  rb_define_singleton_method(cWIN32OLE, "codepage", fole_s_get_code_page, 0);
4009  rb_define_singleton_method(cWIN32OLE, "codepage=", fole_s_set_code_page, 1);
4010  rb_define_singleton_method(cWIN32OLE, "locale", fole_s_get_locale, 0);
4011  rb_define_singleton_method(cWIN32OLE, "locale=", fole_s_set_locale, 1);
4012  rb_define_singleton_method(cWIN32OLE, "create_guid", fole_s_create_guid, 0);
4013  rb_define_singleton_method(cWIN32OLE, "ole_initialize", fole_s_ole_initialize, 0);
4014  rb_define_singleton_method(cWIN32OLE, "ole_uninitialize", fole_s_ole_uninitialize, 0);
4015 
4016  rb_define_method(cWIN32OLE, "invoke", fole_invoke, -1);
4017  rb_define_method(cWIN32OLE, "[]", fole_getproperty_with_bracket, -1);
4018  rb_define_method(cWIN32OLE, "_invoke", fole_invoke2, 3);
4019  rb_define_method(cWIN32OLE, "_getproperty", fole_getproperty2, 3);
4020  rb_define_method(cWIN32OLE, "_setproperty", fole_setproperty2, 3);
4021 
4022  /* support propput method that takes an argument */
4023  rb_define_method(cWIN32OLE, "[]=", fole_setproperty_with_bracket, -1);
4024 
4025  rb_define_method(cWIN32OLE, "ole_free", fole_free, 0);
4026 
4027  rb_define_method(cWIN32OLE, "each", fole_each, 0);
4028  rb_define_method(cWIN32OLE, "method_missing", fole_missing, -1);
4029 
4030  /* support setproperty method much like Perl ;-) */
4031  rb_define_method(cWIN32OLE, "setproperty", fole_setproperty, -1);
4032 
4033  rb_define_method(cWIN32OLE, "ole_methods", fole_methods, 0);
4034  rb_define_method(cWIN32OLE, "ole_get_methods", fole_get_methods, 0);
4035  rb_define_method(cWIN32OLE, "ole_put_methods", fole_put_methods, 0);
4036  rb_define_method(cWIN32OLE, "ole_func_methods", fole_func_methods, 0);
4037 
4038  rb_define_method(cWIN32OLE, "ole_method", fole_method_help, 1);
4039  rb_define_alias(cWIN32OLE, "ole_method_help", "ole_method");
4040  rb_define_method(cWIN32OLE, "ole_activex_initialize", fole_activex_initialize, 0);
4041  rb_define_method(cWIN32OLE, "ole_type", fole_type, 0);
4042  rb_define_alias(cWIN32OLE, "ole_obj_help", "ole_type");
4043  rb_define_method(cWIN32OLE, "ole_typelib", fole_typelib, 0);
4044  rb_define_method(cWIN32OLE, "ole_query_interface", fole_query_interface, 1);
4045  rb_define_method(cWIN32OLE, "ole_respond_to?", fole_respond_to, 1);
4046 
4047  /* Constants definition */
4048 
4049  /*
4050  * Version string of WIN32OLE.
4051  */
4053 
4054  /*
4055  * After invoking OLE methods with reference arguments, you can access
4056  * the value of arguments by using ARGV.
4057  *
4058  * If the method of OLE(COM) server written by C#.NET is following:
4059  *
4060  * void calcsum(int a, int b, out int c) {
4061  * c = a + b;
4062  * }
4063  *
4064  * then, the Ruby OLE(COM) client script to retrieve the value of
4065  * argument c after invoking calcsum method is following:
4066  *
4067  * a = 10
4068  * b = 20
4069  * c = 0
4070  * comserver.calcsum(a, b, c)
4071  * p c # => 0
4072  * p WIN32OLE::ARGV # => [10, 20, 30]
4073  *
4074  * You can use WIN32OLE_VARIANT object to retrieve the value of reference
4075  * arguments instead of referring WIN32OLE::ARGV.
4076  *
4077  */
4078  rb_define_const(cWIN32OLE, "ARGV", rb_ary_new());
4079 
4080  /*
4081  * 0: ANSI code page. See WIN32OLE.codepage and WIN32OLE.codepage=.
4082  */
4083  rb_define_const(cWIN32OLE, "CP_ACP", RB_INT2FIX(CP_ACP));
4084 
4085  /*
4086  * 1: OEM code page. See WIN32OLE.codepage and WIN32OLE.codepage=.
4087  */
4088  rb_define_const(cWIN32OLE, "CP_OEMCP", RB_INT2FIX(CP_OEMCP));
4089 
4090  /*
4091  * 2
4092  */
4093  rb_define_const(cWIN32OLE, "CP_MACCP", RB_INT2FIX(CP_MACCP));
4094 
4095  /*
4096  * 3: current thread ANSI code page. See WIN32OLE.codepage and
4097  * WIN32OLE.codepage=.
4098  */
4099  rb_define_const(cWIN32OLE, "CP_THREAD_ACP", RB_INT2FIX(CP_THREAD_ACP));
4100 
4101  /*
4102  * 42: symbol code page. See WIN32OLE.codepage and WIN32OLE.codepage=.
4103  */
4104  rb_define_const(cWIN32OLE, "CP_SYMBOL", RB_INT2FIX(CP_SYMBOL));
4105 
4106  /*
4107  * 65000: UTF-7 code page. See WIN32OLE.codepage and WIN32OLE.codepage=.
4108  */
4109  rb_define_const(cWIN32OLE, "CP_UTF7", RB_INT2FIX(CP_UTF7));
4110 
4111  /*
4112  * 65001: UTF-8 code page. See WIN32OLE.codepage and WIN32OLE.codepage=.
4113  */
4114  rb_define_const(cWIN32OLE, "CP_UTF8", RB_INT2FIX(CP_UTF8));
4115 
4116  /*
4117  * 0x0800: default locale for the operating system. See WIN32OLE.locale
4118  * and WIN32OLE.locale=.
4119  */
4120  rb_define_const(cWIN32OLE, "LOCALE_SYSTEM_DEFAULT", RB_INT2FIX(LOCALE_SYSTEM_DEFAULT));
4121 
4122  /*
4123  * 0x0400: default locale for the user or process. See WIN32OLE.locale
4124  * and WIN32OLE.locale=.
4125  */
4126  rb_define_const(cWIN32OLE, "LOCALE_USER_DEFAULT", RB_INT2FIX(LOCALE_USER_DEFAULT));
4127 
4138 
4139  ole_init_cp();
4140 }
strcmp
int strcmp(const char *, const char *)
rb_check_symbol
VALUE rb_check_symbol(volatile VALUE *namep)
Definition: symbol.c:952
ole_wc2mb_conv
#define ole_wc2mb_conv(pw, pm, size)
Definition: win32ole.c:713
ole_val2variant
void ole_val2variant(VALUE val, VARIANT *var)
Definition: win32ole.c:1249
rb_get_kwargs
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Definition: class.c:1886
i
uint32_t i
Definition: rb_mjit_min_header-2.7.1.h:5464
ID
unsigned long ID
Definition: ruby.h:103
rb_str_concat
VALUE rb_str_concat(VALUE, VALUE)
Definition: string.c:3065
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:649
T_FALSE
#define T_FALSE
Definition: ruby.h:537
oleparam
Definition: win32ole.c:78
obj
const VALUE VALUE obj
Definition: rb_mjit_min_header-2.7.1.h:5742
dwRejectType
static HTASK DWORD DWORD dwRejectType
Definition: win32ole.c:254
rb_is_const_id
int rb_is_const_id(ID id)
Definition: symbol.c:854
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1244
Check_Type
#define Check_Type(v, t)
Definition: ruby.h:595
TRUE
#define TRUE
Definition: nkf.h:175
T_FLOAT
#define T_FLOAT
Definition: ruby.h:527
g_ole_initialized
#define g_ole_initialized
Definition: win32ole.c:46
rb_str_new2
#define rb_str_new2
Definition: intern.h:903
stdout
#define stdout
Definition: rb_mjit_min_header-2.7.1.h:1484
win32ole.h
ppvObject
static REFIID void __RPC_FAR *__RPC_FAR * ppvObject
Definition: win32ole.c:83
rb_enc_name
#define rb_enc_name(enc)
Definition: encoding.h:177
klass
VALUE klass
Definition: rb_mjit_min_header-2.7.1.h:13259
st_data_t
unsigned long st_data_t
Definition: rb_mjit_min_header-2.7.1.h:5363
id
const int id
Definition: nkf.c:209
sprintf
int sprintf(char *__restrict, const char *__restrict,...) __attribute__((__format__(__printf__
ole_variant2val
VALUE ole_variant2val(VARIANT *pvar)
Definition: win32ole.c:1418
rb_hash_new
VALUE rb_hash_new(void)
Definition: hash.c:1523
rb_gc_register_mark_object
void rb_gc_register_mark_object(VALUE obj)
Definition: gc.c:7065
dispIdMember
static DISPID dispIdMember
Definition: win32ole.c:89
eWIN32OLEQueryInterfaceError
VALUE eWIN32OLEQueryInterfaceError
Definition: win32ole_error.h:5
pctinfo
static UINT __RPC_FAR * pctinfo
Definition: win32ole.c:86
rb_funcall
#define rb_funcall(recv, mid, argc,...)
Definition: rb_mjit_min_header-2.7.1.h:6585
n
const char size_t n
Definition: rb_mjit_min_header-2.7.1.h:5456
ole_val2variant_ex
void ole_val2variant_ex(VALUE val, VARIANT *var, VARTYPE vt)
Definition: win32ole.c:982
rb_during_gc
int rb_during_gc(void)
Definition: gc.c:8689
st
enum ruby_tag_type st
Definition: rb_mjit_min_header-2.7.1.h:11116
RSTRING_PTR
#define RSTRING_PTR(str)
Definition: ruby.h:1009
V_I1REF
#define V_I1REF(X)
Definition: win32ole.h:62
dwTickCount
static DWORD HTASK DWORD dwTickCount
Definition: win32ole.c:218
myCPINFOEX::MaxCharSize
UINT MaxCharSize
Definition: win32ole.c:634
pExcepInfo
static DISPID REFIID LCID WORD DISPPARAMS __RPC_FAR VARIANT __RPC_FAR EXCEPINFO __RPC_FAR * pExcepInfo
Definition: win32ole.c:89
ole_val2variant2
void ole_val2variant2(VALUE val, VARIANT *var)
Definition: win32ole.c:1325
st_init_numtable
st_table * st_init_numtable(void)
Definition: st.c:653
rb_ary_unshift
VALUE rb_ary_unshift(VALUE ary, VALUE item)
Definition: array.c:1494
rb_default_external_encoding
rb_encoding * rb_default_external_encoding(void)
Definition: encoding.c:1427
VALUE
unsigned long VALUE
Definition: ruby.h:102
rb_intern
#define rb_intern(str)
rb_ary_store
void rb_ary_store(VALUE ary, long idx, VALUE val)
Definition: array.c:1079
st_delete
int st_delete(st_table *tab, st_data_t *key, st_data_t *value)
Definition: st.c:1418
RB_TYPE_P
#define RB_TYPE_P(obj, type)
Definition: ruby.h:560
rb_intern_const
#define rb_intern_const(str)
Definition: ruby.h:1879
rb_cTime
RUBY_EXTERN VALUE rb_cTime
Definition: ruby.h:2048
Init_win32ole_error
void Init_win32ole_error(void)
Definition: win32ole_error.c:64
TYPE
#define TYPE(x)
Definition: ruby.h:554
reg_open_key
LONG reg_open_key(HKEY hkey, const char *name, HKEY *phkey)
Definition: win32ole.c:1698
rb_enc_get
rb_encoding * rb_enc_get(VALUE obj)
Definition: encoding.c:872
ole_variant2variant
void ole_variant2variant(VALUE val, VARIANT *var)
Definition: win32ole_variant.c:685
RSTRING_LENINT
#define RSTRING_LENINT(str)
Definition: ruby.h:1017
Init_win32ole_event
void Init_win32ole_event(void)
Definition: win32ole_event.c:1261
rb_call_super
VALUE rb_call_super(int, const VALUE *)
Definition: vm_eval.c:306
DWORD
IUnknown DWORD
Definition: win32ole.c:33
reg_get_val
VALUE reg_get_val(HKEY hkey, const char *subkey)
Definition: win32ole.c:1725
floor
double floor(double)
arg
VALUE arg
Definition: rb_mjit_min_header-2.7.1.h:5601
rb_str_dup
VALUE rb_str_dup(VALUE)
Definition: string.c:1516
rb_str_cat2
#define rb_str_cat2
Definition: intern.h:912
ole_initialized
BOOL ole_initialized(void)
Definition: win32ole.c:395
puArgErr
static DISPID REFIID LCID WORD DISPPARAMS __RPC_FAR VARIANT __RPC_FAR EXCEPINFO __RPC_FAR UINT __RPC_FAR * puArgErr
Definition: win32ole.c:89
Qundef
#define Qundef
Definition: ruby.h:470
WIN32OLE_VERSION
#define WIN32OLE_VERSION
Definition: win32ole.c:30
rb_define_singleton_method
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1755
myCPINFOEX::DefaultChar
BYTE DefaultChar[2]
Definition: win32ole.c:635
WC2VSTR
#define WC2VSTR(x)
Definition: win32ole.h:130
ole_initialize
void ole_initialize(void)
Definition: win32ole.c:813
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1551
rb_long2int
#define rb_long2int(n)
Definition: ruby.h:350
ptr
struct RIMemo * ptr
Definition: debug.c:74
Qfalse
#define Qfalse
Definition: ruby.h:467
threadIDCaller
static DWORD HTASK threadIDCaller
Definition: win32ole.c:217
OLE_RELEASE
#define OLE_RELEASE(X)
Definition: win32ole.h:98
NULL
#define NULL
Definition: _sdbm.c:101
SafeStringValue
#define SafeStringValue(v)
Definition: ruby.h:607
ole_rec2variant
void ole_rec2variant(VALUE rec, VARIANT *var)
Definition: win32ole_record.c:87
Win32OLEIDispatch
struct _Win32OLEIDispatch Win32OLEIDispatch
st_insert
int st_insert(st_table *tab, st_data_t key, st_data_t value)
Definition: st.c:1171
Init_win32ole
void Init_win32ole(void)
Definition: win32ole.c:3967
strlen
size_t strlen(const char *)
T_SYMBOL
#define T_SYMBOL
Definition: ruby.h:540
eWIN32OLERuntimeError
VALUE eWIN32OLERuntimeError
Definition: win32ole_error.h:4
reg_open_vkey
LONG reg_open_vkey(HKEY hkey, VALUE key, HKEY *phkey)
Definition: win32ole.c:1704
rb_define_alias
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition: class.c:1800
oleparam::pNamedArgs
OLECHAR ** pNamedArgs
Definition: win32ole.c:80
rb_check_arity
#define rb_check_arity
Definition: intern.h:347
ALLOC_N
#define ALLOC_N(type, n)
Definition: ruby.h:1663
UNLIMITED_ARGUMENTS
#define UNLIMITED_ARGUMENTS
Definition: intern.h:57
ole_type_from_itypeinfo
VALUE ole_type_from_itypeinfo(ITypeInfo *pTypeInfo)
Definition: win32ole_type.c:84
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2669
rb_ary_entry
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1512
rb_ivar_get
VALUE rb_ivar_get(VALUE, ID)
Definition: variable.c:1070
riid
static REFIID riid
Definition: win32ole.c:83
ole_typedesc2val
VALUE ole_typedesc2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails)
Definition: win32ole.c:3708
lcid
static UINT LCID lcid
Definition: win32ole.c:87
cWIN32OLE_RECORD
VALUE cWIN32OLE_RECORD
Definition: win32ole_record.h:4
oledata
Definition: win32ole.h:111
reg_get_val2
VALUE reg_get_val2(HKEY hkey, const char *subkey)
Definition: win32ole.c:1753
ole_methods_from_typeinfo
VALUE ole_methods_from_typeinfo(ITypeInfo *pTypeInfo, int mask)
Definition: win32ole_method.c:112
pIMultiLanguage
#define pIMultiLanguage
Definition: win32ole.c:75
FIXNUM_FLAG
#define FIXNUM_FLAG
Definition: ruby.h:472
create_win32ole_method
VALUE create_win32ole_method(ITypeInfo *pTypeInfo, VALUE name)
Definition: win32ole_method.c:210
olerecord_set_ivar
void olerecord_set_ivar(VALUE obj, IRecordInfo *pri, void *prec)
Definition: win32ole_record.c:123
DATA_PTR
#define DATA_PTR(dta)
Definition: ruby.h:1175
ole_val_ary2variant_ary
HRESULT ole_val_ary2variant_ary(VALUE val, VARIANT *var, VARTYPE vt)
Definition: win32ole.c:1187
rb_encoding
const typedef OnigEncodingType rb_encoding
Definition: encoding.h:115
V_UI2REF
#define V_UI2REF(X)
Definition: win32ole.h:66
RHASH_SIZE
#define RHASH_SIZE(hsh)
Definition: fbuffer.h:8
pszFile
IUnknown COSERVERINFO MULTI_QI *typedef LPCSTR pszFile
Definition: win32ole.c:35
ppTInfo
static UINT LCID ITypeInfo __RPC_FAR *__RPC_FAR * ppTInfo
Definition: win32ole.c:87
ole_typelib_from_itypeinfo
VALUE ole_typelib_from_itypeinfo(ITypeInfo *pTypeInfo)
Definition: win32ole_typelib.c:114
RB_INT2NUM
#define RB_INT2NUM(x)
Definition: ruby.h:1597
_Win32OLEIDispatch::dispatch
IDispatch dispatch
Definition: win32ole.c:285
NUM2UI8
#define NUM2UI8
Definition: win32ole.h:94
rb_enc_from_index
rb_encoding * rb_enc_from_index(int index)
Definition: encoding.c:609
T_FIXNUM
#define T_FIXNUM
Definition: ruby.h:535
rb_define_dummy_encoding
int rb_define_dummy_encoding(const char *name)
Definition: encoding.c:462
_Win32OLEIDispatch::refcount
ULONG refcount
Definition: win32ole.c:286
sym
#define sym(x)
Definition: date_core.c:3716
pDispParams
static DISPID REFIID LCID WORD DISPPARAMS __RPC_FAR * pDispParams
Definition: win32ole.c:89
mask
enum @11::@13::@14 mask
val2variant_ptr
VOID * val2variant_ptr(VALUE val, VARIANT *var, VARTYPE vt)
Definition: win32ole.c:1017
Init_win32ole_type
void Init_win32ole_type(void)
Definition: win32ole_type.c:886
Init_win32ole_variant_m
void Init_win32ole_variant_m(void)
Definition: win32ole_variant_m.c:3
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:1195
typelib_from_val
HRESULT typelib_from_val(VALUE obj, ITypeLib **pTypeLib)
Definition: win32ole.c:3908
TypedData_Wrap_Struct
#define TypedData_Wrap_Struct(klass, data_type, sval)
Definition: ruby.h:1231
wFlags
static DISPID REFIID LCID WORD wFlags
Definition: win32ole.c:89
myCPINFOEX::CodePage
UINT CodePage
Definition: win32ole.c:638
rb_eTypeError
VALUE rb_eTypeError
Definition: error.c:922
rb_ary_concat
VALUE rb_ary_concat(VALUE x, VALUE y)
Definition: array.c:4069
Init_win32ole_record
void Init_win32ole_record(void)
Definition: win32ole_record.c:593
ALLOC
#define ALLOC(type)
Definition: ruby.h:1664
T_CLASS
#define T_CLASS
Definition: ruby.h:524
rb_eRuntimeError
VALUE rb_eRuntimeError
Definition: error.c:920
oledata::pDispatch
IDispatch * pDispatch
Definition: win32ole.h:112
nameid
ID nameid
Definition: win32ole.c:355
strtoul
unsigned long strtoul(const char *__restrict __n, char **__restrict __end_PTR, int __base)
ALLOCA_N
#define ALLOCA_N(type, n)
Definition: ruby.h:1684
RETURN_ENUMERATOR
#define RETURN_ENUMERATOR(obj, argc, argv)
Definition: intern.h:279
RTYPEDDATA_DATA
#define RTYPEDDATA_DATA(v)
Definition: ruby.h:1179
StringValuePtr
#define StringValuePtr(v)
Definition: ruby.h:603
default_inspect
VALUE default_inspect(VALUE self, const char *class_name)
Definition: win32ole.c:1345
size
int size
Definition: encoding.c:58
rb_str_set_len
void rb_str_set_len(VALUE, long)
Definition: string.c:2692
HWND
IUnknown COSERVERINFO MULTI_QI *typedef HWND(WINAPI FNHTMLHELP)(HWND hwndCaller
Definition: win32ole.c:35
FALSE
#define FALSE
Definition: nkf.h:174
pVarResult
static DISPID REFIID LCID WORD DISPPARAMS __RPC_FAR VARIANT __RPC_FAR * pVarResult
Definition: win32ole.c:89
ole_wc2vstr
VALUE ole_wc2vstr(LPWSTR pw, BOOL isfree)
Definition: win32ole.c:946
V_UNION1
#define V_UNION1(X, Y)
Definition: win32ole.h:47
cNames
static REFIID LPOLESTR __RPC_FAR UINT cNames
Definition: win32ole.c:88
I8_2_NUM
#define I8_2_NUM
Definition: win32ole.h:91
dwCallType
static DWORD dwCallType
Definition: win32ole.c:216
rb_hash_foreach
void rb_hash_foreach(VALUE hash, rb_foreach_func *func, VALUE farg)
Definition: hash.c:1483
V_UINT
#define V_UINT(X)
Definition: win32ole.h:78
MEMCMP
#define MEMCMP(p1, p2, type, n)
Definition: ruby.h:1755
RB_FIX2INT
#define RB_FIX2INT(x)
Definition: ruby.h:712
_Win32OLEIDispatch::obj
VALUE obj
Definition: win32ole.c:287
Init_win32ole_typelib
void Init_win32ole_typelib(void)
Definition: win32ole_typelib.c:826
rb_default_internal_encoding
rb_encoding * rb_default_internal_encoding(void)
Definition: encoding.c:1512
Init_win32ole_param
void Init_win32ole_param(void)
Definition: win32ole_param.c:423
cWIN32OLE
VALUE cWIN32OLE
Definition: win32ole.c:38
rb_add_event_hook
void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data)
Definition: vm_trace.c:157
StringValueCStr
#define StringValueCStr(v)
Definition: ruby.h:604
index
int index
Definition: rb_mjit_min_header-2.7.1.h:11251
RB_NUM2INT
#define RB_NUM2INT(x)
Definition: ruby.h:710
key
key
Definition: openssl_missing.h:181
T_HASH
#define T_HASH
Definition: ruby.h:531
V_INT
#define V_INT(X)
Definition: win32ole.h:70
BUFSIZ
#define BUFSIZ
Definition: rb_mjit_min_header-2.7.1.h:1474
rb_ary_clear
VALUE rb_ary_clear(VALUE ary)
Definition: array.c:3862
rb_eNoMethodError
VALUE rb_eNoMethodError
Definition: error.c:930
T_MODULE
#define T_MODULE
Definition: ruby.h:526
ole_uninitialize
void ole_uninitialize(void)
Definition: win32ole.c:799
RARRAY_LEN
#define RARRAY_LEN(a)
Definition: ruby.h:1070
cWIN32OLE_METHOD
VALUE cWIN32OLE_METHOD
Definition: win32ole_method.h:10
rb_scan_args
#define rb_scan_args(argc, argvp, fmt,...)
Definition: rb_mjit_min_header-2.7.1.h:6372
OLE_FREE
#define OLE_FREE(x)
Definition: win32ole.h:99
g_ole_initialized_set
#define g_ole_initialized_set(val)
Definition: win32ole.c:48
Init_win32ole_variant
void Init_win32ole_variant(void)
Definition: win32ole_variant.c:693
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:2010
rb_event_flag_t
uint32_t rb_event_flag_t
Definition: ruby.h:2278
UI8_2_NUM
#define UI8_2_NUM
Definition: win32ole.h:92
buf
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4322
T_BIGNUM
#define T_BIGNUM
Definition: ruby.h:533
TypedData_Get_Struct
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1252
StringValue
use StringValue() instead")))
T_ARRAY
#define T_ARRAY
Definition: ruby.h:530
argv
char ** argv
Definition: ruby.c:223
RB_INT2FIX
#define RB_INT2FIX(i)
Definition: ruby.h:262
cWIN32OLE_VARIANT
VALUE cWIN32OLE_VARIANT
Definition: win32ole_variant.h:4
ST_CONTINUE
@ ST_CONTINUE
Definition: st.h:99
oleparam::dp
DISPPARAMS dp
Definition: win32ole.c:79
rb_sprintf
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1197
V_UINTREF
#define V_UINTREF(X)
Definition: win32ole.h:82
rb_mark_hash
void rb_mark_hash(st_table *tbl)
Definition: gc.c:4864
rb_str_subseq
VALUE rb_str_subseq(VALUE, long, long)
Definition: string.c:2474
T_NIL
#define T_NIL
Definition: ruby.h:522
rgDispId
static REFIID LPOLESTR __RPC_FAR UINT LCID DISPID __RPC_FAR * rgDispId
Definition: win32ole.c:88
str
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
HRESULT
typedef HRESULT(STDAPICALLTYPE FNCOCREATEINSTANCEEX)(REFCLSID
myCPINFOEX::LeadByte
BYTE LeadByte[12]
Definition: win32ole.c:636
rb_enc_find_index
int rb_enc_find_index(const char *name)
Definition: encoding.c:693
RUBY_TYPED_FREE_IMMEDIATELY
#define RUBY_TYPED_FREE_IMMEDIATELY
Definition: ruby.h:1207
memset
void * memset(void *, int, size_t)
types
enum imemo_type types
Definition: debug.c:72
OLE_ADDREF
#define OLE_ADDREF(X)
Definition: win32ole.h:97
rb_hash_aset
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Definition: hash.c:2847
int
__inline__ int
Definition: rb_mjit_min_header-2.7.1.h:2839
RUBY_EVENT_THREAD_END
#define RUBY_EVENT_THREAD_END
Definition: ruby.h:2256
rb_fix2str
VALUE rb_fix2str(VALUE, int)
Definition: numeric.c:3508
NIL_P
#define NIL_P(v)
Definition: ruby.h:482
iTInfo
static UINT iTInfo
Definition: win32ole.c:87
snprintf
int snprintf(char *__restrict, size_t, const char *__restrict,...) __attribute__((__format__(__printf__
myCPINFOEX
Definition: win32ole.c:633
uCommand
IUnknown COSERVERINFO MULTI_QI *typedef LPCSTR UINT uCommand
Definition: win32ole.c:36
rb_check_id_cstr
ID rb_check_id_cstr(const char *ptr, long len, rb_encoding *enc)
Definition: symbol.c:988
ole_docinfo_from_type
HRESULT ole_docinfo_from_type(ITypeInfo *pTypeInfo, BSTR *name, BSTR *helpstr, DWORD *helpcontext, BSTR *helpfile)
Definition: win32ole.c:3647
argc
int argc
Definition: ruby.c:222
V_INTREF
#define V_INTREF(X)
Definition: win32ole.h:74
rb_define_const
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2880
err
int err
Definition: win32.c:135
NORETURN
NORETURN(static void failed_load_conv51932(void))
load_conv_function51932
#define load_conv_function51932()
Definition: win32ole.c:584
rb_data_type_struct
Definition: ruby.h:1148
xfree
#define xfree
Definition: defines.h:216
ole_vstr2wc
LPWSTR ole_vstr2wc(VALUE vstr)
Definition: win32ole.c:865
v
int VALUE v
Definition: rb_mjit_min_header-2.7.1.h:12337
myCPINFOEX::UnicodeDefaultChar
WCHAR UnicodeDefaultChar
Definition: win32ole.c:637
dwPendingType
static HTASK DWORD DWORD dwPendingType
Definition: win32ole.c:270
g_ole_initialized_init
#define g_ole_initialized_init()
Definition: win32ole.c:47
count
int count
Definition: encoding.c:57
st_memsize
size_t st_memsize(const st_table *tab)
Definition: st.c:719
Qtrue
#define Qtrue
Definition: ruby.h:468
len
uint8_t len
Definition: escape.c:17
printf
int int int printf(const char *__restrict,...) __attribute__((__format__(__printf__
oledata_get_struct
struct oledata * oledata_get_struct(VALUE ole)
Definition: win32ole.c:857
_Win32OLEIDispatch
Definition: win32ole.c:283
T_STRING
#define T_STRING
Definition: ruby.h:528
cWIN32OLE_lcid
LCID cWIN32OLE_lcid
Definition: win32ole.h:116
conv_51932
#define conv_51932(cp)
Definition: win32ole.c:588
rb_sym2str
VALUE rb_sym2str(VALUE)
Definition: symbol.c:784
rgszNames
static REFIID LPOLESTR __RPC_FAR * rgszNames
Definition: win32ole.c:88
rb_const_defined_at
int rb_const_defined_at(VALUE, ID)
Definition: variable.c:2688
ole_raise
void ole_raise(HRESULT hr, VALUE ecs, const char *fmt,...)
Definition: win32ole_error.c:46
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:1237
reg_enum_key
VALUE reg_enum_key(HKEY hkey, DWORD i)
Definition: win32ole.c:1710
Init_win32ole_method
void Init_win32ole_method(void)
Definition: win32ole_method.c:926
dwData
IUnknown COSERVERINFO MULTI_QI *typedef LPCSTR UINT DWORD dwData
Definition: win32ole.c:36
rb_ensure
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
Definition: eval.c:1115
NUM2I8
#define NUM2I8
Definition: win32ole.h:93
rb_ary_new
VALUE rb_ary_new(void)
Definition: array.c:723
rb_big2dbl
double rb_big2dbl(VALUE x)
Definition: bignum.c:5310
FNENUMSYSEMCODEPAGES
BOOL() FNENUMSYSEMCODEPAGES(CODEPAGE_ENUMPROC, DWORD)
Definition: win32ole.c:37
threadIDCallee
static HTASK threadIDCallee
Definition: win32ole.c:250
Qnil
#define Qnil
Definition: ruby.h:469
typelib_file
VALUE typelib_file(VALUE ole)
Definition: win32ole_typelib.c:781
NUM2DBL
#define NUM2DBL(x)
Definition: ruby.h:774
myCPINFOEX::CodePageName
char CodePageName[MAX_PATH]
Definition: win32ole.c:639
st_lookup
int st_lookup(st_table *tab, st_data_t key, st_data_t *value)
Definition: st.c:1101
rb_float_new
#define rb_float_new(d)
Definition: internal.h:1965
Init_win32ole_variable
void Init_win32ole_variable(void)
Definition: win32ole_variable.c:368
RB_GC_GUARD
#define RB_GC_GUARD(v)
Definition: ruby.h:585
RB_NUM2LONG
#define RB_NUM2LONG(x)
Definition: ruby.h:678
make_inspect
VALUE make_inspect(const char *class_name, VALUE detail)
Definition: win32ole.c:1333
free
free(psz)
RSTRING_LEN
#define RSTRING_LEN(str)
Definition: ruby.h:1005
st_free_table
void st_free_table(st_table *tab)
Definition: st.c:709
cWIN32OLE_TYPE
VALUE cWIN32OLE_TYPE
Definition: win32ole_type.h:3
st_table
Definition: st.h:79
OLE_GET_TYPEATTR
#define OLE_GET_TYPEATTR(X, Y)
Definition: win32ole.h:108
rb_enc_str_new
VALUE rb_enc_str_new(const char *, long, rb_encoding *)
Definition: string.c:796
rb_str_cat
VALUE rb_str_cat(VALUE, const char *, long)
Definition: string.c:2812
rb_enc_associate
VALUE rb_enc_associate(VALUE obj, rb_encoding *enc)
Definition: encoding.c:866
T_TRUE
#define T_TRUE
Definition: ruby.h:536
rb_obj_is_kind_of
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Determines if obj is a kind of c.
Definition: object.c:692
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
ENC_MACHING_CP
#define ENC_MACHING_CP(enc, encname, cp)
Definition: win32ole.c:489
ruby::backward::cxxanyargs::type
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:39
ole_wc2mb
char * ole_wc2mb(LPWSTR pw)
Definition: win32ole.c:743
fflush
int fflush(FILE *)
create_win32ole_record
VALUE create_win32ole_record(IRecordInfo *pri, void *prec)
Definition: win32ole_record.c:172
rb_str_cmp
int rb_str_cmp(VALUE, VALUE)
Definition: string.c:3228
lpInterfaceInfo
static DWORD HTASK DWORD LPINTERFACEINFO lpInterfaceInfo
Definition: win32ole.c:221
name
const char * name
Definition: nkf.c:208
rb_funcallv
#define rb_funcallv(recv, mid, argc, argv)
Definition: rb_mjit_min_header-2.7.1.h:7904
rb_const_get
VALUE rb_const_get(VALUE, ID)
Definition: variable.c:2387