Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Classe/Interface aus WinProc aufrufen (https://www.delphipraxis.net/193838-classe-interface-aus-winproc-aufrufen.html)

EWeiss 14. Sep 2017 09:19


Classe/Interface aus WinProc aufrufen
 
Bekomme meine Referenz Zähler nicht herunter.
Das einzige was ich mir vorstellen könnte was das Problem verursacht ist das ich das Interface aus der WinProc heraus aufrufe\muss.

bsp.
Delphi-Quellcode:
WM_COMMAND:
  begin
    ShowWindow(WinHandle, SW_HIDE);
    SkinPopUpMenu.DlgItem := wP;
    SkinPopUpMenu.DestroyWindow;
  end;
Mein Problem ist das ich die Winproc nicht in das Interface integrieren kann.
deshalb muss ich eine globale Variable definieren.
Eventuell ist das mein Problem mit dem Reverenz Zähler

Delphi-Quellcode:
SkinPopUpMenu : TSkinPopUpMenu;


gruss

jaenicke 14. Sep 2017 10:00

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

Zitat von EWeiss (Beitrag 1381115)
Delphi-Quellcode:
SkinPopUpMenu : TSkinPopUpMenu;

Diese Deklaration an sich ist schon problematisch. Ich denke du benutzt das als Interface. Dann muss die Variable auch vom Typ des Interfaces sein. Objekt- und Interfacereferenzen mischen geht meistens schief, wenn man nicht 100%ig weiß was man da tut.

EWeiss 14. Sep 2017 10:09

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

Zitat von jaenicke (Beitrag 1381120)
Zitat:

Zitat von EWeiss (Beitrag 1381115)
Delphi-Quellcode:
SkinPopUpMenu : TSkinPopUpMenu;

Diese Deklaration an sich ist schon problematisch. Ich denke du benutzt das als Interface. Dann muss die Variable auch vom Typ des Interfaces sein. Objekt- und Interfacereferenzen mischen geht meistens schief, wenn man nicht 100%ig weiß was man da tut.

Ok werde es ändern.

Delphi-Quellcode:
TSkinPopUpMenu = class(TInterfacedObject, ISkinPopUpMenu, ISkinPopUpMenuEx)

Delphi-Quellcode:
SkinPopUpMenu : ISkinPopUpMenuEx;


Edit:
Das ist erledigt meine Frage aber damit nicht beantwortet.

gruss

Aviator 14. Sep 2017 11:12

AW: Classe/Interface aus WinProc aufrufen
 
Ich hänge mich mal an die Frage mit ran, weil ich gerade ein ähnliches Problem habe. Meine DLL wird nämlich nicht sauber entladen, da irgendwo noch eine einzelne Referenz existiert, die ich aber ums verrecken nicht finden kann. Mich würde auch mal interessieren ob es irgendwie möglich ist, die Referenzen "aufzulösen". Also praktisch eine Art Liste in der ich sehe, wo ich meine Interface Instanz überall hin referenziert habe.

Ist so etwas möglich und wenn ja, wie?

EWeiss 14. Sep 2017 11:16

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

Ich hänge mich mal an die Frage mit ran
Bitte kein Problem :)

gruss

stahli 14. Sep 2017 11:35

AW: Classe/Interface aus WinProc aufrufen
 
Ist das hier die Fortsetzung von dem: http://www.delphipraxis.net/193802-o...ml#post1381069 ?

Du hast m.E. im Projekt als auch hier in Deinen Fragen zu wenig Ordnung bzw. Übersicht.

Wenn Du mit Interfaces arbeitest und die Referenzzählung nutzen willst, musst Du halt den Ablauf soweit überschauen, dass Du weißt wo Referenzen zugewiesen und ob die wieder aufgelöst werden.

Evtl. kann ein Tool wie EurekaLog helfen, hängende Referenzen zu finden.

Da Du aber vermutlich nur 2 oder 3 Referenzen verwendest, findet man die Stelle aber evtl. auch so.


Was hast Du denn geändert, nachdem Du im anderen Thread gesagt hattest, die Freigabe funktioniert?

Wenn Du z.B. danach noch eine Interfacevariable
Delphi-Quellcode:
MeineNeuePopupVariable: IMyPopup;
deklariert und zugewiesen hast, dann müsstest Du dieser Variablen auch wieder Nil zuweisen, damit Dein Objekt freigegeben wird.

So von außen ist das schwer zu beurteilen.

Vielleicht kannst Du die Ursache eingrenzen, wenn Du die Änderungen seit dem letzten Erfolgs-Post nochmal anschaust...

EWeiss 14. Sep 2017 11:47

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

Da Du aber vermutlich nur 2 oder 3 Referenzen verwendest, findet man die Stelle aber evtl. auch so.
Es wird nur eine Referenz verwendet ;)
Und die wird nicht freigegeben.

Ich habe nichts geändert im anderen Projekt wird diese korrekt freigegeben.
Das einzige was im anderen Projekt anders ist, ist das ich kein Submenu verwende.
Nur was nicht initialisiert wird (SubMenu) muss auch nicht freigegeben werden.

Zitat:

