21 Mayıs 2011 Cumartesi

İsim Çözümleme Metotları

  Bu makalemizde network ortamlarında isim çözümleme şekillerinden ve aşamalarından bahsedeceğiz.
Bir bilgisayarın sahip olabileceği iki tane isim vardır. Bunlardan biri host, diğeri netbios adıdır. Öncelikle netbios ve host adı neyi ifade ediyor onu açıklayalım. Host adı, bir network ortamındaki bilgisayarın tam adını, Netbios adı ise o bilgisayarın kendi adını ifade eder. Her ikisinin de kendine özgü isim çözümleme mekanizmaları vardır. Host isimlerini çözmek için DNS, netbios isimlerini çözmek içinse WINS Server adı verilen yapılar kullanılır. İsim çözümlemekten kastedilen verilen isme sahip bilgisayarın IP adresini bulmak işidir. Host ve NetBios isimlerinn genel özellikleri şunlardır.
1- Host isimleri 255 karaktere kadar destekler fakat NetBios isimleri 15 karakter isim ve 1 karakter sonekten oluşur. Verilen NetBios ismi 15 karakterden az ise 15 karaktere tamamlanıncaya kadar sonuna boşluk eklenir.
2- Host ve NetBios ismi aynı olmamalıdır.
3- www.yazilimgrubu.org adresinde "www" Host adını"yazilimgrubu.org" domain adını ifade eder. Her ikisinin beraber kullanılmasına FQDN(Full Qualified Domain Name) denir.
Bilgisayarlar iki şekilde ağa dahil edilebilirler. Bunlardan birincisi WORKGROUP adı verilen sistemdir. Bu sistemde ağa dahil olan bilgisayarlar arasında güven yoktur. Her bilgisayar kendi güvenliğinden sorumludur. Ayrıca her bilgisayarın kendi yerel yönetici hesabı vardır bunlar merkezi olarak yönetilemez ve kullanıcılar birbirlerinin yetkilerini kısıtlayamaz. Küçük çaplı ağlar kullanılır. İkinci yöntem ise DOMAIN yapısıdır ki en çok kullanılan ve en mantıklı yöntem budur. Domain'e yani ağa dahil olan bilgisayarlar arasında güven vardır. Merkezi yönetim mümkündür. Sunucu-İstemci ilişkisi esas alınmıştır. Tam yetkiye sahip bir veya daha fazla yönetici hesabı olabilir. Orta ve büyük çaplı ağlarda rahatlıkla uygulanabilir.
Bazı temel bilgileri verdikten sonra konumuza dönebiliriz. Makalenin başında da bahsettiğimiz gibi konum isim çözümleme şekilleri ve aşamaları. Ağ ortamlarında bilgisayarlar birbirleriyle veri alışverişi yaparlar. Bunu yaparken daha önceki makalelerimizde bahsettiğimiz IP adresleri ve MAC adreslerini kullanırlar. Büyük bir ağ ortamında olduğunuzu düşünün. Bütün bilgisayarların IP adreslerini ezberlemenin imkansız olduğu apaçık ortada. Bir dosyaya veya kağıda da not almanız da bir o kadar imkansız. 3-5 bilgisayarın olduğu bir ağ ortamında olabilir ama 100-200 veya binlerce bilgisayarın olduğu bir ortamda mümkün değildir. Peki erişmek istediğimiz bilgisayarın IP adresini nasıl elde edeceğiz? İşte burada host ve netbios isimlerini kullanıyoruz. Akılda tutulması zor IP adresleri yerine daha akılda kalıcı isimler (192.168.2.5 yerine yazilimcihasan gibi) kullanmak daha kullanışlı ve daha mantıklı bir çözümdür. Fakat bu beraberinde bir de sorun getirmiştir. Bildiğimiz gibi iki bilgisayarın birbiriyle haberleşebilmesi için birbirlerinin IP adreslerini bilmeleri gerekiyor. Yani host veya netbios ismi bilgisayarlar için hiç birşey ifade etmiyor. Bu da bize bu isimleri IP adreslerine çevirecek bir sistemin geliştirilmesini zorunlu kılıyor.
Bunu sadece yerel ağlar için düşünmeyin. Bugün hemen herkesin kullandığı internet içinde aynı şey söz konusudur. Biz tarayıcı adresine www.yazilimgrubu.org yazıyoruz ama bilgisayarın bu siteye bağlanabilmesi için "yazilimgrubu.org" sitesinin IP adresine sahip olması gerekiyor. Her site için bu şart ama internet ortamında milyonlarca site olduğunu düşünürseniz her birine ait IP adresini ezberlemek mümkün değil. sadece onları değil çok sık kullandığınız 9-10 tane sitenin bile IP adreslerini ezberlemeniz çok zor olacaktır. Bir gün girmeseniz belki de unutacaksınız.
Eskiden bu isim çözümleme işi host isimleri için "HOSTS" netbios isimleri için "LMHOSTS" dosyası adı verilen metin dosyalarına yazılarak yapılıyordu. Herkeste aynı dosya vardı ve sık sık güncellenmesi gerekiyordu. Eğer güncel bir dosyaya sahip değilseniz yeni açılan sitelere erişemiyordunuz. İnternetin bugün geldiği noktada milyonlarca sitenin adresini tek bir dosyada tutmak için kaç GB'lık dosya gerektirir kim bilir. Bu sistem hala geçerliliğini korumakla birlikte yerini daha verimli ve hızlı çalışan sistemlere bırakmıştır.
Peki bu isim çözümleme işi nasıl yapılıyor hangi aşamalardan geçiyor. Bu konuyu hem host isimleri hem de netbios isimleri için anlatacağız. Bir host ismi çözümlemesi 7 aşamadan oluşur.
1- Local Host Name
2- HOSTS Dosyası
3- DNS
4- NetBios Cache
5- WINS
6- Broadcast
7- LMHOSTS Dosyası

Bu aşamalardan herhangi birinde isim çözümlemesi başarı ile sonuçlanırsa işlem o noktada bitirilir diğer aşamalara devam edilmez. Örneğin www.yazilimgrubu.org sitesine girmeye çalıştığımızı varsayalım.
1- www.yazilimgrubu.org ismi istek gönderecek bilgisayarın kendi host ismiyle karşılaştırılır. Eğer eşleşmezse diğer aşamaya geçilir.
2- Hosts dosyası içindeki kayıtlarda eşleşme olup olmadığı kontrol edilir. Bu dosya \Windows\System32\drivers\etc klasöründe bulunur. Bu dosyanın uzantısı yoktur. Uzantı verilirse çalışmaz. Not defteriyle açılıp okunabilen veya değiştirilen bu dosyada IP adresi ve isim çifti satır satır yazılır. Örneğin;
94.102.14.166 www.yazilimgrubu.org
gibi. Biz www.yazilimgrubu.org yazdığımızda 94.102.14.166 IP adresine gideceğiz. IP adresi olarak farklı bir adres yazsaydık o adrese gidecektik. Bu dosyada da eşleşme bulunmazsa üçüncü aşamaya geçilir.
3- Tanımlanmış olan DNS sunucuya host ismi isim-IP çözümlemesi için gönderilir. DNS kayıtlarında eşleşme bulunamazsa dördüncü aşamaya geçilir.
4- Bu aşamada daha önce sorgulanan ve erişimi başarıyla sağlanmış netbios isimleri kontrol edilir. Burada da eşleşme bulunmazsa beşinci aşamaya geçilir.
5- Bu aşama da tanımlanan WINS sunucusuna isim-IP çözümlemesi için başvurulur. Yine eşleşme bulunamazsa altıncı aşamaya geçilir.
6- Bu aşamada istek gönderecek bilgisayar içinde erişilmek istenen host ismininde olduğu bir Broadcast paketi yayınlar. Yani ağdaki veya internetteki bütün bilgisayarlara sorar ve cevap bekler. Eğer bir cevap gelmezse yedinci ve son aşamaya geçer ancak şöyle bir durum var. Eğer broadcast neticesinde bir sonuç alınmamışsa verilen host ismi çok büyük ihtimalle yanlıştır veya host ismine sahip bilgisayar kapalıdır.
7- HOSTS dosyası ile aynı klasörde olan ve aynı HOSTS dosyası gibi kullanılan bir dosyadır. Host dosyasından farkı içinde host isimlerini değil de netbios isimlerini barındırıyor olmasıdır. Bu dosya varsayılan olarak .SAM uzantısına sahiptir. Bu dosyayı kullanabilmek için uzantısının silinmesi gerekir.
Host isimlerinin çözümlenmesi sırasında hangi aşamalarıdan geçtiğini kısaca gördük şimdi sıra NetBios isimlerinin nasıl çözümlendiğine. Aynı yöntemleri kullanarak yapılan bu çözümleme işinde sıralama değişiktir. Aynı işi farklı öncelik sıralarına göre yaparlar. O yüzden bu kısımda sadece aşamaların isimlerini yazacağım. NetBios isim çözümlemesi 6 aşamadan oluşur.
1- NetBios Cache
2-WINS
3-BroadCast
4-LMHOSTS Dosyası
5-HOSTS dosyası
6- DNS

Yukarda NetBios isimlerinin 15 karakter isim ve 1 karakter sonekten oluştuğunu söylemiştik. Aşağıdaki resimde örnek bir NetBios isim listesi görünmektedir. Bu ekran görüntüsüne "nbtstat -n" komutuyla ulaşabilirsiniz. Altı kırmızı renkli çizili olan kısımlar soneklerdir. Bu sonek bilgisayarla ilgili bazı bilgileri ifade eder. Bu eklerin anlamları aşağıdaki tabloda gösterilmiştir. Gerçek metne ise http://support.microsoft.com/kb/163409/tr adresinden ulaşabilirsiniz.
      Name                       Number(h)   Type          Usage
--------------------------------------------------------------------------
<computername>               00             U      Workstation Service
<computername>               01             U      Messenger Service
<\\--__MSBROWSE__>   01              G      Master Browser
<computername>              03              U      Messenger Service
<computername>              06              U      RAS Server Service
<computername>              1F              U     NetDDE Service
<computername>              20              U      File Server Service
<computername>              21              U      RAS Client Service
<computername>              22              U      Microsoft Exchange Interchange(MSMail Connector)
<computername>              23              U      Microsoft Exchange Store
<computername>              24              U      Microsoft Exchange Directory
<computername>              30              U      Modem Sharing Server Service
<computername>              31              U      Modem Sharing Client Service
<computername>              43              U      SMS Clients Remote Control
<computername>              44              U      SMS Administrators Remote Control Tool
<computername>              45              U      SMS Clients Remote Chat
<computername>              46              U      SMS Clients Remote Transfer
<computername>              4C             U      DEC Pathworks TCPIP service on Windows NT
<computername>              42              U      mccaffee anti-virus
<computername>              52              U      DEC Pathworks TCPIP service on Windows NT
<computername>              87              U      Microsoft Exchange MTA
<computername>              6A             U      Microsoft Exchange IMC
<computername>              BE             U      Network Monitor Agent
<computername>              BF             U      Network Monitor Application
<username>                      03              U      Messenger Service
<domain>                         00              G      Domain Name
<domain>                         1B             U      Domain Master Browser
<domain>                         1C             G      Domain Controllers
<domain>                         1D             U      Master Browser
<domain>                         1E              G      Browser Service Elections
<INet~Services>              1C             G       IIS
<IS~computer name>      00              U       IIS
<computername>            [2B]            U      Lotus Notes Server Service
IRISMULTICAST          [2F]            G      Lotus Notes
IRISNAMESERVER      [33]            G       Lotus Notes
Forte_$ND800ZA           [20]            U       DCA IrmaLan Gateway Server Service
U ==> UNIQUE
G ==> GROUP
    Resim ve tabloyu karşılaştırdığınızda
