SetWindowsHookExA
関数シグネチャ
// USER32.dll (ANSI / -A)
#include <windows.h>
HHOOK SetWindowsHookExA(
WINDOWS_HOOK_ID idHook,
HOOKPROC lpfn,
HINSTANCE hmod, // optional
DWORD dwThreadId
);パラメーター
| 名前 | 型 | 方向 | 説明 | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| idHook | WINDOWS_HOOK_ID | in | インストールするフック プロシージャの種類。このパラメーターには、次のいずれかの値を指定できます。
| ||||||||||||||||||||||||||||||||
| lpfn | HOOKPROC | in | フック プロシージャへのポインター。dwThreadId パラメーターが 0 であるか、別のプロセスによって作成されたスレッドの識別子を指定する場合、lpfn パラメーターは DLL 内のフック プロシージャを指している必要があります。それ以外の場合、lpfn は現在のプロセスに関連付けられたコード内のフック プロシージャを指すことができます。 | ||||||||||||||||||||||||||||||||
| hmod | HINSTANCE | inoptional | lpfn パラメーターが指すフック プロシージャを含む DLL へのハンドル。dwThreadId パラメーターが現在のプロセスによって作成されたスレッドを指定し、かつフック プロシージャが現在のプロセスに関連付けられたコード内にある場合、hMod パラメーターは NULL に設定する必要があります。 | ||||||||||||||||||||||||||||||||
| dwThreadId | DWORD | in | フック プロシージャを関連付けるスレッドの識別子。デスクトップ アプリの場合、このパラメーターが 0 であれば、フック プロシージャは呼び出し元スレッドと同じデスクトップ上で実行されている既存のすべてのスレッドに関連付けられます。Windows ストア アプリについては、「解説」セクションを参照してください。 |
戻り値の型: HHOOK
公式ドキュメント
アプリケーション定義のフック プロシージャをフック チェーンにインストールします。(ANSI)
戻り値
型: HHOOK
関数が成功した場合、戻り値はフック プロシージャへのハンドルです。
関数が失敗した場合、戻り値は NULL です。拡張エラー情報を取得するには、GetLastError を呼び出します。
解説(Remarks)
SetWindowsHookEx は、DLL を別のプロセスに注入するために使用できます。32 ビット DLL を 64 ビット プロセスに注入することはできず、64 ビット DLL を 32 ビット プロセスに注入することもできません。アプリケーションが他のプロセスでフックを使用する必要がある場合、32 ビット アプリケーションが SetWindowsHookEx を呼び出して 32 ビット DLL を 32 ビット プロセスに注入し、64 ビット アプリケーションが SetWindowsHookEx を呼び出して 64 ビット DLL を 64 ビット プロセスに注入する必要があります。32 ビット DLL と 64 ビット DLL には異なる名前を付ける必要があります。
フックはアプリケーションのコンテキスト内で実行されるため、アプリケーションの「ビット数 (bitness)」に一致している必要があります。32 ビット アプリケーションが 64 ビット Windows 上でグローバル フックをインストールすると、その 32 ビット フックは各 32 ビット プロセスに注入されます (通常のセキュリティ境界が適用されます)。64 ビット プロセスでは、スレッドは引き続き「フックされている」とマークされます。ただし、32 ビット アプリケーションがフック コードを実行する必要があるため、システムはフックを行うアプリのコンテキスト、具体的には SetWindowsHookEx を呼び出したスレッド上でフックを実行します。つまり、フックを行うアプリケーションはメッセージのポンプを継続する必要があり、そうしないと 64 ビット プロセスの通常の機能をブロックする可能性があります。
64 ビット アプリケーションが 64 ビット Windows 上でグローバル フックをインストールすると、その 64 ビット フックは各 64 ビット プロセスに注入され、一方すべての 32 ビット プロセスはフックを行うアプリケーションへのコールバックを使用します。
64 ビット Windows のインストール環境のデスクトップ上のすべてのアプリケーションをフックするには、適切なプロセスから 32 ビットのグローバル フックと 64 ビットのグローバル フックをそれぞれインストールし、通常の機能のブロックを避けるために、フックを行うアプリケーションでメッセージのポンプを継続するようにしてください。既に 32 ビットのグローバル フック アプリケーションがあり、それが各アプリケーションのコンテキストで実行される必要がない場合は、64 ビット版を作成する必要はないかもしれません。
hMod パラメーターが NULL で、かつ dwThreadId パラメーターが 0 であるか、別のプロセスによって作成されたスレッドの識別子を指定する場合、エラーが発生することがあります。
次のフック プロシージャにチェーンするために CallNextHookEx function 関数を呼び出すことは任意ですが、強く推奨されます。そうしないと、フックをインストールした他のアプリケーションがフック通知を受け取れなくなり、その結果として正しく動作しなくなる可能性があります。他のアプリケーションに通知が見られないようにすることがどうしても必要な場合を除き、CallNextHookEx を呼び出すべきです。
アプリケーションは終了する前に、UnhookWindowsHookEx function 関数を呼び出して、フックに関連付けられたシステム リソースを解放する必要があります。
フックのスコープはフックの種類によって異なります。一部のフックはグローバル スコープでのみ設定できますが、他のフックは次の表に示すように特定のスレッドに対してのみ設定することもできます。
| フック | スコープ |
|---|---|
| WH_CALLWNDPROC | スレッドまたはグローバル |
| WH_CALLWNDPROCRET | スレッドまたはグローバル |
| WH_CBT | スレッドまたはグローバル |
| WH_DEBUG | スレッドまたはグローバル |
| WH_FOREGROUNDIDLE | スレッドまたはグローバル |
| WH_GETMESSAGE | スレッドまたはグローバル |
| WH_JOURNALPLAYBACK | グローバルのみ |
| WH_JOURNALRECORD | グローバルのみ |
| WH_KEYBOARD | スレッドまたはグローバル |
| WH_KEYBOARD_LL | グローバルのみ |
| WH_MOUSE | スレッドまたはグローバル |
| WH_MOUSE_LL | グローバルのみ |
| WH_MSGFILTER | スレッドまたはグローバル |
| WH_SHELL | スレッドまたはグローバル |
| WH_SYSMSGFILTER | グローバルのみ |
指定されたフックの種類について、まずスレッド フックが呼び出され、次にグローバル フックが呼び出されます。WH_MOUSE、WH_KEYBOARD、WH_JOURNAL*、WH_SHELL、および低レベル フックは、フックを処理するスレッドではなく、フックをインストールしたスレッド上で呼び出される場合があることに注意してください。これらのフックでは、フック チェーン内で 32 ビット フックが 64 ビット フックよりも前にある場合、32 ビット フックと 64 ビット フックの両方が呼び出される可能性があります。
グローバル フックは共有リソースであり、1 つをインストールすると、呼び出し元スレッドと同じデスクトップ上のすべてのアプリケーションに影響します。すべてのグローバル フック関数はライブラリ内にある必要があります。グローバル フックは、特殊な用途のアプリケーション、またはアプリケーションのデバッグ中の開発補助としての使用に限定すべきです。フックが不要になったライブラリは、そのフック プロシージャを削除すべきです。
Windows ストア アプリ開発 dwThreadId が 0 の場合、UIAccess プロセス (アクセシビリティ ツール) によってインストールされる場合を除き、Windows ストア アプリ プロセスおよび Windows ランタイム ブローカー プロセスでは、ウィンドウ フック DLL はインプロセスで読み込まれません。次のフックでは、通知はインストーラーのスレッド上で配信されます。
この動作は、フック DLL とターゲット アプリケーション プロセスとの間にアーキテクチャの不一致がある場合、たとえばフック DLL が 32 ビットでアプリケーション プロセスが 64 ビットである場合に起こることと似ています。例
例については、Installing and Releasing Hook Procedures を参照してください。
winuser.h ヘッダーは SetWindowsHookEx を、UNICODE プリプロセッサ定数の定義に基づいてこの関数の ANSI 版または Unicode 版を自動的に選択するエイリアスとして定義しています。エンコーディング ニュートラルなエイリアスの使用を、エンコーディング ニュートラルでないコードと混在させると、コンパイル エラーまたは実行時エラーを引き起こす不一致につながる可能性があります。詳細については、Conventions for Function Prototypes を参照してください。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)
各言語での呼び出し定義
// USER32.dll (ANSI / -A)
#include <windows.h>
HHOOK SetWindowsHookExA(
WINDOWS_HOOK_ID idHook,
HOOKPROC lpfn,
HINSTANCE hmod, // optional
DWORD dwThreadId
);[DllImport("USER32.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
static extern IntPtr SetWindowsHookExA(
int idHook, // WINDOWS_HOOK_ID
IntPtr lpfn, // HOOKPROC
IntPtr hmod, // HINSTANCE optional
uint dwThreadId // DWORD
);<DllImport("USER32.dll", CharSet:=CharSet.Ansi, SetLastError:=True, ExactSpelling:=True)>
Public Shared Function SetWindowsHookExA(
idHook As Integer, ' WINDOWS_HOOK_ID
lpfn As IntPtr, ' HOOKPROC
hmod As IntPtr, ' HINSTANCE optional
dwThreadId As UInteger ' DWORD
) As IntPtr
End Function' idHook : WINDOWS_HOOK_ID
' lpfn : HOOKPROC
' hmod : HINSTANCE optional
' dwThreadId : DWORD
Declare PtrSafe Function SetWindowsHookExA Lib "user32" ( _
ByVal idHook As Long, _
ByVal lpfn As LongPtr, _
ByVal hmod As LongPtr, _
ByVal dwThreadId As Long) As LongPtr
' VBA7前提(PtrSafe)。32bit Office では LongPtr→Long。Integer=16bit / Long=32bit / LongLong=64bit。import ctypes
from ctypes import wintypes
SetWindowsHookExA = ctypes.windll.user32.SetWindowsHookExA
SetWindowsHookExA.restype = ctypes.c_void_p
SetWindowsHookExA.argtypes = [
ctypes.c_int, # idHook : WINDOWS_HOOK_ID
ctypes.c_void_p, # lpfn : HOOKPROC
wintypes.HANDLE, # hmod : HINSTANCE optional
wintypes.DWORD, # dwThreadId : DWORD
]
# GetLastError: use ctypes.GetLastError() (or ctypes.WinDLL(use_last_error=True))require 'fiddle'
require 'fiddle/import'
lib = Fiddle.dlopen('USER32.dll')
SetWindowsHookExA = Fiddle::Function.new(
lib['SetWindowsHookExA'],
[
Fiddle::TYPE_INT, # idHook : WINDOWS_HOOK_ID
Fiddle::TYPE_VOIDP, # lpfn : HOOKPROC
Fiddle::TYPE_VOIDP, # hmod : HINSTANCE optional
-Fiddle::TYPE_INT, # dwThreadId : DWORD
],
Fiddle::TYPE_VOIDP)#[link(name = "user32")]
extern "system" {
fn SetWindowsHookExA(
idHook: i32, // WINDOWS_HOOK_ID
lpfn: *const core::ffi::c_void, // HOOKPROC
hmod: *mut core::ffi::c_void, // HINSTANCE optional
dwThreadId: u32 // DWORD
) -> *mut core::ffi::c_void;
}
// crates: windows-sys provides ready-made bindings for this API.$sig = @"
[DllImport("USER32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
public static extern IntPtr SetWindowsHookExA(int idHook, IntPtr lpfn, IntPtr hmod, uint dwThreadId);
"@
$api = Add-Type -MemberDefinition $sig -Name 'USER32_SetWindowsHookExA' -Namespace Win32 -PassThru
# $api::SetWindowsHookExA(idHook, lpfn, hmod, dwThreadId)#uselib "USER32.dll"
#func global SetWindowsHookExA "SetWindowsHookExA" sptr, sptr, sptr, sptr
; SetWindowsHookExA idHook, lpfn, hmod, dwThreadId ; 戻り値は stat
; idHook : WINDOWS_HOOK_ID -> "sptr"
; lpfn : HOOKPROC -> "sptr"
; hmod : HINSTANCE optional -> "sptr"
; dwThreadId : DWORD -> "sptr"
; ※HSP3.7は #func のため戻り値はシステム変数 stat に格納されます。#uselib "USER32.dll"
#cfunc global SetWindowsHookExA "SetWindowsHookExA" int, sptr, sptr, int
; res = SetWindowsHookExA(idHook, lpfn, hmod, dwThreadId)
; idHook : WINDOWS_HOOK_ID -> "int"
; lpfn : HOOKPROC -> "sptr"
; hmod : HINSTANCE optional -> "sptr"
; dwThreadId : DWORD -> "int"; HHOOK SetWindowsHookExA(WINDOWS_HOOK_ID idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId)
#uselib "USER32.dll"
#cfunc global SetWindowsHookExA "SetWindowsHookExA" int, intptr, intptr, int
; res = SetWindowsHookExA(idHook, lpfn, hmod, dwThreadId)
; idHook : WINDOWS_HOOK_ID -> "int"
; lpfn : HOOKPROC -> "intptr"
; hmod : HINSTANCE optional -> "intptr"
; dwThreadId : DWORD -> "int"import (
"golang.org/x/sys/windows"
"unsafe"
)
var (
user32 = windows.NewLazySystemDLL("USER32.dll")
procSetWindowsHookExA = user32.NewProc("SetWindowsHookExA")
)
// idHook (WINDOWS_HOOK_ID), lpfn (HOOKPROC), hmod (HINSTANCE optional), dwThreadId (DWORD)
r1, _, err := procSetWindowsHookExA.Call(
uintptr(idHook),
uintptr(lpfn),
uintptr(hmod),
uintptr(dwThreadId),
)
_ = err // syscall.Errno (valid when the call sets last-error)
_ = r1 // HHOOKfunction SetWindowsHookExA(
idHook: Integer; // WINDOWS_HOOK_ID
lpfn: Pointer; // HOOKPROC
hmod: THandle; // HINSTANCE optional
dwThreadId: DWORD // DWORD
): THandle; stdcall;
external 'USER32.dll' name 'SetWindowsHookExA';result := DllCall("USER32\SetWindowsHookExA"
, "Int", idHook ; WINDOWS_HOOK_ID
, "Ptr", lpfn ; HOOKPROC
, "Ptr", hmod ; HINSTANCE optional
, "UInt", dwThreadId ; DWORD
, "Ptr") ; return: HHOOK●SetWindowsHookExA(idHook, lpfn, hmod, dwThreadId) = DLL("USER32.dll", "void* SetWindowsHookExA(int, void*, void*, dword)")
# 呼び出し: SetWindowsHookExA(idHook, lpfn, hmod, dwThreadId)
# idHook : WINDOWS_HOOK_ID -> "int"
# lpfn : HOOKPROC -> "void*"
# hmod : HINSTANCE optional -> "void*"
# dwThreadId : DWORD -> "dword"
# なでしこ1は32bit・ANSI(Shift_JIS)。文字列=char*(ANSI)、ポインタ/ハンドル=void*(4byte)。const std = @import("std");
extern "user32" fn SetWindowsHookExA(
idHook: i32, // WINDOWS_HOOK_ID
lpfn: ?*anyopaque, // HOOKPROC
hmod: ?*anyopaque, // HINSTANCE optional
dwThreadId: u32 // DWORD
) callconv(std.os.windows.WINAPI) ?*anyopaque;proc SetWindowsHookExA(
idHook: int32, # WINDOWS_HOOK_ID
lpfn: pointer, # HOOKPROC
hmod: pointer, # HINSTANCE optional
dwThreadId: uint32 # DWORD
): pointer {.importc: "SetWindowsHookExA", stdcall, dynlib: "USER32.dll".}pragma(lib, "user32");
extern(Windows)
void* SetWindowsHookExA(
int idHook, // WINDOWS_HOOK_ID
void* lpfn, // HOOKPROC
void* hmod, // HINSTANCE optional
uint dwThreadId // DWORD
);ccall((:SetWindowsHookExA, "USER32.dll"), stdcall, Ptr{Cvoid},
(Int32, Ptr{Cvoid}, Ptr{Cvoid}, UInt32),
idHook, lpfn, hmod, dwThreadId)
# idHook : WINDOWS_HOOK_ID -> Int32
# lpfn : HOOKPROC -> Ptr{Cvoid}
# hmod : HINSTANCE optional -> Ptr{Cvoid}
# dwThreadId : DWORD -> UInt32
# stdcall は 32bit のみ意味を持つ(x64 では無視)。local ffi = require("ffi")
ffi.cdef[[
void* SetWindowsHookExA(
int32_t idHook,
void* lpfn,
void* hmod,
uint32_t dwThreadId);
]]
local user32 = ffi.load("user32")
-- user32.SetWindowsHookExA(idHook, lpfn, hmod, dwThreadId)
-- idHook : WINDOWS_HOOK_ID
-- lpfn : HOOKPROC
-- hmod : HINSTANCE optional
-- dwThreadId : DWORD
-- 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。const koffi = require('koffi');
const lib = koffi.load('USER32.dll');
const SetWindowsHookExA = lib.func('__stdcall', 'SetWindowsHookExA', 'void *', ['int32_t', 'void *', 'void *', 'uint32_t']);
// SetWindowsHookExA(idHook, lpfn, hmod, dwThreadId)
// idHook : WINDOWS_HOOK_ID -> 'int32_t'
// lpfn : HOOKPROC -> 'void *'
// hmod : HINSTANCE optional -> 'void *'
// dwThreadId : DWORD -> 'uint32_t'
// 出力ポインタは koffi.out(...) で包む。構造体は koffi.struct で定義。
// コールバック(関数ポインタ)は koffi.proto/koffi.register で型を定義して渡す(素の void* では JS 関数を渡せない)。const lib = Deno.dlopen("USER32.dll", {
SetWindowsHookExA: { parameters: ["i32", "pointer", "pointer", "u32"], result: "pointer" },
});
// lib.symbols.SetWindowsHookExA(idHook, lpfn, hmod, dwThreadId)
// idHook : WINDOWS_HOOK_ID -> "i32"
// lpfn : HOOKPROC -> "pointer"
// hmod : HINSTANCE optional -> "pointer"
// dwThreadId : DWORD -> "u32"
// 文字列は "buffer"。ANSI(-A) は new TextEncoder() で UTF-8/ANSI バイト列(末尾に \x00)を渡す。
// 値渡し構造体は { struct: [ ...field types... ] } を使用。<?php
$ffi = FFI::cdef(<<<C
void* SetWindowsHookExA(
int32_t idHook,
void* lpfn,
void* hmod,
uint32_t dwThreadId);
C, "USER32.dll");
// $ffi->SetWindowsHookExA(idHook, lpfn, hmod, dwThreadId);
// idHook : WINDOWS_HOOK_ID
// lpfn : HOOKPROC
// hmod : HINSTANCE optional
// dwThreadId : DWORD
// 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。
// WINAPI(stdcall): x64 では呼出規約が統一されるため問題なし。x86 では __stdcall 対応のラッパが必要な場合あり。import com.sun.jna.*;
import com.sun.jna.ptr.*;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
public interface User32 extends StdCallLibrary {
User32 INSTANCE = Native.load("user32", User32.class, W32APIOptions.ASCII_OPTIONS);
Pointer SetWindowsHookExA(
int idHook, // WINDOWS_HOOK_ID
Callback lpfn, // HOOKPROC
Pointer hmod, // HINSTANCE optional
int dwThreadId // DWORD
);
}@[Link("user32")]
lib LibUSER32
fun SetWindowsHookExA = SetWindowsHookExA(
idHook : Int32, # WINDOWS_HOOK_ID
lpfn : Void*, # HOOKPROC
hmod : Void*, # HINSTANCE optional
dwThreadId : UInt32 # DWORD
) : Void*
end
# 構造体/GUID/enum は lib 内に対応する型定義が必要。
# 呼出規約: x64 は規約統一のため OK。x86(32bit)は WINAPI=stdcall だが Crystal の fun に stdcall 付与構文がなく非対応。import 'dart:ffi';
import 'package:ffi/ffi.dart';
typedef SetWindowsHookExANative = Pointer<Void> Function(Int32, Pointer<Void>, Pointer<Void>, Uint32);
typedef SetWindowsHookExADart = Pointer<Void> Function(int, Pointer<Void>, Pointer<Void>, int);
final SetWindowsHookExA = DynamicLibrary.open('USER32.dll')
.lookupFunction<SetWindowsHookExANative, SetWindowsHookExADart>('SetWindowsHookExA');
// idHook : WINDOWS_HOOK_ID -> Int32
// lpfn : HOOKPROC -> Pointer<Void>
// hmod : HINSTANCE optional -> Pointer<Void>
// dwThreadId : DWORD -> Uint32
// 文字列は package:ffi の "...".toNativeUtf16()/toNativeUtf8() で変換。{$mode objfpc}{$H+}
function SetWindowsHookExA(
idHook: Integer; // WINDOWS_HOOK_ID
lpfn: Pointer; // HOOKPROC
hmod: THandle; // HINSTANCE optional
dwThreadId: DWORD // DWORD
): THandle; stdcall;
external 'USER32.dll' name 'SetWindowsHookExA';import Foreign
import Foreign.C.Types
import Foreign.C.String
foreign import stdcall safe "SetWindowsHookExA"
c_SetWindowsHookExA :: Int32 -> Ptr () -> Ptr () -> Word32 -> IO (Ptr ())
-- idHook : WINDOWS_HOOK_ID -> Int32
-- lpfn : HOOKPROC -> Ptr ()
-- hmod : HINSTANCE optional -> Ptr ()
-- dwThreadId : DWORD -> Word32
-- 要 GHC(Windows)。stdcall は x64 では ccall として扱われる。ブロックする API は safe 呼び出し推奨。open Ctypes
open Foreign
let setwindowshookexa =
foreign "SetWindowsHookExA"
(int32_t @-> (ptr void) @-> (ptr void) @-> uint32_t @-> returning (ptr void))
(* idHook : WINDOWS_HOOK_ID -> int32_t *)
(* lpfn : HOOKPROC -> (ptr void) *)
(* hmod : HINSTANCE optional -> (ptr void) *)
(* dwThreadId : DWORD -> uint32_t *)
(* foreign は cdecl 前提。x64 Windows では WINAPI と一致。構造体は ctypes structure を定義のこと。 *)(cffi:define-foreign-library user32 (t "USER32.dll"))
(cffi:use-foreign-library user32)
(cffi:defcfun ("SetWindowsHookExA" set-windows-hook-ex-a :convention :stdcall) :pointer
(id-hook :int32) ; WINDOWS_HOOK_ID
(lpfn :pointer) ; HOOKPROC
(hmod :pointer) ; HINSTANCE optional
(dw-thread-id :uint32)) ; DWORD
; isize/usize(INT_PTR/SIZE_T)は x64 前提で :int64/:uint64。x86 では :int32/:uint32。use Win32::API;
my $SetWindowsHookExA = Win32::API::More->new('USER32',
'HANDLE SetWindowsHookExA(int idHook, LPVOID lpfn, HANDLE hmod, DWORD dwThreadId)');
# my $ret = $SetWindowsHookExA->Call($idHook, $lpfn, $hmod, $dwThreadId);
# idHook : WINDOWS_HOOK_ID -> int
# lpfn : HOOKPROC -> LPVOID
# hmod : HINSTANCE optional -> HANDLE
# dwThreadId : DWORD -> DWORD
# 値渡し構造体は pack() した文字列、または Win32::API::Struct を使用。
# コールバック(関数ポインタ)は Perl sub を直接渡せません。Win32::API::Callback を使用してください。関連項目
- f SetWindowsHookExW (Unicode版) — フックチェーンにフックプロシージャをインストールする(Unicode版)。
- f SetWindowsHookA — 指定種別のフックプロシージャを設定する旧式関数(ANSI版)。