diff options
-rw-r--r-- | ext/com_dotnet/com_com.c | 52 | ||||
-rw-r--r-- | ext/com_dotnet/com_extension.c | 5 | ||||
-rwxr-xr-x | ext/com_dotnet/com_persist.c | 789 | ||||
-rw-r--r-- | ext/com_dotnet/config.w32 | 2 | ||||
-rw-r--r-- | ext/com_dotnet/php_com_dotnet_internal.h | 4 |
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); |