DLL içinden Dinamik dizi döndüren fonksiyon çağırmak...

Delphi'de kod yazma ile ilgili sorularınızı bu foruma yazabilirsiniz.
Kullanıcı avatarı
vkamadan
Kıdemli Üye
Mesajlar: 1935
Kayıt: 17 Mar 2004 03:52
Konum: Adapazarı
İletişim:

DLL içinden Dinamik dizi döndüren fonksiyon çağırmak...

Mesaj gönderen vkamadan »

Merhaba arkadaşlar , öncelikle yapmak istediğimden bahsedeyim;
Delphi5 ile yazılmış bir uygulamaya entegre TCkimlik numarası sorgulama özelliği eklemek istiyorum, daha önce @coderlord un gönderdiği makaleden yola çıkarak webservisleriyle bu işi yapıyorum tabi delphi7 de mümkün olduğu için Delphi7 de yazılmış bir DLL nin içindeki fonksiyonu delphi5 projeme ithal etmek istiyorum. sorunum örneğin il listesini DLL den dinamik dizi olarak döndürmek, şöyle bir yapı oluşturdum ,

Kod: Tümünü seç


type
  Tiller=record
  ilkod:Integer;
  ilad:string;
 end;

 type
 TGetIller=array of Tiller;

function LoadSehirListesi:TGetIller;export;stdcall;
  var
  KPS:KPSPublicWebServiceSoap;
  HTTPRIO1: THTTPRIO;
  ils:ArrayOfIlBilgisi;
  i:integer;
  begin
    CoInitialize(nil);
     try
     HTTPRIO1:=THTTPRIO.create(nil);
     HTTPRIO1.HTTPWebNode.UseUTF8InHeader:=true;
     KPS:=GetKPSPublicWebServiceSoap(false,'',HTTPRIO1);
     ils:=KPS.IlListesiGetir;
     SetLength(Result,Length(ils));
     for i:=0 to Length(ils)-1 do
      begin
         Result[i].ilkod:=ils[i].Kod;
         Result[i].ilad:=ils[i].Ad;
      end;
      finally
        begin
          KPS:=nil;
          HTTPRIO1.Free;
          CoUninitialize;
        end;
      end;
  end;

{$R *.res}
exports LoadSehirListesi;
bu yapıda ki DLL mi aşağıdaki gibi yüklüyorum ;

Kod: Tümünü seç

....
implementation
function LoadSehirListesi:TGetIller; stdcall; external 'identify.dll';
{$R *.dfm}
....

var
iller:TGetIller;
begin
  iller:=LoadSehirListesi;
end;
tabi Access violation . ... hatası alıyorum yanlız hatayı DLL de webservisini kullanırken değil , Dizi değişkeni döndürmeye çalışırken veriyor acaba nerde hata yapıyorum teşekkürler..
Volkan KAMADAN
www.polisoft.com.tr
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Dinamik dizileri veya string'leri DLL'den programa gönderiyorsan eğer DLL'in Uses kısmına ShareMem unit'ini eklemeli ve BORLANDMM.DLL 'i uygulamanla beraber dağıtmalısın.
Kullanıcı avatarı
vkamadan
Kıdemli Üye
Mesajlar: 1935
Kayıt: 17 Mar 2004 03:52
Konum: Adapazarı
İletişim:

Mesaj gönderen vkamadan »

merhaba @coderlord ;
ilgin için teşekkür ederim fakat gerekli değişlikleri yaptıktan sonra BORLANDMM.DLL içinden bir istisna ile program kırılıyor.
ilginç bir durum acaba gözlediğin kadarıyla yukarıdaki kullanımda bir hata varmı?
teşekkürler.
Volkan KAMADAN
www.polisoft.com.tr
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Orada ne oluyor biliyor musun? Dinamik dizi ve string'ler reference counted'dır. Yani işleri bittiğinde compiler bunları otomatik olarak free yapar.

