1
0
mirror of https://github.com/php/php-src.git synced 2026-04-22 23:48:14 +02:00

Major re-jig.

With thanks to Rob Richards for tracking down a couple of big bugs caused by
teeny bits of code.
This commit is contained in:
Wez Furlong
2004-07-27 03:57:31 +00:00
parent 3e327b6e21
commit ac87800760
8 changed files with 1370 additions and 987 deletions
+1 -8
View File
@@ -4,7 +4,6 @@ This is the ActiveScript SAPI for PHP.
Once registered on your system (using regsvr32), you will be able to use
PHP script in any ActiveScript compliant host. The list includes:
o. Client-side script in Internet Explorer
o. Windows Script Host
o. ASP and ASP.NET
o. Windows Script Components / Behaviours
@@ -24,12 +23,6 @@ Build and install it somewhere; then register the engine like this:
Usage.
======
o. Client-side script in Internet Explorer
<script language="ActivePHP5">
$window->alert("Hello");
</script>
o. Windows Script Host
Create a .wsf file like this:
@@ -38,7 +31,7 @@ o. Windows Script Host
<script language="ActivePHP5">
$WScript->Echo("Hello");
</script>
</script>
</job>
o. ASP and ASP.NET
+15 -5
View File
@@ -98,11 +98,15 @@ STDMETHODIMP TPHPClassFactory::LockServer(BOOL fLock)
STDMETHODIMP TPHPClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppvObject)
{
TPHPScriptingEngine *engine = new TPHPScriptingEngine;
IUnknown *punk = create_scripting_engine(NULL);
HRESULT ret;
HRESULT ret = engine->QueryInterface(iid, ppvObject);
engine->Release();
if (punk) {
ret = punk->QueryInterface(iid, ppvObject);
punk->Release();
} else {
ret = E_UNEXPECTED;
}
return ret;
}
@@ -161,7 +165,13 @@ static const GUID *script_engine_categories[] = {
};
static const struct reg_class classes_to_register[] = {
{ &CLSID_PHPActiveScriptEngine, "PHP Active Script Engine", "Both", engine_entries, script_engine_categories },
{ &CLSID_PHPActiveScriptEngine, "PHP Active Script Engine",
#if ACTIVEPHP_THREADING_MODE == COINIT_MULTITHREADED
"Both",
#else
"Apartment",
#endif
engine_entries, script_engine_categories },
{ NULL, NULL, NULL, 0, NULL }
};
/* }}} */
+1 -1
View File
@@ -8,6 +8,6 @@ if (PHP_ACTIVESCRIPT == "yes") {
ERROR("ActiveScript module requires an --enable-zts build of PHP");
}
SAPI('activescript', 'classfactory.cpp php5activescript.c scriptengine.cpp', 'php' + PHP_VERSION + 'activescript.dll', '/D PHP5ISAPI_EXPORTS /D ACTIVEPHP_OBJECT_SAFETY=1');
SAPI('activescript', 'classfactory.cpp php5activescript.c scriptengine.cpp marshal.cpp', 'php' + PHP_VERSION + 'activescript.dll', '/D PHP5ISAPI_EXPORTS /D ACTIVEPHP_OBJECT_SAFETY=1');
ADD_FLAG('LDFLAGS_ACTIVESCRIPT', 'oleaut32.lib ole32.lib user32.lib advapi32.lib /DEF:' + configure_module_dirname + '\\php5activescript.def');
}
+406
View File
@@ -0,0 +1,406 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 2004 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.0 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_0.txt. |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Wez Furlong <wez@thebrainroom.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
/* Fun with threads */
#define _WIN32_DCOM
#define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
#include <winsock2.h>
#include "php5as_scriptengine.h"
#include "php5as_classfactory.h"
#include <objbase.h>
#undef php_win_err
extern "C" char *php_win_err(HRESULT ret);
#define APHPM_IN 1
#define APHPM_OUT 2
#define APHPT_TERM 0
#define APHPT_UNK 1 /* IUnknown * */
#define APHPT_DISP 2 /* IDispatch * */
#define APHPT_VAR 3 /* PVARIANT */
static inline void trace(char *fmt, ...)
{
va_list ap;
char buf[4096];
sprintf(buf, "T=%08x [MARSHAL] ", tsrm_thread_id());
OutputDebugString(buf);
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
OutputDebugString(buf);
va_end(ap);
}
struct marshal_arg {
int type;
int argno;
int direction;
};
static int parse_script_text_mdef[] = {
APHPT_UNK, 2, APHPM_IN,
APHPT_VAR, 7, APHPM_OUT,
APHPT_TERM
};
static int get_script_dispatch_mdef[] = {
APHPT_DISP, 1, APHPM_OUT,
APHPT_TERM
};
static int *mdef_by_func[APHP__Max] = {
parse_script_text_mdef,
NULL, /* InitNew */
NULL, /* AddNamedItem */
NULL, /* SetScriptState */
get_script_dispatch_mdef,
NULL, /* Close */
NULL, /* AddTypeLib */
NULL, /* AddScriptlet */
};
static HRESULT do_marshal_in(int stub, void *args[16], int *mdef, LPSTREAM *ppstm)
{
int i = 0;
int want;
HRESULT ret = S_OK;
LPSTREAM stm = NULL;
if (!mdef)
return S_OK;
trace("marshalling ... \n");
ret = CreateStreamOnHGlobal(NULL, TRUE, &stm);
if (FAILED(ret)) {
trace(" failed to create stm %s", php_win_err(ret));
return ret;
}
*ppstm = stm;
/* if stub is true, we are the stub and are marshaling OUT params,
* otherwise, we are the proxy and are marshalling IN params */
if (stub) {
want = APHPM_OUT;
} else {
want = APHPM_IN;
}
while (mdef[i] != APHPT_TERM) {
if ((mdef[i+2] & want) == want) {
int argno = mdef[i+1];
int isout = (mdef[i+2] & APHPM_OUT) == APHPM_OUT;
#undef OUT_IFACE
#define OUT_IFACE (isout ? *(IUnknown**)args[argno] : (IUnknown*)args[argno])
#define IFACE_PRESENT args[argno] && (!isout || *(IUnknown**)args[argno])
switch (mdef[i]) {
case APHPT_UNK:
if (IFACE_PRESENT) {
ret = CoMarshalInterface(stm, IID_IUnknown, OUT_IFACE, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
trace(" arg=%d IUnknown --> %s", argno, php_win_err(ret));
} else {
trace(" arg=%d IUnknown(NULL) - skip\n", argno);
}
break;
case APHPT_DISP:
if (IFACE_PRESENT) {
ret = CoMarshalInterface(stm, IID_IDispatch, OUT_IFACE, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
trace(" arg=%d IDispatch --> %s", argno, php_win_err(ret));
} else {
trace(" arg=%d IDispatch(NULL) - skip\n", argno);
}
break;
case APHPT_VAR:
if (args[argno])
ret = E_NOTIMPL;
break;
default:
ret = E_NOTIMPL;
}
if (FAILED(ret))
break;
} else {
trace(" -- skipping (this param is not needed in this direction)\n");
}
i += 3;
}
if (FAILED(ret)) {
/* TODO: rollback (refcounts are held during marshalling) */
trace(" rolling back\n");
stm->Release();
*ppstm = NULL;
} else {
LARGE_INTEGER pos = {0};
stm->Seek(pos, STREAM_SEEK_SET, NULL);
}
return ret;
}
static HRESULT do_marshal_out(int stub, void *args[16], int *mdef, LPSTREAM stm)
{
int i = 0;
int want;
HRESULT ret = S_OK;
if (!mdef)
return S_OK;
trace(" unmarshalling...\n");
/* if stub is true, we are the stub and are unmarshaling IN params,
* otherwise, we are the proxy and are unmarshalling OUT params */
if (!stub) {
want = APHPM_OUT;
} else {
want = APHPM_IN;
}
while (mdef[i] != APHPT_TERM) {
if ((mdef[i+2] & want) == want) {
int argno = mdef[i+1];
int isout = (mdef[i+2] & APHPM_OUT) == APHPM_OUT;
#undef OUT_IFACE
#define OUT_IFACE (isout ? (void**)args[argno] : &args[argno])
switch (mdef[i]) {
case APHPT_UNK:
if (IFACE_PRESENT) {
ret = CoUnmarshalInterface(stm, IID_IUnknown, OUT_IFACE);
trace(" unmarshal arg=%d IUnknown --> %s", argno, php_win_err(ret));
} else {
trace(" unmarshal arg=%d IUnknown(NULL) - skip\n", argno);
}
break;
case APHPT_DISP:
if (IFACE_PRESENT) {
trace(" unmarshal dispatch: args[%d]=%p *args[%d]=%p\n",
argno, args[argno], argno, args[argno] ? *(void**)args[argno] : NULL);
ret = CoUnmarshalInterface(stm, IID_IDispatch, OUT_IFACE);
trace(" unmarshal arg=%d IDispatch --> %s: args[%d]=%p *args[%d]=%p\n", argno, php_win_err(ret),
argno, args[argno], argno, args[argno] ? *(void**)args[argno] : NULL);
} else {
trace(" unmarshal arg=%d IDispatch(NULL) - skip\n", argno);
}
break;
case APHPT_VAR:
if (args[argno])
ret = E_NOTIMPL;
break;
default:
ret = E_NOTIMPL;
}
if (FAILED(ret))
break;
}
i += 3;
}
return ret;
}
struct activephp_serialize_msg {
class TPHPScriptingEngine *engine;
void *args[16];
int nargs;
enum activephp_engine_func func;
int *marshal_defs;
LPSTREAM instm, outstm;
HANDLE evt;
HRESULT ret;
};
static const char *func_names[APHP__Max] = {
"ParseScriptText",
"InitNew",
"AddnamedItem",
"SetScriptState",
"GetScriptDispatch",
"Close",
"AddTypeLib",
"AddScriptlet",
};
HRESULT marshal_call(class TPHPScriptingEngine *engine, enum activephp_engine_func func, int nargs, ...)
{
va_list ap;
struct activephp_serialize_msg msg ;
HRESULT ret;
memset(&msg, 0, sizeof(msg));
msg.engine = engine;
msg.func = func;
msg.marshal_defs = mdef_by_func[func];
trace(" prepping for function code %d %s, %d args, marshal defs at %p\n", func, func_names[func], nargs, msg.marshal_defs);
va_start(ap, nargs);
for (msg.nargs = 0; msg.nargs < nargs; msg.nargs++) {
msg.args[msg.nargs] = va_arg(ap, void*);
}
va_end(ap);
ret = do_marshal_in(0, msg.args, msg.marshal_defs, &msg.instm);
if (FAILED(ret)) {
return ret;
}
#if 1
msg.evt = CreateEvent(NULL, TRUE, FALSE, NULL);
PostMessage(engine->m_queue, WM_ACTIVEPHP_SERIALIZE, 0, (LPARAM)&msg);
while (WAIT_OBJECT_0 != WaitForSingleObject(msg.evt, 0)) {
DWORD status = MsgWaitForMultipleObjects(1, &msg.evt, FALSE, INFINITE, QS_ALLEVENTS|QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SENDMESSAGE|QS_POSTMESSAGE);
if (status == WAIT_OBJECT_0)
break;
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
CloseHandle(msg.evt);
#else
ret = SendMessage(engine->m_queue, WM_ACTIVEPHP_SERIALIZE, 0, (LPARAM)&msg);
#endif
if (msg.outstm) {
ret = do_marshal_out(0, msg.args, msg.marshal_defs, msg.outstm);
msg.outstm->Release();
}
if (msg.instm)
msg.instm->Release();
trace("marshall call to %s completed %s", func_names[func], php_win_err(ret));
return ret;
}
HRESULT marshal_stub(LPARAM lparam)
{
struct activephp_serialize_msg *msg = (struct activephp_serialize_msg*)lparam;
if (msg->instm) {
msg->ret = do_marshal_out(1, msg->args, msg->marshal_defs, msg->instm);
if (FAILED(msg->ret)) {
SetEvent(msg->evt);
return msg->ret;
}
}
switch (msg->func) {
case APHP_ParseScriptText:
msg->ret = msg->engine->ParseScriptText(
(LPCOLESTR)msg->args[0],
(LPCOLESTR)msg->args[1],
(IUnknown*)msg->args[2],
(LPCOLESTR)msg->args[3],
(DWORD)msg->args[4],
(ULONG)msg->args[5],
(DWORD)msg->args[6],
(VARIANT*)msg->args[7],
(EXCEPINFO*)msg->args[8]);
break;
case APHP_InitNew:
msg->ret = msg->engine->InitNew();
break;
case APHP_AddNamedItem:
msg->ret = msg->engine->AddNamedItem(
(LPCOLESTR)msg->args[0],
(DWORD)msg->args[1]);
break;
case APHP_SetScriptState:
msg->ret = msg->engine->SetScriptState((SCRIPTSTATE)(LONG)msg->args[0]);
break;
case APHP_GetScriptDispatch:
msg->ret = msg->engine->GetScriptDispatch(
(LPCOLESTR)msg->args[0],
(IDispatch**)msg->args[1]);
break;
case APHP_Close:
msg->ret = msg->engine->Close();
break;
case APHP_AddTypeLib:
msg->ret = msg->engine->AddTypeLib(
(REFGUID)msg->args[0],
(DWORD)msg->args[1],
(DWORD)msg->args[2],
(DWORD)msg->args[3]);
break;
case APHP_AddScriptlet:
msg->ret = msg->engine->AddScriptlet(
(LPCOLESTR)msg->args[0],
(LPCOLESTR)msg->args[1],
(LPCOLESTR)msg->args[2],
(LPCOLESTR)msg->args[3],
(LPCOLESTR)msg->args[4],
(LPCOLESTR)msg->args[5],
(DWORD)msg->args[6],
(ULONG)msg->args[7],
(DWORD)msg->args[8],
(BSTR*)msg->args[9],
(EXCEPINFO*)msg->args[10]);
break;
default:
msg->ret = E_NOTIMPL;
}
if (SUCCEEDED(msg->ret)) {
msg->ret = do_marshal_in(1, msg->args, msg->marshal_defs, &msg->outstm);
}
SetEvent(msg->evt);
return msg->ret;
}
+1
View File
@@ -145,6 +145,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
activescript_sapi_module.shutdown(&sapi_module);
}
//OutputDebugString("PROCESS_DETACH\n");
sapi_shutdown();
tsrm_shutdown();
break;
}
+4
View File
@@ -25,6 +25,10 @@
DEFINE_GUID(CLSID_PHPActiveScriptEngine,
0xcf108a38, 0x59a9, 0x468a, 0xaf, 0x45, 0x13, 0x68, 0xd7, 0x85, 0x5d, 0xae);
// {AD504760-D6B9-4537-AEAC-512FFB359009}
DEFINE_GUID(CLSID_PHPActiveScriptEngineMarshal,
0xad504760, 0xd6b9, 0x4537, 0xae, 0xac, 0x51, 0x2f, 0xfb, 0x35, 0x90, 0x9);
#if 0
/* this was for PHP 4 */
// {A0AD8E7A-95EC-4819-986F-78D93895F2AE}
+62 -102
View File
@@ -18,129 +18,68 @@
/* $Id$ */
#include <activscp.h>
#if ACTIVEPHP_OBJECT_SAFETY
# include <objsafe.h>
#endif
#include <objsafe.h>
#include "zend.h"
#include <setjmp.h>
/* Definitions for thread messages */
enum {
PHPSE_STATE_CHANGE = WM_USER + 20,
PHPSE_INIT_NEW,
PHPSE_PARSE_SCRIPT,
PHPSE_ADD_SCRIPTLET,
PHPSE_CLOSE,
PHPSE_CLONE,
PHPSE_ENTER,
PHPSE_LEAVE,
PHPSE_TERMINATE,
PHPSE_PARSE_PROC,
PHPSE_EXEC_PROC,
PHPSE_ADD_NAMED_ITEM,
PHPSE_SET_SITE,
PHPSE_ADD_TYPELIB,
PHPSE_TRIGGER_ERROR,
PHPSE_GET_DISPATCH,
PHPSE_DUMMY_TICK,
#if 0
#define ACTIVEPHP_THREADING_MODE COINIT_MULTITHREADED
#else
#define ACTIVEPHP_THREADING_MODE COINIT_APARTMENTTHREADED
#endif
#define ACTIVEPHP_HAS_OWN_THREAD 1
#define WM_ACTIVEPHP_SERIALIZE WM_USER + 200
enum activephp_engine_func { /* if you change the order, change marshal.cpp too */
APHP_ParseScriptText,
APHP_InitNew,
APHP_AddNamedItem,
APHP_SetScriptState,
APHP_GetScriptDispatch,
APHP_Close,
APHP_AddTypeLib,
APHP_AddScriptlet,
APHP__Max
};
struct php_active_script_get_dispatch_info {
LPCOLESTR pstrItemName;
DWORD dispatch;
};
struct php_active_script_add_named_item_info {
LPCOLESTR pstrName;
DWORD dwFlags;
IUnknown *punk;
ITypeInfo *ptyp;
IDispatch *pdisp;
DWORD marshal;
};
struct php_active_script_add_scriptlet_info {
/* [in] */ LPCOLESTR pstrDefaultName;
/* [in] */ LPCOLESTR pstrCode;
/* [in] */ LPCOLESTR pstrItemName;
/* [in] */ LPCOLESTR pstrSubItemName;
/* [in] */ LPCOLESTR pstrEventName;
/* [in] */ LPCOLESTR pstrDelimiter;
/* [in] */ DWORD dwSourceContextCookie;
/* [in] */ ULONG ulStartingLineNumber;
/* [in] */ DWORD dwFlags;
/* [out] */ BSTR *pbstrName;
/* [out] */ EXCEPINFO *pexcepinfo;
};
struct php_active_script_parse_info {
/* [in] */ LPCOLESTR pstrCode;
/* [in] */ LPCOLESTR pstrItemName;
/* [in] */ IUnknown *punkContext;
/* [in] */ LPCOLESTR pstrDelimiter;
/* [in] */ DWORD dwSourceContextCookie;
/* [in] */ ULONG ulStartingLineNumber;
/* [in] */ DWORD dwFlags;
/* [out] */ VARIANT *pvarResult;
/* [out] */ EXCEPINFO *pexcepinfo;
};
struct php_active_script_parse_proc_info {
/* [in] */ LPCOLESTR pstrCode;
/* [in] */ LPCOLESTR pstrFormalParams;
/* [in] */ LPCOLESTR pstrProcedureName;
/* [in] */ LPCOLESTR pstrItemName;
/* [in] */ IUnknown *punkContext;
/* [in] */ LPCOLESTR pstrDelimiter;
/* [in] */ DWORD dwSourceContextCookie;
/* [in] */ ULONG ulStartingLineNumber;
/* [in] */ DWORD dwFlags;
DWORD dispcookie;
};
struct php_active_script_add_tlb_info {
/* [in] */ const GUID * rguidTypeLib;
/* [in] */ DWORD dwMajor;
/* [in] */ DWORD dwMinor;
/* [in] */ DWORD dwFlags;
};
HRESULT marshal_call(class TPHPScriptingEngine *engine, enum activephp_engine_func func, int nargs, ...);
HRESULT marshal_stub(LPARAM lparam);
class TPHPScriptingEngine:
public IActiveScript,
public IActiveScriptParse,
public IActiveScriptParseProcedure
#if ACTIVEPHP_OBJECT_SAFETY
, public IObjectSafety
public IActiveScriptParseProcedure,
public IObjectSafety,
public IDispatch
#if 0
, public IMarshal
#endif
{
public:
volatile LONG m_refcount;
IActiveScriptSite *m_pass;
SCRIPTSTATE m_scriptstate;
MUTEX_T m_mutex;
HashTable m_script_dispatchers;
HANDLE m_engine_thread_handle;
HANDLE m_sync_thread_msg;
HRESULT m_sync_thread_ret;
/* This is hacky, but only used when the host queries us for a script dispatch */
void *** m_tsrm_hack;
void add_to_global_namespace(IDispatch *disp, DWORD flags, char *name TSRMLS_DC);
THREAD_T m_enginethread, m_basethread;
HashTable m_frags;
ULONG m_lambda_count;
IActiveScriptSite *m_pass_eng;
DWORD m_gitcookie, m_asscookie;
HWND m_queue;
int m_done_init;
jmp_buf *m_err_trap;
int m_in_main, m_stop_main;
HRESULT SendThreadMessage(LONG msg, WPARAM wparam, LPARAM lparam);
void engine_thread_func(void);
HRESULT engine_thread_handler(LONG msg, WPARAM wParam, LPARAM lParam, int *handled TSRMLS_DC);
void do_clone(TPHPScriptingEngine *src);
void setup_engine_state(void);
int create_id(OLECHAR *name, DISPID *dispid TSRMLS_DC);
char *m_names[1024];
int m_lens[1024];
int m_ids;
public: /* IUnknown */
STDMETHODIMP QueryInterface(REFIID iid, void **ppvObject);
@@ -234,7 +173,6 @@ public: /* IActiveScriptParseProcedure */
/* [in] */ DWORD dwFlags,
/* [out] */ IDispatch **ppdisp);
#if ACTIVEPHP_OBJECT_SAFETY
public: /* IObjectSafety */
STDMETHODIMP GetInterfaceSafetyOptions(
/* [in] */ REFIID riid, // Interface that we want options for
@@ -245,11 +183,33 @@ public: /* IObjectSafety */
/* [in] */ REFIID riid, // Interface to set options for
/* [in] */ DWORD dwOptionSetMask, // Options to change
/* [in] */ DWORD dwEnabledOptions); // New option values
#if 0
public: /* IMarshal */
STDMETHODIMP GetUnmarshalClass(
REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid);
STDMETHODIMP GetMarshalSizeMax(
REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, ULONG *pSize);
STDMETHODIMP MarshalInterface(
IStream *pStm, REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshflags);
STDMETHODIMP UnmarshalInterface(
IStream *pStm, REFIID riid, void **ppv);
STDMETHODIMP ReleaseMarshalData(IStream *pStm);
STDMETHODIMP DisconnectObject(DWORD dwReserved);
#endif
public: /* IDispatch */
STDMETHODIMP GetIDsOfNames( REFIID riid, OLECHAR **rgszNames, unsigned int cNames, LCID lcid, DISPID *rgDispId);
STDMETHODIMP Invoke( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS FAR* pdp, VARIANT FAR* pvarRes, EXCEPINFO FAR* pei,
unsigned int FAR* puArgErr);
STDMETHODIMP GetTypeInfoCount(unsigned int * pctinfo);
STDMETHODIMP GetTypeInfo( unsigned int iTInfo, LCID lcid, ITypeInfo **ppTInfo);
public:
TPHPScriptingEngine();
~TPHPScriptingEngine();
};
IUnknown *create_scripting_engine(TPHPScriptingEngine *tobecloned);
File diff suppressed because it is too large Load Diff