|
|
// This is a part of the Active Template Library.
// Copyright (C) 1996-2001 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Active Template Library Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Active Template Library product.
#ifndef __ATLSPRIV_H__
#define __ATLSPRIV_H__
#pragma once
#ifndef _WINSOCKAPI_
#include <winsock2.h>
#endif
#ifndef _WINSOCK2API_
#error Winsock2.h has to be included before including windows.h or use atlbase.h instead of windows.h
#endif
#ifndef _ATL_NO_DEFAULT_LIBS
#pragma comment(lib, "ws2_32.lib")
#endif // !_ATL_NO_DEFAULT_LIBS
#include <svcguid.h>
#include <atlcoll.h>
#include <mlang.h>
#include <atlutil.h>
// ATL_SOCK_TIMEOUT defines the amount of time
// this socket will block the calling thread waiting
// for the socket before the call times out.
#ifndef ATL_SOCK_TIMEOUT
#define ATL_SOCK_TIMEOUT 10000
#endif
#define ATL_WINSOCK_VER MAKELONG(2,0)
// This file contains unsupported code used in ATL implementation files. Most of
// this code is support code for various ATL Server functions.
namespace ATL{
// One of these objects can be created globally to turn
// on the socket stuff at CRT startup and shut it down
// on CRT term.
class _AtlWSAInit { public: _AtlWSAInit() throw() { m_dwErr = WSAEFAULT; }
bool Init() { if (!IsStarted()) m_dwErr = WSAStartup(ATL_WINSOCK_VER, &m_stData);
return m_dwErr == 0; }
bool IsStarted(){ return m_dwErr == 0; }
~_AtlWSAInit() throw() { if (!m_dwErr) WSACleanup(); }
WSADATA m_stData; DWORD m_dwErr; };
#ifndef _ATL_NO_GLOBAL_SOCKET_STARTUP
__declspec(selectany)_AtlWSAInit g_HttpInit; #endif
class ZEvtSyncSocket { public: ZEvtSyncSocket() throw(); ~ZEvtSyncSocket() throw(); operator SOCKET() throw(); void Close() throw(); void Term() throw(); bool Create(WORD wFlags=0) throw(); bool Create(short af, short st, short proto, WORD wFlags=0) throw(); bool Connect(LPCTSTR szAddr, unsigned short nPort) throw(); bool Connect(const SOCKADDR* psa) throw(); bool Write(WSABUF *pBuffers, int nCount, DWORD *pdwSize) throw(); bool Write(const unsigned char *pBuffIn, DWORD *pdwSize) throw(); bool Read(const unsigned char *pBuff, DWORD *pdwSize) throw(); bool Init(SOCKET hSocket, void * /*pData=NULL*/) throw(); DWORD GetSocketTimeout(); DWORD SetSocketTimeout(DWORD dwNewTimeout); bool SupportsScheme(ATL_URL_SCHEME scheme);
protected: DWORD m_dwCreateFlags; WSAEVENT m_hEventRead; WSAEVENT m_hEventWrite; WSAEVENT m_hEventConnect;
CComAutoCriticalSection m_csRead; CComAutoCriticalSection m_csWrite; SOCKET m_socket; bool m_bConnected; DWORD m_dwLastError; DWORD m_dwSocketTimeout; };
#define ATL_MAX_QUERYSET (sizeof(WSAQUERYSET) + 4096)
class CTCPAddrLookup { public: CTCPAddrLookup() throw(); ~CTCPAddrLookup() throw();
// properties for this class
__declspec(property(get=GetSockAddr)) const SOCKADDR* Addr; __declspec(property(get=GetSockAddrSize)) int AddrSize; // Takes a string that identifies a TCP service
// to look up. The szName parameter is either the name
// of a server (eg microsoft.com) or the dotted IP address
// of a server (eg 157.24.34.205). This function must succeed
// before accessing the Addr and AddrSize parameters.
// This function returns normal socket errors on failure
int GetRemoteAddr(LPCTSTR szName, short nPort) throw(); const SOCKADDR* GetSockAddr(); int GetSockAddrSize(); protected: SOCKADDR *m_pAddr; int m_nAddrSize; sockaddr_in m_saIn; WSAQUERYSET *m_pQuerySet; };
// MIME helper functions
extern __declspec(selectany) const DWORD ATL_MIME_DEFAULT_CP = 28591;
// This function is used to create an CSMTPConnection-compatible recipient string
// from a recipient string that is in a CMimeMessage object.
inline BOOL AtlMimeMakeRecipientsString(LPCSTR szNames, LPSTR szRecipients, LPDWORD pdwLen = NULL) throw() { ATLASSERT(szNames != NULL); ATLASSERT(szRecipients != NULL);
char ch; DWORD dwLen = 0; while ((ch = *szNames++) != '\0') { // Skip everything that is in double quotes
if (ch == '"') { while (*szNames && *szNames++ != '"'); } if (ch == '<') { // Extract the address from within the <>
while (*szNames && *szNames != '>') { *szRecipients++ = *szNames++; dwLen++; } // End it with a comma
*szRecipients++ = ','; dwLen++; } if (ch == '=') { // Skip any BEncoded or QEncoded parts
while (*szNames) { if (*szNames == '?' && *(szNames+1) == '=') { szNames+=2; break; } szNames++; } } szNames++; } if (dwLen != 0) { szRecipients--; dwLen--; } *szRecipients = '\0';
if (pdwLen) *pdwLen = dwLen;
return TRUE; }
// AtlMimeCharsetFromCodePage, AtlMimeConvertString
// are MIME multilanguage support functions.
// Get the MIME character set of the of the code page. The character set is copied
// into szCharset.
#ifndef ATLSMTP_DEFAULT_CSET
#define ATLSMTP_DEFAULT_CSET "iso-8859-1"
#endif
inline BOOL AtlMimeCharsetFromCodePage(LPSTR szCharset, UINT uiCodePage, IMultiLanguage* pMultiLanguage) throw() { ATLASSERT(szCharset != NULL);
if (!pMultiLanguage) { if ((uiCodePage == 0) || (uiCodePage == ATL_MIME_DEFAULT_CP)) { strcpy(szCharset, ATLSMTP_DEFAULT_CSET); } else { return FALSE; } } else { if (uiCodePage == 0) uiCodePage = GetACP();
HRESULT hr; MIMECPINFO cpInfo; memset(&cpInfo, 0x00, sizeof(cpInfo));
#ifdef __IMultiLanguage2_INTERFACE_DEFINED__
// if IMultiLanguage2 is available, use it
CComPtr<IMultiLanguage2> spMultiLanguage2; hr = pMultiLanguage->QueryInterface(__uuidof(IMultiLanguage2), (void **)&spMultiLanguage2); if (FAILED(hr) || !spMultiLanguage2.p) hr = pMultiLanguage->GetCodePageInfo(uiCodePage, &cpInfo); else hr = spMultiLanguage2->GetCodePageInfo(uiCodePage, LANGIDFROMLCID(GetThreadLocale()), &cpInfo);
#else // __IMultiLanguage2_INTERFACE_DEFINED__
hr = pMultiLanguage->GetCodePageInfo(uiCodePage, &cpInfo);
#endif // __IMultiLanguage2_INTERFACE_DEFINED__
if (hr != S_OK) return FALSE;
_ATLTRY { strcpy(szCharset, CW2A(cpInfo.wszWebCharset)); } _ATLCATCHALL() { return FALSE; } }
return TRUE; }
inline BOOL AtlMimeConvertStringW( IMultiLanguage *pMultiLanguage, UINT uiCodePage, LPCWSTR wszIn, LPSTR *ppszOut, UINT *pnLen) throw() { ATLASSERT( pMultiLanguage != NULL ); ATLASSERT( wszIn != NULL ); ATLASSERT( ppszOut != NULL ); ATLASSERT( pnLen != NULL );
*ppszOut = NULL; *pnLen = 0;
if (uiCodePage == 0) { uiCodePage = GetACP(); }
DWORD dwMode = 0; CHeapPtr<char> pszOut;
// get the length
HRESULT hr = pMultiLanguage->ConvertStringFromUnicode(&dwMode, uiCodePage, const_cast<LPWSTR>(wszIn), NULL, NULL, pnLen); if (SUCCEEDED(hr)) { // allocate the buffer
if (pszOut.Allocate(*pnLen)) { dwMode = 0; // do the conversion
hr = pMultiLanguage->ConvertStringFromUnicode(&dwMode, uiCodePage, const_cast<LPWSTR>(wszIn), NULL, pszOut, pnLen); if (SUCCEEDED(hr)) { *ppszOut = pszOut.Detach(); return TRUE; } } }
return FALSE; }
inline BOOL AtlMimeConvertStringA( IMultiLanguage *pMultiLanguage, UINT uiCodePage, LPCSTR szIn, LPSTR *ppszOut, UINT *pnLen) throw() { _ATLTRY { return AtlMimeConvertStringW(pMultiLanguage, uiCodePage, CA2W(szIn), ppszOut, pnLen); } _ATLCATCHALL() { return FALSE; } }
#ifdef _UNICODE
#define AtlMimeConvertString AtlMimeConvertStringW
#else
#define AtlMimeConvertString AtlMimeConvertStringA
#endif
// SOAP helpers
extern __declspec(selectany) const char * s_szAtlsWSDLSrf = "<?xml version=\"1.0\"?>\r\n" "<!-- ATL Server generated Web Service Description -->\r\n" "<definitions \r\n" " xmlns:s=\"http://www.w3.org/2000/10/XMLSchema\" \r\n" " xmlns:http=\"http://schemas.xmlsoap.org/wsdl/http/\" \r\n" " xmlns:mime=\"http://schemas.xmlsoap.org/wsdl/mime/\" \r\n" " xmlns:soap=\"http://schemas.xmlsoap.org/wsdl/soap/\" \r\n" " xmlns:soapenc=\"http://schemas.xmlsoap.org/soap/encoding/\" \r\n" " xmlns:s0=\"{{GetNamespace}}\" \r\n" " xmlns:wsdl=\"http://schemas.xmlsoap.org/wsdl/\"\r\n" " targetNamespace=\"{{GetNamespace}}\" \r\n" " xmlns=\"http://schemas.xmlsoap.org/wsdl/\"\r\n" ">\r\n" " <types>\r\n" " <s:schema targetNamespace=\"{{GetNamespace}}\" attributeFormDefault=\"qualified\" elementFormDefault=\"qualified\">\r\n" "{{while GetNextFunction}}\r\n" " <s:element name=\"{{GetFunctionName}}\">\r\n" " <s:complexType derivedBy=\"restriction\">\r\n" " <s:all>\r\n" "{{while GetNextParameter}}\r\n" "{{if IsInParameter}}\r\n" " <s:element name=\"{{GetParameterName}}\" {{if NotIsArrayParameter}}type=\"{{if IsParameterUDT}}s0:{{else}}s:{{endif}}{{GetParameterSoapType}}\"/{{else}}nullable=\"{{if IsParameterDynamicArray}}true{{else}}false{{endif}}\"{{endif}}>\r\n" "{{if IsArrayParameter}}\r\n" " <s:complexType derivedBy=\"restriction\">\r\n" " <s:all>\r\n" " <s:element name=\"{{GetParameterSoapType}}\" type=\"{{if IsParameterUDT}}s0:{{else}}s:{{endif}}{{GetParameterSoapType}}\" {{if IsParameterDynamicArray}}minOccurs=\"0\" maxOccurs=\"unbounded\"{{else}}{{if IsParameterOneDimensional}}minOccurs=\"{{GetParameterArraySize}}\" maxOccurs=\"{{GetParameterArraySize}}\"{{else}}soap:arrayType=\"{{GetParameterArraySoapDims}}\"{{endif}}{{endif}}/>\r\n" " </s:all>\r\n" " </s:complexType>\r\n" " </s:element>\r\n" "{{endif}}\r\n" "{{endif}}\r\n" "{{endwhile}}\r\n" " </s:all>\r\n" " </s:complexType>\r\n" " </s:element>\r\n" " <s:element name=\"{{GetFunctionName}}Response\">\r\n" " <s:complexType derivedBy=\"restriction\">\r\n" " <s:all>\r\n" "{{while GetNextParameter}}\r\n" "{{if IsOutParameter}}\r\n" " <s:element name=\"{{GetParameterName}}\" {{if NotIsArrayParameter}}type=\"{{if IsParameterUDT}}s0:{{else}}s:{{endif}}{{GetParameterSoapType}}\"/{{else}}nullable=\"{{if IsParameterDynamicArray}}true{{else}}false{{endif}}\"{{endif}}>\r\n" "{{if IsArrayParameter}}\r\n" " <s:complexType derivedBy=\"restriction\">\r\n" " <s:all>\r\n" " <s:element name=\"{{GetParameterSoapType}}\" type=\"{{if IsParameterUDT}}s0:{{else}}s:{{endif}}{{GetParameterSoapType}}\" {{if IsParameterDynamicArray}}minOccurs=\"0\" maxOccurs=\"unbounded\"{{else}}{{if IsParameterOneDimensional}}minOccurs=\"{{GetParameterArraySize}}\" maxOccurs=\"{{GetParameterArraySize}}\"{{else}}soap:arrayType=\"{{GetParameterArraySoapDims}}\"{{endif}}{{endif}}/>\r\n" " </s:all>\r\n" " </s:complexType>\r\n" " </s:element>\r\n" "{{endif}}\r\n" "{{endif}}\r\n" "{{endwhile}}\r\n" " </s:all>\r\n" " </s:complexType>\r\n" " </s:element>\r\n" "{{endwhile}}\r\n" "{{while GetNextEnum}}\r\n" " <s:simpleType name=\"{{GetEnumName}}\">\r\n" " <s:restriction base=\"s:string\">\r\n" "{{while GetNextEnumElement}}\r\n" " <s:enumeration value=\"{{GetEnumElementName}}\"/>\r\n" "{{endwhile}}\r\n" " </s:restriction>\r\n" " </s:simpleType>\r\n" "{{endwhile}}\r\n" " <s:complexType name=\"ATLSOAP_BLOB\">\r\n" " <s:all>\r\n" " <s:element name=\"size\" type=\"unsignedLong\"/>\r\n" " <s:element name=\"data\" nullable=\"false\">\r\n" " <s:simpleType xmlns:q3=\"http://www.w3.org/2000/10/XMLSchema\" base=\"q3:binary\">\r\n" " <s:encoding value=\"base64\"/>\r\n" " </s:simpleType>\r\n" " </s:element>\r\n" " </s:all>\r\n" " </s:complexType>\r\n" "{{while GetNextStruct}}\r\n" " <s:complexType name=\"{{GetStructName}}\" derivedBy=\"restriction\">\r\n" " <s:all>\r\n" "{{while GetNextStructField}}\r\n" " <s:element name=\"{{GetStructFieldName}}\" {{if NotIsArrayField}}type=\"{{if IsFieldUDT}}s0:{{else}}s:{{endif}}{{GetStructFieldSoapType}}\"/{{else}}nullable=\"false\"{{endif}}>\r\n" "{{if IsArrayField}}\r\n" " <s:complexType derivedBy=\"restriction\">\r\n" " <s:all>\r\n" " <s:element name=\"{{GetStructFieldSoapType}}\" type=\"{{if IsFieldUDT}}s0:{{else}}s:{{endif}}{{GetStructFieldSoapType}}\" {{if IsFieldOneDimensional}}minOccurs=\"{{GetFieldArraySize}}\" maxOccurs=\"{{GetFieldArraySize}}\"{{else}}soap:arrayType=\"{{GetFieldArraySoapDims}}\"{{endif}}/>\r\n" " </s:all>\r\n" " </s:complexType>\r\n" " </s:element>\r\n" "{{endif}}\r\n" "{{endwhile}}\r\n" " </s:all>\r\n" " </s:complexType>\r\n" "{{endwhile}}\r\n" "{{while GetNextHeader}}\r\n" " <s:element name=\"{{GetHeaderName}}\" {{if NotIsArrayHeader}}type=\"{{if IsHeaderUDT}}s0:{{else}}s:{{endif}}{{GetHeaderSoapType}}\"/{{else}}nullable=\"false\"{{endif}}>\r\n" "{{if IsArrayHeader}}\r\n" " <s:complexType derivedBy=\"restriction\">\r\n" " <s:all>\r\n" " <s:element name=\"{{GetHeaderSoapType}}\" type=\"{{if IsHeaderUDT}}s0:{{else}}s:{{endif}}{{GetHeaderSoapType}}\" {{if IsHeaderOneDimensional}}minOccurs=\"{{GetHeaderArraySize}}\" maxOccurs=\"{{GetHeaderArraySize}}\"{{else}}soap:arrayType=\"{{GetHeaderArraySoapDims}}\"{{endif}}/>\r\n" " </s:all>\r\n" " </s:complexType>\r\n" " </s:element>\r\n" "{{endif}}\r\n" "{{endwhile}}\r\n" " </s:schema>\r\n" " </types>\r\n" "{{while GetNextFunction}}\r\n" " <message name=\"{{GetFunctionName}}In\">\r\n" " <part name=\"parameters\" element=\"s0:{{GetFunctionName}}\"/>\r\n" " </message>\r\n" " <message name=\"{{GetFunctionName}}Out\">\r\n" " <part name=\"parameters\" element=\"s0:{{GetFunctionName}}Response\"/>\r\n" " </message>\r\n" "{{endwhile}}\r\n" "{{while GetNextHeader}}\r\n" " <message name=\"{{GetHeaderName}}\">\r\n" " <part name=\"{{GetHeaderName}}\" element=\"s0:{{GetHeaderName}}\"/>\r\n" " </message>\r\n" "{{endwhile}}\r\n" " <portType name=\"{{GetServiceName}}Soap\">\r\n" "{{while GetNextFunction}}\r\n" " <operation name=\"{{GetFunctionName}}\">\r\n" " <input message=\"s0:{{GetFunctionName}}In\"/>\r\n" " <output message=\"s0:{{GetFunctionName}}Out\"/>\r\n" " </operation>\r\n" "{{endwhile}}\r\n" " </portType>\r\n" " <binding name=\"{{GetServiceName}}Soap\" type=\"s0:{{GetServiceName}}Soap\">\r\n" " <soap:binding transport=\"http://schemas.xmlsoap.org/soap/http\" style=\"document\"/>\r\n" "{{while GetNextFunction}}\r\n" " <operation name=\"{{GetFunctionName}}\">\r\n" " <soap:operation soapAction=\"#{{GetFunctionName}}\" style=\"document\"/>\r\n" " <input>\r\n" " <soap:body use=\"literal\"/>\r\n" "{{while GetNextFunctionHeader}}\r\n" "{{if IsInHeader}}\r\n" " <soap:header message=\"s0:{{GetFunctionHeaderName}}\" part=\"{{GetFunctionHeaderName}}\" use=\"literal\"{{if IsRequiredHeader}} wsdl:required=\"true\"{{endif}}/>\r\n" "{{endif}}\r\n" "{{endwhile}}\r\n" " </input>\r\n" " <output>\r\n" " <soap:body use=\"literal\"/>\r\n" "{{while GetNextFunctionHeader}}\r\n" "{{if IsOutHeader}}\r\n" " <soap:header message=\"s0:{{GetFunctionHeaderName}}\" part=\"{{GetFunctionHeaderName}}\" use=\"literal\"{{if IsRequiredHeader}} wsdl:required=\"true\"{{endif}}/>\r\n" "{{endif}}\r\n" "{{endwhile}}\r\n" " </output>\r\n" " </operation>\r\n" "{{endwhile}}\r\n" " </binding>\r\n" " <service name=\"{{GetServiceName}}\">\r\n" " <port name=\"{{GetServiceName}}Soap\" binding=\"s0:{{GetServiceName}}Soap\">\r\n" " <soap:address location=\"{{GetURL}}\"/>\r\n" " </port>\r\n" " </service>\r\n" "</definitions>" "";
extern __declspec(selectany) const size_t s_nAtlsWSDLSrfLen = strlen(s_szAtlsWSDLSrf);
class CStreamOnSequentialStream : public IStream { CComPtr<ISequentialStream> m_spStream; public: CStreamOnSequentialStream(ISequentialStream *pStream) throw() { ATLASSERT(pStream); m_spStream = pStream; }
STDMETHOD(Read)(void *pv, ULONG cb, ULONG *pcbRead) throw() { if (!m_spStream) return E_UNEXPECTED; return m_spStream->Read(pv, cb, pcbRead); }
STDMETHOD(Write)(const void *pv, ULONG cb, ULONG *pcbWritten) throw() { if (!m_spStream) return E_UNEXPECTED; return m_spStream->Write(pv, cb, pcbWritten); }
STDMETHOD(Seek)(LARGE_INTEGER , DWORD , ULARGE_INTEGER *) throw() { return E_NOTIMPL; }
STDMETHOD(SetSize)(ULARGE_INTEGER ) throw() { return E_NOTIMPL; }
STDMETHOD(CopyTo)(IStream *, ULARGE_INTEGER , ULARGE_INTEGER *, ULARGE_INTEGER *) throw() { return E_NOTIMPL; }
STDMETHOD(Commit)(DWORD ) throw() { return E_NOTIMPL; }
STDMETHOD(Revert)( void) throw() { return E_NOTIMPL; }
STDMETHOD(LockRegion)(ULARGE_INTEGER , ULARGE_INTEGER , DWORD ) throw() { return E_NOTIMPL; }
STDMETHOD(UnlockRegion)(ULARGE_INTEGER , ULARGE_INTEGER , DWORD ) throw() { return E_NOTIMPL; }
STDMETHOD(Stat)(STATSTG *, DWORD ) throw() { return E_NOTIMPL; }
STDMETHOD(Clone)(IStream **) throw() { return E_NOTIMPL; }
STDMETHOD(QueryInterface)(REFIID iid, void **ppUnk) throw() { *ppUnk = NULL; if (::InlineIsEqualGUID(iid, IID_IUnknown) || ::InlineIsEqualGUID(iid, IID_ISequentialStream) || ::InlineIsEqualGUID(iid, IID_IStream)) { *ppUnk = (void*)(IStream*)this; AddRef(); return S_OK; } return E_NOINTERFACE; }
ULONG STDMETHODCALLTYPE AddRef( void) throw() { return (ULONG)1; }
ULONG STDMETHODCALLTYPE Release( void) throw() { return (ULONG)1; } };
class CStreamOnByteArray : public IStream { public: BYTE *m_pArray; DWORD m_dwRead;
CStreamOnByteArray(BYTE *pBytes) throw() { ATLASSERT(pBytes); m_pArray = pBytes; m_dwRead = 0; }
STDMETHOD(Read)(void *pv, ULONG cb, ULONG *pcbRead) throw() { if (!pv) return E_INVALIDARG;
if (cb == 0) return S_OK;
if (!m_pArray) return E_UNEXPECTED;
BYTE *pCurr = m_pArray; pCurr += m_dwRead; memcpy(pv, pCurr, cb); if (pcbRead) *pcbRead = cb; m_dwRead += cb; return S_OK; }
STDMETHOD(Write)(const void* , ULONG , ULONG* ) throw() { return E_UNEXPECTED; }
STDMETHOD(Seek)(LARGE_INTEGER , DWORD , ULARGE_INTEGER *) throw() { return E_NOTIMPL; }
STDMETHOD(SetSize)(ULARGE_INTEGER ) throw() { return E_NOTIMPL; }
STDMETHOD(CopyTo)(IStream *, ULARGE_INTEGER , ULARGE_INTEGER *, ULARGE_INTEGER *) throw() { return E_NOTIMPL; }
STDMETHOD(Commit)(DWORD ) throw() { return E_NOTIMPL; }
STDMETHOD(Revert)( void) throw() { return E_NOTIMPL; }
STDMETHOD(LockRegion)(ULARGE_INTEGER , ULARGE_INTEGER , DWORD ) throw() { return E_NOTIMPL; }
STDMETHOD(UnlockRegion)(ULARGE_INTEGER , ULARGE_INTEGER , DWORD ) throw() { return E_NOTIMPL; }
STDMETHOD(Stat)(STATSTG *, DWORD ) throw() { return E_NOTIMPL; }
STDMETHOD(Clone)(IStream **) throw() { return E_NOTIMPL; }
STDMETHOD(QueryInterface)(REFIID iid, void **ppUnk) throw() { *ppUnk = NULL; if (::InlineIsEqualGUID(iid, IID_IUnknown) || ::InlineIsEqualGUID(iid, IID_ISequentialStream) || ::InlineIsEqualGUID(iid, IID_IStream)) { *ppUnk = (void*)(IStream*)this; AddRef(); return S_OK; } return E_NOINTERFACE; }
ULONG STDMETHODCALLTYPE AddRef( void) throw() { return (ULONG)1; }
ULONG STDMETHODCALLTYPE Release( void) throw() { return (ULONG)1; } };
class CVariantStream : public IStream { public: CVariantStream() throw() { m_nCurrRead = 0; m_nVariantSize = 0; m_nRef = 1; } // input variant is put into contained BYTE array.
HRESULT InsertVariant(const VARIANT *pVarIn) throw() { CComVariant vIn; HRESULT hr = E_FAIL; m_nCurrRead = 0; m_nVariantSize = 0; hr = vIn.Copy(pVarIn); if (hr == S_OK) hr = vIn.WriteToStream(static_cast<IStream*>(this));
return hr; }
// variant is read from contained byte array into
// out variant.
HRESULT RetrieveVariant(VARIANT *pVarOut) throw() { CComVariant vOut; HRESULT hr = vOut.ReadFromStream(static_cast<IStream*>(this)); if (hr == S_OK) hr = VariantCopy(pVarOut, &vOut); m_nCurrRead = 0; return hr; }
HRESULT LoadFromStream(ISequentialStream *stream) throw() { m_nCurrRead = 0; CStreamOnSequentialStream stm(stream); CComVariant v; HRESULT hr = v.ReadFromStream(&stm); if (hr == S_OK) hr = v.WriteToStream(static_cast<IStream*>(this)); return hr; }
ISequentialStream* GetStream() throw() { return static_cast<ISequentialStream*>(this); }
size_t GetVariantSize() throw() { return m_nVariantSize; }
// Implementation
// IStream implementation;
STDMETHOD(Read)(void *pv, ULONG cb, ULONG *pcbRead) throw() { if (!pv) return E_INVALIDARG;
if (cb == 0) return S_OK;
if (pcbRead) *pcbRead = 0;
if (!m_nVariantSize) return S_OK; // nothing to do.
size_t nLeft = m_nVariantSize - m_nCurrRead; if (nLeft > 0) { size_t nRead = min(nLeft, cb); BYTE *pCurr = m_stream; pCurr += m_nCurrRead; memcpy(pv, pCurr, nRead); m_nCurrRead += nRead; if (pcbRead) *pcbRead = (ULONG)nRead; }
return S_OK; }
STDMETHOD(Write)(const void *pv, ULONG cb, ULONG *pcbWritten) throw() { HRESULT hr = E_OUTOFMEMORY; if (!pv) return E_INVALIDARG;
if (cb == 0) return S_OK;
if (pcbWritten) *pcbWritten = 0;
BYTE *pBytes = m_stream.Reallocate(cb); if (pBytes) { pBytes += m_nVariantSize; memcpy(pBytes, pv, cb); if (pcbWritten) *pcbWritten = cb; m_nVariantSize += cb; hr = S_OK; } return hr; }
STDMETHOD(Seek)(LARGE_INTEGER , DWORD , ULARGE_INTEGER *) throw() { return E_NOTIMPL; }
STDMETHOD(SetSize)(ULARGE_INTEGER ) throw() { return E_NOTIMPL; }
STDMETHOD(CopyTo)(IStream *, ULARGE_INTEGER , ULARGE_INTEGER *, ULARGE_INTEGER *) throw() { return E_NOTIMPL; }
STDMETHOD(Commit)(DWORD ) throw() { return E_NOTIMPL; }
STDMETHOD(Revert)( void) throw() { return E_NOTIMPL; }
STDMETHOD(LockRegion)(ULARGE_INTEGER , ULARGE_INTEGER , DWORD ) throw() { return E_NOTIMPL; }
STDMETHOD(UnlockRegion)(ULARGE_INTEGER , ULARGE_INTEGER , DWORD ) throw() { return E_NOTIMPL; }
STDMETHOD(Stat)(STATSTG *, DWORD ) throw() { return E_NOTIMPL; }
STDMETHOD(Clone)(IStream **) throw() { return E_NOTIMPL; }
STDMETHOD(QueryInterface)(REFIID iid, void **ppUnk) throw() { *ppUnk = NULL; if (::InlineIsEqualGUID(iid, IID_IUnknown)) { *ppUnk = (void*)(IUnknown*)this; } else if (::InlineIsEqualGUID(iid, IID_ISequentialStream)) { *ppUnk = (void*)(ISequentialStream*)this; } else if (::InlineIsEqualGUID(iid, IID_IStream)) { *ppUnk = (void*)(IStream*)this; }
if (*ppUnk) { AddRef(); return S_OK; } return E_NOINTERFACE; }
ULONG STDMETHODCALLTYPE AddRef( void) throw() { return (ULONG)1; }
ULONG STDMETHODCALLTYPE Release( void) throw() { return (ULONG)1; }
CTempBuffer<BYTE> m_stream; size_t m_nVariantSize; size_t m_nCurrRead; long m_nRef; };
#include <atlspriv.inl>
}; // namespace ATL
#endif // __ATLSPRIV_H__
|