////////////////////////////////////////////////////////////////////////////////
//                                                                            //
//   Wireless Communication Library 7                                         //
//                                                                            //
//   Copyright (C) 2006-2024 Mike Petrichenko                                 //
//                           Soft Service Company                             //
//                           All Rights Reserved                              //
//                                                                            //
//   http://www.btframework.com                                               //
//                                                                            //
//   support@btframework.com                                                  //
//   shop@btframework.com                                                     //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

#pragma once

#include <string>

#include <windows.h>

#include "wclErrors.h"

namespace wclCommon
{
	/// <summary> Defines the string type as UNICODE string. </summary>
	typedef std::wstring tstring;

	/// <summary> The macro disable the copy constructor of a class. </summary>
	#define DISABLE_COPY(Class) \
		private: Class(const Class&); Class& \
		operator=(const Class&)

	/// <summary> The common event handler prototype. </summary>
	/// <param name="Sender"> The object that initiated the event. </param>
	#define wclNotifyEvent(_event_name_) \
		__event void _event_name_(void* Sender)

	/// <summary> Creates a new mutex with given name. </summary>
	/// <param name="Name"> The mutex name. </param>
	/// <param name="Unique"> Set this to <c>true</c> to create a process-dependent
	///   unique mutex. Otherwise system wide named mutex will be created. </param>
	/// <param name="Own"> The optional parameter (default value is <c>false</c>
	///   indicates if the Mutex must be owned by a called. </param>
	/// <returns> If the function succeed the return value is the Mutex handle.
		///   If the function failed the return value is <c>NULL</c>. </returns>
	HANDLE wclCreateMutex(const TCHAR* Name, const bool Unique,
		const bool Own = false);

	/// <summary> Reads the error information. </summary>
	/// <param name="Error"> The WCL error code. </param>
	/// <param name="Framework"> If the function completed with success on output
	///   contains the WCL Framework name that the error relates to. </param>
	/// <param name="Category"> If the function completed with success on output
	///   contains the error category. </param>
	/// <param name="Constant"> If the function completed with success on output
	///   contains the error constant name. </param>
	/// <param name="Description"> If the function completed with success on output
	///   contains the error description. </param>
	/// <returns> If the function completed with success the returning value is
	///   <c>true</c>. Otherwise the function returns <c>false</c>. </returns>
	/// <remarks> The function uses the errors.xml file located on our site.
	///   The file link is https://www.btframework.com/errors.xml. </remarks>
	bool wclGetErrorInfo(const int Error, tstring& Framework, tstring& Category,
		tstring& Constant, tstring& Description);
	/// <summary> Reads the error information. </summary>
	/// <param name="FileName"> The full file path to the error.xml file. </param>
	/// <param name="Error"> The WCL error code. </param>
	/// <param name="Framework"> If the function completed with success on output
	///   contains the WCL Framework name that the error relates to. </param>
	/// <param name="Category"> If the function completed with success on output
	///   contains the error category. </param>
	/// <param name="Constant"> If the function completed with success on output
	///   contains the error constant name. </param>
	/// <param name="Description"> If the function completed with success on output
	///   contains the error description. </param>
	/// <returns> If the function completed with success the returning value is
	///   <c>true</c>. Otherwise the function returns <c>false</c>. </returns>
	bool wclGetErrorInfo(const tstring& FileName, const int Error, tstring& Framework,
		tstring& Category, tstring& Constant, tstring& Description);

	/// <summary> Converts UTF8 string to WCL string. </summary>
	/// <param name="lpszUTF8"> UTF8 encoded string. </param>
	/// <param name="Len"> The UTF8 encoded string length. </param>
	/// <returns> WCL (UNICODE) string. </returns>
	tstring wclUTF8Decode(const PCHAR lpszUTF8, const DWORD Len);
	/// <summary> Converts UTF8 string to WCL string. </summary>
	/// <param name="lpszUTF8"> UTF8 encoding string. </param>
	/// <returns> WCL (UNICODE) string. </returns>
	tstring wclUTF8Decode(const PCHAR lpszUTF8);

