mirror of
https://github.com/reactos/reactos.git
synced 2025-08-07 01:03:16 +00:00
Fix IO completion APIs/Structures.
Implement WSPASyncSelect and friends. Event re-enabling functionality missing and will be added tonight. svn path=/trunk/; revision=11807
This commit is contained in:
parent
3379855217
commit
1623a0079f
13 changed files with 512 additions and 73 deletions
|
@ -52,10 +52,10 @@ typedef struct _AFD_HANDLE_ {
|
||||||
} AFD_HANDLE, *PAFD_HANDLE;
|
} AFD_HANDLE, *PAFD_HANDLE;
|
||||||
|
|
||||||
typedef struct _AFD_POLL_INFO {
|
typedef struct _AFD_POLL_INFO {
|
||||||
LARGE_INTEGER Timeout;
|
LARGE_INTEGER Timeout;
|
||||||
ULONG HandleCount;
|
ULONG HandleCount;
|
||||||
PAFD_HANDLE InternalUse;
|
BOOLEAN Exclusive;
|
||||||
AFD_HANDLE Handles[1];
|
AFD_HANDLE Handles[1];
|
||||||
} AFD_POLL_INFO, *PAFD_POLL_INFO;
|
} AFD_POLL_INFO, *PAFD_POLL_INFO;
|
||||||
|
|
||||||
typedef struct _AFD_ACCEPT_DATA {
|
typedef struct _AFD_ACCEPT_DATA {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $Id: iotypes.h,v 1.69 2004/11/06 04:12:59 ion Exp $
|
/* $Id: iotypes.h,v 1.70 2004/11/25 22:18:15 ion Exp $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -752,7 +752,7 @@ typedef struct _SECTION_OBJECT_POINTERS
|
||||||
typedef struct _IO_COMPLETION_CONTEXT
|
typedef struct _IO_COMPLETION_CONTEXT
|
||||||
{
|
{
|
||||||
PVOID Port;
|
PVOID Port;
|
||||||
ULONG Key;
|
PVOID Key;
|
||||||
} IO_COMPLETION_CONTEXT, *PIO_COMPLETION_CONTEXT;
|
} IO_COMPLETION_CONTEXT, *PIO_COMPLETION_CONTEXT;
|
||||||
|
|
||||||
#define FO_FILE_OPEN 0x00000001
|
#define FO_FILE_OPEN 0x00000001
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
/* $Id: zw.h,v 1.35 2004/11/12 12:06:17 ekohl Exp $
|
/* $Id: zw.h,v 1.36 2004/11/25 22:18:15 ion Exp $
|
||||||
*
|
*
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
* PROJECT: ReactOS kernel
|
||||||
|
@ -3567,8 +3567,8 @@ NTSTATUS
|
||||||
STDCALL
|
STDCALL
|
||||||
NtRemoveIoCompletion(
|
NtRemoveIoCompletion(
|
||||||
IN HANDLE IoCompletionHandle,
|
IN HANDLE IoCompletionHandle,
|
||||||
OUT PULONG CompletionKey,
|
OUT PVOID *CompletionKey,
|
||||||
OUT PULONG CompletionValue,
|
OUT PVOID *CompletionContext,
|
||||||
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
||||||
IN PLARGE_INTEGER Timeout OPTIONAL
|
IN PLARGE_INTEGER Timeout OPTIONAL
|
||||||
);
|
);
|
||||||
|
@ -3577,8 +3577,8 @@ NTSTATUS
|
||||||
STDCALL
|
STDCALL
|
||||||
ZwRemoveIoCompletion(
|
ZwRemoveIoCompletion(
|
||||||
IN HANDLE IoCompletionHandle,
|
IN HANDLE IoCompletionHandle,
|
||||||
OUT PULONG CompletionKey,
|
OUT PVOID *CompletionKey,
|
||||||
OUT PULONG CompletionValue,
|
OUT PVOID *CompletionValue,
|
||||||
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
||||||
IN PLARGE_INTEGER Timeout OPTIONAL
|
IN PLARGE_INTEGER Timeout OPTIONAL
|
||||||
);
|
);
|
||||||
|
@ -4094,8 +4094,8 @@ NTSTATUS
|
||||||
STDCALL
|
STDCALL
|
||||||
NtSetIoCompletion(
|
NtSetIoCompletion(
|
||||||
IN HANDLE IoCompletionPortHandle,
|
IN HANDLE IoCompletionPortHandle,
|
||||||
IN ULONG CompletionKey,
|
IN PVOID CompletionKey,
|
||||||
IN ULONG CompletionValue,
|
IN PVOID CompletionContext,
|
||||||
IN NTSTATUS CompletionStatus,
|
IN NTSTATUS CompletionStatus,
|
||||||
IN ULONG CompletionInformation
|
IN ULONG CompletionInformation
|
||||||
);
|
);
|
||||||
|
@ -4104,8 +4104,8 @@ NTSTATUS
|
||||||
STDCALL
|
STDCALL
|
||||||
ZwSetIoCompletion(
|
ZwSetIoCompletion(
|
||||||
IN HANDLE IoCompletionPortHandle,
|
IN HANDLE IoCompletionPortHandle,
|
||||||
IN ULONG CompletionKey,
|
IN PVOID CompletionKey,
|
||||||
IN ULONG CompletionValue,
|
IN PVOID CompletionContext,
|
||||||
IN NTSTATUS CompletionStatus,
|
IN NTSTATUS CompletionStatus,
|
||||||
IN ULONG CompletionInformation
|
IN ULONG CompletionInformation
|
||||||
);
|
);
|
||||||
|
|
|
@ -971,7 +971,7 @@ typedef struct _FILE_COMPRESSION_INFORMATION {
|
||||||
|
|
||||||
typedef struct _FILE_COMPLETION_INFORMATION { // Information Class 30
|
typedef struct _FILE_COMPLETION_INFORMATION { // Information Class 30
|
||||||
HANDLE IoCompletionHandle;
|
HANDLE IoCompletionHandle;
|
||||||
ULONG CompletionKey;
|
PVOID CompletionKey;
|
||||||
} FILE_COMPLETION_INFORMATION, *PFILE_COMPLETION_INFORMATION;
|
} FILE_COMPLETION_INFORMATION, *PFILE_COMPLETION_INFORMATION;
|
||||||
|
|
||||||
typedef struct _FILE_ALL_INFORMATION {
|
typedef struct _FILE_ALL_INFORMATION {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $Id: iocompl.c,v 1.15 2004/10/30 22:18:17 weiden Exp $
|
/* $Id: iocompl.c,v 1.16 2004/11/25 22:18:16 ion Exp $
|
||||||
*
|
*
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS system libraries
|
* PROJECT: ReactOS system libraries
|
||||||
|
@ -23,7 +23,7 @@ STDCALL
|
||||||
CreateIoCompletionPort(
|
CreateIoCompletionPort(
|
||||||
HANDLE FileHandle,
|
HANDLE FileHandle,
|
||||||
HANDLE ExistingCompletionPort,
|
HANDLE ExistingCompletionPort,
|
||||||
DWORD CompletionKey,
|
ULONG_PTR CompletionKey,
|
||||||
DWORD NumberOfConcurrentThreads
|
DWORD NumberOfConcurrentThreads
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -62,7 +62,7 @@ CreateIoCompletionPort(
|
||||||
{
|
{
|
||||||
#ifdef __USE_W32API
|
#ifdef __USE_W32API
|
||||||
CompletionInformation.Port = CompletionPort;
|
CompletionInformation.Port = CompletionPort;
|
||||||
CompletionInformation.Key = CompletionKey;
|
CompletionInformation.Key = (PVOID)CompletionKey;
|
||||||
#else
|
#else
|
||||||
CompletionInformation.IoCompletionHandle = CompletionPort;
|
CompletionInformation.IoCompletionHandle = CompletionPort;
|
||||||
CompletionInformation.CompletionKey = CompletionKey;
|
CompletionInformation.CompletionKey = CompletionKey;
|
||||||
|
@ -98,7 +98,7 @@ STDCALL
|
||||||
GetQueuedCompletionStatus(
|
GetQueuedCompletionStatus(
|
||||||
HANDLE CompletionHandle,
|
HANDLE CompletionHandle,
|
||||||
LPDWORD lpNumberOfBytesTransferred,
|
LPDWORD lpNumberOfBytesTransferred,
|
||||||
LPDWORD lpCompletionKey,
|
PULONG_PTR lpCompletionKey,
|
||||||
LPOVERLAPPED *lpOverlapped,
|
LPOVERLAPPED *lpOverlapped,
|
||||||
DWORD dwMilliseconds
|
DWORD dwMilliseconds
|
||||||
)
|
)
|
||||||
|
@ -127,8 +127,8 @@ GetQueuedCompletionStatus(
|
||||||
}
|
}
|
||||||
|
|
||||||
errCode = NtRemoveIoCompletion(CompletionHandle,
|
errCode = NtRemoveIoCompletion(CompletionHandle,
|
||||||
lpCompletionKey,
|
(PVOID*)lpCompletionKey,
|
||||||
lpNumberOfBytesTransferred,
|
(PVOID*)lpNumberOfBytesTransferred,
|
||||||
&IoStatus,
|
&IoStatus,
|
||||||
&Interval);
|
&Interval);
|
||||||
|
|
||||||
|
@ -166,10 +166,10 @@ PostQueuedCompletionStatus(
|
||||||
NTSTATUS errCode;
|
NTSTATUS errCode;
|
||||||
|
|
||||||
errCode = NtSetIoCompletion(CompletionHandle,
|
errCode = NtSetIoCompletion(CompletionHandle,
|
||||||
dwCompletionKey,
|
(PVOID)dwCompletionKey,
|
||||||
dwNumberOfBytesTransferred,//CompletionValue
|
(PVOID)lpOverlapped,//CompletionValue
|
||||||
0, //IoStatusBlock->Status
|
STATUS_SUCCESS, //IoStatusBlock->Status
|
||||||
(ULONG)lpOverlapped ); //IoStatusBlock->Information
|
dwNumberOfBytesTransferred); //IoStatusBlock->Information
|
||||||
|
|
||||||
if ( !NT_SUCCESS(errCode) )
|
if ( !NT_SUCCESS(errCode) )
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,11 +22,17 @@
|
||||||
#include <helpers.h>
|
#include <helpers.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
|
|
||||||
|
/* Because our headers are f*cked up */
|
||||||
|
typedef LARGE_INTEGER TIME;
|
||||||
|
#include <ntos/zw.h>
|
||||||
|
|
||||||
extern HANDLE GlobalHeap;
|
extern HANDLE GlobalHeap;
|
||||||
extern WSPUPCALLTABLE Upcalls;
|
extern WSPUPCALLTABLE Upcalls;
|
||||||
extern LPWPUCOMPLETEOVERLAPPEDREQUEST lpWPUCompleteOverlappedRequest;
|
extern LPWPUCOMPLETEOVERLAPPEDREQUEST lpWPUCompleteOverlappedRequest;
|
||||||
extern LIST_ENTRY SockHelpersListHead;
|
extern LIST_ENTRY SockHelpersListHead;
|
||||||
extern HANDLE SockEvent;
|
extern HANDLE SockEvent;
|
||||||
|
extern HANDLE SockAsyncCompletionPort;
|
||||||
|
extern BOOLEAN SockAsyncSelectCalled;
|
||||||
|
|
||||||
typedef enum _SOCKET_STATE {
|
typedef enum _SOCKET_STATE {
|
||||||
SocketOpen,
|
SocketOpen,
|
||||||
|
@ -74,41 +80,48 @@ typedef struct _SOCK_SHARED_INFO {
|
||||||
LONG Unknown;
|
LONG Unknown;
|
||||||
DWORD SequenceNumber;
|
DWORD SequenceNumber;
|
||||||
UINT wMsg;
|
UINT wMsg;
|
||||||
LONG Event;
|
LONG AsyncEvents;
|
||||||
LONG DisabledEvents;
|
LONG AsyncDisabledEvents;
|
||||||
} SOCK_SHARED_INFO, *PSOCK_SHARED_INFO;
|
} SOCK_SHARED_INFO, *PSOCK_SHARED_INFO;
|
||||||
|
|
||||||
typedef struct _SOCKET_INFORMATION {
|
typedef struct _SOCKET_INFORMATION {
|
||||||
ULONG RefCount;
|
ULONG RefCount;
|
||||||
SOCKET Handle;
|
SOCKET Handle;
|
||||||
SOCK_SHARED_INFO SharedData;
|
SOCK_SHARED_INFO SharedData;
|
||||||
DWORD HelperEvents;
|
DWORD HelperEvents;
|
||||||
PHELPER_DATA HelperData;
|
PHELPER_DATA HelperData;
|
||||||
PVOID HelperContext;
|
PVOID HelperContext;
|
||||||
PSOCKADDR LocalAddress;
|
PSOCKADDR LocalAddress;
|
||||||
PSOCKADDR RemoteAddress;
|
PSOCKADDR RemoteAddress;
|
||||||
HANDLE TdiAddressHandle;
|
HANDLE TdiAddressHandle;
|
||||||
HANDLE TdiConnectionHandle;
|
HANDLE TdiConnectionHandle;
|
||||||
PVOID AsyncData;
|
PVOID AsyncData;
|
||||||
HANDLE EventObject;
|
HANDLE EventObject;
|
||||||
LONG NetworkEvents;
|
LONG NetworkEvents;
|
||||||
CRITICAL_SECTION Lock;
|
CRITICAL_SECTION Lock;
|
||||||
PVOID SanData;
|
PVOID SanData;
|
||||||
BOOL TrySAN;
|
BOOL TrySAN;
|
||||||
SOCKADDR WSLocalAddress;
|
SOCKADDR WSLocalAddress;
|
||||||
SOCKADDR WSRemoteAddress;
|
SOCKADDR WSRemoteAddress;
|
||||||
} SOCKET_INFORMATION, *PSOCKET_INFORMATION;
|
} SOCKET_INFORMATION, *PSOCKET_INFORMATION;
|
||||||
|
|
||||||
|
|
||||||
typedef struct _SOCKET_CONTEXT {
|
typedef struct _SOCKET_CONTEXT {
|
||||||
SOCK_SHARED_INFO SharedData;
|
SOCK_SHARED_INFO SharedData;
|
||||||
ULONG SizeOfHelperData;
|
ULONG SizeOfHelperData;
|
||||||
ULONG Padding;
|
ULONG Padding;
|
||||||
SOCKADDR LocalAddress;
|
SOCKADDR LocalAddress;
|
||||||
SOCKADDR RemoteAddress;
|
SOCKADDR RemoteAddress;
|
||||||
/* Plus Helper Data */
|
/* Plus Helper Data */
|
||||||
} SOCKET_CONTEXT, *PSOCKET_CONTEXT;
|
} SOCKET_CONTEXT, *PSOCKET_CONTEXT;
|
||||||
|
|
||||||
|
typedef struct _ASYNC_DATA {
|
||||||
|
PSOCKET_INFORMATION ParentSocket;
|
||||||
|
DWORD SequenceNumber;
|
||||||
|
IO_STATUS_BLOCK IoStatusBlock;
|
||||||
|
AFD_POLL_INFO AsyncSelectInfo;
|
||||||
|
} ASYNC_DATA, *PASYNC_DATA;
|
||||||
|
|
||||||
SOCKET
|
SOCKET
|
||||||
WSPAPI
|
WSPAPI
|
||||||
WSPAccept(
|
WSPAccept(
|
||||||
|
@ -416,6 +429,39 @@ int SetSocketInformation(
|
||||||
int CreateContext(
|
int CreateContext(
|
||||||
PSOCKET_INFORMATION Socket
|
PSOCKET_INFORMATION Socket
|
||||||
);
|
);
|
||||||
|
|
||||||
|
int SockAsyncThread(
|
||||||
|
PVOID ThreadParam
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
SockProcessAsyncSelect(
|
||||||
|
PSOCKET_INFORMATION Socket,
|
||||||
|
PASYNC_DATA AsyncData
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
SockAsyncSelectCompletionRoutine(
|
||||||
|
PVOID Context,
|
||||||
|
PIO_STATUS_BLOCK IoStatusBlock
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
SockCreateOrReferenceAsyncThread(
|
||||||
|
VOID
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOLEAN SockGetAsyncSelectHelperAfdHandle(
|
||||||
|
VOID
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID SockProcessQueuedAsyncSelect(
|
||||||
|
PVOID Context,
|
||||||
|
PIO_STATUS_BLOCK IoStatusBlock
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef VOID (*PASYNC_COMPLETION_ROUTINE)(PVOID Context, PIO_STATUS_BLOCK IoStatusBlock);
|
||||||
|
|
||||||
#endif /* __MSAFD_H */
|
#endif /* __MSAFD_H */
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -20,12 +20,16 @@
|
||||||
DWORD DebugTraceLevel = 0;
|
DWORD DebugTraceLevel = 0;
|
||||||
#endif /* DBG */
|
#endif /* DBG */
|
||||||
|
|
||||||
HANDLE GlobalHeap;
|
HANDLE GlobalHeap;
|
||||||
WSPUPCALLTABLE Upcalls;
|
WSPUPCALLTABLE Upcalls;
|
||||||
LPWPUCOMPLETEOVERLAPPEDREQUEST lpWPUCompleteOverlappedRequest;
|
LPWPUCOMPLETEOVERLAPPEDREQUEST lpWPUCompleteOverlappedRequest;
|
||||||
ULONG SocketCount;
|
ULONG SocketCount;
|
||||||
PSOCKET_INFORMATION *Sockets = NULL;
|
PSOCKET_INFORMATION *Sockets = NULL;
|
||||||
LIST_ENTRY SockHelpersListHead = {NULL};
|
LIST_ENTRY SockHelpersListHead = {NULL};
|
||||||
|
ULONG SockAsyncThreadRefCount;
|
||||||
|
HANDLE SockAsyncHelperAfdHandle;
|
||||||
|
HANDLE SockAsyncCompletionPort;
|
||||||
|
BOOLEAN SockAsyncSelectCalled;
|
||||||
|
|
||||||
SOCKET
|
SOCKET
|
||||||
WSPAPI
|
WSPAPI
|
||||||
|
@ -456,7 +460,7 @@ WSPSelect(
|
||||||
|
|
||||||
/* Number of handles for AFD to Check */
|
/* Number of handles for AFD to Check */
|
||||||
PollInfo->HandleCount = HandleCount;
|
PollInfo->HandleCount = HandleCount;
|
||||||
PollInfo->InternalUse = 0;
|
PollInfo->Exclusive = FALSE;
|
||||||
|
|
||||||
if (readfds != NULL) {
|
if (readfds != NULL) {
|
||||||
for (i = 0; i < readfds->fd_count; i++, j++) {
|
for (i = 0; i < readfds->fd_count; i++, j++) {
|
||||||
|
@ -1291,6 +1295,342 @@ int CreateContext(PSOCKET_INFORMATION Socket)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOLEAN SockCreateOrReferenceAsyncThread(VOID)
|
||||||
|
{
|
||||||
|
HANDLE hAsyncThread;
|
||||||
|
DWORD AsyncThreadId;
|
||||||
|
HANDLE AsyncEvent;
|
||||||
|
OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
/* Check if the Thread Already Exists */
|
||||||
|
if (SockAsyncThreadRefCount) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the Completion Port */
|
||||||
|
if (!SockAsyncCompletionPort) {
|
||||||
|
Status = NtCreateIoCompletion(&SockAsyncCompletionPort,
|
||||||
|
IO_COMPLETION_ALL_ACCESS,
|
||||||
|
NULL,
|
||||||
|
2); // Allow 2 threads only
|
||||||
|
|
||||||
|
/* Protect Handle */
|
||||||
|
HandleFlags.ProtectFromClose = TRUE;
|
||||||
|
HandleFlags.Inherit = FALSE;
|
||||||
|
Status = NtSetInformationObject(SockAsyncCompletionPort,
|
||||||
|
ObjectHandleInformation,
|
||||||
|
&HandleFlags,
|
||||||
|
sizeof(HandleFlags));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the Async Event */
|
||||||
|
Status = NtCreateEvent(&AsyncEvent,
|
||||||
|
EVENT_ALL_ACCESS,
|
||||||
|
NULL,
|
||||||
|
NotificationEvent,
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
/* Create the Async Thread */
|
||||||
|
hAsyncThread = CreateThread(NULL,
|
||||||
|
0,
|
||||||
|
(LPTHREAD_START_ROUTINE)SockAsyncThread,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
&AsyncThreadId);
|
||||||
|
|
||||||
|
/* Close the Handle */
|
||||||
|
NtClose(hAsyncThread);
|
||||||
|
|
||||||
|
/* Increase the Reference Count */
|
||||||
|
SockAsyncThreadRefCount++;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SockAsyncThread(PVOID ThreadParam)
|
||||||
|
{
|
||||||
|
PVOID AsyncContext;
|
||||||
|
PASYNC_COMPLETION_ROUTINE AsyncCompletionRoutine;
|
||||||
|
IO_STATUS_BLOCK IOSB;
|
||||||
|
NTSTATUS Status;
|
||||||
|
LARGE_INTEGER Timeout;
|
||||||
|
|
||||||
|
/* Make the Thread Higher Priority */
|
||||||
|
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
|
||||||
|
|
||||||
|
/* Do a KQUEUE/WorkItem Style Loop, thanks to IoCompletion Ports */
|
||||||
|
do {
|
||||||
|
Status = NtRemoveIoCompletion (SockAsyncCompletionPort,
|
||||||
|
(PVOID*)&AsyncCompletionRoutine,
|
||||||
|
&AsyncContext,
|
||||||
|
&IOSB,
|
||||||
|
&Timeout);
|
||||||
|
|
||||||
|
/* Call the Async Function */
|
||||||
|
if (NT_SUCCESS(Status)) {
|
||||||
|
//(*AsyncCompletionRoutine)(AsyncContext, IOSB);
|
||||||
|
} else {
|
||||||
|
/* It Failed, sleep for a second */
|
||||||
|
Sleep(1000);
|
||||||
|
}
|
||||||
|
} while ((Status != STATUS_TIMEOUT));
|
||||||
|
|
||||||
|
/* The Thread has Ended */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN SockGetAsyncSelectHelperAfdHandle(VOID)
|
||||||
|
{
|
||||||
|
UNICODE_STRING AfdHelper;
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
IO_STATUS_BLOCK IoSb;
|
||||||
|
NTSTATUS Status;
|
||||||
|
FILE_COMPLETION_INFORMATION CompletionInfo;
|
||||||
|
OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleFlags;
|
||||||
|
|
||||||
|
/* First, make sure we're not already intialized */
|
||||||
|
if (SockAsyncHelperAfdHandle) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up Handle Name and Object */
|
||||||
|
RtlInitUnicodeString(&AfdHelper, L"\\Device\\Afd\\AsyncSelectHlp" );
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
|
&AfdHelper,
|
||||||
|
OBJ_INHERIT | OBJ_CASE_INSENSITIVE,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Open the Handle to AFD */
|
||||||
|
Status = NtCreateFile(&SockAsyncHelperAfdHandle,
|
||||||
|
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
|
||||||
|
&ObjectAttributes,
|
||||||
|
&IoSb,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
FILE_OPEN_IF,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now Set up the Completion Port Information
|
||||||
|
* This means that whenever a Poll is finished, the routine will be executed
|
||||||
|
*/
|
||||||
|
CompletionInfo.Port = SockAsyncCompletionPort;
|
||||||
|
CompletionInfo.Key = SockAsyncSelectCompletionRoutine;
|
||||||
|
Status = NtSetInformationFile(SockAsyncHelperAfdHandle,
|
||||||
|
&IoSb,
|
||||||
|
&CompletionInfo,
|
||||||
|
sizeof(CompletionInfo),
|
||||||
|
FileCompletionInformation);
|
||||||
|
|
||||||
|
|
||||||
|
/* Protect the Handle */
|
||||||
|
HandleFlags.ProtectFromClose = TRUE;
|
||||||
|
HandleFlags.Inherit = FALSE;
|
||||||
|
Status = NtSetInformationObject(SockAsyncCompletionPort,
|
||||||
|
ObjectHandleInformation,
|
||||||
|
&HandleFlags,
|
||||||
|
sizeof(HandleFlags));
|
||||||
|
|
||||||
|
|
||||||
|
/* Set this variable to true so that Send/Recv/Accept will know wether to renable disabled events */
|
||||||
|
SockAsyncSelectCalled = TRUE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID SockAsyncSelectCompletionRoutine(PVOID Context, PIO_STATUS_BLOCK IoStatusBlock)
|
||||||
|
{
|
||||||
|
|
||||||
|
PASYNC_DATA AsyncData = Context;
|
||||||
|
PSOCKET_INFORMATION Socket;
|
||||||
|
ULONG x;
|
||||||
|
|
||||||
|
/* Get the Socket */
|
||||||
|
Socket = AsyncData->ParentSocket;
|
||||||
|
|
||||||
|
/* Check if the Sequence Number Changed behind our back */
|
||||||
|
if (AsyncData->SequenceNumber != Socket->SharedData.SequenceNumber ){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check we were manually called b/c of a failure */
|
||||||
|
if (!NT_SUCCESS(IoStatusBlock->Status)) {
|
||||||
|
/* FIXME: Perform Upcall */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (x = 1; x; x<<=1) {
|
||||||
|
switch (AsyncData->AsyncSelectInfo.Handles[0].Events & x) {
|
||||||
|
case AFD_EVENT_RECEIVE:
|
||||||
|
if ((Socket->SharedData.AsyncEvents & FD_READ) && (!Socket->SharedData.AsyncDisabledEvents & FD_READ)) {
|
||||||
|
/* Make the Notifcation */
|
||||||
|
(Upcalls.lpWPUPostMessage)(Socket->SharedData.hWnd,
|
||||||
|
Socket->SharedData.wMsg,
|
||||||
|
Socket->Handle,
|
||||||
|
WSAMAKESELECTREPLY(FD_READ, 0));
|
||||||
|
/* Disable this event until the next read(); */
|
||||||
|
Socket->SharedData.AsyncDisabledEvents |= FD_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AFD_EVENT_OOB_RECEIVE:
|
||||||
|
if ((Socket->SharedData.AsyncEvents & FD_OOB) && (!Socket->SharedData.AsyncDisabledEvents & FD_OOB)) {
|
||||||
|
/* Make the Notifcation */
|
||||||
|
(Upcalls.lpWPUPostMessage)(Socket->SharedData.hWnd,
|
||||||
|
Socket->SharedData.wMsg,
|
||||||
|
Socket->Handle,
|
||||||
|
WSAMAKESELECTREPLY(FD_OOB, 0));
|
||||||
|
/* Disable this event until the next read(); */
|
||||||
|
Socket->SharedData.AsyncDisabledEvents |= FD_OOB;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AFD_EVENT_SEND:
|
||||||
|
if ((Socket->SharedData.AsyncEvents & FD_WRITE) && (!Socket->SharedData.AsyncDisabledEvents & FD_WRITE)) {
|
||||||
|
/* Make the Notifcation */
|
||||||
|
(Upcalls.lpWPUPostMessage)(Socket->SharedData.hWnd,
|
||||||
|
Socket->SharedData.wMsg,
|
||||||
|
Socket->Handle,
|
||||||
|
WSAMAKESELECTREPLY(FD_WRITE, 0));
|
||||||
|
/* Disable this event until the next write(); */
|
||||||
|
Socket->SharedData.AsyncDisabledEvents |= FD_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AFD_EVENT_ACCEPT:
|
||||||
|
if ((Socket->SharedData.AsyncEvents & FD_ACCEPT) && (!Socket->SharedData.AsyncDisabledEvents & FD_ACCEPT)) {
|
||||||
|
/* Make the Notifcation */
|
||||||
|
(Upcalls.lpWPUPostMessage)(Socket->SharedData.hWnd,
|
||||||
|
Socket->SharedData.wMsg,
|
||||||
|
Socket->Handle,
|
||||||
|
WSAMAKESELECTREPLY(FD_ACCEPT, 0));
|
||||||
|
/* Disable this event until the next accept(); */
|
||||||
|
Socket->SharedData.AsyncDisabledEvents |= FD_ACCEPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AFD_EVENT_DISCONNECT:
|
||||||
|
case AFD_EVENT_ABORT:
|
||||||
|
case AFD_EVENT_CLOSE:
|
||||||
|
if ((Socket->SharedData.AsyncEvents & FD_CLOSE) && (!Socket->SharedData.AsyncDisabledEvents & FD_CLOSE)) {
|
||||||
|
/* Make the Notifcation */
|
||||||
|
(Upcalls.lpWPUPostMessage)(Socket->SharedData.hWnd,
|
||||||
|
Socket->SharedData.wMsg,
|
||||||
|
Socket->Handle,
|
||||||
|
WSAMAKESELECTREPLY(FD_CLOSE, 0));
|
||||||
|
/* Disable this event forever; */
|
||||||
|
Socket->SharedData.AsyncDisabledEvents |= FD_CLOSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: Support QOS */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if there are any events left for us to check */
|
||||||
|
if ((Socket->SharedData.AsyncEvents & (~Socket->SharedData.AsyncDisabledEvents)) == 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep Polling */
|
||||||
|
SockProcessAsyncSelect(Socket, AsyncData);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID SockProcessAsyncSelect(PSOCKET_INFORMATION Socket, PASYNC_DATA AsyncData)
|
||||||
|
{
|
||||||
|
|
||||||
|
ULONG lNetworkEvents;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
/* Set up the Async Data Event Info */
|
||||||
|
AsyncData->AsyncSelectInfo.Timeout.HighPart = 0x7FFFFFFF;
|
||||||
|
AsyncData->AsyncSelectInfo.Timeout.LowPart = 0xFFFFFFFF;
|
||||||
|
AsyncData->AsyncSelectInfo.HandleCount = 1;
|
||||||
|
AsyncData->AsyncSelectInfo.Exclusive = TRUE;
|
||||||
|
AsyncData->AsyncSelectInfo.Handles[0].Handle = Socket->Handle;
|
||||||
|
AsyncData->AsyncSelectInfo.Handles[0].Events = 0;
|
||||||
|
|
||||||
|
/* Remove unwanted events */
|
||||||
|
lNetworkEvents = Socket->SharedData.AsyncEvents & (~Socket->SharedData.AsyncDisabledEvents);
|
||||||
|
|
||||||
|
/* Set Events to wait for */
|
||||||
|
if (lNetworkEvents & FD_READ) {
|
||||||
|
AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_RECEIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lNetworkEvents & FD_WRITE) {
|
||||||
|
AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_SEND;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lNetworkEvents & FD_OOB) {
|
||||||
|
AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_OOB_RECEIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lNetworkEvents & FD_ACCEPT) {
|
||||||
|
AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_ACCEPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lNetworkEvents & FD_CONNECT) {
|
||||||
|
AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_CONNECT | AFD_EVENT_CONNECT_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lNetworkEvents & FD_CLOSE) {
|
||||||
|
AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_DISCONNECT | AFD_EVENT_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lNetworkEvents & FD_QOS) {
|
||||||
|
AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_QOS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lNetworkEvents & FD_GROUP_QOS) {
|
||||||
|
AsyncData->AsyncSelectInfo.Handles[0].Events |= AFD_EVENT_GROUP_QOS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send IOCTL */
|
||||||
|
Status = NtDeviceIoControlFile (SockAsyncHelperAfdHandle,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
AsyncData,
|
||||||
|
&AsyncData->IoStatusBlock,
|
||||||
|
IOCTL_AFD_SELECT,
|
||||||
|
&AsyncData->AsyncSelectInfo,
|
||||||
|
sizeof(AsyncData->AsyncSelectInfo),
|
||||||
|
&AsyncData->AsyncSelectInfo,
|
||||||
|
sizeof(AsyncData->AsyncSelectInfo));
|
||||||
|
|
||||||
|
/* I/O Manager Won't call the completion routine, let's do it manually */
|
||||||
|
if (NT_SUCCESS(Status)) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
AsyncData->IoStatusBlock.Status = Status;
|
||||||
|
SockAsyncSelectCompletionRoutine(AsyncData, &AsyncData->IoStatusBlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID SockProcessQueuedAsyncSelect(PVOID Context, PIO_STATUS_BLOCK IoStatusBlock)
|
||||||
|
{
|
||||||
|
PASYNC_DATA AsyncData = Context;
|
||||||
|
PSOCKET_INFORMATION Socket;
|
||||||
|
|
||||||
|
/* Get the Socket */
|
||||||
|
Socket = AsyncData->ParentSocket;
|
||||||
|
|
||||||
|
/* If someone closed it, stop the function */
|
||||||
|
if (Socket->SharedData.State != SocketClosed) {
|
||||||
|
/* Check if the Sequence Number changed by now, in which case quit */
|
||||||
|
if (AsyncData->SequenceNumber == Socket->SharedData.SequenceNumber) {
|
||||||
|
/* Do the actuall select, if needed */
|
||||||
|
if ((Socket->SharedData.AsyncEvents & (~Socket->SharedData.AsyncDisabledEvents))) {
|
||||||
|
SockProcessAsyncSelect(Socket, AsyncData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free the Context */
|
||||||
|
HeapFree(GetProcessHeap(), 0, AsyncData);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
STDCALL
|
STDCALL
|
||||||
DllMain(HANDLE hInstDll,
|
DllMain(HANDLE hInstDll,
|
||||||
|
|
|
@ -42,7 +42,10 @@ WSPEventSelect(
|
||||||
|
|
||||||
/* Deactivate Async Select if there is one */
|
/* Deactivate Async Select if there is one */
|
||||||
if (Socket->EventObject) {
|
if (Socket->EventObject) {
|
||||||
//SockAsyncSelect(Socket, NULL, 0, 0);
|
Socket->SharedData.hWnd = NULL;
|
||||||
|
Socket->SharedData.wMsg = 0;
|
||||||
|
Socket->SharedData.AsyncEvents = 0;
|
||||||
|
Socket->SharedData.SequenceNumber++; // This will kill Async Select after the next completion
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set Structure Info */
|
/* Set Structure Info */
|
||||||
|
|
|
@ -15,15 +15,65 @@
|
||||||
INT
|
INT
|
||||||
WSPAPI
|
WSPAPI
|
||||||
WSPAsyncSelect(
|
WSPAsyncSelect(
|
||||||
IN SOCKET s,
|
IN SOCKET Handle,
|
||||||
IN HWND hWnd,
|
IN HWND hWnd,
|
||||||
IN UINT wMsg,
|
IN UINT wMsg,
|
||||||
IN LONG lEvent,
|
IN LONG lEvent,
|
||||||
OUT LPINT lpErrno)
|
OUT LPINT lpErrno)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED
|
PSOCKET_INFORMATION Socket = NULL;
|
||||||
|
PASYNC_DATA AsyncData;
|
||||||
|
NTSTATUS Status;
|
||||||
|
ULONG BlockMode;
|
||||||
|
|
||||||
return 0;
|
/* Get the Socket Structure associated to this Socket */
|
||||||
|
Socket = GetSocketStructure(Handle);
|
||||||
|
|
||||||
|
/* Allocate the Async Data Structure to pass on to the Thread later */
|
||||||
|
HeapAlloc(GetProcessHeap(), 0, sizeof(*AsyncData));
|
||||||
|
|
||||||
|
/* Change the Socket to Non Blocking */
|
||||||
|
BlockMode = 1;
|
||||||
|
SetSocketInformation(Socket, AFD_INFO_BLOCKING_MODE, &BlockMode, NULL);
|
||||||
|
Socket->SharedData.NonBlocking = TRUE;
|
||||||
|
|
||||||
|
/* Deactive WSPEventSelect */
|
||||||
|
if (Socket->SharedData.AsyncEvents) {
|
||||||
|
WSPEventSelect(Handle, NULL, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the Asynch Thread if Needed */
|
||||||
|
SockCreateOrReferenceAsyncThread();
|
||||||
|
|
||||||
|
/* Open a Handle to AFD's Async Helper */
|
||||||
|
SockGetAsyncSelectHelperAfdHandle();
|
||||||
|
|
||||||
|
/* Store Socket Data */
|
||||||
|
Socket->SharedData.hWnd = hWnd;
|
||||||
|
Socket->SharedData.wMsg = wMsg;
|
||||||
|
Socket->SharedData.AsyncEvents = lEvent;
|
||||||
|
Socket->SharedData.AsyncDisabledEvents = 0;
|
||||||
|
Socket->SharedData.SequenceNumber++;
|
||||||
|
|
||||||
|
/* Return if there are no more Events */
|
||||||
|
if ((Socket->SharedData.AsyncEvents & (~Socket->SharedData.AsyncDisabledEvents)) == 0) {
|
||||||
|
HeapFree(GetProcessHeap(), 0, AsyncData);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up the Async Data */
|
||||||
|
AsyncData->ParentSocket = Socket;
|
||||||
|
AsyncData->SequenceNumber = Socket->SharedData.SequenceNumber;
|
||||||
|
|
||||||
|
/* Begin Async Select by using I/O Completion */
|
||||||
|
Status = NtSetIoCompletion(SockAsyncCompletionPort,
|
||||||
|
(PVOID)&SockProcessQueuedAsyncSelect,
|
||||||
|
AsyncData,
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
|
||||||
|
/* Return */
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
/* $Id: io.h,v 1.49 2004/11/19 21:31:02 navaraf Exp $
|
/* $Id: io.h,v 1.50 2004/11/25 22:18:16 ion Exp $
|
||||||
*
|
*
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
* PROJECT: ReactOS kernel
|
||||||
|
@ -43,8 +43,8 @@
|
||||||
|
|
||||||
|
|
||||||
typedef struct _IO_COMPLETION_PACKET{
|
typedef struct _IO_COMPLETION_PACKET{
|
||||||
ULONG Key;
|
PVOID Key;
|
||||||
ULONG Overlapped;
|
PVOID Context;
|
||||||
IO_STATUS_BLOCK IoStatus;
|
IO_STATUS_BLOCK IoStatus;
|
||||||
LIST_ENTRY ListEntry;
|
LIST_ENTRY ListEntry;
|
||||||
} IO_COMPLETION_PACKET, *PIO_COMPLETION_PACKET;
|
} IO_COMPLETION_PACKET, *PIO_COMPLETION_PACKET;
|
||||||
|
|
|
@ -271,8 +271,8 @@ NTSTATUS
|
||||||
STDCALL
|
STDCALL
|
||||||
NtRemoveIoCompletion(
|
NtRemoveIoCompletion(
|
||||||
IN HANDLE IoCompletionHandle,
|
IN HANDLE IoCompletionHandle,
|
||||||
OUT PULONG CompletionKey,
|
OUT PVOID *CompletionKey,
|
||||||
OUT PULONG CompletionValue,
|
OUT PVOID *CompletionContext,
|
||||||
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
||||||
IN PLARGE_INTEGER Timeout OPTIONAL
|
IN PLARGE_INTEGER Timeout OPTIONAL
|
||||||
)
|
)
|
||||||
|
@ -302,7 +302,7 @@ NtRemoveIoCompletion(
|
||||||
Packet = CONTAINING_RECORD(ListEntry, IO_COMPLETION_PACKET, ListEntry);
|
Packet = CONTAINING_RECORD(ListEntry, IO_COMPLETION_PACKET, ListEntry);
|
||||||
|
|
||||||
if (CompletionKey) *CompletionKey = Packet->Key;
|
if (CompletionKey) *CompletionKey = Packet->Key;
|
||||||
if (CompletionValue) *CompletionValue = Packet->Overlapped;
|
if (CompletionContext) *CompletionContext = Packet->Context;
|
||||||
if (IoStatusBlock) *IoStatusBlock = Packet->IoStatus;
|
if (IoStatusBlock) *IoStatusBlock = Packet->IoStatus;
|
||||||
|
|
||||||
ExFreeToNPagedLookasideList(&IoCompletionPacketLookaside, Packet);
|
ExFreeToNPagedLookasideList(&IoCompletionPacketLookaside, Packet);
|
||||||
|
@ -330,8 +330,8 @@ NTSTATUS
|
||||||
STDCALL
|
STDCALL
|
||||||
NtSetIoCompletion(
|
NtSetIoCompletion(
|
||||||
IN HANDLE IoCompletionPortHandle,
|
IN HANDLE IoCompletionPortHandle,
|
||||||
IN ULONG CompletionKey,
|
IN PVOID CompletionKey,
|
||||||
IN ULONG CompletionValue,
|
IN PVOID CompletionContext,
|
||||||
IN NTSTATUS CompletionStatus,
|
IN NTSTATUS CompletionStatus,
|
||||||
IN ULONG CompletionInformation
|
IN ULONG CompletionInformation
|
||||||
)
|
)
|
||||||
|
@ -352,7 +352,7 @@ NtSetIoCompletion(
|
||||||
Packet = ExAllocateFromNPagedLookasideList(&IoCompletionPacketLookaside);
|
Packet = ExAllocateFromNPagedLookasideList(&IoCompletionPacketLookaside);
|
||||||
|
|
||||||
Packet->Key = CompletionKey;
|
Packet->Key = CompletionKey;
|
||||||
Packet->Overlapped = CompletionValue;
|
Packet->Context = CompletionContext;
|
||||||
Packet->IoStatus.Status = CompletionStatus;
|
Packet->IoStatus.Status = CompletionStatus;
|
||||||
Packet->IoStatus.Information = CompletionInformation;
|
Packet->IoStatus.Information = CompletionInformation;
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@
|
||||||
#include <ntoskrnl.h>
|
#include <ntoskrnl.h>
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
#include <internal/ps.h>
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
|
/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
|
||||||
|
|
|
@ -873,7 +873,7 @@ typedef struct _FILE_BOTH_DIR_INFORMATION {
|
||||||
|
|
||||||
typedef struct _FILE_COMPLETION_INFORMATION {
|
typedef struct _FILE_COMPLETION_INFORMATION {
|
||||||
HANDLE Port;
|
HANDLE Port;
|
||||||
ULONG Key;
|
PVOID Key;
|
||||||
} FILE_COMPLETION_INFORMATION, *PFILE_COMPLETION_INFORMATION;
|
} FILE_COMPLETION_INFORMATION, *PFILE_COMPLETION_INFORMATION;
|
||||||
|
|
||||||
typedef struct _FILE_COMPRESSION_INFORMATION {
|
typedef struct _FILE_COMPRESSION_INFORMATION {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue