1018 lines
28 KiB
C++
1018 lines
28 KiB
C++
// This is a part of the Active Template Library.
|
|
// Copyright (C) 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
|
|
#include <atlsocket.h>
|
|
|
|
#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.
|
|
#pragma pack(push,_ATL_PACKING)
|
|
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(const ADDRINFOT* pAI, WORD wFlags=0) throw();
|
|
bool Create(int af, int st, int proto, WORD wFlags=0) throw();
|
|
bool Connect(LPCTSTR szAddr, unsigned short nPort) throw();
|
|
bool Connect(const SOCKADDR* psa, int len) throw();
|
|
bool Connect(const ADDRINFOT *pAI) 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() throw();
|
|
DWORD SetSocketTimeout(DWORD dwNewTimeout) throw();
|
|
bool SupportsScheme(ATL_URL_SCHEME scheme) throw();
|
|
|
|
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;
|
|
};
|
|
inline bool _AtlIsHttpSpace(TCHAR c)
|
|
{
|
|
return (c == 0x09 ||
|
|
c == 0x0A ||
|
|
c == 0x0D ||
|
|
c == 0x20);
|
|
}
|
|
|
|
// 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(_In_ LPCSTR szNames, _Out_z_cap_post_count_(*pdwLen, *pdwLen) LPSTR szRecipients, _Inout_ LPDWORD pdwLen)
|
|
{
|
|
ATLENSURE(szNames != NULL);
|
|
ATLENSURE(szRecipients != NULL);
|
|
ATLENSURE(pdwLen != 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 != '>')
|
|
{
|
|
if( dwLen >= *pdwLen )
|
|
{
|
|
return FALSE;
|
|
}
|
|
*szRecipients++ = *szNames++;
|
|
dwLen++;
|
|
}
|
|
if( dwLen >= *pdwLen )
|
|
{
|
|
return FALSE;
|
|
}
|
|
// 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';
|
|
*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(_Out_z_cap_(cch) LPSTR szCharset, _In_ UINT uiCodePage, _In_opt_ IMultiLanguage* pMultiLanguage, _In_ size_t cch) throw()
|
|
{
|
|
ATLASSERT(szCharset != NULL);
|
|
|
|
if (!pMultiLanguage)
|
|
{
|
|
if ((uiCodePage == 0) || (uiCodePage == ATL_MIME_DEFAULT_CP))
|
|
{
|
|
ATLASSERT(_countof(ATLSMTP_DEFAULT_CSET) <= cch);
|
|
Checked::strcpy_s(szCharset, cch, 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
|
|
{
|
|
CW2A charSet(cpInfo.wszWebCharset);
|
|
if (strlen(charSet) >= cch)
|
|
return FALSE;
|
|
Checked::strcpy_s(szCharset, cch, charSet);
|
|
}
|
|
_ATLCATCHALL()
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
inline BOOL AtlMimeConvertStringW(
|
|
_In_ IMultiLanguage *pMultiLanguage,
|
|
_In_ UINT uiCodePage,
|
|
_In_ LPCWSTR wszIn,
|
|
_Out_z_cap_post_count_(*pnLen, *pnLen) LPSTR *ppszOut,
|
|
_Inout_ UINT *pnLen) throw()
|
|
{
|
|
ATLENSURE_RETURN_VAL( pMultiLanguage != NULL, FALSE );
|
|
ATLENSURE_RETURN_VAL( wszIn != NULL, FALSE );
|
|
ATLENSURE_RETURN_VAL( ppszOut != NULL, FALSE );
|
|
ATLENSURE_RETURN_VAL( pnLen != NULL, FALSE );
|
|
|
|
*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(
|
|
_In_ IMultiLanguage *pMultiLanguage,
|
|
_In_ UINT uiCodePage,
|
|
_In_ LPCSTR szIn,
|
|
_Out_z_cap_post_count_(*pnLen, *pnLen) LPSTR *ppszOut,
|
|
_Inout_ 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
|
|
|
|
class CStreamOnSequentialStream :
|
|
public IStream
|
|
{
|
|
CComPtr<ISequentialStream> m_spStream;
|
|
public:
|
|
CStreamOnSequentialStream(ISequentialStream *pStream) throw()
|
|
{
|
|
ATLASSERT(pStream);
|
|
m_spStream = pStream;
|
|
}
|
|
virtual ~CStreamOnSequentialStream()
|
|
{
|
|
}
|
|
|
|
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;
|
|
Checked::memcpy_s(pv, cb, 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;
|
|
}
|
|
virtual ~CVariantStream()
|
|
{
|
|
}
|
|
|
|
// 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.Attach(const_cast<VARIANT*>(pVarIn));
|
|
if (hr == S_OK)
|
|
{
|
|
hr = vIn.WriteToStream(static_cast<IStream*>(this));
|
|
vIn.Detach(const_cast<VARIANT*>(pVarIn));
|
|
}
|
|
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 = vOut.Detach(pVarOut);
|
|
|
|
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;
|
|
Checked::memcpy_s(pv, cb, 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;
|
|
|
|
ULONG newsz = cb + (ULONG)m_nVariantSize;
|
|
if (newsz < cb || newsz < m_nVariantSize)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
BYTE *pBytes = NULL;
|
|
ATLTRY(pBytes = m_stream.Reallocate(newsz));
|
|
if (pBytes)
|
|
{
|
|
pBytes += m_nVariantSize;
|
|
Checked::memcpy_s(pBytes, cb, 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;
|
|
};
|
|
|
|
// given a nCurrent and a pointer to a value representing the
|
|
// maximum value that has been seen in nCurrent,
|
|
// will update pnMax if nCurrent is greater
|
|
inline void AtlInterlockedUpdateMax(long nCurrent, long* pnMax)
|
|
{
|
|
ATLENSURE(pnMax != NULL);
|
|
|
|
long nMax;
|
|
long nOrigMax;
|
|
|
|
do
|
|
{
|
|
nMax = *pnMax;
|
|
nOrigMax = 0;
|
|
if (nCurrent > nMax)
|
|
nOrigMax = InterlockedCompareExchange(pnMax, nCurrent, nMax);
|
|
}
|
|
while (nOrigMax != 0 && nOrigMax != nMax);
|
|
}
|
|
|
|
// wrapper around InterlockedExchangeAdd
|
|
inline LONG AtlInterlockedExchangeAdd(_Inout_ long volatile* pAddend, _In_ long nValue)
|
|
{
|
|
#if defined(_WIN64) && defined(_M_CEE)
|
|
|
|
// We use System::Threading::Interlocked::Add because InterlockedExchangeAdd is an intrisinc not supported in managed code with 64bits compilers.
|
|
// System::Threading::Interlocked::Add returns the value after the addition, but we maintain the same semantics as InterlockedExchangeAdd.
|
|
_STATIC_ASSERT(sizeof(int) == sizeof(long));
|
|
return (System::Threading::Interlocked::Add(*((int*)pAddend), nValue) - nValue);
|
|
|
|
#else
|
|
|
|
return InterlockedExchangeAdd(pAddend, nValue);
|
|
|
|
#endif
|
|
}
|
|
|
|
// SOAP helpers
|
|
#define _ATLSOAP_DECLARE_WSDL_SRF() \
|
|
__if_not_exists(s_szAtlsWSDLSrf) \
|
|
{ \
|
|
extern __declspec(selectany) const char * const 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/2001/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" \
|
|
" xmlns:atls=\"http://tempuri.org/vc/atl/server/\"\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" \
|
|
" <s:import namespace=\"http://schemas.xmlsoap.org/soap/encoding/\"/>\r\n" \
|
|
"{{if IsRpcEncoded}}\r\n" \
|
|
"{{while GetNextFunction}}\r\n" \
|
|
"{{while GetNextParameter}}\r\n" \
|
|
"{{if IsArrayParameter}}\r\n" \
|
|
" <s:complexType name=\"{{GetFunctionName}}_{{GetParameterName}}_Array\">\r\n" \
|
|
" <s:complexContent>\r\n" \
|
|
" <s:restriction base=\"soapenc:Array\">\r\n" \
|
|
" <s:attribute ref=\"soapenc:arrayType\" wsdl:arrayType=\"{{if IsParameterUDT}}s0:{{else}}s:{{endif}}{{GetParameterSoapType}}{{if IsParameterDynamicArray}}[]{{else}}{{GetParameterArraySoapDims}}{{endif}}\"/>\r\n" \
|
|
" </s:restriction>\r\n" \
|
|
" </s:complexContent>\r\n" \
|
|
" </s:complexType>\r\n" \
|
|
"{{endif}}\r\n" \
|
|
"{{endwhile}}\r\n" \
|
|
"{{endwhile}}\r\n" \
|
|
"{{endif}}\r\n" \
|
|
"{{while GetNextHeader}}\r\n" \
|
|
"{{if IsHeaderUDT}}\r\n" \
|
|
"{{else}}\r\n" \
|
|
"{{if IsArrayHeader}}\r\n" \
|
|
"{{else}}\r\n" \
|
|
" <s:simpleType name=\"{{GetHeaderName}}_wrapper\">\r\n" \
|
|
" <s:restriction base=\"s:{{GetHeaderSoapType}}\"/>\r\n" \
|
|
" </s:simpleType>\r\n" \
|
|
"{{endif}}\r\n" \
|
|
"{{endif}}\r\n" \
|
|
"{{if IsRpcEncoded}}\r\n" \
|
|
"{{if IsArrayHeader}}\r\n" \
|
|
" <s:complexType name=\"{{GetHeaderName}}_Array\">\r\n" \
|
|
" <s:complexContent>\r\n" \
|
|
" <s:restriction base=\"soapenc:Array\">\r\n" \
|
|
" <s:attribute ref=\"soapenc:arrayType\" wsdl:arrayType=\"{{if IsHeaderUDT}}s0:{{else}}s:{{endif}}{{GetHeaderSoapType}}{{GetHeaderArraySoapDims}}\"/>\r\n" \
|
|
" </s:restriction>\r\n" \
|
|
" </s:complexContent>\r\n" \
|
|
" </s:complexType>\r\n" \
|
|
"{{endif}}\r\n" \
|
|
"{{endif}}\r\n" \
|
|
"{{endwhile}}\r\n" \
|
|
"{{if IsDocumentLiteral}}\r\n" \
|
|
"{{while GetNextFunction}}\r\n" \
|
|
" <s:element name=\"{{GetFunctionName}}\">\r\n" \
|
|
" <s:complexType>\r\n" \
|
|
" <s:sequence>\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}}nillable=\"{{if IsParameterDynamicArray}}true{{else}}false{{endif}}\"{{endif}}>\r\n" \
|
|
"{{if IsArrayParameter}}\r\n" \
|
|
" <s:complexType>\r\n" \
|
|
" <s:sequence>\r\n" \
|
|
" <s:element name=\"{{GetParameterSoapType}}\" type=\"{{if IsParameterUDT}}s0:{{else}}s:{{endif}}{{GetParameterSoapType}}\" {{if IsParameterDynamicArray}}minOccurs=\"0\" maxOccurs=\"unbounded\"{{else}}minOccurs=\"{{GetParameterArraySize}}\" maxOccurs=\"{{GetParameterArraySize}}\"{{endif}}/>\r\n" \
|
|
" </s:sequence>\r\n" \
|
|
" </s:complexType>\r\n" \
|
|
" </s:element>\r\n" \
|
|
"{{endif}}\r\n" \
|
|
"{{endif}}\r\n" \
|
|
"{{endwhile}}\r\n" \
|
|
" </s:sequence>\r\n" \
|
|
" </s:complexType>\r\n" \
|
|
" </s:element>\r\n" \
|
|
" <s:element name=\"{{GetFunctionName}}Response\">\r\n" \
|
|
" <s:complexType>\r\n" \
|
|
" <s:sequence>\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}}nillable=\"{{if IsParameterDynamicArray}}true{{else}}false{{endif}}\"{{endif}}>\r\n" \
|
|
"{{if IsArrayParameter}}\r\n" \
|
|
" <s:complexType>\r\n" \
|
|
" <s:sequence>\r\n" \
|
|
" <s:element name=\"{{GetParameterSoapType}}\" type=\"{{if IsParameterUDT}}s0:{{else}}s:{{endif}}{{GetParameterSoapType}}\" {{if IsParameterDynamicArray}}minOccurs=\"0\" maxOccurs=\"unbounded\"{{else}}minOccurs=\"{{GetParameterArraySize}}\" maxOccurs=\"{{GetParameterArraySize}}\"{{endif}}/>\r\n" \
|
|
" </s:sequence>\r\n" \
|
|
" </s:complexType>\r\n" \
|
|
" </s:element>\r\n" \
|
|
"{{endif}}\r\n" \
|
|
"{{endif}}\r\n" \
|
|
"{{endwhile}}\r\n" \
|
|
" </s:sequence>\r\n" \
|
|
" </s:complexType>\r\n" \
|
|
" </s:element>\r\n" \
|
|
"{{endwhile}}\r\n" \
|
|
"{{endif}}\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" \
|
|
"{{while GetNextStruct}}\r\n" \
|
|
" <s:complexType name=\"{{GetStructName}}\">\r\n" \
|
|
" <s:sequence>\r\n" \
|
|
"{{while GetNextStructField}}\r\n" \
|
|
" <s:element name=\"{{GetStructFieldName}}\" {{if IsFieldDynamicArray}}atls:SizeIs=\"{{GetFieldSizeIsName}}\" {{endif}}{{if NotIsArrayField}}type=\"{{if IsFieldUDT}}s0:{{else}}s:{{endif}}{{GetStructFieldSoapType}}\"/{{else}}nillable=\"{{if IsFieldDynamicArray}}true{{else}}false{{endif}}\"{{endif}}>\r\n" \
|
|
"{{if IsArrayField}}\r\n" \
|
|
" <s:complexType>\r\n" \
|
|
"{{if IsRpcEncoded}}\r\n" \
|
|
" <s:complexContent>\r\n" \
|
|
" <s:restriction base=\"soapenc:Array\">\r\n" \
|
|
" <s:attribute ref=\"soapenc:arrayType\" wsdl:arrayType=\"{{if IsFieldUDT}}s0:{{else}}s:{{endif}}{{GetStructFieldSoapType}}{{if IsFieldDynamicArray}}[]{{else}}{{GetFieldArraySoapDims}}{{endif}}\"/>\r\n" \
|
|
" </s:restriction>\r\n" \
|
|
" </s:complexContent>\r\n" \
|
|
"{{else}}\r\n" \
|
|
" <s:sequence>\r\n" \
|
|
" <s:element name=\"{{GetStructFieldSoapType}}\" type=\"{{if IsFieldUDT}}s0:{{else}}s:{{endif}}{{GetStructFieldSoapType}}\" {{if IsFieldDynamicArray}}minOccurs=\"0\" maxOccurs=\"unbounded\"{{else}}minOccurs=\"{{GetFieldArraySize}}\" maxOccurs=\"{{GetFieldArraySize}}\"{{endif}}/>\r\n" \
|
|
" </s:sequence>\r\n" \
|
|
"{{endif}}\r\n" \
|
|
" </s:complexType>\r\n" \
|
|
" </s:element>\r\n" \
|
|
"{{endif}}\r\n" \
|
|
"{{endwhile}}\r\n" \
|
|
" </s:sequence>\r\n" \
|
|
" </s:complexType>\r\n" \
|
|
"{{endwhile}}\r\n" \
|
|
"{{if IsDocumentLiteral}}\r\n" \
|
|
"{{while GetNextHeader}}\r\n" \
|
|
" <s:element name=\"{{GetHeaderName}}\" {{if NotIsArrayHeader}}type=\"s0:{{if IsHeaderUDT}}{{GetHeaderSoapType}}{{else}}{{GetHeaderName}}_wrapper{{endif}}\"/{{else}}nillable=\"false\"{{endif}}>\r\n" \
|
|
"{{if IsArrayHeader}}\r\n" \
|
|
" <s:complexType>\r\n" \
|
|
" <s:sequence>\r\n" \
|
|
" <s:element name=\"{{GetHeaderSoapType}}\" type=\"{{if IsHeaderUDT}}s0:{{GetHeaderSoapType}}{{else}}s:{{endif}}{{GetHeaderSoapType}}\" minOccurs=\"{{GetHeaderArraySize}}\" maxOccurs=\"{{GetHeaderArraySize}}\"/>\r\n" \
|
|
" </s:sequence>\r\n" \
|
|
" </s:complexType>\r\n" \
|
|
" </s:element>\r\n" \
|
|
"{{endif}}\r\n" \
|
|
"{{endwhile}}\r\n" \
|
|
"{{endif}}\r\n" \
|
|
" </s:schema>\r\n" \
|
|
" </types>\r\n" \
|
|
"{{while GetNextFunction}}\r\n" \
|
|
" <message name=\"{{GetFunctionName}}In\">\r\n" \
|
|
"{{if IsDocumentLiteral}}\r\n" \
|
|
" <part name=\"parameters\" element=\"s0:{{GetFunctionName}}\"/>\r\n" \
|
|
"{{endif}}\r\n" \
|
|
"{{if IsRpcEncoded}}\r\n" \
|
|
"{{while GetNextParameter}}\r\n" \
|
|
"{{if IsInParameter}}\r\n" \
|
|
" <part name=\"{{GetParameterName}}\" type=\"{{if NotIsArrayParameter}}{{if IsParameterUDT}}s0:{{else}}s:{{endif}}{{GetParameterSoapType}}{{else}}s0:{{GetFunctionName}}_{{GetParameterName}}_Array{{endif}}\"/>\r\n" \
|
|
"{{endif}}\r\n" \
|
|
"{{endwhile}}\r\n" \
|
|
"{{endif}}\r\n" \
|
|
" </message>\r\n" \
|
|
" <message name=\"{{GetFunctionName}}Out\">\r\n" \
|
|
"{{if IsDocumentLiteral}}\r\n" \
|
|
" <part name=\"parameters\" element=\"s0:{{GetFunctionName}}Response\"/>\r\n" \
|
|
"{{endif}}\r\n" \
|
|
"{{if IsRpcEncoded}}\r\n" \
|
|
"{{while GetNextParameter}}\r\n" \
|
|
"{{if IsOutParameter}}\r\n" \
|
|
" <part name=\"{{GetParameterName}}\" type=\"{{if NotIsArrayParameter}}{{if IsParameterUDT}}s0:{{else}}s:{{endif}}{{GetParameterSoapType}}{{else}}s0:{{GetFunctionName}}_{{GetParameterName}}_Array{{endif}}\"/>\r\n" \
|
|
"{{endif}}\r\n" \
|
|
"{{endwhile}}\r\n" \
|
|
"{{endif}}\r\n" \
|
|
" </message>\r\n" \
|
|
"{{endwhile}}\r\n" \
|
|
"{{while GetNextHeader}}\r\n" \
|
|
" <message name=\"{{GetHeaderName}}\">\r\n" \
|
|
"{{if IsDocumentLiteral}}\r\n" \
|
|
" <part name=\"{{GetHeaderName}}\" element=\"s0:{{GetHeaderName}}\"/>\r\n" \
|
|
"{{endif}}\r\n" \
|
|
"{{if IsRpcEncoded}}\r\n" \
|
|
" <part name=\"{{GetHeaderName}}\" type=\"{{if NotIsArrayHeader}}s0:{{if IsHeaderUDT}}{{GetHeaderSoapType}}{{else}}{{GetHeaderName}}_wrapper{{endif}}{{else}}s0:{{GetHeaderName}}_Array{{endif}}\"/>\r\n" \
|
|
"{{endif}}\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=\"{{if IsDocumentLiteral}}document{{endif}}{{if IsRpcEncoded}}rpc{{endif}}\"/>\r\n" \
|
|
"{{while GetNextFunction}}\r\n" \
|
|
" <operation name=\"{{GetFunctionName}}\">\r\n" \
|
|
" <soap:operation soapAction=\"#{{GetFunctionName}}\" style=\"{{if IsDocumentLiteral}}document{{endif}}{{if IsRpcEncoded}}rpc{{endif}}\"/>\r\n" \
|
|
" <input>\r\n" \
|
|
" <soap:body {{if IsDocumentLiteral}}use=\"literal\"{{endif}}{{if IsRpcEncoded}}use=\"encoded\" namespace=\"{{GetNamespace}}\" encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"{{endif}}/>\r\n" \
|
|
"{{while GetNextFunctionHeader}}\r\n" \
|
|
"{{if IsInHeader}}\r\n" \
|
|
" <soap:header message=\"s0:{{GetFunctionHeaderName}}\" part=\"{{GetFunctionHeaderName}}\"{{if IsRequiredHeader}} wsdl:required=\"true\"{{endif}} {{if IsDocumentLiteral}}use=\"literal\"{{endif}}{{if IsRpcEncoded}}use=\"encoded\" namespace=\"{{GetNamespace}}\" encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"{{endif}}/>\r\n" \
|
|
"{{endif}}\r\n" \
|
|
"{{endwhile}}\r\n" \
|
|
" </input>\r\n" \
|
|
" <output>\r\n" \
|
|
" <soap:body {{if IsDocumentLiteral}}use=\"literal\"{{endif}}{{if IsRpcEncoded}}use=\"encoded\" namespace=\"{{GetNamespace}}\" encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"{{endif}}/>\r\n" \
|
|
"{{while GetNextFunctionHeader}}\r\n" \
|
|
"{{if IsOutHeader}}\r\n" \
|
|
" <soap:header message=\"s0:{{GetFunctionHeaderName}}\" part=\"{{GetFunctionHeaderName}}\"{{if IsRequiredHeader}} wsdl:required=\"true\"{{endif}} {{if IsDocumentLiteral}}use=\"literal\"{{endif}}{{if IsRpcEncoded}}use=\"encoded\" namespace=\"{{GetNamespace}}\" encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"{{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>"; \
|
|
}
|
|
|
|
#include <atlspriv.inl>
|
|
}; // namespace ATL
|
|
#pragma pack(pop)
|
|
|
|
#endif // __ATLSPRIV_H__
|