Ist das hier die Fortsetzung von dem: http://www.delphipraxis.net/193802-o...ml#post1381069 ?
Nein meine Frage bezog sich darauf ob es vielleicht an der Winproc liegen könnte da ich von hier SkinPopUpMenu aufrufen muss.
Aber im nachhinein dann dürfte im anderen Projekt die Referenz auch nicht freigegeben werden wenn es daran läge.


gruss

stahli 14. Sep 2017 12:10

AW: Classe/Interface aus WinProc aufrufen
 
Sorry, ich kann Deine Fragen nicht ausreichend nachvollziehen.

Sind das zwei Threads zu zwei verschiedenen Projekten?
Existiert das Problem der Nicht-Freigabe im anderen Thread noch - und wenn, dann in dem anderen Projekt oder nur in diesem hier?

Wenn die Fragestellung nicht eindeutig klar ist, kann man darauf natürlich auch nicht hilfreich antworten.

Aber ich orakle mal etwas...

Wenn Du eine Interfacevariable MyPopupMenu hast, und dann noch eine Interfacevariable MySubMenu dann könnten diese u.U. gegenseitige Referenzen aufeinander halten.

Also falls Du so etwas machen solltest wie:
MySubMenu.RegisterOwnerPopupMenu(MyPopupMenu) und darin dem MyPopupMenu auch das SubMenu zugewiesen wird,
dann halten beide eine Referenz aufeinander. Es kann dann keine automatische Freigabe mehr erfolgen, weil Interface1 in Interface2 referenziert wird und somit nicht freigegeben werden kann, weil noch eine Referenz existiert und andersrum auch.

Um das aufzulösen, müsste man eine der beiden zirkulären Referenzen auflösen (z.B. MySubMenu.UnregisterOwnerPopupMenu(MyPopupMenu)).

Vielleicht sind ja solche hängenden oder zirkulären Referenzen Dein Problem.

Wie gesagt, so von außen ist das schwer zu beurteilen.

EWeiss 14. Sep 2017 12:22

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

Sind das zwei Threads zu zwei verschiedenen Projekten?
Existiert das Problem der Nicht-Freigabe im anderen Thread noch - und wenn, dann in dem anderen Projekt oder nur in diesem hier?
Ich habe 2 Projekte

KVPlayer, OTTB

Beide verwenden das gleiche Interface.
KVPlayer mit SubMenus
OTTB ohne

KVPLayer gibt alle Reverenzen korrekt frei.
OTTB nicht.

So nun bin ich am Rätzeln denn eigentlich wäre das Problem verständlich wenn OTTB mit Submenu laufen würde.
Das gibt es hier aber nicht und trotzdem wird die Reverenz nicht freigegeben.

Also beide verwenden das selbe Interface das eine geht das andere nicht.

gruss

stahli 14. Sep 2017 12:33

AW: Classe/Interface aus WinProc aufrufen
 

Ah, ok.
Dann tippe ich wirklich auf gegenseitige Referenzierung.

Wenn das Submenu sein Hauptmenu kennt (also ein einem Property oder ein einer Liste speichert) und auch das Hauptmenu sein Submenü verwaltet (was ja zu vermuten ist ;-) ) dann wird genau dieses Problem vorliegen.


Quatsch. In der Eile hatte ich das falsch gelesen.
Also dann wir es im OTTB noch irgendeine Referenz geben, der nicht NIL zugewiesen wird.

Das zu finden kann aufwendig werden.

EWeiss 14. Sep 2017 12:42

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

Dann tippe ich wirklich auf gegenseitige Referenzierung.
Kann nicht sein denn wenn kein Submenu existiert dann wird diesbezüglich auch nichts Referenziert.
Keine einzige Variable die damit im Zusammenhang stehen könnte wird dann verwendet oder initialisiert.

gruss

stahli 14. Sep 2017 12:47

AW: Classe/Interface aus WinProc aufrufen
 
Habe das gerade korrigiert.

Ich schreibe hier schnell mal parallel während der Arbeit. Da bin ich manchmal nicht konzentriert genug. :-(

Dann musst Du mal schauen, wo da noch eine Referenz gehalten wird.

EWeiss 14. Sep 2017 13:26

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

Zitat von stahli (Beitrag 1381150)
Habe das gerade korrigiert.

Ich schreibe hier schnell mal parallel während der Arbeit. Da bin ich manchmal nicht konzentriert genug. :-(

Dann musst Du mal schauen, wo da noch eine Referenz gehalten wird.

Dank für deine Hilfe..
Werde ich wohl selbst fixen müssen wie auch immer. ;)

gruss

TiGü 14. Sep 2017 14:58

AW: Classe/Interface aus WinProc aufrufen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Delphi-Quellcode:
TSkinPopUpMenu = class(TInterfacedObject, ISkinPopUpMenu...)
   ...
  protected
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  public
   ...
end;

...

function TSkinPopUpMenu._AddRef: Integer;
begin
  Result := inherited _AddRef;
end;

function TSkinPopUpMenu._Release: Integer;
begin
  Result := inherited _Release;
end;
Dann in den eigenen _AddRef und _Release Haltepunkte setzen und vergleichen.
Irgendwo gibt es das Ungleichgewicht.

Fortgeschrittenen-Tipp:
Haltepunkte setzen aber in den Eigenschafen Break/Anhalten deaktivieren und den Call Stack mitloggen in der Ereignisanzeige:

EWeiss 14. Sep 2017 15:08

AW: Classe/Interface aus WinProc aufrufen
 
Danke werde das mal testen obwohl _AddRef , _Release eigentlich geerbt werden :)

