com_com.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2016 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 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_01.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. | Author: Wez Furlong <wez@thebrainroom.com> |
  16. +----------------------------------------------------------------------+
  17. */
  18. /* $Id$ */
  19. #ifdef HAVE_CONFIG_H
  20. #include "config.h"
  21. #endif
  22. #include "php.h"
  23. #include "php_ini.h"
  24. #include "ext/standard/info.h"
  25. #include "php_com_dotnet.h"
  26. #include "php_com_dotnet_internal.h"
  27. #include "Zend/zend_exceptions.h"
  28. /* {{{ com_create_instance - ctor for COM class */
  29. PHP_FUNCTION(com_create_instance)
  30. {
  31. zval *object = getThis();
  32. zval *server_params = NULL;
  33. php_com_dotnet_object *obj;
  34. char *module_name, *typelib_name = NULL, *server_name = NULL;
  35. char *user_name = NULL, *domain_name = NULL, *password = NULL;
  36. int module_name_len, typelib_name_len, server_name_len,
  37. user_name_len, domain_name_len, password_len;
  38. OLECHAR *moniker;
  39. CLSID clsid;
  40. CLSCTX ctx = CLSCTX_SERVER;
  41. HRESULT res = E_FAIL;
  42. int mode = COMG(autoreg_case_sensitive) ? CONST_CS : 0;
  43. ITypeLib *TL = NULL;
  44. COSERVERINFO info;
  45. COAUTHIDENTITY authid = {0};
  46. COAUTHINFO authinfo = {
  47. RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
  48. RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE,
  49. &authid, EOAC_NONE
  50. };
  51. php_com_initialize(TSRMLS_C);
  52. obj = CDNO_FETCH(object);
  53. if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
  54. ZEND_NUM_ARGS() TSRMLS_CC, "s|s!ls",
  55. &module_name, &module_name_len, &server_name, &server_name_len,
  56. &obj->code_page, &typelib_name, &typelib_name_len) &&
  57. FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
  58. ZEND_NUM_ARGS() TSRMLS_CC, "sa|ls",
  59. &module_name, &module_name_len, &server_params, &obj->code_page,
  60. &typelib_name, &typelib_name_len)) {
  61. php_com_throw_exception(E_INVALIDARG, "Could not create COM object - invalid arguments!" TSRMLS_CC);
  62. ZVAL_NULL(object);
  63. return;
  64. }
  65. if (server_name) {
  66. ctx = CLSCTX_REMOTE_SERVER;
  67. } else if (server_params) {
  68. zval **tmp;
  69. /* decode the data from the array */
  70. if (SUCCESS == zend_hash_find(HASH_OF(server_params),
  71. "Server", sizeof("Server"), (void**)&tmp)) {
  72. convert_to_string_ex(tmp);
  73. server_name = Z_STRVAL_PP(tmp);
  74. server_name_len = Z_STRLEN_PP(tmp);
  75. ctx = CLSCTX_REMOTE_SERVER;
  76. }
  77. if (SUCCESS == zend_hash_find(HASH_OF(server_params),
  78. "Username", sizeof("Username"), (void**)&tmp)) {
  79. convert_to_string_ex(tmp);
  80. user_name = Z_STRVAL_PP(tmp);
  81. user_name_len = Z_STRLEN_PP(tmp);
  82. }
  83. if (SUCCESS == zend_hash_find(HASH_OF(server_params),
  84. "Password", sizeof("Password"), (void**)&tmp)) {
  85. convert_to_string_ex(tmp);
  86. password = Z_STRVAL_PP(tmp);
  87. password_len = Z_STRLEN_PP(tmp);
  88. }
  89. if (SUCCESS == zend_hash_find(HASH_OF(server_params),
  90. "Domain", sizeof("Domain"), (void**)&tmp)) {
  91. convert_to_string_ex(tmp);
  92. domain_name = Z_STRVAL_PP(tmp);
  93. domain_name_len = Z_STRLEN_PP(tmp);
  94. }
  95. if (SUCCESS == zend_hash_find(HASH_OF(server_params),
  96. "Flags", sizeof("Flags"), (void**)&tmp)) {
  97. convert_to_long_ex(tmp);
  98. ctx = (CLSCTX)Z_LVAL_PP(tmp);
  99. }
  100. }
  101. if (server_name && !COMG(allow_dcom)) {
  102. php_com_throw_exception(E_ERROR, "DCOM has been disabled by your administrator [com.allow_dcom=0]" TSRMLS_CC);
  103. return;
  104. }
  105. moniker = php_com_string_to_olestring(module_name, module_name_len, obj->code_page TSRMLS_CC);
  106. /* if instantiating a remote object, either directly, or via
  107. * a moniker, fill in the relevant info */
  108. if (server_name) {
  109. info.dwReserved1 = 0;
  110. info.dwReserved2 = 0;
  111. info.pwszName = php_com_string_to_olestring(server_name, server_name_len, obj->code_page TSRMLS_CC);
  112. if (user_name) {
  113. authid.User = php_com_string_to_olestring(user_name, -1, obj->code_page TSRMLS_CC);
  114. authid.UserLength = user_name_len;
  115. if (password) {
  116. authid.Password = (OLECHAR*)password;
  117. authid.PasswordLength = password_len;
  118. } else {
  119. authid.Password = (OLECHAR*)"";
  120. authid.PasswordLength = 0;
  121. }
  122. if (domain_name) {
  123. authid.Domain = (OLECHAR*)domain_name;
  124. authid.DomainLength = domain_name_len;
  125. } else {
  126. authid.Domain = (OLECHAR*)"";
  127. authid.DomainLength = 0;
  128. }
  129. authid.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
  130. info.pAuthInfo = &authinfo;
  131. } else {
  132. info.pAuthInfo = NULL;
  133. }
  134. }
  135. if (FAILED(CLSIDFromString(moniker, &clsid))) {
  136. /* try to use it as a moniker */
  137. IBindCtx *pBindCtx = NULL;
  138. IMoniker *pMoniker = NULL;
  139. ULONG ulEaten;
  140. BIND_OPTS2 bopt = {0};
  141. if (SUCCEEDED(res = CreateBindCtx(0, &pBindCtx))) {
  142. if (server_name) {
  143. /* fill in the remote server info.
  144. * MSDN docs indicate that this might be ignored in
  145. * current win32 implementations, but at least we are
  146. * doing the right thing in readiness for the day that
  147. * it does work */
  148. bopt.cbStruct = sizeof(bopt);
  149. IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS*)&bopt);
  150. bopt.pServerInfo = &info;
  151. /* apparently, GetBindOptions will only ever return
  152. * a regular BIND_OPTS structure. My gut feeling is
  153. * that it will modify the size field to reflect that
  154. * so lets be safe and set it to the BIND_OPTS2 size
  155. * again */
  156. bopt.cbStruct = sizeof(bopt);
  157. IBindCtx_SetBindOptions(pBindCtx, (BIND_OPTS*)&bopt);
  158. }
  159. if (SUCCEEDED(res = MkParseDisplayName(pBindCtx, moniker, &ulEaten, &pMoniker))) {
  160. res = IMoniker_BindToObject(pMoniker, pBindCtx,
  161. NULL, &IID_IDispatch, (LPVOID*)&V_DISPATCH(&obj->v));
  162. if (SUCCEEDED(res)) {
  163. V_VT(&obj->v) = VT_DISPATCH;
  164. }
  165. IMoniker_Release(pMoniker);
  166. }
  167. }
  168. if (pBindCtx) {
  169. IBindCtx_Release(pBindCtx);
  170. }
  171. } else if (server_name) {
  172. MULTI_QI qi;
  173. qi.pIID = &IID_IDispatch;
  174. qi.pItf = NULL;
  175. qi.hr = S_OK;
  176. res = CoCreateInstanceEx(&clsid, NULL, ctx, &info, 1, &qi);
  177. if (SUCCEEDED(res)) {
  178. res = qi.hr;
  179. V_DISPATCH(&obj->v) = (IDispatch*)qi.pItf;
  180. V_VT(&obj->v) = VT_DISPATCH;
  181. }
  182. } else {
  183. res = CoCreateInstance(&clsid, NULL, CLSCTX_SERVER, &IID_IDispatch, (LPVOID*)&V_DISPATCH(&obj->v));
  184. if (SUCCEEDED(res)) {
  185. V_VT(&obj->v) = VT_DISPATCH;
  186. }
  187. }
  188. if (server_name) {
  189. STR_FREE((char*)info.pwszName);
  190. STR_FREE((char*)authid.User);
  191. }
  192. efree(moniker);
  193. if (FAILED(res)) {
  194. char *werr, *msg;
  195. werr = php_win32_error_to_msg(res);
  196. spprintf(&msg, 0, "Failed to create COM object `%s': %s", module_name, werr);
  197. LocalFree(werr);
  198. php_com_throw_exception(res, msg TSRMLS_CC);
  199. efree(msg);
  200. ZVAL_NULL(object);
  201. return;
  202. }
  203. /* we got the object and it lives ! */
  204. /* see if it has TypeInfo available */
  205. if (FAILED(IDispatch_GetTypeInfo(V_DISPATCH(&obj->v), 0, LANG_NEUTRAL, &obj->typeinfo)) && typelib_name) {
  206. /* load up the library from the named file */
  207. int cached;
  208. TL = php_com_load_typelib_via_cache(typelib_name, obj->code_page, &cached TSRMLS_CC);
  209. if (TL) {
  210. if (COMG(autoreg_on) && !cached) {
  211. php_com_import_typelib(TL, mode, obj->code_page TSRMLS_CC);
  212. }
  213. /* cross your fingers... there is no guarantee that this ITypeInfo
  214. * instance has any relation to this IDispatch instance... */
  215. ITypeLib_GetTypeInfo(TL, 0, &obj->typeinfo);
  216. ITypeLib_Release(TL);
  217. }
  218. } else if (obj->typeinfo && COMG(autoreg_on)) {
  219. int idx;
  220. if (SUCCEEDED(ITypeInfo_GetContainingTypeLib(obj->typeinfo, &TL, &idx))) {
  221. /* check if the library is already in the cache by getting its name */
  222. BSTR name;
  223. if (SUCCEEDED(ITypeLib_GetDocumentation(TL, -1, &name, NULL, NULL, NULL))) {
  224. typelib_name = php_com_olestring_to_string(name, &typelib_name_len, obj->code_page TSRMLS_CC);
  225. if (SUCCESS == zend_ts_hash_add(&php_com_typelibraries, typelib_name, typelib_name_len+1, (void*)&TL, sizeof(ITypeLib*), NULL)) {
  226. php_com_import_typelib(TL, mode, obj->code_page TSRMLS_CC);
  227. /* add a reference for the hash */
  228. ITypeLib_AddRef(TL);
  229. }
  230. } else {
  231. /* try it anyway */
  232. php_com_import_typelib(TL, mode, obj->code_page TSRMLS_CC);
  233. }
  234. ITypeLib_Release(TL);
  235. }
  236. }
  237. }
  238. /* }}} */
  239. /* {{{ proto object com_get_active_object(string progid [, int code_page ])
  240. Returns a handle to an already running instance of a COM object */
  241. PHP_FUNCTION(com_get_active_object)
  242. {
  243. CLSID clsid;
  244. char *module_name;
  245. int module_name_len;
  246. long code_page = COMG(code_page);
  247. IUnknown *unk = NULL;
  248. IDispatch *obj = NULL;
  249. HRESULT res;
  250. OLECHAR *module = NULL;
  251. php_com_initialize(TSRMLS_C);
  252. if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l",
  253. &module_name, &module_name_len, &code_page)) {
  254. php_com_throw_exception(E_INVALIDARG, "Invalid arguments!" TSRMLS_CC);
  255. return;
  256. }
  257. module = php_com_string_to_olestring(module_name, module_name_len, code_page TSRMLS_CC);
  258. res = CLSIDFromString(module, &clsid);
  259. if (FAILED(res)) {
  260. php_com_throw_exception(res, NULL TSRMLS_CC);
  261. } else {
  262. res = GetActiveObject(&clsid, NULL, &unk);
  263. if (FAILED(res)) {
  264. php_com_throw_exception(res, NULL TSRMLS_CC);
  265. } else {
  266. res = IUnknown_QueryInterface(unk, &IID_IDispatch, &obj);
  267. if (FAILED(res)) {
  268. php_com_throw_exception(res, NULL TSRMLS_CC);
  269. } else if (obj) {
  270. /* we got our dispatchable object */
  271. php_com_wrap_dispatch(return_value, obj, code_page TSRMLS_CC);
  272. }
  273. }
  274. }
  275. if (obj) {
  276. IDispatch_Release(obj);
  277. }
  278. if (unk) {
  279. IUnknown_Release(obj);
  280. }
  281. efree(module);
  282. }
  283. /* }}} */
  284. /* Performs an Invoke on the given com object.
  285. * returns a failure code and creates an exception if there was an error */
  286. HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member,
  287. WORD flags, DISPPARAMS *disp_params, VARIANT *v, int silent, int allow_noarg TSRMLS_DC)
  288. {
  289. HRESULT hr;
  290. unsigned int arg_err;
  291. EXCEPINFO e = {0};
  292. hr = IDispatch_Invoke(V_DISPATCH(&obj->v), id_member,
  293. &IID_NULL, LOCALE_SYSTEM_DEFAULT, flags, disp_params, v, &e, &arg_err);
  294. if (silent == 0 && FAILED(hr)) {
  295. char *source = NULL, *desc = NULL, *msg = NULL;
  296. int source_len, desc_len;
  297. switch (hr) {
  298. case DISP_E_EXCEPTION:
  299. if (e.bstrSource) {
  300. source = php_com_olestring_to_string(e.bstrSource, &source_len, obj->code_page TSRMLS_CC);
  301. SysFreeString(e.bstrSource);
  302. }
  303. if (e.bstrDescription) {
  304. desc = php_com_olestring_to_string(e.bstrDescription, &desc_len, obj->code_page TSRMLS_CC);
  305. SysFreeString(e.bstrDescription);
  306. }
  307. if (PG(html_errors)) {
  308. spprintf(&msg, 0, "<b>Source:</b> %s<br/><b>Description:</b> %s",
  309. source ? source : "Unknown",
  310. desc ? desc : "Unknown");
  311. } else {
  312. spprintf(&msg, 0, "Source: %s\nDescription: %s",
  313. source ? source : "Unknown",
  314. desc ? desc : "Unknown");
  315. }
  316. if (desc) {
  317. efree(desc);
  318. }
  319. if (source) {
  320. efree(source);
  321. }
  322. if (e.bstrHelpFile) {
  323. SysFreeString(e.bstrHelpFile);
  324. }
  325. break;
  326. case DISP_E_PARAMNOTFOUND:
  327. case DISP_E_TYPEMISMATCH:
  328. desc = php_win32_error_to_msg(hr);
  329. spprintf(&msg, 0, "Parameter %d: %s", arg_err, desc);
  330. LocalFree(desc);
  331. break;
  332. case DISP_E_BADPARAMCOUNT:
  333. if ((disp_params->cArgs + disp_params->cNamedArgs == 0) && (allow_noarg == 1)) {
  334. /* if getting a property and they are missing all parameters,
  335. * we want to create a proxy object for them; so lets not create an
  336. * exception here */
  337. msg = NULL;
  338. break;
  339. }
  340. /* else fall through */
  341. default:
  342. desc = php_win32_error_to_msg(hr);
  343. spprintf(&msg, 0, "Error [0x%08x] %s", hr, desc);
  344. LocalFree(desc);
  345. break;
  346. }
  347. if (msg) {
  348. php_com_throw_exception(hr, msg TSRMLS_CC);
  349. efree(msg);
  350. }
  351. }
  352. return hr;
  353. }
  354. /* map an ID to a name */
  355. HRESULT php_com_get_id_of_name(php_com_dotnet_object *obj, char *name,
  356. int namelen, DISPID *dispid TSRMLS_DC)
  357. {
  358. OLECHAR *olename;
  359. HRESULT hr;
  360. DISPID *dispid_ptr;
  361. if (namelen == -1) {
  362. namelen = strlen(name);
  363. }
  364. if (obj->id_of_name_cache && SUCCESS == zend_hash_find(obj->id_of_name_cache, name, namelen, (void**)&dispid_ptr)) {
  365. *dispid = *dispid_ptr;
  366. return S_OK;
  367. }
  368. olename = php_com_string_to_olestring(name, namelen, obj->code_page TSRMLS_CC);
  369. if (obj->typeinfo) {
  370. hr = ITypeInfo_GetIDsOfNames(obj->typeinfo, &olename, 1, dispid);
  371. if (FAILED(hr)) {
  372. hr = IDispatch_GetIDsOfNames(V_DISPATCH(&obj->v), &IID_NULL, &olename, 1, LOCALE_SYSTEM_DEFAULT, dispid);
  373. if (SUCCEEDED(hr)) {
  374. /* fall back on IDispatch direct */
  375. ITypeInfo_Release(obj->typeinfo);
  376. obj->typeinfo = NULL;
  377. }
  378. }
  379. } else {
  380. hr = IDispatch_GetIDsOfNames(V_DISPATCH(&obj->v), &IID_NULL, &olename, 1, LOCALE_SYSTEM_DEFAULT, dispid);
  381. }
  382. efree(olename);
  383. if (SUCCEEDED(hr)) {
  384. /* cache the mapping */
  385. if (!obj->id_of_name_cache) {
  386. ALLOC_HASHTABLE(obj->id_of_name_cache);
  387. zend_hash_init(obj->id_of_name_cache, 2, NULL, NULL, 0);
  388. }
  389. zend_hash_update(obj->id_of_name_cache, name, namelen, dispid, sizeof(*dispid), NULL);
  390. }
  391. return hr;
  392. }
  393. /* the core of COM */
  394. int php_com_do_invoke_byref(php_com_dotnet_object *obj, char *name, int namelen,
  395. WORD flags, VARIANT *v, int nargs, zval ***args TSRMLS_DC)
  396. {
  397. DISPID dispid, altdispid;
  398. DISPPARAMS disp_params;
  399. HRESULT hr;
  400. VARIANT *vargs = NULL, *byref_vals = NULL;
  401. int i, byref_count = 0, j;
  402. zend_internal_function *f = (zend_internal_function*)EG(current_execute_data)->function_state.function;
  403. /* assumption: that the active function (f) is the function we generated for the engine */
  404. if (!f || f->arg_info == NULL) {
  405. f = NULL;
  406. }
  407. hr = php_com_get_id_of_name(obj, name, namelen, &dispid TSRMLS_CC);
  408. if (FAILED(hr)) {
  409. char *winerr = NULL;
  410. char *msg = NULL;
  411. winerr = php_win32_error_to_msg(hr);
  412. spprintf(&msg, 0, "Unable to lookup `%s': %s", name, winerr);
  413. LocalFree(winerr);
  414. php_com_throw_exception(hr, msg TSRMLS_CC);
  415. efree(msg);
  416. return FAILURE;
  417. }
  418. if (nargs) {
  419. vargs = (VARIANT*)safe_emalloc(sizeof(VARIANT), nargs, 0);
  420. }
  421. if (f) {
  422. for (i = 0; i < nargs; i++) {
  423. if (f->arg_info[nargs - i - 1].pass_by_reference) {
  424. byref_count++;
  425. }
  426. }
  427. }
  428. if (byref_count) {
  429. byref_vals = (VARIANT*)safe_emalloc(sizeof(VARIANT), byref_count, 0);
  430. for (j = 0, i = 0; i < nargs; i++) {
  431. if (f->arg_info[nargs - i - 1].pass_by_reference) {
  432. /* put the value into byref_vals instead */
  433. php_com_variant_from_zval(&byref_vals[j], *args[nargs - i - 1], obj->code_page TSRMLS_CC);
  434. /* if it is already byref, "move" it into the vargs array, otherwise
  435. * make vargs a reference to this value */
  436. if (V_VT(&byref_vals[j]) & VT_BYREF) {
  437. memcpy(&vargs[i], &byref_vals[j], sizeof(vargs[i]));
  438. VariantInit(&byref_vals[j]); /* leave the variant slot empty to simplify cleanup */
  439. } else {
  440. VariantInit(&vargs[i]);
  441. V_VT(&vargs[i]) = V_VT(&byref_vals[j]) | VT_BYREF;
  442. /* union magic ensures that this works out */
  443. vargs[i].byref = &V_UINT(&byref_vals[j]);
  444. }
  445. j++;
  446. } else {
  447. php_com_variant_from_zval(&vargs[i], *args[nargs - i - 1], obj->code_page TSRMLS_CC);
  448. }
  449. }
  450. } else {
  451. /* Invoke'd args are in reverse order */
  452. for (i = 0; i < nargs; i++) {
  453. php_com_variant_from_zval(&vargs[i], *args[nargs - i - 1], obj->code_page TSRMLS_CC);
  454. }
  455. }
  456. disp_params.cArgs = nargs;
  457. disp_params.cNamedArgs = 0;
  458. disp_params.rgvarg = vargs;
  459. disp_params.rgdispidNamedArgs = NULL;
  460. if (flags & DISPATCH_PROPERTYPUT) {
  461. altdispid = DISPID_PROPERTYPUT;
  462. disp_params.rgdispidNamedArgs = &altdispid;
  463. disp_params.cNamedArgs = 1;
  464. }
  465. /* this will create an exception if needed */
  466. hr = php_com_invoke_helper(obj, dispid, flags, &disp_params, v, 0, 0 TSRMLS_CC);
  467. /* release variants */
  468. if (vargs) {
  469. for (i = 0, j = 0; i < nargs; i++) {
  470. /* if this was byref, update the zval */
  471. if (f && f->arg_info[nargs - i - 1].pass_by_reference) {
  472. SEPARATE_ZVAL_IF_NOT_REF(args[nargs - i - 1]);
  473. /* if the variant is pointing at the byref_vals, we need to map
  474. * the pointee value as a zval; otherwise, the value is pointing
  475. * into an existing PHP variant record */
  476. if (V_VT(&vargs[i]) & VT_BYREF) {
  477. if (vargs[i].byref == &V_UINT(&byref_vals[j])) {
  478. /* copy that value */
  479. php_com_zval_from_variant(*args[nargs - i - 1], &byref_vals[j],
  480. obj->code_page TSRMLS_CC);
  481. }
  482. } else {
  483. /* not sure if this can ever happen; the variant we marked as BYREF
  484. * is no longer BYREF - copy its value */
  485. php_com_zval_from_variant(*args[nargs - i - 1], &vargs[i],
  486. obj->code_page TSRMLS_CC);
  487. }
  488. VariantClear(&byref_vals[j]);
  489. j++;
  490. }
  491. VariantClear(&vargs[i]);
  492. }
  493. efree(vargs);
  494. }
  495. return SUCCEEDED(hr) ? SUCCESS : FAILURE;
  496. }
  497. int php_com_do_invoke_by_id(php_com_dotnet_object *obj, DISPID dispid,
  498. WORD flags, VARIANT *v, int nargs, zval **args, int silent, int allow_noarg TSRMLS_DC)
  499. {
  500. DISPID altdispid;
  501. DISPPARAMS disp_params;
  502. HRESULT hr;
  503. VARIANT *vargs = NULL;
  504. int i;
  505. if (nargs) {
  506. vargs = (VARIANT*)safe_emalloc(sizeof(VARIANT), nargs, 0);
  507. }
  508. /* Invoke'd args are in reverse order */
  509. for (i = 0; i < nargs; i++) {
  510. php_com_variant_from_zval(&vargs[i], args[nargs - i - 1], obj->code_page TSRMLS_CC);
  511. }
  512. disp_params.cArgs = nargs;
  513. disp_params.cNamedArgs = 0;
  514. disp_params.rgvarg = vargs;
  515. disp_params.rgdispidNamedArgs = NULL;
  516. if (flags & DISPATCH_PROPERTYPUT) {
  517. altdispid = DISPID_PROPERTYPUT;
  518. disp_params.rgdispidNamedArgs = &altdispid;
  519. disp_params.cNamedArgs = 1;
  520. }
  521. /* this will create an exception if needed */
  522. hr = php_com_invoke_helper(obj, dispid, flags, &disp_params, v, silent, allow_noarg TSRMLS_CC);
  523. /* release variants */
  524. if (vargs) {
  525. for (i = 0; i < nargs; i++) {
  526. VariantClear(&vargs[i]);
  527. }
  528. efree(vargs);
  529. }
  530. /* a bit of a hack this, but it's needed for COM array access. */
  531. if (hr == DISP_E_BADPARAMCOUNT)
  532. return hr;
  533. return SUCCEEDED(hr) ? SUCCESS : FAILURE;
  534. }
  535. int php_com_do_invoke(php_com_dotnet_object *obj, char *name, int namelen,
  536. WORD flags, VARIANT *v, int nargs, zval **args, int allow_noarg TSRMLS_DC)
  537. {
  538. DISPID dispid;
  539. HRESULT hr;
  540. char *winerr = NULL;
  541. char *msg = NULL;
  542. hr = php_com_get_id_of_name(obj, name, namelen, &dispid TSRMLS_CC);
  543. if (FAILED(hr)) {
  544. winerr = php_win32_error_to_msg(hr);
  545. spprintf(&msg, 0, "Unable to lookup `%s': %s", name, winerr);
  546. LocalFree(winerr);
  547. php_com_throw_exception(hr, msg TSRMLS_CC);
  548. efree(msg);
  549. return FAILURE;
  550. }
  551. return php_com_do_invoke_by_id(obj, dispid, flags, v, nargs, args, 0, allow_noarg TSRMLS_CC);
  552. }
  553. /* {{{ proto string com_create_guid()
  554. Generate a globally unique identifier (GUID) */
  555. PHP_FUNCTION(com_create_guid)
  556. {
  557. GUID retval;
  558. OLECHAR *guid_string;
  559. if (zend_parse_parameters_none() == FAILURE) {
  560. return;
  561. }
  562. php_com_initialize(TSRMLS_C);
  563. if (CoCreateGuid(&retval) == S_OK && StringFromCLSID(&retval, &guid_string) == S_OK) {
  564. Z_TYPE_P(return_value) = IS_STRING;
  565. Z_STRVAL_P(return_value) = php_com_olestring_to_string(guid_string, &Z_STRLEN_P(return_value), CP_ACP TSRMLS_CC);
  566. CoTaskMemFree(guid_string);
  567. } else {
  568. RETURN_FALSE;
  569. }
  570. }
  571. /* }}} */
  572. /* {{{ proto bool com_event_sink(object comobject, object sinkobject [, mixed sinkinterface])
  573. Connect events from a COM object to a PHP object */
  574. PHP_FUNCTION(com_event_sink)
  575. {
  576. zval *object, *sinkobject, *sink=NULL;
  577. char *dispname = NULL, *typelibname = NULL;
  578. zend_bool gotguid = 0;
  579. php_com_dotnet_object *obj;
  580. ITypeInfo *typeinfo = NULL;
  581. RETVAL_FALSE;
  582. if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oo|z/",
  583. &object, php_com_variant_class_entry, &sinkobject, &sink)) {
  584. RETURN_FALSE;
  585. }
  586. php_com_initialize(TSRMLS_C);
  587. obj = CDNO_FETCH(object);
  588. if (sink && Z_TYPE_P(sink) == IS_ARRAY) {
  589. /* 0 => typelibname, 1 => dispname */
  590. zval **tmp;
  591. if (zend_hash_index_find(Z_ARRVAL_P(sink), 0, (void**)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_STRING)
  592. typelibname = Z_STRVAL_PP(tmp);
  593. if (zend_hash_index_find(Z_ARRVAL_P(sink), 1, (void**)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_STRING)
  594. dispname = Z_STRVAL_PP(tmp);
  595. } else if (sink != NULL) {
  596. convert_to_string(sink);
  597. dispname = Z_STRVAL_P(sink);
  598. }
  599. typeinfo = php_com_locate_typeinfo(typelibname, obj, dispname, 1 TSRMLS_CC);
  600. if (typeinfo) {
  601. HashTable *id_to_name;
  602. ALLOC_HASHTABLE(id_to_name);
  603. if (php_com_process_typeinfo(typeinfo, id_to_name, 0, &obj->sink_id, obj->code_page TSRMLS_CC)) {
  604. /* Create the COM wrapper for this sink */
  605. obj->sink_dispatch = php_com_wrapper_export_as_sink(sinkobject, &obj->sink_id, id_to_name TSRMLS_CC);
  606. /* Now hook it up to the source */
  607. php_com_object_enable_event_sink(obj, TRUE TSRMLS_CC);
  608. RETVAL_TRUE;
  609. } else {
  610. FREE_HASHTABLE(id_to_name);
  611. }
  612. }
  613. if (typeinfo) {
  614. ITypeInfo_Release(typeinfo);
  615. }
  616. }
  617. /* }}} */
  618. /* {{{ proto bool com_print_typeinfo(object comobject | string typelib, string dispinterface, bool wantsink)
  619. Print out a PHP class definition for a dispatchable interface */
  620. PHP_FUNCTION(com_print_typeinfo)
  621. {
  622. zval *arg1;
  623. char *ifacename = NULL;
  624. char *typelibname = NULL;
  625. int ifacelen;
  626. zend_bool wantsink = 0;
  627. php_com_dotnet_object *obj = NULL;
  628. ITypeInfo *typeinfo;
  629. if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/|s!b", &arg1, &ifacename,
  630. &ifacelen, &wantsink)) {
  631. RETURN_FALSE;
  632. }
  633. php_com_initialize(TSRMLS_C);
  634. if (Z_TYPE_P(arg1) == IS_OBJECT) {
  635. CDNO_FETCH_VERIFY(obj, arg1);
  636. } else {
  637. convert_to_string(arg1);
  638. typelibname = Z_STRVAL_P(arg1);
  639. }
  640. typeinfo = php_com_locate_typeinfo(typelibname, obj, ifacename, wantsink ? 1 : 0 TSRMLS_CC);
  641. if (typeinfo) {
  642. php_com_process_typeinfo(typeinfo, NULL, 1, NULL, obj ? obj->code_page : COMG(code_page) TSRMLS_CC);
  643. ITypeInfo_Release(typeinfo);
  644. RETURN_TRUE;
  645. } else {
  646. zend_error(E_WARNING, "Unable to find typeinfo using the parameters supplied");
  647. }
  648. RETURN_FALSE;
  649. }
  650. /* }}} */
  651. /* {{{ proto bool com_message_pump([int timeoutms])
  652. Process COM messages, sleeping for up to timeoutms milliseconds */
  653. PHP_FUNCTION(com_message_pump)
  654. {
  655. long timeoutms = 0;
  656. MSG msg;
  657. DWORD result;
  658. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &timeoutms) == FAILURE)
  659. RETURN_FALSE;
  660. php_com_initialize(TSRMLS_C);
  661. result = MsgWaitForMultipleObjects(0, NULL, FALSE, timeoutms, QS_ALLINPUT);
  662. if (result == WAIT_OBJECT_0) {
  663. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  664. TranslateMessage(&msg);
  665. DispatchMessage(&msg);
  666. }
  667. /* we processed messages */
  668. RETVAL_TRUE;
  669. } else {
  670. /* we did not process messages (timed out) */
  671. RETVAL_FALSE;
  672. }
  673. }
  674. /* }}} */
  675. /* {{{ proto bool com_load_typelib(string typelib_name [, int case_insensitive])
  676. Loads a Typelibrary and registers its constants */
  677. PHP_FUNCTION(com_load_typelib)
  678. {
  679. char *name;
  680. int namelen;
  681. ITypeLib *pTL = NULL;
  682. zend_bool cs = TRUE;
  683. int codepage = COMG(code_page);
  684. int cached = 0;
  685. if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &name, &namelen, &cs)) {
  686. return;
  687. }
  688. RETVAL_FALSE;
  689. php_com_initialize(TSRMLS_C);
  690. pTL = php_com_load_typelib_via_cache(name, codepage, &cached TSRMLS_CC);
  691. if (pTL) {
  692. if (cached) {
  693. RETVAL_TRUE;
  694. } else if (php_com_import_typelib(pTL, cs ? CONST_CS : 0, codepage TSRMLS_CC) == SUCCESS) {
  695. RETVAL_TRUE;
  696. }
  697. ITypeLib_Release(pTL);
  698. pTL = NULL;
  699. }
  700. }
  701. /* }}} */
  702. /*
  703. * Local variables:
  704. * tab-width: 4
  705. * c-basic-offset: 4
  706. * End:
  707. * vim600: noet sw=4 ts=4 fdm=marker
  708. * vim<600: noet sw=4 ts=4
  709. */