C # Мониторинг запуска исполняемого файла и выполнение операции до того, как пользователь его использует - PullRequest
0 голосов
/ 21 сентября 2018

Я пишу тестовое приложение для мониторинга других приложений Windows и выполнения операций до того, как пользователю будет разрешено их использовать.

Фон

У нас естьпользователи, которые могут получить доступ к компьютерам и запускать приложения.Для некоторых из этих приложений мы хотим, чтобы пользователь заполнил небольшую форму, а затем ему было бы разрешено использовать приложение.В то же время мы хотим отслеживать общее время выполнения приложения (т. Е. Сколько времени пользователь использовал приложение).Приложение, которое может запустить пользователь, - это не все сторонние приложения, и мы не можем контролировать их «качество».

Текущее решение

Использование этого кодаСтатья проекта и WMI, я создал приложение для мониторинга, которое отслеживает открытие и закрытие приложения, отображает форму для заполнения.

Проблема

Я тестирую приложение мониторинга, используя Calculator.exe в качестве примера.Мониторинг правильно определяет запуск и закрытие исполняемого файла, и мы можем убить приложение, если пользователь отменит всплывающую форму.Мы также можем написать журнал с данными из формы и времени начала и окончания.К сожалению, исполняемый файл никоим образом не «привязан» к приложению, и мы не можем помешать пользователю просто игнорировать форму приложения мониторинга и использовать запущенное приложение.

Возможные решения

  1. уничтожить запущенное приложение , отобразить форму и перезапустить приложение, если пользователь отправитвся информацияЭто решение будет работать, но некоторые приложения могут быть не рады внезапному уничтожению.

  2. Приостановить поток запущенного приложения с помощью решения описано в этом ответе .Мое сомнение в том, что мы приостановили эту тему.Как упоминалось выше, мы не знаем, насколько хорошо написано стороннее приложение.Есть ли риск тупиков?Кроме того, в этом случае уничтожение процесса может вызвать проблему с некоторыми сторонними приложениями

  3. Изменить тактику : вместо отслеживания запуска приложения выполните командусредство запуска и отредактируйте раздел реестра для приложения , чтобы запустить средство запуска вместо приложения.Эта стратегия - то, к чему я склоняюсь, но я все еще не знаю, как запустить приложение из модуля запуска, если я изменю ключ реестра.

Есть ли лучшее решение, которым мы являемся?не созерцая?Если нет, то какой из 3 будет "идти"?

Спасибо!

Ответы [ 2 ]

0 голосов
/ 21 сентября 2018

Я что-то пропустил? Кажется, самое простое решение - не запускать приложение, пока они не заполнили вашу форму.

0 голосов
/ 21 сентября 2018

Ваш лучший вариант - использовать * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Вы можете отслеживать систему для определенных типов событий.например, приложение выполняется или перехватывает щелчки и многое другое.
Вы также можете использовать отслеживание событий для мониторинга выполнения и завершения приложения в окнах.
вот пример, взятый по ссылкеЯ просто дал:

using Diagnostics.Tracing;
using Diagnostics.Tracing.Parsers;
using System;
using System.Diagnostics;
using System.IO;

namespace ProcessMonitor
{

