Win32 & .Net(Delphi->C#)

Aslında herşey Java adı verilen programlama dilinin doğuşuna kadar ilerliyor. Java, programlama dünyasına farklı bir perspektif katmıştı. Yazılan kodların applet’ler vasıtası ile web ortamlarında kullanılabilmesi yada Java Runtime ile değişik işletim sistemi platformlarında çalıştırılabiliyor olması onu günden güne daha popüler hâle getiriyordu.

Microsoft, kendi işletim sistemlerinin yeryüzündeki tüm bilgisayarlarda kullanılamayacağının farkına vardığında; Java’ya karşı bir önlem almak gerektiğini düşündü ve bu sayede veriye her ortamdan erişebilecek bir sistem planlamaya başladı. Ancak elbette Java’nın da hâla beceremediği gibi Microsoft’da platform bağımsızlığı hususunda başarılı olamadı. Zaten tasarımların gereği de bunu pek mümkün kılmıyordu. Java’da üretilen kodların bytecode’lara çevrilmesi ve JVM(Java Virtual Machine) adı verilen programlarla üzerinde çalıştığı platforma adapte edilmesindeki süreç, .Net’de de kendisine farklı isimlerle yer buldu.

.Net, ürettiği MSIL kodunu üzerinde çalıştığı platformun anlayacağı makina dili koduna ise JIT vasıtası ile çevirir. Bu tıpkı Java’nın JVM’ine benzer. Aradaki benzerlikleri saymaya kalksak emin olun sayfalarca yazı yazmamız gerekir. Benim bu makalede amacım bu iki platform bağımsız olduğunu iddia eden teknolojinin benzerliklerini ve farklılıklarını anlatmak değil. Bu bilgileri genel kültür amacı ile sunduktan sonra Delphi’nin bu teknolojiler ile iletişimi hakkında bilgi vermek ve gerçek platform bağımsız kodlamanın gelecekte Delphi ile olabileceğinin umudunu sizlerle paylaşmak.

Görüldüğü üzere gerek .Net gerekse de Java platform bağımsız native kod geliştiremiyorlar. Ürettikleri ara kodların, çeşitli işletim sistemlerinde yorumlanıp makina koduna çevrilmeleri gerekiyor. Dolayısı ile teoride bu teknolojileri kullanan uygulamaların, native uygulamalardan hızlı olması beklenmiyor.

.Net, bilindiği üzere programlama dillerinden bağımsız bir platform. Framework adı verilen kod kütüphanelerinin tüm programlama dilleri tarafından ortak bir şekilde kullanılabilmesi, CTS denilen ortak tip sınıflarının .Net içinde olması, herhangi bir .Net destekli dilin bir diğer .Net destekli dil ile iletişimini son derece sorunsuz ve kolay hale getirmekte. Büyük çaplı proje ekiplerinin pek çok programcıya sahip olduğu gerçeği göz önüne alındığında, bu ekip üyelerinin herhangi bir .Net dilini bilmesi ve bu dil ile geliştirme yapmasının projeye olumsuz bir etkisinin olmaması elbette son derece güzel bir durum.

.Net Framework adı verilen kaba tabiri ile programlama kütüphanesi, şu aşamada 3.5 versiyonunda bulunuyor. Yakın bir zamanda 4.0 versiyonunun çıkması bekleniyor. Bildiğim kadarı ile Framework’teki sınıf tasarımları .Net framework 2.0′dan sonra herhangi bir değişikliğe uğramadı. Sadece üzerine yeni yetenekler eklendi. Kısaca .Net terminolojisinden bahsettikten sonra, Delphi’nin bu terminolojiye hangi mesafede olduğu hakkında yazmak isterim.

Delphi 7 , hâla pek çok Delphi kullanıcısının kullandığı ana IDE durumunda. Bunun stabilite ve hız gibi pek çok etkenleri var. Delphi, gerçek anlamda .Net ile 8 versiyonunda buluştu. Ancak Delphi 8, Microsoft’un .Net teknolojisine ilk desteği veren ürün olduğu için hiçte stabil değildi ve Delphi severler tarafından pek de tutulmadı. Ardından Borland, .Net platformuna desteğini Delphi 2005 ile sürdürdü. Ancak kişisel tecrübelerim ile söyleyebilirim ki, o da gerektiği ölçüde stabil değildi ve pek çok sorunu vardı. .Net desteği, 2006 ve 2007 sürümlerine kadar devam etti ve ardından büyük bir değişim ile karşılaştık.

Borland, programlama ürünlerini CodeGear isimli firmaya devretmiş ve ardından bu ürünleri Embarcadero isimli bir firma satın almıştı. Bu süreçte, artık Delphi ve diğer programlama ortamlarının .Net’e destek vermemesine karar verildi. Bu son derece yerinde bir karardı. Delphi, hayata ilk geldiği 1995 yılından bu zamana kadar native uygulama geliştirme konusunda, dünyada pek çok kez ödül almış bir ortam iken, .Net framework desteği adına adeta kendi kendine intihar etme kararı almıştı.

Günümüzde, .Net programlama adına Delphi yazım tarzına aşina olan programcıların Delphi Prism ürününü tercih etmesi isteniyor. Bu ürün; .Net framework ortamına %100 destek veren ve Delphi yazım tarzına son derece benzeyen Embarcadero firması programlama ortamları ailesinin bir başka ürünü.

Embarcadero, Delphi ürününü satın aldıktan sonra, beklentilerimizin aksine bu ürün ailesine son derece önem verdi ve ürünün eskide olduğu gibi popülerliğini yeniden kazanmasında büyük katkı sağlamaya başladı. Bu konuda sevgili arkadaşımız Sadettin POLAT’ın sitesindeki makaleyi okumanızı öneriyorum.

Konumuzun Win32 ve .Net olması münasebeti ile, kısa bir zaman sonra çıkması beklenen yeni Delphi sürümünün yani Delphi Weaver’ın çok önem verdiğim bir özelliğini de sizlerle paylaşmak istiyorum. Delphi Weaver’ın özelliklerinde listelenen ancak pek çok kişinin dikkatini cezbetmeyen, “Seamless .NET <> Native communication” özelliği eminim pek çok kişinin native uygulama geliştirebilecekleri ortamlara geçişinde etken olacaktır. Peki nedir bu “Seamless .NET <> Native communication” özelliği ?

Bu özellik hakkında henüz net bir şey söz konusu değil. Ancak, neler yapılabileceği hususunda ; burayı ve bu haber grubunu takip etmenizi tavsiye edebilirim.

Kısaca; Win32 ortamında tamamen native kod geliştirirken, .Net framework fonksiyonalitesine herhangi bir COM bağımlılığı olmadan, %100 delphi kodları ile erişmek isterseniz bu teknoloji tam size göre demektir. ;)

