Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Wenn of object, dann knallts!!! (https://www.delphipraxis.net/143245-wenn-object-dann-knallts.html)

cherry 12. Nov 2009 11:40


Wenn of object, dann knallts!!!
 
Hallo, ich habe folgende Funktion:

Delphi-Quellcode:
  type
    TGetLdapDomain = procedure(ldap: string) of object;
Delphi-Quellcode:
procedure GetLDAPDomains(CallBack: TGetLdapDomain);
var
  NSContainer  : IADsContainer;
  Enum         : IEnumVariant;
  hr           : integer;
  varArr       : OleVariant;
  lNumElements : ULONG;
  ADsItem      : IADs;
begin
  NSContainer := nil;
  Enum       := nil;
  ADsGetObject('LDAP:', IID_IADsContainer, NSContainer);
  hr := ADsBuildEnumerator(NSContainer, Enum);
  while SUCCEEDED(hr) do
  begin
    hr := ADsEnumerateNext(Enum, 1, varArr, lNumElements);
    if (lNumElements<=0) then Break;
    IDispatch(varArr).QueryInterface(IID_IADs, ADsItem);
    CallBack(ADsItem.ADsPath);
    //ADsItem.Class_;
  end;
  //if Enum <> nil then
   // hr := ADsFreeEnumerator(Enum);
  VariantClear(varArr);
end;
Wenn nun die CallBackFunktion of object ist, dann knallts... Wenn die CallBackFunktion nicht of Object mache, knallts nicht. Aber ich muss Sie of object machen, da sie zu einer Klasse gehören soll...

(mit knallt es meine ich eine Access Violation)

Ein weiteres Phänomen ist, wenn ich hr := ADsFreeEnumerator(Enum) wieder in den Code aufnehme, dann knallts so oder so...

An was kanns liegen? Testet doch die Procedur mal bei euch....

Danke schon mal im Voraus.
PS: Guten Appetit.

mkinzler 12. Nov 2009 11:44

Re: Wenn of object, dann knallts!!!
 
Meinst du vielleicht TObject?

himitsu 12. Nov 2009 11:47

Re: Wenn of object, dann knallts!!!
 
Wie rufst du denn GetLDAPDomains auf, bzw. wie ist die dort angegebene Prozedur definiert?

cherry 12. Nov 2009 12:26

Re: Wenn of object, dann knallts!!!
 
Zitat:

Zitat von himitsu
Wie rufst du denn GetLDAPDomains auf, bzw. wie ist die dort angegebene Prozedur definiert?

Delphi-Quellcode:
procedure TForm1.getLdapDomain(domain: string);
begin
  showMessage(domain);
end;

...

GetLDAPDomains(getLdapDomain);
die Message erscheint zwar noch korrekt, anschliessend gibts aber dann ne Access Violation...

Teekeks 12. Nov 2009 12:50

Re: Wenn of object, dann knallts!!!
 
Müsstest du nicht erst ne Zuweisung machen?
Und: Wie soll die denn zu ner Klasse gehören?
Ich blicke bei deinem Problem nicht ganz durch ^^

cherry 12. Nov 2009 12:59

Re: Wenn of object, dann knallts!!!
 
Probiert doch die Funktion einfach mal aus, dann seht ihr schon was ich meine... Ich kanns selber fast nicht erklären...

Wenn ich z.B

statt
Delphi-Quellcode:
procedure TForm1.getLdapDomain(domain: string);
begin
  showMessage(domain);
end;
dies mache:
Delphi-Quellcode:
procedure TForm1.getLdapDomain(domain: string);
begin
  myList.Add(domain);
end;
dann gehts auch, sobald ich aber dann auf die myList zugreiffen will, gibts ne böse Access Violation und ich weiss nicht woher die kommt!!!!

mleyen 12. Nov 2009 13:05

Re: Wenn of object, dann knallts!!!
 
Zitat:

Zitat von cherry
Delphi-Quellcode:
procedure TForm1.getLdapDomain(domain: string);
begin
  myList.Add(domain);
end;

Wie war das bei Callbacks? Man darf nicht auf private/objektspeziefische Sachen zugreifen? (Ich mein da was im Hinterkopf zu haben, arbeite damit aber zu wenig)

Naja, lass mal das "TForm1." weg und probier es dann nochmal mit globalen variablen.

cherry 12. Nov 2009 13:14

Re: Wenn of object, dann knallts!!!
 
Hmm... ist komisch. Ja es geht wenn die myList nicht TForm gehört, wie greiffe ich dann aber von einem andern Formular darauf zu?

Und das mit der CallBackFunction habe ich nur gemacht, weil es anders auch nicht geht. Die Procedure scheint nur dann keine Zugriffsverletzung zu geben, wenn ich keine listen oder variablen abfülle, die eben einer Klasse z.B. TForm1 angehören, egal ob mit Rückgabewert, var Patameter, Parameter oder eben CallBackFunction... irgendwo scheint etwas ganz Faul zu sein, aber was????

mleyen 12. Nov 2009 13:25

Re: Wenn of object, dann knallts!!!
 
Zitat:

Zitat von cherry
Hmm... ist komisch. Ja es geht wenn die myList nicht TForm gehört, wie greiffe ich dann aber von einem andern Formular darauf zu?

Die Frage hab mich mir damals auch gestellt. Nachher kam irgendwas komisches dabei raus. (Ich find das Projekt leider nicht mehr)

Aber stell dir das doch mal so vor: Du versuchst von einem Objekt auf eine private Variable von einem anderem Objekt zuzugreifen. Das geht nicht, nur bei den Callbackfunktionen beanstandet der Kompiler das nicht.

Soweit ich weiß hab ich damals eine globale Property von der Variable die ich in der CllBck-Mthd brauchte erstellt und dieser dann auch noch die Instanz des Objekts mitübergeben. So konnte ich dann in der Callback-Methode über diese Instanz auf die property zugreifen.

edit:
Also bei dir säh das dann so aus:
Delphi-Quellcode:
procedure getLdapDomain(domain: string; const TheForm: TForm1);
begin
  TheForm.myList.Add(domain);
end;
Kannst du ja mal testen. :wink:
Unschön, aber man hat wenigstens keine Unit-globale Variable. (nur den neuen Zugriff auf die eigentlich private Variable)
Eine sauberere Alternative würde mich auch interessieren. :stupid:

Delphianer 12. Nov 2009 13:52

Re: Wenn of object, dann knallts!!!
 
Mal ne böse Frage..

Existiert das Objekt eigentlich, zu dem die Callback-Methode gehört?

Grüße,

Lutz

cherry 12. Nov 2009 13:56

Re: Wenn of object, dann knallts!!!
 
Zitat:

Zitat von Delphianer
Mal ne böse Frage..

Existiert das Objekt eigentlich, zu dem die Callback-Methode gehört?

Grüße,

Lutz


Ja, TForm1.

Delphianer 12. Nov 2009 14:00

Re: Wenn of object, dann knallts!!!
 
Ich kann mir es zwar nicht richtig vorstellen, aber spielt Dir die Referenzzählung von ADsItem vielleicht einen Streich? Kannst Du mal einen stinknormalen String an Deine Callback übergeben?

Lutz

Delphianer 12. Nov 2009 14:02

Re: Wenn of object, dann knallts!!!
 
Gleich nochmal ich. Besser noch, mal alles auskommentieren und nur die Callback mit einem String aufrufen.

Lutz

cherry 12. Nov 2009 14:04

Re: Wenn of object, dann knallts!!!
 
Zitat:

Zitat von Delphianer
Ich kann mir es zwar nicht richtig vorstellen, aber spielt Dir die Referenzzählung von ADsItem vielleicht einen Streich? Kannst Du mal einen stinknormalen String an Deine Callback übergeben?

Lutz

So irgendwas verflixtes in der Art muss es sein, aber genau das ist es wahrscheinlich nicht. Hab mal die CBF so ausgeführt: CallBack('test'); -> selbes Problem

Delphianer 12. Nov 2009 14:14

Re: Wenn of object, dann knallts!!!
 
Kannst Du mal den Aufruf für

GetLDAPDomains

posten?

Lutz

cherry 12. Nov 2009 14:22

Re: Wenn of object, dann knallts!!!
 
Das habe ich doch schon?!.. wie ich aber sehe, konzentriert ihr euch zu fest auf die Thematik Callback... Das Problem tritt aber auch anders auf,
deshalb habe ich die Methode jetzt umgeschrieben:

Also nochmals von vorne... Ich habe diese Funktion:

Delphi-Quellcode:
function GetLDAPDomain: String;
var
  NSContainer  : IADsContainer;
  Enum         : IEnumVariant;
  hr           : integer;
  varArr       : OleVariant;
  lNumElements : ULONG;
  ADsItem      : IADs;
begin
  NSContainer := nil;
  Enum       := nil;
  ADsGetObject( 'LDAP:', IID_IADsContainer, NSContainer);
  hr := ADsBuildEnumerator(NSContainer, Enum);
  while SUCCEEDED(hr) do
  begin
    hr := ADsEnumerateNext(Enum, 1, varArr, lNumElements);
    if (lNumElements<=0) then Break;
    IDispatch(varArr).QueryInterface(IID_IADs, ADsItem);
    result := result + ADsItem.ADsPath + #13;
    //ADsItem.Class_;
  end;
end;
Wenn ich im Programm z.B. die Funktion so aufrufe:

public {von TForm1}
myVar: String;

Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin
  // es kracht schon so
  myVar := GetLDAPDomain;
end;
Sobald ich myVar direkt in FormCreate deklariere, oder ausserhalb der Klasse TForm, dann gehts... so habe ich aber von anderen Forms keinen Zugriff,,, und überhaupt, wieso sollte das ein Problem sein so wie ich es mache=????

Delphianer 12. Nov 2009 14:57

Re: Wenn of object, dann knallts!!!
 
Dann hast Du uns auf eine falsche Fährte geführt..

Ich sehe eine Reihe von potentiellen Fehlerquellen, die ich gern ausschließen würde:

1. erste Zeile: Result := '';
2. ADsGetObject liefert ein S_OK zurück, bitte auswerten
3. bei den anderen Funktionen bitte auch Rückgabewert auswerten

Lutz

cherry 12. Nov 2009 15:04

Re: Wenn of object, dann knallts!!!
 
Erstmal sorry für die Irreführung...
Hab die Funktion nun ein wenig angepasst:

Delphi-Quellcode:
function GetLDAPDomain: String;
var
  NSContainer  : IADsContainer;
  Enum         : IEnumVariant;
  hr           : integer;
  varArr       : OleVariant;
  lNumElements : ULONG;
  ADsItem      : IADs;
begin
  Result := '';
  NSContainer := nil;
  Enum       := nil;
  if ADsGetObject( 'LDAP:', IID_IADsContainer, NSContainer) = S_OK then
  begin
    hr := ADsBuildEnumerator(NSContainer, Enum);
    while SUCCEEDED(hr) do
    begin
      hr := ADsEnumerateNext(Enum, 1, varArr, lNumElements);
      if (lNumElements<=0) then Break;
      if IDispatch(varArr).QueryInterface(IID_IADs, ADsItem) = S_OK then
        result := result + ADsItem.ADsPath + #13;
    end;
  end;
end;
geht trotzdem nicht. Komisch ist ja, dass die Funktion das erwartete Resultat zurückgibt, wenn das result allerdings in eine Variable von einer Klasse gespeichert werden soll, gehts nicht. Bei einer Prozedur Variable klappts ja prima...

ich kreigs nicht raus?!

>> Ich würd auch gerne

Delphi-Quellcode:
  if Enum <> nil then
    hr := ADsFreeEnumerator(Enum);
  VariantClear(varArr);
verwenden, doch dann krachts auch beim speichern in eine Prozedurvariable... ??!?

Delphianer 12. Nov 2009 15:24

Re: Wenn of object, dann knallts!!!
 
Bei mir läuft's ohne Fehler durch. Allerdings ist bei mir lNumElements 0. Damit reduziert sich der Fehler auf die beiden Zeilen
Delphi-Quellcode:
if IDispatch(varArr).QueryInterface(IID_IADs, ADsItem) = S_OK then
        result := result + ADsItem.ADsPath + #13;
Lutz

[edit=mkinzler]Code-Tag durch Delphi-Tag ersetzt Mfg, mkinzler[/edit]

cherry 12. Nov 2009 15:27

Re: Wenn of object, dann knallts!!!
 
Hmmm... Hab mir eine DummyFunktion gebastelt:

Delphi-Quellcode:
function test: String;
var
  NSContainer  : IADsContainer;
begin
  result := 'test';
  NSContainer := nil;
  ADsGetObject( 'LDAP:', IID_IADsContainer, NSContainer);

then
und habe dabei festgestellt: Das Problem existiert auch so!
Du hast es bei dir getestet? -> hast du auch versucht den Rückgabewert in eine public oder private Variable von TForm1 zu speichern? denn da krachts bei mir...

Delphianer 12. Nov 2009 15:45

Re: Wenn of object, dann knallts!!!
 
Sorry, es kracht doch. Abhilfe könnte aber vielleicht die Zeile

CoInitialize(nil);

schaffen.

Lutz

cherry 12. Nov 2009 15:49

Re: Wenn of object, dann knallts!!!
 
Ne, macht ja auch keinen Sinn... soweit ich weiss ist das schon initialisiert wenn on Create aufgerufen wird..
Also ich habs auch getestet, geht nicht.

Ist aber schon krass komisch oder?

Delphianer 12. Nov 2009 16:17

Re: Wenn of object, dann knallts!!!
 
Sind Deine Funktionsprotypen stdcall oder safecall?

Lutz

cherry 12. Nov 2009 16:33

Re: Wenn of object, dann knallts!!!
 
ich verwende die units von agnisoft...
http://www.agnisoft.com/white_papers..._directory.asp

safecall !

x000x 12. Nov 2009 16:53

Re: Wenn of object, dann knallts!!!
 
Moin moin,

versuche doch mal bitte, Result erst nach dem "nil setzen" zu zuweisen, also so:
Delphi-Quellcode:
function GetLDAPDomain: String;
var
  NSContainer  : IADsContainer;
  Enum         : IEnumVariant;
  hr           : HRESULT;
  varArr       : OleVariant;
  lNumElements : ULONG;
  ADsItem      : IADs;
  res          : String;
begin
  res := '';
  NSContainer := nil;
  Enum       := nil;
  try
    if ADsGetObject( 'LDAP:', IID_IADsContainer, NSContainer) = S_OK then
    begin
      hr := ADsBuildEnumerator(NSContainer, Enum);
      while SUCCEEDED(hr) do
      begin
        hr := ADsEnumerateNext(Enum, 1, varArr, lNumElements);
        if (lNumElements<=0) then Break;
        if IDispatch(varArr).QueryInterface(IID_IADs, ADsItem) = S_OK then
          res := res + ADsItem.ADsPath + #13;
      end;
    end;
  finally
    Enum       := nil;
    NSContainer := nil;
    Result := res;
  end;
end;

Delphianer 12. Nov 2009 17:58

Re: Wenn of object, dann knallts!!!
 
Langsam gehen mir die Ideen aus.

Bei Kosch habe ich einen abweichenden Funktionsprototypen gefunden:

Delphi-Quellcode:
function ADsGetObject(lpszPathName: PWideChar; const riid: TGUID; out ppObject): HRESULT; Safecall;
Und dann noch diesen Artikel:

http://www.mail-archive.com/delphi@d.../msg14930.html

Ob das allerdings auch für Delphi2009 gilt?

Lutz

cherry 12. Nov 2009 19:10

Re: Wenn of object, dann knallts!!!
 
dann bin ich ja wohl nicht der einzige mit diesem Problem. Hehe.
Danke euch beiden. Ich habe jetzt Wochenende und Zuhause hab ich leider weder D2009 noch meine Projektdaten, also kann ich wohl oder übel die Test erst nächsten Montag durchführen.

Ich melde mich dann mit neuigkeiten, hats bei euch geklappt?

lg und schönes Wochenende...
#enemyleft

cherry 16. Nov 2009 13:03

Re: Wenn of object, dann knallts!!!
 
@x000x, @Delphianer

Das funktionert leider alles nichts, das Ergebnis ist immer dasselbe!
Bringts denn niemand zum laufen?

@x000x: Witzig ist ja, dass ich am Ende z.B. schreiben kann result := 'test'; und es passiert immer noch dasselbe Problem...

Was ist hier bloss faul?

Na, bringst Du es zum laufen? ;-)

