19 Mayıs 2011 Perşembe

Başka bir formun butonuna tıklama

Merhaba.

Zaman zaman, "başka bir formun butonunu tıklatma", "başka bir formdaki nesnenin özelliklerini değiştirme", "formlar arası mesaj gönderme" gibi sorularla karşılaşıyorum.

Problemin senaryosu gayet basit. Diyelim Form1 ve Form2 isimlerinde iki form var bir projede. Amaç Form2'de bulunan bir butona basınca Form1'deki bir butona basılma durumunu gerçekleştirmek.

Çözüm de şöyle;


--Form2 içinde--


public Form1 frm1;

private void button1_Click(object sender, EventArgs e)
{
frm1 = (Form1)Application.OpenForms["Form1"];
frm1.button1.PerformClick();

}


Visual Studio Form1'i ve nesnelerini ( frm1.button2.PerformClick() ) şeklinde doğrudan çağırmamıza da izin veriyor ancak derleme anında olmasa da çalışma anında framework NullReferenceException hatası veriyor.

Bu çözüm sadece aynı uygulama içinde farklı formlar arası iletişim içindir. Farklı .net uygulamaları arası iletişim için farklı(.net Remoting), .net mimarisi kullanmayan bir ya da birden fazla uygulama arası iletişim için(Interprocess Communication) farklı yollar vardır.

Bir ara onlardan da bahsedeyim hatırlatın da.

2 Mayıs 2011 Pazartesi

EnumChildWindows İle Bir Windowun Bütün Child Window Handlelarına Ulaşmak

Merhaba. Öncelikle demeliyim ki başlık canınızı sıkmasın, kafanızı karıştırmasın. Altta yapacağım kısa açıklama her şeyi gün gibi aydınlatacak. (Sanırım... Umarım... Belki... Neyse bakın işte....)

Windows'a neden Windows denildiği genelde yanlış bilinmektedir. Etrafta söylenen pencere yöneticisi kullanması şeklindedir. Aslında yanlış değil ama eksik.

Windows'ta çalışan her nesne bir windowdur(pencere) aslında. Hani sağ üstteki kırmızı çarpı ile kapatabildiğimiz form pencerelerinden bahsetmiyorum sadece. Mesela alttaki taskbar, bir penceredir. Microsoft Word kullanırken gördüğümüz üstteki Dosya, Düzelt, Araçların falan bulunduğu bar da bir penceredir. Hatta onların her birisi de birer penceredir.

Bunda anlaştık mı? Tamam. : )

Elbette Windows bu pencereleri açıp sahipsiz koymaz. Hepsinin yaratılma anında tanımlanmış bir kimlik numarası vardır. İşte onlara "Handle" denir. Bu handlelar aracılığı ile o pencereler hakkında bilgilere, isimlerine, türlerine ulaşabildiğimiz gibi onlara mesajlar da yollayabiliriz. Mesela C#'ta yazdığımız bir programla başka bir programın bir metin kutusundaki değeri okumak hatta onu değiştirmek.

Maskelenmiş(***** şeklinde) şekilde tutulan bir metin kutusunun içindeki parolayı böyle bir teknikle alsak acaba bize ne görünürdü? Maskeli parolayı olduğu halde görür müydük? Denemesi zevkli olur. Ancak şu an onu yapmayacağız. Adım adım gidelim.

Amacımız bir Parent Window(Ana pencere) içindeki Child Window(çocuk pencere)ların handlelarını öğrenmek. En azından bunu yapalım önce. : )

*****************************************************


Bu tür low level işleri ne yazık ki doğrusan .net framework'ü ile yapamıyoruz. Ama elimizde aslanlar gibi Win32 API'ler var. Microsoft Windows'un bel kemikleri. İşletim sistemi bu işleri nasıl yapıyorsa, işte biz de öyle yapacağız.