YG ==> <00> UNIQUE değeri Workstation Service olarak ifade ediliyor. Yani bilgisayarımın NetBios adı.
SISTEM ==> <00> GROUP değeri Domain Name olarak ifade ediliyor. Yani bilgisayarımda bir domainin üyesi olduğunu gösteriyor.
SISTEM ==> <1C> GROUP değeri Domain Controllers olarak ifade ediliyor. Yani bilgisayarımının üyesi olduğu ağı yönetebilecek durumda olduğunu gösteriyor.
YG ==> <20> UNIQUE değeri File Server Service olarak ifade ediliyor. Yani bilgisayarımda File Server rolünün yüklü oldıuğunu yani dosya paylaşımı yönetimi araçlarının yüklü olduğunu gösteriyor.
SISTEM ==> <1B> UNIQUE değeri Domain Master Browser olarak ifade ediliyor. Yani bilgisayarımın domain master rolüne sahip olduğunu gösteriyor.

Veri Transfer Türleri

  Bu makalemizde network ortamlarındaki veri transfer yöntemlerinden bahsedeceğiz. Bir network ortamında veri transferi göre üç farklı şekilde yapılır. Bunlar;
1- Unicast
2- Multicast
3- Broadcast

1- Unicast : Bu transfer türü bire-bir bağlantı olarak da adlandırılır. Bu transfer türünde veriler iki bilgisayar arasında transfer edilir. Kaynak ve hedef adresi bir bilgisayardan oluşur. Eğer hedef bilgisayarın IP adresi biliniyorsa çoğunlukla bu transfer yöntemi kullanılır. Örneğin internet tarayıcımızın adres satırına www.yazilimgrubu.org yazdığımızda bizim bilgisayarımız ile www.yazilimgrubu.org sitesinin yer aldığı server arasında unicast bir bağlantı kurulur. Tarayıcıda adres satırına sitenin adresi yazıp ENTER'a bastığımızda belirtilen siteye erişmek istediğimizi belirten bir TCP paketi hazırlanır. Bu paket içinde, paketin header adı verilen parçasına bizim IP adresimiz ve erişmek istediğimiz sitenin IP adresi yerleştirilir. Server paketi aldığına cevabını hazırlar(Site içeriğini) ve bize TCP paketi halinde geri gönderir. Bizim gönderdiğimiz pakette kaynak adresi bizim IP adresimiz, aldığımız pakette ise kaynak IP adresi serverin IP adresi olacaktır.

2- Multicast : Bu transfer türü çoklu bağlantı veya bire-çok bağlantı şeklinde de adlandırılabilir. Bu transfer türünde gönderilen paketler tek bir alıcıya değil de birden fazla alıcıya gönderilir. Video konferanslar bu yöntemle gerçekleştirilir. Multicast bağlantılar kurabilmek için D ve E sınıfı IP adresi kullanmak zorunludur.

3-Broadcast : Bu transfer yöntemi çoğunlukla bizim kontrolümüz dışında gerçekleşir. Broadcast bağlantılar tek bir gönderici tarafından networkte bulunan bütün bilgisayarlara gönderilir. Bu yöntem hedefin IP adresi bilinmiyorsa kullanılır. Paket içeriğinde hedef IP adresi kısmı 255.255.255.255 hedef MAC adresi kısmında ise FF:FF:FF:FF:FF:FF yazılır. Bu IP ve MAC adresi özel bir adrestir ve network içinde bütün bilgisayarları temsil eder. İnternet ortamında ise dünya genelinde internete bağlı olan bütün bilgisayarlar demektir. Bir örnekle daha iyi anlaşılacaktır.
400 bilgisayardan oluşan bir ağımız olduğunu düşünün. Bu 400 bilgisayarın hepsine de IP adresi atanmak zorunda aksi taktirde birbirleriyle haberleşmeleri imkansız hale gelecek dolayısıyla ağımız işlevini kaybedecektir. Tabii ki 400 bilgisayara IP adresi ataması işi elle yapıldığı zaman oldukça zahmetli bir iştir. Bu işi otomatik olarak yapabilecek sistemler mevcuttur. DHCP Server denilen bilgisayarlar network dahilinde bulunan bilgisayarlara otomatik olarak IP konfigürasyonu(IP adresi, Alt Ağ Maskesi, Default gateway, DNS, WINS vb. gibi) sağlamaktan sorumludurlar. Peki ağa dahil olan bir bilgisayar hangi bilgisayarın DHCP server olduğunu nerden bilecek? Tabii ki bilemeyecek. O yüzden IP konfigürasyonu almak isteğiyle ilgili bir broadcast paketi hazırlayıp gönderecek. Paketin kaynak IP adresi boş, kaynak MAC adresi kendi MAC adresi, hedef IP adresi 255.255.255.255 ve hedef MAC adresi ise FF:FF:FF:FF:FF:FF: şeklinde olacaktır. Paketi ağdaki bütün bilgisayarlar kabul edecek paket içeriğine bakacak eğer bilgisayar DHCP server değilse cevap hazırlanmayacaktır. İçlerinde DHCP server olan bilgisayar paketi kabul edince paket içeriğinin kendisiyle ilgili olduğunu anlayacak ve içinde kendi IP adresinin ve bizim için hazırladığı IP konfigürasyonun da olduğu bir paket hazırlayıp yine Broadcast yöntemiyle gönderecektir(Çünkü bizim bilgisayarımızın hala bir IP adresi yok).

IP Adresleri ve Subnet Kavramı -3

   Önceki iki makalemizde IP adreslerinden, IP adreslerinin sınıflandırılmasından, Subnet kavramından ve ağımızı nasıl genişletebileceğimizden kısaca bahsetmiştik. Bu makalede ise var olan ağımızı nasıl daha küçük parçalara bölebileceğimizden bahsedeceğiz. Öncelikle neden var olan ağı daha küçük parçalara ayırmak isteriz? Geniş bir alanda rahat rahat çalışmak varmak niye kendi alanımızı daraltırız?
Bu sorunun alternatifi olmayan bir cevabını bulmak oldukça zor. Ama şöyle bir düşünelim. Ağımızda 150 bilgisayar var bunları gruplara ayırmak istiyoruz fakat her grubun diğer gruplarla doğrudan bağlantısının olmasını istemiyoruz. Mesela Yönetim, Muhasebe, Satış gibi bölümler var bunlar kendi içinde haberleşsin fakat diğer bölümlere doğrudan erişemesin. Bu tür durumlarda bütün bilgisayarları aynı ağda bulundurmak istemeyebiliriz. (Aynı ağda olsalar dahi VLAN kullanarak erişim engellenebilir ama konunun içeriği itibariyle şimdilik VLAN yok gibi davranıyoruz.) Peki birbirleriyle nasıl haberleşecekler. Bunun için araya router konulması gerekiyor.
Şimdi ağımızı daraltma işine dönelim. Bir ağın daha küçük parçalara ayrılması işlemi ağ genişletmekte olduğu gibi alt ağ maskesini değiştirerek yapılıyor. C Sınıfı adresimiz olduğunu düşünelim. C sınıfı adreslerde IP adresinin ilk üç okteti bizim ağımızı temsil ediyordu. Dördüncü oktet ise ağımızda bulunan bilgisayarı temsil ediyordu. C sınıfı bir adres kullanan ağda 254 bilgisayar adresleyebiliyorduk. Bunun hesaplanması şu şekilde:
ABS = Adreslenecek Bilgisayar Sayısı
OS = Bilgisayar adresleme kullanılabilecek bit sayısı (Alt ağ maskesindeki 0 sayısı)

ABS = 2^OS -2

Ağ adresimiz ve Alt ağ maskemiz 192.168.2.0 /24 (192.168.2.0/255.255.255.0) olsun. Alt ağ maskesi adresimizi 1 ve 0 şeklinde gösterecek olursak
Alt Ağ Maskesi ==> 1111 1111 1111 1111 1111 1111 0000 0000
şeklinde yazabiliriz. Bu durumda alt ağ maskemizde 8 tane 0 olduğunu görüyoruz. Formülde değeri yerine yazdığımızda
ABS = 2^8 -2
ABS = 256 -2
ABS = 254 bilgisayar adresleyebileceğimizi buluyoruz. Neden 2 eksilttiğimizi biliyorsunuz(Network ID ve Broadcast adresi)
Bu değer ağımız tek parça halinde kullanıldığı zaman geçerli. Peki biz ağımızı 3 Parçaya bölmek istiyorsak alt ağ maskemizi nasıl değiştireceğiz. Bunun hesaplaması da şu şekilde:
DBS = Değiştirilecek Bit Sayısı
BAS = Bölünecek Ağ Sayısı

BAS <= 2^DBS -2 şeklinde kullanıyoruz. Değiştirilecek bit sayısı kavramı son oktetteki bitlerden kaç tanesinin değerini 1 yapmamız gerektiğini ifade ediyor. Hemen hesaplamaya geçelim.
3<=2^DBS-2 formülünde eşitsizliği sağlayan en küçük DBS değeri 3. Çünkü;
3<= 2^3 -2
3<=6
Yani biz son oktete en soldan itibaren 3 tane bitin değerini 1 yapmalıyız. Fakat 6 değeri neyi ifade ediyor? Bu ağımızın 6 parçaya bölündüğünü gösteriyor. Biz 3 parça isterken 6 parçamız oldu. Bunu 3 yapamazmıyız? Maalesef hayır. Bu durumda alt ağ maskemiz şu hale geldi.
Alt Ağ Maskesi ==> 1111 1111 1111 1111 1111 1111 1110 0000 == 255.255.255.224
Peki 6 tane ağımız olduğuna göre her ağda kaç bilgisayar adresleyebileceğiz onu da hesaplayalım.
ABS = 2^OS -2 formülünde değerleri yerine yazdığımızda
ABS = 2^5 -2 (Alt ağ maskesi adresimizde 5 tane 0 kaldı.)
ABS = 30
Şimdi her birinde 30 bilgisayar adresleyebileceğimiz 6 tane ağımız oldu. Bu durumda toplam adreslenebilecek bilgisayar sayısı 254'ten 180'e düştü(Üzgünüm). Peki ağ parçalarının adresleri hangi aralıkta?
1.Ağ ==> 192.168.2.32 - 192.168.2.63 Alt Ağ Maskesi ==> 255.255.255.224
2.Ağ ==> 192.168.2.64 - 192.168.2.95 Alt Ağ Maskesi ==> 255.255.255.224
3.Ağ ==> 192.168.2.96 - 192.168.2.127 Alt Ağ Maskesi ==> 255.255.255.224
4.Ağ ==> 192.168.2.128 - 192.168.2.159 Alt Ağ Maskesi ==> 255.255.255.224
5.Ağ ==> 192.168.2.160 - 192.168.2.191 Alt Ağ Maskesi ==> 255.255.255.224
6.Ağ ==> 192.168.2.192 - 192.168.2.223 Alt Ağ Maskesi ==> 255.255.255.224
Yukardaki adreslerin içinde Network ID ve Broadcast adresleride var. Yani 1.Ağ için Network ID 192.168.2.32, Broadcast Adresi de 192.168.2.63 olacağı için bu adresleri hiç bir bilgisayara veremeyiz. Şimdi tasarladığımız yapımızla ilgili bir örnek yapalım. İki bilgisayar olsun. IP adresleri
PC1 ==> 192.168.2.34 / 255.255.255.224
PC2 ==> 192.168.2.67 / 255.255.255.224

