AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

DLL: Record aus DLL holen

Ein Thema von Die Muhkuh · begonnen am 24. Apr 2006 · letzter Beitrag vom 24. Apr 2006
Antwort Antwort
Benutzerbild von Die Muhkuh
Die Muhkuh

Registriert seit: 21. Aug 2003
7.332 Beiträge
 
Delphi 2009 Professional
 
#1

DLL: Record aus DLL holen

  Alt 24. Apr 2006, 17:02
Moin moin,

ich hab das ein kleines Problemchen mit meiner DLL.

[ Das Codegerümpel is unten ]

Also, los geht's. Ich hab in einer DLL eine Sprache drin. Diese Sprache ist über einen Record aufgebaut. Das Auslesen klappt, wie es soll (per Debugger überprüft). Dann füge ich das ja in meine ObjectList hinzu ([1]) (TLanguageManager = class(TobjectList). Wenn ich nun auf diese Language zugreife ([2]), steht danach im Record nur Mist drinne.

Bis zu Zeitpunkt von [1] stimmt alles noch. Aber bei [2] ist dann Chaos in dem Record.

[edit]
Ich kann auch noch in der Procedure SearchLanguages das hier schreiben:

 raise Exception.Create(Items['German'].LanguageInfo.lngDate); Da funktionierts einwandfrei...

[/edit]

Erstmal Aufbau der Records:

Delphi-Quellcode:
type
  TLanguageObj = record
    Caption: PChar;
    Hint: PChar;
  end;

  TLanguageInfoRec = record
    lngAuthor: PChar;
    lngLanguageVersion: PChar;
    lngProgramVersion: PChar;
    lngDate: PChar;
    lngLanguageName: PChar;
  end;

  TLangfrmMainRec = record
    lngmiFile: TLanguageObj;
    lngactClose: TLanguageObj;
  end;

  TLanguageRec = record
    lngfrmMain: TLangfrmMainRec;
  end;
So, dann DLL:

Delphi-Quellcode:
function GetLanguageRecord: TLanguageRec; stdcall;
begin
  Result.lngfrmMain.lngmiFile.Caption := 'Datei - DLL';
  Result.lngfrmMain.lngmiFile.Hint := 'Datei - DLL';

  Result.lngfrmMain.lngactClose.Caption := 'Programm beenden - DLL';
  Result.lngfrmMain.lngactClose.Hint := 'Beendet das Programm';
end;

function GetLanguageInfo: TLanguageInfoRec; stdcall;
begin
  Result.lngAuthor := 'Manuel Rauber';
  Result.lngLanguageVersion := '1.0';
  Result.lngProgramVersion := '0.1';
  Result.lngDate := '2006-04-24';
  Result.lngLanguageName := 'German';
end;

exports
  GetLanguageRecord,
  GetLanguageInfo;
Dann Auslesecode ( ):

Delphi-Quellcode:
procedure TLanguageManager.SearchLanguages;
var
  SR: TSearchRec;
  Lang: TLanguage;
begin
  inherited Clear;

  if FindFirst(GetLangDir + '*.dll', faAnyFile, SR) = 0 then
  begin
    repeat
      FDLLCommunicator.Filename := GetLangDir + SR.Name;
      Lang := TLanguage.Create(Self);
      Lang.LanguageInfo := FDLLCommunicator.GetLanguageInfo;
      Lang.LanguageRec := FDLLCommunicator.GetLanguage;
      inherited Add(Lang); //////////////////// [1]
    until FindNext(SR) <> 0;
  end;
end;
Passend dazu noch GetLanguageInfo:

Delphi-Quellcode:
function TLanguageDLLCommunicator.GetLanguageInfo: TLanguageInfoRec;
var
  func: TGetLanguageInfo;
begin
  if FOpened then
  begin
    @func := GetProcAddress(FHandle, 'GetLanguageInfo');

    if @func <> nil then
    begin
      Result := func;
    end;
  end
  else
    raise Exception.Create('DLL is not open');
end;
Und zu guter Letzt noch GetItem:

Delphi-Quellcode:
function TLanguageManager.GetItem(LangName: String): TLanguage;
var
  I: Integer;
begin
  for I := 0 to inherited Count - 1 do
  begin
    //////////////////// [2]
    if (TLanguage(inherited Items[I]).LanguageInfo.lngLanguageName = LangName) then
    begin
      Result := TLanguage(inherited Items[I]);
      Break;
    end;
  end;
end;
  Mit Zitat antworten Zitat
schöni

Registriert seit: 23. Jan 2005
Ort: Dresden
445 Beiträge
 
Delphi 7 Personal
 
#2

