mirror of
https://github.com/ladislav-zezula/FileTest
synced 2026-06-08 15:24:12 +00:00
647 lines
22 KiB
C++
647 lines
22 KiB
C++
/*****************************************************************************/
|
|
/* Page03ReadWrite.cpp Copyright (c) Ladislav Zezula 2004 */
|
|
/*---------------------------------------------------------------------------*/
|
|
/* This module handles both "ReadFile" and "WriteFile" pages */
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Date Ver Who Comment */
|
|
/* -------- ---- --- ------- */
|
|
/* 06.03.04 1.00 Lad The first version of Page03ReadWrite.cpp */
|
|
/*****************************************************************************/
|
|
|
|
#include "FileTest.h"
|
|
#include "resource.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Local defines
|
|
|
|
#define INITIAL_DATA_BUFFER_SIZE 0x10000
|
|
|
|
typedef NTSTATUS (NTAPI * NTREADWRITE)(
|
|
IN HANDLE FileHandle,
|
|
IN HANDLE Event OPTIONAL,
|
|
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
|
|
IN PVOID ApcContext OPTIONAL,
|
|
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
|
OUT PVOID Buffer,
|
|
IN ULONG Length,
|
|
IN PLARGE_INTEGER ByteOffset OPTIONAL,
|
|
IN PULONG Key OPTIONAL
|
|
);
|
|
|
|
typedef BOOL (WINAPI * READWRITE)(
|
|
IN HANDLE hFile,
|
|
IN LPVOID lpBuffer,
|
|
IN DWORD nNumberOfBytesToRead,
|
|
OUT LPDWORD lpNumberOfBytesRead,
|
|
IN LPOVERLAPPED lpOverlapped
|
|
);
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Helper functions
|
|
|
|
static void CompleteAsynchronousOperation(HWND hDlg, TApcEntry * pApc, DWORD dwErrCode, DWORD dwTransferred)
|
|
{
|
|
TFileTestData * pData = GetDialogData(hDlg);
|
|
HWND hWndEditor;
|
|
|
|
// Convert the error code and number of bytes transferred
|
|
if(pApc->bAsynchronousCompletion)
|
|
{
|
|
if(pApc->bHasIoStatus == false)
|
|
{
|
|
if(!GetOverlappedResult(pData->hFile, &pApc->Overlapped, &dwTransferred, TRUE))
|
|
dwErrCode = GetLastError();
|
|
else
|
|
dwErrCode = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
dwErrCode = RtlNtStatusToDosError(pApc->IoStatus.Status);
|
|
dwTransferred = (DWORD)pApc->IoStatus.Information;
|
|
}
|
|
}
|
|
|
|
// If the operation has succeeded, update few UI elements
|
|
if(dwErrCode == ERROR_SUCCESS)
|
|
{
|
|
// If the "increase position" is checked, increment the byte position
|
|
if(pApc->bIncrementPosition)
|
|
{
|
|
pApc->ByteOffset.QuadPart += dwTransferred;
|
|
Hex2DlgText64(hDlg, IDC_BYTE_OFFSET, pApc->ByteOffset.QuadPart);
|
|
}
|
|
|
|
// If we have an output buffer, copy it to the data buffer
|
|
if(pApc->BufferLength)
|
|
{
|
|
// Copy the data buffer from the APC to our user buffer
|
|
pData->RdWrData.SetLength(pApc->BufferLength);
|
|
memcpy(pData->RdWrData.pbData, (pApc + 1), pData->RdWrData.cbData);
|
|
|
|
hWndEditor = GetDlgItem(hDlg, IDC_FILE_DATA);
|
|
DataEditor_SetData(hWndEditor, 0, pData->RdWrData.pbData, pData->RdWrData.cbData);
|
|
}
|
|
}
|
|
|
|
// Set the information about the operation
|
|
if(pApc->bHasIoStatus)
|
|
{
|
|
SetResultInfo(hDlg, pApc->UserParam, pApc->IoStatus.Status, &pApc->IoStatus);
|
|
}
|
|
else
|
|
{
|
|
SetResultInfo(hDlg, pApc->UserParam, dwErrCode, dwTransferred);
|
|
}
|
|
|
|
// Free the APC entry
|
|
FreeApcEntry(pApc);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Message handlers
|
|
|
|
static TAnchors * pAnchors = NULL;
|
|
|
|
static int OnInitDialog(HWND hDlg, LPARAM lParam)
|
|
{
|
|
PROPSHEETPAGE * pPage = (PROPSHEETPAGE *)lParam;
|
|
TFileTestData * pData = (TFileTestData *)pPage->lParam;
|
|
HWND hWndChild;
|
|
|
|
SetDialogData(hDlg, pPage->lParam);
|
|
|
|
// Configure dialog resizing
|
|
if(pData->bEnableResizing)
|
|
{
|
|
pAnchors = new TAnchors(hDlg);
|
|
pAnchors->AddAnchor(hDlg, IDC_BYTE_OFFSET_TITLE, akLeft | akTop | akRightCenter);
|
|
pAnchors->AddAnchor(hDlg, IDC_BYTE_OFFSET, akLeft | akTop | akRightCenter);
|
|
pAnchors->AddAnchor(hDlg, IDC_BYTE_OFFSET_SPIN, akTop | akRightCenter);
|
|
pAnchors->AddAnchor(hDlg, IDC_LENGTH_TITLE, akLeftCenter | akTop | akRight);
|
|
pAnchors->AddAnchor(hDlg, IDC_LENGTH, akLeftCenter | akTop | akRight);
|
|
pAnchors->AddAnchor(hDlg, IDC_LENGTH_SPIN, akTop | akRight);
|
|
pAnchors->AddAnchor(hDlg, IDC_INCREASE_FILEPOS, akLeft | akTop | akRight);
|
|
pAnchors->AddAnchor(hDlg, IDC_READ_FILE, akLeft | akTop);
|
|
pAnchors->AddAnchor(hDlg, IDC_WRITE_FILE, akTop | akRightCenter);
|
|
pAnchors->AddAnchor(hDlg, IDC_NTREAD_FILE, akLeftCenter | akTop);
|
|
pAnchors->AddAnchor(hDlg, IDC_NTWRITE_FILE, akRight | akTop);
|
|
pAnchors->AddAnchor(hDlg, IDC_LOCK_FILE, akLeft | akTop);
|
|
pAnchors->AddAnchor(hDlg, IDC_UNLOCK_FILE, akTop | akRightCenter);
|
|
pAnchors->AddAnchor(hDlg, IDC_NTLOCK_FILE, akLeftCenter | akTop);
|
|
pAnchors->AddAnchor(hDlg, IDC_NTUNLOCK_FILE, akRight | akTop);
|
|
pAnchors->AddAnchor(hDlg, IDC_FILL_DATA_MENU, akLeft | akTop);
|
|
pAnchors->AddAnchor(hDlg, IDC_GET_FILE_SIZE, akTop | akRightCenter);
|
|
pAnchors->AddAnchor(hDlg, IDC_SET_FILE_POINTER, akLeftCenter | akTop);
|
|
pAnchors->AddAnchor(hDlg, IDC_SET_END_OF_FILE, akTop | akRight);
|
|
pAnchors->AddAnchor(hDlg, IDC_FILE_DATA, akAll);
|
|
pAnchors->AddAnchor(hDlg, IDC_RESULT_FRAME, akLeft | akRight | akBottom);
|
|
pAnchors->AddAnchor(hDlg, IDC_ERROR_CODE_TITLE, akLeft | akBottom);
|
|
pAnchors->AddAnchor(hDlg, IDC_ERROR_CODE, akLeft | akRight | akBottom);
|
|
pAnchors->AddAnchor(hDlg, IDC_INFORMATION_TITLE, akLeft | akBottom);
|
|
pAnchors->AddAnchor(hDlg, IDC_INFORMATION, akLeft | akRight | akBottom);
|
|
}
|
|
|
|
// If there's field for data buffer, sets it to 8 bytes per line
|
|
hWndChild = GetDlgItem(hDlg, IDC_FILE_DATA);
|
|
if(hWndChild != NULL)
|
|
DataEditor_SetDataFormat(hWndChild, PtrPointer32Bit, 0x08);
|
|
|
|
// Set initial values for file position and data
|
|
Hex2DlgText64(hDlg, IDC_BYTE_OFFSET, 0);
|
|
Hex2DlgText32(hDlg, IDC_LENGTH, INITIAL_DATA_BUFFER_SIZE);
|
|
return TRUE;
|
|
}
|
|
|
|
static int OnSetActive(HWND hDlg)
|
|
{
|
|
TFileTestData * pData = GetDialogData(hDlg);
|
|
BOOL bEnable = FALSE;
|
|
|
|
if(IsHandleValid(pData->hFile))
|
|
bEnable = TRUE;
|
|
|
|
EnableDlgItems(hDlg, bEnable, IDC_READ_FILE,
|
|
IDC_WRITE_FILE,
|
|
IDC_NTREAD_FILE,
|
|
IDC_NTWRITE_FILE,
|
|
IDC_LOCK_FILE,
|
|
IDC_UNLOCK_FILE,
|
|
IDC_NTLOCK_FILE,
|
|
IDC_NTUNLOCK_FILE,
|
|
IDC_GET_FILE_SIZE,
|
|
IDC_SET_FILE_POINTER,
|
|
IDC_SET_END_OF_FILE,
|
|
0);
|
|
return TRUE;
|
|
}
|
|
|
|
static int OnUpdateByteOffset(HWND hDlg)
|
|
{
|
|
TFileTestData * pData = GetDialogData(hDlg);
|
|
LONGLONG BaseAddress = 0;
|
|
HWND hWndChild;
|
|
|
|
// Convert the byte offset
|
|
if(DlgText2Hex64(hDlg, IDC_BYTE_OFFSET, &BaseAddress) == ERROR_SUCCESS)
|
|
{
|
|
if((hWndChild = GetDlgItem(hDlg, IDC_FILE_DATA)) != NULL)
|
|
{
|
|
DataEditor_SetData(hWndChild, BaseAddress, pData->RdWrData.pbData, pData->RdWrData.cbData);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static int UpdateLength(HWND hDlg)
|
|
{
|
|
TFileTestData * pData = GetDialogData(hDlg);
|
|
DWORD DataLength = 0;
|
|
HWND hWndChild;
|
|
|
|
// Convert the length
|
|
if(DlgText2Hex32(hDlg, IDC_LENGTH, &DataLength) == ERROR_SUCCESS)
|
|
{
|
|
if((hWndChild = GetDlgItem(hDlg, IDC_FILE_DATA)) != NULL)
|
|
{
|
|
pData->RdWrData.SetLength(DataLength);
|
|
DataEditor_SetData(hWndChild, 0, pData->RdWrData.pbData, pData->RdWrData.cbData);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static int OnFillData(HWND hDlg, UINT FillPattern)
|
|
{
|
|
TFileTestData * pData = GetDialogData(hDlg);
|
|
LPCSTR WritePattern = "BAADF00D";
|
|
HWND hWndChild;
|
|
|
|
// If the new pattern is zero, it means to fill the same pattern like before
|
|
if(FillPattern == 0)
|
|
FillPattern = pData->FillPattern;
|
|
|
|
switch(FillPattern)
|
|
{
|
|
case IDC_FILL_DATA_ZEROS:
|
|
memset(pData->RdWrData.pbData, 0, pData->RdWrData.cbData);
|
|
break;
|
|
|
|
case IDC_FILL_DATA_PATTERN:
|
|
for(ULONG i = 0; i < pData->RdWrData.cbData; i++)
|
|
pData->RdWrData.pbData[i] = WritePattern[i % 8];
|
|
break;
|
|
|
|
case IDC_FILL_DATA_RANDOM:
|
|
srand(GetTickCount());
|
|
for(ULONG i = 0; i < pData->RdWrData.cbData; i++)
|
|
pData->RdWrData.pbData[i] = (BYTE)(rand() % 0x100);
|
|
break;
|
|
}
|
|
|
|
// Remember the current pattern
|
|
pData->FillPattern = FillPattern;
|
|
|
|
// Apply the new file data
|
|
if((hWndChild = GetDlgItem(hDlg, IDC_FILE_DATA)) != NULL)
|
|
{
|
|
DataEditor_SetData(hWndChild, 0, pData->RdWrData.pbData, pData->RdWrData.cbData);
|
|
}
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
static int OnDeltaPos(HWND hDlg, NMUPDOWN * pNMUpDown)
|
|
{
|
|
LONGLONG ByteOffset = 0;
|
|
DWORD Length = 0;
|
|
|
|
if(pNMUpDown->hdr.idFrom == IDC_BYTE_OFFSET_SPIN)
|
|
{
|
|
DlgText2Hex64(hDlg, IDC_BYTE_OFFSET, &ByteOffset);
|
|
ByteOffset -= pNMUpDown->iDelta * 0x10000;
|
|
if(ByteOffset < 0)
|
|
ByteOffset = 0;
|
|
Hex2DlgText64(hDlg, IDC_BYTE_OFFSET, ByteOffset);
|
|
}
|
|
|
|
if(pNMUpDown->hdr.idFrom == IDC_LENGTH_SPIN)
|
|
{
|
|
DlgText2Hex32(hDlg, IDC_LENGTH, &Length);
|
|
Length -= pNMUpDown->iDelta * 0x1000;
|
|
if((int)Length < 0)
|
|
Length = 0;
|
|
Hex2DlgText32(hDlg, IDC_LENGTH, Length);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static int OnDataPaste(HWND hDlg, PDTE_PASTE_DATA pPasteData)
|
|
{
|
|
// Ask the user whether to cut the data or not
|
|
if(MessageBoxRc(hDlg, IDS_QUESTION, IDS_WANT_TRIM_DATA) == IDYES)
|
|
{
|
|
TFileTestData * pData = GetDialogData(hDlg);
|
|
SIZE_T nLength = strlen(pPasteData->szPasteText);
|
|
|
|
// Paste the data to the view
|
|
if(pData->RdWrData.SetLength(pPasteData->PasteOffset + nLength) == ERROR_SUCCESS)
|
|
{
|
|
memcpy(pData->RdWrData.pbData + pPasteData->PasteOffset, pPasteData->szPasteText, nLength);
|
|
DataEditor_SetData(GetDlgItem(hDlg, IDC_FILE_DATA), 0, pData->RdWrData.pbData, pData->RdWrData.cbData);
|
|
Hex2DlgText32(hDlg, IDC_LENGTH, (DWORD)(pPasteData->PasteOffset + nLength));
|
|
}
|
|
|
|
// Mark the request as handled, so the data editor stops fuhrter processing
|
|
pPasteData->bHandled = TRUE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static int OnReadWriteFile(HWND hDlg, int nIDCtrl)
|
|
{
|
|
TFileTestData * pData = GetDialogData(hDlg);
|
|
LARGE_INTEGER ByteOffset = {0};
|
|
NTREADWRITE NtReadWrite;
|
|
READWRITE ReadWrite;
|
|
TApcEntry * pApc;
|
|
NTSTATUS Status;
|
|
LPBYTE DataBuffer;
|
|
LPBYTE ApcBuffer;
|
|
DWORD dwTransferred = 0;
|
|
DWORD OutputLength = 0;
|
|
DWORD dwErrCode = ERROR_SUCCESS;
|
|
DWORD Length = 0;
|
|
|
|
// Get the start position
|
|
DlgText2Hex64(hDlg, IDC_BYTE_OFFSET, &ByteOffset.QuadPart);
|
|
DlgText2Hex32(hDlg, IDC_LENGTH, &Length);
|
|
assert(pData->RdWrData.cbData >= Length);
|
|
|
|
// For read operation, we have data in the APC
|
|
if(nIDCtrl == IDC_READ_FILE || nIDCtrl == IDC_NTREAD_FILE)
|
|
OutputLength = Length;
|
|
|
|
// Create new APC entry
|
|
pApc = CreateApcEntry(pData, APC_TYPE_READ_WRITE, OutputLength);
|
|
if(pApc != NULL)
|
|
{
|
|
// Remember the state of "Increment position"
|
|
pApc->ByteOffset = ByteOffset;
|
|
pApc->bIncrementPosition = (IsDlgButtonChecked(hDlg, IDC_INCREASE_FILEPOS) == BST_CHECKED);
|
|
pApc->BufferLength = OutputLength;
|
|
ApcBuffer = (LPBYTE)(pApc + 1);
|
|
|
|
// Prepare the OVERLAPPED structure
|
|
pApc->Overlapped.OffsetHigh = ByteOffset.HighPart;
|
|
pApc->Overlapped.Offset = ByteOffset.LowPart;
|
|
|
|
// Perform the appropriate API
|
|
switch(nIDCtrl)
|
|
{
|
|
case IDC_READ_FILE:
|
|
case IDC_WRITE_FILE:
|
|
|
|
// Set the data buffer and appropriate API function
|
|
pApc->UserParam = (nIDCtrl == IDC_READ_FILE) ? (RSI_LAST_ERROR | RSI_READ) : (RSI_LAST_ERROR | RSI_WRITTEN);
|
|
DataBuffer = (nIDCtrl == IDC_READ_FILE) ? ApcBuffer : pData->RdWrData.pbData;
|
|
ReadWrite = (nIDCtrl == IDC_READ_FILE) ? ReadFile : (READWRITE)WriteFile;
|
|
|
|
// Perform the read operation using ReadFile
|
|
if(!ReadWrite(pData->hFile, DataBuffer, Length, &dwTransferred, &pApc->Overlapped))
|
|
dwErrCode = GetLastError();
|
|
|
|
// If the read operation ended with ERROR_IO_PENDING, queue the APC
|
|
if(dwErrCode == ERROR_IO_PENDING)
|
|
{
|
|
SetResultInfo(hDlg, pApc->UserParam, ERROR_IO_PENDING, 0);
|
|
InsertApcEntry(pData, pApc);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
case IDC_NTREAD_FILE:
|
|
case IDC_NTWRITE_FILE:
|
|
|
|
// Set the data buffer and appropriate API function
|
|
pApc->UserParam = RSI_NTSTATUS | RSI_INFORMATION;
|
|
DataBuffer = (nIDCtrl == IDC_NTREAD_FILE) ? ApcBuffer : pData->RdWrData.pbData;
|
|
NtReadWrite = (nIDCtrl == IDC_NTREAD_FILE) ? NtReadFile : NtWriteFile;
|
|
pApc->bHasIoStatus = TRUE;
|
|
|
|
// Perform the read/write operation
|
|
Status = NtReadWrite(pData->hFile,
|
|
pApc->hEvent,
|
|
NULL,
|
|
NULL,
|
|
&pApc->IoStatus,
|
|
DataBuffer,
|
|
Length,
|
|
&ByteOffset,
|
|
NULL);
|
|
|
|
// If the read operation ended with STATUS_PENDING, queue the APC
|
|
if(Status == STATUS_PENDING)
|
|
{
|
|
SetResultInfo(hDlg, pApc->UserParam, STATUS_PENDING, &pApc->IoStatus);
|
|
InsertApcEntry(pData, pApc);
|
|
return TRUE;
|
|
}
|
|
|
|
pApc->IoStatus.Status = Status;
|
|
break;
|
|
}
|
|
|
|
// Complete the read/write operation
|
|
CompleteAsynchronousOperation(hDlg, pApc, dwErrCode, dwTransferred);
|
|
}
|
|
else
|
|
{
|
|
SetResultInfo(hDlg, RSI_LAST_ERROR | RSI_NOINFO, GetLastError());
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static int OnLockUnlockFile(HWND hDlg, int nReadWriteType)
|
|
{
|
|
TFileTestData * pData = GetDialogData(hDlg);
|
|
LARGE_INTEGER ByteOffset = {0};
|
|
LARGE_INTEGER LockLength = {0};
|
|
TApcEntry * pApc;
|
|
NTSTATUS Status;
|
|
DWORD dwErrCode = ERROR_SUCCESS;
|
|
|
|
// Get the start position
|
|
DlgText2Hex64(hDlg, IDC_BYTE_OFFSET, &ByteOffset.QuadPart);
|
|
DlgText2Hex32(hDlg, IDC_LENGTH, &LockLength.LowPart);
|
|
assert((LONGLONG)pData->RdWrData.cbData >= LockLength.QuadPart);
|
|
|
|
// Create new APC entry
|
|
pApc = CreateApcEntry(pData, APC_TYPE_LOCK_UNLOCK);
|
|
if(pApc != NULL)
|
|
{
|
|
// Perform the I/O operation
|
|
switch(nReadWriteType)
|
|
{
|
|
case IDC_LOCK_FILE:
|
|
|
|
// Prepare flags for completion
|
|
pApc->UserParam = RSI_LAST_ERROR | RSI_NOINFO;
|
|
|
|
// Perform the lock operation using LockFile
|
|
if(!LockFile(pData->hFile, ByteOffset.LowPart, ByteOffset.HighPart, LockLength.LowPart, LockLength.HighPart))
|
|
dwErrCode = GetLastError();
|
|
break;
|
|
|
|
case IDC_UNLOCK_FILE:
|
|
|
|
// Prepare flags for completion
|
|
pApc->UserParam = RSI_LAST_ERROR | RSI_NOINFO;
|
|
|
|
// Perform the unlock operation using UnlockFile
|
|
if(!UnlockFile(pData->hFile, ByteOffset.LowPart, ByteOffset.HighPart, LockLength.LowPart, LockLength.HighPart))
|
|
dwErrCode = GetLastError();
|
|
break;
|
|
|
|
case IDC_NTLOCK_FILE:
|
|
|
|
// Remember that this is a native call
|
|
pApc->UserParam = RSI_NTSTATUS | RSI_NOINFO;
|
|
pApc->bHasIoStatus = TRUE;
|
|
|
|
// Perform the lock operation using NtLockFile
|
|
Status = NtLockFile(pData->hFile,
|
|
pApc->hEvent,
|
|
NULL,
|
|
NULL,
|
|
&pApc->IoStatus,
|
|
&ByteOffset,
|
|
&LockLength,
|
|
0,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
// If the lock operation ended with STATUS_PENDING, queue the APC
|
|
if(Status == STATUS_PENDING)
|
|
{
|
|
SetResultInfo(hDlg, RSI_NTSTATUS | RSI_NOINFO, STATUS_PENDING);
|
|
InsertApcEntry(pData, pApc);
|
|
return TRUE;
|
|
}
|
|
|
|
// Save the error
|
|
pApc->IoStatus.Status = Status;
|
|
break;
|
|
|
|
case IDC_NTUNLOCK_FILE:
|
|
|
|
// Remember that this is a native call
|
|
pApc->UserParam = RSI_NTSTATUS | RSI_NOINFO;
|
|
pApc->bHasIoStatus = TRUE;
|
|
|
|
// Perform the unlock operation using NtUnlockFile
|
|
Status = NtUnlockFile(pData->hFile,
|
|
&pApc->IoStatus,
|
|
&ByteOffset,
|
|
&LockLength,
|
|
0);
|
|
// Save the error
|
|
assert(Status != STATUS_PENDING);
|
|
pApc->IoStatus.Status = Status;
|
|
break;
|
|
}
|
|
|
|
// Set the information about the operation
|
|
CompleteAsynchronousOperation(hDlg, pApc, dwErrCode, 0);
|
|
}
|
|
else
|
|
{
|
|
SetResultInfo(hDlg, RSI_LAST_ERROR | RSI_NOINFO, GetLastError());
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static int OnGetFileSizeClick(HWND hDlg)
|
|
{
|
|
TFileTestData * pData = GetDialogData(hDlg);
|
|
LARGE_INTEGER FileSize = {0};
|
|
DWORD dwErrCode = ERROR_SUCCESS;
|
|
|
|
// Get the file size
|
|
SetLastError(ERROR_SUCCESS);
|
|
FileSize.LowPart = GetFileSize(pData->hFile, (LPDWORD)&FileSize.HighPart);
|
|
dwErrCode = GetLastError();
|
|
|
|
SetResultInfo(hDlg, RSI_LAST_ERROR | RSI_FILESIZE, dwErrCode, &FileSize);
|
|
return TRUE;
|
|
}
|
|
|
|
static int OnSetFilePointerClick(HWND hDlg)
|
|
{
|
|
TFileTestData * pData = GetDialogData(hDlg);
|
|
LARGE_INTEGER ByteOffset;
|
|
DWORD dwErrCode = ERROR_SUCCESS;
|
|
|
|
// Get the file offset from the dialog
|
|
DlgText2Hex64(hDlg, IDC_BYTE_OFFSET, &ByteOffset.QuadPart);
|
|
|
|
// Apply the file size
|
|
SetLastError(ERROR_SUCCESS);
|
|
ByteOffset.LowPart = SetFilePointer(pData->hFile, ByteOffset.LowPart, &ByteOffset.HighPart, FILE_BEGIN);
|
|
dwErrCode = GetLastError();
|
|
|
|
SetResultInfo(hDlg, RSI_LAST_ERROR | RSI_FILEPOS, dwErrCode, &ByteOffset);
|
|
return TRUE;
|
|
}
|
|
|
|
static int OnSetEndOfFileClick(HWND hDlg)
|
|
{
|
|
TFileTestData * pData = GetDialogData(hDlg);
|
|
DWORD dwErrCode = ERROR_SUCCESS;
|
|
|
|
if(!SetEndOfFile(pData->hFile))
|
|
dwErrCode = GetLastError();
|
|
|
|
SetResultInfo(hDlg, RSI_LAST_ERROR | RSI_NOINFO, dwErrCode);
|
|
return TRUE;
|
|
}
|
|
|
|
static int OnCommand(HWND hDlg, UINT nNotify, UINT nIDCtrl)
|
|
{
|
|
if(nNotify == BN_CLICKED)
|
|
{
|
|
switch(nIDCtrl)
|
|
{
|
|
case IDC_READ_FILE:
|
|
case IDC_WRITE_FILE:
|
|
case IDC_NTREAD_FILE:
|
|
case IDC_NTWRITE_FILE:
|
|
return OnReadWriteFile(hDlg, nIDCtrl);
|
|
|
|
case IDC_LOCK_FILE:
|
|
case IDC_UNLOCK_FILE:
|
|
case IDC_NTLOCK_FILE:
|
|
case IDC_NTUNLOCK_FILE:
|
|
return OnLockUnlockFile(hDlg, nIDCtrl);
|
|
|
|
case IDC_FILL_DATA_MENU:
|
|
return ExecuteContextMenuForDlgItem(hDlg, FindContextMenu(IDR_FILL_DATA_MENU), IDC_FILL_DATA_MENU);
|
|
|
|
case IDC_FILL_DATA_ZEROS:
|
|
case IDC_FILL_DATA_PATTERN:
|
|
case IDC_FILL_DATA_RANDOM:
|
|
return OnFillData(hDlg, nIDCtrl);
|
|
|
|
case IDC_GET_FILE_SIZE:
|
|
return OnGetFileSizeClick(hDlg);
|
|
|
|
case IDC_SET_FILE_POINTER:
|
|
return OnSetFilePointerClick(hDlg);
|
|
|
|
case IDC_SET_END_OF_FILE:
|
|
return OnSetEndOfFileClick(hDlg);
|
|
}
|
|
}
|
|
|
|
if(nNotify == EN_CHANGE)
|
|
{
|
|
if(nIDCtrl == IDC_BYTE_OFFSET)
|
|
return OnUpdateByteOffset(hDlg);
|
|
if(nIDCtrl == IDC_LENGTH)
|
|
UpdateLength(hDlg);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static int OnNotify(HWND hDlg, NMHDR * pNMHDR)
|
|
{
|
|
switch(pNMHDR->code)
|
|
{
|
|
case PSN_SETACTIVE:
|
|
return OnSetActive(hDlg);
|
|
|
|
case UDN_DELTAPOS:
|
|
return OnDeltaPos(hDlg, (NMUPDOWN *)pNMHDR);
|
|
|
|
case DEN_PASTE:
|
|
return OnDataPaste(hDlg, (PDTE_PASTE_DATA)pNMHDR);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Public functions
|
|
|
|
INT_PTR CALLBACK PageProc03(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch(uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
return OnInitDialog(hDlg, lParam);
|
|
|
|
case WM_SIZE:
|
|
return pAnchors->OnMessage(uMsg, wParam, lParam);
|
|
|
|
case WM_APC:
|
|
CompleteAsynchronousOperation(hDlg, (TApcEntry *)lParam, 0, 0);
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
return OnCommand(hDlg, HIWORD(wParam), LOWORD(wParam));
|
|
|
|
case WM_NOTIFY:
|
|
return OnNotify(hDlg, (NMHDR *)lParam);
|
|
|
|
case WM_DESTROY:
|
|
if(pAnchors != NULL)
|
|
delete pAnchors;
|
|
pAnchors = NULL;
|
|
return FALSE;
|
|
}
|
|
return FALSE;
|
|
}
|