Sendeki örnekte Diziyi Result'a geçiriyorsun ancak function'dan çıkarken compiler bu diziyi free yapıyor, dolayısıyla diğer app. den ulaşamıyorsun. İstersen debug ederek bir dene ;)

Burada şöyle bir yol izleyebilirsin. Dinamik dizi için APP'den yer ayırıp DLL'e var parametre olarak gönderirsin.

DLL'inde: procedure GetList(var AList: TArrayList); stdcall; gibi bir tanımlama yaparsın.

APP'den listen için yer ayırmadan önce adet sayısını öğrenmek için DLL'e sorarsın. Bunun için basit bir function kullanabilirsin.

Diğer bir yöntem Getmem ile bunlara DLL içinde yer ayırır ve saklarsın.

App.'den bir function ile buna ulaşırsın. Ancak sonra DLL'e Free ettirmen gerekir. DLL finalization'una çıkışta burayı boşalt gibi bir kod yazarsın.
Kullanıcı avatarı
vkamadan
Kıdemli Üye
Mesajlar: 1935
Kayıt: 17 Mar 2004 03:52
Konum: Adapazarı
İletişim:

Mesaj gönderen vkamadan »

@coderlord senide meşkul ediyorum ama sorunu bir türlü çözemedim gçsterdiğin yolda ilerledim ama olmadı somn durumda halen bellek erişim ihlali hatası alıyorum DLL nin ve APP nin son durumu aşağıdaki gibi ,

Kod: Tümünü seç

function LoadSehirListesi(var Iller:TGetIller):Integer;export;stdcall;
  var
  KPS:KPSPublicWebServiceSoap;
  HTTPRIO1: THTTPRIO;
  ils:ArrayOfIlBilgisi;
  i:integer;
  begin
    CoInitialize(nil);
     try
     HTTPRIO1:=THTTPRIO.create(nil);
     HTTPRIO1.HTTPWebNode.UseUTF8InHeader:=true;
     KPS:=GetKPSPublicWebServiceSoap(false,'',HTTPRIO1);
     ils:=KPS.IlListesiGetir;
     SetLength(Iller,Length(ils));
     Result:=Length(ils);
     for i:=0 to Length(ils)-1 do
      begin
         Iller[i].ilkod:=ils[i].Kod;
         Iller[i].ilad:=ils[i].Ad;
      end;
      finally
        begin
          KPS:=nil;
          HTTPRIO1.Free;
          CoUninitialize;
        end;
      end;
  end;

{$R *.res}
exports LoadSehirListesi;

APP ,

Kod: Tümünü seç

