mirror of
https://github.com/hfiref0x/WinObjEx64
synced 2026-06-08 14:40:58 +00:00
61848a3234
+ Centralize and modernize plugin subsystem definitions and fix related bugs, remove duplicate definitions. + Internal rearrangement.
1102 lines
23 KiB
C
1102 lines
23 KiB
C
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT AUTHORS, 2020 - 2026
|
|
*
|
|
* TITLE: UTILS.C
|
|
*
|
|
* VERSION: 1.21
|
|
*
|
|
* DATE: 07 Mar 2026
|
|
*
|
|
* Shared plugins runtime support functions and prototypes.
|
|
*
|
|
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
* PARTICULAR PURPOSE.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#include "utils.h"
|
|
|
|
/*
|
|
* supSetWaitCursor
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Sets cursor state.
|
|
*
|
|
*/
|
|
VOID supSetWaitCursor(
|
|
_In_ BOOL fSet
|
|
)
|
|
{
|
|
HCURSOR h = LoadCursor(NULL, fSet ? IDC_WAIT : IDC_ARROW);
|
|
if (h) {
|
|
SetCursor(h);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* supMapSection
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Return pointer to section mapped view.
|
|
*
|
|
*/
|
|
NTSTATUS supMapSection(
|
|
_In_ HANDLE SectionHandle,
|
|
_Out_ PVOID* BaseAddress,
|
|
_Out_ SIZE_T* ViewSize
|
|
)
|
|
{
|
|
NTSTATUS ntStatus;
|
|
SECTION_BASIC_INFORMATION sbi;
|
|
SIZE_T bytesReturned;
|
|
|
|
*BaseAddress = NULL;
|
|
*ViewSize = 0;
|
|
|
|
__try {
|
|
|
|
//
|
|
// Check if this is image mapped file.
|
|
//
|
|
ntStatus = NtQuerySection(SectionHandle,
|
|
SectionBasicInformation,
|
|
(PVOID)&sbi,
|
|
sizeof(SECTION_BASIC_INFORMATION),
|
|
&bytesReturned);
|
|
|
|
if (!NT_SUCCESS(ntStatus))
|
|
__leave;
|
|
|
|
if (!((sbi.AllocationAttributes & SEC_IMAGE) &&
|
|
(sbi.AllocationAttributes & SEC_FILE)))
|
|
{
|
|
ntStatus = STATUS_NOT_SUPPORTED;
|
|
__leave;
|
|
}
|
|
|
|
ntStatus = NtMapViewOfSection(SectionHandle,
|
|
NtCurrentProcess(),
|
|
BaseAddress,
|
|
0,
|
|
0,
|
|
NULL,
|
|
ViewSize,
|
|
ViewUnmap,
|
|
0,
|
|
PAGE_READONLY);
|
|
|
|
}
|
|
__finally {
|
|
if (AbnormalTermination())
|
|
ntStatus = STATUS_ACCESS_VIOLATION;
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
/*
|
|
* supSaveDialogExecute
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Display SaveDialog.
|
|
*
|
|
*/
|
|
BOOL supSaveDialogExecute(
|
|
_In_ HWND OwnerWindow,
|
|
_Inout_ LPWSTR SaveFileName,
|
|
_In_ LPWSTR lpDialogFilter
|
|
)
|
|
{
|
|
OPENFILENAME tag1;
|
|
|
|
RtlSecureZeroMemory(&tag1, sizeof(OPENFILENAME));
|
|
|
|
tag1.lStructSize = sizeof(OPENFILENAME);
|
|
tag1.hwndOwner = OwnerWindow;
|
|
tag1.lpstrFilter = lpDialogFilter;
|
|
tag1.lpstrFile = SaveFileName;
|
|
tag1.nMaxFile = MAX_PATH;
|
|
tag1.lpstrInitialDir = NULL;
|
|
tag1.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
|
|
|
|
return GetSaveFileName(&tag1);
|
|
}
|
|
|
|
size_t supxEscStrlen(wchar_t* s)
|
|
{
|
|
size_t result, quoteCount;
|
|
wchar_t* s0;
|
|
|
|
if (s == NULL)
|
|
return 0;
|
|
|
|
s0 = s;
|
|
result = 2;
|
|
quoteCount = 0;
|
|
|
|
while (*s) {
|
|
if (*s == L'"')
|
|
++quoteCount;
|
|
++s;
|
|
}
|
|
|
|
return result + (s - s0) + quoteCount;
|
|
}
|
|
|
|
wchar_t* supxEscStrcpy(wchar_t* dst, wchar_t* src)
|
|
{
|
|
if (dst == NULL || src == NULL)
|
|
return dst;
|
|
|
|
*(dst++) = L'"';
|
|
|
|
while (*src != L'\0') {
|
|
if (*src == L'"') {
|
|
*(dst++) = L'"';
|
|
*(dst++) = L'"';
|
|
++src;
|
|
}
|
|
else {
|
|
*(dst++) = *src;
|
|
++src;
|
|
}
|
|
}
|
|
|
|
*(dst++) = L'"';
|
|
*dst = L'\0';
|
|
|
|
return dst;
|
|
}
|
|
|
|
/*
|
|
* supxListViewExportCSV
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Export listview entries into file in csv format.
|
|
*
|
|
*/
|
|
BOOL supxListViewExportCSV(
|
|
_In_ HWND List,
|
|
_In_ PWCHAR FileName)
|
|
{
|
|
HWND hdr;
|
|
int pass, i, c, col_count, icount;
|
|
HDITEM ih;
|
|
LVITEM lvi;
|
|
PWCHAR text, buffer0, buffer;
|
|
BOOL result;
|
|
SIZE_T total_length, field_length;
|
|
DWORD iobytes;
|
|
HANDLE f;
|
|
WORD bom;
|
|
|
|
if (!List || !FileName)
|
|
return FALSE;
|
|
|
|
hdr = ListView_GetHeader(List);
|
|
if (!hdr)
|
|
return FALSE;
|
|
|
|
col_count = Header_GetItemCount(hdr);
|
|
if (col_count <= 0)
|
|
return FALSE;
|
|
|
|
icount = 1 + ListView_GetItemCount(List);
|
|
|
|
text = (PWCHAR)ntsupVirtualAlloc(32768 * sizeof(WCHAR));
|
|
if (!text)
|
|
return FALSE;
|
|
|
|
buffer0 = NULL;
|
|
buffer = NULL;
|
|
result = FALSE;
|
|
|
|
RtlZeroMemory(&ih, sizeof(HDITEM));
|
|
RtlZeroMemory(&lvi, sizeof(LVITEM));
|
|
|
|
ih.pszText = lvi.pszText = text;
|
|
ih.cchTextMax = lvi.cchTextMax = 32767;
|
|
|
|
for (pass = 0; pass < 2; ++pass) {
|
|
total_length = 0;
|
|
|
|
for (i = 0; i < icount; ++i) {
|
|
for (c = 0; c < col_count; ++c) {
|
|
text[0] = L'\0';
|
|
|
|
if (i == 0) {
|
|
ih.mask = HDI_TEXT | HDI_ORDER;
|
|
ih.iOrder = c;
|
|
Header_GetItem(hdr, c, &ih);
|
|
}
|
|
else {
|
|
lvi.mask = LVIF_TEXT;
|
|
lvi.iItem = i - 1;
|
|
lvi.iSubItem = c;
|
|
ListView_GetItem(List, &lvi);
|
|
}
|
|
|
|
field_length = supxEscStrlen(text);
|
|
total_length += field_length;
|
|
|
|
if (buffer) {
|
|
buffer = supxEscStrcpy(buffer, text);
|
|
}
|
|
|
|
if (c != col_count - 1) {
|
|
total_length += 1;
|
|
if (buffer) {
|
|
*(buffer++) = L',';
|
|
}
|
|
}
|
|
else {
|
|
total_length += 2;
|
|
if (buffer) {
|
|
*(buffer++) = L'\r';
|
|
*(buffer++) = L'\n';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (buffer0 == NULL) {
|
|
buffer0 = (PWCHAR)ntsupVirtualAlloc((1 + total_length) * sizeof(WCHAR));
|
|
if (!buffer0)
|
|
break;
|
|
buffer = buffer0;
|
|
}
|
|
else {
|
|
f = CreateFile(FileName,
|
|
GENERIC_WRITE | SYNCHRONIZE,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (f != INVALID_HANDLE_VALUE) {
|
|
bom = 0xFEFF;
|
|
if (WriteFile(f, &bom, sizeof(WORD), &iobytes, NULL) &&
|
|
iobytes == sizeof(WORD) &&
|
|
WriteFile(f, buffer0, (DWORD)(total_length * sizeof(WCHAR)), &iobytes, NULL) &&
|
|
iobytes == (DWORD)(total_length * sizeof(WCHAR)))
|
|
{
|
|
result = TRUE;
|
|
}
|
|
CloseHandle(f);
|
|
result = TRUE;
|
|
}
|
|
ntsupVirtualFree(buffer0);
|
|
buffer0 = NULL;
|
|
}
|
|
}
|
|
|
|
if (buffer0)
|
|
ntsupVirtualFree(buffer0);
|
|
|
|
ntsupVirtualFree(text);
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* supListViewExportToFile
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Export listview contents to the specified file.
|
|
*
|
|
*/
|
|
BOOL supListViewExportToFile(
|
|
_In_ LPWSTR FileName,
|
|
_In_ HWND WindowHandle,
|
|
_In_ HWND ListView,
|
|
_In_ LPWSTR FileFilter
|
|
)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
WCHAR szExportFileName[MAX_PATH + 1];
|
|
|
|
RtlSecureZeroMemory(&szExportFileName, sizeof(szExportFileName));
|
|
|
|
_strcpy(szExportFileName, FileName);
|
|
if (supSaveDialogExecute(WindowHandle,
|
|
(LPWSTR)&szExportFileName,
|
|
FileFilter))
|
|
{
|
|
SetCapture(WindowHandle);
|
|
supSetWaitCursor(TRUE);
|
|
|
|
bResult = supxListViewExportCSV(ListView, szExportFileName);
|
|
|
|
supSetWaitCursor(FALSE);
|
|
ReleaseCapture();
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
* supStatusBarSetText
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Display status in status bar part.
|
|
*
|
|
*/
|
|
VOID supStatusBarSetText(
|
|
_In_ HWND hwndStatusBar,
|
|
_In_ WPARAM partIndex,
|
|
_In_ LPWSTR lpText
|
|
)
|
|
{
|
|
SendMessage(hwndStatusBar, SB_SETTEXT, partIndex, (LPARAM)lpText);
|
|
}
|
|
|
|
/*
|
|
* supTreeListAddItem
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Insert new treelist item.
|
|
*
|
|
*/
|
|
HTREEITEM supTreeListAddItem(
|
|
_In_ HWND TreeList,
|
|
_In_opt_ HTREEITEM hParent,
|
|
_In_ UINT mask,
|
|
_In_ UINT state,
|
|
_In_ UINT stateMask,
|
|
_In_opt_ LPWSTR pszText,
|
|
_In_opt_ PVOID subitems
|
|
)
|
|
{
|
|
TVINSERTSTRUCT tvitem;
|
|
PTL_SUBITEMS si = (PTL_SUBITEMS)subitems;
|
|
|
|
RtlSecureZeroMemory(&tvitem, sizeof(tvitem));
|
|
tvitem.hParent = hParent;
|
|
tvitem.item.mask = mask;
|
|
tvitem.item.state = state;
|
|
tvitem.item.stateMask = stateMask;
|
|
tvitem.item.pszText = pszText;
|
|
tvitem.hInsertAfter = TVI_LAST;
|
|
return TreeList_InsertTreeItem(TreeList, &tvitem, si);
|
|
}
|
|
|
|
/*
|
|
* supAddListViewColumn
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Insert list view column.
|
|
*
|
|
*/
|
|
INT supAddListViewColumn(
|
|
_In_ HWND ListViewHwnd,
|
|
_In_ INT ColumnIndex,
|
|
_In_ INT SubItemIndex,
|
|
_In_ INT OrderIndex,
|
|
_In_ INT ImageIndex,
|
|
_In_ INT Format,
|
|
_In_ LPWSTR Text,
|
|
_In_ INT Width,
|
|
_In_ INT DpiValue
|
|
)
|
|
{
|
|
LVCOLUMN column;
|
|
|
|
column.mask = LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT | LVCF_WIDTH | LVCF_ORDER | LVCF_IMAGE;
|
|
column.fmt = Format;
|
|
column.cx = ScaleDPI(Width, DpiValue);
|
|
column.pszText = Text;
|
|
column.iSubItem = SubItemIndex;
|
|
column.iOrder = OrderIndex;
|
|
column.iImage = ImageIndex;
|
|
|
|
return ListView_InsertColumn(ListViewHwnd, ColumnIndex, &column);
|
|
}
|
|
|
|
/*
|
|
* supTreeListAddCopyValueItem
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Add copy to clipboard menu item depending on hit treelist header item.
|
|
*
|
|
*/
|
|
BOOL supTreeListAddCopyValueItem(
|
|
_In_ HMENU hMenu,
|
|
_In_ HWND hwndTreeList,
|
|
_In_ UINT uId,
|
|
_In_ UINT uPos,
|
|
_In_ LPARAM lParam,
|
|
_In_ INT* pSubItemHit
|
|
)
|
|
{
|
|
HDHITTESTINFO hti;
|
|
HD_ITEM hdItem;
|
|
WCHAR szHeaderText[MAX_PATH + 1];
|
|
WCHAR szItem[MAX_PATH * 2];
|
|
|
|
*pSubItemHit = -1;
|
|
|
|
hti.iItem = -1;
|
|
hti.pt.x = LOWORD(lParam);
|
|
hti.pt.y = HIWORD(lParam);
|
|
ScreenToClient(hwndTreeList, &hti.pt);
|
|
|
|
hti.pt.y = 1;
|
|
if (TreeList_HeaderHittest(hwndTreeList, &hti) < 0)
|
|
return FALSE;
|
|
|
|
RtlSecureZeroMemory(&hdItem, sizeof(hdItem));
|
|
|
|
szHeaderText[0] = 0;
|
|
hdItem.mask = HDI_TEXT;
|
|
|
|
hdItem.cchTextMax = RTL_NUMBER_OF(szHeaderText);
|
|
|
|
hdItem.pszText = szHeaderText;
|
|
if (TreeList_GetHeaderItem(hwndTreeList, hti.iItem, &hdItem)) {
|
|
*pSubItemHit = hti.iItem;
|
|
StringCchPrintf(szItem, RTL_NUMBER_OF(szItem), TEXT("Copy \"%ws\""), szHeaderText);
|
|
if (InsertMenu(hMenu, uPos, MF_BYCOMMAND, uId, szItem)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* supGetItemText
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Returns buffer with text from the given listview item.
|
|
*
|
|
* Returned buffer must be freed with supHeapFree after usage.
|
|
*
|
|
*/
|
|
LPWSTR supGetItemText(
|
|
_In_ HWND ListView,
|
|
_In_ INT nItem,
|
|
_In_ INT nSubItem,
|
|
_Out_opt_ PSIZE_T lpSize
|
|
)
|
|
{
|
|
INT len;
|
|
LPARAM sz = 0;
|
|
LV_ITEM item;
|
|
|
|
RtlSecureZeroMemory(&item, sizeof(item));
|
|
|
|
item.iItem = nItem;
|
|
item.iSubItem = nSubItem;
|
|
len = 128;
|
|
|
|
do {
|
|
len *= 2;
|
|
item.cchTextMax = len;
|
|
if (item.pszText) {
|
|
supHeapFree(item.pszText);
|
|
item.pszText = NULL;
|
|
}
|
|
item.pszText = (LPWSTR)supHeapAlloc(len * sizeof(WCHAR));
|
|
if (item.pszText == NULL)
|
|
break;
|
|
|
|
sz = SendMessage(ListView, LVM_GETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item);
|
|
} while (sz == (LPARAM)len - 1);
|
|
|
|
if (sz == 0) {
|
|
if (item.pszText) {
|
|
supHeapFree(item.pszText);
|
|
item.pszText = NULL;
|
|
}
|
|
}
|
|
|
|
if (lpSize) {
|
|
*lpSize = sz * sizeof(WCHAR);
|
|
}
|
|
|
|
return item.pszText;
|
|
}
|
|
|
|
/*
|
|
* supGetItemText2
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Returns text from the given listview item.
|
|
*
|
|
*/
|
|
LPWSTR supGetItemText2(
|
|
_In_ HWND ListView,
|
|
_In_ INT nItem,
|
|
_In_ INT nSubItem,
|
|
_In_ WCHAR* pszText,
|
|
_In_ UINT cchText
|
|
)
|
|
{
|
|
LV_ITEM item;
|
|
|
|
RtlSecureZeroMemory(&item, sizeof(item));
|
|
|
|
item.iItem = nItem;
|
|
item.iSubItem = nSubItem;
|
|
item.pszText = pszText;
|
|
item.cchTextMax = (SIZE_T)cchText;
|
|
SendMessage(ListView, LVM_GETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item);
|
|
|
|
return item.pszText;
|
|
}
|
|
|
|
/*
|
|
* supClipboardCopy
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Copy text to the clipboard.
|
|
*
|
|
*/
|
|
VOID supClipboardCopy(
|
|
_In_ LPWSTR lpText,
|
|
_In_ SIZE_T cbText
|
|
)
|
|
{
|
|
LPWSTR lptstrCopy;
|
|
HGLOBAL hglbCopy = NULL;
|
|
SIZE_T dwSize;
|
|
BOOL dataSet = FALSE;
|
|
|
|
if (!OpenClipboard(NULL))
|
|
return;
|
|
|
|
__try {
|
|
EmptyClipboard();
|
|
dwSize = cbText + sizeof(UNICODE_NULL);
|
|
hglbCopy = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwSize);
|
|
if (hglbCopy == NULL)
|
|
__leave;
|
|
|
|
lptstrCopy = (LPWSTR)GlobalLock(hglbCopy);
|
|
if (lptstrCopy == NULL)
|
|
__leave;
|
|
|
|
RtlCopyMemory(lptstrCopy, lpText, cbText);
|
|
GlobalUnlock(hglbCopy);
|
|
|
|
dataSet = SetClipboardData(CF_UNICODETEXT, hglbCopy) != NULL;
|
|
if (dataSet) {
|
|
hglbCopy = NULL;
|
|
}
|
|
}
|
|
__finally {
|
|
CloseClipboard();
|
|
if (hglbCopy != NULL) {
|
|
GlobalFree(hglbCopy);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* supListViewCopyItemValueToClipboard
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Copy selected item text to the clipboard.
|
|
*
|
|
*/
|
|
BOOL supListViewCopyItemValueToClipboard(
|
|
_In_ HWND hwndListView,
|
|
_In_ INT iItem,
|
|
_In_ INT iSubItem
|
|
)
|
|
{
|
|
SIZE_T cbText;
|
|
LPWSTR lpText;
|
|
|
|
if ((iSubItem < 0) || (iItem < 0))
|
|
return FALSE;
|
|
|
|
lpText = supGetItemText(hwndListView,
|
|
iItem,
|
|
iSubItem,
|
|
NULL);
|
|
|
|
if (lpText) {
|
|
cbText = _strlen(lpText) * sizeof(WCHAR);
|
|
supClipboardCopy(lpText, cbText);
|
|
supHeapFree(lpText);
|
|
return TRUE;
|
|
}
|
|
else {
|
|
if (OpenClipboard(NULL)) {
|
|
EmptyClipboard();
|
|
CloseClipboard();
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* supFreeDuplicatedUnicodeString
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Release memory allocated for duplicated string.
|
|
*
|
|
*/
|
|
_Success_(return)
|
|
BOOL supFreeDuplicatedUnicodeString(
|
|
_In_ HANDLE HeapHandle,
|
|
_Inout_ PUNICODE_STRING DuplicatedString,
|
|
_In_ BOOL DoZeroMemory
|
|
)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
if (DuplicatedString->Buffer) {
|
|
bResult = RtlFreeHeap(HeapHandle, 0, DuplicatedString->Buffer);
|
|
if (DoZeroMemory) {
|
|
DuplicatedString->Buffer = NULL;
|
|
DuplicatedString->Length = DuplicatedString->MaximumLength = 0;
|
|
}
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
* supDuplicateUnicodeString
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Duplicate existing UNICODE_STRING to another without RtlDuplicateUnicodeString.
|
|
*
|
|
* Note: Use supFreeDuplicatedUnicodeString to release allocated memory.
|
|
*
|
|
*/
|
|
_Success_(return)
|
|
BOOL supDuplicateUnicodeString(
|
|
_In_ HANDLE HeapHandle,
|
|
_Out_ PUNICODE_STRING DestinationString,
|
|
_In_ PUNICODE_STRING SourceString
|
|
)
|
|
{
|
|
USHORT maxLength = SourceString->MaximumLength;
|
|
PWCHAR strBuffer;
|
|
|
|
if (maxLength == 0 || maxLength < SourceString->Length)
|
|
return FALSE;
|
|
|
|
strBuffer = (PWCHAR)RtlAllocateHeap(HeapHandle, HEAP_ZERO_MEMORY, (SIZE_T)maxLength);
|
|
if (strBuffer) {
|
|
DestinationString->Buffer = strBuffer;
|
|
DestinationString->MaximumLength = maxLength;
|
|
RtlCopyUnicodeString(DestinationString, SourceString);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Conversion buffer size
|
|
//
|
|
#define CONVERT_NTNAME_BUFFER_SIZE 512
|
|
|
|
/*
|
|
* supConvertFileName
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Translate Nt path name to Dos path name.
|
|
*
|
|
*/
|
|
BOOL supConvertFileName(
|
|
_In_ LPWSTR NtFileName,
|
|
_Inout_ LPWSTR DosFileName,
|
|
_In_ SIZE_T ccDosFileName
|
|
)
|
|
{
|
|
BOOL bFound = FALSE;
|
|
|
|
SIZE_T nLen;
|
|
|
|
WCHAR szDrive[3];
|
|
WCHAR szName[MAX_PATH];
|
|
WCHAR szTemp[CONVERT_NTNAME_BUFFER_SIZE];
|
|
WCHAR* pszTemp;
|
|
|
|
//
|
|
// All input parameters are validated by caller before.
|
|
//
|
|
|
|
//
|
|
// Drive template.
|
|
//
|
|
szDrive[0] = L'X';
|
|
szDrive[1] = L':';
|
|
szDrive[2] = 0;
|
|
|
|
//
|
|
// Query array of logical disk drive strings.
|
|
//
|
|
szTemp[0] = 0;
|
|
if (GetLogicalDriveStrings(RTL_NUMBER_OF(szTemp), szTemp) == 0)
|
|
return FALSE;
|
|
|
|
pszTemp = szTemp;
|
|
|
|
do {
|
|
|
|
//
|
|
// Copy the drive letter to the template string.
|
|
//
|
|
*szDrive = *pszTemp;
|
|
szName[0] = 0;
|
|
|
|
//
|
|
// Lookup each device name.
|
|
//
|
|
if (QueryDosDevice(szDrive, szName, MAX_PATH)) {
|
|
|
|
nLen = _strlen(szName);
|
|
|
|
if (nLen < MAX_PATH) {
|
|
|
|
//
|
|
// Match device name.
|
|
//
|
|
bFound = ((_strncmpi(NtFileName, szName, nLen) == 0)
|
|
&& *(NtFileName + nLen) == L'\\');
|
|
|
|
if (bFound) {
|
|
|
|
//
|
|
// Build output name.
|
|
//
|
|
StringCchPrintf(
|
|
DosFileName,
|
|
ccDosFileName,
|
|
TEXT("%ws%ws"),
|
|
szDrive,
|
|
NtFileName + nLen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Go to the next NULL character, i.e. the next drive name.
|
|
//
|
|
while (*pszTemp++);
|
|
|
|
} while (!bFound && *pszTemp);
|
|
|
|
return bFound;
|
|
}
|
|
|
|
/*
|
|
* supGetWin32FileName
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Query filename by handle.
|
|
*
|
|
* Input buffer must be at least MAX_PATH length.
|
|
*
|
|
*/
|
|
BOOL supGetWin32FileName(
|
|
_In_ LPWSTR FileName,
|
|
_Inout_ LPWSTR Win32FileName,
|
|
_In_ SIZE_T ccWin32FileName
|
|
)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
HANDLE hFile = NULL;
|
|
UNICODE_STRING NtFileName;
|
|
OBJECT_ATTRIBUTES obja;
|
|
IO_STATUS_BLOCK iost;
|
|
ULONG memIO;
|
|
BYTE* Buffer = NULL;
|
|
|
|
if ((Win32FileName == NULL) || (ccWin32FileName < MAX_PATH)) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
do {
|
|
|
|
RtlInitUnicodeString(&NtFileName, FileName);
|
|
InitializeObjectAttributes(&obja, &NtFileName, OBJ_CASE_INSENSITIVE, 0, NULL);
|
|
|
|
status = NtCreateFile(&hFile, SYNCHRONIZE, &obja, &iost, NULL, 0,
|
|
FILE_SHARE_VALID_FLAGS, FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, NULL, 0);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
break;
|
|
|
|
memIO = 0;
|
|
status = NtQueryObject(hFile, ObjectNameInformation, NULL, 0, &memIO);
|
|
if (status != STATUS_INFO_LENGTH_MISMATCH)
|
|
break;
|
|
|
|
Buffer = (BYTE*)supHeapAlloc(memIO);
|
|
if (Buffer == NULL)
|
|
break;
|
|
|
|
status = NtQueryObject(hFile, ObjectNameInformation, Buffer, memIO, NULL);
|
|
if (!NT_SUCCESS(status))
|
|
break;
|
|
|
|
if (!supConvertFileName(((PUNICODE_STRING)Buffer)->Buffer, Win32FileName, ccWin32FileName))
|
|
break;
|
|
|
|
bResult = TRUE;
|
|
|
|
} while (FALSE);
|
|
|
|
if (hFile)
|
|
NtClose(hFile);
|
|
|
|
if (Buffer != NULL)
|
|
supHeapFree(Buffer);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
* supGetMaxCompareTwoFixedStrings
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Returned value used in listview comparer functions.
|
|
*
|
|
*/
|
|
INT supGetMaxCompareTwoFixedStrings(
|
|
_In_ HWND ListView,
|
|
_In_ LPARAM lParam1,
|
|
_In_ LPARAM lParam2,
|
|
_In_ LPARAM lParamSort,
|
|
_In_ BOOL Inverse
|
|
)
|
|
{
|
|
INT nResult;
|
|
LPWSTR lpItem1 = NULL, lpItem2 = NULL, FirstToCompare, SecondToCompare;
|
|
WCHAR szString1[MAX_PATH + 1], szString2[MAX_PATH + 1];
|
|
|
|
szString1[0] = 0;
|
|
|
|
lpItem1 = supGetItemText2(
|
|
ListView,
|
|
(INT)lParam1,
|
|
(INT)lParamSort,
|
|
szString1,
|
|
MAX_PATH);
|
|
|
|
szString2[0] = 0;
|
|
|
|
lpItem2 = supGetItemText2(
|
|
ListView,
|
|
(INT)lParam2,
|
|
(INT)lParamSort,
|
|
szString2,
|
|
MAX_PATH);
|
|
|
|
if (Inverse) {
|
|
FirstToCompare = lpItem2;
|
|
SecondToCompare = lpItem1;
|
|
}
|
|
else {
|
|
FirstToCompare = lpItem1;
|
|
SecondToCompare = lpItem2;
|
|
}
|
|
|
|
nResult = _strcmpi(FirstToCompare, SecondToCompare);
|
|
|
|
return nResult;
|
|
}
|
|
|
|
/*
|
|
* supGetMaxOfTwoU64FromHex
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Returned value used in listview comparer functions.
|
|
*
|
|
*/
|
|
INT supGetMaxOfTwoU64FromHex(
|
|
_In_ HWND ListView,
|
|
_In_ LPARAM lParam1,
|
|
_In_ LPARAM lParam2,
|
|
_In_ LPARAM lParamSort,
|
|
_In_ BOOL Inverse
|
|
)
|
|
{
|
|
INT nResult = 0;
|
|
LPWSTR lpItem1 = NULL, lpItem2 = NULL;
|
|
ULONG_PTR ad1, ad2;
|
|
WCHAR szText[32];
|
|
|
|
RtlSecureZeroMemory(&szText, sizeof(szText));
|
|
|
|
lpItem1 = supGetItemText2(
|
|
ListView,
|
|
(INT)lParam1,
|
|
(INT)lParamSort,
|
|
szText,
|
|
RTL_NUMBER_OF(szText));
|
|
|
|
ad1 = hextou64(&lpItem1[2]);
|
|
|
|
RtlSecureZeroMemory(&szText, sizeof(szText));
|
|
|
|
lpItem2 = supGetItemText2(
|
|
ListView,
|
|
(INT)lParam2,
|
|
(INT)lParamSort,
|
|
szText,
|
|
RTL_NUMBER_OF(szText));
|
|
|
|
ad2 = hextou64(&lpItem2[2]);
|
|
|
|
if (ad1 < ad2)
|
|
nResult = -1;
|
|
else if (ad1 > ad2)
|
|
nResult = 1;
|
|
|
|
if (Inverse)
|
|
nResult = -nResult;
|
|
|
|
return nResult;
|
|
}
|
|
|
|
/*
|
|
* supTreeListCopyItemValueToClipboard
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Copy selected treelist item text to the clipboard.
|
|
*
|
|
*/
|
|
BOOL supTreeListCopyItemValueToClipboard(
|
|
_In_ HWND hwndTreeList,
|
|
_In_ INT tlSubItemHit
|
|
)
|
|
{
|
|
INT nIndex;
|
|
LPWSTR lpCopyData = NULL;
|
|
SIZE_T cbCopyData = 0;
|
|
TVITEMEX itemex;
|
|
WCHAR szText[MAX_PATH + 1];
|
|
|
|
TL_SUBITEMS_FIXED* pSubItems = NULL;
|
|
|
|
szText[0] = 0;
|
|
RtlSecureZeroMemory(&itemex, sizeof(itemex));
|
|
itemex.mask = TVIF_TEXT;
|
|
itemex.hItem = TreeList_GetSelection(hwndTreeList);
|
|
itemex.pszText = szText;
|
|
itemex.cchTextMax = MAX_PATH;
|
|
|
|
if (TreeList_GetTreeItem(hwndTreeList, &itemex, &pSubItems)) {
|
|
|
|
if ((tlSubItemHit > 0) && (pSubItems != NULL)) {
|
|
|
|
nIndex = (tlSubItemHit - 1);
|
|
if (nIndex < (INT)pSubItems->Count) {
|
|
|
|
lpCopyData = pSubItems->Text[nIndex];
|
|
cbCopyData = _strlen(lpCopyData) * sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
}
|
|
else {
|
|
if (tlSubItemHit == 0) {
|
|
lpCopyData = szText;
|
|
cbCopyData = sizeof(szText); // copy everything
|
|
}
|
|
}
|
|
|
|
if (lpCopyData && cbCopyData) {
|
|
supClipboardCopy(lpCopyData, cbCopyData);
|
|
return TRUE;
|
|
}
|
|
else {
|
|
if (OpenClipboard(NULL)) {
|
|
EmptyClipboard();
|
|
CloseClipboard();
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* supListViewAddCopyValueItem
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Add copy to clipboard menu item depending on hit column.
|
|
*
|
|
*/
|
|
BOOL supListViewAddCopyValueItem(
|
|
_In_ HMENU hMenu,
|
|
_In_ HWND hwndLv,
|
|
_In_ UINT uId,
|
|
_In_ UINT uPos,
|
|
_In_ POINT * lpPoint,
|
|
_Out_ INT * pItemHit,
|
|
_Out_ INT * pColumnHit
|
|
)
|
|
{
|
|
LVHITTESTINFO lvht;
|
|
LVCOLUMN lvc;
|
|
WCHAR szItem[MAX_PATH * 2];
|
|
WCHAR szColumn[MAX_PATH + 1];
|
|
|
|
*pColumnHit = -1;
|
|
*pItemHit = -1;
|
|
|
|
RtlSecureZeroMemory(&lvht, sizeof(lvht));
|
|
lvht.pt.x = lpPoint->x;
|
|
lvht.pt.y = lpPoint->y;
|
|
ScreenToClient(hwndLv, &lvht.pt);
|
|
if (ListView_SubItemHitTest(hwndLv, &lvht) == -1)
|
|
return FALSE;
|
|
|
|
RtlSecureZeroMemory(&lvc, sizeof(lvc));
|
|
RtlSecureZeroMemory(&szColumn, sizeof(szColumn));
|
|
|
|
lvc.mask = LVCF_TEXT;
|
|
lvc.pszText = szColumn;
|
|
lvc.cchTextMax = MAX_PATH;
|
|
if (ListView_GetColumn(hwndLv, lvht.iSubItem, &lvc)) {
|
|
_strcpy(szItem, TEXT("Copy \""));
|
|
_strcat(szItem, szColumn);
|
|
_strcat(szItem, TEXT("\""));
|
|
if (InsertMenu(hMenu, uPos, MF_BYCOMMAND, uId, szItem)) {
|
|
*pColumnHit = lvht.iSubItem;
|
|
*pItemHit = lvht.iItem;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|