Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Implement ListView (https://www.delphipraxis.net/191383-implement-listview.html)

EWeiss 10. Jan 2017 01:18

Implement ListView
 
Habe kleine Probleme beim implementieren einer ListView.
Meine DLL schickt folgende Message beim WM_LBUTTONDBLCLK.
Delphi-Quellcode:
var
  MessageStructure: PNMHdr;
Delphi-Quellcode:
function TSkinListView.ListViewProc(WinHandle: hWnd; Msg: UINT; wP: WParam; lP: LParam): LRESULT;
begin

  case Msg of
    WM_LBUTTONDBLCLK:
      begin
        MessageStructure := PNMHdr(lP);
        MessageStructure.hwndFrom := WinHandle;
        MessageStructure.idFrom := DlgItemID;
        MessageStructure.code := NM_DBLCLK;
        SendMessageW(ListViewParent, WM_NOTIFY, DlgItemID, integer(MessageStructure));
        Result := 0;
        exit;
      end;
  end;
  Result := CallWindowProc(Pointer(FPrevClientProc), WinHandle, Msg, wP, lP);
end;
in der Anwendung wird die Message so verarbeitet.
Delphi-Quellcode:
    WM_NOTIFY:
      begin
         if(PNMHdr(lp)^.hwndFrom = PLList.Handle) then
         begin
           case PNMHdr(lp)^.code of
             NM_DBLCLK:
             begin
               nItem := PLList.GetCursel(lP);
               if nItem > 0 then
               begin
                 LastPlayListTitle := nItem;
                 HiddenPLList.ListSelectPlus(HiddenPLList.Handle, nItem);
                 getAudioFile := HiddenPLList.ListGetText(HiddenPLList.Handle, nItem);
                 SKAERO_UpdateWindow(lP, False);
                 HiddenPLList.ListSetTopIndex(HiddenPLList.Handle, nItem);
                 // PLList.ListSetTopIndex(PLList.Handle, nItem);
                 BassChannelPlay;
               end;
             end;
           end;
        end;
      end;
Das Problem ist ich kann die MessageStructure nicht füllen.

Error:
Zitat:

Erste Gelegenheit für Exception bei $005544BE. Exception-Klasse Zugriffsverletzung ($C0000005) mit Meldung 'access violation at 0x005544be: write of address 0x017a0090'. Prozess Soundmachine.exe (5252)
Was läuft falsch?

gruss

himitsu 10. Jan 2017 02:13

AW: Implement ListView
 
Zitat:

Zitat von EWeiss (Beitrag 1358529)
Was läuft falsch?

Du gehst fahrlässig davon aus, dass in LPARAM ein gewisser Record-Zeiger übergeben wird, aber was sagt denn die Dokumentation dazu?
https://msdn.microsoft.com/de-de/lib.../ms645606.aspx

Zitat:

Delphi-Quellcode:
Integer(IrgendeinPointer)

Und niemals Pointer mit Integern casten.
Intel und Co. haben beschlossen, dass der Integer beim Sprung von 32 auf 64 nicht mehr mit wächst und haben ihn eingefrohren. (früher war der mal 16 Bit, in 16 Bit Systemen)
Besser Typen verwenden, die für solche Casts vorgesehn sind, wie z.B. UIntPtr und IntPtr,
oder die "neuen" Integer-Typen verwenden, welche man nun erfunden hat und die ab jetzt wachsen sollen. In Delphi sind das NativeInt und NativeUInt.
Bzw. für Casts bei Messages gibt es extra die Typen LPARAM, WPARAM und LRESULT, damit immer alles richtig läuft, auch wenn man irgendwann auf 64 Bit umstellen würde.

EWeiss 10. Jan 2017 02:24

AW: Implement ListView
 
Zitat:

Du gehst fahrlässig davon aus, dass in LPARAM ein gewisser Record-Zeiger übergeben wird, aber was sagt denn die Dokumentation dazu?
Nur was soll ich dann verwenden anstelle von WM_LBUTTONDBLCLK
WM_NOTIFY in meiner ListViewProc funktioniert nicht

Delphi-Quellcode:
if(PNMHdr(lp)^.hwndFrom = PLList.Handle) then


tritt niemals ein.
Logisch weil WM_NOTIFY an das MainWindow gesendet wird.

Zitat:

für Casts bei Messages gibt es extra die Typen LPARAM, WPARAM und LRESULT
Habe es geändert ;)
Aber dazu muss ich erst mal erfolgreich die Message senden können.
Delphi-Quellcode:
SendMessageW(ListViewParent, WM_NOTIFY, DlgItemID, LParam(MessageStructure));


