我编写了一个类来执行系统范围的热键操作,这是唯一的构造函数:
''' <summary>
''' Creates a new system-wide hotkey.
''' </summary>
''' <param name="Modifier">The keys that must be pressed in combination with the specified key.</param>
''' <param name="Key">The key used for the hotkey.</param>
''' <exception cref="IsRegisteredException"></exception>
<DebuggerStepperBoundary()>
Public Sub New(ByVal Modifier As HotkeyModifier, ByVal Key As Keys)
Me.CreateHandle(New CreateParams)
Me.PressEventArgs.ID = GetHashCode()
Me.PressEventArgs.Key = Key
Me.PressEventArgs.Modifier = Modifier
If Not NativeMethods.RegisterHotKey(Me.Handle,
Me.PressEventArgs.ID,
Me.PressEventArgs.Modifier,
Me.PressEventArgs.Key) Then
Throw New IsRegisteredException
End If
End Sub
该项目的代码分析说明了这一点:
CA2214不要调用可覆盖的方法 构造函数的GlobalHotkey.New(GlobalHotkey.HotkeyModifier,Keys)' 包含一个调用链,导致调用虚方法 由班级定义。检查以下调用堆栈是否有意外 后果:
GlobalHotkey..ctor(GlobalHotkey + HotkeyModifier,Keys) NativeWindow.CreateHandle(的CreateParams):无效 Object.GetHashCode():Int32 Color .NET GlobalHorkey.vb 213
PS:第213行是:
Public Sub New(ByVal Modifier As HotkeyModifier, ByVal Key As Keys)
我需要做些什么来避免这种冲突?
更新
进入NativeMethods类......:
<DllImport("user32.dll", SetLastError:=True)>
Public Shared Function RegisterHotKey(
ByVal hWnd As IntPtr,
ByVal id As Integer,
ByVal fsModifiers As UInteger,
ByVal vk As UInteger
) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
更新2
这是完整的课程:
#Region " Usage Examples "
'Public Class Form1
' ''' <summary>
' ''' Stores the system-wide hotkey object.
' ''' </summary>
' Private WithEvents Hotkey As GlobalHotkey = Nothing
' ''' <summary>
' ''' Initializes a new instance of the <see cref="Form1"/> class.
' ''' </summary>
' Public Sub New()
' InitializeComponent()
' ' Registers a new global hotkey on the system. (Alt + Ctrl + A)
' Hotkey = New GlobalHotkey(GlobalHotkey.HotkeyModifier.Alt Or GlobalHotkey.HotkeyModifier.Ctrl, Keys.A)
' ' Replaces the current registered hotkey with a new global hotkey on the system. (Alt + Escape)
' Hotkey = New GlobalHotkey([Enum].Parse(GetType(GlobalHotkey.HotkeyModifier), "Alt", True),
' [Enum].Parse(GetType(Keys), "Escape", True))
' End Sub
' ''' <summary>
' ''' Handles the Press event of the HotKey control.
' ''' </summary>
' Private Sub HotKey_Press(ByVal sender As Object, ByVal e As GlobalHotkey.HotKeyEventArgs) _
' Handles Hotkey.Press
' MsgBox(e.ID)
' MsgBox(e.Key.ToString)
' MsgBox(e.Modifier.ToString)
' End Sub
'End Class
#End Region
#Region " Imports "
Imports System.Runtime.InteropServices
#End Region
#Region " Global Hotkey "
''' <summary>
''' Class to perform system-wide hotkey operations.
''' </summary>
Class GlobalHotkey
Inherits NativeWindow
Implements IDisposable
#Region " API "
''' <summary>
''' Native API Methods.
''' </summary>
Public Class NativeMethods
''' <summary>
''' Defines a system-wide hotkey.
''' </summary>
''' <param name="hWnd">The hWND.</param>
''' <param name="id">The identifier of the hotkey.
''' If the hWnd parameter is NULL, then the hotkey is associated with the current thread rather than with a particular window.
''' If a hotkey already exists with the same hWnd and id parameters.</param>
''' <param name="fsModifiers">The keys that must be pressed in combination with the key specified by the uVirtKey parameter
''' in order to generate the WM_HOTKEY message.
''' The fsModifiers parameter can be a combination of the following values.</param>
''' <param name="vk">The virtual-key code of the hotkey.</param>
''' <returns>
''' <c>true</c> if the function succeeds, otherwise <c>false</c>
''' </returns>
<DllImport("user32.dll", SetLastError:=True)>
Public Shared Function RegisterHotKey(
ByVal hWnd As IntPtr,
ByVal id As Integer,
ByVal fsModifiers As UInteger,
ByVal vk As UInteger
) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
''' <summary>
''' Unregisters a hotkey previously registered.
''' </summary>
''' <param name="hWnd">The hWND.</param>
''' <param name="id">The identifier of the hotkey to be unregistered.</param>
''' <returns>
''' <c>true</c> if the function succeeds, otherwise <c>false</c>
''' </returns>
<DllImport("user32.dll", SetLastError:=True)>
Public Shared Function UnregisterHotKey(
ByVal hWnd As IntPtr,
ByVal id As Integer
) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
End Class
#End Region
#Region " Members "
''' <summary>
''' The hotkey modifier used in combination with the key.
''' </summary>
<Flags>
Public Enum HotkeyModifier As Integer
''' <summary>
''' The none
''' </summary>
None = &H0
''' <summary>
''' The alt key
''' </summary>
Alt = &H1
''' <summary>
''' The control key
''' </summary>
Ctrl = &H2
''' <summary>
''' The shift key
''' </summary>
Shift = &H4
''' <summary>
''' The win key
''' </summary>
Win = &H8
End Enum
''' <summary>
''' Event that is raised when a hotkey is pressed.
''' </summary>
Public Event Press As EventHandler(Of HotKeyEventArgs)
''' <summary>
''' Stores the Press Event Arguments.
''' </summary>
Protected PressEventArgs As New HotKeyEventArgs
''' <summary>
''' Event arguments for the Press event.
''' </summary>
Public Class HotKeyEventArgs : Inherits EventArgs
''' <summary>
''' The identifier of the hotkey.
''' </summary>
''' <value>The identifier.</value>
Public Property ID As Integer
''' <summary>
''' The key used for the hotkey.
''' </summary>
''' <value>The key.</value>
Public Property Key As Keys
''' <summary>
''' The key modifier used for the hotkey.
''' </summary>
''' <value>The modifier.</value>
Public Property Modifier As HotkeyModifier
End Class
''' <summary>
''' Exception that is thrown when a hotkey is already registered.
''' </summary>
<Serializable>
Public Class IsRegisteredException : Inherits Exception
''' <summary>
''' Initializes a new instance of the <see cref="IsRegisteredException"/> class.
''' </summary>
Sub New()
MyBase.New("Hotkey combination is already in use.")
End Sub
End Class
#End Region
#Region " Constructor "
''' <summary>
''' Creates a new system-wide hotkey.
''' </summary>
''' <param name="Modifier">The keys that must be pressed in combination with the specified key.</param>
''' <param name="Key">The key used for the hotkey.</param>
''' <exception cref="IsRegisteredException"></exception>
<DebuggerStepperBoundary()>
Public Sub New(ByVal Modifier As HotkeyModifier, ByVal Key As Keys)
Me.CreateHandle(New CreateParams)
Me.PressEventArgs.ID = GetHashCode()
Me.PressEventArgs.Key = Key
Me.PressEventArgs.Modifier = Modifier
If Not NativeMethods.RegisterHotKey(Me.Handle,
Me.PressEventArgs.ID,
Me.PressEventArgs.Modifier,
Me.PressEventArgs.Key) Then
Throw New IsRegisteredException
End If
End Sub
#End Region
#Region " WndProc "
''' <summary>
''' Invokes the default window procedure associated with this window.
''' </summary>
''' <param name="m">
''' A <see cref="T:System.Windows.Forms.Message" /> that is associated with the current Windows message.
''' </param>
Protected Overrides Sub WndProc(ByRef m As Message)
If m.Msg = 786 Then
RaiseEvent Press(Me, Me.PressEventArgs)
Else
MyBase.WndProc(m)
End If
End Sub
#End Region
#Region " IDisposable "
''' <summary>
''' To detect redundant calls when disposing.
''' </summary>
Private IsDisposed As Boolean = False
''' <summary>
''' Prevent calls to methods after disposing.
''' </summary>
''' <exception cref="System.ObjectDisposedException"></exception>
Private Sub DisposedCheck()
If Me.IsDisposed Then
Throw New ObjectDisposedException(Me.GetType().FullName)
End If
End Sub
''' <summary>
''' Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
''' </summary>
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
' IDisposable
''' <summary>
''' Releases unmanaged and - optionally - managed resources.
''' </summary>
''' <param name="IsDisposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
Protected Overridable Sub Dispose(IsDisposing As Boolean)
If Not Me.IsDisposed Then
If IsDisposing Then
NativeMethods.UnregisterHotKey(Me.Handle, Me.PressEventArgs.ID)
End If
End If
Me.IsDisposed = True
End Sub
#End Region
End Class
#End Region
答案 0 :(得分:4)
您的班级继承自NativeWindow
及其CreateHandle()
method is virtual。这是你得到警告的原因。
如果您确定需要调用此方法并且没有其他方法可以这样做,我认为您可以创建一个覆盖并密封它的类:
public class SealedNativeWindow : NativeWindow
{
public override sealed void CreateHandle(CreateParams cp)
{
base.CreateHandle(CreateParams cp);
}
}
然后让你的类从这个继承(你必须将它转换为VB.NET)。
或者你可以ignore the warning。
答案 1 :(得分:2)
CreateHandle
是虚拟的,你自己的任何子类都可以覆盖它,使得对象构造不受控制。有关示例,请参阅:the documentation。
VB相当于CodeCaster的解决方案(这是正确的)来密封方法
Public NotOverridable Overrides Sub _
CreateHandle(cp As System.Windows.Forms.CreateParams)
MyBase.CreateHandle(cp)
End Sub