Pertanyaan Apa cara terbaik untuk menonton aplikasi desktop?


Saya perlu beberapa cara untuk memantau aplikasi desktop dan memulai ulang jika ia mati.

Awalnya saya berasumsi cara terbaik adalah memonitor / me-restart proses dari layanan Windows, sampai saya menemukan bahwa sejak Vista Layanan Windows tidak boleh berinteraksi dengan desktop

Saya telah melihat beberapa pertanyaan yang berkaitan dengan masalah ini, tetapi setiap jawaban yang saya lihat melibatkan beberapa jenis peretasan yang tidak disarankan oleh Microsoft dan kemungkinan akan berhenti bekerja di pembaruan OS mendatang.

Jadi, layanan Windows mungkin bukan pilihan lagi. Saya mungkin bisa saja membuat aplikasi desktop / konsol yang berbeda untuk melakukan ini, tetapi jenis itu mengalahkan tujuannya.

Manakah cara paling elegan untuk mencapai ini, menurut pendapat Anda?

EDIT: Ini bukan malware maupun virus. Aplikasi yang membutuhkan pemantauan adalah pemutar media yang akan berjalan pada sistem yang disematkan, dan meskipun saya mencoba untuk menutupi semua skenario macet yang mungkin, saya tidak dapat mengambil risiko jika mengalami error yang tidak terduga (terjadi s ** t) . Pengawas ini hanya akan menjadi penjaga jika semua yang lainnya salah. Juga, karena pemain akan menampilkan konten flash pihak ketiga, plus tambahan akan menjadi contoh untuk memantau penggunaan sumber daya, dan restart pemain jika mengatakan, beberapa film flash jelek mulai membocorkan memori.

EDIT 2: Saya lupa menyebutkan, aplikasi yang ingin saya pantau / mulai ulang sama sekali tidak perlu untuk berjalan di akun LocalSystem maupun dengan hak administratif apa pun. Sebenarnya, saya akan lebih suka untuk menjalankan menggunakan kredensial pengguna yang saat ini login.


22
2018-06-21 20:40


asal


Jawaban:


Awalnya saya berasumsi cara terbaik adalah memonitor / me-restart proses dari layanan Windows ...

Tentu kamu bisa! Saya melakukannya beberapa waktu yang lalu. Anda dapat mulai belajar bagaimana menonton ini:

http://msdn.microsoft.com/en-us/windows7trainingcourse_win7session0isolation_topic2#_Toc243675529

dan ini:

http://www.codeproject.com/Articles/18367/Launch-your-application-in-Vista-under-the-local-s

Secara substansi, Anda harus menjalankan program sebagai SISTEM, tetapi dengan SessionID dari pengguna saat ini.

Jika Anda merasa malas, saya kira mungkin ada beberapa Layanan kecil yang baik yang membuat hal yang Anda cari. Coba cari di www.codeproject.com.


6
2018-06-21 21:06



Saya akhirnya menerapkan solusi yang disarankan oleh @ A_nto2 dan itu mencapai apa yang saya cari: Saya sekarang memiliki Layanan Windows yang memantau daftar proses dan kapan pun mereka turun, mereka diluncurkan lagi secara otomatis menggunakan kredensial pengguna aktif dan sesi , sehingga GUI terlihat.

Namun, karena tautan yang diposkannya menunjukkan kode VC ++, saya membagikan penerapan C # untuk siapa pun yang menangani masalah yang sama:

public static class ProcessExtensions
{
    public enum SECURITY_IMPERSONATION_LEVEL
    {
        SecurityAnonymous,
        SecurityIdentification,
        SecurityImpersonation,
        SecurityDelegation
    }

    [StructLayout(LayoutKind.Sequential)]
    public class SECURITY_ATTRIBUTES
    {
        public int nLength;
        public IntPtr lpSecurityDescriptor;
        public int bInheritHandle;
    }

    public enum TOKEN_TYPE
    {
        TokenPrimary = 1,
        TokenImpersonation
    }

    [Flags]
    public enum CREATE_PROCESS_FLAGS : uint
    {
        NONE = 0x00000000,
        DEBUG_PROCESS = 0x00000001,
        DEBUG_ONLY_THIS_PROCESS = 0x00000002,
        CREATE_SUSPENDED = 0x00000004,
        DETACHED_PROCESS = 0x00000008,
        CREATE_NEW_CONSOLE = 0x00000010,
        NORMAL_PRIORITY_CLASS = 0x00000020,
        IDLE_PRIORITY_CLASS = 0x00000040,
        HIGH_PRIORITY_CLASS = 0x00000080,
        REALTIME_PRIORITY_CLASS = 0x00000100,
        CREATE_NEW_PROCESS_GROUP = 0x00000200,
        CREATE_UNICODE_ENVIRONMENT = 0x00000400,
        CREATE_SEPARATE_WOW_VDM = 0x00000800,
        CREATE_SHARED_WOW_VDM = 0x00001000,
        CREATE_FORCEDOS = 0x00002000,
        BELOW_NORMAL_PRIORITY_CLASS = 0x00004000,
        ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000,
        INHERIT_PARENT_AFFINITY = 0x00010000,
        INHERIT_CALLER_PRIORITY = 0x00020000,
        CREATE_PROTECTED_PROCESS = 0x00040000,
        EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
        PROCESS_MODE_BACKGROUND_BEGIN = 0x00100000,
        PROCESS_MODE_BACKGROUND_END = 0x00200000,
        CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
        CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
        CREATE_DEFAULT_ERROR_MODE = 0x04000000,
        CREATE_NO_WINDOW = 0x08000000,
        PROFILE_USER = 0x10000000,
        PROFILE_KERNEL = 0x20000000,
        PROFILE_SERVER = 0x40000000,
        CREATE_IGNORE_SYSTEM_DEFAULT = 0x80000000,
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct STARTUPINFO
    {
        public Int32 cb;
        public string lpReserved;
        public string lpDesktop;
        public string lpTitle;
        public Int32 dwX;
        public Int32 dwY;
        public Int32 dwXSize;
        public Int32 dwYSize;
        public Int32 dwXCountChars;
        public Int32 dwYCountChars;
        public Int32 dwFillAttribute;
        public Int32 dwFlags;
        public Int16 wShowWindow;
        public Int16 cbReserved2;
        public IntPtr lpReserved2;
        public IntPtr hStdInput;
        public IntPtr hStdOutput;
        public IntPtr hStdError;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct PROCESS_INFORMATION
    {
        public IntPtr hProcess;
        public IntPtr hThread;
        public int dwProcessId;
        public int dwThreadId;
    }

    public class Kernel32
    {
        [DllImport("kernel32.dll", EntryPoint = "WTSGetActiveConsoleSessionId")]
        public static extern uint WTSGetActiveConsoleSessionId();

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CloseHandle(IntPtr hObject);
    }

    public class WtsApi32
    {
        [DllImport("Wtsapi32.dll", EntryPoint = "WTSQueryUserToken")]
        public static extern bool WTSQueryUserToken(UInt32 sessionId, out IntPtr phToken);
    }

    public class AdvApi32
    {
        public const uint MAXIMUM_ALLOWED = 0x2000000;

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public extern static bool DuplicateTokenEx
        (
            IntPtr hExistingToken,
            uint dwDesiredAccess,
            SECURITY_ATTRIBUTES lpTokenAttributes,
            SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
            TOKEN_TYPE TokenType,
            out IntPtr phNewToken
        );

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool CreateProcessAsUser
        (
            IntPtr hToken,
            string lpApplicationName,
            string lpCommandLine,
            SECURITY_ATTRIBUTES lpProcessAttributes,
            SECURITY_ATTRIBUTES lpThreadAttributes,
            bool bInheritHandles,
            CREATE_PROCESS_FLAGS dwCreationFlags,
            IntPtr lpEnvironment,
            string lpCurrentDirectory,
            ref STARTUPINFO lpStartupInfo,
            out PROCESS_INFORMATION lpProcessInformation
        );
    }

    public class UserEnv
    {
        [DllImport("userenv.dll", SetLastError = true)]
        public static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, IntPtr hToken, bool bInherit);

        [DllImport("userenv.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);
    }

    public static void StartAsActiveUser(this Process process)
    {
        // Sanity check.
        if (process.StartInfo == null)
        {
            throw new InvalidOperationException("The StartInfo property must be defined");
        }

        if (string.IsNullOrEmpty(process.StartInfo.FileName))
        {
            throw new InvalidOperationException("The StartInfo.FileName property must be defined");
        }

        // Retrieve the active session ID and its related user token.
        var sessionId = Kernel32.WTSGetActiveConsoleSessionId();
        var userTokenPtr = new IntPtr();
        if (!WtsApi32.WTSQueryUserToken(sessionId, out userTokenPtr))
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }

        // Duplicate the user token so that it can be used to create a process.
        var duplicateUserTokenPtr = new IntPtr();
        if (!AdvApi32.DuplicateTokenEx(userTokenPtr, AdvApi32.MAXIMUM_ALLOWED, null, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, TOKEN_TYPE.TokenPrimary, out duplicateUserTokenPtr))
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }

        // Create an environment block for the interactive process.
        var environmentPtr = new IntPtr();
        if (!UserEnv.CreateEnvironmentBlock(out environmentPtr, duplicateUserTokenPtr, false))
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }

        // Create the process under the target user’s context.
        var processFlags = CREATE_PROCESS_FLAGS.NORMAL_PRIORITY_CLASS | CREATE_PROCESS_FLAGS.CREATE_NEW_CONSOLE | CREATE_PROCESS_FLAGS.CREATE_UNICODE_ENVIRONMENT;
        var processInfo = new PROCESS_INFORMATION();
        var startupInfo = new STARTUPINFO();
        startupInfo.cb = Marshal.SizeOf(startupInfo);
        if (!AdvApi32.CreateProcessAsUser
        (
            duplicateUserTokenPtr, 
            process.StartInfo.FileName, 
            process.StartInfo.Arguments, 
            null, 
            null, 
            false, 
            processFlags, 
            environmentPtr, 
            null, 
            ref startupInfo, 
            out processInfo
        ))
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }

        // Free used resources.
        Kernel32.CloseHandle(processInfo.hProcess);
        Kernel32.CloseHandle(processInfo.hThread);
        if (userTokenPtr != null)
        {
            Kernel32.CloseHandle(userTokenPtr);
        }

        if (duplicateUserTokenPtr != null)
        {
            Kernel32.CloseHandle(duplicateUserTokenPtr);
        }

        if (environmentPtr != null)
        {
            UserEnv.DestroyEnvironmentBlock(environmentPtr);
        }
    }
}

Dan inilah cara kode ini dipanggil:

var process = new Process();
process.StartInfo = new ProcessStartInfo { FileName = @"C:\path-to\target.exe", Arguments = "-arg1 -arg2" };
process.StartAsActiveUser();

Semoga itu membantu!


13
2018-06-29 18:19



Proses pengawasan dapat memanfaatkan System.Diagnostics.Process untuk meluncurkan aplikasi, gunakan WaitForExitMethod()dan periksa ExitCode milik.

Sebagai tanggapan atas keluhan atas pertanyaan, saya harus menggunakan metode semacam itu ketika bekerja dengan aplikasi pusat panggilan lawas yang tidak dapat saya akses kontrol sumbernya.

EDIT:

Untuk aplikasi host, Anda dapat menggunakan aplikasi .NET tipe output "Aplikasi Windows" dan sama sekali tidak memiliki bentuk sama sekali. Sebagai contoh:

namespace WindowsFormsApplication1
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            var info = new ProcessStartInfo(@"calc.exe");
            var process = Process.Start(info);
            process.WaitForExit();
            MessageBox.Show("Hello World!");
        }
    }
}

4
2018-06-21 21:01