Autor Beitrag
todesgilde
Hält's aus hier
Beiträge: 11

Windows Server 2003
Haskel, Delphi 2005 Prof, C#, Java, VS 2003
BeitragVerfasst: Mi 14.02.07 17:41 
Hallo,

also ich habe mir eine DLL geschrieben und wollte nun diese dynamisch in meiner Anwendung laden.
Doch leider bekomme ich immer eine AV.

Meine DLL sieht so aus.

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
library utilities;



uses
  SysUtils,
  Classes,
  Windows;

{$R *.res}

Function getDrives(DriveTyp : Cardinal) : TStringList; Export;
  Var i : char;
      Temp : TStringList;
 Begin
  // result Field erstellen
  Temp := TStringList.Create;
  
  For i:= 'A' to 'Z' Do
   Begin
    if (GetDriveType(PAnsiChar(i)) = DriveTyp) Then
     Begin
      Temp.Add(i);
     End;


   End;

   result := temp;

 End;



exports
 getDrives index 1 name 'getDrives';



end.


Und die ladene Unit so:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
unit UDLLImport;

interface

uses Classes;

 // Einbinden zur Laufzeit
 Type TGetDriveFunction = function( DriveType : Cardinal) : TStringList;
 Function GetDrives( DriveType : Cardinal ) : TStringList;

implementation

uses
  Windows, SysUtils, Dialogs;

 Function GetDrives ( DriveType : Cardinal ) : TStringList;
   Var GetDriveFunction : TGetDriveFunction;
       Handle : THandle;
  Begin
   Handle := LoadLibrary(PCHAR(ExtractFilePath(ParamStr(0)) + 'utilities.dll')); // hier tritt AV auf

   If (Handle <> 0 ) Then
    Begin
     GetDriveFunction := GetProcAddress(Handle,'getDrives');
     If (@GetDriveFunction <> nil) Then
      Begin
       result := GetDriveFunction(DriveType);
      End
      Else
       result := nil;
     FreeLibrary(Handle);
    End
    Else
     Result := nil;

  End;

end.


Kann mir jemand helfen? Mach ich vielleicht Fehler beim Laden der DLL?

Moderiert von user profile iconmatze: Code- durch Delphi-Tags ersetzt
Bernhard Geyer
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 721
Erhaltene Danke: 3



BeitragVerfasst: Mi 14.02.07 22:46 
Ohne gemeinsamen Speichermanager von DLL und Exe muß es krachen.
Also entweder ShareMem einbinden oder z.B. FastMM verwenden.
HelgeLange
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 735
Erhaltene Danke: 6

Windows 7
Delphi7 - Delphi XE
BeitragVerfasst: Do 15.02.07 00:17 
Ausserdem ist es nicht gut, wenn Du in der DLL ein object samt Datenspeicher erstellst und dann die DLL schliesst. Auch solltest Du den Speicher immer dort freigeben, wo du ihn erstellt hast, also IN der DLL, wenn Du die StringList IN der DLL mit Create erzeigt hast.

Tipp von mir (ich arbeite viel mit StringListen, die in DLLs benutzt werden) :

Erstell in dem Fall die TStringList in Deiner exe und übergib sie an die DLL, weil beim TStringList.Add der code in der exe ausgeführt wird (da es dort erstellt wurde) und nicht in der DLL, auch wenn Du Dich gerade in der DLL befindest. Ansonsten brauchst Du ShareMem oder so nicht, da ShareMem nur benutzt wird, um String als Parameter selbst oder in Records als Parameter benutzt werden. Will sagen, wenn Du TStringList.Add machst, wird das Add dann ja nicht in der DLL ausgeführt, sondern in der exe, wo Du TStringList erzeugt hast.

Da siehst Du dann auch gleich den Fehler : Du hast die DLL zerstört, die auch das Basis-object mit seinen Methoden gehalten hat, und danach beim Anzeigen des Inhalts der StringList in deiner exe drauf zugegriffen. Auch wenn Du glück hast und die daten noch da sind, weil sie noch nicht überschrieben werden konnten, sind die Methoden schon entladen mit der DLL.

Hintergrundwissen : beim Erzeugen einer Instanz von einem Objekt wird eigentlich nur der Speicher für Variablen erzeugt (da diese seperat gefüllt werden müssen) die Methoden aber nicht, da diese von der Klasse zur Verfügung gestellt werden. Deswegen kannst Du auch auf die Methoden eines unitiialisiertes Objekt zugreifen, solange in der Methode nicht auf eine Objekt-Variable zugegriffen wird.

Weitere Ffragen dazu ? immer her damit :P

_________________
"Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
todesgilde Threadstarter
Hält's aus hier
Beiträge: 11

