SHGetPathFromIDList不返回带有前导句号的路径名

问题描述 投票:0回答:4

我有一些Excel x64 VBA代码,可获取MP3文件以及音轨号,大小,长度等,并将它们放在一些工作表中。基本代码来自John Walkenbach的页面,可以在这里找到:http://spreadsheetpage.com/index.php/file/mp3_file_lister/。我通过在函数声明中添加PtrSafe关键字并将某些数据类型从Long更改为LongLong或LongPtr(也许还有其他一些),将其修改为在64位Excel中运行。该代码可以很好地运行,但有一个不太小的例外,它将不会返回包含前导期间的文件夹中的任何文件。例如,我有一个使用WMP翻录的.38 Special专辑。文件夹为:D:\ Users \ username \ Music \ Music.38 Special \ Rock&Roll Strategy ...此路径未出现在生成的列表中。我也有:D:\ Users \ username \ Music \ Music \ Norah Jones ... Featureing Nora Jones ...并且此文件夹也丢失了(结尾的省略号代表歌曲列表)。我已经通过电子邮件联系了约翰·沃肯巴赫,他也不知道为什么会这样。

这是我修改后的代码:


Option Explicit
Dim Sht1Row As Integer
Dim Sht2Row As Integer

' By John Walkenbach
' Maybe be distributed freely, but not sold

'API declarations
Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" Alias "SHGetPathFromIDListA" (ByVal pidl As LongPtr, ByVal pszPath As String) As LongPtr

Declare PtrSafe Function SHBrowseForFolder Lib "shell32.dll" Alias "SHBrowseForFolderA" (lpBrowseInfo As BROWSEINFO) As LongPtr

Public Type BROWSEINFO
  hOwner As LongPtr
  pidlRoot As LongPtr
  pszDisplayName As String
  lpszTitle As String
  ulFlags As LongPtr
  lpfn As LongPtr
  lParam As LongPtr
  iImage As LongPtr
End Type

Sub GetAllFiles()
    Dim Msg As String
    Dim Directory As String
    Dim lastRow1C As Integer
    Dim lastRow2C As Integer
    Dim lastRow1D As Integer
    Dim lastRow2D As Integer

    Msg = "Select the directory that contains the MP3 files. All subdirectories will be included."
    Directory = GetDirectory(Msg)
    If Directory = "" Then Exit Sub
    If Right(Directory, 1)  "\" Then Directory = Directory & "\"
        With Sheet1
            lastRow1C = .Cells(.Rows.Count, "C").End(xlUp).Row
            If lastRow1C  lastRow2D Then
            .Range("D" & lastRow2D, "F" & lastRow2D).Select
            Selection.AutoFill Destination:=Range("D" & lastRow2D, "F" & lastRow2C)
        End If
        .Range("E2:E" & lastRow2C).Copy
        .Range("A2:A" & lastRow2C).PasteSpecial xlPasteValues
        Columns("A:J").Sort key1:=Range("G2"), order1:=xlAscending, key2:=Range("H2"), order2:=xlAscending, Header:=xlYes
        Range("A1").Select
    End With

    With Sheet1
        Worksheets("Music_Library_Full").Activate
        lastRow1C = .Cells(.Rows.Count, "C").End(xlUp).Row
        lastRow1D = .Cells(.Rows.Count, "D").End(xlUp).Row
        If lastRow1C > lastRow1D Then
            .Range("D" & lastRow1D, "F" & lastRow1D).Select
            Selection.AutoFill Destination:=Range("D" & lastRow1D, "F" & lastRow1C)
        End If
        .Range("E2:E" & lastRow1C).Copy
        .Range("A2:A" & lastRow1C).PasteSpecial xlPasteValues
         Columns("A:J").Sort key1:=Range("G2"), order1:=xlAscending, key2:=Range("H2"), order2:=xlAscending, Header:=xlYes
        Range("A1").Select
    End With

Application.ScreenUpdating = True

End Sub

Function GetDirectory(Optional Msg) As String
    Dim bInfo As BROWSEINFO
    Dim path As String
    Dim r As String
    Dim x As String
    Dim pos As Integer
'   Root folder = Desktop
    bInfo.pidlRoot = 0&
'   Title in the dialog
    If IsMissing(Msg) Then
        bInfo.lpszTitle = "Select a folder."
    Else
        bInfo.lpszTitle = Msg
    End If
'   Type of directory to return
    bInfo.ulFlags = &H1
'   Display the dialog
    x = SHBrowseForFolder(bInfo)
'   Parse the result
    path = Space$(512)
    r = SHGetPathFromIDList(ByVal x, ByVal path)
    If r Then
        pos = InStr(path, Chr$(0))
        GetDirectory = Left(path, pos - 1)
    Else
        GetDirectory = ""
    End If
End Function

