title: cfapi: cloud operation is invalid
body: <p>I'm making a <a href="https://docs.microsoft.com/vi-vn/windows/win32/cfapi/build-a-cloud-file-sync-engine" rel="nofollow noreferrer">Cloud Sync Engines Supports Placeholder</a> based on <a href="https://github.com/microsoft/Windows-classic-samples/tree/master/Samples/CloudMirror" rel="nofollow noreferrer">CloudMirror</a>. And got problem on <a href="https://github.com/microsoft/Windows-classic-samples/blob/master/Samples/CloudMirror/CloudMirror/FileCopierWithProgress.cpp#L65" rel="nofollow noreferrer">CF_CALLBACK_TYPE_FETCH_DATA</a></p>
  <p>When i double click file (placeholder) in window explorer, app trigger FILE_ATTRIBUTE_PINNED and <a href="https://github.com/microsoft/Windows-classic-samples/blob/master/Samples/CloudMirror/CloudMirror/CloudProviderSyncRootWatcher.cpp#L82" rel="nofollow noreferrer">Hydrating file</a>. And then cfapi call FETCH_DATA and read asynchronous file (my app work look same with CloudMirror).<br />
  But i got HRESULT return from CfExecute is <code>0x8007017c the cloud operation is invalid</code>. Debug look all value is true</p>
  <p>Then how to resolve it, thank.</p>
  <p><a href="https://i.stack.imgur.com/0z9Cb.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/0z9Cb.png" alt="enter image description here" /></a></p>
  <pre><code>#define CHUNKSIZE 4096
  #define FIELD_SIZE( type, field ) ( sizeof( ( (type*)0 )-&gt;field ) )
  #define CF_SIZE_OF_OP_PARAM( field )( FIELD_OFFSET( CF_OPERATION_PARAMETERS, field ) + FIELD_SIZE( CF_OPERATION_PARAMETERS, field ) )
      struct READ_COMPLETION_CONTEXT
      {
          OVERLAPPED Overlapped;
          LARGE_INTEGER CallbackInfo_FileSize;
          CF_CONNECTION_KEY CallbackInfo_ConnectionKey;
          CF_TRANSFER_KEY CallbackInfo_TransferKey;
          HANDLE PipeHandle{ 0 };
          LARGE_INTEGER StartOffset;
          LARGE_INTEGER RemainingLength;
          ULONG BufferSize;
  
          WCHAR* FullPath{ nullptr };
          BYTE* Buffer{ nullptr };
          ~READ_COMPLETION_CONTEXT()
          {
              if (FullPath) delete FullPath;
              if (Buffer) delete Buffer;
              if (PipeHandle) CloseHandle(PipeHandle);
          }
          void Cancel()
          {
              TransferData(
                  CallbackInfo_ConnectionKey, 
                  CallbackInfo_TransferKey,
                  NULL,
                  StartOffset,
                  RemainingLength,
                  STATUS_UNSUCCESSFUL);
          }
      };
      void CALLBACK FETCH_DATA(_In_ CONST CF_CALLBACK_INFO* callbackInfo, _In_ CONST CF_CALLBACK_PARAMETERS* callbackParameters)
      {
          try
          {
              //...
                  if (DownloadItem(/*call to c++\cli for stream download and copy async to pipe server*/))
                  {
                      std::wstring pipename(L&quot;\\\\.\\pipe\\&quot;);
                      pipename.append(ci-&gt;Id);
                      HANDLE hpipe = CreateFile(pipename.c_str(),
                          GENERIC_READ,
                          0,                  // no sharing 
                          NULL,               // default security attributes
                          OPEN_EXISTING,
                          FILE_FLAG_OVERLAPPED,
                          NULL);              // no template file 
                      if (hpipe != INVALID_HANDLE_VALUE)
                      {
                          if (GetLastError() != ERROR_PIPE_BUSY)
                          {
                              READ_COMPLETION_CONTEXT* readContext = new READ_COMPLETION_CONTEXT();
                              DWORD chunkBufferSize = (ULONG)min(callbackParameters-&gt;FetchData.RequiredLength.QuadPart, CHUNKSIZE);
  
                              std::wstring fullClientPath(callbackInfo-&gt;VolumeDosName);
                              fullClientPath.append(callbackInfo-&gt;NormalizedPath);
                              readContext-&gt;Overlapped.Offset = callbackParameters-&gt;FetchData.RequiredFileOffset.LowPart;
                              readContext-&gt;Overlapped.OffsetHigh = callbackParameters-&gt;FetchData.RequiredFileOffset.HighPart;
                              readContext-&gt;CallbackInfo_FileSize = callbackInfo-&gt;FileSize;
                              readContext-&gt;CallbackInfo_ConnectionKey = callbackInfo-&gt;ConnectionKey;
                              readContext-&gt;CallbackInfo_TransferKey = callbackInfo-&gt;TransferKey;
                              readContext-&gt;PipeHandle = hpipe;
                              readContext-&gt;StartOffset = callbackParameters-&gt;FetchData.RequiredFileOffset;
                              readContext-&gt;RemainingLength = callbackParameters-&gt;FetchData.RequiredLength;
                              readContext-&gt;BufferSize = chunkBufferSize;
                              readContext-&gt;FullPath = Utilities::WStringToWCHARP(fullClientPath);
                              readContext-&gt;Buffer = new BYTE[chunkBufferSize];
  
                              if (ReadFileEx(hpipe, readContext-&gt;Buffer, chunkBufferSize, &amp;readContext-&gt;Overlapped, OverlappedCompletionRoutine)) 
                                  if (GetLastError() == S_OK) return;
                              delete readContext;
                          }
                          else CloseHandle(hpipe);
                      }
                  }               
              }
          
          catch (...)
          {        
          }
          TransferData(
              callbackInfo-&gt;ConnectionKey,
              callbackInfo-&gt;TransferKey,
              NULL,
              callbackParameters-&gt;FetchData.RequiredFileOffset,
              callbackParameters-&gt;FetchData.RequiredLength,
              STATUS_UNSUCCESSFUL);
      }
      void CALLBACK CANCEL_FETCH_DATA(_In_ CONST CF_CALLBACK_INFO* callbackInfo,_In_ CONST CF_CALLBACK_PARAMETERS* callbackParameters)
      {
  
      }
  
      HRESULT TransferData(
          _In_ CF_CONNECTION_KEY connectionKey,
          _In_ LARGE_INTEGER transferKey,
          _In_reads_bytes_opt_(length.QuadPart) LPCVOID transferData,
          _In_ LARGE_INTEGER startingOffset,
          _In_ LARGE_INTEGER length,
          _In_ NTSTATUS completionStatus)
      {
          CF_OPERATION_INFO opInfo = { 0 };
          CF_OPERATION_PARAMETERS opParams = { 0 };
  
          opInfo.StructSize = sizeof(opInfo);
          opInfo.Type = CF_OPERATION_TYPE_TRANSFER_DATA;
          opInfo.ConnectionKey = connectionKey;
          opInfo.TransferKey = transferKey;
          opParams.ParamSize = CF_SIZE_OF_OP_PARAM(TransferData);
          opParams.TransferData.CompletionStatus = completionStatus;
          opParams.TransferData.Buffer = transferData;
          opParams.TransferData.Offset = startingOffset;
          opParams.TransferData.Length = length;
          HRESULT hresult = CfExecute(&amp;opInfo, &amp;opParams);
          return hresult;
      }
  
      void WINAPI OverlappedCompletionRoutine(
          _In_ DWORD errorCode,
          _In_ DWORD numberOfBytesTransfered,
          _Inout_ LPOVERLAPPED overlapped)
      {
          READ_COMPLETION_CONTEXT* readContext = (READ_COMPLETION_CONTEXT*)overlapped;
          if (errorCode == 0 &amp;&amp; !GetOverlappedResult(readContext-&gt;PipeHandle, overlapped, &amp;numberOfBytesTransfered, TRUE)) errorCode = GetLastError();
  
          if (errorCode != 0)
          {
              readContext-&gt;Cancel();
              delete readContext;
              return;
          }
  
          assert(numberOfBytesTransfered != 0);
  
          LONGLONG total = readContext-&gt;CallbackInfo_FileSize.QuadPart;
          LONGLONG completed = readContext-&gt;StartOffset.QuadPart + numberOfBytesTransfered;
  
          Utilities::ApplyTransferStateToFile(readContext-&gt;FullPath,
              readContext-&gt;CallbackInfo_ConnectionKey,
              readContext-&gt;CallbackInfo_TransferKey,
              total,
              completed);
  
          HRESULT hresult = TransferData(
              readContext-&gt;CallbackInfo_ConnectionKey,
              readContext-&gt;CallbackInfo_TransferKey,
              errorCode == 0 ? readContext-&gt;Buffer : NULL,
              readContext-&gt;StartOffset,
              Utilities::LongLongToLargeInteger(numberOfBytesTransfered),
              errorCode);
          if (hresult != S_OK)
          {
              readContext-&gt;Cancel();
              delete readContext;
              winrt::check_hresult(hresult);
              return;
          }
  
          readContext-&gt;StartOffset.QuadPart += numberOfBytesTransfered;
          readContext-&gt;RemainingLength.QuadPart -= numberOfBytesTransfered;
  
          if (readContext-&gt;RemainingLength.QuadPart &gt; 0)
          {
              DWORD bytesToRead = (DWORD)(min(readContext-&gt;RemainingLength.QuadPart, readContext-&gt;BufferSize));
              readContext-&gt;Overlapped.Offset = readContext-&gt;StartOffset.LowPart;
              readContext-&gt;Overlapped.OffsetHigh = readContext-&gt;StartOffset.HighPart;
  
              if (!ReadFileEx(readContext-&gt;PipeHandle, readContext-&gt;Buffer, bytesToRead, &amp;readContext-&gt;Overlapped, OverlappedCompletionRoutine))
              {
                  readContext-&gt;Cancel();
                  delete readContext;
              }
          }
          else delete readContext;//done
      }
  </code></pre>
  <hr />
  <p>Edit: After test, fake byteread = 4096 it running successful.
  Then, how much the min limit of data transfer?</p>