Re-using a mapped drive letter but path in windows copy/move dialog always displays path of first mapping

183 views Asked by At

I have written a program in Delphi 10.2 Tokyo to archive users' home folders. The folders are archived after the users' accounts have been deleted from Active Directory. I am using the Windows IFileOperation to do the folder moves. As the program iterates through the list of users, it maps a drive letter (same one every time) to the user's network home folder then calls IFileOperation to move the folder. The first time, the path displayed in the Windows Move dialog shows the drive letter and the mapped path correctly. After the move is complete the dialog closes, the loop moves to the next user. The drive letter is mapped to the next user's home folder, but this time when the Windows Move dialog appears it displays the path from the first user. The correct folder is moved to the archive location, but the display is incorrect. This occurs for all remaining items. It's as if the first mapping is somehow cached the first time the IFileOperation is called and then all subsequent calls use the cached value instead of interrogating the drive letter for the true network path.

Is there a way to...

  1. force interrogation of the mapped drive letter, or
  2. flush the cache, or
  3. something else

...each time IFileOperation is called, so that the correct path is displayed in the Windows Move dialog?

When mapping the drive letter to the home folder I have tried setting the UpdateProfile parameter to False, but I get the "drive has a remembered connection" error, so that has to be set to True, in both the connect and disconnect.

Pseudo Code to illustrate repetitive drive mapping:

mapDrive('t:','\\archiveServer\home')
for i := 0 to Length(UserList) - 1
begin
    mapDrive('h:',UserList[i].homeDirectory) // e.g. \\server1\home\username, \\server2\home\username (each remote site has a user home share)
    if not MoveDirIFileOperation('h:','t:\'+UserList[i].sAMAccountName) then DisplayErrorMessage
    unmapDrive('h:')
end
unmapDrive('t:')

MoveDirIFileOperation Function:

function MoveDirIFileOperation(const srcDir,dstDir: String): Boolean;
var
  r: HRESULT;
  fileOp: IFileOperation;
  siSrcDir: IShellItem;
  siDstDir: IShellItem;
begin
  Result:=False;
  r:=CoInitializeEx(nil,COINIT_APARTMENTTHREADED or COINIT_DISABLE_OLE1DDE);
  if Succeeded(r) then
  begin
    try
      r:=CoCreateInstance(CLSID_FileOperation, nil, CLSCTX_ALL, IFileOperation, fileOp);
      if Succeeded(r) then
      begin
        r:=fileOp.SetOperationFlags(FOF_NOCONFIRMATION OR FOFX_NOMINIMIZEBOX);
        if Succeeded(r) then
        begin
          try
            r:=SHCreateItemFromParsingName(PChar(srcDir),nil,IShellItem,siSrcDir);
          except
            r:=-1;
          end;
          if Succeeded(r) then
          begin
            try
              r:=SHCreateItemFromParsingName(PChar(dstDir),nil,IShellItem,siDstDir);
            except
              r:=-1;
            end;
            if Succeeded(r) then r:=fileOp.MoveItem(siSrcDir,siDstDir,nil,nil);
          end;
          if Succeeded(r) then r:=fileOp.PerformOperations;
          Result:=Succeeded(r);
        end;
      end;
    finally
      CoUninitialize;
    end;
  end;
end;

If more information is needed, please let me know. I'll provide what I can.

1

There are 1 answers

1
Stephane On

In case it helps, With NET USE, I've read there's an undocumented /Y switch to free the resources when deleting a mapped drive. Ex: NET USE X: /DELETE /Y Untested, just an FYI.