EDIT:// Ich bin echt am Ende meiner Nerven! Wenn ich das ganze nicht im FormCreate oder FormShow der MainForm habe, sondern in FormCreate einer anderen Form, dann klappts ohne Einwände. Nur wenn ich AdsFreeEnumerator Verwenden will tritt dann der Fehler noch auf. Ich schiebs jetzt mal auf Microsoft ab und begnüge mich mit dem Workaround. Obwohl ich damit eigentlich nicht ganz glücklich bin.

Wenn also noch jemand eine Idee hat, bin ich immer noch sehr dankbar dafür. Habe übrigens im Internet viele ähnliche Threads gefunden, nur gelöst wurde er noch nie!

ele 21. Mai 2012 17:59

AW: Wenn of object, dann knallts!!!
 
Hallo,

Entschuldigung wenn ich hier einen alten Thread aufwärme...

Aber ich hatte eben das selbe Problem und ich glaube eine Lösung gefunden zu haben.

Das Problem lag an der Deklaration der Funktion ADsGetObject():

Delphi-Quellcode:
function ADsGetObject(lpszPathName:WideString; const riid:TGUID;
                      out ppObject):HRESULT; safecall; external 'activeds.dll';
Nach langem debuggen und pröbeln habe ich die deklaration abgeändert und siehe da: Keine AV mehr.

