예제 #1
0
VALUE CRbWin32API::initialize(int argc, VALUE * argv, VALUE obj)
{
	VALUE dllname, proc, _import, _export;
	rb_scan_args(argc, argv, "4", &dllname, &proc, &_import, &_export);

	SafeStringValue(dllname);
	SafeStringValue(proc);
	m_hDll = LoadLibraryA(RSTRING_PTR(dllname));
	if (!m_hDll)
		rb_raise(rb_eSinError, "LoadLibrary: %s\n", RSTRING_PTR(dllname));
	
	HANDLE hproc = (HANDLE)GetProcAddress(m_hDll, RSTRING_PTR(proc));
	if (!hproc) 
	{
		VALUE str = rb_str_new3(proc); str = rb_str_cat(str, "A", 1);
		hproc = (HANDLE)GetProcAddress(m_hDll, RSTRING_PTR(str));
		if (!hproc)
		{
			rb_raise(rb_eSinError, "GetProcAddress: %s or %s\n", RSTRING_PTR(proc), RSTRING_PTR(str));
		}
	}
	rb_iv_set(obj, "__dll__",		rb_uint2inum((u32)m_hDll));
	rb_iv_set(obj, "__dllname__",	dllname);
	rb_iv_set(obj, "__proc__",		rb_uint2inum((u32)hproc));

	VALUE ary_import = SinParseImportArgs(_import);
	if (16 < RARRAY_LEN(ary_import))
	{
		rb_raise(rb_eSinError, "too many parameters: %ld\n", RARRAY_LEN(ary_import));
	}
	rb_iv_set(obj, "__import__", ary_import);

	rb_iv_set(obj, "__export__", INT2FIX(SinParseExportArgs(_export)));

	return obj;
}
예제 #2
0
파일: api.c 프로젝트: twobitfool/win32-api
/*
 * call-seq:
 *    Win32::API.new(function, prototype='V', return='L', dll='kernel32')
 *
 * Creates and returns a new Win32::API object. The +function+ is the name
 * of the Windows function.
 *
 * The +prototype+ is the function prototype for +function+. This can be a
 * string or an array of characters.  The possible valid characters are 'I'
 * (integer), 'L' (long), 'V' (void), 'P' (pointer), 'K' (callback) or 'S'
 * (string).
 *
 * The default is void ('V').
 *
 * Constant (const char*) strings should use 'S'. Pass by reference string
 * buffers should use 'P'. The former is faster, but cannot be modified.
 *
 * The +return+ argument is the return type for the function.  The valid
 * characters are the same as for the +prototype+.  The default is 'L' (long).
 *
 * The +dll+ is the name of the DLL file that the function is exported from.
 * The default is 'kernel32'.
 *
 * If the function cannot be found then an API::Error is raised (a subclass
 * of RuntimeError).
 *
 * Example:
 *
 *    require 'win32/api'
 *    include Win32
 *
 *    buf = 0.chr * 260
 *    len = [buf.length].pack('L')
 *
 *    GetUserName = API.new('GetUserName', 'PP', 'I', 'advapi32')
 *    GetUserName.call(buf, len)
 *
 *    puts buf.strip
 */
