Hello,
Welcome to Microsoft Q&A!
Here is an example for your reference https://github.com/Microsoft/Windows-classic-samples/tree/main/Samples/CloudMirror
Generally, RequiredFileOffset and RequiredLength are used. If optionalFileOffset and optionalLength are used in the callback, it means that you need to deal with larger modules. This is just to provide you with an option. The specific data read in the callback needs to be set by yourself. Using these two parameters will not have any impact on normal reading. It is only the passed parameters, use or not use, Need to decide for yourself.
// In a nutshell, it copies a file from the "server" to the
// "client" using the overlapped trickery of Windows to
// chunkatize the copy. This way you don't have to allocate
// a huge buffer.
void FileCopierWithProgress::CopyFromServerToClientWorker(
_In_ CONST CF_CALLBACK_INFO* callbackInfo,
_In_opt_ CONST CF_PROCESS_INFO* processInfo,
_In_ LARGE_INTEGER requiredFileOffset,
_In_ LARGE_INTEGER requiredLength,
_In_ LARGE_INTEGER /*optionalFileOffset*/,
_In_ LARGE_INTEGER /*optionalLength*/,
_In_ CF_CALLBACK_FETCH_DATA_FLAGS /*fetchFlags*/,
_In_ UCHAR priorityHint,
_In_ LPCWSTR serverFolder)
{
HANDLE serverFileHandle;
std::wstring fullServerPath(serverFolder);
fullServerPath.append(L"\\");
fullServerPath.append(reinterpret_cast<wchar_t const*>(callbackInfo->FileIdentity));
std::wstring fullClientPath(callbackInfo->VolumeDosName);
fullClientPath.append(callbackInfo->NormalizedPath);
READ_COMPLETION_CONTEXT* readCompletionContext;
DWORD chunkBufferSize;
wprintf(L"[%04x:%04x] - Received data request from %s for %s%s, priority %d, offset %08x`%08x length %08x`%08x\n",
GetCurrentProcessId(),
GetCurrentThreadId(),
(processInfo && processInfo->ImagePath) ? processInfo->ImagePath : L"UNKNOWN",
callbackInfo->VolumeDosName,
callbackInfo->NormalizedPath,
priorityHint,
requiredFileOffset.HighPart,
requiredFileOffset.LowPart,
requiredLength.HighPart,
requiredLength.LowPart);
serverFileHandle =
CreateFile(
fullServerPath.c_str(),
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if (serverFileHandle == INVALID_HANDLE_VALUE)
{
HRESULT hr = NTSTATUS_FROM_WIN32(GetLastError());
wprintf(L"[%04x:%04x] - Failed to open %s for read, hr %x\n",
GetCurrentProcessId(),
GetCurrentThreadId(),
fullServerPath.c_str(),
hr);
winrt::check_hresult(hr);
}
// Allocate the buffer used in the overlapped read.
chunkBufferSize = (ULONG)min(requiredLength.QuadPart, CHUNKSIZE);
readCompletionContext = (READ_COMPLETION_CONTEXT*)
HeapAlloc(
GetProcessHeap(),
0,
chunkBufferSize + FIELD_OFFSET(READ_COMPLETION_CONTEXT, Buffer));
if (readCompletionContext == NULL)
{
HRESULT hr = E_OUTOFMEMORY;
wprintf(L"[%04x:%04x] - Failed to allocate read buffer for %s, hr %x\n",
GetCurrentProcessId(),
GetCurrentThreadId(),
fullServerPath.c_str(),
hr);
CloseHandle(serverFileHandle);
winrt::check_hresult(hr);
}
// Tell the read completion context where to copy the chunk(s)
wcsncpy_s(
readCompletionContext->FullPath,
fullClientPath.data(),
wcslen(fullClientPath.data()));
// Set up the remainder of the overlapped stuff
readCompletionContext->CallbackInfo = *callbackInfo;
readCompletionContext->Handle = serverFileHandle;
readCompletionContext->PriorityHint = priorityHint;
readCompletionContext->Overlapped.Offset = requiredFileOffset.LowPart;
readCompletionContext->Overlapped.OffsetHigh = requiredFileOffset.HighPart;
readCompletionContext->StartOffset = requiredFileOffset;
readCompletionContext->RemainingLength = requiredLength;
readCompletionContext->BufferSize = chunkBufferSize;
wprintf(L"[%04x:%04x] - Downloading data for %s, priority %d, offset %08x`%08x length %08x\n",
GetCurrentProcessId(),
GetCurrentThreadId(),
readCompletionContext->FullPath,
priorityHint,
requiredFileOffset.HighPart,
requiredFileOffset.LowPart,
chunkBufferSize);
// Initiate the read for the first chunk. When this async operation
// completes (failure or success), it will call the OverlappedCompletionRoutine
// above with that chunk. That OverlappedCompletionRoutine is responsible for
// subsequent ReadFileEx calls to read subsequent chunks. This is only for the
// first one
if (!ReadFileEx(
serverFileHandle,
readCompletionContext->Buffer,
chunkBufferSize,
&readCompletionContext->Overlapped,
OverlappedCompletionRoutine))
{
HRESULT hr = NTSTATUS_FROM_WIN32(GetLastError());
wprintf(L"[%04x:%04x] - Failed to perform async read for %s, Status %x\n",
GetCurrentProcessId(),
GetCurrentThreadId(),
fullServerPath.c_str(),
hr);
CloseHandle(serverFileHandle);
HeapFree(GetProcessHeap(), 0, readCompletionContext);
winrt::check_hresult(hr);
}
}
Thank you.
If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.