dokan-dev / dokany

User mode file system library for windows with FUSE Wrapper
http://dokan-dev.github.io
5.21k stars 661 forks source link

dokan limit speed, but windows10 pop-up never displays progress #1233

Closed zhongguo1987 closed 1 month ago

zhongguo1987 commented 1 month ago

I want to implement a file copying speed limit for Dokan。Specially modified the DispatcheWrite function in write. c of the dokan dll project。Copy the file successfully,But the Windows pop-up window never displays progress information.why,thank you

微信图片_20240724133644

DispatcheWrite is modified as follows

#define MIN(i, j) (((i) < (j)) ? (i) : (j))
#define SPEED_LIMIT (128 * 1024)  

VOID DispatchWrite(PDOKAN_IO_EVENT IoEvent) {
  PDOKAN_IO_BATCH writeIoBatch = IoEvent->IoBatch;
  ULONG writtenLength = 0;
  NTSTATUS status = STATUS_SUCCESS;

  CreateDispatchCommon(IoEvent, 0, /*UseExtraMemoryPool=*/FALSE,
                       /*ClearNonPoolBuffer=*/TRUE);

  CheckFileName(IoEvent->EventContext->Operation.Write.FileName);
  DbgPrint(
      "###WriteFile file handle = 0x%p, eventID = %04d, event Info = 0x%p\n",
      IoEvent->DokanOpenInfo,
      IoEvent->DokanOpenInfo != NULL ? IoEvent->DokanOpenInfo->EventId : -1,
      IoEvent);

  // Since driver requested bigger memory,
  // allocate enough memory and send it to driver
  if (IoEvent->EventContext->Operation.Write.RequestLength > 0) {
    DWORD error = SendWriteRequest(
        IoEvent, IoEvent->EventContext->Operation.Write.RequestLength,
        &writeIoBatch);
    if (error != ERROR_SUCCESS) {
      if (error != ERROR_NO_SYSTEM_RESOURCES) {
        free(writeIoBatch);
      }
      if (error == ERROR_OPERATION_ABORTED) {
        IoEvent->EventResult->Status = STATUS_CANCELLED;
        DbgPrint(
            "WriteFile Error : User should already canceled the operation. "
            "Return STATUS_CANCELLED. \n");
      } else {
        IoEvent->EventResult->Status = DokanNtStatusFromWin32(error);
        DbgPrint("Unknown SendWriteRequest Error : LastError from "
                 "SendWriteRequest = %lu. \nUnknown SendWriteRequest error : "
                 "EventContext had been destoryed. Status = %X. \n",
                 error, IoEvent->EventResult->Status);
      }
      EventCompletion(IoEvent);
      return;
    }
  }
  ULONG havewritelen = 0;
  // for the case SendWriteRequest success
  if (IoEvent->DokanInstance->DokanOperations->WriteFile) {

#if 0
    status = IoEvent->DokanInstance->DokanOperations->WriteFile(
        writeIoBatch->EventContext->Operation.Write.FileName,
        (PCHAR)writeIoBatch->EventContext +
            writeIoBatch->EventContext->Operation.Write.BufferOffset,
        writeIoBatch->EventContext->Operation.Write.BufferLength,
        &writtenLength,
        writeIoBatch->EventContext->Operation.Write.ByteOffset.QuadPart,
        &IoEvent->DokanFileInfo);
#else
    ULONG remainingBytes =
        writeIoBatch->EventContext->Operation.Write.BufferLength;
    LONGLONG currentOffset =
        writeIoBatch->EventContext->Operation.Write.ByteOffset.QuadPart;
    PCHAR currentBuffer =
        (PCHAR)writeIoBatch->EventContext +
        writeIoBatch->EventContext->Operation.Write.BufferOffset;
    while (remainingBytes > 0) {

      DWORD bytesToWrite =
          MIN(remainingBytes,
              SPEED_LIMIT); 
      DWORD writtenLength = 0;
      status = IoEvent->DokanInstance->DokanOperations->WriteFile(
          writeIoBatch->EventContext->Operation.Write.FileName, currentBuffer,
          bytesToWrite, &writtenLength, currentOffset, &IoEvent->DokanFileInfo);

      remainingBytes -= writtenLength;
      currentOffset += writtenLength;
      currentBuffer += writtenLength;

      havewritelen += writtenLength;

      DWORD delayMs = (DWORD)(1000.0 * writtenLength /
                              SPEED_LIMIT);
      Sleep(delayMs);
    }

#endif
  } else {
    status = STATUS_NOT_IMPLEMENTED;
  }

  IoEvent->EventResult->Status = status;
  IoEvent->EventResult->BufferLength = 0;

  if (status == STATUS_SUCCESS) {
    IoEvent->EventResult->BufferLength = havewritelen;
    IoEvent->EventResult->Operation.Write.CurrentByteOffset.QuadPart =
        writeIoBatch->EventContext->Operation.Write.ByteOffset.QuadPart +
        havewritelen;
  }

  if (writeIoBatch != IoEvent->IoBatch) {
    PushIoBatchBuffer(writeIoBatch);
  }

  EventCompletion(IoEvent);
}