问题
I'm trying to write a better (I think is better) and reusable WndProc procedure, but the code below does not work because when I add more arguments to the sub firm it says that the sub does not accept that amount of arguments, of course that is reasonable.
But I know that this trick can be done because I've seen this same wndproc sub with a lot of custom arguments time ago in some thirdparty classes which I don't remember where I've seen neither I don't remember how them did the trick.
Then, someone could help me to fix this code and to improve it if it has something wrong?
Also, there is something to remark about the performance doing a modification like this? really I don't know if something like this can affect the performance in some way.
''' <summary>
''' Windows Message Identifiers.
''' </summary>
Private Enum Messages As Integer
''' <summary>
''' Message is sent when the user chooses a command from the system menu,
''' or when the user chooses the "maximize", "minimize", "restore", or "close" buttons.
''' </summary>
WM_SYSCOMMAND = &H112
End Enum
''' <summary>
''' Intercepts Windows messages for this Window.
''' </summary>
''' <param name="MsgInt32">
''' Message Identifier as Integer.
''' </param>
''' <param name="MsgWin32">
''' Message Identifier as Win32Hex format.
''' </param>
''' <param name="MsgHex">
''' Message Identifier as Hexadecimal format.
''' </param>
''' <param name="HWnd">
''' Window Handle.
''' </param>
''' <param name="LParam">
''' LParan message argument.
''' </param>
''' <param name="WParam">
''' WParam message argument.
''' </param>
''' <param name="Result">
''' Specifies the value that is returned to window in response to handling the message.
''' </param>
Protected Overrides Sub WndProc(ByRef m as Message,
ByRef MsgInt32 As Integer
ByRef MsgWin32 As String,
ByRef MsgHex As String,
ByRef HWnd As IntPtr,
ByRef LParam As IntPtr,
ByRef WParam As IntPtr,
ByRef Result As IntPtr)
Select Case MsgInt32
Case Messages.WM_SYSCOMMAND
MsgBox(MsgWin32)
MsgBox(LParam)
MsgBox(WParam)
End Select
' Return control to base message handler.
MyBase.WndProc(m, CInt(m.Msg), "&H" & Hex(m.Msg), Hex(m.Msg), m.HWnd, m.LParam, m.WParam, m.Result)
End Sub
UPDATE:
I've found one of the original codes that I will to reproduce to manage messages easier.
Public Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" (ByVal _
lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam _
As Long, ByVal lParam As Long) As Long
Public Delegate Function ipWindowProc(ByVal hwnd As Integer, ByVal uMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Dim ip As ipWindowProc = AddressOf Me.WindowProc
' The following function acts as Form1's window procedure to process messages.
Public Function WindowProc(ByVal hwnd As Integer, ByVal uMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Dim bTopMost As Boolean = Me.TopMost
Dim hMenu As Integer = 0
Dim iRet As Integer = 0
Dim mii As MENUITEMINFO
Select Case uMsg
Case WM_INITMENU
hMenu = GetSystemMenu(hwnd, 0)
mii.cbSize = Len(mii)
mii.fMask = MIIM_STATE
If bTopMost = True Then
mii.fState = MFS_ENABLED Or MFS_CHECKED
Else
mii.fState = MFS_ENABLED Or 0
End If
iRet = SetMenuItemInfo(hMenu, 1, 0, mii)
WindowProc = 0
Case WM_SYSCOMMAND
If wParam = 1 Then
mii.cbSize = Len(mii)
mii.fMask = MIIM_STATE
If bTopMost = True Then
mii.fState = MFS_ENABLED Or 0
iRet = SetMenuItemInfo(hMenu, 1, 0, mii)
Me.TopMost = False
Else
mii.fState = MFS_ENABLED Or MFS_CHECKED
iRet = SetMenuItemInfo(hMenu, 1, 0, mii)
Me.TopMost = True
End If
WindowProc = 0
Else
WindowProc = CallWindowProc(ioProc, hwnd, uMsg, wParam, lParam)
End If
Case Else
WindowProc = CallWindowProc(ioProc, hwnd, uMsg, wParam, lParam)
End Select
End Function
UPDATE 2
Well, I have translated this from the code above, now what I need to add to make it working as a wndproc replacement like in the code above?
public class form1
<System.Runtime.InteropServices.
DllImport("user32.dll")>
Private Shared Function CallWindowProc(
ByVal lpPrevWndFunc As WndProcDelegate,
ByVal hWnd As IntPtr,
ByVal Msg As UInteger,
ByVal wParam As IntPtr,
ByVal lParam As IntPtr
) As IntPtr
End Function
Delegate Function WndProcDelegate(
ByVal hWnd As IntPtr,
ByVal msg As UInteger,
ByVal wParam As IntPtr,
ByVal lParam As IntPtr
) As IntPtr
''' <summary>
''' Process Windows messages.
''' This function acts as wndproc.
''' </summary>
Public Function WindowProc(ByVal hwnd As IntPtr,
ByVal uMsg As UInteger,
ByVal wParam As IntPtr,
ByVal lParam As IntPtr) As Integer
Select Case uMsg
Case &H112
MsgBox("Message intercepted!")
End Select
End Function
End class
回答1:
Why?...why would you do this?
You're just opening yourself up to making mistakes. An old school VB6 program would use this type of API because of the simple fact that the language didn't provide a built-in way of doing it. If you needed to go low level then that was one way of doing it.
VB.Net gives this to you for free, though, by allowing you to override WndProc().
That API doesn't make managing messages any easier. All those "extra" parameters you're trying to access by using this API are already there in the Message parameter called "m" in the canned WndProc() procedure:
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
MyBase.WndProc(m)
End Sub
Take a look at the Properties listed for Message:
Those values are all there. You can make a nice Select Case Statement using m.Msg
:
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
Select Case m.Msg
Case WM_LBUTTONDOWN
Case WM_RBUTTONDOWN
End Select
MyBase.WndProc(m)
End Sub
...and you can access the other params the same way. You can set the Result() property to change the way the message is handled. You can even change the message, etc. If you want a friendly String version of the message then use m.ToString()
.
It's all there my friend...using the API doesn't give you anything you don't already have, it just creates more work on your part.
来源:https://stackoverflow.com/questions/19959131/trying-to-write-a-better-wndproc-handling