diff --git a/src/thirtytwo/NativeMethods.txt b/src/thirtytwo/NativeMethods.txt index ddf9171..f1c2d08 100644 --- a/src/thirtytwo/NativeMethods.txt +++ b/src/thirtytwo/NativeMethods.txt @@ -129,6 +129,7 @@ GlobalLock GlobalSize GlobalUnlock HFONT +HKEY_* HRESULT IAccessible IAccessibleEx @@ -178,6 +179,8 @@ IsWindowEnabled IsWindowVisible IUIAutomationElement IUnknown +KEY_INFORMATION_CLASS +KEY_NAME_INFORMATION KF_* LIBFLAGS LoadCursor @@ -215,6 +218,11 @@ PROPVARIANT PropVariantClear RegisterClassEx RegisterClipboardFormat +RegCloseKey +RegEnumValue +RegOpenKeyEx +RegQueryInfoKey +RegQueryValueEx ReleaseDC ROLE_SYSTEM_* S_FALSE @@ -246,7 +254,10 @@ SHParseDisplayName ShowWindow STATE_SYSTEM_* STATIC_STYLES +STATUS_BUFFER_OVERFLOW +STATUS_BUFFER_TOO_SMALL STATUS_INFO_LENGTH_MISMATCH +STATUS_SUCCESS SubtractRect SYS_COLOR_INDEX SYSTEM_PROCESS_INFORMATION diff --git a/src/thirtytwo/Support/Error.cs b/src/thirtytwo/Support/Error.cs index 0b1d0e0..8f750cf 100644 --- a/src/thirtytwo/Support/Error.cs +++ b/src/thirtytwo/Support/Error.cs @@ -18,6 +18,14 @@ public static unsafe class Error [DoesNotReturn] public static void Throw(this WIN32_ERROR error, string? path = null) => throw error.GetException(path); + public static void ThrowIfFailed(this WIN32_ERROR error, string? path = null) + { + if (error != WIN32_ERROR.ERROR_SUCCESS) + { + error.Throw(path); + } + } + [DoesNotReturn] public static void ThrowLastError(string? path = null) => Throw(GetLastError(), path); diff --git a/src/thirtytwo/Support/SpanExtensions.cs b/src/thirtytwo/Support/SpanExtensions.cs index d5551c9..4b7dc43 100644 --- a/src/thirtytwo/Support/SpanExtensions.cs +++ b/src/thirtytwo/Support/SpanExtensions.cs @@ -1,6 +1,8 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using Windows.Support; + namespace System; public static class SpanExtensions @@ -22,4 +24,22 @@ public static Span SliceAtNull(this Span span) int index = span.IndexOf('\0'); return index == -1 ? span : span[..index]; } + + /// + /// Splits into strings on the given . + /// + public static IEnumerable Split(this ReadOnlySpan span, char delimiter, bool includeEmptyStrings = false) + { + List strings = new(); + SpanReader reader = new(span); + while (reader.TryReadTo(out var next, delimiter)) + { + if (includeEmptyStrings || !next.IsEmpty) + { + strings.Add(next.ToString()); + } + } + + return strings; + } } \ No newline at end of file diff --git a/src/thirtytwo/Support/SpanReader.cs b/src/thirtytwo/Support/SpanReader.cs new file mode 100644 index 0000000..d88e5aa --- /dev/null +++ b/src/thirtytwo/Support/SpanReader.cs @@ -0,0 +1,46 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Buffers; + +namespace Windows.Support; + +/// +/// Simple span reader. Follows . +/// +public ref struct SpanReader where T : unmanaged, IEquatable +{ + public ReadOnlySpan Span { get; } + public int Index { get; private set; } + + public SpanReader(ReadOnlySpan span) => Span = span; + + public readonly ReadOnlySpan Remaining => Span[Index..]; + + /// + /// Try to read everything up to the given . + /// + /// The read data, if any. + /// The delimiter to look for. + /// to move past the if found. + /// if the was found. + public bool TryReadTo(out ReadOnlySpan span, T delimiter, bool advancePastDelimiter = true) + { + bool found = false; + ReadOnlySpan remaining = Remaining; + int index = remaining.IndexOf(delimiter); + + if (index != -1) + { + span = index == 0 ? default : remaining[..index]; + Index += index + (advancePastDelimiter ? 1 : 0); + found = true; + } + else + { + span = default; + } + + return found; + } +} \ No newline at end of file diff --git a/src/thirtytwo/Support/ValueBuffer.cs b/src/thirtytwo/Support/ValueBuffer.cs index 8aaaeb8..b07f981 100644 --- a/src/thirtytwo/Support/ValueBuffer.cs +++ b/src/thirtytwo/Support/ValueBuffer.cs @@ -44,7 +44,7 @@ public ValueBuffer(int initialCapacity) public Span Span { get; private set; } - public int Length => Span.Length; + public readonly int Length => Span.Length; /// /// Ensure that the buffer has enough space for number of elements. @@ -101,9 +101,9 @@ public unsafe void EnsureCapacity(int capacity, bool copy = false) } } - public ref T this[int index] => ref Span[index]; + public readonly ref T this[int index] => ref Span[index]; - public ref T GetPinnableReference() => ref MemoryMarshal.GetReference(Span); + public readonly ref T GetPinnableReference() => ref MemoryMarshal.GetReference(Span); public string ToStringAndDispose(int length) { diff --git a/src/thirtytwo/Wdk/Interop.cs b/src/thirtytwo/Wdk/Interop.cs new file mode 100644 index 0000000..f73d97e --- /dev/null +++ b/src/thirtytwo/Wdk/Interop.cs @@ -0,0 +1,39 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.InteropServices; +using Windows.Wdk.System.SystemServices; +using Windows.Win32.System.Registry; + +namespace Windows.Wdk; + +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter + +public static partial class Interop +{ + /// + /// The NtQueryKey routine provides information about the class of a registry key, and the number and sizes of its subkeys. + /// + /// Specifies the size, in bytes, of the buffer. + /// + /// Pointer to a variable that receives the size, in bytes, of the requested key information. If NtQueryKey returns + /// , the variable contains the amount of data returned. If NwQueryKey returns + /// or , you can use the + /// value of the variable to determine the required buffer size. + /// + /// + /// + /// Read more on learn.microsoft.com. + /// + /// + [DllImport("ntdll.dll", ExactSpelling = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern unsafe NTSTATUS NtQueryKey( + HKEY KeyHandle, + KEY_INFORMATION_CLASS KeyInformationClass, + void* KeyInformation, + uint Length, + uint* ResultLength); +} + +#pragma warning restore SA1313 // Parameter names should begin with lower-case letter \ No newline at end of file diff --git a/src/thirtytwo/Win32/System/Registry/HKEY.cs b/src/thirtytwo/Win32/System/Registry/HKEY.cs new file mode 100644 index 0000000..c9edbfa --- /dev/null +++ b/src/thirtytwo/Win32/System/Registry/HKEY.cs @@ -0,0 +1,35 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Windows.Support; + +namespace Windows.Win32.System.Registry; + +public partial struct HKEY : IDisposable +{ + private const uint REMOTE_HANDLE_TAG = 0x00000001; + private const uint REG_CLASSES_SPECIAL_TAG = 0x00000002; + + public bool IsPerfKey() + => this == HKEY_PERFORMANCE_DATA || this == HKEY_PERFORMANCE_NLSTEXT || this == HKEY_PERFORMANCE_TEXT; + + /// + /// Returns true if the key is from the local machine. + /// + public bool IsLocalKey => (Value & REMOTE_HANDLE_TAG) == 0; + + /// + /// Returns true if the key is special (notably in , where + /// it might be redirected to per user settings). + /// + public bool IsSpecialKey => (Value & REG_CLASSES_SPECIAL_TAG) != 0; + + public void Dispose() + { + WIN32_ERROR error = Interop.RegCloseKey(this); + if (error != WIN32_ERROR.ERROR_SUCCESS) + { + error.Throw(); + } + } +} \ No newline at end of file diff --git a/src/thirtytwo/Win32/System/Registry/Registry.cs b/src/thirtytwo/Win32/System/Registry/Registry.cs new file mode 100644 index 0000000..cf65ea2 --- /dev/null +++ b/src/thirtytwo/Win32/System/Registry/Registry.cs @@ -0,0 +1,222 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Buffers.Binary; +using System.Runtime.InteropServices; +using Windows.Support; +using Windows.Wdk.System.SystemServices; + +namespace Windows.Win32.System.Registry; + +public static unsafe partial class Registry +{ + /// + /// Gets the full name of the given . + /// + /// + /// + /// This will not work with the "special" root keys such as as they aren't + /// real key handles. + /// + /// + public static string QueryKeyName(HKEY key) + { + // The special root keys aren't actually handles so they don't work with this API (returns ERROR_INVALID_HANDLE). + + if (key == HKEY.HKEY_USERS) + { + return @"\REGISTRY\USER"; + } + else if (key == HKEY.HKEY_LOCAL_MACHINE) + { + return @"\REGISTRY\MACHINE"; + } + else if (key == HKEY.HKEY_CURRENT_USER) + { + return @"\REGISTRY\USER\.DEFAULT"; + } + else if (key == HKEY.HKEY_CLASSES_ROOT) + { + return @"\REGISTRY\MACHINE\SOFTWARE\CLASSES"; + } + + using BufferScope buffer = new(stackalloc char[256]); + while (true) + { + fixed (char* b = buffer) + { + uint length; + NTSTATUS status = Wdk.Interop.NtQueryKey(key, KEY_INFORMATION_CLASS.KeyNameInformation, b, (uint)buffer.Length, &length); + + if (status == NTSTATUS.STATUS_BUFFER_TOO_SMALL || status == NTSTATUS.STATUS_BUFFER_OVERFLOW) + { + buffer.EnsureCapacity((int)length); + continue; + } + + status.ThrowIfFailed(); + + KEY_NAME_INFORMATION* nameInfo = (KEY_NAME_INFORMATION*)b; + return new ReadOnlySpan(nameInfo->Name.Value, (int)nameInfo->NameLength / sizeof(char)).ToString(); + } + } + } + + /// + /// Open the specified subkey. + /// + public static HKEY OpenKey( + HKEY key, + string? subKeyName, + REG_SAM_FLAGS rights = REG_SAM_FLAGS.KEY_READ) + { + HKEY subKey; + Interop.RegOpenKeyEx(key, subKeyName, 0, rights, &subKey).ThrowIfFailed(); + return subKey; + } + + /// + /// Returns true if the given value exists. + /// + public static bool QueryValueExists(HKEY key, string valueName) + { + fixed (char* c = valueName) + { + WIN32_ERROR result = Interop.RegQueryValueEx(key, c, null, null, null, null); + return result switch + { + WIN32_ERROR.ERROR_SUCCESS => true, + WIN32_ERROR.ERROR_FILE_NOT_FOUND => false, + _ => throw Error.GetException(result) + }; + } + } + + /// + /// Returns the type of the given value, or REG_NONE if it doesn't exist. + /// + public static REG_VALUE_TYPE QueryValueType(HKEY key, string valueName) + { + fixed (char* c = valueName) + { + REG_VALUE_TYPE valueType = default; + WIN32_ERROR result = Interop.RegQueryValueEx(key, c, null, &valueType, null, null); + return result switch + { + WIN32_ERROR.ERROR_SUCCESS => valueType, + WIN32_ERROR.ERROR_FILE_NOT_FOUND => REG_VALUE_TYPE.REG_NONE, + _ => throw result.GetException(), + }; + } + } + + public static object? QueryValue(HKEY key, string valueName) + { + using BufferScope buffer = new(stackalloc byte[512]); + + fixed (char* n = valueName) + while (true) fixed (byte* b = buffer) + { + REG_VALUE_TYPE valueType = default; + + uint length = (uint)buffer.Length; + WIN32_ERROR result = Interop.RegQueryValueEx(key, n, null, &valueType, b, &length); + + switch (result) + { + case WIN32_ERROR.ERROR_SUCCESS: + return ReadValue(buffer[..(int)length], valueType); + case WIN32_ERROR.ERROR_MORE_DATA: + // According to the docs, the byteCapacity given back will not be correct for HKEY_PERFORMANCE_DATA + length = length > buffer.Length ? length : checked(length + 256); + buffer.EnsureCapacity((int)length); + break; + case WIN32_ERROR.ERROR_FILE_NOT_FOUND: + return null; + default: + throw result.GetException(); + } + } + } + + /// + /// Gets all value names for the given registry key. + /// + public static unsafe IEnumerable GetValueNames(HKEY key) + { + uint valueCount; + uint maxValueNameLength; + Interop.RegQueryInfoKey(key, default, lpcValues: &valueCount, lpcbMaxValueNameLen: &maxValueNameLength).ThrowIfFailed(); + + List names = new(); + + // Doesn't include the terminating null. + maxValueNameLength += 1; + + using BufferScope buffer = maxValueNameLength <= 256 + ? new(stackalloc char[(int)maxValueNameLength]) : + new((int)maxValueNameLength); + + WIN32_ERROR result = WIN32_ERROR.NO_ERROR; + + while (true) fixed (char* c = buffer) + { + uint length = (uint)buffer.Length; + result = Interop.RegEnumValue(key, (uint)names.Count, c, &length, null, null, null, null); + + switch (result) + { + case WIN32_ERROR.ERROR_NO_MORE_ITEMS: + return names; + case WIN32_ERROR.ERROR_SUCCESS: + names.Add(buffer.Slice(0, (int)length).ToString()); + break; + case WIN32_ERROR.ERROR_MORE_DATA: + if (key.IsPerfKey()) + { + // Perf keys always report back ERROR_MORE_DATA, + // and also do not report the size of the string. + names.Add(buffer.AsSpan().SliceAtNull().ToString()); + } + else + { + // For some reason the name size isn't reported back, + // even though it is known. Why would they not do this? + buffer.EnsureCapacity(buffer.Length + 100); + } + + break; + default: + throw result.GetException(); + } + } + } + + private static unsafe object ReadValue(ReadOnlySpan buffer, REG_VALUE_TYPE valueType) + { + switch (valueType) + { + case REG_VALUE_TYPE.REG_SZ: + case REG_VALUE_TYPE.REG_EXPAND_SZ: + case REG_VALUE_TYPE.REG_LINK: + // Size includes the null + return MemoryMarshal.Cast(buffer)[..^1].ToString(); + case REG_VALUE_TYPE.REG_MULTI_SZ: + return MemoryMarshal.Cast(buffer).Split('\0').ToArray(); + case REG_VALUE_TYPE.REG_DWORD_LITTLE_ENDIAN: + return BinaryPrimitives.ReadUInt32LittleEndian(buffer); + case REG_VALUE_TYPE.REG_DWORD_BIG_ENDIAN: + return BinaryPrimitives.ReadUInt32BigEndian(buffer); + case REG_VALUE_TYPE.REG_QWORD_LITTLE_ENDIAN: + return BinaryPrimitives.ReadUInt64LittleEndian(buffer); + case REG_VALUE_TYPE.REG_BINARY: + // The next three aren't defined yet, so we'll just return them as binary blobs + case REG_VALUE_TYPE.REG_RESOURCE_LIST: // CM_RESOURCE_LIST + case REG_VALUE_TYPE.REG_FULL_RESOURCE_DESCRIPTOR: // CM_FULL_RESOURCE_DESCRIPTOR + case REG_VALUE_TYPE.REG_RESOURCE_REQUIREMENTS_LIST: // CM_RESOURCE_LIST?? + return buffer.ToArray(); + default: + throw new NotSupportedException($"No support for {valueType} value types."); + } + } +} \ No newline at end of file diff --git a/src/thirtytwo_tests/ClipboardTestCollection.cs b/src/thirtytwo_tests/ClipboardTestCollection.cs index ca83a70..1fc14d6 100644 --- a/src/thirtytwo_tests/ClipboardTestCollection.cs +++ b/src/thirtytwo_tests/ClipboardTestCollection.cs @@ -1,7 +1,7 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -namespace Tests.Windows; +namespace Windows; [CollectionDefinition(nameof(ClipboardTestCollection), DisableParallelization = true)] public class ClipboardTestCollection diff --git a/src/thirtytwo_tests/ClipboardTests.cs b/src/thirtytwo_tests/ClipboardTests.cs index e4f8533..95d8a40 100644 --- a/src/thirtytwo_tests/ClipboardTests.cs +++ b/src/thirtytwo_tests/ClipboardTests.cs @@ -1,12 +1,11 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Windows; using Windows.Support; using Windows.Win32.Foundation; using Windows.Win32.System.Ole; -namespace Tests.Windows; +namespace Windows; [Collection(nameof(ClipboardTestCollection))] public unsafe class ClipboardTests diff --git a/src/thirtytwo_tests/Controls/ActiveXControlTests.cs b/src/thirtytwo_tests/Controls/ActiveXControlTests.cs index 00bcd32..65880a6 100644 --- a/src/thirtytwo_tests/Controls/ActiveXControlTests.cs +++ b/src/thirtytwo_tests/Controls/ActiveXControlTests.cs @@ -1,10 +1,9 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Windows; using Windows.Win32.System.Com; -namespace Tests.Windows.Controls; +namespace Windows.Controls; public class ActiveXControlTests { diff --git a/src/thirtytwo_tests/Controls/EditControlTests.cs b/src/thirtytwo_tests/Controls/EditControlTests.cs index 7d2673d..9863865 100644 --- a/src/thirtytwo_tests/Controls/EditControlTests.cs +++ b/src/thirtytwo_tests/Controls/EditControlTests.cs @@ -1,9 +1,7 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Windows; - -namespace Tests.Windows.Controls; +namespace Windows.Controls; public class EditControlTests { diff --git a/src/thirtytwo_tests/Controls/RichEditControlTests.cs b/src/thirtytwo_tests/Controls/RichEditControlTests.cs index 8dccde6..0c581eb 100644 --- a/src/thirtytwo_tests/Controls/RichEditControlTests.cs +++ b/src/thirtytwo_tests/Controls/RichEditControlTests.cs @@ -1,9 +1,7 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Windows; - -namespace Tests.Windows.Controls; +namespace Windows.Controls; public class RichEditControlTests { diff --git a/src/thirtytwo_tests/Dialogs/FileOpenDialogTests.cs b/src/thirtytwo_tests/Dialogs/FileOpenDialogTests.cs index 19a5cab..297549d 100644 --- a/src/thirtytwo_tests/Dialogs/FileOpenDialogTests.cs +++ b/src/thirtytwo_tests/Dialogs/FileOpenDialogTests.cs @@ -2,12 +2,10 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Runtime.InteropServices; -using Windows; -using Windows.Dialogs; using Windows.Messages; using Windows.Win32.Foundation; -namespace Tests.Windows.Dialogs; +namespace Windows.Dialogs; public class FileOpenDialogTests { diff --git a/src/thirtytwo_tests/IconIdTests.cs b/src/thirtytwo_tests/IconIdTests.cs index 4ad59e4..04e8605 100644 --- a/src/thirtytwo_tests/IconIdTests.cs +++ b/src/thirtytwo_tests/IconIdTests.cs @@ -1,10 +1,9 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Windows; using Windows.Win32; -namespace Tests.Windows; +namespace Windows; public unsafe class IconIdTests { diff --git a/src/thirtytwo_tests/ProcessAndThreads/ProcessInfoTests.cs b/src/thirtytwo_tests/ProcessAndThreads/ProcessInfoTests.cs index 8d8974b..8dba1f9 100644 --- a/src/thirtytwo_tests/ProcessAndThreads/ProcessInfoTests.cs +++ b/src/thirtytwo_tests/ProcessAndThreads/ProcessInfoTests.cs @@ -2,9 +2,8 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Text; -using Windows.ProcessAndThreads; -namespace Tests.Windows.ProcessAndThreads; +namespace Windows.ProcessAndThreads; public class ProcessInfoTests { diff --git a/src/thirtytwo_tests/Support/BufferScopeTests.cs b/src/thirtytwo_tests/Support/BufferScopeTests.cs index 347c722..78d718e 100644 --- a/src/thirtytwo_tests/Support/BufferScopeTests.cs +++ b/src/thirtytwo_tests/Support/BufferScopeTests.cs @@ -1,9 +1,7 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Windows.Support; - -namespace Tests.Windows.Support; +namespace Windows.Support; public unsafe class BufferScopeTests { diff --git a/src/thirtytwo_tests/Support/ErrorTests.cs b/src/thirtytwo_tests/Support/ErrorTests.cs index 89320a5..7c61657 100644 --- a/src/thirtytwo_tests/Support/ErrorTests.cs +++ b/src/thirtytwo_tests/Support/ErrorTests.cs @@ -1,10 +1,9 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Windows.Support; using Windows.Win32.Foundation; -namespace Tests.Windows.Support; +namespace Windows.Support; public class ErrorTests { diff --git a/src/thirtytwo_tests/Support/WindowExtensionTests.cs b/src/thirtytwo_tests/Support/WindowExtensionTests.cs index edd56b6..0f08624 100644 --- a/src/thirtytwo_tests/Support/WindowExtensionTests.cs +++ b/src/thirtytwo_tests/Support/WindowExtensionTests.cs @@ -1,9 +1,7 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Windows; - -namespace Tests.Windows; +namespace Windows; public class WindowExtensionTests { diff --git a/src/thirtytwo_tests/Win32/ComHelpersTests.cs b/src/thirtytwo_tests/Win32/ComHelpersTests.cs index 03a4229..236cb8d 100644 --- a/src/thirtytwo_tests/Win32/ComHelpersTests.cs +++ b/src/thirtytwo_tests/Win32/ComHelpersTests.cs @@ -1,12 +1,11 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.System.Com; using Windows.Win32.System.Ole; -namespace Tests.Windows.Win32; +namespace Windows.Win32; public unsafe class ComHelpersTests { diff --git a/src/thirtytwo_tests/Win32/Foundation/HRESULTTests.cs b/src/thirtytwo_tests/Win32/Foundation/HRESULTTests.cs index 7923b8f..b2d08a0 100644 --- a/src/thirtytwo_tests/Win32/Foundation/HRESULTTests.cs +++ b/src/thirtytwo_tests/Win32/Foundation/HRESULTTests.cs @@ -2,9 +2,8 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Windows.Support; -using Windows.Win32.Foundation; -namespace Tests.Windows.Win32.Foundation; +namespace Windows.Win32.Foundation; public class HRESULTTests { diff --git a/src/thirtytwo_tests/Win32/System/Com/ComTests.cs b/src/thirtytwo_tests/Win32/System/Com/ComTests.cs index 68dab74..9abe306 100644 --- a/src/thirtytwo_tests/Win32/System/Com/ComTests.cs +++ b/src/thirtytwo_tests/Win32/System/Com/ComTests.cs @@ -2,10 +2,9 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Windows.Dialogs; -using Windows.Win32.System.Com; using Windows.Win32.UI.Shell; -namespace Tests.Windows.Win32.System.Com; +namespace Windows.Win32.System.Com; public unsafe class ComTests { diff --git a/src/thirtytwo_tests/Win32/System/Com/ComTypeDescriptorTests.cs b/src/thirtytwo_tests/Win32/System/Com/ComTypeDescriptorTests.cs index fa3adfc..3ee5800 100644 --- a/src/thirtytwo_tests/Win32/System/Com/ComTypeDescriptorTests.cs +++ b/src/thirtytwo_tests/Win32/System/Com/ComTypeDescriptorTests.cs @@ -2,10 +2,8 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.ComponentModel; -using Windows.Win32; -using Windows.Win32.System.Com; -namespace Tests.Windows.Win32.System.Com; +namespace Windows.Win32.System.Com; public unsafe class ComTypeDescriptorTests { diff --git a/src/thirtytwo_tests/Win32/System/Com/ComponentCategoriesManagerTests.cs b/src/thirtytwo_tests/Win32/System/Com/ComponentCategoriesManagerTests.cs index 4618f66..d266b2d 100644 --- a/src/thirtytwo_tests/Win32/System/Com/ComponentCategoriesManagerTests.cs +++ b/src/thirtytwo_tests/Win32/System/Com/ComponentCategoriesManagerTests.cs @@ -1,11 +1,9 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Windows.Win32; using Windows.Win32.Foundation; -using Windows.Win32.System.Com; -namespace Tests.Windows.Win32.System.Com; +namespace Windows.Win32.System.Com; public unsafe class ComponentCategoriesManagerTests { diff --git a/src/thirtytwo_tests/Win32/System/Com/IComCallableWrapperTests.cs b/src/thirtytwo_tests/Win32/System/Com/IComCallableWrapperTests.cs index cc6e769..65b1609 100644 --- a/src/thirtytwo_tests/Win32/System/Com/IComCallableWrapperTests.cs +++ b/src/thirtytwo_tests/Win32/System/Com/IComCallableWrapperTests.cs @@ -2,9 +2,8 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Windows.Win32.Foundation; -using Windows.Win32.System.Com; -namespace Tests.Windows.Win32.System.Com; +namespace Windows.Win32.System.Com; public unsafe class IComCallableWrapperTests { diff --git a/src/thirtytwo_tests/Win32/System/Com/IReflectTests.cs b/src/thirtytwo_tests/Win32/System/Com/IReflectTests.cs index 7fb470b..ea02a4f 100644 --- a/src/thirtytwo_tests/Win32/System/Com/IReflectTests.cs +++ b/src/thirtytwo_tests/Win32/System/Com/IReflectTests.cs @@ -7,15 +7,14 @@ using System.Reflection; using System.Runtime.InteropServices; using Windows.DotNet; -using Windows.Win32; using Windows.Win32.Foundation; -using Windows.Win32.System.Com; -using Windows.Win32.System.Com.Marshal; using Windows.Win32.System.Ole; using Windows.Win32.System.Variant; using static Windows.Win32.System.Ole.FDEX_PROP_FLAGS; +using IMarshal = Windows.Win32.System.Com.Marshal.IMarshal; +using InteropMarshal = System.Runtime.InteropServices.Marshal; -namespace Tests.Windows.Win32.System.Com; +namespace Windows.Win32.System.Com; public unsafe class IReflectTests { @@ -27,7 +26,7 @@ public void SimpleClass_Public_CanGetDispatch() PublicSimpleClass publicSimple = new(); // Can get IUnknown for any class - nint unknown = Marshal.GetIUnknownForObject(publicSimple); + nint unknown = InteropMarshal.GetIUnknownForObject(publicSimple); unknown.Should().NotBe(0); // Can query it for IDispatch when it is public @@ -41,7 +40,7 @@ public void SimpleClass_Public_CanGetDispatch() hr = ((IUnknown*)unknown)->QueryInterface(IID.Get(), (void**)&dispatchEx); hr.Should().Be(HRESULT.E_NOINTERFACE); - Marshal.Release(unknown); + InteropMarshal.Release(unknown); } [Fact] @@ -49,7 +48,7 @@ public void SimpleClass_Public_DispatchBehavior() { PublicSimpleClass publicSimple = new(); - using ComScope dispatch = new((IDispatch*)Marshal.GetIDispatchForObject(publicSimple)); + using ComScope dispatch = new((IDispatch*)InteropMarshal.GetIDispatchForObject(publicSimple)); using ComScope typeInfo = new(null); HRESULT hr = dispatch.Value->GetTypeInfo(0, Interop.GetThreadLocale(), typeInfo); hr.Should().Be(HRESULT.TLBX_E_LIBNOTREGISTERED); @@ -61,7 +60,7 @@ public void SimpleClass_Private_CannotGetDispatch() PrivateSimpleClass privateSimple = new(); // Can get IUnknown for any class - nint unknown = Marshal.GetIUnknownForObject(privateSimple); + nint unknown = InteropMarshal.GetIUnknownForObject(privateSimple); unknown.Should().NotBe(0); // Can not query it for IDispatch when it is private @@ -74,14 +73,14 @@ public void SimpleClass_Private_CannotGetDispatch() hr = ((IUnknown*)unknown)->QueryInterface(IID.Get(), (void**)&dispatchEx); hr.Should().Be(HRESULT.E_NOINTERFACE); - Marshal.Release(unknown); + InteropMarshal.Release(unknown); } [Fact] public void IReflect_GetDispatch() { ReflectClass reflect = new(); - nint unknown = Marshal.GetIUnknownForObject(reflect); + nint unknown = InteropMarshal.GetIUnknownForObject(reflect); unknown.Should().NotBe(0); // Can query IReflect for IDispatch @@ -96,7 +95,7 @@ public void IReflect_GetDispatch() hr.Should().Be(HRESULT.S_OK); dispatchEx->Release(); - Marshal.Release(unknown); + InteropMarshal.Release(unknown); // IDispatchEx is generated for Type, EnumBuilder, TypeBuilder, and any class that derives from IReflect. } @@ -105,7 +104,7 @@ public void IReflect_GetDispatch() public void IReflect_ISupportErrorInfo() { ReflectClass reflect = new(); - using ComScope unknown = new((IUnknown*)Marshal.GetIUnknownForObject(reflect)); + using ComScope unknown = new((IUnknown*)InteropMarshal.GetIUnknownForObject(reflect)); ISupportErrorInfo* supportErrorInfo; HRESULT hr = ((IUnknown*)unknown)->QueryInterface(IID.Get(), (void**)&supportErrorInfo); @@ -126,7 +125,7 @@ public void IReflect_ISupportErrorInfo() public void IReflect_IConnectionPointContainer_NoAttribute() { ReflectEvent reflect = new(); - using ComScope unknown = new((IUnknown*)Marshal.GetIUnknownForObject(reflect)); + using ComScope unknown = new((IUnknown*)InteropMarshal.GetIUnknownForObject(reflect)); IConnectionPointContainer* container; HRESULT hr = ((IUnknown*)unknown)->QueryInterface(IID.Get(), (void**)&container); @@ -155,7 +154,7 @@ public void IReflect_IConnectionPointContainer_NoAttribute() public void IReflect_IConnectionPointContainer_Attributed() { ReflectSourcedEvent reflect = new(); - using ComScope unknown = new((IUnknown*)Marshal.GetIUnknownForObject(reflect)); + using ComScope unknown = new((IUnknown*)InteropMarshal.GetIUnknownForObject(reflect)); IConnectionPointContainer* container; HRESULT hr = ((IUnknown*)unknown)->QueryInterface(IID.Get(), (void**)&container); @@ -186,7 +185,7 @@ public void IReflect_IConnectionPointContainer_Attributed() public void IReflect_IMarshal() { ReflectClass reflect = new(); - using ComScope unknown = new((IUnknown*)Marshal.GetIUnknownForObject(reflect)); + using ComScope unknown = new((IUnknown*)InteropMarshal.GetIUnknownForObject(reflect)); // In Core, the implementation of IMarshal is simply delegated to CoCreateFreeThreadedMarshaler IMarshal* marshal; @@ -199,7 +198,7 @@ public void IReflect_IMarshal() public void IReflect_IAgileObject() { ReflectClass reflect = new(); - using ComScope unknown = new((IUnknown*)Marshal.GetIUnknownForObject(reflect)); + using ComScope unknown = new((IUnknown*)InteropMarshal.GetIUnknownForObject(reflect)); // IAgileObject marks as the object as free-threaded, which will make the Global Interface Table skip // marshalling across apartments. @@ -213,7 +212,7 @@ public void IReflect_IAgileObject() public void IReflect_IClassInfo() { ReflectClass reflect = new(); - using ComScope unknown = new((IUnknown*)Marshal.GetIUnknownForObject(reflect)); + using ComScope unknown = new((IUnknown*)InteropMarshal.GetIUnknownForObject(reflect)); using ComScope provideClassInfo = new(null); HRESULT hr = ((IUnknown*)unknown)->QueryInterface(IID.Get(), provideClassInfo); @@ -233,7 +232,7 @@ public void IReflect_IClassInfo() public void IReflect_IManagedObject() { ReflectClass reflect = new(); - using ComScope unknown = new((IUnknown*)Marshal.GetIUnknownForObject(reflect)); + using ComScope unknown = new((IUnknown*)InteropMarshal.GetIUnknownForObject(reflect)); // IManagedObject is a .NET Framework only thing, it isn't used/implemented in .NET Core. Other interfaces that // don't exist in .NET Core: IObjectSafety, IWeakReferenceSource, ICustomPropertyProvider, ICCW, and IStringTable. @@ -260,7 +259,7 @@ public void IReflect_DoesNotImpactGetType() public void IReflect_InvokeMember() { InvokeMemberClass invoke = new(); - using ComScope dispatch = new((IDispatch*)Marshal.GetIDispatchForObject(invoke)); + using ComScope dispatch = new((IDispatch*)InteropMarshal.GetIDispatchForObject(invoke)); using ComScope dispatchEx = dispatch.TryQueryInterface(out HRESULT hr); using ComScope typeInfo = new(null); @@ -303,7 +302,7 @@ public void IReflect_Enumerate_ReflectSelf() { ReflectSelf reflect = new(); - using ComScope unknown = new((IUnknown*)Marshal.GetIUnknownForObject(reflect)); + using ComScope unknown = new((IUnknown*)InteropMarshal.GetIUnknownForObject(reflect)); using ComScope dispatchEx = unknown.QueryInterface(); // When Invoking via enumerated ids "ToString" is passed to IReflect.InvokeMember (as opposed to "[DISPID=]"). @@ -325,7 +324,7 @@ public void IReflect_Enumerate_ReflectSelf() hr.Succeeded.Should().BeTrue(); result.vt.Should().Be(VARENUM.VT_BSTR); - result.data.bstrVal.ToString().Should().Be("Tests.Windows.Win32.System.Com.IReflectTests+ReflectSelf"); + result.data.bstrVal.ToString().Should().Be("Windows.Win32.System.Com.IReflectTests+ReflectSelf"); result.Dispose(); @@ -343,7 +342,7 @@ public void IReflect_Enumerate_ReflectSelf() hr.Succeeded.Should().BeTrue(); result.vt.Should().Be(VARENUM.VT_BSTR); - result.data.bstrVal.ToString().Should().Be("Tests.Windows.Win32.System.Com.IReflectTests+ReflectSelf"); + result.data.bstrVal.ToString().Should().Be("Windows.Win32.System.Com.IReflectTests+ReflectSelf"); result.Dispose(); @@ -363,7 +362,7 @@ public void IReflect_Enumerate_ReflectSelf() hr.Succeeded.Should().BeTrue(); result.vt.Should().Be(VARENUM.VT_BSTR); - result.data.bstrVal.ToString().Should().Be("Tests.Windows.Win32.System.Com.IReflectTests+ReflectSelf"); + result.data.bstrVal.ToString().Should().Be("Windows.Win32.System.Com.IReflectTests+ReflectSelf"); // Can we get any more info off of IDispatch? Everything but GetDocumentation takes an index, not an id. using ComScope typeInfo = new(null); @@ -394,7 +393,7 @@ public void IReflect_ObjectBehavior(object? obj, VARENUM expected) { ReflectObjectTypes reflect = new(); - using ComScope unknown = new((IUnknown*)Marshal.GetIUnknownForObject(reflect)); + using ComScope unknown = new((IUnknown*)InteropMarshal.GetIUnknownForObject(reflect)); using ComScope dispatch = unknown.QueryInterface(); var dispatchIds = dispatch.Value->GetAllDispatchIds(); @@ -440,7 +439,7 @@ public void IReflect_NonObjectBehavior() Color = Color.Blue }; - using ComScope unknown = new((IUnknown*)Marshal.GetIUnknownForObject(reflect)); + using ComScope unknown = new((IUnknown*)InteropMarshal.GetIUnknownForObject(reflect)); using ComScope dispatch = unknown.QueryInterface(); var dispatchIds = dispatch.Value->GetAllDispatchIds(); @@ -489,7 +488,7 @@ public void IReflect_NonObjectBehavior() [Theory, MemberData(nameof(EnumerateBehaviorTestData))] public void IReflect_IDispatchEx_Enumerate(object reflect, IEnumerable names) { - using ComScope unknown = new((IUnknown*)Marshal.GetIUnknownForObject(reflect)); + using ComScope unknown = new((IUnknown*)InteropMarshal.GetIUnknownForObject(reflect)); using ComScope dispatch = unknown.QueryInterface(); // Only explicitly provided member info in IReflect is exposed. @@ -513,7 +512,7 @@ public void IReflect_IDispatchDefaultBehavior(object reflect) // All we ever see via IDispatch are the IUnknown methods. // Getting IDispatch calls IReflect.GetProperties, IReflect.GetFields, then IReflect.GetMethods - using ComScope dispatch = new((IDispatch*)Marshal.GetIDispatchForObject(reflect)); + using ComScope dispatch = new((IDispatch*)InteropMarshal.GetIDispatchForObject(reflect)); HRESULT hr = dispatch.Value->GetTypeInfoCount(out uint count); hr.Should().Be(HRESULT.S_OK); count.Should().Be(1); @@ -642,11 +641,13 @@ private class InvokeMemberClass : ReflectClass, IMyDispatch [DispId(1776)] public bool Represent { get; } = true; +#pragma warning disable CA1822 // Mark members as static [ComVisible(true)] public bool Foo() => true; [DispId(1066)] public bool Bar() => true; +#pragma warning restore CA1822 protected override object? InvokeMember( string name, diff --git a/src/thirtytwo_tests/Win32/System/Com/ManagedWrapperTests.cs b/src/thirtytwo_tests/Win32/System/Com/ManagedWrapperTests.cs index f9c97e5..f7a49b2 100644 --- a/src/thirtytwo_tests/Win32/System/Com/ManagedWrapperTests.cs +++ b/src/thirtytwo_tests/Win32/System/Com/ManagedWrapperTests.cs @@ -2,10 +2,9 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Windows.Win32.Foundation; -using Windows.Win32.System.Com; using Windows.Win32.System.Ole; -namespace Tests.Windows.Win32.System.Com; +namespace Windows.Win32.System.Com; public unsafe class ManagedWrapperTests { diff --git a/src/thirtytwo_tests/Win32/System/Com/ReflectPropertiesDispatchTests.cs b/src/thirtytwo_tests/Win32/System/Com/ReflectPropertiesDispatchTests.cs index aebf0b9..7575d51 100644 --- a/src/thirtytwo_tests/Win32/System/Com/ReflectPropertiesDispatchTests.cs +++ b/src/thirtytwo_tests/Win32/System/Com/ReflectPropertiesDispatchTests.cs @@ -3,14 +3,12 @@ using System.Drawing; using System.Runtime.InteropServices; -using Windows.Win32; using Windows.Win32.Foundation; -using Windows.Win32.System.Com; using Windows.Win32.System.Ole; using Windows.Win32.System.Variant; using static Windows.Win32.System.Ole.FDEX_PROP_FLAGS; -namespace Tests.Windows.Win32.System.Com; +namespace Windows.Win32.System.Com; public unsafe class ReflectPropertiesDispatchTests { diff --git a/src/thirtytwo_tests/Win32/System/Com/StandardDispatchTests.cs b/src/thirtytwo_tests/Win32/System/Com/StandardDispatchTests.cs index 5a9d8a3..460c848 100644 --- a/src/thirtytwo_tests/Win32/System/Com/StandardDispatchTests.cs +++ b/src/thirtytwo_tests/Win32/System/Com/StandardDispatchTests.cs @@ -1,13 +1,11 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Windows.Win32; using Windows.Win32.Foundation; -using Windows.Win32.System.Com; using Windows.Win32.System.Ole; using Windows.Win32.System.Variant; -namespace Tests.Windows.Win32.System.Com; +namespace Windows.Win32.System.Com; public unsafe class StandardDispatchTests { diff --git a/src/thirtytwo_tests/Win32/System/Com/VariantTests.cs b/src/thirtytwo_tests/Win32/System/Com/VariantTests.cs index 340bd8a..3233177 100644 --- a/src/thirtytwo_tests/Win32/System/Com/VariantTests.cs +++ b/src/thirtytwo_tests/Win32/System/Com/VariantTests.cs @@ -4,12 +4,11 @@ using System.Drawing; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using Windows.Win32; using Windows.Win32.Foundation; -using Windows.Win32.System.Com; using Windows.Win32.System.Variant; +using InteropMarshal = System.Runtime.InteropServices.Marshal; -namespace Tests.Windows.Win32.System.Com; +namespace Windows.Win32.System.Com; public unsafe class VariantTests { @@ -21,11 +20,11 @@ public void MarshalRectangleToVariant() Rectangle rectangle = new(1, 2, 3, 4); using VARIANT variant = default; nint address = (nint)(void*)&variant; - Assert.Throws(() => Marshal.GetNativeVariantForObject(rectangle, address)); + Assert.Throws(() => InteropMarshal.GetNativeVariantForObject(rectangle, address)); using TestVariant test = new(); using ComScope unknown = test.GetComCallableWrapper(); - ITestVariantComInterop comInterop = (ITestVariantComInterop)Marshal.GetObjectForIUnknown(unknown); + ITestVariantComInterop comInterop = (ITestVariantComInterop)InteropMarshal.GetObjectForIUnknown(unknown); Assert.Throws(() => comInterop.SetVariant(rectangle)); } @@ -52,7 +51,7 @@ public void MarshalArrayToVariant() nint address = (nint)(void*)&variant; // Use Marshal to create the VARIANT directly - Marshal.GetNativeVariantForObject(array, address); + InteropMarshal.GetNativeVariantForObject(array, address); variant.vt.Should().Be(VARENUM.VT_ARRAY | VARENUM.VT_I4); SAFEARRAY* safeArray = variant.data.parray; @@ -67,7 +66,7 @@ public void MarshalArrayToVariant() using ComScope unkown = test.GetComCallableWrapper(); // Use legacy COM interop to create an RCW for the pointer and set through that projection. - ITestVariantComInterop comInterop = (ITestVariantComInterop)Marshal.GetObjectForIUnknown(unkown); + ITestVariantComInterop comInterop = (ITestVariantComInterop)InteropMarshal.GetObjectForIUnknown(unkown); comInterop.SetVariant(array); VARIANT setVariant = test.Variant; @@ -90,7 +89,7 @@ public void ArrayToVariantAfterFreeIsSometimesNewObject() nint address = (nint)(void*)&variant; // Use Marshal to create the VARIANT directly - Marshal.GetNativeVariantForObject(array, address); + InteropMarshal.GetNativeVariantForObject(array, address); variant.vt.Should().Be(VARENUM.VT_ARRAY | VARENUM.VT_I4); safeArray = variant.data.parray; @@ -101,7 +100,7 @@ public void ArrayToVariantAfterFreeIsSometimesNewObject() nint address = (nint)(void*)&variant; // Use Marshal to create the VARIANT directly - Marshal.GetNativeVariantForObject(array, address); + InteropMarshal.GetNativeVariantForObject(array, address); variant.vt.Should().Be(VARENUM.VT_ARRAY | VARENUM.VT_I4); SAFEARRAY* newSafeArray = variant.data.parray; diff --git a/src/thirtytwo_tests/Win32/System/Ole/LoadRegTypeLibTests.cs b/src/thirtytwo_tests/Win32/System/Ole/LoadRegTypeLibTests.cs index 6300a17..06da218 100644 --- a/src/thirtytwo_tests/Win32/System/Ole/LoadRegTypeLibTests.cs +++ b/src/thirtytwo_tests/Win32/System/Ole/LoadRegTypeLibTests.cs @@ -1,12 +1,11 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.System.Com; using Windows.Win32.UI.Accessibility; -namespace Tests.Windows.Win32.System.Ole; +namespace Windows.Win32.System.Ole; public unsafe class LoadRegTypeLibTests { diff --git a/src/thirtytwo_tests/Win32/System/Registry/RegistryTests.cs b/src/thirtytwo_tests/Win32/System/Registry/RegistryTests.cs new file mode 100644 index 0000000..3f4d1af --- /dev/null +++ b/src/thirtytwo_tests/Win32/System/Registry/RegistryTests.cs @@ -0,0 +1,143 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Windows.Win32.System.Registry; + +public class RegistryTests +{ + [Fact] + public void Registry_OpenKey_UserKey() + { + using HKEY key = Registry.OpenKey(HKEY.HKEY_CURRENT_USER, null); + key.IsNull.Should().BeFalse(); + } + + [Fact] + public void Registry_QueryKeyName_UserKey() + { + using HKEY key = Registry.OpenKey(HKEY.HKEY_CURRENT_USER, null); + Registry.QueryKeyName(key).Should().Be(@"\REGISTRY\USER\.DEFAULT"); + } + + [Fact] + public void Registry_QueryKeyName_ClassesRoot() + { + using HKEY key = Registry.OpenKey(HKEY.HKEY_CLASSES_ROOT, null); + Registry.QueryKeyName(key).Should().Be(@"\REGISTRY\MACHINE\SOFTWARE\CLASSES"); + } + + [Fact] + public void Registry_OpenKey_UserSubKey() + { + using HKEY key = Registry.OpenKey( + HKEY.HKEY_CURRENT_USER, + @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"); + + key.IsNull.Should().BeFalse(); + } + + [Fact] + public void Registry_QueryKeyName_UserSubKey() + { + using HKEY key = Registry.OpenKey( + HKEY.HKEY_CURRENT_USER, + @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"); + + // \REGISTRY\USER\S-1-5-21-3004159937-2065658190-3839796541-1001\Software\Microsoft\Windows NT\CurrentVersion\Winlogon + Registry.QueryKeyName(key).Should().StartWith(@"\REGISTRY\USER\S-1").And.EndWith(@"\Software\Microsoft\Windows NT\CurrentVersion\Winlogon"); + } + + + [Fact] + public void HKEY_IsLocalKey() + { + using HKEY key = Registry.OpenKey(HKEY.HKEY_CURRENT_USER, null); + key.IsLocalKey.Should().BeFalse(); + } + + [Fact] + public void HKEY_IsSpecialKey() + { + using HKEY key = Registry.OpenKey(HKEY.HKEY_CLASSES_ROOT, null); + key.IsNull.Should().BeFalse(); + key.IsSpecialKey.Should().BeFalse(); + } + + [Fact] + public void Registry_QueryValueExists() + { + using HKEY key = Registry.OpenKey( + HKEY.HKEY_CURRENT_USER, + @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"); + Registry.QueryValueExists(key, "BuildNumber").Should().BeTrue(); + } + + [Fact] + public void Registry_QueryValueExists_False() + { + using HKEY key = Registry.OpenKey( + HKEY.HKEY_CURRENT_USER, + @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"); + Registry.QueryValueExists(key, "Fizzlewig").Should().BeFalse(); + } + + [Fact] + public void Registry_QueryValueType() + { + using HKEY key = Registry.OpenKey( + HKEY.HKEY_CURRENT_USER, + @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"); + Registry.QueryValueType(key, "BuildNumber").Should().Be(REG_VALUE_TYPE.REG_DWORD); + } + + [Fact] + public void Registry_GetValueNames() + { + using HKEY key = Registry.OpenKey( + HKEY.HKEY_CURRENT_USER, + @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"); + var names = Registry.GetValueNames(key); + names.Should().Contain("BuildNumber"); + } + + [Fact] + public void Registry_GetValueNames_PerformanceData() + { + var names = Registry.GetValueNames(HKEY.HKEY_PERFORMANCE_DATA); + names.Should().ContainInOrder("Global", "Costly"); + } + + [Fact] + public void Registry_GetValueNames_PerformanceText() + { + var names = Registry.GetValueNames(HKEY.HKEY_PERFORMANCE_TEXT); + names.Should().ContainInOrder("Counter", "Help"); + } + + [Fact] + public void Registry_GetValueNames_PerformanceNlsText() + { + var names = Registry.GetValueNames(HKEY.HKEY_PERFORMANCE_NLSTEXT); + names.Should().ContainInOrder("Counter", "Help"); + } + + [Fact] + public void Registry_QueryValue_Uint() + { + using HKEY key = Registry.OpenKey( + HKEY.HKEY_CURRENT_USER, + @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"); + var buildNumber = Registry.QueryValue(key, "BuildNumber"); + buildNumber.Should().BeOfType(); + } + + [Fact] + public void Registry_QueryValue_String() + { + using HKEY key = Registry.OpenKey( + HKEY.HKEY_LOCAL_MACHINE, + @"SOFTWARE\Microsoft\Windows NT\CurrentVersion"); + object? productName = Registry.QueryValue(key, "ProductName"); + productName.Should().BeOfType().Which.Should().StartWith("Windows"); + } +} diff --git a/src/thirtytwo_tests/Win32/UI/Accessibility/AccessibleBaseTests.cs b/src/thirtytwo_tests/Win32/UI/Accessibility/AccessibleBaseTests.cs index d9b137e..178e4c7 100644 --- a/src/thirtytwo_tests/Win32/UI/Accessibility/AccessibleBaseTests.cs +++ b/src/thirtytwo_tests/Win32/UI/Accessibility/AccessibleBaseTests.cs @@ -2,13 +2,11 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Windows.Accessibility; -using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.System.Com; using Windows.Win32.System.Variant; -using Windows.Win32.UI.Accessibility; -namespace Tests.Windows.Win32.UI.Accessibility; +namespace Windows.Win32.UI.Accessibility; public unsafe class AccessibleBaseTests { diff --git a/src/thirtytwo_tests/Win32/UI/Accessibility/CreateStdAccessibleObjectTests.cs b/src/thirtytwo_tests/Win32/UI/Accessibility/CreateStdAccessibleObjectTests.cs index 155a7d3..4de8d7d 100644 --- a/src/thirtytwo_tests/Win32/UI/Accessibility/CreateStdAccessibleObjectTests.cs +++ b/src/thirtytwo_tests/Win32/UI/Accessibility/CreateStdAccessibleObjectTests.cs @@ -1,17 +1,14 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Windows; -using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.System.Com; using Windows.Win32.System.Ole; using Windows.Win32.System.Variant; -using Windows.Win32.UI.Accessibility; using Windows.Win32.UI.WindowsAndMessaging; using IServiceProvider = Windows.Win32.System.Com.IServiceProvider; -namespace Tests.Windows.Win32.UI.Accessibility; +namespace Windows.Win32.UI.Accessibility; [Collection("Accessibility")] public unsafe class CreateStdAccessibleObjectTests diff --git a/src/thirtytwo_tests/Win32/UI/Accessibility/CreateStdAccessibleProxyTests.cs b/src/thirtytwo_tests/Win32/UI/Accessibility/CreateStdAccessibleProxyTests.cs index fe94d36..5331496 100644 --- a/src/thirtytwo_tests/Win32/UI/Accessibility/CreateStdAccessibleProxyTests.cs +++ b/src/thirtytwo_tests/Win32/UI/Accessibility/CreateStdAccessibleProxyTests.cs @@ -1,15 +1,12 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Windows; -using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.System.Com; using Windows.Win32.System.Ole; -using Windows.Win32.UI.Accessibility; using Windows.Win32.UI.WindowsAndMessaging; -namespace Tests.Windows.Win32.UI.Accessibility; +namespace Windows.Win32.UI.Accessibility; [Collection("Accessibility")] public unsafe class CreateStdAccessibleProxyTests diff --git a/src/thirtytwo_tests/Win32/UI/Accessibility/UiaProviderForNonClientTests.cs b/src/thirtytwo_tests/Win32/UI/Accessibility/UiaProviderForNonClientTests.cs index 2394e8d..1c4561e 100644 --- a/src/thirtytwo_tests/Win32/UI/Accessibility/UiaProviderForNonClientTests.cs +++ b/src/thirtytwo_tests/Win32/UI/Accessibility/UiaProviderForNonClientTests.cs @@ -1,15 +1,12 @@ // Copyright (c) Jeremy W. Kuhne. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using Windows; -using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.System.Com; using Windows.Win32.System.Variant; -using Windows.Win32.UI.Accessibility; using Windows.Win32.UI.WindowsAndMessaging; -namespace Tests.Windows.Win32.UI.Accessibility; +namespace Windows.Win32.UI.Accessibility; public unsafe class UiaProviderForNonClientTests { diff --git a/src/thirtytwo_tests/Win32/UI/WindowsAndMessaging/IconTests.cs b/src/thirtytwo_tests/Win32/UI/WindowsAndMessaging/IconTests.cs index 07ddae5..80cea2a 100644 --- a/src/thirtytwo_tests/Win32/UI/WindowsAndMessaging/IconTests.cs +++ b/src/thirtytwo_tests/Win32/UI/WindowsAndMessaging/IconTests.cs @@ -2,12 +2,10 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Drawing; -using Windows; using Windows.Win32.Foundation; using Windows.Win32.UI.Shell; -using Windows.Win32.UI.WindowsAndMessaging; -namespace Tests.Windows.Win32.UI.WindowsAndMessaging; +namespace Windows.Win32.UI.WindowsAndMessaging; public class IconTests { diff --git a/src/thirtytwo_tests/thirtytwo_tests.csproj b/src/thirtytwo_tests/thirtytwo_tests.csproj index 73fb98e..1d8ee4f 100644 --- a/src/thirtytwo_tests/thirtytwo_tests.csproj +++ b/src/thirtytwo_tests/thirtytwo_tests.csproj @@ -7,7 +7,7 @@ false - Tests.Windows + Windows True