Atozed Software’in üzerinde çalıştığı CrossTalk isimli ürün, Delphi 5,6,7..2009 altından .Net Framework’e erişebilmeniz için gereken tüm altyapıyı sağlayacak. Projenin lideri olan Chad Z. Hover ile yapmış olduğum görüşme neticesinde öğrendiğim şey ise beni daha da sevindirdi. CrosTalk ürünü Delphi Weawer ile birlikte gelecek. Yani birkaç paragraf önce belirttiğimiz “Seamless .NET <> Native communication” Delphi Weaver altındaki CrossTalk ürününü simgeliyor.

Bu yeni teknolojinin Delphi’nin yükselmesinde büyük bir paydaya hizmet edeceği inancını taşıyorum. Ayrıca Delphi’nin hedefleri arasında Cross platform code compilation olduğunu da bilmenizi istiyorum. İşte gerçek platform bağımsız kodlama bizlerin hizmetine sunulacak. Delphi’de yazdığımız uygulamaları Windows, Linux yada MacOS gibi işletim sistemleri üzerinde çalışır halde göreceğiz. Elbette bu, .Net’in yada Java’nın yaptığı gibi değil, native derleme ile yapılacak.

Tüm bu anlatılanlar, belki de hâla afaki kalmış olabilir. CrossTalk’ın yahut Delphi Weaver içindeki “Seamless .NET <> Native communication” özelliğinin ne kadar önemli olduğu anlaşılmamış da olabilir. Bunun önemini anlatabilmek için, Win32′den .Net’e erişmeye çalışmak gerekir.

