Kakeishi_Misa
@Kakeishi_Misa

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

【C#】現在アクティブなウィンドウ(エクスプローラ)の開いているフォルダのフルパスを取得したい

Q&A

解決したいこと

現在アクティブなウィンドウ(エクスプローラ)の開いているフォルダのフルパスを取得したいです。

下記のサイトを参考に現在アクティブなウィンドウの”フォルダ名”だけ取得できました。
https://teratail.com/questions/55002
デバックで変数の中身確認すると、
「process.MainModule.FileName」にフルパス情報がありましたので
取得しようとしたとき、
デバック実行と、exe実行で結果が異なりました。。

デバック実行すると問題なく、
フルパスを取得することができ、メッセージダイアログにも
フルパスが表示されます。
ただ、exe(bin\Debugフォルダ内に作成されるexe)を直接実行すると、
何も変化がありません。
(WindowsFormで作成していますが、WindowsForm画面もメッセージダイアログも何も表示されません。)

exe実行した時にもフルパスが取得できるようにするには
どのようにすれば良いでしょうか。
ご教示お願いします。

実際のコード

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    /// Win32API の extern 宣言クラス
    public static class WinAPI
    {
        [DllImport("user32.dll")]
        public static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll")]
        public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

    }
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            GetActiveWindow();
        }

        private void GetActiveWindow()
        {
            IntPtr handle = WinAPI.GetForegroundWindow();
            int id;
            WinAPI.GetWindowThreadProcessId(handle, out id);

            Process process = Process.GetProcessById(id);
            if (process.ProcessName == "explorer")
            {
                var  Title = process.ProcessName + " " + process.MainWindowTitle;
                Title = process.MainModule.FileName; //フルパス取得//この行をコメントアウトするとexe実行してもダイアログが表示されます
                MessageBox.Show(Title);
            }
            else
            {
                var tTitle = "[not explorer]" + process.ProcessName;
                tTitle = process.MainModule.FileName;//フルパス取得//この行をコメントアウトするとexe実行してもダイアログが表示されます
                MessageBox.Show(tTitle);
            } 
        }
    }
}

”フルパス取得”のコードをコメントアウトしたexeを
実行した時のダイアログ画像
”フルパス取得”のコードを復活させるとダイアログが表示されない。
(WindowsFormも表示されない。。。)
質問1.PNG

0

4Answer

Visual Studio 2022 (.NET6)の環境で上のソースコードを丸コピペして動作確認しましたが、挙動が質問内容と異なっていました。

■デバック実行時
001_debug.png
現在アクティブなウィンドウのフォルダ名でなく、Visual Studioの本体(devenv.exe)の
フルパスが取れました。

■exe実行時(コメントアウト無し)※Visual Studioは終了させています
002_exe_no_comment_out.png
現在のexe(explorer)のパスがとれているようですね・・・。

■exe実行時(コメントアウト有り)※Visual Studioは終了させています
003_exe_comment_out.png
現在アクティブなウィンドウのフォルダ名がとれました。これが期待する動作ですね。

解に至るどころかちんぷんかんぷんになってしまいました。
正直解決できるか全く自信はありませんが、開発環境(Visual Studioや.NETのverなど)の情報の詳細をいただけないでしょうか。。。

少なくとも、質問内容にある「WindowsForm画面もメッセージダイアログも何も表示されません。」という事象は発生しませんでした。

1Like

Comments

  1. @Kakeishi_Misa

    Questioner

    ご丁寧なご回答ありがとうございます。

    開発環境は
    ・Visual Studio2013
    ・.NET Framework4.5
    です


    >現在アクティブなウィンドウのフォルダ名がとれました
    →どうやら、エクスプローラのタイトルバーの値を取得しているようです。
     https://novlog.me/win/win10-explorer-titlebar-path/

     この値はレジストリで保持しているようですので、
     レジストリの変更と組み合わせでフルパスを取得しようかと思っています。
     https://automationlabo.com/wat/?p=1954

    ありがとうございます。
     

Windowsの設定とべったりな処理ということなのですね。確かなことは言えませんが、
.NET Framework4.5と.NET6では、そのあたりの振るまいが違うのかなと・・・こちらこそ勉強になりました!

1Like

現在アクティブなウィンドウのフォルダ名でなく、Visual Studioの本体(devenv.exe)の
フルパスが取れました。

Visual Studioのデバッガを起動する時点でアクティブなウィンドウはVisual Studioのはずなので、それは正しい動作なのでは…

またexeファイルを起動する場合でも「エクスプローラ上のexeファイルから起動したとき」はエクスプローラがアクティブウィンドウになっていますが、プログラムを起動する方法は他にも

  • スタートメニューから
  • デスクトップアイコンから
  • ランチャーなどのプログラムから
  • タスクスケジューラから

などいろいろな形が考えられます。
そういう意味で「アクティブウィンドウはエクスプローラである」とだけ考えていると、いろいろと想定していないことが起きてしまうかもしれません。

1Like

やりたいこととは関係ないかもしれませんが、
Windows10で、開かれているエクスプローラーのアドレスバーから
パスを取得するサンプルを書いてみました。
(環境によっては動かないかもしれませんが...)

Spy++でアドレスバーのテキストを確認
image.png

Spy++でウィンドウの関係を確認
image.png

以下がサンプルコード

開かれているエクスプローラーのアドレスバーの文字列を取得するサンプル
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpClassName, string lpWindowName);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern int GetWindowText(IntPtr hWnd, string lpString, int nMaxCount);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        static extern int GetWindowTextLength(IntPtr hwnd);

        public Form1()
        {
            InitializeComponent();

            // エクスプローラーのアドレスバーのウィンドウハンドラを取得
            var a = FindWindowEx((IntPtr)0, IntPtr.Zero, "CabinetWClass", null);
            var b = FindWindowEx(a, IntPtr.Zero, "WorkerW", null);
            var c = FindWindowEx(b, IntPtr.Zero, "ReBarWindow32", null);
            var d = FindWindowEx(c, IntPtr.Zero, "Address Band Root", null);
            var e = FindWindowEx(d, IntPtr.Zero, "msctls_progress32", null);
            var f = FindWindowEx(e, IntPtr.Zero, "Breadcrumb Parent", null);
            var g = FindWindowEx(f, IntPtr.Zero, "ToolbarWindow32", null);

            // エクスプローラーのアドレスバーのテキストを取得
            int length = GetWindowTextLength(g);
            string text = new string('\0', length + 1);
            GetWindowText(g, text, text.Length);

            // アドレスバーのテキストからパス部分を取得
            string path = text.Substring(5).Trim('\0');

            MessageBox.Show(path);
        }
    }
}

サンプルコード実行時
image.png

何かの参考になれば幸いです。

1Like

Your answer might help someone💌