Autoit で作成したプログラムの実行時に、管理者として実行をするとドラッグ&ドロップができなくて困ったことがありませんか?
原因は、Windows Vista/Windows Server 2008から追加されたユーザーインターフェイス特権の分離(UIPI)です。
現在実行しているユーザーより権限が上の管理者で実行すると、メッセージが阻止されてしまいます。
今回は、これを回避するコードを紹介します。
サンプルコード
If IsAdmin() Then
_ChangeWindowMessageFilterEx($Gui, $WM_DROPFILES, 1)
_ChangeWindowMessageFilterEx($Gui, $WM_COPYDATA, 1)
_ChangeWindowMessageFilterEx($Gui, $WM_COPYGLOBALDATA, 1)
EndIf
Func _ChangeWindowMessageFilterEx($hwnd, $iMsg, $iAction)
Local $aCall = DllCall("user32.dll", "bool", "ChangeWindowMessageFilterEx", _
"hwnd", $hwnd, _
"dword", $iMsg, _
"dword", $iAction, _
"ptr", 0)
If @error Or Not $aCall[0] Then Return SetError(1, 0, 0)
Return 1
EndFunc ;==>_ChangeWindowMessageFilterEx
コードの解説
If IsAdmin() Then; もしも管理者として実行したなら
_ChangeWindowMessageFilterEx($Gui, $WM_DROPFILES, 1); WM_DROPFILESのメッセージ受信を許可します。
;<WindowsConstants.au3>をインクルードする必要があります。
_ChangeWindowMessageFilterEx($Gui, $WM_COPYDATA, 1); WM_COPYDATAのメッセージ受信を許可します。
_ChangeWindowMessageFilterEx($Gui, $WM_COPYGLOBALDATA, 1); WM_COPYGLOBALDATAのメッセージ受信を許可します。
EndIf
$Gui の部分はメインウィンドウのハンドルを指定します。
ユーザー定義関数
ユーザー定義関数 「_ChangeWindowMessageFilterEx」を作成します。
関数とは、引数と呼ばれるデータを受け取り、定められた通りの処理を実行して結果を返す一連の命令群を言います。
詳しくはAutoit の基礎 – 関数をご覧ください。
Func _ChangeWindowMessageFilterEx($hwnd, $iMsg, $iAction); ユーザー定義関数はここから
Local $aCall = DllCall("user32.dll", "bool", "ChangeWindowMessageFilterEx",
"hwnd", $hwnd, _
"dword", $iMsg, _
"dword", $iAction, _
"ptr", 0); DLL内の関数を呼び出して実行します。
If @error Or Not $aCall[0] Then Return SetError(1, 0, 0); もしもエラーフラグ、または$aCall[0]がTRUEならば(@error、@extended、戻り値に)指定した値を設定します。
Return 1; 返し値「1」を返します。
EndFunc; ユーザー定義関数はここまで
注意事項
- プログラムを初めから管理者として実行する場合、コードの初めにキーワード「#RequireAdmin」を追加する必要があります。
- GUISetState() でウィンドウを表示した後にメッセージ許可のコードを記述します。
#RequireAdmin
#include <Misc.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>
If _Singleton("WRCMenu", 1) = 0 Then
MsgBox(0, "WRCMenu", "既に起動しています")
Exit
EndIf;==>ここまで
Opt("TrayIconHide", 1)
$Gui = GUICreate("WRCMenu", 430, 100, -1, -1, -1, $WS_EX_ACCEPTFILES)
$Input_1 = GUICtrlCreateInput("", 10, 5, 340, 20)
GUICtrlSetState($Input_1, $GUI_DROPACCEPTED)
$Input_2 = GUICtrlCreateInput("", 10, 35, 340, 20)
$btn = GUICtrlCreateButton("開く", 360, 5, 60, 20)
$btn2 = GUICtrlCreateButton("追加", 360, 35, 60, 20)
$btn3 = GUICtrlCreateButton("メニューリスト", 10, 65, 410, 20)
GUISetState()
If IsAdmin() Then ; 管理者として実行した場合にメッセージの受信を許可します
_ChangeWindowMessageFilterEx($Gui, $WM_DROPFILES, 1)
_ChangeWindowMessageFilterEx($Gui, $WM_COPYDATA, 1)
_ChangeWindowMessageFilterEx($Gui, $WM_COPYGLOBALDATA, 1)
EndIf
While 1
$msg = GUIGetMsg()
Select
Case $msg = $GUI_EVENT_CLOSE
Exit
Case $msg = $btn3
$Form1 = GUICreate("メニューリスト", 300, 300, -1, -1, -1, -1, $Gui)
$ListView1 = GUICtrlCreateListView("追加されているメニュー", 10, 10, 280, 250)
_GUICtrlListView_SetColumnWidth($ListView1, 0, 280)
$btn4 = GUICtrlCreateButton("削除", 10, 265, 280, 25)
GUISetState(@SW_SHOW)
While 1
$msgg = GUIGetMsg()
Select
Case $msgg = $GUI_EVENT_CLOSE
GUIDelete($Form1)
ExitLoop
EndSelect
WEnd
EndSelect
WEnd
Func _ChangeWindowMessageFilterEx($hwnd, $iMsg, $iAction)
Local $aCall = DllCall("user32.dll", "bool", "ChangeWindowMessageFilterEx", _
"hwnd", $hwnd, _
"dword", $iMsg, _
"dword", $iAction, _
"ptr", 0)
If @error Or Not $aCall[0] Then Return SetError(1, 0, 0)
Return 1
EndFunc
メッセージ許可のコードを記述した場合と、記述しない場合の違いを確認してみてください。
コメント