XML Documents from Comments
By typing ''' (three apostrophes), the IDE will generate the <summary> and <remarks> tags. If the commented item is a function, a <param> tag with the name attribute will be generated for each argument. Also, if the commented member is a function, the <returns> tag will be generated. (See any method for examples of <summary> and <remarks>. Refer to BlockAltTab for an example of the <returns> tag, and see TestForm_Load for examples of <param>.
The <summary> block represents straight code comments. The <remarks> tag can used to add cross references with the <seealso> tag and cref attribute. (See BlockAltEscape for an example of <seealso>. The <param> tag has a name attribute indicating the name of the parameter, and the <returns> tag is empty. You can specify the type that the function returns by typing it in between the opening and closing <returns></returns> tag pair.
Indicating an Exception that Can be Thrown
There are many kinds of tags you can add to your comments. The complete list is described in the MSDN help top "Recommended XML Tags for Documentation Comments." For example, if a function throws an exception as does KeyboardHooker.CheckedHooked, you can indicate that in the comments with the <exception> tag. (See Listing 2 for the KeyboardHooker class.)
Listing 2: The KeyboardHooker class demonstrates how to comment various kinds of code elements as well as introduces the <exception> tag with a cref attribute.
Option Strict Off Imports System.Runtime.InteropServices Imports System.Reflection Imports System.Windows.Forms Imports System.Diagnostics ''' <summary> ''' A wrapper for Windows API methods for low-level keyboard hooks. ''' </summary> ''' <remarks></remarks> PublicClass KeyboardHooker ''' <summary> ''' An API method to restore the keyboard event handling chain ''' </summary> ''' <param name="hHook"></param> ''' <returns></returns> ''' <remarks></remarks> Public Declare Auto Function UnhookWindowsHookEx Lib "user32" _ (ByVal hHook As Integer) As Integer ''' <summary> ''' An extended API method to hook the keyboard ''' </summary> ''' <param name="idHook"></param> ''' <param name="lpfn">Use System.Runtime.InteropServices. ''' MarshalAs for pointers</param> ''' <param name="hmod"></param> ''' <param name="dwThreadId"></param> ''' <returns></returns> ''' <remarks></remarks> Public Declare Auto Function SetWindowsHookEx Lib "User32" _ Alias "SetWindowsHookExA" ( _ ByVal idHook As Integer, _ <MarshalAs(UnmanagedType.FunctionPtr)> _ ByVal lpfn As KeyboardHookDelegate, _ ByVal hmod As Integer, ByVal dwThreadId As Integer) As Integer ''' <summary> ''' Gets the asynchronous keyboard state for detecting Ctrl key ''' combinations and such ''' </summary> ''' <param name="vKey"></param> ''' <returns></returns> ''' <remarks></remarks> Private Declare Function GetAsyncKeyState Lib "user32" _ (ByVal vKey As Integer) As Integer ''' <summary> ''' Used to call the next eyboard handler in the chain. By not ''' calling this we effectively block other applications from ''' getting keyboard events ''' </summary> ''' <param name="hHook"></param> ''' <param name="nCode"></param> ''' <param name="wParam"></param> ''' <param name="lParam"></param> ''' <returns></returns> ''' <remarks></remarks> Private Declare Function CallNextHookEx Lib "user32" _ (ByVal hHook As Integer, _ ByVal nCode As Integer, _ ByVal wParam As Integer, _ <MarshalAs(UnmanagedType.Struct)> _ ByVal lParam As KBDLLHOOKSTRUCT) As Integer ''' <summary> ''' The structure representing the keyboard state when the ''' low-level keyboard handler is called ''' </summary> ''' <remarks></remarks> Public Structure KBDLLHOOKSTRUCT Public vkCode As Integer Public scanCode As Integer Public flags As Integer Public time As Integer <MarshalAs(UnmanagedType.U8)> _ Public dwExtraInfo As Long End Structure ''' <summary> ''' Low-level keybard constants. These values ''' can go in the KBDLLHOOKSTRUCT.flags field ''' </summary> ''' <remarks><seealso cref="KBDLLHOOKSTRUCT"/></remarks> Private Const HC_ACTION = 0 ''' <summary> ''' Bitmask to check for extended keys ''' </summary> ''' <remarks></remarks> Private Const LLKHF_EXTENDED = &H1 ''' <summary> ''' Test the event-injected flag ''' </summary> ''' <remarks></remarks> Private Const LLKHF_INJECTED = &H10 ''' <summary> ''' Test the context code ''' </summary> ''' <remarks></remarks> Private Const LLKHF_ALTDOWN = &H20 ''' <summary> ''' Set the transition state ''' </summary> ''' <remarks></remarks> Private Const LLKHF_UP = &H80 ''' <summary> ''' Represents the tab key ''' </summary> ''' <remarks></remarks> Public Const VK_TAB = &H9 ''' <summary> ''' Represents the control key ''' </summary> ''' <remarks></remarks> Public Const VK_CONTROL = &H11 ''' <summary> ''' Represents the escape key ''' </summary> ''' <remarks></remarks> Public Const VK_ESCAPE = &H1B ''' <summary> ''' Represents the delete key ''' </summary> ''' <remarks></remarks> Public Const VK_DELETE = &H2E ''' <summary> ''' The function value to pass to idHook for the ''' SetWindowsHookEx API ''' </summary> ''' <remarks><seealso cref="SetWindowsHookEx"/></remarks> Private Const WH_KEYBOARD_LL = 13& ''' <summary> ''' Keyboard hook handle return by SetWindowsHookEx. ''' We're hooked if the value return is not 0 ''' </summary> ''' <remarks><seealso cref="SetWindowsHookEx"/></remarks> Public KeyboardHandle AsInteger ''' <summary> ''' An instance of the IHooker interface, representing the ''' thing that will repsond to keyboard events {i.e. the form ''' in our example} ''' </summary> ''' <remarks></remarks> Public Hooker As IHooker ''' <summary> ''' Scans the Hookstruct to figure out what combinations of ''' keys are pressed ''' </summary> ''' <param name="Hookstruct"></param> ''' <returns></returns> ''' <remarks></remarks> Public Function IsHooked(ByRef Hookstruct As KBDLLHOOKSTRUCT) _ AsBoolean Debug.WriteLine(Hookstruct.vkCode.ToString()) If (Hookstruct.vkCode = VK_ESCAPE) And _ CBool(GetAsyncKeyState(VK_CONTROL) _ And &H8000) Then Call HookedState(Hooker.BlockControlEscape, "Ctrl + Esc blocked") Return Hooker.BlockControlEscape End If If (Hookstruct.vkCode = VK_TAB) And _ CBool(Hookstruct.flags And _ LLKHF_ALTDOWN) Then Call HookedState(Hooker.BlockAltTab, "Alt + Tab blocked") Return Hooker.BlockAltTab End If If (Hookstruct.vkCode = VK_ESCAPE) And _ CBool(Hookstruct.flags And _ LLKHF_ALTDOWN) Then Call HookedState(Hooker.BlockAltEscape, "Alt + Escape blocked") Return Hooker.BlockAltEscape End If End Function ''' <summary> ''' Checks to determine if we are hooked, sending output to the ''' debug window. ''' </summary> ''' <param name="Hooked"></param> ''' <param name="Text"></param> ''' <remarks>If we use a messagebox then the hook chain is ''' goofed up by that window</remarks> Private Sub HookedState(ByVal Hooked As Boolean, _ ByVal Text As String) If (Hooked) Then 'MessageBox.Show(Text) -' lets the key stroke go through Debug.Print(Text) End If End Sub ''' <summary> ''' The wrapper's event handler to catch keyboard events and ''' pass that information to the IsHooked method for specific ''' combinations ''' </summary> ''' <param name="Code"></param> ''' <param name="wParam"></param> ''' <param name="lParam"></param> ''' <returns>Integer</returns> ''' <remarks>If we don't call CallNextHookEx then the keys are ''' blocked</remarks> Public Function KeyboardCallback(ByVal Code As Integer, _ ByVal wParam As Integer, ByRef lParam _ As KBDLLHOOKSTRUCT) _As Integer If (Code = HC_ACTION) Then If (IsHooked(lParam)) Then Return 1 End If End If Return CallNextHookEx(KeyboardHandle, _ Code, wParam, lParam) End Function ''' <summary> ''' A definition of our keyboard event handler ''' </summary> ''' <param name="Code"></param> ''' <param name="wParam"></param> ''' <param name="lparam"></param> ''' <returns></returns> ''' <remarks></remarks> Public Delegate Function KeyboardHookDelegate( _ ByVal Code As Integer, ByVal wParam As Integer, _ ByRef lparam As KBDLLHOOKSTRUCT) As Integer ''' <summary> ''' The instance of the keyboard event handler we pass this ''' as lpfn (the function pointer) to SetWindowsHookEx ''' </summary> ''' <remarks><seealso cref="HookKeyboard"/></remarks> <MarshalAs(UnmanagedType.FunctionPtr)> _ Private callback As KeyboardHookDelegate Public Sub HookKeyboard() callback = New _ KeyboardHookDelegate(AddressOf KeyboardCallback) KeyboardHandle = SetWindowsHookEx( _ WH_KEYBOARD_LL, callback, _ Marshal.GetHINSTANCE([Assembly]. _ GetExecutingAssembly.GetModules()(0)).ToInt32(), 0) Call CheckHooked() End Sub ''' <summary> ''' Were we able to hook the keyboard ''' </summary> ''' <remarks></remarks> ''' <exception cref="Exception">Exception</exception> Public Sub CheckHooked() If (Hooked()) Then Debug.Print("Keyboard hooked") Else Debug.Print("Keyboard hook failed: " & Err.LastDllError) Throw New Exception("Keyboard hook failed") End If End Sub ''' <summary> ''' Test to see if the handle is 0 or not. Non-zero means ''' the keyboard was hooked ''' </summary> ''' <returns></returns> ''' <remarks></remarks> Private Function Hooked() Hooked = KeyboardHandle <> 0 End Function ''' <summary> ''' Unhook the keybaord and restore the chain as it was before ''' we changed it ''' </summary> ''' <remarks></remarks> Public Sub UnhookKeyboard() If (Hooked()) Then Call UnhookWindowsHookEx(KeyboardHandle) End If End Sub End Class
Page 2 of 3
This article was originally published on January 8, 2008