2017-01-21 11 views
-1

Embarcadero Delphi v10.1には、レコードを持つDLLライブラリと、TStringGridとTEditを含むVCLアプリケーションがあります。そのアイデアは、TEditに入力されたショーツを取ることです。それをDLLのレコードに保存し、レコードに格納されているデータを使用してTStringGridのセルの1つを入力します。Delphiでは、DLLプロシージャを使用してTStringGrid内のセルをどのように変更できますか?

私の問題は、ショートストリングをレコードに保存した後、DLLプロシージャ内でTStringGridにアクセスする方法を見つけることができないようです。これまでのところ私は、DLLにTStringGridにアクセスするためのクラスとポインタの両方を使用して試してみましたが、どちらも働いていない:

type 
    pstringgrid = ^TStringGrid; 

//or 

type 
    pstringgrid = ^stringgrid1; 

//or 

type 
    istringgrid = class(TStringGrid); 

私もレコードからのShortStringに入ることになっている手順にTStringGridをインポートしようとしていますTStringGridに:

procedure AddElement (var grid : stringgrid1); stdcall; 

//or 

type 
    pstringgrid = ^TStringGrid; 

procedure AddElement (var grid : ^pstringgrid); stdcall; 

これまでのところ何も働いていないと私は取得していますすべては、デバッガから「undecleared識別子」エラーメッセージです。助けてください! DLLプロシージャでTStringGridにアクセスして編集するにはどうすればよいですか?

編集:

これは、関連するコードです。外部変数名は残念です。

DLL:

library BibliotekaDLL; 

uses 
    System.SysUtils, 
    System.Classes; 

type 
    StringGrid1 = class(TStringGrid); 
    plist = ^game; 
    game = record 
    nazwa: shortstring; 
    wydawca: shortstring; 
    rokwyd: integer; 
    gatunek1: shortstring; 
    gatunek2: shortstring; 
    pointer: plist; 
    end; 

var 
    BazaDanych : file of game; 
    first, current: plist; 

[...] 

procedure WyswietlListe; stdcall; 
var 
    row : integer; 
begin 
    AssignFile(BazaDanych, 'c:\Baza_Danych_Gier.dat'); 
    if not FileExists('c:\Baza_Danych_Gier.dat') then 
    ShowMessage ('Baza Danych Nie Instnieje' +E.Message) 
    else 
    begin 
    Reset(BazaDanych); 
    Read(BazaDanych, first); 
    Close(BazaDanych); 
    current := first; 
    row := 1; 
    while current^.pointer <> nil do 
     begin 
     current := first; 
     StringGrid1.Cells[0,row] := current^.nazwa; 
     StringGrid1.Cells[1,row] := current^.wydawca; 
     StringGrid1.Cells[2,row] := current^.rokwyd; 
     StringGrid1.Cells[3,row] := current^.gatunek1; 
     StringGrid1.Cells[4,row] := current^.gatunek2; 
     current := current^.pointer; 
     row = row +1; 
     StringGrid1.RowCount := row; 
     end; 
    if current^.pointer = nil do 
     begin 
     StringGrid1.Cells[0,row] := current^.nazwa; 
     StringGrid1.Cells[1,row] := current^.wydawca; 
     StringGrid1.Cells[2,row] := current^.rokwyd; 
     StringGrid1.Cells[3,row] := current^.gatunek1; 
     StringGrid1.Cells[4,row] := current^.gatunek2; 
     end; 
    end; 
end; 

[...] 

そして、VCLアプリケーションのコード:

[...] 

type 
    TForm1 = class(TForm) 
    Button2: TButton; 
    StringGrid1: TStringGrid; 
    procedure Button2Click(Sender: TObject); 
    end; 

var 
    Form1: TForm1; 

implementation 

[...] 

procedure TForm1.Button2Click(Sender: TObject); 
var 
    Handle : THandle; 
    WyswietlListe : procedure; 
begin 
    Handle := LoadLibrary('BibliotekaDLL.dll'); 
    try 
    @WyswietlListe:= GetProcAddress(Handle, 'WyswietlListe'); 
    if @WyswietlListe = nil then raise Exception.Create('Nie Można Znaleźć Procedury w Bibliotece!'); 
    WyswietlListe; 
    finally 
    FreeLibrary(Handle); 
    end; 
end; 

[...] 
+0

は、より多くのこのような何かを試してみてください。クラスはすでにポインタです。過度の間接化。パッケージを使用しない限り、これらのタイプのいずれかをモジュール境界に渡すことはできません。それは2017です。ショートストリングの使用をやめてください。 interopを理解できるように[mcve]を表示してください。 –

+0

私はあなたのために感じますが、ここには非常に多くの問題があり、どこから始めるべきかを知ることはほとんど不可能です。私はちょうどこれのためのエネルギーを持っていない –

