/* * Copyright(c) 2000 arton * * $Date$ */ #include "stdafx.h" #ifdef _MERGE_PROXYSTUB #include "RScript.h" #else #include "GRScript.h" #endif #include "RScriptCore.h" #include "win32ole.h" #include "Initializer.h" #ifdef __IRubyWrapper_INTERFACE_DEFINED__ #include "RubyWrapper.h" #endif #include "RubyObject.h" ///////////////////////////////////////////////////////////////////////////// // CRubyScript VALUE CRScriptCore::s_valueWin32Ole; VALUE CRScriptCore::s_valueWin32OleEx; VALUE CRScriptCore::s_valueActiveRubyScript; bool CRScriptCore::s_fTrace(false); bool CRScriptCore::s_fRubyize(false); // Helper Functions from Win32Ole /* $Date$ modified for win32ole (ruby) by M.Suketa */ // modified for ActiveScript (ruby) by arton // VALUE __cdecl CRScriptCore::rubyize(VALUE, VALUE v) { bool f; switch (v) { case Qtrue: f = true; break; case Qfalse: f = false; break; default: rb_raise(rb_eTypeError, "not valid value"); break; } #ifdef __IRubyEngine_INTERFACE_DEFINED__ IRubyEngine* pEngine = CRubyWrapper::GetCWrapper()->GetCurrentEngine(); if (!pEngine) return Qnil; pEngine->SetRubyize(f); #else s_fRubyize = f; #endif return v; } void __cdecl CRScriptCore::ole_free(oledata* pole) { ATLTRACE(_("Freeing Win32OleEx Object %08x\n"), pole); if(pole->pDispatch) { #ifdef __IRubyWrapper_INTERFACE_DEFINED__ CRubyWrapper::GetCWrapper()->ReleaseOle(pole); // never call Release, because not explicit addrefed #else pole->pDispatch->Release(); pole->pDispatch = NULL; #endif } } VALUE CRScriptCore::ole_ary_m_entry(VALUE val, long* pid) { VALUE obj = Qnil; int i = 0; obj = val; while(TYPE(obj) == T_ARRAY) { obj = rb_ary_entry(obj, pid[i]); i++; } return obj; } void CRScriptCore::ole_set_safe_array(long n, SAFEARRAY* psa, long* pid, long* pub, VALUE val, long dim, IRubyEngine* pEngine) { if(n < 0) return; VALUE val1; VARIANT var; VariantInit(&var); if(n == dim) { val1 = ole_ary_m_entry(val, pid); ole_val2variant(val1, &var, pEngine); SafeArrayPutElement(psa, pid, &var); } pid[n] += 1; if (pid[n] < pub[n]) { ole_set_safe_array(dim, psa, pid, pub, val, dim, pEngine); } else { pid[n] = 0; ole_set_safe_array(n-1, psa, pid, pub, val, dim, pEngine); } } void CRScriptCore::ole_val2variant(VALUE val, VARIANT* var, IRubyEngine* pEngine) { #ifdef __IRubyWrapper_INTERFACE_DEFINED__ if (pEngine && pEngine->GetRubyize() == S_OK) { pEngine->SetRubyize(false); V_VT(var) = VT_DISPATCH; V_DISPATCH(var) = CRubyObject::CreateRubyObject(pEngine, val); return; } #else if (s_fRubyize) { s_fRubyize = false; V_VT(var) = VT_DISPATCH; V_DISPATCH(var) = CRubyObject::CreateRubyObject(pEngine, val); return; } #endif USES_CONVERSION; oledata *pole; if(rb_obj_is_kind_of(val, s_valueWin32Ole) || rb_obj_is_kind_of(val, s_valueWin32OleEx)) { Data_Get_Struct(val, struct oledata, pole); pole->pDispatch->AddRef(); V_VT(var) = VT_DISPATCH; V_DISPATCH(var) = pole->pDispatch; return; } if (rb_obj_is_kind_of(val, rb_cTime)) { SYSTEMTIME st; ZeroMemory(&st, sizeof(SYSTEMTIME)); st.wYear = (WORD)FIX2INT(rb_funcall(val, rb_intern("year"), 0)); st.wMonth = (WORD)FIX2INT(rb_funcall(val, rb_intern("month"), 0)); st.wDay = (WORD)FIX2INT(rb_funcall(val, rb_intern("mday"), 0)); st.wHour = (WORD)FIX2INT(rb_funcall(val, rb_intern("hour"), 0)); st.wMinute = (WORD)FIX2INT(rb_funcall(val, rb_intern("min"), 0)); st.wSecond = (WORD)FIX2INT(rb_funcall(val, rb_intern("sec"), 0)); V_VT(var) = VT_DATE; SystemTimeToVariantTime(&st, &var->dblVal); return; } ATLTRACE(_T("Type Of val = %08X\n"), TYPE(val)); switch (TYPE(val)) { case T_ARRAY: { long dim(0); int i(0); VALUE val1 = val; while(TYPE(val1) == T_ARRAY) { val1 = rb_ary_entry(val1, 0); dim += 1; } SAFEARRAYBOUND* psab = reinterpret_cast(_alloca(dim * sizeof(SAFEARRAYBOUND))); long* pub = reinterpret_cast(_alloca(dim * sizeof(long))); long* pid = reinterpret_cast(_alloca(dim * sizeof(long))); val1 = val; i = 0; while(TYPE(val1) == T_ARRAY) { psab[i].cElements = RARRAY(val1)->len; psab[i].lLbound = 0; pub[i] = psab[i].cElements; pid[i] = 0; i ++; val1 = rb_ary_entry(val1, 0); } /* Create and fill VARIANT array */ SAFEARRAY* psa = SafeArrayCreate(VT_VARIANT, dim, psab); if (psa == NULL) { V_VT(var) = VT_ERROR; V_ERROR(var) = E_OUTOFMEMORY; } else { SafeArrayLock(psa); ole_set_safe_array(dim-1, psa, pid, pub, val, dim-1, pEngine); SafeArrayUnlock(psa); V_VT(var) = VT_VARIANT | VT_ARRAY; V_ARRAY(var) = psa; } break; } case T_STRING: V_VT(var) = VT_BSTR; V_BSTR(var) = SysAllocString(A2W(StringValuePtr(val))); break; case T_FIXNUM: V_VT(var) = VT_I4; V_I4(var) = NUM2INT(val); break; case T_BIGNUM: V_VT(var) = VT_R8; V_R8(var) = rb_big2dbl(val); break; case T_FLOAT: V_VT(var) = VT_R8; V_R8(var) = NUM2DBL(val); break; case T_TRUE: V_VT(var) = VT_BOOL; V_BOOL(var) = VARIANT_TRUE; break; case T_FALSE: V_VT(var) = VT_BOOL; V_BOOL(var) = VARIANT_FALSE; break; case T_NIL: V_VT(var) = VT_ERROR; V_ERROR(var) = DISP_E_PARAMNOTFOUND; break; default: #ifdef __IRubyWrapper_INTERFACE_DEFINED__ if (pEngine) { V_VT(var) = VT_DISPATCH; V_DISPATCH(var) = CRubyObject::CreateRubyObject(pEngine, val); } else { ATLTRACE(_T("Without pEngine, ole_val2variant was called\n")); VariantInit(var); // VT_EMPTY } #else V_VT(var) = VT_DISPATCH; V_DISPATCH(var) = CRubyObject::CreateRubyObject(pEngine, val); #endif break; } } VALUE CRScriptCore::ole_variant2val(VARIANT* pvar, IRubyEngine* pEngine, IServiceProvider* pProv) { USES_CONVERSION; VALUE obj = Qnil; HRESULT hr; while ( V_VT(pvar) == (VT_BYREF | VT_VARIANT) ) pvar = V_VARIANTREF(pvar); if(V_ISARRAY(pvar)) { SAFEARRAY *psa = V_ISBYREF(pvar) ? *V_ARRAYREF(pvar) : V_ARRAY(pvar); long i; long *pID, *pLB, *pUB; VARIANT variant; VALUE val; VALUE val2; int dim = SafeArrayGetDim(psa); VariantInit(&variant); V_VT(&variant) = (V_VT(pvar) & ~VT_ARRAY) | VT_BYREF; pID = reinterpret_cast(_alloca(dim * sizeof(long))); pLB = reinterpret_cast(_alloca(dim * sizeof(long))); pUB = reinterpret_cast(_alloca(dim * sizeof(long))); obj = Qnil; for(i = 0; i < dim; ++i) { SafeArrayGetLBound(psa, i+1, &pLB[i]); SafeArrayGetLBound(psa, i+1, &pID[i]); SafeArrayGetUBound(psa, i+1, &pUB[i]); } hr = SafeArrayLock(psa); if (SUCCEEDED(hr)) { val2 = rb_ary_new(); while (i >= 0) { hr = SafeArrayPtrOfIndex(psa, pID, &V_BYREF(&variant)); if (FAILED(hr)) break; val = ole_variant2val(&variant, pEngine); rb_ary_push(val2, val); for (i = dim-1 ; i >= 0 ; --i) { if (++pID[i] <= pUB[i]) break; pID[i] = pLB[i]; if (i > 0) { if (obj == Qnil) obj = rb_ary_new(); rb_ary_push(obj, val2); val2 = rb_ary_new(); } } } SafeArrayUnlock(psa); } return (obj == Qnil) ? val2 : obj; } switch(V_VT(pvar) & ~VT_BYREF){ case VT_EMPTY: break; case VT_NULL: break; case VT_UI1: if(V_ISBYREF(pvar)) obj = INT2NUM((long)*V_UI1REF(pvar)); else obj = INT2NUM((long)V_UI1(pvar)); break; case VT_I2: if(V_ISBYREF(pvar)) obj = INT2NUM((long)*V_I2REF(pvar)); else obj = INT2NUM((long)V_I2(pvar)); break; case VT_I4: if(V_ISBYREF(pvar)) obj = INT2NUM((long)*V_I4REF(pvar)); else obj = INT2NUM((long)V_I4(pvar)); break; case VT_R4: if(V_ISBYREF(pvar)) obj = rb_float_new(*V_R4REF(pvar)); else obj = rb_float_new(V_R4(pvar)); break; case VT_R8: if(V_ISBYREF(pvar)) obj = rb_float_new(*V_R8REF(pvar)); else obj = rb_float_new(V_R8(pvar)); break; case VT_BSTR: { char *p; LPOLESTR pw; if(V_ISBYREF(pvar)) pw = *V_BSTRREF(pvar); else pw = V_BSTR(pvar); if (!pw) p = ""; else p = W2A(pw); obj = rb_str_new2(p); break; } case VT_ERROR: if(V_ISBYREF(pvar)) obj = INT2NUM(*V_ERRORREF(pvar)); else obj = INT2NUM(V_ERROR(pvar)); break; case VT_BOOL: if (V_ISBYREF(pvar)) obj = (*V_BOOLREF(pvar) ? Qtrue : Qfalse); else obj = (V_BOOL(pvar) ? Qtrue : Qfalse); break; case VT_DISPATCH: { IDispatch *pDispatch; if (V_ISBYREF(pvar)) pDispatch = *V_DISPATCHREF(pvar); else pDispatch = V_DISPATCH(pvar); obj = ole_createWin32OleEx(pDispatch, pEngine, pProv); break; } case VT_UNKNOWN: { /* get IDispatch interface from IUnknown interface */ IUnknown *punk; if (V_ISBYREF(pvar)) punk = *V_UNKNOWNREF(pvar); else punk = V_UNKNOWN(pvar); obj = ole_createWin32OleEx(punk, pEngine, pProv); break; } case VT_DATE: { DATE date; if(V_ISBYREF(pvar)) date = *V_DATEREF(pvar); else date = V_DATE(pvar); SYSTEMTIME st; VariantTimeToSystemTime(date, &st); char szTime[20]; int cb = wsprintfA(szTime, "%4.4d/%02.2d/%02.2d %02.2d:%02.2d:%02.2d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); obj = rb_str_new(szTime, cb); break; } case VT_CY: default: { VARIANT variant; VariantInit(&variant); HRESULT hr = VariantChangeTypeEx(&variant, pvar, LOCALE_SYSTEM_DEFAULT, 0, VT_BSTR); if (hr == S_OK && V_VT(&variant) == VT_BSTR) { char *p = W2A(V_BSTR(&variant)); obj = rb_str_new2(p); } VariantClear(&variant); break; } } return obj; } VALUE CRScriptCore::ole_createWin32OleEx(IUnknown* pUnk, IRubyEngine* pEngine, IServiceProvider* pProv) { VALUE obj = Qnil; if (!pUnk) return obj; #ifdef __IRubyWrapper_INTERFACE_DEFINED__ _ASSERT(pEngine); VALUE module; pEngine->GetModule(&module); CRubyWrapper* pWrapper = CRubyWrapper::GetCWrapper(); IDispatchEx* pDispEx; if (pProv && pUnk->QueryInterface(IID_IDispatchEx, (void**)&pDispEx) == S_OK) { oledataex* polex; obj = Data_Make_Struct(s_valueWin32OleEx, struct oledataex, 0, (void(*)(void))ole_free, polex); polex->pDispatchEx = pDispEx; polex->pServiceProvider = pProv; polex->pEngine = pEngine; pWrapper->AddOle(module, polex); return obj; } #endif IDispatch *pDispatch; if (pUnk->QueryInterface(IID_IDispatch, (void **)&pDispatch) == S_OK) { struct oledataex *pole; obj = Data_Make_Struct(s_valueWin32OleEx, struct oledataex, 0, (void(*)(void))ole_free,pole); pole->pDispatch = pDispatch; pole->pEngine = pEngine; #ifdef __IRubyWrapper_INTERFACE_DEFINED__ pWrapper->AddOle(module, pole); #endif } return obj; } VALUE CRScriptCore::ole_hresult2msg(HRESULT hr) { VALUE msg = Qnil; char *p_msg; DWORD dwCount; dwCount = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, hr, LOCALE_SYSTEM_DEFAULT, (LPTSTR)&p_msg, 0, NULL); if (dwCount > 0) { /* remove dots and CRs/LFs */ while (dwCount > 0 && (p_msg[dwCount-1] < ' ' || p_msg[dwCount-1] == '.')) { p_msg[--dwCount] = '\0'; } if (p_msg[0] != '\0') { msg = rb_str_new2(p_msg); } } return msg; } VALUE CRScriptCore::ole_excepinfo2msg(EXCEPINFO* pExInfo) { USES_CONVERSION; char error_code[40]; char *pSource = NULL; char *pDescription = NULL; VALUE error_msg; if(pExInfo->pfnDeferredFillIn != NULL) { (*pExInfo->pfnDeferredFillIn)(pExInfo); } if (pExInfo->bstrSource != NULL) { pSource = W2A(pExInfo->bstrSource); SysFreeString(pExInfo->bstrSource); } if (pExInfo->bstrDescription != NULL) { pDescription = W2A(pExInfo->bstrDescription); SysFreeString(pExInfo->bstrDescription); } if(pExInfo->wCode == 0) { sprintf(error_code, "\n OLE rb_compile_error:%lX in ", pExInfo->scode); } else{ sprintf(error_code, "\n OLE rb_compile_error:%u in ", pExInfo->wCode); } error_msg = rb_str_new2(error_code); if(pSource != NULL) { rb_str_cat(error_msg, pSource, strlen(pSource)); } else { rb_str_cat(error_msg, "", 9); } rb_str_cat(error_msg, "\n ", 5); if(pDescription != NULL) { rb_str_cat(error_msg, pDescription, strlen(pDescription)); } else { rb_str_cat(error_msg, "", 16); } if (pExInfo->bstrHelpFile != NULL) { SysFreeString(pExInfo->bstrHelpFile); } return error_msg; } void CRScriptCore::ole_raise(HRESULT hr, VALUE ecs, LPCSTR p_msg) { VALUE err_msg; err_msg = ole_hresult2msg(hr); if(err_msg != Qnil) { rb_raise(ecs, "%s\n%s", p_msg, StringValuePtr(err_msg)); } else { rb_raise(ecs, "%s", p_msg); } } // // Check Newly Create Object is safe or not. // VALUE __cdecl CRScriptCore::fole_s_new(int argc, VALUE* argv, VALUE self) { VALUE err_msg, svr_name, host_name; CLSID clsid; IDispatch *pDispatch = NULL; IDispatchEx *pDispatchEx = NULL; VALUE obj; rb_scan_args(argc, argv, "11", &svr_name, &host_name); USES_CONVERSION; /* get CLSID from OLE server name */ LPOLESTR pBuf = A2W(StringValuePtr(svr_name)); HRESULT hr = CLSIDFromProgID(pBuf, &clsid); if(hr != S_OK) { err_msg = rb_str_new2("Unknown OLE server : "); rb_str_concat(err_msg, svr_name); ole_raise(hr, rb_eRuntimeError, StringValuePtr(err_msg)); } #ifdef __IRubyWrapper_INTERFACE_DEFINED__ CRubyWrapper* pWrapper = CRubyWrapper::GetCWrapper(); IRubyEngine* pEngine = pWrapper->GetCurrentEngine(); if (pEngine) { HRESULT hr = pEngine->CheckActiveXIsSafety(clsid); if (hr != S_OK) { err_msg = rb_str_new2("Running ActiveX is disallowed : "); rb_str_concat(err_msg, svr_name); ole_raise(hr, rb_eRuntimeError, StringValuePtr(err_msg)); } } #endif /* get IDispatch interface */ #ifdef __IRubyWrapper_INTERFACE_DEFINED__ if (pEngine) { IUnknown* pUnk = NULL; LPWSTR psz; if (host_name == Qnil) psz = NULL; else psz = A2W(StringValuePtr(host_name)); hr = pEngine->CreateObject(clsid, psz, IID_IUnknown, &pUnk); if (hr == S_OK) { hr = pUnk->QueryInterface(IID_IDispatchEx, (void**)&pDispatchEx); if (hr != S_OK) { pDispatchEx = NULL; hr = pUnk->QueryInterface(IID_IDispatch, (void**)&pDispatch); } pUnk->Release(); } } else { #endif MULTI_QI mqi; mqi.pIID = &IID_IDispatch; mqi.pItf = NULL; COSERVERINFO svrInfo; if (host_name != Qnil) { memset(&svrInfo, 0, sizeof(COSERVERINFO)); svrInfo.pwszName = A2W(StringValuePtr(host_name)); hr = CoCreateInstanceEx(clsid, NULL, CLSCTX_REMOTE_SERVER, &svrInfo, 1, &mqi); } else { hr = CoCreateInstanceEx(clsid, NULL, CLSCTX_SERVER, NULL, 1, &mqi); } if (hr == S_OK) { hr = mqi.hr; pDispatch = reinterpret_cast(mqi.pItf); } #ifdef __IRubyWrapper_INTERFACE_DEFINED__ } #endif if(FAILED(hr) || (!pDispatch && !pDispatchEx)) { err_msg = rb_str_new2("Fail to create WIN32OLE object from "); rb_str_concat(err_msg, svr_name); ole_raise(hr, rb_eRuntimeError, StringValuePtr(err_msg)); } /* create WIN32OLE or WIN32OLEEX object */ oledataex *pole; #ifdef __IRubyWrapper_INTERFACE_DEFINED__ obj = Data_Make_Struct(self, oledataex, 0, (void(*)(void))ole_free, pole); if (pDispatchEx) { pole->pDispatchEx = pDispatchEx; } else { pole->pDispatch = pDispatch; } if (pEngine) { VALUE module; pEngine->GetModule(&module); pWrapper->AddOle(module, pole); pole->pEngine = pEngine; if (pDispatchEx) { IServiceProvider* p; if (pEngine->QueryInterface(IID_IServiceProvider, (void**)&p) == S_OK) { pole->pServiceProvider = p; // Release because the extent of this object is same as the engine. p->Release(); } } } #else obj = Data_Make_Struct(s_valueWin32OleEx, struct oledataex,0,(void(*)(void))ole_free,pole); pole->pDispatch = pDispatch; #endif return obj; } VALUE __cdecl CRScriptCore::fole_s_connect(VALUE self, VALUE svr_name) { if (ruby_safe_level >= 3) { rb_raise(rb_eSecurityError, "Connecting ActiveX is disallowed."); } CLSID clsid; IDispatch *pDispatch; LPWSTR pDispName = NULL; IUnknown *pUnknown; VALUE obj; VALUE err_msg; HRESULT hr; USES_CONVERSION; // Check New moniker if (strncmp(StringValuePtr(svr_name), "new:", 4) == 0) { pDispName = A2W(StringValuePtr(svr_name)); } else if (strncmp(StringValuePtr(svr_name), "objref:", 7) == 0) { pDispName = A2W(StringValuePtr(svr_name)); } else { /* get CLSID from OLE server name */ LPOLESTR pBuf = A2W(StringValuePtr(svr_name)); hr = CLSIDFromProgID(pBuf, &clsid); if(hr != S_OK) { if (hr != S_OK) { err_msg = rb_str_new2("Unknown OLE server : "); rb_str_concat(err_msg, svr_name); ole_raise(hr, rb_eRuntimeError, StringValuePtr(err_msg)); } } } #ifdef __IRubyWrapper_INTERFACE_DEFINED__ IRubyEngine* pEngine = CRubyWrapper::GetCWrapper()->GetCurrentEngine(); if (pEngine) { hr = pEngine->CheckActiveXIsSafety(clsid); if (hr != S_OK) { err_msg = rb_str_new2("Running ActiveX is disallowed : "); rb_str_concat(err_msg, svr_name); ole_raise(hr, rb_eRuntimeError, StringValuePtr(err_msg)); } } #endif if (pDispName) hr = CoGetObject(pDispName, NULL, IID_IUnknown, (void**)&pUnknown); else hr = GetActiveObject(clsid, 0, &pUnknown); if (FAILED(hr)) { err_msg = rb_str_new2("Not Running OLE server : "); rb_str_concat(err_msg, svr_name); ole_raise(hr, rb_eRuntimeError, StringValuePtr(err_msg)); } #ifdef __IRubyWrapper_INTERFACE_DEFINED__ if (pEngine) { hr = pEngine->CheckInterfaceIsSafety(clsid, pUnknown); if (hr != S_OK) { pUnknown->Release(); err_msg = rb_str_new2("Fail to connect WIN32OLE server : "); rb_str_concat(err_msg, svr_name); ole_raise(hr, rb_eRuntimeError, StringValuePtr(err_msg)); } } else #endif { hr = pUnknown->QueryInterface(IID_IDispatch, (void **)&pDispatch); if(FAILED(hr)) { pUnknown->Release(); err_msg = rb_str_new2("Fail to create WIN32OLE server : "); rb_str_concat(err_msg, svr_name); ole_raise(hr, rb_eRuntimeError, StringValuePtr(err_msg)); } } pUnknown->Release(); /* create WIN32OLE object */ struct oledataex *pole; obj = Data_Make_Struct(s_valueWin32OleEx,struct oledataex,0,(void(*)(void))ole_free,pole); pole->pDispatch = pDispatch; #ifdef __IRubyWrapper_INTERFACE_DEFINED__ pole->pEngine = pEngine; if (pEngine) { VALUE module; pEngine->GetModule(&module); CRubyWrapper::GetCWrapper()->AddOle(module, pole); } #endif return obj; } // // Attach is always allowed because the objects are given by IE itself. // VALUE __cdecl CRScriptCore::foleex_attach(VALUE self, VALUE ItemName, VALUE Cookie) { ATLTRACE(_T("attach %s - %d\n"), StringValuePtr(ItemName), FIX2LONG(Cookie)); CRScriptCore* p = CRScriptCore::GetEngine(FIX2LONG(Cookie)); if (!p) return Qnil; return p->GetOleObject(self, StringValuePtr(ItemName)); } VALUE CRScriptCore::fole_propertyput(VALUE self, VALUE property, VALUE value) { oledataex *pole; unsigned int index; HRESULT hr; EXCEPINFO excepinfo; DISPID dispID = DISPID_VALUE; DISPID dispIDParam = DISPID_PROPERTYPUT; USHORT wFlags = DISPATCH_PROPERTYPUT; DISPPARAMS dispParams; VARIANTARG propertyValue[2]; LCID lcid = LOCALE_SYSTEM_DEFAULT; dispParams.rgdispidNamedArgs = &dispIDParam; dispParams.rgvarg = propertyValue; dispParams.cNamedArgs = 1; dispParams.cArgs = 1; VariantInit(&propertyValue[0]); VariantInit(&propertyValue[1]); memset(&excepinfo, 0, sizeof(excepinfo)); Data_Get_Struct(self, struct oledataex, pole); /* get ID from property name */ USES_CONVERSION; if (pole->pServiceProvider) { BSTR bstr = SysAllocString(A2W(StringValuePtr(property))); hr = pole->pDispatchEx->GetDispID(bstr, fdexNameCaseSensitive, &dispID); SysFreeString(bstr); } else { LPOLESTR pw = A2W(StringValuePtr(property)); hr = pole->pDispatch->GetIDsOfNames(IID_NULL, &pw, 1, LOCALE_SYSTEM_DEFAULT, &dispID); } if (hr != S_OK) { dispID = DISPID_VALUE; dispParams.cArgs = 2; V_VT(&propertyValue[1]) = VT_BSTR; V_BSTR(&propertyValue[1]) = SysAllocString(A2W(StringValuePtr(property))); } /* set property value */ VARIANT vResult; VariantInit(&vResult); ole_val2variant(value, &propertyValue[0], pole->pEngine); if (pole->pServiceProvider) { hr = pole->pDispatchEx->InvokeEx(dispID, LOCALE_SYSTEM_DEFAULT, wFlags, &dispParams, &vResult, &excepinfo, pole->pServiceProvider); if (hr == S_FALSE) { hr = pole->pDispatchEx->InvokeEx(dispID, LOCALE_SYSTEM_DEFAULT, wFlags, &dispParams, &vResult, &excepinfo, NULL); } } else { UINT ul(0); hr = pole->pDispatch->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, wFlags, &dispParams, &vResult, &excepinfo, &ul); } VariantClear(&vResult); for(index = 0; index < dispParams.cArgs; ++index) VariantClear(&propertyValue[index]); return Qnil; } VALUE CRScriptCore::ole_invoke(int argc, VALUE* argv, VALUE self, WORD wFlags) { ATLTRACE(_T("ole_invoke in thread:%08X\n"), GetCurrentThreadId()); LCID lcid = LOCALE_SYSTEM_DEFAULT; struct oledataex *pole; IServiceProvider* pProv = NULL; HRESULT hr; VALUE cmd; VALUE paramS; VALUE param; VALUE obj; VALUE error_msg; DISPID DispID; DISPPARAMS dp; EXCEPINFO excepinfo; VARIANTARG* prgvarg = NULL; VARIANT result; memset(&excepinfo, 0, sizeof(EXCEPINFO)); VariantInit(&result); dp.rgvarg = NULL; dp.rgdispidNamedArgs = NULL; dp.cNamedArgs = 0; dp.cArgs = 0; rb_scan_args(argc, argv, "1*", &cmd, ¶mS); Data_Get_Struct(self, struct oledataex, pole); /* pick up last argument of method */ param = rb_ary_entry(paramS, argc-2); dp.cArgs = argc - 1; if (dp.cArgs > 0) { dp.rgvarg = reinterpret_cast(_alloca(sizeof(VARIANTARG) * dp.cArgs)); prgvarg = reinterpret_cast(_alloca(sizeof(VARIANTARG) * dp.cArgs)); } /*----------------------------------------------------------- get IDs from method name (or property name) and named args -------------------------------------------------------------*/ USES_CONVERSION; LPOLESTR pwMethodName = A2W(StringValuePtr(cmd)); if (pole->pServiceProvider) { ATLTRACE(_T("Invoke DispatchEx %08\n"), pole->pDispatchEx); BSTR bstr = SysAllocString(pwMethodName); hr = pole->pDispatchEx->GetDispID(bstr, fdexNameCaseSensitive, &DispID); SysFreeString(bstr); } else { hr = pole->pDispatch->GetIDsOfNames(IID_NULL, &pwMethodName, 1, LOCALE_SYSTEM_DEFAULT, &DispID); } if (hr != S_OK) { error_msg = rb_str_new2("Unknown property or method : "); rb_str_concat(error_msg, cmd); ole_raise(hr, rb_eNoMethodError, StringValuePtr(error_msg)); } int nOpt(0); int nArg(0); ITypeInfo* pInfo = NULL; if (pole->pServiceProvider) { hr = pole->pDispatchEx->GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, &pInfo); } else { hr = pole->pDispatch->GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, &pInfo); } if (hr == S_OK) { UINT uIdx; ITypeInfo2* pInfo2; if (pInfo->QueryInterface(IID_ITypeInfo2, (void**)&pInfo2) == S_OK) { if (pInfo2->GetFuncIndexOfMemId(DispID, INVOKE_FUNC, &uIdx) == S_OK) { FUNCDESC* pFuncDesc = NULL; if (pInfo->GetFuncDesc(uIdx, &pFuncDesc) == S_OK) { nOpt = pFuncDesc->cParamsOpt; nArg = pFuncDesc->cParams; pInfo->ReleaseFuncDesc(pFuncDesc); } } pInfo2->Release(); } pInfo->Release(); } if(dp.cArgs > 0) { if (nOpt > 0) nOpt -= (nArg - dp.cArgs); for(int i = 0; i < static_cast(dp.cArgs); i++) { VariantInit(&dp.rgvarg[i]); VariantInit(&prgvarg[i]); param = rb_ary_entry(paramS, dp.cArgs - (i + 1)); ole_val2variant(param, &prgvarg[i], pole->pEngine); if (nOpt > 0) { dp.rgvarg[i] = prgvarg[i]; nOpt--; } else { dp.rgvarg[i].vt = VT_VARIANT | VT_BYREF; dp.rgvarg[i].pvarVal = &prgvarg[i]; } } } VALUE newArg = rb_cvar_get(s_valueWin32Ole, rb_intern("ARGV")); rb_funcall(newArg, rb_intern("clear"), 0); if (pole->pServiceProvider) { hr = pole->pDispatchEx->InvokeEx(DispID, LOCALE_SYSTEM_DEFAULT, wFlags, &dp, &result, &excepinfo, pole->pServiceProvider); if (hr == S_FALSE) { hr = pole->pDispatchEx->InvokeEx(DispID, LOCALE_SYSTEM_DEFAULT, wFlags, &dp, &result, &excepinfo, NULL); } else if (hr == S_OK) { pProv = pole->pServiceProvider; } } else { UINT ul(0); hr = pole->pDispatch->Invoke(DispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, wFlags, &dp, &result, &excepinfo, &ul); } /* clear dispatch parameter */ for(int i = dp.cArgs - 1; i >= 0; i-- ) { rb_ary_push(newArg, ole_variant2val(&prgvarg[i], pole->pEngine, pProv)); VariantClear(&prgvarg[i]); } if (FAILED(hr)) { error_msg = ole_excepinfo2msg(&excepinfo); rb_str_concat(cmd, error_msg); ole_raise(hr, rb_eRuntimeError, StringValuePtr(cmd)); } obj = ole_variant2val(&result, pole->pEngine, pProv); VariantClear(&result); return obj; } VALUE CRScriptCore::foleex_each(VALUE self) { LCID lcid = LOCALE_SYSTEM_DEFAULT; struct oledataex *pole; IServiceProvider* pProv = NULL; unsigned int argErr; EXCEPINFO excepinfo; DISPPARAMS dispParams; VARIANT result, variant; HRESULT hr; IEnumVARIANT *pEnum = NULL; VALUE obj; VariantInit(&result); dispParams.rgvarg = NULL; dispParams.rgdispidNamedArgs = NULL; dispParams.cNamedArgs = 0; dispParams.cArgs = 0; memset(&excepinfo, 0, sizeof(excepinfo)); Data_Get_Struct(self, struct oledataex, pole); hr = pole->pDispatch->Invoke(DISPID_NEWENUM, IID_NULL, lcid, DISPATCH_METHOD | DISPATCH_PROPERTYGET, &dispParams, &result, &excepinfo, &argErr); if (FAILED(hr)) { ole_raise(hr, rb_eRuntimeError, "Fail to get IEnum Interface"); } if (result.vt == VT_UNKNOWN || result.vt == VT_DISPATCH) hr = result.punkVal->QueryInterface(IID_IEnumVARIANT, (void**)&pEnum); if (FAILED(hr) || !pEnum) { VariantClear(&result); ole_raise(hr, rb_eRuntimeError, "Fail to get IEnum Interface"); } VariantInit(&variant); while(pEnum->Next(1, &variant, NULL) == S_OK) { obj = ole_variant2val(&variant, pole->pEngine, pole->pServiceProvider); rb_yield(obj); VariantClear(&variant); VariantInit(&variant); } pEnum->Release(); return Qnil; } VALUE CRScriptCore::foleex_missing(int argc, VALUE* argv, VALUE self) { ID id; char* mname; int n; id = rb_to_id(argv[0]); mname = rb_id2name(id); if(!mname) { rb_raise(rb_eRuntimeError, "Fail : Unknown method or property"); } n = strlen(mname); if(mname[n-1] == '=') { argv[0] = rb_str_new(mname, n-1); return fole_propertyput(self, argv[0], argv[1]); } else { argv[0] = rb_str_new2(mname); return ole_invoke(argc, argv, self, DISPATCH_METHOD|DISPATCH_PROPERTYGET); } } VALUE CRScriptCore::foleex_release(VALUE self) { oledata *pole; Data_Get_Struct(self, struct oledata, pole); #ifdef __IRubyWrapper_INTERFACE_DEFINED__ CRubyWrapper::GetCWrapper()->ReleaseOle(pole); // never call Release, because not explicit addrefed #else pole->pDispatch->Release(); #endif pole->pDispatch = NULL; return Qnil; }