📄 scriptengine.cpp
字号:
if (info->pstrItemName) { strcat(sname, item_name.ansi_string()); strcat(sname, "_"); } if (info->pstrSubItemName) { strcat(sname, sub_item_name.ansi_string()); strcat(sname, "_"); } if (info->pstrEventName) strcat(sname, event_name.ansi_string()); } trace("%08x: AddScriptlet:\n state=%s\n name=%s\n code=%s\n item=%s\n subitem=%s\n event=%s\n delim=%s\n line=%d\n", this, scriptstate_to_string(m_scriptstate), default_name.safe_ansi_string(), code.safe_ansi_string(), item_name.safe_ansi_string(), sub_item_name.safe_ansi_string(), event_name.safe_ansi_string(), delimiter.safe_ansi_string(), info->ulStartingLineNumber); code_frag *frag = compile_code_fragment( FRAG_SCRIPTLET, sname, info->pstrCode, info->ulStartingLineNumber, info->pexcepinfo, this TSRMLS_CC); if (frag) { frag->persistent = (info->dwFlags & SCRIPTTEXT_ISPERSISTENT); zend_hash_next_index_insert(&m_frags, &frag, sizeof(code_frag*), NULL); /* ScriptProcedureDispatch *disp = new ScriptProcedureDispatch; disp->AddRef(); disp->m_frag = frag; disp->m_procflags = info->dwFlags; disp->m_engine = this; frag->ptr = disp; *info->ppdisp = disp; */ ret = S_OK; } else { ret = DISP_E_EXCEPTION; } *info->pbstrName = TWideString::bstr_from_ansi(sname); trace("%08x: done with scriptlet %s\n", this, sname); } break; case PHPSE_GET_DISPATCH: { struct php_active_script_get_dispatch_info *info = (struct php_active_script_get_dispatch_info *)lParam; IDispatch *disp = NULL; if (info->pstrItemName != NULL) { zval **tmp; /* use this rather than php_OLECHAR_to_char because we want to avoid emalloc here */ TWideString itemname(info->pstrItemName); /* Get that item from the global namespace. * If it is an object, export it as a dispatchable object. * */ if (zend_hash_find(&EG(symbol_table), itemname.ansi_string(), itemname.ansi_len() + 1, (void**)&tmp) == SUCCESS) { if (Z_TYPE_PP(tmp) == IS_OBJECT) { /* FIXME: if this causes an allocation (emalloc) and we are * not in the engine thread, things could get ugly!!! */ disp = php_COM_export_object(*tmp TSRMLS_CC); } } } else { /* This object represents PHP global namespace */ disp = (IDispatch*) new ScriptDispatch; } if (disp) { ret = GIT_put(disp, IID_IDispatch, &info->dispatch); disp->Release(); } else { ret = S_FALSE; } } break; case PHPSE_ADD_NAMED_ITEM: { /* The Host uses this to add objects to the global namespace. * Some objects are intended to have their child properties * globally visible, so we add those to the global namespace too. * */ struct php_active_script_add_named_item_info *info = (struct php_active_script_add_named_item_info *)lParam; TWideString name(info->pstrName); IDispatch *disp; if (SUCCEEDED(GIT_get(info->marshal, IID_IDispatch, (void**)&disp))) add_to_global_namespace(disp, info->dwFlags, name.ansi_string() TSRMLS_CC); } break; case PHPSE_SET_SITE: { if (m_pass_eng) { m_pass_eng->Release(); m_pass_eng = NULL; } if (lParam) GIT_get(lParam, IID_IActiveScriptSite, (void**)&m_pass_eng); trace("%08x: site (engine-side) is now %08x (base=%08x)\n", this, m_pass_eng, m_pass); } break; case PHPSE_EXEC_PROC: { ScriptProcedureDispatch *disp = (ScriptProcedureDispatch *)lParam; execute_code_fragment(disp->m_frag, NULL, NULL TSRMLS_CC); } break; case PHPSE_PARSE_PROC: { /* This is the IActiveScriptParseProcedure implementation. * IE uses this to request for an IDispatch that it will invoke in * response to some event, and tells us the code that it wants to * run. * We compile the code and pass it back a dispatch object. * The object will then serialize access to the engine thread and * execute the opcodes */ struct php_active_script_parse_proc_info *info = (struct php_active_script_parse_proc_info*)lParam; TWideString formal_params(info->pstrFormalParams), procedure_name(info->pstrProcedureName), item_name(info->pstrItemName), delimiter(info->pstrDelimiter); trace("%08x: ParseProc:\n state=%s\nparams=%s\nproc=%s\nitem=%s\n delim=%s\n line=%d\n", this, scriptstate_to_string(m_scriptstate), formal_params.ansi_string(), procedure_name.ansi_string(), item_name.safe_ansi_string(), delimiter.safe_ansi_string(), info->ulStartingLineNumber); code_frag *frag = compile_code_fragment( FRAG_PROCEDURE, NULL, info->pstrCode, info->ulStartingLineNumber, NULL, this TSRMLS_CC); if (frag) { frag->persistent = (info->dwFlags & SCRIPTTEXT_ISPERSISTENT); zend_hash_next_index_insert(&m_frags, &frag, sizeof(code_frag*), NULL); ScriptProcedureDispatch *disp = new ScriptProcedureDispatch; disp->m_frag = frag; disp->m_procflags = info->dwFlags; disp->m_engine = this; frag->ptr = disp; info->dispcookie = disp->m_gitcookie; } else { ret = DISP_E_EXCEPTION; } } break; case PHPSE_PARSE_SCRIPT: { struct php_active_script_parse_info *info = (struct php_active_script_parse_info*)lParam; int doexec; TWideString code(info->pstrCode), item_name(info->pstrItemName), delimiter(info->pstrDelimiter); trace("%08x: ParseScriptText:\n state=%s\ncode=%s\n item=%s\n delim=%s\n line=%d\n", this, scriptstate_to_string(m_scriptstate), code.safe_ansi_string(), item_name.safe_ansi_string(), delimiter.safe_ansi_string(), info->ulStartingLineNumber); code_frag *frag = compile_code_fragment( FRAG_MAIN, info->dwFlags & SCRIPTTEXT_ISEXPRESSION ? FRAG_CREATE_FUNC : NULL, info->pstrCode, info->ulStartingLineNumber, info->pexcepinfo, this TSRMLS_CC); doexec = (info->dwFlags & SCRIPTTEXT_ISEXPRESSION) || m_scriptstate == SCRIPTSTATE_STARTED || m_scriptstate == SCRIPTSTATE_CONNECTED || m_scriptstate == SCRIPTSTATE_DISCONNECTED; if (frag) { frag->persistent = (info->dwFlags & SCRIPTTEXT_ISPERSISTENT); ret = S_OK; if (info->dwFlags & SCRIPTTEXT_ISEXPRESSION) { if (m_scriptstate == SCRIPTSTATE_INITIALIZED) { /* not allowed to execute code in this state */ ret = E_UNEXPECTED; doexec = 0; } } if (doexec) { /* execute the code as an expression */ if (!execute_code_fragment(frag, info->pvarResult, info->pexcepinfo TSRMLS_CC)) ret = DISP_E_EXCEPTION; } zend_hash_next_index_insert(&m_frags, &frag, sizeof(code_frag*), NULL); } else { ret = DISP_E_EXCEPTION; } if (info->pvarResult) { VariantInit(info->pvarResult); } } break; default: trace("unhandled message type %08x\n", msg); if (handled) *handled = 0; } return ret;}/* The PHP/Zend state actually lives in this thread */void TPHPScriptingEngine::engine_thread_func(void){ TSRMLS_FETCH(); int handled; int terminated = 0; MSG msg; trace("%08x: engine thread started up!\n", this); CoInitializeEx(0, COINIT_MULTITHREADED); m_tsrm_hack = tsrm_ls; while(!terminated) { DWORD result = MsgWaitForMultipleObjects(0, NULL, FALSE, 4000, QS_ALLINPUT); switch(result) { case WAIT_OBJECT_0: while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { terminated = 1; } else if (msg.hwnd) { TranslateMessage(&msg); DispatchMessage(&msg); } else { handled = 1; m_sync_thread_ret = engine_thread_handler(msg.message, msg.wParam, msg.lParam, &handled TSRMLS_CC); if (handled) SetEvent(m_sync_thread_msg); } } break; case WAIT_TIMEOUT: trace("thread wait timed out\n"); break; default: trace("some strange value\n"); } } #if 0 while(GetMessage(&msg, NULL, 0, 0)) { if (msg.message == WM_QUIT) break; handled = 1; m_sync_thread_ret = engine_thread_handler(msg.message, msg.wParam, msg.lParam, &handled TSRMLS_CC); if (handled) SetEvent(m_sync_thread_msg); } trace("%08x: engine thread exiting!!!!!\n", this);#endif m_enginethread = 0; CoUninitialize();}/* Only call this in the context of the engine thread, or you'll be sorry. * * When SCRIPTITEM_GLOBALMEMBERS is set, we're only adding COM objects to the namespace. * We could add *all* properties, but I don't like this idea; what if the value changes * while the page is running? We'd be left with stale data. * */void TPHPScriptingEngine::add_to_global_namespace(IDispatch *disp, DWORD flags, char *name TSRMLS_DC){ zval *val; ITypeInfo *typ; int i; unsigned int namelen; FUNCDESC *func; BSTR funcname; TYPEATTR *attr; DISPPARAMS dispparams; VARIANT vres; ITypeInfo *rettyp; TYPEATTR *retattr;trace("Add %s to global namespace\n", name); val = php_COM_object_from_dispatch(disp, NULL TSRMLS_CC); if (val == NULL) { disp->Release(); return; } ZEND_SET_SYMBOL(&EG(symbol_table), name, val); if (flags & SCRIPTITEM_GLOBALMEMBERS == 0) { disp->Release(); return; } /* Enumerate properties and add those too */ if (FAILED(disp->GetTypeInfo(0, 0, &typ))) { disp->Release(); return; } if (SUCCEEDED(typ->GetTypeAttr(&attr))) { for (i = 0; i < attr->cFuncs; i++) { if (FAILED(typ->GetFuncDesc(i, &func))) continue; /* Look at it's type */ if (func->invkind == INVOKE_PROPERTYGET && VT_PTR == func->elemdescFunc.tdesc.vt && VT_USERDEFINED == func->elemdescFunc.tdesc.lptdesc->vt && SUCCEEDED(typ->GetRefTypeInfo(func->elemdescFunc.tdesc.lptdesc->hreftype, &rettyp))) { if (SUCCEEDED(rettyp->GetTypeAttr(&retattr))) { if (retattr->typekind == TKIND_DISPATCH) { /* It's dispatchable */ /* get the value */ dispparams.cArgs = 0; dispparams.cNamedArgs = 0; VariantInit(&vres); if (SUCCEEDED(disp->Invoke(func->memid, IID_NULL, 0, func->invkind, &dispparams, &vres, NULL, NULL))) { /* Get it's dispatch */ IDispatch *sub = NULL; if (V_VT(&vres) == VT_UNKNOWN) V_UNKNOWN(&vres)->QueryInterface(IID_IDispatch, (void**)&sub); else if (V_VT(&vres) == VT_DISPATCH) sub = V_DISPATCH(&vres); if (sub) { /* find out it's name */ typ->GetDocumentation(func->memid, &funcname, NULL, NULL, NULL); name = php_OLECHAR_to_char(funcname, &namelen, CP_ACP TSRMLS_CC); /* add to namespace */ zval *subval = php_COM_object_from_dispatch(sub, NULL TSRMLS_CC); if (subval) { ZEND_SET_SYMBOL(&EG(symbol_table), name, subval); } efree(name); SysFreeString(funcname); } VariantClear(&vres); } } rettyp->ReleaseTypeAttr(retattr); } rettyp->Release(); } typ->ReleaseFuncDesc(func); } typ->ReleaseTypeAttr(attr); } disp->Release();}STDMETHODIMP_(DWORD) TPHPScriptingEngine::AddRef(void){ return InterlockedIncrement(const_cast<long*> (&m_refcount));}STDMETHODIMP_(DWORD) TPHPScriptingEngine::Release(void){ DWORD ret = InterlockedDecrement(const_cast<long*> (&m_refcount)); if (ret == 0) { trace("%08x: Release: zero refcount, destroy the engine!\n", this); delete this; } return ret;}STDMETHODIMP TPHPScriptingEngine::QueryInterface(REFIID iid, void **ppvObject){ *ppvObject = NULL; if (IsEqualGUID(IID_IActiveScript, iid)) { *ppvObject = (IActiveScript*)this; } else if (IsEqualGUID(IID_IActiveScriptParse, iid)) { *ppvObject = (IActiveScriptParse*)this; } else if (IsEqualGUID(IID_IActiveScriptParseProcedure, iid)) { *ppvObject = (IActiveScriptParseProcedure*)this; } else if (IsEqualGUID(IID_IUnknown, iid)) { *ppvObject = this; } else { LPOLESTR guidw; StringFromCLSID(iid, &guidw); { TWideString guid(guidw); trace("%08x: QueryInterface for unsupported %s\n", this, guid.ansi_string()); } CoTaskMemFree(guidw); } if (*ppvObject) { AddRef(); return S_OK; } return E_NOINTERFACE;}/* This is called by the host to set the scrite site. * It also defines the base thread. */STDMETHODIMP TPHPScriptingEngine::SetScriptSite(IActiveScriptSite *pass){ TSRMLS_FETCH(); tsrm_mutex_lock(m_mutex); trace("%08x: -----> Base thread is %08x\n", this, tsrm_thread_id()); if (m_pass) { m_pass->Release(); m_pass = NULL; SEND_THREAD_MESSAGE(this, PHPSE_SET_SITE, 0, 0 TSRMLS_CC);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -