Skip to content
This repository was archived by the owner on Jul 26, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/Kernel32.Tests/Kernel32Facts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.IO;
using System.Runtime.InteropServices;
using PInvoke;
using Xunit;
using static PInvoke.Kernel32;
Expand All @@ -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());
}
}
9 changes: 9 additions & 0 deletions src/Kernel32/Kernel32.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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

Expand Down Expand Up @@ -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);

/// <summary>
/// Sets the last-error code for the calling thread.
/// </summary>
/// <param name="dwErrCode">The last-error code for the thread.</param>
[DllImport(api_ms_win_core_errorhandling_l1_1_1, SetLastError = true)]
public static extern void SetLastError(uint dwErrCode);

/// <summary>
/// Closes a file search handle opened by the FindFirstFile, FindFirstFileEx, FindFirstFileNameW,
/// FindFirstFileNameTransactedW, FindFirstFileTransacted, FindFirstStreamTransactedW, or FindFirstStreamW functions.
Expand Down
1 change: 1 addition & 0 deletions src/Kernel32/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
static extern PInvoke.Kernel32.SetLastError(uint dwErrCode) -> void
34 changes: 34 additions & 0 deletions src/User32.Tests/User32Facts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
}
}
17 changes: 17 additions & 0 deletions src/User32/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -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
21 changes: 21 additions & 0 deletions src/User32/User32+GetNextWindowCommands.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <content>
/// Contains the <see cref="GetNextWindowCommands"/> nested type.
/// </content>
public partial class User32
{
/// <summary>The commands that can be used as arguments to <see cref="GetNextWindow" />.</summary>
public enum GetNextWindowCommands
{
/// <summary>Returns a handle to the window below the given window.</summary>
GW_HWNDNEXT = GetWindowCommands.GW_HWNDNEXT,

/// <summary>Returns a handle to the window above the given window.</summary>
GW_HWNDPREV = GetWindowCommands.GW_HWNDPREV,
}
}
}
42 changes: 42 additions & 0 deletions src/User32/User32+GetWindowCommands.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <content>
/// Contains the <see cref="GetWindowCommands"/> nested type.
/// </content>
public partial class User32
{
/// <summary>The commands that can be used as arguments to <see cref="GetWindow" />.</summary>
public enum GetWindowCommands
{
/// <summary>
/// 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.
/// </summary>
GW_HWNDFIRST = 0,

/// <summary>
/// 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.
/// </summary>
GW_HWNDLAST = 1,

/// <summary>Returns a handle to the window below the given window.</summary>
GW_HWNDNEXT = 2,

/// <summary>Returns a handle to the window above the given window.</summary>
GW_HWNDPREV = 3,

/// <summary>The retrieved handle identifies the specified window's owner window, if any. For more information, see Owned Windows.</summary>
GW_OWNER = 4,

/// <summary>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.</summary>
GW_CHILD = 5,

/// <summary>The retrieved handle identifies the enabled popup window owned by the specified window (the search uses the first such window found using <see cref="GW_HWNDNEXT" />); otherwise, if there are no enabled popup windows, the retrieved handle is that of the specified window.</summary>
GW_ENABLEDPOPUP = 6,
}
}
}
74 changes: 74 additions & 0 deletions src/User32/User32.cs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,12 @@ public static extern unsafe int GetClassName(
[Friendly(FriendlyFlags.Array)] char* lpClassName,
int nMaxCount);

/// <summary>
/// Retrieves the identifier of the thread that created the specified window and, optionally, the identifier of the process that created the window.
/// </summary>
/// <param name="hWnd">A handle to the window. </param>
/// <param name="lpdwProcessId">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.</param>
/// <returns>The return value is the identifier of the thread that created the window. </returns>
[DllImport(nameof(User32), SetLastError = true)]
public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);

Expand Down Expand Up @@ -2362,6 +2368,51 @@ public static extern unsafe int GetWindowText(
[Friendly(FriendlyFlags.Array)] char* lpString,
int nMaxCount);

/// <summary>
/// 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.
/// </summary>
/// <param name="hWnd">A handle to the window or control whose text is to be changed. </param>
/// <param name="lpString">The new title or control text. </param>
/// <returns>
/// 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.
/// </returns>
[DllImport(nameof(User32), CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern unsafe bool SetWindowText(
IntPtr hWnd,
string lpString);

/// <summary>
/// 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.
/// </summary>
/// <param name="hWnd">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.</param>
/// <returns>
/// 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.
/// </returns>
[DllImport(nameof(User32), SetLastError = true)]
public static extern IntPtr GetTopWindow(IntPtr hWnd);

/// <summary>
/// Retrieves a handle to a window that has the specified relationship (Z-Order or owner) to the specified window.
/// </summary>
/// <param name="hWnd">A handle to a window. The window handle retrieved is relative to this window, based on the value of the wCmd parameter. </param>
/// <param name="wCmd">The relationship between the specified window and the window whose handle is to be retrieved.</param>
/// <returns>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.</returns>
[DllImport(nameof(User32), SetLastError = true)]
public static extern IntPtr GetWindow(
IntPtr hWnd,
GetWindowCommands wCmd);

/// <summary>
/// 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.
/// </summary>
/// <param name="hWnd">A handle to a window. The window handle retrieved is relative to this window, based on the value of the wCmd parameter. </param>
/// <param name="wCmd">Indicates whether the function returns a handle to the next window or the previous window.</param>
/// <returns>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.</returns>
public static IntPtr GetNextWindow(IntPtr hWnd, GetNextWindowCommands wCmd) => GetWindow(hWnd, (GetWindowCommands)wCmd);

/// <summary>
/// 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
Expand Down Expand Up @@ -2548,6 +2599,20 @@ public static unsafe extern IntPtr CreateWindowEx(
IntPtr hInstance,
void* lpParam);

/// <summary>
/// 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.
/// </summary>
/// <param name="hWnd">A handle to the window to be destroyed. </param>
/// <returns>
/// 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.
/// </returns>
[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);

Expand Down Expand Up @@ -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);

/// <summary>
/// Sets the last-error code for the calling thread.
/// Currently, this function is identical to the SetLastError function. The second parameter is ignored.
/// </summary>
/// <param name="dwErrCode">The last-error code for the thread.</param>
/// <param name="dwType">This parameter is ignored.</param>
[DllImport(nameof(User32), SetLastError = true)]
public static extern void SetLastErrorEx(uint dwErrCode, uint dwType);

/// <summary>
/// The BeginPaint function prepares the specified window for painting and fills a <see cref="PAINTSTRUCT"/> structure with information about the painting.
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions src/Windows.Core/ApiSets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,10 @@ public static class ApiSets
/// The "api-ms-win-core-libraryloader-l1-1-1.dll" constant.
/// </summary>
public const string api_ms_win_core_libraryloader_l1_1_1 = "api-ms-win-core-libraryloader-l1-1-1.dll";

/// <summary>
/// The "api-ms-win-core-errorhandling-l1-1-1.dll" constant.
/// </summary>
public const string api_ms_win_core_errorhandling_l1_1_1 = "api-ms-win-core-errorhandling-l1-1-1.dll";
}
}
1 change: 1 addition & 0 deletions src/Windows.Core/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const PInvoke.ApiSets.api_ms_win_core_errorhandling_l1_1_1 = "api-ms-win-core-errorhandling-l1-1-1.dll" -> string