Xojoで作ったWindowsアプリケーションを管理者権限で起動する

この記事のタイトルに惹かれて来た方は

この記事ではUACとは、という所から語りだしていて非常に鬱陶しいので
タイトルだけ見て「おっ!」と思ってやってきた方は
「XojoでUAC昇格してアプリケーションを起動する」まで読み進めてください。

XojoではWindowsアプリケーション作成への敷居が低くなった

REALbasic、REALStudio、Xojoと数年のうちに何度も名前変えてくれるものだから、ただでさえ少ないネット上の情報をかき集めるのに一苦労な今日この頃ですが、いかがお過ごしでしょうか。


さて、「REALstudio」ではIDE(プログラム開発環境)を実行しているプラットフォーム以外の
プラットフォーム向けのアプリケーションをビルドするにはProfessionalライセンスが必要でしたが
Xojoに転換したときにライセンス形態が変更になり「デスクトップアプリケーション」ビルドライセンスを購入するだけで
どのプラットフォームでIDEが動作していてもMac/Windows/Linuxすべてのプラットフォーム向けにビルドが可能になりました。


なので、普段Mac OS X向けアプリケーションばかり作っている私にも
Windows向けアプリケーションを作るきっかけができたというわけですね。
もちろん、そのぶん今までのPersonalライセンスより実質の値上げになっているのは残念でなりませんが・・・。

UAC(ユーザーアカウント制御)とは

そんなこんなで、Windows (Win32)向けのアプリケーションをXojoでせこせこと作っておりましたら
ひとつの課題が出てまいりました。
作っていたアプリケーションが、内部でshellを呼び出してUAC昇格していないと実行できないコマンドを実行するという
早い話、システムの設定を変更する便利ツールを作っていました。


Windows システムの設定を変更したり、ハードディスクの重要な場所にファイルを書き込もうとするアプリケーションは
Windows Vista以降のOSの場合は、UAC(User Access Control、ユーザーアカウント制御)という機能により
そのままアクセスしようとするとブロックされて期待通りの動作をすることができません。


そのため、Windows Vista登場以前に作られたアプリケーションは、そんなことおかまいなしに設計されていることが多く
管理者権限(Administrators)を持っているアカウントでも「アクセス拒否エラー」とかでプログラムがうまく動かないという事態が発生する場合があり*1、これを忌み嫌うユーザーは
コントロールパネルからユーザーアカウント制御の機能自体をオフにしたり


あるいは、そのようなアプリケーションを使用する際の一時的な回避策として
一般的には以下のような回避策が知られています。

  • 【起動するごとに】プログラム(EXEファイル)を起動する際、右クリックして「管理者として実行」を選択して起動する
  • 【アプリケーションのプロパティを変更】プログラム(EXEファイル)を右クリックして「プロパティ」を開き「互換性」タブの「管理者としてこのプログラムを実行する」にチェックを入れてOK。以後は普通にダブルクリックして起動する


というのが知られています。
ちなみにどちらの方法をとっても「本当に実行しますか」的なダイアログが毎回表示されるのでやや鬱陶しいですが
それを回避するにはUACオフしか手がありません。


さて
前者の方法は、起動するたびに右クリックの上「管理者として実行」を選択しないといけないので非常に億劫です。
後者の方法は、上記の問題点を回避するのにいい方法ですが、圧縮したりコピーしたりしただけで設定が解除されてしまうので、アプリケーション開発者が「俺の作ったアプリケーションは常に管理者として実行しないと不具合が生じるから予め、ただダブルクリックしただけで管理者権限で実行されるように設定する」という目的には実質使用不可能です。

マニフェストファイル

さて、アプリケーションのインストーラーでよく見かけるタイプになりますが
「アプリケーションのアイコンの右隅に盾のようなマークが表示されていて、ダブルクリックしただけでUACの昇格ダイアログが表示される」というアプリケーションがあります。

これらのアプリケーションには、当然のことながら「コピーしただけで属性解除される互換性タブの管理者として実行のチェック」は入っていませんが
なぜかダブルクリックしただけで権限昇格ダイアログが表示されます。

これはまた別の仕掛けがあってWindowsのアプリケーションには、Mac OS Xの「info.plist」に相当するようなファイル「Manifestファイル」というのが組み込まれているものがあり
ここに「このアプリケーションの想定された動作をするためには管理者権限での起動が不可欠」というプロパティを書いておけば
アプリケーションのアイコンに盾マークがついて、ただダブルクリックしただけで強制的にUAC権限昇格ダイアログが表示されるのです。

Windowsアプリケーションの開発環境として有名なVisual Studioでは
アプリケーションのビルド時に任意のマニフェストファイルを含んだ形で
アプリケーションのビルドができるそうなんですが、残念ながらXojoではそれができそうにありません。
Windows向けのビルド設定をいくら見てもそんな項目はないっぽいです。すみません、あったら教えてください。
あればその方法が一番スマートなので。

マニフェストファイル適用方法あれこれ

外部に置いたmanifestファイルを読み込む

さてこの「マニフェストファイル」ですが、アプリケーション内にマニフェストファイルが組み込まれていない場合*2
EXEファイルと同じディレクトリに「EXEファイル名.manifest」というファイルを置いておくだけで組み込みと同じ効果を得ることができるそうです。

というわけで早速XojoでMyApplication.exeというファイル名でWin32アプリをビルドして
MyApplication.exe.manifestというファイルを同じディレクトリに置いてみましたが、なんと効果がありません。