Ich könnte es jetzt auf diese weise machen
Delphi-Quellcode:
SendMessageW(GetParent(WinHandle), WM_COMMAND, MAKELONG(DlgItemID, LBN_DBLCLK), lp);


Aber das ist nicht das typische ListView verhalten beim Doubleclick.
Wenn dann jemand anderes damit arbeitet kommt er nicht mehr zurecht.

gruss

jaenicke 10. Jan 2017 04:49

AW: Implement ListView
 
Zitat:

Zitat von EWeiss (Beitrag 1358532)
Zitat:

Du gehst fahrlässig davon aus, dass in LPARAM ein gewisser Record-Zeiger übergeben wird, aber was sagt denn die Dokumentation dazu?
Nur was soll ich dann verwenden anstelle von WM_LBUTTONDBLCLK

Du kannst das ja verwenden, aber wenn du per WM_NOTIFY einen Record weizergehen möchtest, musst du auch den nötigen Speicher reservieren.

Im Moment schreibst du, da der Parameter, den du einfach auf einen Pointer auf den Record castest, ja nicht einmal ein Pointer ist, an eine quasi zufällige Stelle im Speicher und hoffst, dass das gut geht...

Auffallen tut das bei dir, weil du eben nicht einfach überall in den Speicher schreiben darfst. Deshalb die Zugriffsverletzung.

Deiner Meldung zufolge hast du übrigens an Position 378/144 geklickt.

// edit
Mal ein Beispiel was du da machst:
Delphi-Quellcode:
var
  a: Integer;
  MessageStructure: PNMHdr;
begin
  a := $017a0090;
  MessageStructure := PNMHdr(a);
  MessageStructure.hwndFrom := WinHandle;
...
end;
Die Fehlermeldung sollte deiner aktuellen sehr ähnlich sein.

EWeiss 10. Jan 2017 04:56

AW: Implement ListView
 
Zitat:

Du kannst das ja verwenden, aber wenn du per WM_NOTIFY einen Record weizergehen möchtest, musst du auch den nötigen Speicher reservieren.
Kleines Beispiel anhand meines Codes?

Mein Problem ist das ich nicht weis welche Message ich anstelle von WM_LBUTTONDBLCLK verwenden soll.
Damit im MainWindow WM_NOTIFY NM_DBLCLK: auch ausgelöst wird.

Das macht ärger MessageStructure (nicht immer)..

Zitat:

Die Fehlermeldung sollte deiner aktuellen sehr ähnlich sein.
Ich habe das ListView gesubclassed.
Eigentlich sollte sich dann der Record-Zeiger über lP zugewiesen werden.
Scheint aber nicht immer der Fall zu sein.

gruss

jaenicke 10. Jan 2017 05:03

AW: Implement ListView
 
Hier findest du entsprechenden Code mit Erläuterungen:
https://de.m.wikibooks.org/wiki/Prog...elphi:_Pointer
Es fehlt vor der Verwendung lediglich die Reservierung des Speichers mit New und nach dem SendMessage die Freigabe mit Dispose.

EWeiss 10. Jan 2017 05:11

AW: Implement ListView
 
Zitat:

Zitat von jaenicke (Beitrag 1358537)
Hier findest du entsprechenden Code mit Erläuterungen:
https://de.m.wikibooks.org/wiki/Prog...elphi:_Pointer
Es fehlt vor der Verwendung lediglich die Reservierung des Speichers mit New und nach dem SendMessage die Freigabe mit Dispose.

