summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/com_dotnet/com_com.c52
-rw-r--r--ext/com_dotnet/com_extension.c5
-rwxr-xr-xext/com_dotnet/com_persist.c789
-rw-r--r--ext/com_dotnet/config.w322
-rw-r--r--ext/com_dotnet/php_com_dotnet_internal.h4
5 files changed, 850 insertions, 2 deletions
diff --git a/ext/com_dotnet/com_com.c b/ext/com_dotnet/com_com.c
index 09b2beaf3f..166dd07994 100644
--- a/ext/com_dotnet/com_com.c
+++ b/ext/com_dotnet/com_com.c
@@ -281,6 +281,58 @@ PHP_FUNCTION(com_create_instance)
}
/* }}} */
+/* {{{ proto object com_get_active_object(string progid [, int code_page ])
+ Returns a handle to an already running instance of a COM object */
+PHP_FUNCTION(com_get_active_object)
+{
+ CLSID clsid;
+ char *module_name;
+ long module_name_len;
+ long code_page = COMG(code_page);
+ IUnknown *unk = NULL;
+ IDispatch *obj = NULL;
+ HRESULT res;
+ OLECHAR *module = NULL;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l",
+ &module_name, &module_name_len, &code_page)) {
+ php_com_throw_exception(E_INVALIDARG, "Invalid arguments!" TSRMLS_CC);
+ return;
+ }
+
+ module = php_com_string_to_olestring(module_name, module_name_len, code_page TSRMLS_CC);
+
+ res = CLSIDFromString(module, &clsid);
+
+ if (FAILED(res)) {
+ php_com_throw_exception(res, NULL TSRMLS_CC);
+ } else {
+ res = GetActiveObject(&clsid, NULL, &unk);
+
+ if (FAILED(res)) {
+ php_com_throw_exception(res, NULL TSRMLS_CC);
+ } else {
+ res = IUnknown_QueryInterface(unk, &IID_IDispatch, &obj);
+
+ if (FAILED(res)) {
+ php_com_throw_exception(res, NULL TSRMLS_CC);
+ } else if (obj) {
+ /* we got our dispatchable object */
+ php_com_wrap_dispatch(return_value, obj, code_page TSRMLS_CC);
+ }
+ }
+ }
+
+ if (obj) {
+ IDispatch_Release(obj);
+ }
+ if (unk) {
+ IUnknown_Release(obj);
+ }
+ efree(module);
+}
+/* }}} */
+
/* Performs an Invoke on the given com object.
* returns a failure code and creates an exception if there was an error */
HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member,
diff --git a/ext/com_dotnet/com_extension.c b/ext/com_dotnet/com_extension.c
index 10763aebec..5148451460 100644
--- a/ext/com_dotnet/com_extension.c
+++ b/ext/com_dotnet/com_extension.c
@@ -70,6 +70,7 @@ function_entry com_dotnet_functions[] = {
PHP_FE(com_print_typeinfo, NULL)
PHP_FE(com_message_pump, NULL)
PHP_FE(com_load_typelib, NULL)
+ PHP_FE(com_get_active_object, NULL)
{ NULL, NULL, NULL }
};
@@ -187,7 +188,8 @@ PHP_MINIT_FUNCTION(com_dotnet)
ZEND_INIT_MODULE_GLOBALS(com_dotnet, php_com_dotnet_init_globals, NULL);
REGISTER_INI_ENTRIES();
- php_com_wrapper_minit(INIT_FUNC_ARGS_PASSTHRU);
+ php_com_wrapper_minit(INIT_FUNC_ARGS_PASSTHRU);
+ php_com_persist_minit(INIT_FUNC_ARGS_PASSTHRU);
INIT_CLASS_ENTRY(ce, "com_exception", NULL);
php_com_exception_class_entry = zend_register_internal_class_ex(&ce, zend_exception_get_default(), NULL TSRMLS_CC);
@@ -282,6 +284,7 @@ PHP_MINIT_FUNCTION(com_dotnet)
COM_CONST(DISP_E_DIVBYZERO);
COM_CONST(DISP_E_OVERFLOW);
COM_CONST(DISP_E_BADINDEX);
+ COM_CONST(MK_E_UNAVAILABLE);
return SUCCESS;
}
diff --git a/ext/com_dotnet/com_persist.c b/ext/com_dotnet/com_persist.c
new file mode 100755
index 0000000000..12a7e32a4a
--- /dev/null
+++ b/ext/com_dotnet/com_persist.c
@@ -0,0 +1,789 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-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. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@thebrainroom.com> |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+/* Infrastructure for working with persistent COM objects.
+ * Implements: IStream* wrapper for PHP streams.
+ * TODO: Magic __wakeup and __sleep handlers for serialization
+ * (can wait till 5.1) */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "php_com_dotnet.h"
+#include "php_com_dotnet_internal.h"
+#include "Zend/zend_exceptions.h"
+
+/* {{{ expose php_stream as a COM IStream */
+
+typedef struct {
+ CONST_VTBL struct IStreamVtbl *lpVtbl;
+ THREAD_T engine_thread;
+ LONG refcount;
+ php_stream *stream;
+ int id;
+} php_istream;
+
+static int le_istream;
+static void istream_destructor(php_istream *stm);
+
+static void istream_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ php_istream *stm = (php_istream *)rsrc->ptr;
+ istream_destructor(stm);
+}
+
+#define FETCH_STM() \
+ php_istream *stm = (php_istream*)This; \
+ if (tsrm_thread_id() != stm->engine_thread) \
+ return E_UNEXPECTED;
+
+static HRESULT STDMETHODCALLTYPE stm_queryinterface(
+ IStream *This,
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ void **ppvObject)
+{
+ TSRMLS_FETCH();
+ FETCH_STM();
+
+ if (IsEqualGUID(&IID_IUnknown, riid) ||
+ IsEqualGUID(&IID_IStream, riid)) {
+ *ppvObject = This;
+ InterlockedIncrement(&stm->refcount);
+ return S_OK;
+ }
+
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE stm_addref(IStream *This)
+{
+ TSRMLS_FETCH();
+ FETCH_STM();
+
+ return InterlockedIncrement(&stm->refcount);
+}
+
+static ULONG STDMETHODCALLTYPE stm_release(IStream *This)
+{
+ ULONG ret;
+ TSRMLS_FETCH();
+ FETCH_STM();
+
+ ret = InterlockedDecrement(&stm->refcount);
+ if (ret == 0) {
+ /* destroy it */
+ if (stm->id)
+ zend_list_delete(stm->id);
+ }
+ return ret;
+}
+
+static HRESULT STDMETHODCALLTYPE stm_read(IStream *This, void *pv, ULONG cb, ULONG *pcbRead)
+{
+ int nread;
+ TSRMLS_FETCH();
+ FETCH_STM();
+
+ nread = php_stream_read(stm->stream, pv, cb);
+
+ if (pcbRead) {
+ *pcbRead = nread > 0 ? nread : 0;
+ }
+ if (nread > 0) {
+ return S_OK;
+ }
+ return S_FALSE;
+}
+
+static HRESULT STDMETHODCALLTYPE stm_write(IStream *This, void const *pv, ULONG cb, ULONG *pcbWritten)
+{
+ int nwrote;
+ TSRMLS_FETCH();
+ FETCH_STM();
+
+ nwrote = php_stream_write(stm->stream, pv, cb);
+
+ if (pcbWritten) {
+ *pcbWritten = nwrote > 0 ? nwrote : 0;
+ }
+ if (nwrote > 0) {
+ return S_OK;
+ }
+ return S_FALSE;
+}
+
+static HRESULT STDMETHODCALLTYPE stm_seek(IStream *This, LARGE_INTEGER dlibMove,
+ DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
+{
+ off_t offset;
+ int whence;
+ int ret;
+ TSRMLS_FETCH();
+ FETCH_STM();
+
+ switch (dwOrigin) {
+ case STREAM_SEEK_SET: whence = SEEK_SET; break;
+ case STREAM_SEEK_CUR: whence = SEEK_CUR; break;
+ case STREAM_SEEK_END: whence = SEEK_END; break;
+ default:
+ return STG_E_INVALIDFUNCTION;
+ }
+
+ if (dlibMove.HighPart) {
+ /* we don't support 64-bit offsets */
+ return STG_E_INVALIDFUNCTION;
+ }
+
+ offset = dlibMove.QuadPart;
+
+ ret = php_stream_seek(stm->stream, offset, whence);
+
+ if (plibNewPosition) {
+ plibNewPosition->QuadPart = (ULONGLONG)(ret >= 0 ? ret : 0);
+ }
+
+ return ret >= 0 ? S_OK : STG_E_INVALIDFUNCTION;
+}
+
+static HRESULT STDMETHODCALLTYPE stm_set_size(IStream *This, ULARGE_INTEGER libNewSize)
+{
+ TSRMLS_FETCH();
+ FETCH_STM();
+
+ if (libNewSize.HighPart) {
+ return STG_E_INVALIDFUNCTION;
+ }
+
+ if (php_stream_truncate_supported(stm->stream)) {
+ int ret = php_stream_truncate_set_size(stm->stream, (size_t)libNewSize.QuadPart);
+
+ if (ret == 0) {
+ return S_OK;
+ }
+ }
+
+ return STG_E_INVALIDFUNCTION;
+}
+
+static HRESULT STDMETHODCALLTYPE stm_copy_to(IStream *This, IStream *pstm, ULARGE_INTEGER cb,
+ ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
+{
+ TSRMLS_FETCH();
+ FETCH_STM();
+
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE stm_commit(IStream *This, DWORD grfCommitFlags)
+{
+ TSRMLS_FETCH();
+ FETCH_STM();
+
+ php_stream_flush(stm->stream);
+
+ return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE stm_revert(IStream *This)
+{
+ /* NOP */
+ return S_OK;
+}
+
+static HRESULT STDMETHODCALLTYPE stm_lock_region(IStream *This,
+ ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD lockType)
+{
+ return STG_E_INVALIDFUNCTION;
+}
+
+static HRESULT STDMETHODCALLTYPE stm_unlock_region(IStream *This,
+ ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD lockType)
+{
+ return STG_E_INVALIDFUNCTION;
+}
+
+static HRESULT STDMETHODCALLTYPE stm_stat(IStream *This,
+ STATSTG *pstatstg, DWORD grfStatFlag)
+{
+ return STG_E_INVALIDFUNCTION;
+}
+
+static HRESULT STDMETHODCALLTYPE stm_clone(IStream *This, IStream **ppstm)
+{
+ return STG_E_INVALIDFUNCTION;
+}
+
+static struct IStreamVtbl php_istream_vtbl = {
+ stm_queryinterface,
+ stm_addref,
+ stm_release,
+ stm_read,
+ stm_write,
+ stm_seek,
+ stm_set_size,
+ stm_copy_to,
+ stm_commit,
+ stm_revert,
+ stm_lock_region,
+ stm_unlock_region,
+ stm_stat,
+ stm_clone
+};
+
+static void istream_destructor(php_istream *stm)
+{
+ TSRMLS_FETCH();
+
+ if (stm->id) {
+ int id = stm->id;
+ stm->id = 0;
+ zend_list_delete(id);
+ return;
+ }
+
+ if (stm->refcount > 0) {
+ CoDisconnectObject((IUnknown*)stm, 0);
+ }
+
+ zend_list_delete(stm->stream->rsrc_id);
+
+ CoTaskMemFree(stm);
+}
+/* }}} */
+
+PHPAPI IStream *php_com_wrapper_export_stream(php_stream *stream TSRMLS_DC)
+{
+ php_istream *stm = (php_istream*)CoTaskMemAlloc(sizeof(*stm));
+
+ if (stm == NULL)
+ return NULL;
+
+ memset(stm, 0, sizeof(*stm));
+ stm->engine_thread = tsrm_thread_id();
+ stm->lpVtbl = &php_istream_vtbl;
+ stm->refcount = 1;
+ stm->stream = stream;
+
+ zend_list_addref(stream->rsrc_id);
+ stm->id = zend_list_insert(stm, le_istream);
+
+ return (IStream*)stm;
+}
+
+#define CPH_ME(fname, arginfo) PHP_ME(com_persist, fname, arginfo, ZEND_ACC_PUBLIC)
+#define CPH_SME(fname, arginfo) PHP_ME(com_persist, fname, arginfo, ZEND_ACC_ALLOW_STATIC|ZEND_ACC_PUBLIC)
+#define CPH_METHOD(fname) static PHP_METHOD(com_persist, fname)
+
+#define CPH_FETCH() php_com_persist_helper *helper = (php_com_persist_helper*)zend_object_store_get_object(getThis() TSRMLS_CC);
+
+#define CPH_NO_OBJ() if (helper->unk == NULL) { php_com_throw_exception(E_INVALIDARG, "No COM object is associated with this helper instance" TSRMLS_CC); return; }
+
+typedef struct {
+ zend_object std;
+ long codepage;
+ IUnknown *unk;
+ IPersistStream *ips;
+ IPersistStreamInit *ipsi;
+ IPersistFile *ipf;
+} php_com_persist_helper;
+
+static zend_object_handlers helper_handlers;
+static zend_class_entry *helper_ce;
+
+static inline HRESULT get_persist_stream(php_com_persist_helper *helper)
+{
+ if (!helper->ips && helper->unk) {
+ return IUnknown_QueryInterface(helper->unk, &IID_IPersistStream, &helper->ips);
+ }
+ return helper->ips ? S_OK : E_NOTIMPL;
+}
+
+static inline HRESULT get_persist_stream_init(php_com_persist_helper *helper)
+{
+ if (!helper->ipsi && helper->unk) {
+ return IUnknown_QueryInterface(helper->unk, &IID_IPersistStreamInit, &helper->ipsi);
+ }
+ return helper->ipsi ? S_OK : E_NOTIMPL;
+}
+
+static inline HRESULT get_persist_file(php_com_persist_helper *helper)
+{
+ if (!helper->ipf && helper->unk) {
+ return IUnknown_QueryInterface(helper->unk, &IID_IPersistFile, &helper->ipf);
+ }
+ return helper->ipf ? S_OK : E_NOTIMPL;
+}
+
+
+/* {{{ proto string COMPersistHelper::GetCurFile()
+ Determines the filename into which an object will be saved, or false if none is set, via IPersistFile::GetCurFile */
+CPH_METHOD(GetCurFileName)
+{
+ HRESULT res;
+ OLECHAR *olename = NULL;
+ CPH_FETCH();
+
+ CPH_NO_OBJ();
+
+ res = get_persist_file(helper);
+ if (helper->ipf) {
+ res = IPersistFile_GetCurFile(helper->ipf, &olename);
+
+ if (res == S_OK) {
+ Z_TYPE_P(return_value) = IS_STRING;
+ Z_STRVAL_P(return_value) = php_com_olestring_to_string(olename,
+ &Z_STRLEN_P(return_value), helper->codepage TSRMLS_CC);
+ CoTaskMemFree(olename);
+ return;
+ } else if (res == S_FALSE) {
+ CoTaskMemFree(olename);
+ RETURN_FALSE;
+ }
+ php_com_throw_exception(res, NULL TSRMLS_CC);
+ } else {
+ php_com_throw_exception(res, NULL TSRMLS_CC);
+ }
+}
+/* }}} */
+
+
+/* {{{ proto bool COMPersistHelper::SaveToFile(string filename [, bool remember])
+ Persist object data to file, via IPersistFile::Save */
+CPH_METHOD(SaveToFile)
+{
+ HRESULT res;
+ char *filename, *fullpath = NULL;
+ long filename_len;
+ zend_bool remember = TRUE;
+ OLECHAR *olefilename = NULL;
+ CPH_FETCH();
+
+ CPH_NO_OBJ();
+
+ res = get_persist_file(helper);
+ if (helper->ipf) {
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!|b",
+ &filename, &filename_len, &remember)) {
+ php_com_throw_exception(E_INVALIDARG, "Invalid arguments" TSRMLS_CC);
+ return;
+ }
+
+ if (filename) {
+ fullpath = expand_filepath(filename, NULL TSRMLS_CC);
+
+ if (PG(safe_mode) && (!php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
+ RETURN_FALSE;
+ }
+
+ if (php_check_open_basedir(fullpath TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ olefilename = php_com_string_to_olestring(filename, strlen(fullpath), helper->codepage TSRMLS_CC);
+ efree(fullpath);
+ }
+ res = IPersistFile_Save(helper->ipf, olefilename, remember);
+ if (SUCCEEDED(res)) {
+ if (!olefilename) {
+ res = IPersistFile_GetCurFile(helper->ipf, &olefilename);
+ if (S_OK == res) {
+ IPersistFile_SaveCompleted(helper->ipf, olefilename);
+ CoTaskMemFree(olefilename);
+ olefilename = NULL;
+ }
+ } else if (remember) {
+ IPersistFile_SaveCompleted(helper->ipf, olefilename);
+ }
+ }
+
+ if (olefilename) {
+ efree(olefilename);
+ }
+
+ if (FAILED(res)) {
+ php_com_throw_exception(res, NULL TSRMLS_CC);
+ }
+
+ } else {
+ php_com_throw_exception(res, NULL TSRMLS_CC);
+ }
+}
+/* }}} */
+
+/* {{{ proto bool COMPersistHelper::LoadFromFile(string filename [, int flags])
+ Load object data from file, via IPersistFile::Load */
+CPH_METHOD(LoadFromFile)
+{
+ HRESULT res;
+ char *filename, *fullpath;
+ long filename_len;
+ long flags = 0;
+ OLECHAR *olefilename;
+ CPH_FETCH();
+
+ CPH_NO_OBJ();
+
+ res = get_persist_file(helper);
+ if (helper->ipf) {
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l",
+ &filename, &filename_len, &flags)) {
+ php_com_throw_exception(E_INVALIDARG, "Invalid arguments" TSRMLS_CC);
+ return;
+ }
+
+ fullpath = expand_filepath(filename, NULL TSRMLS_CC);
+
+ if (PG(safe_mode) && (!php_checkuid(fullpath, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
+ RETURN_FALSE;
+ }
+
+ if (php_check_open_basedir(fullpath TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ olefilename = php_com_string_to_olestring(fullpath, strlen(fullpath), helper->codepage TSRMLS_CC);
+ efree(fullpath);
+
+ res = IPersistFile_Load(helper->ipf, olefilename, flags);
+ efree(olefilename);
+
+ if (FAILED(res)) {
+ php_com_throw_exception(res, NULL TSRMLS_CC);
+ }
+
+ } else {
+ php_com_throw_exception(res, NULL TSRMLS_CC);
+ }
+}
+/* }}} */
+
+/* {{{ proto int COMPersistHelper::GetMaxStreamSize()
+ Gets maximum stream size required to store the object data, via IPersistStream::GetSizeMax (or IPersistStreamInit::GetSizeMax) */
+CPH_METHOD(GetMaxStreamSize)
+{
+ HRESULT res;
+ ULARGE_INTEGER size;
+ CPH_FETCH();
+
+ CPH_NO_OBJ();
+
+ res = get_persist_stream_init(helper);
+ if (helper->ipsi) {
+ res = IPersistStreamInit_GetSizeMax(helper->ipsi, &size);
+ } else {
+ res = get_persist_stream(helper);
+ if (helper->ips) {
+ res = IPersistStream_GetSizeMax(helper->ips, &size);
+ } else {
+ php_com_throw_exception(res, NULL TSRMLS_CC);
+ return;
+ }
+ }
+
+ if (res != S_OK) {
+ php_com_throw_exception(res, NULL TSRMLS_CC);
+ } else {
+ /* TODO: handle 64 bit properly */
+ RETURN_LONG((LONG)size.QuadPart);
+ }
+}
+/* }}} */
+
+/* {{{ proto int COMPersistHelper::InitNew()
+ Initializes the object to a default state, via IPersistStreamInit::InitNew */
+CPH_METHOD(InitNew)
+{
+ HRESULT res;
+ CPH_FETCH();
+
+ CPH_NO_OBJ();
+
+ res = get_persist_stream_init(helper);
+ if (helper->ipsi) {
+ res = IPersistStreamInit_InitNew(helper->ipsi);
+
+ if (res != S_OK) {
+ php_com_throw_exception(res, NULL TSRMLS_CC);
+ } else {
+ RETURN_TRUE;
+ }
+ } else {
+ php_com_throw_exception(res, NULL TSRMLS_CC);
+ }
+}
+/* }}} */
+
+/* {{{ proto mixed COMPersistHelper::LoadFromStream(resource stream)
+ Initializes an object from the stream where it was previously saved, via IPersistStream::Load or OleLoadFromStream */
+CPH_METHOD(LoadFromStream)
+{
+ zval *zstm;
+ php_stream *stream;
+ IStream *stm = NULL;
+ HRESULT res;
+ CPH_FETCH();
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstm)) {
+ php_com_throw_exception(E_INVALIDARG, "invalid arguments" TSRMLS_CC);
+ return;
+ }
+
+ php_stream_from_zval_no_verify(stream, &zstm);
+
+ if (stream == NULL) {
+ php_com_throw_exception(E_INVALIDARG, "expected a stream" TSRMLS_CC);
+ return;
+ }
+
+ stm = php_com_wrapper_export_stream(stream TSRMLS_CC);
+ if (stm == NULL) {
+ php_com_throw_exception(E_UNEXPECTED, "failed to wrap stream" TSRMLS_CC);
+ return;
+ }
+
+ res = S_OK;
+ RETVAL_TRUE;
+
+ if (helper->unk == NULL) {
+ IDispatch *disp = NULL;
+
+ /* we need to create an object and load using OleLoadFromStream */
+ res = OleLoadFromStream(stm, &IID_IDispatch, &disp);
+
+ if (SUCCEEDED(res)) {
+ php_com_wrap_dispatch(return_value, disp, COMG(code_page) TSRMLS_CC);
+ }
+ } else {
+ res = get_persist_stream_init(helper);
+ if (helper->ipsi) {
+ res = IPersistStreamInit_Load(helper->ipsi, stm);
+ } else {
+ res = get_persist_stream(helper);
+ if (helper->ips) {
+ res = IPersistStreamInit_Load(helper->ipsi, stm);
+ }
+ }
+ }
+ IStream_Release(stm);
+
+ if (FAILED(res)) {
+ php_com_throw_exception(res, NULL TSRMLS_CC);
+ RETURN_NULL();
+ }
+}
+/* }}} */
+
+/* {{{ proto int COMPersistHelper::SaveToStream(resource stream)
+ Saves the object to a stream, via IPersistStream::Save */
+CPH_METHOD(SaveToStream)
+{
+ zval *zstm;
+ php_stream *stream;
+ IStream *stm = NULL;
+ HRESULT res;
+ CPH_FETCH();
+
+ CPH_NO_OBJ();
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zstm)) {
+ php_com_throw_exception(E_INVALIDARG, "invalid arguments" TSRMLS_CC);
+ return;
+ }
+
+ php_stream_from_zval_no_verify(stream, &zstm);
+
+ if (stream == NULL) {
+ php_com_throw_exception(E_INVALIDARG, "expected a stream" TSRMLS_CC);
+ return;
+ }
+
+ stm = php_com_wrapper_export_stream(stream TSRMLS_CC);
+ if (stm == NULL) {
+ php_com_throw_exception(E_UNEXPECTED, "failed to wrap stream" TSRMLS_CC);
+ return;
+ }
+
+ res = get_persist_stream_init(helper);
+ if (helper->ipsi) {
+ res = IPersistStreamInit_Save(helper->ipsi, stm, TRUE);
+ } else {
+ res = get_persist_stream(helper);
+ if (helper->ips) {
+ res = IPersistStream_Save(helper->ips, stm, TRUE);
+ }
+ }
+
+ IStream_Release(stm);
+
+ if (FAILED(res)) {
+ php_com_throw_exception(res, NULL TSRMLS_CC);
+ return;
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto int COMPersistHelper::__construct([object com_object])
+ Creates a persistence helper object, usually associated with a com_object */
+CPH_METHOD(__construct)
+{
+ php_com_dotnet_object *obj = NULL;
+ zval *zobj = NULL;
+ CPH_FETCH();
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|O!",
+ &zobj, php_com_variant_class_entry)) {
+ php_com_throw_exception(E_INVALIDARG, "invalid arguments" TSRMLS_CC);
+ return;
+ }
+
+ if (!zobj) {
+ return;
+ }
+
+ obj = CDNO_FETCH(zobj);
+
+ if (V_VT(&obj->v) != VT_DISPATCH || V_DISPATCH(&obj->v) == NULL) {
+ php_com_throw_exception(E_INVALIDARG, "parameter must represent an IDispatch COM object" TSRMLS_CC);
+ return;
+ }
+
+ /* it is always safe to cast an interface to IUnknown */
+ helper->unk = (IUnknown*)V_DISPATCH(&obj->v);
+ IUnknown_AddRef(helper->unk);
+ helper->codepage = obj->code_page;
+}
+/* }}} */
+
+
+
+
+static zend_function_entry com_persist_helper_methods[] = {
+ CPH_ME(__construct, NULL)
+ CPH_ME(GetCurFileName, NULL)
+ CPH_ME(SaveToFile, NULL)
+ CPH_ME(LoadFromFile, NULL)
+ CPH_ME(GetMaxStreamSize, NULL)
+ CPH_ME(InitNew, NULL)
+ CPH_ME(LoadFromStream, NULL)
+ CPH_ME(SaveToStream, NULL)
+ {NULL, NULL, NULL}
+};
+
+static void helper_free_storage(void *obj TSRMLS_DC)
+{
+ php_com_persist_helper *object = (php_com_persist_helper*)obj;
+
+ if (object->ipf) {
+ IPersistFile_Release(object->ipf);
+ }
+ if (object->ips) {
+ IPersistStream_Release(object->ips);
+ }
+ if (object->ipsi) {
+ IPersistStreamInit_Release(object->ipsi);
+ }
+ if (object->unk) {
+ IUnknown_Release(object->unk);
+ }
+ zend_hash_destroy(object->std.properties);
+ FREE_HASHTABLE(object->std.properties);
+ efree(object);
+}
+
+
+static void helper_clone(void *obj, void **clone_ptr TSRMLS_DC)
+{
+ php_com_persist_helper *clone, *object = (php_com_persist_helper*)obj;
+ zval *tmp;
+
+ clone = emalloc(sizeof(*object));
+ memcpy(clone, object, sizeof(*object));
+ *clone_ptr = clone;
+
+ ALLOC_HASHTABLE(clone->std.properties);
+ zend_hash_init(clone->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
+
+ if (clone->ipf) {
+ IPersistFile_AddRef(clone->ipf);
+ }
+ if (clone->ips) {
+ IPersistStream_AddRef(clone->ips);
+ }
+ if (clone->ipsi) {
+ IPersistStreamInit_AddRef(clone->ipsi);
+ }
+ if (clone->unk) {
+ IUnknown_AddRef(clone->unk);
+ }
+}
+
+static zend_object_value helper_new(zend_class_entry *ce TSRMLS_DC)
+{
+ php_com_persist_helper *helper;
+ zend_object_value retval;
+ zval *tmp;
+
+ helper = emalloc(sizeof(*helper));
+ memset(helper, 0, sizeof(*helper));
+
+ ALLOC_HASHTABLE(helper->std.properties);
+ zend_hash_init(helper->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
+ helper->std.ce = helper_ce;
+
+ retval.handle = zend_objects_store_put(helper, NULL, helper_free_storage, helper_clone TSRMLS_CC);
+ retval.handlers = &helper_handlers;
+
+ return retval;
+}
+
+int php_com_persist_minit(INIT_FUNC_ARGS)
+{
+ zend_class_entry ce;
+
+ memcpy(&helper_handlers, zend_get_std_object_handlers(), sizeof(helper_handlers));
+ helper_handlers.clone_obj = NULL;
+
+ INIT_CLASS_ENTRY(ce, "COMPersistHelper", com_persist_helper_methods);
+ ce.create_object = helper_new;
+ helper_ce = zend_register_internal_class(&ce TSRMLS_CC);
+ helper_ce->ce_flags |= ZEND_ACC_FINAL;
+
+ le_istream = zend_register_list_destructors_ex(istream_dtor,
+ NULL, "com_dotnet_istream_wrapper", module_number);
+
+ return SUCCESS;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/com_dotnet/config.w32 b/ext/com_dotnet/config.w32
index cc1f3b86f6..1526392c24 100644
--- a/ext/com_dotnet/config.w32
+++ b/ext/com_dotnet/config.w32
@@ -7,7 +7,7 @@ if (PHP_COM_DOTNET == "yes") {
CHECK_LIB('oleaut32.lib', 'com_dotnet');
EXTENSION("com_dotnet", "com_com.c com_dotnet.c com_extension.c \
com_handlers.c com_iterator.c com_misc.c com_olechar.c \
- com_typeinfo.c com_variant.c com_wrapper.c com_saproxy.c");
+ com_typeinfo.c com_variant.c com_wrapper.c com_saproxy.c com_persist.c");
AC_DEFINE('HAVE_COM_DOTNET', 1, 'Have COM_DOTNET support');
CHECK_HEADER_ADD_INCLUDE('mscoree.h', 'CFLAGS_COM_DOTNET');
}
diff --git a/ext/com_dotnet/php_com_dotnet_internal.h b/ext/com_dotnet/php_com_dotnet_internal.h
index d60da9b075..31ce713f17 100644
--- a/ext/com_dotnet/php_com_dotnet_internal.h
+++ b/ext/com_dotnet/php_com_dotnet_internal.h
@@ -99,6 +99,7 @@ PHP_FUNCTION(com_create_guid);
PHP_FUNCTION(com_print_typeinfo);
PHP_FUNCTION(com_message_pump);
PHP_FUNCTION(com_load_typelib);
+PHP_FUNCTION(com_get_active_object);
HRESULT php_com_invoke_helper(php_com_dotnet_object *obj, DISPID id_member,
WORD flags, DISPPARAMS *disp_params, VARIANT *v TSRMLS_DC);
@@ -116,6 +117,9 @@ int php_com_wrapper_minit(INIT_FUNC_ARGS);
PHPAPI IDispatch *php_com_wrapper_export_as_sink(zval *val, GUID *sinkid, HashTable *id_to_name TSRMLS_DC);
PHPAPI IDispatch *php_com_wrapper_export(zval *val TSRMLS_DC);
+/* com_persist.c */
+int php_com_persist_minit(INIT_FUNC_ARGS);
+
/* com_variant.c */
PHP_FUNCTION(com_variant_create_instance);
PHP_FUNCTION(variant_set);