İhtiyacımız FindWindow ve EnumChildWindows fonksiyonları. İkisi de User32.dll kütüphanesi için unmanaged kodlar. Ne güzel ki C#'ta unmamaged kütüphanelere erişim şansımız var. Bunu da framwork içinden System.Runtime.InteropServices referansınız ekleyerek yapıyoruz.

İsterseniz kodlara geçelim;


using System;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;

namespace childhandlesiralama
{

class Program
{

[DllImport("user32.dll", SetLastError = true)]static extern IntPtr
FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll")]public static extern int
EnumChildWindows(IntPtr hwnd, EnumChildCallback Proc, int lParam);



public delegate bool EnumChildCallback(IntPtr hwnd, ref IntPtr lParam);


static void Main(string[] args)
{
IntPtr pHndl = FindWindow("notepad", null);
EnumChildWindows(pHndl, EnumChildProc, 0);
Console.ReadLine();
}

public static bool EnumChildProc(IntPtr hwndChild, ref IntPtr lParam)
{
Console.WriteLine("Handle: " + hwndChild.ToString());
return true;
}
}
}


Burada programın yaptığı (eğer açıksa) Notepad uygulamasının child handlelarını sıralamak. FindWindow ile Notepad'in handleını buluyoruz. Bu Parent Handle oluyor. Ana Handle diyebiliriz. Bu Parent Handle'ı da EnumChildWindows içinde kullanarak çocukların handlelarını bulacağız. Mesela benim sistemimde 394812, 394814 numaralı iki child handle buldu. Bu değerler 10luk sayı sisteminde. Ancak Windows bunları 16lık sayı sisteminde tutup, işlem yapar.
Yani bulduğu 2 Child Handle 0x6063C ve 0x6063E değerlerine sahip. Bunların ilki (0x6063C) Notepad'in altındaki Status Bar, ikincisi de üste taraftaki "File, Edi vb.." gibi şeylerin bulunduğu toolbar. Elbette sadece handlea gözle bakarak bunları öğrenmek olası değil. Ancak Win32 API'nin büyülü dünyası bunların hepsini sunuyor. : )

Gördüğünüz gibi gayet kısa ve kolay. Burada bahsetmek istediğim tek bir önemli nokta var. Bize child window handlelarını veren EnumChildWindows fonksiyonunun dönüş değeri bool. Bu değerleri fonksiyonun ikinci argümanı olarak kendi tanımladığımız EnumChildCallback türünde bir fonksiyon yaratarak ve onunla değerleri alarak yapıyoruz.

Win32API'deki bazı fonksiyonların böyle bir handikapı var. Doğrudan işini yaptığı sonucu getirmiyor, argüman olarak bir callback fonksiyonu çalıştırarak alıyoruz.

Bundan sonraki yazının konusu da handle değeri bilinen bir windowun (eğer varsa) başlık ismine ve class türüne(açıklayacağım) ulaşmak.

Teşekkürler.

21 Haziran 2009 Pazar

Dlink Dsl 500-G Modem İçin IP Değiştirme Programı

İnanın yapılacak açıklama başlıktan daha uzun değil. Bitti bile : ) 

Programı kendim için yazdım. Herhangi bir hatanızda çökebilir, D-Link DSL-500G harici adsl modemlerde çalışmaz, sefam olsun oh oh. 

Kendim için yazdığım Rapidshare download programının minik bir parçası oluyor. O yüzden kodlarını vermiyorum. Üşenmez, yarıda bırakmazsam Free Rapid Premium gibi uyduruk, dandirik ve lame bir isim vermeyi düşündüğüm programın kodlarını veririm. Onda en çok kullanılan 10-20 modem için kendinden ayarları yüklü olacak ama işte "bak şimdi şunu şunu yap sonra da bana şunu şunu söyle" şeklindeki lafımı dinleyecek 10-20 arkadaşım var mı tartışılır.

Bak ya geçenlerde bi arkadaşla oturuyoruz.... eheh napıyom ben ya. Takılın işte. 

"Eeey siz gariban D-Link 500-G kullanıcıları. Eeey en büyük çileyi çekenler!! açılışı sizinle yapıyorum. Yüzünüz kararmaya, boynunuz bükülmeye!"