implementation
function LoadSehirListesi(var Iller:TGetIller):Integer;
stdcall; external 'identify.dll';
{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
illers:TGetIller;
begin
  SetLength(illers,LoadSehirListesi(illers));
end;
teşekkür ederim.
Volkan KAMADAN
www.polisoft.com.tr
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

vkamadan Iller parametresini DLL'de SetLength yapmayacaksın. App. de Iller adedi kadar yer ayırdıktan sonra DLL'e gönderip içini doldurtacaksın.
Kullanıcı avatarı
vkamadan
Kıdemli Üye
Mesajlar: 1935
Kayıt: 17 Mar 2004 03:52
Konum: Adapazarı
İletişim:

Mesaj gönderen vkamadan »

şimdi kafam biraz karıştı , iller in uzunluğunu zaten DLL den buluyorum ,
ve bunu tekrar DLL ye gönderip yer ayırmanı mantığını anlayamadım elim ayağıma dolaştı açıkçası yani nasıl bir yapı olacak ,
kod olarak nasıl kullanmalıyım yani kalıp olarak :oops:
Volkan KAMADAN
www.polisoft.com.tr
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Bu senin DLL'i çağırdığın program olsun.

Kod: Tümünü seç

type
  TListe: array of TIller; 
var
   List: TListe;
  IlCount: Integer;
begin
   IlCount:= GetIlCount; // DLL'de tanımladığın function. Illerin sayısını döndürür
   SetLength(List, IlCount);
  GetIlListesi(List); // DLL'de tanımladığın func. List içine illeri yazar.
end.  
DLL kısmında:

Kod: Tümünü seç

function GetIlCount: Integer; stdcall;
begin
  // Illerin sayısını döndür.
end;

procedure GetIlListesi(AIller: TListe); stdcall;
begin
   // Burada sadece Illerin içini doldur. Yer ayırma.
end;
Umarım anlatabilmişimdir.
Kullanıcı avatarı
vkamadan
Kıdemli Üye
Mesajlar: 1935
Kayıt: 17 Mar 2004 03:52
Konum: Adapazarı
İletişim:

Mesaj gönderen vkamadan »

@coderlord, seni uğraştırdım ama sonunda sonuca ulaştım çok teşekkür ederim.
yanlız şimdide uygulamyı kapatırken

Kod: Tümünü seç

...EInvalidPointer with message InvalitPointer Operation...
hatası alıyorum herhalde uygulamayı kapatırken dll yi serbes bırakma olayları ile ilgili bir durum son olarak bunun için ne yapabiliriz.?
teşekkürler.
Volkan KAMADAN
www.polisoft.com.tr
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Sorununun çözüldüğüne sevindim.

Kodunu adım adım Debug et. Hatanın tam olarak nerede olduğunu öğren. Ona göre bir çözüm geliştirebiliriz. Genelde bu sorun belleğe erişirken kullandığı pointer'in içi nil yani boş olursa oluşur.
Kullanıcı avatarı
vkamadan
Kıdemli Üye
Mesajlar: 1935
Kayıt: 17 Mar 2004 03:52
Konum: Adapazarı
İletişim:

Mesaj gönderen vkamadan »

merhaba ,
adım adım debug ettim hiç bir sıkıntı yok,
progamı kapatırken veriyor yani işleme sırasında sıkıntı olmuyor.
teşekkürler.
Volkan KAMADAN
www.polisoft.com.tr
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Şundan olabilir bir ihtimal:

Sen şöyle bir record kullanıyorsun ya:

Kod: Tümünü seç

type
  Tiller=record
  ilkod:Integer;
  ilad:string;
 end; 
burada ilad'ı DLL'de doldururken string belleği gene DLL'de oluşturuluyor. DLL'i ShareMem ile kullanırsan bunun sorun oluşturmaması gerekir.

Çıkışta App. da DLL unload edilmeden şöyle yapmayı dene.

for I:= 0 to Length(Iller)
Iller.ilad:= '';

bu şekilde string'ler free edilecek.

Bir dene emin değilim..

Bu arada diğer yanıtın geldi. Program kapanışını adım adım debug et.
Kullanıcı avatarı
vkamadan
Kıdemli Üye
Mesajlar: 1935
Kayıt: 17 Mar 2004 03:52
Konum: Adapazarı
İletişim:

Mesaj gönderen vkamadan »

peki , programın kapanışını nasıl debug edebiliriz? onun ayrı bir yöntemimi var? :oops:
birde programı çalıştırıp DLL içindeki procedure ve fonksiyonları hiç çağırmasam bile çıkıştı hata alıyorum yani REcordd tiplerin free edilmesi bi işe yaramadı :(
Volkan KAMADAN
www.polisoft.com.tr
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Ufak test programcıkları yaz. DLL'ini Load Unload etsin. Problem yoksa Ok.

Başka bir test programcığı yaz. DLL'deki func'u çağırsın vs vs.. Bu şekilde kapsamı düşürerek testlerini tamamla ve hatayı çöz. Daha sonra App. gerekli düzeltmeyi yaparsın.
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Debug için bu gibi şeylerde direkt CPU moduna geçer öyle bakarım. :)

Sen Debug DCU desteğini compiler options'dan etkinleştirip. Debug sembollerini de katarsan VCL bazında trace yapabilirsin.
Cevapla