Bagaimana saya bisa tahu jika suatu proses sedang berjalan?

155

Ketika saya mendapatkan referensi ke System.Diagnostics.Process, bagaimana saya bisa tahu jika suatu proses sedang berjalan?

pengesahan ulang
sumber

Jawaban:

252

Ini adalah cara untuk melakukannya dengan nama:

Process[] pname = Process.GetProcessesByName("notepad");
if (pname.Length == 0)
  MessageBox.Show("nothing");
else
  MessageBox.Show("run");

Anda dapat mengulang semua proses untuk mendapatkan ID untuk manipulasi nanti:

Process[] processlist = Process.GetProcesses();
foreach(Process theprocess in processlist){
   Console.WriteLine("Process: {0} ID: {1}", theprocess.ProcessName, theprocess.Id);
}
Patrick Desjardins
sumber
Ini persis apa yang saya cari. Meskipun ini adalah posting yang sangat lama, maukah Anda menjelaskan kepada saya bagaimana ini valid C #. Saya tidak meragukannya, saya melihatnya berfungsi, tetapi saya belum pernah melihat jika tidak tanpa {}.
MatthewD
4
@ MatthewD: if/elsepernyataan C # yang panjangnya hanya satu baris tidak perlu memiliki kurung kurawal untuk mengindikasikan pernyataan blok. Ini juga berlaku untuk foreachdan forpernyataan. Itu bermuara pada gaya pengkodean.
Hallmanac
Saya melakukan riset tentang ini juga, menemukan info itu, tetapi saya tidak melihat forinfo itu. Tahun c # .net dev dan saya belum pernah melihat gaya ini. Seperti yang mereka katakan, "kamu belajar sesuatu yang baru setiap hari". Terima kasih atas kiriman dan jawabannya ..
MatthewD
3
@ MatthewD ya, ini berlaku untuk sebagian besar bahasa sebenarnya (seperti Java). Biasanya merupakan praktik yang baik untuk menghindari one-liner seperti ini dan selalu memasang kurung kurawal, karena selalu ada kesempatan Anda mungkin harus menambahkan lebih banyak pernyataan di sana di masa depan, dalam hal mana kurung akan sudah ada di sana saat Anda membutuhkannya. Tetapi untuk hal-hal seperti ini, jika Anda 100% yakin hanya membutuhkan satu pernyataan, boleh saja dilakukan dan secara sintaksis valid.
David Mordigal
1
Jika Anda tidak dapat menemukan prosesnya, coba hapus ekstensi. (Kel.: Exe)
DxTx
28

Ini adalah cara paling sederhana yang saya temukan setelah menggunakan reflektor. Saya membuat metode ekstensi untuk itu:

public static class ProcessExtensions
{
    public static bool IsRunning(this Process process)
    {
        if (process == null) 
            throw new ArgumentNullException("process");

        try
        {
            Process.GetProcessById(process.Id);
        }
        catch (ArgumentException)
        {
            return false;
        }
        return true;
    }
}

The Process.GetProcessById(processId)Metode menyebut ProcessManager.IsProcessRunning(processId)metode dan melempar ArgumentExceptiondalam hal proses tidak ada. Untuk beberapa alasan ProcessManagerkelas ini internal ...

