AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Delphi Übergabe von Interface an DLL führt zu AccessViolation
Thema durchsuchen
Ansicht
Themen-Optionen

Übergabe von Interface an DLL führt zu AccessViolation

Ein Thema von Aviator · begonnen am 7. Okt 2016 · letzter Beitrag vom 8. Okt 2016
Antwort Antwort
Seite 1 von 2  1 2      
Aviator

Registriert seit: 3. Jun 2010
1.611 Beiträge
 
Delphi 10.3 Rio
 
#1

Übergabe von Interface an DLL führt zu AccessViolation

  Alt 7. Okt 2016, 18:06
Hallo Delphianer,

ich mal wieder mit meinem DLL Problem. Ich habe jetzt angefangen meine DLL zu programmieren und stoße schon ziemlich direkt am Anfang auf einen Fehler.

Meine DLL exportiert zwei Funktionen. Beide geben eine Interface Instanz zurück. Das sollte ja noch kein Problem sein denke ich.

Mein aktueller SourceCode in der DPR der DLL die davon betroffen ist sieht so aus:

Delphi-Quellcode:
library DMSUserManager;

uses
  System.SysUtils,
  System.Classes,
  DMSUM.Manager in 'Source\Classes\DMSUM.Manager.pas',
  Common.Interfaces.Internal in '..\Common\Interfaces\Common.Interfaces.Internal.pas',
  Common.Interfaces in '..\Common\Interfaces\Common.Interfaces.pas',
  Common.Types in '..\Common\Types\Common.Types.pas';



{$R *.res}

function GetInstanceInt(DataBaseConnectionInfo: IDataBaseConnectionInfo): IDMSUserManager;
begin
  Result := TDMSUserManager.Create(DataBaseConnectionInfo) as IDMSUserManager;
end;

function GetInstanceExt(DataBaseConnectionInfo: IDataBaseConnectionInfo): IDMSUserExchanger;
begin
  Result := TDMSUserManager.Create(DataBaseConnectionInfo) as IDMSUserExchanger;
end;

exports
  GetInstanceInt,
  GetInstanceExt;

begin
end.
IDataBaseConnectionInfo ist wie folgt deklariert:

Delphi-Quellcode:
IDataBaseConnectionInfo = interface(IInterface)
['{5C829F64-F5D0-48B9-A7C7-B75A74C3AD7F}']
  procedure SetConnectionInfo(const AServer: PWideChar; const ADatabase: PWideChar; const AUserName: PWideChar;
    const APassword: PWideChar); stdcall;
  function GetConnectionString: PWideChar; stdcall;
end;
IDMSUserManager und IDMSUserExchanger sind so deklariert:

Delphi-Quellcode:
  IDMSUserExchanger = interface(IInterface)
  ['{96FE1197-EEC4-44D6-A305-E8C8FAE89484}']
    procedure FreeAllocatedMemory(var UserExchange: TUserExchange); stdcall; overload;
    procedure FreeAllocatedMemory(var UserExchange: array of TUserExchange); stdcall; overload;
    function GetActiveUserCount(var UserCount: Integer): Boolean; stdcall;
    function GetLastError: PWideChar; stdcall;
    function GetActiveUsers(const Index: Integer; var UserExchange: array of TUserExchange): Boolean; stdcall;
  end;

  IDMSUserManager = interface(IDMSUserExchanger)
  ['{0B695F23-B4E0-4FEA-9EFA-586B487F95B5}']
    function AddNewUser(var UserExchange: TUserExchange): Boolean; stdcall;
    function DeleteUser(const UserID: Integer): Boolean; stdcall;
    function GetAllUsers(var UserExchange: array of TUserExchange): Boolean; stdcall;
    function SetActivationState(const UserID: Integer; const Deactivated: Boolean): Boolean; stdcall;
  end;
Nun habe ich als Hostapplikation meine Anwendung hinterlegt und die von der DLL exportierte Methode GetInstanceInt() ausgeführt. Zuvor natürlich eine Instanz des IDataBaseConnectionInfo erzeugt und als Parameter übergeben. Ich vermute auch, dass hier der Fehler liegt. Nur weiß ich nicht wo ich ansetzen soll.

Hier noch mein SourceCode wie ich die DLL anspreche bzw. die GetInstance() Funktion aufrufe:

Delphi-Quellcode:
type
  TfrmDocuments = class(TForm)
  private
    ConData: IDataBaseConnectionInfo;
    Mgr: IDMSUserManager;
    ...
  public
    ...
  end;