Windows Server 2003
Haskel, Delphi 2005 Prof, C#, Java, VS 2003
BeitragVerfasst: Do 15.02.07 13:32 
So danke euch, also das Problem habe ich jetzt wie es scheint gelöst.
Aber ich habe ein Problem mit der Funktion GetDriveType.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
For i:= 65 to 90 Do
   Begin
    temp := PChar(Chr(i) + ':\');
    If (GetDriveType(temp) = DriveTyp) Then
     Begin
      result.Add(temp);
     End;
   End;


Die GetDriveType Funktion liefert immer inaccesable im Debug Modus.
Und wenn ich das Programm so laufen lasse, bekomme ich keine Laufwerke zurück.

Wenn ich z.B.: GetDriveType(PCHAR(chr(x+65))) so aufrufen will, funktioniert der Cast anscheinend nicht.

Kann mir da jemand helfen.


EDIT
So habe das Problem gerade selber gelöst.

Und zwar so.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
Procedure getDrives(DriveTyp : Cardinal; Var result : TStringList);
  Var x : Byte;
      d : DWord;
      szDrive : array[0..5] of char;
 Begin
   d := GetLogicalDrives; 
   for x := 0 to 31 do
    begin
     If odd(d) Then
      Begin
       FillChar(szDrive, SizeOf(szDrive), #0);
       StrPCopy(szDrive, chr(x+65) + ':\');
       If GetDriveType(@szDrive) = DriveTyp Then
        result.add(chr(x+65));
      End;
     d := d shr 1;
   End; 
 End;


Moderiert von user profile iconKlabautermann: Code- durch Delphi-Tags ersetzt
HelgeLange
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 735
Erhaltene Danke: 6

Windows 7
Delphi7 - Delphi XE
BeitragVerfasst: Do 15.02.07 13:53 
hi, 2 Sachen :

1.) wie wurde das Problem mit den der StringList denn gelöst ? (interessant für den nächsten, der das gleiche Problem hat)

2.) man sollte für ein neues Problem einen neuen Thread machen

LG,

_________________
"Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
todesgilde Threadstarter
Hält's aus hier
Beiträge: 11

Windows Server 2003
Haskel, Delphi 2005 Prof, C#, Java, VS 2003
BeitragVerfasst: Do 15.02.07 15:36 
Gelöst habe ich das ganze Problem jetzt so.

DLL
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
library utilities;



uses
  ShareMem,
  SysUtils,
  Classes,
  Windows;

{$R *.res}

Procedure getDrives(DriveTyp : Cardinal; Var result : TStringList); stdcall;export;
  Var x : Byte;
      d : DWord;
      szDrive : array[0..5] of char;
 Begin
   d := GetLogicalDrives; 
   for x := 0 to 31 do
    begin
     If odd(d) Then
      Begin
       FillChar(szDrive, SizeOf(szDrive), #0);
       StrPCopy(szDrive, chr(x+65) + ':\');
       If GetDriveType(@szDrive) = DriveTyp Then
        result.add(chr(x+65));
      End;
     d := d shr 1;
   End; 
 End;



exports
 getDrives index 1 name 'getDrives';



end.


Import UNIT
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
unit UDLLImport;

interface

uses Classes;

 // Einbinden zur Laufzeit
 Type TGetDriveFunction = procedure( DriveType : Cardinal; Var result :  TStringList);stdcall;
 Procedure GetDrives( DriveType : Cardinal; Var Result : TStringList );

implementation

uses
  Windows, SysUtils, Dialogs;

 Procedure  GetDrives ( DriveType : Cardinal; Var Result : TStringList );
   Var GetDriveFunction : TGetDriveFunction;
       Handle : THandle;
       Temp   : TStringList;
  Begin
   Handle := LoadLibrary(PCHAR(ExtractFilePath(ParamStr(0)) + 'utilities.dll'));

   If (Handle <> 0 ) Then
    Begin
     @GetDriveFunction := GetProcAddress(Handle,'getDrives');
     If (@GetDriveFunction <> nil) Then
      Begin
       GetDriveFunction(DriveType,Result);
      End
      Else
       Result := nil;
     FreeLibrary(Handle);
    End
    Else
     Result := nil;

  End;

end.


Und in dem Hauptprogramm noch ShareMem einbinden.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
program Project1;

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

{$R *.res}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.



Also dann kanns weiter gehen, ich danke euch.
HelgeLange
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 735
Erhaltene Danke: 6

Windows 7
Delphi7 - Delphi XE
BeitragVerfasst: Do 15.02.07 15:45 
brauchst Du denn die ShareMem ? meiner Meinung nach nicht, weil String-Allokations/Deallokations-Routinen dort aufgerufen werden, wo die StringList erstellt wird. Ich habe in keiner meiner DLLs ShareMem eingebunden nd nie Probleme mit TStringList.

_________________
"Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
todesgilde Threadstarter
Hält's aus hier
Beiträge: 11

Windows Server 2003
Haskel, Delphi 2005 Prof, C#, Java, VS 2003
BeitragVerfasst: Do 15.02.07 22:35 
Ja ich habe es ohne probiert, aber da bekomme ich dann immer beim Programm beenden, ne Invalid Pointer Zugriffs Verletzung.

Sobald ich die ShareMem drinne habe funktioniert es einwandfrei.