Posted under C# (csharp)
Bu yazıda COM nesnelerinin dotNET ortamında nasıl kullanabileceğimizi göreceğiz, bunun için VB6 ile yazılmış basit bir COM nesnesini C# kullanarak .NET ortamına taşıyacağız. Bu taşıma işlemi sırasında yapılması gerekenler adım adım incelenecektir. Ayrıca bu yazıda COM teknolojisine dayanan ActiveX bileşenlerini .NET ortamında ne şekilde kullanabileceğimizi de ele alacağız.
COM nedir?
.NET ve COM ilişkisine geçmeden önce COM ve diğer standartlar hakkında bilgi vermekte fayda var. COM, bir komponent geliştirme standartıdır. Öyleki COM standartlarına uygun geliştirilen bütün komponentler COM nesnelerinin kullanılabildiği bütün diller tarafından kullanılabilir. Zatan COM teknolojisinin geliştiricilere sağladığı en büyük fayda dilden bağımsız olmasıdır. Günümüzde COM nesneleri geliştirebileceğimiz bir çok geliştirme ortamı vardır. ATL ve VB bu ortamlara örnek olarak verilebilir. COM teknolojisinin getirdiği yeniliklere rağmen COM geliştirmenin ve COM nesnelerinin dağıtımı zor olduğu için çeşitli sorunlar ortaya çıkmıştır. Bu sorunlardan en önemlisi meşhur “DLL-HELL” dediğimiz problemdir. Bu problem genellikle aynı uygulamanın farklı versiyonlarına ait COM komponentlerinin sisteme kayıt edilmesi ile meydana gelmektedir. .NET’in altyapısında bulunan assmebly versiyonlama sayesinde bu problem tamamen ortadan kalkmıştır.
COM komponentleri ile ilgili diğer önemli bir sorun da, COM komponentlerini kullanmadan önce Registery bölgesine kayıt edilmek zorunda olmasıdır. Register’a kaydedilen COM nesnelerine atanan bir anahtar(GUID) ile çalışma zamanında COM nesnesi ayrıştırılır. .NET komponentlerini kullanmadan önce herhangi bir kayıt işlemi yapmaya gerek yoktur.
Herşeye rağmen .NET eski komponentleri kullanmak için çeşitli mekanizmalar sunmaktadır. Bu yazının amacıda zaten bu mekanizmayı göstermektir.
RCW (Runtime Callable Wraper)
.NET ve COM mimarisi biribirinden tamamen farklıdır. Bu da .NET ortamından COM nesnelerine direkt erişmeyeceğimz anlamına gelir. .NET ortamında COM nesnelerine erişebilmek için, bu nesnelere yönelik RCW komponentlerini oluşturmamız gerekir. RCW, .NET ile COM arasında bir arayüz gibidir. Oluşturulan RCW komponentine normal .NET komponenti gibi erşimek mümkündür. Biz aslında .NET ile RCW komponentine erişmiş oluyoruz. COM ile olan bağlantıyı ise RCW sağlar. Bunu .NET’in bize sunduğu bir hizmet olarak düşünebiliriz.
RCW, yönetilen kod(managed code) ile yönetilmeyen kod(unmanaged) arasında bağlantıyı sağlar diyebiliriz. Burada yönetilen kod .NET kodları yönetilmeyen kodlar ise COM komponentinin kodlarıdır. Bu ilişkiyi kafanızda daha iyi canlandırmak için aşağıdaki şekli inceleyin.

Daha fazla kavram kargaşısına girmeden bu yazıda üzerinde duracağımız mekanizmayı özetleyelim: Birazdan anlatacağım yöntemlerle oluşturacağımız assembly lere referans vererek .NET ortamından bir COM nesnesine RCW üzerinden nasıl erişebileceğimizi göreceğiz.
COM komponentlerini saran(wrap) ve .NET ortamından kendisine referans verebileceğimiz assembly’leri hazırlamak için iki seçeneğimiz var. Bunlardan birincisi komut satırından kullanılan TlbIMP.exe(Type Library Importer) aracı diğeri ise Visual Studio.NET geliştirme aracıdır.
Şimdi adım adım bir COM komponentinin .NET ortamında nasıl kullanıldığını görelim. Bu işlemleri görebilmek için elbette bir COM kompnentine ihtiyacımız olacak. Bu yazıda sisteminizde var olan COM komponentleri kullanabileceğiniz gibi VB 6.0 yada ATL kullanarak yeni bir COM komponenti de oluşturabilirsiniz. Ben herşeyin daha anlaşılır olabilmesi için VB 6.0 ile basit bir ActiveX Component projesi açıp iki metodu olan bir komponent yazdım. Çünkü VB 6.0 ile COM uygulamaları geliştirmek oldukça kolaydır. Siz benim yaptığım komponentin aynısını isterseniz C++ kullanarak ATL ile de oluşturabilirsiniz. Yada daha önceden sisteminizde kayıtlı olan COM komponentini kullanabilirsiniz. Sisteminizde kayıtlı olan COM komponentlerini görmek için Visual Studio.NET’i kullanabilirsiniz. Zira Project menüsünden Add Reference menüsünü seçtikten sonra çıkan pencereden COM sekmesini seçtiğinizde sisteminizde kayıtlı olan COM nesneleri hakkında bilgi edinebilirsiniz.
VB 6.0’da yeni bir proje açtıktan sonra, projeye DortIslem isimli bir “Class Module” ekleyin. DortIslem isimli Class Module’üne aşağıdaki kodları yazıp projeyi derleyin.
| Public Function Topla(ByVal Sayi1 As Long, ByVal Sayi2 As Long) As Long
Topla = Sayi1 + Sayi2 End Function
Carp = Sayi1 * Sayi2 End Function |
Oluşturduğunuz bu projeyi File menüsünden Make VbCOM.dll ’i seçerek COM komponentinin oluşmasını sağlayın. (VbCOM oluşturduğum projenin adıdır.)
Diğer COM istemcilerinin erişimini sağlayabilmemeiz için register’a kayıt etmemiz gerekir. Bunun için komut satırına
regsvr32 VbCOM.dll
yazın. Eğer “DllRegisterServer in VbCOM.dll succeeded” mesajı verildiyese kayıt işlemi başarıyla bitmiş demektir.
Visual Studio.NET ile COM bileşenlerine erişmek
Oluşturulan bu COM tabanlı dll dosyasını .NET projelerinde direkt kullanamayız. Bunun için bu COM nesnesini sarmalayan(wrapper) sınıfı oluşturmamız gerekir. Daha öncede dediğimiz gibi bunun iki yöntemi vardır. İlk yöntem oldukça basittir. Yeni bir Visual Studio.NET projeis açın. Project menüsünden Add Reference’ı seçip COM sekmesine geldiğinizde sisteminize kayıt edilmiş COM bileşenlerini görürsünüz. Aşağıdaki ekran görüntüsünden de görüldüğü üzere bizim oluşturduğumuz VbCOM.dll bileşeni de eklenmiştir.

Project1 isimli COM bileşenine referans verdikten sonra artık projemizde Project1 isim alanı(namesapce) ile bu bileşenin sınıflarını rahatlıkla kullanabiliriz. Project1 VB 6.0 ile oluşturduğum projenin adıdır. Varsayılan olarak bu isim alanı ile oluşturulmuştur. Bu ismi istediğiniz gibi değiştirebilirsiniz. COM bileşenini sarmalayan(wrapper) sınıfı Visual Studio.NET bizim için otomatik oluşturduğu için bu COM bileşeni artık bizim için .NET bileşeninden farklı değildir. Şimdi isterseniz Project1 isim alanında bulunan yapılara bakalım.

Yukarıdaki yapıda biraz tuhaflık olduğunu düşünebilirsiniz. Çünkü DortIslem isimli sınıf yerine DortIslemClass isimli bir sınıf var. Bu her zaman bu şekilde oluşur. DortIslem ise COM nesnesindeki arayüzü belirtmektedir. Bu arayüz orjinal COM bileşenindeki GUID’i taşır. DortIslemClass, bu arayüzü uygulayan bir sınıftır. Bu yüzden nesneleri DortIslemClass sınıfını kullanarak oıluşturacağız. Aşağıdaki gibi “islem” isimli bir nesne oluşturup DortIslemClass sınıfının üye elemanlarına bakalım.
| Project1.DortIslemClass islem = new Project1.DortIslemClass(); |
Not: Project1 isim alanını using deyimi ile programın başına eklerseniz nesne oluştururken isim alanını kullanmanıza gerek yoktur.
“islem” nesnesi üzerinden DortIslemClass sınıfının üye alamanlarına bakacak olursak:

