スキップしてメイン コンテンツへ

 none
Windows 7 のコントロールパネルの展開 RRS feed

  • 質問

  • Visual Studio 2008 standard 版でアプリケーション開発している者です。

    Windows 7 では、スタートメニューをカスタマイズすることでコントロールパネルをメニュー展開できます。

    具体的には、タスクバーとスタートメニューのプロパティー → カスタマイズで

    コントロールパネル → メニューとして表示する のラジオボタンを ON にすることでスタートボタンから

    コントロールパネルをサブメニュー展開できます。

    同じようにコントロールパネルを自作のアプリケーションからメニュー展開したいのですが、Vista までの処理ではできずに悩んでおります。

    Vista までであれば、以下のようにして ContorolPanel 内のオブジェクトが取得可能でした。(エラー処理は割愛)

    // デスクトップの IShellFolder へのポインタを取得
    SHGetDesktopFolder(&pShellFolderDesktop);

    // IMallocを取得
    SHGetMalloc(&lpMalloc);

    // ControlPanel の ITEMIDLIST を取得
    SHGetSpecialFolderLocation(hWnd, CSIDL_CONTROLS, &lpIDList);

    // ControlPanel の ITEMIDLIST から IShellFolder へのポインタを取得
    pShellFolderDesktop->BindToObject(lpIDList, NULL, IID_IShellFolder, (LPVOID*)&pFolder);

    // ControlPanel 内オブジェクトを列挙するためのインターフェースを取得
    pFolder->EnumObjects(hWnd, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &lpEnum);

    // ControlPanel 内オブジェクトのアイテムIDリストを取得
    lpEnum->Next(1, &lpItem, &ulFetched);

    Windows 7 ではコントロールパネル内のオブジェクトをすべて表示するには「すべてのコントロールパネル項目」の表示の選択が必要になっていますので、これに相当する  ITEMIDLIST が取得方法がわかれば実現できそうですがこれがわかりません。

    ご存知の方、情報提供をよろしくお願い致します。

     

    2010年4月3日 9:25

