2015-08-20 135 views
9

我開發了一個函數,它返回給定窗口句柄的窗口圖標。它看起來像這樣。從桌面應用程序獲取「現代」Windows應用程序的圖標?

private static BitmapSource GetWindowIcon(IntPtr windowHandle) 
{ 
    var hIcon = default(IntPtr); 
    hIcon = SendMessage(windowHandle, WM_GETICON, ICON_BIG, IntPtr.Zero); 

    if (hIcon == IntPtr.Zero) 
     hIcon = GetClassLongPtr(windowHandle, GCL_HICON); 

    if (hIcon == IntPtr.Zero) 
    { 
     hIcon = LoadIcon(IntPtr.Zero, (IntPtr)0x7F00/*IDI_APPLICATION*/); 
    } 

    if (hIcon != IntPtr.Zero) 
    { 
     return Imaging.CreateBitmapSourceFromHIcon(hIcon, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); 
    } else { 
     throw new InvalidOperationException("Could not load window icon."); 
    } 
} 

我用這個函數結合GetForegroundWindow得到活動窗口的圖標。

但是,它似乎產生通用應用程序相同的無光澤的圖標。

是否有可能以某種方式從正在運行的通用應用程序中獲取平鋪圖像或圖標?

+0

'LoadIcon只能加載大小符合SM_CXICON和SM_CYICON系統度量值的圖標。使用LoadImage函數加載其他大小的圖標.' - [MSDN](https://msdn.microsoft.com/en-us/library/windows/desktop/ms648072%28v=vs.85%29.aspx) – theB

+1

通常情況下,你可以用LoadLibraryEx做這種事情......但是Windows 10應用程序真的很奇特,它們的圖標沒有作爲資源存儲在它們的主要可執行文件中......它存在於資源文件的迷宮中,構成應用程序包的目錄。 我不知道從所述應用程序中檢索到「大型」圖標,至少不是從桌面上獲取的。 但是,我正在研究它,因爲你激怒了我的好奇心。 –

+1

到目前爲止我發現的是,它深入COM內部,可能需要使用C++/CLI來完成,而且您需要提前知道應用程序主對象的類ID。這只是快速瀏覽API文檔。我只是在黑暗中刺傷,但我似乎越來越接近它可能發生的方式。 –

回答

11

下面是一些示例代碼,演示如何完成此操作。需要注意的是:

  1. 您應該運行此evelated,否則你將無法使用應用程序資源訪問的文件夾(我想,真的沒有檢查自己,因爲調查的事我自己授予訪問該文件夾)。
  2. 現代應用程序正在ApplicationFrameHost主機進程下運行。您需要一些技巧才能獲得真正的可執行文件(如Calculator.exe),這些技巧在代碼中進行了評論。
  3. 現代應用程序清單包含徽標的路徑,但可能會有多個徽標(黑色,白色,以白色爲例)。你將需要一些邏輯來選擇一個。沒有詳細調查這件事。
  4. 我在Windows 10的計算器應用程序上測試了它,它工作正常。然而,當然,更多的應用程序需要更多的測試來確保一切正常。

下面是代碼:

public static class IconHelper { 
    public static BitmapSource GetForegroundWindowIcon() { 
     var hwnd = GetForegroundWindow(); 
     uint pid; 
     GetWindowThreadProcessId(hwnd, out pid); 
     Process proc = Process.GetProcessById((int) pid); 
     // modern apps run under ApplicationFrameHost host process in windows 10 
     // don't forget to check if that is true for windows 8 - maybe they use another host there 
     if (proc.MainModule.ModuleName == "ApplicationFrameHost.exe") { 
      // this should be modern app 
      return GetModernAppLogo(hwnd); 
     } 
     return GetWindowIcon(hwnd); 
    } 

    public static BitmapSource GetModernAppLogo(IntPtr hwnd) { 
     // get folder where actual app resides 
     var exePath = GetModernAppProcessPath(hwnd); 
     var dir = System.IO.Path.GetDirectoryName(exePath); 
     var manifestPath = System.IO.Path.Combine(dir, "AppxManifest.xml");    
     if (File.Exists(manifestPath)) { 
      // this is manifest file 
      string pathToLogo; 
      using (var fs = File.OpenRead(manifestPath)) { 
       var manifest = XDocument.Load(fs); 
       const string ns = "http://schemas.microsoft.com/appx/manifest/foundation/windows10"; 
       // rude parsing - take more care here 
       pathToLogo = manifest.Root.Element(XName.Get("Properties", ns)).Element(XName.Get("Logo", ns)).Value; 
      } 
      // now here it is tricky again - there are several files that match logo, for example 
      // black, white, contrast white. Here we choose first, but you might do differently 
      string finalLogo = null; 
      // serach for all files that match file name in Logo element but with any suffix (like "Logo.black.png, Logo.white.png etc) 
      foreach (var logoFile in Directory.GetFiles(System.IO.Path.Combine(dir, System.IO.Path.GetDirectoryName(pathToLogo)), 
       System.IO.Path.GetFileNameWithoutExtension(pathToLogo) + "*" + System.IO.Path.GetExtension(pathToLogo))) { 
       finalLogo = logoFile; 
       break; 
      } 

      if (System.IO.File.Exists(finalLogo)) { 
       using (var fs = File.OpenRead(finalLogo)) { 
        var img = new BitmapImage() { 
        }; 
        img.BeginInit(); 
        img.StreamSource = fs; 
        img.CacheOption = BitmapCacheOption.OnLoad; 
        img.EndInit(); 
        return img; 
       } 
      } 
     } 
     return null; 
    } 

    private static string GetModernAppProcessPath(IntPtr hwnd) { 
     uint pid = 0; 
     GetWindowThreadProcessId(hwnd, out pid);    
     // now this is a bit tricky. Modern apps are hosted inside ApplicationFrameHost process, so we need to find 
     // child window which does NOT belong to this process. This should be the process we need 
     var children = GetChildWindows(hwnd); 
     foreach (var childHwnd in children) { 
      uint childPid = 0; 
      GetWindowThreadProcessId(childHwnd, out childPid); 
      if (childPid != pid) { 
       // here we are 
       Process childProc = Process.GetProcessById((int) childPid); 
       return childProc.MainModule.FileName; 
      } 
     } 

     throw new Exception("Cannot find a path to Modern App executable file"); 
    } 

    public static BitmapSource GetWindowIcon(IntPtr windowHandle) { 
     var hIcon = default(IntPtr); 
     hIcon = SendMessage(windowHandle, WM_GETICON, (IntPtr) ICON_BIG, IntPtr.Zero); 

     if (hIcon == IntPtr.Zero) 
      hIcon = GetClassLongPtr(windowHandle, GCL_HICON); 

     if (hIcon == IntPtr.Zero) { 
      hIcon = LoadIcon(IntPtr.Zero, (IntPtr) 0x7F00 /*IDI_APPLICATION*/); 
     } 

     if (hIcon != IntPtr.Zero) { 
      return Imaging.CreateBitmapSourceFromHIcon(hIcon, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); 
     } 
     else { 
      throw new InvalidOperationException("Could not load window icon."); 
     } 
    } 

    #region Helper methods 
    const UInt32 WM_GETICON = 0x007F; 
    const int ICON_BIG = 1; 
    const int GCL_HICON = -14; 

    private static List<IntPtr> GetChildWindows(IntPtr parent) 
    { 
     List<IntPtr> result = new List<IntPtr>(); 
     GCHandle listHandle = GCHandle.Alloc(result); 
     try 
     { 
      EnumWindowProc childProc = new EnumWindowProc(EnumWindow); 
      EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle)); 
     } 
     finally 
     { 
      if (listHandle.IsAllocated) 
       listHandle.Free(); 
     } 
     return result; 
    } 

    private static bool EnumWindow(IntPtr handle, IntPtr pointer) 
    { 
     GCHandle gch = GCHandle.FromIntPtr(pointer); 
     List<IntPtr> list = gch.Target as List<IntPtr>; 
     if (list == null) 
     { 
      throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>"); 
     } 
     list.Add(handle); 
     // You can modify this to check to see if you want to cancel the operation, then return a null here 
     return true; 
    } 

    public delegate bool EnumWindowProc(IntPtr hwnd, IntPtr lParam); 
    [DllImport("user32.Dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    public static extern bool EnumChildWindows(IntPtr parentHandle, EnumWindowProc callback, IntPtr lParam); 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern int GetWindowThreadProcessId(IntPtr handle, out uint processId); 

    [DllImport("user32.dll")] 
    private static extern IntPtr GetForegroundWindow(); 

    [DllImport("user32.dll")] 
    static extern IntPtr LoadIcon(IntPtr hInstance, IntPtr lpIconName); 

    [DllImport("user32.dll", CharSet = CharSet.Auto)] 
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam); 

    private static IntPtr GetClassLongPtr(IntPtr hWnd, int nIndex) 
    { 
     if (IntPtr.Size > 4) 
      return GetClassLongPtr64(hWnd, nIndex); 
     else 
      return new IntPtr(GetClassLongPtr32(hWnd, nIndex)); 
    } 

    [DllImport("user32.dll", EntryPoint = "GetClassLong")] 
    public static extern uint GetClassLongPtr32(IntPtr hWnd, int nIndex); 

    [DllImport("user32.dll", EntryPoint = "GetClassLongPtr")] 
    public static extern IntPtr GetClassLongPtr64(IntPtr hWnd, int nIndex); 
    #endregion 

} 

用法就是:

var icon = IconHelper.GetForegroundWindowIcon(); 
+0

非常感謝您的回答。這似乎在不需要管理員權限的應用中工作。 – Jason

+0

奇怪的是,這適用於某些應用程序,但不適用於其他應用程序。它似乎不適用於Skype或設置應用程序。沒有一個孩子有不同的pid – Kir

4

最 「現代應用程序」 的(或Windows Store應用程序,或在AppX中應用模型的應用程序)的信息可以從官方API查詢。

您可以從GetPackageFullName function開始(它獲取指定進程的包全名)。一旦你得到一個包全名,你可以使用Package Query API來獲得更多信息。

這些API是本機的,所以在我所知的.NET Framework中它們沒有等價物。但是,它們可以以某種方式從WinRT應用程序訪問(並且確實可以從標準.NET Framework應用程序訪問某些WinRT API,但這種方法很麻煩)。

因此,我建立了一個實用程序類,它將允許您從這些應用程序獲取信息。這裏是一個示例應用程序,用於轉儲所有當前加載的Windows應用商店包裝&應用程序。

這些應用程序中包含的圖像是特殊的,因爲它們被定義爲可以使用限定符調整以形成最終路徑的資源(資產)密鑰。這例如在這裏被記錄:How to name resources using qualifiers (HTML)並且在這裏:Quickstart: Using file or image resources (HTML)