	/// <summary> Converts WCL (UNICODE) string to UTF8 encoded string. </summary>
	/// <param name="str"> WCL string that should be converted to UTF8. </param>
	/// <param name="lpszUTF8"> Pointer to a buffer that receives UTF8 encoded string. </param>
	/// <param name="dwUTF8Len"> Size of UTF8 buffer. </param>
	void wclUTF8Encode(const tstring& str, const PCHAR lpszUTF8,
		const DWORD dwUTF8Len);

	/// <summary> Converts UNICODE string to ANSI string. </summary>
	/// <param name="s"> The UNICODE string. </param>
	/// <returns> The ANSI string. </returns>
	std::string wclUnicodeToAnsi(const std::wstring& s);

	/// <summary> Converts ANSI string to UNICODE string. </summary>
	/// <param name="s"> The ANSI string. </param>
	/// <returns> The UNICODE string. </returns>
	std::wstring wclAnsiToUnicode(const std::string& s);

	/// <summary> Windows versions. </summary>
	typedef enum
	{
		/// <summary> Unknown Windows version. </summary>
		verUnknown = 1,
		/// <summary> Windows XP. </summary>
		verWinXP = 2,
		/// <summary> Windows Vista. </summary>
		verWinVista = 3,
		/// <summary> Windows 7. </summary>
		verWin7 = 4,
		/// <summary> Windows 8. </summary>
		verWin8 = 5,
		/// <summary> Windows 8.1. </summary>
		verWin81 = 6,
		/// <summary> Windows 10. </summary>
		verWin10 = 7,
		/// <summary> Windows 11. </summary>
		verWin11 = 8
	} wclWinVer;

	/// <summary> The class provides information about OS version. </summary>
	class CwclOsVersion
	{
		DISABLE_COPY(CwclOsVersion);

	private:
		bool			FIsWinIot;
		unsigned short	FOsBuild;
		wclWinVer		FOsVersion;
		
		void ReadIsWinIot();
		void CheckWin10orAbove();
		void ReadOsVersion();

	public:
		/// <summary> Creates new object of the version reading class. </summary>
		CwclOsVersion();
		
		/// <summary> Checks if software runs on Windows 10 IoT. </summary>
		/// <returns> The function returns <c>true</c> if it runs on Windows 10 IoT.
		///   Otherwise returns <c>false</c>. </returns>
		bool GetIsWinIot();
		/// <summary> Checks if software runs on Windows 10 IoT. </summary>
		/// <value> The function returns <c>true</c> if it runs on Windows 10 IoT.
		///   Otherwise returns <c>false</c>. </value>
		__declspec(property(get = GetIsWinIot)) bool IsWinIot;

		/// <summary> Gets Windows OS version. </summary>
		/// <returns> The Windows OS version. </returns>
		/// <seealso cref="wclWinVer" />
		wclWinVer GetOsVersion();
		/// <summary> Gets Windows OS version. </summary>
		/// <value> The Windows OS version. </value>
		/// <seealso cref="wclWinVer" />
		__declspec(property(get = GetOsVersion)) wclWinVer OsVersion;

