mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-07 11:46:30 +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.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
@@ -443,7 +444,31 @@ namespace MouseWithoutBorders
|
|||||||
{
|
{
|
||||||
_ = Common.ImpersonateLoggedOnUserAndDoSomething(() =>
|
_ = 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
|
else
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
@@ -39,23 +38,31 @@ namespace MouseWithoutBorders
|
|||||||
}
|
}
|
||||||
else
|
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;
|
uint dwSessionId;
|
||||||
IntPtr hUserToken = IntPtr.Zero, hUserTokenDup = IntPtr.Zero;
|
IntPtr hUserToken = IntPtr.Zero, hUserTokenDup = IntPtr.Zero;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
dwSessionId = (uint)Process.GetCurrentProcess().SessionId;
|
dwSessionId = (uint)Process.GetCurrentProcess().SessionId;
|
||||||
uint rv = NativeMethods.WTSQueryUserToken(dwSessionId, ref hUserToken);
|
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)
|
if (rv == 0)
|
||||||
{
|
{
|
||||||
Logger.LogDebug($"WTSQueryUserToken failed with: {Marshal.GetLastWin32Error()}.");
|
Logger.Log($"{nameof(NativeMethods.WTSQueryUserToken)} failed with: {lastError}.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!NativeMethods.DuplicateToken(hUserToken, (int)NativeMethods.SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, ref hUserTokenDup))
|
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(hUserToken);
|
||||||
_ = NativeMethods.CloseHandle(hUserTokenDup);
|
_ = NativeMethods.CloseHandle(hUserTokenDup);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -75,6 +75,41 @@ namespace MouseWithoutBorders.Class
|
|||||||
[DllImport("kernel32.dll")]
|
[DllImport("kernel32.dll")]
|
||||||
internal static extern uint WTSGetActiveConsoleSessionId();
|
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
|
#endif
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
@@ -812,7 +847,7 @@ namespace MouseWithoutBorders.Class
|
|||||||
|
|
||||||
// [DllImport("kernel32.dll", SetLastError = true)]
|
// [DllImport("kernel32.dll", SetLastError = true)]
|
||||||
// internal static extern IntPtr CreateToolhelp32Snapshot(UInt32 dwFlags, UInt32 th32ProcessID);
|
// 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);
|
internal static extern uint WTSQueryUserToken(uint SessionId, ref IntPtr phToken);
|
||||||
|
|
||||||
[SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "1", Justification = "Dotnet port with style preservation")]
|
[SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "1", Justification = "Dotnet port with style preservation")]
|
||||||
|
|||||||
Reference in New Issue
Block a user