Files
ladislav-zezula-FileTest/DlgEasEditor.cpp
Ladislav Zezula 96e381601d Testing
2024-01-10 17:47:26 +01:00

504 lines
15 KiB
C++

/*****************************************************************************/
/* DlgEasEditor.cpp Copyright (c) Ladislav Zezula 2008 */
/*---------------------------------------------------------------------------*/
/* Description : */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 25.07.08 1.00 Lad Created */
/*****************************************************************************/
#include "FileTest.h"
#include "resource.h"
//-----------------------------------------------------------------------------
// Local variables
static TListViewColumns Columns[] =
{
{IDS_EA_NAME, 120},
{IDS_EA_SIZE, 80},
{IDS_EA_VALUE, -1},
{0, 0}
};
//-----------------------------------------------------------------------------
// Local functions
static ULONG CopyEaItem(PFILE_FULL_EA_INFORMATION pTrg, PFILE_FULL_EA_INFORMATION pSrc, bool bSetNextOffset)
{
// Things checked by nt!IoCheckEaBufferValidity:
// 1) There must be zero after the EA name
// 2) NextEntryOffset must be aligned to DWORD boundary
ULONG EntryLength = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) + pSrc->EaNameLength + sizeof(CHAR) + pSrc->EaValueLength;
// Copy the entire entry
memcpy(pTrg, pSrc, EntryLength);
pTrg->EaName[pTrg->EaNameLength] = 0;
pTrg->NextEntryOffset = 0;
// Set the offset of the next entry, if needed
if(bSetNextOffset)
pTrg->NextEntryOffset = ALIGN_TO_SIZE(EntryLength, sizeof(DWORD));
return EntryLength;
}
static BOOL UpdateDialogButtons(HWND hDlg)
{
HWND hListView = GetDlgItem(hDlg, IDC_EA_LIST);
HWND hButton;
int nSelected = ListView_GetSelectedCount(hListView);
int nItems = ListView_GetItemCount(hListView);
int nItem = ListView_GetNextItem(hListView, -1, LVNI_SELECTED);
// "Insert will be always enabled"
hButton = GetDlgItem(hDlg, IDC_INSERT);
EnableWindow(hButton, TRUE);
// Enable/disable "Edit"
hButton = GetDlgItem(hDlg, IDC_EDIT);
EnableWindow(hButton, (nSelected == 1));
// Enable/disable "Delete"
hButton = GetDlgItem(hDlg, IDC_DELETE);
EnableWindow(hButton, (nSelected == 1));
// Enable/disable "Up"
hButton = GetDlgItem(hDlg, IDC_MOVE_UP);
EnableWindow(hButton, (nItem > 0));
// Enable/disable "Down"
hButton = GetDlgItem(hDlg, IDC_MOVE_DOWN);
EnableWindow(hButton, (0 <= nItem && nItem < (nItems - 1)));
return TRUE;
}
static int SetListViewEaEntry(
HWND hListView,
int nIndex,
PFILE_FULL_EA_INFORMATION pEaItem,
BOOL bInsertNew)
{
LVITEM lvi;
LPTSTR szEaName;
LPTSTR szEaValue;
LPTSTR szTemp;
PBYTE pbEaValue = (PBYTE)pEaItem->EaName + pEaItem->EaNameLength + 1;
TCHAR szEaSize[20];
size_t cchEaValue;
int i;
// -1 means insert to the end of the list
if(nIndex == -1)
nIndex = ListView_GetItemCount(hListView);
// Allocate buffer for EA name and convert the name
szEaName = new TCHAR[pEaItem->EaNameLength + 1];
for(i = 0; i < pEaItem->EaNameLength; i++)
szEaName[i] = pEaItem->EaName[i];
szEaName[i] = 0;
// Allocate buffer for EA value and convert the value
cchEaValue = (pEaItem->EaValueLength * 3) + 1;
szEaValue = szTemp = new TCHAR[cchEaValue];
if(szEaValue != NULL)
{
LPTSTR szEaValueEnd = szEaValue + cchEaValue;
for(i = 0; i < pEaItem->EaValueLength; i++)
StringCchPrintfEx(szTemp, (szEaValueEnd - szTemp), &szTemp, NULL, 0, _T("%02lX "), pbEaValue[i]);
szTemp[0] = 0;
// Set the main item
ZeroMemory(&lvi, sizeof(LVITEM));
lvi.mask = LVIF_TEXT | LVIF_PARAM;
lvi.iItem = nIndex;
lvi.pszText = szEaName;
lvi.lParam = (LPARAM)pEaItem;
// Insert or set the item
if(bInsertNew)
nIndex = ListView_InsertItem(hListView, &lvi);
else
ListView_SetItem(hListView, &lvi);
// Set the sub item text
StringCchPrintf(szEaSize, _countof(szEaSize), _T("0x%04X"), pEaItem->EaValueLength);
ListView_SetItemText(hListView, nIndex, 1, szEaSize);
// Set the sub item text
ListView_SetItemText(hListView, nIndex, 2, szEaValue);
delete [] szEaValue;
}
delete [] szEaName;
return TRUE;
}
//-----------------------------------------------------------------------------
// Dialog handlers
static int OnInitDialog(HWND hDlg, LPARAM lParam)
{
TOpenPacket * pOP = (TOpenPacket *)lParam;
HWND hListView = GetDlgItem(hDlg, IDC_EA_LIST);
// Save the user data
SetDialogData(hDlg, lParam);
CenterWindowToParent(hDlg);
// Initialize the listview
ListView_CreateColumns(hListView, Columns);
ListView_SetExtendedListViewStyle(hListView, LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP);
// Save the pointer to TFileTestData
if(lParam != 0)
ExtendedAttributesToListView(hDlg, pOP->pvFileEa);
// Initialize the listview
UpdateDialogButtons(hDlg);
return TRUE;
}
void MoveItem(HWND hDlg, BOOL bUp)
{
LVITEM lvi1;
LVITEM lvi2;
TCHAR szText1[MAX_PATH + 1] = _T("");
TCHAR szText2[MAX_PATH + 1] = _T("");
HWND hListView = GetDlgItem(hDlg, IDC_EA_LIST);
int nItems = ListView_GetItemCount(hListView);
int nItem1 = 0;
int nItem2 = 0;
if(bUp == FALSE)
{
nItem1 = ListView_GetNextItem(hListView, -1, LVNI_FOCUSED);
nItem2 = nItem1 + 1;
if(nItem1 == nItems - 1)
return;
}
else
{
nItem1 = ListView_GetNextItem(hListView, -1, LVNI_FOCUSED) - 1;
nItem2 = nItem1 + 1;
if(nItem1 < 0)
return;
}
// Disable redrawing during item acrobatics
EnableRedraw(hListView, FALSE);
// Retrieve the both items
ZeroMemory(&lvi1, sizeof(LVITEM));
lvi1.mask = LVIF_IMAGE | LVIF_STATE | LVIF_TEXT | LVIF_PARAM;
lvi1.stateMask = (UINT)-1;
lvi1.iItem = nItem1;
lvi1.pszText = szText1;
lvi1.cchTextMax = _countof(szText1);
ListView_GetItem(hListView, &lvi1);
ZeroMemory(&lvi2, sizeof(LVITEM));
lvi2.mask = LVIF_IMAGE | LVIF_STATE | LVIF_TEXT | LVIF_PARAM;
lvi2.stateMask = (UINT)-1;
lvi2.iItem = nItem2;
lvi2.pszText = szText2;
lvi2.cchTextMax = _countof(szText2);
ListView_GetItem(hListView, &lvi2);
// Switch the main items
lvi2.iItem = nItem1;
ListView_SetItem(hListView, &lvi2);
lvi1.iItem = nItem2;
ListView_SetItem(hListView, &lvi1);
// Switch the texts for the subitems
ListView_GetItemText(hListView, nItem1, 1, szText1, _countof(szText1));
ListView_GetItemText(hListView, nItem2, 1, szText2, _countof(szText2));
ListView_SetItemText(hListView, nItem1, 1, szText2);
ListView_SetItemText(hListView, nItem2, 1, szText1);
// Enable redrawing and redraw the window
EnableRedraw(hListView);
}
static int OnInsertEa(HWND hDlg)
{
PFILE_FULL_EA_INFORMATION pEaItem = NULL;
HWND hListView;
// Call the dialog for creating new EA
if(EaEditorDialog(hDlg, &pEaItem) != IDOK)
return TRUE;
// Insert listview
hListView = GetDlgItem(hDlg, IDC_EA_LIST);
SetListViewEaEntry(hListView, -1, pEaItem, TRUE);
UpdateDialogButtons(hDlg);
return TRUE;
}
static int OnEditEa(HWND hDlg)
{
PFILE_FULL_EA_INFORMATION pEaItem = NULL;
HWND hListView = GetDlgItem(hDlg, IDC_EA_LIST);
int nSelected = ListView_GetNextItem(hListView, -1, LVNI_SELECTED);
// If no item selected, do nothing
if(nSelected == -1)
return 0;
// Call the dialog for editing EA
pEaItem = (PFILE_FULL_EA_INFORMATION)ListView_GetItemParam(hListView, nSelected);
if(EaEditorDialog(hDlg, &pEaItem) != IDOK)
return TRUE;
SetListViewEaEntry(hListView, nSelected, pEaItem, FALSE);
UpdateDialogButtons(hDlg);
return TRUE;
}
static int OnDeleteEa(HWND hDlg)
{
HWND hListView = GetDlgItem(hDlg, IDC_EA_LIST);
int nSelected = ListView_GetNextItem(hListView, -1, LVNI_FOCUSED);
// If no item selected, do nothing
if(nSelected != -1)
ListView_DeleteItem(hListView, nSelected);
UpdateDialogButtons(hDlg);
return TRUE;
}
static int OnDoubleClick(HWND hDlg)
{
HWND hListView = GetDlgItem(hDlg, IDC_EA_LIST);
int nSelected = ListView_GetNextItem(hListView, -1, LVNI_SELECTED);
if(nSelected == -1)
OnInsertEa(hDlg);
else
OnEditEa(hDlg);
return TRUE;
}
static int OnLVKeyDown(HWND hDlg, NMLVKEYDOWN * pLVKeyDown)
{
switch(pLVKeyDown->wVKey)
{
case VK_INSERT:
return OnInsertEa(hDlg);
case VK_DELETE:
return OnDeleteEa(hDlg);
}
return FALSE;
}
static BOOL OnSaveDialog(HWND hDlg)
{
TOpenPacket * pOP = (TOpenPacket *)GetDialogData(hDlg);
if(pOP != NULL)
{
// Delete the existing EAs
pOP->Free();
// Create new extended attributes
ListViewToExtendedAttributes(hDlg, *pOP);
}
return TRUE;
}
static int OnDeleteItem(HWND /* hDlg */, LPNMLISTVIEW pNMListView)
{
PFILE_FULL_EA_INFORMATION pEaItem = (PFILE_FULL_EA_INFORMATION)pNMListView->lParam;
if(pEaItem != NULL)
delete [] pEaItem;
return TRUE;
}
static int OnCommand(HWND hDlg, UINT nNotify, UINT nIDCtrl)
{
if(nNotify == BN_CLICKED)
{
switch(nIDCtrl)
{
case IDC_MOVE_UP:
MoveItem(hDlg, TRUE);
return TRUE;
case IDC_MOVE_DOWN:
MoveItem(hDlg, FALSE);
return TRUE;
case IDC_INSERT:
OnInsertEa(hDlg);
return TRUE;
case IDC_EDIT:
OnEditEa(hDlg);
return TRUE;
case IDC_DELETE:
OnDeleteEa(hDlg);
return TRUE;
case IDOK:
OnSaveDialog(hDlg);
// No break here !!!
case IDCANCEL:
EndDialog(hDlg, nIDCtrl);
return TRUE;
}
}
return FALSE;
}
static int OnNotify(HWND hDlg, NMHDR * pNMHDR)
{
switch(pNMHDR->code)
{
case NM_DBLCLK:
if(pNMHDR->idFrom == IDC_EA_LIST)
return OnDoubleClick(hDlg);
break;
case LVN_KEYDOWN:
if(pNMHDR->idFrom == IDC_EA_LIST)
return OnLVKeyDown(hDlg, (NMLVKEYDOWN *)pNMHDR);
break;
case LVN_ITEMCHANGED:
if(pNMHDR->idFrom == IDC_EA_LIST)
return UpdateDialogButtons(hDlg);
break;
case LVN_DELETEITEM:
if(pNMHDR->idFrom == IDC_EA_LIST)
return OnDeleteItem(hDlg, (LPNMLISTVIEW)pNMHDR);
break;
}
return FALSE;
}
//-----------------------------------------------------------------------------
// Public functions
void ExtendedAttributesToListView(HWND hDlg, PFILE_FULL_EA_INFORMATION pFileEa)
{
PFILE_FULL_EA_INFORMATION pEaItemCopy;
PFILE_FULL_EA_INFORMATION pEaItem;
ULONG dwEaItemSize = 0;
HWND hListView = GetDlgItem(hDlg, IDC_EA_LIST);
ListView_DeleteAllItems(hListView);
// Load the listview with the extended attributes
if(pFileEa != NULL)
{
pEaItem = pFileEa;
for(;;)
{
// Create the EA copy and insert it to the list
dwEaItemSize = GetEaEntrySize(pEaItem);
pEaItemCopy = (PFILE_FULL_EA_INFORMATION)(new char [dwEaItemSize]);
CopyMemory(pEaItemCopy, pEaItem, dwEaItemSize);
pEaItemCopy->NextEntryOffset = dwEaItemSize;
SetListViewEaEntry(hListView, -1, pEaItemCopy, TRUE);
// Move to the next item
if(pEaItem->NextEntryOffset == 0)
break;
pEaItem = (PFILE_FULL_EA_INFORMATION)((PBYTE)pEaItem + pEaItem->NextEntryOffset);
}
}
}
DWORD ListViewToExtendedAttributes(HWND hDlg, TOpenPacket & OpenPacket)
{
PFILE_FULL_EA_INFORMATION pFileEaPtr;
PFILE_FULL_EA_INFORMATION pEaItem;
PFILE_FULL_EA_INFORMATION pvFileEa = NULL;
DWORD cbFileEa = 0;
HWND hListView = GetDlgItem(hDlg, IDC_EA_LIST);
int nItemCount = ListView_GetItemCount(hListView);
int nIndex;
// Calculate the buffer necessary to set the EA.
for(nIndex = 0; nIndex < nItemCount; nIndex++)
{
pEaItem = (PFILE_FULL_EA_INFORMATION)ListView_GetItemParam(hListView, nIndex);
if(pEaItem != NULL)
{
// The size of the previous EA item must be aligned to 4 bytes
cbFileEa = ALIGN_TO_SIZE(cbFileEa, sizeof(DWORD));
cbFileEa = cbFileEa + FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) + pEaItem->EaNameLength + 1 + pEaItem->EaValueLength;
}
}
// Allocate buffer for the complete EA list and copy the EAs to that buffer
pFileEaPtr = pvFileEa = (PFILE_FULL_EA_INFORMATION)HeapAlloc(g_hHeap, HEAP_ZERO_MEMORY, cbFileEa);
if(pvFileEa != NULL)
{
for(nIndex = 0; nIndex < nItemCount; nIndex++)
{
pEaItem = (PFILE_FULL_EA_INFORMATION)ListView_GetItemParam(hListView, nIndex);
if(pEaItem != NULL)
{
// Copy the EA item to the list. If this is the last item, we want NextEntryOffset to be zero
CopyEaItem(pFileEaPtr, pEaItem, (nIndex < (nItemCount - 1)));
// If this is the last item, we have to set zero as NextEntryOffset
pFileEaPtr = (PFILE_FULL_EA_INFORMATION)((LPBYTE)pFileEaPtr + pFileEaPtr->NextEntryOffset);
}
}
// Give the EAs tothe caller
OpenPacket.pvFileEa = pvFileEa;
OpenPacket.cbFileEa = cbFileEa;
return ERROR_SUCCESS;
}
else
{
OpenPacket.pvFileEa = NULL;
OpenPacket.cbFileEa = 0;
return ERROR_NOT_ENOUGH_MEMORY;
}
}
// Common dialog proc, shared by Page08Ea.cpp
// - Returns nonzero = message has been handled
// - Returns zero = message has NOT been handled
INT_PTR CALLBACK ExtendedAttributesEditorProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
return OnInitDialog(hDlg, lParam);
case WM_COMMAND:
return OnCommand(hDlg, HIWORD(wParam), LOWORD(wParam));
case WM_NOTIFY:
return OnNotify(hDlg, (NMHDR *)lParam);
}
return FALSE;
}
INT_PTR ExtendedAtributesEditorDialog(HWND hParent, TOpenPacket * pOP)
{
return DialogBoxParam(g_hInst,
MAKEINTRESOURCE(IDD_EAS_EDITOR),
hParent,
ExtendedAttributesEditorProc,
(LPARAM)pOP);
}