gruss

Neutral General 14. Sep 2017 15:09

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

Zitat von EWeiss (Beitrag 1381180)
Danke werde das mal testen obwohl _AddRef , _Release eigentlich geerbt werden :)

Die Ableitung ist ja dafür da, dass du Breakpoints setzen kannst..

EWeiss 14. Sep 2017 15:19

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

Zitat von Neutral General (Beitrag 1381181)
Zitat:

Zitat von EWeiss (Beitrag 1381180)
Danke werde das mal testen obwohl _AddRef , _Release eigentlich geerbt werden :)

Die Ableitung ist ja dafür da, dass du Breakpoints setzen kannst..

Ja habe ich schon verstanden .. Danke.

gruss

stahli 14. Sep 2017 15:31

AW: Classe/Interface aus WinProc aufrufen
 
Ich hätte das auch schon vorgeschlagen, dachte aber, das ginge nicht, weil _AddRef ja nicht virtuell ist und somit nicht überschrieben werden kann...

Gibt es (zum Verständnis) eine Erklärung, warum das so funktioniert?

Zacherl 14. Sep 2017 15:59

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

Zitat von stahli (Beitrag 1381185)
Ich hätte das auch schon vorgeschlagen, dachte aber, das ginge nicht, weil _AddRef ja nicht virtuell ist und somit nicht überschrieben werden kann...

Gibt es (zum Verständnis) eine Erklärung, warum das so funktioniert?

Sämtliche Methoden, die du in einem Interface deklarierst, sind automatisch
Delphi-Quellcode:
virtual
(und
Delphi-Quellcode:
abstract
).
Delphi-Quellcode:
_AddRef
,
Delphi-Quellcode:
_Release
und
Delphi-Quellcode:
QueryInterface
werden von Delphi automatisch zu jedem Interface hinzugefügt, um die COM Kompatibilität zu gewährleisten.

Im Grunde sind COM Interfaces auch lediglich Klassen, welche mindestens die oben genannten virtuellen Methoden besitzen. Unter C++ sieht man das ganz schön, denn da ist das Basisinterface MSDN-Library durchsuchenIUnknown einfach als normale Klasse mit den entsprechenden 3 virtuellen Methoden deklariert (eine Unterscheidung zwischen
Delphi-Quellcode:
class
und
Delphi-Quellcode:
interface
gibt es hier gar nicht). Die Unterscheidung - wie man sie in Delphi hat - ist vermutlich nur vorhanden, weil Delphi die Interfaces ja tatsächlich auch unterschiedlich behandelt (automatischer RefCount und Freigabe, etc). In anderen Sprachen hat man dieses Verhalten nicht (man muss manuell
Delphi-Quellcode:
_AddRef
aufrufen, sobald man eine neue Referenz erzeugt bzw. Wrapperklassen verwenden, die das für einen übernehmen).

stahli 14. Sep 2017 16:02

AW: Classe/Interface aus WinProc aufrufen
 
Oha, vielen Dank! Wichtiger Hinweis!

EWeiss 14. Sep 2017 16:17

AW: Classe/Interface aus WinProc aufrufen
 
Also beim Start habe ich 3 Referenzen dann wird einmalig _Release aufgerufen bleiben 2. Dann wird das Menu angezeigt.

Beim beenden jedoch wird nicht einmal _Release aufgerufen und SkinPopUpMenu ist nicht Nil.

Habe meine Funktion mal geändert zum initialisieren rufe nicht mehr
Delphi-Quellcode:
result := TSkinPopUpMenu.Create


von außen auf sondern diese.
Delphi-Quellcode:
function CTRL_PopUpMenuCreate(callback: POPUPSTATECALLBACK): ISkinPopUpMenu; stdcall;
begin

  result := InitPopUpMenu();
  PopUpCallback := callback;
end;
danach
Delphi-Quellcode:
function InitPopUpMenu: ISkinPopUpMenu;
begin

  if SkinPopUpMenu = nil then
    SkinPopUpMenu := TSkinPopUpMenu.Create;

  result := SkinPopUpMenu as ISkinPopUpMenu;
end;
und in create
Delphi-Quellcode:
constructor TSkinPopUpMenu.Create;
begin
  inherited Create;

//  SkinPopUpMenu := self;
  ItemEnabled := True;
  SideBarCount := 0;
  ButtonCount := 0;
  SubMenuHandleCount := 0;
  FHPopupWindow := 0;
  gP.ProgManHandle := FindWindow('Progman', 'Program Manager');
end;
Delphi-Quellcode:
 
var
  SkinPopUpMenu : ISkinPopUpMenuEx;
verstehe es nicht.

Die Funktionen werden alle entladen bzw.. freigegeben. Hilft niemandem weiter nur zur Info.
Und das funktioniert alles in meinem KVPlayer.
Delphi-Quellcode:
procedure TSkinPopUpMenu.DestroyWindow;
var
  IntI: Integer;
  hResource: HBitmap;
