You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

428 lines
10 KiB

  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2004 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.0 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_0.txt. |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Wez Furlong <wez@thebrainroom.com> |
  16. +----------------------------------------------------------------------+
  17. */
  18. /* $Id$ */
  19. /* Fun with threads */
  20. #define _WIN32_DCOM
  21. #define ZEND_INCLUDE_FULL_WINDOWS_HEADERS
  22. #include <winsock2.h>
  23. #include "php5as_scriptengine.h"
  24. #include "php5as_classfactory.h"
  25. #include <objbase.h>
  26. #undef php_win_err
  27. extern "C" char *php_win_err(HRESULT ret);
  28. #define APHPM_IN 1
  29. #define APHPM_OUT 2
  30. #define APHPT_TERM 0
  31. #define APHPT_UNK 1 /* IUnknown * */
  32. #define APHPT_DISP 2 /* IDispatch * */
  33. #define APHPT_VAR 3 /* PVARIANT */
  34. static inline void trace(char *fmt, ...)
  35. {
  36. va_list ap;
  37. char buf[4096];
  38. sprintf(buf, "T=%08x [MARSHAL] ", tsrm_thread_id());
  39. OutputDebugString(buf);
  40. va_start(ap, fmt);
  41. vsnprintf(buf, sizeof(buf), fmt, ap);
  42. OutputDebugString(buf);
  43. va_end(ap);
  44. }
  45. struct marshal_arg {
  46. int type;
  47. int argno;
  48. int direction;
  49. };
  50. static int parse_script_text_mdef[] = {
  51. APHPT_UNK, 2, APHPM_IN,
  52. APHPT_VAR, 7, APHPM_OUT,
  53. APHPT_TERM
  54. };
  55. static int get_script_dispatch_mdef[] = {
  56. APHPT_DISP, 1, APHPM_OUT,
  57. APHPT_TERM
  58. };
  59. static int parse_procedure_text_mdef[] = {
  60. APHPT_UNK, 4, APHPM_IN,
  61. APHPT_DISP, 9, APHPM_OUT,
  62. APHPT_TERM
  63. };
  64. static int *mdef_by_func[APHP__Max] = {
  65. parse_script_text_mdef,
  66. NULL, /* InitNew */
  67. NULL, /* AddNamedItem */
  68. NULL, /* SetScriptState */
  69. get_script_dispatch_mdef,
  70. NULL, /* Close */
  71. NULL, /* AddTypeLib */
  72. NULL, /* AddScriptlet */
  73. parse_procedure_text_mdef,
  74. };
  75. static HRESULT do_marshal_in(int stub, void *args[16], int *mdef, LPSTREAM *ppstm)
  76. {
  77. int i = 0;
  78. int want;
  79. HRESULT ret = S_OK;
  80. LPSTREAM stm = NULL;
  81. if (!mdef)
  82. return S_OK;
  83. trace("marshalling ... \n");
  84. ret = CreateStreamOnHGlobal(NULL, TRUE, &stm);
  85. if (FAILED(ret)) {
  86. trace(" failed to create stm %s", php_win_err(ret));
  87. return ret;
  88. }
  89. *ppstm = stm;
  90. /* if stub is true, we are the stub and are marshaling OUT params,
  91. * otherwise, we are the proxy and are marshalling IN params */
  92. if (stub) {
  93. want = APHPM_OUT;
  94. } else {
  95. want = APHPM_IN;
  96. }
  97. while (mdef[i] != APHPT_TERM) {
  98. if ((mdef[i+2] & want) == want) {
  99. int argno = mdef[i+1];
  100. int isout = (mdef[i+2] & APHPM_OUT) == APHPM_OUT;
  101. #undef OUT_IFACE
  102. #define OUT_IFACE (isout ? *(IUnknown**)args[argno] : (IUnknown*)args[argno])
  103. #define IFACE_PRESENT args[argno] && (!isout || *(IUnknown**)args[argno])
  104. switch (mdef[i]) {
  105. case APHPT_UNK:
  106. if (IFACE_PRESENT) {
  107. ret = CoMarshalInterface(stm, IID_IUnknown, OUT_IFACE, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
  108. trace(" arg=%d IUnknown --> %s", argno, php_win_err(ret));
  109. } else {
  110. trace(" arg=%d IUnknown(NULL) - skip\n", argno);
  111. }
  112. break;
  113. case APHPT_DISP:
  114. if (IFACE_PRESENT) {
  115. ret = CoMarshalInterface(stm, IID_IDispatch, OUT_IFACE, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
  116. trace(" arg=%d IDispatch --> %s", argno, php_win_err(ret));
  117. } else {
  118. trace(" arg=%d IDispatch(NULL) - skip\n", argno);
  119. }
  120. break;
  121. case APHPT_VAR:
  122. if (args[argno])
  123. ret = E_NOTIMPL;
  124. break;
  125. default:
  126. ret = E_NOTIMPL;
  127. }
  128. if (FAILED(ret))
  129. break;
  130. } else {
  131. trace(" -- skipping (this param is not needed in this direction)\n");
  132. }
  133. i += 3;
  134. }
  135. if (FAILED(ret)) {
  136. /* TODO: rollback (refcounts are held during marshalling) */
  137. trace(" rolling back\n");
  138. stm->Release();
  139. *ppstm = NULL;
  140. } else {
  141. LARGE_INTEGER pos = {0};
  142. stm->Seek(pos, STREAM_SEEK_SET, NULL);
  143. }
  144. return ret;
  145. }
  146. static HRESULT do_marshal_out(int stub, void *args[16], int *mdef, LPSTREAM stm)
  147. {
  148. int i = 0;
  149. int want;
  150. HRESULT ret = S_OK;
  151. if (!mdef)
  152. return S_OK;
  153. trace(" unmarshalling...\n");
  154. /* if stub is true, we are the stub and are unmarshaling IN params,
  155. * otherwise, we are the proxy and are unmarshalling OUT params */
  156. if (!stub) {
  157. want = APHPM_OUT;
  158. } else {
  159. want = APHPM_IN;
  160. }
  161. while (mdef[i] != APHPT_TERM) {
  162. if ((mdef[i+2] & want) == want) {
  163. int argno = mdef[i+1];
  164. int isout = (mdef[i+2] & APHPM_OUT) == APHPM_OUT;
  165. #undef OUT_IFACE
  166. #define OUT_IFACE (isout ? (void**)args[argno] : &args[argno])
  167. switch (mdef[i]) {
  168. case APHPT_UNK:
  169. if (IFACE_PRESENT) {
  170. ret = CoUnmarshalInterface(stm, IID_IUnknown, OUT_IFACE);
  171. trace(" unmarshal arg=%d IUnknown --> %s", argno, php_win_err(ret));
  172. } else {
  173. trace(" unmarshal arg=%d IUnknown(NULL) - skip\n", argno);
  174. }
  175. break;
  176. case APHPT_DISP:
  177. if (IFACE_PRESENT) {
  178. trace(" unmarshal dispatch: args[%d]=%p *args[%d]=%p\n",
  179. argno, args[argno], argno, args[argno] ? *(void**)args[argno] : NULL);
  180. ret = CoUnmarshalInterface(stm, IID_IDispatch, OUT_IFACE);
  181. trace(" unmarshal arg=%d IDispatch --> %s: args[%d]=%p *args[%d]=%p\n", argno, php_win_err(ret),
  182. argno, args[argno], argno, args[argno] ? *(void**)args[argno] : NULL);
  183. } else {
  184. trace(" unmarshal arg=%d IDispatch(NULL) - skip\n", argno);
  185. }
  186. break;
  187. case APHPT_VAR:
  188. if (args[argno])
  189. ret = E_NOTIMPL;
  190. break;
  191. default:
  192. ret = E_NOTIMPL;
  193. }
  194. if (FAILED(ret))
  195. break;
  196. }
  197. i += 3;
  198. }
  199. return ret;
  200. }
  201. struct activephp_serialize_msg {
  202. class TPHPScriptingEngine *engine;
  203. void *args[16];
  204. int nargs;
  205. enum activephp_engine_func func;
  206. int *marshal_defs;
  207. LPSTREAM instm, outstm;
  208. HANDLE evt;
  209. HRESULT ret;
  210. };
  211. static const char *func_names[APHP__Max] = {
  212. "ParseScriptText",
  213. "InitNew",
  214. "AddnamedItem",
  215. "SetScriptState",
  216. "GetScriptDispatch",
  217. "Close",
  218. "AddTypeLib",
  219. "AddScriptlet",
  220. "ParseProcedureText",
  221. };
  222. HRESULT marshal_call(class TPHPScriptingEngine *engine, enum activephp_engine_func func, int nargs, ...)
  223. {
  224. va_list ap;
  225. struct activephp_serialize_msg msg ;
  226. HRESULT ret;
  227. memset(&msg, 0, sizeof(msg));
  228. msg.engine = engine;
  229. msg.func = func;
  230. msg.marshal_defs = mdef_by_func[func];
  231. trace(" prepping for function code %d %s, %d args, marshal defs at %p\n", func, func_names[func], nargs, msg.marshal_defs);
  232. va_start(ap, nargs);
  233. for (msg.nargs = 0; msg.nargs < nargs; msg.nargs++) {
  234. msg.args[msg.nargs] = va_arg(ap, void*);
  235. }
  236. va_end(ap);
  237. ret = do_marshal_in(0, msg.args, msg.marshal_defs, &msg.instm);
  238. if (FAILED(ret)) {
  239. return ret;
  240. }
  241. #if 1
  242. msg.evt = CreateEvent(NULL, TRUE, FALSE, NULL);
  243. PostMessage(engine->m_queue, WM_ACTIVEPHP_SERIALIZE, 0, (LPARAM)&msg);
  244. while (WAIT_OBJECT_0 != WaitForSingleObject(msg.evt, 0)) {
  245. DWORD status = MsgWaitForMultipleObjects(1, &msg.evt, FALSE, INFINITE, QS_ALLEVENTS|QS_ALLINPUT|QS_ALLPOSTMESSAGE|QS_SENDMESSAGE|QS_POSTMESSAGE);
  246. if (status == WAIT_OBJECT_0)
  247. break;
  248. MSG msg;
  249. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  250. TranslateMessage(&msg);
  251. DispatchMessage(&msg);
  252. }
  253. }
  254. CloseHandle(msg.evt);
  255. #else
  256. ret = SendMessage(engine->m_queue, WM_ACTIVEPHP_SERIALIZE, 0, (LPARAM)&msg);
  257. #endif
  258. if (msg.outstm) {
  259. ret = do_marshal_out(0, msg.args, msg.marshal_defs, msg.outstm);
  260. msg.outstm->Release();
  261. }
  262. if (msg.instm)
  263. msg.instm->Release();
  264. trace("marshall call to %s completed %s", func_names[func], php_win_err(ret));
  265. return ret;
  266. }
  267. HRESULT marshal_stub(LPARAM lparam)
  268. {
  269. struct activephp_serialize_msg *msg = (struct activephp_serialize_msg*)lparam;
  270. if (msg->instm) {
  271. msg->ret = do_marshal_out(1, msg->args, msg->marshal_defs, msg->instm);
  272. if (FAILED(msg->ret)) {
  273. SetEvent(msg->evt);
  274. return msg->ret;
  275. }
  276. }
  277. switch (msg->func) {
  278. case APHP_ParseScriptText:
  279. msg->ret = msg->engine->ParseScriptText(
  280. (LPCOLESTR)msg->args[0],
  281. (LPCOLESTR)msg->args[1],
  282. (IUnknown*)msg->args[2],
  283. (LPCOLESTR)msg->args[3],
  284. (DWORD)msg->args[4],
  285. (ULONG)msg->args[5],
  286. (DWORD)msg->args[6],
  287. (VARIANT*)msg->args[7],
  288. (EXCEPINFO*)msg->args[8]);
  289. break;
  290. case APHP_InitNew:
  291. msg->ret = msg->engine->InitNew();
  292. break;
  293. case APHP_AddNamedItem:
  294. msg->ret = msg->engine->AddNamedItem(
  295. (LPCOLESTR)msg->args[0],
  296. (DWORD)msg->args[1]);
  297. break;
  298. case APHP_SetScriptState:
  299. msg->ret = msg->engine->SetScriptState((SCRIPTSTATE)(LONG)msg->args[0]);
  300. break;
  301. case APHP_GetScriptDispatch:
  302. msg->ret = msg->engine->GetScriptDispatch(
  303. (LPCOLESTR)msg->args[0],
  304. (IDispatch**)msg->args[1]);
  305. break;
  306. case APHP_Close:
  307. msg->ret = msg->engine->Close();
  308. break;
  309. case APHP_AddTypeLib:
  310. msg->ret = msg->engine->AddTypeLib(
  311. (REFGUID)msg->args[0],
  312. (DWORD)msg->args[1],
  313. (DWORD)msg->args[2],
  314. (DWORD)msg->args[3]);
  315. break;
  316. case APHP_AddScriptlet:
  317. msg->ret = msg->engine->AddScriptlet(
  318. (LPCOLESTR)msg->args[0],
  319. (LPCOLESTR)msg->args[1],
  320. (LPCOLESTR)msg->args[2],
  321. (LPCOLESTR)msg->args[3],
  322. (LPCOLESTR)msg->args[4],
  323. (LPCOLESTR)msg->args[5],
  324. (DWORD)msg->args[6],
  325. (ULONG)msg->args[7],
  326. (DWORD)msg->args[8],
  327. (BSTR*)msg->args[9],
  328. (EXCEPINFO*)msg->args[10]);
  329. break;
  330. case APHP_ParseProcedureText:
  331. msg->ret = msg->engine->ParseProcedureText(
  332. (LPCOLESTR)msg->args[0],
  333. (LPCOLESTR)msg->args[1],
  334. (LPCOLESTR)msg->args[2],
  335. (LPCOLESTR)msg->args[3],
  336. (IUnknown*)msg->args[4],
  337. (LPCOLESTR)msg->args[5],
  338. (DWORD)msg->args[6],
  339. (ULONG)msg->args[7],
  340. (DWORD)msg->args[8],
  341. (IDispatch**)msg->args[9]);
  342. break;
  343. default:
  344. msg->ret = E_NOTIMPL;
  345. }
  346. if (SUCCEEDED(msg->ret)) {
  347. msg->ret = do_marshal_in(1, msg->args, msg->marshal_defs, &msg->outstm);
  348. }
  349. SetEvent(msg->evt);
  350. return msg->ret;
  351. }