static VALUE api_init(int argc, VALUE* argv, VALUE self)
{
   HMODULE hLibrary;
   FARPROC fProc;
   Win32API* ptr;
   int i;
   char* first  = "A";
   char* second = "W";
   VALUE v_proc, v_proto, v_return, v_dll;

   rb_scan_args(argc, argv, "13", &v_proc, &v_proto, &v_return, &v_dll);

   Data_Get_Struct(self, Win32API, ptr);

   // Convert a string prototype to an array of characters
   if(rb_respond_to(v_proto, rb_intern("split")))
      v_proto = rb_str_split(v_proto, "");

   // Convert a nil or empty prototype to 'V' (void) automatically
   if(NIL_P(v_proto) || RARRAY_LEN(v_proto) == 0){
      v_proto = rb_ary_new();
      rb_ary_push(v_proto, rb_str_new2("V"));
   }

   // Set an arbitrary limit of 20 parameters
   if(20 < RARRAY_LEN(v_proto))
      rb_raise(rb_eArgError, "too many parameters: %d\n", RARRAY_LEN(v_proto));

   // Set the default dll to 'kernel32'
   if(NIL_P(v_dll))
      v_dll = rb_str_new2("kernel32");

   // Set the default return type to 'L' (DWORD)
   if(NIL_P(v_return))
      v_return = rb_str_new2("L");

   SafeStringValue(v_dll);
   SafeStringValue(v_proc);

   hLibrary = LoadLibrary(TEXT(RSTRING_PTR(v_dll)));

   // The most likely cause of failure is a bad DLL load path
   if(!hLibrary){
      rb_raise(cAPILoadError, "LoadLibrary() function failed for '%s': %s",
         RSTRING_PTR(v_dll),
         StringError(GetLastError())
      );
   }

   ptr->library = hLibrary;

   /* Attempt to get the function.  If it fails, try again with an 'A'
    * appended.  If that fails, try again with a 'W' appended. If that
    * still fails, raise an API::LoadLibraryError.
    */

   fProc = GetProcAddress(hLibrary, TEXT(RSTRING_PTR(v_proc)));

   // Skip the ANSI and Wide function checks for MSVCRT functions.
   if(!fProc){
      if(strstr(RSTRING_PTR(v_dll), "msvcr")){
         rb_raise(
            cAPILoadError,
            "Unable to load function '%s'",
            RSTRING_PTR(v_proc)
         );
      }
      else{
         VALUE v_ascii = rb_str_new3(v_proc);
         v_ascii = rb_str_cat(v_ascii, first, 1);
         fProc = GetProcAddress(hLibrary, TEXT(RSTRING_PTR(v_ascii)));

         if(!fProc){
            VALUE v_unicode = rb_str_new3(v_proc);
            v_unicode = rb_str_cat(v_unicode, second, 1);
            fProc = GetProcAddress(hLibrary, TEXT(RSTRING_PTR(v_unicode)));

            if(!fProc){
               rb_raise(
                  cAPILoadError,
                  "Unable to load function '%s', '%s', or '%s'",
                  RSTRING_PTR(v_proc),
                  RSTRING_PTR(v_ascii),
                  RSTRING_PTR(v_unicode)
               );
            }
            else{
               rb_iv_set(self, "@effective_function_name", v_unicode);
            }
         }
         else{
            rb_iv_set(self, "@effective_function_name", v_ascii);
         }
      }
   }
   else{
      rb_iv_set(self, "@effective_function_name", v_proc);
   }

   ptr->function = fProc;

   // Push the numeric prototypes onto our int array for later use.

   for(i = 0; i < RARRAY_LEN(v_proto); i++){
      SafeStringValue(RARRAY_PTR(v_proto)[i]);
      switch(*(char*)StringValuePtr(RARRAY_PTR(v_proto)[i])){
         case 'L':
            ptr->prototype[i] = _T_LONG;
            break;
         case 'P':
            ptr->prototype[i] = _T_POINTER;
            break;
         case 'I': case 'B':
            ptr->prototype[i] = _T_INTEGER;
            break;
         case 'V':
            ptr->prototype[i] = _T_VOID;
            break;
         case 'K':
            ptr->prototype[i] = _T_CALLBACK;
            break;
         case 'S':
            ptr->prototype[i] = _T_STRING;
            break;
         default:
            rb_raise(cAPIProtoError, "Illegal prototype '%s'",
               StringValuePtr(RARRAY_PTR(v_proto)[i])
            );
      }
   }

   // Store the return type for later use.

   // Automatically convert empty strings or nil to type void.
   if(NIL_P(v_return) || RSTRING_LEN(v_return) == 0){
      v_return = rb_str_new2("V");
      ptr->return_type = _T_VOID;
   }
   else{
      SafeStringValue(v_return);
      switch(*RSTRING_PTR(v_return)){
         case 'L':
            ptr->return_type = _T_LONG;
            break;
         case 'P':
            ptr->return_type = _T_POINTER;
            break;
         case 'I': case 'B':
            ptr->return_type = _T_INTEGER;
            break;
         case 'V':
            ptr->return_type = _T_VOID;
            break;
         case 'S':
            ptr->return_type = _T_STRING;
            break;
         default:
            rb_raise(cAPIProtoError, "Illegal return type '%s'",
               RSTRING_PTR(v_return)
            );
      }
   }

   rb_iv_set(self, "@dll_name", v_dll);
   rb_iv_set(self, "@function_name", v_proc);
   rb_iv_set(self, "@prototype", v_proto);
   rb_iv_set(self, "@return_type", v_return);

   return self;
}
예제 #3
0
VALUE string_spec_rb_str_new3(VALUE self, VALUE str) {
  return rb_str_new3(str);
}
예제 #4
0
static JSBool set(JSContext* js_context, JSObject* obj, jsval id, jsval* value)
{
  VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
  
  JohnsonContext* context;
  JohnsonRuntime* runtime;
  Data_Get_Struct(ruby_context, JohnsonContext, context);

  VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(JS_GetRuntime(js_context));
  Data_Get_Struct(ruby_runtime, JohnsonRuntime, runtime);

  PREPARE_JROOTS(js_context, 2);
  JROOT(id);
  JROOT_PTR(value);
    
  VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL);

  // Short-circuit for numeric indexes
  
  if (JSVAL_IS_INT(id))
  {
    if (indexable_p(self))
    {
      VALUE idx = INT2FIX(JSVAL_TO_INT(id));
      VALUE val = CONVERT_TO_RUBY(runtime, *value);

      JCHECK(call_ruby_from_js(runtime, NULL, self, rb_intern("[]="), 2, idx, val));
    }

    JRETURN;
  }
  
  VALUE ruby_key = CONVERT_TO_RUBY(runtime, id);
  VALUE ruby_value = CONVERT_TO_RUBY(runtime, *value);

  VALUE setter = rb_str_append(rb_str_new3(ruby_key), rb_str_new2("="));
  VALUE setter_id = rb_intern(StringValueCStr(setter));
  
  VALUE settable_p, indexable_p;
  JCHECK(call_ruby_from_js2(runtime, &settable_p, self, rb_intern("respond_to?"), 1, ID2SYM(setter_id)));
  JCHECK(call_ruby_from_js2(runtime, &indexable_p, self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern("[]="))));
  
  if (settable_p)
  {
    VALUE method, arity;
    JCHECK(call_ruby_from_js2(runtime, &method, self, rb_intern("method"), 1, ID2SYM(setter_id)));
    JCHECK(call_ruby_from_js2(runtime, &arity, method, rb_intern("arity"), 0));

    // if the Ruby object has a 1-arity method named "property=",
    // call it with the converted value
    
    if (NUM2INT(arity) == 1)
      JCHECK(call_ruby_from_js(runtime, NULL, self, setter_id, 1, ruby_value));
  }
  else if(indexable_p)
  {
    // otherwise, if the Ruby object quacks sorta like a hash for assignment
    // (it responds to "[]="), assign it by key
    
    JCHECK(call_ruby_from_js(runtime, NULL, self, rb_intern("[]="), 2, ruby_key, ruby_value));
  }
  else
  {
    JCHECK(call_ruby_from_js(runtime, NULL, Johnson_SpiderMonkey_JSLandProxy(), rb_intern("autovivify"), 
      3, self, ruby_key, ruby_value));
  }

  JRETURN;
}