EventEnabled
関数シグネチャ
// ADVAPI32.dll
#include <windows.h>
BOOLEAN EventEnabled(
REGHANDLE RegHandle,
const EVENT_DESCRIPTOR* EventDescriptor
);パラメーター
| 名前 | 型 | 方向 | 説明 |
|---|---|---|---|
| RegHandle | REGHANDLE | in | プロバイダーの登録ハンドル。このハンドルは EventRegister から取得します。 RegHandle が NULL の場合、EventEnabled は FALSE を返します。 |
| EventDescriptor | EVENT_DESCRIPTOR* | in | イベントが有効かどうかの判定に使用される情報を提供する EVENT_DESCRIPTOR です。 これには、イベントの Level (重大度) および Keyword (カテゴリ) が含まれます。 |
戻り値の型: BOOLEAN
公式ドキュメント
イベントプロバイダーが特定のイベントを生成すべきかどうかを判定します。
戻り値
プロバイダーがイベントの生成をスキップすべき場合は FALSE を返します。すなわち、指定された記述子を持つ当該プロバイダーからのイベントを記録するイベント収集セッションが存在しないと ETW が即座に判定できる場合に FALSE を返します。それ以外の場合は TRUE を返し、プロバイダーがイベントを生成すべきであることを示します。
解説(Remarks)
この API は、プロバイダーハンドルとイベント記述子に基づいて、イベントが有効かどうか (すなわち、いずれかのイベントコンシューマーセッションがそのイベントの受信を必要としているかどうか) を簡単に判定する手段を提供します。
この API は保守的なクイックテストを実行します。後続の詳細なフィルタリングではイベントを記録する必要のあるセッションが存在しないと判定されるような場合でも、この API が true を返すことがあります。
この API は、EventProviderEnabled が提供する機能と同様の機能を提供します。プロバイダーがイベントの完全な EVENT_DESCRIPTOR にアクセスできる場合は、EventEnabled を使用してください。プロバイダーがイベントの Level と Keyword のみにアクセスできる場合は、EventProviderEnabled を使用してください。
ほとんどのイベントプロバイダーは EventEnabled を直接呼び出しません。
- EventWrite API は独自の EventEnabled テストを内部に含んでおり、イベントが有効でない場合はただちに復帰します。
- ほとんどの ETW プロバイダーは、EventWrite や EventEnabled を直接呼び出すのではなく、ETW フレームワーク (マニフェストや TraceLogging など) を使用します。ETW フレームワークは一般に独自のイベント有効判定 API を提供しており、EventEnabled を呼び出す代わりにそちらを使用すべきです。
- ETW フレームワークの実装は通常、EventEnabled を呼び出すのではなく、自身のプロバイダー状態をチェックします。
-details
EventEnabled は有用な機能を提供しますが、通常は直接呼び出す必要はありません。
すべての EventWrite API は、まずイベントが有効かどうかを素早くチェックし、イベントが有効でない場合はただちに復帰します。そのため、EventEnabled の直後に EventWrite の呼び出しが続く場合は、EventEnabled を呼び出してもメリットはありません。
// EventEnabled is not useful here.
if (EventEnabled(provider, &descriptor))
{
EventWrite(provider, &descriptor, dataCount, &data);
}
EventEnabled API は、イベントが有効な場合にのみ重い処理を行うべきシナリオで有用な場合があります。
// EventEnabled may be useful to avoid calling ExpensiveDataPreparation().
if (EventEnabled(provider, &descriptor))
{
ExpensiveDataPreparation(data);
EventWrite(provider, &descriptor, dataCount, &data);
}
しかし、ほとんどのイベントプロバイダーは EventWrite を直接呼び出しません。代わりに、ほとんどのイベントプロバイダーは、EventRegister、EventWrite、EventUnregister の呼び出しをラップする ETW フレームワークを使用して実装されています。これらのイベントプロバイダーは、無効なイベントをスキップするための最適化された独自の仕組みを提供します。
Message Compiler
(MC.exe) を使用して
マニフェスト からコードを生成する場合、生成される各 EventWriteEVENT_NAME マクロには、独自の最適化されたイベント有効判定テストが含まれています。これにより、イベントが無効な場合はマクロの引数が評価されず、EventWrite も呼び出されません。
// This use of an MC-generated EventWrite macro is optimal. Note that the
// ExpensiveDataPreparation() function is not invoked unless the event is
// enabled.
EventWriteMY_EVENT(ExpensiveDataPreparation());
さらに、MC が生成するヘッダーには、より複雑なシナリオをサポートする EventEnabledEVENT_NAME マクロが含まれています。
// Efficiently avoid calling ExpensiveDataPreparation() when event is disabled.
if (EventEnabledMY_EVENT())
{
std::wstring s = ExpensiveDataPreparation();
EventWriteMY_EVENT(s.size(), s.c_str());
}
同様に、TraceLogging を使用する場合、 TraceLoggingWrite マクロには、引数の評価前に実行される最適化された有効判定テストが含まれています。より複雑なシナリオのために、TraceLogging は TraceLoggingProviderEnabled 関数を提供しています。
// This use of TraceLoggingWrite is optimal. Note that the
// ExpensiveDataPreparation() function is not invoked unless the event is
// enabled.
TraceLoggingWrite(
provider,
"EventName",
TraceLoggingLevel(TRACE_LEVEL_VERBOSE),
TraceLoggingKeyword(MyEventKeyword),
TraceLoggingValue(ExpensiveDataPreparation(), "data"));
// Efficiently avoid calling ExpensiveDataPreparation() when event is disabled.
if (TraceLoggingProviderEnabled(provider, TRACE_LEVEL_VERBOSE, MyEventKeyword))
{
std::wstring s = ExpensiveDataPreparation();
TraceLoggingWrite(
provider,
"EventName",
TraceLoggingLevel(TRACE_LEVEL_VERBOSE),
TraceLoggingKeyword(MyEventKeyword),
TraceLoggingCountedWideString(s.data(), s.size(), "data"));
}
ETW フレームワークの実装は、通常 EventEnabled や EventProviderEnabled を呼び出しません。代わりに、フレームワークの実装は プロバイダーコールバック を実装します。このコールバックは、プロバイダーの Level、MatchAnyKeyword、MatchAllKeyword の各値を記録すべきです。そのうえで、フレームワークは次のロジックを持つ独自のイベント有効判定ルーチンを提供すべきです。
return
provider.Enabled &&
event.Level <= provider.Level &&
(event.Keyword == 0 || (
(event.Keyword & provider.MatchAnyKeyword) != 0 &&
(event.Keyword & provider.MatchAllKeyword) == provider.MatchAllKeyword
));
このようなテストは、RegHandle パラメーターからプロバイダー設定を検索するオーバーヘッドを回避できるため、EventEnabled や EventProviderEnabled を呼び出すよりも効率的です。状況によっては、ETW フレームワークの実装でさらなる最適化を適用してパフォーマンスを向上させることができます。たとえば、マニフェストベースのイベント向けに MC.exe が生成するコードは、コールバック内で追加の計算を行うため、EventEnabledMY_EVENT テストはグローバル変数内の 1 ビットをテストするだけで済みます。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)
各言語での呼び出し定義
// ADVAPI32.dll
#include <windows.h>
BOOLEAN EventEnabled(
REGHANDLE RegHandle,
const EVENT_DESCRIPTOR* EventDescriptor
);[return: MarshalAs(UnmanagedType.U1)]
[DllImport("ADVAPI32.dll", ExactSpelling = true)]
static extern bool EventEnabled(
long RegHandle, // REGHANDLE
IntPtr EventDescriptor // EVENT_DESCRIPTOR*
);<DllImport("ADVAPI32.dll", ExactSpelling:=True)>
Public Shared Function EventEnabled(
RegHandle As Long, ' REGHANDLE
EventDescriptor As IntPtr ' EVENT_DESCRIPTOR*
) As <MarshalAs(UnmanagedType.U1)> Boolean
End Function' RegHandle : REGHANDLE
' EventDescriptor : EVENT_DESCRIPTOR*
Declare PtrSafe Function EventEnabled Lib "advapi32" ( _
ByVal RegHandle As LongLong, _
ByVal EventDescriptor As LongPtr) As Byte
' VBA7前提(PtrSafe)。32bit Office では LongPtr→Long。Integer=16bit / Long=32bit / LongLong=64bit。import ctypes
from ctypes import wintypes
EventEnabled = ctypes.windll.advapi32.EventEnabled
EventEnabled.restype = wintypes.BOOLEAN
EventEnabled.argtypes = [
ctypes.c_longlong, # RegHandle : REGHANDLE
ctypes.c_void_p, # EventDescriptor : EVENT_DESCRIPTOR*
]require 'fiddle'
require 'fiddle/import'
lib = Fiddle.dlopen('ADVAPI32.dll')
EventEnabled = Fiddle::Function.new(
lib['EventEnabled'],
[
Fiddle::TYPE_LONG_LONG, # RegHandle : REGHANDLE
Fiddle::TYPE_VOIDP, # EventDescriptor : EVENT_DESCRIPTOR*
],
Fiddle::TYPE_CHAR)#[link(name = "advapi32")]
extern "system" {
fn EventEnabled(
RegHandle: i64, // REGHANDLE
EventDescriptor: *const EVENT_DESCRIPTOR // EVENT_DESCRIPTOR*
) -> u8;
}
// crates: windows-sys provides ready-made bindings for this API.$sig = @"
[return: MarshalAs(UnmanagedType.U1)]
[DllImport("ADVAPI32.dll")]
public static extern bool EventEnabled(long RegHandle, IntPtr EventDescriptor);
"@
$api = Add-Type -MemberDefinition $sig -Name 'ADVAPI32_EventEnabled' -Namespace Win32 -PassThru
# $api::EventEnabled(RegHandle, EventDescriptor)#uselib "ADVAPI32.dll"
#func global EventEnabled "EventEnabled" sptr, sptr
; EventEnabled RegHandle, varptr(EventDescriptor) ; 戻り値は stat
; RegHandle : REGHANDLE -> "sptr"
; EventDescriptor : EVENT_DESCRIPTOR* -> "sptr"
; ※HSP3.7は int64 引数(64bit値渡し)に非対応です。
; ※HSP3.7は #func のため戻り値はシステム変数 stat に格納されます。#uselib "ADVAPI32.dll" #cfunc global EventEnabled "EventEnabled" int64, var ; res = EventEnabled(RegHandle, EventDescriptor) ; RegHandle : REGHANDLE -> "int64" ; EventDescriptor : EVENT_DESCRIPTOR* -> "var" ; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。 ; ※int64 引数の DLL 値渡しは x64 ランタイム(hsp3_64)のみ対応(x86 は未対応)。#uselib "ADVAPI32.dll" #cfunc global EventEnabled "EventEnabled" int64, sptr ; res = EventEnabled(RegHandle, varptr(EventDescriptor)) ; RegHandle : REGHANDLE -> "int64" ; EventDescriptor : EVENT_DESCRIPTOR* -> "sptr" ; ※出力/バッファ引数はポインタ方式(token=sptr / 呼び出しは varptr(変数))。 ; ※int64 引数の DLL 値渡しは x64 ランタイム(hsp3_64)のみ対応(x86 は未対応)。
; BOOLEAN EventEnabled(REGHANDLE RegHandle, EVENT_DESCRIPTOR* EventDescriptor) #uselib "ADVAPI32.dll" #cfunc global EventEnabled "EventEnabled" int64, var ; res = EventEnabled(RegHandle, EventDescriptor) ; RegHandle : REGHANDLE -> "int64" ; EventDescriptor : EVENT_DESCRIPTOR* -> "var" ; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。; BOOLEAN EventEnabled(REGHANDLE RegHandle, EVENT_DESCRIPTOR* EventDescriptor) #uselib "ADVAPI32.dll" #cfunc global EventEnabled "EventEnabled" int64, intptr ; res = EventEnabled(RegHandle, varptr(EventDescriptor)) ; RegHandle : REGHANDLE -> "int64" ; EventDescriptor : EVENT_DESCRIPTOR* -> "intptr" ; ※出力/バッファ引数はポインタ方式(token=intptr / 呼び出しは varptr(変数))。
import (
"golang.org/x/sys/windows"
"unsafe"
)
var (
advapi32 = windows.NewLazySystemDLL("ADVAPI32.dll")
procEventEnabled = advapi32.NewProc("EventEnabled")
)
// RegHandle (REGHANDLE), EventDescriptor (EVENT_DESCRIPTOR*)
r1, _, err := procEventEnabled.Call(
uintptr(RegHandle),
uintptr(EventDescriptor),
)
_ = err // syscall.Errno (valid when the call sets last-error)
_ = r1 // BOOLEANfunction EventEnabled(
RegHandle: Int64; // REGHANDLE
EventDescriptor: Pointer // EVENT_DESCRIPTOR*
): ByteBool; stdcall;
external 'ADVAPI32.dll' name 'EventEnabled';result := DllCall("ADVAPI32\EventEnabled"
, "Int64", RegHandle ; REGHANDLE
, "Ptr", EventDescriptor ; EVENT_DESCRIPTOR*
, "Char") ; return: BOOLEAN●EventEnabled(RegHandle, EventDescriptor) = DLL("ADVAPI32.dll", "byte EventEnabled(int64, void*)")
# 呼び出し: EventEnabled(RegHandle, EventDescriptor)
# RegHandle : REGHANDLE -> "int64"
# EventDescriptor : EVENT_DESCRIPTOR* -> "void*"
# なでしこ1は32bit・ANSI(Shift_JIS)。文字列=char*(ANSI)、ポインタ/ハンドル=void*(4byte)。const std = @import("std");
extern "advapi32" fn EventEnabled(
RegHandle: i64, // REGHANDLE
EventDescriptor: [*c]EVENT_DESCRIPTOR // EVENT_DESCRIPTOR*
) callconv(std.os.windows.WINAPI) u8;proc EventEnabled(
RegHandle: int64, # REGHANDLE
EventDescriptor: ptr EVENT_DESCRIPTOR # EVENT_DESCRIPTOR*
): uint8 {.importc: "EventEnabled", stdcall, dynlib: "ADVAPI32.dll".}pragma(lib, "advapi32");
extern(Windows)
ubyte EventEnabled(
long RegHandle, // REGHANDLE
EVENT_DESCRIPTOR* EventDescriptor // EVENT_DESCRIPTOR*
);ccall((:EventEnabled, "ADVAPI32.dll"), stdcall, UInt8,
(Int64, Ptr{EVENT_DESCRIPTOR}),
RegHandle, EventDescriptor)
# RegHandle : REGHANDLE -> Int64
# EventDescriptor : EVENT_DESCRIPTOR* -> Ptr{EVENT_DESCRIPTOR}
# stdcall は 32bit のみ意味を持つ(x64 では無視)。local ffi = require("ffi")
ffi.cdef[[
uint8_t EventEnabled(
int64_t RegHandle,
void* EventDescriptor);
]]
local advapi32 = ffi.load("advapi32")
-- advapi32.EventEnabled(RegHandle, EventDescriptor)
-- RegHandle : REGHANDLE
-- EventDescriptor : EVENT_DESCRIPTOR*
-- 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。const koffi = require('koffi');
const lib = koffi.load('ADVAPI32.dll');
const EventEnabled = lib.func('__stdcall', 'EventEnabled', 'uint8_t', ['int64_t', 'void *']);
// EventEnabled(RegHandle, EventDescriptor)
// RegHandle : REGHANDLE -> 'int64_t'
// EventDescriptor : EVENT_DESCRIPTOR* -> 'void *'
// 出力ポインタは koffi.out(...) で包む。構造体は koffi.struct で定義。const lib = Deno.dlopen("ADVAPI32.dll", {
EventEnabled: { parameters: ["i64", "pointer"], result: "u8" },
});
// lib.symbols.EventEnabled(RegHandle, EventDescriptor)
// RegHandle : REGHANDLE -> "i64"
// EventDescriptor : EVENT_DESCRIPTOR* -> "pointer"
// 文字列引数は "buffer"(NUL 終端のバイト列を Uint8Array で渡す)。
// 値渡し構造体は { struct: [ ...field types... ] } を使用。<?php
$ffi = FFI::cdef(<<<C
uint8_t EventEnabled(
int64_t RegHandle,
void* EventDescriptor);
C, "ADVAPI32.dll");
// $ffi->EventEnabled(RegHandle, EventDescriptor);
// RegHandle : REGHANDLE
// EventDescriptor : EVENT_DESCRIPTOR*
// 構造体/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 Advapi32 extends StdCallLibrary {
Advapi32 INSTANCE = Native.load("advapi32", Advapi32.class);
byte EventEnabled(
long RegHandle, // REGHANDLE
Pointer EventDescriptor // EVENT_DESCRIPTOR*
);
}@[Link("advapi32")]
lib LibADVAPI32
fun EventEnabled = EventEnabled(
RegHandle : Int64, # REGHANDLE
EventDescriptor : EVENT_DESCRIPTOR* # EVENT_DESCRIPTOR*
) : UInt8
end
# 構造体/GUID/enum は lib 内に対応する型定義が必要。
# 呼出規約: x64 は規約統一のため OK。x86(32bit)は WINAPI=stdcall だが Crystal の fun に stdcall 付与構文がなく非対応。import 'dart:ffi';
import 'package:ffi/ffi.dart';
typedef EventEnabledNative = Uint8 Function(Int64, Pointer<Void>);
typedef EventEnabledDart = int Function(int, Pointer<Void>);
final EventEnabled = DynamicLibrary.open('ADVAPI32.dll')
.lookupFunction<EventEnabledNative, EventEnabledDart>('EventEnabled');
// RegHandle : REGHANDLE -> Int64
// EventDescriptor : EVENT_DESCRIPTOR* -> Pointer<Void>
// 文字列は package:ffi の "...".toNativeUtf16()/toNativeUtf8() で変換。{$mode objfpc}{$H+}
function EventEnabled(
RegHandle: Int64; // REGHANDLE
EventDescriptor: Pointer // EVENT_DESCRIPTOR*
): ByteBool; stdcall;
external 'ADVAPI32.dll' name 'EventEnabled';import Foreign
import Foreign.C.Types
import Foreign.C.String
foreign import stdcall safe "EventEnabled"
c_EventEnabled :: Int64 -> Ptr () -> IO Word8
-- RegHandle : REGHANDLE -> Int64
-- EventDescriptor : EVENT_DESCRIPTOR* -> Ptr ()
-- 要 GHC(Windows)。stdcall は x64 では ccall として扱われる。ブロックする API は safe 呼び出し推奨。open Ctypes
open Foreign
let eventenabled =
foreign "EventEnabled"
(int64_t @-> (ptr void) @-> returning uint8_t)
(* RegHandle : REGHANDLE -> int64_t *)
(* EventDescriptor : EVENT_DESCRIPTOR* -> (ptr void) *)
(* foreign は cdecl 前提。x64 Windows では WINAPI と一致。構造体は ctypes structure を定義のこと。 *)(cffi:define-foreign-library advapi32 (t "ADVAPI32.dll"))
(cffi:use-foreign-library advapi32)
(cffi:defcfun ("EventEnabled" event-enabled :convention :stdcall) :uint8
(reg-handle :int64) ; REGHANDLE
(event-descriptor :pointer)) ; EVENT_DESCRIPTOR*
; isize/usize(INT_PTR/SIZE_T)は x64 前提で :int64/:uint64。x86 では :int32/:uint32。use Win32::API;
my $EventEnabled = Win32::API::More->new('ADVAPI32',
'BYTE EventEnabled(INT64 RegHandle, LPVOID EventDescriptor)');
# my $ret = $EventEnabled->Call($RegHandle, $EventDescriptor);
# RegHandle : REGHANDLE -> INT64
# EventDescriptor : EVENT_DESCRIPTOR* -> LPVOID
# 値渡し構造体は pack() した文字列、または Win32::API::Struct を使用。