Link: http://rapidshare.com/files/247162210/ipayarla.exe.html

16 Haziran 2009 Salı

Dis# Decompiler

Dis# da eh işte bir decompiler. 

Download: http://www.netdecompiler.com/download/DisSharp.zip

Spices.Net Decompiler


Spices.Net de güzel bir decompiler. 

DOWNLOAD: http://download.9rays.net/spices.net/spices5.zip

Shareware. Eheh sadece 899 dolarcık : ) 

C# Decompiler Tools


.Net Reflector güzel bir decompiler. 

DOWNLOAD: http://downloads.red-gate.com/reflector.zip

14 Nisan 2009 Salı

C#'ta bir processi suspend ve resume eylemek, güzel eylemek

Bir alttaki "C# Memory Searcher" ile alakalı bir projede bir processi suspend(askıya almak) ve resume(çözmek falan işte) etmem gerekiyordu. Bu konuda bulabildiğim uygun tek örnek de c++ için konsolda çalışan bir programdı. Aslında bir tane de Hindu bir amcanın c# ile mobil sistemler için yazdığı vardı ama hatalı olduğu gibi gereksizce işimi uzatmaktan başka bir işe yaramadı o da.
Neyse yavaştan başlayalım.
Öncelikle bir programı suspend etmek demek günümüzün multithreading yapısında o processin threadlerini suspend etmek demektir. Başka bir programın threadlerine ulaşıp onlarla oynamak gibi low level bir olayı da c# bize doğrudan izin vermiyor. Hatta Process sınıfında threads bölümü bile non-public. Neyse konuya dönelim. Bunun için bir kaç adet Win32 API kullanıyoruz.

1. CreateToolhelp32Snapshot ile bellekteki çalışan programların snapshotını alıyoruz
2. Thread32first ile ilk thread hakkında bilgilere uaşıyoruz
3. Thread32next ile bir sonraki threade geçiyoruz
4. SuspendThread ile threadi donduruyoruz
5. ResumeThread ile threadi çözüyoruz.

Demin yanlışlıkla sayfayı geri aldım ve son yazdıklarımın büyük çoğunluğu uçtu gitti. Ayıp oldu. Kızdım ben de o güzel açıklamalardan mahrum kaldınız :P:P

[DllImport("kernel32.dll", EntryPoint = "CreateToolhelp32Snapshot", SetLastError = true)]
public static extern IntPtr CreateToolhelp32SnapshotAPI(ulong flags, uint processid);

[DllImport("kernel32.dll", EntryPoint = "Thread32First", SetLastError = true)]
public static extern bool Thread32First(IntPtr handle, ref Patcher.THREADENTRY32 te32);

[DllImport("kernel32.dll", EntryPoint = "Thread32Next", SetLastError = true)]
public static extern bool Thread32Next(IntPtr handle, ref Patcher.THREADENTRY32 te32);

[DllImport("kernel32.dll", EntryPoint = "OpenThread", SetLastError = true)]
public static extern IntPtr OpenThread(uint dwDesiredAccess, bool bInheritHandle, uint dwThreadId);

[DllImport("kernel32.dll", EntryPoint = "SuspendThread", SetLastError = true)]
public static extern uint SuspendThread(IntPtr handle);

[DllImport("kernel32.dll", EntryPoint = "ResumeThread", SetLastError = true)]
public static extern uint ResumeThread(IntPtr handle);

public struct THREADENTRY32
{

public uint dwSize;

public uint cntUsage;

public uint th32ThreadID;

public uint th32OwnerProcessID;

public int tpBasePri;

public int tpDeltaPri;

public uint dwFlags;

}

