返回Excel VBA宏OneDrive本地路径 - 可能的线索

3
我有一个电子表格需要多人访问(在SharePoint上),由于各个用户的知识水平不同,常常出现问题和错误。为了确保表格的结构和一致性,我创建了一个用户表单,其中包含一系列参数,以帮助人们输入准确的数据并避免错误。这是一个招标登记表,用于输入客户、客户联系人和招标信息,生成报价编号、文件夹和文件名等。在OneDrive/Sharepoint路径更改之前,我有一个宏,当用户单击按钮时运行该宏,会在相关本地SharePoint目录中创建一个适当命名的文件夹,并在该文件夹中创建一组标准文件夹(客户文档、合同、产品文件、图纸等)。然后打开招标表单并将其保存在创建的文件夹中。文件名(报价编号)用于查找来自招标登记表的查询,以返回所有客户/联系人/报价信息。由于Sharepoint已将其路径协议从本地更改为URL,因此我无法使其正常工作,导致手动处理,从而导致错误和不一致性。
我一直在寻找使用VBA创建SharePoint上的文件夹和文件的方法,以及与本地路径进行交互的方法,而不是禁用“使用Office应用程序同步我打开的Office文件”(由于文件协作需要此功能)。
当我发现将URL转换为本地路径的方法时,我有一线希望,但这并不是最佳解决方案,因为每个用户在不同级别上同步文件夹(也许有人可以通过宏在OneDrive目录中搜索文件夹“2021 Tenders”并返回路径来帮助我确定路径...但我认为这可能很慢)。
然而,我注意到如果我进入“文件”>“信息”,有一个“打开文件位置”的按钮,它会直接带我到文件的本地路径文件夹,这告诉我这些信息在Excel中的某个地方,必须有一种检索它的方法。我在我的搜索中没有看到任何参考,指出这一点后,是否有人有任何想法如何或是否可以工作?
我尝试录制宏,但根本没有注册。任何帮助都将不胜感激,谢谢您提前的帮助。

文件>信息-屏幕截图 这里输入图片描述

4个回答

2

这对我有用。我使用了环境变量。

OneDrive = Environ("OneDrive")
CurPath = Application.ThisWorkbook.Path
If (InStr(1, Left(CurPath, 4), "http", vbTextCompare)) Then
    SubPathPos = InStr(30, CurPath, "/", vbTextCompare)
    CurPath = OneDrive & Right(CurPath, Len(CurPath) - SubPathPos + 1)
End If
ChDir (CurPath)

虽然按照原文的方式无法实现,但是Environ("OneDrive")可以返回我所使用的系统上OneDrive根目录的本地路径。谢谢。 - Pastychomper thanks Monica
1
谢谢。你是正确的,“OneDrive”是正确的变量。如果你有个人和公司账户,“OneDriveConsumer”选择个人账户,“OneDriveCommercial”选择公司账户。我已经更新了代码。 - engineercliff

2
这是我根据另一个答案组装的东西(请参见代码内部的注释)。
代码属于我组合的一系列类,但为了给你一个简单的答案,将其放入一个模块中。
Option Explicit
Private Const ONEDRIVE_TENANTS_REGISTRY_FOLDER As String = "Software\Microsoft\OneDrive\Accounts\Business1\Tenants\"
Private Const ONEDRIVE_TOTAL_VERSIONS As Long = 3
Private Const ONEDRIVE_PATH_SLASHES As Long = 4
Const HKEY_CURRENT_USER = &H80000001
Public Function GetLocalWorkbookName(ByVal fullName As String, Optional ByVal PathOnly As Boolean = False) As String
    ' Credits: https://dev59.com/W1sX5IYBdhLWcg3wf_r3#57040668
    'returns local wb path or empty string if local path not found

    Dim localFolders As Collection
    Dim localFolder As Variant
    
    Dim evalPath As String
    Dim result As String
    
    Dim isOneDrivePath As Boolean
    
    'Check if it looks like a OneDrive location
    isOneDrivePath = InStr(1, fullName, "https://", vbTextCompare) > 0
    
    If isOneDrivePath = False Then
        result = fullName
    Else
        Set localFolders = GetLocalFolders
        
        evalPath = RemoveTopFoldersByQty(fullName, ONEDRIVE_PATH_SLASHES)
        For Each localFolder In localFolders
            result = GetFilePathByRootFolder(localFolder, evalPath)
            If result <> vbNullString Then Exit For
        Next localFolder
    End If
    If PathOnly Then
        GetLocalWorkbookName = RemoveFileNameFromPath(result)
    Else
        GetLocalWorkbookName = result
    End If
    
