Win32 API 日本語リファレンス
ホームSystem.Threading › QueueUserAPC

QueueUserAPC

関数
指定スレッドのAPCキューにユーザーAPCを登録する。
DLLKERNEL32.dll呼出規約winapiSetLastErrorあり対応OSWindows XP 以降

シグネチャ

// KERNEL32.dll
#include <windows.h>

DWORD QueueUserAPC(
    PAPCFUNC pfnAPC,
    HANDLE hThread,
    UINT_PTR dwData
);

パラメーター

名前方向説明
pfnAPCPAPCFUNCin指定したスレッドがアラート可能な待機操作を実行したときに呼び出される、アプリケーション提供の APC 関数へのポインターです。詳細については、PAPCFUNC コールバック関数 を参照してください。
hThreadHANDLEinスレッドへのハンドルです。このハンドルには THREAD_SET_CONTEXT アクセス権が必要です。詳細については、同期オブジェクトのセキュリティとアクセス権 を参照してください。
dwDataUINT_PTRinpfnAPC パラメーターが指す APC 関数に渡される単一の値です。

戻り値の型: DWORD

公式ドキュメント

ユーザーモードの非同期プロシージャ呼び出し (APC) オブジェクトを、指定したスレッドの APC キューに追加します。(QueueUserAPC)

戻り値

関数が成功した場合、戻り値は 0 以外の値になります。

関数が失敗した場合、戻り値は 0 になります。拡張エラー情報を取得するには、GetLastError を呼び出します。Windows Server 2003 および Windows XP: この関数には、GetLastError を呼び出して取得できるエラー値は定義されていません。

解説(Remarks)

特殊なユーザーモード APC については、QueueUserAPC2 関数 を参照してください。

オペレーティングシステムが提供する APC サポートにより、アプリケーションは APC オブジェクトをスレッドにキューイングできます。APC が使用する関数を確実に実行するため、APC は呼び出し元プロセス内のスレッドにのみキューイングするべきです。

メモ

呼び出し元プロセス外のスレッドへの APC のキューイングは、いくつかの理由により推奨されません。DLL のリベースにより、呼び出し元プロセス外で関数が実行される際に、APC が使用する関数のアドレスが不正になることがあります。同様に、64 ビットプロセスが 32 ビットプロセスに APC をキューイングした場合、またはその逆の場合、アドレスが不正になりアプリケーションがクラッシュします。アドレスが判明していても、その他の要因によって関数が正常に実行されないことがあります。

各スレッドは独自の APC キューを持ちます。APC のキューイングは、スレッドに APC 関数を呼び出すよう要求するものです。オペレーティングシステムはソフトウェア割り込みを発行して、スレッドに APC 関数を呼び出すよう指示します。

ユーザーモード APC がキューイングされた場合、スレッドがアラート可能な状態でない限り、APC 関数を呼び出すように指示されることはありません。スレッドがアラート可能な状態になると、保留中のすべての APC を先入れ先出し (FIFO) 順で処理し、待機操作は WAIT_IO_COMPLETION を返します。スレッドは、SleepEx 関数SignalObjectAndWait 関数WaitForSingleObjectEx 関数WaitForMultipleObjectsEx 関数、または MsgWaitForMultipleObjectsEx 関数 を使用することで、アラート可能な状態に入ります。

アプリケーションがスレッドの実行開始前に APC をキューイングした場合、スレッドはまず APC 関数を呼び出すことから始まります。スレッドは APC 関数を呼び出した後、その APC キュー内のすべての APC に対して APC 関数を呼び出します。

APC 内でオブジェクトをスリープまたは待機することは可能です。APC 内でアラート可能な待機を実行すると、APC が再帰的にディスパッチされます。これによりスタックオーバーフローが発生する可能性があります。

ExitThread 関数 または TerminateThread 関数 を使用してスレッドが終了されると、その APC キュー内の APC は失われます。APC 関数は呼び出されません。

スレッドが終了処理中の場合、QueueUserAPC を呼び出してそのスレッドの APC キューに追加しようとすると、(31) ERROR_GEN_FAILURE で失敗します。

ReadFileEx 関数SetWaitableTimer 関数、および WriteFileEx 関数 は、完了通知のコールバックメカニズムとして APC を使用して実装されていることに注意してください。

この関数を使用するアプリケーションをコンパイルするには、_WIN32_WINNT を 0x0400 以降として定義します。詳細については、Windows ヘッダーの使用 を参照してください。

出典・ライセンス: 上記「公式ドキュメント」の内容は Microsoft の Win32 API ドキュメント(MicrosoftDocs/sdk-api)を日本語に翻訳・改変したものです。© Microsoft Corporation. CC BY 4.0 で提供。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)

