none
SetWindowLong (window procedure to intercept Windows Messages) in VB.NET RRS feed

  • Question

  • I am trying to make some conversions from VB6 to VB.NET and have run across a situation.  

    In trying to convert it to VB.NET, I was having to make calls to SetWindowLong and changing the WindowProc which required the 3rd parameter to use a delegate in VB.NET and able to get rid of delegate issue but getting an error in UnHookWinProc() (this method that I have mentioned in my code)method. Please find the piece of code.
    Created delegate as like below
     Delegate Function WindowProc(ByVal hWnd As IntPtr, ByVal uMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer)

    Declared SetWindowLong  like below
    Declare Function SetWindowLong Lib "User32.dll" (ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal newWndProc As WindowProc) As IntPtr

    first method where I am calling SetWindowLong which works fine
        Private Sub HookWinProc()
     hookedProc = New WindowProc(AddressOf HookedWindowProc)
            glnghPrevWnd = SetWindowLong(hwnd, GWL_WNDPROC, hookedProc)
      End Sub


    Second method where I am calling SetWindowLong which is throwing an error.

       Private Sub UnHookWinProc()

            Dim temp As Long
            temp = SetWindowLong(hwnd, GWL_WNDPROC, glnghPrevWnd)

             End Sub

    in the above method I am getting error like BC30311 Value of type 'IntPtr' cannot be converted to 'InstDS.WindowProc  for parameter  glnghPrevWnd .  Any help would be appreciated
    • Edited by adushetty Friday, October 13, 2017 1:02 PM
    Friday, October 13, 2017 2:15 AM

Answers

  • Hi thanks for all you help. the below code will also work. Please confirm can I use below code?

       Private Sub HookWindowMessage()
            hookedProc = New WindowProc(AddressOf HookedWindowProc)
            lpPrevWndProc = SetWindowLongPtr(hwnd, GWL_WNDPROC, hookedProc)
        End Sub

        Private Sub UnhookWindowMessage()

            hookedProc = Function() lpPrevWndProc
            Dim temp As Long
            temp = SetWindowLongPtr(hwnd, GWL_WNDPROC, hookedProc)
        End Sub

     You just need to set the lpPrevWndProc to the window the same way you assigned the hookedProc to the window.  That is why you need the two different overloads of the SetWindowLong function.  The one to hook the WinProc takes a WindowProcCallback delegate as the last parameter and the one that sets it back to the original WinProc takes an IntPtr type as the last parameter.

     This is what Viorel explained in his post and it is also what i showed in my second post's code example.  Please look back at my example and see how i did it in the Hook button and Unhook button click events.  In my example,  the loNativeProc variable would be the same as your lpPrevWndProc variable and my wpcallback delegate would be the same as your hookedProc delegate.


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Sunday, October 15, 2017 9:26 PM
    • Marked as answer by adushetty Monday, October 16, 2017 7:10 PM
    Sunday, October 15, 2017 9:25 PM
  • Thanks IronRazerz. 
    • Marked as answer by adushetty Friday, October 27, 2017 2:04 PM
    Monday, October 16, 2017 7:11 PM

