Mutex + RegisterWaitForSingleObject = External exception C000070A
Пытаюсь воспользоваться функционалом RegisterWaitForSingleObject для ожидания мьютекса, но при вызове получаю External exception. Не просто "отказ в регистрировании коллбака", а именно EE.
Что я делаю не так? В сети в основном идут примеры на коллбаки к хендлам процессов, но документация утверждает, что мьютексы так же могут использоваться в этом вызове.
Попытка №1, самая простая:
const
MutexName = 'Global\TForm20Mutex'; // префикс Local и без префикса не меняют результат.
// callback-функция
procedure WaitCallback(lpParameter: Pointer; TimerOrWaitFired: Boolean); stdcall;
begin
Sleep(10); // сюда вызов не доходит.
end;
procedure TForm20.btn1Click(Sender: TObject);
var
bResult: BOOL;
begin
FMutexHandle := CreateMutex(nil, False, MutexName);
if FMutexHandle = 0 then
RaiseLastOSError;
bResult:= RegisterWaitForSingleObject(FCallbackHandle, FMutexHandle,//
WaitCallback, nil, INFINITE, //
WT_EXECUTEONLYONCE or WT_EXECUTELONGFUNCTION); // ExternalException здесь
if not bResult then // сюда управление не доходит.
RaiseLastOSError;
end;
Попытка №100500, динамическая загрузка (перед этим - перекрывал статическую линковку, результат тот же).
type
TRegisterWaitForSingleObject = function(out phNewWaitObject: THandle; hObject: THandle;
CallBack: Pointer; Context: Pointer; dwMilliseconds: ULONG;
dwFlags: ULONG): BOOL; stdcall;
// вместо out param пробовал var и PHandle в качестве типа первого параметра.
var
RegisterWaitForSingleObject: TRegisterWaitForSingleObject;
procedure TForm20.btn1Click(Sender: TObject);
var
hKernel: THandle;
bResult: BOOL;
begin
hKernel:=LoadLibrary('kernel32.dll');
if hKernel = 0 then
RaiseLastOSError;
RegisterWaitForSingleObject:=GetProcAddress(hKernel, 'RegisterWaitForSingleObject');
if @RegisterWaitForSingleObject = nil then
RaiseLastOSError;
FMutex := TMutex.Create(nil, False, MutexName);
FCallbackHandle := 0;
bResult := RegisterWaitForSingleObject(FCallbackHandle, FMutex.Handle, @WaitCallback,
nil, 100, WT_EXECUTEONLYONCE or WT_EXECUTELONGFUNCTION); // и вот здесь ExternalException
if not bResult then
RaiseLastOSError;
end;
Stacktrace:
:76f3a6e2 KERNELBASE.RaiseException + 0x62
:00409b50 NotifyNonDelphiException + $1C
:778f8894 ;
:778e4ec6 ntdll.KiUserExceptionDispatcher + 0x26
:77901855 ;
:778a7b7c ntdll.TpSetWaitEx + 0x8c
:778a21d9 ;
:765e7a7d KERNEL32.RegisterWaitForSingleObject + 0x3d
Unit20.TForm20.btn1Click($329DDE0)
Насколько я понимаю - это одна из самых базовых функций в WinAPI, поэтому вряд ли там будет какая-то ошибка, соответственно - это должна быть кривизна моих рук. Вот только в чем?
Дополнительная информация:
IDE: XE2 и 10.4.1, компиляция в 32бит, идентичная ошибка с идентичными стектрейсами на обеих
OS: Windows 10 Pro x64.
И под дебаггером и без - результат аналогичен.