This repository was archived by the owner on Jul 26, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 228
Add DeviceIoControlAsync helper method #504
Merged
AArnott
merged 9 commits into
dotnet:master
from
qmfrederik:features/device-io-control-async
Jul 12, 2020
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
4d17067
Prototype DeviceIoControlAsync
qmfrederik 68a0c7f
Expose async I/O on net45/netstandard2.0 too
AArnott c2ab5a3
Simplify usage pattern
AArnott aabe082
Add unit test for DeviceIOControl where the operation completes synch…
qmfrederik 9da6baf
StyleCop, PublicAPI fixes
qmfrederik efb6e8a
DeviceIoControlAsync: Use ValueTask, test excetpion path
qmfrederik 4929289
Update PublicAPI, add documentation
qmfrederik dd1267b
Add generic type documentation
qmfrederik f20061d
Use temp file in unit tests
qmfrederik File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,12 @@ | ||
<Project Sdk="MSBuild.Sdk.Extras"> | ||
<PropertyGroup> | ||
<TargetFrameworks>$(PlatformAndPortableFrameworks)</TargetFrameworks> | ||
<TargetFrameworks>$(PlatformAndPortableFrameworks);net46</TargetFrameworks> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<ProjectReference Include="..\Windows.Core\Windows.Core.csproj" /> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<PackageReference Include="System.Memory" Version="4.5.4" /> | ||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" /> | ||
</ItemGroup> | ||
</Project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
135 changes: 135 additions & 0 deletions
135
src/Kernel32/storebanned/Kernel32+DeviceIOControlOverlapped.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
// Copyright © .NET Foundation and Contributors. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
namespace PInvoke | ||
{ | ||
using System; | ||
using System.Buffers; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
/// <content> | ||
/// Contains the <see cref="CreateFileFlags"/> nested type. | ||
/// </content> | ||
public partial class Kernel32 | ||
{ | ||
private class DeviceIOControlOverlapped<TInput, TOutput> : Overlapped | ||
where TInput : struct | ||
where TOutput : struct | ||
{ | ||
private readonly Memory<TInput> input; | ||
private readonly Memory<TOutput> output; | ||
|
||
/// <summary> | ||
/// The source for completing the <see cref="Completion"/> property. | ||
/// </summary> | ||
private readonly TaskCompletionSource<uint> completion = new TaskCompletionSource<uint>(); | ||
|
||
private unsafe NativeOverlapped* native; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="DeviceIOControlOverlapped{TInput, TOutput}"/> class. | ||
/// </summary> | ||
/// <param name="input"> | ||
/// The input buffer. | ||
/// </param> | ||
/// <param name="output"> | ||
/// The output buffer. | ||
/// </param> | ||
internal DeviceIOControlOverlapped(Memory<TInput> input, Memory<TOutput> output) | ||
{ | ||
this.input = input; | ||
this.output = output; | ||
} | ||
|
||
/// <summary> | ||
/// Gets a <see cref="MemoryHandle"/> to the input buffer. | ||
/// </summary> | ||
internal MemoryHandle InputHandle { get; private set; } | ||
|
||
/// <summary> | ||
/// Gets a <see cref="MemoryHandle"/> to the output buffer. | ||
/// </summary> | ||
internal MemoryHandle OutputHandle { get; private set; } | ||
|
||
/// <summary> | ||
/// Gets the amount of bytes written. | ||
/// </summary> | ||
internal uint BytesWritten { get; private set; } | ||
|
||
/// <summary> | ||
/// Gets the error code returned by the device driver. | ||
/// </summary> | ||
internal uint ErrorCode { get; private set; } | ||
|
||
/// <summary> | ||
/// Gets a task whose result is the number of bytes transferred, or faults with the <see cref="Win32Exception"/> describing the failure. | ||
/// </summary> | ||
internal Task<uint> Completion => this.completion.Task; | ||
|
||
/// <summary> | ||
/// Packs the current instance of the <see cref="DeviceIOControlOverlapped{TInput, TOutput}"/> into a <see cref="NativeOverlapped"/> | ||
/// structure and pins the input and output buffers. | ||
/// </summary> | ||
/// <returns> | ||
/// A <see cref="NativeOverlapped"/> structure which can be used to call <see cref="Kernel32.DeviceIoControl(Kernel32.SafeObjectHandle, int, void*, int, void*, int, out int, Kernel32.OVERLAPPED*)"/>. | ||
/// </returns> | ||
internal unsafe NativeOverlapped* Pack() | ||
{ | ||
this.InputHandle = this.input.Pin(); | ||
this.OutputHandle = this.output.Pin(); | ||
|
||
this.native = this.Pack( | ||
this.DeviceIOControlCompletionCallback, | ||
null); | ||
|
||
return this.native; | ||
} | ||
|
||
/// <summary> | ||
/// Unpacks the <see cref="NativeOverlapped"/> structure associated with this <see cref="DeviceIOControlOverlapped{TInput, TOutput}"/> | ||
/// instance, frees the native memory used and unpins the input and output buffers. | ||
/// </summary> | ||
internal unsafe void Unpack() | ||
{ | ||
Overlapped.Unpack(this.native); | ||
Overlapped.Free(this.native); | ||
this.native = null; | ||
|
||
this.InputHandle.Dispose(); | ||
this.OutputHandle.Dispose(); | ||
} | ||
|
||
/// <summary> | ||
/// A callback which is invoked once the asynchronous I/O operation completes. | ||
/// </summary> | ||
/// <param name="errorCode"> | ||
/// The error code returned by the device driver. | ||
/// </param> | ||
/// <param name="numberOfBytesTransferred"> | ||
/// The number of bytes transferred. | ||
/// </param> | ||
/// <param name="nativeOverlapped"> | ||
/// A <see cref="NativeOverlapped"/> object representing an unmanaged pointer to the | ||
/// native overlapped value type. | ||
/// </param> | ||
private unsafe void DeviceIOControlCompletionCallback(uint errorCode, uint numberOfBytesTransferred, NativeOverlapped* nativeOverlapped) | ||
{ | ||
this.Unpack(); | ||
|
||
this.BytesWritten = numberOfBytesTransferred; | ||
this.ErrorCode = errorCode; | ||
|
||
if (this.ErrorCode != 0) | ||
{ | ||
this.completion.SetException( | ||
new Win32Exception((int)this.ErrorCode)); | ||
} | ||
else | ||
{ | ||
this.completion.SetResult(numberOfBytesTransferred); | ||
} | ||
} | ||
} | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
src/Kernel32/storebanned/Kernel32+FILE_ZERO_DATA_INFORMATION.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Copyright © .NET Foundation and Contributors. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
namespace PInvoke | ||
{ | ||
using System; | ||
|
||
/// <content> | ||
/// Contains the <see cref="FILE_ZERO_DATA_INFORMATION "/> nested type. | ||
/// </content> | ||
public partial class Kernel32 | ||
{ | ||
/// <summary> | ||
/// Contains a range of a file to set to zeros. This structure is used by the <c>FSCTL_SET_ZERO_DATA</c> control code. | ||
/// </summary> | ||
public struct FILE_ZERO_DATA_INFORMATION | ||
{ | ||
/// <summary> | ||
/// The file offset of the start of the range to set to zeros, in bytes. | ||
/// </summary> | ||
public long FileOffset; | ||
|
||
/// <summary> | ||
/// The byte offset of the first byte beyond the last zeroed byte. | ||
/// </summary> | ||
public long BeyondFinalZero; | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity, since this constructor (and the properties below) are defined on a
class
which isprivate
toKernel32
, is there any difference between marking it aspublic
orinternal
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are subtle differences in Reflection, but the main reason is because
public
triggers "public API review" mode in my mind as public APIs are very hard to change later, and these are in fact not public APIs. The C#public
keyword inprivate
orinternal
types are in fact not public at all (unless they also implement an interface). So it's a misleading keyword to use, and makes code reviews more expensive. So I preferinternal
for members of non-public types instead ofpublic
.