2014-01-10 117 views
2

我寫了一個類來執行全系統熱鍵操作,這是唯一的構造:代碼分析警告有關構造

''' <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,鍵) NativeWindow.CreateHandle(的CreateParams):虛空 Object.GetHashCode()的Int32顏色.NET GlobalHorkey.vb 213

PS:該生產線213是這樣的:

Public Sub New(ByVal Modifier As HotkeyModifier, ByVal Key As Keys) 

我需要做些什麼來避免這個矛盾呢?

UPDATE

進入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

你能否將你的班級標記爲'NotInheritable'? –

+0

@CodeCaster我不知道CAXXX是一個標識符,我現在正在做我的研究,感謝信息 – ElektroStudios

+0

@Damien_The_Unbeliever不,因爲我有一個可覆蓋的方法(Dispose),更好的是我會更新我的問題類 – ElektroStudios

回答

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

Thankyou,我發現了另一個解決方案,我不確定它是否真的是一個解決方案,我將該類設置爲noninhertibale,並且刪除了Dispose方法的'Overrides'關鍵字,並且執行了其他任何修改,我希望知道我做了什麼是一個正確的解決方案。 – ElektroStudios

+2

@Elektro我認爲這也有訣竅,因爲現在你的類不能被繼承,虛擬方法只有一個實現。 – CodeCaster

2

CreateHandle是虛擬的,您自己的任何子類都可以覆蓋它,使對象構造不受控制。例如,請參閱:the documentation

VB等效CodeCaster的溶液(這是正確的)的密封

Public NotOverridable Overrides Sub _ 
         CreateHandle(cp As System.Windows.Forms.CreateParams) 
    MyBase.CreateHandle(cp) 
End Sub 
+0

謝謝,但我的班級不從控制類型繼承 – ElektroStudios

+0

@ElektroStudios對不起,您在我回答後發佈了完整的代碼。 CodeCaster是正確的,然而'NativeWindow'方法也是虛擬的。 –

相關問題