begin

  UnSubClass(gP.ParentHandle);

  KillTimer(Handle, SKAERO_AERO_TIMER);
  KillTimer(Handle, POPUP_TIMER);
  // Alle Skinresourcen freigeben.
  if SubMenuHandleCount > 0 then
    for IntI := 0 to SubMenuHandleCount - 1 do
      SkinEngine.DestroyWindowResource(SubMenuWindow[IntI].Handle);

  // Privaten font freigeben
  if Assigned(FPrivateFont) then
    GdipCheck(GdipDeletePrivateFontCollection(FPrivateFont));

  // erstellte Button freigeben
  if ButtonCount > 0 then
  begin
    for IntI := 0 to ButtonCount - 1 do
    begin
      btnMenu[IntI].DestroyWindow;
      btnMenu[IntI] := nil;
    end;
    FillChar(btnMenu, ButtonCount, 0);
    ButtonCount := 0;
  end;

  // Sidebar resourcen freigeben
  if SideBarCount > 0 then
  begin
    for IntI := 0 to SideBarCount - 1 do
    begin
      SideBarFrame[IntI].DestroyWindow;
      SideBarFrame[IntI] := nil;
    end;
    FillChar(SideBarFrame, SideBarCount, 0);
    SideBarCount := 0;
  end;

  hResource := SkinEngine.GetPaintBitmap(SkinPopUpMenu.Handle);
  DeleteObject(hResource);

  if SubMenuHandleCount > 0 then
  begin
    for IntI := 0 to SubMenuHandleCount - 1 do
      if Windows.DestroyWindow(SubMenuWindow[IntI].Handle) then
        SubMenuWindow[IntI].Handle := 0;

    FillChar(SubMenuWindow, SubMenuHandleCount, 0);
  end;

  if Windows.DestroyWindow(Handle) then
    UnRegisterClass(wc.lpszClassName, hInstance);

  // Skinresource des Hauptfenster freigeben
  SkinEngine.DestroyWindowResource(Handle);

  // TODO
  // FillChar(SkinPopUpMenu, SizeOf(SkinPopUpMenu), 0);

  if not Assigned(SkinPopUpMenu) then
    PopUpCallback(OnPopupDestroyed);

end;
gruss

stahli 14. Sep 2017 16:27

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

Zitat von EWeiss (Beitrag 1381190)
... SkinPopUpMenu ist nicht Nil ...

Das sollte doch in der Callback-Methode gemacht werden - oder?
Wird die ausgeführt?
Wenn ja, müsste später ja SkinPopUpMenu wieder etwas zugewiesen werden.
Wenn nein, dann musst Du prüfen, warum nicht.

EWeiss 14. Sep 2017 16:35

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

Zitat von stahli (Beitrag 1381192)
Zitat:

Zitat von EWeiss (Beitrag 1381190)
... SkinPopUpMenu ist nicht Nil ...

Das sollte doch in der Callback-Methode gemacht werden - oder?
Wird die ausgeführt?
Wenn ja, müsste später ja SkinPopUpMenu wieder etwas zugewiesen werden.
Wenn nein, dann musst Du prüfen, warum nicht.

Ja die wird ausgeführt in der Main Application da hat aber die DLL nichts von.
Und das SkinPopUpMenu(DLL) PopUpMenu(Anwendung) muss vorher schon Nil sein bevor ich die Callback abschicke.

Und das ist auch so im KVPlayer aber nicht in OTTB.

gruss

EWeiss 14. Sep 2017 16:42

AW: Classe/Interface aus WinProc aufrufen
 
Die Anwendung fordert das Interface an.

Delphi-Quellcode:
  PopUpMenu := CTRL_PopUpMenuCreate(PopUpCallback);
Delphi-Quellcode:
procedure TMainApp.CreatePopUpMenu(WinHandle: HWND);
var
  PrivateFont: PWideChar;
begin
  PopUpMenu := CTRL_PopUpMenuCreate(PopUpCallback);
  PopUpMenu.Width := CLIENT_WIDTH;
  PopUpMenu.Height := CLIENT_HEIGHT;
  PopUpMenu.SkinConfigFile := PWideChar(FolderResource + 'PopUpWindow\OTTB.ske');
  PopUpMenu.UseVistaCrystal := true;
  PopUpMenu.UseVistaBlur := false;
  PopUpMenu.UseSideBar := True;
  PopUpMenu.SideBarImgPath := '';
  PopUpMenu.SelectedImgPath := FolderResource + 'PopUpWindow\MEN_Select.png';
  PopUpMenu.IconArrowPath := '';
  PopUpMenu.SeperatorImgPath := '';
  PopUpMenu.SideBarCaption := 'Over the TaskBar';
  PopUpMenu.SideBarCaptionLeft := 12;
  PopUpMenu.SideBarCaptionTop := 198;
  PopUpMenu.ImageStateMax := 0;
  PopUpMenu.ItemHeight := 20;
  PopUpMenu.ItemWidth := 190;
  PopUpMenu.ItemLeft := 29;
  PopUpMenu.ItemShadow := 1;
  PopUpMenu.ItemTextLeft := 20;

  hPopUpHandle := PopUpMenu.CreatePopUpMenu(WinHandle);
  if hPopUpHandle <> 0 then
  begin
    AppendMenu(hPopUpHandle);

    PrivateFont := PWideChar(FolderResource + 'PopUpWindow\OTTB.ttf');
    PopUpMenu.FontName := 'Nasalization Free';
    PopUpMenu.FontSize := 14;
    PopUpMenu.CreatePrivateFont(PrivateFont);

    gP.hPopUpMenu := hPopUpHandle;
  end;
end;
Anschließend werden die Variablen an das Interface der DLL übergeben.
Delphi-Quellcode:
procedure TMainApp.AppendMenu(hMain: HWND);
var
  Text: PWideChar;

procedure Append(Handle: HWND; ItemShadow: integer; ItemIconPath: WideString;
  ItemToolTip: PWideChar; ItemHiliteColor: COLORREF; ItemTextAlligment: TTextAlligment;
  Top: integer; Flags, DlgItemID: UINT; Text: PWideChar; Enabled: BOOL = True);
begin
  PopUpMenu.ItemShadow := ItemShadow;
  PopUpMenu.ItemIconPath := ItemIconPath;
  PopUpMenu.ItemToolTip := ItemToolTip;
  PopUpMenu.ItemHiliteColor := ItemHiliteColor;
  PopUpMenu.ItemTextAlligment := ItemTextAlligment;
  PopUpMenu.ItemTop := Top;
  PopUpMenu.ItemEnabled := Enabled;
  PopUpMenu.AppendMenu(Handle, Flags, DlgItemID, Text);
end;

begin

  panBackgoundFrame := CTRL_FrameButtonCreate();
  panBackgoundFrame.ImagePath := SKAERO_FOLDER + 'Frame.png';
  panBackgoundFrame.Left := 9;
  panBackgoundFrame.Top := 9;
  panBackgoundFrame.Width := 210;
  panBackgoundFrame.Height := 340;
  panBackgoundFrame.DlgItemID := ID_BACKGROUNDFRAME;
  panBackgoundFrame.ImageStateMax := 0;
  panBackgoundFrame.Enabled := false;
  panBackgoundFrame.Visible := True;
  panBackgoundFrame.CreateWindow(hMain);
  SKAERO_SetAnchorMode(panBackgoundFrame.Handle, ANCHOR_HEIGHT_WIDTH);
  SKAERO_SetZorder(panBackgoundFrame.Handle, HWND_TOP);

  // About
  Append(PopUpMenu.Handle, 1, '', 'Oops...' + CHR(13) + 'Are they in the wrong place?',
    SKAERO_BTNTEXTCOLOR, Left, 9, MF_OWNERDRAW, IDM_About, 'About');

  // Icon frame
  Append(PopUpMenu.Handle, 1, '', '', SKAERO_BTNTEXTCOLOR, Left, 49, MF_OWNERDRAW, IDM_IconFrame,
    'Icon frame');

  // Background layer
  Append(PopUpMenu.Handle, 1, '', '', SKAERO_BTNTEXTCOLOR, Left, 69, MF_OWNERDRAW, IDM_IconBack,
    'Background layer');

  // Change Wallpaper
  Append(PopUpMenu.Handle, 1, '', '', SKAERO_BTNTEXTCOLOR, Left, 89, MF_OWNERDRAW, IDM_Wallpaper,
    'Change Wallpaper');

  // Shortcut
  if gP.ShortCutVisible then
    Text := 'Hide shor cut'
  else
  Text := 'Show short cut';
  Append(PopUpMenu.Handle, 1, '', '', SKAERO_BTNTEXTCOLOR, Left, 129, MF_OWNERDRAW, IDM_ShortCut,
    Text);

  // Sound
  if gP.SoundActive then
    Text := 'Disable sound'
  else
  Text := 'Enable sound';
  Append(PopUpMenu.Handle, 1, '', '', SKAERO_BTNTEXTCOLOR, Left, 169, MF_OWNERDRAW, IDM_Sound,
    Text);

  // Build Config file
  Append(PopUpMenu.Handle, 1, '', '', SKAERO_BTNTEXTCOLOR, Left, 209, MF_OWNERDRAW, IDM_BuildCONFIG,
    'Build Config file');

  // Edit Config file
  Append(PopUpMenu.Handle, 1, '', '', SKAERO_BTNTEXTCOLOR, Left, 229, MF_OWNERDRAW, IDM_Edit,
    'Edit Config file');

  // Cleanup Config file
  Append(PopUpMenu.Handle, 1, '', '', SKAERO_BTNTEXTCOLOR, Left, 249, MF_OWNERDRAW, IDM_Cleanup,
    'Cleanup Config file');

  // Restart OverTheTaskBar
  Append(PopUpMenu.Handle, 1, '', '', SKAERO_BTNTEXTCOLOR, Left, 269, MF_OWNERDRAW, IDM_Restart,
    'Restart OverTheTaskBar');

  // Portable App
  if gP.Portable then
    Text := 'Disable Portable App'
  else
  Text := 'Enable Portable App';
  Append(PopUpMenu.Handle, 1, '', '', SKAERO_BTNTEXTCOLOR, Left, 309, MF_OWNERDRAW, IDM_PORTABLE,
    Text);

  // Close OverTheTaskBar
  Append(PopUpMenu.Handle, 1, '', '', SKAERO_BTNTEXTCOLOR, Left, 329, MF_OWNERDRAW, IDM_Close,
  'Close OverTheTaskBar');