Re: DLL: Record aus DLL holen

  Alt 24. Apr 2006, 17:27
Hallo!

Hast Du die Recorddefinition sowohl in der Dll als auch in der Delphi Unit? Wenn sie nämlich in der Dll fehlt, wundert mich nix. Die Records müssen sowohl in der Dll als auch in der Delphi-Unit definiert sein.

schöni
Damit der Topf nicht explodiert, lässt man es ab und zu mal zischen.
  Mit Zitat antworten Zitat
Benutzerbild von Die Muhkuh
Die Muhkuh

Registriert seit: 21. Aug 2003
7.332 Beiträge
 
Delphi 2009 Professional
 
#3

Re: DLL: Record aus DLL holen

  Alt 24. Apr 2006, 17:28
Hi,

ich hab in der DLL die Unit eingebunden in der die Records definiert sind.

[edit] Vielleicht liegts ja auch an den PChars. Muss ich evtl. noch Speicher für die reservieren? Denn, wenn ich wieder auslesen, stehen irgendwelche Kästchen und komische Zeichen da [/edit]

[edit2] Ich sachmal so: Sobald die Procedure SearchLanguages fertig ist, steht nur noch Murks drinne [/edit2]
  Mit Zitat antworten Zitat
Frickeldrecktuxer_TM
(Gast)

n/a Beiträge
 
#4

Re: DLL: Record aus DLL holen

  Alt 24. Apr 2006, 18:35
Zitat von Spider:
[edit2] Ich sachmal so: Sobald die Procedure SearchLanguages fertig ist, steht nur noch Murks drinne [/edit2]
Darf ich raten? Der zuletzt eingetragene Eintrag stimmt?
Die Strings sind in der DLL als Konstanten eingetragen. Die Adresse dieser Konstanten reichst du nun an die PChars weiter. Das Auslesen funktioniert wunderbar, solange an diesen Adressen tatsächlich was brauchbares steht, also solange die DLL geladen ist. Durch deine Schleife wird die erste gefundene DLL geladen, abgearbeitet und anschließend die zweite geladen. Ich kenne die Klasse zu FDLLCommunicator nicht, aber ich nehme mal an, du gibst die DLL korrekt wieder frei. Entsprechend entfernst du die Daten, auf die deine PChars zeigen. Du solltest wirklich die Strings dauerhaft im Adressbereich deines Hauptprozesses sichtbar machen. Ich weiß nicht genau, wie GetMem() sich über Module-Grenzen hinweg verhält, aber eigentlich sollte es damit gehen, um in der DLL Speicher zu allokieren, den der Hauptprozess sieht.
  Mit Zitat antworten Zitat
Benutzerbild von Die Muhkuh
Die Muhkuh

Registriert seit: 21. Aug 2003
7.332 Beiträge
 
Delphi 2009 Professional
 
#5

Re: DLL: Record aus DLL holen

  Alt 24. Apr 2006, 18:44
Hier ist die komplette TLanguageDLLCommunicator-Klasse

Delphi-Quellcode:
{ TLanguageDLLCommunicator }

destructor TLanguageDLLCommunicator.Destroy;
begin
  FreeLibrary(FHandle);
  FOpened := false;
  
  inherited;
end;

function TLanguageDLLCommunicator.GetLanguageInfo: TLanguageInfoRec;
var
  func: TGetLanguageInfo;
begin
  if FOpened then
  begin
    @func := GetProcAddress(FHandle, 'GetLanguageInfo');

    if @func <> nil then
    begin
      Result := func;
    end;
  end
  else
    raise Exception.Create('DLL is not open');
end;

function TLanguageDLLCommunicator.GetLanguage: TLanguageRec;
var
  func: TGetLanguageRecord;
begin
  if FOpened then
  begin
    @func := GetProcAddress(FHandle, 'GetLanguageRecord');

    if @func <> nil then
    begin
      Result := func;
    end;
  end
  else
    raise Exception.Create('DLL is not open');
end;