Public Sub RecursiveDir(ByVal currdir As String)
    Dim Dirs() As Variant
    Dim NumDirs As Long
    Dim FileName As String
    Dim PathAndName As String
    Dim i As Long
    Dim PathName As String
    Dim TrackNum As Variant
    Dim Genre As String
    Dim Duration As Variant
    Dim FileSize As Variant

'   Make sure path ends in backslash
    If Right(currdir, 1)  "\" Then currdir = currdir & "\"

'   Put column headings on active sheet
Worksheets("Music_Library_Full").Activate
    Cells(1, 1) = "Artist & Filename Lookup"
    Cells(1, 2) = "Filename Lookup"
    Cells(1, 3) = "Full Pathname"
    Cells(1, 4) = "Artist"
    Cells(1, 5) = "Artist & Filename"
    Cells(1, 6) = "Filename"
    Cells(1, 7) = "Path"
    Cells(1, 8) = "Track#"
    Cells(1, 9) = "Duration"
    Cells(1, 10) = "Size"
    Range("1:1").Font.Bold = True
    Range("1:1").Font.Italic = True
    Range("1:1").Font.Name = "Consolas"

Worksheets("Best_Greatest").Activate
    Cells(1, 1) = "Artist & Filename Lookup"
    Cells(1, 2) = "Filename Lookup"
    Cells(1, 3) = "Full Pathname"
    Cells(1, 4) = "Artist"
    Cells(1, 5) = "Artist & Filename"
    Cells(1, 6) = "Filename"
    Cells(1, 7) = "Path"
    Cells(1, 8) = "Track#"
    Cells(1, 9) = "Duration"
    Cells(1, 10) = "Size"
    Range("1:1").Font.Bold = True
    Range("1:1").Font.Italic = True
    Range("1:1").Font.Name = "Consolas"

'   Get files
    FileName = Dir(currdir & "*.*", vbDirectory)

    Do While Len(FileName)  0
      If Left$(FileName, 1)  "." Then 'Current dir
        PathAndName = currdir & FileName
        If (GetAttr(PathAndName) And vbDirectory) = vbDirectory Then
          'store found directories
           ReDim Preserve Dirs(0 To NumDirs) As Variant
           Dirs(NumDirs) = PathAndName
           NumDirs = NumDirs + 1
        Else
            If UCase(Right(FileName, 3)) = "MP3" Then
                PathName = currdir 'path
                FileName = FileName 'filename
                TrackNum = FileInfo(currdir, FileName, 26) 'track
                Duration = FileInfo(currdir, FileName, 27) 'duration
                FileSize = Application.Round(FileLen(currdir & FileName) / 1024, 0) 'size
                'Application.StatusBar = Row
                If InStr(1, LCase(PathName), LCase("Best of"), vbTextCompare) Or InStr(1, LCase(PathName), LCase("Greatest"), vbTextCompare) Then
                    'Sht2Row = WorksheetFunction.CountA(Range("C:C")) + 1
                    Worksheets("Best_Greatest").Activate
                    Cells(Sht2Row, 2) = FileName
                    Cells(Sht2Row, 3) = PathName & FileName
                    Cells(Sht2Row, 7) = PathName
                    Cells(Sht2Row, 8) = TrackNum
                    Cells(Sht2Row, 9) = Duration
                    Cells(Sht2Row, 10) = FileSize
                    Sht2Row = Sht2Row + 1
                Else
                    'Sht1Row = WorksheetFunction.CountA(Range("C:C")) + 1
                    Worksheets("Music_Library_Full").Activate
                    Cells(Sht1Row, 2) = FileName
                    Cells(Sht1Row, 3) = PathName & FileName
                    Cells(Sht1Row, 7) = PathName
                    Cells(Sht1Row, 8) = TrackNum
                    Cells(Sht1Row, 9) = Duration
                    Cells(Sht1Row, 10) = FileSize
                    Sht1Row = Sht1Row + 1
                End If
            End If
        End If
    End If
        FileName = Dir()
    Loop
    ' Process the found directories, recursively
    For i = 0 To NumDirs - 1
        RecursiveDir Dirs(i)
    Next i
End Sub

Function FileInfo(path, FileName, item) As Variant
    Dim objShell As IShellDispatch4
    Dim objFolder As Folder3
    Dim objFolderItem As FolderItem2

    Set objShell = CreateObject("Shell.Application")
    Set objFolder = objShell.Namespace(path)
    Set objFolderItem = objFolder.ParseName(FileName)
    FileInfo = objFolder.GetDetailsOf(objFolderItem, item)

    Set objShell = Nothing
    Set objFolder = Nothing
    Set objFolderItem = Nothing
End Function

