5794 lines
105 KiB
C++
5794 lines
105 KiB
C++
/*++
|
|
|
|
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 <assert.h>
|
|
|
|
#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 <class T>
|
|
inline const T Abs(const T& x)
|
|
{
|
|
return x < 0 ? -x : x;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Sqr
|
|
//
|
|
// Returns x^2
|
|
//
|
|
|
|
template <class T>
|
|
inline const T Sqr(const T& x)
|
|
{
|
|
return x * x;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Cube
|
|
//
|
|
// Returns x^3
|
|
//
|
|
|
|
template <class T>
|
|
inline const T Cube(const T& x)
|
|
{
|
|
return x * x * x;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Swap
|
|
//
|
|
// Swaps the values of two variables
|
|
//
|
|
|
|
template <class T>
|
|
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 <class T>
|
|
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 <class T>
|
|
inline const T Max(const T& x, const T& y)
|
|
{
|
|
return x < y ? y : x;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Cmp
|
|
//
|
|
// Compares two variables (based on "==" and "<" operators)
|
|
//
|
|
|
|
template <class T>
|
|
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 <class T>
|
|
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 <class T>
|
|
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 <class T>
|
|
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 <class T>
|
|
inline BOOL IsEqual(T lhs, T rhs)
|
|
{
|
|
return lhs == rhs;
|
|
}
|
|
|
|
template <class T>
|
|
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<PSTR>(pFileName ? pFileName + 1 : pPathName);
|
|
}
|
|
|
|
inline PWSTR FindFileNamePortionW(PCWSTR pPathName)
|
|
{
|
|
PCWSTR pFileName = pPathName ? wcsrchr(pPathName, '\\') : 0;
|
|
return const_cast<PWSTR>(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<PTSTR>(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 T, class Child>
|
|
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 Child>
|
|
class CKernelObject : public CHandle<HANDLE, Child>
|
|
{
|
|
typedef CHandle<HANDLE, Child> 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<File>
|
|
{
|
|
public:
|
|
File()
|
|
{
|
|
}
|
|
|
|
File(
|
|
PCTSTR pFileName,
|
|
DWORD dwDesiredAccess,
|
|
DWORD dwShareMode,
|
|
LPSECURITY_ATTRIBUTES pSecurityAttributes,
|
|
DWORD dwCreationDisposition,
|
|
DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL,
|
|
HANDLE hTemplateFile = 0
|
|
) :
|
|
CKernelObject<File>(::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 <share.h>
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CCFile
|
|
//
|
|
// Wrapper class for C-runtime stream based file handles
|
|
//
|
|
|
|
class CCFile : public CHandle<FILE *, CCFile>
|
|
{
|
|
typedef CHandle<FILE *, CCFile> 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<CFileMapping>
|
|
{
|
|
public:
|
|
CFileMapping()
|
|
{
|
|
}
|
|
|
|
CFileMapping(
|
|
HANDLE hFile,
|
|
LPSECURITY_ATTRIBUTES pFileMappingAttributes,
|
|
DWORD flProtect,
|
|
DWORD dwMaximumSizeHigh = 0,
|
|
DWORD dwMaximumSizeLow = 0,
|
|
PCTSTR pName = 0
|
|
) :
|
|
CKernelObject<CFileMapping>(::CreateFileMapping(
|
|
hFile,
|
|
pFileMappingAttributes,
|
|
flProtect,
|
|
dwMaximumSizeHigh,
|
|
dwMaximumSizeLow,
|
|
pName
|
|
))
|
|
{
|
|
}
|
|
};
|
|
|
|
|
|
#ifdef _LZEXPAND_
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CLZFile
|
|
//
|
|
// Wrapper class for LZ compressed files
|
|
//
|
|
|
|
class CLZFile : public CHandle<INT, CLZFile>
|
|
{
|
|
typedef CHandle<INT, CLZFile> 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<PROCESS_INFORMATION, CProcess>
|
|
{
|
|
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<CThreadBase>
|
|
{
|
|
protected:
|
|
CThreadBase()
|
|
{
|
|
}
|
|
|
|
explicit
|
|
CThreadBase(
|
|
HANDLE hHandle
|
|
) :
|
|
CKernelObject<CThreadBase>(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<Event>
|
|
{
|
|
public:
|
|
Event()
|
|
{
|
|
}
|
|
|
|
Event(
|
|
BOOL bManualReset,
|
|
BOOL bInitialState,
|
|
LPCTSTR lpName = 0,
|
|
LPSECURITY_ATTRIBUTES lpEventAttributes = 0
|
|
) :
|
|
CKernelObject<Event>(::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<Mutex>
|
|
{
|
|
public:
|
|
Mutex()
|
|
{
|
|
}
|
|
|
|
explicit
|
|
Mutex(
|
|
BOOL bInitialOwner,
|
|
PCTSTR pName = 0,
|
|
PSECURITY_ATTRIBUTES pMutexAttributes = 0
|
|
) :
|
|
CKernelObject<Mutex>(::CreateMutex(
|
|
pMutexAttributes,
|
|
bInitialOwner,
|
|
pName
|
|
))
|
|
{
|
|
}
|
|
|
|
public:
|
|
VOID
|
|
Release() const
|
|
{
|
|
CHECK(::ReleaseMutex(*this));
|
|
}
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Semaphore
|
|
//
|
|
// Wrapper class for semaphore handles
|
|
//
|
|
|
|
class Semaphore : public CKernelObject<Semaphore>
|
|
{
|
|
public:
|
|
Semaphore()
|
|
{
|
|
}
|
|
|
|
Semaphore(
|
|
LONG lInitialCount,
|
|
LONG lMaximumCount,
|
|
LPCTSTR lpName = 0,
|
|
LPSECURITY_ATTRIBUTES lpEventAttributes = 0
|
|
) :
|
|
CKernelObject<Semaphore>(::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<CWaitableTimer>
|
|
{
|
|
public:
|
|
CWaitableTimer()
|
|
{
|
|
}
|
|
|
|
explicit
|
|
CWaitableTimer(
|
|
BOOL bManualReset,
|
|
PCTSTR pTimerName = 0,
|
|
PSECURITY_ATTRIBUTES pTimerAttributes = 0
|
|
) :
|
|
CKernelObject<CWaitableTimer>(::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<HINSTANCE, CLibrary>
|
|
{
|
|
typedef CHandle<HINSTANCE, CLibrary> 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 T, class Child>
|
|
class CPointer : public CHandle<T *, Child >
|
|
{
|
|
typedef CHandle<T *, Child> 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 T>
|
|
class CCppMem : public CPointer<T, CCppMem<T> >
|
|
{
|
|
typedef CPointer<T, CCppMem<T> > 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 T>
|
|
class CGlobalMem : public CPointer<T, CGlobalMem<T> >
|
|
{
|
|
typedef CPointer<T, CGlobalMem<T> > 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 T>
|
|
class CLocalMem : public CPointer<T, CLocalMem<T> >
|
|
{
|
|
typedef CPointer<T, CLocalMem<T> > 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 T>
|
|
class CMapViewOfFile : public CPointer<T, CMapViewOfFile<T> >
|
|
{
|
|
public:
|
|
CMapViewOfFile()
|
|
{
|
|
}
|
|
|
|
CMapViewOfFile(
|
|
HANDLE hFileMappingObject,
|
|
DWORD dwDesiredAccess,
|
|
DWORD dwFileOffsetHigh = 0,
|
|
DWORD dwFileOffsetLow = 0,
|
|
DWORD dwNumberOfBytesToMap = 0,
|
|
PVOID pBaseAddress = 0
|
|
) :
|
|
CPointer<T, CMapViewOfFile<T> >((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 <int> struct mapping_traits { };
|
|
|
|
template <> struct mapping_traits<FILE_MAP_READ>
|
|
{
|
|
enum
|
|
{
|
|
dwDesiredAccess = GENERIC_READ,
|
|
dwShareMode = FILE_SHARE_READ,
|
|
flProtect = PAGE_READONLY,
|
|
dwDesiredMapAccess = FILE_MAP_READ
|
|
};
|
|
};
|
|
|
|
template <> struct mapping_traits<FILE_MAP_WRITE>
|
|
{
|
|
enum
|
|
{
|
|
dwDesiredAccess = GENERIC_READ | GENERIC_WRITE,
|
|
dwShareMode = 0,
|
|
flProtect = PAGE_READWRITE,
|
|
dwDesiredMapAccess = FILE_MAP_WRITE
|
|
};
|
|
};
|
|
|
|
template <> struct mapping_traits<FILE_MAP_COPY>
|
|
{
|
|
enum
|
|
{
|
|
dwDesiredAccess = GENERIC_READ | GENERIC_WRITE,
|
|
dwShareMode = FILE_SHARE_READ,
|
|
flProtect = PAGE_WRITECOPY,
|
|
dwDesiredMapAccess = FILE_MAP_COPY
|
|
};
|
|
};
|
|
|
|
template <class T, int Access>
|
|
class CMapFile
|
|
{
|
|
public:
|
|
CMapFile(
|
|
PCTSTR pFileName
|
|
) :
|
|
m_File(
|
|
pFileName, // PCTSTR pFileName
|
|
mapping_traits<Access>::dwDesiredAccess, // DWORD dwDesiredAccess
|
|
mapping_traits<Access>::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<Access>::flProtect, // DWORD flProtect
|
|
0, // DWORD dwMaximumSizeHigh
|
|
0, // DWORD dwMaximumSizeLow
|
|
0 // PCTSTR pName
|
|
),
|
|
|
|
m_ViewOfFile(
|
|
m_Mapping, // HANDLE hFileMappingObject
|
|
mapping_traits<Access>::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<T> m_ViewOfFile;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CSecurityDescriptor
|
|
//
|
|
// Wrapper class for SECURITY_DESCRIPTOR struct
|
|
//
|
|
|
|
class CSecurityDescriptor : public CCppMem<SECURITY_DESCRIPTOR>
|
|
{
|
|
public:
|
|
explicit
|
|
CSecurityDescriptor(
|
|
BOOL bDaclPresent = TRUE,
|
|
PACL pDacl = 0,
|
|
BOOL bDaclDefaulted = FALSE
|
|
) :
|
|
CCppMem<SECURITY_DESCRIPTOR>(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 <pshpack1.h>
|
|
|
|
template <int N>
|
|
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 <poppack.h>
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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<CProcessToken>
|
|
{
|
|
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<CLoggedOnUser>
|
|
{
|
|
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<HANDLE, CEventSource>
|
|
{
|
|
typedef CHandle<HANDLE, CEventSource> 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<HKEY, CKey>
|
|
{
|
|
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<HANDLE, CFindFile>
|
|
{
|
|
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<CToolhelp32Snapshot>
|
|
{
|
|
typedef CKernelObject<CToolhelp32Snapshot> 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 <class T, BOOL (WINAPI *fnFindFirst)(HANDLE, T *), BOOL (WINAPI *fnFindNext)(HANDLE, T *)>
|
|
|
|
#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<SC_HANDLE, CService>
|
|
{
|
|
typedef CHandle<SC_HANDLE, CService> 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<SC_HANDLE, CSCManager>
|
|
{
|
|
typedef CHandle<SC_HANDLE, CSCManager> 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 <int N> class CPath;
|
|
template <int N> std::ostream &operator <<(std::ostream &os, const CPath<N> &rhs);
|
|
#endif //_IOSTREAM_
|
|
|
|
template <int N = MAX_PATH>
|
|
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 <int M>
|
|
bool operator ==(const CPath/*<M>*/ &rhs) const
|
|
{
|
|
return
|
|
m_dwLength == rhs.m_dwLength &&
|
|
_tcscmp(m_szName, rhs.m_szName) == 0;
|
|
}
|
|
|
|
//template <int M>
|
|
bool operator !=(const CPath/*<M>*/ &rhs) const
|
|
{
|
|
return !(*this == rhs);
|
|
}
|
|
|
|
//template <int M>
|
|
bool operator >(const CPath/*<M>*/ &rhs) const
|
|
{
|
|
return
|
|
m_dwLength > rhs.m_dwLength ||
|
|
_tcscmp(m_szName, rhs.m_szName) > 0;
|
|
}
|
|
|
|
//template <int M>
|
|
bool operator <=(const CPath/*<M>*/ &rhs) const
|
|
{
|
|
return !(*this > rhs);
|
|
}
|
|
|
|
//template <int M>
|
|
bool operator <(const CPath/*<M>*/ &rhs) const
|
|
{
|
|
return
|
|
m_dwLength < rhs.m_dwLength ||
|
|
_tcscmp(m_szName, rhs.m_szName) < 0;
|
|
}
|
|
|
|
//template <int M>
|
|
bool operator >=(const CPath/*<M>*/ &rhs) const
|
|
{
|
|
return !(*this < rhs);
|
|
}
|
|
|
|
#ifdef _IOSTREAM_
|
|
|
|
friend std::ostream &operator <<(std::ostream &os, const CPath<N> &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<UNLEN + 1>
|
|
{
|
|
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 <int N>
|
|
class CRegString : public CPath<N>
|
|
{
|
|
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<N> &
|
|
operator =(
|
|
PCTSTR pName
|
|
)
|
|
{
|
|
return CPath<N>::operator =(pName);
|
|
}
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CResourceString
|
|
//
|
|
// Wrapper class for the LoadString() API
|
|
//
|
|
|
|
template <int N>
|
|
class CResourceString : public CPath<N>
|
|
{
|
|
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<class T> struct printer_info_to_level { };
|
|
template<> struct printer_info_to_level<PRINTER_INFO_1> { enum { level = 1 }; };
|
|
template<> struct printer_info_to_level<PRINTER_INFO_2> { enum { level = 2 }; };
|
|
template<> struct printer_info_to_level<PRINTER_INFO_3> { enum { level = 3 }; };
|
|
template<> struct printer_info_to_level<PRINTER_INFO_4> { enum { level = 4 }; };
|
|
template<> struct printer_info_to_level<PRINTER_INFO_5> { enum { level = 5 }; };
|
|
template<> struct printer_info_to_level<PRINTER_INFO_6> { enum { level = 6 }; };
|
|
template<> struct printer_info_to_level<PRINTER_INFO_7> { enum { level = 7 }; };
|
|
template<> struct printer_info_to_level<PRINTER_INFO_8> { enum { level = 8 }; };
|
|
template<> struct printer_info_to_level<PRINTER_INFO_9> { enum { level = 9 }; };
|
|
|
|
template<int N> 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<HANDLE, CPrinter>
|
|
{
|
|
typedef CHandle<HANDLE, CPrinter> parent_type;
|
|
|
|
public:
|
|
explicit
|
|
CPrinter(
|
|
PCTSTR pPrinterName,
|
|
const PRINTER_DEFAULTS *pDefault = &CPrinterDefaults()
|
|
)
|
|
{
|
|
HANDLE hHandle;
|
|
|
|
CHECK(::OpenPrinter(
|
|
const_cast<PTSTR>(pPrinterName),
|
|
&hHandle,
|
|
const_cast<PPRINTER_DEFAULTS>(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 <class T>
|
|
VOID
|
|
SetPrinter(T *pPrinterInfo)
|
|
{
|
|
CHECK(::SetPrinter(
|
|
*this,
|
|
printer_info_to_level<T>::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<class T> struct monitor_info_to_level { };
|
|
template<> struct monitor_info_to_level<MONITOR_INFO_1> { enum { level = 1 }; };
|
|
template<> struct monitor_info_to_level<MONITOR_INFO_2> { enum { level = 2 }; };
|
|
|
|
template <class T>
|
|
inline
|
|
BOOL
|
|
AddMonitor(
|
|
PTSTR pName,
|
|
T *pMonitors
|
|
)
|
|
{
|
|
return ::AddMonitor(
|
|
pName,
|
|
monitor_info_to_level<T>::level,
|
|
(PBYTE) pMonitors
|
|
);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CPrinterChangeNotification
|
|
//
|
|
// Wrapper class for printer change notifications
|
|
//
|
|
|
|
class CPrinterChangeNotification : public CHandle<HANDLE, CPrinter>
|
|
{
|
|
typedef CHandle<HANDLE, CPrinter> 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<PTSTR>(pFileName),
|
|
&dwHandle
|
|
));
|
|
|
|
CCppMem<BYTE> VerInfo(dwVerInfoSize);
|
|
|
|
CHECK(::GetFileVersionInfo(
|
|
const_cast<PTSTR>(pFileName),
|
|
dwHandle,
|
|
dwVerInfoSize,
|
|
VerInfo
|
|
));
|
|
|
|
m_VerInfo = VerInfo;
|
|
}
|
|
|
|
PVOID
|
|
VerQueryValue(
|
|
PCTSTR pSubBlock
|
|
) const
|
|
{
|
|
PVOID pBuffer;
|
|
UINT uLen;
|
|
|
|
CHECK(::VerQueryValue(
|
|
m_VerInfo,
|
|
const_cast<PTSTR>(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<BYTE> 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 <class T>
|
|
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 <int nFirstId, int nLastId>
|
|
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 <int nFileNameLen = MAX_PATH, int nFileTitleSize = MAX_PATH, int nCustomFilterSize = MAX_PATH>
|
|
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 <int nPathNameLen = MAX_PATH>
|
|
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<HINF, CInf>
|
|
{
|
|
typedef CHandle<HINF, CInf> 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 prototype>
|
|
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<return_type (decl_spec *) args> \
|
|
{ \
|
|
public: \
|
|
typedef return_type (decl_spec *prototype) args; \
|
|
\
|
|
C##func_name() : \
|
|
CProc<prototype>(DefaultAPI) \
|
|
{ \
|
|
} \
|
|
\
|
|
C##func_name( \
|
|
HMODULE hModule, \
|
|
PCSTR pProcName = #func_name \
|
|
) : \
|
|
CProc<prototype>( \
|
|
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<TCHAR>
|
|
{
|
|
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<OCHAR> 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<HANDLE>
|
|
{
|
|
public:
|
|
CMultipleWait(
|
|
int nCount
|
|
) :
|
|
m_nCount(nCount),
|
|
CCppMem<HANDLE>(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_
|