Wywala mi taki, i nie wiem co robię źle.
Incompatible types: 'regular procedure and method pointer'
To może daj kod. Szklane kule nam się popsuły.
var
Hook : Integer;
begin
Hook := SetWindowsHookEx(wh_journalrecord, Play, HInstance, 0);
end;
Chyba wiecie co robi funkcja Play...
Poczytaj http://delphi.about.com/cs/adptips2003/a/bltip1003_5.htm
a ta linia kodu co dałeś nic nie mówi...
W parametrze dajesz niezgodny typ.
Funkcja SetWindowsHookEx przyjmuje parametry typów : (kolejno)
- int
- HOOKPROC
- HINSTANCE
- DWORD
Wszystkie parametry sa tylko wejsciowe.
Cala funkcja zwraca wartosc typu HHOOK.
przykład:
HOOKPROC hkprcSysMsg;
static HINSTANCE hinstDLL;
static HHOOK hhookSysMsg;
hinstDLL = LoadLibrary(TEXT("c:\\myapp\\sysmsg.dll"));
hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "SysMessageProc");
hhookSysMsg = SetWindowsHookEx(
WH_SYSMSGFILTER,
hkprcSysMsg,
hinstDLL,
0);
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
Hook: HHOOK;
implementation
{$R *.dfm}
function Play(Code: integer; wParam, lParam: Longint): Longint; stdcall;
begin
//tu mozna by cos cobic ale na sztuke wywolam:
Result := CallNextHookEx(Hook, Code, wParam, lParam);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Hook:=SetWindowsHookEx(wh_journalrecord, play, HInstance, 0);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
UnhookWindowsHookEx(Hook);
end;
end.
unit SystemSpy;
interface
uses
SysUtils, Classes, Windows, Messages;
type
TKomponent = class(TComponent)
private
fHa : Boolean;
fHook : HHook;
MessageBuffer : TEventMsg;
function Play(Code: Integer; wParam, lParam: Longint): Longint; stdcall;
protected
{ Protected declarations }
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property HookActive : Boolean read fHA write fHa;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Standard', [TKomponent]);
end;
function TKomponent.Play(Code: Integer; wParam, lParam: Longint): Longint; stdcall;
var C : Char;
S : String;
begin
case Code of
HC_ACTION:
begin
MessageBuffer := PEventMsg(lParam)^;
if MessageBuffer.Message = WM_KeyDown then
begin
//'nie wazne';
end
else
Result := CallNextHookEx(fHook, Code, wParam, lParam)
end;
end;
constructor TKomponent.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
fHook := SetWindowsHookEx(wh_journalrecord, Play, HInstance, 0);
end;
destructor TKomponent.Destroy;
begin
UnHookWindowsHookEx(fHook);
inherited
end;
end.
Tyle odpowiedzi i każda błędna.
Pytanie to: "Co znaczy błąd incompatible types: 'regular procedure and method pointer'".
Odpowiedź: błąd ten oznacza niezgodność typów - regularna procedura (?) i wskaźnik na metodę (?)
:D
Może popsuję wszystkim zabawę :D, ale czy nie trzeba podać adresu procedury zamiast samej procedury? Czyli @Play
. Delphi to nie to samo co C++...
@up:
Wtedy "Variable required"...
Znalazłem błąd:
Nie może być
Function TForm1.Play(Code: integer; wParam, lParam: Longint): Longint; stdcall;
Tylko
Function Play(Code: integer; wParam, lParam: Longint): Longint; stdcall;
Itp.
Przecież podałem Tobie TomRiddle rozwiązanie w komentarzu, dostałeś w miarę krótko link do źródel z przykładem użycia Hook'a, ktory działa, bo jak mi wspominałeś nie radzisz sobie ze zrozumieniem jak za dużo tekstu masz do przeczytania. Po prostu - o ile się orientuję - funkcja obsługi Hook'a nie może być elementem klasy. Chcesz się odwoływać do jakiejś klasy to podstawiaj sobie w konstruktorze do zmiennej globalnej ten tworzony obiekt i operuj na with ... do begin ... end; Ewentualnie tak jak masz pokazane poniżej. Po co mnożysz sobie problemy i generujesz je tam gdzie ich nie ma lub nie powinno być.
//...
var
MainForm : TMainForm;
const
WH_KEYBOARD_LL = $000D;
type
tagKBDLLHOOKSTRUCT = packed record
vkCode : DWord;
ScanCode : DWord;
Flags : DWord;
Time : DWord;
dwExtraInfo : integer;
end;
KBDLLHOOKSTRUCT = tagKBDLLHOOKSTRUCT;
PKBDLLHOOKSTRUCT = ^KBDLLHOOKSTRUCT;
var
HKHook : HHook;
implementation
{$R *.dfm}
function LowLevelKeyboardProc(nCode : Integer; wParam : Integer; lParam : Integer) : Integer; stdcall; export;
var
Hook : PKBDLLHOOKSTRUCT;
begin
Hook := Pointer(lParam);
case nCode of
HC_ACTION :
begin
with MainForm do
begin
TestMemo.Lines.Add(Format('vkCode: %d ScanCode: %d Flags: %d Time: %d ExtraInfo: %d',
[Hook.vkCode, Hook.ScanCode, Hook.Flags, Hook.Time, Hook.dwExtraInfo]));
end;
end;
end;
Result := CallNextHookEx(HKHook, nCode, wParam, lParam);
end;
procedure HookIt;
begin
HKHook := SetWindowsHookEx(WH_KEYBOARD_LL, @LowLevelKeyboardProc, hInstance, 0);
end;
procedure UnHookIt;
begin
UnHookWindowsHookEx(HKHook);
end;
Może być w klasie ale to większa zabawa. W Google znalazłem taki moduł:
unit HookInst;
//------------------------------------------------------------------------------
// HOOK METHOD INSTANCE
//
// These few lines of code implement for windows hooks what MakeObjectInstance
// and FreeObjectInstance do for windows message functions. They allow a method
// to be written and passed into the SetWindowsHookEx API function rather than a
// stand alone function which cannot directly access variables or methods.
//
// An example of use is in the IDE Peek expert.
//
// The code is based entirely on the MakeObjectInstance and FreeObjectInstance
// in the Delphi Forms unit. In fact my only input has been to change a few
// names and make it work for Hook calls rather than Message calls. So I don't
// claim a lot. Borland's ownership of this code is recognised and I hope
// noone there minds my borrowing it and bodging it for this purpose!
//
// This way of writing a hook function is a bit wasteful of memory for what you
// are doing (but hell, what's 4KB nowadays!, this isn't a Z80 and CPM).
//
// Only tested under Delphi 3.02
//
// Version 1.00 5-2-98 Grahame Marsh
//
// Freeware - you get it for free, I take nothing, I make no promises!
//
// Please feel free to contact me: [email protected]
//------------------------------------------------------------------------------
interface
uses
Windows;
type
THookCall = packed record
Code : integer;
WParam : WPARAM;
LParam : LPARAM;
Result : LResult
end;
THookMethod = procedure (var HookCall: THookCall) of object;
function MakeHookInstance (Method: THookMethod): pointer;
procedure FreeHookInstance (ObjectInstance: pointer);
implementation
const
InstanceCount = 313; // set so that sizeof (TInstanceBlock) < PageSize
type
PObjectInstance = ^TObjectInstance;
TObjectInstance = packed record
Code: Byte;
Offset: Integer;
case Integer of
0: (Next: PObjectInstance);
1: (Method: THookMethod);
end;
type
PInstanceBlock = ^TInstanceBlock;
TInstanceBlock = packed record
Next: PInstanceBlock;
Code: array[1..2] of Byte;
WndProcPtr: Pointer;
Instances: array[0..InstanceCount] of TObjectInstance;
end;
var
InstBlockList : PInstanceBlock = nil;
InstFreeList : PObjectInstance = nil;
function StdHookProc (Code, WParam: WPARAM; LParam: LPARAM): LResult; stdcall; assembler;
asm
XOR EAX,EAX
PUSH EAX
PUSH LParam
PUSH WParam
PUSH Code
MOV EDX,ESP
MOV EAX,[ECX].Longint[4]
CALL [ECX].Pointer
ADD ESP,12
POP EAX
end;
{ Allocate a hook method instance }
function CalcJmpOffset(Src, Dest: Pointer): Longint;
begin
Result := Longint(Dest) - (Longint(Src) + 5);
end;
function MakeHookInstance(Method: THookMethod): Pointer;
const
BlockCode: array [1..2] of Byte = ($59, $E9);
PageSize = 4096;
var
Block: PInstanceBlock;
Instance: PObjectInstance;
begin
if InstFreeList = nil then
begin
Block := VirtualAlloc (nil, PageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Block^.Next := InstBlockList;
Move(BlockCode, Block^.Code, SizeOf(BlockCode));
Block^.WndProcPtr := Pointer(CalcJmpOffset(@Block^.Code[2], @StdHookProc));
Instance := @Block^.Instances;
repeat
Instance^.Code := $E8;
Instance^.Offset := CalcJmpOffset(Instance, @Block^.Code);
Instance^.Next := InstFreeList;
InstFreeList := Instance;
Inc(Longint(Instance), SizeOf(TObjectInstance));
until Longint(Instance) - Longint(Block) >= SizeOf(TInstanceBlock);
InstBlockList := Block
end;
Result := InstFreeList;
Instance := InstFreeList;
InstFreeList := Instance^.Next;
Instance^.Method := Method
end;
{ Free a hook method instance }
procedure FreeHookInstance (ObjectInstance: Pointer);
begin
if ObjectInstance <> nil then
begin
PObjectInstance(ObjectInstance)^.Next := InstFreeList;
InstFreeList := ObjectInstance
end
end;
end.
a tu przykład użycia:
unit KeybHock;
interface
uses
SysUtils, Classes, Windows, Messages, HookInst;
const
WH_KEYBOARD_LL = $000D;
type
tagKBDLLHOOKSTRUCT = packed record
vkCode : DWord;
ScanCode : DWord;
Flags : DWord;
Time : DWord;
dwExtraInfo : integer;
end;
KBDLLHOOKSTRUCT = tagKBDLLHOOKSTRUCT;
PKBDLLHOOKSTRUCT = ^KBDLLHOOKSTRUCT;
TKeybHock = class(TComponent)
private
fHa : Boolean;
fHook : HHook;
fHookProc: Pointer;
MessageBuffer : TEventMsg;
procedure Play(var HookCall: THookCall);
procedure SetHookActive(Value: Boolean);
protected
{ Protected declarations }
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property HookActive: Boolean read fHA write SetHookActive default False;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Standard', [TKeybHock]);
end;
procedure TKeybHock.Play(var HookCall: THookCall);
var
Hook: PKBDLLHOOKSTRUCT;
begin
case HookCall.Code of
HC_ACTION:
begin
Hook:= Pointer(HookCall.lParam);
//tu sie bawisz
end
else
HookCall.Result:= CallNextHookEx(fHook, HookCall.Code, HookCall.wParam, HookCall.lParam);
end;
end;
procedure TKeybHock.SetHookActive(Value: Boolean);
begin
if fHA = Value then exit;
if Value = True then
begin
fHookProc:= MakeHookInstance(Play);
fHook := SetWindowsHookEx(WH_KEYBOARD_LL, fHookProc, HInstance, 0);
fHA:= (fHook > 0);
end
else
begin
UnHookWindowsHookEx(fHook);
FreeHookInstance(fHookProc);
fHA:= False;
end;
end;
constructor TKeybHock.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
fHA:= False;
end;
destructor TKeybHock.Destroy;
begin
SetHookActive(False);
inherited;
end;
end.
Mówię to już 4 czy 5 raz. To nie jest kod bezpośrednio na formie. Tworzę komponent (nazwa klasy TKomponent), i to wtedy (w kodzie komponentu, jak chce go zainstalować) błąd się pojawia. Na formie działa świetnie.
Incompatible types: 'regular procedure and method pointer'
Nie można używać wskaźnika na metodę (procedurę lub funkcję będącą członkiem klasy) tam, gdzie potrzebny jest wskaźnik na procedurę lub funkcję globalną — ani odwrotnie.