From: Pat Thoyts Date: Thu, 18 Jun 2009 01:57:39 +0000 (+0100) Subject: Support object initialization from a Tcl channel. X-Git-Url: http://privyetmir.co.uk/gitweb?a=commitdiff_plain;ds=inline;p=tcom Support object initialization from a Tcl channel. This commit allows a Tcl channel to be presented to an object upon creation as an IStream. The object can then use its IPersistStream interface to initialize itself via tcom::ref createobject -init $chan $progid Signed-off-by: Pat Thoyts --- diff --git a/src/refCmd.cpp b/src/refCmd.cpp index 9a96457..b477291 100644 --- a/src/refCmd.cpp +++ b/src/refCmd.cpp @@ -6,6 +6,7 @@ #include "TypeInfo.h" #include "TclObject.h" #include "Arguments.h" +#include "tclStream.h" static int referenceObjCmd(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []); HandleSupport Extension::referenceHandles(referenceObjCmd); @@ -737,14 +738,15 @@ Extension::refCmd ( bool clsIdOpt = false; DWORD clsCtx = CLSCTX_SERVER; + IStreamPtr pStream; int i = 2; for (; i < objc; ++i) { static char *options[] = { - "-clsid", "-inproc", "-local", "-remote", NULL + "-clsid", "-inproc", "-local", "-remote", "-init", NULL }; enum OptionEnum { - OPTION_CLSID, OPTION_INPROC, OPTION_LOCAL, OPTION_REMOTE + OPTION_CLSID, OPTION_INPROC, OPTION_LOCAL, OPTION_REMOTE, OPTION_INIT }; int index; @@ -766,6 +768,13 @@ Extension::refCmd ( case OPTION_REMOTE: clsCtx = CLSCTX_REMOTE_SERVER; break; + case OPTION_INIT: + if (objc < i+1) { + Tcl_WrongNumArgs(interp, i-1, objv, "-init channel"); + return TCL_ERROR; + } + GetStreamFromObj(interp, objv[++i], &pStream); + break; } } @@ -774,7 +783,7 @@ Extension::refCmd ( interp, 2, objv, - "?-clsid? ?-inproc? ?-local? ?-remote? progID ?hostName?"); + "?-clsid? ?-inproc? ?-local? ?-remote? ?-init channel? progID ?hostName?"); return TCL_ERROR; } @@ -811,6 +820,19 @@ Extension::refCmd ( : Reference::createInstance(progId, clsCtx, hostName); } + IPersistStreamInitPtr pPersistStreamInit; + if (SUCCEEDED(pReference->unknown()->QueryInterface(&pPersistStreamInit))) { + if (pStream) { + pPersistStreamInit->Load(pStream); + } else { + pPersistStreamInit->InitNew(); + } + } else if (pStream) { + IPersistStreamPtr pPersistStream; + if (SUCCEEDED(pReference->unknown()->QueryInterface(&pPersistStream))) + pPersistStream->Load(pStream); + } + Tcl_SetObjResult( interp, referenceHandles.newObj(interp, pReference)); diff --git a/src/tclStream.cpp b/src/tclStream.cpp new file mode 100644 index 0000000..d9aa254 --- /dev/null +++ b/src/tclStream.cpp @@ -0,0 +1,225 @@ +#include "tclStream.h" +#include + +class TclStream : public IStream +{ +public: + // IUnknown + STDMETHOD(QueryInterface)(REFIID riid, void** ppv); + STDMETHOD_(ULONG, AddRef)(); + STDMETHOD_(ULONG, Release)(); + + // ISequentialStream + STDMETHOD(Read)(void *pv, ULONG cb, ULONG *pcbRead); + STDMETHOD(Write)(void const *pv, ULONG cb, ULONG *pcbWritten); + + // IStream + STDMETHOD(Seek)(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition); + STDMETHOD(SetSize)(ULARGE_INTEGER libNewSize); + STDMETHOD(CopyTo)(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten); + STDMETHOD(Commit)(DWORD grfCommitFlags); + STDMETHOD(Revert)(); + STDMETHOD(LockRegion)(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType); + STDMETHOD(UnlockRegion)(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType); + STDMETHOD(Stat)(STATSTG *pstatstg, DWORD grfStatFlag); + STDMETHOD(Clone)(IStream **ppstm); + +public: + TclStream(Tcl_Channel channel, const char *name); + virtual ~TclStream(); + HRESULT FinalConstruct(); + +private: + long m_lRefCount; + Tcl_Channel m_channel; + char *m_name; + STATSTG m_statstg; +}; + +// ------------------------------------------------------------------------- +// IUnknown methods + +STDMETHODIMP TclStream:: +QueryInterface(REFIID riid, void** ppv) +{ + HRESULT hr = E_NOINTERFACE; + *ppv = 0; + + if (riid == IID_IUnknown + || riid == IID_IStream + || riid == IID_ISequentialStream) + { + *ppv = static_cast(this); + static_cast(*ppv)->AddRef(); + hr = S_OK; + } + + return hr; +} + +STDMETHODIMP_(ULONG) TclStream:: +AddRef() +{ + return InterlockedIncrement(&m_lRefCount); +} + +STDMETHODIMP_(ULONG) TclStream:: +Release() +{ + if (InterlockedDecrement(&m_lRefCount) == 0) + { + delete this; + return 0; + } + return m_lRefCount; +} + +// ------------------------------------------------------------------------- +// ISequentialStream methods + +STDMETHODIMP TclStream:: +Read(void *pv, ULONG cb, ULONG *pcbRead) +{ + ULONG cbRead = 0; + cbRead = Tcl_Read(m_channel, (char *)pv, cb); + if (pcbRead) *pcbRead = cbRead; + //if (cbRead == -1) Tcl_GetErrno(); + return (cbRead == -1) ? E_FAIL : S_OK; +} + +STDMETHODIMP TclStream:: +Write(void const *pv, ULONG cb, ULONG *pcbWritten) +{ + ULONG cbWrote = 0; + cbWrote = Tcl_Write(m_channel, (const char *)pv, cb); + if (pcbWritten) *pcbWritten = cbWrote; + return (cbWrote == -1) ? E_FAIL : S_OK; +} + +// ------------------------------------------------------------------------- +// IStream methods +// + +STDMETHODIMP TclStream:: +Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) +{ + int mode = SEEK_SET; + switch (dwOrigin) { + case STREAM_SEEK_SET: mode = SEEK_SET; break; + case STREAM_SEEK_CUR: mode = SEEK_CUR; break; + case STREAM_SEEK_END: mode = SEEK_END; break; + default: + return STG_E_INVALIDFUNCTION; + } + + Tcl_WideInt pos = Tcl_Seek(m_channel, dlibMove.QuadPart, mode); + if (plibNewPosition) + plibNewPosition->QuadPart = pos; + return (pos == -1) ? E_FAIL : S_OK; +} + +STDMETHODIMP TclStream:: +SetSize(ULARGE_INTEGER libNewSize) +{ + return STG_E_INVALIDFUNCTION; +} + +STDMETHODIMP TclStream:: +CopyTo(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) +{ + return E_NOTIMPL; +} + +STDMETHODIMP TclStream:: +Commit(DWORD grfCommitFlags) +{ + return S_OK; +} + +STDMETHODIMP TclStream:: +Revert() +{ + return S_OK; +} + +STDMETHODIMP TclStream:: +LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) +{ + return STG_E_INVALIDFUNCTION; +} + +STDMETHODIMP TclStream:: +UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) +{ + return STG_E_INVALIDFUNCTION; +} + +STDMETHODIMP TclStream:: +Stat(STATSTG *pstatstg, DWORD grfStatFlag) +{ + HRESULT hr = STG_E_INVALIDPOINTER; + if (pstatstg) + { + CopyMemory(pstatstg, &m_statstg, sizeof(STATSTG)); + hr = S_OK; + + if (!(grfStatFlag & STATFLAG_NONAME)) + { + int nChars = MultiByteToWideChar(CP_ACP, 0, m_name, -1, NULL, 0); + pstatstg->pwcsName = (LPWSTR)CoTaskMemAlloc((nChars+1)*sizeof(WCHAR)); + nChars = MultiByteToWideChar(CP_ACP, 0, m_name, nChars, + pstatstg->pwcsName, nChars+1); + } + } + return hr; +} + +STDMETHODIMP TclStream:: +Clone(IStream **ppstm) +{ + return E_NOTIMPL; +} + +// ------------------------------------------------------------------------- + +TclStream::TclStream(Tcl_Channel channel, const char *name) +{ + m_channel = channel; + m_name = strdup(name); +} + +TclStream::~TclStream() +{ + free(m_name); +} + +HRESULT TclStream:: +FinalConstruct() +{ + ZeroMemory(&m_statstg, sizeof(STATSTG)); + m_statstg.type = STGTY_STREAM; + //m_statstg.cbSize.QuadPart = size; + //TimetToFileTime(date, &m_statstg.mtime); + //m_statstg.ctime = m_statstg.mtime; + //m_statstg.atime = m_statstg.mtime; + //m_statstg.grfMode = m_grfFlags; + m_statstg.grfLocksSupported = (DWORD)0; + return S_OK; +} + +// ------------------------------------------------------------------------- + +HRESULT +GetStreamFromObj(Tcl_Interp *interp, Tcl_Obj *chanObj, IStream **ppStream) +{ + int mode = 0; + const char *name = Tcl_GetString(chanObj); + Tcl_Channel channel = Tcl_GetChannel(interp, name, &mode); + if (channel == NULL) + return E_INVALIDARG; + TclStream *pTclStream = new TclStream(channel, name); + HRESULT hr = pTclStream->FinalConstruct(); + if (SUCCEEDED(hr)) + hr = pTclStream->QueryInterface(IID_IStream, (void **)ppStream); + return hr; +} diff --git a/src/tclStream.h b/src/tclStream.h new file mode 100644 index 0000000..2d6a7ac --- /dev/null +++ b/src/tclStream.h @@ -0,0 +1,9 @@ +#ifndef tclStream_h_INCLUDE +#define tclStream_h_INCLUDE + +#include +#include "tclRunTime.h" // + +HRESULT GetStreamFromObj(Tcl_Interp *interp, Tcl_Obj *chanObj, IStream **ppStream); + +#endif // tclStream_h_INCLUDE diff --git a/src/tcom.dsp b/src/tcom.dsp index e7cc1ee..b370600 100644 --- a/src/tcom.dsp +++ b/src/tcom.dsp @@ -41,11 +41,11 @@ RSC=rc.exe # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" -# PROP Intermediate_Dir "Release" +# PROP Intermediate_Dir "Release\Objects" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TCOM_EXPORTS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /Zi /Od /I "\tcl\include" /D "NDEBUG" /D "_WIN32_DCOM" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TCOM_EXPORTS" /D "TCOM_VTBL_SERVER" /D "TCL_THREADS" /D "USE_TCL_STUBS" /D "USE_NON_CONST" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /Zi /O2 /I "c:\opt\tcl8.4\include" /D "NDEBUG" /D "_WIN32_DCOM" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "TCOM_EXPORTS" /D "TCOM_VTBL_SERVER" /D "TCL_THREADS" /D "USE_TCL_STUBS" /D "USE_NON_CONST" /YX /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -55,7 +55,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 rpcrt4.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /libpath:"\tcl\lib" +# ADD LINK32 rpcrt4.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /libpath:"c:\opt\tcl8.4\lib" !ELSEIF "$(CFG)" == "tcom - Win32 Debug" @@ -254,6 +254,10 @@ SOURCE=.\TclObject.cpp # End Source File # Begin Source File +SOURCE=.\tclStream.cpp +# End Source File +# Begin Source File + SOURCE=.\tcomVersion.rc # End Source File # Begin Source File @@ -354,6 +358,10 @@ SOURCE=.\tclRunTime.h # End Source File # Begin Source File +SOURCE=.\tclStream.h +# End Source File +# Begin Source File + SOURCE=.\tcomApi.h # End Source File # Begin Source File