Skip to content

Commit 561bcf2

Browse files
committed
Add more docs + Internal changes
+ Converts nint to FileHandle (backward compatible with previous nint implementation) + Remove duplicates PluginNetworkStream implementation + Rename ABIExtension<T> -> ComWrappersExtension<T> + Rename ComAsyncExtension.WaitFromHandle -> ComAsyncExtension.AsTask + Use ref PluginDisposableMemory<T> on Mem.CreateStringFromNullTerminated() + Revert new Memory<T>() and new Span<T>() creation and use .AsMemory() and .AsSpan() instead.
1 parent 7c13b9b commit 561bcf2

30 files changed

+795
-490
lines changed

ABI/ABI_ILauncherApiWrapper.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace Hi3Helper.Plugin.Core.ABI;
1414
internal sealed unsafe class ABI_ILauncherApiWrapper
1515
{
1616
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvMemberFunction)])]
17-
internal static int ABI_DownloadAssetAsync(ComInterfaceDispatch* thisNative, LauncherPathEntry entry, nint outputStreamHandle, nint downloadProgressNative, Guid* cancelTokenNativeParam, nint* resultNativeParam)
17+
internal static int ABI_DownloadAssetAsync(ComInterfaceDispatch* thisNative, LauncherPathEntry entry, FileHandle outputStreamHandle, nint downloadProgressNative, Guid* cancelTokenNativeParam, nint* resultNativeParam)
1818
{
1919
ref Guid cancelTokenNative = ref *cancelTokenNativeParam;
2020
ref nint resultNative = ref *resultNativeParam;
@@ -40,7 +40,7 @@ internal static int ABI_DownloadAssetAsync(ComInterfaceDispatch* thisNative, Lau
4040
}
4141

4242
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvMemberFunction)])]
43-
internal static int ABI_DownloadAssetAsync(ComInterfaceDispatch* thisNative, ushort* fileUrlNative, nint outputStreamHandle, nint downloadProgressNative, Guid* cancelTokenNativeParam, nint* resultNativeParam)
43+
internal static int ABI_DownloadAssetAsync(ComInterfaceDispatch* thisNative, ushort* fileUrlNative, FileHandle outputStreamHandle, nint downloadProgressNative, Guid* cancelTokenNativeParam, nint* resultNativeParam)
4444
{
4545
ref Guid cancelTokenNative = ref *cancelTokenNativeParam;
4646
ref nint resultNative = ref *resultNativeParam;

ABI/ABI_IPluginPresetConfigWrapper.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ internal static int ABI_comGet_LauncherApiMedia(ComInterfaceDispatch* thisNative
138138
// NotifyForSuccessfulInvoke - Keep alive any managed objects that need to stay alive across the call.
139139
retVal = 0; // S_OK
140140
// Marshal - Convert managed data to native data.
141-
resultNative = ABIExtension<LauncherApiWrappers>.GetComInterfacePtrFromWrappers(result);
141+
resultNative = ComWrappersExtension<LauncherApiWrappers>.GetComInterfacePtrFromWrappers(result);
142142
}
143143
catch (Exception exception)
144144
{
@@ -161,7 +161,7 @@ internal static int ABI_comGet_LauncherApiNews(ComInterfaceDispatch* thisNative,
161161
// NotifyForSuccessfulInvoke - Keep alive any managed objects that need to stay alive across the call.
162162
retVal = 0; // S_OK
163163
// Marshal - Convert managed data to native data.
164-
resultNative = ABIExtension<LauncherApiWrappers>.GetComInterfacePtrFromWrappers(result);
164+
resultNative = ComWrappersExtension<LauncherApiWrappers>.GetComInterfacePtrFromWrappers(result);
165165
}
166166
catch (Exception exception)
167167
{
@@ -184,7 +184,7 @@ internal static int ABI_comGet_GameManager(ComInterfaceDispatch* thisNative, voi
184184
// NotifyForSuccessfulInvoke - Keep alive any managed objects that need to stay alive across the call.
185185
retVal = 0; // S_OK
186186
// Marshal - Convert managed data to native data.
187-
resultNative = ABIExtension<GameManagerWrappers>.GetComInterfacePtrFromWrappers(result);
187+
resultNative = ComWrappersExtension<GameManagerWrappers>.GetComInterfacePtrFromWrappers(result);
188188
}
189189
catch (Exception exception)
190190
{
@@ -207,7 +207,7 @@ internal static int ABI_comGet_GameInstaller(ComInterfaceDispatch* thisNative, v
207207
// NotifyForSuccessfulInvoke - Keep alive any managed objects that need to stay alive across the call.
208208
retVal = 0; // S_OK
209209
// Marshal - Convert managed data to native data.
210-
resultNative = ABIExtension<GameInstallerWrappers>.GetComInterfacePtrFromWrappers(result);
210+
resultNative = ComWrappersExtension<GameInstallerWrappers>.GetComInterfacePtrFromWrappers(result);
211211
}
212212
catch (Exception exception)
213213
{

ABI/ABI_IPluginWrapper.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ internal static int ABI_GetPresetConfig(ComInterfaceDispatch* thisNative, int in
9191
// NotifyForSuccessfulInvoke - Keep alive any managed objects that need to stay alive across the call.
9292
retVal = 0; // S_OK
9393
// Marshal - Convert managed data to native data.
94-
presetConfigNative = ABIExtension<PluginPresetConfigWrappers>.GetComInterfacePtrFromWrappers(presetConfig);
94+
presetConfigNative = ComWrappersExtension<PluginPresetConfigWrappers>.GetComInterfacePtrFromWrappers(presetConfig);
9595
}
9696
catch (Exception exception)
9797
{
@@ -183,7 +183,7 @@ internal static int ABI_GetPluginSelfUpdater(ComInterfaceDispatch* thisNative, v
183183
// NotifyForSuccessfulInvoke - Keep alive any managed objects that need to stay alive across the call.
184184
retVal = 0; // S_OK
185185
// Marshal - Convert managed data to native data.
186-
selfUpdateNative = ABIExtension<PluginSelfUpdateWrappers>.GetComInterfacePtrFromWrappers(selfUpdate);
186+
selfUpdateNative = ComWrappersExtension<PluginSelfUpdateWrappers>.GetComInterfacePtrFromWrappers(selfUpdate);
187187
}
188188
catch (Exception exception)
189189
{

ABI/ABI_VTables.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Hi3Helper.Plugin.Core.Management.Api;
55
using Hi3Helper.Plugin.Core.Management.PresetConfig;
66
using Hi3Helper.Plugin.Core.Update;
7+
using Hi3Helper.Plugin.Core.Utility;
78
using System;
89
using System.Runtime.CompilerServices;
910
using System.Runtime.InteropServices;
@@ -120,8 +121,8 @@ static ABI_VTables()
120121
{
121122
// Inherit IInitializableTask by copying its VTable
122123
NativeMemory.Copy(IInitializableTask, ILauncherApi, (nuint)(sizeof(void*) * 5));
123-
ILauncherApi[5] = (delegate* unmanaged[MemberFunction]<ComInterfaceDispatch*, LauncherPathEntry, nint, nint, Guid*, nint*, int>)&ABI_ILauncherApiWrapper.ABI_DownloadAssetAsync;
124-
ILauncherApi[6] = (delegate* unmanaged[MemberFunction]<ComInterfaceDispatch*, ushort*, nint, nint, Guid*, nint*, int>)&ABI_ILauncherApiWrapper.ABI_DownloadAssetAsync;
124+
ILauncherApi[5] = (delegate* unmanaged[MemberFunction]<ComInterfaceDispatch*, LauncherPathEntry, FileHandle, nint, Guid*, nint*, int>)&ABI_ILauncherApiWrapper.ABI_DownloadAssetAsync;
125+
ILauncherApi[6] = (delegate* unmanaged[MemberFunction]<ComInterfaceDispatch*, ushort*, FileHandle, nint, Guid*, nint*, int>)&ABI_ILauncherApiWrapper.ABI_DownloadAssetAsync;
125126
}
126127

127128
// ILauncherApiMedia

ComAsyncResult.cs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -303,25 +303,19 @@ public static unsafe nint Alloc<T>(Lock threadLock, Task<T> task)
303303

304304
[MethodImpl(MethodImplOptions.AggressiveInlining)]
305305
public static unsafe nint GetWaitHandle(nint handle)
306-
{
307-
ref ComAsyncResult asyncResult = ref Unsafe.AsRef<ComAsyncResult>((void*)handle);
308-
return asyncResult.Handle;
309-
}
306+
=> ((ComAsyncResult*)handle)->Handle;
310307

311308
/// <summary>
312-
/// Dispose/Free the handle of the <see cref="ComAsyncResult"/> struct.
309+
/// Dispose/Free the <see cref="ComAsyncResult"/> struct from its pointer.
313310
/// </summary>
314-
/// <param name="handle">A handle of the <see cref="ComAsyncResult"/> struct.</param>
311+
/// <param name="resultP">A pointer of the <see cref="ComAsyncResult"/> struct.</param>
315312

316313
[MethodImpl(MethodImplOptions.AggressiveInlining)]
317-
public static unsafe void DisposeHandle(nint handle)
318-
{
319-
ref ComAsyncResult asyncResult = ref Unsafe.AsRef<ComAsyncResult>((void*)handle);
320-
asyncResult.Dispose();
321-
}
314+
public static unsafe void FreeResult(nint resultP)
315+
=> ((ComAsyncResult*)resultP)->Dispose();
322316

323317
/// <summary>
324-
/// Dispose this instance of <see cref="ComAsyncResult"/> struct.
318+
/// Dispose this instance of the current <see cref="ComAsyncResult"/> struct.
325319
/// </summary>
326320
public unsafe void Dispose()
327321
{

IInitializableTask.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public partial interface IInitializableTask : IFree
2121
/// <param name="result">A pointer to <see cref="ComAsyncResult"/>.</param>
2222
/// <remarks>
2323
/// This method returns a pointer to <see cref="ComAsyncResult"/> via <c>out</c> <paramref name="result"/>. This method has Return value of <see cref="int"/>.<br/>
24-
/// Please use <see cref="ComAsyncExtension.WaitFromHandle{T}(nint)"/> to get the return value.
24+
/// Please use <see cref="ComAsyncExtension.AsTask{T}(nint)"/> to get the return value.
2525
/// </remarks>
2626
void InitAsync(in Guid cancelToken, out nint result);
2727
}

Management/Api/ILauncherApi.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ public partial interface ILauncherApi : IInitializableTask, IDisposable
3030
/// This method returns a native pointer (<see cref="nint"/>) to a <see cref="ComAsyncResult"/> via <paramref name="result"/> representing the asynchronous operation.
3131
/// </remarks>
3232
void DownloadAssetAsync(LauncherPathEntry entry,
33-
nint outputStreamHandle,
33+
FileHandle outputStreamHandle,
3434
PluginFiles.FileReadProgressDelegate? downloadProgress,
35-
in Guid cancelToken,
35+
in Guid cancelToken,
3636
out nint result);
3737

3838

@@ -47,9 +47,9 @@ void DownloadAssetAsync(LauncherPathEntry entry,
4747
/// <remarks>
4848
/// A native pointer (<see cref="nint"/>) to a <see cref="ComAsyncResult"/> representing the asynchronous operation.
4949
/// </remarks>
50-
void DownloadAssetAsync([MarshalAs(UnmanagedType.LPWStr)] string fileUrl,
51-
nint outputStreamHandle,
52-
PluginFiles.FileReadProgressDelegate? downloadProgress,
53-
in Guid cancelToken,
54-
out nint result);
50+
void DownloadAssetAsync([MarshalAs(UnmanagedType.LPWStr)] string fileUrl,
51+
FileHandle outputStreamHandle,
52+
PluginFiles.FileReadProgressDelegate? downloadProgress,
53+
in Guid cancelToken,
54+
out nint result);
5555
}

Management/Api/LauncherApiBase.cs

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,37 @@
1-
using System;
1+
using Hi3Helper.Plugin.Core.Utility;
2+
using Microsoft.Win32.SafeHandles;
3+
using System;
24
using System.IO;
35
using System.Net.Http;
46
using System.Runtime.InteropServices.Marshalling;
57
using System.Threading;
68
using System.Threading.Tasks;
7-
using Hi3Helper.Plugin.Core.Utility;
8-
using Microsoft.Win32.SafeHandles;
99
// ReSharper disable UnusedMemberInSuper.Global
1010

1111
namespace Hi3Helper.Plugin.Core.Management.Api;
1212

13+
/// <summary>
14+
/// A base class for launcher API related instance (such as: Resource, Media, News, etc.)
15+
/// </summary>
1316
[GeneratedComClass]
1417
public abstract partial class LauncherApiBase : InitializableTask, ILauncherApi
1518
{
1619
protected readonly Lock ThisInstanceLock = new();
1720
protected abstract HttpClient ApiResponseHttpClient { get; set; }
18-
protected abstract string ApiResponseBaseUrl { get; }
1921

2022
protected bool IsDisposed;
2123

24+
/// <inheritdoc/>
2225
public virtual void DownloadAssetAsync(LauncherPathEntry entry,
23-
nint outputStreamHandle,
26+
FileHandle outputStreamHandle,
2427
PluginFiles.FileReadProgressDelegate? downloadProgress,
25-
in Guid cancelToken,
28+
in Guid cancelToken,
2629
out nint result)
2730
{
2831
CancellationTokenSource tokenSource = ComCancellationTokenVault.RegisterToken(in cancelToken);
2932
CancellationToken token = tokenSource.Token;
3033

31-
SafeFileHandle safeFileHandle = new(outputStreamHandle, false);
34+
SafeFileHandle safeFileHandle = new(outputStreamHandle.UnsafeHandle, false);
3235
FileStream outputFileStream = new(safeFileHandle, FileAccess.ReadWrite);
3336

3437
PluginDisposableMemory<byte> fileHash = entry.FileHash;
@@ -41,16 +44,17 @@ public virtual void DownloadAssetAsync(LauncherPathEntry ent
4144
result = DownloadAssetAsyncInner(null, fileUrl, outputFileStream, fileHash, downloadProgress, token).AsResult();
4245
}
4346

47+
/// <inheritdoc/>
4448
public virtual void DownloadAssetAsync(string fileUrl,
45-
nint outputStreamHandle,
49+
FileHandle outputStreamHandle,
4650
PluginFiles.FileReadProgressDelegate? downloadProgress,
47-
in Guid cancelToken,
51+
in Guid cancelToken,
4852
out nint result)
4953
{
5054
CancellationTokenSource tokenSource = ComCancellationTokenVault.RegisterToken(in cancelToken);
5155
CancellationToken token = tokenSource.Token;
5256

53-
SafeFileHandle safeFileHandle = new(outputStreamHandle, false);
57+
SafeFileHandle safeFileHandle = new(outputStreamHandle.UnsafeHandle, false);
5458
FileStream outputFileStream = new(safeFileHandle, FileAccess.ReadWrite);
5559

5660
if (string.IsNullOrEmpty(fileUrl))
@@ -61,6 +65,17 @@ public virtual void DownloadAssetAsync(string fil
6165
result = DownloadAssetAsyncInner(null, fileUrl, outputFileStream, PluginDisposableMemory<byte>.Empty, downloadProgress, token).AsResult();
6266
}
6367

68+
/// <summary>
69+
/// Perform inner asynchronous download operation.
70+
/// </summary>
71+
/// <param name="client"></param>
72+
/// <param name="fileUrl"></param>
73+
/// <param name="outputStream"></param>
74+
/// <param name="fileChecksum"></param>
75+
/// <param name="downloadProgress"></param>
76+
/// <param name="token"></param>
77+
/// <returns></returns>
78+
/// <exception cref="ArgumentNullException"></exception>
6479
protected virtual async Task DownloadAssetAsyncInner(HttpClient? client,
6580
string fileUrl,
6681
Stream outputStream,
@@ -74,20 +89,20 @@ protected virtual async Task DownloadAssetAsyncInner(HttpClient?
7489
throw new ArgumentNullException(nameof(client), "HttpClient cannot be null!");
7590
}
7691

77-
await PluginFiles.DownloadFilesAsync(client, fileUrl, outputStream, downloadProgress, token).ConfigureAwait(false);
92+
await client.DownloadFilesAsync(fileUrl, outputStream, downloadProgress, token: token).ConfigureAwait(false);
7893
}
7994

8095
public override void Free() => Dispose();
8196

8297
public virtual void Dispose()
8398
{
84-
if (IsDisposed)
85-
{
86-
return;
87-
}
88-
8999
using (ThisInstanceLock.EnterScope())
90100
{
101+
if (IsDisposed)
102+
{
103+
return;
104+
}
105+
91106
IsDisposed = true;
92107
ApiResponseHttpClient.Dispose();
93108
ApiResponseHttpClient = null!;

Management/IGameInstaller.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public partial interface IGameInstaller : IGameUninstaller
3737
/// <param name="result">A pointer to the <see cref="ComAsyncResult"/> instance.</param>
3838
/// <remarks>
3939
/// This method returns a pointer to the <see cref="ComAsyncResult"/> instance via <paramref name="result"/>.<br/>
40-
/// The pointer must be passed to <see cref="ComAsyncExtension.WaitFromHandle{T}(nint)"/> and set the generic<br/>
40+
/// The pointer must be passed to <see cref="ComAsyncExtension.AsTask{T}(nint)"/> and set the generic<br/>
4141
/// result to <see cref="long"/> in order to await and get the result from this async function.
4242
/// </remarks>
4343
void GetGameSizeAsync(GameInstallerKind gameInstallerKind, in Guid cancelToken, out nint result);
@@ -50,7 +50,7 @@ public partial interface IGameInstaller : IGameUninstaller
5050
/// <param name="result">A pointer to the <see cref="ComAsyncResult"/> instance.</param>
5151
/// <remarks>
5252
/// This method returns a pointer to the <see cref="ComAsyncResult"/> instance via <paramref name="result"/>.<br/>
53-
/// The pointer must be passed to <see cref="ComAsyncExtension.WaitFromHandle{T}(nint)"/> and set the generic<br/>
53+
/// The pointer must be passed to <see cref="ComAsyncExtension.AsTask{T}(nint)"/> and set the generic<br/>
5454
/// result to <see cref="long"/> in order to await and get the result from this async function.
5555
/// </remarks>
5656
void GetGameDownloadedSizeAsync(GameInstallerKind gameInstallerKind, in Guid cancelToken, out nint result);
@@ -64,7 +64,7 @@ public partial interface IGameInstaller : IGameUninstaller
6464
/// <param name="result">A pointer to the <see cref="ComAsyncResult"/> instance.</param>
6565
/// <remarks>
6666
/// This method returns a pointer to the <see cref="ComAsyncResult"/> instance via <paramref name="result"/>.<br/>
67-
/// The pointer must be passed to <see cref="ComAsyncExtension.WaitFromHandle(nint)"/> in order to await the async function.<br/>
67+
/// The pointer must be passed to <see cref="ComAsyncExtension.AsTask(nint)"/> in order to await the async function.<br/>
6868
/// The function, however is not-returnable.
6969
/// </remarks>
7070
void StartInstallAsync(InstallProgressDelegate? progressDelegate, InstallProgressStateDelegate? progressStateDelegate, in Guid cancelToken, out nint result);
@@ -78,7 +78,7 @@ public partial interface IGameInstaller : IGameUninstaller
7878
/// <param name="result">A pointer to the <see cref="ComAsyncResult"/> instance.</param>
7979
/// <remarks>
8080
/// This method returns a pointer to the <see cref="ComAsyncResult"/> instance via <paramref name="result"/>.<br/>
81-
/// The pointer must be passed to <see cref="ComAsyncExtension.WaitFromHandle(nint)"/> in order to await the async function.<br/>
81+
/// The pointer must be passed to <see cref="ComAsyncExtension.AsTask(nint)"/> in order to await the async function.<br/>
8282
/// The function, however is not-returnable.
8383
/// </remarks>
8484
void StartUpdateAsync(InstallProgressDelegate? progressDelegate, InstallProgressStateDelegate? progressStateDelegate, in Guid cancelToken, out nint result);
@@ -92,7 +92,7 @@ public partial interface IGameInstaller : IGameUninstaller
9292
/// <param name="result">A pointer to the <see cref="ComAsyncResult"/> instance.</param>
9393
/// <remarks>
9494
/// This method returns a pointer to the <see cref="ComAsyncResult"/> instance via <paramref name="result"/>.<br/>
95-
/// The pointer must be passed to <see cref="ComAsyncExtension.WaitFromHandle(nint)"/> in order to await the async function.<br/>
95+
/// The pointer must be passed to <see cref="ComAsyncExtension.AsTask(nint)"/> in order to await the async function.<br/>
9696
/// The function, however is not-returnable.
9797
/// </remarks>
9898
void StartPreloadAsync(InstallProgressDelegate? progressDelegate, InstallProgressStateDelegate? progressStateDelegate, in Guid cancelToken, out nint result);

Management/IGameManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public partial interface IGameManager : IInitializableTask, IDisposable
8888
/// <param name="cancelToken">A <see cref="Guid"/> value token for the cancelling asynchronous operation.</param>
8989
/// <remarks>
9090
/// This method returns a safe pointer to the <see cref="ComAsyncResult"/> via <paramref name="result"/>.<br/>
91-
/// The pointer needs to be passed to <see cref="ComAsyncExtension.WaitFromHandle{T}(nint)"/> and the generic type must be <see cref="PluginDisposableMemoryMarshal"/> of <see cref="byte"/>
91+
/// The pointer needs to be passed to <see cref="ComAsyncExtension.AsTask{T}(nint)"/> and the generic type must be <see cref="PluginDisposableMemoryMarshal"/> of <see cref="byte"/>
9292
/// </remarks>
9393
void FindExistingInstallPathAsync(in Guid cancelToken, out nint result);
9494
}

0 commit comments

Comments
 (0)