End Function
Public Function GetLocalFolders() As Collection
    
    Dim tempCollection As Collection
    Dim tenantFolders As Variant
    Dim localFolders As Variant
    
    Dim tenantCounter As Long

    Set tempCollection = New Collection
    
    ' Look in onedrive for business tenant's folders
    tenantFolders = GetRegistrySubKeys(ONEDRIVE_TENANTS_REGISTRY_FOLDER)
    
    For tenantCounter = 0 To UBound(tenantFolders)
        localFolders = GetRegistryValues(ONEDRIVE_TENANTS_REGISTRY_FOLDER & "\" & tenantFolders(tenantCounter) & "\")
        AddArrayItemsToCollection tempCollection, localFolders
    Next tenantCounter
    
    ' Add the onedrive consumer folder
    tempCollection.Add Environ$("OneDriveConsumer")
    
    Set GetLocalFolders = tempCollection
    
End Function
Public Function RemoveTopFolderFromPath(ByVal ShortName As String) As String
    RemoveTopFolderFromPath = Mid$(ShortName, InStr(ShortName, "\") + 1)
End Function

Public Function RemoveTopFoldersByQty(ByVal FullPath As String, ByVal FolderQty As Long) As String
    Dim counter As Long
    Dim evalPath As String
    evalPath = Replace(FullPath, "/", "\")
    For counter = 1 To FolderQty
        evalPath = RemoveTopFolderFromPath(evalPath)
    Next counter
    RemoveTopFoldersByQty = evalPath
End Function

Public Function RemoveFileNameFromPath(ByVal ShortName As String) As String
    RemoveFileNameFromPath = Mid$(ShortName, 1, Len(ShortName) - InStr(StrReverse(ShortName), "\"))
End Function

Public Function GetFilePathByRootFolder(ByVal RootFolder As String, ByVal SearchPath As String) As String
    Dim result As String
    Dim evalPath As String
    Dim testFilePath As String
    
    Dim oneDrivePathFound As Boolean
       
    evalPath = IIf(InStr(SearchPath, "\") = 0, "\", vbNullString) & SearchPath
    
    Do While evalPath Like "*\*"
        testFilePath = RootFolder & IIf(Left$(evalPath, 1) <> "\", "\", vbNullString) & evalPath
        If Not (Dir(testFilePath)) = vbNullString Then
            oneDrivePathFound = True
            Exit Do
        End If
        'remove top folder in path
        evalPath = RemoveTopFolderFromPath(evalPath)
    Loop
    
    If oneDrivePathFound = True Then
        result = testFilePath
    Else
        result = vbNullString
    End If
    
    GetFilePathByRootFolder = result
    
End Function
Public Function GetRegistrySubKeys(ByVal pathToFolder As String) As Variant
' Credits: https://dev59.com/S17Va4cB1Zd3GeqPMbzf#8667984
    Dim registryObject As Object
    Dim computerID As String
    Dim subkeys() As Variant
    'Dim key As Variant

    computerID = "."
    Set registryObject = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
    computerID & "\root\default:StdRegProv")

    registryObject.EnumKey HKEY_CURRENT_USER, pathToFolder, subkeys
    GetRegistrySubKeys = subkeys
    'For Each key In subKeys
    '    Debug.Print key
    'Next
End Function

Public Function GetRegistryValues(ByVal pathToFolder As String) As Variant
' Credits: https://dev59.com/S17Va4cB1Zd3GeqPMbzf#8667984
    Dim registryObject As Object
    Dim computerID As String
    Dim values() As Variant
    Dim valuesTypes() As Variant
    'Dim value As Variant
    

    computerID = "."
    Set registryObject = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
    computerID & "\root\default:StdRegProv")

    registryObject.EnumValues HKEY_CURRENT_USER, pathToFolder, values, valuesTypes
    GetRegistryValues = values
    'For Each value In values
    '    Debug.Print value
    'Next
End Function



Public Sub AddArrayItemsToCollection(ByVal evalCollection As Collection, ByVal evalArray As Variant)
    
    Dim item As Variant
    
    For Each item In evalArray
        evalCollection.Add item
    Next item
    
End Sub

将其翻译为中文:

并像这样调用:

? GetLocalWorkbookName(ThisWorkbook.fullName, true)

希望对你有所帮助,如果有效请告诉我。

Ricardo,你我的朋友是传奇!我不得不对代码进行一些调整,以使其按照我的意愿运行。我会将其发布为答案,这可能不是最常规的方法,但请看看你能否改进/简化这个更改。 - Andrew Carruthers
很高兴能够帮到你。我曾经也花了好几天来解决同样的问题。干杯! - Ricardo Diaz
1
我在我的元分析中包含了这个解决方案,该分析涵盖了我在网上找到的所有解决方案。当时编写此文时,根据我的测试,这是表现最佳的解决方案。现在,存在更可靠的解决方案。它们与元分析一起在此处呈现。 - GWD

1

对于每个OneDrive/SharePoint根同步文件夹(顶级),该代码可以完美地处理子文件夹中的文件,但如果文件位于顶级本身,则无法处理。

我逐步检查了代码以查看它在每个斜杠处过滤的位置,并在“GetFilePathByRootFolder”函数中从“do while”更改为“for”。使用“do while”循环计算斜杠数量,然后使用“for”循环进行斜杠数量+1次“RemoveTopFolderFromPath”,再进行一次附加运行,仅留下文件名以进行最后一次搜索以查找文件名。

希望这能让您理解。

    Public Function GetFilePathByRootFolder(ByVal RootFolder As String, ByVal SearchPath As String) As String
    Dim result As String
    Dim evalPath As String
    Dim testFilePath As String
    Dim slashCounter As Integer                                                                         'added by AC
    Dim i As Integer                                                                                    'added by AC
    
    Dim oneDrivePathFound As Boolean
       
    evalPath = IIf(InStr(SearchPath, "\") = 0, "\", vbNullString) & SearchPath
    
    slashCounter = 0                                                                                    'added by AC
    Do While evalPath Like "*\*"                                                                        'added by AC
        slashCounter = slashCounter + 1                                                                 'added by AC
        evalPath = RemoveTopFolderFromPath(evalPath)                                                    'added by AC
    Loop                                                                                                'added by AC
    slashCounter = slashCounter + 1
    evalPath = IIf(InStr(SearchPath, "\") = 0, "\", vbNullString) & SearchPath

    For i = 1 To slashCounter                                                                           'added by AC
        testFilePath = RootFolder & IIf(Left$(evalPath, 1) <> "\", "\", vbNullString) & evalPath        'added by AC
        Debug.Print testFilePath                                                                        'added by AC
        If Not (Dir(testFilePath)) = vbNullString Then                                                  'added by AC
            oneDrivePathFound = True                                                                    'added by AC
            Exit For                                                                                    'added by AC
        End If                                                                                          'added by AC
        'remove top folder in path                                                                      'added by AC
        evalPath = RemoveTopFolderFromPath(evalPath)                                                    'added by AC
    Next i                                                                                              'added by AC
    
'    Do While evalPath Like "*\*" ' change loop to "for each \ in evalPath +1"
'        testFilePath = RootFolder & IIf(Left$(evalPath, 1) <> "\", "\", vbNullString) & evalPath
'        Debug.Print testFilePath
'        If Not (Dir(testFilePath)) = vbNullString Then
'            oneDrivePathFound = True
'            Exit Do 'exit for
'        End If
'        'remove top folder in path
'        evalPath = RemoveTopFolderFromPath(evalPath)
'    Loop
    
    If oneDrivePathFound = True Then
        result = testFilePath
    Else
        result = vbNullString
        
    End If
    
    GetFilePathByRootFolder = result
    
End Function

太棒了!我正在寻找非常类似的东西,但是用于不同的目的...代码是否可以修改为列出共享文件夹或OneDrive文件夹中所有Excel文件的URL?我需要获取URL,因为我正在将Excel文件嵌入网页中,所以无法使用本地路径。我会非常感激的! :-) - Chadee Fouad

0

很抱歉我没有足够的声望点数直接评论@engineercliff的代码:

简单易用,我只是将结尾的“/”替换为“”以使其正常工作:

OneDrive = Environ("OneDrive")
CurPath = Application.ThisWorkbook.Path
If (InStr(1, Left(CurPath, 4), "http", vbTextCompare)) Then
   SubPathPos = InStr(30, CurPath, "/", vbTextCompare)
   CurPath = OneDrive & Right(CurPath, Len(CurPath) - SubPathPos + 1)
   Curpath = Replace(Curpath, "/", "\")
End If
ChDir (CurPath)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接