PC1 IP ==> 1100 0000 1010 1000 0000 0010 0010 0010
PC1 Alt ağ ==> 1111 1111 1111 1111 1111 1111 1110 0000
PC1 Ağ ==> 1100 0000 1010 1000 0000 0010 0010 0000 ==> 192.168.2.32

PC2 IP ==> 1100 0000 1010 1000 0000 0010 0100 0011
PC2 Alt ağ ==> 1111 1111 1111 1111 1111 1111 1110 0000
PC2 Ağ ==> 1100 0000 1010 1000 0000 0010 0100 0000 ==> 192.168.2.64
Gördüğümüz gibi ağ adresleri farklı olduğu için birbirleriyle doğrudan haberleşme imkanı bulamayacaklar. Bunu aşağıdaki resimde de görebilirsiniz. Birbirlerine fiziksel olarak bağlı oldukları halde ping komutu zamanaşımına uğradı.
Peki birbiriyle haberleşmesi nasıl olacak. Daha öncede söylediğimiz gibi bunun için router kullanmamız gerekecek. Bunun içinde resimdeki bir tasarım yapıyoruz. Router konfigürasyonu şekildeki gibi olacak. Az önce ping atamadığımız bilgisayara tekrar ping atmayı deniyoruz ve gördüğünüz gibi artık erişimimiz var
Doğrudan erişim değil ama dolaylı olarak ulaşabiliyoruz. Biraz karışık konulardır ama bir kere anladığınızda kolay kolay unutmazsınız.

IP Adresleri ve Subnet Kavramı -2

Önceki makalemizde Subnet kavramına kısa bir giriş yapmıştık. Subnet veya Alt ağ maskesinin ne işe yaradığından nasıl hesaplandığından bahsetmiştik. Bu bölümde ise mevcut ağımızı nasıl genişleteceğimizden veya daraltacağımızdan bahsedeceğiz. Fakat o konuya girmeden önce IP sınıflarından bahsetmek istiyorum. IP adresleri dünya genelinde Internet Society adında bir kurum tarafından ülkelere dağıtılmıştır. Bu kurum hangi ülkelere hangi IP aralıklarının verileceğini belirler. Her ülkede temsilcileri vardır. Türkiye'de bu kurumun temsilciği ODTÜ-Tübitak işbirliği ile yürütülmektedir.
IP adreleri 5 sınıfa ayrılmıştır. Bu sınıflar IP adresinin ilk oktetlerine göre ayrılır.
1- A Sınıfı IP Adresleri : Bu adreslerin ilk okteti 1-126 arasındadır. A sınıfıadreslerde ağ adresi ilk oktet ile belirlenir. Ağ adresi olarak tek oktet kullanılması en fazla 126 tane ağ bulundurabileceği manasına gelmektedir. Geriye kalan 3 oktet her bir ağdaki bilgisayarları temsil etmektedir. Her oktet 0-255 arası değer alabildiğine göre 255*255*255 16 milyondan fazla adres demektir. Yani A sınıfı IP adresine sahip bir ağda 16 milyondan fazla bilgisayar olabilir.
2- B Sınıfı IP Adresleri : Bu adreslerin ilk okteti 128-191 arasındadır. B sınıfı adreslerde ağ adresi ilk iki oktet ile belirlenir. Her bir ağdaki bilgisayarları adreslemek için 3. ve 4. oktetler kullanılır. Ağ adresi olarak ilk iki oktet kullanıldığını söylemiştik. ilk oktet için 64 farklı değer (128-191 arası), ikinci oktet için 256 farklı değer(0-255) olabilir yani B sınıfı adreslerde 64*256 =16384 tane ağ tanımlaması yapılabilir. B sınıfı adrese sahip bir ağ da yaklaşık 65 bin civarında bilgisayar bulunabilir.
3- C Sınıfı IP Adresleri : Bu adreslerin ilk okteti 192-223 arasındadır. C sınıfı adreslerde ağ adresi ilk üç oktet ile belirlenir. Ağdaki bilgisayarları adreslemek için ise son oktet kullanılır. Ağ adresi olarak 3 oktet kullanıldığından ve ilk oktet olarak da 192-223 arası değer alabildiğinden 2,097,152 tane ağ tanımlanabilir. Ağdaki bilgisayarları tanımlamak için son oktet kullanıldığı için her bir ağda 254 tane bilgisayar bulunabilir. Neden 256 değil 254?? Çünkü bir ağda ilk ve son adresler ayrılmıştır. ilk adres ağın kendisini gösterir son adres ise Broadcast adresi adı verilen bir adrestir. Bir mesajın bütün ağa gönderilmesi gerektiği zaman kullanılır.
4- D ve E Sınıfı IP Adresleri : Bu adresler özel IP adresleridir. Elle IP adresi ataması yapılırken dahi kullanılamazlar. Multicast(Video konferans gibi) yayınlar yapmak kullanılır.

Subnet Değiştirme

Önceki makalemizde bir bilgisayarın sadece kendisiyle aynı ağda olan bilgisayarlarla doğrudan iletişim kurabileceğinden bahsetmiştik. Evde, işyerinde vs. vs yerlerde kurduğumuz ağlarda çoğunlukla C sınıfı adresler kullanılırız. Çünkü A ve B sınıfı adresler çoktan bazı kurumlara tahsis edilmiş durumda. Bunlardan bazıları bu adresleri kendi yerel ağları için kullanmaktadır bazılarını da internete bağlandığımız zaman bize tahsis ediyorlar. İşin gerçeği internete bağlandığımızda Türk Telekomun ağına dahil oluyoruz. Yukarda C sınıfı adres kullanan bir ağın 254 tane bilgisayar barındırabileceğinden bahsetmiştik. Peki bilgisayar sayımız bu sayıdan daha fazla ise örneğin 400 tane ise ne olacak? Bu durumda 2 çözüm var
1- 2 tane farklı ağ kullanmak (2 -*254 = 508 tane bilgisayar)
2- Varolan ağımızı genişletmek.

Birinci yöntem mantıklı bir çözüm gibi görünse de beraberinde çok önemli bir sorun getiriyor. Örneğin iki bilgisayar var birbiriyle haberleşmesi gerekiyor. IP adresleri şöyle :
PC1 = 192.168.2.100 /255.255.255.0
PC2 = 192.168.3.16 / 255.255.255.0
Subnet hesaplaması yaptığımızda PC1 192.168.2.0 ağında PC2 ise 192.168.3.0 ağında olduğunu görüyoruz. Ağ adresleri farklı olduğuna göre bu iki bilgisayar doğrudan haberleşemeyecek. Peki nasıl haberleşecekler.
a- Varolan internet bağlantısını kullanacaklar.
b- İki ağ arasında router konulacak. Doğrudan değil de dolaylı olarak haberleşme sağlanacak.
İki çözüm önerisi de yapılması mümkün olan şeyler. Fakat bunu yapmakla sağ kulağımızı sol elimizi başımızın arkasından dolaştırarak gösteriyoruz.
İkinci yöntem hem daha basit hem de daha mantıklı bir çözümdür. Ekstra hiçbir şey yapmaya gerek kalmadan sorunu çözüyoruz. Hem ağımızın bilgisayar kapasitesi artıyor hem de ayrıca router gibi bir donanım almamıza gerek kalmıyor.
Peki ağımızı nasıl genişletiyoruz. Ağımızı genişletmek için alt ağ maskemizi değiştiriyoruz. Önceki makalemizde iki bilgisayarın IP adreslerine ve Alt Ağ Maskesi adreslerine "VE" işlemini uygulamıştık bu sayede söz konusu iki bilgisayarın birbiriyle doğrudan haberleşmesinin mümkün olup olmadığını tespit etmiştik. Fakat alt alğ maskemiz 254 tane bilgisayar adresleyebilecek büyüklükteydi. Bunu nasıl anladık? Alt ağ maskemizin ilk üç biti zaten sınırdaydı(255.255.255). Son oktet ise "0" olduğu için 255'e kadar 254 tane bilgisayar adresleyebiliyorduk(0 ve 255'i kullanamıyoruz). Biz alt ağ maskemizi biraz daha geniş tutarsak ağımıza dahil olabilecek bilgisayar sayısıda artacaktır veya tam tersi daha dar tutarsak ağımıza dahil olabilecek bilgisayar sayısıda azalacaktır. Daha iyi anlamak için bir örnek yapalım. Yukarda birbiriyle haberleştirmek istediğimiz bilgisayarların alt ağ maskelerini değiştirip tekrar hesaplayalım.
PC1 = 192.168.2.100 /255.255.254.0
PC2 = 192.168.3.16 / 255.255.254.0

PC1 IP ==> 1100 0000 1010 1000 0000 0010 0110 0100
PC1 SUBNET ==> 1111 1111 1111 1111 1111 1110 0000 0000
PC1 AĞ ==> 1100 0000 1010 1000 0000 0010 0000 0000 ==> 192.168.2.0

PC2 IP ==> 1100 0000 1010 1000 0000 0011 0001 0000
PC2 SUBNET ==> 1111 1111 1111 1111 1111 1110 0000 0000
PC2 AĞ ==> 1100 0000 1010 1000 0000 0010 0000 0000 ==> 192.168.2.0

Gördüğünüz gibi her iki bilgisayarda artık aynı ağ içinde dolayısıyla birbirleriyle doğrudan haberleşebilecekler. Şimdi ağın geneline bakalım.
192.168.2.0 -192.168.2.255 ve 192.168.3.0 - 192.168.3.255 arası bütün IP adresleri yeni alt ağ maskesi adresimizle birlite aynı ağa dahil olduğuna göre bizim ağımız 254 bilgisayardan 510 bilgisayara çıktı. 254 +254 = 508 olduğu halde nasıl oluyorda bizim ağımız 510 bilgisayar alabiliyor. Sorunun yanıtı oldukça basit. Bir ağda hangi adresleri kullanamıyorduk?
1- Network ID adı verilen ağın tanımlayıcı adresini(Ağdaki ilk adres).
2- Broadcast adresi adı verilen tüm ağ ile aynı anda haberleşmeyi sağlayan adres(Ağdaki son adres).
Peki bizim Network ID'miz hangi adres? 192.168.2.0. Broadcast adresimiz ? 192.168.3.255. Yani 192.168.3.X ile başlayan adreslerdeki 192.168.3.0 adresi artık network ID değil, aynı şekilde 192.168.2.X ile başlatan adreslerdeki 192.168.2.255 adresi de artık Broadcast adresi değil. Artık bu adresleri de kullanabiliriz. O yüzden 2 tane IP adresini fazladan kazanmış olduk.
Bir sonraki makalemizde Subnet işlemlerine devam edeceğiz.

IP Adresleri ve Subnet Kavramı -1

   IP adresi TCP/IP protokolünün bir parçasıdır. Bir ağa bağlı olan bilgisayarın diğer bilgisayarlarla haberleşmesini sağlamak için bir adres bilgisidir. IP adresleri 32 bitlik bir bilgidir. Oktet adı verilen 4 adet 8 bitlik parçadan oluşur. Bu parçalar birbirinden "." ile ayrılır. Örneğin; 192.168.2.125 gibi.
