Pseudo Sudo Window
プロセス起動支援ツール 須藤先生
概要
プロセス起動の支援ツールです。
管理者権限のあるアカウントでUACの警告を出さずに管理者権限でプロセスを起動するツールです。(※インストール時に一度だけ管理者権限が必要です)
TaskScheduler2.0を持たないXP以前のマシンでは通常のランチャーとして動作します。
他にも以下のような場面で、コマンドラインやショートカット等から手軽に利用できます。
- UACを回避して最大権限でプロセスを起動
- 管理者権限で動いているプロセスから通常権限のプロセスを起動
- タスクスケジューラに依存しないミリ秒単位のプロセス遅延起動
- 重いスクリプト言語を経由せずにワンライナーで複数プロセス起動
- WOW64エミュレーション中に64ビットの標準アプリを起動
- プロセスの持つウィンドウへメッセージを送信して最小化や終了などを操作
- プロセスの起動状況に応じた処理の切り替え
Windows 2000以降専用です。Unicodeによるファイル名指定に対応しています。
付属のインストーラはWindows 7〜10用です。TaskScheduler経由でのプロセス起動を利用しない場合はインストール操作は不要です。
もうちょっと説明
Windowsのウザさの象徴UAC。人類から夢と希望とやる気とキャッシュを吸い続けるWindowsの基本理念に違わず、奴等はこの先数世代に渡って我々の前に立ち塞がることでしょう。
そんなわけで、Windows 7の時代になってもなんだかんだいって「管理者として実行」が必要な場面に遭遇します。断腸の思いでソレを選択したが最後、その後に待ち構えているのはお楽しみシーン、UACのダイアログ操作です。「はい」と書かれたボタンを画像認識してスイッチを押すだけの簡単なお仕事とはいえ、サードパーティのリモート操作ツールなどで清く正しく趣味のハッキングを楽しんでいる最中に、ついうっかりこのダイアログとご対面などしちゃった日には、バストアップで絶望の意を絶叫するしかないかもしれません。悪のクラッカーの野望を挫くためならともかく、どこにでもいる善良な一市民をこんなところで足止めする機能なぞ言語道断です。
ところで、管理者として実行を行なうには、プロパティで管理者実行属性をつけておく、Manifestなどを埋め込む、といった事前設定を行なったり、マウス操作で「管理者として実行」を選ぶなどの操作が必要です。このあたりの操作をコマンドライン側から行なうツールとしてElevation PowerToys等があります。ちなみに本プログラムはこうした用途にも利用可能です。
さて、UACを突破する方法としては、標準コマンドであるrunasを利用した方法がよく知られています。
- runas /savecred /user:Administrator cmd
こんな感じで起動してやれば、最初の一回だけパスワード入力を求められますが、以後はいつでも管理者としてコマンドが実行できます。
しかしこの方法には以下のような問題があります。
- Windows 7インストール直後はAdministratorアカウントは無効になっている。追加設定を行なわないとこの方法は使えない。
- ログインユーザと異なるアカウントでの動作なので、新規作成したファイルの所有者情報やプロファイルの位置などが異なる。インストーラなどで問題が発生する可能性がある。
- カレントディレクトリが変わるのでそのあたりを意識してコマンドを実行する必要がある。
- とにかく初回にパスワード入力が必要なのが問題。パスワード入力ってのはその筋の人間にとってはUACのボタンを押してもらうよりも遥かに難易度が高い。
- 単にUACをオフにするだけ全て解決するような雰囲気がそこはかとなく漂っているが、オフにしたら負けだと思っている。
本プログラムは、上記の問題を改善し、インストール時に一回だけUACによる管理者権限をもらうだけで、その後はログオフや再起動が起きても、UACに邪魔されることなくいつでもお気楽極楽に絶対遵守の力が欲しい、そんなちっぽけな願いを少しだけ叶えるツールです。用量・用法を守って正しくお使いください。
インストール/アンインストール方法
タスクスケジューラを使わない場合は書庫内のdo.exeをコピーするだけで利用できます。レジストリは使用していません。
64ビット環境では64ビット版バイナリの利用を推奨します。書庫のx64フォルダ内にあるのでこちらを利用してください。
UACの回避を行なう場合は、タスクスケジューラへの登録が必要です。登録には管理者権限が必要です。
do.exeを任意の場所に置き、同じ場所にインストール用バッチファイル(do_install.bat)を置いて管理者権限で実行してください。
do.exeを置く場所にはパスが通っている必要はありませんが、コマンドラインから利用する場合は、64ビット/32ビット両方のプロセスからパスが通っている場所(例えばC:\Windowsとか)に置くと便利です。
インストールするとdo.exeの場所がタスクスケジューラに登録され、タスクスケジューラのルートフォルダにadmとusrの2つのタスクが登録されます。
インストール後はバッチファイルは不要となるため削除可能です。
アンインストール時は同じ場所にアンインストール用バッチファイル(do_uninstall.bat)を置いて通常権限で実行してください。
タスクスケジューラからタスクが削除されます。あとはバッチファイルおよびdo.exeを手動で削除してください。
利用例
基本的な呼び出し形式について以下に例を示します。オプション等の詳細については後述します。
- do adm cmd
- 管理者権限でコマンドプロンプトを起動する(UAC回避)
- do uac cmd
- 管理者権限でコマンドプロンプトを起動する(管理者権限がない場合はUACダイアログが出現する)
- do med cmd
- 整合性レベルMediumでコマンドプロンプトを起動する(管理者権限のプロセスから制限ユーザーと同じ権限のプロセスを生成する)
- do -d5000 notepad
- 5秒後にメモ帳を起動する
- do -s2 notepad
- 最小化状態でメモ帳を起動する
- do -k notepad
- メモ帳が起動していたら終了させる
- 終了処理はアプリケーション側に依存する(メモ帳の場合、編集中なら終了確認ダイアログが出る)
- do -t notepad
- メモ帳が起動していなければ起動し、フォーカスされていなければ最前面へ、そうでなければ最小化する
- do -x a -x b -x c d
- a b c d 4つのプロセスを同時に起動する
- do
- 何も指定がない場合はカレントディレクトリをシェルで開く
- do C:
- Cドライブをシェルで開く
- do adm regedit (作業フォルダを C:\Windows に設定)
- こんな感じで管理者権限が必要なアプリケーションをショートカットに登録してみたり
- do -b mstsc target.rdp
- 二重起動判定処理のないアプリケーションを二重起動せず最前面にする、といった用途にも
利用方法
コマンドラインやショートカットから以下のように呼び出して利用します。
- do [オプション] [実行対象]
本プログラムは、起動するとコマンドラインの先頭から順番にオプションを解釈します。
オプション以外の文字列が最初に出現した位置以降を実行対象とみなし、解釈したオプションに従ってプロセス起動やメッセージ送信などの動作を行ないます。
オプション指定文字としては / または - または -- が利用可能です。
オプションは先頭の1文字で判定されます。大文字・小文字は区別しません。
実行対象としては以下のものが指定可能です。
- 実行ファイル名 例: notepad
- 通常ファイル名・フォルダ名 例: memo.txt
- ショートカット 例: C:\Users\username\Desktop\ブラウザ.lnk
- URL 例: http://www.google.co.jp/
オプションは省略可能です。省略した場合は実行対象の常時起動の動作を行ないます。
実行対象は省略可能です。省略した場合、カレントディレクトリをシェルで開く動作を行ないます。
オプションについて(1/5) 起動方法の指定
以下のオプションのどれか1つを選択できます。
- EXE
- 現在のプロセスの権限で実行する (default)
- MED
- 現在のプロセスの権限で実行する。整合性レベルMediumで実行する
- LOW
- 現在のプロセスの権限で実行する。整合性レベルLowで実行する
- OPEN
- 強制的にシェル経由で実行する
- UAC
- シェル経由(Win32 APIの未公開設定)で実行する。整合性レベルHighで実行する
- 通常権限だった場合はUACのダイアログが出て、カレントディレクトリが強制的にシステムディレクトリとなる(エクスプローラの「管理者として実行」と同じ挙動となる)
- UACのダイアログでキャンセルした場合は何も実行せずに終了する
- ADM
- タスクスケジューラ経由で実行する。整合性レベルHighで実行する
- USR
- タスクスケジューラ経由で実行する。整合性レベルMediumで実行する
上記起動オプションのうち、adm, usrの2つはOSのタスクスケジューラを利用します。
adm, usrよりも後に記述されたオプションはタスクスケジューラを経由したプロセスで処理されます。
タスクスケジューラを利用するためには、付属のインストーラによる事前登録が必要です。
タスクスケジューラの実行に失敗した場合は何もせずに終了します。
タスクスケジューラのプロセスには、環境変数は引継がれません。(後述の-eオプションで回避)
上記オプションと同じ名前(例えばadm.exe等)のプログラムを実行したい場合は、拡張子部分も含めて記述してください。
オプションについて(2/5) カレントディレクトリやプロセスの起動オプション
動作オプションとして、カレントディレクトリの指定や環境変数の再構築、起動時のウィンドウ状態などを指定することができます。
タスクスケジューラ経由でのプロセス実行や、シェル拡張子の関連付けを用いたプロセス実行など、起動方法の種類によっては、APIの制限により動作が制限されるため記述順序に注意が必要です。
以下のオプション(-c, -a, -e, -s, -p)はタスクスケジューラには引き継がれないため、adm,usrよりも前に記述した場合は無視されます。
利用する場合はadm,usrよりも後に記述してください。
- -C <カレントディレクトリ> (Current directory)
- カレントディレクトリを指定する
- (指定しなかった場合はdo.exeが実行された際のカレントディレクトリが引継がれる)
- -A (At same directory)
- カレントディレクトリを実行ファイルのパスと同じ場所にする
- 実行対象にパス区切り文字が存在する場合、プログラム名部分を除いた部分が
- カレントディレクトリとなる。パス区切り文字がない場合は何もしない
- -cと-aを同時に指定した場合、実行対象にパス名が存在する場合は-aが優先される
- カレントディレクトリ設定機能のないランチャやコマンドプロンプトから実行する場合等に、入力文字数を横着したい時に利用する
- -E (regenerate user Environment)
- システム環境変数を再構築する
- 親の環境変数を引き継がずにシェルが使っているシステム環境変数を反映させたい場合に指定する
- タスクスケジューラを経由する場合はこのオプションを付けるとよい
- ランチャー系のプログラムで指定すると吉
- -S <数値> (Show)
- プロセス起動時のウィンドウ状態を数値で直接指定する
- オプション省略時はOSのデフォルト処理に任せる
ウィンドウ状態 | 指定する数値 |
SW_HIDE | 0 |
SW_NORMAL | 1 |
SW_SHOWMINIMIZED | 2 |
SW_MAXIMIZE | 3 |
SW_SHOWNOACTIVATE | 4 |
SW_SHOW | 5 |
SW_MINIMIZE | 6 |
SW_SHOWMINNOACTIVE | 7 |
SW_SHOWNA | 8 |
SW_RESTORE | 9 |
SW_SHOWDEFAULT | 10 |
SW_FORCEMINIMIZE | 11 |
- 値0で起動した場合はウィンドウの存在そのものが消えて操作できなくなるので注意
- 普通ならコンソール窓が表示されるスクリプトの処理を、モニタの前の人間に気づかれないようにウィンドウを隠してこっそり実行したいなんて時に(ry
- -P <数値> (Process flag)
- プロセス生成時の動作を数値で直接指定する
- オプション省略時はOSのデフォルト処理に任せる
プロセス状態 | 指定する数値 |
IDLE_PRIORITY_CLASS | 64 |
HIGH_PRIORITY_CLASS | 128 |
- 本オプションは隠し扱いなので取扱注意
- 他の値についてはMSDNとSDKのヘッダを参照
- -. <カレントディレクトリ> (set current directory)
- カレントディレクトリをプロセス起動前に変更する
- タスクスケジューラを経由した場合、本オプションが自動的に追加される
オプションについて(3/5) タスクスケジューラに依存しないオプション
タスクスケジューラ経由での呼び出しと無関係なオプションは以下の通りです。
- -D <数値> (Delay)
- 指定した時間(単位ms)が経過するまで待ってから起動する
- 値が0(デフォルト値)の場合は即時処理となる
- 一般的なウィンドウアプリケーションと同様、呼び出し元には即座に復帰する
- 独自処理のため、タスクスケジューラ未登録でも動作する
- -X <コマンドライン> (execute eXtra process)
- 追加でプロセスを起動する
- 何個記述してもよいのでマルチステートメント表記として利用可能
- コマンドラインに空白を含む場合は、ダブルクォートまたはシングルクォートで囲む
- このオプションよりも前に指定した各種オプションの内容が反映される
- 即時処理されるため-dオプションは反映されない
- -V (Verify all window handles for special process)
- ウィンドウの最前面判定処理を変更する
- すべてのウィンドウを探索し、操作対象ウィンドウとプロセスIDが一致し、アイコン化されているウィンドウが1つも存在せず、フォアグラウンドになっているものが1つでもあれば最前面と判定する
- 上記条件のため、同一名称の複数プロセスが存在する場合は-rオプションの影響を受ける
- -R (Reverse window search)
- 操作対象ウィンドウの検索順序を逆にする
- Zオーダー最奥のウィンドウが対象になる
- -F (Force terminate)
- プロセス終了が必要な場面において
- TerminateProcess APIを用いて強制的にプロセス終了処理を行なう
- タスクマネージャでの強制終了と同様の効果があるため、利用には注意すること
- 安全のため単独指定では機能せず、-kと同時に指定した時のみ有効になる
オプションについて(4/5) 動作モードの指定とプロセス起動判定
本プログラムでは単にプロセスを起動させるだけではなく、状況に応じてウィンドウの操作やプロセス削除などの他の動作を行なうことが可能です。
オプション指定と動作内容の対応は以下の通りです。
動作モード | 追加動作 | プロセス起動動作 |
0. なし | なし | 常に起動を行なう |
1. なし | -b, -l, -k, -m, -y指定時 | 起動を行なわない |
2. -o | なし | プロセスが存在しない時だけ起動を行なう |
3. -o | -b, -l, -k, -m, -y指定時 | プロセスが存在しない時だけ起動を行なう |
4. -t | なし | プロセスが存在しない時だけ起動を行なう |
5. -t | -b, -l, -k, -m, -y指定時 | プロセスが存在しない時だけ起動を行なう |
6. -t -o同時 | なし | 起動を行なわない |
7. -t -o同時 | -b, -l, -k, -m, -y指定時 | 起動を行なわない |
- -O (execute Once / anOther / nOne)
- プロセス起動の動作基準を変更する(上記一覧を参照)
- -T (Toggle window focus)
- プロセス起動の動作基準を変更する(上記一覧を参照)
- ウィンドウが最前面になかったりアイコン化されている場合は最前面にする
- 既に最前面にある場合は、デフォルト動作ではウィンドゥの最小化を行なう
- さらに本オプション指定時は、次章で説明する追加動作の判定基準が変化する
- デフォルト時(オプション指定がない場合)は(1)プロセスが存在する場合であれば追加動作を行なうが
- 本オプション指定時は(1)プロセスが存在し、かつ(2)対象のウィンドウが最前面にある時の2つの条件を満たした時だけ追加動作を行なう
- -N <プロセス名> (process Name)
- 検索対象となるプロセス名を直接指定する
- プロセス名に空白を含む場合は、ダブルクォートまたはシングルクォートで囲む
- 本オプションの指定がない場合、実行対象のファイル名部分から拡張子を取り除いたものをプロセス名とする
オプションについて(5/5) プロセス存在時の時追加動作
対象プロセスが存在する場合には、プロセス起動以外の動作を行なわせることができます。(-tオプション指定時は対象ウィンドウが最前面になっていることも条件となります)
追加動作として、以下のうちどれか1つを指定することができます。
複数指定した場合は最後に指定した動作のみが行なわれます。
- -B (Bring to top)
- ウィンドウを最前面に移動する
- SetForegroundWindow APIとBringWindowToTop APIを発行する
- -L (Lowest order)
- ウィンドウを最背面に移動する
- SetWindowPos APIを発行する
- -K (Kill process)
- プロセスを終了させる
- 通常はメインウィンドウへのWM_CLOSEメッセージの送信を行なう
- -fが同時に指定されている場合はTerminateProcess APIを用いて強制終了を行なう
- -M <メッセージ番号>[,<WPARAM値>[,<LPARAM値>]] (post window Message)
- ウィンドウメッセージを送信(Post)する
- Windowsのウィンドウメッセージ番号を数値で直接指定する
- WPARAM/LPARAM値は省略可能 (省略時は0となる)
- メッセージ番号が0x10000+nの場合はShowWindow APIを使用しnの値を設定する(-sオプション参照) (第二, 第三引数は無視される)
- メッセージ番号の例
送信したいメッセージ | メッセージ番号 |
WM_CLOSE | 16 |
WM_QUIT | 18 |
WM_SYSCOMMAND | 274 |
WM_USER | 1024 |
WM_APP | 0x8000 |
SW_HIDE | 0x10000 |
- 想定されていない値を送ると相手が突然死したりすることもあるので注意
- WM_SYSCOMMANDの例
送信したいメッセージ | WPARAM値 |
SC_SIZE | 0xF000 |
SC_MOVE | 0xF010 |
SC_MINIMIZE | 0xF020 |
SC_MAXIMIZE | 0xF030 |
SC_NEXTWINDOW | 0xF040 |
SC_PREVWINDOW | 0xF050 |
SC_CLOSE | 0xF060 |
SC_RESTORE | 0xF120 |
SC_TASKLIST | 0xF130 |
SC_SCREENSAVE | 0xF140 |
- -Y <コマンドライン> (Yet another process)
- 特定条件下で対象プロセスとは別のプロセス(削除用プロセスなど)を起動する
- コマンドラインに空白を含む場合は、ダブルクォートまたはシングルクォートで囲む
オプションについて(6/5) おまけ解説
なんだかオプション指定が複雑で何が何だかわけわからん!とお悩みの諸兄諸姉の皆様のために、ここでオプション指定の組み合わせ例を紹介します。
コマンド | プロセスfoo存在時 | プロセスがない時 |
do foo | fooを起動する | fooを起動する |
do -o foo | 何もしない | fooを起動する |
|
do -b foo | ウィンドウを最前面へ | 何もしない |
do -l foo | ウィンドウを最背面へ | 何もしない |
do -k foo | ウィンドウを閉じる | 何もしない |
do -k -f foo | プロセスを強制終了する | 何もしない |
do -m16 foo | ウィンドウを閉じる(-kと等価) | 何もしない |
do -m274,0xf020 foo | ウィンドウを最小化する | 何もしない |
do -m274,0xf120 foo | 最小化を解除する | 何もしない |
do -m1024 foo | WM_USERを送る | 何もしない |
do -y bar foo | barを起動する | 何もしない |
|
do -o -b foo | ウィンドウを最前面へ | fooを起動する |
do -o -l foo | ウィンドウを最背面へ | fooを起動する |
do -o -k foo | ウィンドウを閉じる | fooを起動する |
do -o -m1024 foo | WM_USERを送る | fooを起動する |
do -o -y bar foo | barを起動する | fooを起動する |
do -o -y bar -n foo baz | barを起動する | bazを起動する |
コマンド | ウィンドウが最前面 | ウィンドウが前面以外 | プロセスがない時 |
do -t foo | ウィンドウを最小化する | ウィンドウを最前面へ | fooを起動する |
do -t -l foo | ウィンドウを最背面へ | ウィンドウを最前面へ | fooを起動する |
do -t -k foo | ウィンドウを閉じる | ウィンドウを最前面へ | fooを起動する |
do -t -m1024 foo | WM_USERを送る | ウィンドウを最前面へ | fooを起動する |
do -t -y bar foo | barを起動する | ウィンドウを最前面へ | fooを起動する |
|
※do -t -oは使う場面がなさそうだが以下の通り |
do -t -o foo | ウィンドウを最小化する | ウィンドウを最前面へ | 何もしない |
do -t -o -l foo | ウィンドウを最背面へ | ウィンドウを最前面へ | 何もしない |
do -t -o -k foo | ウィンドウを閉じる | ウィンドウを最前面へ | 何もしない |
do -t -o -m1024 foo | WM_USERを送る | ウィンドウを最前面へ | 何もしない |
do -t -o -y bar foo | barを起動する | ウィンドウを最前面へ | 何もしない |
応用例
オプション指定を駆使することで、細かく動作を切り替えることができます。
- (例1)
- do adm -x cmd usr -x cmd exe cmd
- コマンドプロンプトを3つ起動。それぞれ管理者権限、ユーザ権限、親プロセスの権限となる
- (例2)
- do adm do -o -k osk
- do adm do -o -k Magnify
- スクリーンキーボードや拡大鏡のON/OFF
- OSの入力支援機能などの一部のプロセスは、内部では管理者権限で動いているため、一旦管理者権限でdoを動作させてそこでプロセス検索を行なわせる
- この手順を踏まずに制限モードでプロセス検索を行なった場合、プロセスと対象ウィンドウを発見することができないので注意
- なお、入力支援用のプロセスは、相性の悪いウィンドウが前面にいたりすると起動しなかったりすることがある模様
- (例3)
- do -t notepad C:\memo.txt
- do -t -n notepad C:\memo.txt
- 標準的な環境においてはどちらも同じ動作となる
- 前者はメモ帳(notepad + ファイル名)を開く/閉じる
- 後者は指定ファイル(memo.txtに関連づけられたアプリ)を開く/閉じる
- (例4)
- do adm -x 'do -k -f ZetPointII' -o -d2000 ZetPointII
- 管理者権限でZetPointIIのプロセスを強制終了させ、2秒後にプロセス終了を確認しつつ管理者権限で起動しなおす。タスクマネージャから再起動を何回も実行しなければならないような不幸な事態にショートカットを作っておけばマウス一つでらくらく操作(ry
- (例5)
- do -d1000000 killme
- do -k do
- 遅延起動の待ち状態になっている自分以外のdoプロセスを1つ終了させる
- (プロセス検索時、自分自身は対象外となる)
- (例6)
- do --kill explorer
- エクスプローラの終了 (OS終了の確認画面になる)
- do --kill --force explorer
- エクスプローラを強制終了させる (エクスプローラだけが自動的に再起動する。取扱注意)
- -fオプション指定時はアプリ側に備わっているデータ保存ダイアログなどの処理を経由せず強制終了するので、取り扱いには注意すること
技術情報
動作試験はWindows 10 Pro x64版のみで行なっています。
コマンドラインのUnicode指定に対応しています。Windows NT系専用です。
限定的ですがUACの存在を無効化するツールですので、利用には十分注意してください。
UACの突破のため、Vista以降のタスクスケジューラ2.0を利用しています。
do.exeからタスクスケジューラへ、カレントディレクトリやコマンドライン等のパラメータを渡し、新たなdo.exeのプロセスを経由して目的のプロセス起動を行なっています。
64ビット環境では64ビット版バイナリの利用を推奨します。32ビット版でもある程度の利用は可能ですが、Windowsの仕様上、32ビットプロセス側からは64ビットプロセス側のハンドルを取得できないため、プロセスの検索が行なえずトグル動作などが正常に機能しません。
またWindowsの仕様上、管理者権限で動いているプロセスは通常権限のプロセス側から検出できません。管理者権限で動作しているプロセスを検索する場合は管理者権限で実行する必要があります。
ShellExecute APIではプロセスの実行優先度や整合性レベルなどを変更することができないため、一旦ダミーのdo.exeをCreaetProcessで経由してからShellExecuteを実行するようになっています。
タスクスケジューラを経由して起動したプロセスでは、タスクスケジューラが持つ環境変数、すなわちログオン時の環境変数が使用されます。システム環境変数の更新が反映されないと何かと不便なので、-eオプションを使ってシステムの環境変数を取得できるようになってます。取得には未公開APIのRegenerateUserEnvironmentを使用しています。
プロセス名からウィンドウハンドルを検索する方法について
本プログラムでのウィンドウハンドル検索は以下の手順で行なっています。SysinternalsのProcExpの動きを(見よう見真似で)参考にしています。ProcExpと同一性能にはまだまだ至っていないと思います。
ProcExpと異なり、本プログラムでは1つのプロセスに対する複数のウィンドウを正順または逆順に選択する必要もあるため、処理は完全に同じではありません。
良い改良のアイディアがあればぜひお知らせください。
- EnumProcessesでプロセスを列挙
- EnumProcessModules/GetModuleBaseNameで名称を取得
- 拡張子部分を取り除いてコマンドラインで指定された名前と比較し、一致したプロセスIDをすべて保存
- EnumWindowsでウィンドウを列挙
- GetWindowThreadProcessIdでプロセスIDが一致することを確認
- 必須: GetParentで親を持たないウィンドウハンドルを探す
- 判定A: IsWindowVisibleのものがあれば最初(-r時は最後)に見つけたものを選択
- 判定B: 判定Aで全てのハンドルを捜しても見つからない場合に限り、IsIconicのものがあれば最初(-r時は最後)に見つけたものを選択
判定Aだけでは、タスクトレイ未対応のアプリを強制的にタスクトレイに収納するようなユーティリティに対処できないので、さらに追加判定が必要となります。
AとBを同時に判定するとOffice系アプリなどのGDI+ Window窓が反応してしまうので、最終的にAを満たさなかった時だけBの判定が有効になるように実装するのがポイントです。
SysinternalsのProcExpを持ってしてもハンドルを発見できないアプリケーションについては本プログラムでも対応しません。例えばWLM2009をVista互換モードでタスクトレイに収納している状態などです。こういうものは専用ツールで対処することにします。
なお、Office系はOffice XPのみ動作確認を行ないましたが、上記のアルゴリズムだけでは、正直まだまだといった感じです。1プロセスあたりウィンドウが1枚の時は意図した通りに動くのですが、ウィンドウを2枚以上所持しているプロセスがあるとうまくハンドルを選択してくれなかったりします。仕様です。やる気が出たらなんとかするかも。
改変履歴
2010.05.01 version 0.00
- x64用コンパイラがx86らしからぬ68kのようなコードを吐くのに感激してああっ!ダーク・メイヤーさまっ!
- そんなわけでWindows 7 x64に本格乗り換え。UACェ…
- インストール処理をバッチファイル化
- adm.jsとusr.jsをC#で実行ファイル化してオーバーヘッドを削減
2010.05.16 version 0.10
- ドキュメント作成。文章を書くのが面倒すぎて生きるのがつらい
- タスクスケジューラとの連携処理を取り込んでオーバーヘッドを削減。adm.exeとusr.exeを廃止
- 多重呼び出し時のパラメータ渡し処理を改良。URLデコード機能を廃止
- -s -xオプション実装
- 各種設定処理を-mオプションとして分離
- 自分自身のプロセスを検索対象から除外するよう改良
2010.05.19 version 0.11
- VisualStudioの出力を気合いで加工してOS制限撤廃
- ヘッダ加工ツールを作ってプログラムサイズをさらに削減
- stosbとか文字列結合などの姑息な手段でさらに削減
- Win32版、Win64版ともスタックサイズを128KBに拡大(スタック容量が溢れる場面があったため)
2010.06.05 version 0.20
- 素のNT4.0環境でも最低限の動作ができるようPSAPI.dllの読み込みタイミングを変更
- TaskScheduler経由時にシステム・ユーザ環境変数がタスクスケジューラのものを引き継がないようSHELL32.dllの未公開API RegenerateUserEnvironmentを利用してシステム/ユーザ環境変数の再構築を行なうように修正
- タスクスケジューラを経由した直後のみ、ShellExecuteを直接呼ばずに子プロセスを経由して実行優先度を通常状態に戻すよう改良
- ハンドル開放処理をOSに任せるなどの姑息な手段でサイズを削減
2010.06.22 version 0.21
- オプション指定方式を変更(過去の指定方式とだいたい同じ動作となっているが、一部互換性のない部分があるので注意)
- TaskSchedulerと通信時にBSTRの確保・開放処理を厳密に行なうように修正
- COM関連の例外呼び出しが発生しないように修正
- ウィンドウのハンドル取得処理をEnumWindows+IsWindowVisibleで検索するように変更
- リロケーションセクションの縮小実験を兼ねてx86版もASLRを有効化
- MSDN曰く while (::GetMessage(&msg, NULL, 0, 0)) ... というコードはまずいらしい。BOOLが3種類の値を返すとか罠すぎる。しかしまぁパラメータエラーとか起きようがないし、どうせ将来のWin32エミュもこれ標準で作られるだろうしコードサイズ優先したいから全力で放置
2010.06.24 version 0.21b
- ウィンドウの検索順序を逆にするオプションを追加 (Emacs/Firefox/オフィス系アプリなどの単独プロセスで複数ウィンドウを持つタイプのウィンドウを順番に切り替えるなどの用途に有効。ただし、VCLを利用しているアプリはこのオプションを指定すると正しく検出できなくなる)
- ウィンドウの検索条件にトップレベルかどうかの判定を追加
2010.10.29 version 0.22
どのみちXP SP1より古いカーネルは華麗にスルーされるだけ。Let's 自己責任。
- 複数のプロセスにまたがったウィンドウ探索処理を追加
モジュール名が同じでプロセスが異なるウィンドウが複数存在する場合、-rオプション指定で順番に切り替わるようにした。
強制終了時のプロセスID選択処理も変更。ウィンドウが見つかった場合は該当するウィンドウを持つプロセスIDを、ウィンドウが見つからない場合は最初(-rオプション時は最後)に見つけたプロセスIDを使用する。
SysinternalsのProcExpとほぼ同じ動作となるようにしたつもり。
- ウィンドウのフォアグラウンド判定処理の別バージョンを追加(-vオプション)
1枚のウィンドウに対して複数の独立したウィンドウハンドルを持つアプリケーションのごく一部で、正常にウィンドウの最前面状態をうまく判定できないものが存在する。こうしたアプリに対応するため、本オプション指定時は全ウィンドウを探索して最前面の判定を行なう。
この判定方式は1プロセスで複数のウィンドウを扱うタイプと相性が悪いため、普段は無効化してある。
VCLアプリケーションで-tオプションが動作しない場合は、-v -rを併用すると動くようになるかも。
2010.11.03 version 0.22a
-tオプション指定時に0.21系と異なる動作があったので修正
2011.03.07 version 0.23
-mオプション使用時にLPARAMとWPARAMの値も指定できるように改良
2017.05.21 version 0.24
- Windows 10 Creators Editionの出るちょっと前あたりから、Task Scheduler経由で起動したGUIアプリケーションが起動した瞬間にフォーカスを取得できないようにサイレント仕様変更が来ていろいろ不便になってしまった。おのれマイク○ソフト!整合性レベルを変えて実行するオプションを追加。
2017.05.24 version 0.25
- プロセス起動やウィンドウ制御まわりはWin95時代にC++の素人(俺)が書いたプログラムが元になってて、20年近く秘伝のタレみたいにコードを継ぎ足して使っていたんだけど、もはや空飛ぶスパゲッティーモンスター魑魅魍魎ラーメン娘ってな感じの悪魔召喚プログラム一歩手前の物体(俺)になってしまった。そこで現在の科学力を駆使して同じような能力を持った別の何か(俺)としてプログラムを作り直してみたらテキストセクションが3割縮んだ。やったぜ。
2017.05.27 version 0.25a
- -dオプションで待機中にウィンドウが見えてしまうエンバグを修正
以降は開発用のメモとなります。読む必要はありません。
コマンドライン後半部分は解析されずに次のプロセスへまるごと引き渡されます。この特性を利用することで、doプロセスの多段呼び出しが可能です。
-tオプションはコマンドラインから起動してもあまり意味はありません。適当なショートカットキー拡張ツールなどと組み合わせて使います。
シェル実行の実装は手抜きです。"open" を使っているため、.rdpなどの一部の関連付けはファイル名だけの指定では起動できません。この場合はアプリ名とファイル名の両方を指定して起動してください。
タスクスケジューラ経由で起動したプロセスは、通常のシェルから起動されたプロセスとほとんど同じ状態になるはず…だったのですが、ProcExpで見るとMemory Priorityの値が微妙に小さかったりします。どうすればいいんだ。
co (Twitter♺)