implementation

procedure TfrmDocuments.btn1Click(Sender: TObject);
var
  cnt: Integer;
  ue: array of TUserExchange;
begin
  ConData := TConnectionStore.Create;
  ConData.SetConnectionInfo('_Server_', 'Dokumentenverwaltung', 'foo', 'bar');

  Mgr := GetInstanceInt(ConData);
  Mgr.GetActiveUserCount(cnt);

  SetLength(ue, cnt);
  if not Mgr.GetAllUsers(ue) then
    ShowMessage(Mgr.GetLastError);

end;
Ich habe bewusst die Variablen ConData und Mgr als privates Feld deklariert, hatte sie vorher aber auch schon direkt in der Procedure deklariert. Beides ergibt das selbe Ergebnis.

Die Fehlermeldung dich ich bekomme wenn die Zeile Mgr := GetInstanceInt(ConData); ausgeführt wird lautet wie folgt:

"Im Projekt DocuMentS.exe ist eine Exception der Klasse $C0000005 mit der Meldung 'access violation at 0x015bdd77: read of address 0x00000004' aufgetreten."

Ich habe auch schon diverse BreakPoints gesetzt und mir auch (obwohl ich mich damit null auskenne) das Disassembly Fenster angeschaut. Anbei mal ein Screenshot. Vielleicht kann ja hemand von euch etwas damit anfangen.

Es ist ein erster Test ob es so funktioniert wie ich mir das vorstelle. Also bitte nicht an den Variablen Namen stören. Aber wie man sieht funktioniert es leider nicht. Die Frage ist nur warum nicht. Ich hoffe jemand von euch kann mir helfen.
Miniaturansicht angehängter Grafiken
interfaceav.jpg  

Geändert von Daniel (24. Feb 2017 um 10:17 Uhr)
  Mit Zitat antworten Zitat
bepe

Registriert seit: 17. Okt 2006
119 Beiträge
 
#2

AW: Übergabe von Interface an DLL führt zu AccessViolation

  Alt 7. Okt 2016, 18:40
Bin gerade auf dem Sprung aber auf die Schnelle kommen mir zwei Dinge in den Sinn:

- deine beiden Funktionen benutzen die falsche Aufrufkonvention
- Delphi kennt überhaupt keine Funktionen

mfg,
bp
  Mit Zitat antworten Zitat
Fritzew

Registriert seit: 18. Nov 2015
Ort: Kehl
678 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: Übergabe von Interface an DLL führt zu AccessViolation

  Alt 7. Okt 2016, 19:24
Hallo,

als erstes solltest Du die
Exporte auch mit stdcall aufrufen. also

Delphi-Quellcode:
function GetInstanceInt(DataBaseConnectionInfo: IDataBaseConnectionInfo): IDMSUserManager; stdcall; external 'DMSUserManager.dll';
 function GetInstanceExt(DataBaseConnectionInfo: IDataBaseConnectionInfo): IDMSUserExchanger; stdcall; external 'DMSUserManager.dll';
natürlich auch in der Dll ändern.

von was sind Deine konkreten Klassen abgeleitet?


Gruss Fritz
Angehängte Dateien
Dateityp: zip Aviator.zip (13,2 KB, 1x aufgerufen)
Fritz Westermann
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.063 Beiträge
 
Delphi 12 Athens
 
#4

AW: Übergabe von Interface an DLL führt zu AccessViolation

  Alt 7. Okt 2016, 19:32
als erstes solltest Du die
Exporte auch mit stdcall aufrufen.
Nee, wieso denn?

Es ist nur wichtig, dass auf beiden Seiten die Schnittstellen gleich aussehn
und wenn hier EXE und DLL mit Delphi geschrieben sind, dann kann die Aufrufkonvention auch problemlos "register" bleiben.

Was man aber nicht machen darf, ist einen PWideChar wie einen String aussehn zu lassen.

DelphiStrings sind zwar intern zu PChar kompatibel (PChar(String) ist also OK), aber andersrum natürlich nicht (niemals String(PChar) ).

Und wenn in der DLL ein String in einen PChar gecastet wurde, dann darf der dennoch nicht zurück nach String gecastet werden.
* Die speicherverwaltung von DLL und EXE sind standardmäßig getrennt (jeder hat seine Eigene)
* und bei Strings gibt es den Sonderfall des Leerstrings, wo der PChar(String) -Cast auf eine Konstante mit dem Inhalt #0#0 umleitet.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu ( 7. Okt 2016 um 19:37 Uhr)
  Mit Zitat antworten Zitat
