camera510PC7の栞

情報系学生のTips、ポエム、活動記録

Thunderbirdを自作プログラムから最小化状態で起動させる

概要

PCのメーラーThunderbirdに乗り換えたところ、デフォルトで最小化状態のまま自動起動させるという機能が備わっていなかったため自分でプログラムを書いた。
(Thunderbirdを起動させていないと新着メールの通知が飛ばない)

まず試したこと

ここで紹介されている

スタートアップフォルダにショートカットを作る->ショートカットのプロパティ
->実行時の大きさ->最小化

を試したところ自分の環境ではうまくいかなかった(どうしても通常のウインドウサイズで起動してしまう)ため起動するためのプログラムを自作するに至った。

自作プログラム

ソースコード

今回はWindowsフォームアプリケーション(C#)として開発。

解説

dll読み込み

[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

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

[DllImport("user32.dll",CharSet=CharSet.Auto)]
static extern int ShowWindow(IntPtr hWnd, int nCmdShow);

//[DllImport("user32.dll", CharSet = CharSet.Auto)]
//static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

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

利用するWindows APIを読み込む。
下の二つはクラス名が分からない時に使うAPI(後述)である。

プログラム起動時(Form_Load)の処理

フォームの非表示

this.Hide();

今回フォーム本体は利用しないので非表示にする。

プロセス生成・起動

//プロセス生成
System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();
psi.FileName = "C:/Program Files/Mozilla Thunderbird/thunderbird.exe";
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Minimized;
//プロセススタート
System.Diagnostics.Process hProcess = System.Diagnostics.Process.Start(psi);

System.Diagnostics.ProcessStartInfo()を利用してプロセスを生成。
FileNameでexeのパスを指定。
WindowStyleはなんでもよいが、今回はMinimizedにした。
System.Diagnostics.Process.Startでプロセスを起動させる。

起動するまで待つ

//6秒待つ→タイミングがずれた時にうまくいかない→WaitForInputIdleで解決
//System.Threading.Thread.Sleep(6000);

//Thunderbirdが起動するまで待つ
hProcess.WaitForInputIdle();

ウインドウを最小化するためにはプロセスが起動するまで待つ必要がある。
n秒待つというようなコードだとタイミングがずれた時にうまくいかなくなる。
WaitForInputIdle()を使うことでプロセスが起動するまで待つことができる。

クラス名が分からない時の処理

//↓↓クラス名が分からない時の処理↓↓
//(もしくはWinspector Spyを利用してクラス名を取得)
            
//アクティブウインドウのウィンドウハンドルを取得
IntPtr hwnd = GetForegroundWindow();  

//クラス名の長さを取得
int length = GetWindowTextLength(hwnd);

//クラス名を取得
StringBuilder className = new StringBuilder(length);
int ret = GetClassName(hwnd, className, length);

//取得したクラス名をMesssageBoxで表示
MessageBox.Show(className.ToString()); 

//↑↑クラス名が分からない時の処理↑↑

ウインドウを制御するためにはウィンドウのクラス名を知る必要がある。
上記の方法もしくはWinspector Spyなどの専用のソフトウェアを使う方法の2種類がある。

上記の方法は

  1. アクティブウインドウのハンドルを取得
  2. クラス名の長さとクラス名と取得
  3. メッセージボックスで取得したクラス名を表示

という手順で取得している。

今回使用するのは「MozillaWindowClass」というクラス名。

プロセス名からウインドウタイトルを取得

//ウインドウタイトルをプロセス名から取得
//プロセス一覧からthunderbirdを検知→ウインドウタイトルを変数に格納
foreach (System.Diagnostics.Process p in
                 System.Diagnostics.Process.GetProcesses())
{
        if (p.MainWindowTitle.Length != 0)
        {
            if (p.ProcessName.Contains("thunderbird"))
            {
                window_name = p.MainWindowTitle;
            }
         }
}

ウインドウクラスだけではハンドルを取得することが出来なかったのでウインドウタイトルも指定する。
プロセス名からウインドウタイトルを取得して変数に格納している。
プロセス一覧をSystem.Diagnostics.Process.GetProcesses()を使って取得している。

ウインドウハンドルの取得

//事前に調べたクラス名(MozillaWindowClass)とウインドウタイトルからウインドウハンドルを取得
IntPtr hwnd = FindWindow("MozillaWindowClass",window_name);  

上記で調べたクラス名とウインドウタイトルからウインドウハンドルを取得。

ウインドウを制御する

//thunderbirdのウインドウを最小化する
ShowWindow(hwnd, 6);

ShowWindowの第一引数に取得したウインドウハンドル、第二引数に状態を渡す。
ShowWindowの第二引数の番号と状態の対応はこちら参照

終了処理

//ウインドウハンドルを閉じる
hProcess.Close();
//ウインドウハンドルを破棄する
hProcess.Dispose();
//本プログラムを終了させる
this.Close();

ウインドウハンドルを閉じて破棄している。
そのあとthis.Close()することでプログラムを終了している。

ハマった点

Visual Studioに付属しているSpy++が起動しない

f:id:camera510PC7:20210331220438p:plain

Visual Studioにはウインドウクラスを調べるためのSpy++というツールが付属しているが、これがユーザーアカウント制御でブロックされてしまう。(Administratorでログインしていてもダメ、管理者として実行してもダメ、多分セキュリティ対策ソフトが原因?)

f:id:camera510PC7:20210331220937j:plain

(スクリーンショットが取れかなったのでモニター直撮り)

今回はSpy++の代替としてWinspector Spyを利用した。

ウインドウクラスだけではハンドルを取得できない

FindWindowについて検索しているとクラス名だけでハンドルを取得している例が見つかるが、Thunderbirdの場合はウインドウタイトルまで指定しないとハンドルが取得できなかった。

これはMozillaWindowClassというクラス名が複数使われていることが原因だと思われる。

f:id:camera510PC7:20210401223341p:plain
↑Winspector SpyのWindow Listのスクリーンショット

ちなみに同じMozilla製であるFireFoxもMozillaWindowClassといいう名称のウインドウクラスを使用している。

アプリケーションの使い方

  1. まず、Thunderbird
    オプション->一般->システム統合
    から「最小化したThunderbirdをタスクトレイにしまう」を有効化する f:id:camera510PC7:20210401221317p:plain
  2. スタートアップフォルダに生成したexeのショートカットを置いておく。
    f:id:camera510PC7:20210401221119p:plain

こうすることでWindows起動時に最小化状態(タスクトレイ常駐)でThunderbirdを立ち上げることができる。

まとめ

今回はThunderbirdを最小化状態で起動させるプログラムを作ってみた。

Thunderbirdには最小化状態で起動させるアドオン等も存在するみたいだが、バージョンアップによってどれも使えなくなっていた。今回利用した方法も将来的にバージョンアップの影響で使えなくなる可能性があるが、その時はまた試行錯誤するしかない。

また、この方法を応用すればSlackなど他のアプリケーションにも使えるのではないかと思う。