ext/Win32API/Win32API.c


DEFINITIONS

This source file includes following functions.
  1. Win32API_FreeLibrary
  2. Win32API_initialize
  3. c_m
  4. Win32API_Call
  5. Init_Win32API


   1  /*
   2    Win32API - Ruby Win32 API Import Facility
   3  */
   4  
   5  #if !defined _MSC_VER && !defined NT
   6  #define  WIN32_LEAN_AND_MEAN
   7  #include <windows.h>
   8  #include <stdio.h>
   9  #endif
  10  
  11  #if defined(_MSC_VER)
  12  #if defined(_M_ALPHA)
  13  #ifdef __cplusplus
  14  extern "C" { long __asm(char *,...); };
  15  #else
  16  long __asm(char *,...);
  17  #endif
  18  #pragma intrinsic(__asm)
  19  #endif
  20  #endif
  21  
  22  #define _T_VOID     0
  23  #define _T_NUMBER   1
  24  #define _T_POINTER  2
  25  #define _T_INTEGER  3
  26  
  27  typedef char *ApiPointer(void);
  28  typedef long  ApiNumber(void);
  29  typedef void  ApiVoid(void);
  30  typedef int   ApiInteger(void);
  31  
  32  #include "ruby.h"
  33  
  34  typedef struct {
  35      HANDLE dll;
  36      HANDLE proc;
  37      VALUE dllname;
  38      VALUE import;
  39      VALUE export;
  40  } Win32API;
  41  
  42  static void
  43  Win32API_FreeLibrary(hdll)
  44      HINSTANCE hdll;
  45  {
  46      FreeLibrary(hdll);
  47  }
  48  
  49  static VALUE
  50  Win32API_initialize(self, dllname, proc, import, export)
  51      VALUE self;
  52      VALUE dllname;
  53      VALUE proc;
  54      VALUE import;
  55      VALUE export;
  56  {
  57      HANDLE hproc;
  58      HINSTANCE hdll;
  59      VALUE str;
  60      VALUE a_import;
  61      VALUE *ptr;
  62      char *s;
  63      int i;
  64      int len;
  65      int ex;
  66  
  67      SafeStringValue(dllname);
  68      SafeStringValue(proc);
  69      hdll = LoadLibrary(RSTRING(dllname)->ptr);
  70      if (!hdll)
  71          rb_raise(rb_eRuntimeError, "LoadLibrary: %s\n", RSTRING(dllname)->ptr);
  72      rb_iv_set(self, "__hdll__", Data_Wrap_Struct(self, 0, Win32API_FreeLibrary, hdll));
  73      hproc = GetProcAddress(hdll, RSTRING(proc)->ptr);
  74      if (!hproc) {
  75          str = rb_str_new3(proc);
  76          str = rb_str_cat(str, "A", 1);
  77          hproc = GetProcAddress(hdll, RSTRING(str)->ptr);
  78          if (!hproc)
  79              rb_raise(rb_eRuntimeError, "GetProcAddress: %s or %s\n",
  80                  RSTRING(proc)->ptr, RSTRING(str)->ptr);
  81      }
  82      rb_iv_set(self, "__dll__", UINT2NUM((unsigned long)hdll));
  83      rb_iv_set(self, "__dllname__", dllname);
  84      rb_iv_set(self, "__proc__", UINT2NUM((unsigned long)hproc));
  85  
  86      a_import = rb_ary_new();
  87      switch (TYPE(import)) {
  88        case T_NIL:
  89          break;
  90        case T_ARRAY:
  91          ptr = RARRAY(import)->ptr;
  92          for (i = 0, len = RARRAY(import)->len; i < len; i++) {
  93              SafeStringValue(ptr[i]);
  94              switch (*(char *)RSTRING(ptr[i])->ptr) {
  95                case 'N': case 'n': case 'L': case 'l':
  96                  rb_ary_push(a_import, INT2FIX(_T_NUMBER));
  97                  break;
  98                case 'P': case 'p':
  99                  rb_ary_push(a_import, INT2FIX(_T_POINTER));
 100                  break;
 101                case 'I': case 'i':
 102                  rb_ary_push(a_import, INT2FIX(_T_INTEGER));
 103                  break;
 104              }
 105          }
 106          break;
 107        default:
 108          SafeStringValue(import);
 109          s = RSTRING(import)->ptr;
 110          for (i = 0, len = RSTRING(import)->len; i < len; i++) {
 111              switch (*s++) {
 112                case 'N': case 'n': case 'L': case 'l':
 113                  rb_ary_push(a_import, INT2FIX(_T_NUMBER));
 114                  break;
 115                case 'P': case 'p':
 116                  rb_ary_push(a_import, INT2FIX(_T_POINTER));
 117                  break;
 118                case 'I': case 'i':
 119                  rb_ary_push(a_import, INT2FIX(_T_INTEGER));
 120                  break;
 121              }
 122          }
 123          break;
 124      }
 125      rb_iv_set(self, "__import__", a_import);
 126  
 127      if (NIL_P(export)) {
 128          ex = _T_VOID;
 129      } else {
 130          SafeStringValue(export);
 131          switch (*RSTRING(export)->ptr) {
 132            case 'V': case 'v':
 133              ex = _T_VOID;
 134              break;
 135            case 'N': case 'n': case 'L': case 'l':
 136              ex = _T_NUMBER;
 137              break;
 138            case 'P': case 'p':
 139              ex = _T_POINTER;
 140              break;
 141            case 'I': case 'i':
 142              ex = _T_INTEGER;
 143              break;
 144          }
 145      }
 146      rb_iv_set(self, "__export__", INT2FIX(ex));
 147  
 148      return Qnil;
 149  }
 150  
 151  #ifdef __BORLANDC__ 
 152  int c_m( FARPROC api, long* p )
 153  {
 154    long pp[16];
 155    memcpy( pp, p, 16*sizeof(long) );
 156    return api();
 157  }
 158  #endif
 159  
 160  static VALUE
 161  Win32API_Call(argc, argv, obj)
 162      int argc;
 163      VALUE *argv;
 164      VALUE obj;
 165  {
 166      VALUE args;
 167  
 168      FARPROC ApiFunction;
 169  
 170      ApiPointer  *ApiFunctionPointer;
 171      ApiNumber   *ApiFunctionNumber;
 172      ApiVoid     *ApiFunctionVoid;
 173      ApiInteger  *ApiFunctionInteger;
 174  
 175      long  lParam;
 176      char *pParam;
 177  
 178      VALUE Return;
 179  
 180      VALUE obj_proc;
 181      VALUE obj_import;
 182      VALUE obj_export;
 183      VALUE import_type;
 184      int nimport, timport, texport, i;
 185      int items;
 186      int ret;
 187  #ifdef __BORLANDC__ 
 188      long* ptr;
 189      long p[16];
 190  #endif
 191  
 192      items = rb_scan_args(argc, argv, "0*", &args);
 193  
 194      obj_proc = rb_iv_get(obj, "__proc__");
 195  
 196      ApiFunction = (FARPROC)NUM2ULONG(obj_proc);
 197  
 198      obj_import = rb_iv_get(obj, "__import__");
 199      obj_export = rb_iv_get(obj, "__export__");
 200      nimport = RARRAY(obj_import)->len;
 201      texport = FIX2INT(obj_export);
 202  
 203      if (items != nimport)
 204          rb_raise(rb_eRuntimeError, "Wrong number of parameters: expected %d, got %d.\n",
 205              nimport, items);
 206  
 207      if (0 < nimport) {
 208  #ifdef __BORLANDC__ 
 209         ptr = p + ( nimport - 1 );
 210  #endif
 211          for (i = nimport - 1; 0 <= i; i--) {
 212              VALUE str;
 213              import_type = rb_ary_entry(obj_import, i);
 214              timport = FIX2INT(import_type);
 215              switch (timport) {
 216              case _T_NUMBER:
 217              case _T_INTEGER:
 218                  lParam = NUM2ULONG(rb_ary_entry(args, i));
 219  #if defined(_MSC_VER) || defined(__LCC__)
 220  #if defined(_M_IX86)
 221                  _asm {
 222                      mov     eax, lParam
 223                      push    eax
 224                  }
 225  #elif defined(_M_ALPHA)
 226                  __asm(
 227                          "ldl r0, 0(%0);"
 228                          "stq r0, -(sp);"
 229                          , lParam
 230                  );
 231  #else
 232  #error
 233  #endif
 234  #elif defined(__BORLANDC__)
 235                  *ptr = lParam;
 236                  --ptr;
 237  #elif defined __GNUC__
 238                  asm volatile ("pushl %0" :: "g" (lParam));
 239  #else
 240  #error
 241  #endif
 242                  break;
 243              case _T_POINTER:
 244                  str = rb_ary_entry(args, i);
 245                  if (NIL_P(str)) {
 246                      pParam = 0;
 247                  } else if (FIXNUM_P(str)){
 248                      pParam = (char *)NUM2ULONG(str);
 249                  } else {
 250                      StringValue(str);
 251                      rb_str_modify(str);
 252                      pParam = StringValuePtr(str);
 253                  }
 254  #if defined(_MSC_VER) || defined(__LCC__)
 255  #if defined(_M_IX86)
 256                  _asm {
 257                      mov     eax, pParam
 258                      push    eax
 259                  }
 260  #elif defined(_M_ALPHA)
 261                  __asm(
 262                          "ldl r0, 0(%0);"
 263                          "stq r0, -(sp);"
 264                          , pParam
 265                  );
 266  #else
 267  #error
 268  #endif
 269  #elif defined(__BORLANDC__)
 270                  *ptr = (long)pParam;
 271                  --ptr;
 272  #elif defined __GNUC__
 273                  asm volatile ("pushl %0" :: "g" (pParam));
 274  #else
 275  #error
 276  #endif
 277                  break;
 278              }
 279          }
 280      }
 281  
 282  #if defined __GNUC__
 283      asm volatile ("call *%1" : "=r" (ret) : "g" (ApiFunction));
 284      switch (texport) {
 285      case _T_NUMBER:
 286      case _T_INTEGER:
 287          Return = INT2NUM(ret);
 288          break;
 289      case _T_POINTER:
 290          Return = rb_str_new2((char *)ret);
 291          break;
 292      case _T_VOID:
 293      default:
 294          Return = INT2NUM(0);
 295          break;
 296      }
 297  #else
 298      switch (texport) {
 299      case _T_NUMBER:
 300  #if defined(__BORLANDC__)
 301          Return = INT2NUM((long)c_m(ApiFunction, p));
 302  #else
 303          ApiFunctionNumber = (ApiNumber *) ApiFunction;
 304          Return = INT2NUM(ApiFunctionNumber());
 305  #endif
 306          break;
 307      case _T_POINTER:
 308  #if defined(__BORLANDC__)
 309          Return = rb_str_new2((char *)c_m(ApiFunction, p));
 310  #else
 311          ApiFunctionPointer = (ApiPointer *) ApiFunction;
 312          Return = rb_str_new2((char *)ApiFunctionPointer());
 313  #endif
 314          break;
 315      case _T_INTEGER:
 316  #if defined(__BORLANDC__)
 317          Return = INT2NUM((int)c_m(ApiFunction, p));
 318  #else
 319          ApiFunctionInteger = (ApiInteger *) ApiFunction;
 320          Return = INT2NUM(ApiFunctionInteger());
 321  #endif
 322          break;
 323      case _T_VOID:
 324      default:
 325          ApiFunctionVoid = (ApiVoid *) ApiFunction;
 326          ApiFunctionVoid();
 327          Return = INT2NUM(0);
 328          break;
 329      }
 330  #endif
 331      return Return;
 332  }
 333  
 334  void
 335  Init_Win32API()
 336  {
 337      VALUE cWin32API = rb_define_class("Win32API", rb_cObject);
 338      rb_define_method(cWin32API, "initialize", Win32API_initialize, 4);
 339      rb_define_method(cWin32API, "call", Win32API_Call, -1);
 340      rb_define_alias(cWin32API,  "Call", "call");
 341  }