Bu makalede, Win32 ortamından .Net Framework’e erişeceğiz ve tüm bu zorlukları sizlerin gözleri önüne sereceğim. Öncelikle Visual Studio 2005 ile bir Class Library(DLL) oluşturacağız.Bu DLL’imiz SQL Server 2005′e erişim sağlayan bir kaç sınıftan ibaret olacak. Ve Bu DLL’imizi Delphi 7 altından kullanacağız.

O halde kodlamaya başlayabiliriz. Öncelikle Visual Studio’muzu açıyoruz ve yeni bir Class Library projesi oluşturuyoruz. Ardından Microsoft.SqlServer.ConnectionInfo, Microsoft.SqlServer.Smo, Microsoft.SqlServer.SmoEnum, Microsoft.SqlServer.SqlEnum library’lerini referans olarak ekliyoruz. Projemiz aşağıda göründüğü gibi olacaktır:

sqlclasslibrary_1

Bu makalenin can alıcı noktası, .Net ortamında yazdığımız kodlarımızın dışarıdan(Win32 ortamından) kullanılabilmesi için COM programlamadan istifade edeceğimiz gerçeğidir. COM programlama kullanacağımıza göre, dışarıdan erişime açacağımız tüm sınıfların ComVisible attribute’u ile görünür hâle getirilmesi gerekir. Bir diğer önemli nokta ise, Class Library projemizin özelliklerinde gizlidir. Bu özel durumları aşağıdaki görsellerden izleyebilirsiniz:

Projemizin Application bölümünden Assembly Information buttonuna tıklanarak yapılalacak ayarlar:
sqlclasslibrary_2

Projemizin Build sayfasında yapılacak ayarlar:
sqlclasslibrary_3

Bu ayarların yapılmasına müteakip, C# tarafında SQL Server 2005′e bağlanan, ve bir veritabanının altındaki tüm tablolara erişim sağlayabileceğimiz kodları yazmaya başlamadan evvel anlatmamız gereken bir kaç husus daha var. Bunlardan en önemlisi; .Net framework platformundaki her veri türünü COM ortamında kullanmanın zorluklarıdır. Kullanmak istediğimiz veri türleri, ki bunların içinde özel sınıflar, framework sınıfları gibi tüm veri türleri ComVisible attribute’u ile işaretlenmiş olmalıdır. .Net ortamındaki tüm türlerin nasıl yönetileceğini dış uygulamalar bilemezler. Binlerce tür olduğu hesaplanırsa, bu türlerin hepsinin ComVisible ile işaretlenmesinin ne kadar zor olduğu da aşikârdır.

Makalemizin başlarında, temel veri türlerinin .Net içinde tanımlı olduğunu ifade etmiştik. Bu CTS adını almıştı ve pek çok programlama dilinin bir arada çalışabilmesi için son derece faydalı bir unsurdu. Ancak, şimdi bizim için bir sorun gibi duruyor. CTS içinde tanımlı olan bazı basit değişken türlerinin COM programlama da ComVisible ile görünür hâle getirilmeden de kullanılabildiğini ifade etmek sanırım sizleri biraz rahatlatacaktır ancak yine de yeteri derece de rahatlamamış olmanız gerekir. Çünkü, pek çok projemizde bu projemizde olduğu gibi, Integer, String vb. gibi basit veri türleri bizim için yeterli değildir.

.Net framework’ün Smo kütüphanesi ile Sql Server’a erişebildiğini biliyoruz. Ve bu Smo kütüphanesi içinde Sql Server içindeki hemen hemen her nesne için tanımlanmış bir veri tipi bulunmaktadır.(Genellikle bir sınıf). Peki biz bu veritiplerini dışarıya nasıl sunacağız ? Smo namespace’ininin tamamını mı ComVisible ile işaretleyeceğiz ?