答えて

1

私の問題は、レコードにShortStringはを保存した後、私はへの道を見つけるように見えることができないということですDLLプロシージャ内でTStringGridにアクセスします。

しないでください。それは悪いデザインです。

RTLとメモリマネージャの1つのインスタンスを共有するように、アプリケーションとDLLの両方をコンパイルしてランタイムパッケージを有効にしない限り、DLL境界を越えてオブジェクトにアクセスすることは安全ではありません。

DLLがあなたのUIを全く知らないのが最善です。 DLLがアプリケーションに情報を伝達する必要がある場合、DLLは、アプリケーションがハンドラを割り当てることができるコールバックイベントを定義し、DLLが必要なときにそのイベントを呼び出すことができます。アプリケーションが独自のUIを管理する方法を決定させる。

また、gameレコードにはポインタメンバーがありますが、ポインターをファイルに保持することはできません。そのメンバーを削除する必要があります。ポインタの使用を理解しないでください

library BibliotekaDLL; 

uses 
    System.SysUtils, 
    System.Classes, 
    Vcl.Dialogs; 

type 
    game = packed record 
    nazwa: shortstring; 
    wydawca: shortstring; 
    rokwyd: integer; 
    gatunek1: shortstring; 
    gatunek2: shortstring; 
    end; 

    gameCallback = procedure(var g: game; userData: Pointer); stdcall; 

procedure WyswietlListe(callback: gameCallback; userData: Pointer); stdcall; 
var 
    BazaDanych : File of game; 
    current: game; 
begin 
    AssignFile(BazaDanych, 'c:\Baza_Danych_Gier.dat'); 
    Reset(BazaDanych); 
    if IOResult <> 0 then 
    ShowMessage ('Baza Danych Nie Instnieje') 
    else 
    try 
    repeat 
     Read(BazaDanych, current); 
     if IOResult <> 0 then Break; 
     if Assigned(callback) then callback(current, userData); 
    until False; 
    finally 
    Close(BazaDanych); 
    end; 
end; 

exports 
    WyswietlListe; 

end. 

interface 

type 
    TForm1 = class(TForm) 
    Button2: TButton; 
    StringGrid1: TStringGrid; 
    procedure Button2Click(Sender: TObject); 
    end; 

var 
    Form1: TForm1; 

implementation 

type 
    game = packed record 
    nazwa: shortstring; 
    wydawca: shortstring; 
    rokwyd: integer; 
    gatunek1: shortstring; 
    gatunek2: shortstring; 
    end; 

    gameCallback = procedure(var g: game; userData: Pointer); stdcall; 

    pmyCallbackInfo = ^myCallbackInfo; 
    myCallbackInfo = record 
    Grid: TStringGrid; 
    FirstTime: Boolean; 
    end; 

procedure myCallback(var g: game; userData: Pointer); stdcall; 
var 
    row: Integer; 
begin 
    Grid := pmyCallbackInfo(userData).Grid; 

    // add a new row only if the initial non-fixed row is already filled... 
    if pmyCallbackInfo(userData).FirstTime then 
    pmyCallbackInfo(userData).FirstTime := False 
    else 
    Grid.RowCount := Grid.RowCount + 1; 

    row := Grid.RowCount - 1; 
    Grid.Cells[0, row] := g.nazwa; 
    Grid.Cells[1, row] := g.wydawca; 
    Grid.Cells[2, row] := IntToStr(g.rokwyd); 
    Grid.Cells[3, row] := g.gatunek1; 
    Grid.Cells[4, row] := g.gatunek2; 
end; 

procedure TForm1.Button2Click(Sender: TObject); 
var 
    DLLHandle : THandle; 
    WyswietlListe : procedure(callback: gameCallback; userData: Pointer); stdcall; 
    info: myCallbackInfo; 
begin 
    // clear the TStringGrid. However, it has an odd quirk 
    // that it requires at least 1 non-fixed row at all times... 
    // 
    StringGrid1.RowCount := StringGrid1.FixedRows + 1; 
    StringGrid1.Rows[StringGrid1.RowCount - 1].Clear; 

    DLLHandle := LoadLibrary('BibliotekaDLL.dll'); 
    if DLLHandle = 0 then raise Exception.Create(...); 
    try 
    @WyswietlListe := GetProcAddress(DLLHandle, 'WyswietlListe'); 
    if not Assigned(WyswietlListe) then raise Exception.Create('Nie Można Znaleźć Procedury w Bibliotece!'); 
    info.Grid := StringGrid1; 
    info.FirstTime := True; 
    WyswietlListe(@myCallback, @info); 
    finally 
    FreeLibrary(DLLHandle); 
    end; 
end; 
関連する問題