none
Windows7で検索結果と表示について質問があります。 RRS feed

  • 質問

  • いつもお世話になります。
    VisualC#2010、Windows7での動作について質問があります。
    Windows7で検索結果と表示について質問があります。
    あるフォルダ以下の画像ファイルを検索して表示しようと思っています。
    検索対象(ルート)はひんぱんに変わります。
    検索条件も変わります。
    検索結果はGUIで表示したく、その結果に対してさまざまな処理をしたいと考えています。

    さまざまな処理の大多数は、エクスプローラでできること(表示、拡大サムネイルで表示、リネーム)なので、できればエクスプローラで表示するのが簡単かと思っています。
    同時に、ほしいのがその検索結果一覧です。それはテキストでほしいと思っています。

    そこでまず、Windows7で検索条件をuri形式(?)で、Process.Startしてみました。
    search-ms:displayname=検索場所%3A%20photo&crumb=ファイルの拡張子:~<*.jpg&crumb=location:C%3A%5CUsers%5Cusername%5CDocuments%5Cphoto%5C2011-08
    をそのままコピー&ペーストしてProcess.Startしてみました。
    すると、ウィンドウは開くのですが、「検索条件に一致する項目はありません」とエクスプローラのエラーで検索できませんでした。
    とすると、この方法ではだめっぽいということです。

    次に、
    C:\Users\username\Searches
    に、
    <include path="::{ID}\{drive?}\photo\2011-08"
    のようにして、
    jpegsearch.search-msファイルを作成しました。検索条件ファイルです。
    このファイルをProcess.Startで起動すれば、エクスプローラで検索結果を表示できました。

    さてそこでつぎに、この検索結果をテキストで保存しようとしました。

    string() jpegs = Directory.GetFiles("C:\Users\username\Documents\photo\2011-08\jpegsearch.search-ms", "*.jpg");

    としましたが、当然のように、これはパスではないので、「ディレクトリ名が無効です」、とエラーになります。

    こういうときって、どのようにしたらよいでしょうね?
    つまり、GUIとテキストで複数フォルダの検索結果がほしいときです。

    string() jpegs = Directory.GetFiles("C:\Users\username\Documents\photo\2011-08", "*.jpg",SearchOption.AllDirectories);
    は当然考えたのですが、ソート順が違うみたいで、GUIの並びとテキストの並びがおなじにならないのです。

    Formに自前でサムネイルを表示して、クリックで起動可能にして、というのも考えました。
    普通に考えたらそれが最短でしょうか?

    2011年8月14日 2:39