Elbette hayır. Bu son derece uğraştırıcı ve zor bir durum olurdu. Bu sebeple, Smo kütüphanesi içinde ilgilendiğimiz sınıflara karar verecek ve bu sınıflar için bir arabirim yazacağız. Ardından bu arabirimi görünür kılacağız ;)

Örneğin, biz bu uygulamamızda Sql Server 2005′e erişip herhangi bir veritabanının içindeki tüm tablo‘lara ulaşmak istediğimize göre, Smo namespace’indeki Table sınıfına ait sahte bir interface düzenleyeceğiz. Gelin biraz da kodlayalım ki daha anlaşılır olsun:

using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Common;
using System.Runtime.InteropServices;

namespace SQLClassLibrary
{
    [ComVisible(true)]
    public interface ITableInterface
    {
        DateTime CreateDate { get; }
        string Name { get; }
        long RowCount { get; }
        int ColumnCount { get; }
        int TriggerCount { get; }
    }

    public class TableClass : ITableInterface
    {
        private Table ActiveTable;

        public DateTime CreateDate
        {
            get
            {
                return ActiveTable.CreateDate;
            }
        }
        public string Name
        {
            get
            {
                return ActiveTable.Name;
            }
        }
        public long RowCount
        {
            get
            {
                return ActiveTable.RowCount;
            }
        }
        public int ColumnCount
        {
            get
            {
                return ActiveTable.Columns.Count;
            }
        }
        public int TriggerCount
        {
            get
            {
                return ActiveTable.Triggers.Count;
            }
        }

        public TableClass(Table tbl)
        {
            ActiveTable = tbl;
        }

        ~TableClass()
        {
            // Nesneleri yok etmeyi unutma.! GC ye güvenme..
        }
    }

    public class SQLServerClass
    {
    }
}

Yukarıdaki kod örneğimizde öncelikle System.Runtime.InteropServices isimli alanı using bloğuna eklediğimizi görüyorsunuz. ComVisible attribute’unu kullanmak için bunu yapmak durumundayız. Ardından Smo namespace’i içinde tanımlı olan Table isimli sınıfın ilgilendiğimiz birkaç tane property’sini tanımladığımız ITableInterface arabiriminin içinde görüyorsunuz. Bu arabirim, ComVisible ile işaretli durumda. Biz ileride Delphi üzerinden yazdığımız C# kodlarını kullanırken arabirim referanslarına erişeceğiz ;)

Ardından basit bir sınıf olan TableClass sınıfının ITableInterface arabirimini implemente ettiğini görüyorsunuz. Sizinde farkettiğiniz gibi, bu sınıf ComVisible ile işaretlenmemiş. Çünkü biz bu sınıfa ilgili arabirimi üzerinden erişim sağlayacağız. Dolayısı ile sınıfımız ITableInterface’i implemente ettiği için sadece arabirimi ComVisible ile görünür kılmak bizim için yeterli olacaktır.

Buradaki anafikri anlamanız çok önemli. .Net framework altındaki kompleks yapıları COM ortamından kullanabilmek için onların COM görünürlüğünün sağlanması gereklidir. Biz bu uygulamamızda .Net framework’ün Smo kütüphanesi içindeki Table isimli sınıfı bu sebeple dışarıya veremedik ! İlgili sınıfı(Table) ComVisible ile görünür kılamadığımız için, biz de bu sınıfın sahte bir kopyasına bir arabirim oluşturduk ve o kopyayı görünür kıldık. Meselenin özü aslında sadece bu kadar. Şimdi Sql Server 2005′e erişim sağlamasını düşündüğümüz sınıfımıza birer adet Connect ve Disconnect metodu yazmamız işimizi görecek midir ? Evet server’a bağlanmak için server’ın adına ve bağlantı şifresine ihtiyaç duyacağız ancak peki ya hangi veritabanından ilgili tabloları alacağız ?

