Autor Beitrag
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Di 29.11.05 23:52 
Ich habe hier eine DLL, die mir COM-Objekte liefert. Irgendwo ist der Wurm drin und ich suche schon seit 2 Jahren, finde den Fehler einfach nicht. Neuschreiben geht nicht, weil 100.000 Zeilen. FastMM4, MemProof etc liefern keine Lösung.

Das Problem ist nun so eingekreist bzw. verlagert, das der Client beim Aufruf von CoUninitialize im Finalization-Teil von ComObjs auftritt, also nur dann, wenn das Programm sowieso terminiert. Nun, man soll ja nicht mauscheln, aber mittlerweile ist mir das sowas von egal, ich will nur diese dämlichen Fehler beim Beenden der Client-Anwendung unterdrücken, unterbinden, unsichtbar machen, mir ist das Schnurz! :autsch: ! Ich will nur, das mein Programm terminiert, und aus dem Speicher verschwindet.

Was kann man tun? Kann man einen Stub schreiben, der die Anwendung aufruft und diese dann einfach wegschnippelt (so, wie der Taskmanager, wenn man den Prozess abschiesst?)

Hilfe, helft einem armen alten Mann kurz vor Weihnachten, :bawling:

Ich verspreche, demjenigen, der mir eine von mir aus total perverse Lösung :think: anbietet, das hier: :flehan: und ich werde ihn niemals nie :mahn: und immer :beer: , wenn er mir übern Weg läuft und artig will ich auch sein und immer aufessen, aber bitte

heeeelllfttt mir!

:nut:

Und mein Motto ändere ich auch, dann das hier, stimmt nicht mehr: :schmoll:

_________________
Na denn, dann. Bis dann, denn.
digi_c
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1905

W98, XP
D7 PE, Lazarus, WinAVR
BeitragVerfasst: Mi 30.11.05 14:18 
Hehe so einen Post mit soo vielen Smileys habe ich ja lange nciht mehr gesehen :)

Das hört sich so an als ob da Speicher durch das ActiveX freigegeben werden soll, der garnicht dem ActiveX gehört sondern z.B. deinem Programm.

Die COM hast du auch geschrieben? Mit Delphi oder MSC++?

Wäre Code möglich bei welcher Anweisung der Anwendung/COM es kracht?
alzaimar Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Mi 30.11.05 14:32 
Hi,

Danke für die Anteilnahme. Gestern abend war ich mit den Nerven am Ende. In meiner Verzeiflung hab ich dann diesen Post geschrieben.

Ich habe den COM-Server selbst gebastelt.Eventuell ist der Fehler im Server, aber eine andere Anwendung läuft wesentlich stabiler Die Zeile, bei der es kracht ist im Client in ComObj.Pas:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
finalization
begin
  OleUninitializing := True;
  ComClassManagerVar.Free;
  SafeCallErrorProc := nil;
  DispCallByIDProc := nil;
  VarDispProc := nil;
  if NeedToUninitialize then CoUninitialize; // <-- Hier, na super
end;

Da ich nicht genau weiss, was CoUninitialize macht, weiss ich natürlich auch nicht genau, wo der Fehler ist. Ich vermute aber, das irgendwelche COM-Objekte noch nicht freigegeben sind.

Nochwas passiert: Normalerweise ist es doch so, das COM die garbagecollection übernimmt, also:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
Var
  Foo : IMyObject;

Begin
  Foo := MyServer.GetObject;
  Foo.Bar := 'Bla';
End// <--- implizites Foo._Release und das Objekt wird freigegeben.

Und Foo wird automatisch freigegeben, gell? Leider ist das an einigen Stellen nicht so. Ich vermute, das COM mit den Refcounts durcheinander kommt, aber bis ich das finde, vergehen wieder Jahre. Und ich hab Frau und Kinder und will die aufwachsen sehen. :wink:

