Array[0..0] of - ez meg mi a csuda?

Array[0..0] of - ez meg mi a csuda?
2005-05-16T13:22:30+02:00
2005-05-18T09:30:08+02:00
2022-10-25T06:02:06+02:00
XdaniX
Sziasztok Guruk!

Nézzétek el nekem, nem vagyok még olyan jó a programozásban, de nagyon igyekszem...

1. kérdésem: Szeretnék csinálni egy dll függvényt, aminek a paraméterlistájában egy record -ot adnék át. A record -ban viszont kellene nekem egy olyasmi tömb változó is, aminek a méretét előre nem határozom meg. Valahogy így néz ki eddig:

IGY NÉZ KI A DLL-BEN A CUCC:

type TFilterData = record szName: array[0..127] of char; dwOptions: word; bVisible: boolean; end; TFilterProgress = record dwFlags: DWORD; dwFilterCount: DWORD; // ebből tudnám, hány elemmel lett feltöltve lpFilters: array of TFilterData; // itt nem akarom előre megmondani, hogy mekkora a max. méret pCallbackMessage: UINT; end; procedure ExecuteFilter(lpData: TFilterProgress); stdcall;

IGY NÉZ KI AZ ALKALMAZÁSBAN:

const Szurok: array[0..1] of TFilterData = ( (szName: 'Name1'; dwOptions: 0; bVisible: True), (szName: 'Name2'; dwOptions: 0; bVisible: True)); var Proba: TFilter begin (...) Proba.dwFilterCount:= 2; Proba.lpFilters:= Szurok; // ezt kéne itt megoldani, mert így nem fogadja el a delphi ExecuteFilter(Proba); (...) end;

2. kérdésem: nézegettem a Delphi7\Source forráskódjait és ott találtam a Windows.pas fájlban olyan record -okat, amikben hasonló felépítés volt mint az enyém, csak ott "array of VALAMI" helyett "array[0..0] of VALAMI" volt írva, megjegyzésként pedig hogy ez egy dinamikus tömb vagy mi a fene. Lehet, hogy ez kelle nekem? De hogyan kell ilyet készíteni, használni? Próbáltam a neten keresni valami infót, de nem nagyon sikerült.

Ha nagyon nehezek a kérdések, akkor nyithatok még egy 50 pontért egy másik topikot is (2. kérdésemhez), de remélem tudtok rá válaszolni.

Üdv Néktek...

Dani
Mutasd a teljes hozzászólást!
A fenti egy némileg "Delphi-barátabban" (vagyis a DLL használatának Delphi alóli megkönnyítése) egyben példa a második kérdésedre.

type TFilterDataArray = array[0..0] of TFilterData; PFilterDataArray = ^TFilterDataArray; TFilterProgress = record dwFlags: DWORD; dwFilterCount: DWORD; lpFilters: PFilterDataArray; pCallbackMessage: UINT; end; // használat procedure Valami(const fp: TFilterProgress); var i: integer; begin for i := 0 to dwFilterCount - 1 do begin fp.lpFilters[i].Visible := false; // pl. // Itt ilyen hasonló műveletek jönnek end; end;

Vagyis így a mutatót "tömbszerűen" használhatod, a fixtömb-mutatót nem kell se castoldod, se derefrencálnod (^, nem tud valaki erre egy jó magyar szót?). A dereferencálást fixtömb és rekordmutatók esetében automatikusan megteszi a Delphi. Az lpFilters-ben ugyanaz a mutató található, mint az előző példában (a tömb első elemének mutatója).
Vagyis a [0..0] elemű tömb deklarációja a legtöbb esetben csak azért létezik, hogy a mutatóját vehessük. Lehetne mondjuk [0..MaxInt - 1] is, de ebben az esetben ha véletlenül elírod a deklarációnál a P-t T-re (TFilterDataArray), akkor a rekordod pár gigás lesz, ami elég furcsa hibákhoz vezet... (én már megcsináltam). A [0..0]-s megoldás hátránya viszont, hogy rinyál a range checking, ha bekapcsolod.

Ja, a feltöltésre még nem írtam példát. Íme:

var fp: TFilterProgress; begin // ... fp.lpFilters := @Szurok[0]; fp.dwFilterCount := 2; // stb. end;
Mutasd a teljes hozzászólást!

  • Dinamikus tömbre lesz szükséged:

    var tomb : array of VALAMI

    ...

    Méretezés:
    SetLength(tomb, MÉRET);

    Hivatkozás az elemekre:
    tomb[index] := ...

    vagy
    High(tomb) - az utsó elemre mutat
    Low(tomb) - az első elemre mutat
    Mutasd a teljes hozzászólást!
  • Igen, tudom. Azt is próbáltam belepaszírozni a record -ba (lásd a bemásolt kódomat), de az istenért nem akarja a Delphi megemészteni. Külön az eljárás paraméterlistájába meg nem nagyon szeretném bepakolni.

    Mutasd a teljes hozzászólást!
  • szName: array[0..127] of char;

    miért nem

    szName : ShortString ?
    Mutasd a teljes hozzászólást!
  • Talán némi támpontot jelenthet (nem próbáltam ki):

    type TFilterData = record szName: array[0..127] of char; dwOptions: word; bVisible: boolean; end; TFilterArray = array of TFilterData; PFilterArray = ^TFilterArray; TFilterProgress = record dwFlags: DWORD; dwFilterCount: DWORD; lpFilters: PFilterArray; pCallbackMessage: UINT; end; var Form1: TForm1; Filters: array of TFilterData; implementation {$R *.dfm} procedure AddFilter(Name: string; Options: Word; Visible: Boolean); begin SetLength(Filters, Length(Filters) + 1); StrPLCopy(Filters[High(Filters)].szName, Name, 127); Filters[High(Filters)].dwOptions := Options; Filters[High(Filters)].bVisible := Visible; end; procedure TForm1.FormCreate(Sender: TObject); var Proba: TFilterProgress; begin AddFilter('Name1', 0, True); AddFilter('Name2', 0, True); Proba.dwFilterCount:= Length(Filters); Proba.lpFilters:= @Filters; end;

    array[0..0] of VALAMI


    Ez olyan memóriaterületet jelöl, amelynek nincs előre definiálva a mérete, de tömbszerűen kezelheted. Viszont a terület lefoglalásáról és felszabadításáról neked kell gondoskodnod.
    Mutasd a teljes hozzászólást!
  • Talán még annyit, hogy jobb lenne valamilyen listát használni.
    De ha dinamikus tömböt használsz, akkor ahogy petrot is írta, használhatod, csak ne felejtsd el inicializálni is.
    Initialize(tomb);
    Delphi 5-ben voltam ilyennel legutoljára, úgyhogy lehet, hogy azóta ez már nem kell...
    Viszont ott a memóriából is ki kellett rúgni:
    SetLength(tomb, 0);
    vagy
    Finalize(tomb);

    De én akkor is a listánál maradnék, mondván az tisztább...
    Egyébként hanyas Delphi-ről van szó, mert attól is függnek azért a dolgok. Pl.: ha .Net-es, akkor ezt el kell felejteni...
    Mutasd a teljes hozzászólást!
  • Ha DLL-t írsz, akkor gyanítom, hogy nem csak Delphi-ből akarod majd a DLL funkciókat elérni. Ekkor nem használhatsz Delphi specifikus konstrukciókat, mint dinamikus tömbök vagy objektumok.

    Ekkor az ilyen változó számú paraméter átadást két módon szokás megoldani:
    - egy nagyobb fix méretű tömböt és egy elemszámot adsz át. Ez persze csak akkor érdemes/lehet, ha az átadandó elemek számának van egy praktikus maximuma.
    - Egy tömb első elemére való mutatót adsz át, valamint az elemek számát.

    pl.

    type PFilterData = ^TFilterData; TFilterProgress = record dwFlags: DWORD; dwFilterCount: DWORD; lpFilters: PFilterData; pCallbackMessage: UINT; end;

    A használat egyszerű. Pl.:

    procedure Valami(const fp: TFilterProgress); var f: PFilterData; i: integer; begin f := fp.lpFilters; for i := 1 to dwFilterCount do begin f.Visible := false; // pl. // Itt ilyen hasonló műveletek jönnek inc(f); end; end;
    Mutasd a teljes hozzászólást!
  • A fenti egy némileg "Delphi-barátabban" (vagyis a DLL használatának Delphi alóli megkönnyítése) egyben példa a második kérdésedre.

    type TFilterDataArray = array[0..0] of TFilterData; PFilterDataArray = ^TFilterDataArray; TFilterProgress = record dwFlags: DWORD; dwFilterCount: DWORD; lpFilters: PFilterDataArray; pCallbackMessage: UINT; end; // használat procedure Valami(const fp: TFilterProgress); var i: integer; begin for i := 0 to dwFilterCount - 1 do begin fp.lpFilters[i].Visible := false; // pl. // Itt ilyen hasonló műveletek jönnek end; end;

    Vagyis így a mutatót "tömbszerűen" használhatod, a fixtömb-mutatót nem kell se castoldod, se derefrencálnod (^, nem tud valaki erre egy jó magyar szót?). A dereferencálást fixtömb és rekordmutatók esetében automatikusan megteszi a Delphi. Az lpFilters-ben ugyanaz a mutató található, mint az előző példában (a tömb első elemének mutatója).
    Vagyis a [0..0] elemű tömb deklarációja a legtöbb esetben csak azért létezik, hogy a mutatóját vehessük. Lehetne mondjuk [0..MaxInt - 1] is, de ebben az esetben ha véletlenül elírod a deklarációnál a P-t T-re (TFilterDataArray), akkor a rekordod pár gigás lesz, ami elég furcsa hibákhoz vezet... (én már megcsináltam). A [0..0]-s megoldás hátránya viszont, hogy rinyál a range checking, ha bekapcsolod.

    Ja, a feltöltésre még nem írtam példát. Íme:

    var fp: TFilterProgress; begin // ... fp.lpFilters := @Szurok[0]; fp.dwFilterCount := 2; // stb. end;
    Mutasd a teljes hozzászólást!
  • Szia Bruck!

    Neked szánom az 50 pöttyöt, de még előtte szeretném megkérdezni, hogy...


    ...nekem kell a memórialefoglalást és felszabadítást elvégeznem a GetMem és FreeMem parancsokkal, vagy a Delphi megoldja ezt nekem?

    ...ha nekem kell, akkor pontosan mennyit is kell lefoglalnom?
    GetMem(fp, SizeOf(TFilterProgress) * dwFilterCount) <- talán ennyi elég? :)


    Egyébként nagyon hálás vagyok a segítségedért, sajnos az interneten nem találtam megfelelő anyagot az ilyen tömbkezeléssel kapcsolatban. Különben valóban úgy kell megoldanom a dolgot, hogy ne csak Delphi tudja használi a DLL-t (azért írtam a témanyitásnál is, hogy "DLL", meg nem string, hanem array char)

    Üdvözlettel...

    Dani
    Mutasd a teljes hozzászólást!
  • A Delphi dinamikus tömb támogatása miatt gyakorlatilag sosem kell GetMem-et vagy FreeMem-et használni. Mielőtt leírnál egy GetMem-et, mindig gondolkozz el, hogyan lehet-e másként megoldani, mert lehet.

    Leírom még egyszer a használatot. Példa a DLL-ben található eljárásra:

    procedure DLLfunction(const fp: TFilterProgress); var i: integer; begin for i := 0 to dwFilterCount - 1 do begin // // itt csinálsz valamit a szűrőkkel, // az elérés pl. fp.lpFilters[i].Visible // end; end;

    Delphiben az adattípusokat deklaráld úgy, ahogy a korábban írtam. Ha más nyelvekre konvertálod a DLL fejlécet (gondolom C++ lesz), akkor az lpFilters-t sima PFilterData mutatónak (pl. FilterData *) deklaráld, a DLLfunction paraméterét pedig PFilterProgress-nek (pl. FilterProgress *), a const ugyanis refrencia (mutató) szerinti átadás.

    A DLL használata Delphi-ből:

    procedure FilterDLLUsage; var fp: TFilterProgress; const Szurok: array[0..1] of TFilterData = ( (szName: 'Name1'; dwOptions: 0; bVisible: True), (szName: 'Name2'; dwOptions: 0; bVisible: True)); begin fp.dwFlags := valami; fp.pCallBackMessage := valami; fp.lpFilters := @Szurok[0]; fp.dwFilterCount := 2; DLLfunction(fp); end;

    A rekordok statikusan foglalódnak, a fenti példában lokális változóként a veremben. Vagyis nem kell külön foglalnod. Itt a szűrők csak az eljáráson belül láthatóak, szükség szerint ez nagyobb láthatósági szintre emelheted.
    A Szurok más kérdés, ennek foglalása attól függ, hogyan használod. A fenti példában ez az általad előre deklarált tömb. Ha előre nem tudod a tartalmát és a hosszát, akkor használhatsz dinamikus tömböt (array of TFilterData). Vagy lehet valahol egy nagy fixtömböd (ha tudod, hogy pl. 20-nál nem lehet több szűrő). Az lpFilters feltöltése azonban mindig ugyanaz: a tömb első elemének címét kell beleírnod.
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd