/* * Copyright(c) 2000 arton * * You may distribute under the terms of either the GNU General Public * License * $Date: 2001/12/11 17:53:03 $ */ #include "stdafx.h" #include "GRScript.h" #include "GlobalRubyScript.h" #include "ItemDisp.h" #include "win32ole.h" #include "RubyObject.h" #include "ScrError.h" ///////////////////////////////////////////////////////////////////////////// // CGlobalRubyScript // This Object is tightly bound to Windows Script Host // HRESULT CGlobalRubyScript::FinalConstruct() { DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &m_hThread, 0, FALSE, DUPLICATE_SAME_ACCESS); HRESULT h = CRScriptCore::FinalConstruct(); // m_idMethodDefined = rb_intern("method_defined?"); return h; } void CGlobalRubyScript::FinalRelease() { if (m_pRubyObject) { m_pRubyObject->ClearEngine(); } CloseHandle(m_hThread); CRScriptCore::FinalRelease(); ruby_finalize(); } void CGlobalRubyScript::MakeScope() { } HRESULT STDMETHODCALLTYPE CGlobalRubyScript::ClearModuleObject( void) { m_pRubyObject = NULL; return S_OK; } IDispatch* CGlobalRubyScript::GetOuterDispatch(IDispatch*) { if (!m_pRubyObject) { m_pRubyObject = new CRubyObject(this, rb_mKernel, true); } return m_pRubyObject; } IDispatch* CGlobalRubyScript::GetGlobalDispatch() { return GetOuterDispatch(NULL); } HRESULT STDMETHODCALLTYPE CGlobalRubyScript::InterruptScriptThread( /* [in] */ SCRIPTTHREADID stidThread, /* [in] */ const EXCEPINFO __RPC_FAR *pexcepinfo, /* [in] */ DWORD dwFlags) { if (stidThread == SCRIPTTHREADID_ALL || stidThread == SCRIPTTHREADID_BASE || stidThread == m_dwThreadID) { SuspendThread(m_hThread); if (m_threadState != SCRIPTTHREADSTATE_NOTINSCRIPT) { InterruptThread(m_hThread); } ResumeThread(m_hThread); } return S_OK; } void CGlobalRubyScript::AddNamedItem(LPCOLESTR pstrName) { int stacktop; if (reinterpret_cast(&stacktop) > s_pStackTop) _alloca(reinterpret_cast(&stacktop) - s_pStackTop); USES_CONVERSION; LPSTR pName = W2A(pstrName); if (islower(*pName)) *pName = toupper(*pName); int cb = lstrlenA(pName); LPSTR pCapitalizedName = pName; if (islower(*pName)) { pCapitalizedName = lstrcpyA(reinterpret_cast(_alloca(cb + 1)), pName); *pCapitalizedName = toupper(*pName); } char* pstr = reinterpret_cast(_alloca(cb * 4 + 64)); if (isupper(*pCapitalizedName)) cb = sprintf(pstr, "$%s = WIN32OLE.attach(\"%s\", %d)\r\n%s = $%s", pName, pName, m_lCookie, pCapitalizedName, pName); else cb = sprintf(pstr, "$%s = WIN32OLE.attach(\"%s\", %d)", pName, pName, m_lCookie); rb_eval_string(pstr); // if (lstrcmpiW(pstrName, L"WScript") == 0) { SetupArgs(pstrName); } } HRESULT CGlobalRubyScript::ParseText(int StartLine, LPCOLESTR pstrCode, LPCOLESTR pstrItemName, EXCEPINFO *pExcepInfo, VARIANT*, DWORD) { int stacktop; if (reinterpret_cast(&stacktop) > s_pStackTop) _alloca(reinterpret_cast(&stacktop) - s_pStackTop); int len = wcslen(pstrCode); int blen = WideCharToMultiByte(GetACP(), 0, pstrCode, len, NULL, 0, NULL, NULL); HRESULT hr = S_OK; TCHAR szScriptFile[_MAX_PATH], szTempPath[_MAX_PATH + 4]; GetTempPath(_MAX_PATH, szTempPath); GetTempFileName(szTempPath, "RSC", 0, szScriptFile); lstrcat(szScriptFile, ".rb"); EnterScript(); TraceOn(); try { int state; DWORD dw; char* pScript = (char*)_alloca(blen + 8); int cbScript = WideCharToMultiByte(GetACP(), 0, pstrCode, len, pScript, blen, NULL, NULL); *(pScript + cbScript) = '\0'; HANDLE h = CreateFile(szScriptFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); WriteFile(h, pScript, cbScript, &dw, NULL); CloseHandle(h); state = 0; LPSTR ps = T2A(szScriptFile); for (LPSTR p = ps; *p; p++) { if (IsDBCSLeadByte(*p)) p++; else if (*p == '\\') *p = '/'; } rb_load_protect(rb_str_new2(ps), 0, &state); if (state) { if (!NIL_P(ruby_errinfo) && rb_obj_is_kind_of(ruby_errinfo, rb_eSystemExit) == Qfalse) { CScrError* pError = new CScrError(ruby_errinfo, pScript); OnScriptError(pError); } } } catch (...) { hr = DISP_E_EXCEPTION; if (pExcepInfo) { memset(pExcepInfo, 0, sizeof(EXCEPINFO)); pExcepInfo->wCode = 0x0201; pExcepInfo->bstrSource = SysAllocString(L"RubyScript"); pExcepInfo->bstrDescription = SysAllocString(L"Exception"); pExcepInfo->scode = DISP_E_EXCEPTION; } } TraceOff(); LeaveScript(); DeleteFile(szScriptFile); return hr; } void CGlobalRubyScript::SetupArgs(LPCOLESTR pstrName) { if (m_fArgInitialized) return; ItemMapIter it = m_mapItem.find(pstrName); if (it == m_mapItem.end()) return; IDispatch* pDisp = (*it).second->GetDispatch(); if (!pDisp) return; static const LPCOLESTR szArguments[] = { L"Arguments", L"ScriptFullName" }; DISPID dispId; DISPPARAMS param = { NULL, NULL, 0, 0, }; VARIANT vResult; VariantInit(&vResult); // Windows Script Host never understand after the second name. HRESULT hr = pDisp->GetIDsOfNames(IID_NULL, const_cast(&szArguments[1]), 1, LOCALE_SYSTEM_DEFAULT, &dispId); if (hr == S_OK) { hr = pDisp->Invoke(dispId, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET | DISPATCH_METHOD, ¶m, &vResult, NULL, NULL); if (hr == S_OK) { USES_CONVERSION; m_strCurrentScript = W2A(vResult.bstrVal); ruby_script(const_cast(m_strCurrentScript.c_str())); VariantClear(&vResult); } } hr = pDisp->GetIDsOfNames(IID_NULL, const_cast(&szArguments[0]), 1, LOCALE_SYSTEM_DEFAULT, &dispId); if (hr == S_OK) { hr = pDisp->Invoke(dispId, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET | DISPATCH_METHOD, ¶m, &vResult, NULL, NULL); if (hr == S_OK) { if (vResult.vt == VT_DISPATCH) { VARIANT vUnk; VariantInit(&vUnk); hr = vResult.pdispVal->Invoke(DISPID_NEWENUM, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET | DISPATCH_METHOD, ¶m, &vUnk, NULL, NULL); if (hr == S_OK) { if (vUnk.vt == VT_UNKNOWN) { FillArgs(vUnk.punkVal); } VariantClear(&vUnk); } } VariantClear(&vResult); } } pDisp->Release(); } void CGlobalRubyScript::FillArgs(IUnknown* pUnk) { CComQIPtr pEnum(pUnk); if (!pEnum) return; std::list listArgs; ULONG Fetched; VARIANT vResult; VariantInit(&vResult); for (; pEnum->Next(1, &vResult, &Fetched) == S_OK; VariantClear(&vResult)) { ExpandArg(vResult.bstrVal, listArgs); } if (listArgs.size() > 0) { char** argv = reinterpret_cast(_alloca(listArgs.size() * sizeof(char*))); char** pt = argv; for (std::list::iterator it = listArgs.begin(); it != listArgs.end(); it++) { *pt++ = const_cast((*it).c_str()); } ruby_set_argv(listArgs.size(), argv); m_fArgInitialized = true; } } void CGlobalRubyScript::ExpandArg(BSTR str, std::list& list) { USES_CONVERSION; LPSTR p = W2A(str); if (wcschr(str, L'?') || wcschr(str, L'*')) { WIN32_FIND_DATA fdata; HANDLE h = FindFirstFileA(p, &fdata); if (h != INVALID_HANDLE_VALUE) { int l = -1; for (LPSTR pn = p; *pn; pn = CharNextA(pn)) { if (*pn == '\\') { l = pn - p; } } l++; char* buff = reinterpret_cast(_alloca(l + sizeof(fdata.cFileName) + 4)); do { if (l > 0) strncpy(buff, p, l); strcpy(buff + l, fdata.cFileName); list.push_back(buff); } while (FindNextFile(h, &fdata)); FindClose(h); return; } } list.push_back(p); }