問題是你可以發現很大程度上取決於應用程序本身,所以確定你可以使用什麼圖像並不是很容易,我還沒有找到任何API,所以我編寫了一個樣本獲得最高的樣本以給定資源名稱的縮放圖像爲例(FindHighestScaleQualifiedImagePath)。您可以從此路徑加載WPF BitmapSource(或任何其他映像平臺資源)。

static void Main(string[] args) 
    { 
     foreach (var p in Process.GetProcesses()) 
     { 
      var package = AppxPackage.FromProcess(p); 
      if (package != null) 
      { 
       Show(0, package); 
       Console.WriteLine(); 
       Console.WriteLine(); 
      } 
     } 
    } 

    private static void Show(int indent, AppxPackage package) 
    { 
     string sindent = new string(' ', indent); 
     Console.WriteLine(sindent + "FullName    : " + package.FullName); 
     Console.WriteLine(sindent + "FamilyName    : " + package.FamilyName); 
     Console.WriteLine(sindent + "IsFramework   : " + package.IsFramework); 
     Console.WriteLine(sindent + "ApplicationUserModelId : " + package.ApplicationUserModelId); 
     Console.WriteLine(sindent + "Path     : " + package.Path); 
     Console.WriteLine(sindent + "Publisher    : " + package.Publisher); 
     Console.WriteLine(sindent + "PublisherId   : " + package.PublisherId); 
     Console.WriteLine(sindent + "Logo     : " + package.Logo); 
     Console.WriteLine(sindent + "Best Logo Path   : " + package.FindHighestScaleQualifiedImagePath(package.Logo)); 
     Console.WriteLine(sindent + "ProcessorArchitecture : " + package.ProcessorArchitecture); 
     Console.WriteLine(sindent + "Version    : " + package.Version); 
     Console.WriteLine(sindent + "PublisherDisplayName : " + package.PublisherDisplayName); 
     Console.WriteLine(sindent + " Localized   : " + package.LoadResourceString(package.PublisherDisplayName)); 
     Console.WriteLine(sindent + "DisplayName   : " + package.DisplayName); 
     Console.WriteLine(sindent + " Localized   : " + package.LoadResourceString(package.DisplayName)); 
     Console.WriteLine(sindent + "Description   : " + package.Description); 
     Console.WriteLine(sindent + " Localized   : " + package.LoadResourceString(package.Description)); 

     Console.WriteLine(sindent + "Apps     :"); 
     int i = 0; 
     foreach (var app in package.Apps) 
     { 
      Console.WriteLine(sindent + " App [" + i + "] Description  : " + app.Description); 
      Console.WriteLine(sindent + " Localized   : " + package.LoadResourceString(app.Description)); 
      Console.WriteLine(sindent + " App [" + i + "] DisplayName  : " + app.DisplayName); 
      Console.WriteLine(sindent + " Localized   : " + package.LoadResourceString(app.DisplayName)); 
      Console.WriteLine(sindent + " App [" + i + "] ShortName   : " + app.ShortName); 
      Console.WriteLine(sindent + " Localized   : " + package.LoadResourceString(app.ShortName)); 
      Console.WriteLine(sindent + " App [" + i + "] EntryPoint  : " + app.EntryPoint); 
      Console.WriteLine(sindent + " App [" + i + "] Executable  : " + app.Executable); 
      Console.WriteLine(sindent + " App [" + i + "] Id    : " + app.Id); 
      Console.WriteLine(sindent + " App [" + i + "] Logo    : " + app.Logo); 
      Console.WriteLine(sindent + " App [" + i + "] SmallLogo   : " + app.SmallLogo); 
      Console.WriteLine(sindent + " App [" + i + "] StartPage   : " + app.StartPage); 
      Console.WriteLine(sindent + " App [" + i + "] Square150x150Logo : " + app.Square150x150Logo); 
      Console.WriteLine(sindent + " App [" + i + "] Square30x30Logo : " + app.Square30x30Logo); 
      Console.WriteLine(sindent + " App [" + i + "] BackgroundColor : " + app.BackgroundColor); 
      Console.WriteLine(sindent + " App [" + i + "] ForegroundText : " + app.ForegroundText); 
      Console.WriteLine(sindent + " App [" + i + "] WideLogo   : " + app.WideLogo); 
      Console.WriteLine(sindent + " App [" + i + "] Wide310x310Logo : " + app.Wide310x310Logo); 
      Console.WriteLine(sindent + " App [" + i + "] Square310x310Logo : " + app.Square310x310Logo); 
      Console.WriteLine(sindent + " App [" + i + "] Square70x70Logo : " + app.Square70x70Logo); 
      Console.WriteLine(sindent + " App [" + i + "] MinWidth   : " + app.MinWidth); 
      Console.WriteLine(sindent + " App [" + i + "] Square71x71Logo : " + app.GetStringValue("Square71x71Logzo")); 
      i++; 
     } 

     Console.WriteLine(sindent + "Deps     :"); 
     foreach (var dep in package.DependencyGraph) 
     { 
      Show(indent + 1, dep); 
     } 
    } 