end;
diese übernimmt nun das Zeichen und alle anderen dinge die mit dem Menu zu tun haben.
Das war's.

Aber entladen wird das Interface nicht.
Warum habe ich schon gesagt.

wird die Callback abgefeuert
Delphi-Quellcode:
procedure PopUpCallback(PopUpState: TPopUpState); stdcall;
begin
  case PopUpState of
    OnPopupDestroyed:
      PopUpMenu := nil;
  end;
end;
wird nur das PopUpMenu der Anwendung auf Nil gesetzt.
Das Interface in der DLL sollte dann schon NIL sein.

EDIT:
Das Menu wird dann in der WinProc gestartet.
Delphi-Quellcode:
    WM_RBUTTONDOWN:
      begin
        if PopUpMenu <> nil then
          PopUpMenu.DestroyWindow;

        nObjectID := MainApp.GetMouseMoveSpriteID(WinHandle, lpX, lpY);
        if nObjectID = 0 then
        begin

          SKAERO_CONFIG_ShadowColor(SKAERO_ColorARGB(255, RGB(0, 0, 0)), SKAERO_WRITE);
          KillTimer(MainHandle, 1);
          MainApp.CreatePopupMenu(WinHandle);

          GetCursorPos(P);
          GetWindowRect(gP.hPopUpMenu, Rect);
          ClientToScreen(gP.hPopUpMenu, P);

          MenuWahl := PopUpMenu.TrackPopupMenu(gP.hPopUpMenu, P.X - 7, (P.Y - Rect.Bottom) + 9,
            Rect.Right, Rect.Bottom);

          if MenuWahl then
            SendMessage(WinHandle, WM_COMMAND, Makelong(word(MenuWahl), 0), 0);
Wenn man zweimal hintereinander den rechten Button klickt wird das Menu über PopUpMenu.DestroyWindow; zerstört.
Andernfalls wird es in der DLL beendet.

gruss

stahli 14. Sep 2017 18:03

AW: Classe/Interface aus WinProc aufrufen
 
Schwierig nachzuvollziehen, finde ich.

Auf DLL-Seite ist das Problem, dass "SkinPopUpMenu" nicht Nil ist?
Delphi-Quellcode:
  if not Assigned(SkinPopUpMenu) then
     PopUpCallback(OnPopupDestroyed);
Der Callback wird aber auf Anwendungsseite ausgeführt?
Dann muss die obige Anweisung ja ausgeführt worden sein.

Wenn SkinPopUpMenu nicht Nil ist, müsstest Du Nil zuweisen - das kann nicht das Problem sein.
Wird vielleicht SkinPopUpMenu erst mal auf Nil gesetzt und dann nochmal neu durch irgendeine unbeabsichtigte Reaktion wieder zugewiesen?

Kannst Du das Problem genau auf einer Seite eingrenzen?

EWeiss 14. Sep 2017 18:09

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

Auf DLL-Seite ist das Problem, dass "SkinPopUpMenu" nicht Nil ist?
richtig deshalb kann ich auch kein Callback schicken.
Das macht nur sinn wenn in der DLL das Interface Nil ist vorher kann ich das in der Anwendung nicht löschen.

Zitat:

Wird vielleicht SkinPopUpMenu erst mal auf Nil gesetzt und dann nochmal neu durch irgendeine unbeabsichtigte Reaktion wieder zugewiesen?
Nein denn _Release wird nicht aufgerufen.

Zitat:

Der Callback wird aber auf Anwendungsseite ausgeführt?
Nein kann ich nicht schicken.. ansonsten ja wenn das Interface in der DLL Nil ist funktioniert das Callback.

Aus der DLL heraus wenn SkinPopUpMenu Nil ist

gruss

stahli 14. Sep 2017 19:10

AW: Classe/Interface aus WinProc aufrufen
 
Ok.
Delphi-Quellcode:
  if not Assigned(SkinPopUpMenu) then
      PopUpCallback(OnPopupDestroyed);
wird nicht ausgeführt, weil SkinPopupMenu immer zugewiesen ist (lassen wir mal die doppelte Verneinung weg).

Ich habe hier den Thread durchsucht nach "SkinPopUpMenu :=". Zumindest hier kann ich nichts finden, das SkinPopupMenu Nil zuweist.

Dort, wo das passiert (oder erfolgt dies vielleicht gar nicht?), sollte SkinPopupMenu danach ja auch Nil sein (andernfalls verwendest Du vielleicht eine lokale Variable gleichen Namens).

Wenn das so ist,
- kommt das Programm danach nie mehr zur obigen Prüfung
oder
- SkinPopupMenu wird wieder ein InterfaceObject zugewiesen.

EWeiss 14. Sep 2017 19:26

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

Zumindest hier kann ich nichts finden, das SkinPopupMenu Nil zuweist.
Den Status Nil erhält das SkinPopupMenu wenn der Reverenz Zähler auf 0 ist.