Yukarıdaki ekran görüntüsünden de gördüğünüz gibi COM bileşenindeki metotların yanısıra .NET’teki Object sınıfının metotları olan Equlas(), ToString() gibi metotlarda eklenmiştir. Bunları COM nesnesinde olmayan ancak RCW tarafından .NET ortamı için eklenen metotlardır. Bu ekran görüntüsünde önemli olan diğer bir konu ise Topla() ve Carp() metotlarının parametrik yapısdır. Hatırlarsanız VB 6.0 ile oluşturduğumuz bu metotların parametreleri ve geri dönüş değerleri long türündendi. Halbuki sarmalayıcı(wrapper) sınıf içinde bunlar int türüne dönüştürülmüştür. Bu da COM türlerinin, .NET’ e uygun türlere dönüştürüldüğü anlamına gelmektedir. Diğer türlerin ne şekilde dönüştürüldüğünü görmek için VB 6.0 da oluşturduğunuz COM bileşeninde değişiklikler yapın.
DortIslemClass sınıfı aşağıdaki program ile test edebilirsiniz. Herhangi bir hata almadıysanız COM bileşenini .NET ortamında kullanmış oldunuz demektir.
| using System; using Project1; class Class1 Console.WriteLine(islem.Topla(5,6)); |
TlbImp.exe ile COM bileşenlerine erişmek
Herkesin Visual Studio.NET geliştirme aracına sahip olma şansı olmayabilir. Bu yüzden Microsoft komut satırından çalışan çeşitli kullanışlı araçlar sunmuştur. Bu araçlarıdan biri de TlbImp.exe(Type Library Importer) aracıdır. Bu program ile COM bileşenleri içinde bulunan sınıflar .NET ortamından referans verilebilecek hale getirilir. Yani COM bileşenini sarmalayan(wrap) RCW bileşeni oluşturulur. Aşağıdaki erandan TlbImp.exe programının ne şekilde kullanıldığı görülmektedir.
TlbImp programı 3 argüman ile kullanılmıştır. /namesapce:CsNedir argümanı ile oluşturulacak assembly’ye ilişkin isim alanını belirtir. Bu kullanımda varsayılan isim alanı yerine CsNedir seçilmiştir. Eğer bu argüman kullanılmasaydı assembly’nin varsayılan isim alanı olan Project1 olacaktı. /out:VbCOM_RCW argümanı ile COM bileşenini sarmalayan assembly’nin hangi isimle kaydedileceği belirtilmektedir. /verbose argümanı ise yapılan işlemler hakkında detaylı bilgi almak amacıyla kullanılır. Bu argümanı kullanmanız gerekmez. Son olarak COM tabanlı dll dosyasının ismi yazılmıştır. Bu dosyanın ismide VbCOM.dll ’dir. TlbImp aracı ile kullanılabilecek diğer argümanların listesini görmek için komut satırına
tlbimp /?
yazın.
TlbImp ile oluşturulan VbCOM_RCW.dll assembly’sine ILDASM aracı ile baktığınızda aşağıdaki ekran görüntüsünü elde etmelisiniz.

Yukarıdaki görüntüden de anlaşıldığı gibi Visual Studio.NET’in otomatik oluşturduğu sarmalayıcı sınıflar ve arayüzler, TlbImp aracının oluşturdukları ile aynıdır.
Şimdi sıra geldi oluşturduğumuz VbCOM_RCW.dll assembly’sini test etmeye. Öncelikle aşağıdaki programı yazın.
| //Test.cs
using System;using CsNedir; class Class1 Console.WriteLine(islem.Topla(5,6)); |
Komut satırından bu programı aşağıdaki gibi derleyin.
csc /r:VbCOM_RCW.dll Test.cs
Eğer herhangi bir hata yapmadıysanız COM bileşeni kullanan .NET programınız hazır. Programı çalıştırdığınızda ekrana
11
30
yazması gerektiğini tahmin etmiş olmalısınız.
Not: TlbImp ile oluşturduğumuz DortIslemClass sınıf yönetilen kod kapsamına girdiği için kontrolü CLR tarafından sağlanmaktadır. Yani gereksiz nesne toplayıcısı(garbage collection) ile “islem” nesnesi bellekten kaldırılır.
.NET’te ActiveX Bileşenlerini Kullanmak
ActiveX kontrolleri genellikle grafik arayüzü içeren COM tabanlı bileşenlerdir. Grafik arayüzü olmayan ActiveX kontrollerinin olabileceğinide unutmayın. ActiveX kontrolleri .ocx uzantılı dosyalardır. ActiveX kontrollerinin .NET’te kullanılması yukarıda anlattığım diğer COM bileşenlerinin kullanılması ile aynıdır. Değişen tek şey kullanacağımız aracıın farklı olması ve oluşturulan .NET sınıflarının grafik arayüzü içermesidir.
COM tabanlı ActiveX bilşenlerine .NET projelerinden referans verilebilecek hale getrimek için AxImp.exe(ActiveX Importer) aracı kullanılmaktadır. Bu yazıda örnek olarak COM tabanlı olan Windows Media Player’ı bir form üzerinde göstermek için gereken adımları göstereceğim. Bu yüzden Windows Media Player’ı temsil eden msdxm.ocx dosyasını kullanacağım.
Not: msdxm.ock dosyası X:/WINNT/System32 dizini altında bulunmaktadır.
AxImp aracını komut satırından aşağıdaki gibi çalıştırın.

AxImp aracı iki tane assembly oluşturmuştur. MediaPlayer.dll assembly’si grafik arayüzü içermeyn ama .NET paltformundan referans verebileceğimiz bir assembly’dir. AxMediaPlayer.dll ise Form tabanlı(Windows Form, ASP.NET Form) projelerde kullanabileceğimiz grafik arayüzü içeren kontrolleri temsil eder. Bu assembly’ye .NET projelerinden referans verdiğimizde MediaPlayer nesnesine bir kontrol gibi erişebiliriz.
Bir Windows Form uygulaması yaparak AxMediaPlayer assembly’sindeki kontrolü test edelim. Test işlemi için bir video(mpeg) dosyasına ihtiyacımız olacak. Kendinize herhangi bir video dosyası belirledikten sonra aşağıdaki programı bir metin editöründe yazın.
| //MPFrom.cs
using System;using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; public class Form1 : Form public Form1() axMediaPlayer1.Location = new Point(8,8); Controls.AddRange(new Control[] Name = “Form1″; [STAThread] private void Form_Load(object sender, EventArgs e) |
Kodu yazdıktan sonra komut satırından aşağıdaki gibi derleyin.
csc /t:winexe /r:D:/WINNT/System32/AxMediaPlayer.dll MPForm.cs
Not: /r: argümanı ile msdxm.ocx dosyasından AxImp ile oluşturduğunuz assembly’ye referans veriyoruz.
Programı çalıştırdığımızda aşağıdaki gibi bir ekran görüntüsü ile karşılaştığımızı görürüz.

Visual Studio.NET ortamından ActiveX kontrollerini kullanmak ise oldukça kolaydır. ToolBox penceresine sağ tıklayıp “Customize Toolbox” menüsünü seçtikten sonra karşınıza çıkacak pencereden “COM Components” sekmesini seçip istediğiniz ActiveX kontrolüne referans verebilirsiniz. İlgili ActiveX kontrolünü seçip OK düğmesine bastıktan sonra ToolBox penceresine ActiveX bileşenini temsil eden yeni bir kontrol eklendiğini görürsünüz.
Sonuç: .NET sunduğu yeni mimarisinin yanısıra eski teknolojileride kullanma imkanı vermesi .NET platformuna geçmek için yeterli bir sebeptir.
Bu konu ile ilgili bir sonraki yazıda .NET bileşenlerinin COM istemcileri tarafından nasıl kullanılabileceğini ele alacağım.