トップ回答者
Windows 7 のコントロールパネルの展開

質問
-
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 が取得方法がわかれば実現できそうですがこれがわかりません。
ご存知の方、情報提供をよろしくお願い致します。
回答
-
「すべてのコントロール パネル項目」の 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 );
} -
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月26日 1:22
すべての返信
-
「すべてのコントロール パネル項目」の 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 );
} -
こんにちは、Sahleck さん。
NothingLastsForever さんからの情報はご確認いただけましたか?
ご確認された結果など、その後の状況もお知らせくださいね。
NohingLastsForever さん、情報ありがとうございます。いただきました情報は有効な情報であるかと思いますので、勝手ながらこちらで回答としてマークさせていただきました。
有効な情報に回答としてマークすることで、今後このスレッドを参照する方の目にも留まりやすくなりますので、Sahleck さんも回答としてマークしてみてくださいね。
他の方も、こちらの件で何か情報をお持ちの方がいらっしゃいましたら、是非投稿ください。お待ちしています。
それでは。
_______________________________________________
マイクロソフト株式会社 フォーラム オペレーター 山本 春海- 編集済み 山本春海 2010年5月21日 7:53 誤字修正
-
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月26日 1:22
-
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" という項目した出力されませんでした。
ん~~、なんでだろ・・・。