Nur das wird er nie.
Das ist doch mein Problem das ich dir über Mail mitgeteilt habe.
Deshalb wollte ich alle Variablen des SkinPopupMenu mit FillChar auf 0 setzen um den Status bzw. den Reverenz Zähler auf 0 zu bekommen.
Du sagtest das soll ich nicht tun.

Im Netzt ist leider nichts zu finden ohne das man sich ein Buch dafür zulegen muss.

Der eine sagt man darf ein Interface selber nicht auf NIL setzen.
Der andere sagt doch ist kein Problem
Der nächste sehe zu das der Reverenz Zähler auf 0 geht dann ist SkinPopupMenu automatisch Nil.

Langsam blicke ich da selbst nicht mehr durch da jeder etwas anderes sagt.

gruss

stahli 14. Sep 2017 19:40

AW: Classe/Interface aus WinProc aufrufen
 
Den Referenzzähler verwaltet Delphi für Dich.
Und zwar wird er erhöht, wenn Du einer Interfacevariable Dein InterfaceObject zuweist und verringert, wenn Du Nil zuweist.

Intf1 := TInterfacedObject.Create; // RefCount = 1
Intf2 := Intf1; // RefCount = 2
Intf1 := Nil; // RefCount = 1
Intf2 := Nil; // RefCount = 0 --> InterfaceObject.Free wird "von Delphi" ausgeführt.

In dem anderen Thread hatte ich Dir das erklärt.


Zitat:

Den Status Nil erhält das SkinPopupMenu wenn der Reverenz Zähler auf 0 ist.
kann also nicht funktionieren, da der Referenzzähler erst auf 0 fällt, wenn alle Referenzvariablen Nil sind.


Also setze SkinPopupMenu auf Nil, wenn das Ding nicht mehr gebraucht wird.
Dann wird der Callback ausgeführt und auch im Hauptprogramm die Referenzvariable auf Nil gesetzt und das Objekt freigeben.


Du musst den Interfacevariablen Nil zuweisen. Den Rest macht Delphi für Dich.

In dem anderen Projekt scheint das ja auch zu klappen.

Fritzew 14. Sep 2017 19:42

AW: Classe/Interface aus WinProc aufrufen
 
Ich habe versucht jetzt durchzusteigen wo das Problem ist.
Zitat:

Den Status Nil erhält das SkinPopupMenu wenn der Reverenz Zähler auf 0 ist.
das widerspricht allem was mit Interfaces zu tun hat.

Andersherum wird ein Schuh daraus:
Wenn alle!!! Referenzen auf das Interface nil sind geht der Referenz Zähler auf 0 und das darunter liegende Objekt wird freigegeben.

Du weist wie Du mich erreichen kannst......

stahli 14. Sep 2017 19:48

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

Zitat von Fritzew (Beitrag 1381216)
Wenn alle!!! Referenzen auf das Interface nil sind geht der Referenz Zähler auf 0 und das darunter liegende Objekt wird freigegeben.

Noch genauer wäre: "... wenn alle Referenzen auf das InterfaceObject Nil sind ..."

Das ist zum Verständnis vielleicht wichtig, da wir hier schon so lange um den Brei herum reden.
Wenn ein Objekt 5 Interfaces unterstützt und 3 Interfaces je einer Interfacevariablen zugewiesen sind, ist der RefCounter des Objektes = 3.

Fritzew 14. Sep 2017 19:51

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

Zitat von stahli (Beitrag 1381218)
Noch genauer wäre: "... wenn alle Referenzen auf das InterfaceObject Nil sind ..."

Oder so ;-)

EWeiss 14. Sep 2017 20:06

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

das widerspricht allem was mit Interfaces zu tun hat.
Aber das ist was man mir hier verklickert.

Ich suche das jetzt raus.
Zitat:

•Niemals eine Referenz auf das Objekt behalten und nutzen! Immer nur mit dem Interface arbeiten. Schon gar nicht das Objekt mit Free freigeben und damit allen Interfaces unter dem Allerwertesten wegziehen. Das gibt sehr schöne Fehler...
Free ist für mich das gleiche wie als wenn ich das Interface auf NIL setze. Darf man aber anscheinend nicht.

Dann tue ich folgendes..
Delphi-Quellcode:
  // TODO
FillChar(SkinPopUpMenu, SizeOf(SkinPopUpMenu), 0);

  if not Assigned(SkinPopUpMenu) then
    PopUpCallback(OnPopupDestroyed);
Hier setze ich alle variablen auf 0, NIL oder wie auch immer danach ist mein Interface NIL (Da keine Variable mehr in gebrauch ist.)
Darf man aber anscheinend auch nicht.

Und ja ich weis das man eine Variable direkt auf Nil setzen kann wäre es nicht so dann sollte man es direkt lassen.
Aber da hat man mir dann wieder zwischen gepfuscht mit der Meldung nein man darf kein Interface selbst auf NIL setzen.
Delphi-Quellcode:
SkinPopUpMenu := Nil;

Ehrlich keine Ahnung was das noch soll.
Wie man es macht, macht man es falsch.

Hätte man mich nicht so irritiert mit den Referenz Zähler dann hätte ich schon lange einfach vor

Delphi-Quellcode:
PopUpCallback(OnPopupDestroyed);


Einfach

Delphi-Quellcode:
SkinPopUpMenu := Nil;


