/*****************************************************************************/ /* 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; }