2017-04-08 9 views
0

J'essaie de porter un cours que j'ai écrit en Delphi sur Lazarus. Il s'appuie sur WM_DEVICECHANGE pour détecter les périphériques USB connectés. Je n'arrive pas à recevoir les messages Windows de mon composant alors qu'il fonctionnait parfaitement dans Delphi. Après avoir réalisé que AllocateHwnd est juste un espace réservé dans Free Pascal, j'ai commencé à imiter ce que fait LCL dans ce but.Recevoir et gérer les messages Windows dans Lazarus

TUSB = class(TComponent) 
private 
    FHandle: HWND; 
    procedure WndProc(var Msg: TMessage); 
    procedure AllocHandle(Method: TWndMethod); 
public 
    constructor Create(AOwner: TComponent); 
end; 
. 
. 
. 
procedure CallbackAllocateHWnd(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam); stdcall; 
var 
    Msg: TMessage; 
    PMethod: ^TWndMethod; 
begin 
    FillChar(Msg{%H-}, SizeOf(Msg), #0); 

    Msg.msg := uMsg; 
    Msg.wParam := wParam; 
    Msg.lParam := lParam; 

    PMethod := {%H-}Pointer(GetWindowLong(ahwnd, GWL_USERDATA)); 

    if Assigned(PMethod) then PMethod^(Msg); 

    Windows.DefWindowProc(ahwnd, uMsg, wParam, lParam); 
end; 

procedure TUSB.AllocHandle(Method: TWndMethod); 
var 
    PMethod: ^TWndMethod; 
begin 
    FHandle := Windows.CreateWindow(PChar('STATIC'), '', WS_OVERLAPPED, 0, 0, 0, 0, 0, 0, MainInstance, nil); 
    if Assigned(Method) then 
    begin 
    Getmem(PMethod, SizeOf(TMethod)); 
    PMethod^ := Method; 

    SetWindowLong(FHandle, GWL_USERDATA, {%H-}PtrInt(PMethod)); 
    end; 

    SetWindowLong(FHandle, GWL_WNDPROC, {%H-}PtrInt(@CallbackAllocateHWnd)); 
end; 

constructor TUSB.Create(AOwner: TComponent); 
begin 
    inherited Create(AOwner); 

    AllocHandle(@WndProc); 
end; 

Cela me donne une poignée de fenêtre valide, mais CallbackAllocateHWnd est jamais appelé. Je sais que ce genre de choses est propre à Windows et non portable, mais ce n'est pas le problème maintenant. Je veux juste dériver une classe de TComponent et pouvoir recevoir et manipuler des messages de Windows. Les mêmes lignes de code exactes, fonctionnent en Delphi.

Modifier: également essayé HWND_MESSAGE comme hWndParent.

Édition 2: J'ai trouvé que l'appel GetLastError après SetWindowLong(FHandle, GWL_WNDPROC, {%H-}PtrInt(@CallbackAllocateHWnd)); renvoie 1413 ce qui signifie un index invalide. J'ai même essayé GetWindowLong là et me donne la même erreur!

+0

Est-ce que allochandle s'exécute? Afaik setwindowlong retourne l'ancien wndproc, l'enregistre et l'appelle dans votre wndproc –

+0

FHandle a un handle de fenêtre valide après l'exécution de AllocHandle, mais mon WndProc personnalisé n'est pas déclenché lorsqu'un message lui est envoyé. –

Répondre

1

Juste pour référence de toute autre personne qui se termine sur cette page:

Après avoir obtenu des idées du forum Lazare, je trouve que l'unité incluant LCLIntf dans la clause uses résoudra la question. J'ai suivi le code en cours d'exécution et il a fini par appeler Windows.SetWindowLongPtrW. Donc, juste en remplaçant le deuxième appel à SetWindowLong avec Windows.SetWindowLongPtrW maintenant ça marche!