/*++ Copyright (c) 2000 Microsoft Corporation Module Name: Wrappers.h Abstract: Contains some commonly used macros, inline utility functions and wrapper/helper classes Author: Hakki T. Bostanci (hakkib) 06-Apr-2000 Revision History: --*/ #ifndef _WRAPPERS_H_ #define _WRAPPERS_H_ ////////////////////////////////////////////////////////////////////////// // // Cross references // #include #include "Conv.h" #include "Result.h" ////////////////////////////////////////////////////////////////////////// // // // #ifndef ASSERT #define ASSERT assert #endif typedef CONST TCHAR *PCTSTR; #if !defined(NDEBUG) || defined(_DEBUG) || defined(DBG) #ifndef DEBUG #define DEBUG #endif //DEBUG #endif #ifdef DEBUG #define IFDEBUG(Statement) Statement #else //DEBUG #define IFDEBUG(Statement) #endif //DEBUG ////////////////////////////////////////////////////////////////////////// // // COUNTOF // // Returns the number of elements in an array // #define COUNTOF(array) ( sizeof(array) / sizeof(array[0]) ) ////////////////////////////////////////////////////////////////////////// // // STRING // // Stringizing operator // #define STRING(arg) #arg ////////////////////////////////////////////////////////////////////////// // // DISABLE_COPY_CONTRUCTION // // Declares copy construction operators as private to prevent outside access // #define DISABLE_COPY_CONTRUCTION(Class) \ private: \ Class(const Class&) { } \ Class& operator =(const Class&) { return *this; } \ ////////////////////////////////////////////////////////////////////////// // // IS_NT // // Returns true on an NT based OS // #define IS_NT ( GetVersion() < 0x80000000 ) ////////////////////////////////////////////////////////////////////////// // // LONG_PATH // // Returns the \\?\ string (that can be used in file APIs) in UNICODE builds // #ifdef UNICODE #define LONG_PATH L"\\\\?\\" #else //UNICODE #define LONG_PATH #endif //UNICODE ////////////////////////////////////////////////////////////////////////// // // AW, _AW // // Append a 'W' or 'A' depending on UNICODE or ANSI builds // #ifdef UNICODE #define AW(name) name##W #define _AW "W" #else //UNICODE #define AW(name) name##A #define _AW "A" #endif //UNICODE ////////////////////////////////////////////////////////////////////////// // // IGNORE_EXCEPTIONS // // Ignores any exceptions thrown from the code block // #define IGNORE_EXCEPTIONS(Statement) try { Statement; } catch (...) {} ////////////////////////////////////////////////////////////////////////// // // WAIT_AND_RETRY_ON_EXCEPTION // // Pauses and retries if an exception is thrown from the code block // #define WAIT_AND_RETRY_ON_EXCEPTION(func, nRetries, nWaitTime) \ { \ int nTrials = nRetries; \ \ while (1) \ { \ try \ { \ func; \ break; \ } \ catch (...) \ { \ if (nTrials-- == 0) \ { \ throw; \ } \ \ Sleep(nWaitTime); \ } \ } \ } \ ////////////////////////////////////////////////////////////////////////// // // Abs // // Returns the absolute value of the variable // template inline const T Abs(const T& x) { return x < 0 ? -x : x; } ////////////////////////////////////////////////////////////////////////// // // Sqr // // Returns x^2 // template inline const T Sqr(const T& x) { return x * x; } ////////////////////////////////////////////////////////////////////////// // // Cube // // Returns x^3 // template inline const T Cube(const T& x) { return x * x * x; } ////////////////////////////////////////////////////////////////////////// // // Swap // // Swaps the values of two variables // template inline void Swap(T& x, T& y) { T temp = x; x = y; y = temp; } ////////////////////////////////////////////////////////////////////////// // // Min // // Returns the smaller of the two variables (based on "<" operator) // template inline const T Min(const T& x, const T& y) { return x < y ? x : y; } ////////////////////////////////////////////////////////////////////////// // // Max // // Returns the larger of the two variables (based on "<" operator) // template inline const T Max(const T& x, const T& y) { return x < y ? y : x; } ////////////////////////////////////////////////////////////////////////// // // Cmp // // Compares two variables (based on "==" and "<" operators) // template inline int Cmp(const T& x, const T& y) { return x == y ? 0 : x < y ? -1 : 1; } ////////////////////////////////////////////////////////////////////////// // // StructCmp // // Compares two structs byte by byte // template inline int StructCmp(const T *x, const T *y) { return memcmp(x, y, sizeof(T)); } ////////////////////////////////////////////////////////////////////////// // // CopyData // // Copies a number of data structures memory from one location to another // Source and destination blocks should not overlap // template inline void CopyData(T *x, const T *y, int n) { CopyMemory(x, y, n * sizeof(T)); } ////////////////////////////////////////////////////////////////////////// // // MoveData // // Copies a number of data structures memory from one location to another // Source and destination blocks may overlap // template inline void MoveData(T *x, const T *y, int n) { MoveMemory(x, y, n * sizeof(T)); } ////////////////////////////////////////////////////////////////////////// // // IsEqual // // Returns true if the two comperands are equal // template inline BOOL IsEqual(T lhs, T rhs) { return lhs == rhs; } template inline BOOL IsEqual(const T *lhs, const T *rhs) { return *lhs == *rhs; } template <> inline BOOL IsEqual(const CHAR *lhs, const CHAR *rhs) { return strcmp(lhs, rhs) == 0; } template <> inline BOOL IsEqual(const WCHAR *lhs, const WCHAR *rhs) { return wcscmp(lhs, rhs) == 0; } ////////////////////////////////////////////////////////////////////////// // // CharLower // // Converts a single character to lowercase // inline TCHAR CharLower(TCHAR c) { return (TCHAR) CharLower((PTSTR) c); } ////////////////////////////////////////////////////////////////////////// // // CharUpper // // Converts a single character to uppercase // inline TCHAR CharUpper(TCHAR c) { return (TCHAR) CharUpper((PTSTR) c); } ////////////////////////////////////////////////////////////////////////// // // _tcssafecmp // // Compares two strings (that can be null) // inline int strsafecmp(PCSTR psz1, PCSTR psz2) { return psz1 != 0 ? (psz2 != 0 ? strcmp(psz1, psz2) : 1) : (psz2 != 0 ? -1 : 0); } inline int wcssafecmp(PCWSTR psz1, PCWSTR psz2) { return psz1 != 0 ? (psz2 != 0 ? wcscmp(psz1, psz2) : 1) : (psz2 != 0 ? -1 : 0); } #ifdef UNICODE #define _tcssafecmp wcssafecmp #else //UNICODE #define _tcssafecmp strsafecmp #endif //UNICODE ////////////////////////////////////////////////////////////////////////// // // multiszlen // // Returns the length of a null terminated list of null terminated strings // inline size_t multiszlenA(PCSTR pszzStr) { PCSTR pszStr = pszzStr; if (pszStr) { while (*pszStr) { pszStr += strlen(pszStr) + 1; } } return pszStr - pszzStr; } inline size_t multiszlenW(PCWSTR pwszzStr) { PCWSTR pwszStr = pwszzStr; if (pwszStr) { while (*pwszStr) { pwszStr += wcslen(pwszStr) + 1; } } return pwszStr - pwszzStr; } #ifdef UNICODE #define multiszlen multiszlenW #else //UNICODE #define multiszlen multiszlenA #endif //UNICODE ////////////////////////////////////////////////////////////////////////// // // FindFileNamePortion // // Returns a pointer to the file name portion of a full path name // inline PSTR FindFileNamePortionA(PCSTR pPathName) { PCSTR pFileName = pPathName ? strrchr(pPathName, '\\') : 0; return const_cast(pFileName ? pFileName + 1 : pPathName); } inline PWSTR FindFileNamePortionW(PCWSTR pPathName) { PCWSTR pFileName = pPathName ? wcsrchr(pPathName, '\\') : 0; return const_cast(pFileName ? pFileName + 1 : pPathName); } #ifdef UNICODE #define FindFileNamePortion FindFileNamePortionW #else //UNICODE #define FindFileNamePortion FindFileNamePortionA #endif //UNICODE ////////////////////////////////////////////////////////////////////////// // // FindEol // // Finds the first end-of-line character in a string // inline PTSTR FindEol(PCTSTR pStr) { while (*pStr != '\0' && *pStr != '\r' && *pStr != '\n') { pStr = CharNext(pStr); } return const_cast(pStr); } #ifdef _SHLOBJ_H_ ////////////////////////////////////////////////////////////////////////// // // SHFree // // Frees a block of memory allocated through shell's IMalloc interface // inline void SHFree(PVOID pVoid) { LPMALLOC pMalloc; SHGetMalloc(&pMalloc); pMalloc->Free(pVoid); pMalloc->Release(); } #endif //_SHLOBJ_H_ ////////////////////////////////////////////////////////////////////////// // // WriteConsole // // Writes a character string to a console screen // inline BOOL WriteConsole(PCTSTR pStr, DWORD nStdHandle = STD_OUTPUT_HANDLE) { DWORD dwNumWritten; return WriteConsole( GetStdHandle(nStdHandle), pStr, _tcslen(pStr), &dwNumWritten, 0 ); } #ifdef _INC_STDLIB ////////////////////////////////////////////////////////////////////////// // // GetEnvironmentInt // // Retrieves the value of the specified variable from the environment block // inline BOOL GetEnvironmentInt(PCTSTR pName, PINT piValue) { TCHAR szValue[48]; DWORD dwResult = GetEnvironmentVariable(pName, szValue, COUNTOF(szValue)); if (dwResult > 0 && dwResult < COUNTOF(szValue)) { if (piValue == 0) { SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } *piValue = _ttoi(szValue); return TRUE; } return FALSE; } #endif //_INC_STDLIB #ifdef _INC_STDIO ////////////////////////////////////////////////////////////////////////// // // _tcsdupc // // Duplicates a string to a buffer allocated by new [] // inline PTSTR _tcsdupc(PCTSTR pStrSource) { if (!pStrSource) { pStrSource = _T(""); } PTSTR pStrDest = new TCHAR[_tcslen(pStrSource) + 1]; if (pStrDest) { _tcscpy(pStrDest, pStrSource); } return pStrDest; } ////////////////////////////////////////////////////////////////////////// // // bufvprintf, bufprintf // // Writes a printf style formatted string to a buffer allocated by new [] // inline PTSTR bufvprintf(PCTSTR format, va_list arglist) { PTSTR pBuffer = 0; for ( size_t nBufferSize = 1024; (pBuffer = new TCHAR[nBufferSize]) != 0 && _vsntprintf(pBuffer, nBufferSize, format, arglist) < 0; delete [] pBuffer, nBufferSize *= 2 ) { // start with a 1KB buffer size // if buffer allocation fails, exit // if _vsntprintf succeeds, exit // otherwise, delete the buffer and retry with double size } return pBuffer; } inline PTSTR __cdecl bufprintf(PCTSTR format, ...) { va_list arglist; va_start(arglist, format); return bufvprintf(format, arglist); } ////////////////////////////////////////////////////////////////////////// // // TextOutF // // Writes a printf style formatted string to the DC // inline BOOL __cdecl TextOutF(HDC hDC, int nX, int nY, PCTSTR format, ...) { va_list arglist; va_start(arglist, format); BOOL bResult = FALSE; PTSTR pStr = bufvprintf(format, arglist); if (pStr) { bResult = TextOut(hDC, nX, nY, pStr, _tcslen(pStr)); delete [] pStr; } return bResult; } ////////////////////////////////////////////////////////////////////////// // // OutputDebugStringF // // Outputs a printf style formatted string to the debug console // inline void __cdecl OutputDebugStringF(PCTSTR format, ...) { va_list arglist; va_start(arglist, format); PTSTR pStr = bufvprintf(format, arglist); if (pStr) { OutputDebugString(pStr); delete [] pStr; } va_end(arglist); } #ifdef DEBUG #define DEBUGMSG(x) OutputDebugString(x) #define DEBUGMSGF(x) OutputDebugStringF x #else //DEBUG #define DEBUGMSG(x) #define DEBUGMSGF(x) #endif //DEBUG ////////////////////////////////////////////////////////////////////////// // // IsChildWindow // // Determines whether the second hWnd is a child of the first // inline BOOL IsChildWindow(HWND hWndParent, HWND hWnd) { while (hWnd) { hWnd = GetParent(hWnd); if (hWnd == hWndParent) { return TRUE; } } return FALSE; } #endif //_INC_STDIO #if defined(_INC_IO) && defined(_INC_FCNTL) ////////////////////////////////////////////////////////////////////////// // // OpenOSHandle // // Associates a stream with an operating-system file handle // inline FILE *OpenOSHandle(HANDLE osfhandle, int flags, PCTSTR mode) { int hCrt = _open_osfhandle((intptr_t) osfhandle, flags); return hCrt ? _tfdopen(hCrt, mode) : 0; } ////////////////////////////////////////////////////////////////////////// // // OpenStdHandle // // Assigns a stream to an operating-system file handle for standard I/O // inline void OpenStdHandle(HANDLE osfhandle, FILE *stream, PCTSTR mode) { *stream = *OpenOSHandle(osfhandle, _O_TEXT, mode); setvbuf(stream, 0, _IONBF, 0); } ////////////////////////////////////////////////////////////////////////// // // AllocCRTConsole // // Allocates a new console and associates standard handles with this console // inline void AllocCRTConsole() { if (AllocConsole()) { OpenStdHandle(GetStdHandle(STD_INPUT_HANDLE), stdin, _T("r")); OpenStdHandle(GetStdHandle(STD_OUTPUT_HANDLE), stdout, _T("w")); OpenStdHandle(GetStdHandle(STD_ERROR_HANDLE), stderr, _T("w")); } } #endif //defined(_INC_IO) && defined(_INC_FCNTL) #ifdef _INC_COMMCTRL ////////////////////////////////////////////////////////////////////////// // // ListView_InsertColumn2 // // Inserts a new column in a list view control // inline int ListView_InsertColumn2( HWND hWnd, int nCol, PCTSTR pszColumnHeading, int nFormat, int nWidth, int nSubItem ) { LVCOLUMN column; column.mask = LVCF_TEXT|LVCF_FMT|LVCF_WIDTH|LVCF_SUBITEM; column.pszText = (PTSTR) pszColumnHeading; column.fmt = nFormat; column.cx = nWidth; column.iSubItem = nSubItem; return ListView_InsertColumn(hWnd, nCol, &column); } ////////////////////////////////////////////////////////////////////////// // // ListView_GetItemData // // Returns the lParam value associated with a list view item // inline LPARAM ListView_GetItemData(HWND hWnd, int nItem) { LVITEM item; item.mask = LVIF_PARAM; item.iItem = nItem; item.iSubItem = 0; item.lParam = 0; ListView_GetItem(hWnd, &item); return item.lParam; } ////////////////////////////////////////////////////////////////////////// // // ListView_GetItemData // // Sets the lParam value associated with a list view item // inline BOOL ListView_SetItemData(HWND hWnd, int nItem, LPARAM lParam) { LVITEM item; item.mask = LVIF_PARAM; item.iItem = nItem; item.iSubItem = 0; item.lParam = lParam; return ListView_SetItem(hWnd, &item); } ////////////////////////////////////////////////////////////////////////// // // operator ==, operator != // // Compares two TVITEM structs based on their contents // inline bool operator ==(const TVITEM &lhs, const TVITEM &rhs) { UINT mask = lhs.mask; return mask == rhs.mask && (!(mask & TVIF_HANDLE) || lhs.hItem == rhs.hItem) && (!(mask & TVIF_STATE) || (lhs.state == rhs.state && lhs.stateMask == rhs.stateMask)) && (!(mask & TVIF_TEXT) || (lhs.pszText == rhs.pszText && lhs.cchTextMax == rhs.cchTextMax)) && (!(mask & TVIF_IMAGE) || lhs.iImage == rhs.iImage) && (!(mask & TVIF_SELECTEDIMAGE) || lhs.iSelectedImage == rhs.iSelectedImage) && (!(mask & TVIF_CHILDREN) || lhs.cChildren == rhs.cChildren) && (!(mask & TVIF_PARAM) || lhs.lParam == rhs.lParam); } inline bool operator !=(const TVITEM &lhs, const TVITEM &rhs) { return !(lhs == rhs); } #endif //_INC_COMMCTRL ////////////////////////////////////////////////////////////////////////// // // ResizeDlgItem // // Changes the relative position and size of a dialog item // inline BOOL ResizeDlgItem( HWND hWnd, HWND hDlgItem, int dX, int dY, int dW, int dH, BOOL bRepaint = TRUE ) { RECT r; return GetWindowRect(hDlgItem, &r) && ScreenToClient(hWnd, (PPOINT) &r.left) && ScreenToClient(hWnd, (PPOINT) &r.right) && MoveWindow( hDlgItem, r.left + dX, r.top + dY, r.right - r.left + dW, r.bottom - r.top + dH, bRepaint ); } ////////////////////////////////////////////////////////////////////////// // // CLargeInteger // class CLargeInteger // union cannot be used as a base class { public: CLargeInteger( DWORD LowPart, LONG HighPart ) { m_Int.LowPart = LowPart; m_Int.HighPart = HighPart; } CLargeInteger( LONGLONG QuadPart ) { m_Int.QuadPart = QuadPart; } CLargeInteger( const LARGE_INTEGER& rhs ) { m_Int.QuadPart = rhs.QuadPart; } LARGE_INTEGER * operator &() { return &m_Int; } const LARGE_INTEGER * operator &() const { return &m_Int; } operator LONGLONG&() { return m_Int.QuadPart; } operator const LONGLONG&() const { return m_Int.QuadPart; } private: LARGE_INTEGER m_Int; }; ////////////////////////////////////////////////////////////////////////// // // CULargeInteger // class CULargeInteger // union cannot be used as a base class { public: CULargeInteger( DWORD LowPart, DWORD HighPart ) { m_Int.LowPart = LowPart; m_Int.HighPart = HighPart; } CULargeInteger( ULONGLONG QuadPart ) { m_Int.QuadPart = QuadPart; } CULargeInteger( const ULARGE_INTEGER& rhs ) { m_Int.QuadPart = rhs.QuadPart; } ULARGE_INTEGER * operator &() { return &m_Int; } const ULARGE_INTEGER * operator &() const { return &m_Int; } operator ULONGLONG&() { return m_Int.QuadPart; } operator const ULONGLONG&() const { return m_Int.QuadPart; } private: ULARGE_INTEGER m_Int; }; ////////////////////////////////////////////////////////////////////////// // // CFileTime // class CFileTime : public FILETIME { public: CFileTime() { } CFileTime(ULONGLONG Value) { ((ULARGE_INTEGER *)this)->QuadPart = Value; } }; ////////////////////////////////////////////////////////////////////////// // // CHandle // // Base class that handles reference counting // template class CHandle { public: CHandle() { m_pNext = 0; } explicit CHandle(const T &Value) { m_pNext = 0; Attach(Value); } CHandle(CHandle &rhs) { m_pNext = 0; Attach(rhs); } CHandle & operator =(const T &Value) { Detach(); Attach(Value); return *this; } CHandle & operator =(CHandle &rhs) { if (&rhs != this) { Detach(); Attach(rhs); } return *this; } ~CHandle() { Detach(); } operator const T &() const { return m_Value; } // void Destroy() // { // must be defined in the derived class // } // bool IsValid() // { // must be defined in the derived class // } void Attach(const T &Value) { ASSERT(!IsAttached()); m_Value = Value; CHECK(((Child *)this)->IsValid()); m_pNext = this; m_pPrev = this; } void Attach(CHandle &rhs) { ASSERT(!IsAttached()); if (rhs.IsAttached()) { m_Value = rhs.m_Value; m_pPrev = &rhs; m_pNext = rhs.m_pNext; m_pPrev->m_pNext = this; m_pNext->m_pPrev = this; } } void Detach() { if (IsLastReference()) { ((Child *)this)->Destroy(); m_pNext = 0; } else { Unlink(); } } void Unlink() { if (IsAttached()) { m_pPrev->m_pNext = m_pNext; m_pNext->m_pPrev = m_pPrev; m_pNext = 0; } } bool IsLastReference() const { return m_pNext == this; } bool IsAttached() const { return m_pNext != 0; } private: T m_Value; CHandle *m_pNext; CHandle *m_pPrev; }; ////////////////////////////////////////////////////////////////////////// // // CKernelObject // // Base class for kernel objects that can be destroyed with CloseHandle() // template class CKernelObject : public CHandle { typedef CHandle parent_type; protected: CKernelObject() { } explicit CKernelObject( HANDLE hHandle ) : parent_type(hHandle) { } public: void Destroy() { ::CloseHandle(*this); } bool IsValid() { return *this != 0; } DWORD WaitForSingleObject( DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE ) const { return ::WaitForSingleObjectEx( *this, dwMilliseconds, bAlertable ); } bool IsSignaled() const { return WaitForSingleObject(0) == WAIT_OBJECT_0; } }; ////////////////////////////////////////////////////////////////////////// // // File // // Wrapper class for Win32 file handles // class File : public CKernelObject { public: File() { } File( PCTSTR pFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES pSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, HANDLE hTemplateFile = 0 ) : CKernelObject(::CreateFile( pFileName, dwDesiredAccess, dwShareMode, pSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile )) { } bool IsValid() { return (HANDLE) *this != INVALID_HANDLE_VALUE; } LARGE_INTEGER GetFileSize() const { LARGE_INTEGER Result; Result.LowPart = ::GetFileSize( *this, (PDWORD) &Result.HighPart ); return Result; } DWORD WriteFile( CONST VOID *pBuffer, DWORD nNumberOfBytesToWrite, LPOVERLAPPED pOverlapped = 0 ) const { DWORD dwNumberOfBytesWritten; CHECK(::WriteFile( *this, pBuffer, nNumberOfBytesToWrite, &dwNumberOfBytesWritten, pOverlapped )); return dwNumberOfBytesWritten; } DWORD ReadFile( PVOID pBuffer, DWORD nNumberOfBytesToRead, LPOVERLAPPED pOverlapped = 0 ) const { DWORD dwNumberOfBytesRead; CHECK(::ReadFile( *this, pBuffer, nNumberOfBytesToRead, &dwNumberOfBytesRead, pOverlapped )); return dwNumberOfBytesRead; } }; ////////////////////////////////////////////////////////////////////////// // // CInFile // // Read only file // class CInFile : public File { public: CInFile() { } explicit CInFile( PCTSTR pFileName, DWORD dwDesiredAccess = GENERIC_READ, DWORD dwShareMode = FILE_SHARE_READ, LPSECURITY_ATTRIBUTES pSecurityAttributes = 0, DWORD dwCreationDisposition = OPEN_EXISTING, DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, HANDLE hTemplateFile = 0 ) : File( pFileName, dwDesiredAccess, dwShareMode, pSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile ) { } }; ////////////////////////////////////////////////////////////////////////// // // COutFile // // Write only file // class COutFile : public File { public: COutFile() { } explicit COutFile( PCTSTR pFileName, DWORD dwDesiredAccess = GENERIC_WRITE, DWORD dwShareMode = FILE_SHARE_READ, LPSECURITY_ATTRIBUTES pSecurityAttributes = 0, DWORD dwCreationDisposition = CREATE_ALWAYS, DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, HANDLE hTemplateFile = 0 ) : File( pFileName, dwDesiredAccess, dwShareMode, pSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile ) { } }; ////////////////////////////////////////////////////////////////////////// // // CopyFileContents // // Copies the contents of one file to another // inline void CopyFileContents(const File &InFile, const File &OutFile) { BYTE Buffer[32*1024]; DWORD nNumRead; do { nNumRead = InFile.ReadFile(Buffer, sizeof(Buffer)); OutFile.WriteFile(Buffer, nNumRead); } while (nNumRead == sizeof(Buffer)); } #ifdef _INC_STDIO #include ////////////////////////////////////////////////////////////////////////// // // CCFile // // Wrapper class for C-runtime stream based file handles // class CCFile : public CHandle { typedef CHandle parent_type; public: CCFile() { } CCFile( PCTSTR filename, PCTSTR mode, int shflag = _SH_DENYNO ) : parent_type(::_tfsopen( filename, mode, shflag )) { } void Destroy() { ::fclose(*this); } bool IsValid() { return *this != 0; } }; #endif _INC_STDIO ////////////////////////////////////////////////////////////////////////// // // CNamedPipe // // Wrapper class for named pipes // class CNamedPipe : public File { public: CNamedPipe() { } CNamedPipe( PCTSTR pName, DWORD dwOpenMode, DWORD dwPipeMode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, DWORD nMaxInstances = PIPE_UNLIMITED_INSTANCES, DWORD nOutBufferSize = 0, DWORD nInBufferSize = 0, DWORD nDefaultTimeOut = INFINITE, LPSECURITY_ATTRIBUTES pSecurityAttributes = 0 ) { Attach(::CreateNamedPipe( pName, dwOpenMode, dwPipeMode, nMaxInstances, nOutBufferSize, nInBufferSize, nDefaultTimeOut, pSecurityAttributes )); } }; ////////////////////////////////////////////////////////////////////////// // // CFileMapping // // Wrapper class for file mapping objects // class CFileMapping : public CKernelObject { public: CFileMapping() { } CFileMapping( HANDLE hFile, LPSECURITY_ATTRIBUTES pFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh = 0, DWORD dwMaximumSizeLow = 0, PCTSTR pName = 0 ) : CKernelObject(::CreateFileMapping( hFile, pFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pName )) { } }; #ifdef _LZEXPAND_ ////////////////////////////////////////////////////////////////////////// // // CLZFile // // Wrapper class for LZ compressed files // class CLZFile : public CHandle { typedef CHandle parent_type; public: CLZFile( PTSTR pFileName, WORD wStyle ) : parent_type(::LZOpenFile( pFileName, &m_of, wStyle )) { } void Destroy() { ::LZClose(*this); } bool IsValid() { return *this >= 0; } private: OFSTRUCT m_of; }; #endif _LZEXPAND_ ////////////////////////////////////////////////////////////////////////// // // CStartupInfo // // Wrapper class for the STARTUPINFO struct // class CStartupInfo : public STARTUPINFO { public: CStartupInfo() { ZeroMemory(this, sizeof(STARTUPINFO)); cb = sizeof(STARTUPINFO); } void UseStdHandles( HANDLE _hStdInput = GetStdHandle(STD_INPUT_HANDLE), HANDLE _hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE), HANDLE _hStdError = GetStdHandle(STD_ERROR_HANDLE) ) { dwFlags |= STARTF_USESTDHANDLES; hStdInput = _hStdInput; hStdOutput = _hStdOutput; hStdError = _hStdError; } void UseShowWindow(WORD _wShowWindow) { dwFlags |= STARTF_USESHOWWINDOW; wShowWindow = _wShowWindow; } }; ////////////////////////////////////////////////////////////////////////// // // CProcess // // Wrapper class for process handles // class CProcess : public CHandle { public: CProcess() { } explicit CProcess( PTSTR pCommandLine, PSECURITY_ATTRIBUTES pProcessAttributes = 0, PSECURITY_ATTRIBUTES pThreadAttributes = 0, BOOL bInheritHandles = FALSE, DWORD dwCreationFlags = 0, PVOID pEnvironment = 0, PCTSTR pCurrentDirectory = 0, LPSTARTUPINFO psi = &CStartupInfo() ) { PROCESS_INFORMATION pi; CHECK(::CreateProcess( 0, pCommandLine, pProcessAttributes, pThreadAttributes, bInheritHandles, dwCreationFlags, pEnvironment, pCurrentDirectory, psi, &pi )); Attach(pi); } CProcess( HANDLE hToken, PTSTR pCommandLine, PSECURITY_ATTRIBUTES pProcessAttributes = 0, PSECURITY_ATTRIBUTES pThreadAttributes = 0, BOOL bInheritHandles = FALSE, DWORD dwCreationFlags = 0, PVOID pEnvironment = 0, PCTSTR pCurrentDirectory = 0, LPSTARTUPINFO psi = &CStartupInfo() ) { PROCESS_INFORMATION pi; CHECK(::CreateProcessAsUser( hToken, 0, pCommandLine, pProcessAttributes, pThreadAttributes, bInheritHandles, dwCreationFlags, pEnvironment, pCurrentDirectory, psi, &pi )); Attach(pi); } #if (_WIN32_WINNT >= 0x0500) && defined(UNICODE) CProcess( PCWSTR pUsername, PCWSTR pDomain, PCWSTR pPassword, DWORD dwLogonFlags, PWSTR pCommandLine, DWORD dwCreationFlags = 0, PVOID pEnvironment = 0, PCWSTR pCurrentDirectory = 0, LPSTARTUPINFO psi = &CStartupInfo() ) { PROCESS_INFORMATION pi; CHECK(::CreateProcessWithLogonW( pUsername, pDomain, pPassword, dwLogonFlags, 0, pCommandLine, dwCreationFlags, pEnvironment, pCurrentDirectory, psi, &pi )); Attach(pi); } #endif void Destroy() { ::CloseHandle(((PROCESS_INFORMATION &)(*this)).hThread); ::CloseHandle(((PROCESS_INFORMATION &)(*this)).hProcess); } bool IsValid() { return ((PROCESS_INFORMATION &)(*this)).hProcess != 0; } DWORD WaitForInputIdle( DWORD dwMilliseconds = INFINITE ) const { return ::WaitForInputIdle( ((PROCESS_INFORMATION &)(*this)).hProcess, dwMilliseconds ); } DWORD WaitForSingleObject( DWORD dwMilliseconds = INFINITE ) const { return ::WaitForSingleObject( ((PROCESS_INFORMATION &)(*this)).hProcess, dwMilliseconds ); } VOID Terminate( DWORD dwExitCode = 0 ) const { CHECK(::TerminateProcess( ((PROCESS_INFORMATION &)(*this)).hProcess, dwExitCode )); } DWORD GetExitCode() const { DWORD dwExitCode; CHECK(::GetExitCodeProcess( ((PROCESS_INFORMATION &)(*this)).hProcess, &dwExitCode )); return dwExitCode; } }; ////////////////////////////////////////////////////////////////////////// // // CThreadBase // // Base class for Win32 and CRT library style thread objects // class CThreadBase : public CKernelObject { protected: CThreadBase() { } explicit CThreadBase( HANDLE hHandle ) : CKernelObject(hHandle) { } public: operator DWORD() const { return m_dwThreadId; } VOID Terminate( DWORD dwExitCode = 0 ) const { CHECK(::TerminateThread( *this, dwExitCode )); } DWORD GetExitCode() const { DWORD dwExitCode; CHECK(::GetExitCodeThread( *this, &dwExitCode )); return dwExitCode; } protected: DWORD m_dwThreadId; }; ////////////////////////////////////////////////////////////////////////// // // CThread // // Wrapper class for Win32 thread handles // class CThread : public CThreadBase { public: CThread() { } explicit CThread( PTHREAD_START_ROUTINE pStartAddress, PVOID pParameter = 0, PSECURITY_ATTRIBUTES pThreadAttributes = 0, DWORD dwStackSize = 0, DWORD dwCreationFlags = 0 ) : CThreadBase(::CreateThread( pThreadAttributes, dwStackSize, pStartAddress, pParameter, dwCreationFlags, &m_dwThreadId )) { } }; #ifdef _INC_PROCESS ////////////////////////////////////////////////////////////////////////// // // CCThread // // Wrapper class for C-runtime threads // class CCThread : public CThreadBase { public: CCThread() { } explicit CCThread( unsigned ( __stdcall *start_address )( void * ), void *arglist = 0, void *security = 0, unsigned stack_size = 0, unsigned initflag = 0 ) : CThreadBase((HANDLE)(LONG_PTR) _beginthreadex( security, stack_size, start_address, arglist, initflag, (unsigned int *) &m_dwThreadId )) { } }; #endif //_INC_PROCESS ////////////////////////////////////////////////////////////////////////// // // Event // // Wrapper class for event handles // class Event : public CKernelObject { public: Event() { } Event( BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName = 0, LPSECURITY_ATTRIBUTES lpEventAttributes = 0 ) : CKernelObject(::CreateEvent( lpEventAttributes, bManualReset, bInitialState, lpName )) { } public: VOID Set() const { CHECK(::SetEvent(*this)); } VOID Reset() const { CHECK(::ResetEvent(*this)); } }; ////////////////////////////////////////////////////////////////////////// // // Mutex // // Wrapper class for mutex handles // class Mutex : public CKernelObject { public: Mutex() { } explicit Mutex( BOOL bInitialOwner, PCTSTR pName = 0, PSECURITY_ATTRIBUTES pMutexAttributes = 0 ) : CKernelObject(::CreateMutex( pMutexAttributes, bInitialOwner, pName )) { } public: VOID Release() const { CHECK(::ReleaseMutex(*this)); } }; ////////////////////////////////////////////////////////////////////////// // // Semaphore // // Wrapper class for semaphore handles // class Semaphore : public CKernelObject { public: Semaphore() { } Semaphore( LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName = 0, LPSECURITY_ATTRIBUTES lpEventAttributes = 0 ) : CKernelObject(::CreateSemaphore( lpEventAttributes, lInitialCount, lMaximumCount, lpName )) { } public: VOID Release( LONG lReleaseCount = 1, PLONG pPreviousCount = 0 ) const { CHECK(::ReleaseSemaphore(*this, lReleaseCount, pPreviousCount)); } VOID WaitFor( LONG lCount ) const { for (int i = 0; i < lCount; ++i) { WaitForSingleObject(); } Release(lCount); } }; #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) ////////////////////////////////////////////////////////////////////////// // // CWaitableTimer // // Wrapper class for waitable timer handles // class CWaitableTimer : public CKernelObject { public: CWaitableTimer() { } explicit CWaitableTimer( BOOL bManualReset, PCTSTR pTimerName = 0, PSECURITY_ATTRIBUTES pTimerAttributes = 0 ) : CKernelObject(::CreateWaitableTimer( pTimerAttributes, bManualReset, pTimerName )) { } public: VOID Set( const CLargeInteger &DueTime, LONG lPeriod = 0, PTIMERAPCROUTINE pfnCompletionRoutine = 0, LPVOID lpArgToCompletionRoutine = 0, BOOL fResume = FALSE ) const { CHECK(::SetWaitableTimer( *this, &DueTime, lPeriod, pfnCompletionRoutine, lpArgToCompletionRoutine, fResume )); } VOID Cancel() const { CHECK(::CancelWaitableTimer(*this)); } }; #endif ////////////////////////////////////////////////////////////////////////// // // CriticalSection // // Wrapper class for critical sections // class CriticalSection : private CRITICAL_SECTION { public: CriticalSection() { ::InitializeCriticalSection(this); } ~CriticalSection() { ::DeleteCriticalSection(this); } #if _WIN32_WINNT >= 0x0400 BOOL TryEnter() { return ::TryEnterCriticalSection(this); } #endif //_WIN32_WINNT >= 0x0400 VOID Enter() { ::EnterCriticalSection(this); } VOID Leave() { ::LeaveCriticalSection(this); } }; ////////////////////////////////////////////////////////////////////////// // // CLibrary // // Wrapper class for loading DLL's // class CLibrary : public CHandle { typedef CHandle parent_type; public: CLibrary() { } explicit CLibrary( PCTSTR pLibFileName, DWORD dwFlags = 0 ) : parent_type(::LoadLibraryEx(pLibFileName, 0, dwFlags)) { } void Destroy() { ::FreeLibrary(*this); } bool IsValid() { return *this != 0; } }; ////////////////////////////////////////////////////////////////////////// // // CPointer // // Base class for pointer wrappers // #pragma warning(4: 4284) // return type for 'identifier::operator ->()' is not a UDT or reference to a UDT. Will produce errors if applied using infix notation template class CPointer : public CHandle { typedef CHandle parent_type; typedef T *pointer_type; public: CPointer() { } CPointer( const T *pPointer ) : parent_type((pointer_type) pPointer) { } CPointer & operator =(const T *pPointer) { return (CPointer &) parent_type::operator =((pointer_type) pPointer); } T * operator ->() { return *this; } bool IsValid() { return *this != 0; } }; ////////////////////////////////////////////////////////////////////////// // // CCppMem // // Wrapper class for allocations through C++ new[] and delete[] operators // template class CCppMem : public CPointer > { typedef CPointer > parent_type; public: CCppMem() { } CCppMem( const T *pPointer ) : parent_type(pPointer) { } explicit CCppMem( size_t nSize, BOOL bZeroInit = FALSE ) : parent_type(new T[nSize]) { if (bZeroInit) { ZeroMemory(*this, sizeof(T) * nSize); } } // bugbug: why isn't this inherited? CCppMem & operator =(const T *pPointer) { return (CCppMem &) parent_type::operator =(pPointer); } void Destroy() { delete [] *this; } }; ////////////////////////////////////////////////////////////////////////// // // CGlobalMem // // Wrapper class for allocations through GlobalAlloc() GlobalFree() APIs // template class CGlobalMem : public CPointer > { typedef CPointer > parent_type; public: CGlobalMem() { } CGlobalMem( const T *pPointer ) : parent_type(pPointer) { } explicit CGlobalMem( DWORD dwBytes, UINT uFlags = GMEM_FIXED ) : parent_type((T *) ::GlobalAlloc(uFlags, dwBytes)) { } // bugbug: why isn't this inherited? CGlobalMem & operator =(const T *pPointer) { return (CGlobalMem &) parent_type::operator =(pPointer); } void Destroy() { ::GlobalFree(*this); } }; ////////////////////////////////////////////////////////////////////////// // // CLocalMem // // Wrapper class for allocations through LocalAlloc() LocalFree() APIs // template class CLocalMem : public CPointer > { typedef CPointer > parent_type; public: CLocalMem() { } CLocalMem( const T *pPointer ) : parent_type(pPointer) { } explicit CLocalMem( DWORD dwBytes, UINT uFlags = LMEM_FIXED ) : parent_type((T *) ::LocalAlloc(uFlags, dwBytes)) { } // bugbug: why isn't this inherited? CLocalMem & operator =(const T *pPointer) { return (CLocalMem &) parent_type::operator =(pPointer); } void Destroy() { ::LocalFree(*this); } }; ////////////////////////////////////////////////////////////////////////// // // CMapViewOfFile // // Wrapper class for memory mapped file objects // template class CMapViewOfFile : public CPointer > { public: CMapViewOfFile() { } CMapViewOfFile( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh = 0, DWORD dwFileOffsetLow = 0, DWORD dwNumberOfBytesToMap = 0, PVOID pBaseAddress = 0 ) : CPointer >((T *) ::MapViewOfFileEx( hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap, pBaseAddress )) { } void Destroy() { ::UnmapViewOfFile(*this); } }; ////////////////////////////////////////////////////////////////////////// // // CMapFile // // Helper class for CreateFile(), CreateNamedPipe() and MapViewOfFileEx() APIs // // bugbug: these should be defined in class scope, but vc5 doesn't let me... template struct mapping_traits { }; template <> struct mapping_traits { enum { dwDesiredAccess = GENERIC_READ, dwShareMode = FILE_SHARE_READ, flProtect = PAGE_READONLY, dwDesiredMapAccess = FILE_MAP_READ }; }; template <> struct mapping_traits { enum { dwDesiredAccess = GENERIC_READ | GENERIC_WRITE, dwShareMode = 0, flProtect = PAGE_READWRITE, dwDesiredMapAccess = FILE_MAP_WRITE }; }; template <> struct mapping_traits { enum { dwDesiredAccess = GENERIC_READ | GENERIC_WRITE, dwShareMode = FILE_SHARE_READ, flProtect = PAGE_WRITECOPY, dwDesiredMapAccess = FILE_MAP_COPY }; }; template class CMapFile { public: CMapFile( PCTSTR pFileName ) : m_File( pFileName, // PCTSTR pFileName mapping_traits::dwDesiredAccess, // DWORD dwDesiredAccess mapping_traits::dwShareMode, // DWORD dwShareMode 0, // LPSECURITY_ATTRIBUTES OPEN_EXISTING, // DWORD dwCreationDisposition FILE_ATTRIBUTE_NORMAL, // DWORD dwFlagsAndAttributes 0 // HANDLE hTemplateFile ), m_Mapping( m_File, // HANDLE hFile 0, // LPSECURITY_ATTRIBUTES mapping_traits::flProtect, // DWORD flProtect 0, // DWORD dwMaximumSizeHigh 0, // DWORD dwMaximumSizeLow 0 // PCTSTR pName ), m_ViewOfFile( m_Mapping, // HANDLE hFileMappingObject mapping_traits::dwDesiredMapAccess, // DWORD dwDesiredAccess 0, // DWORD dwFileOffsetHigh 0, // DWORD dwFileOffsetLow 0, // DWORD dwNumberOfBytesToMap 0 // PVOID pBaseAddress ) { } operator T *() { return m_ViewOfFile; } private: File m_File; CFileMapping m_Mapping; CMapViewOfFile m_ViewOfFile; }; ////////////////////////////////////////////////////////////////////////// // // CSecurityDescriptor // // Wrapper class for SECURITY_DESCRIPTOR struct // class CSecurityDescriptor : public CCppMem { public: explicit CSecurityDescriptor( BOOL bDaclPresent = TRUE, PACL pDacl = 0, BOOL bDaclDefaulted = FALSE ) : CCppMem(SECURITY_DESCRIPTOR_MIN_LENGTH) { CHECK(::InitializeSecurityDescriptor( *this, SECURITY_DESCRIPTOR_REVISION )); CHECK(::SetSecurityDescriptorDacl( *this, bDaclPresent, pDacl, bDaclDefaulted )); } }; ////////////////////////////////////////////////////////////////////////// // // CSecurityAttributes // // Wrapper class for the SECURITY_ATTRIBUTES struct // class CSecurityAttributes : public SECURITY_ATTRIBUTES { public: explicit CSecurityAttributes( PSECURITY_DESCRIPTOR pSD, BOOL bInheritHandle = TRUE ) { nLength = sizeof(SECURITY_ATTRIBUTES); lpSecurityDescriptor = pSD; bInheritHandle = bInheritHandle; } }; ////////////////////////////////////////////////////////////////////////// // // CTokenPrivileges // // Wrapper class for the TOKEN_PRIVILEGES struct // #include template struct CTokenPrivileges : public TOKEN_PRIVILEGES { CTokenPrivileges() { PrivilegeCount = N; } LUID_AND_ATTRIBUTES & operator [](int i) { ASSERT(i < N); return Privileges[i]; } private: LUID_AND_ATTRIBUTES RemainingPrivileges[N - ANYSIZE_ARRAY]; }; #include ////////////////////////////////////////////////////////////////////////// // // CLuid // // Wrapper class for the LUID struct // struct CLuid : public LUID { CLuid( LPCTSTR lpSystemName, LPCTSTR lpName ) { CHECK(::LookupPrivilegeValue( lpSystemName, lpName, this )); } }; ////////////////////////////////////////////////////////////////////////// // // CLuidAndAttributes // // Wrapper class for the LUID_AND_ATTRIBUTES struct // struct CLuidAndAttributes : public LUID_AND_ATTRIBUTES { CLuidAndAttributes( const LUID& _Luid, DWORD _Attributes ) { Luid = _Luid; Attributes = _Attributes; } }; ////////////////////////////////////////////////////////////////////////// // // CProcessToken // // Wrapper class for the process token object // class CProcessToken : public CKernelObject { public: CProcessToken() { } CProcessToken( HANDLE ProcessHandle, DWORD DesiredAccess ) { HANDLE hHandle; CHECK(::OpenProcessToken( ProcessHandle, DesiredAccess, &hHandle )); Attach(hHandle); } VOID AdjustTokenPrivileges( BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, DWORD BufferLength = 0, PTOKEN_PRIVILEGES PreviousState = 0, PDWORD ReturnLength = 0 ) const { CHECK(::AdjustTokenPrivileges( *this, DisableAllPrivileges, NewState, BufferLength, PreviousState, ReturnLength )); CHECK(GetLastError() == ERROR_SUCCESS); } }; ////////////////////////////////////////////////////////////////////////// // // CLoggedOnUser // // Wrapper class for the logged on user object // class CLoggedOnUser : public CKernelObject { public: CLoggedOnUser() { } CLoggedOnUser( LPTSTR lpszUsername, LPTSTR lpszDomain, LPTSTR lpszPassword, DWORD dwLogonType = LOGON32_LOGON_INTERACTIVE, DWORD dwLogonProvider = LOGON32_PROVIDER_DEFAULT ) { HANDLE hHandle; CHECK(::LogonUser( lpszUsername, lpszDomain, lpszPassword, dwLogonType, dwLogonProvider, &hHandle )); Attach(hHandle); } VOID Impersonate() const { CHECK(::ImpersonateLoggedOnUser(*this)); } }; ////////////////////////////////////////////////////////////////////////// // // CEventSource // // Wrapper class for the event source object // class CEventSource : public CHandle { typedef CHandle parent_type; public: CEventSource() { } CEventSource( PCTSTR pUNCServerName, PCTSTR pSourceName ) : parent_type(::RegisterEventSource( pUNCServerName, pSourceName )) { } void Destroy() { ::DeregisterEventSource(*this); } bool IsValid() { return *this != 0; } VOID ReportEvent( WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid, WORD wNumStrings, DWORD dwDataSize, PCTSTR *pStrings, PVOID pRawData ) const { CHECK(::ReportEvent( *this, wType, wCategory, dwEventID, lpUserSid, wNumStrings, dwDataSize, pStrings, pRawData )); } VOID ReportEventText( WORD wType, PCTSTR pString, DWORD dwEventID ) const { PCTSTR pStrings[] = { pString }; ReportEvent( wType, 0, dwEventID, 0, 1, 0, pStrings, 0 ); } }; ////////////////////////////////////////////////////////////////////////// // // CKey // // Wrapper class for registry key objects and registry APIs // class CKey : public CHandle { public: CKey() { } CKey( HKEY hKey ) { Attach(hKey); } CKey( HKEY hKey, PCTSTR pSubKey, REGSAM samDesired = KEY_ALL_ACCESS ) { HKEY hHandle; CHECK_REG(::RegOpenKeyEx( hKey, pSubKey, 0, samDesired, &hHandle )); Attach(hHandle); } CKey( PCTSTR pMachineName, HKEY hKey ) { HKEY hHandle; CHECK_REG(::RegConnectRegistry( pMachineName, hKey, &hHandle )); Attach(hHandle); } CKey( HKEY hKey, PCTSTR pSubKey, PTSTR pClass, DWORD dwOptions, REGSAM samDesired = KEY_ALL_ACCESS, PSECURITY_ATTRIBUTES pSecurityAttributes = 0 ) { HKEY hHandle; DWORD dwDisposition; CHECK_REG(::RegCreateKeyEx( hKey, pSubKey, 0, pClass, dwOptions, samDesired, pSecurityAttributes, &hHandle, &dwDisposition )); Attach(hHandle); } void Destroy() { ::RegCloseKey(*this); } bool IsValid() { return *this != 0; } VOID RegQueryValueEx( PTSTR pValueName, PDWORD pType, PVOID pData, PDWORD pcbData ) const { CHECK_REG(::RegQueryValueEx( *this, pValueName, 0, pType, (PBYTE) pData, pcbData )); } VOID RegSetValueEx( PTSTR pValueName, DWORD dwType, CONST VOID *pData, DWORD cbData ) const { CHECK_REG(::RegSetValueEx( *this, pValueName, 0, dwType, (PBYTE) pData, cbData )); } BOOL RegEnumKeyEx( DWORD dwIndex, PTSTR pName, PDWORD pcbName, PTSTR pClass = 0, PDWORD pcbClass = 0, PFILETIME pftLastWriteTime = 0 ) const { LONG bResult = ::RegEnumKeyEx( *this, dwIndex, pName, pcbName, 0, pClass, pcbClass, pftLastWriteTime ); if (bResult == ERROR_NO_MORE_ITEMS) { return FALSE; } CHECK_REG(bResult); return TRUE; } BOOL RegEnumValue( DWORD dwIndex, PTSTR pValueName, PDWORD pcbValueName, PDWORD pType, PBYTE pData, PDWORD pcbData ) const { LONG bResult = ::RegEnumValue( *this, dwIndex, pValueName, pcbValueName, 0, pType, pData, pcbData ); if (bResult == ERROR_NO_MORE_ITEMS) { return FALSE; } CHECK_REG(bResult); return TRUE; } typedef struct _REG_INFO_KEY { DWORD cSubKeys; DWORD cbMaxSubKeyLen; DWORD cbMaxClassLen; DWORD cValues; DWORD cbMaxValueNameLen; DWORD cbMaxValueLen; DWORD cbSecurityDescriptor; FILETIME ftLastWriteTime; } REG_INFO_KEY, *PREG_INFO_KEY; REG_INFO_KEY RegQueryInfoKey() { REG_INFO_KEY rik; CHECK_REG(::RegQueryInfoKey( *this, 0, 0, 0, &rik.cSubKeys, &rik.cbMaxSubKeyLen, &rik.cbMaxClassLen, &rik.cValues, &rik.cbMaxValueNameLen, &rik.cbMaxValueLen, &rik.cbSecurityDescriptor, &rik.ftLastWriteTime )); return rik; } }; ////////////////////////////////////////////////////////////////////////// // // CFindFile // // Wrapper class for directory search objects // class CFindFile : public WIN32_FIND_DATA, public CHandle { public: CFindFile( PCTSTR pFileName ) { HANDLE hHandle = ::FindFirstFile( pFileName, this ); if (hHandle == INVALID_HANDLE_VALUE) { m_bFound = FALSE; } else { m_bFound = TRUE; Attach(hHandle); } } void Destroy() { ::FindClose(*this); } bool IsValid() { return (HANDLE) *this != INVALID_HANDLE_VALUE; } VOID FindNextFile() { m_bFound = ::FindNextFile( *this, this ); CHECK(m_bFound || GetLastError() == ERROR_NO_MORE_FILES); } BOOL Found() const { return m_bFound; } private: BOOL m_bFound; }; ////////////////////////////////////////////////////////////////////////// // // FileExists // // Returns TRUE if the specified file exists // inline BOOL FileExists(PCTSTR pName) { CFindFile ff(pName); return ff.Found(); } ////////////////////////////////////////////////////////////////////////// // // DirectoryExists // // Returns TRUE if the specified directory exists // inline BOOL DirectoryExists(PCTSTR pName) { TCHAR pRootDir[3]; // change "X:\" to "X:" if (pName && pName[1] == _T(':') && pName[2] == _T('\\') && pName[3] == _T('\0')) { pRootDir[0] = pName[0]; pRootDir[1] = _T(':'); pRootDir[2] = _T('\0'); pName = pRootDir; } CFindFile ff(pName); return ff.Found() && (ff.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); } ////////////////////////////////////////////////////////////////////////// // // GetFileSize // // Returns the size of the specified file // inline ULARGE_INTEGER GetFileSize(PCTSTR pFileName) { CFindFile ff(pFileName); CHECK(ff.Found()); ULARGE_INTEGER nSize = { ff.nFileSizeLow, ff.nFileSizeHigh }; return nSize; } #ifdef _INC_TOOLHELP32 ////////////////////////////////////////////////////////////////////////// // // CToolhelp32Snapshot // // Wrapper class for the toolhelp snapshot objects // class CToolhelp32Snapshot : public CKernelObject { typedef CKernelObject parent_type; public: explicit CToolhelp32Snapshot( DWORD dwFlags = TH32CS_SNAPALL, DWORD th32ProcessID = 0 ) : parent_type(CreateToolhelp32Snapshot( dwFlags, th32ProcessID )) { } }; ////////////////////////////////////////////////////////////////////////// // // CFindHeapList, CFindModule, CFindProcess, CFindThread // // Wrapper classes for toolhelp find functions // // bugbug: this template declaration is better, but VC compiler cannot resolve it yet //template #define DECLARE_TOOLHELP32_FIND(CLASSNAME, STRUCT, FINDFIRST, FINDNEXT) \ \ class CLASSNAME : public STRUCT \ { \ public: \ CLASSNAME( \ HANDLE hSnapShot \ ) \ { \ m_hSnapShot = hSnapShot; \ dwSize = sizeof(STRUCT); \ m_bFound = FINDFIRST(m_hSnapShot, this); \ } \ \ VOID \ FindNext() \ { \ m_bFound = FINDNEXT(m_hSnapShot, this); \ } \ \ BOOL \ IsFound() const \ { \ return m_bFound; \ } \ \ private: \ HANDLE m_hSnapShot; \ BOOL m_bFound; \ }; \ DECLARE_TOOLHELP32_FIND(CFindHeapList, HEAPLIST32, Heap32ListFirst, Heap32ListNext); DECLARE_TOOLHELP32_FIND(CFindModule, MODULEENTRY32, Module32First, Module32Next); DECLARE_TOOLHELP32_FIND(CFindProcess, PROCESSENTRY32, Process32First, Process32Next); DECLARE_TOOLHELP32_FIND(CFindThread, THREADENTRY32, Thread32First, Thread32Next); ////////////////////////////////////////////////////////////////////////// // // FindProcessId // // Returns the id of the process specified by name // inline DWORD FindProcessId(PCTSTR pProcessName) { CToolhelp32Snapshot Snapshot(TH32CS_SNAPPROCESS); for (CFindProcess pe32(Snapshot); pe32.IsFound(); pe32.FindNext()) { if (_tcsicmp(FindFileNamePortion(pe32.szExeFile), pProcessName) == 0) { return pe32.th32ProcessID; } } return 0; } #endif //_INC_TOOLHELP32 ////////////////////////////////////////////////////////////////////////// // // CFindWindow // // Wrapper class for finding child windows // class CFindWindow { public: CFindWindow( HWND hWnd ) { m_hChild = ::GetTopWindow(hWnd); } VOID FindNext() { m_hChild = ::GetNextWindow( m_hChild, GW_HWNDNEXT ); } operator HWND() const { return m_hChild; } BOOL IsFound() const { return m_hChild != 0; } private: HWND m_hChild; }; #ifdef _WINSVC_ ////////////////////////////////////////////////////////////////////////// // // CService // // Wrapper class for service objects // class CService : public CHandle { typedef CHandle parent_type; public: CService() { } CService( SC_HANDLE hHandle ) : parent_type(hHandle) { } void Destroy() { ::CloseServiceHandle(*this); } bool IsValid() { return *this != 0; } VOID StartService( DWORD dwNumServiceArgs = 0, LPCTSTR *lpServiceArgVectors = 0 ) { if (QueryServiceStatus().dwCurrentState != SERVICE_RUNNING) { CHECK(::StartService( *this, dwNumServiceArgs, lpServiceArgVectors )); while (QueryServiceStatus().dwCurrentState != SERVICE_RUNNING) { //bugbug: this might cause a hang } } } SERVICE_STATUS & QueryServiceStatus() { CHECK(::QueryServiceStatus(*this, &m_ss)); return m_ss; } VOID DeleteService() const { CHECK(::DeleteService(*this)); } VOID ControlService( DWORD dwControl ) { CHECK(::ControlService(*this, dwControl, &m_ss)); } VOID ChangeServiceState( DWORD dwControl, DWORD dwNewState ) { if (QueryServiceStatus().dwCurrentState != dwNewState) { ControlService(dwControl); while (QueryServiceStatus().dwCurrentState != dwNewState) { //bugbug: this might cause a hang } } } VOID StopService() { ChangeServiceState(SERVICE_CONTROL_STOP, SERVICE_STOPPED); } VOID PauseService() { ChangeServiceState(SERVICE_CONTROL_PAUSE, SERVICE_PAUSED); } VOID ContinueService() { ChangeServiceState(SERVICE_CONTROL_CONTINUE, SERVICE_RUNNING); } friend class CSCManager; private: SERVICE_STATUS m_ss; }; ////////////////////////////////////////////////////////////////////////// // // CSCManager // // Wrapper class for service control manager // class CSCManager : public CHandle { typedef CHandle parent_type; public: explicit CSCManager( PCTSTR pRemoteComputerName = 0, PCTSTR pDatabaseName = SERVICES_ACTIVE_DATABASE, DWORD dwDesiredAccess = SC_MANAGER_ALL_ACCESS ) : parent_type(OpenSCManager( pRemoteComputerName, pDatabaseName, dwDesiredAccess )) { } void Destroy() { CloseServiceHandle(*this); } bool IsValid() { return *this != 0; } public: SC_HANDLE CreateService( PCTSTR pServiceName, PCTSTR pDisplayName, DWORD dwDesiredAccess, DWORD dwServiceType, DWORD dwStartType, DWORD dwErrorControl, PCTSTR pBinaryPathName, PCTSTR pLoadOrderGroup = 0, PDWORD pdwTagId = 0, PCTSTR pDependencies = 0, PCTSTR pServiceStartName = 0, PCTSTR pPassword = 0 ) const { return ::CreateService( *this, pServiceName, pDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl, pBinaryPathName, pLoadOrderGroup, pdwTagId, pDependencies, pServiceStartName, pPassword ); } SC_HANDLE OpenService( PCTSTR pServiceName, DWORD dwDesiredAccess = SERVICE_ALL_ACCESS ) const { return ::OpenService( *this, pServiceName, dwDesiredAccess ); } }; #endif //_WINSVC_ ////////////////////////////////////////////////////////////////////////// // // CPath // // Base class for wrapper classes that deal with path names // #ifdef _IOSTREAM_ template class CPath; template std::ostream &operator <<(std::ostream &os, const CPath &rhs); #endif //_IOSTREAM_ template class CPath { public: CPath() { m_szName[0] = _T('\0'); m_szName[1] = _T('\0'); m_dwLength = 0; } CPath(PCTSTR pName) { assign(pName); } CPath & operator =(PCTSTR pName) { return assign(pName); } CPath & assign(PCTSTR pName) { _tcsncpy(m_szName, pName, N); FindLength(); return *this; } DWORD length() const { return m_dwLength; } bool empty() const { return m_szName[0] == _T('\0'); } operator PCTSTR() const { return m_szName; } PCTSTR FileName() const { return m_szName + m_dwLength + 1; } CPath & operator +=(PCTSTR pName) { SetFileName(pName); FindLength(); return *this; } CPath & SetFileName(PCTSTR pName) { m_szName[m_dwLength] = _T('\\'); _tcsncpy(m_szName + m_dwLength + 1, pName, N - m_dwLength - 1); return *this; } CPath & StripFileName() { m_szName[m_dwLength] = _T('\0'); return *this; } void FindLength() { m_dwLength = _tcslen(m_szName); while (m_dwLength && m_szName[m_dwLength-1] == _T('\\')) { m_szName[--m_dwLength] = _T('\0'); } } //bugbug: just to please the VC5 compiler, drop templates //template bool operator ==(const CPath/**/ &rhs) const { return m_dwLength == rhs.m_dwLength && _tcscmp(m_szName, rhs.m_szName) == 0; } //template bool operator !=(const CPath/**/ &rhs) const { return !(*this == rhs); } //template bool operator >(const CPath/**/ &rhs) const { return m_dwLength > rhs.m_dwLength || _tcscmp(m_szName, rhs.m_szName) > 0; } //template bool operator <=(const CPath/**/ &rhs) const { return !(*this > rhs); } //template bool operator <(const CPath/**/ &rhs) const { return m_dwLength < rhs.m_dwLength || _tcscmp(m_szName, rhs.m_szName) < 0; } //template bool operator >=(const CPath/**/ &rhs) const { return !(*this < rhs); } #ifdef _IOSTREAM_ friend std::ostream &operator <<(std::ostream &os, const CPath &rhs) { return os << m_szName; } #endif //_IOSTREAM_ protected: TCHAR m_szName[N]; DWORD m_dwLength; }; ////////////////////////////////////////////////////////////////////////// // // CWindowsDirectory // // Wrapper class for the GetWindowsDirectory() API // class CWindowsDirectory : public CPath<> { public: CWindowsDirectory() { CHECK(::GetWindowsDirectory( m_szName, COUNTOF(m_szName) )); FindLength(); } }; ////////////////////////////////////////////////////////////////////////// // // CSystemWindowsDirectory // // Wrapper class for the GetSystemWindowsDirectory() API // class CSystemWindowsDirectory : public CPath<> { public: CSystemWindowsDirectory() { typedef UINT (WINAPI *PFN)(LPTSTR lpBuffer, UINT uSize); static PFN pfn = (PFN) GetProcAddress( ::GetModuleHandle(_T("kernel32.dll")), "GetSystemWindowsDirectory"_AW ); if (pfn) { CHECK((*pfn)( m_szName, COUNTOF(m_szName) )); } else { CHECK(::GetWindowsDirectory( m_szName, COUNTOF(m_szName) )); } FindLength(); } }; ////////////////////////////////////////////////////////////////////////// // // CSystemDirectory // // Wrapper class for the GetSystemDirectory() API // class CSystemDirectory : public CPath<> { public: CSystemDirectory() { CHECK(::GetSystemDirectory( m_szName, COUNTOF(m_szName) )); FindLength(); } }; ////////////////////////////////////////////////////////////////////////// // // CCurrentDirectory // // Wrapper class for the GetCurrentDirectory() API // class CCurrentDirectory : public CPath<> { public: CCurrentDirectory() { CHECK(::GetCurrentDirectory( COUNTOF(m_szName), m_szName )); FindLength(); } }; ////////////////////////////////////////////////////////////////////////// // // CModuleFileName // // Wrapper class for the GetModuleFileName() API // class CModuleFileName : public CPath<> { public: CModuleFileName( HMODULE hModule = 0 ) { CHECK(::GetModuleFileName( hModule, m_szName, COUNTOF(m_szName) )); FindLength(); } }; #ifdef _ICM_H_ ////////////////////////////////////////////////////////////////////////// // // CColorDirectory // // Wrapper class for the GetColorDirectory() API // class CColorDirectory : public CPath<> { public: explicit CColorDirectory( PCTSTR pMachineName = 0 ) { m_dwLength = sizeof(m_szName); CHECK(GetColorDirectory( pMachineName, m_szName, &m_dwLength )); FindLength(); } }; #endif //_ICM_H_ ////////////////////////////////////////////////////////////////////////// // // CComputerName // // Wrapper class for the GetComputerName() API // class CComputerName : public CPath<2 + MAX_COMPUTERNAME_LENGTH + 1> { public: CComputerName( BOOL bUNC = FALSE ) { if (bUNC) { m_dwLength = COUNTOF(m_szName) - 2; CHECK(::GetComputerName( m_szName + 2, &m_dwLength )); m_szName[0] = '\\'; m_szName[1] = '\\'; } else { m_dwLength = COUNTOF(m_szName); CHECK(::GetComputerName( m_szName, &m_dwLength )); } FindLength(); } }; ////////////////////////////////////////////////////////////////////////// // // CFullPathName // // Wrapper class for the GetFullPathName() API // class CFullPathName : public CPath<> { public: CFullPathName( PCTSTR pFileName ) { if (pFileName && *pFileName) { PTSTR pFilePart; CHECK(::GetFullPathName( pFileName, COUNTOF(m_szName), m_szName, &pFilePart )); m_dwLength = (DWORD)(pFilePart - m_szName - 1); } } }; ////////////////////////////////////////////////////////////////////////// // // CTempFileName // // Wrapper class for the GetTempPath() API // class CTempPath : public CPath<> { public: CTempPath() { CHECK(::GetTempPath( COUNTOF(m_szName), m_szName )); FindLength(); } }; ////////////////////////////////////////////////////////////////////////// // // CTempFileName // // Wrapper class for the GetTempFileName() API // class CTempFileName : public CPath<> { public: CTempFileName( PCTSTR pPathName, PCTSTR pPrefixString, UINT uUnique = 0 ) { CHECK(::GetTempFileName( pPathName, pPrefixString, uUnique, m_szName )); FindLength(); } }; ////////////////////////////////////////////////////////////////////////// // // CWindowText // // Wrapper class for the GetWindowText() API // class CWindowText : public CPath<1024> //bugbug { public: CWindowText( HWND hWnd ) { ::SetLastError(0); CHECK( ::GetWindowText(hWnd, m_szName, COUNTOF(m_szName)) || ::GetLastError() == 0 ); } }; ////////////////////////////////////////////////////////////////////////// // // CSafeWindowText // // Helper class for the GetClassName() API (that works better on Win9x) // class CSafeWindowText : public CPath<1024> //bugbug { public: CSafeWindowText( HWND hWnd ) { WNDPROC pfnWndProc = (WNDPROC) GetWindowLongPtr( hWnd, GWLP_WNDPROC ); CallWindowProc( pfnWndProc, hWnd, WM_GETTEXT, COUNTOF(m_szName), (LPARAM) m_szName ); } }; ////////////////////////////////////////////////////////////////////////// // // CClassName // // Wrapper class for the GetClassName() API // class CClassName : public CPath<1024> //bugbug { public: CClassName( HWND hWnd ) { CHECK(::GetClassName( hWnd, m_szName, COUNTOF(m_szName) )); } }; ////////////////////////////////////////////////////////////////////////// // // CConsoleTitle // // Wrapper class for the GetConsoleTitle() API // class CConsoleTitle : public CPath<1024> //bugbug { public: CConsoleTitle() { CHECK(::GetConsoleTitle( m_szName, COUNTOF(m_szName) )); } }; ////////////////////////////////////////////////////////////////////////// // // CUserName // // Returns a handle to the console window // inline HWND GetConsoleHwnd() { HWND hConsoleWnd = 0; try { // read the current console title CConsoleTitle OldTitle; // change the title to a supposedly random value TCHAR szNewTitle[17]; wsprintf( szNewTitle, _T("%08x%08x"), GetTickCount(), GetCurrentProcessId() ); SetConsoleTitle(szNewTitle); Sleep(50); // try find the window based on this new title HWND hWnd = FindWindow(0, szNewTitle); // restore the title SetConsoleTitle(OldTitle); Sleep(50); // compare the title of the window we found against the console title CWindowText HWndTitle(hWnd); if (_tcscmp(OldTitle, HWndTitle) == 0) { hConsoleWnd = hWnd; } } catch (const CError &) { } return hConsoleWnd; } ////////////////////////////////////////////////////////////////////////// // // CUserName // // Wrapper class for the GetUserName API // #ifndef UNLEN #define UNLEN 256 #endif //UNLEN class CUserName : public CPath { public: CUserName() { m_dwLength = COUNTOF(m_szName); CHECK(::GetUserName( m_szName, &m_dwLength )); } }; ////////////////////////////////////////////////////////////////////////// // // CRegString // // Helper class for reading a string with the RegQueryValueEx() API // template class CRegString : public CPath { public: CRegString() { } CRegString( HKEY hKey, PCTSTR pSubKey, PTSTR pValueName, BOOL bExpandEnvironmentStrings = TRUE ) { CKey Key( hKey, pSubKey, KEY_READ ); DWORD dwType; m_dwLength = sizeof(m_szName); Key.RegQueryValueEx( pValueName, &dwType, m_szName, &m_dwLength ); if (dwType == REG_EXPAND_SZ && bExpandEnvironmentStrings) { TCHAR szExpanded[N]; CHECK(ExpandEnvironmentStrings( m_szName, szExpanded, COUNTOF(szExpanded) )); _tcscpy(m_szName, szExpanded); } FindLength(); } // bugbug: Aren't we supposed to inherit this? CPath & operator =( PCTSTR pName ) { return CPath::operator =(pName); } }; ////////////////////////////////////////////////////////////////////////// // // CResourceString // // Wrapper class for the LoadString() API // template class CResourceString : public CPath { public: CResourceString() { } explicit CResourceString( UINT uID, HINSTANCE hInstance = 0 ) { CHECK(m_dwLength = LoadString( hInstance, uID, m_szName, COUNTOF(m_szName) )); } CResourceString( UINT uID, HINSTANCE hInstance, PCTSTR pszDefault ) { m_dwLength = LoadString( hInstance, uID, m_szName, COUNTOF(m_szName) ); if (m_dwLength == 0) { assign(pszDefault); } } }; #ifdef _WINSPOOL_ ////////////////////////////////////////////////////////////////////////// // // CPrinterDriverDirectory // // Wrapper class for the GetPrinterDriverDirectory() API // class CPrinterDriverDirectory : public CPath<> { public: explicit CPrinterDriverDirectory( PTSTR pName = 0, PTSTR pEnvironment = 0 ) { m_dwLength = sizeof(m_szName); CHECK(::GetPrinterDriverDirectory( pName, pEnvironment, 1, (PBYTE) m_szName, m_dwLength, &m_dwLength )); FindLength(); } }; ////////////////////////////////////////////////////////////////////////// // // CPrintProcessorDirectory // // Wrapper class for the GetPrintProcessorDirectory() API // class CPrintProcessorDirectory : public CPath<> { public: explicit CPrintProcessorDirectory( PTSTR pName = 0, PTSTR pEnvironment = 0 ) { m_dwLength = sizeof(m_szName); CHECK(::GetPrintProcessorDirectory( pName, pEnvironment, 1, (PBYTE) m_szName, m_dwLength, &m_dwLength )); FindLength(); } }; ////////////////////////////////////////////////////////////////////////// // // CDefaultPrinter // // Wrapper class for the GetDefaultPrinter() API // #ifndef INTERNET_MAX_HOST_NAME_LENGTH #define INTERNET_MAX_HOST_NAME_LENGTH 256 #endif class CDefaultPrinter : public CPath<2 + INTERNET_MAX_HOST_NAME_LENGTH + 1 + MAX_PATH + 1> { public: CDefaultPrinter() { typedef BOOL (WINAPI *PFN)(LPTSTR, LPDWORD); static PFN pfnGetDefaultPrinter = (PFN) GetProcAddress( ::GetModuleHandle(_T("winspool.drv")), "GetDefaultPrinter"_AW ); m_dwLength = sizeof(m_szName); if (pfnGetDefaultPrinter) { pfnGetDefaultPrinter( m_szName, &m_dwLength ); } else { GetProfileString( _T("windows"), _T("device"), _T(",,,"), m_szName, COUNTOF(m_szName) ); PTSTR pComma = _tcschr(m_szName, ','); if (pComma) { *pComma = _T('\0'); } } FindLength(); } }; ////////////////////////////////////////////////////////////////////////// // // CPrinterDefaults // // Wrapper class for PRINTER_DEFAULTS struct // struct CPrinterDefaults : public PRINTER_DEFAULTS { CPrinterDefaults( PTSTR _pDatatype = 0, PDEVMODE _pDevMode = 0, ACCESS_MASK _DesiredAccess = PRINTER_ALL_ACCESS ) { pDatatype = _pDatatype; pDevMode = _pDevMode; DesiredAccess = _DesiredAccess; } }; ////////////////////////////////////////////////////////////////////////// // // printer_info_to_level, level_to_printer_info // // Traits classes to map PRINTER_INFO_XXX to level numbers and vice versa // template struct printer_info_to_level { }; template<> struct printer_info_to_level { enum { level = 1 }; }; template<> struct printer_info_to_level { enum { level = 2 }; }; template<> struct printer_info_to_level { enum { level = 3 }; }; template<> struct printer_info_to_level { enum { level = 4 }; }; template<> struct printer_info_to_level { enum { level = 5 }; }; template<> struct printer_info_to_level { enum { level = 6 }; }; template<> struct printer_info_to_level { enum { level = 7 }; }; template<> struct printer_info_to_level { enum { level = 8 }; }; template<> struct printer_info_to_level { enum { level = 9 }; }; template struct level_to_printer_info { }; template<> struct level_to_printer_info<1> { typedef PRINTER_INFO_1 struct_type; }; template<> struct level_to_printer_info<2> { typedef PRINTER_INFO_2 struct_type; }; template<> struct level_to_printer_info<3> { typedef PRINTER_INFO_3 struct_type; }; template<> struct level_to_printer_info<4> { typedef PRINTER_INFO_4 struct_type; }; template<> struct level_to_printer_info<5> { typedef PRINTER_INFO_5 struct_type; }; template<> struct level_to_printer_info<6> { typedef PRINTER_INFO_6 struct_type; }; template<> struct level_to_printer_info<7> { typedef PRINTER_INFO_7 struct_type; }; template<> struct level_to_printer_info<8> { typedef PRINTER_INFO_8 struct_type; }; template<> struct level_to_printer_info<9> { typedef PRINTER_INFO_9 struct_type; }; ////////////////////////////////////////////////////////////////////////// // // CPrinter // // Wrapper class for printer objects // class CPrinter : public CHandle { typedef CHandle parent_type; public: explicit CPrinter( PCTSTR pPrinterName, const PRINTER_DEFAULTS *pDefault = &CPrinterDefaults() ) { HANDLE hHandle; CHECK(::OpenPrinter( const_cast(pPrinterName), &hHandle, const_cast(pDefault) )); Attach(hHandle); } CPrinter( PTSTR pServerName, const PRINTER_INFO_2 *pPrinter ) : parent_type(::AddPrinter( pServerName, 2, (PBYTE) pPrinter )) { } void Destroy() { ::ClosePrinter(*this); } bool IsValid() { return *this != 0; } VOID Delete() const { CHECK(::DeletePrinter(*this)); } template VOID SetPrinter(T *pPrinterInfo) { CHECK(::SetPrinter( *this, printer_info_to_level::level, (PBYTE) pPrinterInfo, 0 )); } }; ////////////////////////////////////////////////////////////////////////// // // DeletePrinterDriverExRetry // // Helper for DeletePrinterDriverEx() API that implements wait & retry // inline BOOL DeletePrinterDriverExRetry( PTSTR pName, PTSTR pEnvironment, PTSTR pDriverName, DWORD dwDeleteFlag, DWORD dwVersionFlag, int nMaxRetries = 3, DWORD dwSleepMilliseconds = 1000 ) { BOOL bResult = FALSE; for ( int nRetries = 0; (bResult = DeletePrinterDriverEx( pName, pEnvironment, pDriverName, dwDeleteFlag, dwVersionFlag )) == FALSE && GetLastError() == ERROR_PRINTER_DRIVER_IN_USE && nRetries < nMaxRetries; ++nRetries ) { Sleep(dwSleepMilliseconds); } return bResult; } ////////////////////////////////////////////////////////////////////////// // // AddMonitor // // Helper for AddMonitor() API that infers the struct level at compile time // template struct monitor_info_to_level { }; template<> struct monitor_info_to_level { enum { level = 1 }; }; template<> struct monitor_info_to_level { enum { level = 2 }; }; template inline BOOL AddMonitor( PTSTR pName, T *pMonitors ) { return ::AddMonitor( pName, monitor_info_to_level::level, (PBYTE) pMonitors ); } ////////////////////////////////////////////////////////////////////////// // // CPrinterChangeNotification // // Wrapper class for printer change notifications // class CPrinterChangeNotification : public CHandle { typedef CHandle parent_type; public: CPrinterChangeNotification( HANDLE hPrinter, DWORD fdwFlags, PPRINTER_NOTIFY_OPTIONS pPrinterNotifyOptions = 0 ) : parent_type(::FindFirstPrinterChangeNotification( hPrinter, fdwFlags, 0, pPrinterNotifyOptions )) { } void Destroy() { ::FindClosePrinterChangeNotification(*this); } bool IsValid() { return (HANDLE) *this != INVALID_HANDLE_VALUE; } DWORD FindNext( PPRINTER_NOTIFY_OPTIONS pPrinterNotifyOptions = 0, PPRINTER_NOTIFY_INFO *ppPrinterNotifyInfo = 0 ) { DWORD dwChange; CHECK(::FindNextPrinterChangeNotification( *this, &dwChange, pPrinterNotifyOptions, (PVOID *) ppPrinterNotifyInfo )); return dwChange; } }; #endif //_WINSPOOL_ ////////////////////////////////////////////////////////////////////////// // // CStringFileInfo // // Helper class for creating \StringFileInfo\lang-codepage\name type strings // class CStringFileInfo : public CPath<80> { public: CStringFileInfo( WORD wLang, WORD wCodePage ) { _stprintf( m_szName, _T("\\StringFileInfo\\%04X%04X"), wLang, wCodePage ); FindLength(); } CStringFileInfo( DWORD dwLangCodePage ) { _stprintf( m_szName, _T("\\StringFileInfo\\%04X%04X"), LOWORD(dwLangCodePage), HIWORD(dwLangCodePage) ); FindLength(); } }; ////////////////////////////////////////////////////////////////////////// // // CVersionInfo // // Helper class for parsing version resource information // class CVersionInfo { public: CVersionInfo( PCTSTR pFileName = 0 ) { CModuleFileName ModuleFileName; if (!pFileName) { pFileName = ModuleFileName; } DWORD dwVerInfoSize; DWORD dwHandle; CHECK(dwVerInfoSize = GetFileVersionInfoSize( const_cast(pFileName), &dwHandle )); CCppMem VerInfo(dwVerInfoSize); CHECK(::GetFileVersionInfo( const_cast(pFileName), dwHandle, dwVerInfoSize, VerInfo )); m_VerInfo = VerInfo; } PVOID VerQueryValue( PCTSTR pSubBlock ) const { PVOID pBuffer; UINT uLen; CHECK(::VerQueryValue( m_VerInfo, const_cast(pSubBlock), &pBuffer, &uLen )); return pBuffer; } VS_FIXEDFILEINFO *GetFixedFileInfo() const { return (VS_FIXEDFILEINFO *) VerQueryValue(_T("\\")); } PDWORD GetTranslation() const { return (PDWORD) VerQueryValue(_T("\\VarFileInfo\\Translation")); } PCTSTR GetStringFileInfo( WORD wLang, WORD wCodePage, PCTSTR pSubBlock ) const { return (PCTSTR) VerQueryValue(CStringFileInfo(wLang, wCodePage).SetFileName(pSubBlock)); } ULARGE_INTEGER GetFileVersion() const { VS_FIXEDFILEINFO *pFixedFileInfo = GetFixedFileInfo(); ULARGE_INTEGER nVersion = { pFixedFileInfo->dwFileVersionLS, pFixedFileInfo->dwFileVersionMS }; return nVersion; } ULARGE_INTEGER GetProductVersion() const { VS_FIXEDFILEINFO *pFixedFileInfo = GetFixedFileInfo(); ULARGE_INTEGER nVersion = { pFixedFileInfo->dwProductVersionLS, pFixedFileInfo->dwProductVersionMS }; return nVersion; } private: CCppMem m_VerInfo; }; ////////////////////////////////////////////////////////////////////////// // // CResource // // Wrapper class for FindResourceEx(), LoadResource() and LockResource() APIs // class CResource { public: CResource( HMODULE hModule, PCTSTR pType, PCTSTR pName, WORD wLanguage = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) ) { HRSRC hResInfo; CHECK(hResInfo = FindResourceEx(hModule, pType, pName, wLanguage)); HGLOBAL hResData; CHECK(hResData = LoadResource(hModule, hResInfo)); CHECK(m_pData = LockResource(hResData)); CHECK(m_nSize = SizeofResource(hModule, hResInfo)); } PVOID Data() { return m_pData; } DWORD Size() { return m_nSize; } private: PVOID m_pData; DWORD m_nSize; }; ////////////////////////////////////////////////////////////////////////// // // CDialogResource // // Helper class for parsing a dialog resource // class CDialogResource { public: CDialogResource( HMODULE hModule, PCTSTR pName, WORD wLanguage = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) ) { CResource Dlg(hModule, RT_DIALOG, pName, wLanguage); ParseDlgResource(Dlg.Data()); } CDialogResource( PVOID pDlgResource ) { ParseDlgResource(pDlgResource); } private: class CParseDlgResource { public: CParseDlgResource( PVOID pDlgResource ) { Goto(pDlgResource); } void Goto(PVOID pDlgResource) { m_pNextValue = (PBYTE) pDlgResource; } template void Read(T &Value) { Value = *(T *) m_pNextValue; m_pNextValue += sizeof(T); } template <> void Read(PWSTR &pStr) { pStr = (PWSTR) m_pNextValue; if (*pStr == MAXWORD) { pStr = (PWSTR) pStr[1]; m_pNextValue += 2 * sizeof(WCHAR); } else { m_pNextValue += (wcslen(pStr) + 1) * sizeof(WCHAR); } } private: PBYTE m_pNextValue; }; private: void ParseDlgResource(PVOID pDlgResource) { ZeroMemory(this, sizeof(*this)); CParseDlgResource Parser(pDlgResource); Parser.Read(dlgVer); Parser.Read(signature); BOOL bIsExTemplate = dlgVer == 1 && signature == MAXWORD; if (bIsExTemplate) { Parser.Read(helpID); Parser.Read(exStyle); Parser.Read(style); } else { Parser.Goto(pDlgResource); Parser.Read(style); Parser.Read(exStyle); } Parser.Read(cDlgItems); Parser.Read(x); Parser.Read(y); Parser.Read(cx); Parser.Read(cy); Parser.Read(menu); Parser.Read(windowClass); Parser.Read(title); if (style & DS_SHELLFONT) { if (bIsExTemplate) { Parser.Read(pointsize); Parser.Read(weight); Parser.Read(italic); Parser.Read(charset); Parser.Read(typeface); } else { Parser.Read(pointsize); Parser.Read(typeface); } } } public: WORD dlgVer; WORD signature; DWORD helpID; DWORD exStyle; DWORD style; WORD cDlgItems; short x; short y; short cx; short cy; PWSTR menu; PWSTR windowClass; PWSTR title; WORD pointsize; WORD weight; BYTE italic; BYTE charset; PWSTR typeface; }; ////////////////////////////////////////////////////////////////////////// // // CStringTable // template class CStringTable { public: CStringTable( HINSTANCE hInstance = GetModuleHandle(0) ) { TCHAR szBuffer[4098]; // max length of a resource string for (int i = 0; i < m_nStrings; ++i) { int nLength = LoadString( hInstance, i + nFirstId, szBuffer, COUNTOF(szBuffer) ); m_pTable[i] = new TCHAR[nLength + 1]; if (nLength && m_pTable[i]) { CopyMemory( m_pTable[i], szBuffer, nLength * sizeof(TCHAR) ); } } } ~CStringTable() { for (int i = 0; i < m_nStrings; ++i) { if (m_pTable[i]) { delete [] m_pTable[i]; } } } PCTSTR operator[](int i) { ASSERT(nFirstId <= i && i <= nLastId); return m_pTable[i - nFirstId]; } private: enum { m_nStrings = nLastId - nFirstId + 1 }; PTSTR m_pTable[m_nStrings]; }; #ifdef _NTSECAPI_ ////////////////////////////////////////////////////////////////////////// // // CLsaUnicodeString // // Wrapper class for LSA_UNICODE_STRING struct // class CLsaUnicodeString : public LSA_UNICODE_STRING { public: CLsaUnicodeString( PWSTR pStr ) { if (pStr) { Buffer = pStr; Length = (USHORT) (wcslen(pStr) * sizeof(WCHAR)); MaximumLength = (USHORT) (Length + sizeof(WCHAR)); } else { Buffer = 0; Length = 0; MaximumLength = 0; } } }; #endif //_NTSECAPI_ ////////////////////////////////////////////////////////////////////////// // // COSVersionInfo // // Wrapper class for GetVersion() API // class COSVersionInfo : public OSVERSIONINFO { public: COSVersionInfo() { dwOSVersionInfoSize = sizeof(OSVERSIONINFO); CHECK(GetVersionEx(this)); } }; ////////////////////////////////////////////////////////////////////////// // // COSVersionInfoEx // // Wrapper class for GetVersionEx() API // class COSVersionInfoEx : public OSVERSIONINFOEX { public: COSVersionInfoEx() { dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); CHECK(GetVersionEx((POSVERSIONINFO)this)); } }; #ifdef _INC_CDERR ////////////////////////////////////////////////////////////////////////// // // COpenFileName // // Wrapper class for GetOpenFileName() and GetSaveFileName() APIs // template class COpenFileName : public OPENFILENAME { public: COpenFileName( HWND hWndOwner = 0, PCTSTR pFilter = 0, PCTSTR pInitialDir = 0, PCTSTR pTitle = 0, PCTSTR pDefExt = 0, DWORD dwFlags = 0 ) { ZeroMemory(this, sizeof(*this)); lStructSize = sizeof(OPENFILENAME); hwndOwner = hWndOwner; hInstance = 0; lpstrFilter = pFilter; lpstrCustomFilter = m_szCustomFilter; nMaxCustFilter = COUNTOF(m_szCustomFilter); nFilterIndex = 1; lpstrFile = m_szFileName; nMaxFile = COUNTOF(m_szFileName); lpstrFileTitle = m_szFileTitle; nMaxFileTitle = COUNTOF(m_szFileTitle); lpstrInitialDir = pInitialDir; lpstrTitle = pTitle; Flags = dwFlags | OFN_EXPLORER | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_FILEMUSTEXIST; lpstrDefExt = pDefExt; } BOOL GetOpenFileName() { BOOL bResult = ::GetOpenFileName(this); if (!bResult && CommDlgExtendedError() == CDERR_STRUCTSIZE) { lStructSize = OPENFILENAME_SIZE_VERSION_400; bResult = ::GetOpenFileName(this); } return bResult; } BOOL GetSaveFileName() { BOOL bResult = ::GetSaveFileName(this); if (!bResult && CommDlgExtendedError() == CDERR_STRUCTSIZE) { lStructSize = OPENFILENAME_SIZE_VERSION_400; bResult = ::GetSaveFileName(this); } return bResult; } private: TCHAR m_szFileName[nFileNameLen]; TCHAR m_szFileTitle[nFileTitleSize]; TCHAR m_szCustomFilter[nCustomFilterSize]; }; #endif //_INC_CDERR #ifdef _SHLOBJ_H_ ////////////////////////////////////////////////////////////////////////// // // CBrowseInfo // // Wrapper class for SHBrowseForFolder() API // template class CBrowseInfo : public BROWSEINFO { public: CBrowseInfo( HWND _hWndOwner = 0, UINT _ulFlags = 0 ) { ZeroMemory(this, sizeof(*this)); hwndOwner = _hWndOwner; pszDisplayName = m_szPath; ulFlags = _ulFlags; } BOOL BrowseForFolder() { LPITEMIDLIST pidl = SHBrowseForFolder(this); if (pidl) { TCHAR szPath[nPathNameLen]; if (SHGetPathFromIDList(pidl, szPath)) { _tcscpy(m_szPath, szPath); } SHFree(pidl); return TRUE; } return FALSE; } private: TCHAR m_szPath[nPathNameLen]; }; #endif //_SHLOBJ_H_ #ifdef _INC_SETUPAPI ////////////////////////////////////////////////////////////////////////// // // CInf // // Wrapper class for Inf file parsing object and APIs // class CInf : public CHandle { typedef CHandle parent_type; public: CInf() { } explicit CInf( PCTSTR FileName, PCTSTR InfClass = 0, DWORD InfStyle = INF_STYLE_WIN4, PUINT ErrorLine = 0 ) : parent_type(::SetupOpenInfFile( FileName, InfClass, InfStyle, ErrorLine )) { } public: void Destroy() { ::SetupCloseInfFile(*this); } bool IsValid() { return *this != 0; } }; #endif //_INC_SETUPAPI ////////////////////////////////////////////////////////////////////////// // // CDisplayWaitCursor // // Helper class that displays the wait cursor // class CDisplayWaitCursor { DISABLE_COPY_CONTRUCTION(CDisplayWaitCursor) public: CDisplayWaitCursor() { m_hOldCursor = SetCursor(LoadCursor(0, IDC_WAIT)); } ~CDisplayWaitCursor() { SetCursor(m_hOldCursor); } private: HCURSOR m_hOldCursor; }; ////////////////////////////////////////////////////////////////////////// // // CSystemInfo // // Wrapper class for the GetSystemInfo() API // class CSystemInfo : public SYSTEM_INFO { public: CSystemInfo() { GetSystemInfo(this); } }; ////////////////////////////////////////////////////////////////////////// // // CProc // // Wrapper class for the GetProcAddress() API // template class CProc { public: CProc( prototype pfnDefault = 0 ) : m_pfnProc(pfnDefault) { } CProc( HMODULE hModule, PCSTR pProcName ) { CHECK(m_pfnProc = (prototype) ::GetProcAddress( hModule, pProcName )); } CProc( HMODULE hModule, PCSTR pProcName, prototype pfnDefault ) { m_pfnProc = (prototype) ::GetProcAddress( hModule, pProcName ); if (m_pfnProc == 0) { m_pfnProc = pfnDefault; } } operator prototype() const { return m_pfnProc; } private: prototype m_pfnProc; }; ////////////////////////////////////////////////////////////////////////// // // DECL_CWINAPI // // Creates wrapper classes for fail-safe API address loading // #define DECL_CWINAPI(return_type, decl_spec, func_name, args) \ \ class C##func_name : public CProc \ { \ public: \ typedef return_type (decl_spec *prototype) args; \ \ C##func_name() : \ CProc(DefaultAPI) \ { \ } \ \ C##func_name( \ HMODULE hModule, \ PCSTR pProcName = #func_name \ ) : \ CProc( \ hModule, \ pProcName, \ DefaultAPI \ ) \ { \ } \ \ protected: \ static return_type decl_spec DefaultAPI args \ { \ ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED); \ return 0; \ } \ \ } func_name \ ////////////////////////////////////////////////////////////////////////// // // CBlob // // Contains a binary block of data specified by its start address and size // struct CBlob { const void *pData; SIZE_T cbData; CBlob() { } CBlob(const void *_pData, SIZE_T _cbData) { pData = _pData; cbData = _cbData; } }; ////////////////////////////////////////////////////////////////////////// // // CStrBlob // // Contains an ANSI or UNICODE string without a terminating NULL // struct CStrBlob : public CBlob { explicit CStrBlob(PCSTR pStr) { if (pStr) { pData = pStr; cbData = strlen(pStr) * sizeof(CHAR); } else { pData = ""; cbData = 0; } } explicit CStrBlob(PCWSTR pStr) { if (pStr) { pData = pStr; cbData = wcslen(pStr) * sizeof(WCHAR); } else { pData = ""; cbData = 0; } } }; ////////////////////////////////////////////////////////////////////////// // // CSzBlob // // Contains an ANSI or UNICODE string with a terminating NULL // struct CSzBlob : public CStrBlob { explicit CSzBlob(PCSTR pStr) : CStrBlob(pStr) { cbData += sizeof(CHAR); } explicit CSzBlob(PCWSTR pStr) : CStrBlob(pStr) { cbData += sizeof(WCHAR); } }; ////////////////////////////////////////////////////////////////////////// // // CMultiSzBlob // // Contains a NULL terminated list of ANSI or UNICODE NULL terminated strings // struct CMultiSzBlob : public CBlob { explicit CMultiSzBlob(PCSTR pStr) { if (pStr) { pData = pStr; cbData = (multiszlenA(pStr) + 1) * sizeof(CHAR); } else { pData = "\0"; cbData = 2 * sizeof(CHAR); } } explicit CMultiSzBlob(PCWSTR pStr) { if (pStr) { pData = pStr; cbData = (multiszlenW(pStr) + 1) * sizeof(WCHAR); } else { pData = L"\0"; cbData = 2 * sizeof(WCHAR); } } }; ////////////////////////////////////////////////////////////////////////// // // CBufferFill // // Helper class for filling in a block of memory in an overflow safe way // class CBufferFill { public: CBufferFill(PVOID pBuffer, SIZE_T cbBuffer) { m_pTop = (PBYTE) pBuffer; m_pEnd = (PBYTE) pBuffer + cbBuffer; } INT_PTR BytesLeft() const { return m_pEnd - m_pTop; } PVOID AddTop(const CBlob &Blob) { PVOID pDest = m_pTop; m_pTop += Blob.cbData; if (BytesLeft() >= 0) { CopyMemory(pDest, Blob.pData, Blob.cbData); } return pDest; } PVOID AddEnd(const CBlob &Blob) { m_pEnd -= Blob.cbData; if (BytesLeft() >= 0) { CopyMemory(m_pEnd, Blob.pData, Blob.cbData); } return m_pEnd; } private: PBYTE m_pTop; PBYTE m_pEnd; }; #if 0 //bugbug: not ready for prime time yet ////////////////////////////////////////////////////////////////////////// // // _tstring // // Helper class that handles UNICODE to ANSI conversions // _STD_BEGIN class _tstring : public basic_string { public: _tstring(PCOSTR pStr) { ostr = pStr; } _tstring &operator =(PCOSTR pStr) { ostr = pStr; return *this; } operator PCTSTR() const { if (empty()) { USES_CONVERSION; assign(T2O(ostr.c_str())); } return c_str(); } operator PCOSTR() const { if (ostr.empty()) { USES_CONVERSION; ostr = T2O(c_str()); } return ostr.c_str(); } private: basic_string ostr; }; _STD_END #endif ////////////////////////////////////////////////////////////////////////// // // CMySimpleCriticalSection // // Implementation for a simple critical section class that does not // handle recursions // class CMySimpleCriticalSection { public: CMySimpleCriticalSection() { m_lLockCount = -1; m_hLockHandle = 0; } ~CMySimpleCriticalSection() { if (m_hLockHandle) { CloseHandle(m_hLockHandle); } } VOID Enter() { if (InterlockedIncrement(&m_lLockCount) != 0) { CheckLockHandle(); WaitForSingleObject(m_hLockHandle, INFINITE); } } VOID Leave() { if (InterlockedDecrement(&m_lLockCount) >= 0) { CheckLockHandle(); SetEvent(m_hLockHandle); } } BOOL TryEnter() { return InterlockedCompareExchange(&m_lLockCount, 0, -1) == -1; } protected: VOID CheckLockHandle() { if (!m_hLockHandle) { HANDLE hLockHandle; CHECK(hLockHandle = CreateEvent(0, FALSE, FALSE, 0)); if (InterlockedCompareExchangePointer(&m_hLockHandle, hLockHandle, 0) != 0) { // another thread initialized and stored an hLockHandle // before us, better close ours CloseHandle(hLockHandle); } } } protected: LONG m_lLockCount; HANDLE m_hLockHandle; }; ////////////////////////////////////////////////////////////////////////// // // CMyCriticalSection // // Implementation for a full blown critical section class // class CMyCriticalSection : public CMySimpleCriticalSection { public: CMyCriticalSection() { m_lRecursionCount = 0; m_dwOwningThreadId = 0; } BOOL Enter( DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE ) { DWORD dwCurrentThreadId = GetCurrentThreadId(); if (InterlockedIncrement(&m_lLockCount) == 0) { m_dwOwningThreadId = dwCurrentThreadId; m_lRecursionCount = 1; return TRUE; } else { if (m_dwOwningThreadId == dwCurrentThreadId) { ++m_lRecursionCount; return TRUE; } else { CheckLockHandle(); DWORD dwWaitResult = WaitForSingleObjectEx( m_hLockHandle, dwMilliseconds, bAlertable ); if (dwWaitResult == WAIT_OBJECT_0) { m_dwOwningThreadId = dwCurrentThreadId; m_lRecursionCount = 1; return TRUE; } else { return FALSE; } } } } VOID Leave() { if (--m_lRecursionCount != 0) { InterlockedDecrement(&m_lLockCount); } else { m_dwOwningThreadId = 0; if (InterlockedDecrement(&m_lLockCount) >= 0) { CheckLockHandle(); SetEvent(m_hLockHandle); } } } BOOL TryEnter() { DWORD dwCurrentThreadId = GetCurrentThreadId(); if (InterlockedCompareExchange(&m_lLockCount, 0, -1) == -1) { m_dwOwningThreadId = dwCurrentThreadId; m_lRecursionCount = 1; return TRUE; } else { if (m_dwOwningThreadId == dwCurrentThreadId) { InterlockedIncrement(&m_lLockCount); ++m_lRecursionCount; return TRUE; } else { return FALSE; } } } protected: LONG m_lRecursionCount; DWORD m_dwOwningThreadId; }; ////////////////////////////////////////////////////////////////////////// // // CMultipleWait // // Wrapper class for the WaitForMultipleObjectsEx() API // class CMultipleWait : public CCppMem { public: CMultipleWait( int nCount ) : m_nCount(nCount), CCppMem(nCount) { } DWORD WaitFor( BOOL bWaitAll = TRUE, DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE ) { return WaitForMultipleObjectsEx( m_nCount, *this, bWaitAll, dwMilliseconds, bAlertable ); } void Erase( int nFirstHandle, int nNumHandles = 1 ) { m_nCount -= nNumHandles; MoveData( *this + nFirstHandle, *this + nFirstHandle + nNumHandles, m_nCount - nFirstHandle ); } private: int m_nCount; }; ////////////////////////////////////////////////////////////////////////// #endif //_WRAPPERS_H_