diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c index 64d5ba9f44d..3256c59b3e7 100644 --- a/dlls/ntdll/directory.c +++ b/dlls/ntdll/directory.c @@ -2168,8 +2168,18 @@ struct read_changes_info HANDLE FileHandle; PVOID Buffer; ULONG BufferSize; + PIO_APC_ROUTINE apc; + void *apc_arg; }; +/* callback for ioctl user APC */ +static void WINAPI read_changes_user_apc( void *arg, IO_STATUS_BLOCK *io, ULONG reserved ) +{ + struct read_changes_info *info = arg; + if (info->apc) info->apc( info->apc_arg, io, reserved ); + RtlFreeHeap( GetProcessHeap(), 0, info ); +} + static NTSTATUS read_changes_apc( void *user, PIO_STATUS_BLOCK iosb, NTSTATUS status ) { struct read_changes_info *info = user; @@ -2221,8 +2231,6 @@ static NTSTATUS read_changes_apc( void *user, PIO_STATUS_BLOCK iosb, NTSTATUS st iosb->u.Status = ret; iosb->Information = len; - - RtlFreeHeap( GetProcessHeap(), 0, info ); return ret; } @@ -2265,6 +2273,8 @@ NtNotifyChangeDirectoryFile( HANDLE FileHandle, HANDLE Event, info->FileHandle = FileHandle; info->Buffer = Buffer; info->BufferSize = BufferSize; + info->apc = ApcRoutine; + info->apc_arg = ApcContext; SERVER_START_REQ( read_directory_changes ) { @@ -2275,8 +2285,8 @@ NtNotifyChangeDirectoryFile( HANDLE FileHandle, HANDLE Event, req->async.callback = read_changes_apc; req->async.iosb = IoStatusBlock; req->async.arg = info; - req->async.apc = ApcRoutine; - req->async.apc_arg = ApcContext; + req->async.apc = read_changes_user_apc; + req->async.apc_arg = info; req->async.event = Event; status = wine_server_call( req ); } diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index dc397357b2f..7c166a9c3ee 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -237,9 +237,16 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB * Asynchronous file I/O * */ -typedef struct +struct async_fileio { HANDLE handle; + PIO_APC_ROUTINE apc; + void *apc_arg; +}; + +typedef struct +{ + struct async_fileio io; char* buffer; unsigned int already; unsigned int count; @@ -248,13 +255,21 @@ typedef struct typedef struct { - HANDLE handle; + struct async_fileio io; const char *buffer; unsigned int already; unsigned int count; } async_fileio_write; +/* callback for file I/O user APC */ +static void WINAPI fileio_apc( void *arg, IO_STATUS_BLOCK *io, ULONG reserved ) +{ + struct async_fileio *async = arg; + if (async->apc) async->apc( async->apc_arg, io, reserved ); + RtlFreeHeap( GetProcessHeap(), 0, async ); +} + /*********************************************************************** * FILE_GetNtStatus(void) * @@ -315,7 +330,7 @@ static NTSTATUS FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, NTSTATU { case STATUS_ALERTED: /* got some new data */ /* check to see if the data is ready (non-blocking) */ - if ((status = server_get_unix_fd( fileio->handle, FILE_READ_DATA, &fd, + if ((status = server_get_unix_fd( fileio->io.handle, FILE_READ_DATA, &fd, &needs_close, NULL, NULL ))) break; @@ -365,7 +380,6 @@ static NTSTATUS FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, NTSTATU { iosb->u.Status = status; iosb->Information = fileio->already; - RtlFreeHeap( GetProcessHeap(), 0, fileio ); } return status; } @@ -608,7 +622,9 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, status = STATUS_NO_MEMORY; goto done; } - fileio->handle = hFile; + fileio->io.handle = hFile; + fileio->io.apc = apc; + fileio->io.apc_arg = apc_user; fileio->already = total; fileio->count = length; fileio->buffer = buffer; @@ -622,8 +638,8 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, req->async.callback = FILE_AsyncReadService; req->async.iosb = io_status; req->async.arg = fileio; - req->async.apc = apc; - req->async.apc_arg = apc_user; + req->async.apc = fileio_apc; + req->async.apc_arg = fileio; req->async.event = hEvent; status = wine_server_call( req ); } @@ -701,7 +717,7 @@ static NTSTATUS FILE_AsyncWriteService(void *user, IO_STATUS_BLOCK *iosb, NTSTAT { case STATUS_ALERTED: /* write some data (non-blocking) */ - if ((status = server_get_unix_fd( fileio->handle, FILE_WRITE_DATA, &fd, + if ((status = server_get_unix_fd( fileio->io.handle, FILE_WRITE_DATA, &fd, &needs_close, &type, NULL ))) break; @@ -734,7 +750,6 @@ static NTSTATUS FILE_AsyncWriteService(void *user, IO_STATUS_BLOCK *iosb, NTSTAT { iosb->u.Status = status; iosb->Information = fileio->already; - RtlFreeHeap( GetProcessHeap(), 0, fileio ); } return status; } @@ -842,7 +857,9 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent, status = STATUS_NO_MEMORY; goto done; } - fileio->handle = hFile; + fileio->io.handle = hFile; + fileio->io.apc = apc; + fileio->io.apc_arg = apc_user; fileio->already = total; fileio->count = length; fileio->buffer = buffer; @@ -855,8 +872,8 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent, req->async.callback = FILE_AsyncWriteService; req->async.iosb = io_status; req->async.arg = fileio; - req->async.apc = apc; - req->async.apc_arg = apc_user; + req->async.apc = fileio_apc; + req->async.apc_arg = fileio; req->async.event = hEvent; status = wine_server_call( req ); } @@ -920,9 +937,11 @@ done: struct async_ioctl { - HANDLE handle; /* handle to the device */ - void *buffer; /* buffer for output */ - ULONG size; /* size of buffer */ + HANDLE handle; /* handle to the device */ + void *buffer; /* buffer for output */ + ULONG size; /* size of buffer */ + PIO_APC_ROUTINE apc; /* user apc params */ + void *apc_arg; }; /* callback for ioctl async I/O completion */ @@ -942,14 +961,18 @@ static NTSTATUS ioctl_completion( void *arg, IO_STATUS_BLOCK *io, NTSTATUS statu } SERVER_END_REQ; } - if (status != STATUS_PENDING) - { - RtlFreeHeap( GetProcessHeap(), 0, async ); - io->u.Status = status; - } + if (status != STATUS_PENDING) io->u.Status = status; return status; } +/* callback for ioctl user APC */ +static void WINAPI ioctl_apc( void *arg, IO_STATUS_BLOCK *io, ULONG reserved ) +{ + struct async_ioctl *async = arg; + if (async->apc) async->apc( async->apc_arg, io, reserved ); + RtlFreeHeap( GetProcessHeap(), 0, async ); +} + /* do a ioctl call through the server */ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, PVOID apc_context, @@ -964,9 +987,11 @@ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event, if (!(async = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*async) ))) return STATUS_NO_MEMORY; - async->handle = handle; - async->buffer = out_buffer; - async->size = out_size; + async->handle = handle; + async->buffer = out_buffer; + async->size = out_size; + async->apc = apc; + async->apc_arg = apc_context; SERVER_START_REQ( ioctl ) { @@ -975,8 +1000,8 @@ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event, req->async.callback = ioctl_completion; req->async.iosb = io; req->async.arg = async; - req->async.apc = apc; - req->async.apc_arg = apc_context; + req->async.apc = (apc || event) ? ioctl_apc : NULL; + req->async.apc_arg = async; req->async.event = event; wine_server_add_data( req, in_buffer, in_size ); wine_server_set_reply( req, out_buffer, out_size ); @@ -998,6 +1023,7 @@ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event, NtWaitForSingleObject( wait_handle, (options & FILE_SYNCHRONOUS_IO_ALERT), NULL ); status = io->u.Status; NtClose( wait_handle ); + RtlFreeHeap( GetProcessHeap(), 0, async ); } return status;