Makale Özeti

İşletim sistemimizde çalışan uygulamalar, servisler gibi bileşenler hakkında bilgi edinmek, yönetimlerini sağlamak, çalışmaları sırasında ortaya çıkan hataları veya perfomans problemlerini gözlemlemek ve bu hataların / problemlerin nedenlerine ulaşmak gereksinimi ile karşılaştığımızda Window Management Instrumentation (WMI) mimarisini kullanarak biraz önce bahsedilen işlemleri ve daha fazlasını kendi geliştirdiğimiz uygulamalar sayesinde kolayca yapabiliriz. WMI bütün Windows tabanlı uygulamalarda özellikle yönetimsel işlemlerin yapılmasında kullanılabilir. Bu kısımda ise örnek uygulamalar yapacağız.

Makale

Merhabalar,

Örnek uygulamamızda bilgisayarımızdaki hard disk, sürücü, işletim sistemi, bilgisayar, işlemci, BIOS, zaman dilimi, bellek, ekran kartı, process ve servis bilgilerini alacak ve uygulamamız üstünden bilgisayarda çalışan servisleri durdurup başlatacağız. İlk olarak projemize System.Management referansını ekleyelim:



Ardından ise System.Management namespace'ini kodumuzda using ile tanımlıyoruz:

using System.Management;

Formumuza birer treeview ve listview ekliyoruz. Bazı sistem bilgilerini alırken treeview bazılarını alırken listview kullanacağımız için ikisini de üst üste gelecek şekilde forma yerleştirip kullanılacakları zamanlarda visible property'lerini true ve/veya false olarak set edeceğiz. Formumuza bir menustrip ekledikten sonra aşağıdaki gibi öğeleri ekliyoruz:



Kodumuzda class level bir ManagementObjectSearcher (mos) nesnesi tanımlıyoruz. Ardından ise formumuzdaki listview'i dolduracağımız zaman kullanacağımız Listele metod'unu yazıyoruz:

private void Listele(string query, ManagementObjectSearcher m, ListView lv, TreeView tv)
{
    lv.Items.Clear();
    lv.Visible = true;
    tv.Visible = false;
    m.Query = new ObjectQuery(query);
    foreach
(ManagementObject mo in m.Get())
    {
        foreach
(PropertyData pd in mo.Properties)
        {
            if
(mo[pd.Name] != null)
            {
                ListViewItem
lvi = new ListViewItem();
                System.Windows.Forms.ListViewItem.ListViewSubItem lvi2 = new System.Windows.Forms.ListViewItem.ListViewSubItem();
                lvi.Text = pd.Name;
                lv.Items.Add(lvi);
                lvi2.Text = mo[pd.Name].ToString();
                lvi.SubItems.Add(lvi2);
            }
        }
    }
}

Listele metodunda ilk olarak parametre geçirilen listview'in item'larını temizliyoruz. Sonra da listview'ın visible'ını true, treeview'ı kullanmayacağımız için de treeview'ın visible'ını false olarak set ediyoruz. Ardından parametre geçirdiğimiz ManagementObjectSearcher nesnesinin (m) Query property'sine yine parametre geçirdiğimiz string tipinde query değişkenini atıyoruz. Ardından ise ManagementObjectSearcher'ın (m) Get metodunu kullanarak her bir ManagementObject içinde foreach ile dolaşmaya başlıyoruz. Bu ManagementObject'lerin propertylerini ve değerlerini listview'e eklemek içinse ManagementObject nesnesinin (mo) Properties array'indeki her bir PropertyData nesnesini foreach ile alıyoruz. Management object'in ilgili PropertyData'sının değeri null değilse ilk olarak ilgili PropertyData'nın adını listview'e ekliyoruz. Ardından ise ManagementObject nesnesinin (mo) ilgili PropertyData'sının aldığı değeri de listview'daki her property'nin karşısına ekliyoruz.

private void işletimSistemiBilgileriToolStripMenuItem_Click(object sender, EventArgs e)
{
    Listele("Select * from Win32_OperatingSystem", mos, listView1, treeView1);
}

private void bilgisayarBilgileriToolStripMenuItem_Click(object sender, EventArgs e)
{
    Listele("SELECT * FROM Win32_ComputerSystem", mos, listView1, treeView1);
}

private void işlemciBilgileriToolStripMenuItem_Click(object sender, EventArgs e)
{
    Listele("SELECT * FROM Win32_processor", mos, listView1, treeView1);
}