procedure TLanguageDLLCommunicator.SetFileName(const Value: String);
begin
  try
    FreeLibrary(FHandle);
    FOpened := false;
  except
    { Do nothing }
  end;

  FFileName := Value;

  try
    FHandle := LoadLibrary(PChar(Value));

    if FHandle = 0 then
    begin
      raise Exception.Create('Can not load languagedll'#13#10+Value);
    end;

    FOpened := true;
  except
    raise Exception.Create('Can not load languagedll'#13#10+Value);
  end;
end;
Müsste ich GetMem für jeden einzelnen PChar aufrufen?
Wo müsste ich das dann aufrufen? In der DLL oder in meinem Programm?

[edit] Hast richtig geraten. Wenn ich nur eine DLL verwende, funktioniert das ganze Problemlos.

Könnte man nicht die Records für DLL -> Programm mit PChar machen, im Programm dann aber als String speichern?

Quasi zweimal den gleichen Records, nur verwendet das Programm Stringrecordun die DLL PChar-Records.
OK, geht nich... [/edit]
  Mit Zitat antworten Zitat
Benutzerbild von Die Muhkuh
Die Muhkuh

Registriert seit: 21. Aug 2003
7.332 Beiträge
 
Delphi 2009 Professional
 
#6

Re: DLL: Record aus DLL holen

  Alt 24. Apr 2006, 18:57
ok, ich hab jetzt mal auf ShortStrings umgestellt (eigentlich dürften mir 255 Zeichen langen). Damit funktioniert das Problemlos.

Falls jemand noch ne Idee hat, meine Ohren sind offen
  Mit Zitat antworten Zitat
Frickeldrecktuxer_TM
(Gast)

n/a Beiträge
 
#7

Re: DLL: Record aus DLL holen

  Alt 24. Apr 2006, 19:01
Zitat von Spider:
Müsste ich GetMem für jeden einzelnen PChar aufrufen?
Du kannst genausogut einen einzigen Speicherblock allokieren, der groß genug für alle Strings inklusive Nullterminator (einen für jeden String, logischerweise) ist, aller Strings der Reihe nach (inklusive Nullterminator) reinkopieren und die Pointer für das verwendete Record passend setzen. Dürfte wahrscheinlich sogar effizienter beim Speicher sein, es ist aber mindestens schneller, weil nur ein Speicherblock angefordert wird.

Zitat von Spider:
Wo müsste ich das dann aufrufen? In der DLL oder in meinem Programm?
Zitat von Frickeldrecktuxer_TM:
Ich weiß nicht genau, wie GetMem() sich über Module-Grenzen hinweg verhält, aber eigentlich sollte es damit gehen, um in der DLL Speicher zu allokieren, den der Hauptprozess sieht.
Probier's aus und schau im Debugger, ob der Speicher wieder freigegeben wird, wenn das Modul finalisiert wird.

Zitat von Spider:
Könnte man nicht die Records für DLL -> Programm mit PChar machen, im Programm dann aber als String speichern?
Kannste auch, dann brauchst du halt zwei Records, überlässt dafür aber dem Compiler das Kopieren des Speichers (Stimmt das? Schau zur Sicherheit lieber, ob beim Zuweisen UniqueString() aufgerufen wird). Ist genau das gleiche in grün, nur daß vorne noch 8 Byte extra für RefCount und StrLen stehen.
Für mich wäre es logischer, es bei einem Record zu belassen und meine Strings selber zu kopieren.

Zitat von Spider:
Delphi-Quellcode:
{ TLanguageDLLCommunicator }

procedure TLanguageDLLCommunicator.SetFileName(const Value: String);
begin
  try
    FreeLibrary(FHandle);
    FOpened := false;
  except
    { Do nothing } // argh
  end;

  FFileName := Value;

  try
    FHandle := LoadLibrary(PChar(Value));

    if FHandle = 0 then
    begin
      raise Exception.Create('Can not load languagedll'#13#10+Value);
    end;

    FOpened := true;
  except
    raise Exception.Create('Can not load languagedll'#13#10+Value); // argh
  end;
end;
Was ist das denn bitte? Die mit "argh" gekennzeichneten Stellen sind genau das, wie man's nicht macht.
Hinweis: Calls ins Win32-API erzeugen keine Exceptions. Wenn "FOpened := False" oder "FreeLibrary(FHandle)" eine Exception werfen, hast du ganz andere Probleme, die du auf keinen Fall mit einem leeren Except-Block zu schlucken hast. Genauso verhält es sich mit dem zweiten "argh". Dein Code sollte keine Exception verursachen, außer deine eigene. Die fängst du ab und wirfst sie nochmal? Lass den try-Müll da weg, der hat an dieser Stelle nichts zu suchen. Wenn das Exception-Handling nötig wird, hast du ein so massives Problem, daß es einfacher sein wird, dein System neu zu installieren, als nach einer Fehlerursache zu forschen.
  Mit Zitat antworten Zitat
Benutzerbild von Die Muhkuh
Die Muhkuh

Registriert seit: 21. Aug 2003
7.332 Beiträge
 
Delphi 2009 Professional
 
#8

Re: DLL: Record aus DLL holen

  Alt 24. Apr 2006, 19:06


Ok, hast ja recht... Ich werde es verbessern
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:00 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz