Tablica do dll

0

Witam
Mam problem z przekazaniem tablicy jako parametru do dllki
Mam taki oto kod:
-----------dllka-----------

library slshow;

{ Important note about DLL memory management: ShareMem must be the
  first unit in your library's USES clause AND your project's (select
  Project-View Source) USES clause if your DLL exports any procedures or
  functions that pass strings as parameters or function results. This
  applies to all strings passed to and from your DLL--even those that
  are nested in records and classes. ShareMem is the interface unit to
  the BORLNDMM.DLL shared memory manager, which must be deployed along
  with your DLL. To avoid using BORLNDMM.DLL, pass string information
  using PChar or ShortString parameters. }

uses
  ShareMem,
  SysUtils,
  Classes,
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

type
  TKont = record
    KolumnaDBGrid_zm: AnsiString; //kolumna na jaka ma reagowac w DBGridzie
    DataField_zm: AnsiString;
    KeyField_zm: AnsiString;
    ListField_zm: AnsiString;
    Zapytanie_zm: AnsiString;
  end;

  TPola = record
    pole: AnsiString; //field
    nazwa: AnsiString; //title
    view: Boolean; //visible
    ronly: boolean; //readonly
    w: integer; //dlugosc
    al: TAlignment; //wyrownanie
  end;

  PKolumny = ^TKolumny;
  TKolumny = array of TPola;
  PKontrolki = ^TKontrolki;
  TKontrolki = array of TKont;


{$R *.res}

function showOkno(conStr_zm, mainSel_zm:PChar;var kolumny_zm: PKolumny;var kontrolki_zm: PKontrolki):integer;stdcall;
var
  F: TForm1;
begin
  try
    F := TForm1.Create(Application);
    with F do
    begin
      connectionStr_zm := conStr_zm;
      mainSelect_zm := mainSel_zm;
      Kolumny_zm := kolumny_zm;
      Kontrolki_zm := kontrolki_zm;
      ShowModal;
  end;
  finally
    F.Free;
  end;
  Result := 0;
end;

exports
  showOkno name 'showOkno';


begin
end.

-----------formatka-------------

type
  TKont = record
    KolumnaDBGrid_zm: AnsiString; //kolumna na jaka ma reagowac w DBGridzie
    DataField_zm: AnsiString;
    KeyField_zm: AnsiString;
    ListField_zm: AnsiString;
    Zapytanie_zm: AnsiString;
  end;

  TPola = record
    pole: AnsiString; //field
    nazwa: AnsiString; //title
    view: Boolean; //visible
    ronly: boolean; //readonly
    w: integer; //dlugosc
    al: TAlignment; //wyrownanie
  end;

  PKolumny = ^TKolumny;
  TKolumny = array of TPola;
  PKontrolki = ^TKontrolki;
  TKontrolki = array of TKont;

  TShowOkno = function (conStr_zm, mainSel_zm:PChar;var kolumny_zm: PKolumny;var kontrolki_zm: PKontrolki):integer;stdcall;

var
  DLLInstance: THandle;
  ShowOkno: TShowOkno;
  wynik: integer;
  mainSel_zm, conStr_zm: AnsiString;
  kol_zm: TKolumny;
  kon_zm: TKontrolki;
  pkol_zm: PKolumny;
  pkon_zm: PKontrolki;
begin
  mainSel_zm := 'SELECT bank_naz, a.kraj_id, kraj_naz, kraj_skr, a.woj_id, woj_naz FROM do_bank a, do_kraj b, do_woj c WHERE a.kraj_id = b.kraj_id AND a.woj_id = c.woj_id';
  conStr_zm := ADOConnection1.ConnectionString;

  SetLength(kon_zm, 2);
  with kon_zm[0] do
  begin
    KolumnaDBGrid_zm := PChar('kraj_naz');
    Zapytanie_zm := PChar('SELECT * FROM do_kraj');
    ListField_zm := PChar('kraj_id;kraj_skr;kraj_naz');
    KeyField_zm := PChar('kraj_id');
    DataField_zm := PChar('kraj_id');
  end;
  with kon_zm[1] do
  begin
    KolumnaDBGrid_zm := PChar('woj_naz');
    Zapytanie_zm := PChar('SELECT * FROM do_woj');
    ListField_zm := PChar('woj_naz');
    KeyField_zm := PChar('woj_id');
    DataField_zm := PChar('woj_id');
  end;
  setlength(kol_zm, 5);
  with kol_zm[0] do
  begin
    pole := PChar('bank_naz');
    nazwa := PChar('Bank');
    view := True;
    ronly := False;
    w := 80;
    al:= taLeftJustify;
  end;
  with kol_zm[1] do
  begin
    pole := PChar('woj_naz');
    nazwa := PChar('Województwo');
    view := True;
    ronly := False;
    w := 80;
    al:= taLeftJustify;
  end;
  with kol_zm[2] do
  begin
    pole := PChar('woj_id');
    nazwa := PChar('Województwo_id');
    view := False;
    ronly := False;
    w := 80;
    al:= taLeftJustify;
  end;
  with kol_zm[3] do
  begin
    pole := PChar('kraj_id');
    nazwa := PChar('kraj_id');
    view := False;
    ronly := False;
    w := 80;
    al:= taLeftJustify;
  end;
  with kol_zm[4] do
  begin
    pole := PChar('kraj_naz');
    nazwa := PChar('Kraj');
    view := True;
    ronly := False;
    w := 80;
    al:= taLeftJustify;
  end;

  pkol_zm := @kol_zm;
  pkon_zm := @kon_zm;

  DLLInstance := LoadLibrary('slshow.dll');
  if DLLInstance = 0 then begin
    MessageDlg('Nie mogę załadować biblioteki DLL.', mtError, [mbOK], 0);
    Exit;
  end;
  @ShowOkno := GetProcAddress(DLLInstance, 'showOkno');
  if (@ShowOkno <> nil)then
  begin
    wynik := ShowOkno(PChar(conStr_zm),PChar(mainSel_zm),pkol_zm,pkon_zm);
    showmessage(inttostr(Wynik));
    FreeLibrary(DLLInstance);
  end
  else
  begin
    MessageDlg('Nie mogę znaleźć procedury.', mtError, [mbOK], 0);
  end;

