SetWindowsHookEx mit WH_CALLWNDPROC

Windowsspezifisches Forum , API ,..
Beiträge, die plattformübergreifend sind, gehören ins 'Allgemein'-Forum.
DNA
Beiträge: 40
Registriert: 25.02.2006 23:54

SetWindowsHookEx mit WH_CALLWNDPROC

Beitrag von DNA »

Ich hab folgendes Problem:
Ich möchte eine eigene Uhr bzw. Timer im Systray anzeigen lassen, oder evtl. die Uhr von Windows (XP) ersetzten. Hier in diesem Thread wurde so ein ähnliches Thema mal angesprochen, hat mir aber nicht viel geholfen.

Ich hab es mit einer DLL-Injektion Probiert, nach dem Prinzip, wie auch der Taskmanager unter XP abgeschaltet werden kann, aber das funktioniert auch nicht.

Nun hab ich ein Beispiel gefunden, welches genau das tut was ich auch will, und hab mir dazu dann den C-Code angeschaut und bin zu dem Entschluss gekommen, dass es mit Hilfe der SetWindowsHookEx_() Funktion gehen muss. Hier der Link von dem C-Code

Nun hab ich darauf folgenden Code geschrieben:

Code: Alles auswählen

#TCM_CLOCKERROR = #WM_USER + 1
#CLOCKM_EXIT    = #WM_USER + 9

Global g_hhook.l = #Null
Global g_hwndTClockMain.l = #Null
Global g_hInst.l = GetModuleHandle_(0)

Procedure.l MyWnd(hwnd, message, wParam, lParam)
  Debug "MyWnd"
  ProcedureReturn DefWindowProc_(hwnd, message, wParam, lParam)
EndProcedure