pengesahan ulang
sumber
Ini adalah jawaban yang sangat bagus; namun, Anda tidak harus melalui argumen pengecualian nol (Karena pengecualian referensi nol akan tetap dibuang dan Anda tidak melakukan apa pun dengan pengecualian. Juga, Anda akan mendapatkan InvalidOperationException jika Anda tidak menjalankan Start () metode atau Anda memanggil metode close (). Saya memposting Jawaban lain untuk menjelaskan dua situasi ini.
Aelphaeis
16

Solusi sinkron:

void DisplayProcessStatus(Process process)
{
    process.Refresh();  // Important


    if(process.HasExited)
    {
        Console.WriteLine("Exited.");
    }
    else
    {
        Console.WriteLine("Running.");
    } 
}

Solusi asinkron:

void RegisterProcessExit(Process process)
{
    // NOTE there will be a race condition with the caller here
    //   how to fix it is left as an exercise
    process.Exited += process_Exited;
}

static void process_Exited(object sender, EventArgs e)
{
   Console.WriteLine("Process has exited.");
}
Coincoin
sumber
6
Untuk opsi pertama: bagaimana saya bisa tahu apakah proses itu dimulai?
reshefm
8

reshefm punya jawaban yang cukup bagus; namun, itu tidak menjelaskan situasi di mana prosesnya tidak pernah dimulai.

Ini adalah versi modifikasi dari apa yang dia posting.

    public static bool IsRunning(this Process process)
    {
        try  {Process.GetProcessById(process.Id);}
        catch (InvalidOperationException) { return false; }
        catch (ArgumentException){return false;}
        return true;
    }

Saya menghapus ArgumentNullException-nya karena sebenarnya seharusnya menjadi pengecualian referensi nol dan itu akan dilemparkan oleh sistem dan saya juga menjelaskan situasi di mana proses tidak pernah dimulai dengan memulai atau metode close () digunakan untuk menutup proses.

Aelphaeis
sumber
Secara pribadi, saya lebih suka melihat ArgumentNullException ketika meninjau pengecualian yang dicatat daripada NullReferenceException, karena ArgumentNullException jauh lebih eksplisit tentang apa yang salah.
Sean
1
@Sean Saya biasanya setuju dengan Anda tetapi ini adalah metode ekstensi. Saya pikir lebih tepat untuk melempar pengecualian null pointer yang diberikan sintaks, itu hanya terasa lebih konsisten dengan metode memanggil objek null.
Aelphaeis
Ini akan memicu pengendali acara FirstHandledException setiap waktu. Caranya dengan spam log Anda di sana sobat.
Latensi
6

Ini harus satu kalimat:

public static class ProcessHelpers {
    public static bool IsRunning (string name) => Process.GetProcessesByName(name).Length > 0;
}
guneysus
sumber
3

Tergantung pada seberapa andal Anda menginginkan fungsi ini. Jika Anda ingin tahu apakah proses proses tertentu yang Anda miliki masih berjalan dan tersedia dengan akurasi 100% maka Anda kurang beruntung. Alasannya adalah bahwa dari objek proses yang dikelola hanya ada 2 cara untuk mengidentifikasi proses.

Yang pertama adalah Id Proses. Sayangnya, id proses tidak unik dan dapat didaur ulang. Mencari daftar proses untuk Id yang cocok hanya akan memberi tahu Anda bahwa ada proses dengan id yang sama berjalan, tetapi itu belum tentu proses Anda.

Item kedua adalah Pegangan Proses. Ini memiliki masalah yang sama meskipun sebagai ID dan lebih canggung untuk bekerja dengannya.

Jika Anda mencari keandalan tingkat menengah maka memeriksa daftar proses saat ini untuk proses ID yang sama sudah cukup.

JaredPar
sumber
1

Process.GetProcesses()adalah cara untuk pergi. Tetapi Anda mungkin perlu menggunakan satu atau lebih kriteria yang berbeda untuk menemukan proses Anda, tergantung pada bagaimana prosesnya berjalan (yaitu sebagai layanan atau aplikasi normal, apakah memiliki tajuk atau tidak).

Jeff Kotula
sumber
Jika Anda meletakkan metode ini dalam satu lingkaran, dibutuhkan banyak siklus CPU. Saya sarankan untuk menggunakan GetProcessByName () atau GetProcessByID ().
Hao Nguyen
0

Mungkin (mungkin) saya salah membaca pertanyaan, tetapi apakah Anda mencari properti HasExited yang akan memberi tahu Anda bahwa proses yang diwakili oleh objek Proses Anda telah keluar (baik secara normal atau tidak).

Jika proses yang Anda rujuk memiliki UI, Anda dapat menggunakan properti Respons untuk menentukan apakah UI saat ini merespons input pengguna atau tidak.

Anda juga dapat mengatur EnableRaisingEvents dan menangani acara Keluar (yang dikirim secara serempak) atau menelepon WaitForExit () jika Anda ingin memblokir.


sumber
0

Anda dapat instantiate contoh Proses sekali untuk proses yang Anda inginkan dan terus melacak proses menggunakan objek NET. Proses (itu akan terus melacak sampai Anda memanggil Tutup objek NET. Secara eksplisit, bahkan jika proses itu pelacakan telah mati [ini untuk memberi Anda waktu proses dekat, alias ExitTime dll.])

Mengutip http://msdn.microsoft.com/en-us/library/fb4aw7b8.aspx :

Ketika proses terkait keluar (yaitu, ketika dimatikan oleh sistem operasi melalui penghentian normal atau abnormal), sistem menyimpan informasi administratif tentang proses dan kembali ke komponen yang disebut WaitForExit. Komponen Proses kemudian dapat mengakses informasi, yang termasuk ExitTime, dengan menggunakan Handle untuk proses yang keluar.

Karena proses terkait telah keluar, properti Handle komponen tidak lagi menunjuk ke sumber daya proses yang ada. Sebagai gantinya, pegangan hanya dapat digunakan untuk mengakses informasi sistem operasi tentang sumber daya proses. Sistem menyadari adanya pegangan untuk keluar dari proses yang belum dirilis oleh komponen Proses, sehingga ExitTime dan Informasi penanganan dalam memori sampai komponen Proses secara spesifik membebaskan sumber daya. Untuk alasan ini, setiap kali Anda menelepon Mulai untuk proses Contoh, panggil Tutup ketika proses terkait telah berakhir dan Anda tidak lagi memerlukan informasi administratif tentang hal itu. Tutup membebaskan memori yang dialokasikan untuk proses keluar.

George Birbilis
sumber
0

Saya mencoba solusi Coincoin:
Sebelum memproses beberapa file, saya menyalinnya sebagai file sementara dan membukanya.
Setelah selesai, saya menutup aplikasi jika masih terbuka dan menghapus file sementara:
Saya hanya menggunakan variabel Proses dan memeriksanya setelahnya:

private Process openApplication;  
private void btnOpenFile_Click(object sender, EventArgs e) {  
    ...
    // copy current file to fileCache  
    ...  
    // open fileCache with proper application
    openApplication = System.Diagnostics.Process.Start( fileCache );  
}

Kemudian saya menutup aplikasi:

 ...   
openApplication.Refresh(); 

// close application if it is still open       
if ( !openApplication.HasExited() ) {
    openApplication.Kill();  
}

// delete temporary file  
System.IO.File.Delete( fileCache );

Berhasil (sejauh ini)

Jack Griffin
sumber
3
Di openApplication.HasExited(), HasExited bukan fungsi. Cara yang benar adalah openApplication.HasExited.
caiosm1005
0

Meskipun didukung API dari .Net frameworks tentang memeriksa proses yang ada dengan proses ID, fungsi-fungsi tersebut sangat lambat. Biayanya sejumlah besar siklus CPU untuk menjalankan Process.GetProcesses () atau Process.GetProcessById / Name ().

Metode yang jauh lebih cepat untuk memeriksa proses yang berjalan dengan ID adalah dengan menggunakan API asli OpenProcess () asli . Jika pegangan kembali adalah 0, prosesnya tidak ada. Jika pegangan berbeda dari 0, proses sedang berjalan. Tidak ada jaminan metode ini akan bekerja 100% setiap saat karena izin.

Hao Nguyen
sumber
0

Ada banyak masalah yang terkait dengan hal ini, karena sebagian lainnya tampaknya mengatasi sebagian:

  • Anggota instance mana pun tidak dijamin aman dari utas. Berarti ada kondisi balapan yang mungkin terjadi dengan masa foto ketika mencoba untuk mengevaluasi sifat-sifat objek.
  • Pegangan proses akan membuang Win32Exception untuk ACCESS DENIED di mana izin untuk mengevaluasi ini dan properti lainnya tidak diizinkan.
  • Untuk status TIDAK MENJALANKAN, ArgumentException juga akan dimunculkan ketika mencoba untuk mengevaluasi beberapa propertinya.

Apakah properti yang disebutkan orang lain adalah internal atau tidak, Anda masih dapat memperoleh informasi dari mereka melalui refleksi jika izin memungkinkan.

var x = obj.GetType().GetProperty("Name", BindingFlags.NonPublic | BindingFlags.Instance);

Anda bisa menyematkan kode Win32 untuk Snapshot atau Anda dapat menggunakan WMI yang lebih lambat.

HANDLE CreateToolhelp32Snapshot(
  DWORD dwFlags,
  DWORD th32ProcessID
);

Opsi lain adalah OpenProcess / CloseProcess, tetapi Anda masih akan mengalami masalah yang sama dengan pengecualian yang dilemparkan sama seperti sebelumnya.

Untuk WMI - OnNewEvent.Properties ["?"]:

  • "ParentProcessID"
  • "ProcessID"
  • "Nama proses"
  • "SECURITY_DESCRIPTOR"
  • "SessionID"
  • "Sid"
  • "TIME_CREATED"
Latensi
sumber
0
string process = "notepad";
if (Process.GetProcessesByName(process).Length == 0)
{
    MessageBox.Show("Working");
}
else
{
    MessageBox.Show("Not Working");
}

Anda juga dapat menggunakan timer untuk memeriksa proses setiap waktu

berkay
sumber
3
Bukankah sebaliknya? jika panjang == 0 itu berarti tidak berfungsi?
Jay Jacobs
Jawabannya sama dengan oleh Patrick Desjardins: stackoverflow.com/a/262291/7713750
Rekshino
Sebaliknya panjang> 0 berarti proses ditemukan.
HaseeB Mir
Ini mungkin memiliki kesalahan, ( length == 0harus ditampilkan Not Working) tetapi masih menyelesaikan pekerjaan.
Momoro