No i po otwarciu dllki nic sie nie dzieje, tzn nie wyskakuje zaden blad, wszystko jest ok, ale tez tablice ta pewno nie sa przekazywane poniewaz ich zawartosc sie nie wyswietla :-(

0

Oczywiscie, funkcja jest wyeksportowana
Funkcja na pewno dziala. Przekazuje do niej po za tymi dwoma tablicami jeszcze inne parametry typu PChar (zreszta widac to po deklaracji funkcji) i one sie przekazuja, z nimi jest wszystko OK. Tylko nie przekazuja mi sie te tablice :-(

0

Zaraz zaraz, tablica dynamiczna jest wskaźnikiem. Czy jest sens przekazywać wskaźnik do wskaźnika? Może to błędny trop, ale ja bym go rozważył.

0

Obawiam sie czy winne za to nie jest alokacja tablicy setlength i alokowanie lancuchow do ansistring poprzez pchar('lancuch'); Poprzez przekazywanie zmiennych do biblioteki (<ort>w ogóle</ort> miedzy roznymi modlami; procesami) <ort>wolal bym</ort> wykonac to standardowo dla windows. A wiec przypisac nie jako wejsciowa w rekordzie ansistring tylko pchar i przydzielic pamiec (Getmem).

0

Witam
W kodzie ktory wkleilem wkradl sie blad. Po napisaniu posta zauwazylem te AnsiStringi w deklaracji i zmienilem je oczywiscie na PChar'y

Co do getmem to nie robie tego :-( Moze to stwarza ten problem? :-( Zaraz lookne do helpa co to dzielajet

0

Hmm, nic :-(
Robie teraz tak

  kol_zm: TKolumny;
  kon_zm: TKontrolki;
  pkol_zm: PKolumny;
  pkon_zm: PKontrolki; // PKontrolki = ^TKontrolki;
begin
  new(pkol_zm);
  new(pkon_zm);

a deklaracja funkcji wyglada tak

  TShowOkno = function (conStr_zm, mainSel_zm:PChar;var kolumny_zm: PKolumny;var kontrolki_zm: PKontrolki):integer;stdcall;

Jesli ktos przesylal kiedys tablice recordow do funkcji z DLLki i moglby cos poradzic to niech sie odezwie :-) A moze tego po prostu sie nie da zrobic? Czytalem gdzies ze tablice dwuwymiarowe jest bardzo ciezko przeslac do funkcji z dll - zwiazane to bylo z dynamiczna alokacja pamieci czy czyms tam innym ;-)

Najlepiej jakbys sie jakis guru wypowiedzial :D

0
function showOkno(conStr_zm, mainSel_zm:PChar;var kolumny_zm: PKolumny;var kontrolki_zm: PKontrolki):integer;stdcall;
var
   F: TForm1;
begin
   try
      F := TForm1.Create(Application);
      with F do
      begin
         connectionStr_zm := conStr_zm;
         mainSelect_zm := mainSel_zm;
         Kolumny_zm := kolumny_zm;  // <=============
         Kontrolki_zm := kontrolki_zm; // <=============
         ShowModal;
   end;

Jak rozumiem, w zaznaczonych linijkach Kolumny i Kontrolki są polami F (with F...) a kolumny i kontrolki parametrami funkcji showOkno. Problem w tym, że Delphi nie jest czułe na wielkość liter i zapewne traktuje jedno i drugie jako pola F (a może jedno i drugie jako parametry funkcji... egal). Proponuję zmienić nazwy parametrów funjcji na odmienne niż nazwy pól albo nie używać with

//a już zmieniłeś :)) spróbuj ze zmianą nazw i bez new/getmem

0

Ok, zrobilem tak jak napisales ale ku mojemu zdziwieniu kompilator wywala blad ze zmienne nie sa tego samego typu :-( Mimo ze i w unit1 (zawartym w dll) i w "glownym" kodzie dllki deklaracje zmiennych sa takie same! :-(

jak przepisac teraz wartosc z tej tablicy z parametru do tej tablicy zadeklarowanej w unit1?

0

Kolejny update:

Jako ze nie moglem przepisac danych zrobilem tak

aaa: TKontrolki;
kontrolki_zm: PKontrolki; //PKontrolki = ^Tkontrolki; - parametr z funkcji wyekpsportowanej z dll

aaa := @kontrolki_zm;

Ale po takim czyms wg delphi tablica ma ze 140k rekordow :-) A na formie pokazuja mi sie jakies teksty z kosmosu

0

Trochę się przestaję łapać. Chciałbym zobaczyć aktualny widok kodu, szczególnie pól formy F, deklaracji w głównym Unicie i w DLL-u i tego, jak wygląda zawartość ShowOkno w DDL-u.
Zresztą nie spodziewaj się po mnie za wiele: w moich testach udało mi się przekazać do DLLki dynamiczną tablicę rekordów, ale jeśli w polach rekordu były PChary to coś się psuło. Ale nawet komuś lepszemu ode mnie, kto będzie umiał to zrobić, może się przydać aktualny stan kodu.
PS. Poza tym niestety nie mam teraz czasu siedzieć nad tym wnikliwie. :-(

0

Na glownej formi, po wcisnieciu przycisku:

procedure TMenuG_f.Button1Click(Sender: TObject);
type
  TKont = record
    KolumnaDBGrid_zm: PChar; //kolumna na jaka ma reagowac w DBGridzie
    DataField_zm: PChar;
    KeyField_zm: PChar;
    ListField_zm: PChar;
    Zapytanie_zm: PChar;
  end;

  TPola = record
    pole: PChar; //field
    nazwa: PChar; //title
    view: Boolean; //visible
    ronly: boolean; //readonly
    w: integer; //dlugosc
    al: TAlignment; //wyrownanie
  end;

  PKolumny = ^TKolumny;
  TKolumny = array of TPola;
  PKontrolki = ^TKontrolki;
  TKontrolki = array of TKont;

  TShowOkno = function (conStr_zm, mainSel_zm:PChar;var kolumny_zm: Pkolumny;kontrolki_zm: Pkontrolki):integer;stdcall;

var
  DLLInstance: THandle;
  ShowOkno: TShowOkno;
  wynik: integer;
  mainSel_zm, conStr_zm: AnsiString;
  kol_zm: TKolumny;
  kon_zm: TKontrolki;
  pkol_zm: PKolumny;
  pkon_zm: PKontrolki;
//  kol_zm: array of TPola;
//  kon_zm: array of TKont;
begin
  mainSel_zm := 'SELECT bank_naz, a.kraj_id, kraj_naz, kraj_skr, a.woj_id, woj_naz FROM do_bank a, do_kraj b, do_woj c WHERE a.kraj_id = b.kraj_id AND a.woj_id = c.woj_id';
  conStr_zm := ADOConnection1.ConnectionString;

//  new(pkol_zm);
//  new(pkon_zm);

//----------- TUTAJ NASTEPUJE USTALENIE DLUGOSCI TABLICY REKORDOW I WPISANIE DO NICH DANYCH ----------

  pkol_zm := @kol_zm;
  pkon_zm := @kon_zm;

  DLLInstance := LoadLibrary('slshow.dll');
  if DLLInstance = 0 then
  begin
    MessageDlg('Nie mogę załadować biblioteki DLL.', mtError, [mbOK], 0);
    Exit;
  end;
  @ShowOkno := GetProcAddress(DLLInstance, 'showOkno');
  if (@ShowOkno <> nil)then
  begin
    wynik := ShowOkno(PChar(conStr_zm),PChar(mainSel_zm),pkol_zm,pkon_zm);
    showmessage(inttostr(Wynik));
    FreeLibrary(DLLInstance);
  end
  else
  begin
    MessageDlg('Nie mogę znaleźć procedury.', mtError, [mbOK], 0);
  end;
end;

//TAK WYGLADA DLL
library slshow;

{ Important note about DLL memory management: ShareMem must be the
  first unit in your library's USES clause AND your project's (select
  Project-View Source) USES clause if your DLL exports any procedures or
  functions that pass strings as parameters or function results. This
  applies to all strings passed to and from your DLL--even those that
  are nested in records and classes. ShareMem is the interface unit to
  the BORLNDMM.DLL shared memory manager, which must be deployed along
  with your DLL. To avoid using BORLNDMM.DLL, pass string information
  using PChar or ShortString parameters. }

uses
  ShareMem,
  SysUtils,
  Classes,
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

type
  TKont = record
    KolumnaDBGrid_zm: PChar; //kolumna na jaka ma reagowac w DBGridzie
    DataField_zm: PChar;
    KeyField_zm: PChar;
    ListField_zm: PChar;
    Zapytanie_zm: PChar;
  end;

  TPola = record
    pole: PChar; //field
    nazwa: PChar; //title
    view: Boolean; //visible
    ronly: boolean; //readonly
    w: integer; //dlugosc
    al: TAlignment; //wyrownanie
  end;

  PKolumny = ^TKolumny;
  TKolumny = array of TPola;
  PKontrolki = ^TKontrolki;
  TKontrolki = array of TKont;

{$R *.res}

function showOkno(conStr_zm, mainSel_zm:PChar;var kolumny_zm: PKolumny;var kontrolki_zm: PKontrolki):integer;stdcall;
var
  F: TForm1;
begin
  try
    F := TForm1.Create(Application);
    with F do
    begin
      connectionStr_zm := conStr_zm;
      mainSelect_zm := mainSel_zm;
      bbb := kolumny_zm;
      aaa := kontrolki_zm;
      ShowModal;
    end;
  finally
    F.Free;
  end;
  Result := 0;
end;

exports
  showOkno name 'showOkno';


begin
end.


//TAK WYGLADA UNIT1 W DLL
unit Unit1;

interface

uses
  ShareMem, Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, Grids, DBGrids, DB, ADODB, StdCtrls, Buttons, DBCtrls;

type
  TKont = record
    KolumnaDBGrid_zm: PChar; //kolumna na jaka ma reagowac w DBGridzie
    DataField_zm: PChar;
    KeyField_zm: PChar;
    ListField_zm: PChar;
    Zapytanie_zm: PChar;
  end;

  TPola = record
    pole: PChar; //field
    nazwa: PChar; //title
    view: Boolean; //visible
    ronly: boolean; //readonly
    w: integer; //dlugosc
    al: TAlignment; //wyrownanie
  end;

  PKolumny = ^TKolumny;
  TKolumny = array of TPola;
  PKontrolki = ^TKontrolki;
  TKontrolki = array of TKont;

  TForm1 = class(TForm)
    ADOConnection1: TADOConnection;
    ADOQuery1: TADOQuery;
    DataSource1: TDataSource;
    DBGrid1: TDBGrid;
    Panel1: TPanel;
    Zamknij: TBitBtn;
    DBNavigator1: TDBNavigator;
    procedure ZamknijClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormActivate(Sender: TObject);
    procedure DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
      DataCol: Integer; Column: TColumn; State: TGridDrawState);
    procedure DBGrid1ColExit(Sender: TObject);
    procedure DBGrid1KeyPress(Sender: TObject; var Key: Char);
    procedure DBNavigator1Click(Sender: TObject; Button: TNavigateBtn);
    procedure ADOQuery1BeforeEdit(DataSet: TDataSet);
  private
    { Private declarations }
  public
    { Public declarations }
    connectionStr_zm, mainSelect_zm: PChar;
    aaa: PKontrolki;
    bbb: PKolumny;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.ZamknijClick(Sender: TObject);
begin
  Close;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  ADOQuery1.Close;
  ADOConnection1.Close;
  Action := caFree;
end;

procedure TForm1.FormActivate(Sender: TObject);
var
  column: Tcolumn;
  i: integer;
begin
//  showmessage(inttostr(length(bbb)));

  for i := 0 to Length(bbb)-1 do
  begin
//------------- POKAZANIE DANYCH PRZESLANYCH ------------
  end;
  for i:=0 to Length(aaa) - 1 do
  begin
//------------- POKAZANIE DANYCH PRZESLANYCH ------------
  end;
end;

end.

A to moze wiesz jak zrobic zeby przekazac tablice rekordow gdzie np zamias PChar beda stringi? To tez by mi pasowalo Co prawda z tego co wiem wtedy taka DLLka raczej jest nie do uzytku w innych jezykach ale ona i tak bylaby uzywana wylacznie w delphi

0

OK Zrobilem :-)

Oto kod:

//deklaracja funkcji
function showOkno(conStr_zm, mainSel_zm:PChar;var kontrolki_zm:pointer; var kolumny_zm: pointer):integer;stdcall;
var
  F: TForm1;
begin
  try
    F := TForm1.Create(Application);
    with F do
    begin
      connectionStr_zm := conStr_zm;
      mainSelect_zm := mainSel_zm;
      bbb := kolumny_zm;
      aaa := kontrolki_zm;
      ShowModal;
    end;
  finally
    F.Free;
  end;
  Result := 0;
end;


//w unit1
type
  TKont = record
    KolumnaDBGrid_zm: PChar; //kolumna na jaka ma reagowac w DBGridzie
    DataField_zm: PChar;
    KeyField_zm: PChar;
    ListField_zm: PChar;
    Zapytanie_zm: PChar;
  end;

  TPola = record
    pole: PChar; //field
    nazwa: PChar; //title
    view: Boolean; //visible
    ronly: boolean; //readonly
    w: integer; //dlugosc
    al: TAlignment; //wyrownanie
  end;

  PKolumny = ^TKolumny;
  TKolumny = array of TPola;
  PKontrolki = ^TKontrolki;
  TKontrolki = array of TKont;

  TForm1 = class(TForm)
    ADOConnection1: TADOConnection;
    ADOQuery1: TADOQuery;
    DataSource1: TDataSource;
    DBGrid1: TDBGrid;
    Panel1: TPanel;
    Zamknij: TBitBtn;
    DBNavigator1: TDBNavigator;
    procedure ZamknijClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormActivate(Sender: TObject);
    procedure DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
      DataCol: Integer; Column: TColumn; State: TGridDrawState);
    procedure DBGrid1ColExit(Sender: TObject);
    procedure DBGrid1KeyPress(Sender: TObject; var Key: Char);
    procedure DBNavigator1Click(Sender: TObject; Button: TNavigateBtn);
    procedure ADOQuery1BeforeEdit(DataSet: TDataSet);
  private
    { Private declarations }
  public
    { Public declarations }
    connectionStr_zm, mainSelect_zm: PChar;
    aaa: PKontrolki;
    bbb: PKolumny;
  end;

//pokazanie przekazanych parametro to juz pikus
  for i := 0 to Length(bbb^)-1 do
  begin
     showmessage(bbb^[i].jedna_ze_zmiennych_rekordu);
  end;

//a oto form w glownej ap
  TShowOkno = function (conStr_zm, mainSel_zm:PChar;var kontrolki_zm: pointer; var kolumny_zm: pointer):integer;stdcall;

var
  DLLInstance: THandle;
  ShowOkno: TShowOkno;
  wynik: integer;
  mainSel_zm, conStr_zm: AnsiString;
  kol_zm: TKolumny;
  kon_zm: TKontrolki;
  pkol_zm: pointer;
  pkon_zm: pointer;

  pkol_zm := @kol_zm;
  pkon_zm := @kon_zm;

  DLLInstance := LoadLibrary('slshow.dll');
  if DLLInstance = 0 then
  begin
    MessageDlg('Nie mogę załadować biblioteki DLL.', mtError, [mbOK], 0);
    Exit;
  end;
  @ShowOkno := GetProcAddress(DLLInstance, 'showOkno');
  if (@ShowOkno <> nil)then
  begin
    wynik := ShowOkno(PChar(conStr_zm),PChar(mainSel_zm),pkon_zm,pkol_zm);
    showmessage(inttostr(Wynik));
    FreeLibrary(DLLInstance);
  end
  else
  begin
    MessageDlg('Nie mogę znaleźć procedury.', mtError, [mbOK], 0);
  end;

Przy czym wysypuje mi sie jeszcze jakis blad podczas wylaczania aplikacji :-( Jak dojde czemu to napisze

1 użytkowników online, w tym zalogowanych: 0, gości: 1