2017-11-13 9 views
1

C#でユーザーPC上で動作するアプリケーションを作成していますが、Windowsの「デバイスとプリンタ」コントロールパネルに表示されているデバイスディスプレイ、キーボード、マウス、スピーカーなどのもの「デバイスとプリンタ」パネルに表示されているデバイスのみを一覧表示する

WMIを使用してすべてのデバイスの一覧を抽出できますが、完全ではなくコントロールパネルの部分にのみ表示されるものだけを抽出する方法がありますリスト?

私はオンラインで検索しましたが、これに関連するものは何も見つかりませんでしたし、デバイスがそのリストに表示される基準が何かを見つけることさえできません。

リストに表示されているデバイスのリストにアクセスすることはできますか?そうでない場合は、それらのデバイスのみを表示する完全リストに適用できるフィルタはありますか?事前

+2

私はp/invokeとCOM interopを使ってC#で['Microsoft.DevicesAndPrinters'](https://msdn.microsoft.com/en-us/library/windows/desktop/ee330741)のシェル項目を列挙しています%28v = vs.85%29.aspx?f = 255&MSPPError = -2147217396#DevicesAndPrinters)、['PKEY_Devices_CategoryIds'](https://msdn.microsoft.com/en-us/library/windows/)を確認してフィルタリングしてください。 desktop/mt805664.aspx)には 'PrintFax'で始まる項目が含まれています。あなたが興味を持っているならば、コードを共有するのは楽しいですが、それのどれもWMIではありません。 – jnm2

+0

コードを見ると素晴らしいと思います - 私は解決策としてWMIに固執していません:) –

答えて

1

おかげで、私は、pでそれを行う/確認PKEY_Devices_CategoryIdsPrintFaxで始まる項目が含まれていることを行うことでMicrosoft.DevicesAndPrintersとフィルタリングにおけるシェルの項目を列挙することによって起動し、COM相互運用機能。

あり答えに収まるように必要な相互運用機能の定義を煮詰めるする方法はませんが、これは私が表示名を列挙するために使用するロジック、DEVMODE名、および任意のサイズの画像です:

public sealed class PrinterInfo 
{ 
    public string IdName { get; } 
    public string DisplayName { get; } 
    public Bitmap Image { get; } 

    private PrinterInfo(string idName, string displayName, Bitmap image) 
    { 
     IdName = idName; 
     DisplayName = displayName; 
     Image = image; 
    } 

    public static IReadOnlyList<PrinterInfo> GetInstalledPrinterNamesAndImages(Size imageSize) 
    { 
     var r = new List<PrinterInfo>(); 

     using (var folderIdList = CreateDevicesAndPrintersIDL()) 
     { 
      var folder = GetShellFolder(folderIdList); 
      var enumerator = folder.EnumObjects(IntPtr.Zero, SHCONTF.NONFOLDERS); 

      for (;;) 
      { 
       // If you request more than are left, actualCount is 0, so we'll do one at a time. 
       var next = enumerator.Next(1, out var relativeIdList, out var actualCount); 
       next.ThrowIfError(); 
       if (next == HResult.False || actualCount != 1) break; // printerChild is junk 

       using (relativeIdList) 
       using (var absoluteIdList = ILCombine(folderIdList, relativeIdList)) 
       { 
        var shellItem = GetShellItem(absoluteIdList); 
        var idName = GetPrinterFriendlyNameIfPrinter(shellItem); 
        if (idName != null) 
         r.Add(new PrinterInfo(idName, GetDisplayName(shellItem), GetImage(shellItem, imageSize))); 
       } 
      } 
     } 

     return r; 
    } 

    private static ItemIdListSafeHandle CreateDevicesAndPrintersIDL() 
    { 
     SHGetKnownFolderIDList(FOLDERID.ControlPanelFolder, KF_FLAG.DEFAULT, IntPtr.Zero, out var controlPanelIdList).ThrowIfError(); 
     using (controlPanelIdList) 
     { 
      GetShellFolder(controlPanelIdList).ParseDisplayName(IntPtr.Zero, null, "::{A8A91A66-3A7D-4424-8D24-04E180695C7A}", IntPtr.Zero, out var childDevicesAndPriversIdList, IntPtr.Zero); 
      using (childDevicesAndPriversIdList) 
       return ILCombine(controlPanelIdList, childDevicesAndPriversIdList); 
     } 
    } 

    private static string GetPrinterFriendlyNameIfPrinter(IShellItem2 shellItem) 
    { 
     // Devices_PrimaryCategory returns "Printers" for printers and faxes on Windows 10 but "Printers and faxes" on Windows 7. 
     using (var categoryIds = new PropVariantSafeHandle()) 
     { 
      shellItem.GetProperty(PKEY.Devices_CategoryIds, categoryIds).ThrowIfError(); 
      if (!categoryIds.ToStringVector().Any(id => id.StartsWith("PrintFax", StringComparison.OrdinalIgnoreCase))) 
       return null; 
     } 

     // The canonical or "friendly name" needed to match the devmode 
     // https://blogs.msdn.microsoft.com/asklar/2009/10/21/getting-the-printer-friendly-name-from-the-device-center-shell-folder/ 
     // PKEY_Devices_InterfacePaths doesn't seem to ever be found, but PKEY_Devices_FriendlyName works so... 
     shellItem.GetString(PKEY.Devices_FriendlyName, out var friendlyName).ThrowIfError(); 
     return friendlyName.ReadAndFree(); 
    } 

    private static string GetDisplayName(IShellItem2 shellItem) 
    { 
     return shellItem.GetDisplayName(SIGDN.NORMALDISPLAY).ReadAndFree(); 
    } 

    private static Bitmap GetImage(IShellItem2 shellItem, Size imageSize) 
    { 
     return ((IShellItemImageFactory)shellItem).GetImage(new POINT(imageSize.Width, imageSize.Height), SIIGBF.SIIGBF_BIGGERSIZEOK) 
      .CopyAndFree(); // Bitmap.FromHbitmap is useless with alpha, so make a copy 
    } 


    private static IShellFolder GetShellFolder(ItemIdListSafeHandle itemIdList) 
    { 
     SHBindToObject(IntPtr.Zero, itemIdList, null, typeof(IShellFolder).GUID, out var objShellFolder).ThrowIfError(); 
     return (IShellFolder)objShellFolder; 
    } 

    private static IShellItem2 GetShellItem(ItemIdListSafeHandle itemIdList) 
    { 
     SHCreateItemFromIDList(itemIdList, typeof(IShellItem2).GUID, out var objShellItem).ThrowIfError(); 
     return (IShellItem2)objShellItem; 
    } 
} 

https://github.com/jnm2/example-devices-and-printers/tree/master/src

https://github.com/jnm2/example-devices-and-printers/tree/master/src-csharp6を参照してください、ValueTupleを必要としない、C#6バージョンの場合:(C#7)

ここでは、コンパイルすることができ、完全なデモがあります。

ご質問にはお答えします。

+0

これはありがとう、私は見て、それをテストし、私に質問があるかどうかをお知らせします:) –

関連する問題