    /// <summary>
    /// The main program monitors processes (and image loads) using ETW.  
    /// </summary>
    class Program
    {
        /// <summary>
        /// This is a demo of using TraceEvent to activate a 'real time' provider that is listening to 
        /// the MyEventSource above.   Normally this event source would be in a differnet process,  but 
        /// it also works if this process generate the evnets and I do that here for simplicity.  
        /// </summary>
        static int Main(string[] args)
        {
            // Today you have to be Admin to turn on ETW events (anyone can write ETW events).   
            if (!(TraceEventSession.IsElevated() ?? false))
            {
                Console.WriteLine("To turn on ETW events you need to be Administrator, please run from an Admin process.");
                return -1;
            }

            // As mentioned below, sessions can outlive the process that created them.  Thus you need a way of 
            // naming the session so that you can 'reconnect' to it from another process.   This is what the name
            // is for.  It can be anything, but it should be descriptive and unique.   If you expect mulitple versions
            // of your program to run simultaneously, you need to generate unique names (e.g. add a process ID suffix) 
            var sessionName = "ProessMonitorSession";
            using (var session = new TraceEventSession(sessionName, null))  // the null second parameter means 'real time session'
            {
                // Note that sessions create a OS object (a session) that lives beyond the lifetime of the process
                // that created it (like Filles), thus you have to be more careful about always cleaning them up. 
                // An importanty way you can do this is to set the 'StopOnDispose' property which will cause the session to 
                // stop (and thus the OS object will die) when the TraceEventSession dies.   Because we used a 'using'
                // statement, this means that any exception in the code below will clean up the OS object.   
                session.StopOnDispose = true;

                // By default, if you hit Ctrl-C your .NET objects may not be disposed, so force it to.  It is OK if dispose is called twice.
                Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { session.Dispose(); };

                // prepare to read from the session, connect the ETWTraceEventSource to the session
                using (var source = new ETWTraceEventSource(sessionName, TraceEventSourceType.Session))
                {
                    Action<TraceEvent> action = delegate(TraceEvent data)
                    {
                        // Console.WriteLine("GOT EVENT: " + data.ToString());
                        var taskName = data.TaskName;
                        if (taskName == "ProcessStart" || taskName == "ProcessStop") 
                        {
                            string exe = (string) data.PayloadByName("ImageName");
                            string exeName = Path.GetFileNameWithoutExtension(exe);

                            int processId = (int) data.PayloadByName("ProcessID");
                            if (taskName == "ProcessStart")
                            {
                                int parentProcessId = (int)data.PayloadByName("ParentProcessID");
                                Console.WriteLine("{0:HH:mm:ss.fff}: {1,-12}: {2} ID: {3} ParentID: {4}", 
                                    data.TimeStamp, taskName, exeName, processId, parentProcessId);
                            }
                            else
                            {
                                int exitCode = (int) data.PayloadByName("ExitCode");
                                long cpuCycles = (long) data.PayloadByName("CPUCycleCount");
                                Console.WriteLine("{0:HH:mm:ss.fff}: {1,-12}: {2} ID: {3} EXIT: {4} CPU Cycles: {5:n0}",
                                    data.TimeStamp, taskName, exeName, processId, exitCode, cpuCycles);
                            }
                        }
                    };

                    // Hook up the parser that knows about Any EventSources regsitered with windows.  (e.g. the OS ones. 
                    var registeredParser = new RegisteredTraceEventParser(source);
                    registeredParser.All += action;

                    // You can also simply use 'logman query providers' to find out the GUID yourself and wire it in. 
                    var processProviderGuid = TraceEventSession.GetProviderByName("Microsoft-Windows-Kernel-Process");
                    if (processProviderGuid == Guid.Empty)
                    {
                        Console.WriteLine("Error could not find Microsoft-Windows-Kernel-Process etw provider.");
                        return -1;
                    }

                    // Using logman query providers Microsoft-Windows-Kernel-Process I get 
                    //     0x0000000000000010  WINEVENT_KEYWORD_PROCESS
                    //     0x0000000000000020  WINEVENT_KEYWORD_THREAD
                    //     0x0000000000000040  WINEVENT_KEYWORD_IMAGE
                    //     0x0000000000000080  WINEVENT_KEYWORD_CPU_PRIORITY
                    //     0x0000000000000100  WINEVENT_KEYWORD_OTHER_PRIORITY
                    //     0x0000000000000200  WINEVENT_KEYWORD_PROCESS_FREEZE
                    //     0x8000000000000000  Microsoft-Windows-Kernel-Process/Analytic
                    // So 0x10 is WINEVENT_KEYWORD_PROCESS
                    session.EnableProvider(processProviderGuid, TraceEventLevel.Informational, 0x10);

                    Console.WriteLine("Starting Listening for events");
                    // go into a loop processing events can calling the callbacks.  Because this is live data (not from a file)
                    // processing never completes by itself, but only because someone called 'source.Close()'.  
                    source.Process();
                    Console.WriteLine();
                    Console.WriteLine("Stopping Listening for events");
                }
            }
            return 0;
        }
    }

}
...