Bu noktada bizim için bir de Smo namespace’indeki Database sınıfına bir interface uydurmamız gerekecek. Bu interface’de aşağıdaki gibi olacak:

    [ComVisible(true)]
    public interface IDatabaseInterface
    {
        int ActiveConnections { get; }
        DateTime CreateDate { get; }
        DateTime LastBackupDate { get; }
        string Name { get; }
        double Size { get; }

        int StoredProcedureCount { get; }
        int TableCount { get; }
        int UserDefinedFunctionCount { get; }
        int ViewCount { get; }

        ITableInterface TableFromName(string TableName);
        ITableInterface TableFromIndex(int Index);
    }

    public class DatabaseClass : IDatabaseInterface
    {
        private Database ActiveDatabase;
        private Hashtable hTables;

        public int ActiveConnections
        {
            get
            {
                return ActiveDatabase.ActiveConnections;
            }
        }
        public string Collation
        {
            get
            {
                return ActiveDatabase.Collation;
            }
            set
            {
                ActiveDatabase.Collation = value;
                ActiveDatabase.Alter();
            }
        }
        public DateTime CreateDate
        {
            get
            {
                return ActiveDatabase.CreateDate;
            }
        }
        public DateTime LastBackupDate
        {
            get
            {
                return ActiveDatabase.LastBackupDate;
            }
        }
        public string Name
        {
            get
            {
                return ActiveDatabase.Name;
            }
        }
        public double Size
        {
            get
            {
                return ActiveDatabase.Size;
            }
        }
        public int StoredProcedureCount
        {
            get
            {
                return ActiveDatabase.StoredProcedures.Count;
            }
        }
        public int TableCount
        {
            get
            {
                return ActiveDatabase.Tables.Count;
            }
        }
        public int UserDefinedFunctionCount
        {
            get
            {
                return ActiveDatabase.UserDefinedFunctions.Count;
            }
        }
        public int ViewCount
        {
            get
            {
                return ActiveDatabase.Views.Count;
            }
        }

        public ITableInterface TableFromName(string TableName)
        {
            return (ITableInterface)hTables[TableName];
        }

        public ITableInterface TableFromIndex(int Index)
        {
            ITableInterface Result = null;

            int iCounter = 0;
            IDictionaryEnumerator TableEnum = hTables.GetEnumerator();
            while (TableEnum.MoveNext())
            {
                if (iCounter == Index)
                {
                    Result = (TableClass)TableEnum.Value;
                    break;
                }

                iCounter += 1;
            }

            return Result;
        }

        public DatabaseClass(Database db)
        {
            ActiveDatabase = db;
            hTables = new Hashtable();

            foreach (Table tbl in ActiveDatabase.Tables)
            {
                if (!tbl.IsSystemObject) hTables.Add(tbl.Name, new TableClass(tbl));
            }
        }
    }

Yukarıda IDatabaseInterface tanımını ve bu interface’i implemente eden sınıfın tanımını görüyorsunuz. Biz ilgili veritabanının tablolarına TableFromName ve TableFromIndex metodları ile erişeceğiz. Bu durumda artık son sınıfımız olan en başta tanımını boş olarak gördüğünüz SQLServerClass sınıfını yazmaya başlayabiliriz. Ancak bu sınıfımız içinde bir interface tasarlamamız ve ComVisible ile görünür kılmamız gerekiyor. Tanım aşağıdaki gibi olacak;

    [ComVisible(true)]
    public interface ISQLLibrary
    {
        bool Connect(string ServerName, string DatabaseName, string UserName, string Password);
        void Disconnect();

        IDatabaseInterface Database { get; }
    }

    public class SQLServerClass : ISQLLibrary
    {
        private Server srv;
        private IDatabaseInterface CurrentDatabase;

        public IDatabaseInterface Database
        {
            get
            {
                return CurrentDatabase;
            }
        }

        public bool Connect(
                            string ServerName,
                            string DatabaseName,
                            string UserName,
                            string Password
                           )
        {
            bool Result = false;

            srv = new Server(ServerName);
            srv.ConnectionContext.LoginSecure = false;
            srv.ConnectionContext.Login = UserName;
            srv.ConnectionContext.Password = Password;
            Result = true;

            if (Result)
            {
                Database db = srv.Databases[DatabaseName];
                CurrentDatabase = new DatabaseClass(db);
            }

            return Result;
        }

        public void Disconnect()
        {
            srv.ConnectionContext.Disconnect();
        }

        ~SQLServerClass()
        {
            Disconnect();
        }
    }

