C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[10]: 起動中のフォルダの情報を列挙したい


(過去ログ 90 を表示中)

[トピック内 15 記事 (1 - 15 表示)]  << 0 >>

■53715 / inTopicNo.1)  起動中のフォルダの情報を列挙したい
  
□投稿者/ めめ (1回)-(2010/09/25(Sat) 01:18:27)

分類:[.NET 全般] 

こんにちは

C#で、現在起動しているフォルダの情報を取得したいです。

フォルダ名自体はEnumWindows関数で、列挙されるリストで挙がるのですが、
それがフォルダであることをプログラムに識別させる手立てがわかりませんでした。

GetWindowTextで、ウィンドウのキャプションの情報は取れたりするのですが、
それがフォルダであると識別して、そのフォルダが例えばC:\tempを参照しているといった所まで自分は知りたいです。


こういうことは、どうすればよいのでしょうか?
よろしくお願いします。



引用返信 編集キー/
■53718 / inTopicNo.2)  Re[1]: 起動中のフォルダの情報を列挙したい
□投稿者/ Azulean (615回)-(2010/09/25(Sat) 06:33:36)
最近、似たようなスレッドを見かけました。
参考になりますか?

フォルダが既に開かれているかどうかを調べる方法
http://dobon.net/cgi-bin/vbbbs/cbbs.cgi?mode=al2&namber=27286&rev=&no=0
引用返信 編集キー/
■53728 / inTopicNo.3)  Re[2]: 起動中のフォルダの情報を列挙したい
□投稿者/ めめ (2回)-(2010/09/25(Sat) 13:42:20)
Azulean さん返信ありがとうございます

解決できるかと思ったのですがInvokeMemberのやり方が難しく困っています。

ttp://dobon.net/vb/dotnet/programing/typeinvokemember.html
上記のサイトを参考にやってみたのですが、うまくいっていません。

Windowsプロパティで返却されるのはIShellWindows型?らしく、objectでよいのかも不明です。
配列のプロパティ的にはLocationName,FullName, LocationURL, Name, Path辺りだというのは分かったのですが、
またしても取得方法がわからない状態です。


Type type;
type = Type.GetTypeFromProgID("Shell.Application");
object shell = Activator.CreateInstance(type);

// エラーになる
object windows = type.GetType().InvokeMember("Windows", System.Reflection.BindingFlags.GetProperty, null, shell, null);


VBなどの記述
'オブジェクトの取得
Set sh = CreateObject("Shell.Application")

'コレクションオブジェクトの取得
Set wcobj = sh.Windows <ーこの部分の書き換えがよくわからない


すいませんが、分かる方いましたらよろしくお願いします。

引用返信 編集キー/
■53729 / inTopicNo.4)  Re[2]: 起動中のフォルダの情報を列挙したい
□投稿者/ ちゃっぴ (38回)-(2010/09/25(Sat) 14:06:22)
ちゃっぴ さんの Web サイト
解放処理書くのめんどくさいですが、COM 「Microsoft Internet Controls」 を使ってできます。
以下めんどくさいので、Excel VBA でちょろっと書いた code。

Dim windows As SHDocVw.ShellWindows
Dim window As SHDocVw.IWebBrowser2

Set windows = New SHDocVw.ShellWindows
For Each window In windows
If window.FullName = "C:\Windows\explorer.exe" Then
Debug.Print window.LocationURL
End If
Next

C# に変換してお使いください。
引用返信 編集キー/
■53730 / inTopicNo.5)  Re[3]: 起動中のフォルダの情報を列挙したい
□投稿者/ ちゃっぴ (39回)-(2010/09/25(Sat) 14:23:02)
ちゃっぴ さんの Web サイト
> // エラーになる
> object windows = type.GetType().InvokeMember("Windows", System.Reflection.BindingFlags.GetProperty, null, shell, null);

GetType() が余計でしょ。
引用返信 編集キー/
■53732 / inTopicNo.6)  Re[3]: 起動中のフォルダの情報を列挙したい
□投稿者/ 魔界の仮面弁士 (1834回)-(2010/09/25(Sat) 14:38:31)
No53728 (めめ さん) に返信
> 解決できるかと思ったのですがInvokeMemberのやり方が難しく困っています。
> Windowsプロパティで返却されるのはIShellWindows型?らしく、objectでよいのかも不明です。
C# なら、object の代わりに dynamic を使うのが簡単かと思います。.NET Framework 4 が必要ですけれども。