Hier ist so eine Code-Stelle, bei der die Garbagecollection nicht klappt. Ich ziehe mir eine Liste von Dingern (aTemplates) und schreibe die Beschreibung ('Description') sowie eine ID jedes Objektes (in aXLS kopiert) in die Items-Property einer ComboBox (von DevExpress, deshalb 'edTemplates.Properties.Items'. Kann es sein, das hier der RefCount durcheinandergerät?
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
Var
  aTemplates : IdboObjects;
  clID, i : Integer;
  aXls : IdboObject;
  clCoil,
  aClass : IdboClass;

...
  With edTemplates.Properties.LookupItems do begin
    Clear;
    aTemplates := DM.cdb.dboObjects ['excelTemplate']; // Liste der EXCEL-Templates 
    AddObject('(use default)'nil);
    for i:=0 to aTemplates.Count - 1 do begin
      axls := aTemplates.Items [i];  // Das i.te Element 
      AddObject(aXLS.dboValue ['Description'].DisplayText, Pointer (aXLS.id));
      End;
    End;
  edTemplates.ItemIndex := 0;
end// <-- hier sollte aTemplates freigegeben werden. Tut es aber nicht



Wenn ich den Fehler finde, ist das Produkt so gut, das man damit mal hausieren gehen könnte, aber so ist es auf Haufen Mist. Es ist eine objektorientierte Datenbank mit eigener Engine und optimalen Recherchemöglichkeiten (Zeig mir alle Objekte, deren 'Fuss' grün ist oder die ein M5-'Gewinde' haben).

Ich hab mir jetzt einen 'Sentinel' geschrieben, der einfach im Hintergrund läuft und auf eine Message wartet. Dann schiesst er den Prozess, der ihm die Message geschickt hat, einfach ab. Meine Schrott-Anwendung sucht im FormClose des Hauptformulares also nach dem Sentinel und schickt ihm die Message 'Töte mich' zusammen mit dem eigenen Handle. So merkt der User wenigstens nicht mehr, das mein Programm Müll ist.

Wie gesagt, an sich läuft es, nur beim Beenden knallt es weg. Aber so richtig.

_________________
Na denn, dann. Bis dann, denn.
digi_c
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1905

W98, XP
D7 PE, Lazarus, WinAVR
BeitragVerfasst: Do 01.12.05 10:05 
Uff zu komplex für mich, da habe ich deutlich zu wenig Erfahrung mit COM :/
noidic
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 851

Win 2000 Win XP Vista
D7 Ent, SharpDevelop 2.2
BeitragVerfasst: Do 01.12.05 10:24 
Hi!

Ich hab zwar null Erfahrung mit eigenen COM-Servern, aber was mir bei ähnlichen Problemen mit MAPI geholfen hat, war vor das CoUninitialize ein Sleep von 100ms zu setzen. Vielleicht tuts das ja bei dem Problem auch?

Gruß

noidic

_________________
Bravery calls my name in the sound of the wind in the night...
alzaimar Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Do 01.12.05 10:34 
Probiere ich mal, danke

_________________
Na denn, dann. Bis dann, denn.
Horst_H
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1654
Erhaltene Danke: 244

WIN10,PuppyLinux
FreePascal,Lazarus
BeitragVerfasst: Do 01.12.05 11:32 
Hallo,

Ich habe mal bestimmte Verzeichnisse gesucht:
msdn.microsoft.com/l...alfolderlocation.asp

Dort steht etwas:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
Syntax

WINSHELLAPI HRESULT WINAPI SHGetSpecialFolderLocation(
  HWND hwndOwner, 
  int nFolder, 
  LPITEMIDLIST* ppidl 
);

und speziell:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
ppidl
 Pointer to a pointer to an item identifier list specifying the folder's
location relative to the root of the namespace (the desktop). The calling
application is responsible for freeing this pointer with the
shell's IMalloc interface (see SHGetMalloc).in
http://msdn.microsoft.com/library/en-us/wceappservices5/html/wce50lrfIMallocIUnknown.asp


Vielleicht musst Du den Speicher selbst freigeben:
IMalloc
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
When to Implement

In general, you should not implement IMalloc, instead use the COM 
implementation, which is guaranteed to be thread-safe in managing task
memory.
::::::::::::::::::::::::
You get a pointer to the COM task allocator object's IMalloc through a call
to the CoGetMalloc function.
::::::::::::::::::::::::
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceappservices5/html/wce50lrfcogetmalloc.asp


Gruss Horst
alzaimar Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Do 01.12.05 12:21 
Hallo Horst, Ich alloziiere im Laufe einer Session ca. 10.000 Objekte, die Alle, bis auf ein Paar, wieder freigegeben werden. COM implementiert eine eigene Garbage Collection: Sobald ein COM-Objekt nicht mehr referenziert wird, wird der Speicher freigegeben.

_________________
Na denn, dann. Bis dann, denn.
opfer.der.genauigkeit
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 754
Erhaltene Danke: 1



BeitragVerfasst: Do 01.12.05 13:05 
Hallo alzaimar,

ausblenden Delphi-Quelltext
1:
aTemplates := DM.cdb.dboObjects ['excelTemplate'];					


aTemplates ist eine Referenz auf das Objekt in DM.cdb.dboObjects.
D.h. nachdem die Routine abgearbeitet wurde in der du das benutzt, wird das Objekt natürlich nicht freigegeben, da es ja zu dboObjects gehört. Höchstens wird aTemplates auf nil gesetzt.

Evtl. ist das aber nicht der Fall und deshalb wird RefCount auch nicht dekrementiert???
Bin mir nicht sicher. Normalerweise würde inc( RefCount ) ja nur beim Aufruf über einen Konstruktor oder eine Initialisierung erfolgen. Oder irre ich? :roll:

Setz aTemplates doch mal auf nil.
Is evtl. nur n Schuß ins Blaue.. aber bevor du garnix mehr als Alternative hast... :)

