I ran into a similar issue with Arbed 1.9 when built with Xojo 2019r3. I was trying to use replaceItemAtURL
, like Sam suggested, but it was tricky because I needed a true exchange (swap) operation.
I came up with this code, including a way for Windows (though that’s not thoroughly tested). It requires a little bit of MBS but could also be solved by using NSURL from the good olde macOSLib. The use of fileSystemRepresentation
may be replaced by NativePath
.
(Update: I’ve fixed a little code issue - now the FolderItems are cloned first, even for macOS)
[code]Protected Function ExchangeFileContents(destFile as FolderItem, tempFile as FolderItem) As Boolean
// use clones so that the caller’s don’t get mixed up
destFile = new FolderItem(destFile)
tempFile = new FolderItem(tempFile)
#if TargetMacOS
dim urlDest as new NSURLMBS (destFile)
dim urlTemp as new NSURLMBS (tempFile)
if urlDest.VolumeIdentifier = urlTemp.VolumeIdentifier then
const CocoaLib = "Cocoa"
declare function objc_getClass lib CocoaLib (aClassName as CString) as Ptr
declare function defaultManager lib CocoaLib selector "defaultManager" (obj as Ptr) as Ptr
static defaultMgr as Ptr = defaultManager (objc_getClass("NSFileManager"))
declare function replaceItem lib CocoaLib _
selector "replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error:" _
(obj as Ptr, url1 as Integer, url2 as Integer, backupName as CFStringRef, opts as Integer, _
ByRef result as Integer, err as Ptr) as Boolean
// we need this to get a swap effect; otherwise we'd lose the tempFile:
const NSFileManagerItemReplacementWithoutDeletingBackupItem = 2
dim tempName as String = tempFile.Name
dim backupName as String = tempName+"_"
dim result as Integer
if replaceItem (defaultMgr, urlDest.Handle, urlTemp.Handle, backupName, _
NSFileManagerItemReplacementWithoutDeletingBackupItem, result, nil) then
dim newTemp as FolderItem = tempFile.Parent.TrueChild(backupName)
newTemp.Name = tempName
dim url_res as NSURLMBS = NSURLMBS.URLWithHandle (result)
if StrComp (url_res.fileSystemRepresentation, urlDest.fileSystemRepresentation, 0) = 0 then
return true
end if
end
break
end if
#elseif TargetWin32
Soft Declare Function ReplaceFileW Lib “Kernel32” ( destination as WString, source as WString, _
backup as Integer, flags as Integer, reserved1 as Integer, reserved2 as Integer ) as Boolean
if System.IsFunctionAvailable( "ReplaceFileW", "Kernel32" ) then
Const REPLACEFILE_WRITE_THROUGH = &h1
dim success as Boolean = ReplaceFileW( destFile.AbsolutePath, tempFile.AbsolutePath, _
0, REPLACEFILE_WRITE_THROUGH, 0, 0 )
if success then
destFile.Visible = true
return true
end
end if
#endif
return SimpleSwapFiles (destFile, tempFile)
End Function
Private Function SimpleSwapFiles(f as FolderItem, g as FolderItem) As Boolean
dim temp as FolderItem = f.Parent.TrueChild("."+f.Name+"-"+Format(Rnd()*10000,"#")+".tmp")
if temp.Exists then
temp.Delete
end if
f.MoveFileTo temp
If f.LastErrorCode <> 0 or f.Exists or NOT temp.Exists then
return false
End if
g.MoveFileTo f
If g.LastErrorCode <> 0 or g.Exists or NOT f.Exists then
return false
End if
temp.MoveFileTo g
If temp.LastErrorCode <> 0 or temp.Exists or NOT g.Exists then
return false
End if
return true
End Function
[/code]