public sealed class AppxPackage 
{ 
    private List<AppxApp> _apps = new List<AppxApp>(); 
    private IAppxManifestProperties _properties; 

    private AppxPackage() 
    { 
    } 

    public string FullName { get; private set; } 
    public string Path { get; private set; } 
    public string Publisher { get; private set; } 
    public string PublisherId { get; private set; } 
    public string ResourceId { get; private set; } 
    public string FamilyName { get; private set; } 
    public string ApplicationUserModelId { get; private set; } 
    public string Logo { get; private set; } 
    public string PublisherDisplayName { get; private set; } 
    public string Description { get; private set; } 
    public string DisplayName { get; private set; } 
    public bool IsFramework { get; private set; } 
    public Version Version { get; private set; } 
    public AppxPackageArchitecture ProcessorArchitecture { get; private set; } 

    public IReadOnlyList<AppxApp> Apps 
    { 
     get 
     { 
      return _apps; 
     } 
    } 

    public IEnumerable<AppxPackage> DependencyGraph 
    { 
     get 
     { 
      return QueryPackageInfo(FullName, PackageConstants.PACKAGE_FILTER_ALL_LOADED).Where(p => p.FullName != FullName); 
     } 
    } 

    public string FindHighestScaleQualifiedImagePath(string resourceName) 
    { 
     if (resourceName == null) 
      throw new ArgumentNullException("resourceName"); 

     const string scaleToken = ".scale-"; 
     var sizes = new List<int>(); 
     string name = System.IO.Path.GetFileNameWithoutExtension(resourceName); 
     string ext = System.IO.Path.GetExtension(resourceName); 
     foreach (var file in Directory.EnumerateFiles(System.IO.Path.Combine(Path, System.IO.Path.GetDirectoryName(resourceName)), name + scaleToken + "*" + ext)) 
     { 
      string fileName = System.IO.Path.GetFileNameWithoutExtension(file); 
      int pos = fileName.IndexOf(scaleToken) + scaleToken.Length; 
      string sizeText = fileName.Substring(pos); 
      int size; 
      if (int.TryParse(sizeText, out size)) 
      { 
       sizes.Add(size); 
      } 
     } 
     if (sizes.Count == 0) 
      return null; 

     sizes.Sort(); 
     return System.IO.Path.Combine(Path, System.IO.Path.GetDirectoryName(resourceName), name + scaleToken + sizes.Last() + ext); 
    } 

