Stack Overflow hatası - 960 KB üzerindeki dizilerde alınan...

Delphi'de kod yazma ile ilgili sorularınızı bu foruma yazabilirsiniz.
Cevapla
aligel54
Üye
Mesajlar: 41
Kayıt: 20 Nis 2009 11:34

Stack Overflow hatası - 960 KB üzerindeki dizilerde alınan...

Mesaj gönderen aligel54 »

Bir cihazdan loglarını ve personel bilgilerini almam gerekiyor.
Gelen SDK örnekleri C# ile yazılmış. Örneklerde 10 MB lık bir değişken-diziyle veriler alınıyor.
Dll dosyası içinden GetDeviceData fonksiyonunu çağırmam gerekiyor.

[Function]
int GetDeviceData(HANDLE handle, char *Buffer, int BufferSize, const char *TableName, const char *FieldNames,const char *Filter, const char *Options)

C# örneği:
----------------------

Kod: Tümünü seç

int ret = 0;
int BUFFERSIZE = 10 * 1024 * 1024;
byte[] buffer = new byte[BUFFERSIZE];
string devtablename = "user";
string str = "*";
string devdatfilter = "";
string options = "";
ret = GetDeviceData(h, ref buffer[0], BUFFERSIZE, devtablename, str, devdatfilter, options);
C# da gördüğüm kadarıyla BUFFER adında bir dizi tanımlanıyor ve bu dizinin ilk elemanı fonksiyon içindeki parametrelere yazılıyor.

Şimdi bunu Delphiye nasıl uyarlayacağım? Biraz üzerinde çalıştım fakat takıldığım nokta Stack overflow hatası...

Kod: Tümünü seç

interface
.
.
.
Type
  TGetDeviceData = Function(Handle:THandle; var Buffer:PChar; Var BufferSize:Integer; TableName:PChar; Str: PChar; Filter:PChar; Options:PChar):integer; stdcall;
.
.
.


procedure TForm1.Button1Click(Sender: TObject);
const
  //_BufferSize = 960000;
  _BufferSize = 10*1024*1024;

var
  CommDLL: TGetDeviceData;
  DonenDeger : Integer;

  _Buffer:Array[0.._BufferSize] of char;
  Buffer:PChar Absolute _Buffer;

  BufferSize:Integer;

  TableName, STR, Filter, Options:PChar;

  CihazHandle : THandle;
begin
  CihazHandle := Cihazlar[1];
  TableName := 'user';
  STR       := '*';
  Filter    := '';
  Options   := '';
  BufferSize := _BufferSize;

  @CommDLL := GetProcAddress(DLLHandle, 'GetDeviceData');

  if Assigned(@CommDLL) then
    DonenDeger := CommDLL(CihazHandle, Buffer, BufferSize, TableName, STR, Filter, Options);

  memo1.lines.add(inttostr(DonenDeger));

end;

Yukarıdaki kodlarda dizinin uzunluğunu 960KB yaptığımda bir problem yok.
Fakat SDK örneğindeki gibi 10 MB yaptığımda Stack overflow hatası veriyor.

Dll içindeki fonksiyona geri dönüşü olan bir PAnsichar tipinde bir değişken yazmam gerekiyor.
Fakat buna nasıl C# daki gibi hafızada alan açabilirim.
Bir dizi tanımlayıp Absolute ile aynı yeri işgal edecek şekilde başka bir PAnsiChar ya da PChar tipinde değişken tanımlıyorum.
Fakat boyut 960KB yi geçince bu sorun oluşuyor.
Daha önce karşılaşan var mıdır? Ya da başka bir çözüm önerecek var mıdır?
ikra
Üye
Mesajlar: 900
Kayıt: 28 Nis 2005 01:26
Konum: Simdilik Topragin Üstü

Re: Stack Overflow hatası - 960 KB üzerindeki dizilerde alınan...

Mesaj gönderen ikra »

Konuyla ilgili bir fikrim yok fakat c ile yazilmis olan dll dosyalarini delphi'de kullandiginda stdcall yerine cdecl kullanin diye bir yazi okumustum. aklinda bulunsun.
bir de dönen deger unicode olup 2byte char tutuyor olabilir.

Kod: Tümünü seç

buffersize * SizeOf(Char)
yapmakta fayda var.
kolay gelsin.
kıdemsiz üye
aligel54
Üye
Mesajlar: 41
Kayıt: 20 Nis 2009 11:34

Re: Stack Overflow hatası - 960 KB üzerindeki dizilerde alınan...

Mesaj gönderen aligel54 »

Dediğin gibi cdecl i denedim fakat Access violation hatası alıyorum.

Stdcall ile 960 KB de olsa bilgiyi alabiliyorum.
Aslında 960 KB yeterli olabilir. Fakat içindeki alacağım kayıt miktarı büyüdüğünde 10 MB alana ihtiyacım olabilir.
ikra
Üye
Mesajlar: 900
Kayıt: 28 Nis 2005 01:26
Konum: Simdilik Topragin Üstü

Re: Stack Overflow hatası - 960 KB üzerindeki dizilerde alınan...

Mesaj gönderen ikra »

hatayi kesinlikle buffer'in kapasite sinirindan dolayi aliyorsun.

Kod: Tümünü seç

buffer: array of char;
SetLength(Buffer, BufferSize *SizeOf(Char));
bu sekilde yaparak dene.
Sonucu yazarsan sevinirim.
kıdemsiz üye
ikra
Üye
Mesajlar: 900
Kayıt: 28 Nis 2005 01:26
Konum: Simdilik Topragin Üstü