Edit:// Oder die Referenz hängt noch in der Kompo von DevExpress fest. Weiß ja nicht, wo du das dort eingehängt hat. Aber meine Erfahrung war immer, daß die meisten Komponenten von DevExpress die Verwaltung der Objekte selber übernehmen.

_________________
Stellen Sie sich bitte Zirkusmusik vor.
alzaimar Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Do 01.12.05 15:49 
Ich glaube nicht, das die DevEx Komponente das Interface 'festhält'. cdb.dboObjects['Something'] liefert eine Liste von IdboObject Objekten, analog zu einem ADO.Recordset. Diese Liste (und die dadrin enthaltenen IdboObject Objekte, und die in jedem IdboObject enthaltenen IdboValue-Objekte) wird dynamisch erzeugt. Sie enthält im geposteten Beispiel für jeses Objekt zwei Werte: 'Description' und 'ID'.

Ich verwende die LookupItems-Eigenschaft (TStrings) einer Combobox um sowohl die 'Description' als auch die 'ID' zu speichern. Wenn man dann einen Eintrag auswählt, habe ich sofort die korrespondierende ID.

Ich kann mir nicht vorstellen, wo das Interface noch gehalten wird, außer, Delphi generiert bei einem Typecast Müll, und zwar hier:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
Var
  aXLS : IdboObject;

...
  Pointer(aXLS.ID);
...

Ich sach ja, es ist zum :bawling:

_________________
Na denn, dann. Bis dann, denn.
opfer.der.genauigkeit
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 754
Erhaltene Danke: 1



BeitragVerfasst: Do 01.12.05 16:26 
Bevor du in deinem großen Projekt noch weiter debuggst, bau doch einen kleinen Testprototypen auf um die Vorgehensweise nachvollziehen zu können.

Evtl. liegt dort garnicht der Wurm, sondern ist nur ein Seiteneffekt.

//Edit: Alternativ kannst du mir ja den Quellcode schicken, damit ich mal ne Runde mitdebuggen kann. :mrgreen:

_________________
Stellen Sie sich bitte Zirkusmusik vor.