Win32 & .Net(Delphi->C#)

// 21 Haziran 2009 // .Net, C#, Delphi, Programlama, Veritabanı, Win32

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..

“Win32 & .Net(Delphi->C#)” için 20 Yorum

  1. Ferruh Koroglu diyor ki:

    Çok güzel bir makale Tuğrul Hocam,

    Eline sağlık.

  2. Tuğrul HELVACI diyor ki:

    Teşekkür ederim, beğenmenize sevindim.

  3. Olcay DAĞLI diyor ki:

    Hocam yine güzel bir makale daha, eline sağlık…;)

  4. Nihal Alıcı diyor ki:

    Ben bu makaleni yeni okudum Tuğrul, gerçekten çok faydalı, güzel bir yazı olmuş. Hani tam da “Delphi ile hiç alakam kalmıyor artık” dediğim zamanlarda, yine aklıma bir kurt düşürdün yani. Artık CodeGear bloglarını bile okumaz olmuştum, tekrar başlasam mı acaba :) ?
    Eline, emeğine sağlık

    • Tuğrul HELVACI diyor ki:

      Teşekkür ederim nihal, beğenmene sevindim. Delphi biz onu bilerek ve kasten öldürmeye teşebbüs etmediğimiz sürece ölecek gibi görünmüyor :) Bende yaşasın diye mümkün mertebe elimden geleni nacizane yapma gayretindeyim. Sen oku oku Delphi bloglarını yine :D

  5. Nurullah diyor ki:

    Hocam eline sağlık çok güzel bir makale yanlız benim bir sorunum var :(

    SQLServerClass sınıfının tek constructor ı var olsun oda

    Public SQLServerClass(string cnnString)
    {

    }
    gibi olsun benim elimde bunun gibi bir örnek var ve ben constructor ın parametresini gönderemediğim için Class not registered hatası alıyorum. Bununla ilgili bir çözümün var mı?

  6. Tuğrul HELVACI diyor ki:

    Şu an deneme imkanım yok ama benim yaptığım gibi parametresiz bir constructor kullanıp, onun yerine ilgili parametreleri Connect gibi bir metoda geçmeniz mümkün değil mi ?

  7. Nurullah ERCAN diyor ki:

    Valla DLL i yazan bizim müşterimiz. Axapta entegrasyonu için yazılmış bir dll aslında söylediğinizin benzerini talep ettim. Ama müşteri derki değiştiremyiz :( Açıkcası en net kaynak bu dün akşamdan bu yana ara ara sonuç yok. Çıldırmak üzereyim :( Yardımcı olabilirsen çok sevinirim.

    • Tuğrul HELVACI diyor ki:

      Mail adresimi ziyaretçi defterinden bulabilirsiniz. Oraya konu ile ilgili mümkün olan en detaylı açıklamayı içeren bir mail atabilirseniz eve gittiğimde elimden geldiğince yardımcı olabilirim.

  8. Nurullah ERCAN diyor ki:

    Teşekkürler hocam.

  9. Barış Kırgıç diyor ki:

    Hocam Merhaba ,
    Öncelikle harika bir kaynak sağlamışsınız teşekkür ederim.

    Yukarıda dediğiniz gibi herşeyi yaptım . Kendi yaptığım dll de hiç sorun yok .

    Aynı işi müşterinden istedim ve oda yaptı ve bana “TLB” file gönderdi . Register ettim fakat
    “Class not registered” hatası alıyorum .

    Sizce neden olabilir.

    • Tuğrul HELVACI diyor ki:

      Merhaba Barış bey, acaba müşteriniz sınıf tasarımında ilgili interface’leri COMVisible ile işaretlememiş olabilir mi ? Müşterinizin yazmış olduğu class library’i bana mail ile ulaştırabilirseniz daha net bir yorum yapabilirim. Normalde sizinde bileceğiniz üzere .Net class library’leri regasm yardımcı aracı ile ilgili sisteme kayıt ettirilirler ardından başka dillerde COM programlamanın kullanımına açık hale gelirler. regasm ile sisteme kayıt ettirilmemiş dll’ler için sınıf kaydedilmemiş(Class not registered) gibi bir hata alabilirsiniz. Müşterinizden ilgili dll’i isteyip regasm ile bu dll’i sisteme kayıt edip, ardından Delphi’den import type library ile import etmeyi denediniz mi ?

      Tüm bunları denediğiniz halde hâla aynı hata ile karşılaşıyorsanız, o zaman başta belirttiğim gibi ilgili dll’i yada mümkünse dll’in c# kaynak kodlarını yollayabilirseniz fikir yürütmekte daha başarılı olabilirim.

  10. Taner İNEKÇİ diyor ki:

    Hocam öncelikle verdiğiniz değerli bilgiler için çok teşekkürler…

    Ben yukarıda verdiğiniz tüm adımları visual basic ile uyguladım dll oluşturdum register ettim delphi ye import u gerçekleştirdim. Projeme oluşturduğum unit i ekledim ancak ki visual basicta yarattığım class taki proseduru mu gorebılıyorum ancakki projeyı derleyıp
    calıstırdıgımda access violation hatası alıyorum sizce sebebi ne olabilir.??

    yardımcı olabilirseniz çok sevinirim şimdiden teşekkürler

    • Tuğrul HELVACI diyor ki:

      Access Violation çok genel bir hatadır. Sıklıkla henüz oluşturulmamış(hafızada yer ayırılmamış) nesnelere erişimlerde, yada Free edilmiş ama hâla hafızada anlamsız bir yeri gösteren işaretçiler kullanıldığında karşılaşırsınız. Soruna bu açıdan bir bakmanızı önerebilirim.

  11. Gürcan Öztürk diyor ki:

    Yazılımcılık mesleğine yönelmemdeki yegane kişi :)
    Selamlar
    Walla ne yalan söylim uğraşıp bende böyle dökümanlar hazırlayayım diyorum ama uğraşmaya gelince sıkılıyorum…

    izahatların için teşekkürler
    Delphi’nin tekrar yaşaması dileğiyle..
    Platform bağımsızlığı zırvası ile ilgili sözlerine birebir katılıyorum.

    Eski kadro olsaydı eminim borland bu işi yapardı.

  12. Gürcan Öztürk diyor ki:

    bisürü şey yazmıştım sanırım uçtu gitti.
    yazın çk güzel
    teşekkürler..

  13. erbay diyor ki:

    Hocam s.a,
    Sitenizde bir yazınızı okudum, aslında benim yapacağım iş için yeterli olduğunu düşünüyorum fakat;
    benden işimde çalışan ve desteği verilen programın delphiye dönüştürülmesini
    istediler java ve c# kütüphaneleri var bunları delphide kullanmam için nasıl bir yol izlememi söylersiniz…
    Kütüphaneler çok , 5 6 yıllık bir çalışmanın ürünü sizin makaledekileri yapsam yani interface arayüz yazzsam
    tüm kütüphanelere tek başıma altından kalkamam..
    Cross Talk tan bahsetmişsiniz acaba cross talk ile daha mı kolay olur…
    Şimdiden cevabınızı sabırsızlıkla bekliyorum hayırlı işler…
    mail de attım

  14. mehmet diyor ki:

    selamlar hocam benim programcılığa ilgm var. şu an için piyasada en çok c# dili öneriliyor. ben c#, java arasında kararsız kaldım. delphi 7 programını daha önce kurmustum vsual studio yanında çok basit kalmıştı. bu yuzden delphiye hiç yanaşmadım. sizden ricam hangi dili öğrenmemi tavsiye edersiniz.

Yorum Yazın