		/// <summary> Gets the OS build number. </summary>
		/// <returns> The OS build number. </returns>
		/// <remarks> <para> For Win 10 <c>Build</c> can be translated to OS version
		///   (release) using the table below. </para>
		///   <para><c> Build </c> <c> Release </c></para>
		///   <para><c>=======</c> <c>=========</c></para>
		///   <para><c> 10240 </c> <c>   1507  </c></para>
		///   <para><c> 10586 </c> <c>   1511  </c></para>
		///   <para><c> 14393 </c> <c>   1607  </c></para>
		///   <para><c> 15063 </c> <c>   1703  </c></para>
		///   <para><c> 16299 </c> <c>   1709  </c></para>
		///   <para><c> 17134 </c> <c>   1803  </c></para>
		///   <para><c> 17763 </c> <c>   1809  </c></para>
		///   <para><c> 18362 </c> <c>   1903  </c></para>
		///   <para><c> 18363 </c> <c>   1909  </c></para>
		///   <para><c> 19041 </c> <c>   2004  </c></para>
		///   <para><c> 19042 </c> <c>   20H2  </c></para>
		///   <para><c> 19043 </c> <c>   21H1  </c></para>
		///   <para><c> 19044 </c> <c>   21H2  </c></para>
		///   <para><c> 19045 </c> <c>   22H2  </c></para>
		///   <para></para>
		/// <para> For Win 11 <c>Build</c> can be translated to OS version
		///   (release) using the table below. </para>
		///   <para><c> Build </c> <c> Release </c></para>
		///   <para><c>=======</c> <c>=========</c></para>
		///   <para><c> 22000 </c> <c>   21H2  </c></para>
		///   <para><c> 22621 </c> <c>   22H2  </c></para>
		///   <para><c> 22631 </c> <c>   23H2  </c></para> </remarks>
		unsigned short GetOsBuild();
		/// <summary> Gets the OS build number. </summary>
		/// <value> The OS build number. </value>
		/// <remarks> <para> For Win 10 <c>Build</c> can be translated to OS version
		///   (release) using the table below. </para>
		///   <para><c> Build </c> <c> Release </c></para>
		///   <para><c>=======</c> <c>=========</c></para>
		///   <para><c> 10240 </c> <c>   1507  </c></para>
		///   <para><c> 10586 </c> <c>   1511  </c></para>
		///   <para><c> 14393 </c> <c>   1607  </c></para>
		///   <para><c> 15063 </c> <c>   1703  </c></para>
		///   <para><c> 16299 </c> <c>   1709  </c></para>
		///   <para><c> 17134 </c> <c>   1803  </c></para>
		///   <para><c> 17763 </c> <c>   1809  </c></para>
		///   <para><c> 18362 </c> <c>   1903  </c></para>
		///   <para><c> 18363 </c> <c>   1909  </c></para>
		///   <para><c> 19041 </c> <c>   2004  </c></para>
		///   <para><c> 19042 </c> <c>   20H2  </c></para>
		///   <para><c> 19043 </c> <c>   21H1  </c></para>
		///   <para><c> 19044 </c> <c>   21H2  </c></para>
		///   <para><c> 19045 </c> <c>   22H2  </c></para>
		///   <para></para>
		/// <para> For Win 11 <c>Build</c> can be translated to OS version
		///   (release) using the table below. </para>
		///   <para><c> Build </c> <c> Release </c></para>
		///   <para><c>=======</c> <c>=========</c></para>
		///   <para><c> 22000 </c> <c>   21H2  </c></para>
		///   <para><c> 22621 </c> <c>   22H2  </c></para>
		///   <para><c> 22631 </c> <c>   23H2  </c></para> </remarks>
		__declspec(property(get = GetOsBuild)) unsigned short OsBuild;
	};

	/// <summary> Global instance of the OS version reader class. </summary>
	extern CwclOsVersion wclOsVersion;

	/// <summary> Stream origins. </summary>
	typedef enum
	{
		/// <summary> From stream beginning. </summary>
		soBeginning,
		/// <summary> From current position. </summary>
		soCurrent,
		/// <summary> From stream end. </summary>
		soEnd
	} wclSeekOrigin;

	/// <summary> The base class for WCL streams. </summary>
	class CwclStream
	{
		DISABLE_COPY(CwclStream);
		
	public:
		/// <summary> Creates new stream object. </summary>
		CwclStream();
		/// <summary> Frees the stream object. </summary>
		virtual ~CwclStream();