private void bIOSBilgileriToolStripMenuItem_Click(object sender, EventArgs e)
{
    Listele("SELECT * FROM Win32_bios", mos, listView1, treeView1);
}

private void zamanDilimiBilgileriToolStripMenuItem_Click(object sender, EventArgs e)
{
    Listele("SELECT * FROM Win32_timezone", mos, listView1, treeView1);
}

private void bellekBilgileriToolStripMenuItem_Click(object sender, EventArgs e)
{
    Listele("SELECT * FROM Win32_LogicalMemoryConfiguration", mos, listView1, treeView1);
}

private void ekranKartıBilgileriToolStripMenuItem_Click(object sender, EventArgs e)
{
    Listele("SELECT * FROM Win32_VideoController", mos, listView1, treeView1);
}

Şimdi de treeview'da göstereceğimiz hard disk, sürücü ve process bilgilerinin kodunu yazmaya geldi. İlk olarak treeview'ın nodelarını temizliyoruz ve formumuzdaki listview'ın visible property'sini false, treeview'ın visible property'sini true olarak set ediyoruz. Ardından class level tanımladığımız ManagementObjectSearcher nesnesinin (mos) Query property'sini set ediyoruz. Ardından ise ManagementObjectSearcher'ın Get metoduyla bütün ManagementObject'leri treeview'ın node'larına ekliyoruz. Ardından ise bir foreach içinde tekrar bu ManagementObject'lerde dolaşıyor ve Properties array'indeki PropertyData nesneleri için bir daha foreach yazıyoruz. Ardından ise ManagementObject'in Caption property'si treenode'ın text'ine eşitse, ilgili treenode'a ilgili PropertyData'nın adını ve değerini atıyoruz.
Hard disk, sürücü ve process bilgilerinin kodlarını bu şekilde yazabiliriz. Değişen tek şey ManagementObjectQuery'leri olacaktır.

private void tsmiHardDiskBilgileri_Click(object sender, EventArgs e)
{
    treeView1.Nodes.Clear();
    listView1.Visible = false;
    treeView1.Visible = true;
   
    mos.Query = new ObjectQuery("SELECT * From Win32_DiskDrive");
   
    foreach
(ManagementObject mo in mos.Get())
    {
        treeView1.Nodes.Add(mo["Caption"].ToString(), mo["Caption"].ToString());
    }

    foreach
(TreeNode tn in treeView1.Nodes)
    {
        foreach
(ManagementObject mo in mos.Get())
        {
            foreach
(PropertyData pd in mo.Properties)
            {
                if
(mo["Caption"].ToString() == tn.Text)
                {
                    if
(mo[pd.Name] != null)
                    {
                        tn.Nodes.Add(pd.Name + ": " + mo[pd.Name].ToString());
                    }
                }
            }
        }
    }
}

private void sürücüBilgileriToolStripMenuItem_Click(object sender, EventArgs e)
{
    treeView1.Nodes.Clear();
    listView1.Visible = false;
    treeView1.Visible = true;

    mos.Query = new ObjectQuery("SELECT * From Win32_LogicalDisk");

    foreach
(ManagementObject mo in mos.Get())
    {
        treeView1.Nodes.Add(mo["Caption"].ToString(), mo["Caption"].ToString());
    }

    foreach (TreeNode tn in treeView1.Nodes)
   {
        foreach
(ManagementObject mo in mos.Get())
        {
            foreach
(PropertyData pd in mo.Properties)
            {
                if
(mo["Caption"].ToString() == tn.Text)
                {
                    if
(mo[pd.Name] != null)
                    {
                        tn.Nodes.Add(pd.Name + ": " + mo[pd.Name].ToString());
                    }
                }
            }
        }
    }
}

private
void processBilgileriToolStripMenuItem_Click(object sender, EventArgs e)
{
    treeView1.Nodes.Clear();
    listView1.Visible = false;
    treeView1.Visible = true;

    mos.Query = new ObjectQuery("SELECT * From Win32_Process");

    foreach
(ManagementObject mo in mos.Get())
    {
        treeView1.Nodes.Add(mo["Caption"].ToString(), mo["Caption"].ToString());
    }

    foreach (TreeNode tn in treeView1.Nodes)
    {
        foreach
(ManagementObject mo in mos.Get())
        {
            foreach
(PropertyData pd in mo.Properties)
            {
                if
(mo["Caption"].ToString() == tn.Text)
                {
                    if
(mo[pd.Name] != null)
                    {
                        tn.Nodes.Add(pd.Name + ": " + mo[pd.Name].ToString());
                    }
                }
            }
        }
    }
}