回答

  • 「すべてのコントロール パネル項目」の ITEMIDLIST は取得できるようです。

    が、↓のコードはやり方が良くないのか、なぜか、コントロールパネルの項目は一つ ( "Java" ) しかリストされませんでした。

    #include "stdafx.h"

    LPSHELLFOLDER GetSubFolder( LPSHELLFOLDER psfParent, LPTSTR pszName );

    int _tmain(int argc, _TCHAR* argv[])
    {
     LPSHELLFOLDER psfDeskTop;
     ULONG ulEaten;
     LPITEMIDLIST piidlControlPanel;
     TCHAR szBuffer[ MAX_PATH ];

     if( S_OK == SHGetDesktopFolder( &psfDeskTop ) ) {
      if( S_OK == psfDeskTop->ParseDisplayName( NULL, NULL, L"::{26EE0668-A00A-44D7-9371-BEB064C98683}", &ulEaten, &piidlControlPanel, NULL ) ) {
       LPSHELLFOLDER psfControlPanel;
       if( S_OK == psfDeskTop->BindToObject( piidlControlPanel, NULL, IID_IShellFolder, ( LPVOID * )&psfControlPanel ) ) {
        LPSHELLFOLDER psfAll = GetSubFolder( psfControlPanel, _T("すべてのコントロール パネル項目") );
        if( psfAll ) {
         LPENUMIDLIST peidl;
         if( S_OK == psfAll->EnumObjects( NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &peidl ) ) {
          STRRET srName;
          LPITEMIDLIST piidl;
          while( S_OK == peidl->Next( 1, &piidl, &ulEaten ) ) {
           // peidl->Next() が失敗します。
           if( S_OK == psfAll->GetDisplayNameOf( piidl, SHGDN_FORADDRESSBAR, &srName ) ) {
            StrRetToBuf( &srName, piidl, szBuffer, MAX_PATH );
            _tprintf( _T("%s\n"), szBuffer );
           }
          }
         }
        }
       }
      }
     }

     return 0;
    }

    LPSHELLFOLDER GetSubFolder( LPSHELLFOLDER psfParent, LPTSTR pszName )
    {
     LPENUMIDLIST peidl;
     ULONG ulEaten;
     TCHAR szBuffer[ MAX_PATH ];

     if( S_OK == psfParent->EnumObjects( NULL, SHCONTF_FOLDERS, &peidl ) ) {
      STRRET srName;
      LPITEMIDLIST piidl;

      while( S_OK == peidl->Next( 1, &piidl, &ulEaten ) ) {
       if( S_OK == psfParent->GetDisplayNameOf( piidl, SHGDN_FORADDRESSBAR, &srName ) ) {
        StrRetToBuf( &srName, piidl, szBuffer, MAX_PATH );
        if( _tcscmp( szBuffer, pszName ) == 0 ) {
         LPSHELLFOLDER psf;
         if( S_OK == psfParent->BindToObject( piidl, NULL, IID_IShellFolder, ( LPVOID * )&psf ) ) {
          return( psf );
         }
        }
       }
      }
     }
     return( NULL );
    }

    2010年5月4日 6:17
  • NothingLastsForever 様

    情報ありがとうございます。

    申し訳ありません、しばらく見ていませんでした。

    (アラート?イベント?を登録しておいたつもりでしたがうまく登録できていないようです)

    すべてのコントロールパネル項目は "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}" のようです。

    "::{26EE0668-A00A-44D7-9371-BEB064C98683}" はコントロールパネルでこの下には "システムとセキュリティ" 等の9つのフォルダが取得できました。

    Desktop からたどると SHCONTF_FOLDERS 属性のコントロールパネルと SHCONTF_NONFOLDERS 属性のコントロールパネルの2つがあり、"::{26EE0668-A00A-44D7-9371-BEB064C98683}" は SHCONTF_FOLDERS 属性のコントロールパネルでした。

    残念ながら個々のコントロールパネル情報はやはり取得できないようです。

    http://logicalerror.seesaa.net/article/143148390.html

    に個々のコントロールパネル情報がありますが、これを決め打ちするぐらいのようです。

    Microsoft が情報を公開してくれるといいのですけどね。

    2010年5月25日 13:28

