Thanks to beerockxs and RMK for their excellent responses.
I had to make a few minor adjustments to get it to work reliably. For example, in my case a CID value was returned, but the CID was not actually part of the full OneDrive URL. So, because of that, stripping off the number of characters for that broke the local path for me.
As a solution, I'm not stripping off the CID and URL Name Space by counting characters, but instead by doing simple String Replace operations. That way, if you get a CID value back that is not part of the URL, it won't remove anything from the URL for that. It also makes the code a little easier to read.
In my case I need the local root folder of my Excel spreadsheet, so created a simple extra method on top of that as well.
I also added a few simple Mac checks (to avoid this from trying to run on a Mac, as it won't work for that), and added some debug MsgBox calls -- comment those out once you find it works for you as well:
Function GetLocalPath(wb As Workbook) As String
strLocalFile = GetLocalFile(wb)
' Remove everything after the last slash to get just the path itself:
GetLocalPath = Left(strLocalFile, InStrRev(strLocalFile, "\"))
''''''''''''''' DEBUG '''''''''''''''''''''''''
MsgBox "Local file:" & vbCrLf & strLocalFile & vbCrLf & vbCrLf & "Local path:" & vbCrLf & GetLocalPath
''''''''''''''' DEBUG '''''''''''''''''''''''''
End Function
Function GetLocalFile(wb As Workbook) As String
#If Mac Then
MsgBox "Sorry, this script only works on Windows."
#Else
' Set default return
GetLocalFile = wb.FullName
Const HKEY_CURRENT_USER = &H80000001
Dim strUrlNameSpace As String
Dim objReg As Object: Set objReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
Dim strRegPath As String: strRegPath = "Software\SyncEngines\Providers\OneDrive\"
Dim arrSubKeys() As Variant
objReg.EnumKey HKEY_CURRENT_USER, strRegPath, arrSubKeys
Dim varKey As Variant
For Each varKey In arrSubKeys
' Check if this key has a value named "UrlNamespace", and save the value to strUrlNameSpace:
objReg.getStringValue HKEY_CURRENT_USER, strRegPath & varKey, "UrlNamespace", strUrlNameSpace
' If the namespace is in FullName, then we know we have a URL and need to get the path on disk:
If InStr(wb.FullName, strUrlNameSpace) > 0 Then
Dim strTemp As String
Dim strCID As String
Dim strMountpoint As String
' Get the mount point for OneDrive, and make sure it ends in "\":
objReg.getStringValue HKEY_CURRENT_USER, strRegPath & varKey, "MountPoint", strMountpoint
If Right(strMountpoint, 1) <> "\" Then
strMountpoint = strMountpoint & "\"
End If
' Get the CID, and add "/" at the start if any value returned:
objReg.getStringValue HKEY_CURRENT_USER, strRegPath & varKey, "CID", strCID
If strCID <> vbNullString Then
strCID = "/" & strCID
End If
' Replace the URL name space with local mount point:
strTemp = Replace(wb.FullName, strUrlNameSpace, strMountpoint)
' Remove CID from the path if the CID is indeed part of it:
strTemp = Replace(strTemp, strCID, "")
' Replace any remaining forward slashes with backslashes:
GetLocalFile = Replace(strTemp, "/", "\")
''''''''''''''' DEBUG '''''''''''''''''''''''''
MsgBox "OneDrive URL:" & vbCrLf & wb.FullName & vbCrLf & vbCrLf & "URL Name Space (strUrlNameSpace):" & vbCrLf & strUrlNameSpace & vbCrLf & vbCrLf & "OneDrive Mount Point (strMountpoint):" & vbCrLf & strMountpoint & vbCrLf & vbCrLf & "CID (strCID):" & vbCrLf & strCID & vbCrLf & vbCrLf & "Local file:" & vbCrLf & GetLocalFile
''''''''''''''' DEBUG '''''''''''''''''''''''''
Exit Function
End If
Next
#End If
End Function
Verified in testing that this now works perfectly, both in OneDrive folders and in regular folders.
Erik