Görüldüğü gibi son derece basit bir yapıya sahip olan SQLServerClass sınıfımız ISQLLibrary interface’ini implemente etmiş ve ISQLLibrary ComVisible ile görünür hâle getirilmiş. Kodumuzun nihai hali aşağıdaki gibi olacaktır:

using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Common;
using System.Runtime.InteropServices;
using System.Collections;

namespace SQLClassLibrary
{
    [ComVisible(true)]
    public interface ITableInterface
    {
        DateTime CreateDate { get; }
        string Name { get; }
        long RowCount { get; }
        int ColumnCount { get; }
        int TriggerCount { get; }
    }

    public class TableClass : ITableInterface
    {
        private Table ActiveTable;

        public DateTime CreateDate
        {
            get
            {
                return ActiveTable.CreateDate;
            }
        }
        public string Name
        {
            get
            {
                return ActiveTable.Name;
            }
        }
        public long RowCount
        {
            get
            {
                return ActiveTable.RowCount;
            }
        }
        public int ColumnCount
        {
            get
            {
                return ActiveTable.Columns.Count;
            }
        }
        public int TriggerCount
        {
            get
            {
                return ActiveTable.Triggers.Count;
            }
        }

        public TableClass(Table tbl)
        {
            ActiveTable = tbl;
        }

        ~TableClass()
        {
            // Nesneleri yok etmeyi unutma.! GC ye güvenme..
        }
    }

    [ComVisible(true)]
    public interface IDatabaseInterface
    {
        int ActiveConnections { get; }
        DateTime CreateDate { get; }
        DateTime LastBackupDate { get; }
        string Name { get; }
        double Size { get; }

        int StoredProcedureCount { get; }
        int TableCount { get; }
        int UserDefinedFunctionCount { get; }
        int ViewCount { get; }

        ITableInterface TableFromName(string TableName);
        ITableInterface TableFromIndex(int Index);
    }

    public class DatabaseClass : IDatabaseInterface
    {
        private Database ActiveDatabase;
        private Hashtable hTables;

        public int ActiveConnections
        {
            get
            {
                return ActiveDatabase.ActiveConnections;
            }
        }
        public string Collation
        {
            get
            {
                return ActiveDatabase.Collation;
            }
            set
            {
                ActiveDatabase.Collation = value;
                ActiveDatabase.Alter();
            }
        }
        public DateTime CreateDate
        {
            get
            {
                return ActiveDatabase.CreateDate;
            }
        }
        public DateTime LastBackupDate
        {
            get
            {
                return ActiveDatabase.LastBackupDate;
            }
        }
        public string Name
        {
            get
            {
                return ActiveDatabase.Name;
            }
        }
        public double Size
        {
            get
            {
                return ActiveDatabase.Size;
            }
        }
        public int StoredProcedureCount
        {
            get
            {
                return ActiveDatabase.StoredProcedures.Count;
            }
        }
        public int TableCount
        {
            get
            {
                return ActiveDatabase.Tables.Count;
            }
        }
        public int UserDefinedFunctionCount
        {
            get
            {
                return ActiveDatabase.UserDefinedFunctions.Count;
            }
        }
        public int ViewCount
        {
            get
            {
                return ActiveDatabase.Views.Count;
            }
        }

        public ITableInterface TableFromName(string TableName)
        {
            return (ITableInterface)hTables[TableName];
        }