各言語での呼び出し定義

// KERNEL32.dll
#include <windows.h>

DWORD QueueUserAPC(
    PAPCFUNC pfnAPC,
    HANDLE hThread,
    UINT_PTR dwData
);
[DllImport("KERNEL32.dll", SetLastError = true, ExactSpelling = true)]
static extern uint QueueUserAPC(
    IntPtr pfnAPC,   // PAPCFUNC
    IntPtr hThread,   // HANDLE
    UIntPtr dwData   // UINT_PTR
);
<DllImport("KERNEL32.dll", SetLastError:=True, ExactSpelling:=True)>
Public Shared Function QueueUserAPC(
    pfnAPC As IntPtr,   ' PAPCFUNC
    hThread As IntPtr,   ' HANDLE
    dwData As UIntPtr   ' UINT_PTR
) As UInteger
End Function
' pfnAPC : PAPCFUNC
' hThread : HANDLE
' dwData : UINT_PTR
Declare PtrSafe Function QueueUserAPC Lib "kernel32" ( _
    ByVal pfnAPC As LongPtr, _
    ByVal hThread As LongPtr, _
    ByVal dwData As LongPtr) As Long
' VBA7前提(PtrSafe)。32bit Office では LongPtr→Long。Integer=16bit / Long=32bit / LongLong=64bit。
import ctypes
from ctypes import wintypes

QueueUserAPC = ctypes.windll.kernel32.QueueUserAPC
QueueUserAPC.restype = wintypes.DWORD
QueueUserAPC.argtypes = [
    ctypes.c_void_p,  # pfnAPC : PAPCFUNC
    wintypes.HANDLE,  # hThread : HANDLE
    ctypes.c_size_t,  # dwData : UINT_PTR
]
# GetLastError: use ctypes.GetLastError() (or ctypes.WinDLL(use_last_error=True))
require 'fiddle'
require 'fiddle/import'

lib = Fiddle.dlopen('KERNEL32.dll')
QueueUserAPC = Fiddle::Function.new(
  lib['QueueUserAPC'],
  [
    Fiddle::TYPE_VOIDP,  # pfnAPC : PAPCFUNC
    Fiddle::TYPE_VOIDP,  # hThread : HANDLE
    Fiddle::TYPE_UINTPTR_T,  # dwData : UINT_PTR
  ],
  -Fiddle::TYPE_INT)
#[link(name = "kernel32")]
extern "system" {
    fn QueueUserAPC(
        pfnAPC: *const core::ffi::c_void,  // PAPCFUNC
        hThread: *mut core::ffi::c_void,  // HANDLE
        dwData: usize  // UINT_PTR
    ) -> u32;
}
// crates: windows-sys provides ready-made bindings for this API.
$sig = @"
[DllImport("KERNEL32.dll", SetLastError = true)]
public static extern uint QueueUserAPC(IntPtr pfnAPC, IntPtr hThread, UIntPtr dwData);
"@
$api = Add-Type -MemberDefinition $sig -Name 'KERNEL32_QueueUserAPC' -Namespace Win32 -PassThru
# $api::QueueUserAPC(pfnAPC, hThread, dwData)
#uselib "KERNEL32.dll"
#func global QueueUserAPC "QueueUserAPC" sptr, sptr, sptr
; QueueUserAPC pfnAPC, hThread, dwData   ; 戻り値は stat
; pfnAPC : PAPCFUNC -> "sptr"
; hThread : HANDLE -> "sptr"
; dwData : UINT_PTR -> "sptr"
; ※HSP3.7は #func のため戻り値はシステム変数 stat に格納されます。
#uselib "KERNEL32.dll"
#cfunc global QueueUserAPC "QueueUserAPC" sptr, sptr, sptr
; res = QueueUserAPC(pfnAPC, hThread, dwData)
; pfnAPC : PAPCFUNC -> "sptr"
; hThread : HANDLE -> "sptr"
; dwData : UINT_PTR -> "sptr"
; DWORD QueueUserAPC(PAPCFUNC pfnAPC, HANDLE hThread, UINT_PTR dwData)
#uselib "KERNEL32.dll"
#cfunc global QueueUserAPC "QueueUserAPC" intptr, intptr, intptr
; res = QueueUserAPC(pfnAPC, hThread, dwData)
; pfnAPC : PAPCFUNC -> "intptr"
; hThread : HANDLE -> "intptr"
; dwData : UINT_PTR -> "intptr"
import (
	"golang.org/x/sys/windows"
	"unsafe"
)