		/// <summary> Reads from stream. </summary>
		/// <param name="Buffer"> The pointer to the memory buffer. </param>
		/// <param name="Count"> Amount of bytes to read. </param>
		/// <returns> Number of read bytes. </returns>
		virtual unsigned long Read(void* const Buffer, const unsigned long Count) = 0;
		/// <summary> Writes to the stream. </summary>
		/// <param name="Buffer"> The pointer to the memory buffer. </param>
		/// <param name="Count"> Amount of bytes to write. </param>
		/// <returns> Number of written bytes. </returns>
		virtual unsigned long Write(const void* const Buffer,
			const unsigned long Count) = 0;
		/// <summary> Changes current position. </summary>
		/// <param name="Offset"> The offset. </param>
		/// <param name="Origin"> Seek origin. </param>
		/// <returns> Current position. </returns>
		/// <seealso cref="wclSeekOrigin" />
		virtual unsigned long Seek(const long Offset, const wclSeekOrigin Origin) = 0;
		/// <summary> Copies data from other stream. </summary>
		/// <param name="Source"> The source stream. </param>
		/// <param name="Count"> Amount of bytes to copy. </param>
		/// <seealso cref="CwclStream" />
		unsigned long CopyFrom(CwclStream* const Source,
			unsigned long Count);
		
		/// <summary> Gets the stream size. </summary>
		/// <returns> The current stream size. </returns>
		unsigned long GetSize();
		/// <summary> Sets the stream size. </summary>
		/// <param name="NewSize"> The new stream size. </param>
		virtual void SetSize(const unsigned long NewSize) = 0;
		
		/// <summary> Gets the current position. </summary>
		/// <returns> The current position. </returns>
		unsigned long GetPosition();
		/// <summary> Sets the current position. </summary>
		/// <param name="Pos"> The new position. </param>
		void SetPosition(const unsigned long Pos);
	};

	/// <summary> The base class for handle based streams. </summary>
	/// <seealso cref="CwclStream" />
	class CwclHandleStream : public CwclStream
	{
		DISABLE_COPY(CwclHandleStream);
		
	protected:
		HANDLE	FHandle;

	public:	
		/// <summary> Creates new stream. </summary>
		CwclHandleStream();
		/// <summary> Frees the stream object. </summary>
		virtual ~CwclHandleStream();

		/// <summary> Sets the stream size. </summary>
		/// <param name="NewSize"> The new stream size. </param>
		virtual void SetSize(const unsigned long NewSize) override;
		
		/// <summary> Reads from stream. </summary>
		/// <param name="Buffer"> The pointer to the memory buffer. </param>
		/// <param name="Count"> Amount of bytes to read. </param>
		/// <returns> Number of read bytes. </returns>
		virtual unsigned long Read(void* const Buffer, const unsigned long Count) override;
		/// <summary> Writes to the stream. </summary>
		/// <param name="Buffer"> The pointer to the memory buffer. </param>
		/// <param name="Count"> Amount of bytes to write. </param>
		/// <returns> Number of written bytes. </returns>
		virtual unsigned long Write(const void* const Buffer,
			const unsigned long Count) override;
		/// <summary> Changes current position. </summary>
		/// <param name="Offset"> The offset. </param>
		/// <param name="Origin"> Seek origin. </param>
		/// <returns> Current position. </returns>
		/// <seealso cref="wclSeekOrigin" />
		virtual unsigned long Seek(const long Offset,
			const wclSeekOrigin Origin) override;

		/// <summary> Gets the handle. </summary>
		/// <returns> The handle. </returns>
		HANDLE GetHandle() const;
	};

	/// <summary> The class represents a file stream. </summary>
	/// <seealso cref="CwclHandleStream" />
	class CwclFileStream : public CwclHandleStream
	{
		DISABLE_COPY(CwclFileStream);
		