        public ITableInterface TableFromIndex(int Index)
        {
            ITableInterface Result = null;

            int iCounter = 0;
            IDictionaryEnumerator TableEnum = hTables.GetEnumerator();
            while (TableEnum.MoveNext())
            {
                if (iCounter == Index)
                {
                    Result = (TableClass)TableEnum.Value;
                    break;
                }

                iCounter += 1;
            }

            return Result;
        }

        public DatabaseClass(Database db)
        {
            ActiveDatabase = db;
            hTables = new Hashtable();

            foreach (Table tbl in ActiveDatabase.Tables)
            {
                if (!tbl.IsSystemObject) hTables.Add(tbl.Name, new TableClass(tbl));
            }
        }
    }

    [ComVisible(true)]
    public interface ISQLLibrary
    {
        bool Connect(string ServerName, string DatabaseName, string UserName, string Password);
        void Disconnect();

        IDatabaseInterface Database { get; }
    }

    public class SQLServerClass : ISQLLibrary
    {
        private Server srv;
        private IDatabaseInterface CurrentDatabase;

        public IDatabaseInterface Database
        {
            get
            {
                return CurrentDatabase;
            }
        }

        public bool Connect(
                            string ServerName,
                            string DatabaseName,
                            string UserName,
                            string Password
                           )
        {
            bool Result = false;

            srv = new Server(ServerName);
            srv.ConnectionContext.LoginSecure = false;
            srv.ConnectionContext.Login = UserName;
            srv.ConnectionContext.Password = Password;
            Result = true;

            if (Result)
            {
                Database db = srv.Databases[DatabaseName];
                CurrentDatabase = new DatabaseClass(db);
            }

            return Result;
        }

        public void Disconnect()
        {
            srv.ConnectionContext.Disconnect();
        }

        ~SQLServerClass()
        {
            Disconnect();
        }

    }
}

Şimdi Visual Studio ortamında Ctrl+Shift+B tuşlarına basarak yada Build menüsünden Build seçeneklerinden birisini seçerek derleme işlemi yaptığımızda Delphi tarafına geçmeye hazırız demektir. İlgili DLL’imiz artık projemizi kaydettiğimiz yerde oluşturulduğu gibi, proje ayarlarından Com görünürlüğünü işaretlediğimiz için bu DLL aynı zamanda COM sistemine Register edilmiş durumdadır. Eğer elle register işlemi yapmak istiyorsanız o halde, regasm kullanmak durumunda kalacaksınız. Ancak şu anda bu işi Visual Studio bizim için yapmış durumda. Delphi’mize geçip yeni bir proje açalım, ve Project/Import Type Library adımından aşağıdaki görselde görebileceğiniz gibi ilgili DLL’imizi listeden bulalım ve Create Unit’e basalım.

sqlclasslibrary_4

SQLClassLibrary_TLB.pas isimli dosyamız artık oluşmuş durumda. Delphi örneğimiz ise aşağıdaki gibi olacaktır;

uses SQLClassLibrary_TLB;
..
..
..
procedure TForm1.Button1Click(Sender: TObject);
var
  SqlServer : ISQLLibrary;
begin
  SqlServer := CoSQLServerClass.Create as ISqlLibrary;
  SqlServer.Connect('TUGRUL', 'BENIMDB', 'sa', '*****');
  ShowMessage(
     Format('Kayıt Sayısı=%d, Kolon Sayısı=%d',
       [
         SqlServer.Database.TableFromName('BenimTablom').RowCount,
         SqlServer.Database.TableFromName('BenimTablom').ColumnCount
       ]) );
  SqlServer.Disconnect;
  SqlServer := nil;
end;

Özetlemek gerekir ise, Delphi Win32 projelerinde herhangi bir .Net framework kütüphanesine erişebilir ve onu kullanabilirsiniz. Ancak ComVisible görünürlük durumuna dikkat ederek ;) Sanırım şimdi makalemin başlarında belirttiğim, CrossTalk ve Delphi Weaver içinde .Net erişimi özelliklerinin ne derece önemli olduğu daha açıktır.

Saygılar, sevgiler..