svenguenter
Goto Top

VB6 Mouse Scrollen im Datagrid

Nach dem maximieren klappt das scrollen nicht mehr

So also folgendes Problem. Innerhalb meines VB6 Programmes habe ich ein Datagrid. Dort will ich aber gerne die Möglichkeit haben mit dem Mouserad zu scrollen.

Beim Aufruf des Programmes klappt es auch einwandfrei. nun minimiere ich das Programm mache etwas anderes und maximiere es wieder. Nun klappt das scrollen nicht mehr.

Hier mal mein Code den ich bis jetzt habe.

'------------------------Allgemeiner Teil  
Private WithEvents Msg As MsgHook
'-------------------------------------------  
'Formaufruf  
  Set Msg = New MsgHook
  Msg.Hook Me.hWnd, WM_MOUSEWHEEL


Option Explicit

Private Const GWL_WNDPROC = -4
Private Const MAX_HASH = 257

Private Type typHook
  hWnd As Long
  MsgHookPtr As Long
  ProcAddr As Long
  WndProc As Long
  uMsgCount As Long
  uMsg(MAX_HASH - 1) As Boolean
  uMsgCol As Collection
End Type

Private Declare Function CallWindowProcA Lib "user32" ( _  
    ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, _
    ByVal Msg As Long, ByVal wParam As Long, _
    ByVal lParam As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _  
    (dest As Any, source As Any, ByVal NumBytes As Long)
Private Declare Function SetWindowLongA Lib "user32" ( _  
    ByVal hWnd As Long, ByVal nIndex As Long, _
    ByVal dwNewLong As Long) As Long

Private Const MAXHOOKS = 9
Private Initialized As Boolean
Private arrHook() As typHook
Private NrCol As Collection
'---------'---------'---------'---------'---------'---------'---------  

Public Function DoHook(ByVal ObjPtr As Long, ByVal hWnd As Long, _
    uMsg As Variant) As Long
  Dim i As Long
  Dim j As Long
  
  If Not Initialized Then
    ReDim Preserve arrHook(1 To MAXHOOKS)
    arrHook(1).WndProc = Addr2Long(AddressOf WndProc1)
    arrHook(2).WndProc = Addr2Long(AddressOf WndProc2)
    arrHook(3).WndProc = Addr2Long(AddressOf WndProc3)
    arrHook(4).WndProc = Addr2Long(AddressOf WndProc4)
    arrHook(5).WndProc = Addr2Long(AddressOf WndProc5)
    arrHook(6).WndProc = Addr2Long(AddressOf WndProc6)
    arrHook(7).WndProc = Addr2Long(AddressOf WndProc7)
    arrHook(8).WndProc = Addr2Long(AddressOf WndProc8)
    arrHook(9).WndProc = Addr2Long(AddressOf WndProc9)
    Set NrCol = New Collection
    Initialized = True
  End If
  
  'Hook-Nr suchen:  
  For i = 1 To UBound(arrHook)
    If arrHook(i).MsgHookPtr = 0 Then Exit For
  Next i
  If i > UBound(arrHook) Then
    ReDim Preserve arrHook(1 To 2 * UBound(arrHook))
  End If
  If i > MAXHOOKS Then
    NrCol.Add i, "H" & hWnd  
    arrHook(i).WndProc = Addr2Long(AddressOf WndProcX)
  End If
  DoHook = i
  
  'Hook einrichten:  
  arrHook(i).uMsgCount = UBound(uMsg) + 1
  If arrHook(i).uMsgCount Then
    Erase arrHook(i).uMsg
    Set arrHook(i).uMsgCol = New Collection
    For j = LBound(uMsg) To UBound(uMsg)
      arrHook(i).uMsg(uMsg(j) Mod MAX_HASH) = True
      arrHook(i).uMsgCol.Add True, "H" & uMsg(j)  
    Next j
  End If
  arrHook(i).hWnd = hWnd
  arrHook(i).MsgHookPtr = ObjPtr
  arrHook(i).ProcAddr = _
      SetWindowLongA(hWnd, GWL_WNDPROC, arrHook(i).WndProc)
End Function

Public Sub DoUnhook(ByVal Nr As Long)
  If Nr Then
    With arrHook(Nr)
      SetWindowLongA .hWnd, GWL_WNDPROC, .ProcAddr
      .MsgHookPtr = 0
      Erase .uMsg
      Set .uMsgCol = Nothing
      If Nr > MAXHOOKS Then NrCol.Remove "H" & .hWnd  
    End With
''    If (Nr <= MAXHOOKS) And (NrCol.Count > 0) Then  
''      'Ggf. garbage collection?! / optimieren  
''    End If  
  End If
End Sub

Public Function WndProc(ByVal Nr As Long, ByVal hWnd As Long, _
    ByVal uMsg As Long, ByVal wParam As Long, _
    ByVal lParam As Long) As Long
  Dim oMsgHook As MsgHook
  Dim retVal As Long
  Dim Ok As Boolean
  
  With arrHook(Nr)
    If .uMsgCount > 0 Then
      If .uMsg(uMsg Mod MAX_HASH) Then
        On Error Resume Next
          Ok = .uMsgCol("H" & uMsg) And (Err = 0)  
        On Error GoTo 0
      End If
    Else
      Ok = True
    End If
    If Ok Then
      CopyMemory oMsgHook, .MsgHookPtr, 4
      oMsgHook.RaiseBefore uMsg, wParam, lParam, retVal
      If uMsg Then
        retVal = CallWindowProcA(.ProcAddr, hWnd, uMsg, wParam, lParam)
        oMsgHook.RaiseAfter uMsg, wParam, lParam
      End If
      CopyMemory oMsgHook, 0&, 4
    Else
      retVal = CallWindowProcA(.ProcAddr, hWnd, uMsg, wParam, lParam)
    End If
  End With
  WndProc = retVal
End Function

Public Function WndProc1(ByVal hWnd As Long, ByVal uMsg As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long
  WndProc1 = WndProc(1, hWnd, uMsg, wParam, lParam)
End Function

Public Function WndProc2(ByVal hWnd As Long, ByVal uMsg As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long
  WndProc2 = WndProc(2, hWnd, uMsg, wParam, lParam)
End Function

Public Function WndProc3(ByVal hWnd As Long, ByVal uMsg As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long
  WndProc3 = WndProc(3, hWnd, uMsg, wParam, lParam)
End Function

Public Function WndProc4(ByVal hWnd As Long, ByVal uMsg As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long
  WndProc4 = WndProc(4, hWnd, uMsg, wParam, lParam)
End Function

Public Function WndProc5(ByVal hWnd As Long, ByVal uMsg As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long
  WndProc5 = WndProc(5, hWnd, uMsg, wParam, lParam)
End Function

Public Function WndProc6(ByVal hWnd As Long, ByVal uMsg As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long
  WndProc6 = WndProc(6, hWnd, uMsg, wParam, lParam)
End Function

Public Function WndProc7(ByVal hWnd As Long, ByVal uMsg As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long
  WndProc7 = WndProc(7, hWnd, uMsg, wParam, lParam)
End Function

Public Function WndProc8(ByVal hWnd As Long, ByVal uMsg As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long
  WndProc8 = WndProc(8, hWnd, uMsg, wParam, lParam)
End Function

Public Function WndProc9(ByVal hWnd As Long, ByVal uMsg As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long
  WndProc9 = WndProc(9, hWnd, uMsg, wParam, lParam)
End Function

Public Function WndProcX(ByVal hWnd As Long, ByVal uMsg As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long
  Dim Nr As Long
On Error Resume Next
  Nr = NrCol("H" & hWnd)  
On Error GoTo 0
  If Nr Then WndProcX = WndProc(Nr, hWnd, uMsg, wParam, lParam)
End Function
'---------'---------'---------'---------'---------'---------'---------  

Private Function Addr2Long(ByVal Addr As Long) As Long
  Addr2Long = Addr
End Function



Option Explicit

Public Enum WM_CONST
    WM_MOUSEWHEEL = &H20A
End Enum

Public Event After(ByRef uMsg As Long, ByRef wParam As Long, _
    ByRef lParam As Long)
Public Event Before(ByRef uMsg As Long, ByRef wParam As Long, _
    ByRef lParam As Long, ByRef retVal As Long)

Private Nr As Long
'---------'---------'---------'---------'---------'---------'---------  

Public Sub Hook(ByVal hWnd As Long, ParamArray uMsg() As Variant)
  Dim i As Long
  Dim v As Variant
  
  If Nr Then DoUnhook Nr
  v = uMsg
  Nr = DoHook(ObjPtr(Me), hWnd, v)
End Sub

Public Sub RaiseAfter(ByRef uMsg As Long, _
    ByRef wParam As Long, ByRef lParam As Long)
  RaiseEvent After(uMsg, wParam, lParam)
End Sub

Public Sub RaiseBefore(ByRef uMsg As Long, _
    ByRef wParam As Long, ByRef lParam As Long, ByRef retVal As Long)
  RaiseEvent Before(uMsg, wParam, lParam, retVal)
End Sub

Public Sub Unhook()
  DoUnhook Nr
  Nr = 0
End Sub
'---------'---------'---------'---------'---------'---------'---------  

Private Sub Class_Terminate()
  If Nr Then DoUnhook Nr
End Sub

im resize ereignis habe ich die unhook und im unload ereignis auch. Im resizze muss ich den unhook setzen da sonst ein fehler kommt da hwnd eine andere zahl liefert und dann die klasse versucht da was zu machen und dort aber ncihts machen kann.
Hoffe mal das mir hier jemand helfen kann.

Frage also wie bekomme ich es hin das wenn cih das Programm wieder maximiere das es wieder scrollt.

Gruß

Sven

Lösung
Den hook aufruf einfach in den got_focus des Datagrids setzen. Dann klappt es mit dem Scrollen. Problem ist nun nur noch das im zweiten Beitrag von mir

Content-ID: 83030

Url: https://administrator.de/contentid/83030

Ausgedruckt am: 24.11.2024 um 17:11 Uhr

SvenGuenter
SvenGuenter 13.03.2008 um 14:42:19 Uhr
Goto Top
Hat sich soweit erledigt aber eine kleine Frage habe ich noch auch wenn ich weitergooglen werde.
Ich habe es soweit hinbekommen das sich mein Programm nciht aufhängt wenn ich minimiere und dann wieder maximiere. Aber ich kann nur die Records im Dataset scrollen wenn ich entweder den DG-Header anklicke oder den Row-Header. Dann hat das DG den Focus und das scrollen klappt. Klicke ich direkt eine Zelle an verliert das DG den Focus das verstehe ich nicht ganz. Kann mir da ener auf die Sprünge helfen?
misterdemeanor
misterdemeanor 13.03.2008 um 15:05:40 Uhr
Goto Top
Grüß Dich Sven,

sehr anschaulicher Code! Wenn ich Ihn richtig lese sehr praktisch um für einzelne Controls eines Containers "eigene" WindowProcedures zu verwenden. Also einem instanzierten MsgHook-Objekt (sozusagen per "Konstruktor") ein WindowHandle eines Controls zuzuweisen.
Wenn ich aber Deinen
'------------------------Allgemeiner[n] Teil
betrachte sieht es aus das Du der Variablen Msg(Instanz einer MsgHook) aber den Handle eines Form gibst. Jetzt kenne ich den Code den Du im Before bzw After Event von Msg hast. Sprich ob ein Mausscrollen außerhalb des DataGrids (also auf der Form allgemein) auch ein scrollen im DataGrid "verurachen" soll. Eigtl. unrelevant...

nun minimiere ich das Programm mache etwas anderes und maximiere es wieder

Also was anderes machen heißt hier zumindest keine Zugriffe mehr auf die Anwendung? OK, wirst Dir jetzt sagen: Dumme Frage, App/Form ist doch minimiert...aber ist ja nur eine Frage *g

im resize ereignis habe ich die unhook und im unload ereignis auch

Weihe alle interessierten Leser bitte ein ob es sich hier um Events-eines Forms handelt face-wink

Im resizze muss ich den unhook setzen da sonst ein fehler kommt da hwnd eine andere zahl liefert

Das kann ich jetzt nicht ganz nachvollziehen. Aber um ehrlich zu sein verstehe ich auch folgenden Code nicht ganz(im nicht näher benannten Modul innerhalb der Function WndProc)

With arrHook(Nr)
    If .uMsgCount > 0 Then
      If .uMsg(uMsg Mod MAX_HASH) Then
        On Error Resume Next
          Ok = .uMsgCol("H" & uMsg) And (Err = 0)  
        On Error GoTo 0
      End If
    Else
      Ok = True
    End If
...

Das liegt aber mehr daran das ich mit der VB6 eigenen "Boolean-Geschichte" noch nie ganz klarkam.
Wenn Du allerdings wirklich im Resize Event des Forms (?) die Unhook Methode Deiner MsgHook-Instanz(Msg) aufrufst, passiert natürlich nichts mehr! Der Eintrag im arrHook wird damit ja zurückgesetzt und Du hast keine "WindowProcedure" mehr.

Am besten einfach mal (ausführliche) Fehlerbeschreibung posten. Also wenn Du im Resize-Event des Forms (?) NICHT unhookst. face-wink Und sag mir mal bitte wo Du diesen sehr netten Code herhast.

BG; Felix -misterdemeanor-
SvenGuenter
SvenGuenter 13.03.2008 um 15:24:55 Uhr
Goto Top
Hi Felix,

Code komt von vb-tech und wurde dann von mir angepasst.

Wie gesagt er Fehler ist weg. Man muss den unhook im resize setzen da wenn die Form minimiert wird läuft das programm ja weiter und wenn ich dann ein anderes Programm noch offen habe bekommt meine klasse den hwnd von diesem Programm und mein Code versucht dann dort ein Datagrid mit meinem Namen die Scrolleigenschaft zu geben was natürlich nicht geht.

Mein Problem besteht nur noch darin das ich gerne wollen würde das ich im DG scrollen kann wenn ich direkt ins DG reinklicke und eine Zelle markiert habe.

Im Moment greift das Modul und die Klasse bei mir wenn das DG den Focus bekommt. Und nun halt das kuriose das DG hat den Focus nicht mehr wenn ich eine Zelle anklicke sondern nur wenn ich den Spaltenkopf oder den Zeilenkopf anklicke.


Gruß

Sven
misterdemeanor
misterdemeanor 13.03.2008 um 15:36:48 Uhr
Goto Top
Hey Sven,

Lösung
Den hook aufruf einfach in den got_focus des Datagrids setzen. Dann klappt es mit dem Scrollen.
Problem ist nun nur noch das im zweiten Beitrag von mir

Absoluter Schwachsinn! Entschuldige! Aber so wird immer wieder aufs neue der bestehende "Hook" gelöscht und ein neuer angelegt.
Jetzt ist mir mittlerweile auch wieder bewusst geworden das ein DataGrid (MSDATGRD.OCX mit VB SP6) bereits von Haus aus Mausscrolen unterstützt. Stellt sich mir jetzt die Frage warum die ganze Showse.
Magst Du mal den Code posten den Du im After bzw Before Event Deiner MsgHook-Instanz geschrieben hast?
misterdemeanor
misterdemeanor 13.03.2008 um 15:43:44 Uhr
Goto Top
...wenn die Form minimiert wird läuft das programm ja weiter und wenn ich dann
ein anderes Programm noch offen habe bekommt meine klasse den hwnd
von diesem Programm ...

Was? Wieso? Hää?
Sorry, verstehe ich nicht. Aus welchem Grund sollte so etwas geschehen?
SvenGuenter
SvenGuenter 13.03.2008 um 15:45:42 Uhr
Goto Top
Tja Felix das ist nett das VB6 mit SP6 das kann. Aber leider kann das VB6 mit SP5 nicht und genau dieses Service Pack habe ich nur zur Verfügung da wir hier in der Firma ein Programm einsetzen welches nur das SP5 unterstützt. Ich weiß auch das ich in VB.net das ganze noch einfacher hätte lösen können aber leider ist dies nicht der Rahmen der mir zur Verfügung steht.

Nur Zur Info deinerseits was den Schwachsinn angeht. Ich hatte erst das "Hook" in der Form_Load stehen da ich auch davon ausgegangen bin das dies reichen würde.
Dann traten in dieser Reihenfolge die Probleme auf.
1. Programm hängt isch auf OHNE FEHLERMELDUNG wenn ich es minimiere und dann wieder maximiere.
Lösung war: unhook und das resize ereignis.

2. Problem Ich minimiere das Programm und maximiere es wieder aber wenn es maximiert wurde ging das scrollen nicht mehr. Komischerweise habe ich mir dann die hwnd angeschaut und gesehen das sich der Wert geändert hat.
Lösung ich mache das "hook" wenn das Steuerelement welches gescrollt werden soll den Focus bekommst. Nun kann ich durch anklicken des DG die Datensätze scrollen. Allerdings beschränkt sich das anklicken auf den Spaltenköpfe und die Reihenköpfe.

Du kannst mir glauben das ich hier schon einige Zeit dran sitze und im moment graue Haare bekomme. Was nicht nur daran liegt das ich das SP5 nur verwenden kann wodurch einige Steuerelemente andere Eventverhalten an den Tag legen als ich bisher kannte.


Gruß

Sven
SvenGuenter
SvenGuenter 13.03.2008 um 15:46:34 Uhr
Goto Top
ließ meine Antwort auf den Beitrag von dir mit dem Schwachsinn. ;o)

Und verstehen tu ich es auch nicht, sonst würde ich mich hier nciht melden face-confused
misterdemeanor
misterdemeanor 13.03.2008 um 17:14:05 Uhr
Goto Top
Tja Felix das ist nett das VB6 mit SP6 das
kann. Aber leider kann das VB6 mit SP5 nicht
und genau dieses Service Pack habe ich nur
zur Verfügung da wir hier in der Firma
ein Programm einsetzen welches nur das SP5
unterstützt. Ich weiß auch das ich
in VB.net das ganze noch einfacher hätte
lösen können aber leider ist dies
nicht der Rahmen der mir zur Verfügung
steht.

Nur Zur Info deinerseits was den Schwachsinn
angeht. Ich hatte erst das "Hook"
in der Form_Load stehen da ich auch davon
ausgegangen bin das dies reichen würde.
Dann traten in dieser Reihenfolge die
Probleme auf.
1. Programm hängt isch auf OHNE
FEHLERMELDUNG wenn ich es minimiere und dann
wieder maximiere.
Lösung war: unhook und das resize
ereignis.

2. Problem Ich minimiere das Programm und
maximiere es wieder aber wenn es maximiert
wurde ging das scrollen nicht mehr.
Komischerweise habe ich mir dann die hwnd
angeschaut und gesehen das sich der Wert
geändert hat.
Lösung ich mache das "hook"
wenn das Steuerelement welches gescrollt
werden soll den Focus bekommst. Nun kann ich
durch anklicken des DG die Datensätze
scrollen. Allerdings beschränkt sich das
anklicken auf den Spaltenköpfe und die
Reihenköpfe.

Du kannst mir glauben das ich hier schon
einige Zeit dran sitze und im moment graue
Haare bekomme. Was nicht nur daran liegt das
ich das SP5 nur verwenden kann wodurch einige
Steuerelemente andere Eventverhalten an den
Tag legen als ich bisher kannte.


Gruß

Sven