すべての返信

  • 質問文から何を欲しているのか読み取れませんでした。

    • 検索結果をExplorerに表示したい
    • 検索結果をデータで受け取り、プログラムで処理したい(GUI内に表示するとか)

    どちらでしょうか?

    2011年8月14日 3:07
  • 質問文から何を欲しているのか読み取れませんでした。

    • 検索結果をExplorerに表示したい
    • 検索結果をデータで受け取り、プログラムで処理したい(GUI内に表示するとか)

    どちらでしょうか?

    両方なのでは?
    表示には Explorer そのものか、それと同等の表示の仕組みを使って楽したいが、Explorer で得られた結果のデータはプログラムでもほしいということなのかなと思っています。

    ただ、正直面倒くさそうな話ですね。
    Windows Search Interfaces - Querying Interfaces で検索はできるかもしれませんが、Explorer と一致する保障がありません。
    IShellFolder 方面で仮装フォルダーを列挙するというアプローチでも一致するかわかりませんし、Explorer と同じようなビューを持ってそれで取得するというのも手間がかかりそうですし…。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年8月14日 3:24
    モデレータ
  • Shellレベルの検索については、API(COM)レベルの話になりますが、
    ISearchFolderItemFactoryで要件を満たせないか、検証してみてください。

    以下にSampleがあります。
    [Shell Application Sample Code]
      http://archive.msdn.microsoft.com/shellapplication
      ※Search Folder SampleがISearchFolderItemFactoryのSampleです。

    軽く説明しますと、ISearchFolderItemFactoryを起点に、検索場所の指定や表示項目の設定を行っています。
    SampleのCreateScopeが検索場所で、GetConditionが条件のようです。

    OpenCommonFileDialogToでOpen Dialogを利用して、検索結果を表示しています。
    この関数の引数がExplorerの検索結果を示すIShellItemになっています。

    ということは、検索結果の各itemは列挙することができそうです。
    そこでOpenCommonFileDialogToの直下で以下のCodeを記述すると、itemの情報が列挙・取得できました。

    HRESULT OpenCommonFileDialogTo(IShellItem *pShellItemSearch)
    {
     {
     IEnumShellItems *items;
     HRESULT h;
     IShellItem *si; 
     ULONG cnt;
     LPWSTR str;
    		
     h = pShellItemSearch->BindToHandler(NULL,BHID_EnumItems,IID_IEnumShellItems,(void **)&items);
    
     while(items->Next(1,&si,&cnt) == S_OK){
      h = si->GetDisplayName(SIGDN_NORMALDISPLAY,&str);
      CoTaskMemFree(str);
      h = si->GetDisplayName(SIGDN_FILESYSPATH,&str);
      CoTaskMemFree(str);
     }
    
    ....
    
    

    ※このCodeはあくまでTest Codeですので、実際にTestする際はMSDNに従い正しく書いてください。

    ところでShellについてご理解されていますでしょうか?
    もし不得手でしたら、MSDNや上記Linkの他のSample、Windows API Code Pack(これはC#)を参考にしてみてください。


    補足です。
    Windows API Code Packにありますね。
    ISearchFolderItemFactoryのGUIDとWindows API Code Pack側で定義しているGUIDが一致したので、利用できますね。

    Windows API Code PackのSolutionを開いて、SearchConditionで検索してみてください。 

    [Windows API Code Pack for Microsoft .NET Framework 概要]
      http://msdn.microsoft.com/ja-jp/windows/gg213859

    • 編集済み kozz 2011年8月14日 5:32 補足
    2011年8月14日 5:15
  • 佐祐理さん、コメントありがとうございます。
    どちらかというと両方かなと。
    ・検索結果をデータでほしい。
    ・検索結果を楽して表示したい。Explorerを使えば楽そうだが、うまくいかなければ(データと一致しなければ)プログラムで処理するしかないか…。
    です。

    Azuleanさん、ありがとうございます。
    そうですね。なんかめんどうくさそうという感じで、ひょっとして先達のアドバイスをと思いました。

    kozzさん、ありがとうございます。
    さっそく(Shell Application Sample Code)をダウンロードしてみました。が…。これC++なんですね。
    読めませんでした…。

    Windows API Code Pack 1.1をダウンロードしました。
    SearchCondition.csは見つかったのですが、
    これ、どう使うものでしょうか?
    public IEnumerable<SearchCondition> GetSubConditions()
    にフォルダ名を与えることができればよいのかなと思ったのですが。

    2011年8月15日 10:25
  • Windows API Code Pack には Samples も入っています。
    Shell/SearchApplication がそれにあたりますので一度読み解いてください。
    (私自身は実践していないので、ピンポイントの回答は現時点では無理です)

    Windows Search Interfaces をラップしたようなものなので、必要であればネイティブの COM を使ったサンプルとか、API Code Pack のクラスライブラリをオブジェクトブラウザでみて探すとか、試行錯誤していただくことが早道でしょう。

    # 聞くだけでなく、自分で開拓していきましょう、英語ドキュメントにひるまずに。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年8月15日 12:17
    モデレータ
  • Querying the Index with the search-ms Protocolがsearch-msの書式説明になります。これを使えば、意図した検索条件でExplorerを開けるはずです。既に試されているようにProcess.Start()でいいはずです。

    kozzさんの紹介しているWindows API Code Packに含まれているクラスはExplorerが表示している検索結果情報にアクセスするためのもののような気がしました。どういうものかは深く調べてません。

    Explorerに表示するのではなく、検索結果をデータでほしい場合は、Windows API Code Packに含まれていないクラスを使います。"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Lib\IA64\SearchAPI.tlb"をtlbimpすればラッパークラスが作られます。

    		var query = "SELECT System.ItemName FROM SystemIndex WHERE SCOPE='file:C:/Users' AND CONTAINS(System.FileName, '*.jpg')";
    		var searchManager = new SearchAPILib.CSearchManager();
    		var searchCatalogManager = searchManager.GetCatalog("SystemIndex");
    		var queryHelper = searchCatalogManager.GetQueryHelper();
    		var connectionString = queryHelper.ConnectionString;
    		Console.WriteLine(connectionString);
    		using (var connection = new OleDbConnection(connectionString)) {
    			connection.Open();
    			using (var command = new OleDbCommand(query, connection))
    			using (var reader = command.ExecuteReader()) {
    				while (reader.Read()) {
    					var name = reader.GetString(0);
    					Console.WriteLine(name);
    				}
    			}
    		}
    
    
    *.jpgを列挙するクエリーでなんとなく書いてみました。最終的なクエリーはSystem.Data.OleDbを使えばいいのかな。Querying the Index with Windows Search SQL SyntaxがSQL文の書式説明になります。

    2011年8月15日 12:39
  • SampleのSearchAppを見てみたところ、以下の関数でbreak pointを張り、
    処理を確認すると使い方はある程度わかると思います。

    • DoSimpleSearch()  (Window1.xaml.cs)
    • DoAdvancedSearch() (AdvancedSearch.xaml.cs)

    >これC++なんですね。読めませんでした…。
    ISearchFolderItemFactoryについては、比較的新しい技術ですので情報も少なく、
    Native codeのSampleやWindows SDKの情報に頼る機会が多くなります。

    2011年8月16日 11:22