ext/win32ole/win32ole.c


DEFINITIONS

This source file includes following functions.
  1. time2d
  2. d2time
  3. civil2jd
  4. jd2civil
  5. double2time
  6. time_object2date
  7. date2time_str
  8. ole_wc2mb
  9. ole_hresult2msg
  10. ole_excepinfo2msg
  11. ole_raise
  12. ole_uninitialize
  13. ole_initialize
  14. ole_msg_loop
  15. ole_free
  16. oletype_free
  17. olemethod_free
  18. olevariable_free
  19. oleparam_free
  20. ole_mb2wc
  21. ole_wc2vstr
  22. ole_ary_m_entry
  23. ole_set_safe_array
  24. ole_val2variant
  25. ole_set_member
  26. fole_s_allocate
  27. create_win32ole_object
  28. ole_variant2val
  29. reg_open_key
  30. reg_open_vkey
  31. reg_enum_key
  32. reg_get_val
  33. typelib_file_from_clsid
  34. typelib_file_from_typelib
  35. typelib_file
  36. ole_const_load
  37. clsid_from_remote
  38. ole_create_dcom
  39. ole_bind_obj
  40. fole_s_connect
  41. fole_s_const_load
  42. ole_classes_from_typelib
  43. reference_count
  44. fole_s_reference_count
  45. fole_s_free
  46. ole_show_help
  47. fole_s_show_help
  48. fole_initialize
  49. hash2named_arg
  50. ole_invoke
  51. fole_invoke
  52. ole_invoke2
  53. fole_invoke2
  54. fole_getproperty2
  55. fole_setproperty2
  56. fole_setproperty
  57. fole_getproperty
  58. ole_propertyput
  59. fole_free
  60. ole_each_sub
  61. ole_ienum_free
  62. fole_each
  63. fole_missing
  64. ole_method_sub
  65. olemethod_from_typeinfo
  66. ole_methods_sub
  67. ole_methods_from_typeinfo
  68. typeinfo_from_ole
  69. ole_methods
  70. fole_methods
  71. fole_get_methods
  72. fole_put_methods
  73. fole_func_methods
  74. fole_obj_help
  75. ole_docinfo_from_type
  76. ole_usertype2val
  77. ole_ptrtype2val
  78. ole_typedesc2val
  79. fole_method_help
  80. foletype_s_ole_classes
  81. foletype_s_typelibs
  82. foletype_s_progids
  83. foletype_s_allocate
  84. oletype_set_member
  85. oleclass_from_typelib
  86. foletype_initialize
  87. foletype_name
  88. ole_ole_type
  89. foletype_ole_type
  90. ole_type_guid
  91. foletype_guid
  92. ole_type_progid
  93. foletype_progid
  94. ole_type_visible
  95. foletype_visible
  96. ole_type_major_version
  97. foletype_major_version
  98. ole_type_minor_version
  99. foletype_minor_version
  100. ole_type_typekind
  101. foletype_typekind
  102. ole_type_helpstring
  103. foletype_helpstring
  104. ole_type_src_type
  105. foletype_src_type
  106. ole_type_helpfile
  107. foletype_helpfile
  108. ole_type_helpcontext
  109. foletype_helpcontext
  110. ole_variables
  111. foletype_variables
  112. foletype_methods
  113. folevariable_name
  114. ole_variable_ole_type
  115. folevariable_ole_type
  116. ole_variable_ole_type_detail
  117. folevariable_ole_type_detail
  118. ole_variable_value
  119. folevariable_value
  120. ole_variable_visible
  121. folevariable_visible
  122. ole_variable_kind
  123. folevariable_variable_kind
  124. ole_variable_varkind
  125. folevariable_varkind
  126. olemethod_set_member
  127. folemethod_s_allocate
  128. folemethod_initialize
  129. folemethod_name
  130. ole_method_return_type
  131. folemethod_return_type
  132. ole_method_return_vtype
  133. folemethod_return_vtype
  134. ole_method_return_type_detail
  135. folemethod_return_type_detail
  136. ole_method_invkind
  137. ole_method_invoke_kind
  138. folemethod_invkind
  139. folemethod_invoke_kind
  140. ole_method_visible
  141. folemethod_visible
  142. ole_method_event
  143. folemethod_event
  144. folemethod_event_interface
  145. ole_method_docinfo_from_type
  146. ole_method_helpstring
  147. folemethod_helpstring
  148. ole_method_helpfile
  149. folemethod_helpfile
  150. ole_method_helpcontext
  151. folemethod_helpcontext
  152. ole_method_dispid
  153. folemethod_dispid
  154. ole_method_offset_vtbl
  155. folemethod_offset_vtbl
  156. ole_method_size_params
  157. folemethod_size_params
  158. ole_method_size_opt_params
  159. folemethod_size_opt_params
  160. ole_method_params
  161. folemethod_params
  162. foleparam_name
  163. ole_param_ole_type
  164. foleparam_ole_type
  165. ole_param_ole_type_detail
  166. foleparam_ole_type_detail
  167. ole_param_flag_mask
  168. foleparam_input
  169. foleparam_output
  170. foleparam_optional
  171. foleparam_retval
  172. ole_param_default
  173. foleparam_default
  174. EVENTSINK_QueryInterface
  175. STDMETHODIMP_
  176. STDMETHODIMP_
  177. EVENTSINK_GetTypeInfoCount
  178. EVENTSINK_GetTypeInfo
  179. EVENTSINK_GetIDsOfNames
  180. ole_search_event
  181. val2ptr_variant
  182. ary2ptr_dispparams
  183. EVENTSINK_Invoke
  184. EVENTSINK_Constructor
  185. EVENTSINK_Destructor
  186. find_iid
  187. find_default_source
  188. ole_event_free
  189. fev_s_allocate
  190. fev_initialize
  191. fev_s_msg_loop
  192. add_event_call_back
  193. ev_on_event
  194. fev_on_event
  195. fev_on_event_with_outargs
  196. Init_win32ole


   1  /*
   2   *  (c) 1995 Microsoft Corporation. All rights reserved.
   3   *  Developed by ActiveWare Internet Corp., http://www.ActiveWare.com
   4   *
   5   *  Other modifications Copyright (c) 1997, 1998 by Gurusamy Sarathy
   6   *  <gsar@umich.edu> and Jan Dubois <jan.dubois@ibm.net>
   7   *
   8   *  You may distribute under the terms of either the GNU General Public
   9   *  License or the Artistic License, as specified in the README file
  10   *  of the Perl distribution.
  11   *
  12   */
  13  
  14  /*
  15    $Date: 2002/09/01 08:14:11 $
  16    modified for win32ole (ruby) by Masaki.Suketa <masaki.suketa@nifty.ne.jp>
  17   */
  18  
  19  #include "ruby.h"
  20  #include "st.h"
  21  #include <windows.h>
  22  #include <ocidl.h>
  23  #include <ole2.h>
  24  #ifdef HAVE_STDARG_PROTOTYPES
  25  #include <stdarg.h>
  26  #define va_init_list(a,b) va_start(a,b)
  27  #else
  28  #include <varargs.h>
  29  #define va_init_list(a,b) va_start(a)
  30  #endif
  31  
  32  #define DOUT fprintf(stderr,"[%d]\n",__LINE__)
  33  #define DOUTS(x) fprintf(stderr,"[%d]:" #x "=%s\n",__LINE__,x)
  34  #define DOUTMSG(x) fprintf(stderr, "[%d]:" #x "\n",__LINE__)
  35  #define DOUTI(x) fprintf(stderr, "[%ld]:" #x "=%d\n",__LINE__,x)
  36  #define DOUTD(x) fprintf(stderr, "[%d]:" #x "=%f\n",__LINE__,x)
  37  
  38  #if defined NONAMELESSUNION && __GNUC__
  39  #define V_UNION1(X, Y) ((X)->u.Y)
  40  #else
  41  #define V_UNION1(X, Y) ((X)->Y)
  42  #endif
  43  
  44  #if defined NONAMELESSUNION && __GNUC__
  45  #undef V_UNION
  46  #define V_UNION(X,Y) ((X)->n1.n2.n3.Y)
  47  
  48  #undef V_VT
  49  #define V_VT(X) ((X)->n1.n2.vt)
  50  
  51  #undef V_BOOL
  52  #define V_BOOL(X) V_UNION(X,boolVal)
  53  #endif
  54  
  55  #define OLE_RELEASE(X) (X) ? ((X)->lpVtbl->Release(X)) : 0
  56  
  57  #define OLE_ADDREF(X) (X) ? ((X)->lpVtbl->AddRef(X)) : 0
  58  
  59  #define OLE_GET_TYPEATTR(X, Y) ((X)->lpVtbl->GetTypeAttr((X), (Y)))
  60  #define OLE_RELEASE_TYPEATTR(X, Y) ((X)->lpVtbl->ReleaseTypeAttr((X), (Y)))
  61  
  62  #define OLE_FREE(x) {\
  63      if(gOLEInitialized == Qtrue) {\
  64          if(x) {\
  65              OLE_RELEASE(x);\
  66              (x) = 0;\
  67          }\
  68      }\
  69      ole_msg_loop();\
  70      CoFreeUnusedLibraries();\
  71  }
  72  
  73  #define OLEData_Get_Struct(obj, pole) {\
  74      Data_Get_Struct(obj, struct oledata, pole);\
  75      if(!pole->pDispatch) {\
  76          rb_raise(rb_eRuntimeError, "Fail to get Dispatch Interface");\
  77      }\
  78  }
  79  
  80  #define WC2VSTR(x) ole_wc2vstr((x), TRUE)
  81  
  82  #define WIN32OLE_VERSION "0.5.2"
  83  
  84  typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX)
  85      (REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*);
  86  
  87  typedef HWND (WINAPI FNHTMLHELP)(HWND hwndCaller, LPCSTR pszFile,
  88                                   UINT uCommand, DWORD dwData);
  89  typedef struct {
  90      struct IEventSinkVtbl * lpVtbl;
  91  } IEventSink, *PEVENTSINK;
  92  
  93  typedef struct IEventSinkVtbl IEventSinkVtbl;
  94  
  95  struct IEventSinkVtbl {
  96      STDMETHOD(QueryInterface)(
  97          PEVENTSINK,
  98          REFIID,
  99          LPVOID *);
 100      STDMETHOD_(ULONG, AddRef)(PEVENTSINK);
 101      STDMETHOD_(ULONG, Release)(PEVENTSINK);
 102  
 103      STDMETHOD(GetTypeInfoCount)(
 104          PEVENTSINK,
 105          UINT *);
 106      STDMETHOD(GetTypeInfo)(
 107          PEVENTSINK,
 108          UINT,
 109          LCID,
 110          ITypeInfo **);
 111      STDMETHOD(GetIDsOfNames)(
 112          PEVENTSINK,
 113          REFIID,
 114          OLECHAR **,
 115          UINT,
 116          LCID,
 117          DISPID *);
 118      STDMETHOD(Invoke)(
 119          PEVENTSINK,
 120          DISPID,
 121          REFIID,
 122          LCID,
 123          WORD,
 124          DISPPARAMS *,
 125          VARIANT *,
 126          EXCEPINFO *,
 127          UINT *);
 128  };
 129  
 130  typedef struct tagIEVENTSINKOBJ {
 131      IEventSinkVtbl *lpVtbl;
 132      DWORD m_cRef;
 133      IID m_iid;
 134      int m_event_id;
 135      DWORD m_dwCookie;
 136      IConnectionPoint *pConnectionPoint;
 137      ITypeInfo *pTypeInfo;
 138  }IEVENTSINKOBJ, *PIEVENTSINKOBJ;
 139  
 140  VALUE cWIN32OLE;
 141  VALUE cWIN32OLE_TYPE;
 142  VALUE cWIN32OLE_VARIABLE;
 143  VALUE cWIN32OLE_METHOD;
 144  VALUE cWIN32OLE_PARAM;
 145  VALUE cWIN32OLE_EVENT;
 146  VALUE eWIN32OLE_RUNTIME_ERROR;
 147  VALUE mWIN32OLE_VARIANT;
 148  
 149  static VALUE ary_ole_event;
 150  static ID id_events;
 151  static BOOL gOLEInitialized = Qfalse;
 152  static HINSTANCE ghhctrl = NULL;
 153  static HINSTANCE gole32 = NULL;
 154  static FNCOCREATEINSTANCEEX *gCoCreateInstanceEx = NULL;
 155  
 156  struct oledata {
 157      IDispatch *pDispatch;
 158  };
 159  
 160  struct oletypedata {
 161      ITypeInfo *pTypeInfo;
 162  };
 163  
 164  struct olemethoddata {
 165      ITypeInfo *pOwnerTypeInfo;
 166      ITypeInfo *pTypeInfo;
 167      UINT index;
 168  };
 169  
 170  struct olevariabledata {
 171      ITypeInfo *pTypeInfo;
 172      UINT index;
 173  };
 174  
 175  struct oleparamdata {
 176      ITypeInfo *pTypeInfo;
 177      UINT method_index;
 178      UINT index;
 179  };
 180  
 181  struct oleeventdata {
 182      IEVENTSINKOBJ *pEvent;
 183  };
 184  
 185  struct oleparam {
 186      DISPPARAMS dp;
 187      OLECHAR** pNamedArgs;
 188  };
 189  
 190  static VALUE folemethod_s_allocate _((VALUE));
 191  static VALUE olemethod_set_member _((VALUE, ITypeInfo *, ITypeInfo *, int, VALUE));
 192  static VALUE foletype_s_allocate _((VALUE));
 193  static VALUE oletype_set_member  _((VALUE, ITypeInfo *, VALUE));
 194  static VALUE olemethod_from_typeinfo _((VALUE, ITypeInfo *, VALUE));
 195  static HRESULT ole_docinfo_from_type _((ITypeInfo *, BSTR *, BSTR *, DWORD *, BSTR *));
 196  
 197  static void
 198  time2d(hh, mm, ss, pv)
 199      int hh, mm, ss;
 200      double *pv;
 201  {
 202      *pv =  (hh * 60.0 * 60.0 + mm * 60.0 + ss) / 86400.0;
 203  }
 204  
 205  static void
 206  d2time(v, hh, mm, ss)
 207      double v;
 208      int *hh, *mm, *ss;
 209  {
 210      double d_hh, d_mm, d_ss;
 211      int    i_hh, i_mm, i_ss;
 212  
 213      double d = v * 86400.0;
 214  
 215      d_hh = d / 3600.0;
 216      i_hh = (int)d_hh;
 217  
 218      d = d - i_hh * 3600.0;
 219  
 220      d_mm = d / 60.0;
 221      i_mm = (int)d_mm;
 222  
 223      d = d - i_mm * 60.0;
 224  
 225      d_ss = d * 10.0 + 5;
 226      
 227      i_ss = (int)d_ss / 10;
 228  
 229      if(i_ss == 60) {
 230          i_mm += 1;
 231          i_ss = 0;
 232      }
 233  
 234      if (i_mm == 60) {
 235          i_hh += 1;
 236          i_mm = 0;
 237      }
 238      if (i_hh == 24) {
 239          i_hh = 0;
 240      }
 241      
 242      *hh = i_hh;
 243      *mm = i_mm;
 244      *ss = i_ss;
 245  }
 246  
 247  static void
 248  civil2jd(y, m, d, jd)
 249      int y, m, d;
 250      long *jd;
 251  {
 252      long a, b;
 253      if (m <= 2) {
 254          y -= 1;
 255          m += 12;
 256      }
 257      a = (long)(y / 100.0);
 258      b = 2 - a + (long)(a / 4.0);
 259      *jd = (long)(365.25 * (double)(y + 4716))
 260           + (long)(30.6001 * (m + 1))
 261           + d + b - 1524;
 262  }
 263  
 264  static void
 265  jd2civil(day, yy, mm, dd)
 266      long day;
 267      int *yy, *mm, *dd;
 268  {
 269      long x, a, b, c, d, e;
 270      x = (long)(((double)day - 1867216.25) / 36524.25);
 271      a = day + 1 + x - (long)(x / 4.0);
 272      b = a + 1524;
 273      c = (long)(((double)b -122.1) /365.25);
 274      d = (long)(365.25 * c);
 275      e = (long)((double)(b - d) / 30.6001);
 276      *dd = b - d - (long)(30.6001 * e);
 277      if (e <= 13) {
 278          *mm = e - 1;
 279          *yy = c - 4716;
 280      }
 281      else {
 282          *mm = e - 13;
 283          *yy = c - 4715;
 284      }
 285  }
 286  
 287  static void
 288  double2time(v, y, m, d, hh, mm, ss)
 289      double v;
 290      int *y, *m, *d, *hh, *mm, *ss;
 291  {
 292      long day;
 293      double t;
 294  
 295      day = (long)v;
 296      t = v - day;
 297      jd2civil(2415019 + day, y, m, d);
 298  
 299      d2time(t, hh, mm, ss);
 300  }
 301  
 302  static double
 303  time_object2date(tmobj)
 304      VALUE tmobj;
 305  {
 306      long y, m, d, hh, mm, ss;
 307      long day;
 308      double t;
 309      y = FIX2INT(rb_funcall(tmobj, rb_intern("year"), 0));
 310      m = FIX2INT(rb_funcall(tmobj, rb_intern("month"), 0));
 311      d = FIX2INT(rb_funcall(tmobj, rb_intern("mday"), 0));
 312      hh = FIX2INT(rb_funcall(tmobj, rb_intern("hour"), 0));
 313      mm = FIX2INT(rb_funcall(tmobj, rb_intern("min"), 0));
 314      ss = FIX2INT(rb_funcall(tmobj, rb_intern("sec"), 0));
 315      civil2jd(y, m, d, &day);
 316      time2d(hh, mm, ss, &t);
 317      return t + day - 2415019;
 318  }
 319  
 320  static VALUE
 321  date2time_str(date)
 322      double date;
 323  {
 324      int y, m, d, hh, mm, ss;
 325      char szTime[20];
 326      double2time(date, &y, &m, &d, &hh, &mm, &ss);
 327      sprintf(szTime,
 328              "%4.4d/%02.2d/%02.2d %02.2d:%02.2d:%02.2d",
 329              y, m, d, hh, mm, ss);
 330      return rb_str_new2(szTime);
 331  }
 332  
 333  static void ole_val2variant();
 334  
 335  static char *
 336  ole_wc2mb(pw)
 337      LPWSTR pw;
 338  {
 339      int size;
 340      LPSTR pm;
 341      size = WideCharToMultiByte(CP_ACP, 0, pw, -1, NULL, 0, NULL, NULL);
 342      if (size) {
 343          pm = ALLOC_N(char, size);    
 344          WideCharToMultiByte(CP_ACP, 0, pw, -1, pm, size, NULL, NULL);
 345      }
 346      else {
 347          pm = ALLOC_N(char, 1);
 348          *pm = '\0';
 349      }
 350      return pm;
 351  } 
 352  
 353  static VALUE
 354  ole_hresult2msg(hr)
 355      HRESULT hr;
 356  {
 357      VALUE msg = Qnil;
 358      char *p_msg;
 359      DWORD dwCount;
 360  
 361      char strhr[100];
 362      sprintf(strhr, "    HRESULT error code:0x%08x\n      ", hr);
 363      msg = rb_str_new2(strhr);
 364  
 365      dwCount = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
 366                              FORMAT_MESSAGE_FROM_SYSTEM |
 367                              FORMAT_MESSAGE_IGNORE_INSERTS,
 368                              NULL, hr, LOCALE_SYSTEM_DEFAULT,
 369                              (LPTSTR)&p_msg, 0, NULL);
 370      if (dwCount > 0) {
 371          /* remove dots and CRs/LFs */
 372          while (dwCount > 0 &&
 373                 (p_msg[dwCount-1] < ' ' || p_msg[dwCount-1] == '.')) {
 374              p_msg[--dwCount] = '\0';
 375          }
 376          if (p_msg[0] != '\0') {
 377              rb_str_cat2(msg, p_msg);
 378          }
 379      }
 380      return msg;
 381  }
 382  
 383  static VALUE
 384  ole_excepinfo2msg(pExInfo)
 385      EXCEPINFO *pExInfo;
 386  {
 387      char error_code[40];
 388      char *pSource = NULL;
 389      char *pDescription = NULL;
 390      VALUE error_msg;
 391      if(pExInfo->pfnDeferredFillIn != NULL) {
 392          (*pExInfo->pfnDeferredFillIn)(pExInfo);
 393      }
 394      if (pExInfo->bstrSource != NULL) {
 395          pSource = ole_wc2mb(pExInfo->bstrSource);
 396      }
 397      if (pExInfo->bstrDescription != NULL) {
 398          pDescription = ole_wc2mb(pExInfo->bstrDescription);
 399      }
 400      if(pExInfo->wCode == 0) {
 401          sprintf(error_code, "\n    OLE error code:%lX in ", pExInfo->scode);
 402      }
 403      else{
 404          sprintf(error_code, "\n    OLE error code:%u in ", pExInfo->wCode);
 405      }
 406      error_msg = rb_str_new2(error_code);
 407      if(pSource != NULL) {
 408          rb_str_cat(error_msg, pSource, strlen(pSource));
 409      }
 410      else {
 411          rb_str_cat(error_msg, "<Unknown>", 9);
 412      }
 413      rb_str_cat2(error_msg, "\n      ");
 414      if(pDescription != NULL) {
 415          rb_str_cat2(error_msg, pDescription);
 416      }
 417      else {
 418          rb_str_cat2(error_msg, "<No Description>");
 419      }
 420      if(pSource) free(pSource);
 421      if(pDescription) free(pDescription);
 422      SysFreeString(pExInfo->bstrDescription);
 423      SysFreeString(pExInfo->bstrSource);
 424      SysFreeString(pExInfo->bstrHelpFile);
 425      return error_msg;
 426  }
 427  
 428  static void
 429  #ifdef HAVE_STDARG_PROTOTYPES
 430  ole_raise(HRESULT hr, VALUE ecs, const char *fmt, ...)
 431  #else
 432  ole_raise(hr, exc, fmt, va_alist)
 433      HRESULT hr;
 434      VALUE exc;
 435      const char *fmt;
 436      va_dcl
 437  #endif
 438  {
 439      va_list args;
 440      char buf[BUFSIZ];
 441      VALUE err_msg;
 442      va_init_list(args, fmt);
 443      vsnprintf(buf, BUFSIZ, fmt, args);
 444      va_end(args);
 445  
 446      err_msg = ole_hresult2msg(hr);
 447      if(err_msg != Qnil) {
 448          rb_raise(ecs, "%s\n%s", buf, StringValuePtr(err_msg));
 449      }
 450      else {
 451          rb_raise(ecs, "%s", buf);
 452      }
 453  }
 454  
 455  void
 456  ole_uninitialize()
 457  {
 458      OleUninitialize();
 459      gOLEInitialized = Qfalse;
 460  }
 461  
 462  static void
 463  ole_initialize() 
 464  {
 465      HRESULT hr;
 466      int rc;
 467      
 468      if(gOLEInitialized == Qfalse) {
 469          hr = OleInitialize(NULL);
 470          if(FAILED(hr)) {
 471              ole_raise(hr, rb_eRuntimeError, "Fail : OLE initialize");
 472          }
 473          gOLEInitialized = Qtrue;
 474          rc = atexit((void (*)(void))ole_uninitialize);
 475      }
 476  }
 477  
 478  static void
 479  ole_msg_loop() {
 480      MSG msg;
 481      while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
 482          TranslateMessage(&msg);
 483          DispatchMessage(&msg);
 484      }
 485  }
 486  
 487  static void
 488  ole_free(pole)
 489      struct oledata *pole;
 490  {
 491      OLE_FREE(pole->pDispatch);
 492  }
 493  
 494  static void
 495  oletype_free(poletype)
 496      struct oletypedata *poletype;
 497  {
 498      OLE_FREE(poletype->pTypeInfo);
 499  }
 500  
 501  static void
 502  olemethod_free(polemethod)
 503      struct olemethoddata *polemethod;
 504  {
 505      OLE_FREE(polemethod->pTypeInfo);
 506      OLE_FREE(polemethod->pOwnerTypeInfo);
 507  }
 508  
 509  static void
 510  olevariable_free(polevar)
 511      struct olevariabledata *polevar;
 512  {
 513      OLE_FREE(polevar->pTypeInfo);
 514  }
 515  
 516  static void
 517  oleparam_free(pole)
 518      struct oleparamdata *pole;
 519  {
 520      OLE_FREE(pole->pTypeInfo);
 521  }
 522  
 523  static LPWSTR
 524  ole_mb2wc(pm, len)
 525      char *pm;
 526      int  len;
 527  {
 528      int size;
 529      LPWSTR pw;
 530      size = MultiByteToWideChar(CP_ACP, 0, pm, len, NULL, 0);
 531      pw = SysAllocStringLen(NULL, size - 1);
 532      MultiByteToWideChar(CP_ACP, 0, pm, len, pw, size);
 533      return pw;
 534  }
 535  
 536  static VALUE
 537  ole_wc2vstr(pw, isfree)
 538      LPWSTR pw;
 539      BOOL isfree;
 540  {
 541      char *p = ole_wc2mb(pw);
 542      VALUE vstr = rb_str_new2(p);
 543      if(isfree)
 544          SysFreeString(pw);
 545      free(p);
 546      return vstr;
 547  }
 548  
 549  static VALUE
 550  ole_ary_m_entry(val, pid)
 551      VALUE val;
 552      long *pid;
 553  {
 554      VALUE obj = Qnil;
 555      int i = 0;
 556      obj = val;
 557      while(TYPE(obj) == T_ARRAY) {
 558          obj = rb_ary_entry(obj, pid[i]);
 559          i++;
 560      }
 561      return obj;
 562  }
 563  
 564  static void
 565  ole_set_safe_array(n, psa, pid, pub, val, dim)
 566      long n;
 567      SAFEARRAY *psa;
 568      long *pid;
 569      long *pub;
 570      VALUE val;
 571      long dim;
 572  {
 573      VALUE val1;
 574      VARIANT var;
 575      VariantInit(&var);
 576      if(n < 0) return;
 577      if(n == dim) {
 578          val1 = ole_ary_m_entry(val, pid);
 579          ole_val2variant(val1, &var);
 580          SafeArrayPutElement(psa, pid, &var);
 581      }
 582      pid[n] += 1;
 583      if (pid[n] < pub[n]) {
 584          ole_set_safe_array(dim, psa, pid, pub, val, dim);
 585      }
 586      else {
 587          pid[n] = 0;
 588          ole_set_safe_array(n-1, psa, pid, pub, val, dim);
 589      }
 590  }
 591  
 592  static void
 593  ole_val2variant(val, var)
 594      VALUE val;
 595      VARIANT *var;
 596  {
 597      struct oledata *pole;
 598      if(rb_obj_is_kind_of(val, cWIN32OLE)) {
 599          Data_Get_Struct(val, struct oledata, pole);
 600          OLE_ADDREF(pole->pDispatch);
 601          V_VT(var) = VT_DISPATCH;
 602          V_DISPATCH(var) = pole->pDispatch;
 603          return;
 604      }
 605      if (rb_obj_is_kind_of(val, rb_cTime)) {
 606          V_VT(var) = VT_DATE;
 607          V_DATE(var) = time_object2date(val);
 608          return;
 609      }
 610      switch (TYPE(val)) {
 611      case T_ARRAY:
 612      {
 613          VALUE val1;
 614          long dim = 0;
 615          int  i = 0;
 616  
 617          HRESULT hr;
 618          SAFEARRAYBOUND *psab;
 619          SAFEARRAY *psa;
 620          long      *pub, *pid;
 621  
 622          val1 = val;
 623          while(TYPE(val1) == T_ARRAY) {
 624              val1 = rb_ary_entry(val1, 0);
 625              dim += 1;
 626          }
 627          psab = ALLOC_N(SAFEARRAYBOUND, dim);
 628          pub  = ALLOC_N(long, dim);
 629          pid  = ALLOC_N(long, dim);
 630  
 631          if(!psab || !pub || !pid) {
 632              if(pub) free(pub);
 633              if(psab) free(psab);
 634              if(pid) free(pid);
 635              rb_raise(rb_eRuntimeError, "memory allocate error");
 636          }
 637          val1 = val;
 638          i = 0;
 639          while(TYPE(val1) == T_ARRAY) {
 640              psab[i].cElements = RARRAY(val1)->len;
 641              psab[i].lLbound = 0;
 642              pub[i] = psab[i].cElements;
 643              pid[i] = 0;
 644              i ++;
 645              val1 = rb_ary_entry(val1, 0);
 646          }
 647          /* Create and fill VARIANT array */
 648          psa = SafeArrayCreate(VT_VARIANT, dim, psab);
 649          if (psa == NULL)
 650              hr = E_OUTOFMEMORY;
 651          else
 652              hr = SafeArrayLock(psa);
 653          if (SUCCEEDED(hr)) {
 654              ole_set_safe_array(dim-1, psa, pid, pub, val, dim-1);
 655              hr = SafeArrayUnlock(psa);
 656          }
 657          if(pub) free(pub);
 658          if(psab) free(psab);
 659          if(pid) free(pid);
 660  
 661          if (SUCCEEDED(hr)) {
 662              V_VT(var) = VT_VARIANT | VT_ARRAY;
 663              V_ARRAY(var) = psa;
 664          }
 665          else if (psa != NULL)
 666              SafeArrayDestroy(psa);
 667          break;
 668      }
 669      case T_STRING:
 670          V_VT(var) = VT_BSTR;
 671          V_BSTR(var) = ole_mb2wc(StringValuePtr(val), -1);
 672          break;
 673      case T_FIXNUM:
 674          V_VT(var) = VT_I4;
 675          V_I4(var) = NUM2INT(val);
 676          break;
 677      case T_BIGNUM:
 678          V_VT(var) = VT_R8;
 679          V_R8(var) = rb_big2dbl(val);
 680          break;
 681      case T_FLOAT:
 682          V_VT(var) = VT_R8;
 683          V_R8(var) = NUM2DBL(val);
 684          break;
 685      case T_TRUE:
 686          V_VT(var) = VT_BOOL;
 687          V_BOOL(var) = VARIANT_TRUE;
 688          break;
 689      case T_FALSE:
 690          V_VT(var) = VT_BOOL;
 691          V_BOOL(var) = VARIANT_FALSE;
 692          break;
 693      case T_NIL:
 694          V_VT(var) = VT_ERROR;
 695          V_ERROR(var) = DISP_E_PARAMNOTFOUND;
 696          break;
 697      default:
 698          rb_raise(rb_eTypeError, "not valid value");
 699          break;
 700      }
 701  }
 702  
 703  static VALUE
 704  ole_set_member(self, dispatch)
 705      VALUE self;
 706      IDispatch * dispatch;
 707  {
 708      struct oledata *pole;
 709      Data_Get_Struct(self, struct oledata, pole);
 710      if (pole->pDispatch) {
 711          OLE_RELEASE(pole->pDispatch);
 712          pole->pDispatch = NULL;
 713      }
 714      pole->pDispatch = dispatch;
 715      return self;
 716  }
 717  
 718  static VALUE
 719  fole_s_allocate(klass)
 720      VALUE klass;
 721  {
 722      struct oledata *pole;
 723      VALUE obj;
 724      ole_initialize();
 725      obj = Data_Make_Struct(klass,struct oledata,0,ole_free,pole);
 726      pole->pDispatch = NULL;
 727      return obj;
 728  }
 729  
 730  static VALUE
 731  create_win32ole_object(klass, pDispatch, argc, argv)
 732      VALUE klass;
 733      IDispatch *pDispatch;
 734      int argc;
 735      VALUE *argv;
 736  {
 737      VALUE obj = fole_s_allocate(klass);
 738      ole_set_member(obj, pDispatch);
 739      return obj;
 740  }
 741  
 742  static VALUE
 743  ole_variant2val(pvar)
 744      VARIANT *pvar;
 745  {
 746      VALUE obj = Qnil;
 747      HRESULT hr;
 748      while ( V_VT(pvar) == (VT_BYREF | VT_VARIANT) )
 749          pvar = V_VARIANTREF(pvar);
 750  
 751      if(V_ISARRAY(pvar)) {
 752          SAFEARRAY *psa = V_ISBYREF(pvar) ? *V_ARRAYREF(pvar) : V_ARRAY(pvar);
 753          long i;
 754          long *pID, *pLB, *pUB;
 755          VARIANT variant;
 756          VALUE val;
 757          VALUE val2;
 758  
 759          int dim = SafeArrayGetDim(psa);
 760          VariantInit(&variant);
 761          V_VT(&variant) = (V_VT(pvar) & ~VT_ARRAY) | VT_BYREF;
 762  
 763          pID = ALLOC_N(long, dim);
 764          pLB = ALLOC_N(long, dim);
 765          pUB = ALLOC_N(long, dim);
 766  
 767          if(!pID || !pLB || !pUB) {
 768              if(pID) free(pID);
 769              if(pLB) free(pLB);
 770              if(pUB) free(pUB);
 771              rb_raise(rb_eRuntimeError, "memory allocate error");
 772          }
 773  
 774          obj = Qnil;
 775  
 776          for(i = 0; i < dim; ++i) {
 777              SafeArrayGetLBound(psa, i+1, &pLB[i]);
 778              SafeArrayGetLBound(psa, i+1, &pID[i]);
 779              SafeArrayGetUBound(psa, i+1, &pUB[i]);
 780          }
 781  
 782          hr = SafeArrayLock(psa);
 783          if (SUCCEEDED(hr)) {
 784              val2 = rb_ary_new();
 785              while (i >= 0) {
 786                  hr = SafeArrayPtrOfIndex(psa, pID, &V_BYREF(&variant));
 787                  if (FAILED(hr))
 788                      break;
 789  
 790                  val = ole_variant2val(&variant);
 791                  rb_ary_push(val2, val);
 792                  for (i = dim-1 ; i >= 0 ; --i) {
 793                      if (++pID[i] <= pUB[i])
 794                          break;
 795  
 796                      pID[i] = pLB[i];
 797                      if (i > 0) {
 798                          if (obj == Qnil)
 799                              obj = rb_ary_new();
 800                          rb_ary_push(obj, val2);
 801                          val2 = rb_ary_new();
 802                      }
 803                  }
 804              }
 805              SafeArrayUnlock(psa);
 806          }
 807          if(pID) free(pID);
 808          if(pLB) free(pLB);
 809          if(pUB) free(pUB);
 810          return (obj == Qnil) ? val2 : obj;
 811      }
 812      switch(V_VT(pvar) & ~VT_BYREF){
 813      case VT_EMPTY:
 814          break;
 815      case VT_NULL:
 816          break;
 817      case VT_UI1:
 818          if(V_ISBYREF(pvar)) 
 819              obj = INT2NUM((long)*V_UI1REF(pvar));
 820          else 
 821              obj = INT2NUM((long)V_UI1(pvar));
 822          break;
 823  
 824      case VT_I2:
 825          if(V_ISBYREF(pvar))
 826              obj = INT2NUM((long)*V_I2REF(pvar));
 827          else 
 828              obj = INT2NUM((long)V_I2(pvar));
 829          break;
 830  
 831      case VT_I4:
 832          if(V_ISBYREF(pvar))
 833              obj = INT2NUM((long)*V_I4REF(pvar));
 834          else 
 835              obj = INT2NUM((long)V_I4(pvar));
 836          break;
 837  
 838      case VT_R4:
 839          if(V_ISBYREF(pvar))
 840              obj = rb_float_new(*V_R4REF(pvar));
 841          else
 842              obj = rb_float_new(V_R4(pvar));
 843          break;
 844  
 845      case VT_R8:
 846          if(V_ISBYREF(pvar))
 847              obj = rb_float_new(*V_R8REF(pvar));
 848          else
 849              obj = rb_float_new(V_R8(pvar));
 850          break;
 851  
 852      case VT_BSTR:
 853      {
 854          char *p;
 855          if(V_ISBYREF(pvar))
 856              p = ole_wc2mb(*V_BSTRREF(pvar));
 857          else
 858              p = ole_wc2mb(V_BSTR(pvar));
 859          obj = rb_str_new2(p);
 860          if(p) free(p);
 861          break;
 862      }
 863  
 864      case VT_ERROR:
 865          if(V_ISBYREF(pvar))
 866              obj = INT2NUM(*V_ERRORREF(pvar));
 867          else
 868              obj = INT2NUM(V_ERROR(pvar));
 869          break;
 870  
 871      case VT_BOOL:
 872          if (V_ISBYREF(pvar))
 873              obj = (*V_BOOLREF(pvar) ? Qtrue : Qfalse);
 874          else
 875              obj = (V_BOOL(pvar) ? Qtrue : Qfalse);
 876          break;
 877  
 878      case VT_DISPATCH:
 879      {
 880          IDispatch *pDispatch;
 881  
 882          if (V_ISBYREF(pvar))
 883              pDispatch = *V_DISPATCHREF(pvar);
 884          else
 885              pDispatch = V_DISPATCH(pvar);
 886  
 887          if (pDispatch != NULL ) {
 888              OLE_ADDREF(pDispatch);
 889              obj = create_win32ole_object(cWIN32OLE, pDispatch, 0, 0);
 890          }
 891          break;
 892      }
 893  
 894      case VT_UNKNOWN:
 895      {
 896  
 897          /* get IDispatch interface from IUnknown interface */
 898          IUnknown *punk;
 899          IDispatch *pDispatch;
 900          HRESULT hr;
 901  
 902          if (V_ISBYREF(pvar))
 903              punk = *V_UNKNOWNREF(pvar);
 904          else
 905              punk = V_UNKNOWN(pvar);
 906  
 907          if(punk != NULL) {
 908             hr = punk->lpVtbl->QueryInterface(punk, &IID_IDispatch,
 909                                               (void **)&pDispatch);
 910             if(SUCCEEDED(hr)) {
 911                 obj = create_win32ole_object(cWIN32OLE, pDispatch, 0, 0);
 912             }
 913          }
 914          break;
 915      }
 916  
 917      case VT_DATE:
 918      {
 919          DATE date;
 920          if(V_ISBYREF(pvar))
 921              date = *V_DATEREF(pvar);
 922          else
 923              date = V_DATE(pvar);
 924  
 925          obj =  date2time_str(date);
 926          break;
 927      }
 928      case VT_CY:
 929      default:
 930          {
 931          HRESULT hr;
 932          VARIANT variant;
 933          VariantInit(&variant);
 934          hr = VariantChangeTypeEx(&variant, pvar, 
 935                                    LOCALE_SYSTEM_DEFAULT, 0, VT_BSTR);
 936          if (SUCCEEDED(hr) && V_VT(&variant) == VT_BSTR) {
 937              char *p = ole_wc2mb(V_BSTR(&variant));
 938              obj = rb_str_new2(p);
 939              if(p) free(p);
 940          }
 941          VariantClear(&variant);
 942          break;
 943          }
 944      }
 945      return obj;
 946  }
 947  
 948  static LONG reg_open_key(hkey, name, phkey)
 949      HKEY hkey;
 950      const char *name;
 951      HKEY *phkey;
 952  {
 953      return RegOpenKeyEx(hkey, name, 0, KEY_READ, phkey);
 954  }
 955  
 956  static LONG reg_open_vkey(hkey, key, phkey)
 957      HKEY hkey;
 958      VALUE key;
 959      HKEY *phkey;
 960  {
 961      return reg_open_key(hkey, StringValuePtr(key), phkey);
 962  }
 963  
 964  static VALUE
 965  reg_enum_key(hkey, i)
 966      HKEY hkey;
 967      DWORD i;
 968  {
 969      char buf[BUFSIZ];
 970      DWORD size_buf = sizeof(buf);
 971      FILETIME ft;
 972      LONG err = RegEnumKeyEx(hkey, i, buf, &size_buf,
 973                              NULL, NULL, NULL, &ft);
 974      if(err == ERROR_SUCCESS) {
 975          return rb_str_new2(buf);
 976      }
 977      return Qnil;
 978  }
 979  
 980  static VALUE
 981  reg_get_val(hkey, subkey)
 982      HKEY hkey;
 983      const char *subkey;
 984  {
 985      char buf[BUFSIZ];
 986      LONG size_buf = sizeof(buf);
 987      LONG err = RegQueryValue(hkey, subkey, buf, &size_buf);
 988      if (err == ERROR_SUCCESS) {
 989          return rb_str_new2(buf);
 990      }
 991      return Qnil;
 992  }
 993  
 994  static VALUE
 995  typelib_file_from_clsid(ole)
 996      VALUE ole;
 997  {
 998      OLECHAR *pbuf;
 999      CLSID clsid;
1000      HRESULT hr;
1001      HKEY hroot, hclsid;
1002      LONG err;
1003      VALUE typelib;
1004      VALUE vclsid;
1005      char *pclsid = NULL;
1006  
1007      pbuf  = ole_mb2wc(StringValuePtr(ole), -1);
1008      hr = CLSIDFromProgID(pbuf, &clsid);
1009      SysFreeString(pbuf);
1010      if (FAILED(hr)) {
1011          return Qnil;
1012      }
1013      StringFromCLSID(&clsid, &pbuf);
1014      vclsid = WC2VSTR(pbuf);
1015      err = reg_open_key(HKEY_CLASSES_ROOT, "CLSID", &hroot);
1016      if (err != ERROR_SUCCESS) {
1017          return Qnil;
1018      }
1019      err = reg_open_key(hroot, StringValuePtr(vclsid), &hclsid);
1020      if (err != ERROR_SUCCESS) {
1021          RegCloseKey(hroot);
1022          return Qnil;
1023      }
1024      typelib = reg_get_val(hclsid, "InprocServer32");
1025      RegCloseKey(hroot);
1026      RegCloseKey(hclsid);
1027      return typelib;
1028  }
1029  
1030  static VALUE
1031  typelib_file_from_typelib(ole)
1032      VALUE ole;
1033  {
1034      HKEY htypelib, hclsid, hversion, hlang;
1035      double fver;
1036      DWORD i, j, k;
1037      LONG err;
1038      BOOL found = FALSE;
1039      VALUE typelib;
1040      VALUE file = Qnil;
1041      VALUE clsid;
1042      VALUE ver;
1043      VALUE lang;
1044  
1045      err = reg_open_key(HKEY_CLASSES_ROOT, "TypeLib", &htypelib);
1046      if(err != ERROR_SUCCESS) {
1047          return Qnil;
1048      }
1049      for(i = 0; !found; i++) {
1050          clsid = reg_enum_key(htypelib, i);
1051          if (clsid == Qnil)
1052              break;
1053          err = reg_open_vkey(htypelib, clsid, &hclsid);
1054          if (err != ERROR_SUCCESS)
1055              continue;
1056          fver = 0;
1057          for(j = 0; !found; j++) {
1058              ver = reg_enum_key(hclsid, j);
1059              if (ver == Qnil)
1060                  break;
1061              err = reg_open_vkey(hclsid, ver, &hversion);
1062              if (err != ERROR_SUCCESS || fver > atof(StringValuePtr(ver)))
1063                  continue;
1064              fver = atof(StringValuePtr(ver));
1065              typelib = reg_get_val(hversion, NULL);
1066              if (typelib == Qnil)
1067                  continue;
1068              if (rb_str_cmp(typelib, ole) == 0) {
1069                  for(k = 0; !found; k++) {
1070                      lang = reg_enum_key(hversion, k);
1071                      if (lang == Qnil)
1072                          break;
1073                      err = reg_open_vkey(hversion, lang, &hlang);
1074                      if (err == ERROR_SUCCESS) {
1075                          if ((file = reg_get_val(hlang, "win32")) != Qnil) 
1076                              found = TRUE;
1077                          RegCloseKey(hlang);
1078                      }
1079                  }
1080              }
1081              RegCloseKey(hversion);
1082          }
1083          RegCloseKey(hclsid);
1084      }
1085      RegCloseKey(htypelib);
1086      return  file;
1087  }
1088  
1089  static VALUE
1090  typelib_file(ole)
1091      VALUE ole;
1092  {
1093      VALUE file = typelib_file_from_clsid(ole);
1094      if (file != Qnil) {
1095          return file;
1096      }
1097      return typelib_file_from_typelib(ole);
1098  }
1099  
1100  static void
1101  ole_const_load(pTypeLib, klass, self)
1102      ITypeLib *pTypeLib;
1103      VALUE klass;
1104      VALUE self;
1105  {
1106      unsigned int count;
1107      unsigned int index;
1108      int iVar;
1109      ITypeInfo *pTypeInfo;
1110      TYPEATTR  *pTypeAttr;
1111      VARDESC   *pVarDesc;
1112      HRESULT hr;
1113      unsigned int len;
1114      BSTR bstr;
1115      char *pName = NULL;
1116      VALUE val;
1117      VALUE constant;
1118      ID id;
1119      constant = rb_hash_new();
1120      count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
1121      for (index = 0; index < count; index++) {
1122          hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, index, &pTypeInfo);
1123          if (FAILED(hr))
1124              continue;
1125          hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
1126          if(FAILED(hr)) {
1127              OLE_RELEASE(pTypeInfo);
1128              continue;
1129          }
1130          for(iVar = 0; iVar < pTypeAttr->cVars; iVar++) {
1131              hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, iVar, &pVarDesc);
1132              if(FAILED(hr))
1133                  continue;
1134              if(pVarDesc->varkind == VAR_CONST &&
1135                 !(pVarDesc->wVarFlags & (VARFLAG_FHIDDEN |
1136                                          VARFLAG_FRESTRICTED |
1137                                          VARFLAG_FNONBROWSABLE))) {
1138                  hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, pVarDesc->memid, &bstr,
1139                                                   1, &len);
1140                  if(FAILED(hr) || len == 0 || !bstr)
1141                      continue;
1142                  pName = ole_wc2mb(bstr);
1143                  val = ole_variant2val(V_UNION1(pVarDesc, lpvarValue));
1144                  *pName = toupper(*pName);
1145                  id = rb_intern(pName);
1146                  if (rb_is_const_id(id)) {
1147                      rb_define_const(klass, pName, val);
1148                  }
1149                  else {
1150                      rb_hash_aset(constant, rb_str_new2(pName), val);
1151                  }
1152                  SysFreeString(bstr);
1153                  if(pName) {
1154                      free(pName);
1155                      pName = NULL;
1156                  }
1157              }
1158              pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
1159          }
1160          pTypeInfo->lpVtbl->ReleaseTypeAttr(pTypeInfo, pTypeAttr);
1161          OLE_RELEASE(pTypeInfo);
1162      }
1163      rb_define_const(klass, "CONSTANTS", constant);
1164  }
1165  
1166  static HRESULT
1167  clsid_from_remote(host, com, pclsid)
1168      VALUE host;
1169      VALUE com;
1170      CLSID *pclsid;
1171  {
1172      HKEY hlm;
1173      HKEY hpid;
1174      VALUE subkey;
1175      LONG err;
1176      char clsid[100];
1177      OLECHAR *pbuf;
1178      DWORD len;
1179      DWORD dwtype;
1180      HRESULT hr = S_OK;
1181      err = RegConnectRegistry(StringValuePtr(host), HKEY_LOCAL_MACHINE, &hlm);
1182      if (err != ERROR_SUCCESS)
1183          return HRESULT_FROM_WIN32(err);
1184      subkey = rb_str_new2("SOFTWARE\\Classes\\");
1185      rb_str_concat(subkey, com);
1186      rb_str_cat2(subkey, "\\CLSID");
1187      err = RegOpenKeyEx(hlm, StringValuePtr(subkey), 0, KEY_READ, &hpid);
1188      if (err != ERROR_SUCCESS)
1189          hr = HRESULT_FROM_WIN32(err);
1190      else {
1191          len = sizeof(clsid);
1192          err = RegQueryValueEx(hpid, "", NULL, &dwtype, clsid, &len);
1193          if (err == ERROR_SUCCESS && dwtype == REG_SZ) {
1194              pbuf  = ole_mb2wc(clsid, -1);
1195              hr = CLSIDFromString(pbuf, pclsid);
1196              SysFreeString(pbuf);
1197          }
1198          else {
1199              hr = HRESULT_FROM_WIN32(err);
1200          }
1201          RegCloseKey(hpid);
1202      }
1203      RegCloseKey(hlm);
1204      return hr;
1205  }
1206  
1207  static VALUE
1208  ole_create_dcom(argc, argv, self)
1209      int argc;
1210      VALUE *argv;
1211      VALUE self;
1212  {
1213      VALUE ole, host, others;
1214      HRESULT hr;
1215      CLSID   clsid;
1216      OLECHAR *pbuf;
1217  
1218      COSERVERINFO serverinfo;
1219      MULTI_QI multi_qi;
1220      DWORD clsctx = CLSCTX_REMOTE_SERVER;
1221  
1222      if (!gole32)
1223          gole32 = LoadLibrary("OLE32");
1224      if (!gole32)
1225          rb_raise(rb_eRuntimeError, "Fail to load OLE32.");
1226      if (!gCoCreateInstanceEx)
1227          gCoCreateInstanceEx = (FNCOCREATEINSTANCEEX*)
1228              GetProcAddress(gole32, "CoCreateInstanceEx");
1229      if (!gCoCreateInstanceEx)
1230          rb_raise(rb_eRuntimeError, "CoCreateInstanceEx is not supported in this environment.");
1231      rb_scan_args(argc, argv, "2*", &ole, &host, &others);
1232  
1233      pbuf  = ole_mb2wc(StringValuePtr(ole), -1);
1234      hr = CLSIDFromProgID(pbuf, &clsid);
1235      if (FAILED(hr))
1236          hr = clsid_from_remote(host, ole, &clsid);
1237      if (FAILED(hr))
1238          hr = CLSIDFromString(pbuf, &clsid);
1239      SysFreeString(pbuf);
1240      if (FAILED(hr))
1241          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, 
1242                    "Unknown OLE server : `%s'",
1243                    StringValuePtr(ole));
1244      memset(&serverinfo, 0, sizeof(COSERVERINFO));    
1245      serverinfo.pwszName = ole_mb2wc(StringValuePtr(host), -1);
1246      memset(&multi_qi, 0, sizeof(MULTI_QI));
1247      multi_qi.pIID = &IID_IDispatch;
1248      hr = gCoCreateInstanceEx(&clsid, NULL, clsctx, &serverinfo, 1, &multi_qi);
1249      SysFreeString(serverinfo.pwszName);
1250      if (FAILED(hr))
1251          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, 
1252                    "Fail to create DCOM server : `%s' in `%s'",
1253                    StringValuePtr(ole),
1254                    StringValuePtr(host));
1255  
1256      ole_set_member(self, (IDispatch*)multi_qi.pItf);
1257      return self;
1258  }
1259  
1260  static VALUE
1261  ole_bind_obj(moniker, argc, argv, self)
1262      VALUE moniker;
1263      int argc;
1264      VALUE *argv;
1265      VALUE self;
1266  {
1267      IBindCtx *pBindCtx;
1268      IMoniker *pMoniker;
1269      IDispatch *pDispatch;
1270      HRESULT hr;
1271      OLECHAR *pbuf;
1272      ULONG eaten = 0;
1273      
1274      ole_initialize();
1275  
1276      hr = CreateBindCtx(0, &pBindCtx);
1277      if(FAILED(hr)) {
1278          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, 
1279                    "Fail to create bind context");
1280      }
1281  
1282      pbuf  = ole_mb2wc(StringValuePtr(moniker), -1);
1283      hr = MkParseDisplayName(pBindCtx, pbuf, &eaten, &pMoniker);
1284      SysFreeString(pbuf);
1285      if(FAILED(hr)) {
1286          OLE_RELEASE(pBindCtx);
1287          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR,
1288                    "Faile to parse display name of moniker:%s",
1289                    StringValuePtr(moniker));
1290      }
1291      hr = pMoniker->lpVtbl->BindToObject(pMoniker, pBindCtx, NULL, 
1292                                          &IID_IDispatch,
1293                                          (void**)&pDispatch);
1294      OLE_RELEASE(pMoniker);
1295      OLE_RELEASE(pBindCtx);
1296  
1297      if(FAILED(hr)) {
1298          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR,
1299                    "Faile to bind moniker:%s",
1300                    StringValuePtr(moniker));
1301      }
1302      return create_win32ole_object(self, pDispatch, argc, argv);
1303  }
1304  
1305  /*
1306   * WIN32OLE.connect( ole ) --> aWIN32OLE
1307   * ----
1308   * Returns running OLE Automation object or WIN32OLE object from moniker.
1309   * 1st argument should be OLE program id or class id or moniker.
1310   */
1311  static VALUE
1312  fole_s_connect(argc, argv, self)
1313      int argc;
1314      VALUE *argv;
1315      VALUE self;
1316  {
1317      VALUE svr_name;
1318      VALUE others;
1319      HRESULT hr;
1320      CLSID   clsid;
1321      OLECHAR *pBuf;
1322      IDispatch *pDispatch;
1323      IUnknown *pUnknown;
1324  
1325      /* initialize to use OLE */
1326      ole_initialize();
1327  
1328      rb_scan_args(argc, argv, "1*", &svr_name, &others);
1329  
1330      /* get CLSID from OLE server name */
1331      pBuf  = ole_mb2wc(StringValuePtr(svr_name), -1);
1332      hr = CLSIDFromProgID(pBuf, &clsid);
1333      if(FAILED(hr)) {
1334          hr = CLSIDFromString(pBuf, &clsid);
1335      }
1336      SysFreeString(pBuf);
1337      if(FAILED(hr)) {
1338          return ole_bind_obj(svr_name, argc, argv, self);
1339      }
1340  
1341      hr = GetActiveObject(&clsid, 0, &pUnknown);
1342      if (FAILED(hr)) {
1343          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, 
1344                    "Not Running OLE server : `%s'", StringValuePtr(svr_name));
1345      }
1346      hr = pUnknown->lpVtbl->QueryInterface(pUnknown, &IID_IDispatch,
1347                                               (void **)&pDispatch);
1348      if(FAILED(hr)) {
1349          OLE_RELEASE(pUnknown);
1350          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, 
1351                    "Fail to create WIN32OLE server : `%s'", 
1352                    StringValuePtr(svr_name));
1353      }
1354  
1355      OLE_RELEASE(pUnknown);
1356  
1357      return create_win32ole_object(self, pDispatch, argc, argv);
1358  }
1359  
1360  /* 
1361   * WIN32OLE.const_load( ole, mod = WIN32OLE)
1362   * ----
1363   * Defines the constants of OLE Automation server as mod's constants.
1364   * If 2nd argument is omitted, the default is WIN32OLE.
1365   */
1366  static VALUE
1367  fole_s_const_load(argc, argv, self)
1368      int argc;
1369      VALUE *argv;
1370      VALUE self;
1371  {
1372      VALUE ole;
1373      VALUE klass;
1374      struct oledata *pole;
1375      ITypeInfo *pTypeInfo;
1376      ITypeLib *pTypeLib;
1377      unsigned int index;
1378      HRESULT hr;
1379      OLECHAR *pBuf;
1380      VALUE file;
1381      LCID    lcid = LOCALE_SYSTEM_DEFAULT;
1382      
1383      rb_scan_args(argc, argv, "11", &ole, &klass);
1384      if (TYPE(klass) != T_CLASS &&
1385          TYPE(klass) != T_MODULE &&
1386          TYPE(klass) != T_NIL) {
1387          rb_raise(rb_eTypeError, "2nd paramator must be Class or Module.");
1388      }
1389      if (rb_obj_is_kind_of(ole, cWIN32OLE)) {
1390          OLEData_Get_Struct(ole, pole);
1391          hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch,
1392                                                    0, lcid, &pTypeInfo);
1393          if(FAILED(hr)) {
1394              ole_raise(hr, rb_eRuntimeError, "fail to GetTypeInfo");
1395          }
1396          hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &index);
1397          if(FAILED(hr)) {
1398              OLE_RELEASE(pTypeInfo);
1399              ole_raise(hr, rb_eRuntimeError, "fail to GetContainingTypeLib");
1400          }
1401          OLE_RELEASE(pTypeInfo);
1402          if(TYPE(klass) != T_NIL) {
1403              ole_const_load(pTypeLib, klass, self);
1404          }
1405          else {
1406              ole_const_load(pTypeLib, cWIN32OLE, self);
1407          }
1408          OLE_RELEASE(pTypeLib);
1409      }
1410      else if(TYPE(ole) == T_STRING) {
1411          file = typelib_file(ole);
1412          if (file == Qnil) {
1413              file = ole;
1414          }
1415          pBuf = ole_mb2wc(StringValuePtr(file), -1);
1416          hr = LoadTypeLibEx(pBuf, REGKIND_NONE, &pTypeLib);
1417          SysFreeString(pBuf);
1418          if (FAILED(hr))
1419            ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "Fail to LoadTypeLibEx");
1420          if(TYPE(klass) != T_NIL) {
1421              ole_const_load(pTypeLib, klass, self);
1422          }
1423          else {
1424              ole_const_load(pTypeLib, cWIN32OLE, self);
1425          }
1426          OLE_RELEASE(pTypeLib);
1427      }
1428      else {
1429          rb_raise(rb_eTypeError, "1st paramator must be WIN32OLE instance");
1430      }
1431      return Qnil;
1432  }
1433  
1434  static VALUE
1435  ole_classes_from_typelib(pTypeLib, classes)
1436      ITypeLib *pTypeLib;
1437      VALUE classes;
1438  {
1439      
1440      long count;
1441      int i;
1442      HRESULT hr;
1443      BSTR bstr;
1444      ITypeInfo *pTypeInfo;
1445      VALUE type;
1446    
1447      count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
1448      for (i = 0; i < count; i++) {
1449          hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i,
1450                                                  &bstr, NULL, NULL, NULL);
1451          if (FAILED(hr)) 
1452              continue;
1453  
1454          hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, i, &pTypeInfo);
1455          if (FAILED(hr))
1456              continue;
1457  
1458          type = foletype_s_allocate(cWIN32OLE_TYPE);
1459          oletype_set_member(type, pTypeInfo, WC2VSTR(bstr));
1460  
1461          rb_ary_push(classes, type);
1462          OLE_RELEASE(pTypeInfo);
1463      }
1464      return classes;
1465  }
1466  
1467  static ULONG
1468  reference_count(pole)
1469      struct oledata * pole;
1470  {
1471      ULONG n = 0;
1472      if(pole->pDispatch) {
1473          OLE_ADDREF(pole->pDispatch);
1474          n = OLE_RELEASE(pole->pDispatch);
1475      }
1476      return n;
1477  }
1478  
1479  /*
1480   * WIN32OLE.ole_reference_count(aWIN32OLE) --> number
1481   * ----
1482   * Returns reference counter of Dispatch interface of WIN32OLE object. 
1483   * You should not use this method because this method
1484   * exists only for debugging WIN32OLE.
1485   */
1486  static VALUE
1487  fole_s_reference_count(self, obj)
1488      VALUE self;
1489      VALUE obj;
1490  {
1491      struct oledata * pole;
1492      OLEData_Get_Struct(obj, pole);
1493      return INT2NUM(reference_count(pole));
1494  }
1495  
1496  /*
1497   * WIN32OLE.ole_free(aWIN32OLE) --> number
1498   * ----
1499   * Invokes Release method of Dispatch interface of WIN32OLE object. 
1500   * You should not use this method because this method
1501   * exists only for debugging WIN32OLE.
1502   * The return value is reference counter of OLE object.
1503   */
1504  static VALUE
1505  fole_s_free(self, obj)
1506      VALUE self;
1507      VALUE obj;
1508  {
1509      ULONG n = 0;
1510      struct oledata * pole;
1511      OLEData_Get_Struct(obj, pole);
1512      if(pole->pDispatch) {
1513          if (reference_count(pole) > 0) {
1514              n = OLE_RELEASE(pole->pDispatch);
1515          }
1516      }
1517      return INT2NUM(n);
1518  }
1519  
1520  static HWND
1521  ole_show_help(helpfile, helpcontext)
1522      VALUE helpfile;
1523      VALUE helpcontext;
1524  {
1525      FNHTMLHELP *pfnHtmlHelp;
1526      HWND hwnd = 0;
1527  
1528      if(!ghhctrl)
1529          ghhctrl = LoadLibrary("HHCTRL.OCX");
1530      if (!ghhctrl)
1531          return hwnd;
1532      pfnHtmlHelp = (FNHTMLHELP*)GetProcAddress(ghhctrl, "HtmlHelpA");
1533      if (!pfnHtmlHelp)
1534          return hwnd;
1535      hwnd = pfnHtmlHelp(GetDesktopWindow(), StringValuePtr(helpfile), 
1536                      0x0f, NUM2INT(helpcontext));
1537      if (hwnd == 0)
1538          hwnd = pfnHtmlHelp(GetDesktopWindow(), StringValuePtr(helpfile), 
1539                   0,  NUM2INT(helpcontext));
1540      return hwnd;
1541  }
1542  
1543  /*
1544   * WIN32OLE.ole_show_help(obj [,helpcontext])
1545   * ----
1546   * Displays helpfile. The 1st argument specifies WIN32OLE_TYPE
1547   * object or WIN32OLE_METHOD object or helpfile.
1548   */
1549  static VALUE
1550  fole_s_show_help(argc, argv, self)
1551      int argc;
1552      VALUE *argv;
1553      VALUE self;
1554  {
1555      VALUE target;
1556      VALUE helpcontext;
1557      VALUE helpfile;
1558      VALUE name;
1559      HWND  hwnd;
1560      rb_scan_args(argc, argv, "11", &target, &helpcontext);
1561      if (rb_obj_is_kind_of(target, cWIN32OLE_TYPE) ||
1562          rb_obj_is_kind_of(target, cWIN32OLE_METHOD)) {
1563          helpfile = rb_funcall(target, rb_intern("helpfile"), 0);
1564          if(strlen(StringValuePtr(helpfile)) == 0) {
1565              name = rb_ivar_get(target, rb_intern("name"));
1566              rb_raise(rb_eRuntimeError, "no helpfile of `%s'",
1567                       StringValuePtr(name));
1568          }
1569          helpcontext = rb_funcall(target, rb_intern("helpcontext"), 0);
1570      } else {
1571          helpfile = target;
1572      }
1573      if (TYPE(helpfile) != T_STRING) {
1574          rb_raise(rb_eTypeError, "1st parametor must be (String|WIN32OLE_TYPE|WIN32OLE_METHOD).");
1575      }
1576      hwnd = ole_show_help(helpfile, helpcontext);
1577      if(hwnd == 0) {
1578          rb_raise(rb_eRuntimeError, "fail to open help file:%s",
1579                   StringValuePtr(helpfile));
1580      }
1581      return Qnil;
1582  }
1583  
1584  static VALUE
1585  fole_initialize(argc, argv, self)
1586      int argc;
1587      VALUE *argv;
1588      VALUE self;
1589  {
1590      VALUE svr_name;
1591      VALUE host;
1592      VALUE others;
1593      HRESULT hr;
1594      CLSID   clsid;
1595      OLECHAR *pBuf;
1596      IDispatch *pDispatch;
1597  
1598      rb_call_super(0, 0);
1599      rb_scan_args(argc, argv, "11*", &svr_name, &host, &others);
1600  
1601      if (!NIL_P(host))
1602          return ole_create_dcom(argc, argv, self);
1603  
1604      /* get CLSID from OLE server name */
1605      pBuf  = ole_mb2wc(StringValuePtr(svr_name), -1);
1606      hr = CLSIDFromProgID(pBuf, &clsid);
1607      if(FAILED(hr)) {
1608          hr = CLSIDFromString(pBuf, &clsid);
1609      }
1610      SysFreeString(pBuf);
1611      if(FAILED(hr)) {
1612          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, 
1613                    "Unknown OLE server : `%s'",
1614                    StringValuePtr(svr_name));
1615      }
1616  
1617      /* get IDispatch interface */
1618      hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
1619                            &IID_IDispatch, (void**)&pDispatch);
1620      if(FAILED(hr)) {
1621          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR,
1622                    "Fail to create WIN32OLE object from `%s'",
1623                    StringValuePtr(svr_name));
1624      }
1625      
1626      ole_set_member(self, pDispatch);
1627      return self;
1628  }
1629  
1630  static VALUE
1631  hash2named_arg(pair, pOp)
1632      VALUE pair;
1633      struct oleparam* pOp;
1634  {
1635      unsigned int index, i;
1636      VALUE key, value;
1637      index = pOp->dp.cNamedArgs;
1638  
1639      /*-------------------------------------
1640        the data-type of key must be String
1641      ---------------------------------------*/
1642      key = rb_ary_entry(pair, 0);
1643      if(TYPE(key) != T_STRING) {
1644          /* clear name of dispatch parameters */
1645          for(i = 1; i < index + 1; i++) {
1646              SysFreeString(pOp->pNamedArgs[i]);
1647          }
1648          /* clear dispatch parameters */
1649          for(i = 0; i < index; i++ ) {
1650              VariantClear(&(pOp->dp.rgvarg[i]));
1651          }
1652          /* raise an exception */
1653          Check_Type(key, T_STRING);
1654      }
1655  
1656      /* pNamedArgs[0] is <method name>, so "index + 1" */
1657      pOp->pNamedArgs[index + 1] = ole_mb2wc(StringValuePtr(key), -1);
1658  
1659      value = rb_ary_entry(pair, 1);
1660      VariantInit(&(pOp->dp.rgvarg[index]));
1661      ole_val2variant(value, &(pOp->dp.rgvarg[index]));
1662  
1663      pOp->dp.cNamedArgs += 1;
1664      return Qnil;
1665  }
1666  
1667  static VALUE
1668  ole_invoke(argc, argv, self, wFlags)
1669      int argc;
1670      VALUE *argv;
1671      VALUE self;
1672      USHORT wFlags;
1673  {
1674      LCID    lcid = LOCALE_SYSTEM_DEFAULT;
1675      struct oledata *pole;
1676      HRESULT hr;
1677      VALUE cmd;
1678      VALUE paramS;
1679      VALUE param;
1680      VALUE obj;
1681      VALUE v;
1682  
1683      BSTR wcmdname;
1684  
1685      DISPID DispID;
1686      DISPID* pDispID;
1687      EXCEPINFO excepinfo;
1688      VARIANT result;
1689      VALUE args;
1690      VARIANTARG* realargs = NULL;
1691      unsigned int argErr = 0;
1692      unsigned int i;
1693      unsigned int cNamedArgs;
1694      int n;
1695      struct oleparam op;
1696      memset(&excepinfo, 0, sizeof(EXCEPINFO));
1697  
1698      VariantInit(&result);
1699  
1700      op.dp.rgvarg = NULL;
1701      op.dp.rgdispidNamedArgs = NULL;
1702      op.dp.cNamedArgs = 0;
1703      op.dp.cArgs = 0;
1704  
1705      rb_scan_args(argc, argv, "1*", &cmd, &paramS);
1706      OLEData_Get_Struct(self, pole);
1707      if(!pole->pDispatch) {
1708          rb_raise(rb_eRuntimeError, "Fail to get dispatch interface.");
1709      }
1710      wcmdname = ole_mb2wc(StringValuePtr(cmd), -1);
1711      hr = pole->pDispatch->lpVtbl->GetIDsOfNames( pole->pDispatch, &IID_NULL,
1712                                                   &wcmdname, 1, lcid, &DispID);
1713      SysFreeString(wcmdname);
1714      if(FAILED(hr)) {
1715          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, 
1716                    "Unknown property or method : `%s'",
1717                    StringValuePtr(cmd));
1718      }
1719  
1720      /* pick up last argument of method */
1721      param = rb_ary_entry(paramS, argc-2);
1722  
1723      op.dp.cNamedArgs = 0;
1724  
1725      /* if last arg is hash object */
1726      if(TYPE(param) == T_HASH) {
1727          /*------------------------------------------ 
1728            hash object ==> named dispatch parameters 
1729          --------------------------------------------*/
1730          cNamedArgs = NUM2INT(rb_funcall(param, rb_intern("length"), 0));
1731          op.dp.cArgs = cNamedArgs + argc - 2;
1732          op.pNamedArgs = ALLOCA_N(OLECHAR*, cNamedArgs + 1);
1733          op.dp.rgvarg = ALLOCA_N(VARIANTARG, op.dp.cArgs);
1734          rb_iterate(rb_each, param, hash2named_arg, (VALUE)&op);
1735  
1736          pDispID = ALLOCA_N(DISPID, cNamedArgs + 1);
1737          op.pNamedArgs[0] = ole_mb2wc(StringValuePtr(cmd), -1);
1738          hr = pole->pDispatch->lpVtbl->GetIDsOfNames(pole->pDispatch,
1739                                                      &IID_NULL,
1740                                                      op.pNamedArgs,
1741                                                      op.dp.cNamedArgs + 1,
1742                                                      lcid, pDispID);
1743          for(i = 0; i < op.dp.cNamedArgs + 1; i++) {
1744              SysFreeString(op.pNamedArgs[i]);
1745              op.pNamedArgs[i] = NULL;
1746          }
1747          if(FAILED(hr)) {
1748              /* clear dispatch parameters */
1749              for(i = 0; i < op.dp.cArgs; i++ ) {
1750                  VariantClear(&op.dp.rgvarg[i]);
1751              }
1752              ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, 
1753                        "FAIL to get named argument info : `%s'",
1754                        StringValuePtr(cmd));
1755          }
1756          op.dp.rgdispidNamedArgs = &(pDispID[1]);
1757      }
1758      else {
1759          cNamedArgs = 0;
1760          op.dp.cArgs = argc - 1;
1761          op.pNamedArgs = ALLOCA_N(OLECHAR*, cNamedArgs + 1);
1762          if (op.dp.cArgs > 0) {
1763              op.dp.rgvarg  = ALLOCA_N(VARIANTARG, op.dp.cArgs);
1764          }
1765      }
1766      /*--------------------------------------
1767        non hash args ==> dispatch parameters 
1768       ----------------------------------------*/
1769      if(op.dp.cArgs > cNamedArgs) {
1770          realargs = ALLOCA_N(VARIANTARG, op.dp.cArgs-cNamedArgs+1);
1771          for(i = cNamedArgs; i < op.dp.cArgs; i++) {
1772              n = op.dp.cArgs - i + cNamedArgs - 1;
1773              VariantInit(&realargs[n]);
1774              VariantInit(&op.dp.rgvarg[n]);
1775              param = rb_ary_entry(paramS, i-cNamedArgs);
1776              
1777              ole_val2variant(param, &realargs[n]);
1778              V_VT(&op.dp.rgvarg[n]) = VT_VARIANT | VT_BYREF;
1779              V_VARIANTREF(&op.dp.rgvarg[n]) = &realargs[n];
1780  
1781          }
1782      }
1783      /* apparent you need to call propput, you need this */
1784      if (wFlags & DISPATCH_PROPERTYPUT) {
1785          if (op.dp.cArgs == 0)
1786              return ResultFromScode(E_INVALIDARG);
1787  
1788          op.dp.cNamedArgs = 1;
1789          op.dp.rgdispidNamedArgs = ALLOCA_N( DISPID, 1 );
1790          op.dp.rgdispidNamedArgs[0] = DISPID_PROPERTYPUT;
1791      }
1792      
1793      hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID, 
1794                                           &IID_NULL, lcid, wFlags, &op.dp, 
1795                                           &result, &excepinfo, &argErr);
1796      if (FAILED(hr)) {
1797          /* retry to call args by value */
1798          if(op.dp.cArgs > cNamedArgs) {
1799              for(i = cNamedArgs; i < op.dp.cArgs; i++) {
1800                  n = op.dp.cArgs - i + cNamedArgs - 1;
1801                  param = rb_ary_entry(paramS, i-cNamedArgs);
1802                  ole_val2variant(param, &op.dp.rgvarg[n]);
1803              }
1804              memset(&excepinfo, 0, sizeof(EXCEPINFO));
1805              hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID, 
1806                                                   &IID_NULL, lcid, wFlags,
1807                                                   &op.dp, NULL,
1808                                                   &excepinfo, &argErr);
1809              for(i = cNamedArgs; i < op.dp.cArgs; i++) {
1810                  n = op.dp.cArgs - i + cNamedArgs - 1;
1811                  VariantClear(&op.dp.rgvarg[n]);
1812              }
1813          }
1814          /* mega kludge. if a method in WORD is called and we ask
1815           * for a result when one is not returned then
1816           * hResult == DISP_E_EXCEPTION. this only happens on
1817           * functions whose DISPID > 0x8000 */
1818          if (hr == DISP_E_EXCEPTION && DispID > 0x8000) {
1819              memset(&excepinfo, 0, sizeof(EXCEPINFO));
1820              hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DispID, 
1821                                                   &IID_NULL, lcid, wFlags,
1822                                                   &op.dp, NULL,
1823                                                   &excepinfo, &argErr);
1824  
1825          }
1826      }
1827      /* clear dispatch parameter */
1828      if(op.dp.cArgs > cNamedArgs) {
1829          args = rb_cvar_get(cWIN32OLE, rb_intern("ARGV"));
1830          rb_funcall(args, rb_intern("clear"), 0);
1831          for(i = cNamedArgs; i < op.dp.cArgs; i++) {
1832              n = op.dp.cArgs - i + cNamedArgs - 1;
1833              rb_ary_push(args, ole_variant2val(&realargs[n]));
1834              VariantClear(&realargs[n]);
1835          }
1836      }
1837      else {
1838          for(i = 0; i < op.dp.cArgs; i++) {
1839              VariantClear(&op.dp.rgvarg[i]);
1840          }
1841      }
1842  
1843      if (FAILED(hr)) {
1844          v = ole_excepinfo2msg(&excepinfo);
1845          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "%s%s",
1846                    StringValuePtr(cmd), StringValuePtr(v));
1847      }
1848      obj = ole_variant2val(&result);
1849      VariantClear(&result);
1850      return obj;
1851  }
1852  
1853  static VALUE
1854  fole_invoke(argc, argv, self)
1855      int argc;
1856      VALUE *argv;
1857      VALUE self;
1858  {
1859      return ole_invoke(argc, argv, self, DISPATCH_METHOD|DISPATCH_PROPERTYGET);
1860  }
1861  
1862  static VALUE
1863  ole_invoke2(self, dispid, args, types, dispkind)
1864      VALUE self;
1865      VALUE dispid;
1866      VALUE args;
1867      VALUE types;
1868      USHORT dispkind;
1869  {
1870      HRESULT hr;
1871      struct oledata *pole;
1872      unsigned int argErr = 0;
1873      EXCEPINFO excepinfo;
1874      VARIANT result;
1875      DISPPARAMS dispParams;
1876      VARIANTARG* realargs = NULL;
1877      int i, j;
1878      VALUE obj = Qnil;
1879      VALUE tp, param;
1880      VALUE v;
1881      VARTYPE vt;
1882  
1883      Check_Type(args, T_ARRAY);
1884      Check_Type(types, T_ARRAY);
1885      
1886      memset(&excepinfo, 0, sizeof(EXCEPINFO));
1887      memset(&dispParams, 0, sizeof(DISPPARAMS));
1888      VariantInit(&result);
1889      OLEData_Get_Struct(self, pole);
1890  
1891      dispParams.cArgs = RARRAY(args)->len;
1892      dispParams.rgvarg = ALLOCA_N(VARIANTARG, dispParams.cArgs);
1893      realargs = ALLOCA_N(VARIANTARG, dispParams.cArgs);
1894      for (i = 0, j = dispParams.cArgs - 1; i < (int)dispParams.cArgs; i++, j--)
1895      {
1896          VariantInit(&realargs[i]);
1897          VariantInit(&dispParams.rgvarg[i]);
1898          tp = rb_ary_entry(types, j);
1899          vt = (VARTYPE)FIX2INT(tp);
1900          V_VT(&dispParams.rgvarg[i]) = vt;
1901          param = rb_ary_entry(args, j);
1902          if (param == Qnil)
1903          {
1904  
1905              V_VT(&dispParams.rgvarg[i]) = V_VT(&realargs[i]) = VT_ERROR;
1906              V_ERROR(&dispParams.rgvarg[i]) = V_ERROR(&realargs[i]) = DISP_E_PARAMNOTFOUND;
1907          }
1908          else
1909          {
1910              if (vt & VT_ARRAY)
1911              {
1912                  int ent;
1913                  LPBYTE pb;
1914                  short* ps;
1915                  LPLONG pl;
1916                  VARIANT* pv;
1917                  CY *py;
1918                  VARTYPE v;
1919                  SAFEARRAYBOUND rgsabound[1];
1920                  Check_Type(param, T_ARRAY);
1921                  rgsabound[0].lLbound = 0;
1922                  rgsabound[0].cElements = RARRAY(param)->len;
1923                  v = vt & ~(VT_ARRAY | VT_BYREF);
1924                  V_ARRAY(&realargs[i]) = SafeArrayCreate(v, 1, rgsabound);
1925                  V_VT(&realargs[i]) = VT_ARRAY | v;
1926                  SafeArrayLock(V_ARRAY(&realargs[i]));
1927                  pb = V_ARRAY(&realargs[i])->pvData;
1928                  ps = V_ARRAY(&realargs[i])->pvData;
1929                  pl = V_ARRAY(&realargs[i])->pvData;
1930                  py = V_ARRAY(&realargs[i])->pvData;
1931                  pv = V_ARRAY(&realargs[i])->pvData;
1932                  for (ent = 0; ent < (int)rgsabound[0].cElements; ent++)
1933                  {
1934                      VARIANT velem;
1935                      VALUE elem = rb_ary_entry(param, ent);
1936                      ole_val2variant(elem, &velem);
1937                      if (v != VT_VARIANT)
1938                      {
1939                          VariantChangeTypeEx(&velem, &velem,
1940                              LOCALE_SYSTEM_DEFAULT, 0, v);
1941                      }
1942                      switch (v)
1943                      {
1944                      /* 128 bits */
1945                      case VT_VARIANT:
1946                          *pv++ = velem;
1947                          break;
1948                      /* 64 bits */
1949                      case VT_R8:
1950                      case VT_CY:
1951                      case VT_DATE:
1952                          *py++ = V_CY(&velem);
1953                          break;
1954                      /* 16 bits */
1955                      case VT_BOOL:
1956                      case VT_I2:
1957                      case VT_UI2:
1958                          *ps++ = V_I2(&velem);
1959                          break;
1960                      /* 8 bites */
1961                      case VT_UI1:
1962                      case VT_I1:
1963                          *pb++ = V_UI1(&velem);
1964                          break;
1965                      /* 32 bits */
1966                      default:
1967                          *pl++ = V_I4(&velem);
1968                          break;
1969                      }
1970                  }
1971                  SafeArrayUnlock(V_ARRAY(&realargs[i]));
1972              }
1973              else
1974              {
1975                  ole_val2variant(param, &realargs[i]);
1976                  if ((vt & (~VT_BYREF)) != VT_VARIANT)
1977                  {
1978                      hr = VariantChangeTypeEx(&realargs[i], &realargs[i],
1979                                               LOCALE_SYSTEM_DEFAULT, 0,
1980                                               (VARTYPE)(vt & (~VT_BYREF)));
1981                      if (hr != S_OK)
1982                      {
1983                          rb_raise(rb_eTypeError, "not valid value");
1984                      }
1985                  }
1986              }
1987              if ((vt & VT_BYREF) || vt == VT_VARIANT)
1988              {
1989                  if (vt == VT_VARIANT)
1990                      V_VT(&dispParams.rgvarg[i]) = VT_VARIANT | VT_BYREF;
1991                  switch (vt & (~VT_BYREF))
1992                  {
1993                  /* 128 bits */
1994                  case VT_VARIANT:
1995                      V_VARIANTREF(&dispParams.rgvarg[i]) = &realargs[i];
1996                      break;
1997                  /* 64 bits */
1998                  case VT_R8:
1999                  case VT_CY:
2000                  case VT_DATE:
2001                      V_CYREF(&dispParams.rgvarg[i]) = &V_CY(&realargs[i]);
2002                      break;
2003                  /* 16 bits */
2004                  case VT_BOOL:
2005                  case VT_I2:
2006                  case VT_UI2:
2007                      V_I2REF(&dispParams.rgvarg[i]) = &V_I2(&realargs[i]);
2008                      break;
2009                  /* 8 bites */
2010                  case VT_UI1:
2011                  case VT_I1:
2012                      V_UI1REF(&dispParams.rgvarg[i]) = &V_UI1(&realargs[i]);
2013                      break;
2014                  /* 32 bits */
2015                  default:
2016                      V_I4REF(&dispParams.rgvarg[i]) = &V_I4(&realargs[i]);
2017                      break;
2018                  }
2019              }
2020              else
2021              {
2022                  /* copy 64 bits of data */
2023                  V_CY(&dispParams.rgvarg[i]) = V_CY(&realargs[i]);
2024              }
2025          }
2026      }
2027  
2028      if (dispkind & DISPATCH_PROPERTYPUT) {
2029          dispParams.cNamedArgs = 1;
2030          dispParams.rgdispidNamedArgs = ALLOCA_N( DISPID, 1 );
2031          dispParams.rgdispidNamedArgs[0] = DISPID_PROPERTYPUT;
2032      }
2033  
2034      hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, FIX2INT(dispid),
2035                                           &IID_NULL, LOCALE_SYSTEM_DEFAULT,
2036                                           dispkind,
2037                                           &dispParams, &result,
2038                                           &excepinfo, &argErr);
2039  
2040      if (FAILED(hr)) {
2041          v = ole_excepinfo2msg(&excepinfo);
2042          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "_invoke %s",
2043                    StringValuePtr(v));
2044      }
2045  
2046      /* clear dispatch parameter */
2047      if(dispParams.cArgs > 0) {
2048          VALUE argv = rb_cvar_get(cWIN32OLE, rb_intern("ARGV"));
2049          rb_funcall(argv, rb_intern("clear"), 0);
2050          for(i = dispParams.cArgs - 1; i >= 0; i--) {
2051              rb_ary_push(argv, ole_variant2val(&realargs[i]));
2052              VariantClear(&realargs[i]);
2053          }
2054      }
2055  
2056      obj = ole_variant2val(&result);
2057      VariantClear(&result);
2058      return obj;
2059  }
2060  
2061  /*
2062   * WIN32OLE#_invoke(dispid, args, types)
2063   * ----
2064   * Runs the early binding method.
2065   * The 1st argument specifies dispatch ID, 
2066   * the 2nd argument specifies the array of arguments,
2067   * the 3rd argument specifies the array of the type of arguments.
2068   */
2069  static VALUE
2070  fole_invoke2(self, dispid, args, types)
2071      VALUE self;
2072      VALUE dispid;
2073      VALUE args;
2074      VALUE types;
2075  {
2076      return ole_invoke2(self, dispid, args, types, DISPATCH_METHOD);
2077  }
2078  
2079  /*
2080   * WIN32OLE#_getproperty(dispid, args, types)
2081   * ----
2082   * Runs the early binding method to get property.
2083   * The 1st argument specifies dispatch ID, 
2084   * the 2nd argument specifies the array of arguments,
2085   * the 3rd argument specifies the array of the type of arguments.
2086   */
2087  static VALUE
2088  fole_getproperty2(self, dispid, args, types)
2089      VALUE self;
2090      VALUE dispid;
2091      VALUE args;
2092      VALUE types;
2093  {
2094      return ole_invoke2(self, dispid, args, types, DISPATCH_PROPERTYGET);
2095  }
2096  
2097  /*
2098   * WIN32OLE#_setproperty(dispid, args, types)
2099   * ----
2100   * Runs the early binding method to set property.
2101   * The 1st argument specifies dispatch ID, 
2102   * the 2nd argument specifies the array of arguments,
2103   * the 3rd argument specifies the array of the type of arguments.
2104   */
2105  static VALUE
2106  fole_setproperty2(self, dispid, args, types)
2107      VALUE self;
2108      VALUE dispid;
2109      VALUE args;
2110      VALUE types;
2111  {
2112      return ole_invoke2(self, dispid, args, types, DISPATCH_PROPERTYPUT);
2113  }
2114  
2115  /*
2116   * WIN32OLE['property']=val 
2117   *
2118   * WIN32OLE.setproperty('property', [arg1, arg2,] val)
2119   * -----
2120   * Sets property of OLE object.
2121   * When you want to set property with argument, you can use setproperty method.
2122   */
2123  static VALUE
2124  fole_setproperty(argc, argv, self)
2125      int argc;
2126      VALUE *argv;
2127      VALUE self;
2128  {
2129      return ole_invoke(argc, argv, self, DISPATCH_PROPERTYPUT);
2130  }
2131  
2132  /*
2133   * WIN32OLE['property'] 
2134   * -----
2135   * Returns property of OLE object.
2136   */
2137  static VALUE
2138  fole_getproperty(self, property)
2139      VALUE self, property;
2140  {
2141      return ole_invoke(1, &property, self, DISPATCH_PROPERTYGET);
2142  }
2143  
2144  static VALUE
2145  ole_propertyput(self, property, value)
2146      VALUE self, property, value;
2147  {
2148      struct oledata *pole;
2149      unsigned argErr;
2150      unsigned int index;
2151      HRESULT hr;
2152      EXCEPINFO excepinfo;
2153      DISPID dispID = DISPID_VALUE;
2154      DISPID dispIDParam = DISPID_PROPERTYPUT;
2155      USHORT wFlags = DISPATCH_PROPERTYPUT;
2156      DISPPARAMS dispParams;
2157      VARIANTARG propertyValue[2];
2158      OLECHAR* pBuf[1];
2159      VALUE v;
2160      LCID    lcid = LOCALE_SYSTEM_DEFAULT;
2161      dispParams.rgdispidNamedArgs = &dispIDParam;
2162      dispParams.rgvarg = propertyValue;
2163      dispParams.cNamedArgs = 1;
2164      dispParams.cArgs = 1;
2165  
2166      VariantInit(&propertyValue[0]);
2167      VariantInit(&propertyValue[1]);
2168      memset(&excepinfo, 0, sizeof(excepinfo));
2169  
2170      OLEData_Get_Struct(self, pole);
2171  
2172      /* get ID from property name */
2173      pBuf[0]  = ole_mb2wc(StringValuePtr(property), -1);
2174      hr = pole->pDispatch->lpVtbl->GetIDsOfNames(pole->pDispatch, &IID_NULL,
2175                                                  pBuf, 1, lcid, &dispID);
2176      SysFreeString(pBuf[0]);
2177      pBuf[0] = NULL;
2178  
2179      if(FAILED(hr)) {
2180          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, 
2181                    "Unknown property or method : `%s'",
2182                    StringValuePtr(property));
2183      }
2184      /* set property value */
2185      ole_val2variant(value, &propertyValue[0]);
2186      hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, dispID, &IID_NULL, 
2187                                           lcid, wFlags, &dispParams,
2188                                           NULL, &excepinfo, &argErr);
2189  
2190      for(index = 0; index < dispParams.cArgs; ++index) {
2191          VariantClear(&propertyValue[index]);
2192      }
2193      if (FAILED(hr)) {
2194          v = ole_excepinfo2msg(&excepinfo);
2195          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, StringValuePtr(v));
2196      }
2197      return Qnil;
2198  }
2199  
2200  static VALUE
2201  fole_free(self)
2202      VALUE self;
2203  {
2204      struct oledata *pole;
2205      OLEData_Get_Struct(self, pole);
2206      OLE_FREE(pole->pDispatch);
2207      pole->pDispatch = NULL;
2208      return Qnil;
2209  }
2210  
2211  static VALUE
2212  ole_each_sub(pEnumV)
2213      VALUE pEnumV;
2214  {
2215      VARIANT variant;
2216      VALUE obj = Qnil;
2217      IEnumVARIANT *pEnum = (IEnumVARIANT *)pEnumV;
2218      VariantInit(&variant);
2219      while(pEnum->lpVtbl->Next(pEnum, 1, &variant, NULL) == S_OK) {
2220          obj = ole_variant2val(&variant);
2221          VariantClear(&variant);
2222          VariantInit(&variant);
2223          rb_yield(obj);
2224      }
2225      return Qnil;
2226  }
2227  
2228  static VALUE
2229  ole_ienum_free(pEnumV)
2230      VALUE pEnumV;
2231  {
2232      IEnumVARIANT *pEnum = (IEnumVARIANT *)pEnumV;
2233      OLE_RELEASE(pEnum);
2234      return Qnil;
2235  }
2236  
2237  /*
2238   * WIN32OLE#each {|i|...}
2239   * -----
2240   * Iterates over each item of OLE collection which has IEnumVARIANT interface.
2241   */
2242  static VALUE
2243  fole_each(self)
2244      VALUE self;
2245  {
2246      LCID    lcid = LOCALE_SYSTEM_DEFAULT;
2247  
2248      struct oledata *pole;
2249  
2250      unsigned int argErr;
2251      EXCEPINFO excepinfo;
2252      DISPPARAMS dispParams;
2253      VARIANT result;
2254      HRESULT hr;
2255      IEnumVARIANT *pEnum = NULL;
2256  
2257      VariantInit(&result);
2258      dispParams.rgvarg = NULL;
2259      dispParams.rgdispidNamedArgs = NULL;
2260      dispParams.cNamedArgs = 0;
2261      dispParams.cArgs = 0;
2262      memset(&excepinfo, 0, sizeof(excepinfo));
2263      
2264      OLEData_Get_Struct(self, pole);
2265      hr = pole->pDispatch->lpVtbl->Invoke(pole->pDispatch, DISPID_NEWENUM,
2266                                           &IID_NULL, lcid,
2267                                           DISPATCH_METHOD | DISPATCH_PROPERTYGET,
2268                                           &dispParams, &result,
2269                                           &excepinfo, &argErr);
2270  
2271      if (FAILED(hr)) {
2272          VariantClear(&result);
2273          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "Fail to get IEnum Interface");
2274      }
2275  
2276      if (V_VT(&result) == VT_UNKNOWN)
2277          hr = V_UNKNOWN(&result)->lpVtbl->QueryInterface(V_UNKNOWN(&result),
2278                                                          &IID_IEnumVARIANT,
2279                                                          (void**)&pEnum);
2280      else if (V_VT(&result) == VT_DISPATCH)
2281          hr = V_DISPATCH(&result)->lpVtbl->QueryInterface(V_DISPATCH(&result),
2282                                                           &IID_IEnumVARIANT,
2283                                                           (void**)&pEnum);
2284      if (FAILED(hr) || !pEnum) {
2285          VariantClear(&result);
2286          ole_raise(hr, rb_eRuntimeError, "Fail to get IEnum Interface");
2287      }
2288  
2289      VariantClear(&result);
2290      rb_ensure(ole_each_sub, (VALUE)pEnum, ole_ienum_free, (VALUE)pEnum);
2291      return Qnil;
2292  }
2293  
2294  /*
2295   * WIN32OLE#method_missing(id [,arg1, arg2, ...])
2296   * ----
2297   * Calls WIN32OLE#invoke method.
2298   */
2299  static VALUE
2300  fole_missing(argc, argv, self)
2301      int argc;
2302      VALUE *argv;
2303      VALUE self;
2304  {
2305      ID id;
2306      char* mname;
2307      int n;
2308      id = rb_to_id(argv[0]);
2309      mname = rb_id2name(id);
2310      if(!mname) {
2311          rb_raise(rb_eRuntimeError, "Fail : Unknown method or property");
2312      }
2313      n = strlen(mname);
2314      if(mname[n-1] == '=') {
2315          argv[0] = rb_str_new(mname, n-1);
2316  
2317          return ole_propertyput(self, argv[0], argv[1]);
2318      }
2319      else {
2320          argv[0] = rb_str_new2(mname);
2321          return ole_invoke(argc, argv, self, DISPATCH_METHOD|DISPATCH_PROPERTYGET);
2322      }
2323  }
2324  
2325  static VALUE
2326  ole_method_sub(self, pOwnerTypeInfo, pTypeInfo, name)
2327      VALUE self;
2328      ITypeInfo *pOwnerTypeInfo;
2329      ITypeInfo *pTypeInfo;
2330      VALUE name;
2331  {
2332      HRESULT hr;
2333      TYPEATTR *pTypeAttr;
2334      BSTR bstr;
2335      FUNCDESC *pFuncDesc;
2336      WORD i;
2337      VALUE fname;
2338      VALUE method = Qnil;
2339      hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
2340      if (FAILED(hr)) {
2341          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "Fail to GetTypeAttr");
2342      }
2343      for(i = 0; i < pTypeAttr->cFuncs && method == Qnil; i++) {
2344          hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, i, &pFuncDesc);
2345          if (FAILED(hr))
2346               continue;
2347  
2348          hr = pTypeInfo->lpVtbl->GetDocumentation(pTypeInfo, pFuncDesc->memid,
2349                                                   &bstr, NULL, NULL, NULL);
2350          if (FAILED(hr)) {
2351              pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
2352              continue;
2353          }
2354          fname = WC2VSTR(bstr);
2355          if (strcasecmp(StringValuePtr(name), StringValuePtr(fname)) == 0) {
2356              olemethod_set_member(self, pTypeInfo, pOwnerTypeInfo, i, fname);
2357              method = self;
2358          }
2359          pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
2360          pFuncDesc=NULL;
2361      }
2362      OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
2363      return method;
2364  }
2365  
2366  static VALUE
2367  olemethod_from_typeinfo(self, pTypeInfo, name)
2368      VALUE self;
2369      ITypeInfo *pTypeInfo;
2370      VALUE name;
2371  {
2372      HRESULT hr;
2373      TYPEATTR *pTypeAttr;
2374      WORD i;
2375      HREFTYPE href;
2376      ITypeInfo *pRefTypeInfo;
2377      VALUE method = Qnil;
2378      hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
2379      if (FAILED(hr)) {
2380          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "Fail to GetTypeAttr");
2381      }
2382      method = ole_method_sub(self, 0, pTypeInfo, name);
2383      if (method != Qnil) {
2384         return method;
2385      }
2386      for(i=0; i < pTypeAttr->cImplTypes && method == Qnil; i++){
2387         hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo, i, &href);
2388         if(FAILED(hr))
2389             continue;
2390         hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo, href, &pRefTypeInfo);
2391         if (FAILED(hr))
2392             continue;
2393         method = ole_method_sub(self, pTypeInfo, pRefTypeInfo, name);
2394         OLE_RELEASE(pRefTypeInfo);
2395      }
2396      OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
2397      return method;
2398  }
2399  
2400  static VALUE
2401  ole_methods_sub(pOwnerTypeInfo, pTypeInfo, methods, mask)
2402      ITypeInfo *pOwnerTypeInfo;
2403      ITypeInfo *pTypeInfo;
2404      VALUE     methods;
2405      int       mask;
2406  {
2407      HRESULT hr;
2408      TYPEATTR *pTypeAttr;
2409      BSTR bstr;
2410      char *pstr;
2411      FUNCDESC *pFuncDesc;
2412      VALUE method;
2413      WORD i;
2414      hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
2415      if (FAILED(hr)) {
2416          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "Fail to GetTypeAttr");
2417      }
2418      for(i = 0; i < pTypeAttr->cFuncs; i++) {
2419          pstr = NULL;
2420          hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, i, &pFuncDesc);
2421          if (FAILED(hr))
2422               continue;
2423                   
2424          hr = pTypeInfo->lpVtbl->GetDocumentation(pTypeInfo, pFuncDesc->memid,
2425                                                   &bstr, NULL, NULL, NULL);
2426          if (FAILED(hr)) {
2427              pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
2428              continue;
2429          }
2430          if(pFuncDesc->invkind & mask) {
2431              method = folemethod_s_allocate(cWIN32OLE_METHOD);
2432              olemethod_set_member(method, pTypeInfo, pOwnerTypeInfo, 
2433                                   i, WC2VSTR(bstr));
2434              rb_ary_push(methods, method);
2435          }
2436          pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
2437          pFuncDesc=NULL;
2438      }
2439      OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
2440  
2441      return methods;
2442  }
2443  
2444  static VALUE
2445  ole_methods_from_typeinfo(pTypeInfo, mask)
2446      ITypeInfo *pTypeInfo;
2447      int mask;
2448  {
2449      HRESULT hr;
2450      TYPEATTR *pTypeAttr;
2451      WORD i;
2452      HREFTYPE href;
2453      ITypeInfo *pRefTypeInfo;
2454      VALUE methods = rb_ary_new();
2455      hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
2456      if (FAILED(hr)) {
2457          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "Fail to GetTypeAttr");
2458      }
2459  
2460      ole_methods_sub(0, pTypeInfo, methods, mask);
2461      for(i=0; i < pTypeAttr->cImplTypes; i++){
2462         hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo, i, &href);
2463         if(FAILED(hr))
2464             continue;
2465         hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo, href, &pRefTypeInfo);
2466         if (FAILED(hr))
2467             continue;
2468         ole_methods_sub(pTypeInfo, pRefTypeInfo, methods, mask);
2469         OLE_RELEASE(pRefTypeInfo);
2470      }
2471      OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
2472      return methods;
2473  }
2474  
2475  static HRESULT
2476  typeinfo_from_ole(pole, ppti)
2477      struct oledata *pole;
2478      ITypeInfo **ppti;
2479  {
2480      ITypeInfo *pTypeInfo;
2481      ITypeLib *pTypeLib;
2482      BSTR bstr;
2483      VALUE type;
2484      UINT i;
2485      UINT count;
2486      LCID    lcid = LOCALE_SYSTEM_DEFAULT;
2487      HRESULT hr = pole->pDispatch->lpVtbl->GetTypeInfo(pole->pDispatch,
2488                                                        0, lcid, &pTypeInfo);
2489      if(FAILED(hr)) {
2490          ole_raise(hr, rb_eRuntimeError, "fail to GetTypeInfo");
2491      }
2492      hr = pTypeInfo->lpVtbl->GetDocumentation(pTypeInfo,
2493                                               -1,
2494                                               &bstr,
2495                                               NULL, NULL, NULL);
2496      type = WC2VSTR(bstr);
2497      hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &i);
2498      OLE_RELEASE(pTypeInfo);
2499      if (FAILED(hr)) {
2500          ole_raise(hr, rb_eRuntimeError, "fail to GetContainingTypeLib");
2501      }
2502      count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
2503      for (i = 0; i < count; i++) {
2504          hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i,
2505                                                  &bstr, NULL, NULL, NULL);
2506          if (SUCCEEDED(hr) && rb_str_cmp(WC2VSTR(bstr), type) == 0) {
2507              hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, i, &pTypeInfo);
2508              if (SUCCEEDED(hr)) {
2509                  *ppti = pTypeInfo;
2510                  break;
2511              }
2512          }
2513      }
2514      OLE_RELEASE(pTypeLib);
2515      return hr;
2516  }
2517  
2518  static VALUE
2519  ole_methods(self,mask)
2520      VALUE self;
2521      int mask;
2522  {
2523      ITypeInfo *pTypeInfo;
2524      HRESULT hr;
2525      VALUE methods;
2526      struct oledata *pole;
2527  
2528      OLEData_Get_Struct(self, pole);
2529      methods = rb_ary_new();
2530  
2531      hr = typeinfo_from_ole(pole, &pTypeInfo);
2532      if(FAILED(hr))
2533          return methods;
2534      rb_ary_concat(methods, ole_methods_from_typeinfo(pTypeInfo, mask));
2535      OLE_RELEASE(pTypeInfo);
2536      return methods;
2537  }
2538  
2539  /*
2540   * WIN32OLE#ole_methods
2541   * ----
2542   * Returns OLE methods
2543   */
2544  static VALUE
2545  fole_methods( self )
2546      VALUE self;
2547  {
2548      return ole_methods( self, INVOKE_FUNC | INVOKE_PROPERTYGET | INVOKE_PROPERTYPUT);
2549  }
2550  
2551  /*
2552   * WIN32OLE#ole_get_methods
2553   * ----
2554   * Returns get properties.
2555   */
2556  static VALUE
2557  fole_get_methods( argc, argv, self )
2558      int argc;
2559      VALUE *argv;
2560      VALUE self;
2561  {
2562      return ole_methods( self, INVOKE_PROPERTYGET);
2563  }
2564  
2565  /*
2566   * WIN32OLE#ole_put_methods
2567   * ----
2568   * Returns put properties.
2569   */
2570  static VALUE
2571  fole_put_methods( argc, argv, self )
2572      int argc;
2573      VALUE *argv;
2574      VALUE self;
2575  {
2576      return ole_methods( self, INVOKE_PROPERTYPUT);
2577  }
2578  
2579  /*
2580   * WIN32OLE#ole_func_methods
2581   * ---
2582   * Returns OLE func methods.
2583   */
2584  static VALUE
2585  fole_func_methods( argc, argv, self )
2586      int argc;
2587      VALUE *argv;
2588      VALUE self;
2589  {
2590      return ole_methods( self, INVOKE_FUNC);
2591  }
2592  
2593  /*
2594   * WIN32OLE#ole_obj_help
2595   * ----
2596   * Returns WIN32OLE_TYPE object.
2597   */
2598  static VALUE
2599  fole_obj_help( self )
2600      VALUE self;
2601  {
2602      unsigned int index;
2603      ITypeInfo *pTypeInfo;
2604      ITypeLib *pTypeLib;
2605      HRESULT hr;
2606      struct oledata *pole;
2607      BSTR bstr;
2608      LCID  lcid = LOCALE_SYSTEM_DEFAULT;
2609      VALUE type = Qnil;
2610  
2611      OLEData_Get_Struct(self, pole);
2612  
2613      hr = pole->pDispatch->lpVtbl->GetTypeInfo( pole->pDispatch, 0, lcid, &pTypeInfo );
2614      if(FAILED(hr)) {
2615          ole_raise(hr, rb_eRuntimeError, "fail to GetTypeInfo");
2616      }
2617      hr = pTypeInfo->lpVtbl->GetContainingTypeLib( pTypeInfo, &pTypeLib, &index );
2618      if(FAILED(hr)) {
2619          OLE_RELEASE(pTypeInfo);
2620          ole_raise(hr, rb_eRuntimeError, "fail to GetContainingTypeLib");
2621      }
2622      hr = pTypeLib->lpVtbl->GetDocumentation( pTypeLib, index,
2623                                               &bstr, NULL, NULL, NULL);
2624      if (SUCCEEDED(hr)) {
2625          type = foletype_s_allocate(cWIN32OLE_TYPE);
2626          oletype_set_member(type, pTypeInfo, WC2VSTR(bstr));
2627      }
2628      OLE_RELEASE(pTypeLib);
2629      OLE_RELEASE(pTypeInfo);
2630  
2631      return type;
2632  }
2633  
2634  static HRESULT
2635  ole_docinfo_from_type(pTypeInfo, name, helpstr, helpcontext, helpfile)
2636      ITypeInfo *pTypeInfo;
2637      BSTR *name;
2638      BSTR *helpstr; 
2639      DWORD *helpcontext;
2640      BSTR *helpfile;
2641  {
2642      HRESULT hr;
2643      ITypeLib *pTypeLib;
2644      UINT i;
2645  
2646      hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo, &pTypeLib, &i);
2647      if (FAILED(hr)) {
2648          return hr;
2649      }
2650      
2651      hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i,
2652                                              name, helpstr, 
2653                                              helpcontext, helpfile);
2654      if (FAILED(hr)) {
2655          OLE_RELEASE(pTypeLib);
2656          return hr;
2657      }
2658      OLE_RELEASE(pTypeLib);
2659      return hr;
2660  }
2661  
2662  static VALUE
2663  ole_usertype2val(pTypeInfo, pTypeDesc, typedetails)
2664      ITypeInfo *pTypeInfo;
2665      TYPEDESC *pTypeDesc;
2666      VALUE typedetails;
2667  {
2668      HRESULT hr;
2669      BSTR bstr;
2670      ITypeInfo *pRefTypeInfo;
2671      VALUE type = Qnil;
2672  
2673      hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo, 
2674                                             V_UNION1(pTypeDesc, hreftype),
2675                                             &pRefTypeInfo);
2676      if(FAILED(hr))
2677          return Qnil;
2678      hr = ole_docinfo_from_type(pRefTypeInfo, &bstr, NULL, NULL, NULL);
2679      if(FAILED(hr)) {
2680          OLE_RELEASE(pRefTypeInfo);
2681          return Qnil;
2682      }
2683      OLE_RELEASE(pRefTypeInfo);
2684      type = WC2VSTR(bstr);
2685      if(typedetails != Qnil)
2686          rb_ary_push(typedetails, type);
2687      return type;
2688  }
2689  
2690  static VALUE ole_typedesc2val();
2691  static VALUE
2692  ole_ptrtype2val(pTypeInfo, pTypeDesc, typedetails) 
2693      ITypeInfo *pTypeInfo;
2694      TYPEDESC *pTypeDesc;
2695      VALUE typedetails;
2696  {    
2697      TYPEDESC *p = pTypeDesc;
2698      VALUE type = rb_str_new2("");
2699      while(p->vt == VT_PTR || p->vt == VT_SAFEARRAY) {
2700          p = V_UNION1(p, lptdesc);
2701          if(strlen(StringValuePtr(type)) == 0) {
2702             type = ole_typedesc2val(pTypeInfo, p, typedetails);
2703          } else {
2704             rb_str_cat(type, ",", 1);
2705             rb_str_concat(type, ole_typedesc2val(pTypeInfo, p, typedetails));
2706          }
2707      }
2708      return type;
2709  }
2710  
2711  static VALUE
2712  ole_typedesc2val(pTypeInfo, pTypeDesc, typedetails)
2713      ITypeInfo *pTypeInfo;
2714      TYPEDESC *pTypeDesc;
2715      VALUE typedetails;
2716  {
2717      VALUE str;
2718      switch(pTypeDesc->vt) {
2719      case VT_I2:
2720          if(typedetails != Qnil)
2721              rb_ary_push(typedetails, rb_str_new2("I2"));
2722          return rb_str_new2("I2");
2723      case VT_I4:
2724          if(typedetails != Qnil)
2725              rb_ary_push(typedetails, rb_str_new2("I4"));
2726          return rb_str_new2("I4");
2727      case VT_R4:
2728          if(typedetails != Qnil)
2729              rb_ary_push(typedetails, rb_str_new2("R4"));
2730          return rb_str_new2("R4");
2731      case VT_R8:
2732          if(typedetails != Qnil)
2733              rb_ary_push(typedetails, rb_str_new2("R8"));
2734          return rb_str_new2("R8");
2735      case VT_CY:
2736          if(typedetails != Qnil)
2737              rb_ary_push(typedetails, rb_str_new2("CY"));
2738          return rb_str_new2("CY");
2739      case VT_DATE:
2740          if(typedetails != Qnil)
2741              rb_ary_push(typedetails, rb_str_new2("DATE"));
2742          return rb_str_new2("DATE");
2743      case VT_BSTR:
2744          if(typedetails != Qnil)
2745              rb_ary_push(typedetails, rb_str_new2("BSTR"));
2746          return rb_str_new2("BSTR");
2747      case VT_BOOL:
2748          if(typedetails != Qnil)
2749              rb_ary_push(typedetails, rb_str_new2("BOOL"));
2750          return rb_str_new2("BOOL");
2751      case VT_VARIANT:
2752          if(typedetails != Qnil)
2753              rb_ary_push(typedetails, rb_str_new2("VARIANT"));
2754          return rb_str_new2("VARIANT");
2755      case VT_DECIMAL:
2756          if(typedetails != Qnil)
2757              rb_ary_push(typedetails, rb_str_new2("DECIMAL"));
2758          return rb_str_new2("DECIMAL");
2759      case VT_I1:
2760          if(typedetails != Qnil)
2761              rb_ary_push(typedetails, rb_str_new2("I1"));
2762          return rb_str_new2("I1");
2763      case VT_UI1:
2764          if(typedetails != Qnil)
2765              rb_ary_push(typedetails, rb_str_new2("UI1"));
2766          return rb_str_new2("UI1");
2767      case VT_UI2:
2768          if(typedetails != Qnil)
2769              rb_ary_push(typedetails, rb_str_new2("UI2"));
2770          return rb_str_new2("UI2");
2771      case VT_UI4:
2772          if(typedetails != Qnil)
2773              rb_ary_push(typedetails, rb_str_new2("UI4"));
2774          return rb_str_new2("UI4");
2775      case VT_I8:
2776          if(typedetails != Qnil)
2777              rb_ary_push(typedetails, rb_str_new2("I8"));
2778          return rb_str_new2("I8");
2779      case VT_UI8:
2780          if(typedetails != Qnil)
2781              rb_ary_push(typedetails, rb_str_new2("UI8"));
2782          return rb_str_new2("UI8");
2783      case VT_INT:
2784          if(typedetails != Qnil)
2785              rb_ary_push(typedetails, rb_str_new2("INT"));
2786          return rb_str_new2("INT");
2787      case VT_UINT:
2788          if(typedetails != Qnil)
2789              rb_ary_push(typedetails, rb_str_new2("UINT"));
2790          return rb_str_new2("UINT");
2791      case VT_VOID:
2792          if(typedetails != Qnil)
2793              rb_ary_push(typedetails, rb_str_new2("VOID"));
2794          return rb_str_new2("VOID");
2795      case VT_HRESULT:
2796          if(typedetails != Qnil)
2797              rb_ary_push(typedetails, rb_str_new2("HRESULT"));
2798          return rb_str_new2("HRESULT");
2799      case VT_PTR:
2800          if(typedetails != Qnil)
2801              rb_ary_push(typedetails, rb_str_new2("PTR"));
2802          return ole_ptrtype2val(pTypeInfo, pTypeDesc, typedetails);
2803      case VT_SAFEARRAY:
2804          if(typedetails != Qnil)
2805              rb_ary_push(typedetails, rb_str_new2("SAFEARRAY"));
2806          return ole_ptrtype2val(pTypeInfo, pTypeDesc, typedetails);
2807      case VT_CARRAY:
2808          if(typedetails != Qnil)
2809              rb_ary_push(typedetails, rb_str_new2("CARRAY"));
2810          return rb_str_new2("CARRAY");
2811      case VT_USERDEFINED:
2812          if(typedetails != Qnil)
2813              rb_ary_push(typedetails, rb_str_new2("USERDEFINED"));
2814          str = ole_usertype2val(pTypeInfo, pTypeDesc, typedetails);
2815          if (str != Qnil) {
2816              return str;
2817          }
2818          return rb_str_new2("USERDEFINED");
2819      case VT_UNKNOWN:
2820          return rb_str_new2("UNKNOWN");
2821      case VT_DISPATCH:
2822          if(typedetails != Qnil)
2823              rb_ary_push(typedetails, rb_str_new2("DISPATCH"));
2824          return rb_str_new2("DISPATCH");
2825      default:
2826          str = rb_str_new2("Unknown Type ");
2827          rb_str_concat(str, rb_fix2str(INT2FIX(pTypeDesc->vt), 10));
2828          return str;
2829      }
2830  }
2831  
2832  /*
2833   * WIN32OLE#ole_method_help(method)
2834   * -----
2835   * Returns WIN32OLE_METHOD object corresponding with method 
2836   * specified by 1st argument.
2837   */
2838  static VALUE
2839  fole_method_help( self, cmdname )
2840      VALUE self;
2841      VALUE cmdname;
2842  {
2843      ITypeInfo *pTypeInfo;
2844      HRESULT hr;
2845      struct oledata *pole;
2846      VALUE method, obj;
2847      LCID    lcid = LOCALE_SYSTEM_DEFAULT;
2848  
2849      Check_SafeStr(cmdname);
2850      OLEData_Get_Struct(self, pole);
2851      hr = typeinfo_from_ole(pole, &pTypeInfo);
2852      if(FAILED(hr))
2853          ole_raise(hr, rb_eRuntimeError, "fail to get ITypeInfo");
2854      method = folemethod_s_allocate(cWIN32OLE_METHOD);
2855      obj = olemethod_from_typeinfo(method, pTypeInfo, cmdname);
2856      OLE_RELEASE(pTypeInfo);
2857      if (obj == Qnil)
2858          rb_raise(eWIN32OLE_RUNTIME_ERROR, "Not found %s",
2859                   StringValuePtr(cmdname));
2860      return obj;
2861  }
2862  
2863  /*
2864   * WIN32OLE.ole_classes(typelibrary)
2865   * ----
2866   * Returns array of WIN32OLE_TYPE objects defined by type library.
2867   */
2868  static VALUE
2869  foletype_s_ole_classes(self, typelib)
2870      VALUE self;
2871      VALUE typelib;
2872  {
2873      VALUE file, classes;
2874      OLECHAR * pbuf;
2875      ITypeLib *pTypeLib;
2876      HRESULT hr;
2877  
2878      classes = rb_ary_new();
2879      if(TYPE(typelib) == T_STRING) {
2880          file = typelib_file(typelib);
2881          if (file == Qnil) {
2882              file = typelib;
2883          }
2884          pbuf = ole_mb2wc(StringValuePtr(file), -1);
2885          hr = LoadTypeLibEx(pbuf, REGKIND_NONE, &pTypeLib);
2886          if (FAILED(hr))
2887            ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "Fail to LoadTypeLibEx");
2888          SysFreeString(pbuf);
2889          ole_classes_from_typelib(pTypeLib, classes);
2890          OLE_RELEASE(pTypeLib);
2891      } else {
2892          rb_raise(rb_eTypeError, "1st argument should be TypeLib string");
2893      }
2894      return classes;
2895  }
2896  
2897  /*
2898   * WIN32OLE_TYPE.typelibs
2899   * ----
2900   * Returns array of type libraries.
2901   */
2902  static VALUE
2903  foletype_s_typelibs(self)
2904      VALUE self;
2905  {
2906      HKEY htypelib, hclsid;
2907      double fversion;
2908      DWORD i, j;
2909      LONG err;
2910      VALUE clsid;
2911      VALUE ver;
2912      VALUE v = Qnil;
2913      VALUE typelibs = rb_ary_new();
2914  
2915      err = reg_open_key(HKEY_CLASSES_ROOT, "TypeLib", &htypelib);
2916      if(err != ERROR_SUCCESS) {
2917          return typelibs;
2918      }
2919      for(i = 0; ; i++) {
2920          clsid = reg_enum_key(htypelib, i);
2921          if (clsid == Qnil)
2922              break;
2923          err = reg_open_vkey(htypelib, clsid, &hclsid);
2924          if (err != ERROR_SUCCESS)
2925              continue;
2926          fversion = 0;
2927          for(j = 0; ; j++) {
2928              ver = reg_enum_key(hclsid, j);
2929              if (ver == Qnil)
2930                  break;
2931              if (fversion > atof(StringValuePtr(ver)))
2932                  continue;
2933              fversion = atof(StringValuePtr(ver));
2934              if ( (v = reg_get_val(hclsid, StringValuePtr(ver))) != Qnil ) {
2935                  rb_ary_push(typelibs, v);
2936              }
2937          }
2938          RegCloseKey(hclsid);
2939      }
2940      RegCloseKey(htypelib);
2941      return typelibs;
2942  }
2943  
2944  /*
2945   * WIN32OLE_TYPE.progids
2946   * ---
2947   * Returns array of ProgID.
2948   */
2949  static VALUE
2950  foletype_s_progids(self)
2951      VALUE self;
2952  {
2953      HKEY hclsids, hclsid;
2954      DWORD i;
2955      LONG err;
2956      VALUE clsid;
2957      VALUE v = rb_str_new2("");
2958      VALUE progids = rb_ary_new();
2959  
2960      err = reg_open_key(HKEY_CLASSES_ROOT, "CLSID", &hclsids);
2961      if(err != ERROR_SUCCESS) {
2962          return progids;
2963      }
2964      for(i = 0; ; i++) {
2965          clsid = reg_enum_key(hclsids, i);
2966          if (clsid == Qnil)
2967              break;
2968          err = reg_open_vkey(hclsids, clsid, &hclsid);
2969          if (err != ERROR_SUCCESS)
2970              continue;
2971          if ((v = reg_get_val(hclsid, "ProgID")) != Qnil) 
2972              rb_ary_push(progids, v);
2973          if ((v = reg_get_val(hclsid, "VersionIndependentProgID")) != Qnil)
2974              rb_ary_push(progids, v);
2975          RegCloseKey(hclsid);
2976      }
2977      RegCloseKey(hclsids);
2978      return progids;
2979  }
2980  
2981  static VALUE
2982  foletype_s_allocate(klass)
2983      VALUE klass;
2984  {
2985      struct oletypedata *poletype;
2986      VALUE obj;
2987      ole_initialize();
2988      obj = Data_Make_Struct(klass,struct oletypedata,0,oletype_free,poletype);
2989      poletype->pTypeInfo = NULL;
2990      return obj;
2991  }
2992  
2993  static VALUE
2994  oletype_set_member(self, pTypeInfo, name)
2995      VALUE self;
2996      ITypeInfo *pTypeInfo;
2997      VALUE name;
2998  {
2999      struct oletypedata *ptype;
3000      Data_Get_Struct(self, struct oletypedata, ptype);
3001      rb_ivar_set(self, rb_intern("name"), name);
3002      ptype->pTypeInfo = pTypeInfo;
3003      if(pTypeInfo) OLE_ADDREF(pTypeInfo);
3004      return self;
3005  }
3006  
3007  static VALUE
3008  oleclass_from_typelib(self, pTypeLib, oleclass)
3009      VALUE self;
3010      ITypeLib *pTypeLib;
3011      VALUE oleclass;
3012  {
3013      
3014      long count;
3015      int i;
3016      HRESULT hr;
3017      BSTR bstr;
3018      VALUE typelib;
3019      ITypeInfo *pTypeInfo;
3020  
3021      VALUE found = Qfalse;
3022    
3023      count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
3024      for (i = 0; i < count && found == Qfalse; i++) {
3025          hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib, i, &pTypeInfo);
3026          if (FAILED(hr))
3027              continue;
3028          hr = pTypeLib->lpVtbl->GetDocumentation(pTypeLib, i,
3029                                                  &bstr, NULL, NULL, NULL);
3030          if (FAILED(hr)) 
3031              continue;
3032          typelib = WC2VSTR(bstr);
3033          if (rb_str_cmp(oleclass, typelib) == 0) {
3034              oletype_set_member(self, pTypeInfo, typelib);
3035              found = Qtrue;
3036          }
3037          OLE_RELEASE(pTypeInfo);
3038      }
3039      return found;
3040  }
3041  
3042  static VALUE
3043  foletype_initialize(self, typelib, oleclass)
3044      VALUE self;
3045      VALUE typelib;
3046      VALUE oleclass;
3047  {
3048      VALUE file;
3049      OLECHAR * pbuf;
3050      ITypeLib *pTypeLib;
3051      HRESULT hr;
3052  
3053      Check_SafeStr(oleclass);
3054      Check_SafeStr(typelib);
3055      file = typelib_file(typelib);
3056      if (file == Qnil) {
3057          file = typelib;
3058      }
3059      pbuf = ole_mb2wc(StringValuePtr(file), -1);
3060      hr = LoadTypeLibEx(pbuf, REGKIND_NONE, &pTypeLib);
3061      if (FAILED(hr))
3062          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "Fail to LoadTypeLibEx");
3063      SysFreeString(pbuf);
3064      if (oleclass_from_typelib(self, pTypeLib, oleclass) == Qfalse) {
3065          OLE_RELEASE(pTypeLib);
3066          rb_raise(eWIN32OLE_RUNTIME_ERROR, "Not found `%s` in `%s`",
3067                   StringValuePtr(oleclass), StringValuePtr(typelib));
3068      }
3069      OLE_RELEASE(pTypeLib);
3070      return self;
3071  }
3072  
3073  /*
3074   * WIN32OLE_TYPE#name
3075   * ---
3076   * Returns name.
3077   */
3078  static VALUE
3079  foletype_name(self)
3080      VALUE self;
3081  {
3082      return rb_ivar_get(self, rb_intern("name"));
3083  }
3084  
3085  static VALUE
3086  ole_ole_type(pTypeInfo)
3087      ITypeInfo *pTypeInfo;
3088  {
3089      HRESULT hr;
3090      TYPEATTR *pTypeAttr;
3091      VALUE type = Qnil;
3092      hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
3093      if(FAILED(hr)){
3094          return type;
3095      }
3096      switch(pTypeAttr->typekind) {
3097      case TKIND_ENUM:
3098          type = rb_str_new2("Enum");
3099          break;
3100      case TKIND_RECORD:
3101          type = rb_str_new2("Record");
3102          break;
3103      case TKIND_MODULE:
3104          type = rb_str_new2("Module");
3105          break;
3106      case TKIND_INTERFACE:
3107          type = rb_str_new2("Interface");
3108          break;
3109      case TKIND_DISPATCH:
3110          type = rb_str_new2("Dispatch");
3111          break;
3112      case TKIND_COCLASS:
3113          type = rb_str_new2("Class");
3114          break;
3115      case TKIND_ALIAS:
3116          type = rb_str_new2("Alias");
3117          break;
3118      case TKIND_UNION:
3119          type = rb_str_new2("Union");
3120          break;
3121      case TKIND_MAX:
3122          type = rb_str_new2("Max");
3123          break;
3124      default:
3125          type = Qnil;
3126          break;
3127      }
3128      OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
3129      return type;
3130  }
3131  
3132  /*
3133   * WIN32OLE_TYPE#ole_type
3134   * ----
3135   * returns type of class.
3136   */
3137  static VALUE
3138  foletype_ole_type(self)
3139      VALUE self;
3140  {
3141      struct oletypedata *ptype;
3142      Data_Get_Struct(self, struct oletypedata, ptype);
3143      return ole_ole_type(ptype->pTypeInfo);
3144  }
3145  
3146  static VALUE
3147  ole_type_guid(pTypeInfo) 
3148      ITypeInfo *pTypeInfo;
3149  {
3150      HRESULT hr;
3151      TYPEATTR *pTypeAttr;
3152      int len;
3153      OLECHAR bstr[80];
3154      VALUE guid = Qnil;
3155      hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
3156      if (FAILED(hr)) 
3157          return guid;
3158      len = StringFromGUID2(&pTypeAttr->guid, bstr, sizeof(bstr)/sizeof(OLECHAR));
3159      if (len > 3) {
3160          guid = ole_wc2vstr(bstr, FALSE);
3161      }
3162      OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
3163      return guid;
3164  }
3165  
3166  /*
3167   * WIN32OLE_TYPE#guid
3168   * ----
3169   * Returns GUID.
3170   */
3171  static VALUE
3172  foletype_guid(self)
3173  {
3174      struct oletypedata *ptype;
3175      Data_Get_Struct(self, struct oletypedata, ptype);
3176      return ole_type_guid(ptype->pTypeInfo);
3177  }
3178  
3179  static VALUE
3180  ole_type_progid(pTypeInfo)
3181      ITypeInfo *pTypeInfo;
3182  {
3183      HRESULT hr;
3184      TYPEATTR *pTypeAttr;
3185      OLECHAR *pbuf;
3186      VALUE progid = Qnil;
3187      hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
3188      if (FAILED(hr)) 
3189          return progid;
3190      hr = ProgIDFromCLSID(&pTypeAttr->guid, &pbuf);
3191      if (SUCCEEDED(hr)) 
3192          progid = WC2VSTR(pbuf);
3193      OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
3194      return progid;
3195  }
3196  
3197  /*
3198   * WIN32OLE_TYPE#progid
3199   * ----
3200   * Returns ProgID if it exists. If not found, then returns nil.
3201   */
3202  static VALUE
3203  foletype_progid(self)
3204  {
3205      struct oletypedata *ptype;
3206      Data_Get_Struct(self, struct oletypedata, ptype);
3207      return ole_type_progid(ptype->pTypeInfo);
3208  }
3209  
3210  
3211  static VALUE
3212  ole_type_visible(pTypeInfo) 
3213      ITypeInfo *pTypeInfo;
3214  {
3215      HRESULT hr;
3216      TYPEATTR *pTypeAttr;
3217      VALUE visible;
3218      hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
3219      if (FAILED(hr)) 
3220          return Qtrue;
3221      if (pTypeAttr->wTypeFlags & (TYPEFLAG_FHIDDEN | TYPEFLAG_FRESTRICTED)) {
3222          visible = Qfalse;
3223      } else {
3224          visible = Qtrue;
3225      }
3226      OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
3227      return visible;
3228  }
3229  
3230  /*
3231   * WIN32OLE_TYPE#visible
3232   * ----
3233   * returns true if the OLE class is public.
3234   */
3235  static VALUE
3236  foletype_visible(self)
3237      VALUE self;
3238  {
3239      struct oletypedata *ptype;
3240      Data_Get_Struct(self, struct oletypedata, ptype);
3241      return ole_type_visible(ptype->pTypeInfo);
3242  }
3243  
3244  static VALUE
3245  ole_type_major_version(pTypeInfo)
3246      ITypeInfo *pTypeInfo;
3247  {
3248      VALUE ver;
3249      TYPEATTR *pTypeAttr;
3250      HRESULT hr;
3251      hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
3252      if (FAILED(hr))
3253          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "Fail to GetTypeAttr");
3254      ver = INT2FIX(pTypeAttr->wMajorVerNum);
3255      OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
3256      return ver;
3257  }
3258  
3259  /*
3260   * WIN32OLE_TYPE#major_version
3261   * ----
3262   * Returns major version.
3263   */
3264  static VALUE
3265  foletype_major_version(self)
3266      VALUE self;
3267  {
3268      struct oletypedata *ptype;
3269      Data_Get_Struct(self, struct oletypedata, ptype);
3270      return ole_type_major_version(ptype->pTypeInfo);
3271  }
3272  
3273  static VALUE
3274  ole_type_minor_version(pTypeInfo)
3275      ITypeInfo *pTypeInfo;
3276  {
3277      VALUE ver;
3278      TYPEATTR *pTypeAttr;
3279      HRESULT hr;
3280      hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
3281      if (FAILED(hr))
3282          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "Fail to GetTypeAttr");
3283      ver = INT2FIX(pTypeAttr->wMinorVerNum);
3284      OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
3285      return ver;
3286  }
3287  
3288  /*
3289   * WIN32OLE_TYPE#minor_version
3290   * ----
3291   * Returns minor version.
3292   */
3293  static VALUE
3294  foletype_minor_version(self)
3295      VALUE self;
3296  {
3297      struct oletypedata *ptype;
3298      Data_Get_Struct(self, struct oletypedata, ptype);
3299      return ole_type_minor_version(ptype->pTypeInfo);
3300  }
3301  
3302  static VALUE
3303  ole_type_typekind(pTypeInfo)
3304      ITypeInfo *pTypeInfo;
3305  {
3306      VALUE typekind;
3307      TYPEATTR *pTypeAttr;
3308      HRESULT hr;
3309      hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
3310      if (FAILED(hr))
3311          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "Fail to GetTypeAttr");
3312      typekind = INT2FIX(pTypeAttr->typekind);
3313      OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
3314      return typekind;
3315  }
3316  
3317  /*
3318   * WIN32OLE_TYPE#typekind
3319   * ----
3320   * Returns number which represents type.
3321   */
3322  static VALUE 
3323  foletype_typekind(self)
3324      VALUE self;
3325  {
3326      struct oletypedata *ptype;
3327      Data_Get_Struct(self, struct oletypedata, ptype);
3328      return ole_type_typekind(ptype->pTypeInfo);
3329  }
3330  
3331  static VALUE
3332  ole_type_helpstring(pTypeInfo)
3333      ITypeInfo *pTypeInfo;
3334  {
3335      HRESULT hr;
3336      BSTR bhelpstr;
3337      hr = ole_docinfo_from_type(pTypeInfo, NULL, &bhelpstr, NULL, NULL);
3338      if(FAILED(hr)) {
3339          return Qnil;
3340      }
3341      return WC2VSTR(bhelpstr);
3342  }
3343  
3344  /*
3345   * WIN32OLE_TYPE#helpstring
3346   * ---
3347   * Returns help string.
3348   */
3349  static VALUE 
3350  foletype_helpstring(self)
3351      VALUE self;
3352  {
3353      struct oletypedata *ptype;
3354      Data_Get_Struct(self, struct oletypedata, ptype);
3355      return ole_type_helpstring(ptype->pTypeInfo);
3356  }
3357  
3358  static VALUE
3359  ole_type_src_type(pTypeInfo)
3360      ITypeInfo *pTypeInfo;
3361  {
3362      HRESULT hr;
3363      TYPEATTR *pTypeAttr;
3364      VALUE alias = Qnil;
3365      hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
3366      if (FAILED(hr))
3367          return alias;
3368      if(pTypeAttr->typekind != TKIND_ALIAS) {
3369          OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
3370          return alias;
3371      }
3372      alias = ole_typedesc2val(pTypeInfo, &(pTypeAttr->tdescAlias), Qnil);
3373      OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
3374      return alias;
3375  }
3376  
3377  /*
3378   * WIN32OLE_TYPE#src_type
3379   * ----
3380   * Returns source class when the OLE class is 'Alias'.
3381   */
3382  static VALUE
3383  foletype_src_type(self)
3384      VALUE self;
3385  {
3386      struct oletypedata *ptype;
3387      Data_Get_Struct(self, struct oletypedata, ptype);
3388      return ole_type_src_type(ptype->pTypeInfo);
3389  }
3390  
3391  static VALUE
3392  ole_type_helpfile(pTypeInfo)
3393      ITypeInfo *pTypeInfo;
3394  {
3395      HRESULT hr;
3396      BSTR bhelpfile;
3397      hr = ole_docinfo_from_type(pTypeInfo, NULL, NULL, NULL, &bhelpfile);
3398      if(FAILED(hr)) {
3399          return Qnil;
3400      }
3401      return WC2VSTR(bhelpfile);
3402  }
3403  
3404  /*
3405   * WIN32OLE_TYPE#helpfile
3406   * ----
3407   * Returns helpfile
3408   */
3409  static VALUE
3410  foletype_helpfile(self)
3411      VALUE self;
3412  {
3413      struct oletypedata *ptype;
3414      Data_Get_Struct(self, struct oletypedata, ptype);
3415      return ole_type_helpfile(ptype->pTypeInfo);
3416  }
3417  
3418  static VALUE
3419  ole_type_helpcontext(pTypeInfo)
3420      ITypeInfo *pTypeInfo;
3421  {
3422      HRESULT hr;
3423      DWORD helpcontext;
3424      hr = ole_docinfo_from_type(pTypeInfo, NULL, NULL, 
3425                                 &helpcontext, NULL);
3426      if(FAILED(hr))
3427          return Qnil;
3428      return INT2FIX(helpcontext);
3429  }
3430  
3431  /*
3432   * WIN32OLE_TYPE#helpcontext
3433   * ---
3434   * Returns helpcontext.
3435   */
3436  static VALUE
3437  foletype_helpcontext(self)
3438      VALUE self;
3439  {
3440      struct oletypedata *ptype;
3441      Data_Get_Struct(self, struct oletypedata, ptype);
3442      return ole_type_helpcontext(ptype->pTypeInfo);
3443  }
3444  
3445  static VALUE
3446  ole_variables(pTypeInfo)
3447      ITypeInfo *pTypeInfo;
3448  {
3449      HRESULT hr;
3450      TYPEATTR *pTypeAttr;
3451      WORD i;
3452      UINT len;
3453      BSTR bstr;
3454      char *pstr;
3455      VARDESC *pVarDesc;
3456      struct olevariabledata *pvar;
3457      VALUE var;
3458      VALUE variables = rb_ary_new();
3459      hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
3460      if (FAILED(hr)) {
3461          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "Fail to GetTypeAttr");
3462      }
3463      
3464      for(i = 0; i < pTypeAttr->cVars; i++) {
3465          hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, i, &pVarDesc);
3466          if(FAILED(hr))
3467              continue;
3468          len = 0;
3469          pstr = NULL;
3470          hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, pVarDesc->memid, &bstr,
3471                                           1, &len);
3472          if(FAILED(hr) || len == 0 || !bstr)
3473              continue;
3474  
3475          var = Data_Make_Struct(cWIN32OLE_VARIABLE, struct olevariabledata,
3476                                 0,olevariable_free,pvar);
3477          pvar->pTypeInfo = pTypeInfo;
3478          OLE_ADDREF(pTypeInfo);
3479          pvar->index = i;
3480          rb_ivar_set(var, rb_intern("name"), WC2VSTR(bstr));
3481          rb_ary_push(variables, var);
3482  
3483          pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
3484          pVarDesc = NULL;
3485      }
3486      OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
3487      return variables;
3488  }
3489  
3490  /*
3491   * WIN32OLE_TYPE#variables
3492   * ----
3493   * Returns array of variables defined in OLE class.
3494   */
3495  static VALUE
3496  foletype_variables(self)
3497      VALUE self;
3498  {
3499      struct oletypedata *ptype;
3500      Data_Get_Struct(self, struct oletypedata, ptype);
3501      return ole_variables(ptype->pTypeInfo);
3502  }
3503  
3504  /*
3505   * WIN32OLE_TYPE#ole_methods
3506   * ----
3507   * Returns array of WIN32OLE_METHOD objects.
3508   */
3509  static VALUE
3510  foletype_methods(argc, argv, self)
3511      int argc;
3512      VALUE *argv;
3513      VALUE self;
3514  {
3515      struct oletypedata *ptype;
3516      Data_Get_Struct(self, struct oletypedata, ptype);
3517      return ole_methods_from_typeinfo(ptype->pTypeInfo, INVOKE_FUNC | INVOKE_PROPERTYGET | INVOKE_PROPERTYPUT | INVOKE_PROPERTYPUTREF);
3518  }
3519  
3520  /*
3521   * WIN32OLE_VARIABLE#name
3522   * ---
3523   * Returns the name.
3524   */
3525  static VALUE
3526  folevariable_name(self)
3527      VALUE self;
3528  {
3529      return rb_ivar_get(self, rb_intern("name"));
3530  }
3531  
3532  static ole_variable_ole_type(pTypeInfo, var_index)
3533      ITypeInfo *pTypeInfo;
3534      UINT var_index;
3535  {
3536      VARDESC *pVarDesc;
3537      HRESULT hr;
3538      VALUE type;
3539      hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, var_index, &pVarDesc);
3540      if (FAILED(hr))
3541          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "Fail to GetVarDesc");
3542      type = ole_typedesc2val(pTypeInfo, &(pVarDesc->elemdescVar.tdesc), Qnil);
3543      pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
3544      return type;
3545  }
3546  
3547  /*
3548   * WIN32OLE_VARIABLE#ole_type
3549   * ----
3550   * Returns type.
3551   */
3552  static VALUE
3553  folevariable_ole_type(self)
3554      VALUE self;
3555  {
3556      struct olevariabledata *pvar;
3557      Data_Get_Struct(self, struct olevariabledata, pvar);
3558      return ole_variable_ole_type(pvar->pTypeInfo, pvar->index);
3559  }
3560  
3561  static ole_variable_ole_type_detail(pTypeInfo, var_index)
3562      ITypeInfo *pTypeInfo;
3563      UINT var_index;
3564  {
3565      VARDESC *pVarDesc;
3566      HRESULT hr;
3567      VALUE type = rb_ary_new();
3568      hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, var_index, &pVarDesc);
3569      if (FAILED(hr))
3570          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "Fail to GetVarDesc");
3571      ole_typedesc2val(pTypeInfo, &(pVarDesc->elemdescVar.tdesc), type);
3572      pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
3573      return type;
3574  }
3575  
3576  /*
3577   * WIN32OLE_VARIABLE#ole_type_detail
3578   * ---
3579   * Returns detail information of type. The information is array of type.
3580   */
3581  static VALUE
3582  folevariable_ole_type_detail(self)
3583      VALUE self;
3584  {
3585      struct olevariabledata *pvar;
3586      Data_Get_Struct(self, struct olevariabledata, pvar);
3587      return ole_variable_ole_type_detail(pvar->pTypeInfo, pvar->index);
3588  }
3589  
3590  static ole_variable_value(pTypeInfo, var_index)
3591      ITypeInfo *pTypeInfo;
3592      UINT var_index;
3593  {
3594      VARDESC *pVarDesc;
3595      HRESULT hr;
3596      VALUE val = Qnil;
3597      hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, var_index, &pVarDesc);
3598      if (FAILED(hr))
3599          return Qnil;
3600      if(pVarDesc->varkind == VAR_CONST)
3601          val = ole_variant2val(V_UNION1(pVarDesc, lpvarValue));
3602      pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
3603      return val;
3604  }
3605  
3606  /*
3607   * WIN32OLE_VARIABLE#value
3608   * ----
3609   * Returns value if value is exists. If the value does not exist, 
3610   * this method returns nil.
3611   */    
3612  static VALUE
3613  folevariable_value(self)
3614      VALUE self;
3615  {
3616      struct olevariabledata *pvar;
3617      Data_Get_Struct(self, struct olevariabledata, pvar);
3618      return ole_variable_value(pvar->pTypeInfo, pvar->index);
3619  }
3620  
3621  static ole_variable_visible(pTypeInfo, var_index)
3622      ITypeInfo *pTypeInfo;
3623      UINT var_index;
3624  {
3625      VARDESC *pVarDesc;
3626      HRESULT hr;
3627      VALUE visible = Qfalse;
3628      hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, var_index, &pVarDesc);
3629      if (FAILED(hr))
3630          return visible;
3631      if (!(pVarDesc->wVarFlags & (VARFLAG_FHIDDEN |
3632                                   VARFLAG_FRESTRICTED |
3633                                   VARFLAG_FNONBROWSABLE))) {
3634          visible = Qtrue;
3635      }
3636      pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
3637      return visible;
3638  }
3639  
3640  /*
3641   * WIN32OLE_VARIABLE#visible?
3642   * ----
3643   * Returns true if the variable is public.
3644   */
3645  static VALUE
3646  folevariable_visible(self)
3647      VALUE self;
3648  {
3649      struct olevariabledata *pvar;
3650      Data_Get_Struct(self, struct olevariabledata, pvar);
3651      return ole_variable_visible(pvar->pTypeInfo, pvar->index);
3652  }
3653  
3654  static VALUE
3655  ole_variable_kind(pTypeInfo, var_index)
3656      ITypeInfo *pTypeInfo;
3657      UINT var_index;
3658  {
3659      VARDESC *pVarDesc;
3660      HRESULT hr;
3661      VALUE kind = rb_str_new2("UNKNOWN");
3662      hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, var_index, &pVarDesc);
3663      if (FAILED(hr))
3664          return kind;
3665      switch(pVarDesc->varkind) {
3666      case VAR_PERINSTANCE:
3667          kind = rb_str_new2("PERINSTANCE");
3668          break;
3669      case VAR_STATIC:
3670          kind = rb_str_new2("STATIC");
3671          break;
3672      case VAR_CONST:
3673          kind = rb_str_new2("CONSTANT");
3674          break;
3675      case VAR_DISPATCH:
3676          kind = rb_str_new2("DISPATCH");
3677          break;
3678      default:
3679          break;
3680      }
3681      pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
3682      return kind;
3683  }
3684  
3685  /*
3686   * WIN32OLE_VARIABLE#variable_kind
3687   * ----
3688   * Returns variable kind string.
3689   */
3690  static VALUE
3691  folevariable_variable_kind(self)
3692      VALUE self;
3693  {
3694      struct olevariabledata *pvar;
3695      Data_Get_Struct(self, struct olevariabledata, pvar);
3696      return ole_variable_kind(pvar->pTypeInfo, pvar->index);
3697  }
3698  
3699  static VALUE
3700  ole_variable_varkind(pTypeInfo, var_index)
3701      ITypeInfo *pTypeInfo;
3702      UINT var_index;
3703  {
3704      VARDESC *pVarDesc;
3705      HRESULT hr;
3706      VALUE kind = Qnil;
3707      hr = pTypeInfo->lpVtbl->GetVarDesc(pTypeInfo, var_index, &pVarDesc);
3708      if (FAILED(hr))
3709          return kind;
3710      pTypeInfo->lpVtbl->ReleaseVarDesc(pTypeInfo, pVarDesc);
3711      kind = INT2FIX(pVarDesc->varkind);    
3712      return kind;
3713  }
3714  
3715  /*
3716   * WIN32OLE_VARIABLE#varkind
3717   * ----
3718   * Returns the number which represents variable kind.
3719   */
3720  static VALUE
3721  folevariable_varkind(self)
3722      VALUE self;
3723  {
3724      struct olevariabledata *pvar;
3725      Data_Get_Struct(self, struct olevariabledata, pvar);
3726      return ole_variable_varkind(pvar->pTypeInfo, pvar->index);
3727  }
3728  
3729  static VALUE
3730  olemethod_set_member(self, pTypeInfo, pOwnerTypeInfo, index, name)
3731      VALUE self;
3732      ITypeInfo *pTypeInfo;
3733      ITypeInfo *pOwnerTypeInfo;
3734      int index;
3735      VALUE name;
3736  {
3737      struct olemethoddata *pmethod;
3738      Data_Get_Struct(self, struct olemethoddata, pmethod);
3739      pmethod->pTypeInfo = pTypeInfo;
3740      OLE_ADDREF(pTypeInfo);
3741      pmethod->pOwnerTypeInfo = pOwnerTypeInfo;
3742      if(pOwnerTypeInfo) OLE_ADDREF(pOwnerTypeInfo);
3743      pmethod->index = index;
3744      rb_ivar_set(self, rb_intern("name"), name);
3745      return self;
3746  }
3747  
3748  static VALUE
3749  folemethod_s_allocate(klass)
3750      VALUE klass;
3751  {
3752      struct olemethoddata *pmethod;
3753      VALUE obj;
3754      obj = Data_Make_Struct(klass, 
3755                             struct olemethoddata,
3756                             0, olemethod_free, pmethod);
3757      pmethod->pTypeInfo = NULL;
3758      pmethod->pOwnerTypeInfo = NULL;
3759      pmethod->index = 0;
3760      return obj;
3761  }
3762  
3763  static VALUE
3764  folemethod_initialize(self, oletype, method)
3765      VALUE self;
3766      VALUE oletype;
3767      VALUE method;
3768  {
3769      struct oletypedata *ptype;
3770      VALUE obj = Qnil;
3771      if (rb_obj_is_kind_of(oletype, cWIN32OLE_TYPE)) {
3772          Check_SafeStr(method);
3773          Data_Get_Struct(oletype, struct oletypedata, ptype);
3774          obj = olemethod_from_typeinfo(self, ptype->pTypeInfo, method);
3775          if (obj == Qnil) {
3776              rb_raise(eWIN32OLE_RUNTIME_ERROR, "Not found %s",
3777                       StringValuePtr(method));
3778          }
3779      }
3780      else {
3781          rb_raise(rb_eTypeError, "1st argument should be WIN32OLE_TYPE object.");
3782      }
3783      return obj;
3784  }
3785  
3786  /*
3787   * WIN32OLE_METHOD#name
3788   * ----
3789   * Returns the name of the method.
3790   */
3791  static VALUE
3792  folemethod_name(self)
3793      VALUE self;
3794  {
3795      return rb_ivar_get(self, rb_intern("name"));
3796  }
3797  
3798  static VALUE
3799  ole_method_return_type(pTypeInfo, method_index)
3800      ITypeInfo *pTypeInfo;
3801      UINT method_index;
3802  {
3803      FUNCDESC *pFuncDesc;
3804      HRESULT hr;
3805      VALUE type;
3806  
3807      hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
3808      if (FAILED(hr)) 
3809          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "Fail to GetFuncDesc");
3810      
3811      type = ole_typedesc2val(pTypeInfo, &(pFuncDesc->elemdescFunc.tdesc), Qnil);
3812      pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
3813      return type;
3814  }
3815  
3816  /*
3817   * WIN32OLE_METHOD#return_type
3818   * ----
3819   * Returns string of return value type of method.
3820   */
3821  static VALUE
3822  folemethod_return_type(self)
3823      VALUE self;
3824  {
3825      struct olemethoddata *pmethod;
3826      Data_Get_Struct(self, struct olemethoddata, pmethod);
3827      return ole_method_return_type(pmethod->pTypeInfo, pmethod->index);
3828  }
3829  
3830  static VALUE
3831  ole_method_return_vtype(pTypeInfo, method_index)
3832      ITypeInfo *pTypeInfo;
3833      UINT method_index;
3834  {
3835      FUNCDESC *pFuncDesc;
3836      HRESULT hr;
3837      VALUE vt;
3838  
3839      hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
3840      if (FAILED(hr)) 
3841          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "Fail to GetFuncDesc");
3842      
3843      vt = INT2FIX(pFuncDesc->elemdescFunc.tdesc.vt);
3844      pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
3845      return vt;
3846  }
3847  
3848  /*
3849   * WIN32OLE_METHOD#return_vtype
3850   * ----
3851   * Returns number of return value type of method.
3852   */
3853  static VALUE
3854  folemethod_return_vtype(self)
3855      VALUE self;
3856  {
3857      struct olemethoddata *pmethod;
3858      Data_Get_Struct(self, struct olemethoddata, pmethod);
3859      return ole_method_return_vtype(pmethod->pTypeInfo, pmethod->index);
3860  }
3861  
3862  static VALUE
3863  ole_method_return_type_detail(pTypeInfo, method_index)
3864      ITypeInfo *pTypeInfo;
3865      UINT method_index;
3866  {
3867      FUNCDESC *pFuncDesc;
3868      HRESULT hr;
3869      VALUE type = rb_ary_new();
3870  
3871      hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
3872      if (FAILED(hr)) 
3873          return type;
3874      
3875      ole_typedesc2val(pTypeInfo, &(pFuncDesc->elemdescFunc.tdesc), type);
3876      pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
3877      return type;
3878  }
3879  
3880  /*
3881   * WIN32OLE_METHOD#return_type_detail
3882   * -----
3883   * Returns detail information of return value type of method.
3884   * The information is array.
3885   */
3886  static VALUE
3887  folemethod_return_type_detail(self)
3888      VALUE self;
3889  {
3890      struct olemethoddata *pmethod;
3891      Data_Get_Struct(self, struct olemethoddata, pmethod);
3892      return ole_method_return_type_detail(pmethod->pTypeInfo, pmethod->index);
3893  }
3894  
3895  static VALUE
3896  ole_method_invkind(pTypeInfo, method_index)
3897      ITypeInfo *pTypeInfo;
3898      UINT method_index;
3899  {
3900      FUNCDESC *pFuncDesc;
3901      HRESULT hr;
3902      VALUE invkind;
3903      hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
3904      if(FAILED(hr)) 
3905          ole_raise(hr, eWIN32OLE_RUNTIME_ERROR, "Fail to GetFuncDesc");
3906      invkind = INT2FIX(pFuncDesc->invkind);
3907      pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
3908      return invkind;
3909  }
3910  
3911  static VALUE
3912  ole_method_invoke_kind(pTypeInfo, method_index)
3913      ITypeInfo *pTypeInfo;
3914      WORD method_index;
3915  {
3916      VALUE type = rb_str_new2("UNKNOWN");
3917      VALUE invkind = ole_method_invkind(pTypeInfo, method_index);
3918      if((FIX2INT(invkind) & INVOKE_PROPERTYGET) &&
3919         (FIX2INT(invkind) & INVOKE_PROPERTYPUT) ) {
3920          type = rb_str_new2("PROPERTY");
3921      } else if(FIX2INT(invkind) & INVOKE_PROPERTYGET) {
3922          type =  rb_str_new2("PROPERTYGET");
3923      } else if(FIX2INT(invkind) & INVOKE_PROPERTYPUT) {
3924          type = rb_str_new2("PROPERTYPUT");
3925      } else if(FIX2INT(invkind) & INVOKE_PROPERTYPUTREF) {
3926          type = rb_str_new2("PROPERTYPUTREF");
3927      } else if(FIX2INT(invkind) & INVOKE_FUNC) {
3928          type = rb_str_new2("FUNC");
3929      }
3930      return type;
3931  }
3932  
3933  /*
3934   * WIN32OLE_MTHOD#invkind
3935   * ----
3936   * Returns invkind.
3937   */
3938  static VALUE
3939  folemethod_invkind(self)
3940      VALUE self;
3941  {
3942      struct olemethoddata *pmethod;
3943      Data_Get_Struct(self, struct olemethoddata, pmethod);
3944      return ole_method_invkind(pmethod->pTypeInfo, pmethod->index);
3945  }
3946  
3947  /*
3948   * WIN32OLE_METHOD#invoke_kind
3949   * ----
3950   * Returns invoke kind string.
3951   */
3952  static VALUE
3953  folemethod_invoke_kind(self)
3954      VALUE self;
3955  {
3956      struct olemethoddata *pmethod;
3957      Data_Get_Struct(self, struct olemethoddata, pmethod);
3958      return ole_method_invoke_kind(pmethod->pTypeInfo, pmethod->index);
3959  }
3960  
3961  static VALUE
3962  ole_method_visible(pTypeInfo, method_index)
3963      ITypeInfo *pTypeInfo;
3964      UINT method_index;
3965  {
3966      FUNCDESC *pFuncDesc;
3967      HRESULT hr;
3968      VALUE visible;
3969      hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
3970      if(FAILED(hr))
3971          return Qfalse;
3972      if (pFuncDesc->wFuncFlags & (FUNCFLAG_FRESTRICTED |
3973                                   FUNCFLAG_FHIDDEN |
3974                                   FUNCFLAG_FNONBROWSABLE)) {
3975          visible = Qfalse;
3976      } else {
3977          visible = Qtrue;
3978      }
3979      pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
3980      return visible;
3981  }
3982  
3983  /*
3984   * WIN32OLE_METHOD#visible?
3985   * ----
3986   * Returns true if the method is public.
3987   */
3988  static VALUE
3989  folemethod_visible(self) 
3990      VALUE self;
3991  {
3992      struct olemethoddata *pmethod;
3993      Data_Get_Struct(self, struct olemethoddata, pmethod);
3994      return ole_method_visible(pmethod->pTypeInfo, pmethod->index);
3995  }
3996  
3997  static ole_method_event(pTypeInfo, method_index, method_name)
3998      ITypeInfo *pTypeInfo;
3999      WORD method_index;
4000      VALUE method_name;
4001  {
4002      TYPEATTR *pTypeAttr;
4003      HRESULT hr;
4004      WORD i;
4005      int flags;
4006      HREFTYPE href;
4007      ITypeInfo *pRefTypeInfo;
4008      FUNCDESC *pFuncDesc;
4009      BSTR bstr;
4010      VALUE name;
4011      VALUE event = Qfalse;
4012      
4013      hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
4014      if (FAILED(hr)) 
4015          return event;
4016      if(pTypeAttr->typekind != TKIND_COCLASS) {
4017          pTypeInfo->lpVtbl->ReleaseTypeAttr(pTypeInfo, pTypeAttr);
4018          return event;
4019      }
4020      for (i = 0; i < pTypeAttr->cImplTypes; i++) {
4021          hr = pTypeInfo->lpVtbl->GetImplTypeFlags(pTypeInfo, i, &flags);
4022          if (FAILED(hr))
4023              continue;
4024  
4025          if (flags & IMPLTYPEFLAG_FSOURCE) {
4026              hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo,
4027                                                           i, &href);
4028              if (FAILED(hr))
4029                  continue;
4030              hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo,
4031                                                     href, &pRefTypeInfo);
4032              if (FAILED(hr))
4033                  continue;
4034              hr = pRefTypeInfo->lpVtbl->GetFuncDesc(pRefTypeInfo, method_index, 
4035                                                     &pFuncDesc);
4036              if (FAILED(hr)) {
4037                  OLE_RELEASE(pRefTypeInfo);
4038                  continue;
4039              }
4040  
4041              hr = pRefTypeInfo->lpVtbl->GetDocumentation(pRefTypeInfo, 
4042                                                          pFuncDesc->memid,
4043                                                          &bstr, NULL, NULL, NULL);
4044              if (FAILED(hr)) {
4045                  pRefTypeInfo->lpVtbl->ReleaseFuncDesc(pRefTypeInfo, pFuncDesc);
4046                  OLE_RELEASE(pRefTypeInfo);
4047                  continue;
4048              }
4049  
4050              name = WC2VSTR(bstr);
4051              pRefTypeInfo->lpVtbl->ReleaseFuncDesc(pRefTypeInfo, pFuncDesc);
4052              OLE_RELEASE(pRefTypeInfo);
4053              if (rb_str_cmp(method_name, name) == 0) {
4054                  event = Qtrue;
4055                  break;
4056              }
4057          }
4058      }
4059      OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
4060      return event;
4061  }
4062  
4063  /*
4064   * WIN32OLE_METHOD#event?
4065   * ----
4066   * Returns true if the method is event.
4067   */
4068  static VALUE
4069  folemethod_event(self)
4070      VALUE self;
4071  {
4072      struct olemethoddata *pmethod;
4073      Data_Get_Struct(self, struct olemethoddata, pmethod);
4074      if (!pmethod->pOwnerTypeInfo)
4075          return Qfalse;
4076      return ole_method_event(pmethod->pOwnerTypeInfo, 
4077                              pmethod->index,
4078                              rb_ivar_get(self, rb_intern("name")));
4079  }
4080  
4081  static VALUE
4082  folemethod_event_interface(self)
4083      VALUE self;
4084  {
4085      BSTR name;
4086      struct olemethoddata *pmethod;
4087      HRESULT hr;
4088      Data_Get_Struct(self, struct olemethoddata, pmethod);
4089      if(folemethod_event(self) == Qtrue) {
4090          hr = ole_docinfo_from_type(pmethod->pTypeInfo, &name, NULL, NULL, NULL);
4091          if(SUCCEEDED(hr))
4092              return WC2VSTR(name);
4093      }
4094      return Qnil;
4095  }
4096  
4097  static VALUE
4098  ole_method_docinfo_from_type(pTypeInfo, method_index, name, helpstr,
4099                               helpcontext, helpfile)
4100      ITypeInfo *pTypeInfo;
4101      UINT method_index;
4102      BSTR *name;
4103      BSTR *helpstr;
4104      DWORD *helpcontext;
4105      BSTR *helpfile;
4106  {
4107      FUNCDESC *pFuncDesc;
4108      HRESULT hr;
4109      hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
4110      if (FAILED(hr))
4111          return hr;
4112      hr = pTypeInfo->lpVtbl->GetDocumentation(pTypeInfo, pFuncDesc->memid,
4113                                               name, helpstr,
4114                                               helpcontext, helpfile);
4115      pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
4116      return hr;
4117  }
4118  
4119  static VALUE
4120  ole_method_helpstring(pTypeInfo, method_index)
4121      ITypeInfo *pTypeInfo;
4122      UINT method_index;
4123  {
4124      HRESULT hr;
4125      BSTR bhelpstring;
4126      hr = ole_method_docinfo_from_type(pTypeInfo, method_index, NULL, &bhelpstring,
4127                                        NULL, NULL); 
4128      if (FAILED(hr))
4129          return Qnil;
4130      return WC2VSTR(bhelpstring);
4131  }
4132  
4133  static VALUE
4134  folemethod_helpstring(self)
4135      VALUE self;
4136  {
4137      struct olemethoddata *pmethod;
4138      Data_Get_Struct(self, struct olemethoddata, pmethod);
4139      return ole_method_helpstring(pmethod->pTypeInfo, pmethod->index);
4140  }
4141  
4142  static VALUE
4143  ole_method_helpfile(pTypeInfo, method_index)
4144      ITypeInfo *pTypeInfo;
4145      UINT method_index;
4146  {
4147      HRESULT hr;
4148      BSTR bhelpfile;
4149      hr = ole_method_docinfo_from_type(pTypeInfo, method_index, NULL, NULL,
4150                                        NULL, &bhelpfile); 
4151      if (FAILED(hr))
4152          return Qnil;
4153      return WC2VSTR(bhelpfile);
4154  }
4155  
4156  /*
4157   * WIN32OLE_METHOD#helpfile
4158   * ---
4159   * Returns help file.
4160   */
4161  static VALUE
4162  folemethod_helpfile(self)
4163      VALUE self;
4164  {
4165      struct olemethoddata *pmethod;
4166      Data_Get_Struct(self, struct olemethoddata, pmethod);
4167  
4168      return ole_method_helpfile(pmethod->pTypeInfo, pmethod->index);
4169  }
4170  
4171  static VALUE
4172  ole_method_helpcontext(pTypeInfo, method_index)
4173      ITypeInfo *pTypeInfo;
4174      UINT method_index;
4175  {
4176      HRESULT hr;
4177      DWORD helpcontext = 0;
4178      hr = ole_method_docinfo_from_type(pTypeInfo, method_index, NULL, NULL,
4179                                        &helpcontext, NULL); 
4180      if (FAILED(hr))
4181          return Qnil;
4182      return INT2FIX(helpcontext);
4183  }
4184  
4185  /* 
4186   * WIN32OLE_METHOD#helpcontext
4187   * -----
4188   * Returns help context.
4189   */
4190  static VALUE
4191  folemethod_helpcontext(self)
4192      VALUE self;
4193  {
4194      struct olemethoddata *pmethod;
4195      Data_Get_Struct(self, struct olemethoddata, pmethod);
4196      return ole_method_helpcontext(pmethod->pTypeInfo, pmethod->index);
4197  }
4198  
4199  static VALUE
4200  ole_method_dispid(pTypeInfo, method_index)
4201      ITypeInfo *pTypeInfo;
4202      UINT method_index;
4203  {
4204      FUNCDESC *pFuncDesc;
4205      HRESULT hr;
4206      VALUE dispid = Qnil;
4207      hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
4208      if (FAILED(hr))
4209          return dispid;
4210      dispid = INT2FIX(pFuncDesc->memid); 
4211      pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
4212      return dispid;
4213  }
4214  
4215  /*
4216   * WIN32OLE_METHOD#dispid
4217   * ----
4218   * Returns dispatch ID.
4219   */
4220  static VALUE
4221  folemethod_dispid(self)
4222      VALUE self;
4223  {
4224      struct olemethoddata *pmethod;
4225      Data_Get_Struct(self, struct olemethoddata, pmethod);
4226      return ole_method_dispid(pmethod->pTypeInfo, pmethod->index);
4227  }
4228  
4229  static VALUE
4230  ole_method_offset_vtbl(pTypeInfo, method_index)
4231      ITypeInfo *pTypeInfo;
4232      UINT method_index;
4233  {
4234      FUNCDESC *pFuncDesc;
4235      HRESULT hr;
4236      VALUE offset_vtbl = Qnil;
4237      hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
4238      if (FAILED(hr))
4239          return offset_vtbl;
4240      offset_vtbl = INT2FIX(pFuncDesc->oVft); 
4241      pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
4242      return offset_vtbl;
4243  }
4244  
4245  /*
4246   * WIN32OLE_METHOD#offset_vtbl
4247   * ----
4248   * Returns the offset ov VTBL.
4249   */
4250  static VALUE
4251  folemethod_offset_vtbl(self)
4252      VALUE self;
4253  {
4254      struct olemethoddata *pmethod;
4255      Data_Get_Struct(self, struct olemethoddata, pmethod);
4256      return ole_method_offset_vtbl(pmethod->pTypeInfo, pmethod->index);
4257  }
4258  
4259  static VALUE
4260  ole_method_size_params(pTypeInfo, method_index)
4261      ITypeInfo *pTypeInfo;
4262      UINT method_index;
4263  {
4264      FUNCDESC *pFuncDesc;
4265      HRESULT hr;
4266      VALUE size_params = Qnil;
4267      hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
4268      if (FAILED(hr))
4269          return size_params;
4270      size_params = INT2FIX(pFuncDesc->cParams);
4271      pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
4272      return size_params;
4273  }
4274  
4275  /*
4276   * WIN32OLE_METHOD#size_params
4277   * ----
4278   * Returns the size of arguments.
4279   */
4280  static VALUE
4281  folemethod_size_params(self)
4282      VALUE self;
4283  {
4284      struct olemethoddata *pmethod;
4285      Data_Get_Struct(self, struct olemethoddata, pmethod);
4286      return ole_method_size_params(pmethod->pTypeInfo, pmethod->index);
4287  }
4288  
4289  /*
4290   * WIN32OLE_METHOD#size_opt_params
4291   * ----
4292   * Returns the size of optional parameters.
4293   */
4294  static VALUE
4295  ole_method_size_opt_params(pTypeInfo, method_index)
4296      ITypeInfo *pTypeInfo;
4297      UINT method_index;
4298  {
4299      FUNCDESC *pFuncDesc;
4300      HRESULT hr;
4301      VALUE size_opt_params = Qnil;
4302      hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
4303      if (FAILED(hr))
4304          return size_opt_params;
4305      size_opt_params = INT2FIX(pFuncDesc->cParamsOpt);
4306      pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
4307      return size_opt_params;
4308  }
4309  
4310  static VALUE
4311  folemethod_size_opt_params(self)
4312      VALUE self;
4313  {
4314      struct olemethoddata *pmethod;
4315      Data_Get_Struct(self, struct olemethoddata, pmethod);
4316      return ole_method_size_opt_params(pmethod->pTypeInfo, pmethod->index);
4317  }
4318  
4319  static VALUE
4320  ole_method_params(pTypeInfo, method_index)
4321      ITypeInfo *pTypeInfo;
4322      UINT method_index;
4323  {
4324      FUNCDESC *pFuncDesc;
4325      HRESULT hr;
4326      BSTR *bstrs;
4327      UINT len, i;
4328      struct oleparamdata *pparam;
4329      VALUE param;
4330      VALUE params = rb_ary_new();
4331      hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
4332      if (FAILED(hr)) 
4333          return params;
4334  
4335      len = 0;
4336      bstrs = ALLOCA_N(BSTR, pFuncDesc->cParams + 1);
4337      hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, pFuncDesc->memid, 
4338                                       bstrs, pFuncDesc->cParams + 1,
4339                                       &len);
4340      if (FAILED(hr)) {
4341          pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
4342          return params;
4343      }
4344      SysFreeString(bstrs[0]);
4345      if (pFuncDesc->cParams > 0) {
4346          for(i = 1; i < len; i++) {
4347              param = Data_Make_Struct(cWIN32OLE_PARAM, struct oleparamdata, 0,
4348                                       oleparam_free, pparam);
4349              pparam->pTypeInfo = pTypeInfo;
4350              OLE_ADDREF(pTypeInfo);
4351              pparam->method_index = method_index;
4352              pparam->index = i - 1;
4353              rb_ivar_set(param, rb_intern("name"), WC2VSTR(bstrs[i]));
4354              rb_ary_push(params, param);
4355           }
4356       }
4357       pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
4358       return params;
4359  }
4360  
4361  /*
4362   * WIN32OLE_METHOD#params
4363   * ----
4364   * returns array of WIN32OLE_PARAM object corresponding with method parameters.
4365   */
4366  static VALUE
4367  folemethod_params(self)
4368      VALUE self;
4369  {
4370      struct olemethoddata *pmethod;
4371      Data_Get_Struct(self, struct olemethoddata, pmethod);
4372      return ole_method_params(pmethod->pTypeInfo, pmethod->index);
4373  }
4374  
4375  /*
4376   * WIN32OLE_PARAM#name
4377   * ----
4378   * Returns name.
4379   */
4380  static VALUE
4381  foleparam_name(self)
4382      VALUE self;
4383  {
4384      return rb_ivar_get(self, rb_intern("name"));
4385  }
4386  
4387  static VALUE
4388  ole_param_ole_type(pTypeInfo, method_index, index)
4389      ITypeInfo *pTypeInfo;
4390      UINT method_index;
4391      UINT index;
4392  {
4393      FUNCDESC *pFuncDesc;
4394      HRESULT hr;
4395      VALUE type = rb_str_new2("UNKNOWN");
4396      hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
4397      if (FAILED(hr))
4398          return type;
4399      type = ole_typedesc2val(pTypeInfo, 
4400                              &(pFuncDesc->lprgelemdescParam[index].tdesc), Qnil);
4401      pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
4402      return type;
4403  }
4404  
4405  static VALUE 
4406  foleparam_ole_type(self)
4407      VALUE self;
4408  {
4409      struct oleparamdata *pparam;
4410      Data_Get_Struct(self, struct oleparamdata, pparam);
4411      return ole_param_ole_type(pparam->pTypeInfo, pparam->method_index, 
4412                                pparam->index);
4413  }
4414  
4415  static VALUE
4416  ole_param_ole_type_detail(pTypeInfo, method_index, index)
4417      ITypeInfo *pTypeInfo;
4418      UINT method_index;
4419      UINT index;
4420  {
4421      FUNCDESC *pFuncDesc;
4422      HRESULT hr;
4423      VALUE typedetail = rb_ary_new();
4424      hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
4425      if (FAILED(hr))
4426          return typedetail;
4427      ole_typedesc2val(pTypeInfo, 
4428                       &(pFuncDesc->lprgelemdescParam[index].tdesc), typedetail);
4429      pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
4430      return typedetail;
4431  }
4432  
4433  static VALUE 
4434  foleparam_ole_type_detail(self)
4435      VALUE self;
4436  {
4437      struct oleparamdata *pparam;
4438      Data_Get_Struct(self, struct oleparamdata, pparam);
4439      return ole_param_ole_type_detail(pparam->pTypeInfo, pparam->method_index, 
4440                                       pparam->index);
4441  }
4442  
4443  static VALUE
4444  ole_param_flag_mask(pTypeInfo, method_index, index, mask)
4445      ITypeInfo *pTypeInfo;
4446      UINT method_index;
4447      UINT index;
4448      USHORT mask;
4449  {
4450      FUNCDESC *pFuncDesc;
4451      HRESULT hr;
4452      VALUE ret = Qfalse;
4453      hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
4454      if(FAILED(hr)) 
4455          return ret;
4456      if (V_UNION1((&(pFuncDesc->lprgelemdescParam[index])), paramdesc).wParamFlags &mask) 
4457          ret = Qtrue;
4458      pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
4459      return ret;
4460  }
4461  
4462  /*
4463   * WIN32OLE_PARAM#input?
4464   * ----
4465   * Returns true if the parameter is input.
4466   */
4467  static VALUE foleparam_input(self)
4468      VALUE self;
4469  {
4470      struct oleparamdata *pparam;
4471      Data_Get_Struct(self, struct oleparamdata, pparam);
4472      return ole_param_flag_mask(pparam->pTypeInfo, pparam->method_index, 
4473                                 pparam->index, PARAMFLAG_FIN);
4474  }
4475  
4476  /*
4477   * WIN32OLE#output?
4478   * ----
4479   * Returns true if argument is output.
4480   */
4481  static VALUE foleparam_output(self)
4482      VALUE self;
4483  {
4484      struct oleparamdata *pparam;
4485      Data_Get_Struct(self, struct oleparamdata, pparam);
4486      return ole_param_flag_mask(pparam->pTypeInfo, pparam->method_index, 
4487                                 pparam->index, PARAMFLAG_FOUT);
4488  }
4489  
4490  /*
4491   * WIN32OLE_PARAM#optional?
4492   * -----
4493   * Returns true if argument is output.
4494   */
4495  static VALUE foleparam_optional(self)
4496      VALUE self;
4497  {
4498      struct oleparamdata *pparam;
4499      Data_Get_Struct(self, struct oleparamdata, pparam);
4500      return ole_param_flag_mask(pparam->pTypeInfo, pparam->method_index, 
4501                                 pparam->index, PARAMFLAG_FOPT);
4502  }
4503  
4504  static VALUE foleparam_retval(self)
4505      VALUE self;
4506  {
4507      struct oleparamdata *pparam;
4508      Data_Get_Struct(self, struct oleparamdata, pparam);
4509      return ole_param_flag_mask(pparam->pTypeInfo, pparam->method_index, 
4510                                 pparam->index, PARAMFLAG_FRETVAL);
4511  }
4512  
4513  static VALUE
4514  ole_param_default(pTypeInfo, method_index, index)
4515      ITypeInfo *pTypeInfo;
4516      UINT method_index;
4517      UINT index;
4518  {
4519      FUNCDESC *pFuncDesc;
4520      ELEMDESC *pElemDesc;
4521      PARAMDESCEX * pParamDescEx;
4522      HRESULT hr;
4523      USHORT wParamFlags;
4524      USHORT mask = PARAMFLAG_FOPT|PARAMFLAG_FHASDEFAULT;
4525      VALUE defval = Qnil;
4526      hr = pTypeInfo->lpVtbl->GetFuncDesc(pTypeInfo, method_index, &pFuncDesc);
4527      if (FAILED(hr))
4528          return defval;
4529      pElemDesc = &pFuncDesc->lprgelemdescParam[index]; 
4530      wParamFlags = V_UNION1(pElemDesc, paramdesc).wParamFlags;
4531      if ((wParamFlags & mask) == mask) {
4532           pParamDescEx = V_UNION1(pElemDesc, paramdesc).pparamdescex;
4533           defval = ole_variant2val(&pParamDescEx->varDefaultValue);
4534      }
4535      pTypeInfo->lpVtbl->ReleaseFuncDesc(pTypeInfo, pFuncDesc);
4536      return defval;
4537  }
4538  
4539  /*
4540   * WIN32OLE_PARAM#default
4541   * ----
4542   * Returns default value. If the default value does not exist, 
4543   * this method returns nil.
4544   */
4545  static VALUE foleparam_default(self)
4546      VALUE self;
4547  {
4548      struct oleparamdata *pparam;
4549      Data_Get_Struct(self, struct oleparamdata, pparam);
4550      return ole_param_default(pparam->pTypeInfo, pparam->method_index,
4551                               pparam->index);
4552  }
4553  
4554  static IEventSinkVtbl vtEventSink;
4555  static BOOL g_IsEventSinkVtblInitialized = FALSE;
4556  
4557  void EVENTSINK_Destructor(PIEVENTSINKOBJ);
4558  
4559  STDMETHODIMP
4560  EVENTSINK_QueryInterface(
4561      PEVENTSINK pEV,
4562      REFIID     iid,
4563      LPVOID*    ppv
4564      ) {
4565      if (IsEqualIID(iid, &IID_IUnknown) ||
4566          IsEqualIID(iid, &IID_IDispatch) ||
4567          IsEqualIID(iid, &((PIEVENTSINKOBJ)pEV)->m_iid)) {
4568          *ppv = pEV;
4569      }
4570      else {
4571          *ppv = NULL;
4572          return E_NOINTERFACE;
4573      }
4574      ((LPUNKNOWN)*ppv)->lpVtbl->AddRef((LPUNKNOWN)*ppv);
4575      return NOERROR;
4576  }
4577  
4578  STDMETHODIMP_(ULONG)
4579  EVENTSINK_AddRef(
4580      PEVENTSINK pEV
4581      ){
4582      PIEVENTSINKOBJ pEVObj = (PIEVENTSINKOBJ)pEV;
4583      return ++pEVObj->m_cRef;
4584  }
4585  
4586  STDMETHODIMP_(ULONG) EVENTSINK_Release(
4587      PEVENTSINK pEV
4588      ) {
4589      PIEVENTSINKOBJ pEVObj = (PIEVENTSINKOBJ)pEV;
4590      --pEVObj->m_cRef;
4591      if(pEVObj->m_cRef != 0)
4592          return pEVObj->m_cRef;
4593      EVENTSINK_Destructor(pEVObj);
4594      return 0;
4595  }
4596  
4597  STDMETHODIMP EVENTSINK_GetTypeInfoCount(
4598      PEVENTSINK pEV,
4599      UINT *pct
4600      ) {
4601      *pct = 0;
4602      return NOERROR;
4603  }
4604  
4605  STDMETHODIMP EVENTSINK_GetTypeInfo(
4606      PEVENTSINK pEV,
4607      UINT info,
4608      LCID lcid,
4609      ITypeInfo **pInfo
4610      ) {
4611      *pInfo = NULL;
4612      return DISP_E_BADINDEX;
4613  }
4614  
4615  STDMETHODIMP EVENTSINK_GetIDsOfNames(
4616      PEVENTSINK pEV,
4617      REFIID riid,
4618      OLECHAR **szNames,
4619      UINT cNames,
4620      LCID lcid,
4621      DISPID *pDispID
4622      ) {
4623      return DISP_E_UNKNOWNNAME;
4624  }
4625  
4626  static VALUE
4627  ole_search_event(ary, ev, is_default)
4628      VALUE ary;
4629      VALUE ev;
4630      BOOL  *is_default;
4631  {
4632      VALUE event;
4633      VALUE def_event;
4634      VALUE event_name;
4635      int i, len;
4636      *is_default = FALSE;
4637      def_event = Qnil;
4638      len = RARRAY(ary)->len;
4639      for(i = 0; i < len; i++) {
4640          event = rb_ary_entry(ary, i);
4641          event_name = rb_ary_entry(event, 1);
4642          if(NIL_P(event_name)) {
4643              *is_default = TRUE;
4644              def_event = event;
4645          }
4646          else if (rb_str_cmp(ev, event_name) == 0) {
4647              *is_default = FALSE;
4648              return event;
4649          }
4650      }
4651      return def_event;
4652  }
4653  
4654  static void
4655  val2ptr_variant(val, var)
4656      VALUE val;
4657      VARIANT *var;
4658  {
4659      switch (TYPE(val)) {
4660      case T_STRING:
4661          if (V_VT(var) == (VT_BSTR | VT_BYREF)) {
4662              *V_BSTRREF(var) = ole_mb2wc(StringValuePtr(val), -1);
4663          }
4664          break;
4665      case T_FIXNUM:
4666          switch(V_VT(var)) {
4667          case (VT_UI1 | VT_BYREF) :
4668              *V_UI1REF(var) = NUM2CHR(val);
4669              break;
4670          case (VT_I2 | VT_BYREF) :
4671              *V_I2REF(var) = (short)NUM2INT(val);
4672              break;
4673          case (VT_I4 | VT_BYREF) :
4674              *V_I4REF(var) = NUM2INT(val);
4675              break;
4676          case (VT_R4 | VT_BYREF) :
4677              *V_R4REF(var) = (float)NUM2INT(val);
4678              break;
4679          case (VT_R8 | VT_BYREF) :
4680              *V_R8REF(var) = NUM2INT(val);
4681              break;
4682          default:
4683              break;
4684          }
4685          break;
4686      case T_FLOAT:
4687          switch(V_VT(var)) {
4688          case (VT_I2 | VT_BYREF) :
4689              *V_I2REF(var) = (short)NUM2INT(val);
4690              break;
4691          case (VT_I4 | VT_BYREF) :
4692              *V_I4REF(var) = NUM2INT(val);
4693              break;
4694          case (VT_R4 | VT_BYREF) :
4695              *V_R4REF(var) = (float)NUM2DBL(val);
4696              break;
4697          case (VT_R8 | VT_BYREF) :
4698              *V_R8REF(var) = NUM2DBL(val);
4699              break;
4700          default:
4701              break;
4702          }
4703          break;
4704      case T_BIGNUM:
4705          if (V_VT(var) == (VT_R8 | VT_BYREF)) {
4706              *V_R8REF(var) = rb_big2dbl(val);
4707          }
4708          break;
4709      case T_TRUE:
4710          if (V_VT(var) == (VT_BOOL | VT_BYREF)) {
4711              *V_BOOLREF(var) = VARIANT_TRUE;
4712          }
4713          break;
4714      case T_FALSE:
4715          if (V_VT(var) == (VT_BOOL | VT_BYREF)) {
4716              *V_BOOLREF(var) = VARIANT_FALSE;
4717          }
4718          break;
4719      default:
4720          break;
4721      }
4722  }
4723  
4724  static void
4725  ary2ptr_dispparams(ary, pdispparams)
4726      VALUE ary;
4727      DISPPARAMS *pdispparams;
4728  {
4729      int i;
4730      VALUE v;
4731      VARIANT *pvar;
4732      for(i = 0; i < RARRAY(ary)->len && (unsigned int) i < pdispparams->cArgs; i++) {
4733          v = rb_ary_entry(ary, i);
4734          pvar = &pdispparams->rgvarg[pdispparams->cArgs-i-1];
4735          val2ptr_variant(v, pvar);
4736      }
4737  }
4738  
4739  STDMETHODIMP EVENTSINK_Invoke(
4740      PEVENTSINK pEventSink,
4741      DISPID dispid,
4742      REFIID riid,
4743      LCID lcid,
4744      WORD wFlags,
4745      DISPPARAMS *pdispparams,
4746      VARIANT *pvarResult,
4747      EXCEPINFO *pexcepinfo,
4748      UINT *puArgErr
4749      ) {
4750  
4751      HRESULT hr;
4752      BSTR bstr;
4753      unsigned int count;
4754      unsigned int i;
4755      ITypeInfo *pTypeInfo;
4756      VARIANT *pvar;
4757      VALUE ary, obj, event, handler, args, argv, ev;
4758      BOOL is_default_handler = FALSE;
4759  
4760      PIEVENTSINKOBJ pEV = (PIEVENTSINKOBJ)pEventSink;
4761      pTypeInfo = pEV->pTypeInfo;
4762  
4763      obj = rb_ary_entry(ary_ole_event, pEV->m_event_id);
4764      if (!rb_obj_is_kind_of(obj, cWIN32OLE_EVENT)) {
4765          return NOERROR;
4766      }
4767  
4768      ary = rb_ivar_get(obj, id_events);
4769      if (NIL_P(ary) || TYPE(ary) != T_ARRAY) {
4770          return NOERROR;
4771      }
4772      hr = pTypeInfo->lpVtbl->GetNames(pTypeInfo, dispid,
4773                                       &bstr, 1, &count);
4774      if (FAILED(hr)) {
4775          return NOERROR;
4776      }
4777      ev = WC2VSTR(bstr);
4778      event = ole_search_event(ary, ev, &is_default_handler);
4779      if (NIL_P(event)) {
4780          return NOERROR;
4781      }
4782      args = rb_ary_new();
4783      if (is_default_handler) {
4784          rb_ary_push(args, ev);
4785      }
4786  
4787      /* make argument of event handler */
4788      for (i = 0; i < pdispparams->cArgs; ++i) {
4789          pvar = &pdispparams->rgvarg[pdispparams->cArgs-i-1];
4790          rb_ary_push(args, ole_variant2val(pvar));
4791      }
4792      handler = rb_ary_entry(event, 0);
4793  
4794      if (rb_ary_entry(event, 3) == Qtrue) {
4795          argv = rb_ary_new();
4796          rb_ary_push(args, argv);
4797          rb_apply(handler, rb_intern("call"), args);
4798          ary2ptr_dispparams(argv, pdispparams);
4799      }
4800      else {
4801          rb_apply(handler, rb_intern("call"), args);
4802      }
4803      return NOERROR;
4804  }
4805  
4806  PIEVENTSINKOBJ
4807  EVENTSINK_Constructor() {
4808      PIEVENTSINKOBJ pEv;
4809      if (!g_IsEventSinkVtblInitialized) {
4810          vtEventSink.QueryInterface=EVENTSINK_QueryInterface;
4811          vtEventSink.AddRef = EVENTSINK_AddRef;
4812          vtEventSink.Release = EVENTSINK_Release;
4813          vtEventSink.Invoke = EVENTSINK_Invoke;
4814          vtEventSink.GetIDsOfNames = EVENTSINK_GetIDsOfNames;
4815          vtEventSink.GetTypeInfoCount = EVENTSINK_GetTypeInfoCount;
4816          vtEventSink.GetTypeInfo = EVENTSINK_GetTypeInfo;
4817  
4818          g_IsEventSinkVtblInitialized = TRUE;
4819      }
4820      pEv = ALLOC_N(IEVENTSINKOBJ, 1);
4821      if(pEv == NULL) return NULL;
4822      pEv->lpVtbl = &vtEventSink;
4823      pEv->m_cRef = 0;
4824      pEv->m_event_id = 0;
4825      pEv->m_dwCookie = 0;
4826      pEv->pConnectionPoint = NULL;
4827      pEv->pTypeInfo = NULL;
4828      return pEv;
4829  }
4830  
4831  void EVENTSINK_Destructor(
4832      PIEVENTSINKOBJ pEVObj
4833      ) {
4834      if(pEVObj != NULL) {
4835          free(pEVObj);
4836      }
4837  }
4838  
4839  static HRESULT
4840  find_iid(ole, pitf, piid, ppTypeInfo)
4841      VALUE ole;
4842      char *pitf;
4843      IID *piid;
4844      ITypeInfo **ppTypeInfo;
4845  {
4846      HRESULT hr;
4847      IDispatch *pDispatch;
4848      ITypeInfo *pTypeInfo;
4849      ITypeLib *pTypeLib;
4850      TYPEATTR *pTypeAttr;
4851      HREFTYPE RefType;
4852      ITypeInfo *pImplTypeInfo;
4853      TYPEATTR *pImplTypeAttr;
4854  
4855      struct oledata *pole;
4856      unsigned int index;
4857      unsigned int count;
4858      int type;
4859      BSTR bstr;
4860      char *pstr;
4861  
4862      BOOL is_found = FALSE;
4863      LCID    lcid = LOCALE_SYSTEM_DEFAULT;
4864  
4865      OLEData_Get_Struct(ole, pole);
4866  
4867      pDispatch = pole->pDispatch;
4868  
4869      hr = pDispatch->lpVtbl->GetTypeInfo(pDispatch, 0, lcid, &pTypeInfo);
4870      if (FAILED(hr))
4871          return hr;
4872  
4873      hr = pTypeInfo->lpVtbl->GetContainingTypeLib(pTypeInfo,
4874                                                   &pTypeLib,
4875                                                   &index);
4876      OLE_RELEASE(pTypeInfo);
4877      if (FAILED(hr))
4878          return hr;
4879  
4880      if (!pitf) {
4881          hr = pTypeLib->lpVtbl->GetTypeInfoOfGuid(pTypeLib,
4882                                                   piid,
4883                                                   ppTypeInfo);
4884          OLE_RELEASE(pTypeLib);
4885          return hr;
4886      }
4887      count = pTypeLib->lpVtbl->GetTypeInfoCount(pTypeLib);
4888      for (index = 0; index < count; index++) {
4889          hr = pTypeLib->lpVtbl->GetTypeInfo(pTypeLib,
4890                                             index,
4891                                             &pTypeInfo);
4892          if (FAILED(hr))
4893              break;
4894          hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
4895  
4896          if(FAILED(hr)) {
4897              OLE_RELEASE(pTypeInfo);
4898              break;
4899          }
4900          if(pTypeAttr->typekind == TKIND_COCLASS) {
4901              for (type = 0; type < pTypeAttr->cImplTypes; type++) {
4902                  hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo,
4903                                                               type,
4904                                                               &RefType);
4905                  if (FAILED(hr))
4906                      break;
4907                  hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo,
4908                                                         RefType,
4909                                                         &pImplTypeInfo);
4910                  if (FAILED(hr))
4911                      break;
4912  
4913                  hr = pImplTypeInfo->lpVtbl->GetDocumentation(pImplTypeInfo,
4914                                                               -1,
4915                                                               &bstr,
4916                                                               NULL, NULL, NULL);
4917                  if (FAILED(hr)) {
4918                      OLE_RELEASE(pImplTypeInfo);
4919                      break;
4920                  }
4921                  pstr = ole_wc2mb(bstr);
4922                  if (strcmp(pitf, pstr) == 0) {
4923                      hr = pImplTypeInfo->lpVtbl->GetTypeAttr(pImplTypeInfo,
4924                                                              &pImplTypeAttr);
4925                      if (SUCCEEDED(hr)) {
4926                          is_found = TRUE;
4927                          *piid = pImplTypeAttr->guid;
4928                          if (ppTypeInfo) {
4929                              *ppTypeInfo = pImplTypeInfo;
4930                              (*ppTypeInfo)->lpVtbl->AddRef((*ppTypeInfo));
4931                          }
4932                          pImplTypeInfo->lpVtbl->ReleaseTypeAttr(pImplTypeInfo,
4933                                                                 pImplTypeAttr);
4934                      }
4935                  }
4936                  free(pstr);
4937                  OLE_RELEASE(pImplTypeInfo);
4938                  if (is_found || FAILED(hr))
4939                      break;
4940              }
4941          }
4942  
4943          OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
4944          OLE_RELEASE(pTypeInfo);
4945          if (is_found || FAILED(hr))
4946              break;
4947      }
4948      OLE_RELEASE(pTypeLib);
4949      if(!is_found)
4950          return E_NOINTERFACE;
4951      return hr;
4952  }
4953  
4954  static HRESULT
4955  find_default_source(ole, piid, ppTypeInfo)
4956      VALUE ole;
4957      IID *piid;
4958      ITypeInfo **ppTypeInfo;
4959  {
4960      HRESULT hr;
4961      IProvideClassInfo2 *pProvideClassInfo2;
4962      IProvideClassInfo *pProvideClassInfo;
4963  
4964      IDispatch *pDispatch;
4965      ITypeInfo *pTypeInfo;
4966      TYPEATTR *pTypeAttr;
4967      int i;
4968      int iFlags;
4969      HREFTYPE hRefType;
4970  
4971      struct oledata *pole;
4972  
4973      OLEData_Get_Struct(ole, pole);
4974      pDispatch = pole->pDispatch;
4975      hr = pDispatch->lpVtbl->QueryInterface(pDispatch,
4976                                             &IID_IProvideClassInfo2,
4977                                             (void**)&pProvideClassInfo2);
4978      if (SUCCEEDED(hr)) {
4979          hr = pProvideClassInfo2->lpVtbl->GetGUID(pProvideClassInfo2,
4980                                                   GUIDKIND_DEFAULT_SOURCE_DISP_IID,
4981                                                   piid);
4982          OLE_RELEASE(pProvideClassInfo2);
4983          return find_iid(ole, NULL, piid, ppTypeInfo);
4984      }
4985      hr = pDispatch->lpVtbl->QueryInterface(pDispatch,
4986                                             &IID_IProvideClassInfo,
4987                                             (void**)&pProvideClassInfo);
4988      if (FAILED(hr))
4989          return hr;
4990  
4991      hr = pProvideClassInfo->lpVtbl->GetClassInfo(pProvideClassInfo,
4992                                                   &pTypeInfo);
4993      OLE_RELEASE(pProvideClassInfo);
4994      if (FAILED(hr))
4995          return hr;
4996  
4997      hr = OLE_GET_TYPEATTR(pTypeInfo, &pTypeAttr);
4998      if (FAILED(hr)) {
4999          OLE_RELEASE(pTypeInfo);
5000          return hr;
5001      }
5002      /* Enumerate all implemented types of the COCLASS */
5003      for (i = 0; i < pTypeAttr->cImplTypes; i++) {
5004          hr = pTypeInfo->lpVtbl->GetImplTypeFlags(pTypeInfo, i, &iFlags);
5005          if (FAILED(hr))
5006              continue;
5007  
5008          /*
5009             looking for the [default] [source]
5010             we just hope that it is a dispinterface :-)
5011          */
5012          if ((iFlags & IMPLTYPEFLAG_FDEFAULT) &&
5013              (iFlags & IMPLTYPEFLAG_FSOURCE)) {
5014  
5015              hr = pTypeInfo->lpVtbl->GetRefTypeOfImplType(pTypeInfo,
5016                                                           i, &hRefType);
5017              if (FAILED(hr))
5018                  continue;
5019              hr = pTypeInfo->lpVtbl->GetRefTypeInfo(pTypeInfo,
5020                                                     hRefType, ppTypeInfo);
5021              if (SUCCEEDED(hr))
5022                  break;
5023          }
5024      }
5025  
5026      OLE_RELEASE_TYPEATTR(pTypeInfo, pTypeAttr);
5027      OLE_RELEASE(pTypeInfo);
5028  
5029      /* Now that would be a bad surprise, if we didn't find it, wouldn't it? */
5030      if (!*ppTypeInfo) {
5031          if (SUCCEEDED(hr))
5032              hr = E_UNEXPECTED;
5033          return hr;
5034      }
5035  
5036      // Determine IID of default source interface
5037      hr = (*ppTypeInfo)->lpVtbl->GetTypeAttr(*ppTypeInfo, &pTypeAttr);
5038      if (SUCCEEDED(hr)) {
5039          *piid = pTypeAttr->guid;
5040          (*ppTypeInfo)->lpVtbl->ReleaseTypeAttr(*ppTypeInfo, pTypeAttr);
5041      }
5042      else
5043          OLE_RELEASE(*ppTypeInfo);
5044  
5045      return hr;
5046  
5047  }
5048  
5049  static void
5050  ole_event_free(poleev)
5051      struct oleeventdata *poleev;
5052  {
5053      ITypeInfo *pti = NULL;
5054      IConnectionPoint *pcp = NULL;
5055  
5056      if(poleev->pEvent) {
5057          pti = poleev->pEvent->pTypeInfo;
5058          if(pti) OLE_RELEASE(pti);
5059          pcp = poleev->pEvent->pConnectionPoint;
5060          if(pcp) {
5061              pcp->lpVtbl->Unadvise(pcp, poleev->pEvent->m_dwCookie);
5062              OLE_RELEASE(pcp);
5063          }
5064          ole_msg_loop();
5065          CoFreeUnusedLibraries();
5066      }
5067  }
5068  
5069  static VALUE
5070  fev_s_allocate(klass)
5071      VALUE klass;
5072  {
5073      VALUE obj;
5074      struct oleeventdata *poleev;
5075      obj = Data_Make_Struct(klass,struct oleeventdata,0,ole_event_free,poleev);
5076      poleev->pEvent = NULL;
5077      return obj;
5078  }
5079  
5080  static VALUE
5081  fev_initialize(argc, argv, self)
5082      int argc;
5083      VALUE *argv;
5084      VALUE self;
5085  {
5086      VALUE ole, itf;
5087      struct oledata *pole;
5088      char *pitf;
5089      HRESULT hr;
5090      IID iid;
5091      ITypeInfo *pTypeInfo;
5092      IDispatch *pDispatch;
5093      IConnectionPointContainer *pContainer;
5094      IConnectionPoint *pConnectionPoint;
5095      IEVENTSINKOBJ *pIEV;
5096      DWORD dwCookie;
5097      struct oleeventdata *poleev;
5098  
5099      rb_scan_args(argc, argv, "11", &ole, &itf);
5100  
5101      if (!rb_obj_is_kind_of(ole, cWIN32OLE)) {
5102          rb_raise(rb_eTypeError, "1st parametor must be WIN32OLE object.");
5103      }
5104  
5105      if(TYPE(itf) != T_NIL) {
5106          Check_SafeStr(itf);
5107          pitf = StringValuePtr(itf);
5108          hr = find_iid(ole, pitf, &iid, &pTypeInfo);
5109      }
5110      else {
5111          hr = find_default_source(ole, &iid, &pTypeInfo);
5112      }
5113      if (FAILED(hr)) {
5114          ole_raise(hr, rb_eRuntimeError, "not found interface");
5115      }
5116  
5117      OLEData_Get_Struct(ole, pole);
5118      pDispatch = pole->pDispatch;
5119      hr = pDispatch->lpVtbl->QueryInterface(pDispatch,
5120                                             &IID_IConnectionPointContainer,
5121                                             (void**)&pContainer);
5122      if (FAILED(hr)) {
5123          OLE_RELEASE(pTypeInfo);
5124          ole_raise(hr, rb_eRuntimeError,
5125                    "fail to query IConnectionPointContainer");
5126      }
5127  
5128      hr = pContainer->lpVtbl->FindConnectionPoint(pContainer,
5129                                                   &iid,
5130                                                   &pConnectionPoint);
5131      OLE_RELEASE(pContainer);
5132      if (FAILED(hr)) {
5133          OLE_RELEASE(pTypeInfo);
5134          ole_raise(hr, rb_eRuntimeError, "fail to query IConnectionPoint");
5135      }
5136      pIEV = EVENTSINK_Constructor();
5137      pIEV->m_iid = iid;
5138      hr = pConnectionPoint->lpVtbl->Advise(pConnectionPoint,
5139                                            (IUnknown*)pIEV,
5140                                            &dwCookie);
5141      if (FAILED(hr)) {
5142          ole_raise(hr, rb_eRuntimeError, "Advise Error");
5143      }
5144  
5145      Data_Get_Struct(self, struct oleeventdata, poleev);
5146      poleev->pEvent = pIEV;
5147      poleev->pEvent->m_event_id
5148          = NUM2INT(rb_funcall(ary_ole_event, rb_intern("length"), 0));
5149      poleev->pEvent->pConnectionPoint = pConnectionPoint;
5150      poleev->pEvent->pTypeInfo = pTypeInfo;
5151      poleev->pEvent->m_dwCookie = dwCookie;
5152  
5153      rb_ary_push(ary_ole_event, self);
5154      return self;
5155  }
5156  
5157  /*
5158   * WIN32OLE_EVENT.message_loop
5159   * ---
5160   * Translates and dispatches Windows message.
5161   */
5162  static VALUE
5163  fev_s_msg_loop(klass)
5164      VALUE klass;
5165  {
5166      ole_msg_loop();
5167      return Qnil;
5168  }
5169  
5170  
5171  static void
5172  add_event_call_back(obj, data)
5173      VALUE obj;
5174      VALUE data;
5175  {
5176      VALUE ary = rb_ivar_get(obj, id_events);
5177      if (NIL_P(ary) || TYPE(ary) != T_ARRAY) {
5178          ary = rb_ary_new();
5179          rb_ivar_set(obj, id_events, ary);
5180      }
5181      rb_ary_push(ary, data);
5182  }
5183  
5184  static VALUE
5185  ev_on_event(argc, argv, self, is_ary_arg)
5186      int argc;
5187      VALUE *argv;
5188      VALUE self;
5189      VALUE is_ary_arg;
5190  {
5191      VALUE event, args, data;
5192      rb_scan_args(argc, argv, "01*", &event, &args);
5193      if(!NIL_P(event)) {
5194          Check_SafeStr(event);
5195      }
5196      data = rb_ary_new3(4, rb_f_lambda(), event, args, is_ary_arg);
5197      add_event_call_back(self, data);
5198      return Qnil;
5199  }
5200  
5201  /*
5202   * WIN32OLE_EVENT#on_event([event]){...}
5203   * ----
5204   * defines the callback event.
5205   * If argument is omitted, this method defines the callback of all events.
5206   */
5207  static VALUE
5208  fev_on_event(argc, argv, self)
5209      int argc;
5210      VALUE *argv;
5211      VALUE self;
5212  {
5213      return ev_on_event(argc, argv, self, Qfalse);
5214  }
5215  
5216  /*
5217   * WIN32OLE_EVENT#on_event_with_outargs([event]){...}
5218   * ----
5219   * defines the callback of event.
5220   * If you want modify argument in callback, 
5221   * you should use this method instead of WIN32OLE_EVENT#on_event.
5222   */
5223  static VALUE
5224  fev_on_event_with_outargs(argc, argv, self)
5225      int argc;
5226      VALUE *argv;
5227      VALUE self;
5228  {
5229      return ev_on_event(argc, argv, self, Qtrue);
5230  }
5231  
5232  
5233  void
5234  Init_win32ole()
5235  {
5236      ary_ole_event = rb_ary_new();
5237      rb_global_variable(&ary_ole_event);
5238      id_events = rb_intern("events");
5239  
5240      cWIN32OLE = rb_define_class("WIN32OLE", rb_cObject);
5241  
5242      rb_define_singleton_method(cWIN32OLE, "allocate", fole_s_allocate, 0);
5243  
5244      rb_define_method(cWIN32OLE, "initialize", fole_initialize, -1);
5245      rb_enable_super(cWIN32OLE, "initialize");
5246  
5247      rb_define_singleton_method(cWIN32OLE, "connect", fole_s_connect, -1);
5248      rb_define_singleton_method(cWIN32OLE, "const_load", fole_s_const_load, -1);
5249  
5250      rb_define_singleton_method(cWIN32OLE, "ole_free", fole_s_free, 1);
5251      rb_define_singleton_method(cWIN32OLE, "ole_reference_count", fole_s_reference_count, 1);
5252      rb_define_singleton_method(cWIN32OLE, "ole_show_help", fole_s_show_help, -1);
5253  
5254  
5255      rb_define_method(cWIN32OLE, "invoke", fole_invoke, -1);
5256      rb_define_method(cWIN32OLE, "[]", fole_getproperty, 1);
5257      rb_define_method(cWIN32OLE, "_invoke", fole_invoke2, 3);
5258      rb_define_method(cWIN32OLE, "_getproperty", fole_getproperty2, 3);
5259      rb_define_method(cWIN32OLE, "_setproperty", fole_setproperty2, 3);
5260  
5261      /* support propput method that takes an argument */
5262      rb_define_method(cWIN32OLE, "[]=", fole_setproperty, -1); 
5263  
5264      rb_define_method(cWIN32OLE, "ole_free", fole_free, 0);
5265  
5266      rb_define_method(cWIN32OLE, "each", fole_each, 0);
5267      rb_define_method(cWIN32OLE, "method_missing", fole_missing, -1);
5268  
5269      /* support setproperty method much like Perl ;-) */
5270      rb_define_method(cWIN32OLE, "setproperty", fole_setproperty, -1);
5271  
5272      rb_define_method(cWIN32OLE, "ole_methods", fole_methods, 0);
5273      rb_define_method(cWIN32OLE, "ole_get_methods", fole_get_methods, 0);
5274      rb_define_method(cWIN32OLE, "ole_put_methods", fole_put_methods, 0);
5275      rb_define_method(cWIN32OLE, "ole_func_methods", fole_func_methods, 0);
5276  
5277      rb_define_method(cWIN32OLE, "ole_method", fole_method_help, 1);
5278      rb_define_alias(cWIN32OLE, "ole_method_help", "ole_method");
5279      rb_define_method(cWIN32OLE, "ole_obj_help", fole_obj_help, 0);
5280  
5281      rb_define_const(cWIN32OLE, "VERSION", rb_str_new2(WIN32OLE_VERSION));
5282      rb_define_const(cWIN32OLE, "ARGV", rb_ary_new());
5283  
5284      mWIN32OLE_VARIANT = rb_define_module_under(cWIN32OLE, "VARIANT");
5285      rb_define_const(mWIN32OLE_VARIANT, "VT_I2", INT2FIX(VT_I2));
5286      rb_define_const(mWIN32OLE_VARIANT, "VT_I4", INT2FIX(VT_I4));
5287      rb_define_const(mWIN32OLE_VARIANT, "VT_R4", INT2FIX(VT_R4));
5288      rb_define_const(mWIN32OLE_VARIANT, "VT_R8", INT2FIX(VT_R8));
5289      rb_define_const(mWIN32OLE_VARIANT, "VT_CY", INT2FIX(VT_CY));
5290      rb_define_const(mWIN32OLE_VARIANT, "VT_DATE", INT2FIX(VT_DATE));
5291      rb_define_const(mWIN32OLE_VARIANT, "VT_BSTR", INT2FIX(VT_BSTR));
5292      rb_define_const(mWIN32OLE_VARIANT, "VT_USERDEFINED", INT2FIX(VT_USERDEFINED));
5293      rb_define_const(mWIN32OLE_VARIANT, "VT_PTR", INT2FIX(VT_PTR));
5294      rb_define_const(mWIN32OLE_VARIANT, "VT_DISPATCH", INT2FIX(VT_DISPATCH));
5295      rb_define_const(mWIN32OLE_VARIANT, "VT_ERROR", INT2FIX(VT_ERROR));
5296      rb_define_const(mWIN32OLE_VARIANT, "VT_BOOL", INT2FIX(VT_BOOL));
5297      rb_define_const(mWIN32OLE_VARIANT, "VT_VARIANT", INT2FIX(VT_VARIANT));
5298      rb_define_const(mWIN32OLE_VARIANT, "VT_UNKNOWN", INT2FIX(VT_UNKNOWN));
5299      rb_define_const(mWIN32OLE_VARIANT, "VT_I1", INT2FIX(VT_I1));
5300      rb_define_const(mWIN32OLE_VARIANT, "VT_UI1", INT2FIX(VT_UI1));
5301      rb_define_const(mWIN32OLE_VARIANT, "VT_UI2", INT2FIX(VT_UI2));
5302      rb_define_const(mWIN32OLE_VARIANT, "VT_UI4", INT2FIX(VT_UI4));
5303      rb_define_const(mWIN32OLE_VARIANT, "VT_INT", INT2FIX(VT_INT));
5304      rb_define_const(mWIN32OLE_VARIANT, "VT_UINT", INT2FIX(VT_UINT));
5305      rb_define_const(mWIN32OLE_VARIANT, "VT_ARRAY", INT2FIX(VT_ARRAY));
5306      rb_define_const(mWIN32OLE_VARIANT, "VT_BYREF", INT2FIX(VT_BYREF));
5307      
5308      cWIN32OLE_TYPE = rb_define_class("WIN32OLE_TYPE", rb_cObject);
5309      rb_define_singleton_method(cWIN32OLE_TYPE, "ole_classes", foletype_s_ole_classes, 1);
5310      rb_define_singleton_method(cWIN32OLE_TYPE, "typelibs", foletype_s_typelibs, 0);
5311      rb_define_singleton_method(cWIN32OLE_TYPE, "progids", foletype_s_progids, 0);
5312      rb_define_singleton_method(cWIN32OLE_TYPE, "allocate", foletype_s_allocate, 0);
5313      rb_define_method(cWIN32OLE_TYPE, "initialize", foletype_initialize, 2);
5314      rb_enable_super(cWIN32OLE_TYPE, "initialize");
5315      rb_define_method(cWIN32OLE_TYPE, "name", foletype_name, 0);
5316      rb_define_method(cWIN32OLE_TYPE, "ole_type", foletype_ole_type, 0);
5317      rb_define_method(cWIN32OLE_TYPE, "guid", foletype_guid, 0);
5318      rb_define_method(cWIN32OLE_TYPE, "progid", foletype_progid, 0);
5319      rb_define_method(cWIN32OLE_TYPE, "visible?", foletype_visible, 0);
5320  
5321      rb_define_method(cWIN32OLE_TYPE, "major_version", foletype_major_version, 0);
5322      rb_define_method(cWIN32OLE_TYPE, "minor_version", foletype_minor_version, 0);
5323      rb_define_method(cWIN32OLE_TYPE, "typekind", foletype_typekind, 0);
5324      rb_define_method(cWIN32OLE_TYPE, "helpstring", foletype_helpstring, 0);
5325      rb_define_method(cWIN32OLE_TYPE, "src_type", foletype_src_type, 0);
5326      rb_define_method(cWIN32OLE_TYPE, "helpfile", foletype_helpfile, 0);
5327      rb_define_method(cWIN32OLE_TYPE, "helpcontext", foletype_helpcontext, 0);
5328      rb_define_method(cWIN32OLE_TYPE, "variables", foletype_variables, 0);
5329      rb_define_method(cWIN32OLE_TYPE, "ole_methods", foletype_methods, -1);
5330  
5331      cWIN32OLE_VARIABLE = rb_define_class("WIN32OLE_VARIABLE", rb_cObject);
5332      rb_define_method(cWIN32OLE_VARIABLE, "name", folevariable_name, 0);
5333      rb_define_method(cWIN32OLE_VARIABLE, "ole_type", folevariable_ole_type, 0);
5334      rb_define_method(cWIN32OLE_VARIABLE, "ole_type_detail", folevariable_ole_type_detail, 0);
5335      rb_define_method(cWIN32OLE_VARIABLE, "value", folevariable_value, 0);
5336      rb_define_method(cWIN32OLE_VARIABLE, "visible?", folevariable_visible, 0);
5337      rb_define_method(cWIN32OLE_VARIABLE, "variable_kind", folevariable_variable_kind, 0);
5338      rb_define_method(cWIN32OLE_VARIABLE, "varkind", folevariable_varkind, 0);
5339  
5340      cWIN32OLE_METHOD = rb_define_class("WIN32OLE_METHOD", rb_cObject);
5341      rb_define_singleton_method(cWIN32OLE_METHOD, "allocate", folemethod_s_allocate, 0);
5342      rb_define_method(cWIN32OLE_METHOD, "initialize", folemethod_initialize, 2);
5343      rb_enable_super(cWIN32OLE_METHOD, "initialize");
5344  
5345      rb_define_method(cWIN32OLE_METHOD, "name", folemethod_name, 0);
5346      rb_define_method(cWIN32OLE_METHOD, "return_type", folemethod_return_type, 0);
5347      rb_define_method(cWIN32OLE_METHOD, "return_vtype", folemethod_return_vtype, 0);
5348      rb_define_method(cWIN32OLE_METHOD, "return_type_detail", folemethod_return_type_detail, 0);
5349      rb_define_method(cWIN32OLE_METHOD, "invoke_kind", folemethod_invoke_kind, 0);
5350      rb_define_method(cWIN32OLE_METHOD, "invkind", folemethod_invkind, 0);
5351      rb_define_method(cWIN32OLE_METHOD, "visible?", folemethod_visible, 0);
5352      rb_define_method(cWIN32OLE_METHOD, "event?", folemethod_event, 0);
5353      rb_define_method(cWIN32OLE_METHOD, "event_interface", folemethod_event_interface, 0);
5354      rb_define_method(cWIN32OLE_METHOD, "helpstring", folemethod_helpstring, 0);
5355      rb_define_method(cWIN32OLE_METHOD, "helpfile", folemethod_helpfile, 0);
5356      rb_define_method(cWIN32OLE_METHOD, "helpcontext", folemethod_helpcontext, 0);
5357      rb_define_method(cWIN32OLE_METHOD, "dispid", folemethod_dispid, 0);
5358      rb_define_method(cWIN32OLE_METHOD, "offset_vtbl", folemethod_offset_vtbl, 0);
5359      rb_define_method(cWIN32OLE_METHOD, "size_params", folemethod_size_params, 0);
5360      rb_define_method(cWIN32OLE_METHOD, "size_opt_params", folemethod_size_opt_params, 0);
5361      rb_define_method(cWIN32OLE_METHOD, "params", folemethod_params, 0);
5362  
5363      cWIN32OLE_PARAM = rb_define_class("WIN32OLE_PARAM", rb_cObject);
5364      rb_define_method(cWIN32OLE_PARAM, "name", foleparam_name, 0);
5365      rb_define_method(cWIN32OLE_PARAM, "ole_type", foleparam_ole_type, 0);
5366      rb_define_method(cWIN32OLE_PARAM, "ole_type_detail", foleparam_ole_type_detail, 0);
5367      rb_define_method(cWIN32OLE_PARAM, "input?", foleparam_input, 0);
5368      rb_define_method(cWIN32OLE_PARAM, "output?", foleparam_output, 0);
5369      rb_define_method(cWIN32OLE_PARAM, "optional?", foleparam_optional, 0);
5370      rb_define_method(cWIN32OLE_PARAM, "retval?", foleparam_retval, 0);
5371      rb_define_method(cWIN32OLE_PARAM, "default", foleparam_default, 0);
5372   
5373      cWIN32OLE_EVENT = rb_define_class("WIN32OLE_EVENT", rb_cObject);
5374  
5375      rb_define_singleton_method(cWIN32OLE_EVENT, "allocate", fev_s_allocate, 0);
5376      rb_define_method(cWIN32OLE_EVENT, "initialize", fev_initialize, -1);
5377      rb_enable_super(cWIN32OLE_EVENT, "initialize");
5378      rb_define_singleton_method(cWIN32OLE_EVENT, "message_loop", fev_s_msg_loop, 0);
5379  
5380      rb_define_method(cWIN32OLE_EVENT, "on_event", fev_on_event, -1);
5381      rb_define_method(cWIN32OLE_EVENT, "on_event_with_outargs", fev_on_event_with_outargs, -1);
5382      eWIN32OLE_RUNTIME_ERROR = rb_define_class("WIN32OLERuntimeError", rb_eRuntimeError);
5383  }