using System;
class Sample {
  static void Main() {
    dynamic shellWindows = Activator.CreateInstance(Type.GetTypeFromCLSID(
      new Guid("{9BA05972-F6A8-11CF-A442-00A0C90A8F39}")));
    foreach(dynamic obj in shellWindows) {
      Console.WriteLine("0x{0:X8} - {1}", obj.HWND, obj.FullName);
      Console.WriteLine("\t{" + obj.LocationName + "}");
      Console.WriteLine("\t{0}", obj.LocationURL);
    }
  }
}

(注意点) http://support.microsoft.com/kb/940998/ja


> // エラーになる            
> object windows = type.GetType().InvokeMember("Windows", System.Reflection.BindingFlags.GetProperty, null, shell, null);
Windows プロパティではなく、Windows メソッドですよ。
http://msdn.microsoft.com/en-us/library/bb774107.aspx

> 配列のプロパティ的にはLocationName,FullName, LocationURL, Name, Path辺りだというのは分かったのですが、
配列というか、ShellWindows コレクションですね。個々の要素は InternetExplorer オブジェクトです。
http://msdn.microsoft.com/en-us/library/bb773974.aspx

引用返信 編集キー/
■53733 / inTopicNo.7)  Re[4]: 起動中のフォルダの情報を列挙したい
□投稿者/ 魔界の仮面弁士 (1835回)-(2010/09/25(Sat) 14:51:39)
No53732 (魔界の仮面弁士) に追記
>     foreach(dynamic obj in shellWindows) {
>       Console.WriteLine("0x{0:X8} - {1}", obj.HWND, obj.FullName);
>       Console.WriteLine("\t{" + obj.LocationName + "}");
>       Console.WriteLine("\t{0}", obj.LocationURL);
>     }
上記では、Internet Explorer と Windows エクスプローラーの両方を列挙しています。

フォルダを表示している物に限定したい場合は、FullName プロパティで判定する方法と、
Document プロパティの型で判定する方法とがあります。適宜使い分けてください。

FullName で判定した場合、Win2000 + IE5.5 などの古い環境では、
 「エクスプローラー(explorer.exe)で Web ページを開いていた場合」
 「IE(iexplore.exe) でローカルフォルダを開いていた場合」
などを判定できないため、フォルダ以外も列挙されてしまうという問題があります。

一方、Document プロパティの型から判定した場合は、これらも判定できますが、
読み込み中などのタイミングでは 稀に Document プロパティの取得に
失敗することがある点に注意が必要です。


なお、最近の環境(IE7以降?)では前者の取り違いが起こらないため、実行環境を
限定できる場合には、FullName だけでも問題無いと思います。

引用返信 編集キー/
■53734 / inTopicNo.8)  Re[5]: 起動中のフォルダの情報を列挙したい
□投稿者/ ちゃっぴ (40回)-(2010/09/25(Sat) 15:06:10)
ちゃっぴ さんの Web サイト
2010/09/25(Sat) 15:15:57 編集(投稿者)
dynamic 使えない場合はこんな感じ。

using System;
using System.Reflection;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      const string ExplorerFullPath = @"%WINDIR%\explorer.exe";
      string explorerExpandedPath 
        = Environment.ExpandEnvironmentVariables(ExplorerFullPath);

      Type shellType = Type.GetTypeFromProgID("Shell.Application");
      object shell = null;  // Shell32.Shell
      try
      {
        shell = Activator.CreateInstance(shellType);
        object windows = null;  // SHDocVw.IShellWindows
        try
        {
          windows
            = shellType.InvokeMember(
                  "Windows"
                , BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public
                , null
                , shell
                , null);
          Type windowsType = windows.GetType();
          int windowCounts
            = (int)windowsType.InvokeMember(
                  "Count"
                , BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public
                , null
                , windows
                , null);
          object window = null; // SHDocVw.IWebBrowser2
          for (int i = 0; i < windowCounts; ++i)
          {
            try
            {
              window
                = windowsType.InvokeMember(
                      "Item"
                    , BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public
                    , null
                    , windows
                    , new object[] { i });
              Type windowType = window.GetType();
              string processFullPath
                = (string)windowType.InvokeMember(
                      "FullName"
                    , BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public
                    , null
                    , window
                    , null);
              if (explorerExpandedPath.Equals(
                processFullPath, StringComparison.InvariantCultureIgnoreCase))
              {
                string currentDirectory
                  = (string)windowType.InvokeMember(
                        "LocationUrl"
                      , BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public
                      , null
                      , window
                      , null);
                Console.WriteLine(Uri.UnescapeDataString(currentDirectory));
              }
            }
            finally
            {
              if (window != null) { Marshal.ReleaseComObject(window); }
            }
          }
        }
        finally
        {
          if (windows != null) { Marshal.ReleaseComObject(windows); }
        }
      }
      finally
      {
        if (shell != null) { Marshal.ReleaseComObject(shell); }
      }
    }
  }
}