    public override string ToString() 
    { 
     return FullName; 
    } 

    public static AppxPackage FromWindow(IntPtr handle) 
    { 
     int processId; 
     GetWindowThreadProcessId(handle, out processId); 
     if (processId == 0) 
      return null; 

     return FromProcess(processId); 
    } 

    public static AppxPackage FromProcess(Process process) 
    { 
     if (process == null) 
     { 
      process = Process.GetCurrentProcess(); 
     } 

     try 
     { 
      return FromProcess(process.Handle); 
     } 
     catch 
     { 
      // probably access denied on .Handle 
      return null; 
     } 
    } 

    public static AppxPackage FromProcess(int processId) 
    { 
     const int QueryLimitedInformation = 0x1000; 
     IntPtr hProcess = OpenProcess(QueryLimitedInformation, false, processId); 
     try 
     { 
      return FromProcess(hProcess); 
     } 
     finally 
     { 
      if (hProcess != IntPtr.Zero) 
      { 
       CloseHandle(hProcess); 
      } 
     } 
    } 

    public static AppxPackage FromProcess(IntPtr hProcess) 
    { 
     if (hProcess == IntPtr.Zero) 
      return null; 

     // hprocess must have been opened with QueryLimitedInformation 
     int len = 0; 
     GetPackageFullName(hProcess, ref len, null); 
     if (len == 0) 
      return null; 

     var sb = new StringBuilder(len); 
     string fullName = GetPackageFullName(hProcess, ref len, sb) == 0 ? sb.ToString() : null; 
     if (string.IsNullOrEmpty(fullName)) // not an AppX 
      return null; 

     var package = QueryPackageInfo(fullName, PackageConstants.PACKAGE_FILTER_HEAD).First(); 

     len = 0; 
     GetApplicationUserModelId(hProcess, ref len, null); 
     sb = new StringBuilder(len); 
     package.ApplicationUserModelId = GetApplicationUserModelId(hProcess, ref len, sb) == 0 ? sb.ToString() : null; 
     return package; 
    } 

    public string GetPropertyStringValue(string name) 
    { 
     if (name == null) 
      throw new ArgumentNullException("name"); 

     return GetStringValue(_properties, name); 
    } 

    public bool GetPropertyBoolValue(string name) 
    { 
     if (name == null) 
      throw new ArgumentNullException("name"); 

     return GetBoolValue(_properties, name); 
    } 

    public string LoadResourceString(string resource) 
    { 
     return LoadResourceString(FullName, resource); 
    } 

