Страницы

Поиск по вопросам

вторник, 10 декабря 2019 г.

Не могу программно убить ранее запущенный процесс

#c_sharp #процесс


В программе я открываю новый системный процесс, который проигрывает видео в дефолтном
плеере. Стартует и играет без проблем. Потом я пытаюсь закрыть (убить) процесс и получаю
ошибку: System.InvalidOperationException: No process is associated with this object. 
Кусок кода:

    string filename = "747225775.mp4";
    var myProc = new Process()
    {
        StartInfo = new ProcessStartInfo(filename)
    };
    myProc.Start();
    Thread.Sleep(5000);
    try
    {
       myProc.Kill(); //Error is here
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex);
        Debugger.Break();
    }


Вопрос как закрыть процесс.
PS. Задаю имя файла, а не программы, чтобы использовать программу по умолчанию.
    


Ответы

Ответ 1



Метод Process.Start связывает объект Process с дескриптором процесса только когда его вызов непосредственно порождает новый процесс. При передаче имени файла вместо имени программы класс Process обращается к функциям из shell32.dll и пытается определить, какие ассоциации в реестре установлены для данного расширения. Если используется "традиционный" способ ассоциации, с вызовом командной строки и передачей имени файла первым параметром (такой используется, например, Блокнотом), вызов Process.Start самостоятельно создает новый процесс, и связь с дескриптором устанавливается нормально. Если же для расширения установлен более новый способ ассоциации, с вызовом специального COM-объекта (который используется многими новыми приложениями, например Windows Media Player), вызов Process.Start лишь отправляет через RPC запрос на вызов метода COM-объекта и завершается, не устанавливая связь с процессом. (Как показали исследования, непосредственное создание процесса в этом случае происходит в контексте svchost.exe) Для решения этой проблемы можно использовать метод создания процесса, модифицированный следующим образом: using System; using System.ComponentModel; using System.Text; using System.Windows.Forms; using System.Diagnostics; using System.Threading; using System.Runtime.InteropServices; namespace ProcessTest { public partial class Form1 : Form { [DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern uint AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string pszExtra, [Out] StringBuilder pszOut, ref uint pcchOut); /*Модифицированный метод создания процесса*/ public static Process TrueProcessStart(string filename) { ProcessStartInfo psi; string ext = System.IO.Path.GetExtension(filename);//получаем расширение var sb = new StringBuilder(500);//буфер для пути к exe-файлу uint size = 500;//размер буфера /*Получаем приложение, ассоциированное с файлом*/ uint res = AssocQueryString(AssocF.None, AssocStr.Executable, ext,null, sb, ref size); if (res != 0) { Debug.WriteLine("AssocQueryString returned error: " + res.ToString("X")); psi = new ProcessStartInfo(filename);//не удалось получить приложение, используем стандартный метод } else { psi = new ProcessStartInfo(sb.ToString(), filename); } return Process.Start(psi);//запуск процесса } public Form1() { InitializeComponent(); } private void button2_Click(object sender, EventArgs e) { string filename = "c:\\images\\clip.wmv"; var myProc = TrueProcessStart(filename); if (myProc == null) { MessageBox.Show("Process can't be killed"); return; } Thread.Sleep(5000); try { myProc.Kill(); } catch (Exception ex) { MessageBox.Show(ex.ToString()); } } } [Flags] enum AssocF : uint { None = 0, Init_NoRemapCLSID = 0x1, Init_ByExeName = 0x2, Open_ByExeName = 0x2, Init_DefaultToStar = 0x4, Init_DefaultToFolder = 0x8, NoUserSettings = 0x10, NoTruncate = 0x20, Verify = 0x40, RemapRunDll = 0x80, NoFixUps = 0x100, IgnoreBaseClass = 0x200, Init_IgnoreUnknown = 0x400, Init_FixedProgId = 0x800, IsProtocol = 0x1000, InitForFile = 0x2000, } enum AssocStr { Command = 1, Executable, FriendlyDocName, FriendlyAppName, NoOpen, ShellNewValue, DDECommand, DDEIfExec, DDEApplication, DDETopic, InfoTip, QuickTip, TileInfo, ContentType, DefaultIcon, ShellExtension, DropTarget, DelegateExecute, SupportedUriProtocols, Max, } } Здесь для получения программы, ассоциированной с файлом, используется функция AssocQueryString. Потом полученное значение передается в ProcessStartInfo. Однако этот метод не всегда работает, в этом случае вызывается стандартный метод. Например, для файлов изображений нет определенной программы, просто dll грузится в процесс проводника. В этом случае убить процесс просто так не получится.

Ответ 2



знаешь почему у тебя производится такая ошибка. потому что когда ты этот файл стартуешь,как процесс но файл не может стартовать ся как процесс , просто у него определенно по умолчанию (Process File exe)'Video-Media Player' то есть Windows сохраняет эти расширение в регистре поэтому когда автоматически Кликаешь или стартуешь он автоматически стартует процесс который совпадает с этим расширением когда стартует ся файл тогда стартует ся (Process File exe)'Video-Media Player' а это новый Другой процесс. а у тебя находится пустой объект и поэтому ты не можешь убивать этот процесс. вот пример. string filename = @"C:\Test\Wildlife.wmv"; Process p = new Process(); p.StartInfo = new ProcessStartInfo("wmplayer.exe", filename); p.Start(); Thread.Sleep(2000); try { p.Kill(); } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.Read();

Ответ 3



Я с таким столкнулся первый раз, когда писал приложение для контроля за RDP сессиями на ферме серверов. mstsc.exe создает головной процесс, запускает дочерний процесс с окном RDP подключения и убивает головной процесс. Таким образом, PID не может быть использован для контроля за mstsc.exe Также точно работает 1С 8. Выход для себя я нашел в получении всех процессов по имени exe файла, у которых командная строка соответствует определенному критерию. Вам нужно работать именно в этом направлении

Комментариев нет:

Отправить комментарий