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...
- force interrogation of the mapped drive letter, or
- flush the cache, or
- 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.
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.