public void Suspend(Process ProName)
{




try
{
thandle = Readerapi.CreateToolhelp32SnapshotAPI(TH32CS_SNAPTHREAD, (uint)ProName.Id);
}
catch (Exception hata)
{
System.Windows.Forms.MessageBox.Show("1");
System.Windows.Forms.MessageBox.Show(hata.ToString());
}
THREADENTRY32 te32 = new THREADENTRY32();

ulong size = (ulong)System.Runtime.InteropServices.Marshal.SizeOf(te32);

te32.dwSize = (uint)size;



bool devammi = true;
Stack depo = new Stack();
threadlist = new IntPtr[ProName.Threads.Count];

if (Readerapi.Thread32First(thandle, ref te32))
{
while (devammi)
{
if (te32.th32OwnerProcessID == ProName.Id)
{
IntPtr srhandle = Readerapi.OpenThread(2, false, te32.th32ThreadID);
Readerapi.SuspendThread(srhandle);
threadlist[counter] = srhandle;
counter++;
}
te32.dwSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(THREADENTRY32));
devammi = Readerapi.Thread32Next(thandle, ref te32);
}
}
Readerapi.CloseHandle(thandle);
counter = 0;



}

public void Resume(Process ProName)
{
try
{
thandle = Readerapi.CreateToolhelp32SnapshotAPI(TH32CS_SNAPTHREAD, (uint)ProName.Id);
}
catch (Exception hata)
{
System.Windows.Forms.MessageBox.Show("1");
System.Windows.Forms.MessageBox.Show(hata.ToString());
}
THREADENTRY32 te32 = new THREADENTRY32();

ulong size = (ulong)System.Runtime.InteropServices.Marshal.SizeOf(te32);

te32.dwSize = (uint)size;



bool devammi = true;
Stack depo = new Stack();
counter = 0;
if (Readerapi.Thread32First(thandle, ref te32))
{
while (devammi)
{
if (te32.th32OwnerProcessID == ProName.Id)
{

// IntPtr srhandle = Readerapi.OpenThread(2, false, te32.th32ThreadID);
// IntPtr rhandle = depo.Pop();
Readerapi.ResumeThread(threadlist[counter]);
counter++;



}
te32.dwSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(THREADENTRY32));
devammi = Readerapi.Thread32Next(thandle, ref te32);
}
}
Readerapi.CloseHandle(thandle);
counter = 0;

}



Aslında açıklanacak bir kaç şey var;

  1. thread32first illa ki boyutun önceden belirtilmesini ister
  2. CreateToolhelp32Snapshot açıklamaları için www.pinvoke.com ya da www.msdn.com'a bakabilirsiniz.
  3. Hani biliyorsunuz ama ben yine de söyleyeyim. Böyle API eklemek için projenin referanslarında "System.Runtime.InteropServices" sınıfı da bulunmalıdır.
  4. Dangıl dungul tanımlanmış böyle bakınca bir şey anlaşılmayan nesneler projede anlamlıdır. Müsterih olunuz hiç birini yersiz yurtsuz koymadık.
  5. Kodlar daha doğrusu bu yolla bir processi suspend/resume etmek çok da güvenli değil. Birbirine bağlı ve düzensiz sıralanmış threadlerin yanlış suspend edilmesi programın kilitlenmesine yol açabilir. Büyük ihtimalle de kaydedilmemiş verileriniz kaybolacaktır. Hihohaha bu son cümleyi hep kullanmak istemiştim. Öylesine mutluyum ki şu an. 
  6. Windows'larda kullanılan API'ler kernel32.dll'de bulunmaktadır ama Win CE falan mobil işlerde toolhelp mi toolhelp32 mi öyle bir kütüphanededir kendileri. THREADENTRY32 yapısı da daha fazla değer alıyordu. 
  7. C++'da mis gibi headeri varmış THREADENTRY32'nin. C#'ta yok öyle bir şey. Orjinalinde Dword olan zamazingoların c# karşılıklarını ayarlamak çok uğraştırdı. 
  8. Suspend/Resume konusunda nette C# için bir makale bulunmuyor. Aslında bir gün üşenmeyip İngilizce güzel bişiler yazsam bu konuda(böyle dandirik değil elbette. hıh!) iyi olacak.