192 ==> 1.Oktet
168 ==> 2.Oktet
2 ==> 3.Oktet
125 ==> 4.Oktet
herbir parça 8 bitten oluştuğu için 0-255 arası rakamlardan oluşabilir.
Daha önceki makalelerimizde bahsettiğimiz gibi bilgisayarlar arası haberleşmede bağlantı IP adresi aracılığıyla sağlanır. Bu bağlantı ya doğrudan ya da dolaylı olarak (yönlendirme) yapılır. Doğrudan bağlantı haberleşme sağlanacak bilgisayarlar (kaynak ve hedef bilgisayar) aynı IP bloğunda bulunuyorsa, dolaylı bağlantı ise farklı IP bloklarında bulunuyorsa gerçekleşir. Peki iki bilgisayarın aynı IP bloğunda olup olmadığını nasıl bileceğiz. İşte bu noktada devreye Subnet kavramı giriyor. Subnet bir bilgisayarın bulunduğu ağı tespit etmek için kullanılan bir adrestir. Subnet Mask veya Alt Ağ Maskesi olarak da isimlendirilir. IP adresi gibi 8 bitlik 4 oktetten oluşur.
Bir bilgisayar başka bir bilgisayarla haberleşmek istediğinde şunlar gerçekleşir.
1- Kaynak bilgisayar hedef bilgisayarın IP adresini tespit eder (Cache-Host Dosyası-DNS-WINS-BroadCast-LmHost Dosyası gibi yöntemlerle)
2- Hedef bilgisayarla aynı ağda bulunup bulunmadığını kontrol eder.
3- Haberleşme protokolünü uygular (TCP veya UDP)
Burada 1. ve 3. Maddeler henüz anlatılmış konular değil fakat oldukça geniş konulardır. Konunun dağılmaması için bunları sonraki makalelerimizde anlatacağım. Gelelim kaynak ve hedef bilgisayarın aynı ağda olup olmadığının nasıl tespit edileceğine. İki bilgisayarın aynı ağda olup olmadığı IP adresi ve alt ağ maskesinin AND işlemine tabi tutulması sonucu ortaya çıkar. Eğer her iki bilgisayarda da AND işleminin sonucu aynıysa bu iki bilgisayar aynı ağda bulunuyor demektir. Bu durumda iki bilgisayar doğrudan haberleşebilir. AND işlemi IP adresi ve alt ağ maskesinin karşılıklı oktetlerinin ikilik sistemdeki karşılıklarıyla yapılır. Örneğin;
Kaynak IP Adresi : 192.168.2.125
Kaynak Alt Ağ Maskesi : 255.255.255.0

Hedef IP Adresi : 192.168.2.9
Hedef Alt Ağ Maskesi : 255.255.255.0

olsun. Öncelike oktetleri ayrı ayrı ikilik sisteme çeviriyoruz.

Kaynak IP ==> 1100 0000 1010 1000 0000 0010 0111 1101
Kaynak Subnet ==> 1111 1111 1111 1111 1111 1111 0000 0000

Daha sonra her biti kendisine karşılık gelen bitle karşılaştırıyoruz. Eğer bitlerin ikisi birden "1" ise sonuc olarak "1" en az bir tanesi "0" ise sonuç olarak "0" yazıyoruz.

Kaynak IP ==> 1100 0000 1010 1000 0000 0010 0111 1101
Kaynak Subnet ==> 1111 1111 1111 1111 1111 1111 0000 0000
Kaynak Ağ ==> 1100 0000 1010 1000 0000 0010 0000 0000
Şimdi Çıkan sonucu onlu sisteme çeviriyoruz.
Kaynak Ağ ==> 1100 0000 1010 1000 0000 0010 0000 0000 ==> 192.168.2.0
Aynı işlemleri hedef bilgisayar içinde yapıyoruz.
Hedef IP ==> 1100 0000 1010 1000 0000 0010 0000 1001
Hedef Subnet ==> 1111 1111 1111 1111 1111 1111 0000 0000
Hedef Ağ ==> 1100 0000 1010 1000 0000 0010 0000 0000 ==> 192.168.2.0
Şimdi her iki bilgisayarında ağ adreslerini karşılaştırıyoruz.

Kaynak Ağ ==> 192.168.2.0
Hedef Ağ ==> 192.168.2.0
Gördüğünüz gibi her iki bilgisayarında Ağ adresleri aynı çıktı. Burda şu sonucu çıkarıyoruz. Kaynak ve hedef bilgisayarlar aynı ağda bulunuyorlar. Birbiriyle doğrudan haberleşebilirler. Bulduğumuz bu adres Bilgisayarların bağlı bulunduğu ağın adresidir. Ağ adresi veya Network ID olarak da isimlendirilir. Bir bilgisayarın ağdaki adresi verilirken alt ağ maskesi de yazılır. Altağ maskesi iki şekilde yazılabilir.
1- 192.168.2.125 / 255.255.255.0
2- 192.168.2.125 /24
Burada "24" rakamı ile belirtilen altağ maskesindeki "1" lerin sayısıdır. birinci oktetten itibaren 24 tane 1 olduğunu ifade eder.
255.255.255.0 ==> 1111 1111 1111 1111 1111 1111 0000 0000
gördüğünüz gibi 24 tane 1 rakamı bulunmaktadır. Burada dikkat edilmesi gereken en önemli nokta bir altağ maskesi adresi yazılırken iki tane 1 rakamının arasında 0 olmaması gerektiğidir. yani şu şekilde bir alt ağ maskesi yanlıştır
1111 1111 1110 1111 0001 1111 0000 0000.
Bu nedenledir ki alt ağ maskelerinde bazı rakamların karşılığı yoktur(250, 253 gibi).
Bir sonraki makalemizde Subnet kavramına devam edeceğiz ve Subnet bölme işlemlerini inceleyeceğiz.

C# Sürükle--Bırak Uygulamaları

   Günümüzde komut satırında çalışan uygulamalar hariç bütün uygulamalarda kullanılan sürükle bırak uygulamalarında uygulamalarından bahsetmek istiyorum. Sürüklü bırak uygulamaları hepimizin hergün defalarda kullandığı bir özelliktir. Dosya kopyalarken, metin düzenlerken vs vs farkında olmasak bile birçok yerde kullanıyoruz. Artık bu işlemin nasıl yapıldığını öğrenme vakti geldi sanırım. Öncelikle bu işlem için biraz ön bilgi vermek istiyorum. Sürükle-Bırak tekniği basit bir fare hareketinden öte bir işlemdir fakat korkulacak kadar zor değildir. Dikkat edilmesi gereken klavye ve fare tuş durumlarını aynı anda kontrol edebilmektir. Ctrl , Shift, Alt tuşları basılı mı? Farenin sol tuşu mu basılmış yoksa sağ tuşu bunları kontrol edebildikten sonra geriye fazla bişey kalmıyor. Bunun için "KeyState" özelliğini kullanıyoruz.
    Öncelikle Form üzerine 2 tane PictureBox nesnesi oluşturun ve isimlerini "pctResim1" ve "pctResim2" olarak değiştirin. "pctResim1" e istediğiniz bir resmi ekleyin hangi resim olacağı veya resim dosyasının adının ne olacağı size kalmış. Form açıldığında PictureBox nesnelerini Sürüklü-Bırak işlemi için etkinleştirmemiz gerekli bunun için formumuzun "Load" olayına şu kodları yazıyoruz. İsterseniz pctResim1 e resim ekleme işini de bu kısımda yapablirsiniz.

pctResim1.AllowDrop = true;
pctResim2.AllowDrop = true;
pctResim1.Image = Image.FromFile(@"C:\img0.jpg");
pctResim1.SizeMode = PictureBoxSizeMode.StretchImage; //Resmi picturebox için tam sığacak şekilde ayarlar.

pctResim2.SizeMode = PictureBoxSizeMode.StretchImage; //Resmi picturebox için tam sığacak şekilde ayarlar.
Daha sonra sürükle-bırak işlemlerinde kullanmak için class seviyesinde 2 tane picturebox nesnesi daha tanımlayın fakat yapıcı metot kullanmayın.
PictureBox kaynak, hedef;
   Şimdi farenin hangi tuşunun kullanıldığını bulmamız gerekiyor.Sürükle bırak olayının gerçekleşmesi için ilk şart farenin sol tuşunun bırakılmadan hedefe sürüklenmesidir. Yani bütün işlem boyunca fare tuşu basılı kalmak zorunda daha teknik ifadeyle MouseDown olayı gerçekleşmek zorunda. Şimdi picturebox nesnelerinin mousedown olaylarını düzenlemeye başlayalım. Bir tanesinde düzenleme yapmamız yeterli olacaktır. Çünkü yapılacak işlemler aynı olacağı için referans gösterme şeklinde kod kalabalıklığından kurtulabiliriz. Şimdi pctResim1 nesnemizin MouseDown olayını şu şekilde düzenleyelim.
// Asıl picturebox nesnelerimiz için referans bir picturbox nesnesi oluşturuyoruz.
//Burda yapacağımız değişiklikler asıl picturebox nesnemizde de etkili olacaktır
// sender as PictureBox ifadesi object türünden nesneyi picturebox nesnesi gibi davranmasını sağlamak için kullandık.
//Gelen object nesnesi zaten picturebox türünden olduğu herhangi bir sorun teşkil etmeyecektir.

