com_persist.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Author: Wez Furlong <wez@thebrainroom.com> |
  14. +----------------------------------------------------------------------+
  15. */
  16. /* Infrastructure for working with persistent COM objects.
  17. * Implements: IStream* wrapper for PHP streams.
  18. * TODO: Magic __wakeup and __sleep handlers for serialization
  19. * (can wait till 5.1) */
  20. #ifdef HAVE_CONFIG_H
  21. #include "config.h"
  22. #endif
  23. #include "php.h"
  24. #include "php_ini.h"
  25. #include "ext/standard/info.h"
  26. #include "php_com_dotnet.h"
  27. #include "php_com_dotnet_internal.h"
  28. #include "Zend/zend_exceptions.h"
  29. #include "com_persist_arginfo.h"
  30. /* {{{ expose php_stream as a COM IStream */
  31. typedef struct {
  32. CONST_VTBL struct IStreamVtbl *lpVtbl;
  33. DWORD engine_thread;
  34. LONG refcount;
  35. php_stream *stream;
  36. zend_resource *res;
  37. } php_istream;
  38. static int le_istream;
  39. static void istream_destructor(php_istream *stm);
  40. static void istream_dtor(zend_resource *rsrc)
  41. {
  42. php_istream *stm = (php_istream *)rsrc->ptr;
  43. istream_destructor(stm);
  44. }
  45. #define FETCH_STM() \
  46. php_istream *stm = (php_istream*)This; \
  47. if (GetCurrentThreadId() != stm->engine_thread) \
  48. return RPC_E_WRONG_THREAD;
  49. #define FETCH_STM_EX() \
  50. php_istream *stm = (php_istream*)This; \
  51. if (GetCurrentThreadId() != stm->engine_thread) \
  52. return RPC_E_WRONG_THREAD;
  53. static HRESULT STDMETHODCALLTYPE stm_queryinterface(
  54. IStream *This,
  55. /* [in] */ REFIID riid,
  56. /* [iid_is][out] */ void **ppvObject)
  57. {
  58. FETCH_STM_EX();
  59. if (IsEqualGUID(&IID_IUnknown, riid) ||
  60. IsEqualGUID(&IID_IStream, riid)) {
  61. *ppvObject = This;
  62. InterlockedIncrement(&stm->refcount);
  63. return S_OK;
  64. }
  65. *ppvObject = NULL;
  66. return E_NOINTERFACE;
  67. }
  68. static ULONG STDMETHODCALLTYPE stm_addref(IStream *This)
  69. {
  70. FETCH_STM_EX();
  71. return InterlockedIncrement(&stm->refcount);
  72. }
  73. static ULONG STDMETHODCALLTYPE stm_release(IStream *This)
  74. {
  75. ULONG ret;
  76. FETCH_STM();
  77. ret = InterlockedDecrement(&stm->refcount);
  78. if (ret == 0) {
  79. /* destroy it */
  80. if (stm->res)
  81. zend_list_delete(stm->res);
  82. }
  83. return ret;
  84. }
  85. static HRESULT STDMETHODCALLTYPE stm_read(IStream *This, void *pv, ULONG cb, ULONG *pcbRead)
  86. {
  87. ULONG nread;
  88. FETCH_STM();
  89. nread = (ULONG)php_stream_read(stm->stream, pv, cb);
  90. if (pcbRead) {
  91. *pcbRead = nread > 0 ? nread : 0;
  92. }
  93. if (nread > 0) {
  94. return S_OK;
  95. }
  96. return S_FALSE;
  97. }
  98. static HRESULT STDMETHODCALLTYPE stm_write(IStream *This, void const *pv, ULONG cb, ULONG *pcbWritten)
  99. {
  100. ssize_t nwrote;
  101. FETCH_STM();
  102. nwrote = php_stream_write(stm->stream, pv, cb);
  103. if (pcbWritten) {
  104. *pcbWritten = nwrote > 0 ? (ULONG)nwrote : 0;
  105. }
  106. if (nwrote > 0) {
  107. return S_OK;
  108. }
  109. return S_FALSE;
  110. }
  111. static HRESULT STDMETHODCALLTYPE stm_seek(IStream *This, LARGE_INTEGER dlibMove,
  112. DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
  113. {
  114. off_t offset;
  115. int whence;
  116. int ret;
  117. FETCH_STM();
  118. switch (dwOrigin) {
  119. case STREAM_SEEK_SET: whence = SEEK_SET; break;
  120. case STREAM_SEEK_CUR: whence = SEEK_CUR; break;
  121. case STREAM_SEEK_END: whence = SEEK_END; break;
  122. default:
  123. return STG_E_INVALIDFUNCTION;
  124. }
  125. if (dlibMove.HighPart) {
  126. /* we don't support 64-bit offsets */
  127. return STG_E_INVALIDFUNCTION;
  128. }
  129. offset = (off_t) dlibMove.QuadPart;
  130. ret = php_stream_seek(stm->stream, offset, whence);
  131. if (plibNewPosition) {
  132. plibNewPosition->QuadPart = (ULONGLONG)(ret >= 0 ? ret : 0);
  133. }
  134. return ret >= 0 ? S_OK : STG_E_INVALIDFUNCTION;
  135. }
  136. static HRESULT STDMETHODCALLTYPE stm_set_size(IStream *This, ULARGE_INTEGER libNewSize)
  137. {
  138. FETCH_STM();
  139. if (libNewSize.HighPart) {
  140. return STG_E_INVALIDFUNCTION;
  141. }
  142. if (php_stream_truncate_supported(stm->stream)) {
  143. int ret = php_stream_truncate_set_size(stm->stream, (size_t)libNewSize.QuadPart);
  144. if (ret == 0) {
  145. return S_OK;
  146. }
  147. }
  148. return STG_E_INVALIDFUNCTION;
  149. }
  150. static HRESULT STDMETHODCALLTYPE stm_copy_to(IStream *This, IStream *pstm, ULARGE_INTEGER cb,
  151. ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
  152. {
  153. FETCH_STM_EX();
  154. return E_NOTIMPL;
  155. }
  156. static HRESULT STDMETHODCALLTYPE stm_commit(IStream *This, DWORD grfCommitFlags)
  157. {
  158. FETCH_STM();
  159. php_stream_flush(stm->stream);
  160. return S_OK;
  161. }
  162. static HRESULT STDMETHODCALLTYPE stm_revert(IStream *This)
  163. {
  164. /* NOP */
  165. return S_OK;
  166. }
  167. static HRESULT STDMETHODCALLTYPE stm_lock_region(IStream *This,
  168. ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD lockType)
  169. {
  170. return STG_E_INVALIDFUNCTION;
  171. }
  172. static HRESULT STDMETHODCALLTYPE stm_unlock_region(IStream *This,
  173. ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD lockType)
  174. {
  175. return STG_E_INVALIDFUNCTION;
  176. }
  177. static HRESULT STDMETHODCALLTYPE stm_stat(IStream *This,
  178. STATSTG *pstatstg, DWORD grfStatFlag)
  179. {
  180. return STG_E_INVALIDFUNCTION;
  181. }
  182. static HRESULT STDMETHODCALLTYPE stm_clone(IStream *This, IStream **ppstm)
  183. {
  184. return STG_E_INVALIDFUNCTION;
  185. }
  186. static struct IStreamVtbl php_istream_vtbl = {
  187. stm_queryinterface,
  188. stm_addref,
  189. stm_release,
  190. stm_read,
  191. stm_write,
  192. stm_seek,
  193. stm_set_size,
  194. stm_copy_to,
  195. stm_commit,
  196. stm_revert,
  197. stm_lock_region,
  198. stm_unlock_region,
  199. stm_stat,
  200. stm_clone
  201. };
  202. static void istream_destructor(php_istream *stm)
  203. {
  204. if (stm->refcount > 0) {
  205. CoDisconnectObject((IUnknown*)stm, 0);
  206. }
  207. zend_list_delete(stm->stream->res);
  208. CoTaskMemFree(stm);
  209. }
  210. /* }}} */
  211. PHP_COM_DOTNET_API IStream *php_com_wrapper_export_stream(php_stream *stream)
  212. {
  213. php_istream *stm = (php_istream*)CoTaskMemAlloc(sizeof(*stm));
  214. if (stm == NULL)
  215. return NULL;
  216. memset(stm, 0, sizeof(*stm));
  217. stm->engine_thread = GetCurrentThreadId();
  218. stm->lpVtbl = &php_istream_vtbl;
  219. stm->refcount = 1;
  220. stm->stream = stream;
  221. GC_ADDREF(stream->res);
  222. stm->res = zend_register_resource(stm, le_istream);
  223. return (IStream*)stm;
  224. }
  225. #define CPH_METHOD(fname) PHP_METHOD(COMPersistHelper, fname)
  226. #define CPH_FETCH() php_com_persist_helper *helper = (php_com_persist_helper*)Z_OBJ_P(getThis());
  227. #define CPH_NO_OBJ() if (helper->unk == NULL) { php_com_throw_exception(E_INVALIDARG, "No COM object is associated with this helper instance"); RETURN_THROWS(); }
  228. typedef struct {
  229. zend_object std;
  230. long codepage;
  231. IUnknown *unk;
  232. IPersistStream *ips;
  233. IPersistStreamInit *ipsi;
  234. IPersistFile *ipf;
  235. } php_com_persist_helper;
  236. static zend_object_handlers helper_handlers;
  237. static zend_class_entry *helper_ce;
  238. static inline HRESULT get_persist_stream(php_com_persist_helper *helper)
  239. {
  240. if (!helper->ips && helper->unk) {
  241. return IUnknown_QueryInterface(helper->unk, &IID_IPersistStream, &helper->ips);
  242. }
  243. return helper->ips ? S_OK : E_NOTIMPL;
  244. }
  245. static inline HRESULT get_persist_stream_init(php_com_persist_helper *helper)
  246. {
  247. if (!helper->ipsi && helper->unk) {
  248. return IUnknown_QueryInterface(helper->unk, &IID_IPersistStreamInit, &helper->ipsi);
  249. }
  250. return helper->ipsi ? S_OK : E_NOTIMPL;
  251. }
  252. static inline HRESULT get_persist_file(php_com_persist_helper *helper)
  253. {
  254. if (!helper->ipf && helper->unk) {
  255. return IUnknown_QueryInterface(helper->unk, &IID_IPersistFile, &helper->ipf);
  256. }
  257. return helper->ipf ? S_OK : E_NOTIMPL;
  258. }
  259. /* {{{ Determines the filename into which an object will be saved, or false if none is set, via IPersistFile::GetCurFile */
  260. CPH_METHOD(GetCurFileName)
  261. {
  262. HRESULT res;
  263. OLECHAR *olename = NULL;
  264. CPH_FETCH();
  265. if (zend_parse_parameters_none() == FAILURE) {
  266. RETURN_THROWS();
  267. }
  268. CPH_NO_OBJ();
  269. res = get_persist_file(helper);
  270. if (helper->ipf) {
  271. res = IPersistFile_GetCurFile(helper->ipf, &olename);
  272. if (res == S_OK) {
  273. size_t len;
  274. char *str = php_com_olestring_to_string(olename,
  275. &len, helper->codepage);
  276. RETVAL_STRINGL(str, len);
  277. // TODO: avoid reallocarion???
  278. efree(str);
  279. CoTaskMemFree(olename);
  280. return;
  281. } else if (res == S_FALSE) {
  282. CoTaskMemFree(olename);
  283. RETURN_FALSE;
  284. }
  285. php_com_throw_exception(res, NULL);
  286. } else {
  287. php_com_throw_exception(res, NULL);
  288. }
  289. }
  290. /* }}} */
  291. /* {{{ Persist object data to file, via IPersistFile::Save */
  292. CPH_METHOD(SaveToFile)
  293. {
  294. HRESULT res;
  295. char *filename, *fullpath = NULL;
  296. size_t filename_len;
  297. bool remember = TRUE;
  298. OLECHAR *olefilename = NULL;
  299. CPH_FETCH();
  300. if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "p!|b",
  301. &filename, &filename_len, &remember)) {
  302. RETURN_THROWS();
  303. }
  304. CPH_NO_OBJ();
  305. res = get_persist_file(helper);
  306. if (helper->ipf) {
  307. if (filename) {
  308. fullpath = expand_filepath(filename, NULL);
  309. if (!fullpath) {
  310. RETURN_FALSE;
  311. }
  312. if (php_check_open_basedir(fullpath)) {
  313. efree(fullpath);
  314. RETURN_FALSE;
  315. }
  316. olefilename = php_com_string_to_olestring(fullpath, strlen(fullpath), helper->codepage);
  317. efree(fullpath);
  318. }
  319. res = IPersistFile_Save(helper->ipf, olefilename, remember);
  320. if (SUCCEEDED(res)) {
  321. if (!olefilename) {
  322. res = IPersistFile_GetCurFile(helper->ipf, &olefilename);
  323. if (S_OK == res) {
  324. IPersistFile_SaveCompleted(helper->ipf, olefilename);
  325. CoTaskMemFree(olefilename);
  326. olefilename = NULL;
  327. }
  328. } else if (remember) {
  329. IPersistFile_SaveCompleted(helper->ipf, olefilename);
  330. }
  331. }
  332. if (olefilename) {
  333. efree(olefilename);
  334. }
  335. if (FAILED(res)) {
  336. php_com_throw_exception(res, NULL);
  337. }
  338. } else {
  339. php_com_throw_exception(res, NULL);
  340. }
  341. }
  342. /* }}} */
  343. /* {{{ Load object data from file, via IPersistFile::Load */
  344. CPH_METHOD(LoadFromFile)
  345. {
  346. HRESULT res;
  347. char *filename, *fullpath;
  348. size_t filename_len;
  349. zend_long flags = 0;
  350. OLECHAR *olefilename;
  351. CPH_FETCH();
  352. if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "p|l",
  353. &filename, &filename_len, &flags)) {
  354. RETURN_THROWS();
  355. }
  356. CPH_NO_OBJ();
  357. res = get_persist_file(helper);
  358. if (helper->ipf) {
  359. if (!(fullpath = expand_filepath(filename, NULL))) {
  360. RETURN_FALSE;
  361. }
  362. if (php_check_open_basedir(fullpath)) {
  363. efree(fullpath);
  364. RETURN_FALSE;
  365. }
  366. olefilename = php_com_string_to_olestring(fullpath, strlen(fullpath), helper->codepage);
  367. efree(fullpath);
  368. res = IPersistFile_Load(helper->ipf, olefilename, (DWORD)flags);
  369. efree(olefilename);
  370. if (FAILED(res)) {
  371. php_com_throw_exception(res, NULL);
  372. }
  373. } else {
  374. php_com_throw_exception(res, NULL);
  375. }
  376. }
  377. /* }}} */
  378. /* {{{ Gets maximum stream size required to store the object data, via IPersistStream::GetSizeMax (or IPersistStreamInit::GetSizeMax) */
  379. CPH_METHOD(GetMaxStreamSize)
  380. {
  381. HRESULT res;
  382. ULARGE_INTEGER size;
  383. CPH_FETCH();
  384. if (zend_parse_parameters_none() == FAILURE) {
  385. RETURN_THROWS();
  386. }
  387. CPH_NO_OBJ();
  388. res = get_persist_stream_init(helper);
  389. if (helper->ipsi) {
  390. res = IPersistStreamInit_GetSizeMax(helper->ipsi, &size);
  391. } else {
  392. res = get_persist_stream(helper);
  393. if (helper->ips) {
  394. res = IPersistStream_GetSizeMax(helper->ips, &size);
  395. } else {
  396. php_com_throw_exception(res, NULL);
  397. RETURN_THROWS();
  398. }
  399. }
  400. if (res != S_OK) {
  401. php_com_throw_exception(res, NULL);
  402. } else {
  403. /* TODO: handle 64 bit properly */
  404. RETURN_LONG((zend_long)size.QuadPart);
  405. }
  406. }
  407. /* }}} */
  408. /* {{{ Initializes the object to a default state, via IPersistStreamInit::InitNew */
  409. CPH_METHOD(InitNew)
  410. {
  411. HRESULT res;
  412. CPH_FETCH();
  413. if (zend_parse_parameters_none() == FAILURE) {
  414. RETURN_THROWS();
  415. }
  416. CPH_NO_OBJ();
  417. res = get_persist_stream_init(helper);
  418. if (helper->ipsi) {
  419. res = IPersistStreamInit_InitNew(helper->ipsi);
  420. if (res != S_OK) {
  421. php_com_throw_exception(res, NULL);
  422. } else {
  423. RETURN_TRUE;
  424. }
  425. } else {
  426. php_com_throw_exception(res, NULL);
  427. }
  428. }
  429. /* }}} */
  430. /* {{{ Initializes an object from the stream where it was previously saved, via IPersistStream::Load or OleLoadFromStream */
  431. CPH_METHOD(LoadFromStream)
  432. {
  433. zval *zstm;
  434. php_stream *stream;
  435. IStream *stm = NULL;
  436. HRESULT res;
  437. CPH_FETCH();
  438. if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zstm)) {
  439. RETURN_THROWS();
  440. }
  441. php_stream_from_zval_no_verify(stream, zstm);
  442. if (stream == NULL) {
  443. php_com_throw_exception(E_INVALIDARG, "expected a stream");
  444. RETURN_THROWS();
  445. }
  446. stm = php_com_wrapper_export_stream(stream);
  447. if (stm == NULL) {
  448. php_com_throw_exception(E_UNEXPECTED, "failed to wrap stream");
  449. RETURN_THROWS();
  450. }
  451. res = S_OK;
  452. RETVAL_TRUE;
  453. if (helper->unk == NULL) {
  454. IDispatch *disp = NULL;
  455. /* we need to create an object and load using OleLoadFromStream */
  456. res = OleLoadFromStream(stm, &IID_IDispatch, &disp);
  457. if (SUCCEEDED(res)) {
  458. php_com_wrap_dispatch(return_value, disp, COMG(code_page));
  459. }
  460. } else {
  461. res = get_persist_stream_init(helper);
  462. if (helper->ipsi) {
  463. res = IPersistStreamInit_Load(helper->ipsi, stm);
  464. } else {
  465. res = get_persist_stream(helper);
  466. if (helper->ips) {
  467. res = IPersistStreamInit_Load(helper->ipsi, stm);
  468. }
  469. }
  470. }
  471. IStream_Release(stm);
  472. if (FAILED(res)) {
  473. php_com_throw_exception(res, NULL);
  474. RETURN_THROWS();
  475. }
  476. }
  477. /* }}} */
  478. /* {{{ Saves the object to a stream, via IPersistStream::Save */
  479. CPH_METHOD(SaveToStream)
  480. {
  481. zval *zstm;
  482. php_stream *stream;
  483. IStream *stm = NULL;
  484. HRESULT res;
  485. CPH_FETCH();
  486. CPH_NO_OBJ();
  487. if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zstm)) {
  488. RETURN_THROWS();
  489. }
  490. php_stream_from_zval_no_verify(stream, zstm);
  491. if (stream == NULL) {
  492. php_com_throw_exception(E_INVALIDARG, "expected a stream");
  493. RETURN_THROWS();
  494. }
  495. stm = php_com_wrapper_export_stream(stream);
  496. if (stm == NULL) {
  497. php_com_throw_exception(E_UNEXPECTED, "failed to wrap stream");
  498. RETURN_THROWS();
  499. }
  500. res = get_persist_stream_init(helper);
  501. if (helper->ipsi) {
  502. res = IPersistStreamInit_Save(helper->ipsi, stm, TRUE);
  503. } else {
  504. res = get_persist_stream(helper);
  505. if (helper->ips) {
  506. res = IPersistStream_Save(helper->ips, stm, TRUE);
  507. }
  508. }
  509. IStream_Release(stm);
  510. if (FAILED(res)) {
  511. php_com_throw_exception(res, NULL);
  512. RETURN_THROWS();
  513. }
  514. RETURN_TRUE;
  515. }
  516. /* }}} */
  517. /* {{{ Creates a persistence helper object, usually associated with a com_object */
  518. CPH_METHOD(__construct)
  519. {
  520. php_com_dotnet_object *obj = NULL;
  521. zval *zobj = NULL;
  522. CPH_FETCH();
  523. if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|O!",
  524. &zobj, php_com_variant_class_entry)) {
  525. RETURN_THROWS();
  526. }
  527. if (!zobj) {
  528. return;
  529. }
  530. obj = CDNO_FETCH(zobj);
  531. if (V_VT(&obj->v) != VT_DISPATCH || V_DISPATCH(&obj->v) == NULL) {
  532. php_com_throw_exception(E_INVALIDARG, "parameter must represent an IDispatch COM object");
  533. RETURN_THROWS();
  534. }
  535. /* it is always safe to cast an interface to IUnknown */
  536. helper->unk = (IUnknown*)V_DISPATCH(&obj->v);
  537. IUnknown_AddRef(helper->unk);
  538. helper->codepage = obj->code_page;
  539. }
  540. /* }}} */
  541. static void helper_free_storage(zend_object *obj)
  542. {
  543. php_com_persist_helper *object = (php_com_persist_helper*)obj;
  544. if (object->ipf) {
  545. IPersistFile_Release(object->ipf);
  546. }
  547. if (object->ips) {
  548. IPersistStream_Release(object->ips);
  549. }
  550. if (object->ipsi) {
  551. IPersistStreamInit_Release(object->ipsi);
  552. }
  553. if (object->unk) {
  554. IUnknown_Release(object->unk);
  555. }
  556. zend_object_std_dtor(&object->std);
  557. }
  558. static zend_object* helper_clone(zend_object *obj)
  559. {
  560. php_com_persist_helper *clone, *object = (php_com_persist_helper*) obj;
  561. clone = emalloc(sizeof(*object));
  562. memcpy(clone, object, sizeof(*object));
  563. zend_object_std_init(&clone->std, object->std.ce);
  564. if (clone->ipf) {
  565. IPersistFile_AddRef(clone->ipf);
  566. }
  567. if (clone->ips) {
  568. IPersistStream_AddRef(clone->ips);
  569. }
  570. if (clone->ipsi) {
  571. IPersistStreamInit_AddRef(clone->ipsi);
  572. }
  573. if (clone->unk) {
  574. IUnknown_AddRef(clone->unk);
  575. }
  576. return (zend_object*)clone;
  577. }
  578. static zend_object* helper_new(zend_class_entry *ce)
  579. {
  580. php_com_persist_helper *helper;
  581. helper = emalloc(sizeof(*helper));
  582. memset(helper, 0, sizeof(*helper));
  583. zend_object_std_init(&helper->std, helper_ce);
  584. helper->std.handlers = &helper_handlers;
  585. return &helper->std;
  586. }
  587. int php_com_persist_minit(INIT_FUNC_ARGS)
  588. {
  589. memcpy(&helper_handlers, &std_object_handlers, sizeof(helper_handlers));
  590. helper_handlers.free_obj = helper_free_storage;
  591. helper_handlers.clone_obj = helper_clone;
  592. helper_ce = register_class_COMPersistHelper();
  593. helper_ce->create_object = helper_new;
  594. le_istream = zend_register_list_destructors_ex(istream_dtor,
  595. NULL, "com_dotnet_istream_wrapper", module_number);
  596. return SUCCESS;
  597. }