型名 comments 付与。

引用返信 編集キー/
■53735 / inTopicNo.9)  Re[6]: 起動中のフォルダの情報を列挙したい
□投稿者/ めめ (3回)-(2010/09/25(Sat) 15:54:10)
返信ありがとうございます。
ちゃっぴさんの参照追加(Microsoft Internet Control)で解決できたと思います。
(若干VBAとクラス名が違う?)


あと、これもまたMarshal.ReleaseComObjectしないとダメなのですかね?

また、Re[5]のInvokeMemberのソースよりシンプルになったと思うのですが、
dynamic, InvokeMember, 自分のソース。どのソースがより良いとかあるのでしょうか? 
これももっとtryしまくるものなのか、ちょっと分からないのです。

以上、2点最後にどなたか教えていただけるとうれしいです。


以下が記述したソースです。

SHDocVw.ShellWindows windows = new SHDocVw.ShellWindows();

// 各正規表現
System.Text.RegularExpressions.Regex likeExplorer = new System.Text.RegularExpressions.Regex(@".*explorer\.exe", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Singleline);
System.Text.RegularExpressions.Regex likeLocal = new System.Text.RegularExpressions.Regex(@"file:///.*", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Singleline);
System.Text.RegularExpressions.Regex likeServer = new System.Text.RegularExpressions.Regex(@"file:.*", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Singleline);


foreach (SHDocVw.WebBrowser window in windows)
{

if (likeExplorer.IsMatch(window.FullName) == false) continue; // ガード節(explorerだけにする)

string name = window.Name; // エクスプローラー
string folderName = window.LocationName; // フォルダ名
string folderPath = window.LocationURL; // フォルダ file:///C:/...

string path = string.Empty; // 最終パス

// 接頭語(file:..)を取り除く
if (likeLocal.IsMatch(folderPath) == true) path = folderPath.Substring(@"file:///".Length); // ローカル
else if (likeServer.IsMatch(folderPath) == true) path = folderPath.Substring(@"file:".Length); // サーバー
else{
// 例外
}
}



引用返信 編集キー/
■53736 / inTopicNo.10)  Re[7]: 起動中のフォルダの情報を列挙したい
□投稿者/ ちゃっぴ (41回)-(2010/09/25(Sat) 16:05:35)
ちゃっぴ さんの Web サイト
> あと、これもまたMarshal.ReleaseComObjectしないとダメなのですかね?

Finalizer (destructor) で GC による回収時に解放されますので、それまで待つのが問題なければやらなくても良いです。

> また、Re[5]のInvokeMemberのソースよりシンプルになったと思うのですが、
> dynamic, InvokeMember, 自分のソース。どのソースがより良いとかあるのでしょうか? 

InvokeMember や dynamic は対象を参照したくない場合に利用します。
Windows 等の version up により COM interface が変わった場合には参照設定ではもう一度参照し直して build する必要がありますが、dynamic や InvokeMember を利用した方法では利用している interface members が変わらない限り rebuild する必要はありません。

あと、おいらの環境 Windows 7 では path に white space が入っていた場合に %20 に encode されていました。
そちらを考慮する必要があるかもしれません。


引用返信 編集キー/
■53737 / inTopicNo.11)  Re[8]: 起動中のフォルダの情報を列挙したい
□投稿者/ めめ (4回)-(2010/09/25(Sat) 16:29:49)
ちゃっぴさん返信ありがとうございます。

