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; }
/* * 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; }
VALUE string_spec_rb_str_new3(VALUE self, VALUE str) { return rb_str_new3(str); }
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; }