📄 scriptengine.cpp
字号:
if (excepinfo) { memset(excepinfo, 0, sizeof(EXCEPINFO)); excepinfo->wCode = 1000; excepinfo->bstrSource = TWideString::bstr_from_ansi("fragment"); excepinfo->bstrDescription = TWideString::bstr_from_ansi("Problem while parsing/compiling"); } return NULL; } return frag;}static void free_code_fragment(code_frag *frag){ switch(frag->fragtype) { case FRAG_PROCEDURE: if (frag->ptr) { ScriptProcedureDispatch *disp = (ScriptProcedureDispatch*)frag->ptr; disp->Release(); GIT_revoke(disp->m_gitcookie, (IDispatch*)disp); frag->ptr = NULL; } break; } if (frag->opcodes) destroy_op_array(frag->opcodes); if (frag->functionname) CoTaskMemFree(frag->functionname); CoTaskMemFree(frag->code); CoTaskMemFree(frag);}static code_frag *clone_code_fragment(code_frag *frag, TPHPScriptingEngine *engine TSRMLS_DC){ zval pv; code_frag *newfrag = (code_frag*)CoTaskMemAlloc(sizeof(code_frag)); memset(newfrag, 0, sizeof(code_frag)); newfrag->engine = engine;trace("%08x: CLONED FRAG\n", newfrag); newfrag->persistent = frag->persistent; newfrag->codelen = frag->codelen; newfrag->code = (char*)CoTaskMemAlloc(sizeof(char) * frag->codelen + 1); memcpy(newfrag->code, frag->code, frag->codelen + 1); if (frag->functionname) { int namelen = strlen(frag->functionname); newfrag->functionname = (char*)CoTaskMemAlloc(sizeof(char) * (namelen + 1)); memcpy(newfrag->functionname, frag->functionname, namelen+1); } else { newfrag->functionname = NULL; } newfrag->fragtype = frag->fragtype; newfrag->starting_line = frag->starting_line; pv.type = IS_STRING; pv.value.str.val = newfrag->code; pv.value.str.len = newfrag->codelen; newfrag->opcodes = compile_string(&pv, "fragment" TSRMLS_CC); if (newfrag->opcodes == NULL) { free_code_fragment(newfrag);/* if (excepinfo) { memset(excepinfo, 0, sizeof(EXCEPINFO)); excepinfo->wCode = 1000; excepinfo->bstrSource = TWideString::bstr_from_ansi("fragment"); excepinfo->bstrDescription = TWideString::bstr_from_ansi("Problem while parsing/compiling"); }*/ return NULL; } return newfrag;}static int execute_code_fragment(code_frag *frag, VARIANT *varResult, EXCEPINFO *excepinfo TSRMLS_DC){ zval *retval_ptr = NULL; jmp_buf *orig_jmpbuf; jmp_buf err_trap; if (frag->fragtype == FRAG_MAIN && frag->executed) return 1; orig_jmpbuf = frag->engine->m_err_trap; frag->engine->m_err_trap = &err_trap; if (setjmp(err_trap) == 0) { trace("*** Executing code in thread %08x\n", tsrm_thread_id()); if (frag->functionname) { zval fname; fname.type = IS_STRING; fname.value.str.val = frag->functionname; fname.value.str.len = strlen(frag->functionname); call_user_function_ex(CG(function_table), NULL, &fname, &retval_ptr, 0, NULL, 1, NULL TSRMLS_CC); } else { zend_op_array *active_op_array = EG(active_op_array); zend_function_state *function_state_ptr = EG(function_state_ptr); zval **return_value_ptr_ptr = EG(return_value_ptr_ptr); zend_op **opline_ptr = EG(opline_ptr); EG(return_value_ptr_ptr) = &retval_ptr; EG(active_op_array) = frag->opcodes; EG(no_extensions) = 1; zend_execute(frag->opcodes TSRMLS_CC); EG(no_extensions) = 0; EG(opline_ptr) = opline_ptr; EG(active_op_array) = active_op_array; EG(function_state_ptr) = function_state_ptr; EG(return_value_ptr_ptr) = return_value_ptr_ptr; } } else { trace("*** --> caught error while executing\n"); if (frag->engine->m_in_main) frag->engine->m_stop_main = 1; } frag->engine->m_err_trap = orig_jmpbuf; if (frag->fragtype == FRAG_MAIN) frag->executed = 1; if (varResult) VariantInit(varResult); if (retval_ptr) { if (varResult) php_pval_to_variant(retval_ptr, varResult, CP_ACP TSRMLS_CC); zval_ptr_dtor(&retval_ptr); } return 1;}static void frag_dtor(void *pDest){ code_frag *frag = *(code_frag**)pDest; free_code_fragment(frag);}/* }}} *//* glue for getting back into the OO land */static DWORD WINAPI begin_engine_thread(LPVOID param){ TPHPScriptingEngine *engine = (TPHPScriptingEngine*)param; engine->engine_thread_func(); trace("engine thread has really gone away!\n"); return 0;}TPHPScriptingEngine::TPHPScriptingEngine(){ m_scriptstate = SCRIPTSTATE_UNINITIALIZED; m_pass = NULL; m_in_main = 0; m_stop_main = 0; m_err_trap = NULL; m_lambda_count = 0; m_pass_eng = NULL; m_refcount = 1; m_basethread = tsrm_thread_id(); m_mutex = tsrm_mutex_alloc(); m_sync_thread_msg = CreateEvent(NULL, TRUE, FALSE, NULL); TPHPClassFactory::AddToObjectCount(); m_engine_thread_handle = CreateThread(NULL, 0, begin_engine_thread, this, 0, &m_enginethread); CloseHandle(m_engine_thread_handle);}void activescript_run_ticks(int count){ MSG msg; TSRMLS_FETCH(); TPHPScriptingEngine *engine; trace("ticking %d\n", count); engine = (TPHPScriptingEngine*)SG(server_context);/* PostThreadMessage(engine->m_enginethread, PHPSE_DUMMY_TICK, 0, 0); */ while(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { if (msg.hwnd) { PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); TranslateMessage(&msg); DispatchMessage(&msg); } else { break; } }}/* Synchronize with the engine thread */HRESULT TPHPScriptingEngine::SendThreadMessage(LONG msg, WPARAM wparam, LPARAM lparam){ HRESULT ret; if (m_enginethread == 0) return E_UNEXPECTED; trace("I'm waiting for a mutex in SendThreadMessage\n this=%08x ethread=%08x msg=%08x\n", this, m_enginethread, msg); tsrm_mutex_lock(m_mutex); ResetEvent(m_sync_thread_msg); /* If we call PostThreadMessage before the thread has created the queue, the message * posting fails. MSDN docs recommend the following course of action */ while (!PostThreadMessage(m_enginethread, msg, wparam, lparam)) { Sleep(50); if (m_enginethread == 0) { tsrm_mutex_unlock(m_mutex); trace("breaking out of dodgy busy wait\n"); return E_UNEXPECTED; } } /* Wait for the event object to be signalled. * This is a nice "blocking without blocking" wait; window messages are dispatched * and everything works out quite nicely */ while(1) { DWORD result = MsgWaitForMultipleObjects(1, &m_sync_thread_msg, FALSE, 4000, QS_ALLINPUT); if (result == WAIT_OBJECT_0 + 1) { /* Dispatch some messages */ MSG msg; while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { //trace("dispatching message while waiting\n"); TranslateMessage(&msg); DispatchMessage(&msg); } } else if (result == WAIT_TIMEOUT) { trace("timeout while waiting for thread reply\n"); } else { /* the event was signalled */ break; } } ret = m_sync_thread_ret; ResetEvent(m_sync_thread_msg); tsrm_mutex_unlock(m_mutex); return ret;}TPHPScriptingEngine::~TPHPScriptingEngine(){ trace("\n\n *** Engine Destructor Called\n\n"); if (m_scriptstate != SCRIPTSTATE_UNINITIALIZED && m_scriptstate != SCRIPTSTATE_CLOSED && m_enginethread) Close(); PostThreadMessage(m_enginethread, WM_QUIT, 0, 0); TPHPClassFactory::RemoveFromObjectCount(); tsrm_mutex_free(m_mutex);}/* Set some executor globals and execute a zend_op_array. * The declaration looks wierd because this can be invoked from * zend_hash_apply_with_argument */static int execute_main(void *pDest, void *arg TSRMLS_DC){ code_frag *frag = *(code_frag**)pDest; if (frag->fragtype == FRAG_MAIN && !(frag->engine->m_in_main && frag->engine->m_stop_main)) execute_code_fragment(frag, NULL, NULL TSRMLS_CC); return ZEND_HASH_APPLY_KEEP;}static int clone_frags(void *pDest, void *arg TSRMLS_DC){ code_frag *frag, *src = *(code_frag**)pDest; TPHPScriptingEngine *engine = (TPHPScriptingEngine*)arg; if (src->persistent) { frag = clone_code_fragment(src, engine TSRMLS_CC); if (frag) zend_hash_next_index_insert(&engine->m_frags, &frag, sizeof(code_frag*), NULL); else trace("WARNING: clone failed!\n"); } return ZEND_HASH_APPLY_KEEP;} HRESULT TPHPScriptingEngine::engine_thread_handler(LONG msg, WPARAM wparam, LPARAM lParam, int *handled TSRMLS_DC){ HRESULT ret = S_OK; trace("engine_thread_handler: running in thread %08x, should be %08x msg=%08x this=%08x\n", tsrm_thread_id(), m_enginethread, msg, this); if (handled) *handled = 1; if (m_enginethread == 0) return E_UNEXPECTED; switch(msg) { case PHPSE_ADD_TYPELIB: { struct php_active_script_add_tlb_info *info = (struct php_active_script_add_tlb_info*)lParam; ITypeLib *TypeLib; if (SUCCEEDED(LoadRegTypeLib(*info->rguidTypeLib, (USHORT)info->dwMajor, (USHORT)info->dwMinor, LANG_NEUTRAL, &TypeLib))) { php_COM_load_typelib(TypeLib, CONST_CS TSRMLS_CC); TypeLib->Release(); } } break; case PHPSE_STATE_CHANGE: { /* handle the state change here */ SCRIPTSTATE ss = (SCRIPTSTATE)lParam; int start_running = 0; trace("%08x: DoSetScriptState(current=%s, new=%s)\n", this, scriptstate_to_string(m_scriptstate), scriptstate_to_string(ss)); if (m_scriptstate == SCRIPTSTATE_INITIALIZED && (ss == SCRIPTSTATE_STARTED || ss == SCRIPTSTATE_CONNECTED)) start_running = 1; m_scriptstate = ss; /* inform host/site of the change */ if (m_pass_eng) m_pass_eng->OnStateChange(m_scriptstate); if (start_running) { /* run "main()", as described in the docs */ if (m_pass_eng) m_pass_eng->OnEnterScript(); trace("%08x: apply execute main to m_frags\n", this); m_in_main = 1; m_stop_main = 0; zend_hash_apply_with_argument(&m_frags, execute_main, this TSRMLS_CC); m_in_main = 0; trace("%08x: --- done execute main\n", this); if (m_pass_eng) m_pass_eng->OnLeaveScript(); /* docs are a bit ambiguous here, but it appears that we should * inform the host that the main script execution has completed, * and also what the return value is */ VARIANT varRes; VariantInit(&varRes); if (m_pass_eng) m_pass_eng->OnScriptTerminate(&varRes, NULL); /* m_scriptstate = SCRIPTSTATE_INITIALIZED; if (m_pass_eng) m_pass_eng->OnStateChange(m_scriptstate); */ } } break; case PHPSE_INIT_NEW: { /* Prepare PHP/ZE for use */ trace("%08x: m_frags : INIT NEW\n", this); zend_hash_init(&m_frags, 0, NULL, frag_dtor, TRUE); SG(options) |= SAPI_OPTION_NO_CHDIR; SG(server_context) = this; /* override the default PHP error callback */ zend_error_cb = activescript_error_handler; zend_alter_ini_entry("register_argc_argv", 19, "1", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE); zend_alter_ini_entry("html_errors", 12, "0", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE); zend_alter_ini_entry("implicit_flush", 15, "1", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE); zend_alter_ini_entry("max_execution_time", 19, "0", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE); php_request_startup(TSRMLS_C); PG(during_request_startup) = 0; trace("\n\n *** ticks func at %08x %08x ***\n\n\n", activescript_run_ticks, &activescript_run_ticks);// php_add_tick_function(activescript_run_ticks); } break; case PHPSE_CLOSE: { /* Close things down */ trace("%08x: m_frags : CLOSE/DESTROY\n", this); m_scriptstate = SCRIPTSTATE_CLOSED; if (m_pass_eng) { m_pass_eng->OnStateChange(m_scriptstate); trace("%08x: release site from this side\n", this); m_pass_eng->Release(); m_pass_eng = NULL; } zend_hash_destroy(&m_frags); php_request_shutdown(NULL); break; } break; case PHPSE_CLONE: { /* Clone the engine state. This is semantically equal to serializing all * the parsed code from the source and unserializing it in the dest (this). * IE doesn't appear to use it, but Windows Script Host does. I'd expect * ASP/ASP.NET to do so also. * * FIXME: Probably won't work with IActiveScriptParseProcedure scriplets * */ TPHPScriptingEngine *src = (TPHPScriptingEngine*)lParam; trace("%08x: m_frags : CLONE\n", this); zend_hash_apply_with_argument(&src->m_frags, clone_frags, this TSRMLS_CC); } break; case PHPSE_ADD_SCRIPTLET: { /* Parse/compile a chunk of script that will act as an event handler. * If the host supports IActiveScriptParseProcedure, this code will * not be called. * The docs are (typically) vague: AFAICT, once the code has been * compiled, we are supposed to arrange for an IConnectionPoint * advisory connection to the item/subitem, once the script * moves into SCRIPTSTATE_CONNECTED. * That's a lot of work! * * FIXME: this is currently almost useless * */ struct php_active_script_add_scriptlet_info *info = (struct php_active_script_add_scriptlet_info*)lParam; TWideString default_name(info->pstrDefaultName), code(info->pstrCode), item_name(info->pstrItemName), sub_item_name(info->pstrSubItemName), event_name(info->pstrEventName), delimiter(info->pstrDelimiter); /* lets invent a function name for the scriptlet */ char sname[256]; /* should check if the name is already used! */ if (info->pstrDefaultName) strcpy(sname, default_name.ansi_string()); else { sname[0] = 0; strcat(sname, "__");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -