|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: Transact.hxx
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 12-04-95 JohannP (Johann Posch) Created
//
//----------------------------------------------------------------------------
#ifndef _TRANSACT_HXX_
#define _TRANSACT_HXX_
#include <urlmon.hxx>
#include <urlmki.h>
#include "cbinding.hxx"
#ifdef DBG
#define AssertDo(a) (a)
#else // !DEBUG
#define ASSERTDATA
#define AssertDo(a) (a)
#define WITH_EXCEPTION
#endif // DBG
#ifdef unix
#undef offsetof
#endif /* unix */
#define offsetof(s,m) ( (SIZE_T) &(((s *)0)->m) )
#define GETPPARENT(pmemb, struc, membname) (\
(struc*)(((char*)(pmemb))-offsetof(struc, membname)))
//#define BREAK_ONERROR(hrBreak) if (FAILED(hrBreak)) { break; }
#define DATASNIFSIZE_MIN 256
#define DATASNIFSIZEDOCFILE_MIN 2048
#define DATASNIFSIZEDOCFILE_MAX 4096
class CTransactionMgr; class CTransPacket; class CTransaction; class CTransData; #define PI_FILTER_MODE_DATA 0x00000100
class CTransactionMgr : public CLifePtr { public: CTransactionMgr(); virtual ~CTransactionMgr();
HRESULT AddTransaction(CTransaction *pCTrans); HRESULT RemoveTransaction(CTransaction *pCTrans);
private: CTransaction *_pCTransFirst; // First in the linked list
CTransaction *_pCTransLast; // First in the linked list
};
// These two structures are used to pass data from the inloader callbacks
// to the wndproc of the hidden window in the main thread.
class CTransPacket : public PROTOCOLDATA { public:
CTransPacket(PROTOCOLDATA *pSI); CTransPacket(BINDSTATUS NMsg, HRESULT hrRet = NOERROR, LPCWSTR szStr = NULL, DWORD cbAvailable = 0, DWORD cbTotal = 0, DWORD dwResult = 0);
~CTransPacket();
CTransPacket& operator=(const CTransPacket& CTPSrc);
LPWSTR DupWStr(LPSTR szStr) { DWORD dwLen = strlen(szStr) + 1; LPWSTR wzStr = new WCHAR [dwLen]; if (wzStr) { A2W(szStr, wzStr,dwLen); } return wzStr; }
CTransPacket *GetNext() { return _pCTPNext; }
void SetNext(CTransPacket *pCTP) { _pCTPNext = pCTP; } BINDSTATUS GetNotMsg() { return _NotMsg; } BOOL IsLastNotMsg() { return (_NotMsg == BINDSTATUS_ENDDOWNLOADDATA || _NotMsg == BINDSTATUS_ERROR); } BOOL IsAsyncNotMsg() { return (_NotMsg == BINDSTATUS_INTERNALASYNC); }
//private:
DWORD _dwCurrentSize; DWORD _dwTotalSize; DWORD _dwResult; LPWSTR _pwzStr; HRESULT _hrResult;
private: BINDSTATUS _NotMsg; CTransPacket *_pCTPNext; //the next packet
};
typedef enum { TransSt_None = 0 ,TransSt_Initialized = 1 ,TransSt_OperationStarted = 2 ,TransSt_OperationFinished = 3 ,TransSt_Aborted = 4 } TransactionState;
typedef enum { TransData_None = 0 ,TransData_Initialized = 1 ,TransData_ReadingStarted = 2 ,TransData_ReadingFinished = 3 ,TransData_ProtoTerminated = 4 } TransDataState;
typedef enum { DataSink_Unknown = 0 ,DataSink_StreamNoCopyData = 1 ,DataSink_File ,DataSink_Storage ,DataSink_StreamOnFile ,DataSink_StreamBindToObject ,DataSink_GenericStream } DataSink;
typedef enum { TS_None = 0 ,TS_Prepared = 1 ,TS_Completed = 2 } ThreadSwitchState;
#include "prothndl.hxx"
class CTransaction : public IOInetProtocolSink ,public ITransProtocolSink ,public IOInetBindInfo ,public IServiceProvider ,public IAuthenticate ,public IOInetProtocol ,public IOInetPriority ,public IWrappedProtocol { public: // IUnknown methods
STDMETHODIMP QueryInterface(REFIID iid, void **ppvObj); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); //
// IOInetProtocolSink
//
STDMETHODIMP Switch( PROTOCOLDATA *pStateInfo);
STDMETHODIMP ReportProgress( ULONG ulStatusCode, LPCWSTR szStatusText);
STDMETHODIMP ReportData( DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax);
STDMETHODIMP ReportResult( HRESULT hrResult, DWORD dwError, LPCWSTR wzResult);
// ITransProtocolSink
STDMETHODIMP QueryBindFlags (DWORD *pdwFlags); // IAuthenticate methods
STDMETHODIMP Authenticate( HWND* phwnd, LPWSTR *pszUsername, LPWSTR *pszPassword);
// IOInetBindInfo methods
STDMETHODIMP GetBindInfo( DWORD *grfBINDF, BINDINFO * pbindinfo);
STDMETHODIMP GetBindString( ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched );
// IServiceProvider
STDMETHODIMP QueryService(REFGUID rsid, REFIID iid, void ** ppvObj); //
// IOInetProtocol
//
STDMETHODIMP Start( LPCWSTR szUrl, IOInetProtocolSink *pProtSink, IOInetBindInfo *pOIBindInfo, DWORD grfSTI, DWORD_PTR dwReserved );
STDMETHODIMP Continue( PROTOCOLDATA *pStateInfo );
STDMETHODIMP Abort( HRESULT hrReason, DWORD dwOptions );
STDMETHODIMP Terminate( DWORD dwOptions );
STDMETHODIMP Suspend();
STDMETHODIMP Resume();
STDMETHODIMP Read( void *pv, ULONG cb, ULONG *pcbRead);
STDMETHODIMP Seek( LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition);
STDMETHODIMP LockRequest( DWORD dwOptions);
STDMETHODIMP UnlockRequest(); // end IOInetProtocol
// OInetPriority
STDMETHODIMP SetPriority(LONG nPriority);
STDMETHODIMP GetPriority(LONG * pnPriority);
// IWrappedProtocol
STDMETHODIMP GetWrapperCode(LONG * pnCode, DWORD_PTR dwReserved);
static HRESULT Create(LPBC pBC, DWORD grfFlags, IUnknown *pUnkOuter, IUnknown **ppUnk, CTransaction **ppCTrans);
LPWSTR GetUrl() { UrlMkAssert((_pwzUrl != NULL)); return _pwzUrl; }
LPWSTR GetRedirectUrl() { return _pwzRedirectUrl; }
LPWSTR SetRedirectUrl(LPWSTR pwzStr) { TransAssert((_pProt));
if (_pwzRedirectUrl) { delete [] _pwzRedirectUrl; }
_pwzRedirectUrl = OLESTRDuplicate(pwzStr);
return _pwzRedirectUrl; }
REFCLSID GetProtocolClassID() { if (_pProt) { TransAssert((_clsidProtocol != CLSID_NULL ));
return (REFCLSID)_clsidProtocol; } else { return CLSID_NULL; } }
HRESULT QueryOption(DWORD dwOption, LPVOID pBuffer, DWORD *pcbBuf); HRESULT QueryInfo(DWORD dwOption, LPVOID pBuffer, DWORD *pcbBuf, DWORD *pdwFlags, DWORD *pdwReserved);
//
// manage clients interfaces
//
HRESULT AddClientOInet(IOInetProtocolSink *pOInetProtSink, IOInetBindInfo *pOInetBindInfo); HRESULT RemoveClientOInet(); HRESULT RestartOperation(LPWSTR pwzURL, DWORD dwCase); HRESULT Redirect(LPWSTR pwzUrl); HRESULT CompleteOperation(BOOL fNested = FALSE); HRESULT MyPeekMessage(MSG *pMsg, HWND hwnd, UINT min, UINT max, WORD wFlag);
// These two methods are used to implement the linked list of
// internet transactions that is owned by the internet transaction list
// object.
CTransaction *GetNextTransaction() { return _pCTransNext; } void SetNextTransaction(CTransaction *pCTransNext) { _pCTransNext = pCTransNext; }
STDMETHOD_(HWND, GetNotificationWnd)() { if (!_hwndNotify) { _hwndNotify = GetThreadNotificationWnd(); } return _hwndNotify; }
void SetNext(CTransaction *pCTransNext) { _pCTransNext = pCTransNext; }
void SetBinding(CBinding *pCBdg) { _pClntProtSink = pCBdg; }
HRESULT PrepareThreadTransfer(); HRESULT ThreadTransfer(); //TRIDENT BTS->BTO
void SuspendDispatchingPackets(CTransPacket* pCTP); void ResumeDispatchingPackets();
TransactionState GetState() { return _State; }
TransactionState SetState(TransactionState newTS ) { TransactionState tsTemp = _State; _State = newTS; return tsTemp; }
OperationState GetOperationState() { return _OperationState; }
OperationState SetOperationState(OperationState newTS) { OperationState tsTemp = _OperationState; _OperationState = newTS; return tsTemp; }
ULONG BdgAddRef() { return _cBdgRefs++; } ULONG BdgRelease() { return --_cBdgRefs; } STDMETHOD (OnINetCallback)(BOOL fFromMsgQueue = FALSE); STDMETHOD (OnINetInternalCallback)(CTransPacket *pCTPIn); STDMETHOD (PreDispatch)(); STDMETHOD (PostDispatch)();
void AddCTransPacket(CTransPacket *pCTP, BOOL fTail = TRUE); CTransPacket *GetNextCTransPacket(); CTransPacket *GetCurrentCTransPacket() { return _pCTPCur; }
BOOL GotCTransPacket(); STDMETHODIMP DispatchPacket(CTransPacket *pCTPIn); STDMETHODIMP DispatchReport(BINDSTATUS NotMsg, DWORD grfBSCF, DWORD dwCurrentSize, DWORD dwTotalSize, LPCWSTR pwzStr = 0, DWORD dwError = 0, HRESULT hresult = NOERROR); STDMETHODIMP OnDataReceived(DWORD *pgrfBSC, DWORD *pcbBytesAvailable, DWORD *pdwTotalSize); STDMETHODIMP OnAttach(LPCWSTR pwzURL, IOInetBindInfo *pOInetBindInfo, IOInetProtocolSink *pOInetBindSink, DWORD grfOptions, DWORD_PTR dwReserved); STDMETHODIMP LoadHandler(LPCWSTR pwzURL, COInetProt *pCProt, DWORD dwMode);
HRESULT GetHResult() { return _hrResult; } BINDINFO *GetTransBindInfo(); DWORD GetTransBindFlags() { return _grfBINDF; }
void SetTransBindFlags(DWORD dwF) { _grfBINDF = dwF; }
BOOL IsFreeThreaded() { return !(_dwOInetBdgFlags & OIBDG_APARTMENTTHREADED); }
BOOL IsApartmentThread() { TransAssert((_dwThreadId != 0)); return (_dwThreadId == GetCurrentThreadId()); }
DWORD GetBSCF() { return _grfBSCF; }
VOID UpdateVerifiedMimeType(LPCWSTR pwzMime);
public:
class CPrivUnknown : public IUnknown { public: STDMETHOD(QueryInterface) ( REFIID riid, LPVOID FAR* ppvObj); STDMETHOD_(ULONG,AddRef) (void); STDMETHOD_(ULONG,Release) (void);
~CPrivUnknown() {} CPrivUnknown() : _CRefs() {}
private: CRefCount _CRefs; // the total refcount of this object
};
friend class CPrivUnknown; CPrivUnknown _Unknown;
IUnknown *_pUnkOuter; //
// the pUnkInner of the aggregated APP (protocol)
IUnknown *_pUnkInner; // the inner object if the protocol supports aggregation
IUnknown *GetIUnkInner(BOOL fReleaseOuter = FALSE) { if (fReleaseOuter) { TransAssert((_CRefs > 0));
_CRefs--; } return &_Unknown; }
private: CTransaction(DWORD grfFlags, LPBYTE pByte, ULONG cbSizeBuffer, IUnknown *pUnkOuter); ~CTransaction();
#if DBG==1
WORD GetTotalPostedMsgId() { return _wTotalPostedMsg; } #else
#define GetTotalPostedMsgId() 0
#endif
public:
private: union { ULONG _flags; #ifndef unix
struct { #endif /* !unix */
unsigned _fAborted : 1; #ifndef unix
}; #endif /* !unix */
};
CRefCount _CRefs; // the total refcount of this object
// File that the data is being downloaded to
LPWSTR _pwzRedirectUrl; LPWSTR _pwzUrl; LPWSTR _pwzProtClsId; LONG _nPriority; // client pointer
IOInetProtocolSink *_pClntProtSink; IOInetBindInfo *_pClntBindInfo;
IBindCtx *_pBndCtx; CTransaction *_pCTransNext; // Next transaction in the linked list
IOInetProtocol *_pProt;
IWinInetHttpInfo *_pInetHttpInfo; IWinInetInfo *_pInetInfo;
CLSID _clsidProtocol;
DWORD _dwPacketsTotal;
HWND _hwndNotify; // notification window for this
CTransactionMgr *_pCTransMgr; TransactionState _State; OperationState _OperationState; ULONG _cBdgRefs; DWORD _dwThreadId; DWORD _dwProcessId; DWORD _grfBSCF;
// data to handle the packets
CTransPacket *_pCTPHead; // frist on
CTransPacket *_pCTPTail; //
CTransPacket *_pCTPCur; // the current one which gets dispatched
CTransPacket *_pCTPTransfer; // used on transfering to another thread
DWORD _grfInternalFlags;
CRefCount _cPacketsInList; CRefCount _cPostedMsg; BOOL _fDispatch; BOOL _fUnlocked; ThreadSwitchState _ThreadTransferState; BOOL _fResultReported; BOOL _fResultDispatched; DWORD _dwDispatchLevel; BOOL _fTerminated; BOOL _fTerminating; BOOL _fReceivedTerminate; BOOL _fCallTerminate; BOOL _fDocFile; BOOL _fMimeVerified; BOOL _fResultReceived;
BOOL _fMimeHandlerEnabled; BOOL _fEncodingHandlerEnabled; BOOL _fClsInstallerHandlerEnabled; BOOL _fMimeHandlerLoaded; BOOL _fAttached; BOOL _fLocked; BOOL _fModalLoopRunning; BOOL _fForceAsyncReportResult; BOOL _fPreferDefaultHandler;
// special (delayed) abort handling
BOOL _fStarting; BOOL _fReceivedAbort; HRESULT _hrAbort; DWORD _dwAbort; DWORD _dwTerminateOptions;
HRESULT _hrResult; DWORD _dwResult; LPWSTR _pwzResult; LPWSTR _pwzFileName; LPWSTR _pwzAttachmentName; LPWSTR _pwzMimeSuggested;
CMutexSem _mxs; // used in Read, Seek, Abort and package list in case of apartment threaded
CMutexSem _mxsBind; // used in method Bind
BINDINFO *_pBndInfo; DWORD _grfBINDF; DWORD _dwOInetBdgFlags;
ULONG _ulCurrentSize; ULONG _ulTotalSize;
LPBYTE _pBuffer; // DNLD_BUFFER_SIZE size buffer
ULONG _cbBufferSize; ULONG _cbTotalBytesRead; ULONG _cbBufferFilled; //how much of the buffer is in use
//
ULONG _cbDataSize; ULONG _cbReadReturn; ULONG _cbDataSniffMin; ULONG _cbBytesReported; // how much was reported
//
LARGE_INTEGER _dlibReadPos;
COInetProt _CProtEmbed; // to embed
// Not used: COInetProt _CProtEncoding; // encoding
COInetProt _CProtClsInstaller; // encoding
// Not used: COInetProt _COInetProtPost; // for mime verification on worker thread
BOOL _fProtEmbed;
BOOL _fContentDispositionAttach; BOOL _fAcceptRanges; #if DBG==1
WORD _wTotalPostedMsg; #endif
};
class CTransData : public ITransactionData { private: CTransData(CTransaction *pTrans, LPBYTE pByte, DWORD dwSizeBuffer, BOOL fBindToObject); ~CTransData();
public: STDMETHODIMP SetFileName(LPWSTR szFile); LPWSTR GetFileName();
STDMETHODIMP GetData(FORMATETC **ppformatetc, STGMEDIUM **ppmedium, DWORD grfBSCF); STDMETHODIMP FindFormatETC(); STDMETHODIMP SetClipFormat(CLIPFORMAT cfFormat);
STDMETHODIMP ReadHere(LPBYTE pBuffer, DWORD cbBytes, DWORD *dwRead); STDMETHODIMP Seek(LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER *plibNewPosition);
STDMETHODIMP OnDataReceived(DWORD grfBSC, DWORD cbBytesRead, DWORD dwTotalSize, DWORD *pcbNewAvailable); STDMETHODIMP OnDataInBuffer(BYTE *pBuffer, DWORD cbBytesRead, DWORD dwBytesTotal); STDMETHODIMP GetReadBuffer(BYTE **ppBuffer, DWORD *pcbBytes);
STDMETHODIMP OnStart(IOInetProtocol *pCINet); STDMETHODIMP OnTerminate();
STDMETHODIMP IsObjectReady(); STDMETHODIMP InProgress();
STDMETHODIMP_(BOOL) IsRemoteObjectReady() { return _fRemoteReady; }
STDMETHODIMP GetClassID(CLSID clsidIn, CLSID *pclsid);
STDMETHODIMP SetMimeType(LPCWSTR pszMine); LPCWSTR GetMimeType();
STDMETHODIMP GetAcceptStr(LPWSTR *ppwzStr, ULONG *pcElements); STDMETHODIMP GetAcceptMimes(LPWSTR *ppStr, ULONG cel, ULONG *pcElements);
STDMETHODIMP PrepareThreadTransfer();
DataSink GetDataSink(); DataSink SetDataSink(DWORD dwBindF); DataSink SwitchDataSink(DataSink dsNew);
void OnEndofData();
BOOL IsFileRequired(); BOOL IsFromCache() { return _fCache; } void SetFromCacheFlag(BOOL fCache) { _fCache = fCache; }
void ResetCINet(IOInetProtocol *pCINet) { if (_pProt) { _pProt->Release(); }
_pProt = pCINet;
if (_pProt) { _pProt->AddRef(); } }
ULONG GetDataSize() { return _cbDataSize; }
DWORD GetBindFlags() { return _grfBindF; } LPWSTR GetUrl() { UrlMkAssert((FALSE)); return NULL; }
VOID SetFileAsStmFile() { _fFileAsStmOnFile = TRUE; }
BOOL IsEOFOnSwitchSink() { return _fEOFOnSwitchSink; }
LPWSTR SetRedirectUrl(LPWSTR pwzStr) { if (_pwzRedirectUrl) { delete [] _pwzRedirectUrl; }
_pwzRedirectUrl = OLESTRDuplicate(pwzStr);
return _pwzRedirectUrl; }
public:
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID iid, void **ppvObj); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // ITransactionData methods
STDMETHODIMP GetTransactionData(LPCWSTR pwzUrl, LPOLESTR *ppwzFilename, LPOLESTR *ppwzMime, DWORD *pdwSizeTotal, DWORD *pdwSizeAvailable, DWORD dwReserved);
static HRESULT Create(LPCWSTR pwzUrl, DWORD grfBindF, REFIID riid, IBindCtx *pBndCtx, BOOL fBindToObject, CTransData **ppCTD); STDMETHODIMP Initialize(LPCWSTR pwzUrl, DWORD grfBindF, REFIID riid, IBindCtx *pBndCtx, BOOL fBindToObject = FALSE);
private: CRefCount _CRefs; // refcount class
TransDataState _TransDataState; IOInetProtocol *_pProt;
STGMEDIUM *_pStgMed; FORMATETC _formatetc; // The format that we are sending
CLIPFORMAT _cfFormat; IEnumFORMATETC *_pEnumFE; IBindCtx *_pBndCtx; IID *_piidRes; DWORD _grfMode; DWORD _dwAttached; DWORD _grfBindF; DWORD _grfBSC; LPWSTR _pwzUrl; LPWSTR _pwzRedirectUrl;
unsigned _fBindToObject : 1; //changes with attachment... DO NOT USE FLAG.
unsigned _fMimeTypeVerified : 1; unsigned _fDocFile : 1; unsigned _fInitialized : 1; unsigned _fRemoteReady : 1; unsigned _fCache : 1; unsigned _fLocked : 1; unsigned _fFileAsStmOnFile : 1; unsigned _fEOFOnSwitchSink : 1;
LPBYTE _lpBuffer; // DNLD_BUFFER_SIZE size buffer
ULONG _cbBufferSize; ULONG _cbDataSize; ULONG _cbTotalBytesRead; ULONG _cbReadReturn; ULONG _cbBufferFilled; //how much of the buffer is in use
ULONG _cbDataSniffMin; ULONG _cbBytesReported; // how much was reported
DataSink _ds;
HANDLE _hFile; WCHAR _wzMime[SZMIMESIZE_MAX]; WCHAR _wzFileName[MAX_PATH];
};
//+---------------------------------------------------------------------------
//
// Class: CModalLoop ()
//
// Purpose:
//
// Interface: CModalLoop --
// ~CModalLoop --
// QueryInterface --
// AddRef --
// Release --
// HandleInComingCall --
// RetryRejectedCall --
// MessagePending --
// _CRefs --
// _pMsgFlter --
//
// History: 8-21-96 JohannP (Johann Posch) Created
//
// Notes:
//
//----------------------------------------------------------------------------
class CModalLoop : public IMessageFilter { public: CModalLoop(HRESULT *phr); ~CModalLoop();
STDMETHOD(QueryInterface) ( REFIID riid, LPVOID FAR* ppvObj); STDMETHOD_(ULONG,AddRef) (void); STDMETHOD_(ULONG,Release) (void);
STDMETHOD_(DWORD, HandleInComingCall)( DWORD dwCallType,HTASK htaskCaller, DWORD dwTickCount,LPINTERFACEINFO lpInterfaceInfo);
STDMETHOD_(DWORD, RetryRejectedCall)( HTASK htaskCallee,DWORD dwTickCount, DWORD dwRejectType);
STDMETHOD_(DWORD, MessagePending)( HTASK htaskCallee, DWORD dwTickCount, DWORD dwPendingType);
HRESULT HandlePendingMessage( DWORD dwPendingType, DWORD dwPendingRecursion, DWORD dwReserved);
private: CRefCount _CRefs; // refcount class
IMessageFilter *_pMsgFlter; };
CTransactionMgr * GetThreadTransactionMgr(BOOL fCreate = TRUE); #define ChkHResult(hr) { if (FAILED(hr)) { UrlMkAssert((FALSE)); goto End; } }
extern char szContent[]; extern char szClassID[]; extern char szFlags[]; extern char szClass[]; extern char szExtension[]; extern const GUID CLSID_PluginHost;
// private flags for bad header
#define MIMESNIFF_BADHEADER 0x00010000
HRESULT GetMimeFileExtension(LPSTR pszMime, LPSTR pszExt, DWORD cbSize); HRESULT GetClassFromExt(LPSTR pszExt, CLSID *pclsid); HRESULT IsDocFile(LPVOID pBuffer, DWORD cbSize);
HRESULT GetPlugInClsID(LPSTR pszExt, LPSTR pszName, LPSTR pszMime, CLSID *pclsid); HRESULT FindMediaTypeFormat(LPCWSTR pwzType, CLIPFORMAT *cfType, DWORD *pdwFormat); HRESULT GetMimeFlags(LPCWSTR pwzMime, DWORD *pdwFlags);
#endif //_TRANSACT_HXX_
|