PictureBox resim = sender as PictureBox;
if (e.Button == MouseButtons.Left && resim.Image!=null)
{
resim.DoDragDrop(resim.Image, DragDropEffects.All); //Sürükle-bırak işlemi başladı.}

   Şimdi yaptıklarımızı gözden geçirelim.
   1- Farenin sol tuşuna basılıp basılmadığını öğrendik
   2- Farenin sol tuş basıl olarak hareket ettiğini öğrendik (Resim hareket etmeye başladı)
   Şimdi sırada resmin taşıma sırasında diğer PictureBox nesnesi üzerine gelip gelmediğini kontrol edecez. Yine pctResim1 nesnesinin DragEnter olayını düzenleyecez burada aynı zamanda tuş kontrolü de yapıyoruz Eğer Ctrl tuşuna basılmışsa resmi diğer picturebox nesnesine kopyalıyoruz basılmamışsa veya Shft tuşuna basılmışsa taşıma işlemi yapıyoruz. DragEnter olayını şu şekilde kodluyoruz.
private void pctResim1_DragEnter(object sender, DragEventArgs e)
{
//İlk kontrol etmemiz gereken şey taşınan nesne bir resim nesnesi mi??
//GetDataPresent fonksiyonu sürüklenen içeriği Bitmap data formatıyla karşılaştırıyor
//Sürüklenen içerik Bitmap formatıyla aynıysa true değilse false değerini verir.

if (e.Data.GetDataPresent(DataFormats.Bitmap))
{
//Ctrl tuşunun basılı olup olmadığını kontrol ediyoruz.
//Keystate özelliği Shift, Ctrl, Alt gibi özel tuşları ve fare tuşlarının durumunu verir
//8 bitlik bir değeri vardır. Herbit bir tuşun durumuna karşılık gelir.
//3.bit Ctrl tuşunun basılı olma durumudur. Eğer ctrl tuşu basılı ise 3. bit 1 olmak zorundadır. 000001000
// 10 lu sistemdeki karşılığı ise 8 dir. & operatörü ise ikilik sistemde VE işlemi yapar.
//    000001001      Keystate özelliğinin durumu (Ctrl ve Fare sol tuşu basılı.1.bit fare sol tuşuna karşılık geliyor)
//    000001000      Ctrl tuşunun basılı olduğu durum
//    000000100      Shift tuşunun basılı olduğu durum
//    000001000      & işleminin Ctrl tuşu için sonucu
//    000000100      & işleminin Shift tuşu için sonucu. diğer bitler şimdilik bizi ilgilendirmiyor.

if ((e.KeyState & 8) == 8)
{
e.Effect = DragDropEffects.Copy;
}
else if ((e.KeyState & 4) == 4)
{
e.Effect = DragDropEffects.Move;
}
else
{
e.Effect = DragDropEffects.Move;
}
}
else
{
//Sürüklenen içerik Bitmap formatında değilse hiçbişey yapmayacak

e.Effect = DragDropEffects.None;
}
}

Sıra geldi içeriğin diğer picturebox nesnesi üzerine bırakıldığı ana. Bunun için picturebox nesnesinin DragDrop olayını kullanıyoruz. Bu olayı sürükle bırak işlemi tamamlandığında yani bırakma aşamasında tetikleniyor. Bizim yapmamız gereken sürüklenen içeriği hedef üzerine aktarmak. Kod kalabalıklığından kurtulmak için yine tek fonksiyon kullanmak istiyorum. Öncelikle bir referans nesnesi oluşturalım ve bu nesneye sürüklenen içeriği aktaralım ve Ctrl tuşunun durumuna göre taşıma veya kopyalama yapalım.
private void pctResim1_DragDrop(object sender, DragEventArgs e)
{
// Hedef için bir referans nesnesi oluşturduk.hedef = sender as PictureBox;
//Sürüklenen içeriği referans nesnesine aktardıkhedef.Image = (Bitmap)e.Data.GetData(DataFormats.Bitmap);
//Aslında şu an itibariyle sürükle bırak işlemi tamamlanmış oldu fakat
//kopyalama veya taşıma işlemi kontrolü yapmadığımız için kaynak nesne olduğu gibi duruyor.
//Bunun için yine KeyState özelliğini kullanıyoruz.
//Ctrl tuşunun durumuna bakıyoruz. Eğer Ctrl tuşu basılı değilse kaynak nesnedeki resmi silmemiz gerekecek

if ((e.KeyState & 8) != 8)
{
kaynak.Image = null;
}
}


NOT: Yazacağımız bütün kodlar bu kadar ama bu haliyle çalışmayacaktır. Kodların çalışması için pctResim2 nesnesinin özellikler penceresinde olaylar kısmına geçin ve
1- MouseDown olayının sağındaki ok işaretine basın açılan listeden pctResim1_MouseDown'ı seçin
2- DragEnter olayının sağındaki ok işaretine basın açılan listeden pctResim1_DragEnter'i seçin
3- DragDrop olayının sağındaki ok işaretine basın açılan listeden pctResim1_DragDown'ı seçin

uygulamanız sorunsuz bir şekilde çalışacaktır.

C# Resim İşleme

C# .Net FrameWork 3.5 ve .NetFrameWork 4 versiyonları ile birlikte resim işleme konusunda güzel özellikler kazanmıştır. Burada şimdilik bir resmi gri tonlamalı hale nasıl getireceğimiz anlatılacak olup ilerde diğer resim işleme konuları da ayrıca anlatılacaktır. Resim işleme tamamen bir resmin piksellerindeki değerlerin değiştirilmesi temeline dayanır. İşin püf noktası da burası tekniğinizin kalitesini belirleyen pikseli nasıl ele aldığınızdır. İnternette araştırma yaptığınızda resim işleme ile ilgili birçok kaynak var fakat bunların büyük bir çoğunluğu piksellere erişirken dolaylı yolları kullandığı için biraz yavaş çalışan kodlar paylaşmaktadır. Birazdan anlatacağım teknik ise diğer kodlara kıyasla en az 2-3 kat daha hızlı çalışmaktadır. Kodlamaya geçmeden önce biraz ön hazırlık yapmak gerekiyor. Bunun için Solution Explorer'da projemizin özelliklerini açıyoruz(Proje adı ->Properties). Daha sonra Build Sekmesini açıp "Allow unsafe code" seçeneğini işaretliyip ayarları kaydediyoruz. Bunu yapmamızın sebebi C# da varsayılan olarak Pointer(işaretçi) kullanımı pasiftir önce bunu aktifleştirmek gerekiyor. Daha sonra form üzerine bir adet PictureBox nesnesi oluşturup ismini pctResim diye değiştirin.
Şimdi projemize
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace lerini ekliyoruz. Öncelikle program içinde kullanacağımız değişkenlerimizi oluşturuyoruz.
byte siyah=0;  // Piksel renk değeri
int dizisayisi;    // rgbdeger dizisi için eleman sayısı
IntPtr baslangic;  // Resmin RAM üzerindeki adresi
byte[] rgbdeger;  //Resmin pikselleri
Bitmap resim;   //gösterilecek resim
Rectangle rct;  // resim için çerçeve
BitmapData bmData;   // resim üzerinde işlem yapacak sınıf.
Değişkenlerimizi oluşturduktan sonra hangi resim üzerinde çalışacağımızı belirtmemiz gerekiyor.
resim = new Bitmap(@"C:\YazilimGrubu.jpg");
Sonra resmimizle aynı boyutta bir çerçeve oluşturuyoruz
rct = new Rectangle(0, 0, resim.Width, resim.Height);
Sonra üzerinde çalışacağımız resmi RAM üzerine aktarıyoruz. Bunun için Bitmap nesnesinin LockBits fonksiyonunu kullanıyoruz. Bu fonksiyon bir tanesi 3 parametre alan diğeri 4 parametre alan 2 adet overload edilmiş şekilde kullanılabilir.Kullanım şekilleri şunlardır.
    1- Bitmap.LockBits(Rectangele r, ImageLockMode flags, PixelFormat format);
    2- Bitmap.LockBits(Rectangele r, ImageLockMode flags, PixelFormat format, BitmapData bitmapdata);
Ben ilk şeklini kullandım.
bmData = resim.LockBits(rct, ImageLockMode.ReadWrite, resim.PixelFormat);
dilerseniz
bmData = new BitmapData();
resim.LockBits(rct, ImageLockMode.ReadWrite, resim.PixelFormat,bmData);

şeklinde de kullanabilirsiniz. Resmi RAM üzerine aktardığımıza göre bunun hangi adreste olduğunu tespit etmeliyiz. bunun için
baslangic = bmData.Scan0;
komutunu kullanıyoruz. Scan0 özelliği resmin ilk pixel değerinin adresini verir.bunu da IntPtr türünden tanımladığımız baslangic değişkenine aktardık.
Şimdi bir dizi oluşturacağız. Bu dizi byte[] türünden olacak ve içerisine resmimizin piksel değerlerini aktaracağız. Tabii bunun için öncelikle kaç elemanlı bir diziye ihtiyacım olduğunu belirlemem gerekiyo. Herbir pikseli bir dizi değişkenine atayacağıma göre resmim kaç pikselse o kadar sayıda diziye ihtiyacım olacak bunu bulmak için de
dizisayisi = bmData.Stride * resim.Height;   // Stride özelliği bitmap nesnesinin tarama genişliğini verir. Daha kaba bir tabirle bir satırın kaç pikselden oluştuğunu
rgbdeger = new byte[dizisayisi];   // dizimiz oluşturuldu.
Dizimi oluştuğuna göre resmin piksel değerlerini bu diziye aktarmanın zamanı gelmiş demektir. Bunun için Marshal.Copy komutunu kullanıyoruz. bu komut RAM üzerindeki belli bir adresten verileri alır ve diziye aktarır.
Marshal.Copy(baslangic, rgbdeger, 0, dizisayisi);
Artık resmin piksel değerlerini diziye aktardık. Hadi biraz resim yapalım :) Bunun için for döngüsünü kullanıyoruz. Yavaş olur diye düşünmeyin işaretçi kullanmanın verdiği avantajla gerçekten hızlı çalışıyor.  Gri tonlamalı resim oluşturmanın kuralı aynı pikseldeki Kırmızı,Mavi,Yeşil değerlerinin ortalamasını almak ve o pikseldeki değerlere bu ortalama değeri tekrar atamaktır.
for (int i = 2; i < rgbdeger.Length; i += 3)
{
siyah = (Byte)Math.Abs((Byte.Parse(rgbdeger[i - 2].ToString()) + Byte.Parse(rgbdeger[i - 1].ToString()) + Byte.Parse(rgbdeger[i].ToString())) / 3);
rgbdeger[i - 2] = siyah;
rgbdeger[i - 1] = siyah;
rgbdeger[i] = siyah;
}

Burada üçer üçer atlamamızın sebebi dizi her pikselin 3 elemandan oluşuyor olması. Yani her 3 dizi elemanı bir araya geldiğinde bir piksel değeri oluşuyor. Resmin bütün piksellerini düzenlediğimize göre şimdi bu değerleri tekrar RAM üzerindeki yerlerine aktarmayalıyız. bunun için yine Marshal.Copy komutunu kullanıyoruz. Tabii ki işlem ters olduğu için parametreler biraz farklı olacak
 Marshal.Copy(rgbdeger, 0, baslangic, dizisayisi);
RAM deki piksel değerlerini de güncellediğimize göre artık resimdeki kilidi açabiliriz.
resim.UnlockBits(bmData);
ve son olarak resmi görüntülemenin zamanı geldi. Resim nesnesini picturebox nesnemize atıyoruz.
pctResim.Image = resim;

NOT: BitmapData sınıfı ile işlenen resimler RGB olarak değil BGR olarak düşünülmelidir. Yani Piksel Kırmızı, Yeşil, Mavi olarak değil de Mavi, Yeşil, Kırmızı olarak oluşur

Klasör Erişim İzinlerini Ayarlamak

Bilgisayarımızda paylaşımda olan veya olmayan klasörlere erişimi kısıtlamak isteyebiliriz. Bunun için projemize
using System.IO;
using System.Security.AccessControl;
using System.Management;
using System.Management.Instrumentation;

namespacelerini ekliyoruz. Bir klasöre ait izinleri ayarlamak için öncelikle klasörün yolunu DirectoryInfo türünden bir değişkene aktarmamız gereklidir.
DirectoryInfo dizin = new  DirectoryInfo("c:\YazilimGrubu");
Daha sonra bu dizine erişimleri kontrol edecek DirectorySecurity türünden bir değişken tanımlıyoruz ve bu değişkene erişim haklarını ayarlayacağımız dizinin erişim denetleyicisini aktarmamız gerekli. Bunu da
DirectorySecurity guvenlik = dizin.GetAccessControl();
komutuyla yapıyoruz. Sıra geldi dizine uygulayacağımız erişim haklarını belirlemeye Bunun için FileAccessRule türünden değişkenler tanımlıyoruz her bir erişim türü için (Okuma, Yazma, Değiştirme vb.) ayrı bir değişken tanımlıyoruz.