var (
	kernel32 = windows.NewLazySystemDLL("KERNEL32.dll")
	procQueueUserAPC = kernel32.NewProc("QueueUserAPC")
)

// pfnAPC (PAPCFUNC), hThread (HANDLE), dwData (UINT_PTR)
r1, _, err := procQueueUserAPC.Call(
	uintptr(pfnAPC),
	uintptr(hThread),
	uintptr(dwData),
)
_ = err  // syscall.Errno (valid when the call sets last-error)
_ = r1   // DWORD
function QueueUserAPC(
  pfnAPC: Pointer;   // PAPCFUNC
  hThread: THandle;   // HANDLE
  dwData: NativeUInt   // UINT_PTR
): DWORD; stdcall;
  external 'KERNEL32.dll' name 'QueueUserAPC';
result := DllCall("KERNEL32\QueueUserAPC"
    , "Ptr", pfnAPC   ; PAPCFUNC
    , "Ptr", hThread   ; HANDLE
    , "UPtr", dwData   ; UINT_PTR
    , "UInt")   ; return: DWORD
●QueueUserAPC(pfnAPC, hThread, dwData) = DLL("KERNEL32.dll", "dword QueueUserAPC(void*, void*, int)")
# 呼び出し: QueueUserAPC(pfnAPC, hThread, dwData)
# pfnAPC : PAPCFUNC -> "void*"
# hThread : HANDLE -> "void*"
# dwData : UINT_PTR -> "int"
# なでしこ1は32bit・ANSI(Shift_JIS)。文字列=char*(ANSI)、ポインタ/ハンドル=void*(4byte)。
const std = @import("std");

extern "kernel32" fn QueueUserAPC(
    pfnAPC: ?*anyopaque, // PAPCFUNC
    hThread: ?*anyopaque, // HANDLE
    dwData: usize // UINT_PTR
) callconv(std.os.windows.WINAPI) u32;
proc QueueUserAPC(
    pfnAPC: pointer,  # PAPCFUNC
    hThread: pointer,  # HANDLE
    dwData: uint  # UINT_PTR
): uint32 {.importc: "QueueUserAPC", stdcall, dynlib: "KERNEL32.dll".}
pragma(lib, "kernel32");
extern(Windows)
uint QueueUserAPC(
    void* pfnAPC,   // PAPCFUNC
    void* hThread,   // HANDLE
    size_t dwData   // UINT_PTR
);
ccall((:QueueUserAPC, "KERNEL32.dll"), stdcall, UInt32,
      (Ptr{Cvoid}, Ptr{Cvoid}, Csize_t),
      pfnAPC, hThread, dwData)
# pfnAPC : PAPCFUNC -> Ptr{Cvoid}
# hThread : HANDLE -> Ptr{Cvoid}
# dwData : UINT_PTR -> Csize_t
# stdcall は 32bit のみ意味を持つ(x64 では無視)。
local ffi = require("ffi")
ffi.cdef[[
uint32_t QueueUserAPC(
    void* pfnAPC,
    void* hThread,
    uintptr_t dwData);
]]
local kernel32 = ffi.load("kernel32")
-- kernel32.QueueUserAPC(pfnAPC, hThread, dwData)
-- pfnAPC : PAPCFUNC
-- hThread : HANDLE
-- dwData : UINT_PTR
-- 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。
const koffi = require('koffi');
const lib = koffi.load('KERNEL32.dll');
const QueueUserAPC = lib.func('__stdcall', 'QueueUserAPC', 'uint32_t', ['void *', 'void *', 'uintptr_t']);
// QueueUserAPC(pfnAPC, hThread, dwData)
// pfnAPC : PAPCFUNC -> 'void *'
// hThread : HANDLE -> 'void *'
// dwData : UINT_PTR -> 'uintptr_t'
// 出力ポインタは koffi.out(...) で包む。構造体は koffi.struct で定義。
// コールバック(関数ポインタ)は koffi.proto/koffi.register で型を定義して渡す(素の void* では JS 関数を渡せない)。
const lib = Deno.dlopen("KERNEL32.dll", {
  QueueUserAPC: { parameters: ["pointer", "pointer", "usize"], result: "u32" },
});
// lib.symbols.QueueUserAPC(pfnAPC, hThread, dwData)
// pfnAPC : PAPCFUNC -> "pointer"
// hThread : HANDLE -> "pointer"
// dwData : UINT_PTR -> "usize"
// 文字列引数は "buffer"(NUL 終端のバイト列を Uint8Array で渡す)。
// 値渡し構造体は { struct: [ ...field types... ] } を使用。
<?php
$ffi = FFI::cdef(<<<C
uint32_t QueueUserAPC(
    void* pfnAPC,
    void* hThread,
    size_t dwData);
C, "KERNEL32.dll");
// $ffi->QueueUserAPC(pfnAPC, hThread, dwData);
// pfnAPC : PAPCFUNC
// hThread : HANDLE
// dwData : UINT_PTR
// 構造体/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 Kernel32 extends StdCallLibrary {
    Kernel32 INSTANCE = Native.load("kernel32", Kernel32.class);
    int QueueUserAPC(
        Callback pfnAPC,   // PAPCFUNC
        Pointer hThread,   // HANDLE
        long dwData   // UINT_PTR
    );
}
@[Link("kernel32")]
lib LibKERNEL32
  fun QueueUserAPC = QueueUserAPC(
    pfnAPC : Void*,   # PAPCFUNC
    hThread : Void*,   # HANDLE
    dwData : LibC::SizeT   # UINT_PTR
  ) : UInt32
end
# 構造体/GUID/enum は lib 内に対応する型定義が必要。
# 呼出規約: x64 は規約統一のため OK。x86(32bit)は WINAPI=stdcall だが Crystal の fun に stdcall 付与構文がなく非対応。
import 'dart:ffi';
import 'package:ffi/ffi.dart';

typedef QueueUserAPCNative = Uint32 Function(Pointer<Void>, Pointer<Void>, UintPtr);
typedef QueueUserAPCDart = int Function(Pointer<Void>, Pointer<Void>, int);
final QueueUserAPC = DynamicLibrary.open('KERNEL32.dll')
    .lookupFunction<QueueUserAPCNative, QueueUserAPCDart>('QueueUserAPC');
// pfnAPC : PAPCFUNC -> Pointer<Void>
// hThread : HANDLE -> Pointer<Void>
// dwData : UINT_PTR -> UintPtr
// 文字列は package:ffi の "...".toNativeUtf16()/toNativeUtf8() で変換。
{$mode objfpc}{$H+}
function QueueUserAPC(
  pfnAPC: Pointer;   // PAPCFUNC
  hThread: THandle;   // HANDLE
  dwData: NativeUInt   // UINT_PTR
): DWORD; stdcall;
  external 'KERNEL32.dll' name 'QueueUserAPC';
import Foreign
import Foreign.C.Types
import Foreign.C.String

foreign import stdcall safe "QueueUserAPC"
  c_QueueUserAPC :: Ptr () -> Ptr () -> CUIntPtr -> IO Word32
-- pfnAPC : PAPCFUNC -> Ptr ()
-- hThread : HANDLE -> Ptr ()
-- dwData : UINT_PTR -> CUIntPtr
-- 要 GHC(Windows)。stdcall は x64 では ccall として扱われる。ブロックする API は safe 呼び出し推奨。
open Ctypes
open Foreign

let queueuserapc =
  foreign "QueueUserAPC"
    ((ptr void) @-> (ptr void) @-> size_t @-> returning uint32_t)
(* pfnAPC : PAPCFUNC -> (ptr void) *)
(* hThread : HANDLE -> (ptr void) *)
(* dwData : UINT_PTR -> size_t *)
(* foreign は cdecl 前提。x64 Windows では WINAPI と一致。構造体は ctypes structure を定義のこと。 *)
(cffi:define-foreign-library kernel32 (t "KERNEL32.dll"))
(cffi:use-foreign-library kernel32)

(cffi:defcfun ("QueueUserAPC" queue-user-apc :convention :stdcall) :uint32
  (pfn-apc :pointer)   ; PAPCFUNC
  (h-thread :pointer)   ; HANDLE
  (dw-data :uint64))   ; UINT_PTR
; isize/usize(INT_PTR/SIZE_T)は x64 前提で :int64/:uint64。x86 では :int32/:uint32。
use Win32::API;
my $QueueUserAPC = Win32::API::More->new('KERNEL32',
    'DWORD QueueUserAPC(LPVOID pfnAPC, HANDLE hThread, WPARAM dwData)');
# my $ret = $QueueUserAPC->Call($pfnAPC, $hThread, $dwData);
# pfnAPC : PAPCFUNC -> LPVOID
# hThread : HANDLE -> HANDLE
# dwData : UINT_PTR -> WPARAM
# 値渡し構造体は pack() した文字列、または Win32::API::Struct を使用。
# コールバック(関数ポインタ)は Perl sub を直接渡せません。Win32::API::Callback を使用してください。

関連項目

類似 API
使用する型