Почему этот вызов WSAIoctl для загрузки AcceptEx возвращает 10022?
Я пытаюсь загрузить указатель на функцию AcceptEx для кода, преобразованного из примера Microsoft IOCPSERVEREX.CPP, который по сути совпадает с примером кода на странице microsoft.com AcceptEx(). Я использую Delphi 6, отсюда и встроенные определения Winsock2. Я сократил все до этого небольшого примера, но WSAIoctl всегда возвращает ошибку 10022, и я не могу понять, почему.
program test;
{$APPTYPE CONSOLE}
uses windows, winsock;
type
GUID = packed record
D1: DWORD;
D2: DWORD;
D3: DWORD;
D4: array[0..7] of BYTE;
end;
PAddrInfo = ^addrinfo;
addrinfo = packed record
ai_flags, ai_family, ai_socktype, ai_protocol: integer;
ai_addrlen: Cardinal;
ai_canonname: PAnsiChar;
ai_addr: PSockAddrIn;
ai_next: PAddrInfo;
end;
const
AI_PASSIVE = $01;
IOC_WS2 = $08000000;
IOC_OUT = $40000000;
IOC_IN = $80000000;
IOC_INOUT = (IOC_IN or IOC_OUT);
SIO_GET_EXTENSION_FUNCTION_POINTER = 6 or IOC_WS2 or IOC_INOUT;
WSA_FLAG_OVERLAPPED = $01;
WSAID_ACCEPTEX: GUID = (D1:$b5367df1; D2:$cbac; D3:$11cf; D4:($95, $ca, $00, $80, $5f, $48, $a1, $92)); // GUID to Microsoft specific extensions
function GetAddrInfo(nodename, servname: PAnsiChar; pHints: PAddrInfo; out res: PAddrInfo): integer; stdcall; external 'ws2_32.dll' name 'getaddrinfo';
function WSAIoctl(const s: TSocket; dwIoControlCode: DWORD; lpvInBuffer: Pointer; cbInBuffer: DWORD; lpvOutBuffer: Pointer; cbOutBuffer: DWORD;
lpcbBytesReturned: LPDWORD; AOverlapped: Pointer; lpCompletionRoutine: pointer): LongInt; stdcall; external 'ws2_32.dll' name 'WSAIoctl';
function WSASocketA(af, iType, protocol: Integer; lpProtocolInfo: pointer; grp, dwFlags: DWORD): TSocket; stdcall; external 'ws2_32.dll' name 'WSASocketA';
var
wsaData: TWSADATA;
g_hIOCP: THANDLE;
hints: addrinfo;
g_sdListen: TSOCKET;
addrlocal: PAddrInfo;
P: pointer; Bytes: dword;
begin
if WSAStartup(MAKEWORD(2,2), wsaData) <> 0 then writeln('WSAStartup failed');
g_hIOCP := CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
if g_hIOCP = 0 then writeln('CreateIoCompletionPort failed');
fillchar(hints, sizeof(hints), 0);
hints.ai_flags := AI_PASSIVE;
hints.ai_family := AF_INET;
hints.ai_socktype := SOCK_STREAM;
hints.ai_protocol := IPPROTO_IP;
if getaddrinfo('localhost', '80', PAddrInfo(@hints), addrlocal) <> 0 then writeln('getaddrinfo failed');
if addrlocal = nil then writeln('no addrlocal');
g_sdListen := WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_IP, nil, 0, WSA_FLAG_OVERLAPPED);
if g_sdListen = INVALID_SOCKET then writeln('WSASocketA failed');
if bind(g_sdListen, addrlocal^.ai_addr^, integer(addrlocal^.ai_addrlen)) = SOCKET_ERROR then writeln('bind failed');
if listen(g_sdListen, 5) = SOCKET_ERROR then writeln('listen failed');
g_hIOCP := CreateIoCompletionPort(THANDLE(g_sdListen), g_hIOCP, 0, 0);
if g_hIOCP = 0 then writeln('CreateIoCompletionPort failed');
if WSAIoctl(g_sdListen, SIO_GET_EXTENSION_FUNCTION_POINTER, @WSAID_ACCEPTEX, sizeof(WSAID_ACCEPTEX), @P, SizeOf(P), @Bytes, nil, nil) = SOCKET_ERROR then
writeln('AcceptEx failed to load: ', WSAGetLastError);
write('exit:'); readln;
end.