> Finalizer (destructor) で GC による回収時に解放されますので、それまで待つのが問題なければやらなくても良いです。

これは、通常のnewと同じ動作ということですか?
明示的な開放をするかしないかの差、という認識でよいでしょうか。


> あと、おいらの環境 Windows 7 では path に white space が入っていた場合に %20 に encode されていました。
> そちらを考慮する必要があるかもしれません。

フォルダ名にスペースを入れると、自分のほうでもなっていました。(自分もWindows7環境ですが)

path = path.Replace("%20", " "); // white spaceの置換
以上で解決させることにしました。


参照の問題はとても参考になりました。ここまで考慮して設計するのですね……。
自分の中でCOMは予測文字も出なくなるので、「変なもの」という認識でとまっていました。

考えを改めないとダメですね。



引用返信 編集キー/
■53738 / inTopicNo.12)  Re[9]: 起動中のフォルダの情報を列挙したい
□投稿者/ ちゃっぴ (42回)-(2010/09/25(Sat) 18:01:16)
ちゃっぴ さんの Web サイト
No53737 (めめ さん) に返信
> ちゃっぴさん返信ありがとうございます。
>
>>Finalizer (destructor) で GC による回収時に解放されますので、それまで待つのが問題なければやらなくても良いです。
>
> これは、通常のnewと同じ動作ということですか?
> 明示的な開放をするかしないかの差、という認識でよいでしょうか。

そうです。MarshalReleaseComObject は IDisposable.Dispose() みたいなもんだと思っていただければよいかと。

> 参照の問題はとても参考になりました。ここまで考慮して設計するのですね……。
> 自分の中でCOMは予測文字も出なくなるので、「変なもの」という認識でとまっていました。

逆に参照することにより、毎回 interface の member を検索する必要がなくなり実行速度は向上します。
そのあたりの trade off を考慮してどちらを利用するか選択します。
引用返信 編集キー/
■53742 / inTopicNo.13)  Re[10]: 起動中のフォルダの情報を列挙したい
□投稿者/ めめ (5回)-(2010/09/25(Sat) 19:04:01)

ちゃっぴさんご返信ありがとうございました。
フォルダの件から多岐に渡って、非常に勉強になりました。

恥ずかしい話ですが、トレードオフのような広い考え方をなかなか持てていないのが現状です。
単純なのでは、オブジェクト指向に目が行けば、そっちに関心が高まりすぎて、
実行速度やプログラムの使用メモリサイズというのは視界から消えてしまいがちです。

プログラムが完成してから、あれ15kもメモリ常用するの? みたいな自体になっていたり…。
まだまだプログラムを見る距離が上手くいかないです。


ともあれ、長々と質問に付き合って頂きありがとうございました!

解決済み
引用返信 編集キー/
■53754 / inTopicNo.14)  Re[9]: 起動中のフォルダの情報を列挙したい
□投稿者/ 魔界の仮面弁士 (1836回)-(2010/09/26(Sun) 15:04:09)
No53737 (めめ さん) に返信
> path = path.Replace("%20", " "); // white spaceの置換
> 以上で解決させることにしました。

処理しなければならない文字は、それだけではありませんよ。
(たとえば、パスに "%" や "&" が含まれる場合など)

> if (likeLocal.IsMatch(folderPath) == true) path = folderPath.Substring(@"file:///".Length); // ローカル
> else if (likeServer.IsMatch(folderPath) == true) path = folderPath.Substring(@"file:".Length); // サーバー
System.Uri.LocalPath を使った方が便利かと。

Uri location = new Uri(locationURL);
if (location.IsFile)
{
 // Console.WriteLine(location.IsUnc);
 path = location.LocalPath;
}

解決済み
引用返信 編集キー/
■53799 / inTopicNo.15)  Re[10]: 起動中のフォルダの情報を列挙したい
□投稿者/ めめ (6回)-(2010/09/27(Mon) 15:56:41)

> 処理しなければならない文字は、それだけではありませんよ。
> (たとえば、パスに "%" や "&" が含まれる場合など)

> Uri location = new Uri(locationURL);
> if (location.IsFile)
> {
>  // Console.WriteLine(location.IsUnc);
>  path = location.LocalPath;
> }


URLで対応していたのですね。修正します。
コメントありがとうございます。


解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -