mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 17:56:44 +02:00
[MWB] Fix file transfer not working in service mode (#37542)
* [MWB] Fix file transfer not working in service mode * Spellcheck issues
This commit is contained in:
@@ -9,6 +9,7 @@ using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Principal;
|
||||
using System.Windows.Forms;
|
||||
|
||||
@@ -443,7 +444,31 @@ namespace MouseWithoutBorders
|
||||
{
|
||||
_ = Common.ImpersonateLoggedOnUserAndDoSomething(() =>
|
||||
{
|
||||
Setting.Values.Username = WindowsIdentity.GetCurrent(true).Name;
|
||||
// See: https://stackoverflow.com/questions/19487541/how-to-get-windows-user-name-from-sessionid
|
||||
static string GetUsernameBySessionId(int sessionId)
|
||||
{
|
||||
string username = "SYSTEM";
|
||||
if (NativeMethods.WTSQuerySessionInformation(IntPtr.Zero, sessionId, NativeMethods.WTSInfoClass.WTSUserName, out nint buffer, out int strLen) && strLen > 1)
|
||||
{
|
||||
username = Marshal.PtrToStringAnsi(buffer);
|
||||
NativeMethods.WTSFreeMemory(buffer);
|
||||
|
||||
if (NativeMethods.WTSQuerySessionInformation(IntPtr.Zero, sessionId, NativeMethods.WTSInfoClass.WTSDomainName, out buffer, out strLen) && strLen > 1)
|
||||
{
|
||||
username = @$"{Marshal.PtrToStringAnsi(buffer)}\{username}";
|
||||
NativeMethods.WTSFreeMemory(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
return username;
|
||||
}
|
||||
|
||||
// The most direct way to fetch the username is WindowsIdentity.GetCurrent(true).Name
|
||||
// but GetUserName can run within an ExecutionContext.SuppressFlow block, which creates issues
|
||||
// with WindowsIdentity.GetCurrent.
|
||||
// See: https://stackoverflow.com/questions/76998988/exception-when-using-executioncontext-suppressflow-in-net-7
|
||||
// So we use WTSQuerySessionInformation as a workaround.
|
||||
Setting.Values.Username = GetUsernameBySessionId(Process.GetCurrentProcess().SessionId);
|
||||
});
|
||||
}
|
||||
else
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Principal;
|
||||
@@ -39,23 +38,31 @@ namespace MouseWithoutBorders
|
||||
}
|
||||
else
|
||||
{
|
||||
// SuppressFlow fixes an issue on service mode, where WTSQueryUserToken runs successfully once and then fails
|
||||
// on subsequent calls. The reason appears to be an unknown issue with reverting the impersonation,
|
||||
// meaning that subsequent impersonation attempts run as the logged-on user and fail.
|
||||
// This is a workaround.
|
||||
using var asyncFlowControl = System.Threading.ExecutionContext.SuppressFlow();
|
||||
|
||||
uint dwSessionId;
|
||||
IntPtr hUserToken = IntPtr.Zero, hUserTokenDup = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
dwSessionId = (uint)Process.GetCurrentProcess().SessionId;
|
||||
uint rv = NativeMethods.WTSQueryUserToken(dwSessionId, ref hUserToken);
|
||||
Logger.LogDebug("WTSQueryUserToken returned " + rv.ToString(CultureInfo.CurrentCulture));
|
||||
var lastError = rv == 0 ? Marshal.GetLastWin32Error() : 0;
|
||||
|
||||
Logger.LogDebug($"{nameof(NativeMethods.WTSQueryUserToken)} returned {rv.ToString(CultureInfo.CurrentCulture)}");
|
||||
|
||||
if (rv == 0)
|
||||
{
|
||||
Logger.LogDebug($"WTSQueryUserToken failed with: {Marshal.GetLastWin32Error()}.");
|
||||
Logger.Log($"{nameof(NativeMethods.WTSQueryUserToken)} failed with: {lastError}.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!NativeMethods.DuplicateToken(hUserToken, (int)NativeMethods.SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, ref hUserTokenDup))
|
||||
{
|
||||
Logger.TelemetryLogTrace($"DuplicateToken Failed! {Logger.GetStackTrace(new StackTrace())}", SeverityLevel.Warning);
|
||||
Logger.TelemetryLogTrace($"{nameof(NativeMethods.DuplicateToken)} Failed! {Logger.GetStackTrace(new StackTrace())}", SeverityLevel.Warning);
|
||||
_ = NativeMethods.CloseHandle(hUserToken);
|
||||
_ = NativeMethods.CloseHandle(hUserTokenDup);
|
||||
return false;
|
||||
|
||||
@@ -75,6 +75,41 @@ namespace MouseWithoutBorders.Class
|
||||
[DllImport("kernel32.dll")]
|
||||
internal static extern uint WTSGetActiveConsoleSessionId();
|
||||
|
||||
[DllImport("Wtsapi32.dll")]
|
||||
internal static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WTSInfoClass infoClass, out IntPtr ppBuffer, out int pBytesReturned);
|
||||
|
||||
[DllImport("Wtsapi32.dll")]
|
||||
internal static extern void WTSFreeMemory(IntPtr pointer);
|
||||
|
||||
internal enum WTSInfoClass
|
||||
{
|
||||
WTSInitialProgram,
|
||||
WTSApplicationName,
|
||||
WTSWorkingDirectory,
|
||||
WTSOEMId,
|
||||
WTSSessionId,
|
||||
WTSUserName,
|
||||
WTSWinStationName,
|
||||
WTSDomainName,
|
||||
WTSConnectState,
|
||||
WTSClientBuildNumber,
|
||||
WTSClientName,
|
||||
WTSClientDirectory,
|
||||
WTSClientProductId,
|
||||
WTSClientHardwareId,
|
||||
WTSClientAddress,
|
||||
WTSClientDisplay,
|
||||
WTSClientProtocolType,
|
||||
WTSIdleTime,
|
||||
WTSLogonTime,
|
||||
WTSIncomingBytes,
|
||||
WTSOutgoingBytes,
|
||||
WTSIncomingFrames,
|
||||
WTSOutgoingFrames,
|
||||
WTSClientInfo,
|
||||
WTSSessionInfo,
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
@@ -812,7 +847,7 @@ namespace MouseWithoutBorders.Class
|
||||
|
||||
// [DllImport("kernel32.dll", SetLastError = true)]
|
||||
// internal static extern IntPtr CreateToolhelp32Snapshot(UInt32 dwFlags, UInt32 th32ProcessID);
|
||||
[DllImport("Wtsapi32.dll")]
|
||||
[DllImport("Wtsapi32.dll", SetLastError = true)]
|
||||
internal static extern uint WTSQueryUserToken(uint SessionId, ref IntPtr phToken);
|
||||
|
||||
[SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "1", Justification = "Dotnet port with style preservation")]
|
||||
|
||||
Reference in New Issue
Block a user