summaryrefslogtreecommitdiff
path: root/sapi/activescript/marshal.cpp
diff options
context:
space:
mode:
authorWez Furlong <wez@php.net>2004-07-27 03:57:31 +0000
committerWez Furlong <wez@php.net>2004-07-27 03:57:31 +0000
commitac878007602a8fb06d17de5daa559a31fabf85cb (patch)
treeacdab5fc7b344e371d385039ae67da71f95e9324 /sapi/activescript/marshal.cpp
parent3e327b6e21b2fa10ab08935f4eb10f18b0c8d960 (diff)
downloadphp-git-ac878007602a8fb06d17de5daa559a31fabf85cb.tar.gz
Major re-jig.
With thanks to Rob Richards for tracking down a couple of big bugs caused by teeny bits of code.
Diffstat (limited to 'sapi/activescript/marshal.cpp')
-rwxr-xr-xsapi/activescript/marshal.cpp406
1 files changed, 406 insertions, 0 deletions
diff --git a/sapi/activescript/marshal.cpp b/sapi/activescript/marshal.cpp
new file mode 100755
index 0000000000..2d4c61cb87
--- /dev/null
+++ b/sapi/activescript/marshal.cpp
@@ -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;
+}
+