すべての返信

  • 「すべてのコントロール パネル項目」の ITEMIDLIST は取得できるようです。

    が、↓のコードはやり方が良くないのか、なぜか、コントロールパネルの項目は一つ ( "Java" ) しかリストされませんでした。

    #include "stdafx.h"

    LPSHELLFOLDER GetSubFolder( LPSHELLFOLDER psfParent, LPTSTR pszName );

    int _tmain(int argc, _TCHAR* argv[])
    {
     LPSHELLFOLDER psfDeskTop;
     ULONG ulEaten;
     LPITEMIDLIST piidlControlPanel;
     TCHAR szBuffer[ MAX_PATH ];

     if( S_OK == SHGetDesktopFolder( &psfDeskTop ) ) {
      if( S_OK == psfDeskTop->ParseDisplayName( NULL, NULL, L"::{26EE0668-A00A-44D7-9371-BEB064C98683}", &ulEaten, &piidlControlPanel, NULL ) ) {
       LPSHELLFOLDER psfControlPanel;
       if( S_OK == psfDeskTop->BindToObject( piidlControlPanel, NULL, IID_IShellFolder, ( LPVOID * )&psfControlPanel ) ) {
        LPSHELLFOLDER psfAll = GetSubFolder( psfControlPanel, _T("すべてのコントロール パネル項目") );
        if( psfAll ) {
         LPENUMIDLIST peidl;
         if( S_OK == psfAll->EnumObjects( NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &peidl ) ) {
          STRRET srName;
          LPITEMIDLIST piidl;
          while( S_OK == peidl->Next( 1, &piidl, &ulEaten ) ) {
           // peidl->Next() が失敗します。
           if( S_OK == psfAll->GetDisplayNameOf( piidl, SHGDN_FORADDRESSBAR, &srName ) ) {
            StrRetToBuf( &srName, piidl, szBuffer, MAX_PATH );
            _tprintf( _T("%s\n"), szBuffer );
           }
          }
         }
        }
       }
      }
     }

     return 0;
    }

    LPSHELLFOLDER GetSubFolder( LPSHELLFOLDER psfParent, LPTSTR pszName )
    {
     LPENUMIDLIST peidl;
     ULONG ulEaten;
     TCHAR szBuffer[ MAX_PATH ];

     if( S_OK == psfParent->EnumObjects( NULL, SHCONTF_FOLDERS, &peidl ) ) {
      STRRET srName;
      LPITEMIDLIST piidl;

      while( S_OK == peidl->Next( 1, &piidl, &ulEaten ) ) {
       if( S_OK == psfParent->GetDisplayNameOf( piidl, SHGDN_FORADDRESSBAR, &srName ) ) {
        StrRetToBuf( &srName, piidl, szBuffer, MAX_PATH );
        if( _tcscmp( szBuffer, pszName ) == 0 ) {
         LPSHELLFOLDER psf;
         if( S_OK == psfParent->BindToObject( piidl, NULL, IID_IShellFolder, ( LPVOID * )&psf ) ) {
          return( psf );
         }
        }
       }
      }
     }
     return( NULL );
    }

    2010年5月4日 6:17
  • こんにちは、Sahleck さん。

    NothingLastsForever さんからの情報はご確認いただけましたか?
    ご確認された結果など、その後の状況もお知らせくださいね。

    NohingLastsForever さん、情報ありがとうございます。いただきました情報は有効な情報であるかと思いますので、勝手ながらこちらで回答としてマークさせていただきました。
    有効な情報に回答としてマークすることで、今後このスレッドを参照する方の目にも留まりやすくなりますので、Sahleck さんも回答としてマークしてみてくださいね。

    他の方も、こちらの件で何か情報をお持ちの方がいらっしゃいましたら、是非投稿ください。お待ちしています。
    それでは。
    _______________________________________________
    マイクロソフト株式会社 フォーラム オペレーター 山本 春海

    2010年5月21日 7:50
    モデレータ
  • NothingLastsForever 様

    情報ありがとうございます。

    申し訳ありません、しばらく見ていませんでした。

    (アラート?イベント?を登録しておいたつもりでしたがうまく登録できていないようです)

    すべてのコントロールパネル項目は "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}" のようです。

    "::{26EE0668-A00A-44D7-9371-BEB064C98683}" はコントロールパネルでこの下には "システムとセキュリティ" 等の9つのフォルダが取得できました。

    Desktop からたどると SHCONTF_FOLDERS 属性のコントロールパネルと SHCONTF_NONFOLDERS 属性のコントロールパネルの2つがあり、"::{26EE0668-A00A-44D7-9371-BEB064C98683}" は SHCONTF_FOLDERS 属性のコントロールパネルでした。

    残念ながら個々のコントロールパネル情報はやはり取得できないようです。

    http://logicalerror.seesaa.net/article/143148390.html

    に個々のコントロールパネル情報がありますが、これを決め打ちするぐらいのようです。

    Microsoft が情報を公開してくれるといいのですけどね。

    2010年5月25日 13:28
  • http://logicalerror.seesaa.net/article/143148390.html

    の情報を元に、ちょっと試してみました。

    C# で

    ------------------------------------------------------------------------------------------------------------------------

    using System;
    using Shell32;

    namespace CsControlPanelList
    {
        class Program
        {
            static void Main(string[] args)
            {
                Shell s = new Shell();
                Folder fld = s.NameSpace("::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0");
                FolderItems fis = fld.Items();
                foreach (FolderItem fi in fis)
                {
                    Console.WriteLine(fi.Name + " " + fi.Path );
                }
            }
        }
    }

    ------------------------------------------------------------------------------------------------------------------------

    ( Microsoft Shell Controls And Automation を参照設定に追加 )

    とすると、コントロールパネルの項目の一覧を取得することができました。

    これと同じことを C++ で記述すれば、C++ でもコントロールパネルの項目の一覧が取得できるはずなのですが、

    stdafx.h

    ------------------------------------------------------------------------------------------------------------------------

    #pragma once

    #include "targetver.h"

    #include <windows.h>
    #include <shlobj.h>
    #include <locale.h>
    #include <stdio.h>
    #include <tchar.h>
    ------------------------------------------------------------------------------------------------------------------------

     

    ------------------------------------------------------------------------------------------------------------------------

    #include "stdafx.h"

    void _tmain(int argc, _TCHAR* argv[])
    {
     IShellDispatch *pShell;

     _tsetlocale( LC_ALL, _T("") );

     CoInitialize(0);

     if( S_OK == CoCreateInstance( (REFCLSID)CLSID_Shell, 0, CLSCTX_INPROC_SERVER, (REFIID)IID_IShellDispatch, ( LPVOID * )&pShell ) ) {
      VARIANT vDir;
      VariantInit( &vDir );
      vDir.vt = VT_BSTR;
      vDir.bstrVal = SysAllocString( _T("::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0") );
      Folder *pf;
      if( S_OK == pShell->NameSpace( vDir, &pf ) ) {
       FolderItems2 *pfis;
       if( S_OK == pf->Items( (FolderItems **)&pfis ) ) {

        // FolderItems::Item を使用した方法
        long lCount;
        if( S_OK == pfis->get_Count( &lCount ) ) {
         VARIANT vIndex;
         VariantInit( &vIndex );
         vIndex.vt = VT_I4;
         FolderItem *pfi;
         BSTR bs;
         for( int i = 0; i < lCount; i++ ) {
          vIndex.intVal = i;
          if( S_OK == pfis->Item( vIndex, &pfi ) ) {
           if( S_OK == pfi->get_Name( &bs ) ) {
            _tprintf( _T("%s "), bs );
           }
           if( S_OK == pfi->get_Path( &bs ) ) {
            _tprintf( _T("%s\n"), bs );
           }
          }

         }
         VariantClear( &vIndex );
        }

        // FolderItems::_NewEnum を使用した方法
        IEnumVARIANT *pev;
        if( S_OK == pfis->_NewEnum( (IUnknown **)&pev ) ) {
         VARIANT vItem;
         VariantInit( &vItem );
         BSTR bs;
         ULONG ulFetched;
         while( S_OK == pev->Next( 1, &vItem, &ulFetched ) ) {
          if( S_OK == pf->GetDetailsOf( vItem, 0, &bs ) ) {
           _tprintf( _T("%s "), bs );
          }
         }
         VariantClear( &vItem );
         pev->Release();
        }

        pfis->Release();
       }
       pf->Release();
      }
      SysFreeString( vDir.bstrVal );
      VariantClear( &vDir );
      pShell->Release();
     }

     CoUninitialize();
    }
    ------------------------------------------------------------------------------------------------------------------------

    のようにしてみたところ、私の環境では前回の IShellFolder、IEnumIDList を使用した方法と同様、 "Java" という項目した出力されませんでした。

    ん~~、なんでだろ・・・。

     

     

    2010年5月29日 14:01
  • のようにしてみたところ、私の環境では前回の IShellFolder、IEnumIDList を使用した方法と同様、 "Java" という項目した出力されませんでした。

    ん~~、なんでだろ・・・。


    私のPC環境は Windows7 の 64bit 版なのですが、今まで、対象プラットフォームを Win32 に設定してビルドしていました。

    しかし、対象プラットフォームを x64 にしてビルドしてみると、問題なく動作しました。( Win32 でも、なぜ "Java" だけ出力されるのか、よくわかりませんが・・・。 )

    2010年5月30日 14:40