Compare commits

...

13 Commits

20 changed files with 276 additions and 73 deletions

View File

@ -1,9 +1,10 @@
<Project>
<PropertyGroup>
<Version>4.0.0-beta2</Version>
<TargetFrameworks>net45;net48;net6.0;net7.0;net8.0-windows;netstandard2.0;netcoreapp3.1</TargetFrameworks>
<Configurations>Debug;Release</Configurations>
<Platforms>AnyCPU;x64;x86</Platforms>
<Version>4.0.0-beta2</Version>
<PackageVersion>4.0.0-beta2</PackageVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using Vanara.Extensions.Reflection;
namespace Vanara.PInvoke;
@ -780,7 +781,7 @@ public static partial class FwpUClnt
/// <para>The GUID for a valid callout in the layer.</para>
/// <para>Available when the action invokes a callout, that is, <c>type</c> contains <c>FWP_ACTION_FLAG_CALLOUT</c>.</para>
/// </summary>
public Guid calloutKey;
public Guid calloutKey { get => filterType; set => filterType = value; }
}
/// <summary>The <c>FWPM_CALLOUT_CHANGE0</c> structure specifies a change notification dispatched to subscribers.</summary>
@ -1547,7 +1548,11 @@ public static partial class FwpUClnt
/// documented in the WDK.
/// </para>
/// </summary>
public ulong rawContext;
public ulong rawContext
{
get => BitConverter.ToUInt64(providerContextKey.ToByteArray(), 0);
set { var bytes = BitConverter.GetBytes(value); Array.Resize(ref bytes, 16); providerContextKey = new Guid(bytes); }
}
/// <summary>
/// <para>

View File

@ -1013,19 +1013,4 @@ public static partial class IMAPI
/// </summary>
IMAPI_READ_TRACK_ADDRESS_TYPE_SESSION,
}
internal class SafeArrayMarshaler<T> : ICustomMarshaler
{
public static ICustomMarshaler GetInstance(string cookie) => new SafeArrayMarshaler<T>();
void ICustomMarshaler.CleanUpManagedData(object ManagedObj) { }
void ICustomMarshaler.CleanUpNativeData(IntPtr pNativeData) => SafeArrayDestroy(pNativeData);
int ICustomMarshaler.GetNativeDataSize() => -1;
IntPtr ICustomMarshaler.MarshalManagedToNative(object ManagedObj) => throw new NotImplementedException();
object ICustomMarshaler.MarshalNativeToManaged(IntPtr pNativeData)
{
var sa = new SafeSAFEARRAY(pNativeData, false);
return sa.ToArray().Cast<T>().ToArray();
}
}
}

View File

@ -2,6 +2,7 @@ using System.Collections;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.InteropServices.CustomMarshalers;
using static Vanara.PInvoke.OleAut32;
namespace Vanara.PInvoke;
@ -913,7 +914,7 @@ public static partial class IMAPI
// https://docs.microsoft.com/en-us/windows/win32/api/imapi2/nf-imapi2-idiscformat2data-get_multisessioninterfaces HRESULT
// get_MultisessionInterfaces( SAFEARRAY **value );
[DispId(280)]
IMultisession[] MultisessionInterfaces { [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(SafeArrayMarshaler<IMultisession>))] get; }
object[] MultisessionInterfaces { get; }
/// <summary>Writes the data stream to the device.</summary>
/// <param name="data">An <c>IStream</c> interface of the data stream to write.</param>

View File