Sırada bilgisayarda kurulu olan servisleri getireceğimiz metod var. ServisleriGetir adında bir metod oluşturuyoruz ve ilk olarak listview'ın öğelerini ve kolonlarını temizliyoruz. Ardından ise listview'ın visible property'sini true, treeview'ın visible property'sini false olarak set ediyoruz. Sonrasında listview'a 4 adet kolon ekliyor ve genişliklerini set ediyoruz.
Class level tanımladığımız ManagementObjectSearcher nesnesinin (mos) Query property'sini set ettikten sonra Get metoduyla Caption, State, StartName ve StartMode property'lerini her process için listview'a ekliyoruz. Service Bilgileri menustrip öğesinin click event'inde de ServisleriGetir metodunu çağırıyoruz:

private void ServisleriGetir()
{
    listView1.Items.Clear();
    listView1.Columns.Clear();
    listView1.Visible = true;
    treeView1.Visible = false;

    listView1.Columns.Add("Caption");
    listView1.Columns.Add("State");
    listView1.Columns.Add("StartName");
    listView1.Columns.Add("StartMode");
    listView1.Columns[0].Width = 250;
    listView1.Columns[1].Width = 90;
    listView1.Columns[2].Width = 150;
    listView1.Columns[3].Width = 150;

    mos.Query = new ObjectQuery("Select * from Win32_Service");

    foreach
(ManagementObject mo in mos.Get())
    {
        ListViewItem
lvi = new ListViewItem();
        System.Windows.Forms.ListViewItem.ListViewSubItem lvi2 = new System.Windows.Forms.ListViewItem.ListViewSubItem();
        System.Windows.Forms.ListViewItem.ListViewSubItem lvi3 = new System.Windows.Forms.ListViewItem.ListViewSubItem();
        System.Windows.Forms.ListViewItem.ListViewSubItem lvi4 = new System.Windows.Forms.ListViewItem.ListViewSubItem();
        lvi.Text = mo["Caption"].ToString();
        listView1.Items.Add(lvi);
        lvi2.Text = mo["State"].ToString();
        lvi.SubItems.Add(lvi2);
        lvi3.Text = mo["StartName"].ToString();
        lvi.SubItems.Add(lvi3);
        lvi4.Text = mo["StartMode"].ToString();
        lvi.SubItems.Add(lvi4);
    }
}

private
void serviceBilgileriToolStripMenuItem_Click(object sender, EventArgs e)
{
    ServisleriGetir();
}

Şimdi uygulamamız üzerinden servisleri durdurup yeniden başlatacağımız kodu yazalım. Bunun için listview'ın MouseDown event'ine aşağıdaki kodu yazıyoruz. Event'te farenin sağ tuşuna tıklandığı zaman listview için yeni bir context menü oluşturup, context menu'ye eklemek için bir menu item oluşturuyoruz. Class level tanımladığımız _servisAdı property'sine listview'de tıklanan item'ın text'ini atıyoruz. Class level tanımladığımız ManagementObjectSearcher nesnemizin (mos) Query property'sine bu sefer de Win32_Service içinde Caption property'si _servisAdi olan servisleri getirecek property'i yazıyoruz. Böylece ManagementObjectSearcher nesnesinin Get metoduyla durdurma veya başlatma işlemini yapabileceğimiz servisin tüm özelliklerini elde ediyoruz. Sonrasında ise bir if içinde servisin çalışıp çalışmama durumuna göre menu item'ın text property'sini set ediyor ve _servisDurumu değişkenine de StopService veya StartService değerlerinden gerekli olanı atıyoruz. Son olarak da context menu'nun item'larına menu item'ı (mi) ekliyoruz. Listview'in ContextMenu property'sine oluşturduğumuz context menu'yu atıyoruz (cm). Sonrasında ise servisi durdurmak veya başlatmak için menu item'ın click event'ini handle ediyoruz:

private string _servisAdi;
private
string _servisDurumu;

