AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Warum zerstören sich meine Classen
Thema durchsuchen
Ansicht
Themen-Optionen

Warum zerstören sich meine Classen

Ein Thema von EWeiss · begonnen am 21. Mär 2011 · letzter Beitrag vom 23. Mär 2011
Antwort Antwort
Seite 1 von 3  1 23      
EWeiss
(Gast)

n/a Beiträge
 
#1

Warum zerstören sich meine Classen

  Alt 21. Mär 2011, 23:54
Ich bekomme langsam die Krise.
Ich hab ein neues Control angefangen uGrid..

Delphi-Quellcode:
type
  ISkinGrid = interface
    ['{89A97429-5E4B-43B6-87D8-381DD4E8CF21}']
    function GetHandle: hWnd;
    property Handle: hWnd read GetHandle;
  end;

  TSkinGrid = class(TInterfacedObject, ISkinGrid)
  private
    FHGrid: HWND;
    FWidth: Integer;
    FHeight: Integer;
    Img: cardinal;
    dwStyle: DWORD;
    IsInitialized: BOOL;
    FOffsetX: Integer;
    FOffsetY: Integer;
    function GetOffsetY: Integer;
    function GetOffsetX: Integer;
    function GetHandle: hWnd;
    procedure DrawGrid(WinHandle: HWND);
  public
    property Handle: HWND Read FhGrid;
    property Width: Integer Read FWidth;
    property Height: Integer Read FHeight;
    property OffsetX: Integer read GetOffsetX write FOffsetX;
    property OffsetY: Integer read GetOffsetY write FOffsetY;
    constructor Create(hOwner: HWND; FullpathImageName: string;
       x, y, xW, yH, OffsX, OffsY, ButID: Integer);
    destructor Destroy; override;
  end;
sollte alles in Ordnung sein.

Classe wird ordnungsgemäß erstellt.
Danach stimmen alles meine Variablen.

Mit einmal zerstört sie sich selbst und alles ist weg.
Warum?

Der Aufruf wie zuvor.

Delphi-Quellcode:
    BoxGrid := CTRL_GridCreate(hMain, SKAERO_FOLDER +
      'Grid.png', 150, 67, 585, 257, 20, 10, ID_BOXGRID);
    SKAERO_SetAnchorMode(BoxGrid.Handle, ANCHOR_HEIGHT_WIDTH);
    SKAERO_SetZorder(BoxGrid.Handle, HWND_TOP);

Siehe Bilder..
Wie man sehen kann sind bei DrawGrid alle Eigenschaften gelöscht.

gruss