Delphi-Quellcode:
function ADsGetObject(lpszPathName:WideString; const riid:TGUID;
                      out ppObject):HRESULT; stdcall; external 'activeds.dll';
stdcall ist das Schlüsselwort.

Ich hoffe es hilft, auch wenn der Threaderzeuger schon längs nicht mehr an diesem Projekt arbeiten sollte...

Aphton 21. Mai 2012 18:25

AW: Wenn of object, dann knallts!!!
 
Mal zurück zur ersten Codeversion: Wie rufst du diese Funktion auf?
Zeig mir die Zeile!

Edit:
Och...
Klar -.-'
Bei Stdcall werden alle Parameter verkehrt herum auf den Stack gepusht, wohingegen bei der anderen Variante Register verwendet werden. Kehrt ADsGetObject zurück und beendet mit Ret X so poppt es wertvolle Register vom Stack, die es nicht darf (per SafeCall Deklaration), jedoch trotzdem tut (weil StdCall). Dadurch kommt es zu Problemen mit der Rücksprungsadresse die vor jeder Unterroutinenaufruf (SubProgramCall) auf den Stack gepusht wird...
Ach ach...

ele 21. Mai 2012 19:08

AW: Wenn of object, dann knallts!!!
 
Wenn ich das richtig verstehe, dann ist safecall hauptsächlich für COM wichtig. Für alle anderen Windows-API funktionen ist stdcall zu benutzen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:44 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