Fritzew

Registriert seit: 18. Nov 2015
Ort: Kehl
678 Beiträge
 
Delphi 11 Alexandria
 
#5

AW: Übergabe von Interface an DLL führt zu AccessViolation

  Alt 7. Okt 2016, 19:36
Zitat:
Es ist nur wichtig, dass auf beiden Seiten die Schnittstellen gleich aussehn
und wenn hier EXE und DLL mit Delphi geschrieben sind, dann kann die Aufrufkonvention auch problemlos "register" bleiben.
Der Meinung bin ich nicht. Eine Dll sollte soweit als möglich Compilerunabhängig sein.
Und wenn man das mit so etwas einfachem wie stdcall erreichen kann ist das schon mal gut.
Fritz Westermann
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.063 Beiträge
 
Delphi 12 Athens
 
#6

AW: Übergabe von Interface an DLL führt zu AccessViolation

  Alt 7. Okt 2016, 19:44
Auch andere Sprachen kennen viele der Konventionen, somit ist es nicht per se inkompatibel, zu anderen Sprachen.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Fritzew

Registriert seit: 18. Nov 2015
Ort: Kehl
678 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: Übergabe von Interface an DLL führt zu AccessViolation

  Alt 7. Okt 2016, 20:01
Nenn mir einen Win32 compiler (nicht Delphi / Fpc) der unter Win32 die Register Aufruf Konvention von Delphi kennt.
Ich lerne gerne dazu...
Fritz Westermann
  Mit Zitat antworten Zitat
Aviator

Registriert seit: 3. Jun 2010
1.611 Beiträge
 
Delphi 10.3 Rio
 
#8

AW: Übergabe von Interface an DLL führt zu AccessViolation

  Alt 7. Okt 2016, 20:23
Hallo Fritze,

danke dir.

Manchmal muss man nur mit der Nase drauf gestoßen werden. Die Aufrufkonvention stdcall hatte ich zwar in meinem Programm hinterlegt, aber nicht in der DLL. Jetzt flutscht es.

Nochmals vielen Dank!

Ich hoffe alle weiteren Fehler bekomme ich von selbst gelöst.
DelphiStrings sind zwar intern zu PChar kompatibel (PChar(String) ist also OK), aber andersrum natürlich nicht (niemals String(PChar) ).
Wie denn dann? Hast du ein Beispiel?
  Mit Zitat antworten Zitat
Fritzew

Registriert seit: 18. Nov 2015
Ort: Kehl
678 Beiträge
 
Delphi 11 Alexandria
 
#9

AW: Übergabe von Interface an DLL führt zu AccessViolation

  Alt 7. Okt 2016, 20:36
DelphiStrings sind zwar intern zu PChar kompatibel (PChar(String) ist also OK), aber andersrum natürlich nicht (niemals String(PChar) ).
Wie denn dann? Hast du ein Beispiel?
Das ist schlicht falsch. Der Delphi Compiler ersetzt deinen Cast String(Pchar) durch

procedure _UStrFromPWChar(var Dest: UnicodeString; Source: PWideChar); Beweis: mit debug dcu compilieren und in den cast mit f7 reinsteppen

Gruss Fritz
Fritz Westermann
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#10

AW: Übergabe von Interface an DLL führt zu AccessViolation

  Alt 7. Okt 2016, 20:37
DelphiStrings sind zwar intern zu PChar kompatibel (PChar(String) ist also OK), aber andersrum natürlich nicht (niemals String(PChar) ).
Wie denn dann? Hast du ein Beispiel?
Doch doch, das kannst du ruhig machen. Delphi Hilfe sagt zur StrPas Funktion beispielsweise
Zitat:
This function is provided for backwards compatibility only. To convert a null terminated string to an AnsiString or native Delphi language string, use a typecast or an assignment.
Und im Assembly sieht man auch, dass Delphi da Compiler Magic betreibt:
Code:
Unit1.pas.30: S := 'hallo';
005C9BA3 B8D89B5C00       mov eax,$005c9bd8
005C9BA8 8945F8           mov [ebp-$08],eax
Unit1.pas.31: T := String(S);
005C9BAB 8D45F4           lea eax,[ebp-$0c]
005C9BAE 8B55F8           mov edx,[ebp-$08]
005C9BB1 E8EE0AE4FF      call @UStrFromPWChar
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 06:03 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