    private static IEnumerable<AppxPackage> QueryPackageInfo(string fullName, PackageConstants flags) 
    { 
     IntPtr infoRef; 
     OpenPackageInfoByFullName(fullName, 0, out infoRef); 
     if (infoRef != IntPtr.Zero) 
     { 
      IntPtr infoBuffer = IntPtr.Zero; 
      try 
      { 
       int len = 0; 
       int count; 
       GetPackageInfo(infoRef, flags, ref len, IntPtr.Zero, out count); 
       if (len > 0) 
       { 
        var factory = (IAppxFactory)new AppxFactory(); 
        infoBuffer = Marshal.AllocHGlobal(len); 
        int res = GetPackageInfo(infoRef, flags, ref len, infoBuffer, out count); 
        for (int i = 0; i < count; i++) 
        { 
         var info = (PACKAGE_INFO)Marshal.PtrToStructure(infoBuffer + i * Marshal.SizeOf(typeof(PACKAGE_INFO)), typeof(PACKAGE_INFO)); 
         var package = new AppxPackage(); 
         package.FamilyName = Marshal.PtrToStringUni(info.packageFamilyName); 
         package.FullName = Marshal.PtrToStringUni(info.packageFullName); 
         package.Path = Marshal.PtrToStringUni(info.path); 
         package.Publisher = Marshal.PtrToStringUni(info.packageId.publisher); 
         package.PublisherId = Marshal.PtrToStringUni(info.packageId.publisherId); 
         package.ResourceId = Marshal.PtrToStringUni(info.packageId.resourceId); 
         package.ProcessorArchitecture = info.packageId.processorArchitecture; 
         package.Version = new Version(info.packageId.VersionMajor, info.packageId.VersionMinor, info.packageId.VersionBuild, info.packageId.VersionRevision); 

         // read manifest 
         string manifestPath = System.IO.Path.Combine(package.Path, "AppXManifest.xml"); 
         const int STGM_SHARE_DENY_NONE = 0x40; 
         IStream strm; 
         SHCreateStreamOnFileEx(manifestPath, STGM_SHARE_DENY_NONE, 0, false, IntPtr.Zero, out strm); 
         if (strm != null) 
         { 
          var reader = factory.CreateManifestReader(strm); 
          package._properties = reader.GetProperties(); 
          package.Description = package.GetPropertyStringValue("Description"); 
          package.DisplayName = package.GetPropertyStringValue("DisplayName"); 
          package.Logo = package.GetPropertyStringValue("Logo"); 
          package.PublisherDisplayName = package.GetPropertyStringValue("PublisherDisplayName"); 
          package.IsFramework = package.GetPropertyBoolValue("Framework"); 

          var apps = reader.GetApplications(); 
          while (apps.GetHasCurrent()) 
          { 
           var app = apps.GetCurrent(); 
           var appx = new AppxApp(app); 
           appx.Description = GetStringValue(app, "Description"); 
           appx.DisplayName = GetStringValue(app, "DisplayName"); 
           appx.EntryPoint = GetStringValue(app, "EntryPoint"); 
           appx.Executable = GetStringValue(app, "Executable"); 
           appx.Id = GetStringValue(app, "Id"); 
           appx.Logo = GetStringValue(app, "Logo"); 
           appx.SmallLogo = GetStringValue(app, "SmallLogo"); 
           appx.StartPage = GetStringValue(app, "StartPage"); 
           appx.Square150x150Logo = GetStringValue(app, "Square150x150Logo"); 
           appx.Square30x30Logo = GetStringValue(app, "Square30x30Logo"); 
           appx.BackgroundColor = GetStringValue(app, "BackgroundColor"); 
           appx.ForegroundText = GetStringValue(app, "ForegroundText"); 
           appx.WideLogo = GetStringValue(app, "WideLogo"); 
           appx.Wide310x310Logo = GetStringValue(app, "Wide310x310Logo"); 
           appx.ShortName = GetStringValue(app, "ShortName"); 
           appx.Square310x310Logo = GetStringValue(app, "Square310x310Logo"); 
           appx.Square70x70Logo = GetStringValue(app, "Square70x70Logo"); 
           appx.MinWidth = GetStringValue(app, "MinWidth"); 
           package._apps.Add(appx); 
           apps.MoveNext(); 
          } 
          Marshal.ReleaseComObject(strm); 
         } 
         yield return package; 
        } 
        Marshal.ReleaseComObject(factory); 
       } 
      } 
      finally 
      { 
       if (infoBuffer != IntPtr.Zero) 
       { 
        Marshal.FreeHGlobal(infoBuffer); 
       } 
       ClosePackageInfo(infoRef); 
      } 
     } 
    } 

    public static string LoadResourceString(string packageFullName, string resource) 
    { 
     if (packageFullName == null) 
      throw new ArgumentNullException("packageFullName"); 

     if (string.IsNullOrWhiteSpace(resource)) 
      return null; 

     const string resourceScheme = "ms-resource:"; 
     if (!resource.StartsWith(resourceScheme)) 
      return null; 

     string part = resource.Substring(resourceScheme.Length); 
     string url; 

     if (part.StartsWith("/")) 
     { 
      url = resourceScheme + "//" + part; 
     } 
     else 
     { 
      url = resourceScheme + "///resources/" + part; 
     } 

     string source = string.Format("@{{{0}? {1}}}", packageFullName, url); 
     var sb = new StringBuilder(1024); 
     int i = SHLoadIndirectString(source, sb, sb.Capacity, IntPtr.Zero); 
     if (i != 0) 
      return null; 

     return sb.ToString(); 
    } 

    private static string GetStringValue(IAppxManifestProperties props, string name) 
    { 
     if (props == null) 
      return null; 

     string value; 
     props.GetStringValue(name, out value); 
     return value; 
    } 

    private static bool GetBoolValue(IAppxManifestProperties props, string name) 
    { 
     bool value; 
     props.GetBoolValue(name, out value); 
     return value; 
    } 

    internal static string GetStringValue(IAppxManifestApplication app, string name) 
    { 
     string value; 
     app.GetStringValue(name, out value); 
     return value; 
    } 

    [Guid("5842a140-ff9f-4166-8f5c-62f5b7b0c781"), ComImport] 
    private class AppxFactory 
    { 
    } 