gesetzt und fertig.
Wäre ja nicht das erste mal das ich eine Variable auf NIL setze LOL.

Zitat:

Noch genauer wäre: "... wenn alle Referenzen auf das InterfaceObject Nil sind ..."
Sorry! Das ist genau mein Problem jeder sagt was anderes...
Mich interessiert das überhaupt nicht ob der Zähler 0 oder auf 3 steht.

Mich interessiert nur eins kann ich mein Interface selbst auf NIL setzen oder nicht.

Dann wäre meine Lösung diese
Delphi-Quellcode:
  SkinPopUpMenu := nil;
  PopUpCallback(OnPopupDestroyed);
und fertig .. alles so wie gehabt. (Bei normalen Classen)


gruss

stahli 14. Sep 2017 20:11

AW: Classe/Interface aus WinProc aufrufen
 
Genau so ist es korrekt. Berichte mal, ob dann alles funktioniert.

Wenn Du mit Interfaces incl. Referenzzählung arbeitest, dann nie bei dem Objekt hinter dem Interface Free aufrufen!
Immer nur Interfacevariablen Nil zuweisen.
Bei der letzten Nil-Zuweisung wird Free automatisch ausgeführt. Dafür ist die Referenzzählung da.

Wie schon mal gesagt: "InterfaceObject.Free" ist etwas völlig anderes als "MyInterfaceVariable := Nil"

EWeiss 14. Sep 2017 20:14

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

Zitat von stahli (Beitrag 1381223)
Genau so ist es korrekt. Berichte mal, ob dann alles funktioniert.

Wenn Du mit Interfaces incl. Referenzzählung arbeitest, dann nie bei dem Objekt hinter dem Interface Free aufrufen!
Immer nur Interfacevariablen Nil zuweisen.
Bei der letzten Nil-Zuweisung wird Free automatisch ausgeführt. Dafür ist die Referenzzählung da.

Wie schon mal gesagt: "InterfaceObject.Free" ist etwas völlig anderes als "MyInterfaceVariable := Nil"

Da muss ich nichts berichten das funktioniert hat immer schon.
Warum auch nicht.
Ich habe mich hier einfach nur verrückt machen lassen weil entschuldige kein Angriff gegen irgend jemanden jeder etwas anderes gesagt hat.

Zitat:

Wie schon mal gesagt: "InterfaceObject.Free" ist etwas völlig anderes als "MyInterfaceVariable := Nil"
Ok das war wohl das Missverständnis warum das jetzt so ausgeartet ist. ;)


gruss

stahli 14. Sep 2017 20:19

AW: Classe/Interface aus WinProc aufrufen
 
Du hast das m.E. nur falsch verstanden. Ist auch kein Vorwurf. :-)

Ich habe auch Interfaces schon eine Weile genutzt, bis ich die Zusammenhänge wirklich verstanden habe.
Jetzt ist mir gar nicht klar, was daran so schwierig war.

Auch durch so eine Diskussion hier festigt man die eigenen Kenntnisse.
Insofern profitieren hier alle. :thumb:

EWeiss 14. Sep 2017 20:24

AW: Classe/Interface aus WinProc aufrufen
 
Ich denke da ich kein Informatiker bin .. ist es mir auch nicht so geläufig die richtigen Ausdrücke für ein Problem zu definieren.
Auf Grund dessen entstehen die Probleme mit denen ich zu kämpfen habe. (siehe Spaghetti Code) usw... für mich stellt dann so etwas einen Angriff gegen meine Person dar.

Ich bin ja nicht blöd.. hab ich wohl schon bewiesen aber mir fehlt es halt an den Dingen die ein Informatiker als selbstverständlich voraussetzt.
Aber das muss man nicht alles wissen. ;)

PS:
EurekaLog ist ein mächtiges Werkzeug :) Habe mal die 30Tage Test Version versucht.
Feines Teil.

gruss

stahli 14. Sep 2017 20:41

AW: Classe/Interface aus WinProc aufrufen
 
Wir helfen uns ja hier gegenseitig und freiwillig.
Persönliche Angriffe gibt es ja hier zum Glück so gut wie nicht - ist ja leider selten im Netz, dass es so freundlich zugeht.

Insofern muss man nur versuchen, nicht aneinander vorbei zu reden.

An Dich der Tipp: Es wäre vielleicht etwas geordneter zugegangen, wenn Du die Probleme und Fragen präziser formuliert hättest.
Wobei mir auch klar ist, dass das manchmal nicht so einfach ist, wenn man die Zusammenhänge noch nicht richtig einordnen kann.

Geht ja fast jedem so.

EWeiss 14. Sep 2017 21:07

AW: Classe/Interface aus WinProc aufrufen
 
Zitat:

An Dich der Tipp: Es wäre vielleicht etwas geordneter zugegangen, wenn Du die Probleme und Fragen präziser formuliert hättest.
Korrekt..
Nur. Ich bin Hobbykoch und da kennt man auch nicht jede Apfelsorte ;)

So sieht s jetzt aus und ist gut genug für mich.

gruss

stahli 14. Sep 2017 21:32

AW: Classe/Interface aus WinProc aufrufen
 
Also die Optik entschädigt jede Mühe. Das hast Du echt drauf. :thumb:


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