@ -4,6 +4,7 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.InteropServices.CustomMarshalers;
using Vanara.Collections;
using static Vanara.PInvoke.OleAut32;
namespace Vanara.PInvoke;
@ -1122,7 +1123,7 @@ public static partial class IMAPI
// https://docs.microsoft.com/en-us/windows/win32/api/imapi2fs/nf-imapi2fs-ifilesystemimage-get_multisessioninterfaces HRESULT
// get_MultisessionInterfaces( SAFEARRAY **pVal );
[DispId(40)]
IMultisession[] MultisessionInterfaces { [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(SafeArrayMarshaler<IMultisession>))] get; set; }
object[] MultisessionInterfaces { get; set; }
}
/// <summary>
@ -1639,7 +1640,8 @@ public static partial class IMAPI
// https://docs.microsoft.com/en-us/windows/win32/api/imapi2fs/nf-imapi2fs-ifilesystemimage-get_multisessioninterfaces HRESULT
// get_MultisessionInterfaces( SAFEARRAY **pVal );
[DispId(40)]
new IMultisession[] MultisessionInterfaces { [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(SafeArrayMarshaler<IMultisession>))] get; set; }
//new IMultisession[] MultisessionInterfaces { [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(SafeArrayMarshaler<IMultisession>))] get; set; }
new object[] MultisessionInterfaces { get; set; }
/// <summary>Retrieves the boot option array that will be utilized to generate the file system image.</summary>
/// <value>
@ -1652,7 +1654,8 @@ public static partial class IMAPI
// https://docs.microsoft.com/en-us/windows/win32/api/imapi2fs/nf-imapi2fs-ifilesystemimage2-get_bootimageoptionsarray HRESULT
// get_BootImageOptionsArray( SAFEARRAY **pVal );
[DispId(60)]
IBootOptions[] BootImageOptionsArray { [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(SafeArrayMarshaler<IBootOptions>))] get; set; }
//IBootOptions[] BootImageOptionsArray { [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(SafeArrayMarshaler<IBootOptions>))] get; set; }
object[] BootImageOptionsArray { get; set; }
}
/// <summary>
@ -2175,7 +2178,8 @@ public static partial class IMAPI
// https://docs.microsoft.com/en-us/windows/win32/api/imapi2fs/nf-imapi2fs-ifilesystemimage-get_multisessioninterfaces HRESULT
// get_MultisessionInterfaces( SAFEARRAY **pVal );
[DispId(40)]
new IMultisession[] MultisessionInterfaces { [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(SafeArrayMarshaler<IMultisession>))] get; set; }
//new IMultisession[] MultisessionInterfaces { [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(SafeArrayMarshaler<IMultisession>))] get; set; }
new object[] MultisessionInterfaces { get; set; }
/// <summary>Retrieves the boot option array that will be utilized to generate the file system image.</summary>
/// <value>
@ -2188,7 +2192,8 @@ public static partial class IMAPI
// https://docs.microsoft.com/en-us/windows/win32/api/imapi2fs/nf-imapi2fs-ifilesystemimage2-get_bootimageoptionsarray HRESULT
// get_BootImageOptionsArray( SAFEARRAY **pVal );
[DispId(60)]
new IBootOptions[] BootImageOptionsArray { [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(SafeArrayMarshaler<IBootOptions>))] get; set; }
//new IBootOptions[] BootImageOptionsArray { [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(SafeArrayMarshaler<IBootOptions>))] get; set; }
new object[] BootImageOptionsArray { get; set; }
/// <summary>Retrieves a property value that specifies if the UDF Metadata will be redundant in the file system image.</summary>
/// <value>

View File

@ -422,28 +422,39 @@ public static partial class IpHlpApi
// _MIB_UDPROW_OWNER_PID { DWORD dwLocalAddr; DWORD dwLocalPort; DWORD dwOwningPid; } MIB_UDPROW_OWNER_PID, *PMIB_UDPROW_OWNER_PID;
[PInvokeData("udpmib.h", MSDNShortId = "b914b6eb-adf9-4a61-ae8f-05d3ff90ce90")]
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct MIB_UDPROW_OWNER_PID
public struct MIB_UDPROW_OWNER_PID : IComparable, IComparable<MIB_UDPROW_OWNER_PID>
{
/// <summary>
/// <para>The IPv4 address of the UDP endpoint on the local computer.</para>
/// <para>
/// A value of zero indicates a UDP listener willing to accept datagrams for any IP interface associated with the local computer.
/// </para>
/// <para>A value of zero indicates a UDP listener willing to accept datagrams for any IP interface associated with the local computer.</para>
/// </summary>
public IN_ADDR dwLocalAddr;
/// <summary>
/// <para>The port number of the UDP endpoint on the local computer. This member is stored in network byte order.</para>
/// </summary>
/// <summary>The port number of the UDP endpoint on the local computer. This member is stored in network byte order.</summary>
public uint dwLocalPort;
/// <summary>
/// <para>
/// The PID of the process that issued the call to the bind function for the UDP endpoint. This member is set to 0 when the PID
/// is unavailable.
/// </para>
/// The PID of the process that issued the call to the bind function for the UDP endpoint. This member is set to 0 when the PID is unavailable.
/// </summary>
public uint dwOwningPid;
/// <summary>The port number of the UDP endpoint on the local computer. This member is in host byte order.</summary>
public ushort dwHostLocalPort { readonly get => ntohs((ushort)dwLocalPort); set => dwLocalPort = htons(value); }
/// <inheritdoc/>
readonly int IComparable<MIB_UDPROW_OWNER_PID>.CompareTo(MIB_UDPROW_OWNER_PID p)
{
var cmp = ((IComparable<IN_ADDR>)dwLocalAddr).CompareTo(p.dwLocalAddr);
if (cmp == 0)
cmp = dwHostLocalPort.CompareTo(p.dwHostLocalPort);
if (cmp == 0)
cmp = dwOwningPid.CompareTo(p.dwOwningPid);
return cmp;
}
/// <inheritdoc/>
readonly int IComparable.CompareTo(object? obj) => obj is MIB_UDPROW_OWNER_PID i ? ((IComparable<MIB_UDPROW_OWNER_PID>)this).CompareTo(i) :
(obj is null ? 1 : throw new ArgumentException("Invalid type for comparison.", nameof(obj)));
}
/// <summary>

View File

