diff --git a/src/Kernel32.Tests/Kernel32Facts.cs b/src/Kernel32.Tests/Kernel32Facts.cs
index 93e9d8f6..abb7ad04 100644
--- a/src/Kernel32.Tests/Kernel32Facts.cs
+++ b/src/Kernel32.Tests/Kernel32Facts.cs
@@ -3,6 +3,7 @@
using System;
using System.IO;
+using System.Runtime.InteropServices;
using PInvoke;
using Xunit;
using static PInvoke.Kernel32;
@@ -22,4 +23,11 @@ public void GetTickCount64_Nonzero()
ulong result = GetTickCount64();
Assert.NotEqual(0ul, result);
}
+
+ [Fact]
+ public void SetLastError_ImpactsMarshalGetLastWin32Error()
+ {
+ SetLastError(2);
+ Assert.Equal(2, Marshal.GetLastWin32Error());
+ }
}
diff --git a/src/Kernel32/Kernel32.cs b/src/Kernel32/Kernel32.cs
index ec20b0dd..8a459e10 100644
--- a/src/Kernel32/Kernel32.cs
+++ b/src/Kernel32/Kernel32.cs
@@ -43,6 +43,7 @@ public static partial class Kernel32
private const string api_ms_win_core_libraryloader_l1_1_1 = ApiSets.api_ms_win_core_libraryloader_l1_1_1;
private const string api_ms_win_core_sysinfo_l1_2_1 = ApiSets.api_ms_win_core_sysinfo_l1_2_1;
private const string api_ms_win_core_sysinfo_l1_2_0 = ApiSets.api_ms_win_core_sysinfo_l1_2_0;
+ private const string api_ms_win_core_errorhandling_l1_1_1 = ApiSets.api_ms_win_core_errorhandling_l1_1_1;
#else
private const string api_ms_win_core_localization_l1_2_0 = nameof(Kernel32);
private const string api_ms_win_core_processthreads_l1_1_1 = nameof(Kernel32);
@@ -57,6 +58,7 @@ public static partial class Kernel32
private const string api_ms_win_core_libraryloader_l1_1_1 = nameof(Kernel32);
private const string api_ms_win_core_sysinfo_l1_2_1 = nameof(Kernel32);
private const string api_ms_win_core_sysinfo_l1_2_0 = nameof(Kernel32);
+ private const string api_ms_win_core_errorhandling_l1_1_1 = nameof(Kernel32);
#endif
#pragma warning restore SA1303 // Const field names must begin with upper-case letter
@@ -661,6 +663,13 @@ public static extern unsafe bool DeviceIoControl(
[DllImport(api_ms_win_core_libraryloader_l1_1_1, CharSet = CharSet.Unicode, SetLastError = true)]
public static unsafe extern void* LockResource(IntPtr hResData);
+ ///
+ /// Sets the last-error code for the calling thread.
+ ///
+ /// The last-error code for the thread.
+ [DllImport(api_ms_win_core_errorhandling_l1_1_1, SetLastError = true)]
+ public static extern void SetLastError(uint dwErrCode);
+
///
/// Closes a file search handle opened by the FindFirstFile, FindFirstFileEx, FindFirstFileNameW,
/// FindFirstFileNameTransactedW, FindFirstFileTransacted, FindFirstStreamTransactedW, or FindFirstStreamW functions.
diff --git a/src/Kernel32/PublicAPI.Unshipped.txt b/src/Kernel32/PublicAPI.Unshipped.txt
index e69de29b..7e7ee73a 100644
--- a/src/Kernel32/PublicAPI.Unshipped.txt
+++ b/src/Kernel32/PublicAPI.Unshipped.txt
@@ -0,0 +1 @@
+static extern PInvoke.Kernel32.SetLastError(uint dwErrCode) -> void
\ No newline at end of file
diff --git a/src/User32.Tests/User32Facts.cs b/src/User32.Tests/User32Facts.cs
index 39d6da17..9dddac2c 100644
--- a/src/User32.Tests/User32Facts.cs
+++ b/src/User32.Tests/User32Facts.cs
@@ -58,4 +58,38 @@ public unsafe void INPUT_UnionMemoryAlignment()
Assert.Equal(IntPtr.Size, (long)&input.Inputs.mi - (long)&input);
Assert.Equal(IntPtr.Size, (long)&input.Inputs.ki - (long)&input);
}
+
+ [Fact]
+ public void GetWindowTextHelper_WithNonzeroLastError()
+ {
+ IntPtr hwnd = CreateWindow(
+ "BUTTON",
+ string.Empty, // empty window name
+ WindowStyles.WS_OVERLAPPED,
+ 0,
+ 0,
+ 0,
+ 0,
+ IntPtr.Zero,
+ IntPtr.Zero,
+ Process.GetCurrentProcess().Handle,
+ IntPtr.Zero);
+ if (hwnd == IntPtr.Zero)
+ {
+ throw new Win32Exception();
+ }
+
+ try
+ {
+ Kernel32.SetLastError(2);
+ Assert.Equal(string.Empty, GetWindowText(hwnd));
+ }
+ finally
+ {
+ if (!DestroyWindow(hwnd))
+ {
+ throw new Win32Exception();
+ }
+ }
+ }
}
diff --git a/src/User32/PublicAPI.Unshipped.txt b/src/User32/PublicAPI.Unshipped.txt
index e69de29b..700d1edf 100644
--- a/src/User32/PublicAPI.Unshipped.txt
+++ b/src/User32/PublicAPI.Unshipped.txt
@@ -0,0 +1,17 @@
+PInvoke.User32.GetNextWindowCommands
+PInvoke.User32.GetNextWindowCommands.GW_HWNDNEXT = 2 -> PInvoke.User32.GetNextWindowCommands
+PInvoke.User32.GetNextWindowCommands.GW_HWNDPREV = 3 -> PInvoke.User32.GetNextWindowCommands
+PInvoke.User32.GetWindowCommands
+PInvoke.User32.GetWindowCommands.GW_CHILD = 5 -> PInvoke.User32.GetWindowCommands
+PInvoke.User32.GetWindowCommands.GW_ENABLEDPOPUP = 6 -> PInvoke.User32.GetWindowCommands
+PInvoke.User32.GetWindowCommands.GW_HWNDFIRST = 0 -> PInvoke.User32.GetWindowCommands
+PInvoke.User32.GetWindowCommands.GW_HWNDLAST = 1 -> PInvoke.User32.GetWindowCommands
+PInvoke.User32.GetWindowCommands.GW_HWNDNEXT = 2 -> PInvoke.User32.GetWindowCommands
+PInvoke.User32.GetWindowCommands.GW_HWNDPREV = 3 -> PInvoke.User32.GetWindowCommands
+PInvoke.User32.GetWindowCommands.GW_OWNER = 4 -> PInvoke.User32.GetWindowCommands
+static PInvoke.User32.GetNextWindow(System.IntPtr hWnd, PInvoke.User32.GetNextWindowCommands wCmd) -> System.IntPtr
+static extern PInvoke.User32.DestroyWindow(System.IntPtr hWnd) -> bool
+static extern PInvoke.User32.GetTopWindow(System.IntPtr hWnd) -> System.IntPtr
+static extern PInvoke.User32.GetWindow(System.IntPtr hWnd, PInvoke.User32.GetWindowCommands wCmd) -> System.IntPtr
+static extern PInvoke.User32.SetLastErrorEx(uint dwErrCode, uint dwType) -> void
+static extern PInvoke.User32.SetWindowText(System.IntPtr hWnd, string lpString) -> bool
\ No newline at end of file
diff --git a/src/User32/User32+GetNextWindowCommands.cs b/src/User32/User32+GetNextWindowCommands.cs
new file mode 100644
index 00000000..51609939
--- /dev/null
+++ b/src/User32/User32+GetNextWindowCommands.cs
@@ -0,0 +1,21 @@
+// Copyright (c) to owners found in https://github.com/AArnott/pinvoke/blob/master/COPYRIGHT.md. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+
+namespace PInvoke
+{
+ ///
+ /// Contains the nested type.
+ ///
+ public partial class User32
+ {
+ /// The commands that can be used as arguments to .
+ public enum GetNextWindowCommands
+ {
+ /// Returns a handle to the window below the given window.
+ GW_HWNDNEXT = GetWindowCommands.GW_HWNDNEXT,
+
+ /// Returns a handle to the window above the given window.
+ GW_HWNDPREV = GetWindowCommands.GW_HWNDPREV,
+ }
+ }
+}
diff --git a/src/User32/User32+GetWindowCommands.cs b/src/User32/User32+GetWindowCommands.cs
new file mode 100644
index 00000000..70d876b9
--- /dev/null
+++ b/src/User32/User32+GetWindowCommands.cs
@@ -0,0 +1,42 @@
+// Copyright (c) to owners found in https://github.com/AArnott/pinvoke/blob/master/COPYRIGHT.md. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+
+namespace PInvoke
+{
+ ///
+ /// Contains the nested type.
+ ///
+ public partial class User32
+ {
+ /// The commands that can be used as arguments to .
+ public enum GetWindowCommands
+ {
+ ///
+ /// The retrieved handle identifies the window of the same type that is highest in the Z order.
+ /// If the specified window is a topmost window, the handle identifies a topmost window. If the specified window is a top-level window, the handle identifies a top-level window. If the specified window is a child window, the handle identifies a sibling window.
+ ///
+ GW_HWNDFIRST = 0,
+
+ ///
+ /// The retrieved handle identifies the window of the same type that is lowest in the Z order.
+ /// If the specified window is a topmost window, the handle identifies a topmost window. If the specified window is a top-level window, the handle identifies a top-level window. If the specified window is a child window, the handle identifies a sibling window.
+ ///
+ GW_HWNDLAST = 1,
+
+ /// Returns a handle to the window below the given window.
+ GW_HWNDNEXT = 2,
+
+ /// Returns a handle to the window above the given window.
+ GW_HWNDPREV = 3,
+
+ /// The retrieved handle identifies the specified window's owner window, if any. For more information, see Owned Windows.
+ GW_OWNER = 4,
+
+ /// The retrieved handle identifies the child window at the top of the Z order, if the specified window is a parent window; otherwise, the retrieved handle is NULL. The function examines only child windows of the specified window. It does not examine descendant windows.
+ GW_CHILD = 5,
+
+ /// The retrieved handle identifies the enabled popup window owned by the specified window (the search uses the first such window found using ); otherwise, if there are no enabled popup windows, the retrieved handle is that of the specified window.
+ GW_ENABLEDPOPUP = 6,
+ }
+ }
+}
diff --git a/src/User32/User32.cs b/src/User32/User32.cs
index e4b3cbae..20c50d2a 100644
--- a/src/User32/User32.cs
+++ b/src/User32/User32.cs
@@ -237,6 +237,12 @@ public static extern unsafe int GetClassName(
[Friendly(FriendlyFlags.Array)] char* lpClassName,
int nMaxCount);
+ ///
+ /// Retrieves the identifier of the thread that created the specified window and, optionally, the identifier of the process that created the window.
+ ///
+ /// A handle to the window.
+ /// A pointer to a variable that receives the process identifier. If this parameter is not NULL, GetWindowThreadProcessId copies the identifier of the process to the variable; otherwise, it does not.
+ /// The return value is the identifier of the thread that created the window.
[DllImport(nameof(User32), SetLastError = true)]
public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
@@ -2362,6 +2368,51 @@ public static extern unsafe int GetWindowText(
[Friendly(FriendlyFlags.Array)] char* lpString,
int nMaxCount);
+ ///
+ /// Changes the text of the specified window's title bar (if it has one). If the specified window is a control, the text of the control is changed. However, SetWindowText cannot change the text of a control in another application.
+ ///
+ /// A handle to the window or control whose text is to be changed.
+ /// The new title or control text.
+ ///
+ /// If the function succeeds, the return value is nonzero.
+ /// If the function fails, the return value is zero. To get extended error information, call GetLastError.
+ ///
+ [DllImport(nameof(User32), CharSet = CharSet.Unicode, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern unsafe bool SetWindowText(
+ IntPtr hWnd,
+ string lpString);
+
+ ///
+ /// Examines the Z order of the child windows associated with the specified parent window and retrieves a handle to the child window at the top of the Z order.
+ ///
+ /// A handle to the parent window whose child windows are to be examined. If this parameter is NULL, the function returns a handle to the window at the top of the Z order.
+ ///
+ /// If the function succeeds, the return value is a handle to the child window at the top of the Z order. If the specified window has no child windows, the return value is NULL. To get extended error information, use the GetLastError function.
+ ///
+ [DllImport(nameof(User32), SetLastError = true)]
+ public static extern IntPtr GetTopWindow(IntPtr hWnd);
+
+ ///
+ /// Retrieves a handle to a window that has the specified relationship (Z-Order or owner) to the specified window.
+ ///
+ /// A handle to a window. The window handle retrieved is relative to this window, based on the value of the wCmd parameter.
+ /// The relationship between the specified window and the window whose handle is to be retrieved.
+ /// If the function succeeds, the return value is a handle to the next (or previous) window. If there is no next (or previous) window, the return value is NULL. To get extended error information, call GetLastError.
+ [DllImport(nameof(User32), SetLastError = true)]
+ public static extern IntPtr GetWindow(
+ IntPtr hWnd,
+ GetWindowCommands wCmd);
+
+ ///
+ /// Retrieves a handle to the next or previous window in the Z-Order. The next window is below the specified window; the previous window is above.
+ /// If the specified window is a topmost window, the function searches for a topmost window. If the specified window is a top-level window, the function searches for a top-level window. If the specified window is a child window, the function searches for a child window.
+ ///
+ /// A handle to a window. The window handle retrieved is relative to this window, based on the value of the wCmd parameter.
+ /// Indicates whether the function returns a handle to the next window or the previous window.
+ /// If the function succeeds, the return value is a handle to the next (or previous) window. If there is no next (or previous) window, the return value is NULL. To get extended error information, call GetLastError.
+ public static IntPtr GetNextWindow(IntPtr hWnd, GetNextWindowCommands wCmd) => GetWindow(hWnd, (GetWindowCommands)wCmd);
+
///
/// Moves the cursor to the specified screen coordinates. If the new coordinates are not within the screen
/// rectangle set by the most recent ClipCursor function call, the system automatically adjusts the coordinates so that the
@@ -2548,6 +2599,20 @@ public static unsafe extern IntPtr CreateWindowEx(
IntPtr hInstance,
void* lpParam);
+ ///
+ /// Destroys the specified window. The function sends WM_DESTROY and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus from it. The function also destroys the window's menu, flushes the thread message queue, destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if the window is at the top of the viewer chain).
+ /// If the specified window is a parent or owner window, DestroyWindow automatically destroys the associated child or owned windows when it destroys the parent or owner window. The function first destroys child or owned windows, and then it destroys the parent or owner window.
+ /// DestroyWindow also destroys modeless dialog boxes created by the CreateDialog function.
+ ///
+ /// A handle to the window to be destroyed.
+ ///
+ /// If the function succeeds, the return value is nonzero.
+ /// If the function fails, the return value is zero. To get extended error information, call GetLastError.
+ ///
+ [DllImport(nameof(User32), SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool DestroyWindow(IntPtr hWnd);
+
[DllImport(nameof(User32), SetLastError = true)]
public static extern IntPtr DispatchMessage(ref MSG lpmsg);
@@ -2671,6 +2736,15 @@ public static extern unsafe bool SetWindowPlacement(
[DllImport(nameof(User32), SetLastError = true)]
public static extern unsafe void keybd_event(byte bVk, byte bScan, KEYEVENTF dwFlags, void* dwExtraInfo);
+ ///
+ /// Sets the last-error code for the calling thread.
+ /// Currently, this function is identical to the SetLastError function. The second parameter is ignored.
+ ///
+ /// The last-error code for the thread.
+ /// This parameter is ignored.
+ [DllImport(nameof(User32), SetLastError = true)]
+ public static extern void SetLastErrorEx(uint dwErrCode, uint dwType);
+
///
/// The BeginPaint function prepares the specified window for painting and fills a structure with information about the painting.
///
diff --git a/src/Windows.Core/ApiSets.cs b/src/Windows.Core/ApiSets.cs
index 57851ca1..0ffae8aa 100644
--- a/src/Windows.Core/ApiSets.cs
+++ b/src/Windows.Core/ApiSets.cs
@@ -118,5 +118,10 @@ public static class ApiSets
/// The "api-ms-win-core-libraryloader-l1-1-1.dll" constant.
///
public const string api_ms_win_core_libraryloader_l1_1_1 = "api-ms-win-core-libraryloader-l1-1-1.dll";
+
+ ///
+ /// The "api-ms-win-core-errorhandling-l1-1-1.dll" constant.
+ ///
+ public const string api_ms_win_core_errorhandling_l1_1_1 = "api-ms-win-core-errorhandling-l1-1-1.dll";
}
}
diff --git a/src/Windows.Core/PublicAPI.Unshipped.txt b/src/Windows.Core/PublicAPI.Unshipped.txt
index e69de29b..6d3031b9 100644
--- a/src/Windows.Core/PublicAPI.Unshipped.txt
+++ b/src/Windows.Core/PublicAPI.Unshipped.txt
@@ -0,0 +1 @@
+const PInvoke.ApiSets.api_ms_win_core_errorhandling_l1_1_1 = "api-ms-win-core-errorhandling-l1-1-1.dll" -> string
\ No newline at end of file