先ほども書きましたが、マニフェストファイルが組み込まれていない場合は
この方法がつかえますが、組み込まれている場合は外部のファイルは無視される仕様なんだそうです。しかもWindows Vista以降から。

Xojoでビルドしたアプリケーションにはmanifestファイルが含まれているのか?

結論から言うと、含まれていて、しかも「このアプリケーションは管理者権限を必要としない」という命令が組み込まれているという徹底ぶりでした。
しかもそのマニフェストファイルを書き換えようとするとアプリケーションが起動しなくなるという八方ふさがりぶりです。

どうやってわかったかといえば、Visual Studioをインストールするとくっついてくるmt.exeというマニフェストファイル組み込み/読み出し専用のユーティリティを使って
XojoでビルドしたWindowsアプリケーションのEXEファイルからmanifestを読み出してみました。

Microsoft Visual Studio 2010 Expressという無償版の開発環境でしたが

C:\Program Files\Microsoft SDKs\v7.0\bin\mt.exe

にしっかりとそれが入っていました。


これを使って、

cd "My Documents"
"C:\Program Files\Microsoft SDKs\v7.0\bin\mt.exe" -inputresource:"C:\Documents and Settings\User\My Documents\MyApplication.exe" -out:test.manifest

というようなコマンドを実行しましたら、見事にマイドキュメントに「test.manifest」ができあがりまして
中身をメモ帳で開きますと、















マニフェストファイルで管理者権限が必要なアプリケーションかどうか
定義するための項目が

まさにこれなんですが、これは「管理者権限は必要ないアプリですよ」宣言です。
asInvokerの部分がrequireAdministratorと書いてあると、さっき書いたような
「ダブルクリックだけでUAC昇格アプリ」ができあがるのですが。
これではだめです。


ちなみに先ほどのmt.exeを使ってマニフェストファイルを再度アプリケーションに組み込み直すことができますので
requireAdministratorに変更したものを再度

"C:\Program Files\Microsoft SDKs\v7.0\bin\mt.exe" -manifest test.manifest -outputresource:"C:\Documents and Settings\User\My Documents\MyApplication.exe"

とかいうコマンドで組み込んだところ、なんとアプリが起動しなくなりました。
しかもexeのファイルサイズが1.3MBぐらいあったのが300KB台に減ってるし
明らかにファイルをぶっ壊してしまっているのが原因と判断。
そうならないように組み込む方法もよくわからないので、このやりかたはボツになりました。

プロパティの互換性タブにある「管理者権限でこのプログラムを実行する」にバッチファイルからチェックを入れる方法を探したが見つからなかった

英語のサイトも含めてググってみましたが、みつかりませんでした。
インストールを行った後からバッチファイルとかでそこにチェックを入れることができれば同じことが実現可能だとおもったんですけど。

英語版のWindowsだとこのチェックの名前は「Run this program as an Administrator」だそうなので
これ関連で探すと、いつの日かできるぞーという情報がでてくるかも。
run as an administrator attribute batchとかのキーワードがいいかも。

XojoでUAC昇格してアプリケーションを起動する

さて本題です。
最終的にこうすることで落ち着きました。

  • Shellでwhoami /groupsというコマンドを発行すると今実行中のアプリケーションが管理者として実行されているかどうかが取得できる
  • 管理者として実行されていなければ、同じくshellからPowerShellのコマンドを呼び出して管理者権限付きで自分のEXEをキック
  • キックしたら、shellを閉じて自分はquitで落ちる
  • 上記の動作をXojoプロジェクトのApp.openイベントに組み込むことで、普通にダブルクリックしたらWindow1が立ち上がる前に即座に管理者として立ち上がりなおして、最初に立ち上がったほうのプロセスは自爆という動作ができる

どういう動作をするかはご自分の目でお確かめください。
以下はapp.openに入力するコード。

dim s as new shell
dim c as TextConverter
c=GetTextConverter(Encodings.ShiftJIS, Encodings.UTF8)
s.Execute("whoami /groups")
if instr(c.convert(s.Result), "Medium Mandatory Level")<>0 then
s.Execute("powershell start-process -verb runas "+app.ExecutableFile.NativePath)
s.Close
if not Keyboard.AsyncShiftKey then quit
else
// Windows XP or Administrator Mode => Continue
end if

whoami /groupsを実行すると最後のほうに

  • UAC昇格していない場合は「Medium Mandatory Level」という文字列が現れます。
  • UAC昇格している場合は「High Mandatory Level」という文字列が現れます。
  • Windows XPではwhoamiコマンド自体がないようです。
  • したがって、「Medium Mandatory Level」が現れた際だけ特別な処理をするように仕込んでおけばたぶん大丈夫


そして、もし「Medium Mandatory Level」が見つかった場合は即座に
powershell start-process -verb runasという指定されたEXEファイルを管理者として実行するコマンドの引数に自分のEXEパス
app.ExecutableFile.NativePathを渡して管理者として実行しなおし
自分はquit(なにかあったときのためにShiftキーを押しながらの場合はquitはしない)。


なお、PowerShellWindows 7から標準搭載と聞いていますので
Windows Vistaでは、起動した直後ただ死ぬだけという悲惨な動作になる可能性あり。
Vistaとかもう知らん。

*1: このことがWindows XPからVistaへの移行が進まなかった原因のひとつではないかと思っています

*2: そんな場合があるのかどうかはしらない