All replies

  • Any help on this?
    Saturday, October 14, 2017 4:30 PM
  •  The SetWindowLong function returns an IntPtr type,  not a Long type which you are trying to use.  Change your 'temp' variable to an IntPtr type.

            Dim temp As IntPtr
            temp = SetWindowLong(hwnd, GWL_WNDPROC, glnghPrevWnd)

     In VB6 they used Longs for handles but,  in VB.Net they use IntPtr types for handles.  Not sure what the rest of your code looks like so,  i am not sure exactly what the error is suggesting.


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Saturday, October 14, 2017 6:41 PM
    Saturday, October 14, 2017 6:35 PM
  • Try adding another declaration:

    Declare Function SetWindowLong2 Lib "User32.dll" Alias "SetWindowLong" (ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal newWndProc As IntPtr) As IntPtr

    Then use it in your second case:

    SetWindowLong2(hwnd, GWL_WNDPROC, glnghPrevWnd)


    • Edited by Viorel_MVP Saturday, October 14, 2017 7:17 PM
    Saturday, October 14, 2017 7:15 PM
  •  Here is a good working example.  You can test it in a new form project with 2 Buttons and 1 PictureBox added to the form.  If you run it and click the mouse on the PictureBox,  nothing happens.  If you then click the Hook button and then click the PictureBox,  the hooked WinProc of the PictureBox will detect the WM_MouseUp message and pop up a messagebox.  The Unhook button will of coarse set the WinProc of the PictureBox back to the original.

    Imports System.Runtime.InteropServices

    Public Class Form1
        <DllImport("user32.dll", EntryPoint:="SetWindowLongW")>
        Private Shared Function SetWindowLongW(ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal dwCallBack As IntPtr) As IntPtr
        End Function

        <DllImport("user32.dll", EntryPoint:="SetWindowLongW")>
        Private Shared Function SetWindowLongW(ByVal hWnd As IntPtr, ByVal nIndex As Integer, ByVal dwCallBack As WindowProcCallback) As IntPtr
        End Function

        <DllImport("user32.dll", EntryPoint:="CallWindowProcW")>
        Private Shared Function CallWindowProcW(ByVal wndproc As IntPtr, ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
        End Function

        Private Delegate Function WindowProcCallback(ByVal hWnd As IntPtr, ByVal iMsg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer

        Private Const GWL_WNDPROC As Integer = -4
        Private Const WM_LBUTTONUP As Integer = &H202

        Private wpcallback As WindowProcCallback = Nothing
        Private loNativeProc As IntPtr

        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
            wpcallback = New WindowProcCallback(AddressOf WindowProc) 'create the new callback delegate when this form loads
        End Sub

        Private Sub Button_Hook_Click(sender As Object, e As EventArgs) Handles Button_Hook.Click
            loNativeProc = SetWindowLongW(PictureBox1.Handle, GWL_WNDPROC, wpcallback) 'hook the WinProc of the PictureBox
        End Sub

        Private Sub Button_Unhook_Click(sender As Object, e As EventArgs) Handles Button_Unhook.Click
            SetWindowLongW(PictureBox1.Handle, GWL_WNDPROC, loNativeProc) 'unhook the WinProc of the PictureBox
        End Sub

        Protected Function WindowProc(ByVal hWnd As IntPtr, ByVal iMsg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
            'captures the left mouse button being released on the picturebox just to show that this example works
            If iMsg = WM_LBUTTONUP Then
                MessageBox.Show("Left Button Released.")
            End If
            Return CallWindowProcW(loNativeProc, hWnd, iMsg, wParam, lParam)
        End Function
    End Class
     

     Here you can see it working...

     

     Also i should add that the SetWindowLong function has been superseded by the SetWindowLongPtr function.  Please see the first few sentences in both of those links for more details.


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Saturday, October 14, 2017 7:48 PM
    Saturday, October 14, 2017 7:25 PM
  •  I figured i would also show you another method which does not require the use of win32 apis in your code.  It uses the NativeWindow Class to do all the work.  This example does pretty much the same as the SetWindowLong example i just posted.  It is a little different but,  i am not sure what you are doing and just figured it may be another approach to look at.

     Since the WinProc is in a separate class,  you could use a public event or events to send messages back to the form's class if that is needed.

    Public Class Form1
        Private SbCls As SubClassedWindow = Nothing
    
        Private Sub Button_Hook_Click(sender As Object, e As EventArgs) Handles Button_Hook.Click
            If SbCls Is Nothing Then
                SbCls = New SubClassedWindow(PictureBox1.Handle)
            End If
        End Sub
    
        Private Sub Button_Unhook_Click(sender As Object, e As EventArgs) Handles Button_Unhook.Click
            If SbCls IsNot Nothing Then
                SbCls.ReleaseHandle()
                SbCls = Nothing
            End If
        End Sub
    End Class
    
    
    Public Class SubClassedWindow
        Inherits NativeWindow
    
        Public Sub New(hWnd As IntPtr)
            Me.AssignHandle(hWnd)
        End Sub
    
        Private Const WM_LBUTTONUP As Integer = &H202
    
        Protected Overrides Sub WndProc(ByRef m As Message)
            If m.Msg = WM_LBUTTONUP Then
                MessageBox.Show("Left Button Released.")
            End If
            MyBase.WndProc(m)
        End Sub
    End Class


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Saturday, October 14, 2017 8:18 PM
    Saturday, October 14, 2017 8:16 PM
  • Hi thanks for all you help. the below code will also work. Please confirm can I use below code?

       Private Sub HookWindowMessage()
            hookedProc = New WindowProc(AddressOf HookedWindowProc)
            lpPrevWndProc = SetWindowLongPtr(hwnd, GWL_WNDPROC, hookedProc)
        End Sub

        Private Sub UnhookWindowMessage()

            hookedProc = Function() lpPrevWndProc
            Dim temp As Long
            temp = SetWindowLongPtr(hwnd, GWL_WNDPROC, hookedProc)
        End Sub

    Sunday, October 15, 2017 8:59 PM
  • Hi thanks for all you help. the below code will also work. Please confirm can I use below code?

       Private Sub HookWindowMessage()
            hookedProc = New WindowProc(AddressOf HookedWindowProc)
            lpPrevWndProc = SetWindowLongPtr(hwnd, GWL_WNDPROC, hookedProc)
        End Sub

        Private Sub UnhookWindowMessage()

            hookedProc = Function() lpPrevWndProc
            Dim temp As Long
            temp = SetWindowLongPtr(hwnd, GWL_WNDPROC, hookedProc)
        End Sub

     You just need to set the lpPrevWndProc to the window the same way you assigned the hookedProc to the window.  That is why you need the two different overloads of the SetWindowLong function.  The one to hook the WinProc takes a WindowProcCallback delegate as the last parameter and the one that sets it back to the original WinProc takes an IntPtr type as the last parameter.

     This is what Viorel explained in his post and it is also what i showed in my second post's code example.  Please look back at my example and see how i did it in the Hook button and Unhook button click events.  In my example,  the loNativeProc variable would be the same as your lpPrevWndProc variable and my wpcallback delegate would be the same as your hookedProc delegate.


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Sunday, October 15, 2017 9:26 PM
    • Marked as answer by adushetty Monday, October 16, 2017 7:10 PM
    Sunday, October 15, 2017 9:25 PM
  • Thanks IronRazerz. 
    • Marked as answer by adushetty Friday, October 27, 2017 2:04 PM
    Monday, October 16, 2017 7:11 PM