private
void listView1_MouseDown(object sender, MouseEventArgs e)
{
    if
(e.Button == MouseButtons.Right)
    {
        ContextMenu
cm = new ContextMenu();
        MenuItem
mi = new MenuItem();

        _servisAdi = listView1.GetItemAt(e.X, e.Y).Text;

        mos.Query = new ObjectQuery("Select * from Win32_Service WHERE Caption = '" + _servisAdi + "'");

        foreach
(ManagementObject mo in mos.Get())
        {
            if
(Convert.ToBoolean(mo["Started"]))
            {
                mi.Text = "Durdur";
                _servisDurumu = "StopService";
            }
           
else
           
{
                mi.Text = "Başlat";
                _servisDurumu = "StartService";
            }
        }
   
        cm.MenuItems.Add(mi);
        listView1.ContextMenu = cm;
        mi.Click += new EventHandler(mi_Click);
    }
        _servisAdi = "";
}

Menu item'ın (mi) click event'inde ise class level ManagementObjectSearcher nesnesinin (mos) Query property'sine servisler içinde Caption property'si _servisAdı değişkeninin değerine eşit olan servisi çeken sorguyu atıyoruz. Ardından ManagementObjectSearcher'ın Get metoduyla elde ettiğimiz ManagementObject'in (mo) InvokeMethod metoduna _servisDurumu değişkenini geçirerek servisi çalışma durumuna göre durdurup / başlatıyoruz. Son olarak da listemizi yenilemek için ServisleriGetir metodunu çağırıyoruz:

void
mi_Click(object sender, EventArgs e)
{
    mos.Query = new ObjectQuery("Select * from Win32_Service WHERE Caption = '" + _servisAdi + "'");
    ManagementObjectCollection
moc = mos.Get();

    foreach
(ManagementObject mo in moc)
    {
        mo.InvokeMethod(_servisDurumu, null, null);
    }

    ServisleriGetir();
}



Bu kısımda ise tüm WMI Class'larının özelliklerinin açıklamalarıyla beraber nasıl listelenebileceğini inceleyelim. Bunun için öncelikle bir uygulama yazıyoruz ve uygulamada bulunan combobox içine tüm WMI Class'larının isimlerini yüklüyoruz. Daha sonrasında ise bu combobox'tan seçilmiş olan class'a ait property'leri, bu property'lerin tiplerini ve açıklamalarını bir datatable'a doldurup girdde göstereceğiz.
Bunun için öncelikle combobox'ın SelectedIndexChanged event'ını aşağıdaki gibi yazıyoruz:

private void cmbClasses_SelectedIndexChanged(object sender, EventArgs e)
{
    string
txt = cmbClasses.SelectedItem.ToString();
    ManagementClass
m = new ManagementClass(txt.Substring(txt.IndexOf("-")+1).Trim());
    m.Options.UseAmendedQualifiers = true;

    DataTable
dt = new DataTable();
    dt.Columns.Add("Name", typeof(string));
    dt.Columns.Add("Type", typeof(string));
    dt.Columns.Add("Description", typeof(string));

    foreach
(PropertyData pd in m.Properties)
    {
        DataRow
dr = dt.NewRow();
        dr["Name"] = pd.Name;
        dr["Type"] = pd.Type.ToString();

       
try
       
{
            dr["Description"] =pd.Qualifiers["Description"].Value.ToString();
        }
        catch
(Exception ex)
        {
       
        }
        dt.Rows.Add(dr);
    }
    grdDescription.DataSource = dt;
}

Bu event'in içinde ise ilk önce ManagementClass tanımlarken constructor'unda WMI class'ının adını string olarak geçiyoruz. daha sonrasında ise dolduracağımız datatable şemasını oluşturuyor ve classda bulunan propert'ler içinde Management Class nesnesine ait Properties collection'unda bulunan her bir PropertyData nesnesi için datatable'ımıza row'ları eklemeye başlıyoruz. PropertyData nesnesinin Name property'si ile mevcut property'nin adını, Type property'si ile tipini alabiliyoruz. Bu property'e ait açıklamayı alabilmek için ise PropertyData nesnesindeki Qualifiers propertsinde bulunan Description değerini kullanabiliriz. Ancak bu değer her property'de dolu olmadığı için try catch bloğu içine yazılmıştır. Oluşturduğumuz bu datatable'ı DataGridView nesnesine bağlayarak kullanıcıya gösterilmesini sağlıyoruz.



Makale serimin bu son bölümünde .NET ile WMI bileşenlerinin nasıl sorgulanabileceğine dair bir örnek yaptım. Umarım faydalı olmuştur.

Işıl ORHANEL
 

 

Ornek Kodlar