	public:
		/// <summary> Creates new file stream object. </summary>
		/// <param name="FileName"> The file name. </param>
		/// <param name="CreationDisposition"> An action to take on a file or device that exists
		///   or does not exist. </param>
		/// <param name="DesiredAccess"> The requested access to the file or device, which can be
		///   summarized as read, write, both or neither zero). </param>
		/// <param name="ShareMode"> The requested sharing mode of the file or device, which
		///   can be read, write, both, delete, all of these, or none (refer to the following table).
		///   Access requests to attributes or extended attributes are not affected by this
		///   flag. </param>
		/// <remarks> If the open or create file failed the <see cref="wclEFileOpenFailed" />
		///   exception raises. </remarks>
		/// <exception cref="wclEFileOpenFailed"></exception>
		CwclFileStream(const tstring& FileName, const unsigned long CreationDisposition,
			const unsigned long DesiredAccess, const unsigned long ShareMode);
		/// <summary> Frees the file. </summary>
		virtual ~CwclFileStream();
	};

	// Forward declaration.
	class CwclMemoryStream;

	/// <summary> The base class for memory streams. </summary>
	/// <seealso cref="CwclStream" />
	class CwclCustomMemoryStream : public CwclStream
	{
		DISABLE_COPY(CwclCustomMemoryStream);

	private:
		friend class CwclMemoryStream;

		void*			FMemory;
		unsigned long	FSize;
		unsigned long	FPosition;

	protected:
		/// <summary> Sets new memory pointer and size. </summary>
		/// <param name="Ptr"> The new pointer. </param>
		/// <param name="Size"> The new size. </param>
		void SetPointer(void* const Ptr, const unsigned long Size);

	public:
		/// <summary> Creates new memory stream. </summary>
		CwclCustomMemoryStream();
		/// <summary> Frees the stream. </summary>
		virtual ~CwclCustomMemoryStream();

		/// <summary> Reads from stream. </summary>
		/// <param name="Buffer"> The pointer to the memory buffer. </param>
		/// <param name="Count"> Amount of bytes to read. </param>
		/// <returns> Number of read bytes. </returns>
		virtual unsigned long Read(void* const Buffer,
			const unsigned long Count) override;
		/// <summary> Changes current position. </summary>
		/// <param name="Offset"> The offset. </param>
		/// <param name="Origin"> Seek origin. </param>
		/// <returns> Current position. </returns>
		/// <seealso cref="wclSeekOrigin" />
		virtual unsigned long Seek(const long Offset,
			const wclSeekOrigin Origin) override;
		/// <summary> Saves the data into the stream. </summary>
		/// <param name="Stream"> The stream object. </param>
		/// <seealso cref="CwclStream" />
		void SaveToStream(CwclStream* const Stream);
		
		/// <summary> Gets the pointer to the memory used by the stream. </summary>
		/// <returns> The pointer to the memory. </returns>
		void* GetMemory() const;
	};

	/// <summary> The memory stream. </summary>
	/// <seealso cref="CwclCustomMemoryStream" />
	class CwclMemoryStream : public CwclCustomMemoryStream
	{
		DISABLE_COPY(CwclMemoryStream);
		
	private:
		unsigned long	FCapacity;
		
	protected:
		/// <summary> Reallocates memory. </summary>
		/// <param name="NewCapacity"> New capacity. </param>
		virtual void* Realloc(unsigned long& NewCapacity);
		
		/// <summary> Sets the stream capacity. </summary>
		/// <param name="NewCapacity"> New capacity. </param>
		void SetCapacity(unsigned long NewCapacity);
		/// <summary> Gets the stream capacity. </summary>
		/// <returns> The stream capacity. </returns>
		unsigned long GetCapacity() const;

	public:
		/// <summary> Creates new memory stream. </summary>
		CwclMemoryStream();
		/// <summary> Frees the stream. </summary>
		virtual ~CwclMemoryStream();

		/// <summary> Clears the memory. </summary>
		void Clear();
		/// <summary> Loads data from stream. </summary>
		/// <param name="Stream"> The source stream. </param>
		/// <seealso cref="CwclStream" />
		void LoadFromStream(CwclStream* const Stream);
		/// <summary> Sets the stream size. </summary>
		/// <param name="NewSize"> The new stream size. </param>
		virtual void SetSize(const unsigned long NewSize) override;
		/// <summary> Writes to the stream. </summary>
		/// <param name="Buffer"> The pointer to the memory buffer. </param>
		/// <param name="Count"> Amount of bytes to write. </param>
		/// <returns> Number of written bytes. </returns>
		virtual unsigned long Write(const void* const Buffer,
			const unsigned long Count) override;
	};

