Here it is, finally!
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
}
So, how did I do it?
First off, there's this function SHGetKnownFolderPath
in the shell32.dll
library, which returns the path of a folder provided its GUID (documentation).
And there's also a list of GUIDs for each Known Folder on Windows.
"491E922F-5643-4AF4-A7EB-4E7A138D8174"
is the ID for the Videos_Library
folder.
But there's one problem! That function will return this path: %appdata%\Microsoft\Windows\Libraries\Videos.library-ms
If you try to access that folder with methods like Directory.GetDirectories
you will get a DirectoryNotFoundException
. What's wrong? Well, the problem is: Videos.library-ms
isn't a folder! It's a XML file. If you open it with some text editor, you'll see.
After discovering that it was a XML file, then all I had to do was to read it and we would have the path to the directories. If you open the xml, you'll see that all the folders in a Library are under <simpleLocation>
elements. So you simply have to read all the <simpleLocation>
XML Elements and then their child element <url>
, which content contains the path for the folder itself.
Although that could be the end, I luckily noticed that not every folder path is described as an usual path in the .library-ms
file; some of them are described with GUID's (yes, those same I linked previously), and those have the knownfolder
attribute in them. Thus, in the last for
, I search for elements in the List of directories which have the knownfolder
attribute in them. For each one found, I then replace their value with the correct one, by searching all over again to which path that GUID points using SHGetKnownFolderPath
.
So, that's it!