FileSystemAccessRule okuma;   //Okuma yetkisi için değişken
FileSystemAccessRule yazma;   //Yazma yetkisi için değişken
FileSystemAccessRule degistirme; //Değiştirme yetkisi için değişken
FileSystemAccessRule tamyetki;  //Tam kontrol yetkisi için değişken

değişkenleri tanımladıktan sonra bunların hangi kullanıcılar için geçerli olacağını izin verilip verilmeyeceğini ayrı ayrı belirliyoruz.

okuma= new FileSystemAccessRule("olcayguzel", FileSystemRights.Read, AccessControlType.Allow);  // okuma yetkisi verildiWrite = new FileSystemAccessRule("olcayguzel", FileSystemRights.Write, AccessControlType.Allow);  //Yazma yetkisi verildiModify = new FileSystemAccessRule("olcayguzel", FileSystemRights.Modify,  AccessControlType.Deny); //Değiştirme yetkisi verilmediFullControl = new FileSystemAccessRule("olcayguzel", FileSystemRights.FullControl, AccessControlType.Deny);  //Tam kontrol yetkisi verilmedi           

Eğer görsel bir arayüzünüz var ve kullanıcının yetkileri seçebilmesini istiyorsanız CheckBox bileşeninden faydalanabilirsiniz. Bu durumda kolaylık olması açısından şu şekilde kullanabilirsiniz.

okuma= new FileSystemAccessRule("olcayguzel", FileSystemRights.Read, chkOkuma.Checked == true ? AccessControlType.Allow:AccessControlType.Deny );
 Yetki durumlarını belirlediğimize göre bunları dizinimizin güvenlik denetleyicisine aktarıyoruz.

guvenlik.AddAccessRule(okuma);
guvenlik.AddAccessRule(yazma);
guvenlik.AddAccessRule(degistirme);
guvenlik.AddAccessRule(tamyetki);

Son olarak da dizinimin erişim denetleyicisine guvenlik ayarlarını aktarıyoruz.
dizin.SetAccessControl(guvenlik);

NOT:
chkOkuma.Checked == true ? AccessControlType.Allow : AccessControlType.Deny

bu komut şunu ifade eder. chkOkuma bileşeninin Checked özelliğini "true" değeri ile karşılaştırır karşılaştırmanın sonucu doğru ise
soru işaretinden hemen sonraki komut yanlış ise en son komut çalıştırılır. aslında if komutunun kısaltılmış halidir. bu komut yerine if komutu kullanılmış olsaydı şu şekilde kullanılacaktı.
if(chkOkuma.Checked == true)
{
okuma= new FileSystemAccessRule("olcayguzel", FileSystemRights.Read, AccessControlType.Allow);
}
else
{
okuma= new FileSystemAccessRule("olcayguzel", FileSystemRights.Read, AccessControlType.Deny);
}
Aynı işi daha kısa bir şekilde yani
chkOkuma.Checked == true ? AccessControlType.Allow:AccessControlType.Deny;şeklinde kullanmak daha mantıklıdır.

C# Yazıcı Kullanımı

C# da yazıcı kullanmak için PrintDocument nesnesi kullanılır.PrintDocument nesnesini kullanabilmek için ilk olarak
System.Drawing.Printing;
namespace i projeye eklenmelidir. PrintDocument nesnesi parametre almayan bir yapıcı fonksiyon kullanılarak oluşturulur.
PrintDocument belge = new PrintDocument();
bu tanımlamayı class seviyesinde yaparsanız nesneye heryerden erişebilirsiniz. Yazdırılacak metin bir dosyadan alınabileceği gibi form üzerindeki componentlerden veya herhangi bir değişkendende alınabilir. Biz burada dosyadan yazdırma işlemi yapacağız. Onun için yine class seviyesinde dosyadan okuma yapacak bir nesne oluşturuyoruz.
StreamReader okuyucu = new StreamReader(@"C:\Yazilimgrubu.txt");
veya
StreamReader okuyucu = new StreamReader("C:\\Yazilimgrubu.txt");
@ işareti escape karekterleri pasif hale getirir. Yazdırma işlemine başlamak için
belge.Print();
komutu kullanılır. bu komut kullanıldığında PrintPage olayı tetiklenir. Biz bu olay tetiklendiğinde hangi fonksiyonun çalışacağınıbelirlemek zorundayız. onun için şu satırı eklemeliyiz.
belge.PrintPage += new PrinPagetEventHandler(belge_Yazdir);daha sonra yazdırma sırasında kullanılacak yazı tipini belirlemeye. Yine bunun için de class seviyesinde bir tanımlama yapacağız.
Font yazitipi = new Font("Arial", 10);
daha sonra "belge_Yazdir" adında bir fonksiyon oluşturmalıyız. Tüm işi yapacak olan fonksiyon işte bu.
private void belge_Yazdir(object sender, PrintPageEventArgs e)
{
           
}

Artık bu kısımdan sonra işin en önemli kısmı. öncelikle kenar boşlukları için birkaç tane float türünden değişken oluşturuyoruz.
float satirsayisi = 0;   // Belgedeki bir sayfanın kaç satırdan oluştuğunu bulmak için
float pozisyon = 0;    //Yazdırılacak satırın koordinatı
float aktifsatir = 0;   //  O an aktif sayfadaki kaçıncı satırın yazdırıldığı

float solbosluk = e.MarginBounds.Left;   //Sayfanın sol kenar boşluğu. bu değer sayfa özelliklerinden alınıyor
float ustbosluk = e.MarginBounds.Top;    //Sayfanın üst kenar boşluğu. bu değer sayfa özelliklerinden alınıyor
string satir = null;           //O an yazdırılacak satırdaki metin
Değişkenlerimizi oluşturduktan sonra bir sayfaya kaç satır metin yazdırılacağını bulmamız gerekiyor. A4 boyutundaki bir kağıda sığacak satır sayısı ile A3 boyutundaki kağıda sığacak satır sayısı farklıdır. Bunu bulmak için sayfa yüksekliğini yazıtipinin yüksekliğine bölüyoruz.
            satirsayisi = e.MarginBounds.Height / yazitipi.GetHeight(e.Graphics);
Metnimizin kaç satırdan oluştuğunu hesapladığımıza göre artık metni satır satır yazıcıya gönderebiliriz. Bunun için döngülerden faydalanacağız. Bu iş için en uygun döngü türü while döngüsüdür.
            while (aktifsatir < satirsayisi && (satir = okuyucu.ReadLine())!=null)
            {
                pozisyon = ustbosluk + (aktifsatir * yazitipi.GetHeight(e.Graphics));
                e.Graphics.DrawString(satir, yazitipi, new SolidBrush(Color.Black), solbosluk, pozisyon);
                aktifsatir++;
            }

Yazdırma işlemi bitti fakat while döngüsü sadece 1 sayfa için çalıştı yazdırılacak başka sayfalar olup olmadığını kontrol etmemiz gerekli.
bunun için
            if (satir != null)
                e.HasMorePages = true;
            else
                e.HasMorePages = false;

komutunu kullanıyoruz ve yazdırma işlemi otomatik olarak devam ediyor. Son olarak kodun tamamı şu şekilde
using System;
using System.Drawing.Printing;
using System.Drawing;
using System.IO;
using System.Windows.Forms;

namespace YazilimGrubu
{
    public partial class Form1 : Form
    {
        PrintDocument belge = new PrintDocument();
        StreamReader okuyucu = new StreamReader(@"C:\Yazilimgrubu.txt");
        Font yazitipi = new Font("Arial", 10);
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            belge.Print();
            belge.PrintPage += new PrintPageEventHandler(belge_Yazdir);
        }

        void belge_PrintPage(object sender, PrintPageEventArgs e)
        {
            float satirsayisi = 0;
            float pozisyon = 0;
            float aktifsatir = 0;
            float solbosluk = e.MarginBounds.Left;
            float ustbosluk = e.MarginBounds.Top;
            string satir = null;

            satirsayisi = e.MarginBounds.Height / yazitipi.GetHeight(e.Graphics);
            while (aktifsatir < satirsayisi && (satir = okuyucu.ReadLine())!=null)
            {
                pozisyon = ustbosluk + (aktifsatir * yazitipi.GetHeight(e.Graphics));
                e.Graphics.DrawString(satir, yazitipi, new SolidBrush(Color.Black), solbosluk, pozisyon);
                aktifsatir++;
            }
            if (satir != null)
                e.HasMorePages = true;
            else
                e.HasMorePages = false;
        }
    }
}

Windows Bileşenlerini Kullanma

            ProcessStartInfo psi = new ProcessStartInfo();
            psi.FileName = "rundll32.exe";
            psi.CreateNoWindow = true;
            psi.Arguments = "shell32.dll,Control_RunDLL";
            psi.UseShellExecute = true;
            Process.Start(psi);
Yukarıdaki kod parçasında
psi.Arguments = "shell32.dll,Control_RunDLL";
satırını değiştirerek birbirinden farklı windows özelliklerini kullanabilirsiniz. Aşağıda hangi parametrenin ne işe yaradığı yer almaktadır.

Denetim Masası
"shell32.dll,Control_RunDLL"       Denetim Masasını açar.
Erişilebilirlik Özellikleri
"shell32.dll,Control_RunDLL access.cpl,1"- Erişilebilirlik klavye özelliklerini gösterir.
"shell32.dll,Control_RunDLL access.cpl,2" - Erişilebilirlik ses özelliklerini gösterir.
"shell32.dll,Control_RunDLL access.cpl,3" - Erişilebilirlik görüntü özelliklerini gösterir."shell32.dll,Control_RunDLL access.cpl,4" - Erişilebilirlik fare özelliklerini gösterir."shell32.dll,Control_RunDLL access.cpl,5" - Erişilebilirlik genel özelliklerini gösterir.

Donanım Ekle
"shell32.dll,Control_RunDLL sysdm.cpl @1" - Yeni Donanım Ekle Sihirbazını çalıştırır.
Yazıcı Ekle
"shell32.dll,SHHelpShortcuts_RunDLL AddPrinter" - Yeni Yazıcı Ekle Sihirbazını çalıştırır.
Program Ekle/Kaldır
"shell32.dll,Control_RunDLL appwiz.cpl,1" - Ekle/Kaldır penceresi aktif"shell32.dll,Control_RunDLL appwiz.cpl,2" - Windows Özelliklerini Ekle/Kaldır penceresi aktif."shell32.dll,Control_RunDLL appwiz.cpl,3" - Başlangıç Diski Oluştur penceresi aktif
Disk Kopyalama"diskcopy.dll,DiskCopyRunDll" - Çıkarılabilir sürücüler için disk kopyalama diyalog penceresi görüntülenir.

Kısayol
"appwiz.cpl, NewLinkHere {dosyaadi}" - Kısayol oluştur diyalog kutusunu gösterir. Diyalog penceresindeki dosya adı belirtilen konumdaki dosyadı ile tamamlanır.

Tarih &Saat Özellikleri
"shell32.dll,Control_RunDLL timedate.cpl,,0" - Tarih ve Saat ayarları diyalog penceresini görüntüler."shell32.dll,Control_RunDLL timedate.cpl,,1" - Zaman bölgesini ayarla diyalog penceresini görüntüler.

Görüntü "shell32.dll,Control_RunDLL desk.cpl,,0" - Arkaplan sekmesi görüntülenir."shell32.dll,Control_RunDLL desk.cpl,,1" - Ekran koruyucu sekmesi görüntülenir."shell32.dll,Control_RunDLL desk.cpl,,2" - Görüntü sekmesi görüntülenir."shell32.dll,Control_RunDLL desk.cpl,,3" - Ayarlar sekmesi görüntülenir.

