mirror of
https://github.com/php/php-src.git
synced 2026-04-26 01:18:19 +02:00
Use the GIT for inter-thread marshalling.
This commit is contained in:
+183
-129
@@ -27,17 +27,6 @@
|
||||
* running script in the PHP/Zend engine must take place on the engine
|
||||
* thread. Likewise, calling back to the host must take place on the base
|
||||
* thread - the thread that set the script site.
|
||||
*
|
||||
* For talking to the site from engine thread, we use an invisible window:
|
||||
* the window processing is guaranteed to occur in the correct thread,
|
||||
* and the message queue provides a useful synchronization device.
|
||||
*
|
||||
* For talking to the engine from any other thread, the engine thread waits
|
||||
* for messages to arrive at it's message queue. Since the only API for
|
||||
* dealing with thread messages is asynchronous, we use a mutex to ensure
|
||||
* that only one thread can talk to the engine at a time, and an event
|
||||
* object to signal to it that the processing is complete.
|
||||
*
|
||||
* */
|
||||
|
||||
#define _WIN32_DCOM
|
||||
@@ -57,74 +46,11 @@ extern "C" {
|
||||
#include "ext/com/php_COM.h"
|
||||
#include "ext/com/conversion.h"
|
||||
}
|
||||
#include "php_ticks.h"
|
||||
#include "php4as_scriptengine.h"
|
||||
#include "php4as_classfactory.h"
|
||||
#include <objbase.h>
|
||||
|
||||
enum fragtype {
|
||||
FRAG_MAIN,
|
||||
FRAG_SCRIPTLET,
|
||||
FRAG_PROCEDURE
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
enum fragtype fragtype;
|
||||
zend_op_array *opcodes;
|
||||
char *code;
|
||||
int persistent; /* should be retained for Clone */
|
||||
int executed; /* for "main" */
|
||||
char *functionname;
|
||||
unsigned int codelen;
|
||||
unsigned int starting_line;
|
||||
TPHPScriptingEngine *engine;
|
||||
void *ptr;
|
||||
} code_frag;
|
||||
|
||||
#define FRAG_CREATE_FUNC (char*)-1
|
||||
static code_frag *compile_code_fragment(
|
||||
enum fragtype fragtype,
|
||||
char *functionname,
|
||||
LPCOLESTR code,
|
||||
ULONG starting_line,
|
||||
EXCEPINFO *excepinfo,
|
||||
TPHPScriptingEngine *engine
|
||||
TSRMLS_DC);
|
||||
|
||||
static int execute_code_fragment(code_frag *frag,
|
||||
VARIANT *varResult,
|
||||
EXCEPINFO *excepinfo
|
||||
TSRMLS_DC);
|
||||
static void free_code_fragment(code_frag *frag);
|
||||
static code_frag *clone_code_fragment(code_frag *frag, TPHPScriptingEngine *engine TSRMLS_DC);
|
||||
|
||||
/* Magic for handling threading correctly */
|
||||
static inline HRESULT SEND_THREAD_MESSAGE(TPHPScriptingEngine *engine, LONG msg, WPARAM wparam, LPARAM lparam TSRMLS_DC)
|
||||
{
|
||||
if (engine->m_enginethread == 0)
|
||||
return E_UNEXPECTED;
|
||||
if (tsrm_thread_id() == (engine)->m_enginethread)
|
||||
return (engine)->engine_thread_handler((msg), (wparam), (lparam), NULL TSRMLS_CC);
|
||||
return (engine)->SendThreadMessage((msg), (wparam), (lparam));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* {{{ scriptstate_to_string */
|
||||
static const char *scriptstate_to_string(SCRIPTSTATE ss)
|
||||
{
|
||||
switch(ss) {
|
||||
case SCRIPTSTATE_UNINITIALIZED: return "SCRIPTSTATE_UNINITIALIZED";
|
||||
case SCRIPTSTATE_INITIALIZED: return "SCRIPTSTATE_INITIALIZED";
|
||||
case SCRIPTSTATE_STARTED: return "SCRIPTSTATE_STARTED";
|
||||
case SCRIPTSTATE_CONNECTED: return "SCRIPTSTATE_CONNECTED";
|
||||
case SCRIPTSTATE_DISCONNECTED: return "SCRIPTSTATE_DISCONNECTED";
|
||||
case SCRIPTSTATE_CLOSED: return "SCRIPTSTATE_CLOSED";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ trace */
|
||||
static inline void trace(char *fmt, ...)
|
||||
{
|
||||
@@ -142,7 +68,21 @@ static inline void trace(char *fmt, ...)
|
||||
va_end(ap);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ scriptstate_to_string */
|
||||
static const char *scriptstate_to_string(SCRIPTSTATE ss)
|
||||
{
|
||||
switch(ss) {
|
||||
case SCRIPTSTATE_UNINITIALIZED: return "SCRIPTSTATE_UNINITIALIZED";
|
||||
case SCRIPTSTATE_INITIALIZED: return "SCRIPTSTATE_INITIALIZED";
|
||||
case SCRIPTSTATE_STARTED: return "SCRIPTSTATE_STARTED";
|
||||
case SCRIPTSTATE_CONNECTED: return "SCRIPTSTATE_CONNECTED";
|
||||
case SCRIPTSTATE_DISCONNECTED: return "SCRIPTSTATE_DISCONNECTED";
|
||||
case SCRIPTSTATE_CLOSED: return "SCRIPTSTATE_CLOSED";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
/* {{{ TWideString */
|
||||
/* This class helps manipulate strings from OLE.
|
||||
* It does not use emalloc, so it is better suited for passing pointers
|
||||
@@ -226,6 +166,113 @@ class TWideString {
|
||||
};
|
||||
/* }}} */
|
||||
|
||||
/* {{{ code fragment structures */
|
||||
enum fragtype {
|
||||
FRAG_MAIN,
|
||||
FRAG_SCRIPTLET,
|
||||
FRAG_PROCEDURE
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
enum fragtype fragtype;
|
||||
zend_op_array *opcodes;
|
||||
char *code;
|
||||
int persistent; /* should be retained for Clone */
|
||||
int executed; /* for "main" */
|
||||
char *functionname;
|
||||
unsigned int codelen;
|
||||
unsigned int starting_line;
|
||||
TPHPScriptingEngine *engine;
|
||||
void *ptr;
|
||||
} code_frag;
|
||||
|
||||
#define FRAG_CREATE_FUNC (char*)-1
|
||||
static code_frag *compile_code_fragment(
|
||||
enum fragtype fragtype,
|
||||
char *functionname,
|
||||
LPCOLESTR code,
|
||||
ULONG starting_line,
|
||||
EXCEPINFO *excepinfo,
|
||||
TPHPScriptingEngine *engine
|
||||
TSRMLS_DC);
|
||||
|
||||
static int execute_code_fragment(code_frag *frag,
|
||||
VARIANT *varResult,
|
||||
EXCEPINFO *excepinfo
|
||||
TSRMLS_DC);
|
||||
static void free_code_fragment(code_frag *frag);
|
||||
static code_frag *clone_code_fragment(code_frag *frag, TPHPScriptingEngine *engine TSRMLS_DC);
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* Magic for handling threading correctly */
|
||||
static inline HRESULT SEND_THREAD_MESSAGE(TPHPScriptingEngine *engine, LONG msg, WPARAM wparam, LPARAM lparam TSRMLS_DC)
|
||||
{
|
||||
if (engine->m_enginethread == 0)
|
||||
return E_UNEXPECTED;
|
||||
if (tsrm_thread_id() == (engine)->m_enginethread)
|
||||
return (engine)->engine_thread_handler((msg), (wparam), (lparam), NULL TSRMLS_CC);
|
||||
return (engine)->SendThreadMessage((msg), (wparam), (lparam));
|
||||
}
|
||||
|
||||
/* These functions do some magic so that interfaces can be
|
||||
* used across threads without worrying about marshalling
|
||||
* or not marshalling, as appropriate.
|
||||
* Win95 without DCOM 1.1, and NT SP 2 or lower do not have
|
||||
* the GIT; so we emulate the GIT using other means.
|
||||
* If you trace problems back to this code, installing the relevant
|
||||
* SP should solve them.
|
||||
* */
|
||||
static inline HRESULT GIT_get(DWORD cookie, REFIID riid, void **obj)
|
||||
{
|
||||
IGlobalInterfaceTable *git;
|
||||
HRESULT ret;
|
||||
|
||||
if (SUCCEEDED(CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL,
|
||||
CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable,
|
||||
(void**)&git))) {
|
||||
|
||||
ret = git->GetInterfaceFromGlobal(cookie, riid, obj);
|
||||
git->Release();
|
||||
return ret;
|
||||
}
|
||||
return CoGetInterfaceAndReleaseStream((LPSTREAM)cookie, riid, obj);
|
||||
}
|
||||
|
||||
static inline HRESULT GIT_put(IUnknown *unk, REFIID riid, DWORD *cookie)
|
||||
{
|
||||
IGlobalInterfaceTable *git;
|
||||
HRESULT ret;
|
||||
|
||||
if (SUCCEEDED(CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL,
|
||||
CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable,
|
||||
(void**)&git))) {
|
||||
|
||||
ret = git->RegisterInterfaceInGlobal(unk, riid, cookie);
|
||||
git->Release();
|
||||
return ret;
|
||||
}
|
||||
return CoMarshalInterThreadInterfaceInStream(riid, unk, (LPSTREAM*)cookie);
|
||||
}
|
||||
|
||||
static inline HRESULT GIT_revoke(DWORD cookie, IUnknown *unk)
|
||||
{
|
||||
IGlobalInterfaceTable *git;
|
||||
HRESULT ret;
|
||||
|
||||
if (SUCCEEDED(CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL,
|
||||
CLSCTX_INPROC_SERVER, IID_IGlobalInterfaceTable,
|
||||
(void**)&git))) {
|
||||
|
||||
ret = git->RevokeInterfaceFromGlobal(cookie);
|
||||
git->Release();
|
||||
}
|
||||
/* Kill remote clients */
|
||||
return CoDisconnectObject(unk, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* {{{ A generic stupid IDispatch implementation */
|
||||
class IDispatchImpl:
|
||||
public IDispatch
|
||||
@@ -325,6 +372,7 @@ public:
|
||||
code_frag *m_frag;
|
||||
DWORD m_procflags;
|
||||
TPHPScriptingEngine *m_engine;
|
||||
DWORD m_gitcookie;
|
||||
|
||||
STDMETHODIMP Invoke( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
|
||||
DISPPARAMS FAR* pDispParams, VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo,
|
||||
@@ -340,6 +388,7 @@ public:
|
||||
}
|
||||
ScriptProcedureDispatch() {
|
||||
m_refcount = 1;
|
||||
GIT_put((IDispatch*)this, IID_IDispatch, &m_gitcookie);
|
||||
}
|
||||
};
|
||||
/* }}} */
|
||||
@@ -433,7 +482,7 @@ static void free_code_fragment(code_frag *frag)
|
||||
if (frag->ptr) {
|
||||
ScriptProcedureDispatch *disp = (ScriptProcedureDispatch*)frag->ptr;
|
||||
disp->Release();
|
||||
CoDisconnectObject((IUnknown*)disp, 0);
|
||||
GIT_revoke(disp->m_gitcookie, (IDispatch*)disp);
|
||||
frag->ptr = NULL;
|
||||
}
|
||||
break;
|
||||
@@ -599,6 +648,29 @@ TPHPScriptingEngine::TPHPScriptingEngine()
|
||||
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)
|
||||
{
|
||||
@@ -635,6 +707,7 @@ HRESULT TPHPScriptingEngine::SendThreadMessage(LONG msg, WPARAM wparam, LPARAM l
|
||||
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) {
|
||||
@@ -786,6 +859,8 @@ HRESULT TPHPScriptingEngine::engine_thread_handler(LONG msg, WPARAM wparam, LPAR
|
||||
|
||||
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;
|
||||
@@ -917,44 +992,32 @@ HRESULT TPHPScriptingEngine::engine_thread_handler(LONG msg, WPARAM wparam, LPAR
|
||||
{
|
||||
struct php_active_script_get_dispatch_info *info = (struct php_active_script_get_dispatch_info *)lParam;
|
||||
IDispatch *disp = NULL;
|
||||
char *itemname;
|
||||
unsigned int itemlen;
|
||||
|
||||
if (info->pstrItemName != NULL) {
|
||||
zval **tmp;
|
||||
|
||||
itemname = php_OLECHAR_to_char((OLECHAR*)info->pstrItemName, &itemlen, CP_ACP TSRMLS_CC);
|
||||
|
||||
/* 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, itemlen+1, (void**)&tmp) == SUCCESS) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
trace("%08x: GetScriptDispatch(%s --> %08x)\n", this, itemname, disp);
|
||||
|
||||
efree(itemname);
|
||||
|
||||
} else {
|
||||
#if 0
|
||||
zval *obj;
|
||||
|
||||
MAKE_STD_ZVAL(obj);
|
||||
object_init(obj);
|
||||
disp = php_COM_export_object(obj TSRMLS_CC);
|
||||
#else
|
||||
|
||||
/* This object represents PHP global namespace */
|
||||
disp = (IDispatch*) new ScriptDispatch;
|
||||
#endif
|
||||
trace("%08x: GetScriptDispatch(NULL --> %08x)\n", this, disp);
|
||||
}
|
||||
|
||||
if (disp) {
|
||||
trace("--- Marshaling to stream\n");
|
||||
ret = CoMarshalInterThreadInterfaceInStream(IID_IDispatch, disp, &info->dispatch);
|
||||
ret = GIT_put(disp, IID_IDispatch, &info->dispatch);
|
||||
disp->Release();
|
||||
} else {
|
||||
ret = S_FALSE;
|
||||
@@ -972,22 +1035,20 @@ HRESULT TPHPScriptingEngine::engine_thread_handler(LONG msg, WPARAM wparam, LPAR
|
||||
TWideString name(info->pstrName);
|
||||
IDispatch *disp;
|
||||
|
||||
if (SUCCEEDED(CoGetInterfaceAndReleaseStream(info->marshal, IID_IDispatch, (void**)&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:
|
||||
{
|
||||
LPSTREAM stream = (LPSTREAM)lParam;
|
||||
|
||||
if (m_pass_eng) {
|
||||
m_pass_eng->Release();
|
||||
m_pass_eng = NULL;
|
||||
}
|
||||
|
||||
if (stream)
|
||||
CoGetInterfaceAndReleaseStream(stream, IID_IActiveScriptSite, (void**)&m_pass_eng);
|
||||
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);
|
||||
|
||||
@@ -1010,15 +1071,14 @@ HRESULT TPHPScriptingEngine::engine_thread_handler(LONG msg, WPARAM wparam, LPAR
|
||||
* execute the opcodes */
|
||||
struct php_active_script_parse_proc_info *info = (struct php_active_script_parse_proc_info*)lParam;
|
||||
TWideString
|
||||
code(info->pstrCode),
|
||||
formal_params(info->pstrFormalParams),
|
||||
procedure_name(info->pstrProcedureName),
|
||||
item_name(info->pstrItemName),
|
||||
delimiter(info->pstrDelimiter);
|
||||
formal_params(info->pstrFormalParams),
|
||||
procedure_name(info->pstrProcedureName),
|
||||
item_name(info->pstrItemName),
|
||||
delimiter(info->pstrDelimiter);
|
||||
|
||||
trace("%08x: ParseProc:\n state=%s\ncode=%s\n params=%s\nproc=%s\nitem=%s\n delim=%s\n line=%d\n",
|
||||
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),
|
||||
code.safe_ansi_string(), formal_params.ansi_string(), procedure_name.ansi_string(),
|
||||
formal_params.ansi_string(), procedure_name.ansi_string(),
|
||||
item_name.safe_ansi_string(), delimiter.safe_ansi_string(),
|
||||
info->ulStartingLineNumber);
|
||||
|
||||
@@ -1039,17 +1099,12 @@ HRESULT TPHPScriptingEngine::engine_thread_handler(LONG msg, WPARAM wparam, LPAR
|
||||
|
||||
ScriptProcedureDispatch *disp = new ScriptProcedureDispatch;
|
||||
|
||||
disp->AddRef();
|
||||
disp->m_frag = frag;
|
||||
disp->m_procflags = info->dwFlags;
|
||||
disp->m_engine = this;
|
||||
frag->ptr = disp;
|
||||
info->dispcookie = disp->m_gitcookie;
|
||||
|
||||
*info->ppdisp = disp;
|
||||
/*
|
||||
ret = CoMarshalInterThreadInterfaceInStream(IID_IDispatch, disp, &info->disp);
|
||||
disp->Release();
|
||||
*/
|
||||
} else {
|
||||
ret = DISP_E_EXCEPTION;
|
||||
}
|
||||
@@ -1147,8 +1202,11 @@ void TPHPScriptingEngine::engine_thread_func(void)
|
||||
|
||||
if (msg.message == WM_QUIT) {
|
||||
terminated = 1;
|
||||
} else {
|
||||
} 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)
|
||||
@@ -1354,9 +1412,9 @@ STDMETHODIMP TPHPScriptingEngine::SetScriptSite(IActiveScriptSite *pass)
|
||||
if (m_pass) {
|
||||
m_pass->AddRef();
|
||||
|
||||
LPSTREAM stream;
|
||||
if (SUCCEEDED(CoMarshalInterThreadInterfaceInStream(IID_IActiveScriptSite, m_pass, &stream)))
|
||||
SEND_THREAD_MESSAGE(this, PHPSE_SET_SITE, 0, (LPARAM)stream TSRMLS_CC);
|
||||
DWORD cookie;
|
||||
if (SUCCEEDED(GIT_put(m_pass, IID_IActiveScriptSite, &cookie)))
|
||||
SEND_THREAD_MESSAGE(this, PHPSE_SET_SITE, 0, cookie TSRMLS_CC);
|
||||
|
||||
if (m_scriptstate == SCRIPTSTATE_UNINITIALIZED)
|
||||
SEND_THREAD_MESSAGE(this, PHPSE_STATE_CHANGE, 0, SCRIPTSTATE_INITIALIZED TSRMLS_CC);
|
||||
@@ -1424,7 +1482,7 @@ STDMETHODIMP TPHPScriptingEngine::AddNamedItem(LPCOLESTR pstrName, DWORD dwFlags
|
||||
info.dwFlags = dwFlags;
|
||||
|
||||
m_pass->GetItemInfo(pstrName, SCRIPTINFO_IUNKNOWN, &info.punk, NULL);
|
||||
if (SUCCEEDED(CoMarshalInterThreadInterfaceInStream(IID_IDispatch, info.punk, &info.marshal))) {
|
||||
if (SUCCEEDED(GIT_put(info.punk, IID_IDispatch, &info.marshal))) {
|
||||
SEND_THREAD_MESSAGE(this, PHPSE_ADD_NAMED_ITEM, 0, (LPARAM)&info TSRMLS_CC);
|
||||
}
|
||||
info.punk->Release();
|
||||
@@ -1485,7 +1543,7 @@ STDMETHODIMP TPHPScriptingEngine::GetScriptDispatch(
|
||||
}
|
||||
|
||||
if (S_OK == engine_thread_handler(PHPSE_GET_DISPATCH, 0, (LPARAM)&info, NULL TSRMLS_CC)) {
|
||||
CoGetInterfaceAndReleaseStream(info.dispatch, IID_IDispatch, (void**)ppdisp);
|
||||
GIT_get(info.dispatch, IID_IDispatch, (void**)ppdisp);
|
||||
}
|
||||
|
||||
if (*ppdisp) {
|
||||
@@ -1670,16 +1728,12 @@ STDMETHODIMP TPHPScriptingEngine::ParseProcedureText(
|
||||
info.dwSourceContextCookie = dwSourceContextCookie;
|
||||
info.ulStartingLineNumber = ulStartingLineNumber;
|
||||
info.dwFlags = dwFlags;
|
||||
info.ppdisp = ppdisp;
|
||||
|
||||
ret = SEND_THREAD_MESSAGE(this, PHPSE_PARSE_PROC, 0, (LPARAM)&info TSRMLS_CC);
|
||||
|
||||
/*
|
||||
if (ret == S_OK) {
|
||||
ret = CoGetInterfaceAndReleaseStream(info.disp, IID_IDispatch, (void**)ppdisp);
|
||||
|
||||
}
|
||||
*/
|
||||
if (ret == S_OK)
|
||||
ret = GIT_get(info.dispcookie, IID_IDispatch, (void**)ppdisp);
|
||||
|
||||
trace("ParseProc: ret=%08x disp=%08x\n", ret, *ppdisp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user