mirror of
https://github.com/ladislav-zezula/FileTest
synced 2026-06-08 15:24:12 +00:00
2040 lines
64 KiB
C++
2040 lines
64 KiB
C++
/*****************************************************************************/
|
|
/* Utils.cpp Copyright (c) Ladislav Zezula 2004 */
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Description: */
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Date Ver Who Comment */
|
|
/* -------- ---- --- ------- */
|
|
/* 05.01.04 1.00 Lad The first version of Utils.cpp */
|
|
/*****************************************************************************/
|
|
|
|
#include "FileTest.h"
|
|
#include "resource.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// _tcstol replacement
|
|
|
|
static BYTE CharToValue[0x80] =
|
|
{
|
|
// 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
};
|
|
|
|
LPCTSTR HexaAlphabetUpper = _T("0123456789ABCDEF");
|
|
|
|
static bool IsPossibleFileId(LPCTSTR szFileName)
|
|
{
|
|
size_t nLength = _tcslen(szFileName);
|
|
|
|
// File ID has 15 characters, object ID has 32
|
|
if(nLength != 16 && nLength != 32)
|
|
return false;
|
|
|
|
// File ID can only contain hexadecimal letters
|
|
for(size_t i = 0; i < nLength; i++)
|
|
{
|
|
if(!isxdigit(szFileName[i]))
|
|
return false;
|
|
}
|
|
|
|
// All checks passed. It could be a file ID
|
|
return true;
|
|
}
|
|
|
|
static void ShowConversionError(HWND hWndParent, HWND hWndChild)
|
|
{
|
|
// Show the error to the user
|
|
MessageBoxRc(hWndParent, IDS_ERROR, IDS_E_CONVERT_VALUE);
|
|
|
|
// Select and focus the control
|
|
SendMessage(hWndChild, EM_SETSEL, 0, (LPARAM)-1);
|
|
SetFocus(hWndChild);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Converts the string to long. This function was written because
|
|
// the builtin strtol does not work correctly (try to convert 0xAABBCCDD !!!)
|
|
|
|
DWORD StrToInt(LPCTSTR szString, LPTSTR * szEnd, int nRadix)
|
|
{
|
|
DWORD nSaveValue = 0;
|
|
DWORD nValue = 0;
|
|
int nDigit;
|
|
|
|
while((nDigit = szString[0]) != 0)
|
|
{
|
|
// If the character is not an hexa number, break
|
|
if(nDigit > 0x80 || CharToValue[nDigit] == 0xFF)
|
|
break;
|
|
|
|
// Convert to digit
|
|
nDigit = CharToValue[nDigit];
|
|
if(nDigit > (nRadix - 1))
|
|
break;
|
|
|
|
// Move the value to the next rank and add the digit
|
|
nSaveValue = nValue;
|
|
nValue *= nRadix;
|
|
nValue += nDigit;
|
|
szString++;
|
|
|
|
// Overflow check
|
|
if(nValue < nSaveValue)
|
|
break;
|
|
}
|
|
|
|
if(szEnd != NULL)
|
|
*szEnd = (LPTSTR)szString;
|
|
return nValue;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// bool values support
|
|
|
|
DWORD Text2Bool(LPCTSTR szText, bool * pValue)
|
|
{
|
|
bool bNewValue = false;
|
|
|
|
if(_tcsicmp(szText, _T("true")))
|
|
bNewValue = true;
|
|
else if(_tcsicmp(szText, _T("on")))
|
|
bNewValue = true;
|
|
else if(_tcsicmp(szText, _T("1")))
|
|
bNewValue = true;
|
|
|
|
pValue[0] = bNewValue;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// 32-bit values support
|
|
|
|
LPCTSTR SkipHexaPrefix(LPCTSTR szString)
|
|
{
|
|
return (szString[0] == _T('0') && (szString[1] == _T('x') || szString[1] == _T('X'))) ? szString + 2 : szString;
|
|
}
|
|
|
|
DWORD Text2Hex32(LPCTSTR szText, PDWORD pValue)
|
|
{
|
|
DWORD Value = 0;
|
|
int nDigit;
|
|
|
|
// Skip the C-style hexa prefix, if any
|
|
szText = SkipHexaPrefix(szText);
|
|
|
|
// Convert the value
|
|
while((nDigit = *szText++) != 0)
|
|
{
|
|
// If the character is not a hexa number, break
|
|
if(nDigit > 0x80 || CharToValue[nDigit] == 0xFF)
|
|
return ERROR_BAD_FORMAT;
|
|
|
|
// Convert to digit
|
|
nDigit = CharToValue[nDigit];
|
|
|
|
// Overflow check
|
|
if(Value & 0xF0000000)
|
|
return ERROR_ARITHMETIC_OVERFLOW;
|
|
Value = (Value << 0x04) + nDigit;
|
|
}
|
|
|
|
// Give the value to the caller
|
|
*pValue = Value;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD DlgText2Hex32(HWND hDlg, UINT nIDCtrl, PDWORD pValue)
|
|
{
|
|
TCHAR szText[128];
|
|
HWND hWndChild = GetDlgItem(hDlg, nIDCtrl);
|
|
DWORD dwErrCode = ERROR_INVALID_PARAMETER;
|
|
|
|
// Perform the conversion of the child text to a 32-bit hexa value
|
|
if(hWndChild != NULL)
|
|
{
|
|
// Retrieve the window text
|
|
GetWindowText(hWndChild, szText, _countof(szText));
|
|
|
|
// Attempt to convert the value
|
|
dwErrCode = Text2Hex32(szText, pValue);
|
|
if(dwErrCode != ERROR_SUCCESS)
|
|
ShowConversionError(hDlg, hWndChild);
|
|
}
|
|
|
|
return dwErrCode;
|
|
}
|
|
|
|
void Hex2TextXX(ULONGLONG Value, LPTSTR szBuffer, size_t nSize)
|
|
{
|
|
// Get the number of hexa digits
|
|
nSize = nSize + nSize - 1;
|
|
|
|
// Convert the number to string
|
|
for(size_t i = 0; i <= nSize; i++)
|
|
{
|
|
szBuffer[nSize - i] = HexaAlphabetUpper[Value & 0x0F];
|
|
Value >>= 4;
|
|
}
|
|
|
|
// Terminate the string
|
|
szBuffer[nSize + 1] = 0;
|
|
}
|
|
|
|
void Hex2Text32(LPTSTR szBuffer, DWORD Value)
|
|
{
|
|
Hex2TextXX(Value, szBuffer, sizeof(DWORD));
|
|
}
|
|
|
|
void Hex2DlgText32(HWND hDlg, UINT nIDCtrl, DWORD Value)
|
|
{
|
|
TCHAR szText[128];
|
|
|
|
Hex2TextXX(Value, szText, sizeof(DWORD));
|
|
SetDlgItemText(hDlg, nIDCtrl, szText);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Pointer support
|
|
|
|
DWORD Text2HexPtr(LPCTSTR szText, PDWORD_PTR pValue)
|
|
{
|
|
DWORD_PTR ValueMask = ((DWORD_PTR)0x0F << ((sizeof(DWORD_PTR) * 8) - 4));
|
|
DWORD_PTR Value = 0;
|
|
int nDigit;
|
|
|
|
// Skip the C-style hexa prefix, if any
|
|
szText = SkipHexaPrefix(szText);
|
|
|
|
// Convert the value
|
|
while((nDigit = *szText++) != 0)
|
|
{
|
|
// If the character is not a hexa number, break
|
|
if(nDigit > 0x80 || CharToValue[nDigit] == 0xFF)
|
|
return ERROR_BAD_FORMAT;
|
|
|
|
// Convert to digit
|
|
nDigit = CharToValue[nDigit];
|
|
|
|
// Overflow check
|
|
if(Value & ValueMask)
|
|
return ERROR_ARITHMETIC_OVERFLOW;
|
|
Value = (Value << 0x04) + nDigit;
|
|
|
|
}
|
|
|
|
// Give the value to the caller
|
|
*pValue = Value;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD DlgText2HexPtr(HWND hDlg, UINT nIDCtrl, PDWORD_PTR pValue)
|
|
{
|
|
TCHAR szText[128];
|
|
HWND hWndChild = GetDlgItem(hDlg, nIDCtrl);
|
|
DWORD dwErrCode = ERROR_INVALID_PARAMETER;
|
|
|
|
// Perform the conversion of the child text to a 32-bit hexa value
|
|
if(hWndChild != NULL)
|
|
{
|
|
// Retrieve the window text
|
|
GetWindowText(hWndChild, szText, _countof(szText));
|
|
|
|
// Attempt to convert the value
|
|
dwErrCode = Text2HexPtr(szText, pValue);
|
|
if(dwErrCode != ERROR_SUCCESS)
|
|
ShowConversionError(hDlg, hWndChild);
|
|
}
|
|
|
|
return dwErrCode;
|
|
}
|
|
|
|
void Hex2TextPtr(LPTSTR szBuffer, DWORD_PTR Value)
|
|
{
|
|
Hex2TextXX(Value, szBuffer, sizeof(DWORD_PTR));
|
|
}
|
|
|
|
void Hex2DlgTextPtr(HWND hDlg, UINT nIDCtrl, DWORD_PTR Value)
|
|
{
|
|
TCHAR szText[128];
|
|
|
|
Hex2TextXX(Value, szText, sizeof(DWORD_PTR));
|
|
SetDlgItemText(hDlg, nIDCtrl, szText);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// 64-bit values support
|
|
|
|
DWORD Text2Hex64(LPCTSTR szText, PLONGLONG pValue)
|
|
{
|
|
ULONGLONG SaveValue = 0;
|
|
ULONGLONG Value = 0;
|
|
int nDigit;
|
|
|
|
// Skip the C-style hexa prefix, if any
|
|
szText = SkipHexaPrefix(szText);
|
|
|
|
// Convert the value
|
|
while((nDigit = *szText++) != 0)
|
|
{
|
|
// If the character is not a hexa number, break
|
|
if(nDigit > 0x80 || CharToValue[nDigit] == 0xFF)
|
|
return ERROR_BAD_FORMAT;
|
|
|
|
// Convert to digit
|
|
nDigit = CharToValue[nDigit];
|
|
|
|
// Move the value to the next rank and add the digit
|
|
SaveValue = Value;
|
|
Value = (Value << 0x04) + nDigit;
|
|
|
|
// Overflow check
|
|
if(Value < SaveValue)
|
|
return ERROR_ARITHMETIC_OVERFLOW;
|
|
}
|
|
|
|
// Give the value to the caller
|
|
*pValue = Value;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD DlgText2Hex64(HWND hDlg, UINT nIDCtrl, PLONGLONG pValue)
|
|
{
|
|
TCHAR szText[128];
|
|
HWND hWndChild = GetDlgItem(hDlg, nIDCtrl);
|
|
DWORD dwErrCode = ERROR_INVALID_PARAMETER;
|
|
|
|
// Perform the conversion of the child text to a 32-bit hexa value
|
|
if(hWndChild != NULL)
|
|
{
|
|
// Retrieve the window text
|
|
GetWindowText(hWndChild, szText, _countof(szText));
|
|
|
|
// Attempt to convert the value
|
|
dwErrCode = Text2Hex64(szText, pValue);
|
|
if(dwErrCode != ERROR_SUCCESS)
|
|
ShowConversionError(hDlg, hWndChild);
|
|
}
|
|
|
|
return dwErrCode;
|
|
}
|
|
|
|
void Hex2Text64(LPTSTR szBuffer, LONGLONG Value)
|
|
{
|
|
Hex2TextXX(Value, szBuffer, sizeof(LONGLONG));
|
|
}
|
|
|
|
void Hex2DlgText64(HWND hDlg, UINT nIDCtrl, LONGLONG Value)
|
|
{
|
|
TCHAR szText[128];
|
|
|
|
Hex2TextXX(Value, szText, sizeof(LONGLONG));
|
|
SetDlgItemText(hDlg, nIDCtrl, szText);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Clipboard manipulation
|
|
|
|
HGLOBAL Clipboard_AddText(HGLOBAL hMemory, LPCTSTR szText)
|
|
{
|
|
LPBYTE pbClipboard;
|
|
size_t cbTotalSize;
|
|
size_t cbPrevSize = 0;
|
|
size_t cbAddSize = _tcslen(szText) * sizeof(TCHAR);
|
|
|
|
// If we don't have any previousle allocated memory, then allocate new block
|
|
if(hMemory == NULL)
|
|
{
|
|
// Allocate text plus EOS
|
|
cbTotalSize = cbAddSize + sizeof(WCHAR);
|
|
hMemory = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, cbTotalSize);
|
|
}
|
|
else
|
|
{
|
|
// Find out the previous size of the memory
|
|
cbPrevSize = GlobalSize(hMemory);
|
|
cbTotalSize = cbPrevSize + cbAddSize;
|
|
hMemory = GlobalReAlloc(hMemory, cbTotalSize, GMEM_MOVEABLE | GMEM_ZEROINIT);
|
|
|
|
// Subtract the end-of-string
|
|
cbPrevSize -= sizeof(TCHAR);
|
|
}
|
|
|
|
// Now if we have a memory allocated, append the text there
|
|
if(hMemory != NULL)
|
|
{
|
|
pbClipboard = (LPBYTE)GlobalLock(hMemory);
|
|
if(pbClipboard != NULL)
|
|
{
|
|
memcpy(pbClipboard + cbPrevSize, szText, cbAddSize);
|
|
GlobalUnlock(hMemory);
|
|
}
|
|
}
|
|
|
|
// Return the allocated memory
|
|
return hMemory;
|
|
}
|
|
|
|
bool Clipboard_Finish(HWND hWnd, HGLOBAL hMemory)
|
|
{
|
|
if(hMemory != NULL)
|
|
{
|
|
// Insert text to the clipboard
|
|
if(OpenClipboard(hWnd))
|
|
{
|
|
EmptyClipboard();
|
|
SetClipboardData(CF_UNICODETEXT, hMemory);
|
|
CloseClipboard();
|
|
return true;
|
|
}
|
|
|
|
// If the opening clipboard failed, free the memory
|
|
GlobalFree(hMemory);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Path manipulation
|
|
|
|
LPTSTR FindDirectoryPathPart(LPTSTR szFullPath)
|
|
{
|
|
LPTSTR szPathPart = szFullPath;
|
|
|
|
// Skip the initial complicated parts
|
|
// \\.\GlobalRoot\Device\Mup\Dir1\Dir2
|
|
// \\.\Device\Mup\Dir1\Dir2
|
|
while(szPathPart[0] != 0 && !isalpha(szPathPart[0]))
|
|
szPathPart++;
|
|
|
|
// If found, search fuhrter for well-known path parts
|
|
if(szPathPart[0] != 0)
|
|
{
|
|
// Is it "GlobalRoot" ?
|
|
if(!_tcsnicmp(szPathPart, _T("GlobalRoot\\"), 11))
|
|
szPathPart += 11;
|
|
if(!_tcsnicmp(szPathPart, _T("Device\\"), 7))
|
|
szPathPart += 11;
|
|
|
|
// Skip the Drive letter, if present
|
|
if(isalpha(szPathPart[0]) && szPathPart[1] == _T(':'))
|
|
szPathPart += 2;
|
|
|
|
// Skip slashes and backslashes
|
|
while(szPathPart[0] == _T('\\') || szPathPart[0] == _T('/'))
|
|
szPathPart++;
|
|
|
|
// Return what we got
|
|
return szPathPart;
|
|
}
|
|
|
|
// Not recognized, return NULL
|
|
return NULL;
|
|
}
|
|
|
|
LPTSTR FindNextPathSeparator(LPTSTR szPathPart)
|
|
{
|
|
// Skip slashes and backslashes
|
|
while(szPathPart[0] == _T('\\') || szPathPart[0] == _T('/'))
|
|
szPathPart++;
|
|
|
|
// Find next slash, backslash or end of string
|
|
while(szPathPart[0] != 0 && szPathPart[0] != _T('\\') && szPathPart[0] != _T('/'))
|
|
szPathPart++;
|
|
|
|
return szPathPart;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Other
|
|
|
|
// Calculates the necessary length of PFILE_FULL_EA_INFORMATION structure
|
|
ULONG GetEaEntrySize(PFILE_FULL_EA_INFORMATION EaInfo)
|
|
{
|
|
ULONG EntrySize = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]);
|
|
|
|
//
|
|
// The length of the item must be calculated very exactly.
|
|
// No additional bytes (except for default alignment of
|
|
// FILE_FULL_EA_INFORMATION structure) is allowed.
|
|
//
|
|
|
|
EntrySize += EaInfo->EaNameLength + 1; // Add the name length plus the ending zero character
|
|
EntrySize += EaInfo->EaValueLength; // Add the data length
|
|
EntrySize = ALIGN_INT32(EntrySize); // Align to 4-byte boundary
|
|
|
|
return EntrySize;
|
|
}
|
|
|
|
void TreeView_SetItemText(HWND hWndTree, HTREEITEM hItem, LPCTSTR szText)
|
|
{
|
|
TVITEM tvi = {TVIF_TEXT, hItem};
|
|
|
|
tvi.pszText = (LPTSTR)(szText);
|
|
TreeView_SetItem(hWndTree, &tvi);
|
|
}
|
|
|
|
DWORD TreeView_GetChildCount(HWND hWndTree, HTREEITEM hItem)
|
|
{
|
|
DWORD dwChildCount = 0;
|
|
|
|
// If both TreeView and item handle are valid
|
|
if(hWndTree != NULL && hItem != NULL)
|
|
{
|
|
// Count all children
|
|
hItem = TreeView_GetChild(hWndTree, hItem);
|
|
while(hItem != NULL)
|
|
{
|
|
dwChildCount++;
|
|
hItem = TreeView_GetNextSibling(hWndTree, hItem);
|
|
}
|
|
}
|
|
|
|
return dwChildCount;
|
|
}
|
|
|
|
LPARAM TreeView_GetItemParam(HWND hWndTree, HTREEITEM hItem)
|
|
{
|
|
TVITEM tvi;
|
|
|
|
// Retrieve the item param
|
|
tvi.mask = TVIF_PARAM;
|
|
tvi.hItem = hItem;
|
|
tvi.lParam = 0;
|
|
TreeView_GetItem(hWndTree, &tvi);
|
|
|
|
// Return the parameter
|
|
return tvi.lParam;
|
|
}
|
|
|
|
void TreeView_SetItemParam(HWND hWndTree, HTREEITEM hItem, LPARAM lParam)
|
|
{
|
|
TVITEM tvi = {TVIF_PARAM};
|
|
|
|
// Set the new item param
|
|
tvi.hItem = hItem;
|
|
tvi.lParam = lParam;
|
|
TreeView_SetItem(hWndTree, &tvi);
|
|
}
|
|
|
|
HTREEITEM TreeView_SetTreeItem(HWND hWndTree, HTREEITEM hItem, LPCTSTR szText, LPARAM lParam)
|
|
{
|
|
TVITEM tvi = {TVIF_TEXT | TVIF_PARAM};
|
|
|
|
// Prepare the TVITEM structure
|
|
tvi.hItem = hItem;
|
|
tvi.lParam = lParam;
|
|
tvi.pszText = (LPTSTR)szText;
|
|
|
|
// Set the text¶m to the tree item
|
|
return TreeView_SetItem(hWndTree, &tvi) ? hItem : NULL;
|
|
}
|
|
|
|
BOOL TreeView_EditLabel_ID(HWND hDlg, UINT nID)
|
|
{
|
|
HTREEITEM hItem = NULL;
|
|
HWND hWndTree = GetDlgItem(hDlg, nID);
|
|
BOOL bResult = FALSE;
|
|
|
|
// Only start editing if the proper tree view has focus
|
|
if(GetFocus() == hWndTree)
|
|
{
|
|
hItem = TreeView_GetSelection(hWndTree);
|
|
if(hItem != NULL)
|
|
{
|
|
TreeView_EditLabel(hWndTree, hItem);
|
|
bResult = TRUE;
|
|
}
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
HTREEITEM InsertTreeItem(HWND hWndTree, HTREEITEM hParent, HTREEITEM hInsertAfter, LPCTSTR szText, PVOID pParam)
|
|
{
|
|
TVINSERTSTRUCT tvis;
|
|
|
|
// Insert the item to the tree
|
|
tvis.hParent = (hParent != NULL) ? hParent : TVI_ROOT;
|
|
tvis.hInsertAfter = (hInsertAfter != NULL) ? hInsertAfter : TVI_LAST;
|
|
tvis.item.mask = TVIF_TEXT | TVIF_PARAM;
|
|
tvis.item.pszText = (LPTSTR)szText;
|
|
tvis.item.lParam = (LPARAM)pParam;
|
|
return TreeView_InsertItem(hWndTree, &tvis);
|
|
}
|
|
|
|
HTREEITEM InsertTreeItem(HWND hWndTree, HTREEITEM hParent, LPCTSTR szText, PVOID pParam)
|
|
{
|
|
return InsertTreeItem(hWndTree, hParent, NULL, szText, pParam);
|
|
}
|
|
|
|
HTREEITEM InsertTreeItem(HWND hWndTree, HTREEITEM hParent, LPCTSTR szText, LPARAM lParam)
|
|
{
|
|
return InsertTreeItem(hWndTree, hParent, TVI_LAST, szText, (PVOID)lParam);
|
|
}
|
|
|
|
HTREEITEM InsertTreeItem(HWND hWndTree, HTREEITEM hParent, LPARAM lParam, UINT nID, ...)
|
|
{
|
|
va_list argList;
|
|
TCHAR szItemText[512];
|
|
|
|
// Format the text
|
|
va_start(argList, nID);
|
|
rsvprintf(szItemText, _countof(szItemText), nID, argList);
|
|
va_end(argList);
|
|
|
|
// Insert the item text
|
|
return InsertTreeItem(hWndTree, hParent, TVI_LAST, szItemText, (PVOID)lParam);
|
|
}
|
|
|
|
void TreeView_DeleteChildren(HWND hWndTree, HTREEITEM hParent)
|
|
{
|
|
HTREEITEM hItem;
|
|
|
|
// Remove all children, if any
|
|
while((hItem = TreeView_GetChild(hWndTree, hParent)) != NULL)
|
|
TreeView_DeleteItem(hWndTree, hItem);
|
|
}
|
|
|
|
HGLOBAL TreeView_CopyToClipboard(HWND hWndTree, HTREEITEM hItem, HGLOBAL hGlobal, size_t nLevel)
|
|
{
|
|
HTREEITEM hChild;
|
|
TVITEMEX tvi;
|
|
LPTSTR szText;
|
|
LPTSTR szEnd;
|
|
TCHAR szBuffer[0x400] = _T("");
|
|
size_t i;
|
|
|
|
// Prepare the item
|
|
ZeroMemory(&tvi, sizeof(TVITEM));
|
|
tvi.mask = TVIF_TEXT;
|
|
|
|
// Create the indent string
|
|
for(i = 0; i < nLevel * 4; i++)
|
|
szBuffer[i] = ' ';
|
|
szBuffer[i] = 0;
|
|
|
|
// Set the range for text
|
|
szText = szBuffer + (nLevel * 4);
|
|
szEnd = szBuffer + _countof(szBuffer);
|
|
|
|
// Get all siblings
|
|
while(hItem != NULL)
|
|
{
|
|
// Get the item text
|
|
memset(szText, 0, (szEnd - szText) * sizeof(TCHAR));
|
|
tvi.hItem = hItem;
|
|
tvi.pszText = szText;
|
|
tvi.cchTextMax = (int)(szEnd - szText);
|
|
TreeView_GetItem(hWndTree, &tvi);
|
|
StringCchCat(szBuffer, _countof(szBuffer), _T("\r\n"));
|
|
|
|
// Insert the indent
|
|
hGlobal = Clipboard_AddText(hGlobal, szBuffer);
|
|
|
|
// Are there any children?
|
|
if((hChild = TreeView_GetChild(hWndTree, hItem)) != NULL)
|
|
{
|
|
hGlobal = TreeView_CopyToClipboard(hWndTree, hChild, hGlobal, nLevel + 1);
|
|
}
|
|
|
|
// Get the next sibling
|
|
if(nLevel == 0)
|
|
break;
|
|
hItem = TreeView_GetNextSibling(hWndTree, hItem);
|
|
}
|
|
|
|
return hGlobal;
|
|
}
|
|
|
|
void TreeView_CopyToClipboard(HWND hWndTree)
|
|
{
|
|
HGLOBAL hGlobal = NULL;
|
|
|
|
hGlobal = TreeView_CopyToClipboard(hWndTree, TreeView_GetSelection(hWndTree), hGlobal, 0);
|
|
Clipboard_Finish(hWndTree, hGlobal);
|
|
}
|
|
|
|
int OnTVKeyDown_CopyToClipboard(HWND /* hDlg */, LPNMTVKEYDOWN pNMTVKeyDown)
|
|
{
|
|
// On Ctrl+C, copy the text to clipboard
|
|
if(pNMTVKeyDown->wVKey == 'C' && GetAsyncKeyState(VK_CONTROL) < 0)
|
|
{
|
|
TreeView_CopyToClipboard(pNMTVKeyDown->hdr.hwndFrom);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Token operations
|
|
|
|
HANDLE OpenCurrentToken(DWORD dwDesiredAccess)
|
|
{
|
|
HANDLE hToken = NULL;
|
|
|
|
// Open process or thread token
|
|
if(!OpenThreadToken(GetCurrentThread(), dwDesiredAccess, TRUE, &hToken))
|
|
{
|
|
if(GetLastError() == ERROR_NO_TOKEN)
|
|
OpenProcessToken(GetCurrentProcess(), dwDesiredAccess, &hToken);
|
|
}
|
|
return hToken;
|
|
}
|
|
|
|
BOOL GetTokenElevation(PBOOL pbElevated)
|
|
{
|
|
TOKEN_ELEVATION Elevation;
|
|
HANDLE hToken;
|
|
DWORD dwLength = 0;
|
|
DWORD dwValue = 0;
|
|
BOOL bResult = FALSE;
|
|
|
|
if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
|
|
{
|
|
// Step1: Query the elevation type
|
|
bResult = GetTokenInformation(hToken, TokenElevationType, &dwValue, sizeof(dwValue), &dwLength);
|
|
if(bResult)
|
|
{
|
|
switch((TOKEN_ELEVATION_TYPE)dwValue)
|
|
{
|
|
case TokenElevationTypeDefault:
|
|
bResult = GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &dwLength);
|
|
if(bResult)
|
|
pbElevated[0] = Elevation.TokenIsElevated ? TRUE : FALSE;
|
|
break;
|
|
|
|
case TokenElevationTypeFull:
|
|
pbElevated[0] = TRUE;
|
|
break;
|
|
|
|
case TokenElevationTypeLimited:
|
|
pbElevated[0] = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL GetTokenVirtualizationEnabled(PBOOL pbEnabled)
|
|
{
|
|
HANDLE hToken;
|
|
DWORD dwEnabled = 0;
|
|
DWORD dwLength = 0;
|
|
BOOL bResult = FALSE;
|
|
|
|
if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
|
|
{
|
|
bResult = GetTokenInformation(hToken, TokenVirtualizationEnabled, &dwEnabled, sizeof(dwEnabled), &dwLength);
|
|
if(bResult && pbEnabled)
|
|
pbEnabled[0] = dwEnabled ? TRUE : FALSE;
|
|
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL SetTokenVirtualizationEnabled(BOOL bEnabled)
|
|
{
|
|
HANDLE hToken;
|
|
DWORD dwEnabled = bEnabled;
|
|
BOOL bResult = FALSE;
|
|
|
|
if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_DEFAULT, &hToken))
|
|
{
|
|
bResult = SetTokenInformation(hToken,
|
|
TokenVirtualizationEnabled,
|
|
&dwEnabled,
|
|
sizeof(dwEnabled));
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Set result status
|
|
|
|
static void DeleteBlinkTimer(HWND hDlg)
|
|
{
|
|
TFileTestData * pData = GetDialogData(hDlg);
|
|
|
|
// If there is already a blinker timer, destroy it
|
|
if(pData->BlinkTimer != 0)
|
|
KillTimer(hDlg, pData->BlinkTimer);
|
|
pData->BlinkTimer = 0;
|
|
|
|
// If there is a blink window already, destroy it
|
|
if(pData->hWndBlink != NULL)
|
|
DestroyWindow(pData->hWndBlink);
|
|
pData->hWndBlink = NULL;
|
|
}
|
|
|
|
static VOID CALLBACK BlinkTimerProc(HWND hDlg, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
|
|
{
|
|
UNREFERENCED_PARAMETER(dwTime);
|
|
UNREFERENCED_PARAMETER(uMsg);
|
|
|
|
if(idEvent == WM_TIMER_BLINK)
|
|
{
|
|
DeleteBlinkTimer(hDlg);
|
|
}
|
|
}
|
|
|
|
HWND AttachIconToEdit(HWND hDlg, HWND hWndChild, LPTSTR szIDIcon)
|
|
{
|
|
HINSTANCE hInst = g_hInst;
|
|
HICON hIcon;
|
|
POINT pt;
|
|
HWND hWndBlink = NULL;
|
|
RECT rect;
|
|
int cx = 16; // GetSystemMetrics(SM_CXSMICON);
|
|
int cy = 16; // GetSystemMetrics(SM_CYSMICON);
|
|
|
|
// Load OEM icons if it's their ID
|
|
if(IDI_APPLICATION <= szIDIcon && szIDIcon <= IDI_SHIELD)
|
|
hInst = NULL;
|
|
|
|
// Load the icon, 16x16
|
|
hIcon = (HICON)LoadImage(hInst, szIDIcon, IMAGE_ICON, cx, cy, LR_SHARED);
|
|
if(hIcon != NULL)
|
|
{
|
|
// Get the position of the edit box window
|
|
GetWindowRect(hWndChild, &rect);
|
|
pt.x = rect.left;
|
|
pt.y = rect.top;
|
|
ScreenToClient(hDlg, &pt);
|
|
pt.x = pt.x - cx - 4;
|
|
pt.y = pt.y + (rect.bottom - rect.top - cx) / 2;
|
|
|
|
// Create the window for icon
|
|
hWndBlink = CreateWindowEx(WS_EX_NOPARENTNOTIFY,
|
|
WC_STATIC,
|
|
NULL,
|
|
WS_CHILD | WS_VISIBLE | SS_ICON,
|
|
pt.x, pt.y, cx, cx,
|
|
hDlg,
|
|
NULL,
|
|
g_hInst,
|
|
NULL);
|
|
if(hWndBlink != NULL)
|
|
{
|
|
// Apply the icon to the icon window
|
|
SendMessage(hWndBlink, STM_SETICON, (WPARAM)hIcon, 0);
|
|
}
|
|
}
|
|
|
|
return hWndBlink;
|
|
}
|
|
|
|
static void CreateBlinkingIcon(HWND hDlg, HWND hWndChild, int nSeverity)
|
|
{
|
|
TFileTestData * pData = GetDialogData(hDlg);
|
|
// LPTSTR IconSet[] = { IDI_INFORMATION, IDI_ERROR, MAKEINTRESOURCE(IDI_ICON_WAIT)};
|
|
HWND hWndBlink;
|
|
UINT IconSet[] = {IDI_ICON_INFORMATION, IDI_ICON_ERROR, IDI_ICON_WAIT};
|
|
|
|
// If there is already a blinker timer, destroy it
|
|
DeleteBlinkTimer(hDlg);
|
|
|
|
// Create the icon, left-attached to the edit field
|
|
// Note that I tried the system icons, but they look like shit
|
|
// when reduced to small icon.
|
|
hWndBlink = AttachIconToEdit(hDlg, hWndChild, MAKEINTRESOURCE(IconSet[nSeverity]));
|
|
|
|
// Create timer for hiding the window
|
|
pData->BlinkTimer = SetTimer(hDlg, WM_TIMER_BLINK, 800, BlinkTimerProc);
|
|
pData->hWndBlink = hWndBlink;
|
|
}
|
|
|
|
void SetWindowEnumText(HWND hWndChild, LPCTSTR TextArray[], size_t nArraySize, size_t nIndex)
|
|
{
|
|
LPCTSTR szTextToSet = _T("");
|
|
|
|
// Sanity check
|
|
assert(hWndChild != NULL);
|
|
|
|
// Get the proper text message
|
|
if(nIndex < nArraySize)
|
|
szTextToSet = TextArray[nIndex];
|
|
|
|
// Set the text message
|
|
SetWindowText(hWndChild, szTextToSet);
|
|
}
|
|
|
|
int GetLastErrorSeverity(DWORD dwErrCode)
|
|
{
|
|
switch(dwErrCode)
|
|
{
|
|
case ERROR_SUCCESS:
|
|
return SEVERITY_SUCCESS;
|
|
|
|
case ERROR_IO_PENDING:
|
|
return SEVERITY_PENDING;
|
|
|
|
default:
|
|
return SEVERITY_ERROR;
|
|
}
|
|
}
|
|
|
|
void SetResultInfo(HWND hDlg, DWORD dwFlags, ...)
|
|
{
|
|
TCHAR szText[256];
|
|
HWND hWndChild;
|
|
va_list argList;
|
|
|
|
// Start the argument list
|
|
va_start(argList, dwFlags);
|
|
|
|
//
|
|
// 1) RSI_LAST_ERROR: DWORD dwErrCode
|
|
//
|
|
|
|
if(dwFlags & RSI_LAST_ERROR)
|
|
{
|
|
LPTSTR szError;
|
|
DWORD dwErrCode = va_arg(argList, DWORD);
|
|
|
|
// Set the title
|
|
if((hWndChild = GetDlgItem(hDlg, IDC_ERROR_CODE_TITLE)) != NULL)
|
|
SetWindowText(hWndChild, _T("GetLastError:"));
|
|
|
|
// Set the error text and the blinking icon
|
|
if((hWndChild = GetDlgItem(hDlg, IDC_ERROR_CODE)) != NULL)
|
|
{
|
|
// Create the error text (code + text)
|
|
szError = GetErrorText(dwErrCode);
|
|
if(szError != NULL)
|
|
{
|
|
StringCchPrintf(szText, _countof(szText), _T("(0x%08lX) %s"), dwErrCode, szError);
|
|
SetWindowText(hWndChild, szText);
|
|
delete [] szError;
|
|
}
|
|
|
|
// Create the blinking icon
|
|
CreateBlinkingIcon(hDlg, hWndChild, GetLastErrorSeverity(dwErrCode));
|
|
}
|
|
}
|
|
|
|
//
|
|
// 2) RSI_NTSTATUS: NTSTATUS Status
|
|
//
|
|
|
|
if(dwFlags & RSI_NTSTATUS)
|
|
{
|
|
LPCTSTR szStatus;
|
|
NTSTATUS Status = va_arg(argList, NTSTATUS);
|
|
int nSeverity;
|
|
|
|
// Set the title
|
|
if((hWndChild = GetDlgItem(hDlg, IDC_ERROR_CODE_TITLE)) != NULL)
|
|
SetWindowText(hWndChild, _T("Status:"));
|
|
|
|
// Set the error text and the blinking icon
|
|
if((hWndChild = GetDlgItem(hDlg, IDC_ERROR_CODE)) != NULL)
|
|
{
|
|
switch(Status)
|
|
{
|
|
case STATUS_PENDING:
|
|
szStatus = NtStatus2Text(Status);
|
|
nSeverity = SEVERITY_PENDING;
|
|
break;
|
|
|
|
case STATUS_INVALID_DATA_FORMAT:
|
|
szStatus = _T("The entered value has bad format.");
|
|
nSeverity = SEVERITY_ERROR;
|
|
break;
|
|
|
|
case STATUS_AUTO_CALCULATED:
|
|
szStatus = _T("This item is auto-calculated.");
|
|
nSeverity = SEVERITY_ERROR;
|
|
break;
|
|
|
|
case STATUS_CANNOT_EDIT_THIS:
|
|
szStatus = _T("This item is not editable.");
|
|
nSeverity = SEVERITY_ERROR;
|
|
break;
|
|
|
|
case STATUS_FILE_ID_CONVERSION:
|
|
szStatus = _T("Skipped conversion of File ID to an NT name.");
|
|
nSeverity = SEVERITY_SUCCESS;
|
|
break;
|
|
|
|
case STATUS_COPIED_TO_CLIPBOARD:
|
|
szStatus = _T("Item value copied to clipboard.");
|
|
nSeverity = SEVERITY_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
szStatus = NtStatus2Text(Status);
|
|
nSeverity = NT_SUCCESS(Status) ? SEVERITY_SUCCESS : SEVERITY_ERROR;
|
|
break;
|
|
}
|
|
|
|
// Set the status text and blinking icon
|
|
SetWindowText(hWndChild, szStatus);
|
|
CreateBlinkingIcon(hDlg, hWndChild, nSeverity);
|
|
}
|
|
}
|
|
|
|
//
|
|
// 3) RSI_HANDLE: HANDLE hHandle
|
|
//
|
|
|
|
if(dwFlags & RSI_HANDLE)
|
|
{
|
|
HANDLE hHandle = va_arg(argList, HANDLE);
|
|
BOOL bEnable = TRUE;
|
|
|
|
// Enable/disable the hint for close handle, if any
|
|
if((hWndChild = GetDlgItem(hDlg, IDC_CLOSE_HANDLE_HINT)) != NULL)
|
|
{
|
|
if(IsHandleInvalid(hHandle))
|
|
bEnable = FALSE;
|
|
EnableWindow(hWndChild, bEnable);
|
|
}
|
|
|
|
// Enable/disable the "CloseHandle" button, if present
|
|
if((hWndChild = GetDlgItem(hDlg, IDC_CLOSE_HANDLE)) != NULL)
|
|
{
|
|
if(IsHandleInvalid(hHandle))
|
|
bEnable = FALSE;
|
|
EnableWindow(hWndChild, bEnable);
|
|
}
|
|
|
|
// Set the handle value
|
|
if((hWndChild = GetDlgItem(hDlg, IDC_HANDLE)) != NULL)
|
|
{
|
|
if(hHandle == INVALID_HANDLE_VALUE)
|
|
SetWindowText(hWndChild, _T("INVALID_HANDLE_VALUE"));
|
|
else if(hHandle == NULL)
|
|
SetWindowText(hWndChild, _T("NULL"));
|
|
else
|
|
Hex2DlgTextPtr(hDlg, IDC_HANDLE, (DWORD_PTR)hHandle);
|
|
}
|
|
}
|
|
|
|
//
|
|
// 4) RSI_NOINFO: Set the info field to empty
|
|
//
|
|
|
|
if(dwFlags & RSI_NOINFO)
|
|
{
|
|
// Set the title
|
|
if((hWndChild = GetDlgItem(hDlg, IDC_INFORMATION_TITLE)) != NULL)
|
|
SetWindowText(hWndChild, _T("Result:"));
|
|
SetDlgItemText(hDlg, IDC_INFORMATION, _T(""));
|
|
}
|
|
|
|
//
|
|
// 5) RSI_INFORMATION: PIO_STATUS_BLOCK IoStatus
|
|
//
|
|
|
|
if(dwFlags & RSI_INFORMATION)
|
|
{
|
|
PIO_STATUS_BLOCK IoStatus = va_arg(argList, PIO_STATUS_BLOCK);
|
|
|
|
// Set the title
|
|
if((hWndChild = GetDlgItem(hDlg, IDC_INFORMATION_TITLE)) != NULL)
|
|
SetWindowText(hWndChild, _T("IoStatus.Info:"));
|
|
Hex2DlgTextPtr(hDlg, IDC_INFORMATION, IoStatus->Information);
|
|
}
|
|
|
|
//
|
|
// 6) RSI_INFO_INT32: DWORD dwInfo
|
|
//
|
|
|
|
if(dwFlags & RSI_INFO_INT32)
|
|
{
|
|
DWORD dwInfo = va_arg(argList, DWORD);
|
|
|
|
// Set the title
|
|
if((hWndChild = GetDlgItem(hDlg, IDC_INFORMATION_TITLE)) != NULL)
|
|
SetWindowText(hWndChild, _T("Length:"));
|
|
Hex2DlgText32(hDlg, IDC_INFORMATION, dwInfo);
|
|
}
|
|
|
|
//
|
|
// 7) RSI_NTCREATE: PIO_STATUS_BLOCK IoStatus (result of NtCreateFile)
|
|
//
|
|
|
|
if(dwFlags & RSI_NTCREATE)
|
|
{
|
|
PIO_STATUS_BLOCK IoStatus = va_arg(argList, PIO_STATUS_BLOCK);
|
|
|
|
if((hWndChild = GetDlgItem(hDlg, IDC_INFORMATION)) != NULL)
|
|
{
|
|
LPCTSTR szNtCreateResult[] =
|
|
{
|
|
_T("FILE_SUPERSEDED"),
|
|
_T("FILE_OPENED"),
|
|
_T("FILE_CREATED"),
|
|
_T("FILE_OVERWRITTEN"),
|
|
_T("FILE_EXISTS"),
|
|
_T("FILE_DOES_NOT_EXIST"),
|
|
_T("0x00000006"),
|
|
_T("FILE_OPLOCK_BROKEN_TO_LEVEL_2"),
|
|
_T("FILE_OPLOCK_BROKEN_TO_NONE"),
|
|
_T("FILE_OPBATCH_BREAK_UNDERWAY")
|
|
};
|
|
|
|
SetWindowEnumText(hWndChild, szNtCreateResult, _countof(szNtCreateResult), IoStatus->Information);
|
|
}
|
|
}
|
|
|
|
//
|
|
// 8) RSI_READ: DWORD dwBytesRead
|
|
//
|
|
|
|
if(dwFlags & RSI_READ)
|
|
{
|
|
DWORD dwBytesRead = va_arg(argList, DWORD);
|
|
|
|
// Set the title text
|
|
if((hWndChild = GetDlgItem(hDlg, IDC_INFORMATION_TITLE)) != NULL)
|
|
{
|
|
SetWindowText(hWndChild, _T("Bytes Read:"));
|
|
}
|
|
|
|
// Set the value
|
|
Hex2DlgText32(hDlg, IDC_INFORMATION, dwBytesRead);
|
|
}
|
|
|
|
//
|
|
// 9) RSI_WRITTEN: DWORD dwBytesWritten
|
|
//
|
|
|
|
if(dwFlags & RSI_WRITTEN)
|
|
{
|
|
DWORD dwBytesWritten = va_arg(argList, DWORD);
|
|
|
|
// Set the title text
|
|
if((hWndChild = GetDlgItem(hDlg, IDC_INFORMATION_TITLE)) != NULL)
|
|
{
|
|
SetWindowText(hWndChild, _T("Bytes Written:"));
|
|
}
|
|
|
|
// Set the value
|
|
Hex2DlgText32(hDlg, IDC_INFORMATION, dwBytesWritten);
|
|
}
|
|
|
|
//
|
|
// 10) RSI_FILESIZE: PLARGE_INTEGER pFileSize
|
|
//
|
|
|
|
if(dwFlags & RSI_FILESIZE)
|
|
{
|
|
PLARGE_INTEGER pFileSize = va_arg(argList, PLARGE_INTEGER);
|
|
|
|
// Set the title text
|
|
if((hWndChild = GetDlgItem(hDlg, IDC_INFORMATION_TITLE)) != NULL)
|
|
{
|
|
SetWindowText(hWndChild, _T("File Size:"));
|
|
}
|
|
|
|
// Set the value
|
|
Hex2DlgText64(hDlg, IDC_INFORMATION, pFileSize->QuadPart);
|
|
}
|
|
|
|
//
|
|
// 11) RSI_FILEPOS: PLARGE_INTEGER pFilePos
|
|
//
|
|
|
|
if(dwFlags & RSI_FILEPOS)
|
|
{
|
|
PLARGE_INTEGER pFilePos = va_arg(argList, PLARGE_INTEGER);
|
|
|
|
// Set the title text
|
|
if((hWndChild = GetDlgItem(hDlg, IDC_INFORMATION_TITLE)) != NULL)
|
|
{
|
|
SetWindowText(hWndChild, _T("File Pos:"));
|
|
}
|
|
|
|
// Set the value
|
|
Hex2DlgText64(hDlg, IDC_INFORMATION, pFilePos->QuadPart);
|
|
}
|
|
|
|
// End the arguments
|
|
va_end(argList);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Dynamic loaded APIs
|
|
|
|
RTLGETCURRENTTRANSACTION pfnRtlGetCurrentTransaction = NULL;
|
|
RTLSETCURRENTTRANSACTION pfnRtlSetCurrentTransaction = NULL;
|
|
CREATETRANSACTION pfnCreateTransaction = NULL;
|
|
COMMITTRANSACTION pfnCommitTransaction = NULL;
|
|
ROLLBACKTRANSACTION pfnRollbackTransaction = NULL;
|
|
CREATEDIRTRANSACTED pfnCreateDirectoryTransacted = NULL;
|
|
CREATEFILETRANSACTED pfnCreateFileTransacted = NULL;
|
|
CREATEHARDLINK pfnCreateHardLink = NULL;
|
|
ADDMANDATORYACE pfnAddMandatoryAce = NULL;
|
|
|
|
static HINSTANCE hKtmw32 = NULL;
|
|
|
|
void ResolveDynamicLoadedAPIs()
|
|
{
|
|
// Get imports from Ntdll.dll
|
|
ResolveAPIs(g_szNtdllDll, "RtlGetCurrentTransaction", (FARPROC *)(&pfnRtlGetCurrentTransaction),
|
|
"RtlSetCurrentTransaction", (FARPROC *)(&pfnRtlSetCurrentTransaction), NULL);
|
|
g_dwWinBuild = GetWindowsBuildNumber();
|
|
|
|
// Get imports from Kernel32.dll
|
|
ResolveAPIs(g_szKernel32Dll,
|
|
#ifdef _UNICODE
|
|
"CreateDirectoryTransactedW", (FARPROC *)(&pfnCreateDirectoryTransacted),
|
|
"CreateFileTransactedW", (FARPROC *)(&pfnCreateFileTransacted),
|
|
"CreateHardLinkW", (FARPROC *)(&pfnCreateHardLink),
|
|
#else
|
|
"CreateDirectoryTransactedA", (FARPROC *)(&pfnCreateDirectoryTransacted),
|
|
"CreateFileTransactedA", (FARPROC *)(&pfnCreateFileTransacted),
|
|
"CreateHardLinkA", (FARPROC *)(&pfnCreateHardLink),
|
|
#endif
|
|
NULL);
|
|
|
|
// Get imports from Advapi32.dll
|
|
ResolveAPI(g_szAdvapi32Dll, "AddMandatoryAce", (FARPROC *)(&pfnAddMandatoryAce));
|
|
|
|
// Get imports from Ktmw32.dll
|
|
ResolveAPIs(_T("Ktmw32.dll"),
|
|
"CreateTransaction", (FARPROC *)(&pfnCreateTransaction),
|
|
"CommitTransaction", (FARPROC *)(&pfnCommitTransaction),
|
|
"RollbackTransaction", (FARPROC *)(&pfnRollbackTransaction),
|
|
NULL);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Obtaining NT name from a name, either DOS or NT
|
|
|
|
static LPCWSTR szGlobalRootMaskW = L"\\\\.\\GlobalRoot";
|
|
|
|
typedef enum _PATH_TYPE
|
|
{
|
|
PathTypeNative, // Full local path in native format ("\??\")
|
|
PathTypeNativePrefix, // Full local path prefixed with native prefix ("\\?\" or "\\.\")
|
|
PathTypeLocalFull, // Full local path, including drive letter ("C:\Windows\...")
|
|
PathTypeLocalRoot, // Local root of the current drive ("\Windows\...")
|
|
PathTypeLocalRelative, // Relative path ("Windows\...")
|
|
PathTypeNetwork, // Network path ("\\Server\Share\...")
|
|
PathTypeUnknown
|
|
} PATH_TYPE, *PPATH_TYPE;
|
|
|
|
static PATH_TYPE GetDosPathType(LPCWSTR szFileNameW)
|
|
{
|
|
// Does it begin with backslash character?
|
|
if(szFileNameW[0] == L'\\')
|
|
{
|
|
// Check for native-like win32 prefixes and network share paths
|
|
if(szFileNameW[1] == L'\\')
|
|
{
|
|
// "\\?\" or "\\.\"
|
|
if(szFileNameW[2] == '?' && szFileNameW[3] == '\\')
|
|
return PathTypeNativePrefix;
|
|
if(szFileNameW[2] == '.' && szFileNameW[3] == '\\')
|
|
return PathTypeNativePrefix;
|
|
|
|
// Network paths begin with "\\"
|
|
return PathTypeNetwork;
|
|
}
|
|
|
|
// Check for native path ([refixed with "\??\")
|
|
if(szFileNameW[1] == L'?' && szFileNameW[2] == L'?' && szFileNameW[3] == L'\\')
|
|
return PathTypeNative;
|
|
|
|
// Anything else that begins with "\\" is considered a local root path
|
|
return PathTypeLocalRoot;
|
|
}
|
|
else
|
|
{
|
|
// Check for local DOS paths ("C:\Path\File.ext")
|
|
// Note: Do not use "isalpha()" function, because it could fail on exotic characters
|
|
// (and also ASSERTs in debug builds)
|
|
if(('A' <= szFileNameW[0] && szFileNameW[0] <= 'Z') || ('a' <= szFileNameW[0] && szFileNameW[0] <= 'z'))
|
|
{
|
|
if(szFileNameW[1] == ':' && szFileNameW[2] == '\\')
|
|
return PathTypeLocalFull;
|
|
}
|
|
|
|
// Anything else that does not begin with "\\" is considered a local relative path
|
|
return PathTypeLocalRelative;
|
|
}
|
|
}
|
|
|
|
size_t IsGlobalRootPrefix(LPCWSTR szFileNameW)
|
|
{
|
|
// If the path name is a Win32 native-like prefix
|
|
if(GetDosPathType(szFileNameW) == PathTypeNativePrefix)
|
|
{
|
|
// Skip the native prefix
|
|
szFileNameW += 4;
|
|
|
|
// Check for "GlobalRoot".
|
|
// Note: Return length without the backslash after "GlobalRoot"
|
|
if(!_wcsnicmp(szFileNameW, L"GlobalRoot\\", 11))
|
|
return 4 + 10;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOLEAN IsNativeName(LPCWSTR szFileName)
|
|
{
|
|
OBJECT_ATTRIBUTES ObjAttr;
|
|
UNICODE_STRING FileName;
|
|
UNICODE_STRING TempName;
|
|
PATH_TYPE PathType;
|
|
NTSTATUS Status;
|
|
HANDLE Handle;
|
|
|
|
// Determine the path type
|
|
PathType = GetDosPathType(szFileName);
|
|
if(PathType == PathTypeNative)
|
|
return TRUE;
|
|
|
|
// If the path begins with backslash, determine if it really is an NT name,
|
|
// and for example not local root path (e.g. "\Systemroot" is an NT name,
|
|
// but "\Windows" it a local path name)
|
|
if(PathType == PathTypeLocalRoot)
|
|
{
|
|
// Prepare the object attributes
|
|
InitializeObjectAttributes(&ObjAttr, &FileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
|
|
// Find the next path part
|
|
FileName.MaximumLength =
|
|
FileName.Length = 0;
|
|
FileName.Buffer = (PWSTR)szFileName;
|
|
szFileName++;
|
|
|
|
// Go until we find the second backslash
|
|
while(szFileName[0] != 0 && szFileName[0] != L'\\')
|
|
szFileName++;
|
|
|
|
// Set the length to the UNICODE_STRING
|
|
FileName.MaximumLength =
|
|
FileName.Length = (USHORT)((szFileName - FileName.Buffer) * sizeof(WCHAR));
|
|
|
|
// Note: "\Windows" matches both FS directory and NT namespace directory
|
|
RtlInitUnicodeString(&TempName, L"\\Windows");
|
|
if(RtlCompareUnicodeString(&FileName, &TempName, TRUE) == 0)
|
|
return FALSE;
|
|
|
|
// Attempt to open the symlink (Example: "\Systemroot")
|
|
Status = NtOpenSymbolicLinkObject(&Handle, SYMBOLIC_LINK_QUERY, &ObjAttr);
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
NtClose(Handle);
|
|
return TRUE;
|
|
}
|
|
|
|
// Try to open a directory (Example: "\Device")
|
|
Status = NtOpenDirectoryObject(&Handle, DIRECTORY_TRAVERSE, &ObjAttr);
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
NtClose(Handle);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// Replacement for RtlDosPathNameToNtPathName_U
|
|
BOOLEAN Win32PathNameToNtPathName(PUNICODE_STRING FileName, LPCWSTR szFileNameW)
|
|
{
|
|
LPCWSTR szNtPrefix = NULL;
|
|
LPWSTR szCurrentDir = NULL;
|
|
// LPWSTR szBufferEnd;
|
|
// LPWSTR szBuffer;
|
|
size_t cbFileName = 0;
|
|
size_t cbNtPrefix = 0;
|
|
|
|
// Determine the path type
|
|
switch(GetDosPathType(szFileNameW))
|
|
{
|
|
// DOS native-like paths ("\\?\C:\" and "\\.\C:\") - need to replace prefix
|
|
case PathTypeNativePrefix:
|
|
szNtPrefix = L"\\??\\";
|
|
cbNtPrefix = 8;
|
|
szFileNameW += 4;
|
|
break;
|
|
|
|
// Local full paths need to be prefixed with "\??\"
|
|
case PathTypeLocalFull:
|
|
szNtPrefix = L"\\??\\";
|
|
cbNtPrefix = 8;
|
|
break;
|
|
|
|
// Local root paths need to be prefixed with the current drive
|
|
// case PathTypeLocalRoot:
|
|
// szCurrentDir = Win32PathGetCurrentDir(FALSE);
|
|
// cbNtPrefix = wcslen(szCurrentDir) * sizeof(WCHAR);
|
|
// szNtPrefix = szCurrentDir;
|
|
// break;
|
|
|
|
// Local relative paths need to be prefixed with the current directory
|
|
// case PathTypeLocalRelative:
|
|
// szCurrentDir = Win32PathGetCurrentDir(TRUE);
|
|
// cbNtPrefix = wcslen(szCurrentDir) * sizeof(WCHAR);
|
|
// szNtPrefix = szCurrentDir;
|
|
// break;
|
|
|
|
// Network share paths need to be prefixed with "\??\UNC\"
|
|
case PathTypeNetwork:
|
|
szNtPrefix = L"\\??\\UNC\\";
|
|
cbNtPrefix = 16;
|
|
szFileNameW += 2;
|
|
break;
|
|
}
|
|
|
|
// Do not try to convert the name if it would be too long
|
|
cbFileName = wcslen(szFileNameW) * sizeof(WCHAR);
|
|
if((cbNtPrefix + cbFileName) >= 0xFFFE)
|
|
return FALSE;
|
|
|
|
// Allocate buffer for the path name
|
|
FileName->MaximumLength = (USHORT)(cbNtPrefix + cbFileName + sizeof(WCHAR));
|
|
FileName->Length = (USHORT)(cbNtPrefix + cbFileName);
|
|
FileName->Buffer = (PWSTR)RtlAllocateHeap(RtlProcessHeap(), 0, FileName->MaximumLength);
|
|
if(FileName->Buffer == NULL)
|
|
return FALSE;
|
|
|
|
// Copy the prefix, if any
|
|
if(szNtPrefix != NULL && cbNtPrefix != 0)
|
|
memcpy(FileName->Buffer, szNtPrefix, cbNtPrefix);
|
|
|
|
// Copy the name itself. Also terminate the name with zero
|
|
// (i.e. the same like RtlDosPathNameToNtPathName_U)
|
|
memcpy(FileName->Buffer + (cbNtPrefix / sizeof(WCHAR)), szFileNameW, cbFileName);
|
|
FileName->Buffer[FileName->Length / sizeof(WCHAR)] = 0;
|
|
|
|
// Change slashes to backslashes
|
|
// szBufferEnd = FileName->Buffer + (FileName->Length / sizeof(WCHAR));
|
|
// for(szBuffer = FileName->Buffer; szBuffer < szBufferEnd; szBuffer++)
|
|
// szBuffer[0] = (szBuffer[0] == L'/') ? L'\\' : szBuffer[0];
|
|
|
|
// Free buffers and exit
|
|
delete [] szCurrentDir;
|
|
return TRUE;
|
|
}
|
|
|
|
// Converts file name to UNICODE_STRING
|
|
// Both DOS names and native NT names are processed properly
|
|
// Buffer in "FileName" needs to be freed using FreeFileNameString(&FileName)
|
|
NTSTATUS FileNameToUnicodeString(
|
|
PUNICODE_STRING FileName,
|
|
LPCTSTR szFileName)
|
|
{
|
|
UNICODE_STRING UnicodeName = {0, 0, NULL};
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
BOOLEAN Result;
|
|
PWSTR szFileNameW = NULL;
|
|
|
|
// Set the FileName to empty UNICODE_STRING
|
|
FileName->MaximumLength = 0;
|
|
FileName->Length = 0;
|
|
FileName->Buffer = NULL;
|
|
|
|
// Convert the file name to Unicode, if needed
|
|
#ifndef UNICODE
|
|
// CreateUnicodeStringFromAsciiz produces zero-terminated UNICODE_STRING
|
|
Status = RtlCreateUnicodeStringFromAsciiz(&UnicodeName, szFileName);
|
|
if(!NT_SUCCESS(Status))
|
|
return Status;
|
|
|
|
szFileNameW = UnicodeName.Buffer;
|
|
#else
|
|
UNREFERENCED_PARAMETER(UnicodeName);
|
|
szFileNameW = (PWSTR)szFileName;
|
|
#endif
|
|
|
|
//
|
|
// Several problems of RtlDosPathNameToNtPathName_U
|
|
// ================================================
|
|
//
|
|
// 1) Names longer than about 0x200 characters are not correctly processed
|
|
// 2) If the name ends with space, that space is cut
|
|
// 3) Generally works unpredicably for the following path types:
|
|
//
|
|
// - \??\C:\Dir\File.ext - doesn't work on WinNT 4.0
|
|
// - \\?\C:\Dir\File.ext - works OK on WinNT 4.0
|
|
// - \\Server\Share\Dir\File.ext - works OK on WinNT 4.0
|
|
// - \Device\LanmanRedirector\Server\Share\... - doesn't work on WinNT 4.0
|
|
// - \SystemRoot\System32\Kernel32.dll - doesn't work on WinNT 4.0
|
|
// - \??\UNC\Server\Share\Dir\File.ext - doesn't work on WinNT 4.0
|
|
//
|
|
// From the above reasons, we won't use the RtlDosPathNameToNtPathName_U.
|
|
//
|
|
|
|
// Convert Win32 name using GlobalRoot to native name
|
|
// ("\\?\GlobalRoot\Device\xxxx" to "\Device\xxxx")
|
|
szFileNameW += IsGlobalRootPrefix(szFileNameW);
|
|
|
|
// If it's not an NT path name yet, convert it to an NT name.
|
|
if(IsNativeName(szFileNameW) == FALSE)
|
|
{
|
|
// Use our own method for converting the DOS path name to NT name
|
|
// Result = RtlDosPathNameToNtPathName_U(szFileNameW, FileName, NULL, NULL);
|
|
Result = Win32PathNameToNtPathName(FileName, szFileNameW);
|
|
if(!Result || FileName->Length == 0)
|
|
{
|
|
Status = STATUS_OBJECT_PATH_SYNTAX_BAD;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!RtlCreateUnicodeString(FileName, szFileNameW))
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
// Free the allocated unicode string with DOS name
|
|
RtlFreeUnicodeString(&UnicodeName);
|
|
return Status;
|
|
}
|
|
|
|
void FreeFileNameString(PUNICODE_STRING FileName)
|
|
{
|
|
if(FileName != NULL)
|
|
{
|
|
if(FileName->Buffer != NULL)
|
|
RtlFreeHeap(RtlProcessHeap(), 0, FileName->Buffer);
|
|
FileName->Buffer = NULL;
|
|
}
|
|
}
|
|
|
|
NTSTATUS ConvertToNtName(HWND hDlg, UINT nIDEdit)
|
|
{
|
|
UNICODE_STRING NtName = {0};
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
HWND hEdit = GetDlgItem(hDlg, nIDEdit);
|
|
LPTSTR szFileName = NULL;
|
|
int nLength = GetWindowTextLength(hEdit);
|
|
|
|
// Only do something if the text length is > 0)
|
|
if(nLength > 0)
|
|
{
|
|
// Allocate buffer
|
|
szFileName = new TCHAR[nLength + 1];
|
|
if(szFileName != NULL)
|
|
{
|
|
// Get the window text
|
|
// If it already appears to be an NT name, do nothing
|
|
GetWindowText(hEdit, szFileName, nLength + 1);
|
|
|
|
// Don't convert file ID
|
|
if(nIDEdit == IDC_FILE_NAME && IsPossibleFileId(szFileName))
|
|
{
|
|
SetResultInfo(hDlg, RSI_NTSTATUS, STATUS_FILE_ID_CONVERSION);
|
|
}
|
|
else
|
|
{
|
|
// Convert the name to UNICODE_STRING
|
|
Status = FileNameToUnicodeString(&NtName, szFileName);
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
SetWindowText(hEdit, NtName.Buffer);
|
|
FreeFileNameString(&NtName);
|
|
}
|
|
}
|
|
|
|
delete [] szFileName;
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
int ConvertToWin32Name(HWND hDlg, UINT nIDEdit)
|
|
{
|
|
LPTSTR szNewFileName;
|
|
LPTSTR szFileName;
|
|
HWND hWndEdit = GetDlgItem(hDlg, nIDEdit);
|
|
size_t nLength = GetWindowTextLength(hWndEdit);
|
|
|
|
// Only do something if the text length is > 0)
|
|
if(nLength > 0)
|
|
{
|
|
// Allocate buffer
|
|
szFileName = new TCHAR[nLength + 1];
|
|
if(szFileName != NULL)
|
|
{
|
|
// Get the window text
|
|
// If it already appears to be an Win32 name, do nothing
|
|
GetWindowText(hWndEdit, szFileName, (int)(nLength + 1));
|
|
|
|
// The "\??\Path" case
|
|
if(!_tcsnicmp(szFileName, _T("\\??\\"), 4))
|
|
{
|
|
// If it looks like the \??\C:\..., just skip the initial NT prefix
|
|
if(szFileName[4] != 0 && szFileName[5] == _T(':') && szFileName[6] == _T('\\'))
|
|
{
|
|
SetWindowText(hWndEdit, szFileName + 4);
|
|
}
|
|
|
|
// Network paths: Remove the "\??\UNC\"
|
|
else if(!_tcsnicmp(szFileName, _T("\\??\\UNC\\"), 8))
|
|
{
|
|
szFileName[6] = _T('\\');
|
|
SetWindowText(hWndEdit, szFileName + 6);
|
|
}
|
|
|
|
// Otherwise, replace "\??\" with "\\.\"
|
|
else
|
|
{
|
|
szFileName[1] = _T('\\');
|
|
szFileName[2] = _T('.');
|
|
SetWindowText(hWndEdit, szFileName);
|
|
}
|
|
}
|
|
|
|
// The "\Device\XXX case can still be solved on WinXP or newer
|
|
// The "\Systemroot case can still be solved on WinXP or newer
|
|
else if(g_dwWinVer >= 0x0501 && IsNativeName(szFileName))
|
|
{
|
|
nLength = nLength + wcslen(szGlobalRootMaskW) + 1;
|
|
szNewFileName = new TCHAR[nLength];
|
|
if(szNewFileName != NULL)
|
|
{
|
|
StringCchPrintf(szNewFileName, nLength, _T("%s%s"), szGlobalRootMaskW, szFileName);
|
|
SetWindowText(hWndEdit, szNewFileName);
|
|
delete [] szNewFileName;
|
|
}
|
|
}
|
|
|
|
// Leave the name be
|
|
delete [] szFileName;
|
|
}
|
|
}
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Conversion flags to the text value
|
|
|
|
LPTSTR FlagsToString(TFlagInfo * pFlags, LPTSTR szBuffer, size_t cchBuffer, DWORD dwBitMask, bool bNewLineSeparated)
|
|
{
|
|
TFlagString fs(pFlags, dwBitMask, (bNewLineSeparated) ? GetBitSeparatorNewLine() : NULL);
|
|
|
|
StringCchCopy(szBuffer, cchBuffer, fs);
|
|
return szBuffer;
|
|
}
|
|
|
|
LPTSTR NamedValueToString(TFlagInfo * pFlags, LPTSTR szBuffer, size_t cchBuffer, LPCTSTR szFormat, DWORD dwBitMask)
|
|
{
|
|
LPTSTR szSaveBuffer = szBuffer;
|
|
LPTSTR szBufferEnd = szBuffer + cchBuffer;
|
|
|
|
// Print the format and value
|
|
StringCchPrintfEx(szBuffer, cchBuffer, &szBuffer, NULL, 0, szFormat, dwBitMask);
|
|
|
|
// Format the flags as user-friendly value
|
|
if(dwBitMask != 0)
|
|
FlagsToString(pFlags, szBuffer, (szBufferEnd - szBuffer), dwBitMask, false);
|
|
|
|
// Return the start of the buffer
|
|
return szSaveBuffer;
|
|
}
|
|
|
|
LPTSTR NamedValueToString(TFlagInfo * pFlags, LPTSTR szBuffer, size_t cchBuffer, UINT nIDFormat, DWORD dwBitMask)
|
|
{
|
|
TCHAR szFormat[128];
|
|
|
|
LoadString(g_hInst, nIDFormat, szFormat, _countof(szFormat));
|
|
return NamedValueToString(pFlags, szBuffer, cchBuffer, szFormat, dwBitMask);
|
|
}
|
|
|
|
LPTSTR GuidValueToString(LPTSTR szBuffer, size_t cchBuffer, LPCTSTR szFormat, LPGUID PtrGuid)
|
|
{
|
|
LPTSTR szSaveBuffer = szBuffer;
|
|
TCHAR szGuidText[0x40];
|
|
|
|
GuidToString(PtrGuid, szGuidText, _countof(szGuidText));
|
|
StringCchPrintf(szBuffer, cchBuffer, szFormat, szGuidText);
|
|
return szSaveBuffer;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// File ID and object ID support
|
|
|
|
void FileIDToString(TFileTestData * pData, ULONGLONG FileId, LPTSTR szBuffer)
|
|
{
|
|
PATH_TYPE PathType;
|
|
LPTSTR szPath = (pData->szDirName[0] != 0) ? pData->szDirName : pData->szFileName1;
|
|
|
|
// Skip the NT prefix, if any
|
|
PathType = GetDosPathType(szPath);
|
|
if(PathType == PathTypeNative || PathType == PathTypeNativePrefix)
|
|
szPath += 4;
|
|
|
|
// Supply the disk name
|
|
if(isalpha(szPath[0]) && szPath[1] == _T(':') && szPath[2] == _T('\\'))
|
|
{
|
|
*szBuffer++ = *szPath++;
|
|
*szBuffer++ = *szPath++;
|
|
*szBuffer++ = *szPath++;
|
|
}
|
|
|
|
Hex2Text64(szBuffer, FileId);
|
|
}
|
|
|
|
void ObjectIDToString(PBYTE pbObjId, LPCTSTR szFileName, LPTSTR szObjectID)
|
|
{
|
|
// Supply the disk name
|
|
if(szFileName != NULL)
|
|
{
|
|
if(isalpha(szFileName[0]) && szFileName[1] == _T(':') && szFileName[2] == _T('\\'))
|
|
{
|
|
*szObjectID++ = *szFileName++;
|
|
*szObjectID++ = *szFileName++;
|
|
*szObjectID++ = *szFileName++;
|
|
}
|
|
}
|
|
|
|
// Format the object ID
|
|
for(int i = 0; i < 0x10; i++)
|
|
{
|
|
BYTE OneByte = *pbObjId++;
|
|
|
|
*szObjectID++ = HexaAlphabetUpper[OneByte >> 0x04];
|
|
*szObjectID++ = HexaAlphabetUpper[OneByte & 0x0F];
|
|
}
|
|
|
|
*szObjectID = 0;
|
|
}
|
|
|
|
DWORD StringToFileID(
|
|
LPCTSTR szFileOrObjId,
|
|
LPTSTR szVolume,
|
|
PVOID pvFileObjId,
|
|
PDWORD pLength)
|
|
{
|
|
PBYTE pbObjectID = (PBYTE)pvFileObjId;
|
|
DWORD dwLength = 0;
|
|
TCHAR OneChar;
|
|
BYTE OneByte;
|
|
DWORD dwErrCode = ERROR_SUCCESS;
|
|
|
|
// Is there drive letter?
|
|
if(isalpha(szFileOrObjId[0]) && szFileOrObjId[1] == _T(':') && szFileOrObjId[2] == _T('\\'))
|
|
{
|
|
if(szVolume != NULL)
|
|
{
|
|
szVolume[0] = szFileOrObjId[0];
|
|
szVolume[1] = szFileOrObjId[1];
|
|
szVolume[2] = szFileOrObjId[2];
|
|
szVolume[3] = 0;
|
|
}
|
|
szFileOrObjId += 3;
|
|
}
|
|
|
|
//
|
|
// TODO: Is there a device name?
|
|
//
|
|
|
|
// Perform conversion based of length of the string
|
|
switch(_tcslen(szFileOrObjId))
|
|
{
|
|
// Is the rest a file ID? (16 characters)
|
|
case 0x10:
|
|
dwLength = sizeof(ULONGLONG);
|
|
dwErrCode = Text2Hex64(szFileOrObjId, (PLONGLONG)pvFileObjId);
|
|
break;
|
|
|
|
case 0x20:
|
|
for(int i = 0; i < 0x10; i++)
|
|
{
|
|
if(szFileOrObjId[0] > 0x80 || szFileOrObjId[1] > 0x80)
|
|
{
|
|
dwErrCode = ERROR_BAD_FORMAT;
|
|
break;
|
|
}
|
|
|
|
// Convert the first character
|
|
OneChar = *szFileOrObjId++;
|
|
if(CharToValue[OneChar] == 0xFF)
|
|
{
|
|
dwErrCode = ERROR_BAD_FORMAT;
|
|
break;
|
|
}
|
|
OneByte = CharToValue[OneChar] << 0x04;
|
|
|
|
// Convert the second character
|
|
OneChar = *szFileOrObjId++;
|
|
if(CharToValue[OneChar] == 0xFF)
|
|
{
|
|
dwErrCode = ERROR_BAD_FORMAT;
|
|
break;
|
|
}
|
|
OneByte |= CharToValue[OneChar];
|
|
*pbObjectID++ = OneByte;
|
|
}
|
|
dwLength = 0x10;
|
|
break;
|
|
|
|
default:
|
|
dwErrCode = ERROR_BAD_FORMAT;
|
|
break;
|
|
}
|
|
|
|
// Give the output length
|
|
if(dwErrCode == ERROR_SUCCESS && pLength != NULL)
|
|
*pLength = dwLength;
|
|
return dwErrCode;
|
|
}
|
|
|
|
HMENU FindContextMenu(UINT nIDMenu)
|
|
{
|
|
// Search the pre-loaded menu array
|
|
for(size_t i = 0; i < MAX_CONTEXT_MENUS; i++)
|
|
{
|
|
if(g_ContextMenus[i].szMenuName == MAKEINTRESOURCE(nIDMenu))
|
|
return g_ContextMenus[i].hMenu;
|
|
}
|
|
|
|
// Chould never happen, but anyway
|
|
assert(false);
|
|
return LoadMenu(g_hInst, MAKEINTRESOURCE(nIDMenu));
|
|
}
|
|
|
|
int ExecuteContextMenu(HWND hWndParent, HMENU hMainMenu, LPARAM lParam)
|
|
{
|
|
HMENU hSubMenu = GetSubMenu(hMainMenu, 0);
|
|
POINT pt;
|
|
|
|
if(hSubMenu != NULL)
|
|
{
|
|
// If activated by a key, get the left-top window position
|
|
if(lParam == 0xFFFFFFFF)
|
|
{
|
|
pt.x = pt.y = 5;
|
|
ClientToScreen(hWndParent, &pt);
|
|
}
|
|
else
|
|
{
|
|
pt.x = GET_X_LPARAM(lParam);
|
|
pt.y = GET_Y_LPARAM(lParam);
|
|
}
|
|
|
|
// Set the window to foreground due to capture mouse events
|
|
SetForegroundWindow(hWndParent);
|
|
TrackPopupMenu(hSubMenu, (TPM_LEFTBUTTON | TPM_RIGHTBUTTON), pt.x, pt.y, 0, hWndParent, NULL);
|
|
PostMessage(hWndParent, WM_NULL, 0, 0);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
int ExecuteContextMenuForDlgItem(HWND hWndParent, HMENU hMainMenu, UINT nIDCtrl)
|
|
{
|
|
LPARAM lParam;
|
|
HWND hWndChild = GetDlgItem(hWndParent, nIDCtrl);
|
|
RECT rect;
|
|
|
|
// Calculate position of the menu
|
|
GetWindowRect(hWndChild, &rect);
|
|
lParam = MAKELPARAM(rect.left, rect.bottom);
|
|
|
|
// Execute the context menu
|
|
return ExecuteContextMenu(hWndParent, hMainMenu, lParam);
|
|
}
|
|
|
|
NTSTATUS NtDeleteReparsePoint(HANDLE ObjectHandle)
|
|
{
|
|
PREPARSE_DATA_BUFFER pReparseData = NULL;
|
|
IO_STATUS_BLOCK IoStatus;
|
|
ULONGLONG ReparseBuffer[0x100]; // ULONGLONG makes sure it's aligned to 8
|
|
NTSTATUS Status;
|
|
ULONG Length = sizeof(ReparseBuffer);
|
|
|
|
// Query the reparse point
|
|
pReparseData = (PREPARSE_DATA_BUFFER)ReparseBuffer;
|
|
Status = NtFsControlFile(ObjectHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
FSCTL_GET_REPARSE_POINT,
|
|
NULL,
|
|
0,
|
|
pReparseData,
|
|
Length);
|
|
|
|
// ... and delete it
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
pReparseData->ReparseDataLength = 0;
|
|
Status = NtFsControlFile(ObjectHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&IoStatus,
|
|
FSCTL_DELETE_REPARSE_POINT,
|
|
pReparseData,
|
|
REPARSE_GUID_DATA_BUFFER_HEADER_SIZE,
|
|
NULL,
|
|
0);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS NtDeleteReparsePoint(POBJECT_ATTRIBUTES PtrObjectAttributes)
|
|
{
|
|
IO_STATUS_BLOCK IoStatus;
|
|
NTSTATUS Status;
|
|
HANDLE FileHandle = NULL;
|
|
|
|
// Open the reparse point
|
|
Status = NtOpenFile(&FileHandle,
|
|
FILE_WRITE_ATTRIBUTES,
|
|
PtrObjectAttributes,
|
|
&IoStatus,
|
|
0,
|
|
FILE_OPEN_REPARSE_POINT);
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
Status = NtDeleteReparsePoint(FileHandle);
|
|
NtClose(FileHandle);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Enable/disable redrawing
|
|
|
|
void EnableRedraw(HWND hWnd, BOOL bEnableRedraw)
|
|
{
|
|
// Enable / disable redrawing
|
|
SendMessage(hWnd, WM_SETREDRAW, (WPARAM)(bEnableRedraw), 0);
|
|
|
|
// Redraw the window if needed
|
|
if(bEnableRedraw)
|
|
{
|
|
InvalidateRect(hWnd, NULL, TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL WINAPI MyAddMandatoryAce(PACL pAcl, DWORD dwAceRevision, DWORD dwAceFlags, DWORD MandatoryPolicy, PSID pSid)
|
|
{
|
|
if(pfnAddMandatoryAce == NULL)
|
|
return FALSE;
|
|
|
|
// Call the function
|
|
return pfnAddMandatoryAce(pAcl, dwAceRevision, dwAceFlags, MandatoryPolicy, pSid);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// My own implementation of RtlComputeCrc32
|
|
|
|
/* CRC polynomial 0xedb88320 */
|
|
static const DWORD CRC_table[256] =
|
|
{
|
|
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
|
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
|
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
|
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
|
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
|
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
|
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
|
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
|
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
|
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
|
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
|
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
|
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
|
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
|
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
|
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
|
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
|
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
|
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
|
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
|
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
|
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
|
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
|
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
|
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
|
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
|
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
|
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
|
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
|
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
|
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
|
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
|
};
|
|
|
|
ULONG RtlComputeCrc32(ULONG InitialCrc, PVOID Buffer, ULONG Length)
|
|
{
|
|
LPBYTE DataPtr = (LPBYTE)Buffer;
|
|
DWORD Crc32 = ~InitialCrc;
|
|
|
|
while (Length > 0)
|
|
{
|
|
Crc32 = CRC_table[(Crc32 ^ *DataPtr) & 0xff] ^ (Crc32 >> 8);
|
|
DataPtr++;
|
|
Length--;
|
|
}
|
|
|
|
return ~Crc32;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Methods of the TDataBlob structure
|
|
|
|
DWORD TDataBlob::SetLength(SIZE_T cbNewData)
|
|
{
|
|
LPBYTE pbNewData;
|
|
SIZE_T cbNewDataAligned = ALIGN_TO_SIZE(cbNewData, WIN32_PAGE_SIZE);
|
|
|
|
if(cbNewData > cbDataMax)
|
|
{
|
|
// Allocate new data
|
|
pbNewData = (LPBYTE)VirtualAlloc(NULL, cbNewDataAligned, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
|
if(pbNewData == NULL)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
// Copy and free old data
|
|
if(pbData != NULL)
|
|
{
|
|
if(cbData != 0)
|
|
memcpy(pbNewData, pbData, cbData);
|
|
VirtualFree(pbData, cbDataMax, MEM_RELEASE);
|
|
}
|
|
|
|
// Assign the new data
|
|
pbData = pbNewData;
|
|
cbDataMax = cbNewDataAligned;
|
|
}
|
|
|
|
// Set the new length. Zero the space behind, if any
|
|
if(cbNewData < cbDataMax)
|
|
memset(pbData + cbNewData, 0, (cbDataMax - cbNewData));
|
|
cbData = cbNewData;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
void TDataBlob::Free()
|
|
{
|
|
if(pbData != NULL)
|
|
VirtualFree(pbData, cbDataMax, MEM_RELEASE);
|
|
|
|
pbData = NULL;
|
|
cbData = 0;
|
|
cbDataMax = 0;
|
|
}
|