Fonts
"shell32.dll,SHHelpShortcuts_RunDLL FontsFolder" - Yazıtipleri klasörünü görüntüler"shell32.dll,Control_RunDLL main.cpl @3" - Yazıtipleri klasörünü görüntüler
Sürücü Formatlama
"shell32.dll,SHFormatDrive" - Sürücü formatla penceresini görüntüler.
Game Controllers
"shell32.dll,Control_RunDLL joy.cpl,,0" - Joystick genel ayarları penceresini görüntüler"shell32.dll,Control_RunDLL joy.cpl,,1" - Joystick gelişmiş ayarları penceresini görüntüler
İnternet Seçenekleri
"shell32.dll,Control_RunDLL inetcpl.cpl" - İnternet seçenekleri Genel sekmesini görüntüler"shell32.dll,Control_RunDLL inetcpl.cpl,,0" - İnternet seçenekleri Genel sekmesini görüntüler"shell32.dll,Control_RunDLL inetcpl.cpl,,1" - İnternet seçenekleri Güvenlik sekmesini görüntüler
"shell32.dll,Control_RunDLL inetcpl.cpl,,2" - İnternet seçenekleri İçerik sekmesini görüntüler"shell32.dll,Control_RunDLL inetcpl.cpl,,3" - İnternet seçenekleri Bağlantı sekmesini görüntüler"shell32.dll,Control_RunDLL inetcpl.cpl,,4" - İnternet seçenekleri Programlar sekmesini görüntüler
"shell32.dll,Control_RunDLL inetcpl.cpl,,5" - İnternet seçenekleri Gelişmiş sekmesini görüntüler

Birlikte Aç
"shell32.dll,OpenAs_RunDLL drive:\path\filename" -
Birlikte aç iletişim kutusunu görüntüler. hangi dosya açılmak isteniyorsa dosyanın tam yolu belirtilir.

Ağ Bağdaştırıcılarım Penceresini Görüntüleme

Mevcut ağ bağdaştırıcılarının gösterildiği pencereyi açmak için kullanılır.
            try
            {
                System.Diagnostics.Process proc = new System.Diagnostics.Process();
                proc.StartInfo.FileName = "rundll32.exe";
                proc.StartInfo.Arguments = "shell32.dll,Control_RunDLL ncpa.cpl,,0";
                proc.Start();
            }
            catch
            {
            }

Çalışan Uygulamaların Listesi

Bu yazımızda hangi uygulamaların çalıştığını nasıl bulunacağını anlatmak istiyorum. Bunun için öncelikle uygulamamıza "System.Diagnostics" namespace ini ekliyoruz.
using System.Diagnostics;

Projemize iki tane combobox nesnesi ekliyoruz. Bunlardan birinin adını "cmbIslem", diğerinin adını "cmbUygulama" olarak değiştiriyoruz. Formumuzun "Load" olayına şu kodları yazıyoruz.

private void Form1_Load(object sender, EventArgs e)
{
cmbIslem.Items.Clear(); //ComboBox nesnesinin içeriği temizleniyor
cmbUygulama.Items.Clear();
Process[] procs = Process.GetProcesses(); // GetProcesses fonksiyonu ile çalışan uygulamaların listesi diziye aktarırılıyor.
for (int i = 0; i < procs.Length; i++)
{
if (procs[i].MainWindowTitle != "") // Eğer işlemin ana pencere başlığı varsa bunun ana uygulama olduğunu anlıyoruz.
{
cmbUygulama.Items.Add(procs[i].MainWindowTitle);
}
cmbIslem.Items.Add(procs[i].ProcessName);
}
}

OpenFileDialog-SaveFileDialog Kullanımı ve Özellikleri

OpenFileDialog ve SaveFileDialog nesneleri FileDialog nesnesinden türetilmiştir. İşlerimizi kolaylaştıracak güzel özellikleri vardır. Burada OpenFileDialog nesnesine göre anlatım yapılacak fakat aynı kurallar SaveFileDialog için de geçerlidir. Bu nesneler
OpenFileDialog dosyaac = new OpenFileDialog();
veya
SaveFileDialog dosyaac = new SaveFileDialog();
yapıcı metot kullanılarak oluşturulur. İçerdiği özellik ve fonksiyonlar şu şekildedir.
dosyaac.AddExtension = true;
   
        //Eğer dosyaadı yazılırken uzantı girilmemişse dosyaadının sonuna otomatik olarak uzantı eklenir.
dosyaac.AutoUpgradeEnabled = true;
  
         //Diyalog penceresi açıkken aktif klasör üzerinde meydana gelen değişiklikler anında güncelleştirilir.
dosyaac.CheckFileExists = true;           //Dosya adının elle girilmesi durumunda dosyanın var olup olmadığı kontrol edilir
dosyaac.CheckPathExists = true;
          
// Dosya adının dosya yolu ile birlikte girilmesi durumunda yolun gerçekten var olup olmadığı kontrol edilir.
dosyaac.DefaultExt = "txt";        
            // Varsayılan olarak kullanılacak dosya uzantısı belirlenir.

dosyaac.FileName = "yazilimgrubu";
  
          // Diyalog penceresi ilk açıldığında dosya adı kısmında otomatik olarak yazılacak dosya adı. veya dialog penceresi kapandığında kullanıcının seçtiği dosyaadı
dosyaac.FileNames;
            // Çoklu dosya seçimlerinde kullanılır. dosya isimleri string türünden bir diziye aktarılır.
Örneğin string[] dosyalar = dosyaac.FileNames;   gibi
dosyaac.Filter = "Metin Dosyaları|*.txt|Tüm Dosyalar|*.*";            // Dosya türüne göre filtreleme yapmak için kullanılır.
dosyaac.FilterIndex;
        
// Diyalog penceresinde dosya türü kısmında seçili olan türün indeksi. int türünden bir değişkene aktarılır. Örneğin int index = dosyaac.FilterIndex; gibi
dosyaac.InitialDirectory = "c:\\";         //Diyalog penceresi ilk açıldığın gösterilecek klasörün yolu belirtilir.
dosyaac.Multiselect = true;           //Çoklu dosya seçilmesine izin verir.
Stream oku = dosyaac.OpenFile(); 
         //Seçilen dosyayı read-only olarak açar. 

dosyaac.ReadOnlyChecked = true;            //Diyalog penceresinde salt okunur olarak aç seçeneğinin seçili olup olmadığını denetler.
dosyaac.Reset();            // Yapılan tüm değişiklikleri varsayılan haline getirir.
dosyaac.RestoreDirectory = true;               //Diyalog penceresinin uygulama kapanmadan farklı zamanlarda tekrar açılması durumunda aktif klasörün varsayılan klasör mü yoksa en son kullanılan klasör mü olacağını belirler
string dosya = dosyaac.SafeFileName;
     
         //Kullanıcının seçtiği dosyanın ismini sadece dosya adı ve uzantısı olacak şekilde verir. klasör isminide almak istiyorsanız FileName özelliğini kullanmalısınız.
string[] dosyalar = dosyaac.SafeFileNames;
              // SafeFileName özelliği ile aynı işi yapar sadece bu özellik çoklu dosya seçimlerinde
kullanılır.
dosyaac.ShowDialog();             // Diyalog penceresinin ekranda görüntülenmesini sağlar.
dosyaac.ShowHelp = true;
            // Yardım butonunu görüntüler
dosyaac.ShowReadOnly = true;
           // Salt okunur aç seçeneğinin görüntülenmesini sağlar.
dosyaac.SupportMultiDottedExtensions = true;          // Birden fazla uzantısı olan dosyaların izin verir.
dosyaac.Title = "Yazılım Grubu";            // Pencere başlığını düzenler.
dosyaac.ValidateNames = true;
            // Diyalog penceresinin geçerli Win32 sistemlerde kullanılan dosya adlarına izin vermesini sağlar.

   Kullanım şekli ise şöyle. Yukarda da bahsettiğim gibi diyalog penceresinin ekranda görüntülenmesi için ShowDialog() fonksiyonunu kullanmanız gereklidir. Şimdi bu fonksiyonu kullandık ama kullanıcı "Aç" veya "Kaydet" butonuna mı yoksa "İptal" butonuna mı bastı bunu kontrol etmemiz gerekli. Bunun 4 farklı yolu ben burada hepsini anlatacağım.
1. Yol
ShowDialog() fonksiyonu DialogResult türünden bir değer döndürür. Bu değere bakarak kullanıcının hangi tuşa bastığını anlayabiliriz.           
            DialogResult dr = dosyaac.ShowDialog();
            if (dr == DialogResult.OK)
            {
                MessageBox.Show(dosyaac.SafeFileName);
            }
            else if (dr == DialogResult.Cancel)
            {
                MessageBox.Show("Kullanıcı Kapattı");
            }

2. Yol
Bu yöntem yine if kullanacağız fakat DialogResult türünden bir değişken oluşturmayacağız.
            if (dosyaac.ShowDialog() == DialogResult.OK)
            {
                MessageBox.Show(dosyaac.SafeFileName);
            }
            else
            {
                MessageBox.Show("Kullanıcı Kapattı");
            }

3. Yol
Bu yöntemde de yine DialogResult sorgulaması yapıyoruz. Fakat bu sefer swtich-case yapısını kullanarak           
            DialogResult dr = dosyaac.ShowDialog();
            switch (dr)
            {
                case System.Windows.Forms.DialogResult.OK:
                    MessageBox.Show(dosyaac.SafeFileName);
                    break;
                case System.Windows.Forms.DialogResult.Cancel:
                    MessageBox.Show("Kullanıcı Kapattı");
                    break;
            }

4. Yol
Bu yöntem daha teknik bir yöntemdir ve aynı zamanda kodlarımızın daha düzenli olmasını sağlar. Bunun için OpenFileDialog nesnesinin FileOk event'ını kullanıyoruz. önce event tanımlamamızı yapalım ve ShowDialog fonksiyonunu kullanarak diyalog penceremizi görüntüleyelim. Artık kullanıcı "Aç" veya "Kaydet" butonuna bastığında event içinde tanımlanan dosyaac_FileOk adlı fonksiyondaki komutlar çalışacaktır. Şimdide fonksiyonumuzu oluşturalım.       
        dosyaac.FileOk += new System.ComponentModel.CancelEventHandler(dosyaac_FileOk);
        dosyaac.ShowDialog();


        void dosyaac_FileOk(object sender, System.ComponentModel.CancelEventArgs e)
        {
            MessageBox.Show(dosyaac.FileName);
        }

Gördüğünüz gibi birçok kullanım şekli var hepsi de aynı işi yapıyor hangisini seçeceğiniz size bağlı. Benim tavsiyem işlemleriniz uzun olacaksa 4.yolu kısa olacaksa 2.yolu tercih etmenizdir mümkün olduğu kadar switch-case yapısını kullanmamaya çalışın çünkü diğer yöntemler daha hızlı çalışıyor.