    [Guid("BEB94909-E451-438B-B5A7-D79E767B75D8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    private interface IAppxFactory 
    { 
     void _VtblGap0_2(); // skip 2 methods 
     IAppxManifestReader CreateManifestReader(IStream inputStream); 
    } 

    [Guid("4E1BD148-55A0-4480-A3D1-15544710637C"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    private interface IAppxManifestReader 
    { 
     void _VtblGap0_1(); // skip 1 method 
     IAppxManifestProperties GetProperties(); 
     void _VtblGap1_5(); // skip 5 methods 
     IAppxManifestApplicationsEnumerator GetApplications(); 
    } 

    [Guid("9EB8A55A-F04B-4D0D-808D-686185D4847A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    private interface IAppxManifestApplicationsEnumerator 
    { 
     IAppxManifestApplication GetCurrent(); 
     bool GetHasCurrent(); 
     bool MoveNext(); 
    } 

    [Guid("5DA89BF4-3773-46BE-B650-7E744863B7E8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    internal interface IAppxManifestApplication 
    { 
     [PreserveSig] 
     int GetStringValue([MarshalAs(UnmanagedType.LPWStr)] string name, [MarshalAs(UnmanagedType.LPWStr)] out string vaue); 
    } 

    [Guid("03FAF64D-F26F-4B2C-AAF7-8FE7789B8BCA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
    private interface IAppxManifestProperties 
    { 
     [PreserveSig] 
     int GetBoolValue([MarshalAs(UnmanagedType.LPWStr)]string name, out bool value); 
     [PreserveSig] 
     int GetStringValue([MarshalAs(UnmanagedType.LPWStr)] string name, [MarshalAs(UnmanagedType.LPWStr)] out string vaue); 
    } 

    [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)] 
    private static extern int SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, int cchOutBuf, IntPtr ppvReserved); 

    [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)] 
    private static extern int SHCreateStreamOnFileEx(string fileName, int grfMode, int attributes, bool create, IntPtr reserved, out IStream stream); 

    [DllImport("user32.dll")] 
    private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); 

    [DllImport("kernel32.dll")] 
    private static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); 

    [DllImport("kernel32.dll")] 
    private static extern bool CloseHandle(IntPtr hObject); 

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] 
    private static extern int OpenPackageInfoByFullName(string packageFullName, int reserved, out IntPtr packageInfoReference); 

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] 
    private static extern int GetPackageInfo(IntPtr packageInfoReference, PackageConstants flags, ref int bufferLength, IntPtr buffer, out int count); 

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] 
    private static extern int ClosePackageInfo(IntPtr packageInfoReference); 

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] 
    private static extern int GetPackageFullName(IntPtr hProcess, ref int packageFullNameLength, StringBuilder packageFullName); 

    [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] 
    private static extern int GetApplicationUserModelId(IntPtr hProcess, ref int applicationUserModelIdLength, StringBuilder applicationUserModelId); 

    [Flags] 
    private enum PackageConstants 
    { 
     PACKAGE_FILTER_ALL_LOADED = 0x00000000, 
     PACKAGE_PROPERTY_FRAMEWORK = 0x00000001, 
     PACKAGE_PROPERTY_RESOURCE = 0x00000002, 
     PACKAGE_PROPERTY_BUNDLE = 0x00000004, 
     PACKAGE_FILTER_HEAD = 0x00000010, 
     PACKAGE_FILTER_DIRECT = 0x00000020, 
     PACKAGE_FILTER_RESOURCE = 0x00000040, 
     PACKAGE_FILTER_BUNDLE = 0x00000080, 
     PACKAGE_INFORMATION_BASIC = 0x00000000, 
     PACKAGE_INFORMATION_FULL = 0x00000100, 
     PACKAGE_PROPERTY_DEVELOPMENT_MODE = 0x00010000, 
    } 

    [StructLayout(LayoutKind.Sequential, Pack = 4)] 
    private struct PACKAGE_INFO 
    { 
     public int reserved; 
     public int flags; 
     public IntPtr path; 
     public IntPtr packageFullName; 
     public IntPtr packageFamilyName; 
     public PACKAGE_ID packageId; 
    } 

    [StructLayout(LayoutKind.Sequential, Pack = 4)] 
    private struct PACKAGE_ID 
    { 
     public int reserved; 
     public AppxPackageArchitecture processorArchitecture; 
     public ushort VersionRevision; 
     public ushort VersionBuild; 
     public ushort VersionMinor; 
     public ushort VersionMajor; 
     public IntPtr name; 
     public IntPtr publisher; 
     public IntPtr resourceId; 
     public IntPtr publisherId; 
    } 
} 

public sealed class AppxApp 
{ 
    private AppxPackage.IAppxManifestApplication _app; 

    internal AppxApp(AppxPackage.IAppxManifestApplication app) 
    { 
     _app = app; 
    } 

    public string GetStringValue(string name) 
    { 
     if (name == null) 
      throw new ArgumentNullException("name"); 

     return AppxPackage.GetStringValue(_app, name); 
    } 

    // we code well-known but there are others (like Square71x71Logo, Square44x44Logo, whatever ...) 
    // https://msdn.microsoft.com/en-us/library/windows/desktop/hh446703.aspx 
    public string Description { get; internal set; } 
    public string DisplayName { get; internal set; } 
    public string EntryPoint { get; internal set; } 
    public string Executable { get; internal set; } 
    public string Id { get; internal set; } 
    public string Logo { get; internal set; } 
    public string SmallLogo { get; internal set; } 
    public string StartPage { get; internal set; } 
    public string Square150x150Logo { get; internal set; } 
    public string Square30x30Logo { get; internal set; } 
    public string BackgroundColor { get; internal set; } 
    public string ForegroundText { get; internal set; } 
    public string WideLogo { get; internal set; } 
    public string Wide310x310Logo { get; internal set; } 
    public string ShortName { get; internal set; } 
    public string Square310x310Logo { get; internal set; } 
    public string Square70x70Logo { get; internal set; } 
    public string MinWidth { get; internal set; } 
} 

public enum AppxPackageArchitecture 
{ 
    x86 = 0, 
    Arm = 5, 
    x64 = 9, 
    Neutral = 11, 
    Arm64 = 12 
} 
相關問題