I know that I'm going to answer my own question, but I've been doing a lot of research and found the answer to my question. This took a while to find, so I'm also going to show my solution and list some other things I learned about metro apps.
- Metro apps are installed in packages (folders) in C:/Program Files/WindowsApps
- There can be multiple metro apps in one package
- There is a AppxManifest.xml in every package telling what is in the package
- In the manifest, each application has its own Application Tag
- Metro apps can be started with a DOS command:
start [ProtocolName]:
I modified my function to account for two apps being in a single package. I also filtered the list based on whether or not the app has a protocol name.
[DllImport("shlwapi.dll", BestFitMapping = false, CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = false, ThrowOnUnmappableChar = true)]
public static extern int SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, int cchOutBuf, IntPtr ppvReserved);
public static List<string> GetMetroAppnames() {
List<string> names = new List<string>();
foreach(string dir in Directory.GetDirectories(@"c:\program files\WindowsApps\")) {
if(System.IO.File.Exists(dir + @"\AppxManifest.xml")) {
XmlDocument doc = new XmlDocument();
doc.Load(dir + @"\AppxManifest.xml");
if(doc.GetElementsByTagName("Framework")[0] != null)
if(doc.GetElementsByTagName("Framework")[0].InnerText.ToLower() == "true")
continue;
if(doc.GetElementsByTagName("Protocol")[0] == null) continue;
string name = doc.GetElementsByTagName("DisplayName")[0].InnerText;
string identity = doc.GetElementsByTagName("Identity")[0].Attributes["Name"].Value;
string appName = "";
if(!name.Contains("ms-resource")) {
names.Add(name);
} else {
if(doc.GetElementsByTagName("Application").Count > 1) {
foreach(XmlElement elem in doc.GetElementsByTagName("Application")) {
name = elem.GetElementsByTagName("m2:VisualElements")[0].Attributes["DisplayName"].Value;
if(name.Contains("AppName")) name = name.Replace("AppName", "AppTitle");
appName = GetName(dir, name, identity);
if(appName != "") names.Add(appName);
}
}
appName = GetName(dir, name, identity);
if(appName != "") names.Add(appName);
}
}
}
return names.Distinct().ToList();
}
private static string GetName(string dir, string name, string identity) {
StringBuilder sb = new StringBuilder();
int result;
result = SHLoadIndirectString(
@"@{" + Path.GetFileName(dir) + "? ms-resource://" + identity + "/resources/" + name.Split(':')[1] + "}",
sb, -1,
IntPtr.Zero
);
if(result == 0) return sb.ToString();
return "";
}
The code seems a bit lengthy, but it was the only was I found to do it. If you're looking at this later, then I hope this helped you solve your problem, but for now, I've learned what I needed.