Re: Stack Overflow hatası - 960 KB üzerindeki dizilerde alınan...

Mesaj gönderen ikra »

bir de

Kod: Tümünü seç

DonenDeger := CommDLL(CihazHandle, Buffer[0], BufferSize, TableName, STR, Filter, Options);
Buffere baslangic indexi vermen gerekir Buffer[0].
kıdemsiz üye
aligel54
Üye
Mesajlar: 41
Kayıt: 20 Nis 2009 11:34

Re: Stack Overflow hatası - 960 KB üzerindeki dizilerde alınan...

Mesaj gönderen aligel54 »

Maalesef aynı hata devam ediyor.

Zaten Char tipi 1 byte tır.
Zaten 10MB ı ayıramıyorum. 2 byte olsa 20MB ayırmak zorunda kalacağım.

İkincisi Buffer[0] yaptğımda da değişen bir şey yok.
boyut 960 KB ı geçince yine stack overflow hatası alıyorum.


Aslında bunun dll le bir ilgisi de yok .
Aşağıdaki şekilde yeni bir uygulama açıp butona aşağıdaki satırları girdiğimde de stack overflow hatasını alıyorum.
Uzunluk 960.000 den küçük olduğunda problem yok.

Kod: Tümünü seç

procedure TForm1.Button1Click(Sender: TObject);
const
  Uzunluk = 10*1024*1024;
var
  Dizi:array[0..Uzunluk] of Char;
  STR:PChar absolute Dizi;
begin
  //
end;
ikra
Üye
Mesajlar: 900
Kayıt: 28 Nis 2005 01:26
Konum: Simdilik Topragin Üstü

Re: Stack Overflow hatası - 960 KB üzerindeki dizilerde alınan...

Mesaj gönderen ikra »

aligel54 yazdı:Zaten Char tipi 1 byte tır.
Delphi 7 kullaniyorsan evet. 2009 ve üzeri 2 byte. Bu nedenle

Kod: Tümünü seç

* SizeOf(Char)
yaptiginda eger 1 byte ise 1 ile carpacak ve degisen birsey olmayacaktir. Eger 2 byte ise 2 ile carpip Buffer'in kapasitesini genisletecektir. Bufferi dinamik array olarak tanitip

Kod: Tümünü seç

SetLength(Buffer, BufferSize *SizeOf(Char)
yapmakta fayda var.
STR'yi neden absolute olarak isaretliyorsun. Yani neden

Kod: Tümünü seç

STR := PChar(@Buffer[0]);
gibi isaretlemiyorsun. Özel bir sebebi var mi?
kıdemsiz üye
ikra
Üye
Mesajlar: 900
Kayıt: 28 Nis 2005 01:26
Konum: Simdilik Topragin Üstü

Re: Stack Overflow hatası - 960 KB üzerindeki dizilerde alınan...

Mesaj gönderen ikra »

Kod: Tümünü seç

procedure TForm1.Button1Click(Sender: TObject);
const
  BufferSize = (10 *1024) *1024;

var
  CommDLL: TGetDeviceData;
  DonenDeger : Integer;
  Buffer: array of char;
  TableName, Filter, STR, Options: Char;
  CihazHandle : THandle;
  _BufferSize: Integer;
begin
  _BufferSize := BufferSize *SizeOf(Char);
  SetLength(Buffer, _BufferSize));
  
  CihazHandle := Cihazlar[1];
  TableName := 'user';
  STR       := '*';
  Filter    := '';
  Options   := '';
  
  @CommDLL := GetProcAddress(DLLHandle, 'GetDeviceData');

  if Assigned(@CommDLL) then
    DonenDeger := CommDLL(CihazHandle, PChar(@Buffer[0]), _BufferSize, PChar(@TableName), PChar(@STR), PChar(@Filter), PChar(@Options));

  memo1.lines.add(inttostr(DonenDeger));

end;
Dikkatimi ceken su oldu. PChar olarak tanimladigin variableler aslinda hic bir adresi göstermiyor. bu nedenle char olarak tanimlanip daha sonra adreslerinin belirtilmesi gerekmekte degil mi?
kıdemsiz üye
ikra
Üye
Mesajlar: 900
Kayıt: 28 Nis 2005 01:26
Konum: Simdilik Topragin Üstü

Re: Stack Overflow hatası - 960 KB üzerindeki dizilerde alınan...

Mesaj gönderen ikra »

[quote="ikra"]

Kod: Tümünü seç

procedure TForm1.Button1Click(Sender: TObject);
const
  BufferSize = (10 *1024) *1024;

var
  CommDLL: TGetDeviceData;
  DonenDeger : Integer;
  Buffer: array of PChar;
  TableName, Filter, STR, Options: PChar;
  CihazHandle : THandle;
  _BufferSize: Integer;
begin
  _BufferSize := BufferSize *SizeOf(Char);
  SetLength(Buffer, _BufferSize));
  
  CihazHandle := Cihazlar[1];
  TableName := 'user';
  STR       := '*';
  Filter    := '';
  Options   := '';
  
  @CommDLL := GetProcAddress(DLLHandle, 'GetDeviceData');

  if Assigned(@CommDLL) then
    DonenDeger := CommDLL(CihazHandle, Buffer, _BufferSize, TableName, STR, Filter, Options);

  memo1.lines.add(inttostr(DonenDeger));

end;
Düzeltmeler yaptim. Adresleme konusunda yanilmisim.
kıdemsiz üye
Cevapla