Procedure.l HookStart()
	hwndTaskbar.l = FindWindow_("Shell_TrayWnd", "")
  hwndTray.l    = FindWindowEx_(hwndTaskbar, #Null, "TrayNotifyWnd", "")
	g_hwndClock.l = FindWindowEx_(hwndTray, #Null, "TrayClockWClass", #Null)
	idThread.l    = GetWindowThreadProcessId_(hwndTaskbar, #Null)
	g_hhook       = SetWindowsHookEx_(#WH_CALLWNDPROC, @MyWnd(), g_hInst, idThread)
  
  If hwndTaskbar And hwndTray And g_hwndClock And idThread And g_hhook
	  PostMessage_(hwndTaskbar, #WM_SIZE, #SIZE_RESTORED, 0)
	  ProcedureReturn #True
	EndIf
	
	SendMessage_(hwndMain, #TCM_CLOCKERROR, 0, 5)
	ProcedureReturn #False
EndProcedure

Procedure HookEnd()
	If g_hwndTClockMain And IsWindow_(g_hwndTClockMain)
		SendMessage_(g_hwndTClockMain, #CLOCKM_EXIT, 0, 0)
	EndIf
	
	If(g_hhook <> #Null)
		UnhookWindowsHookEx_(g_hhook)
  EndIf

	g_hhook = #Null
EndProcedure

OpenWindow(1, 0,0, 200, 200, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
g_hwndTClockMain = WindowID(1)
HookStart()

Repeat
  Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow

HookEnd()
Dieser Code sollte mir nur zeigen ob es Funktioniert und ich die CallBack-Funktion von der Uhr abfangen kann oder nicht, jedoch wird beim start dieses Codes der Explorer geschlossen und neugestartet. Das gleiche ist auch bei der DLL-Injektion gewesen. Aber warum das so ist und wieso das nicht funktioniert hab ich nicht herausgefunden und mit einer DLL hab ich es auch nicht geschafft das ganze zum laufen zu bringen.

Wenn einer von euch mir sagen könnte, wo mein Fehler ist, wäre das super. Zerbreche mir schon die ganze Zeit den Kopf darüber woran es liegen könnte, aber ich komm einfach nicht drauf. :cry:
Benutzeravatar
Fluid Byte
Beiträge: 3110
Registriert: 27.09.2006 22:06
Wohnort: Berlin, Mitte

Beitrag von Fluid Byte »

Zunächst mal ist mir deine Hook Prozedur aufgefallen die nicht ganz konform ist. Wenn du einen Hook mit #WH_CALLWNDPROC setzt muss diese eine bestimmte Form haben. Als zweites wäre zu erwähnen das dein Code eigentlich sowie so nicht funktionieren sollte denn laut MSDN:
MSDN hat geschrieben:If the dwThreadId parameter is zero or specifies the identifier of a thread created by a different process, the lpfn parameter must point to a hook procedure in a dynamic-link library (DLL).
Das heisst du musst die Hook Prozedur aus einer DLL laden weil du einen anderen Thread als deinen eigenen spezifizierst (so macht es übrigens auch das C Beispiel aus dem Link). Kann sein das es da Möglichkeiten gibt das zu umgehen aber so gut kenn ich mich da auch nicht aus.

Das merkwürdige ist ja das der Aufruf zu SetWindowsHookEx_() / UnhookWindowsHookEx_() erfolgreich ist obwohl der Hinweis aus MSDN nicht zutrifft. Dies liegt ausschließlich an dem hInst Parameter der mit GetModuleHandle_() ermittelt wird.

Der folgende Code ist eine verkürzte Version von deinem leidet aber am selben Problem. Allerdings sei gesagt das sobald man das Erstellen Fensters und den Event Loop rausnimmt es fehlerfrei funktioniert.

Code: Alles auswählen

Procedure CallWndProc(nCode,wParam,lParam)
  	
	ProcedureReturn CallNextHookEx_(0,nCode,wParam,lParam) 
EndProcedure

hwndTaskbar = FindWindow_("Shell_TrayWnd",0)
hwndSysTray = FindWindowEx_(hwndTaskbar,0,"TrayNotifyWnd",0)
hwndTrayClock = FindWindowEx_(hwndSysTray,0,"TrayClockWClass",0)

hInstance = GetModuleHandle_(0)
ThreadID = GetWindowThreadProcessId_(hwndTaskbar,0)

hhkTaskbar = SetWindowsHookEx_(#WH_CALLWNDPROC,@CallWndProc(),hInstance,ThreadID)

OpenWindow(0,0,0,320,240,"void",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)

While WaitWindowEvent() ! #PB_Event_CloseWindow : Wend

UnhookWindowsHookEx_(hhkTaskbar)
Windows 10 Pro, 64-Bit / Outtakes | Derek
DNA
Beiträge: 40
Registriert: 25.02.2006 23:54

Beitrag von DNA »

Mit diesem Code als DLL kompiliert, funktioniert der Aufruf von SetWindowsHookEx. Jedoch ist das Problem, dass die Globalen Variablen in der Funktion: "CallWndProc" nicht global sind. Also das ist so, als ob die Variablen vorher nicht definiert und somit auch nicht gesetzt sind.
Hat jemand ne lösung dafür, dass die Variablen doch als Global gezählt werden? Wenn es geht, dann nicht mit der AttachProcess Funktion, weil ich mehrere Stellen habe, die am gleichen Problem leiden und nicht das alles in einer Funktion unterbringen kann.

Code: Alles auswählen

#DLLFILENAME           = "MyDll.dll"
Global g_hInst.l      = #Null
Global hwndTaskbar.l  = #Null
Global hwndTray.l     = #Null
Global g_hwndClock.l  = #Null
Global idThread.l     = #Null
Global g_bInitClock.b = #False
Global g_hhook.l      = #Null

Procedure.l CallWndProc(nCode.l, wParam.l, lParam.l)
  *pcwps.CWPSTRUCT = @lParam
  SetClipboardText(Str(g_hwndClock))
  
  If nCode = #HC_ACTION And *pcwps And *pcwps\hwnd
    If (Not g_bInitClock) And *pcwps\hwnd = g_hwndClock
      MessageRequester("hmm", "diese Bedingung sollte erfüllt sein, geht aber nicht :(")
    EndIf
	EndIf
	
	ProcedureReturn CallNextHookEx_(g_hhook, nCode, wParam, lParam)
EndProcedure

ProcedureDLL.l start_Hook()
	g_hInst     = GetModuleHandle_(#DLLFILENAME)
	hwndTaskbar = FindWindow_("Shell_TrayWnd", "")
	hwndTray    = FindWindowEx_(hwndTaskbar, #Null, "TrayNotifyWnd", "")
	g_hwndClock = FindWindowEx_(hwndTray, #Null, "TrayClockWClass", #Null)
	idThread    = GetWindowThreadProcessId_(hwndTaskbar, #Null)
  g_hhook     = SetWindowsHookEx_(#WH_CALLWNDPROC, @CallWndProc(), g_hInst, idThread)
                PostMessage_(hwndTaskbar, #WM_SIZE, #SIZE_RESTORED, 0)
  
  ProcedureReturn g_hhook
EndProcedure

ProcedureDLL.l end_Hook()
  ProcedureReturn UnhookWindowsHookEx_(g_hhook)
EndProcedure

ProcedureDLL.l get_Hook()
  ProcedureReturn g_hhook
EndProcedure
Hab das Problem nun mit Shared Memory behoben :mrgreen:
Benutzeravatar
Scarabol
Beiträge: 1427
Registriert: 30.11.2005 21:00

Beitrag von Scarabol »

Hi,

währst du so net die Codes als Beispiel der Nachwelt zu hinterlassen?

Gruß
Scarabol
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea

PB-V: 4
WinXP
Benutzeravatar
Fluid Byte
Beiträge: 3110
Registriert: 27.09.2006 22:06
Wohnort: Berlin, Mitte

Beitrag von Fluid Byte »

Wer jetzt?
Windows 10 Pro, 64-Bit / Outtakes | Derek
Benutzeravatar
Scarabol
Beiträge: 1427
Registriert: 30.11.2005 21:00

Beitrag von Scarabol »

DNA


Gruß
Scarabol
Abgeschlossen Projekte:
Schreibmaschine, Bildschirmlupe, Wings3DtoOgreMeshConverter
Watch: PureArea

PB-V: 4
WinXP
DNA
Beiträge: 40
Registriert: 25.02.2006 23:54

Beitrag von DNA »

Erst einmal sorry, hab lang nicht mehr hier rein geschaut.
Mit dem Code hier, sollte das Hooken funktionieren, jedoch hab ich es so nicht getestet, da ich es aus meinem Projekt rauskopieren musste.

Code: Alles auswählen

; HookStart(hWnd) muss zum Hooken aufgerufen werden und
; dabei sollte das Fensterhandle übergeben werden,
; welches als Uhr dargestellt werden soll

; wenn ihr das ganze beenden wollt, solltet ihr vorher die Prozedur HookEnd() aufrufen

#DLLFILENAME           = "MyDll.dll" ;Der dll-Name muss gleich dem Inhalt dieser Konstante sein

Global g_hInst.l      = #Null
Global hwndTaskbar.l  = #Null
Global hwndTray.l     = #Null
Global idThread.l     = #Null
Global g_bInitClock.b = #False

;{ shared Memory
Global g_hhook           = #Null
Global g_hwndTClockMain  = #Null
Global g_hwndClock       = #Null
;}

Procedure.l AllocateMemoryGlobal(Name.s, Size.l)
  HandleMap = CreateFileMapping_($FFFFFFFF, 0, 402653188, 0, Size, @Name)
  If HandleMap
    ProcedureReturn MapViewOfFile_(HandleMap, 983071, 0, 0 ,0)
  EndIf
EndProcedure

Procedure FreeMemoryGlobal(MemoryAddress.l)
  UnmapViewOfFile_(MemoryAddress)
  CloseHandle_(HandleMap)
EndProcedure

Procedure reset_Memory()
  g_hhook          = AllocateMemoryGlobal("g_hhook", 4)
  g_hwndClock      = AllocateMemoryGlobal("g_hwndClock", 4)
  g_hwndTClockMain = AllocateMemoryGlobal("g_hwndTClockMain", 4)
  
  FreeMemoryGlobal(g_hhook)
  FreeMemoryGlobal(g_hwndClock)
  FreeMemoryGlobal(g_hwndTClockMain)
  
  g_hhook          = AllocateMemoryGlobal("g_hhook", 4)
  g_hwndClock      = AllocateMemoryGlobal("g_hwndClock", 4)
  g_hwndTClockMain = AllocateMemoryGlobal("g_hwndTClockMain", 4)
EndProcedure

ProcedureDLL AttachProcess(hInst.l)
  g_hInst          = hInst ;GetModuleHandle_(#DLLFILENAME)
  g_hhook          = AllocateMemoryGlobal("g_hhook", 4)
  g_hwndClock      = AllocateMemoryGlobal("g_hwndClock", 4)
  g_hwndTClockMain = AllocateMemoryGlobal("g_hwndTClockMain", 4)

  ProcedureReturn #True
EndProcedure

Procedure.l CallWndProc(nCode.l, wParam.l, lParam.l)
  *pcwps.CWPSTRUCT = @lParam
  If nCode = #HC_ACTION And *pcwps And *pcwps\hwnd
    If (Not g_bInitClock) And *pcwps\hwnd = PeekL(g_hwndClock)
      ;Wenn alles gut gelaufen ist, könnt ihr hier nun eure Uhr initialisieren
    EndIf
  EndIf

  ProcedureReturn CallNextHookEx_(PeekL(g_hhook), nCode, wParam, lParam)
EndProcedure

ProcedureDLL.b HookStart(hwndMain.l)
  reset_Memory()

  g_hInst       = GetModuleHandle_(#DLLFILENAME)
  hwndTaskbar.l = FindWindow_("Shell_TrayWnd", "")
  hwndTray.l    = FindWindowEx_(hwndTaskbar, #Null, "TrayNotifyWnd", "")
  idThread.l    = GetWindowThreadProcessId_(hwndTaskbar, #Null)
  
  PokeL(g_hwndTClockMain, hwndMain)
	PokeL(g_hwndClock, FindWindowEx_(hwndTray, #Null, "TrayClockWClass", #Null))
  PokeL(g_hhook, SetWindowsHookEx_(#WH_CALLWNDPROC, @CallWndProc(), g_hInst, idThread))

	If Not PeekL(g_hhook)
		ProcedureReturn #False
	EndIf

  MoveWindow_(PeekL(g_hwndClock), 0, 0, 0, 0, #True)
  PostMessage_(PeekL(g_hwndClock), #WM_SIZE, #SIZE_RESTORED, 0)
  PostMessage_(hwndTaskbar, #WM_SIZE, #SIZE_RESTORED, 0)
  
  ProcedureReturn #True
EndProcedure

ProcedureDLL HookEnd()
  If PeekL(g_hhook) <> #Null
    UnhookWindowsHookEx_(PeekL(g_hhook))
	EndIf

  PokeL(g_hhook, #Null)
EndProcedure

ProcedureDLL.l get_Hook()
  ProcedureReturn PeekL(g_hhook)
EndProcedure
Antworten