	/// <summary> The enumeration indicates whether a stream object should be
	///   freed by the object that uses it. </summary>
	typedef enum
	{
		/// <summary> The stream is an independent object with a different Owner.
		///   The object that uses the stream does not free it when it is
		///   destroyed. </summary>
		soReference,
		/// <summary> The stream is owned by the object that uses it (and exists solely
		///   for that object). The object that uses the stream frees the associated
		///   stream when it no longer needs to use the stream. </summary>
		soOwned
	} wclStreamOwnership;

	/// <summary> The class implements the <c>IStream</c> interface on a
	///   <see cref="CwclStream" /> object. </summary>
	class CwclStreamAdapter : public IStream
	{
		DISABLE_COPY(CwclStreamAdapter);

	private:
		CwclStream*			FStream;
		wclStreamOwnership	FOwnership;

		LONG				FRefCount;

	public:
		/* IUnknown */	
		
		/// <summary> Queries a COM object for a pointer to one of its interface; identifying
		///   the interface by a reference to its interface identifier (IID). If the COM object
		///   implements the interface, then it returns a pointer to that interface after calling 
		///   <c>AddRef</c> on it. </summary>
		/// <param name="riid"> A reference to the interface identifier (IID) of the interface
		///   being queried for. </param>
		/// <param name="ppvObject"> The address of a pointer to an interface with the IID specified
		///   in the <c>riid</c> parameter. Because you pass the address of an interface pointer, the
		///   method can overwrite that address with the pointer to the interface being queried for.
		///   Upon successful return, <c>*ppvObject</c> (the dereferenced address) contains a pointer to
		///   the requested interface. If the object doesn't support the interface, the method sets
		///   <c>*ppvObject</c> (the dereferenced address) to <c>NULL</c>. </param>
		/// <returns> This method returns <c>S_OK</c> if the interface is supported, and
		///   <c>E_NOINTERFACE</c> otherwise. If <c>ppvObject</c> (the address) is <c>NULL</c>,
		///   then this method returns <c>E_POINTER</c>. </returns>
		virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override;
		/// <summary> Increments the reference count for an interface pointer to a COM object.
		///   You should call this method whenever you make a copy of an interface pointer </summary>
		/// <returns> The method returns the new reference count. This value is intended to be used
		///   only for test purposes. </returns>
		virtual ULONG STDMETHODCALLTYPE AddRef() override;
		/// <summary> Decrements the reference count for an interface on a COM object. </summary>
		/// <returns> The method returns the new reference count. This value is intended to be used
		///   only for test purposes. </returns>
		virtual ULONG STDMETHODCALLTYPE Release() override;
		
		/* ISequentialStream */

		/// <summary> The method reads a specified number of bytes from the stream object
		///   into memory, starting at the current seek pointer. </summary>
		/// <param name="pv"> A pointer to the buffer which the stream data is read into. </param>
		/// <param name="cb"> The number of bytes of data to read from the stream object. </param>
		/// <param name="pcbRead"> A pointer to a <c>ULONG</c> variable that receives the actual
		///   number of bytes read from the stream object. <c>Note:</c> The number of bytes read may
		///   be zero. </param>
		/// <returns> <c>S_OK</c> if operation completed with success. </returns>
		virtual HRESULT STDMETHODCALLTYPE Read(void *pv, ULONG cb, ULONG *pcbRead) override;
		/// <summary> The method writes a specified number of bytes into the stream object
		///   starting at the current seek pointer. </summary>
		/// <param name="pv"> A pointer to the buffer that contains the data that is to be written
		///   to the stream. A valid pointer must be provided for this parameter even when
		///   <c>cb</c> is zero. </param>
		/// <param name="cb"> The number of bytes of data to attempt to write into the stream.
		///   This value can be zero. </param>
		/// <param name="pcbWritten"> A pointer to a <c>ULONG</c> variable where this method writes
		///   the actual number of bytes written to the stream object. The caller can set this
		///   pointer to <c>NULL</c>, in which case this method does not provide the actual number of
		///   bytes written. </param>
		/// <returns> <c>S_OK</c> if operation completed with success. </returns>
		virtual HRESULT STDMETHODCALLTYPE Write(const void *pv, ULONG cb, ULONG *pcbWritten) override;