Geändert von EWeiss ( 9. Jul 2019 um 09:33 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von rollstuhlfahrer
rollstuhlfahrer

Registriert seit: 1. Aug 2007
Ort: Ludwigshafen am Rhein
1.529 Beiträge
 
Delphi 7 Professional
 
#2

AW: Warum zerstören sich meine Classen

  Alt 22. Mär 2011, 00:05
Interfaces lösen sich selbst auf, sobald nicht mehr auf sie zugegriffen wird (Referenz-Zähler = 0). Hast du eventuell eine gleichnamige lokale Variable zu deiner eventuell vorhandenen globalen Variable?

Bernhard
Bernhard
Iliacos intra muros peccatur et extra!
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#3

AW: Warum zerstören sich meine Classen

  Alt 22. Mär 2011, 00:08
Du musst bei Interfaces die Referenzzählung beachten. Wenn der Referenzzähler 0 erreicht, wird das Objekt automatisch zerstört.
Das kann z.B. passieren, wenn du Klassen- und Interface-Variablen mischt:
Delphi-Quellcode:
type
  IMyObj = interface
    …
  end;

  TMyObj = class(TInterfacedObject, IMyObj)
    …
  end;

var
  obj: TMyObj;
  intf: IMyObj;
begin
  obj := TMyObj.Create; // Referenzzähler von obj ist 0
  intf := obj; // Referenzzähler von obj wird inkrementiert → 1
  intf := nil; // Referenzzähler von obj wird dekrementiert → 0 → obj wird freigegeben
  { ab hier kannst du obj nicht mehr benutzen }
end
Dabei muss nicht unbedingt eine Interface-Variable auf nil gesetzt werden, es kann auch sein, dass in einer Subroutine ein Objekt einer lokalen Interface-Variable zugewiesen wird. Am Ende der Subroutine wird die Variable nämlich finalisiert, der Referenzzähler wird also ebenfalls dekrementiert, natürlich mit dem selben Effekt.

Deshalb sollte man Interfaces wenn dann immer konsequent verwenden.
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#4

AW: Warum zerstören sich meine Classen

  Alt 22. Mär 2011, 00:34
Hier ist mal meine komplette Klasse..
Hab nicht gedacht das es so schwierig mit den Interfacen ist.

Delphi-Quellcode:
unit uGrid;

interface

uses Windows, Classes, Messages, SysUtils, uGlobal, uGDIUnit, uSkin, uTrackBar;

type
  ISkinGrid = interface
    ['{89A97429-5E4B-43B6-87D8-381DD4E8CF21}']
    function GetHandle: hWnd;
    property Handle: hWnd read GetHandle;
  end;

  TSkinGrid = class(TInterfacedObject, ISkinGrid)
  private
    FHGrid: HWND;
    FWidth: Integer;
    FHeight: Integer;
    Img: cardinal;
    dwStyle: DWORD;
    IsInitialized: BOOL;
    FOffsetX: Integer;
    FOffsetY: Integer;
    function GetOffsetY: Integer;
    function GetOffsetX: Integer;
    function GetHandle: hWnd;
    procedure DrawGrid(WinHandle: HWND);
  public
    property Handle: HWND Read FhGrid;
    property Width: Integer Read FWidth;
    property Height: Integer Read FHeight;
    property OffsetX: Integer read GetOffsetX write FOffsetX;
    property OffsetY: Integer read GetOffsetY write FOffsetY;
    constructor Create(hOwner: HWND; FullpathImageName: string;
       x, y, xW, yH, OffsX, OffsY, ButID: Integer);
    destructor Destroy; override;
  end;

function GridProc(WinHandle: HWND; Msg: UINT; wP: WParam; lP: LParam): LRESULT; stdcall;

var
 SkinGrid : TSkinGrid;

implementation

constructor TSkinGrid.Create(hOwner: HWND; FullpathImageName: string;
  x, y, xW, yH, OffsX, OffsY, ButID: integer);

var
  wc: TWndClassEx;
  zClass: PAnsiChar;

begin
  inherited Create;

  with SkinEngine do
  begin
    zClass := SKGRID;
    wc.cbSize := SIZEOF(wc);
    IsInitialized := GetClassInfoEx(skInstance, zClass, wc);
    if IsInitialized = False then
    begin
      wc.cbSize := SIZEOF(wc);
      wc.style := CS_HREDRAW or CS_VREDRAW or CS_DBLCLKS;{ or CS_PARENTDC;}
      wc.lpfnWndProc := @GridProc;
      wc.cbClsExtra := 0;
      wc.cbWndExtra := EXTEND_EXTRA * 4;
      wc.hInstance := skInstance;
      wc.hIcon := 0;
      wc.hCursor := 0;
      wc.hbrBackground := 0;
      wc.lpszMenuName := nil;
      wc.lpszClassName := zClass;
      wc.hIconSm := wc.hIcon;
      if RegisterClassEx(wc) <> 0 then
        IsInitialized := True;
    end;

    if IsInitialized = True then
    begin
      dwStyle := WS_CHILD or WS_VISIBLE or WS_TABSTOP;
      // Erstelle das GDIPLUS image von Datei
      Img := AddResource(PAnsiChar(FullpathImageName));
      if Img <> 0 then
      begin
        // Hole die Thumb GDIPLUS image größe
        GetImageSize(Img, imgW, imgH);

        FWidth := xW;
        FHeight := yH;
        FOffsetX := OffsX;
        FOffsetY := OffsY;

        FHGrid := CreateWindowEx(WS_EX_TRANSPARENT,
          SKGRID, nil, dwStyle, x, y, xW, yH,
          hOwner, ButID, skInstance, nil);

        if FHGrid <> 0 then
        begin
          // Speichere das Image Handle in die Property
          SetImageProperty(FHGrid, PROP_STYLE, BS_GROUPBOX);
          SetImageProperty(FHGrid, GRID_IMAGE, Img);

          SkinGrid := @FHGrid;
          SkinGrid.Img := Img;
          SkinGrid.dwStyle := dwStyle;
          SkinGrid.FWidth := xW;
          SkinGrid.FHeight := yH;
          SkinGrid.FOffsetX := OffsX;
          SkinGrid.FOffsetY := OffsY;

        end else
          // Image löschen wenn Fehler
          DeleteResource(Img);
      end;
    end;
  end;
end;

function GridProc(WinHandle: HWND; Msg: UINT; wP: WParam; lP: LParam): LRESULT;
var
  ps: TPaintstruct;

begin

  with SkinEngine do
  begin
    case Msg of
      WM_ERASEBKGND:
      begin
        Result := 1;
        exit;
      end;
      WM_DESTROY:
      begin
        PostQuitMessage(0);
        Result := 0;
        Exit;
      end;
      WM_PAINT:
      begin
        BeginPaint(WinHandle, ps);
        SkinGrid.DrawGrid(WinHandle);
        EndPaint(WinHandle, ps);
        Result := 0;
        Exit;
      end;
    end;
    Result := DefWindowProc(WinHandle, Msg, wP, lP);
  end; // end SkinEngine

end;

destructor TSkinGrid.Destroy;
begin

  inherited Destroy;
end;

procedure TSkinGrid.DrawGrid(WinHandle: HWND);
var
  graphics: Cardinal;
  pen: Integer;
  IntI: Integer;
  DC: HDC;
  rc: TRect;

begin
  with SkinEngine do
  begin
    // Initialisierern
    DC := GetDC(WinHandle);

    GetClientRect(WinHandle, rc);

    GdipCreateFromHDC(DC, graphics);
    GdipCreatePen1(ColorARGB(255, RGB(0, 0, 0)), 1, UnitPixel, pen);

    for IntI := 0 to rc.Right do
    begin
      if IntI mod FOffsetX <> 0 then continue;
        GdipDrawLineI(graphics, pen, IntI, 0, IntI, rc.Bottom);
    end;

    for IntI := 0 to rc.Bottom do
    begin
       if IntI mod FOffsetY <> 0 then continue;
         GdipDrawLineI(graphics, pen, 0, IntI, rc.Right, IntI);
    end;

    // Freigeben
    GdipDeletePen(pen);
    GdipDeleteGraphics(graphics);
    ReleaseDC(WinHandle, DC);
  end;

end;

function TSkinGrid.GetHandle: hWnd;
begin

  result := FhGrid;
end;

function TSkinGrid.GetOffsetX: Integer;
begin

  Result := FOffsetX;
end;

function TSkinGrid.GetOffsetY: Integer;
begin

  Result := FOffsetY;
end;

end.
SkinGrid := @FHGrid;
Mußte ich auf die Classe casten weil ich sonst ein problem mit den Variablen in der WinProc habe.

Zitat:
Hast du eventuell eine gleichnamige lokale Variable zu deiner eventuell vorhandenen globalen Variable?
Denke nicht.
Aber der zähler ist auf 0 .. kann man auf dem bild auch sehen.

EDIT:
Wenn ich jetzt eine globale Variable definiere.
Zitat:
mOffsetX : Integer;
mOffsetY : Integer;
und übergebe dieser die Variable welche noch gültig ist beim start
dann funktioniert es.

Zitat:
mOffsetX := FOffsetX;
mOffsetY := FOffsetY;

Nur welchen Sinn haben dann die Variablen die ich in der Classe definiert habe wenn sie nicht funktionieren.
Bzw.. das Interface vorher zerstört wird.


gruss

Geändert von EWeiss (22. Mär 2011 um 14:22 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#5

AW: Warum zerstören sich meine Classen

  Alt 22. Mär 2011, 08:14
Definiere doch mal (und wenn auch nur zum Testen) folgende Variable:

Delphi-Quellcode:
var
  FPrevClientProc: TFNWndProc;
  SkinGrid : TSkinGrid;
  SkinGridIntf: ISkinGrid;
Dann erzeugst du das SkinGrid mit

SkinGridIntf := TSkinGrid.Create(...); und schau mal, ob es dann geht.

Sorry, aber deine Art mit Klassen, Interfaces und Handles zu hantieren ist irgendwie, sagen wir "unüblich".

Wenn du die Referenzzählung nicht brauchst, dann leite deine Klassen nicht von TInterfacedObject sonder von TInterfacedPersistent (classes.pas) ab. Dann musst du die Instanzen aber auch selbst wieder freigeben.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.464 Beiträge
 
Delphi 12 Athens
 
#6

AW: Warum zerstören sich meine Classen

  Alt 22. Mär 2011, 09:41
Diese Variablen werden überschrieben, sobald es mehr als eine Instance von TSkinGrid gibt:
Delphi-Quellcode:
var
  FPrevClientProc: TFNWndProc;
  SkinGrid : TSkinGrid;
Deshalb müssen diese Member der Klasse sein.
In der Funktion GridProc soll auf die jeweilige Instanz von TSkinGrid zugegriffen werden.
Benötigt wird eine List aller Instanzen, um sich auf Grund des Handle die richtige zu ermitteln.

Das Interface und die implementierende Klasse in der selben Unit zu deklarieren ist zumindest fragwürdig.
Aus welchen Gründen wird hier überhaupt mit einem Interface gearbeitet?

Ich würde TSkinGrid von TComponent ableiten und beim Constructor als Owner die jeweils das skinnende Objekt übergeben.
Damit hat das TSkinGrid die selbe Lebensdauer wie der Owner und es kann auch auf Owner zugegriffen werden.
  Mit Zitat antworten Zitat
QuickAndDirty

Registriert seit: 13. Jan 2004
Ort: Hamm(Westf)
1.930 Beiträge
 
Delphi 12 Athens
 
#7

AW: Warum zerstören sich meine Classen

  Alt 22. Mär 2011, 12:13
Ich nehme an er nimmt interfaces um später mal Skins aus DLLs importieren zu können. ???
Andreas
Monads? Wtf are Monads?
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#8

AW: Warum zerstören sich meine Classen

  Alt 22. Mär 2011, 12:36
Aus welchen Gründen wird hier überhaupt mit einem Interface gearbeitet?
Weil meine Objecte(Controls oder wie auch immer) sich in einer DLL befinden.
Und ich von außen auf die später Mitgelieferte API.. der DLL zugreife.

Wie also soll ich das komplette Object von außen Aufrufen ohne Interface?

Delphi-Quellcode:
    BoxGrid := CTRL_GridCreate(hMain, SKAERO_FOLDER +
      'Grid.png', 150, 67, 585, 257, 20, 10, ID_BOXGRID);
    SKAERO_SetAnchorMode(BoxGrid.Handle, ANCHOR_HEIGHT_WIDTH);
    SKAERO_SetZorder(BoxGrid.Handle, HWND_TOP);
Das ist in der Anwendung...
Der rest in einer DLL
Warum soll der User der meine DLL verwenden möchte sich mit GDI+ und konsorte rumquälen
wenn die DLL das später alles zur verfügung stellt.


Delphi-Quellcode:
function CTRL_GridCreate(hOwner: HWND; FullpathImageName: string;
  x, y, xW, yH, OffsX, OffsY, ButID: Integer): ISkinGrid; stdcall;
begin

  result := TSkinGrid.Create(hOwner, FullpathImageName, x, y, xW, yH,
    OffsX, OffsY, ButID);
end;

Zitat:
FPrevClientProc: TFNWndProc;

Habe ich wieder entfernt wollte die GridProc Subclassen
ist aber in dem Fall nicht nötig.

gruss

Geändert von EWeiss (22. Mär 2011 um 12:40 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von rollstuhlfahrer
rollstuhlfahrer

Registriert seit: 1. Aug 2007
Ort: Ludwigshafen am Rhein
1.529 Beiträge
 
Delphi 7 Professional
 
#9

AW: Warum zerstören sich meine Classen

  Alt 22. Mär 2011, 12:43
Es hängt ja nicht daran, wo was ist und für was es verwendet werden soll, sondern wie die Typen gebraucht werden. Für ein Interface gibt es einen automatischen Referenzzähler (also ein Garbage Collector für Delphi, der funktioniert). Dieser funktioniert allerdings nur dann korrekt, wenn man keine Objekt-Typen mehr verwendet, sondern nur noch Interface-Typen.

2. Stoplerstein: Wenn ein Interface keiner Variablen mehr zugeordnet ist, dann heißt das automatisch, dass das Interface weg muss (Garbage Collector). Dazu im Gegensatz das Nicht-Interface-Objekt: Das verschwindet erst, wenn jemand explizit Free (Destroy) aufgerufen hat.

Bernhard

PS: Hoffe, alles nochmal zusammengefasst und richtig dargestellt zu haben.
Bernhard
Iliacos intra muros peccatur et extra!
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#10

AW: Warum zerstören sich meine Classen

  Alt 22. Mär 2011, 12:58
Es hängt ja nicht daran, wo was ist und für was es verwendet werden soll, sondern wie die Typen gebraucht werden. Für ein Interface gibt es einen automatischen Referenzzähler (also ein Garbage Collector für Delphi, der funktioniert). Dieser funktioniert allerdings nur dann korrekt, wenn man keine Objekt-Typen mehr verwendet, sondern nur noch Interface-Typen.

2. Stoplerstein: Wenn ein Interface keiner Variablen mehr zugeordnet ist, dann heißt das automatisch, dass das Interface weg muss (Garbage Collector). Dazu im Gegensatz das Nicht-Interface-Objekt: Das verschwindet erst, wenn jemand explizit Free (Destroy) aufgerufen hat.

Bernhard

PS: Hoffe, alles nochmal zusammengefasst und richtig dargestellt zu haben.
Danke das habe ich jetzt verstanden.

Wie Uwe schon sagt...
Zitat:
Sorry, aber deine Art mit Klassen, Interfaces und Handles zu hantieren ist irgendwie, sagen wir "unüblich".

Er hat schon recht aber letztendlich zählt das ergebnis wie man dahin kommt ist eine andere sache.
Ich verwende jetzt TInterfacedPersistent obwohl mir der unterschied nicht geläufig ist abgesehen davon das sie keinen Referenzzähler hat
Damit funktioniert es.

Wie muß ich das nun korrekt freigeben?
Bedeutet das ich müßte eine Free Methode nach außen weiterleiten?


gruss
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


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 09:45 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