C# Ses Dosyası Çalma

 Bugünkü makalemizde C# dilini kullanarak uygulalarımızda ses dosyalarını nasıl çalabileceğimizi anlatacağız. .NET Framework kütüphanesi içinde uygulamalarınız içerisinde ses dosyalarını kullanabileceğiniz sınıflar mevcuttur. Bu sınıflar "System.Media" namespace i içersinde yer almaktadır. System.Media namespace'i üç sınıftan meydana gelir. Bunlar "SoundPlayer, SystemSound ve SystemSounds" sınıflarıdır.
 SoundPlayer : *.wav dosyalarını çalmak için kullanılır.
 SystemSound : Windows işletim sistemine ait temel ses dosyalarını temsil eder  ve çalıştırır.
 SystemSounds : SystemSound sınıfı için referans niteliğinde olup sistem olayları için atanan ses dosyalarını temsil eder ve çalıştırır.
 System.Media namespace ve sınıfları kullanılarak sadece *.wav dosyaları çalıştırılabilir. Diğer dosya türlerini çalıştırabilmek için uygulamaya Windows Media Player Control'un eklenmesi gereklidir. Bu makalede *.wav dosyalarının nasıl çalıştırabileceğini anlatacağım diğer dosya türleri için ayrıca anlatacağım.
 Uygulamalarınızda ses dosyalarını 2 şekilde kullabilirsiniz.
1.Yol :  Ses dosyasının yolunu program içerisinde kullanarak
2.Yol :  Resource dosyalarından faydalanarak.
 1.Yol uygulamaların boyutu ve esnekliği açısından daha verimli olabilir ama dosya adresi değiştiğinde doğal olarak çalışmayacaktır. Bununla birlikte 2.Yol ses dosyaları uygulama içine entegre edildiğinden dosyanın belirtilen yolda olmaması gibi bir durum söz konusu değildir fakat uygulama dosyasının boyutunu büyütür. Bununla birlikte eğer kullanıcılarınıza birtakım işlemler için ses dosyası seçmesini istiyorsanız fakat bu seçilen dosyaya erişilemiyorsa varsayılan olarak başka bir ses dosyasının çalışmasını istiyorsanız 2.Yolu kullanabilirsiniz.
 Dilerseniz basit bir uygulama hazırlayalım. bu uygulamada kullanıcıdan bir ses dosyası seçmesini istiyoruz. Eğer belirtilen dosya mevcutsa ve erişilebiliyorsa (Klasör izinleri buna engel olabilir.) kullanıcının seçtiği dosya aksi taktirde bizim belirlediğimiz bir ses dosyası çalsın. Öncelikle uygulamada kullanacağımız bileşenleri formumuza ekleylim. Bunun için forma
      Bileşen                                   Adı 
 1 TextBox               ==>    txtDosya
 3 Button                  ==>    btnOynat, btnDurdur, btnGozat
 1 OpenFileDialog   ==>    dlgDosyaAc
 1 Label                    ==>    lblBaslik

ekleyin ve isimleri gördüğünüz gibi değiştirin. Şimdi bu bileşenlerin ayarlarını yapalım. Bunu bir fonksiyon olarak yazalım. Dilerseniz bunları tasarım ekranında da yapabilirsiniz yaptığım ayarları daha iyi görebilmeniz açısından bu yolu seçtim. BileşenAyarlar() adıyla bir fonksiyon oluşturuyorum ve içerisine şu kodları ekliyorum.
        private void BilesenAyarlar()
        {
            //Form Ayarları
            this.CancelButton = btnDurdur;
            this.Size = new System.Drawing.Size(370, 110);
            this.Text = "Wav Dosyaları";
            //lblBaslik bileşen ayarları
            lblBaslik.Text = "Çalınacak wav dosyasının yolu :";
            lblBaslik.Location = new System.Drawing.Point(9, 9);
            //txtDosya bileşen ayarları
            txtDosya.Text = "";
            txtDosya.Location = new System.Drawing.Point(12, 26);
            txtDosya.Size = new System.Drawing.Size(285,20);
            //btnGozat bileşen ayarları
            btnGozat.Text = "Gözat";
            btnGozat.Location = new System.Drawing.Point(298, 24);
            btnGozat.Size = new System.Drawing.Size(59, 23);
            //btnOynat bileşen ayarları
            btnOynat.Text = "Oynat";
            btnOynat.Enabled = false;
            btnOynat.Location = new System.Drawing.Point(179, 52);
            btnOynat.Size = new System.Drawing.Size(59, 23);
            //btnDurdur bileşen ayarları
            btnDurdur.Text = "Durdur";
            btnDurdur.Location = new System.Drawing.Point(238, 52);
            btnDurdur.Size = new System.Drawing.Size(59, 23);
            //dlgDosyaAc bileşen ayarları
            dlgDosyaAc.CheckFileExists = false;
            dlgDosyaAc.CheckPathExists = false;
            dlgDosyaAc.FileName = "";
            dlgDosyaAc.Filter = "Ses Dosyaları(*.wav)|*.wav|Tüm Dosyalar|*.*";
            dlgDosyaAc.Title = "Dosya Aç";
        }

 daha sonra bu fonksiyonu uygulamanın yapıcı fonksiyonunun içinde InitializeComponent() satırından hemen sonra yazıyoruz. Yapıcı fonkiyon şu halde olmalı.
        public Form1()
        {
            InitializeComponent();
            BilesenAyarlar();
        }

Uygulamayı derleyip çalıştırdığınızda görünüm şu şekilde olacaktır.

 Görünüm olarak sorun olmadığına göre uygulamayı kapatıp Visual Studio IDE ekranına dönebiliriz.

  Burada Solution Explorer projemize üzerinde farenin sağ tuşuna basıp Properties menüsünü seçiyoruz. Açılan pencerede "Resources" tabına geçiyoruz üst kısımdaki menülerde en soldaki menünün sağındaki ok işaretine basıp "Audio" seçeneğini seçiyoruz ve "AddResource" butonuna basarak uygulamada kullanılacak bir wav dosyası seçiyoruz. Ben burda "Windows\Media" klasöründen "Windows_Critical_Stop.wav" dosyasını seçiyorum. Bu dosya kullanıcının belirttiği yolda ses dosyası bulunmazsa oynatılacak. Dosyamızı seçtikten sonra kaydedip bu pencereyi kapatabiliriz.
 Şimdi uygulamamızın çalışması esnasında kullanılacak nesnelerimizi tanımlıyoruz. İhtiyacımız olanlar kullanıcının seçeceği dosyanın yolunu tutacak string bir değişken, Belirtilen yolun geçerliliğini kontrol edecek FileInfo türünden bir değişken (Dosya işlemleri için ayrıca bir makale hazırlayacağım), ses dosyalarını çalacak SoundPlayer türünden bir değişken. Değişkenlerimizi class seviyesinde tanımlıyoruz.
        SoundPlayer ses = new SoundPlayer();
        string dosyayolu="";
        FileInfo dosya
;
 Kullanıcının "Gözat" butonuna bastığında Dosya Aç diyalog penceresinin görünmesini sağlıyoruz. btnGozat nesnesinin "Click" olayını şu şekilde düzenliyoruz. OpenFileDialog nesnesi ile ilgili makale daha önce
http://olcayguzel.blogspot.com/2011/05/openfiledialog-savefiledialog-kullanm.html adresinde yayınlanmıştı.
         private void btnGozat_Click(object sender, EventArgs e)
         {
            if (dlgDosyaAc.ShowDialog() == DialogResult.OK)
            {
                txtDosya.Text = dlgDosyaAc.FileName;
            }
         }
 
 BileşenAyarlar() fonksiyonunu incelediğinizde btnOynat nesnesinin Enabled özelliğini false olarak ayarlamıştık. Şimdi kullanıcı bir dosya seçtiğine daha doğrusu txtDosya nesnesinin içeriği artık boş olmadığına göre bu butonu aktifleştirebiliriz. Bu işlemi yapmak için txtDosya nesnesinin "TextChanged" olayını şu şekilde düzenliyoruz.
        private void txtDosya_TextChanged(object sender, EventArgs e)
        {
            btnOynat.Enabled = txtDosya.Text.Trim().Length > 0 ? true : false;
        }

  Trim() fonksiyonunu kullanmamızın sebebi txtDosya nesnesinin içeriğinde geçerli bir karakter olmasını sağlamaktır. Burada txtDosya nesnesinin Text özelliğindeki değer yani textbox nesnesinin üzerindeki metnin baş ve son kısmındaki boşluk karakterleri atılıyor ve karakter sayısının sıfırdan büyük olup olmadığı kontrol ediliyor. Eğer sıfırdan büyükse btnOynat nesnesinin Enabled özelliğine true değilse false değeri atanıyor. Artık kullanıcı bize çalınacak bir dosya adı verdiğine göre ses dosyasını çalma işine dönebiliriz. Kullanıcı seçtiği dosyayı oynatmak için "Oynat" butonuna bastığında çalma işlemi için hazırlıklar başlayacak. Öncelikle belirtilen dosyanın gerçekten var olup olmadığını kontrol etmeliyiz. Bunun için FileInfo sınıfının Exists() fonksiyonundan faydalanıyoruz. btnOynat bileşeninin "Click" olayını şu şekilde düzenliyoruz.
         private void btnOynat_Click(object sender, EventArgs e)
        {
            dosyayolu = txtDosya.Text;
            dosya = new FileInfo(dosyayolu);
            if (dosya.Exists)
            {
                ses = new SoundPlayer();
                ses.SoundLocation = dosya.FullName;
                ses.PlayLooping();
            }
            else
            {
                ses = new SoundPlayer();
                ses.Stream = Properties.Resources.Windows_Critical_Stop;
                ses.Play();
            }
        }

 Burada kısım kısım açıklayalım
 1- txtDosya bileşeninin değerini dosyayolu değişkenine aktardık
 2- dosyayolu değişkenini kullanarak belirtilen adres ve isimdeki dosyayla işlem yapabilmek için dosya nesnesini oluşturduk.
 3- if komutu ve FileInfo sınıfının Exists() fonksiyonunu kullanarak belirtilen dosyanın gerçekten varolup olmadığını kontrol ettik.
 Eğer dosya gerçekten varsa if komutundan sonraki satırlar çalışacak aksi halde else kısmı çalışacak yani bizim varsayılan olarak çalmayı planladığımız dosya çalışacak. Peki ya kullanıcının belirttiği dosya gerçekten var ama ses dosyası değilse örneğin bir *.pdf dosyası seçmişse bunu nasıl kontrol edeceğiz. Bunu yapmak için if komutumuzu biraz değiştirmemiz yeterli olacaktır yeni koşulumuz şu şekilde.
 if (dosya.Exists && dosya.Extension==".wav") Uygulamamızı çalıştırdığınızda seçilen dosya eğer *.wav dosyası ise sürekli çaldığını göreceksiniz. Eğer dosyanın bir kere çaldıktan sonra durmasını tekrar Oynat butonuna basana kadar çalmasını istemiyorsanız "ses.PlayLooping();" satırlarını "ses.Play()" şeklinde değiştirmeniz yeterli olacaktır. Burada "Durdur" butonunun çalışmasını göstermek amacıyla "PlayLooping()" fonksiyonunu kullandım.
 Şimdi sıra geldi "btnDurdur" butonuna basıldığında çalan ses dosyasının durdurmaya. Bunun için btnDurdur bileşeninin "Click" olayını şu şekilde düzenliyoruz.
        private void btnDurdur_Click(object sender, EventArgs e)
        {
            ses.Stop();
        }

Uygulamamızı derleyip çalıştırıyoruz ve gördüğünüz gibi sorunsuz bir şekilde çalışıyor.