Vista からフォルダ選択ダイアログが変わりました。
大半のソフトは、古い形式を使っていますが、今後は少しずつXP非対応アプリも増えてくると思うので、じわじわと新しいフォルダ選択ダイアログが増えていくでしょう。実際 Visual Studio は何気に新しいものを使ってますし。。。
が、.NET Framework はまだ対応していません。ということで、だれでも使えるように、コアルーチンだけここに張り付けておきます。
作り方は、
- C++/CLIで、クラスライブラリプロジェクトを作成する。
- 下記のコードを PickupFolderDialogCore.h と PickupFolderDialogCore.cpp で保存する。
- プロジェクトをビルドする。
以上です。WPFやWindows Forms からの呼出しは、それぞれでラッパーを書いたほうがいいでしょう。
理由はウィンドウハンドルの取り方がそれぞれで微妙に異なるからです。
説明が必要になるほど複雑なコードじゃないので解説はなし。
ということでヘッダー
using namespace System;
namespace Wankuma
{
public ref class PickupFolderDialogCore
{
public:
PickupFolderDialogCore();
property System::String^ SelectedPath{
System::String^ get();
void set( System::String^ value );
}
bool ShowDialog( System::IntPtr ownerWindow );
private:
System::String^ m_selectedPath;
};
}
続いてソース
// class PickupFolderDialogCore
#include "stdafx.h"
#define STRICT
#include <ShObjIdl.h>
#include <comdef.h>
#include <vcclr.h>
#pragma comment( lib, "user32.lib" )
#pragma comment( lib, "shell32.lib" )
_COM_SMARTPTR_TYPEDEF(IFileOpenDialog,__uuidof(IFileOpenDialog));
_COM_SMARTPTR_TYPEDEF(IShellItem,__uuidof(IShellItem));
static HWND APIENTRY GetSafeOwnerWindow( HWND hwndOwner )
{
if( hwndOwner != nullptr && !IsWindow( hwndOwner ) ){
hwndOwner = nullptr;
}
if( hwndOwner == nullptr ){
hwndOwner = GetForegroundWindow();
}
HWND hwndParent = hwndOwner;
while( hwndParent != nullptr ){
hwndOwner = hwndParent;
hwndParent = GetParent( hwndOwner );
}
if( hwndOwner != nullptr ){
hwndOwner = GetLastActivePopup( hwndOwner );
}
return hwndOwner;
}
#include "PickupFolderDialogCore.h"
Wankuma::PickupFolderDialogCore::PickupFolderDialogCore()
{
}
String^ Wankuma::PickupFolderDialogCore::SelectedPath::get()
{
return m_selectedPath;
}
void Wankuma::PickupFolderDialogCore::SelectedPath::set( String^ value )
{
m_selectedPath = value;
}
bool Wankuma::PickupFolderDialogCore::ShowDialog( IntPtr ownerWindow )
{
HWND hwndOwner = GetSafeOwnerWindow( static_cast<HWND>( ownerWindow.ToPointer() ) );
IFileOpenDialogPtr dlg( __uuidof(FileOpenDialog) );
dlg->SetOptions( FOS_PICKFOLDERS|FOS_FORCEFILESYSTEM );
if( String::IsNullOrWhiteSpace( m_selectedPath ) == false ){
cli::pin_ptr<const System::Char> folder = PtrToStringChars( SelectedPath );
IShellItemPtr item;
if( SUCCEEDED( SHCreateItemFromParsingName( folder, nullptr, IID_PPV_ARGS( &item ) ) ) ){
dlg->SetFolder( item );
}
}
HRESULT hRes = dlg->Show( hwndOwner );
if( SUCCEEDED( hRes ) ){
IShellItemPtr item;
if( SUCCEEDED( (hRes=dlg->GetResult( &item )) ) ){
wchar_t* folder = nullptr;
item->GetDisplayName( SIGDN_FILESYSPATH, &folder );
SelectedPath = gcnew System::String( folder );
CoTaskMemFree( folder );
return true;
}
}
return false;
}