【问题标题】:Get directories list from windows media libraries从 Windows 媒体库中获取目录列表
【发布时间】:2014-12-14 00:57:42
【问题描述】:

有没有办法以编程方式查找当前在 Windows 媒体库上设置的目录列表?

例如:假设我有以下库(我为葡萄牙语道歉,但你会明白的):

如何以编程方式获取视频库中列出的这三个目录路径

D:\Filmes
D:\Series
D:\Videos

This question 差点让我到达那里,但这并不是我想要的。到目前为止,我的替代方法是尝试直接从 Windows 注册表 中查找。

【问题讨论】:

    标签: c# .net windows


    【解决方案1】:

    终于来了!

     using System.Runtime.InteropServices;
     using System.Diagnostics;
     using System.IO;
     using System.Xml;
    
    
     [DllImport("shell32.dll")]
     private static extern int SHGetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)] Guid rfid, uint dwFlags, IntPtr hToken, ref IntPtr ppszPath);
    
     public void GetVideoLibraryFolders()
     {
         var pathPtr = default(IntPtr);
         var videoLibGuid = new Guid("491E922F-5643-4AF4-A7EB-4E7A138D8174");
         SHGetKnownFolderPath(videoLibGuid, 0, IntPtr.Zero, ref pathPtr);
    
         string path = Marshal.PtrToStringUni(pathPtr);
         Marshal.FreeCoTaskMem(pathPtr);
         List<string> foldersInLibrary = new List<string>();
    
         using (XmlReader reader = XmlReader.Create(path))
         {
             while (reader.ReadToFollowing("simpleLocation"))
             {
                 reader.ReadToFollowing("url");
                 foldersInLibrary.Add(reader.ReadElementContentAsString());
             }
         }
    
         for (int i = 0; i < foldersInLibrary.Count; i++)
         {
             if (foldersInLibrary[i].Contains("knownfolder"))
             {
                 foldersInLibrary[i] = foldersInLibrary[i].Replace("knownfolder:{", "");
                 foldersInLibrary[i] = foldersInLibrary[i].Replace("}", "");
    
                 SHGetKnownFolderPath(new Guid(foldersInLibrary[i]), 0, IntPtr.Zero, ref pathPtr);
                 foldersInLibrary[i] = Marshal.PtrToStringUni(pathPtr);
                 Marshal.FreeCoTaskMem(pathPtr);
             }
         }
    
        // foldersInLibrary now contains the path to all folders in the Videos Library
    
     }
    

    那么,我是怎么做到的?

    首先,shell32.dll 库中有一个函数 SHGetKnownFolderPath,它返回提供其 GUID (documentation) 的文件夹的路径。 对于 Windows 上的每个已知文件夹,还有一个 list 的 GUID。

    "491E922F-5643-4AF4-A7EB-4E7A138D8174"Videos_Library 文件夹的 ID。

    但是有一个问题!该函数将返回此路径:%appdata%\Microsoft\Windows\Libraries\Videos.library-ms

    如果您尝试使用Directory.GetDirectories 等方法访问该文件夹,您将获得DirectoryNotFoundException。怎么了?好吧,问题是:Videos.library-ms 不是文件夹!这是一个 XML 文件。如果你用一些文本编辑器打开它,你会看到。

    在发现它是一个 XML 文件后,我所要做的就是阅读它,我们将获得目录的路径。如果打开 xml,您会看到库中的所有文件夹都在 &lt;simpleLocation&gt; 元素下。因此,您只需阅读所有 &lt;simpleLocation&gt; XML 元素,然后阅读它们的子元素 &lt;url&gt;,其中的内容包含文件夹本身的路径。

    虽然这可能是结束,但幸运的是,我注意到并非每个文件夹路径都被描述为 .library-ms 文件中的常用路径;其中一些是用 GUID 描述的(是的,我之前链接的那些),并且其中有 knownfolder 属性。因此,在最后一个for 中,我在目录列表中搜索具有knownfolder 属性的元素。对于找到的每一个,然后我用正确的值替换它们的值,方法是使用SHGetKnownFolderPath 重新搜索 GUID 指向的路径。

    所以,就是这样!

    【讨论】:

    • 差不多了...这将返回我的用户文件夹下的“我的视频”文件夹(及其子目录)。这些媒体目录不在那里...
    • 所以,据我了解,它不会返回“电影”和“系列”文件夹,而只会返回“视频”中的文件夹。对吗?
    • 其实不是。我已经从“视频”库中删除了“我的视频”文件夹。
    • 好吧,我设法获得了库的目录路径,但不幸的是它们与普通目录路径不同,因此 Directory.EnumerateDirectories 或 Directory.GetDirectories 等函数无法访问它们(他们抛出一个 DirectoryNotFoundException)。如果你想要代码,我可以发布它。此外,我发现 Windows 应用商店应用程序有一种访问这些应用程序的简单方法,那就是通过 KnownFolders 类,所以如果您正在使用应用商店应用程序,那么就不需要所有这些复杂的事情。
    • 我想我的解决方案和你一样,虽然我会等待你的编辑,所以我可以接受;)
    【解决方案2】:

    为了未来的研究人员,这里也是我提出的代码:

    public class MediaLibraries
    {
        private static readonly string LibrariesFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Microsoft\\Windows\\Libraries";
        private static readonly string VideosLibraryFileName = "Videos.library-ms";
    
        private static IEnumerable<DirectoryInfo> _videosDirectories;
    
        public static IEnumerable<DirectoryInfo> VideosDirectories
        {
            get
            {
                if (_videosDirectories != null)
                    return _videosDirectories;
    
                _videosDirectories = new HashSet<DirectoryInfo>();
    
                var videosLibraryXmlFilePath = Path.Combine(LibrariesFolderPath, VideosLibraryFileName);
    
                if (!File.Exists(videosLibraryXmlFilePath))
                    return _videosDirectories;
    
                XDocument videosLibraryXml = XDocument.Load(File.OpenRead(videosLibraryXmlFilePath));
                XNamespace ns = videosLibraryXml.Root.Name.Namespace;
    
                string[] videoFoldersPaths = videosLibraryXml.Root
                                                             .Element(ns + "searchConnectorDescriptionList")
                                                             .Elements(ns + "searchConnectorDescription")
                                                             .Select(scd => scd.Element(ns + "simpleLocation").Element(ns + "url").Value)
                                                             .ToArray();
    
                _videosDirectories = videoFoldersPaths.Select(v => new DirectoryInfo(v)).AsEnumerable();
    
                return _videosDirectories;
            }
        }
    }
    

    这个想法与@AndreSilva 的回答相同,尽管我不必通过互操作。

    基本上,我已经编写了 Libraries 文件夹 的路径,然后附加了 Video Libraries XML 的文件名。之后就是Linq2XML魔法了。

    【讨论】:

    • 不错!不过记得检查knownfolder。在 Windows 8 中,Documents 库默认包含 SkyDrive 的 Documents 文件夹,这是一个已知文件夹,因此将在 Documents.library-ms 中由其 GUID 而非其地址来描述。
    • 很高兴知道,虽然现在只有视频库对我很重要。顺便说一句,这是为了这个:subsync.codeplex.com
    • 我现在明白你的意思了。即使对于视频库,Windows 也会使用 GUID 设置默认视频文件夹。我还需要使用您的代码来检查它们:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多