[如果有人知道如何修改此名称,以便可以返回包含前导句作为路径的任何部分的路径名,我将非常高兴看到它。我只是通过删除前置时间来重命名那些特定的路径,但是恐怕WMP只会在一天之内将一切恢复原状(以前发生过)。另外,如果您在BrowseForFolder API中选择实际的文件夹,则该带有前导句号的文件夹实际上会进入工作表,但当然只有该文件夹。谢谢

worksheet-function
4个回答
1
投票

查看代码示例中的此行:

如果为Left $(FileName,1)“。然后“当前目录

由于当前目录被定义为单个'。字符,并且此代码仅检查初始字符,在递归检查之前将其删除。将条件更改为检查字符串的长度以及初始字符,例如

如果(Left $(FileName,1)=“。” And FileName.Length = 1)然后'当前目录

N.B。此代码尚未经过测试;希望它对您有用。


0
投票

我能够通过将根目录和子目录的测试分成单独的IF语句来解决此问题,即:

    If filename <> "." Then
        If filename <> ".." Then
            *Code here*
        End If
    End If

可能笨拙,但是有效。

原始的If语句是:

如果文件名<>“。”或文件名<>“ ..”然后

这没用。但是后来我想到也许我需要使用NAND语句。 NAND =不与。所以我尝试了这个:

如果不是filename =“。”而不是Filename =“ ..”然后

此方法确实有效,并且似乎比早期的解决方案执行得更快。


0
投票
显式期权约翰·沃肯巴赫'可以自由分发,但不出售子GetAllFiles()昏暗的消息作为字符串昏暗目录Msg =“选择包含MP3文件的目录。将包含所有子目录。设置目录= Application.FileDialog(msoFileDialogFolderPicker)带目录。标题=消息.AllowMultiSelect =假。显示如果.SelectedItems.Count> 0然后目录= .SelectedItems.item(1)其他退出子万一结束于如果为Right(Directory,1)<>“ \”,则Directory = Directory&“ \”工作表(“ Sheet1”)。激活细胞清除'将列标题放在活动工作表上单元格(1,1)=“路径”Cells(1,2)=“文件名”单元格(1,3)=“全路径”Cells(1,4)=“艺术家”单元格(1,5)=“相册”单元格(1,6)=“标题”单元格(1,7)=“ Track#”Cells(1,8)=“流派”单元格(1,9)=“持续时间”单元格(1,10)=“年份”单元格(1,12)=“大小”Range(“ 1:1”)。Font.Bold = True呼叫RecursiveDir(目录)结束子公共子RecursiveDir(ByVal currdir作为字符串)Dim Dirs()作为变体昏暗的数字昏暗的文件名作为字符串昏暗的PathAndName作为字符串变暗变暗行作为变体'确保路径以反斜杠结尾如果为Right(currdir,1)<>“ \”,则currdir = currdir&“ \”Application.ScreenUpdating = False'获取文件文件名= Dir(currdir&“ *。*”,vbDirectory)做While Len(文件名)<> 0活动事件如果不是filename =“。”。而且不是filename =“ ..”然后是'当前目录PathAndName = currdir和文件名如果(GetAttr(PathAndName)And vbDirectory)= vbDirectory,则'存储找到的目录ReDim将Dirs(0到NumDirs)保留为变体Dirs(NumDirs)=路径和名称NumDirs = NumDirs + 1其他如果UCase(Right(filename,3))=“ MP3”,则行= WorksheetFunction.CountA(Range(“ A:A”))+ 1单元格(行,1)= currdir'路径单元格(行,2)=文件名'文件名单元格(行3)= PathAndNameCells(Row,4)= FileInfo(currdir,filename,20)'artistCells(Row,5)= FileInfo(currdir,filename,14)'专辑Cells(Row,6)= FileInfo(currdir,filename,21)'标题Cells(Row,7)= FileInfo(currdir,filename,26)'trackCells(Row,8)= FileInfo(currdir,filename,16)'genreCells(Row,9)= FileInfo(currdir,filename,27)'持续时间Cells(Row,10)= FileInfo(currdir,filename,15)'年单元格(行11)= FileInfo(currdir,文件名5)Cells(Row,12)= Application.Round(FileLen(currdir&filename)/ 1024,0)'sizeApplication.StatusBar =行万一万一万一文件名= Dir()环'递归处理找到的目录对于i = 0至NumDirs-1递归Dir Dirs(i)接下来我Application.StatusBar = False结束子函数FileInfo(路径,文件名,项目)为变体昏暗的objShell作为IShellDispatch4暗objFolder作为Folder3昏暗的objFolderItem作为FolderItem2设置objShell = CreateObject(“ Shell.Application”)设置objFolder = objShell.Namespace(path)设置objFolderItem = objFolder.ParseName(文件名)FileInfo = objFolder.GetDetailsOf(objFolderItem,项目)设置objShell = Nothing设置objFolder = Nothing设置objFolderItem = Nothing结束功能

另外,其他文件信息项:27 =持续时间,28 =比特率,26 =音轨号。


0
投票

无法设置“作曲家”。编辑命令不起作用。请建议添加作曲家和/或专辑艺术家

© www.soinside.com 2019 - 2024. All rights reserved.