@ -638,13 +638,19 @@ public static partial class Kernel32
/// The ReadDirectoryChangesExW function should provide information that describes the changes within the specified directory,
/// and return this information in the output buffer in the form of FILE_NOTIFY_INFORMATION structures.
/// </summary>
ReadDirectoryNotifyInformation,
ReadDirectoryNotifyInformation = 1,
/// <summary>
/// The ReadDirectoryChangesExW function should provide extended information that describes the changes within the specified
/// directory, and return this information in the output buffer in the form of FILE_NOTIFY_EXTENDED_INFORMATION structures.
/// </summary>
ReadDirectoryNotifyExtendedInformation,
/// <summary/>
ReadDirectoryNotifyFullInformation,
/// <summary/>
ReadDirectoryNotifyMaximumInformation
}
/// <summary>Flags used by <see cref="FILE_REMOTE_PROTOCOL_INFO"/>.</summary>

View File

@ -1369,7 +1369,7 @@ public static partial class OleAut32
// *psa, LONG *rgIndices, void *pv );
[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("oleauto.h", MSDNShortId = "7c837b4f-d319-4d98-934a-b585fe521bf8")]
public static extern HRESULT SafeArrayPutElement(SafeSAFEARRAY psa, [MarshalAs(UnmanagedType.LPArray)] int[] rgIndices, [In, MarshalAs(UnmanagedType.Struct)] object pv);
public static extern HRESULT SafeArrayPutElement(SafeSAFEARRAY psa, [MarshalAs(UnmanagedType.LPArray)] int[] rgIndices, [In, MarshalAs(UnmanagedType.Struct)] object? pv);
/// <summary>
/// <para>Stores the data element at the specified location in the array.</para>
@ -1430,7 +1430,7 @@ public static partial class OleAut32
// *psa, LONG *rgIndices, void *pv );
[DllImport(Lib.OleAut32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("oleauto.h", MSDNShortId = "7c837b4f-d319-4d98-934a-b585fe521bf8")]
public static extern HRESULT SafeArrayPutElement(SafeSAFEARRAY psa, in int rgIndices, [In, MarshalAs(UnmanagedType.Struct)] object pv);
public static extern HRESULT SafeArrayPutElement(SafeSAFEARRAY psa, in int rgIndices, [In, MarshalAs(UnmanagedType.Struct)] object? pv);
/// <summary>
/// <para>Stores the data element at the specified location in the array.</para>
@ -1935,6 +1935,15 @@ public static partial class OleAut32
/// </remarks>
public VARTYPE VarType { get { SafeArrayGetVartype(this, out VARTYPE vt).ThrowIfFailed(); return vt; } }
/// <summary>Gets or sets the <see cref="object"/> at the specified index.</summary>
/// <value>The <see cref="object"/>.</value>
/// <param name="index">The index.</param>
public object? this[int index]
{
get => GetValue(index);
set => SetValue(value, index);
}
/// <summary>Creates a SAFEARRAY from a .NET array.</summary>
/// <param name="array">
/// The array used to initialize the SAFEARRAY. This can be a single or multi-dimensional array, but cannot be a jagged array
@ -1946,6 +1955,8 @@ public static partial class OleAut32
{
Type elemType = array.GetType().GetElementType()!;
if (elemType.IsArray) throw new ArgumentException("Input array cannot be jagged.", nameof(array));
if (elemType.IsCOMObject || elemType.IsImport && elemType.IsInterface) elementVarType = VARTYPE.VT_UNKNOWN;
// Create list of bounds in reverse
SAFEARRAYBOUND[] bounds = new SAFEARRAYBOUND[array.Rank];
for (int d = 0; d < bounds.Length; d++)
@ -1953,7 +1964,7 @@ public static partial class OleAut32
// Create safe array
SafeSAFEARRAY sa = SafeArrayCreate(elementVarType, (uint)array.Rank, bounds);
// Copy values
if (elemType == typeof(object))
if (elemType == typeof(object) || elementVarType == VARTYPE.VT_UNKNOWN)
{
switch (elementVarType)
{
@ -2175,7 +2186,7 @@ public static partial class OleAut32
/// <param name="value">The new value for the specified element.</param>
/// <param name="index">A 32-bit integer that represents the position of the Array element to set.</param>
/// <exception cref="ArgumentException">To take objects, the SAFEARRAY must be for VARIANTS.</exception>
public void SetValue(object value, int index)
public void SetValue(object? value, int index)
{
if (VarType != VARTYPE.VT_VARIANT)
throw new ArgumentException("To take objects, the SAFEARRAY must be for VARIANTS.");
@ -2192,7 +2203,7 @@ public static partial class OleAut32
/// <para>The order of the indices follows .NET <see cref="Array"/> order and not the backwards ordering imposed by <c>SafeArrayGetElement</c>.</para>
/// </param>
/// <exception cref="ArgumentException">To take objects, the SAFEARRAY must be for VARIANTS.</exception>
public void SetValue(object value, params int[] indices)
public void SetValue(object? value, params int[] indices)
{
if (VarType != VARTYPE.VT_VARIANT)
throw new ArgumentException("To take objects, the SAFEARRAY must be for VARIANTS.");
@ -2244,14 +2255,7 @@ public static partial class OleAut32
object eTypeVal = Activator.CreateInstance(eType)!;
// Get details and build Array instance
int dims = Rank;
SAFEARRAYBOUND[] bounds = new SAFEARRAYBOUND[dims];
for (int i = 1; i <= dims; i++)
{
_ = SafeArrayGetLBound(this, (uint)i, out int lb);
_ = SafeArrayGetUBound(this, (uint)i, out int ub);
bounds[dims - i] = new SAFEARRAYBOUND(ub, lb);
}
SAFEARRAYBOUND[] bounds = GetBounds();
Array ret = Array.CreateInstance(eType, Array.ConvertAll(bounds, b => (int)b.cElements), Array.ConvertAll(bounds, b => b.lLbound));
// Fill in values
@ -2310,7 +2314,21 @@ public static partial class OleAut32
public HRESULT Unlock() => SafeArrayUnlock(this);
/// <inheritdoc/>
protected override bool InternalReleaseHandle() => SafeArrayDestroy(handle).Succeeded;
protected override bool InternalReleaseHandle()
{
// Release all conversions from COM objects to pointers
if (VarType is VARTYPE.VT_UNKNOWN or VARTYPE.VT_DISPATCH)
{
using SafeCoTaskMemHandle mem = new(SafeArrayGetElemsize(this));
foreach ((int[] from, int[] _) in BuildIndexList(GetBounds()))
{
SafeArrayGetElement(this, from, mem).ThrowIfFailed();
unsafe { VARIANT* pVar = (VARIANT*)mem.DangerousGetHandle(); Marshal.Release(pVar->byref); }
}
}
// Release the array
return SafeArrayDestroy(handle).Succeeded;
}
private static IEnumerable<(int[] from, int[] to)> BuildIndexList(SAFEARRAYBOUND[] bounds)
{
@ -2336,7 +2354,59 @@ public static partial class OleAut32
}
}
private SAFEARRAYBOUND[] GetBounds()
{
int dims = Rank;
SAFEARRAYBOUND[] bounds = new SAFEARRAYBOUND[dims];
for (int i = 1; i <= dims; i++)
{
_ = SafeArrayGetLBound(this, (uint)i, out int lb);
_ = SafeArrayGetUBound(this, (uint)i, out int ub);
bounds[dims - i] = new SAFEARRAYBOUND(ub, lb);
}
return bounds;
}
/// <inheritdoc/>
IEnumerator IEnumerable.GetEnumerator() => ToArray().GetEnumerator();
}
/// <summary>Custom marshaler for SAFEARRAY types. This marshaler is used to marshal SAFEARRAY types to and from managed code.</summary>
/// <typeparam name="T">The type of the array element.</typeparam>
public class SafeArrayMarshaler<T> : ICustomMarshaler
{
/// <inheritdoc/>
public static ICustomMarshaler GetInstance(string cookie) => new SafeArrayMarshaler<T>();
private static readonly Dictionary<object, SafeSAFEARRAY> store = [];
/// <inheritdoc/>
void ICustomMarshaler.CleanUpManagedData(object ManagedObj) { if (ManagedObj is not null) store.Remove(ManagedObj); }
/// <inheritdoc/>
void ICustomMarshaler.CleanUpNativeData(IntPtr pNativeData) => SafeArrayDestroy(pNativeData);
/// <inheritdoc/>
int ICustomMarshaler.GetNativeDataSize() => -1;
/// <inheritdoc/>
IntPtr ICustomMarshaler.MarshalManagedToNative(object ManagedObj)
{
if (ManagedObj is null) return IntPtr.Zero;
if (ManagedObj.GetType().IsArray)
{
var sa = SafeSAFEARRAY.CreateFromArray((Array)ManagedObj, Ole32.PROPVARIANT.GetVarType(ManagedObj.GetType().GetElementType()));
store.Add(ManagedObj, sa);
return sa.DangerousGetHandle();
}
throw new ArgumentException("ManagedObj must be an array or null.", nameof(ManagedObj));
}
/// <inheritdoc/>
object ICustomMarshaler.MarshalNativeToManaged(IntPtr pNativeData)
{
var sa = new SafeSAFEARRAY(pNativeData, false);
return sa.ToArray().Cast<T>().ToArray();
}
}
}

View File

@ -76,7 +76,7 @@ public static class OverlappedAsync
if (asyncResult.IsCompleted) return;
asyncResult.FreeOverlapped();
if (code == 0x217) code = 0;
asyncResult.Complete(true, (int)code);
asyncResult.Complete(true, (int)code, bytes);
}, userState);
return ar;
}
@ -98,7 +98,7 @@ public static class OverlappedAsync
if (asyncResult.IsCompleted) return;
asyncResult.FreeOverlapped();
if (code == 0x217) code = 0;
asyncResult.Complete(true, (int)code);
asyncResult.Complete(true, (int)code, bytes);
}, userState);
return ar;
}
@ -157,6 +157,10 @@ public static class OverlappedAsync
/// <summary>Gets a value that indicates whether the asynchronous operation completed synchronously.</summary>
public bool CompletedSynchronously { get; internal set; } = true;
/// <summary>Gets the error code associated with an I/O operation completion on a thread pool.</summary>
/// <value>The error code.</value>
public int ErrorCode => errorCode;
/// <summary>Gets the handle to which this operation is bound.</summary>
/// <value>The handle.</value>
public HFILE Handle => handle;
@ -172,13 +176,19 @@ public static class OverlappedAsync
internal set => overlapped = value;
}
/// <summary>Gets the number of bytes that are transferred with an I/O operation completion on a thread pool.</summary>
/// <value>The number of bytes that are transferred.</value>
public uint ProcessedBytes { get; internal set; }
/// <summary>Completes the specified synch.</summary>
/// <param name="synch">The value for the <see cref="CompletedSynchronously"/> property.</param>
/// <param name="error">The error code, if necessary.</param>
internal void Complete(bool synch = false, int error = 0)
/// <param name="bytes">The number of bytes that have been transferred, if supplied.</param>
internal void Complete(bool synch = false, int error = 0, uint bytes = 0)
{
CompletedSynchronously = synch;
errorCode = error;
ProcessedBytes = bytes;
if (IsCompleted) return;
IsCompleted = true;
lock (lockObj)

View File

@ -2493,13 +2493,10 @@ public static partial class User32
/// </returns>
public static IntPtr GetWindowLongAuto(HWND hWnd, WindowLongFlags nIndex)
{
IntPtr ret;
if (IntPtr.Size == 4)
ret = (IntPtr)GetWindowLong(hWnd, nIndex);
else
ret = GetWindowLongPtr(hWnd, nIndex);
SetLastErrorEx(0, 0);
IntPtr ret = IntPtr.Size == 4 ? (IntPtr)GetWindowLong(hWnd, nIndex) : GetWindowLongPtr(hWnd, nIndex);
if (ret == IntPtr.Zero)
throw new System.ComponentModel.Win32Exception();
Win32Error.GetLastError().ThrowIfFailed();
return ret;
}

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Vanara.PInvoke.VssApi</id>
<version>$version$</version>
<version>4.0.0-beta2</version>
<description>PInvoke API (methods, structures and constants) imported from Windows Volume Shadow Copy Service (VssApi.dll).</description>
<copyright>Copyright © 2017-2023</copyright>
<authors>David Hall</authors>
@ -37,7 +37,6 @@
</group>-->
</dependencies>
<releaseNotes></releaseNotes>
<suppportedDlls>vssapi.dll</suppportedDlls>
</metadata>
<files>
<!--<file src="bin\Release\net45\Win32\Vanara.PInvoke.VssApi*.???" target="lib\net45" />
@ -49,7 +48,7 @@
<file src="bin\Release\net48\x64\Vanara.PInvoke.VssApi*.???" target="runtimes\win10-x64\lib\net48" />-->
<file src="bin\Release\net6.0\x64\Vanara.PInvoke.VssApi*.???" target="lib\net6.0" />
<!--<file src="bin\Release\net6.0\Win32\Vanara.PInvoke.VssApi*.???" target="runtimes\win10-x86\lib\net6.0" />-->
<file src="bin\Release\net6.0\x64\Vanara.PInvoke.VssApi*.???" target="runtimes\win10-x64\lib\net6.0" />
<!--<file src="bin\Release\net6.0\x64\Vanara.PInvoke.VssApi*.???" target="runtimes\win10-x64\lib\net6.0" />-->
<!--<file src="bin\Release\net7.0\Win32\Vanara.PInvoke.VssApi*.???" target="lib\net7.0" />
<file src="bin\Release\net7.0\Win32\Vanara.PInvoke.VssApi*.???" target="runtimes\win10-x86\lib\net7.0" />
<file src="bin\Release\net7.0\x64\Vanara.PInvoke.VssApi*.???" target="runtimes\win10-x64\lib\net7.0" />

View File

@ -27,7 +27,7 @@
<UpdateFiles PackageSource="..\..\Package.targets" UpdateProjectFile="false">
<File Path="AssemblyInfo.cpp">
<Version>AssemblyInformationalVersionAttribute</Version>
<Version type="sem">AssemblyVersionAttribute</Version>
<Version type="v4">AssemblyVersionAttribute</Version>
<Copyright>AssemblyCopyrightAttribute</Copyright>
<Product>AssemblyProductAttribute</Product>
</File>
@ -206,6 +206,8 @@
<ItemGroup>
<None Include="cpp.hint" />
<None Include="packages.config" />
<None Include="pkgreadme.md" />
<None Include="readme.md" />
<None Include="Vanara.PInvoke.VssApi.nuspec" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -7,14 +7,12 @@
<AssemblyName>Vanara.PInvoke.VssApiMgd</AssemblyName>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<IsPackable>false</IsPackable>
<!--<TargetFrameworks>net6.0</TargetFrameworks>-->
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Core\Vanara.Core.csproj" />
<ProjectReference Include="..\Shared\Vanara.PInvoke.Shared.csproj" />
</ItemGroup>
<Target Name="WipeObj" BeforeTargets="Clean;CoreClean">
<!-- obj -->
<!--<Target Name="WipeObj" BeforeTargets="Clean;CoreClean">
<RemoveDir Directories="$(ProjectDir)$(BaseIntermediateOutputPath)" ContinueOnError="true" />
</Target>
</Target>-->
</Project>

View File

@ -3080,7 +3080,7 @@ public static partial class WTSApi32
public long LastInputTimeUTC;
/// <summary>The time of the last user input in the session.</summary>
public DateTime LastInputTime => DateTime.FromFileTimeUtc(LogonTimeUTC);
public DateTime LastInputTime => DateTime.FromFileTimeUtc(LastInputTimeUTC);
/// <summary>The time that the user logged on to the session.</summary>
public long LogonTimeUTC;

View File

@ -1111,7 +1111,7 @@ public static partial class Ws2_32
/// <summary>The IN_ADDR structure represents an IPv4 address.</summary>
[PInvokeData("winsock2.h")]
[StructLayout(LayoutKind.Sequential)]
public struct IN_ADDR : IEquatable<IN_ADDR>
public struct IN_ADDR : IEquatable<IN_ADDR>, IComparable, IComparable<IN_ADDR>
{
/// <summary>An IPv4 address formatted as a u_long.</summary>
public uint S_addr;
@ -1216,12 +1216,27 @@ public static partial class Ws2_32
byte[] b = S_un_b;
return $"{b[0]}.{b[1]}.{b[2]}.{b[3]}";
}
/// <inheritdoc/>
readonly int IComparable.CompareTo(object? obj) => obj is IN_ADDR i ? S_addr.CompareTo(i.S_addr) : (obj is null ? 1 : throw new ArgumentException("Invalid type for comparison.", nameof(obj)));
/// <inheritdoc/>
readonly int IComparable<IN_ADDR>.CompareTo(IN_ADDR other)
{
var b = S_un_b; var o = other.S_un_b;
for (int i = 0; i < 4; i++)
{
if (b[i] < o[i]) return -1;
if (b[i] > o[i]) return 1;
}
return 0;
}
}
/// <summary>The IN6_ADDR structure represents an IPv6 address.</summary>
[PInvokeData("winsock2.h")]
[StructLayout(LayoutKind.Sequential, Size = IN6_ADDR_SIZE)]
public struct IN6_ADDR : IEquatable<IN6_ADDR>
public struct IN6_ADDR : IEquatable<IN6_ADDR>, IComparable, IComparable<IN6_ADDR>
{
private const int IN6_ADDR_SIZE = 16;
@ -1229,7 +1244,7 @@ public static partial class Ws2_32
private ulong upper;
/// <summary>The IPv6 standard loopback address (<c>IN6ADDR_LOOPBACK_INIT</c>).</summary>
public static readonly IN6_ADDR Loopback = new(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 });
public static readonly IN6_ADDR Loopback = new([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
/// <summary>The IPv6 standard unspecified address (<c>IN6ADDR_ANY_INIT</c>).</summary>
public static readonly IN6_ADDR Unspecified = new();
@ -1464,6 +1479,21 @@ public static partial class Ws2_32
/// <param name="other">The value to compare with this instance.</param>
/// <returns><see langword="true"/> if the specified value is equal to this instance; otherwise, <see langword="false"/>.</returns>
public readonly bool Equals(IN6_ADDR other) => lower == other.lower && upper == other.upper;
/// <inheritdoc/>
readonly int IComparable.CompareTo(object? obj) => obj is IN6_ADDR i ? ((IComparable<IN6_ADDR>)this).CompareTo(i) : (obj is null ? 1 : throw new ArgumentException("Invalid type for comparison.", nameof(obj)));
/// <inheritdoc/>
readonly int IComparable<IN6_ADDR>.CompareTo(IN6_ADDR other)
{
var b = bytes; var o = other.bytes;
for (int i = 0; i < IN6_ADDR_SIZE; i++)
{
if (b[i] < o[i]) return -1;
if (b[i] > o[i]) return 1;
}
return 0;
}
}
/// <summary>

View File

@ -124,7 +124,7 @@ usp10.dll | [Vanara.PInvoke.Usp10](https://github.com/dahall/Vanara/blob/master/
uxtheme.dll | [Vanara.PInvoke.UxTheme](https://github.com/dahall/Vanara/blob/master/PInvoke/UxTheme/readme.md) | ![Coverage](https://img.shields.io/badge/100%25-green.svg?style=flat-square) | [![Nuget](https://img.shields.io/nuget/v/Vanara.PInvoke.UxTheme?label=%20&logo=nuget&style=flat-square)![Nuget](https://img.shields.io/nuget/dt/Vanara.PInvoke.UxTheme?label=%20&style=flat-square)](https://www.nuget.org/packages/Vanara.PInvoke.UxTheme)
Version.dll | [Vanara.PInvoke.Version](https://github.com/dahall/Vanara/blob/master/PInvoke/Version/readme.md) | ![Coverage](https://img.shields.io/badge/100%25-green.svg?style=flat-square) | [![Nuget](https://img.shields.io/nuget/v/Vanara.PInvoke.Version?label=%20&logo=nuget&style=flat-square)![Nuget](https://img.shields.io/nuget/dt/Vanara.PInvoke.Version?label=%20&style=flat-square)](https://www.nuget.org/packages/Vanara.PInvoke.Version)
virtdisk.dll | [Vanara.PInvoke.VirtDisk](https://github.com/dahall/Vanara/blob/master/PInvoke/VirtDisk/readme.md) | ![Coverage](https://img.shields.io/badge/100%25-green.svg?style=flat-square) | [![Nuget](https://img.shields.io/nuget/v/Vanara.PInvoke.VirtDisk?label=%20&logo=nuget&style=flat-square)![Nuget](https://img.shields.io/nuget/dt/Vanara.PInvoke.VirtDisk?label=%20&style=flat-square)](https://www.nuget.org/packages/Vanara.PInvoke.VirtDisk)
vssapi.dll | [Vanara.PInvoke.VssApiMgd](https://github.com/dahall/Vanara/blob/master/PInvoke/VssApiMgd/readme.md) | ![Coverage](https://img.shields.io/badge/100%25-green.svg?style=flat-square) | [![Nuget](https://img.shields.io/nuget/v/Vanara.PInvoke.VssApiMgd?label=%20&logo=nuget&style=flat-square)![Nuget](https://img.shields.io/nuget/dt/Vanara.PInvoke.VssApiMgd?label=%20&style=flat-square)](https://www.nuget.org/packages/Vanara.PInvoke.VssApiMgd)
vssapi.dll | [Vanara.PInvoke.VssApi](https://github.com/dahall/Vanara/blob/master/PInvoke/VssApi/readme.md) | ![Coverage](https://img.shields.io/badge/100%25-green.svg?style=flat-square) | [![Nuget](https://img.shields.io/nuget/v/Vanara.PInvoke.VssApi?label=%20&logo=nuget&style=flat-square)![Nuget](https://img.shields.io/nuget/dt/Vanara.PInvoke.VssApi?label=%20&style=flat-square)](https://www.nuget.org/packages/Vanara.PInvoke.VssApi)
WcmApi.dll | [Vanara.PInvoke.WcmApi](https://github.com/dahall/Vanara/blob/master/PInvoke/WcmApi/readme.md) | ![Coverage](https://img.shields.io/badge/100%25-green.svg?style=flat-square) | [![Nuget](https://img.shields.io/nuget/v/Vanara.PInvoke.WcmApi?label=%20&logo=nuget&style=flat-square)![Nuget](https://img.shields.io/nuget/dt/Vanara.PInvoke.WcmApi?label=%20&style=flat-square)](https://www.nuget.org/packages/Vanara.PInvoke.WcmApi)
WcnApi.dll | [Vanara.PInvoke.WcnApi](https://github.com/dahall/Vanara/blob/master/PInvoke/WcnApi/readme.md) | ![Coverage](https://img.shields.io/badge/100%25-green.svg?style=flat-square) | [![Nuget](https://img.shields.io/nuget/v/Vanara.PInvoke.WcnApi?label=%20&logo=nuget&style=flat-square)![Nuget](https://img.shields.io/nuget/dt/Vanara.PInvoke.WcnApi?label=%20&style=flat-square)](https://www.nuget.org/packages/Vanara.PInvoke.WcnApi)
websocket.dll | [Vanara.PInvoke.WebSocket](https://github.com/dahall/Vanara/blob/master/PInvoke/WebSocket/readme.md) | ![Coverage](https://img.shields.io/badge/100%25-green.svg?style=flat-square) | [![Nuget](https://img.shields.io/nuget/v/Vanara.PInvoke.WebSocket?label=%20&logo=nuget&style=flat-square)![Nuget](https://img.shields.io/nuget/dt/Vanara.PInvoke.WebSocket?label=%20&style=flat-square)](https://www.nuget.org/packages/Vanara.PInvoke.WebSocket)

View File

@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>UnitTest.PInvoke.IMAPI</AssemblyName>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\PInvoke\IMAPI\Vanara.PInvoke.IMAPI.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,55 @@
using NUnit.Framework;
using NUnit.Framework.Internal;
using System.Linq;
using static Vanara.PInvoke.IMAPI;
namespace Vanara.PInvoke.Tests;
[TestFixture]
public class IMAPITests
{
[OneTimeSetUp]
public void _Setup()
{
}
[OneTimeTearDown]
public void _TearDown()
{
}
[Test]
public void RecorderTest()
{
IDiscMaster2 discMaster = new();
Assert.True(discMaster.IsSupportedEnvironment, "There are no media sources on which to test.");
IDiscRecorder2 discRecorder = new();
discRecorder.InitializeDiscRecorder(discMaster[0]);
discRecorder.SupportedProfiles.WriteValues();
// Get the media type in the recorder
IDiscFormat2Data iDiscFormat2Data = new();
Assert.True(iDiscFormat2Data.IsCurrentMediaSupported(discRecorder));
iDiscFormat2Data.Recorder = discRecorder;
IMAPI_MEDIA_PHYSICAL_TYPE mediaType = iDiscFormat2Data.CurrentPhysicalMediaType;
TestContext.WriteLine($"Media Type : {mediaType.GetDescription()}");
iDiscFormat2Data.SupportedWriteSpeedDescriptors.WriteValues();
// Create a file system and select media type
IFileSystemImage iFileSystemImage = new();
iFileSystemImage.ChooseImageDefaultsForMediaType(mediaType);
// If there are other recored sessions on the disc, import them into the file system image
if (!iDiscFormat2Data.MediaHeuristicallyBlank)
{
iFileSystemImage.MultisessionInterfaces = iDiscFormat2Data.MultisessionInterfaces;
iFileSystemImage.ImportFileSystem();
}
// Get the total size of the file system image
int fileMediaBlocks = iFileSystemImage.FreeMediaBlocks;
int totalDiskSize = 2048 * fileMediaBlocks;
TestContext.WriteLine($"Total Disk Size: {totalDiskSize}");
}
}

View File

@ -280,7 +280,7 @@ public partial class IpHlpApiTests
Assert.That(t5.dwNumEntries, Is.GreaterThan(0));
MIB_UDPTABLE_OWNER_PID t10 = GetExtendedUdpTable<MIB_UDPTABLE_OWNER_PID>(UDP_TABLE_CLASS.UDP_TABLE_OWNER_PID);
Assert.That(t10.dwNumEntries, Is.GreaterThan(0));
TestContext.WriteLine("UDP PID: " + string.Join(",", t10.Select(t => t.dwOwningPid)));
TestContext.WriteLine("UDP PID:\n" + string.Join("\n", t10.OrderBy(t => t).Select(t => $"{t.dwLocalAddr}:{t.dwHostLocalPort}\t{t.dwOwningPid}")));
MIB_UDP6TABLE_OWNER_PID t11 = GetExtendedUdpTable<MIB_UDP6TABLE_OWNER_PID>(UDP_TABLE_CLASS.UDP_TABLE_OWNER_PID, ADDRESS_FAMILY.AF_INET6);
Assert.That(t11.dwNumEntries, Is.GreaterThan(0));
TestContext.WriteLine("UDP6 PID: " + string.Join(",", t11.Select(t => t.dwOwningPid)));

View File

@ -431,6 +431,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Windows.Shell.Common", "Uni
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSocket", "UnitTests\PInvoke\WebSocket\WebSocket.csproj", "{AEA2913A-5E67-4C33-823F-CE06295DB35A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IMAPI", "UnitTests\PInvoke\IMAPI\IMAPI.csproj", "{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -3771,6 +3773,23 @@ Global
{AEA2913A-5E67-4C33-823F-CE06295DB35A}.Release|x64.Build.0 = Release|x64
{AEA2913A-5E67-4C33-823F-CE06295DB35A}.Release|x86.ActiveCfg = Release|x86
{AEA2913A-5E67-4C33-823F-CE06295DB35A}.Release|x86.Build.0 = Release|x86
{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB}.Debug|x64.ActiveCfg = Debug|x64
{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB}.Debug|x64.Build.0 = Debug|x64
{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB}.Debug|x86.ActiveCfg = Debug|x86
{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB}.Debug|x86.Build.0 = Debug|x86
{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB}.DebugNoTests|Any CPU.ActiveCfg = DebugNoTests|Any CPU
{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB}.DebugNoTests|Any CPU.Build.0 = DebugNoTests|Any CPU
{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB}.DebugNoTests|x64.ActiveCfg = DebugNoTests|x64
{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB}.DebugNoTests|x64.Build.0 = DebugNoTests|x64
{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB}.DebugNoTests|x86.ActiveCfg = DebugNoTests|x86
{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB}.DebugNoTests|x86.Build.0 = DebugNoTests|x86
{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB}.Release|x64.ActiveCfg = Release|x64
{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB}.Release|x64.Build.0 = Release|x64
{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB}.Release|x86.ActiveCfg = Release|x86
{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -3964,6 +3983,7 @@ Global
{7729B4B9-4837-49D5-91CC-5BB66E23A376} = {212ABBD0-B724-4CFA-9D6D-E3891547FA90}
{2727B06D-1E73-4108-AFDE-39C1A6F99806} = {3EC6B40D-71D3-4E59-A0E0-544EC605FE11}
{AEA2913A-5E67-4C33-823F-CE06295DB35A} = {385CAD2D-0A5E-4F80-927B-D5499D126B90}
{55E8ADA4-D27A-42B9-8BFD-8313B2DEF6DB} = {385CAD2D-0A5E-4F80-927B-D5499D126B90}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {543FAC75-2AF1-4EF1-9609-B242B63FEED4}