尝试在虚拟机中部署一个作为后台服务运行的控制台应用程序

问题描述 投票:0回答:1

我正在尝试部署一个作为后台服务运行的控制台应用程序,该控制台应用程序会截取用户当前屏幕的屏幕截图并将其保存在 blob 容器中,当我手动单击 exe 文件时,代码可以在本地计算机和虚拟机上完美运行并运行它,但是当我通过创建服务来自动化相同的操作时,存储在 blob 中的所有 ss 都是空白的,有人可以帮助我知道发生了什么吗?

我正在尝试将 ss 保存在 blob 文件中,以便 c# 控制台应用程序应该在我的 azure vm 中作为后台服务工作,但是该服务正在运行,存储在 blob 中的 ss 是空白的,但是当我通过单击它手动运行 exe 文件时,它是很好

c# azure blob azure-webjobs background-service
1个回答
0
投票
您很可能正在尝试捕获远程会话 (RDP) 的屏幕。当您在本地运行时,您正在处理默认(控制台)会话。

你有两个选择。你可以:

    使用其中一种启动方法(例如 RunOmce 或 RunOnceEx)在用户登录时运行应用程序,或者,
  1. 修改你的代码。
如果修改代码,则需要枚举虚拟机上的登录会话,获取用户令牌,并在用户会话中创建一个进程。

假设您的代码是 C#.NET(不太难反应为 C# 或 C++)...

枚举会话

using System; using System.Runtime.InteropServices; public class SessionHelper { [DllImport("wtsapi32.dll")] private static extern bool WTSEnumerateSessions(IntPtr hServer, int Reserved, int Version, ref IntPtr ppSessionInfo, ref int pCount); [DllImport("wtsapi32.dll")] private static extern void WTSFreeMemory(IntPtr pMemory); [DllImport("wtsapi32.dll")] private static extern bool WTSQueryUserToken(uint sessionId, out IntPtr phToken); public static uint GetActiveSessionId() { IntPtr ppSessionInfo = IntPtr.Zero; int count = 0; if (WTSEnumerateSessions(IntPtr.Zero, 0, 1, ref ppSessionInfo, ref count)) { int dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO)); long current = (long)ppSessionInfo; for (int i = 0; i < count; i++) { WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((IntPtr)current, typeof(WTS_SESSION_INFO)); current += dataSize; if (si.State == WTS_CONNECTSTATE_CLASS.WTSActive) { WTSFreeMemory(ppSessionInfo); return si.SessionId; } } WTSFreeMemory(ppSessionInfo); } throw new Exception("No active sessions found"); } public static IntPtr GetUserToken(uint sessionId) { if (!WTSQueryUserToken(sessionId, out IntPtr token)) throw new Exception("Could not get user token"); return token; } [StructLayout(LayoutKind.Sequential)] private struct WTS_SESSION_INFO { public uint SessionId; [MarshalAs(UnmanagedType.LPStr)] public string pWinStationName; public WTS_CONNECTSTATE_CLASS State; } private enum WTS_CONNECTSTATE_CLASS { WTSActive } }
在用户会话中创建进程

using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Security.Principal; public class ProcessHelper { [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern bool CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); public static void StartCaptureProcess(IntPtr userToken) { STARTUPINFO si = new STARTUPINFO(); PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); si.cb = Marshal.SizeOf(si); string captureApp = @"C:\Path\To\YourCaptureApp.exe"; // Path to your screen capture application if (!CreateProcessAsUser(userToken, captureApp, null, IntPtr.Zero, IntPtr.Zero, false, 0, IntPtr.Zero, null, ref si, out pi)) throw new Exception("Could not start process in user session"); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } [DllImport("kernel32.dll", SetLastError = true)] private static extern bool CloseHandle(IntPtr hObject); [StructLayout(LayoutKind.Sequential)] private struct STARTUPINFO { public int cb; public string lpReserved; public string lpDesktop; public string lpTitle; public int dwX; public int dwY; public int dwXSize; public int dwYSize; public int dwXCountChars; public int dwYCountChars; public int dwFillAttribute; public int dwFlags; public short wShowWindow; public short cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } [StructLayout(LayoutKind.Sequential)] private struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public uint dwProcessId; public uint dwThreadId; } }

确保您遵守法律。用户应该意识到,出于隐私原因和数据保护,他们的会话被捕获。

© www.soinside.com 2019 - 2024. All rights reserved.