Supi.. Sebastian hast mir sehr geholfen.

Delphi-Quellcode:
function TSkinListView.ListViewProc(WinHandle: hWnd; Msg: UINT; wP: WParam; lP: LParam): LRESULT;
begin

  case Msg of
    WM_LBUTTONDBLCLK:
      begin
        OldSelected := GetCurSel(WinHandle);
        new(MessageStructure);
        MessageStructure.hwndFrom := WinHandle;
        MessageStructure.idFrom := DlgItemID;
        MessageStructure.code := NM_DBLCLK;
        SendMessageW(GetParent(WinHandle), WM_NOTIFY, DlgItemID, LParam(MessageStructure));
        Dispose(MessageStructure);
        Result := 0;
        exit;
      end;
  end;
  Result := CallWindowProc(Pointer(FPrevClientProc), WinHandle, Msg, wP, lP);
end;
Jetzt kann ich mich mit den anderen Kram Ownerdraw usw. .beschäftigen.
Hab ich so groß noch nicht verwendet NEW.. man lernt immer was dazu.
Wann ist das grundsätzlich gegeben den Speicher mit NEW zu Reservieren?

gruss

jaenicke 10. Jan 2017 05:17

AW: Implement ListView
 
Zitat:

Zitat von EWeiss (Beitrag 1358538)
Wann ist das grundsätzlich gegeben den Speicher mit NEW zu Reservieren?

Immer wenn du einen Pointer hast, der auf nichts Bekanntes zeigt. Sprich einen Pointer auf eine lokale Variable musst du nicht initialisieren, einen Pointer, den du ohne weitere Zusammenhänge lokal als Variable deklariert hast, schon.

Nebenbei:
Du musst auch nicht WM_NOTIFY benutzen. Du kannst ruhig eine eigene Windows Message und einem eigenen Recordtyp verwenden, wenn du vielleicht noch andere Informationen weitergeben möchtest.

EWeiss 10. Jan 2017 05:35

AW: Implement ListView
 
Zitat:

Immer wenn du einen Pointer hast, der auf nichts Bekanntes zeigt. Sprich einen Pointer auf eine lokale Variable musst du nicht initialisieren, einen Pointer, den du ohne weitere Zusammenhänge lokal als Variable deklariert hast, schon.
Das ist mal Aussagekräftig ;) Danke.

Zitat:

Du musst auch nicht WM_NOTIFY benutzen. Du kannst ruhig eine eigene Windows Message und einem eigenen Recordtyp verwenden, wenn du vielleicht noch andere Informationen weitergeben möchtest.
Jo wie ich es hier schon gemacht habe.

Delphi-Quellcode:
SendMessageW(GetParent(WinHandle), WM_COMMAND, MAKELONG(DlgItemID, LBN_DBLCLK), lp);


Das Problem dabei ist nur das LBN_DBLCLK (Listbox DoubleClick) eigentlich nichts mit dem ListView gemein hat.
Wenn man über WM_NOTIFY geht weis jeder was mit NM_DBLCLK: in Verbindung mit dem ListView gemeint ist.


gruss

himitsu 10. Jan 2017 09:23

AW: Implement ListView
 
Natürlich kann man auch direkt den Datentypen verwenden und spart sich dann die manuelle Speicherreservierung und den von dir vergessenen Ressourcenschutzblock (Try-Finally). :zwinker:
Delphi-Quellcode:
var
  MessageStructure: TNMHdr;

SendMessage(..., LPARAM(@MessageStructure));

PS: Eigentlich müsste man beim Zugriff auf Pointer noch den Zeiger dereferenzieren
Delphi-Quellcode:
MessageStructure^.hwndFrom
,
aber Delphi macht das netterweise implizit, von sich aus, wenn man
Delphi-Quellcode:
.irgendwas
auf den Zeiger anwendet.


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:34 Uhr.
Seite 1 von 2  1 2      

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