		/* IStream */

		/// <summary> The method changes the seek pointer to a new location. The new location is
		///   relative to either the beginning of the stream, the end of the stream, or the current
		///   seek pointer. </summary>
		/// <param name="dlibMove"> The displacement to be added to the location indicated by the
		///   <c>dwOrigin</c> parameter. If <c>dwOrigin</c> is <c>STREAM_SEEK_SET</c>, this is
		///   interpreted as an unsigned value rather than a signed value. </param>
		/// <param name="dwOrigin"> The origin for the displacement specified in <c>dlibMove</c>. The
		///   origin can be the beginning of the file (<c>STREAM_SEEK_SET</c>), the current seek pointer
		///   (<c>STREAM_SEEK_CUR</c>), or the end of the file (<c>STREAM_SEEK_END</c>). </param>
		/// <param name="plibNewPosition"> A pointer to the location where this method writes the value
		///   of the new seek pointer from the beginning of the stream. You can set this pointer to
		///   <c>NULL</c>. In this case, this method does not provide the new seek pointer. </param>
		/// <returns> <c>S_OK</c> if operation completed with success. </returns>
		virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin,
			ULARGE_INTEGER *plibNewPosition) override;
		/// <summary> The method changes the size of the stream object. </summary>
		/// <param name="libNewSize"> Specifies the new size, in bytes, of the stream. </param>
		/// <returns> <c>S_OK</c> if operation completed with success. </returns>
		virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER libNewSize) override;
		/// <summary> The method copies a specified number of bytes from the current seek
		///   pointer in the stream to the current seek pointer in another stream. </summary>
		/// <param name="pstm"> A pointer to the destination stream. The stream pointed to by <c>pstm</c>
		///   can be a new stream or a clone of the source stream. </param>
		/// <param name="cb"> The number of bytes to copy from the source stream. </param>
		/// <param name="pcbRead"> A pointer to the location where this method writes the actual
		///   number of bytes read from the source. You can set this pointer to <c>NULL</c>. In this case,
		///   this method does not provide the actual number of bytes read. </param>
		/// <param name="pcbWritten"> A pointer to the location where this method writes the actual
		///   number of bytes written to the destination. You can set this pointer to <c>NULL</c>.
		///   In this case, this method does not provide the actual number of bytes written. </param>
		/// <returns> <c>S_OK</c> if operation completed with success. </returns>
		virtual HRESULT STDMETHODCALLTYPE CopyTo(IStream *pstm, ULARGE_INTEGER cb,
			ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) override;
		/// <summary> The method ensures that any changes made to a stream object open in transacted mode
		///   are reflected in the parent storage. If the stream object is open in direct mode, <c>Commit</c>
		///   has no effect other than flushing all memory buffers to the next-level storage object.
		///   The COM compound file implementation of streams does not support opening streams in transacted
		///   mode. </summary>
		/// <param name="grfCommitFlags"> Controls how the changes for the stream object are committed. </param>
		/// <returns> <c>S_OK</c> if operation completed with success. </returns>
		virtual HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags) override;
		/// <summary> The method discards all changes that have been made to a transacted stream since
		///   the last <c>Commit</c> call. On streams open in direct mode and streams using the COM compound
		///   file implementation of IStream::Revert, this method has no effect. </summary>
		/// <returns> <c>S_OK</c> if operation completed with success. </returns>
		virtual HRESULT STDMETHODCALLTYPE Revert() override;
		/// <summary> The method restricts access to a specified range of bytes in the stream. Supporting this
		///   functionality is optional since some file systems do not provide it. </summary>
		/// <param name="libOffset"> Integer that specifies the byte offset for the beginning of the
		///   range. </param>
		/// <param name="cb"> Integer that specifies the length of the range, in bytes, to be
		///   restricted. </param>
		/// <param name="dwLockType"> Specifies the restrictions being requested on accessing the
		///   range. </param>
		/// <returns> <c>S_OK</c> if operation completed with success. </returns>
		virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER libOffset,
			ULARGE_INTEGER cb, DWORD dwLockType) override;
		/// <summary> The method removes the access restriction on a range of bytes previously
		///   restricted with <c>LockRegion</c>. </summary>
		/// <param name="libOffset"> Specifies the byte offset for the beginning of the range. </param>
		/// <param name="cb"> Specifies, in bytes, the length of the range to be restricted. </param>
		/// <param name="dwLockType"> Specifies the access restrictions previously placed on the
		///   range. </param>
		/// <returns> <c>S_OK</c> if operation completed with success. </returns>
		virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER libOffset,
			ULARGE_INTEGER cb, DWORD dwLockType) override;
		/// <summary> The method retrieves the <c>STATSTG</c> structure for this
		///   stream. </summary>
		/// <param name="pstatstg"> Pointer to a <c>STATSTG</c> structure where this method places
		///   information about this stream object. </param>
		/// <param name="grfStatFlag"> Specifies that this method does not return some of the members
		///   in the <c>STATSTG</c> structure, thus saving a memory allocation operation. Values are
		///   taken from the <c>STATFLAG</c> enumeration. </param>
		/// <returns> <c>S_OK</c> if operation completed with success. </returns>
		virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG *pstatstg, DWORD grfStatFlag) override;
		/// <summary> The method creates a new stream object with its own seek pointer that
		///   references the same bytes as the original stream. </summary>
		/// <param name="ppstm"> When successful, pointer to the location of an <c>IStream</c> pointer
		///   to the new stream object. If an error occurs, this parameter is <c>NULL</c>. </param>
		/// <returns> <c>S_OK</c> if operation completed with success. </returns>
		virtual HRESULT STDMETHODCALLTYPE Clone(IStream **ppstm) override;

	public:
		/// <summary> Creates new Stream Adapter object. </summary>
		/// <param name="Stream"> The <see cref="CwclStream" /> object that needs to be "converted" to
		///   the <c>IStream</c> interface. If this parameter is <c>NULL</c> the 
		///   <see cref="wclEInvalidArgument" /> exception raises. </param>
		/// <param name="Ownership"> Indicates how the Stream Adapter owns the <c>Stream</c> object. </param>
		/// <seealso cref="CwclStream" />
		/// <seealso cref="wclStreamOwnership" />
		/// <exception cref="wclEInvalidArgument"></exception>
		CwclStreamAdapter(CwclStream* const Stream,
			const wclStreamOwnership Ownership = soReference);
		/// <summary> Frees the Stream Adapter object. </summary>
		virtual ~CwclStreamAdapter();

		/// <summary> Gets the <see cref="CwclStream" /> object that is owned by the Stream
		///   Adapter. </summary>
		/// <returns> The <see cref="CwclStream" /> object. </returns>
		/// <seealso cref="CwclStream" />
		CwclStream* GetStream() const;

		/// <summary> Gets the associated <c>Stream</c> ownership. </summary>
		/// <returns> The current ownership of the associated <c>Stream</c>. </returns>
		/// <seealso cref="wclStreamOwnership" />
		wclStreamOwnership GetStreamOwnership() const;
		/// <summary> Sets the associated <c>Stream</c> ownership. </summary>
		/// <param name="Value"> The new ownership of the associated <c>Stream</c>. </param>
		/// <seealso cref="wclStreamOwnership" />
		void SetStreamOwnership(const wclStreamOwnership Value);
	};
}
