Click here to Skip to main content
15,867,568 members
Articles / Programming Languages / C#
Article

MessageBox with a timeout for .NET

Rate me:
Please Sign up or sign in to vote.
4.83/5 (53 votes)
12 Aug 2004CPOL1 min read 265K   12.5K   72   52
Just like MessageBox.Show but with an added timeout parameter

Introduction

Have you ever wanted a message box that times out? Well here you go.

Using the code

  1. Add MessageBoxEx.cs to your project or assembly your project references.
  2. Change MessageBox.Show(...); calls to MessageBoxEx.Show(..., timeout);.
  3. That's it!

Notes

  1. MessageBoxEx has all 12 of the MessageBox.Show overloads.
  2. The timeout is expressed in milliseconds.
  3. MessageBoxEx does not support reentrancy. Good thing too. Why would you want to have more than one message box at the same time?
  4. If the user doesn't press a button before the timeout elapses the function will return the DialogResult of the messagebox dialogs default button.

How does it work?

Just before calling MessageBox.Show(...), SetWindowsHookEx(WH_CALLWNDPROCRET, ...) is called. The hook proc looks for a WM_INITDIALOG on a window with text equal to the message box caption. A windows timer is started on that window with the appropriate timeout. When the timeout fires EndDialog is called with the result set to the dialog default button ID. You can get that ID by sending a dialog box a DM_GETDEFID message. Pretty simple.

References

KB318804: HOW TO: Set a Windows Hook in Visual C#.NET

Acknowledgements

GipsySoft: http://www.gipsysoft.com/messagebox. You'll find a C++ implementation with many more features.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Adobe, LLC
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionAwesomesauce! Pin
Blerghl4-Dec-15 16:45
Blerghl4-Dec-15 16:45 
QuestionHow to set icon MessageBox display on Windows Taskbar ? Pin
Member 1139632522-Jan-15 20:37
Member 1139632522-Jan-15 20:37 
AnswerRe: How to set icon MessageBox display on Windows Taskbar ? Pin
Member 1084242722-Jan-15 22:22
Member 1084242722-Jan-15 22:22 
QuestionSystem.AppDomain.GetCurrentThreadId()' is obsolete Pin
Member 1034965229-Oct-13 5:10
Member 1034965229-Oct-13 5:10 
QuestionGracias CApo! Pin
ovamendocino23-Feb-13 5:37
ovamendocino23-Feb-13 5:37 
QuestionThanks Pin
vasanthkumarmk17-Aug-12 2:40
vasanthkumarmk17-Aug-12 2:40 
Questionit does not work when we use servicenotification message box (please suggest something) Pin
hsubhashis4-Jun-12 23:20
hsubhashis4-Jun-12 23:20 
AnswerRe: it does not work when we use servicenotification message box (please suggest something) Pin
RodgerB4-Jun-12 23:34
RodgerB4-Jun-12 23:34 
GeneralWow Pin
WabiSabi16-Oct-11 4:52
WabiSabi16-Oct-11 4:52 
GeneralConverted to C++/CLI Pin
Sharjith1-Sep-11 9:07
professionalSharjith1-Sep-11 9:07 
GeneralRe: Converted to C++/CLI Pin
RodgerB1-Sep-11 9:28
RodgerB1-Sep-11 9:28 
GeneralThank you! Pin
ChrisKane15-May-11 22:19
ChrisKane15-May-11 22:19 
GeneralMy vote of 5 Pin
matrixology4-May-11 5:06
matrixology4-May-11 5:06 
GeneralIts not working with DefaultDesktopOnly/ ServiceNotification option Pin
kirangiri4-Jan-11 7:26
kirangiri4-Jan-11 7:26 
GeneralIts not working with DefaultDesktopOnly/ ServiceNotification option Pin
kirangiri4-Jan-11 7:26
kirangiri4-Jan-11 7:26 
GeneralMy vote of 5 Pin
Francesco Pasquesi1-Dec-10 3:10
Francesco Pasquesi1-Dec-10 3:10 
GeneralSome enhancements PinPopular
Daniel Leykauf25-Sep-10 6:59
Daniel Leykauf25-Sep-10 6:59 
Thanks Rodger for the great posting; it helped me a lot!

Attached the vb.net code with a few enhancements:

1. The remaining time will be shown either in text or in caption if the placeholder {0} can be found.
2. The timeout can be set to 0 to have no timing.
3. Possibility to show a checkbox below the buttons - e.g.: Dont ask me again. The checkstate will be
returned as CheckAndExDialogResult
4. New DialogResults (ExDialogResult): Save, Discard, TryAgain and Continue to use this MessageBox also as
"Unsaved changes" dialog with save, discard and cancel results; therefore is does not longer return the
System.Windows.Forms.DialogResult.
5. Adding of language support: The button text will be replaced by GUI language - if there are native
speakers of below languages pls. feel free to correct the google translations. Thanks for that!!
Additional languages can be easy included: Just a the related enumeration and change the small part
within the sub: _setLanguage.
The languages are: English, German, French, Spain, Portugese, Polish, Czech and Dutch.

Here the code:
#Region " Imports "
Imports System.Text
Imports System.Runtime.InteropServices
Imports System.Security.Permissions
Imports System.Reflection
#End Region

'--------------------------------------------------------------------------
'Purpose:       Standard MessageBox with TimeOut
'Original code: http://www.codeproject.com/KB/miscctrl/CsMsgBoxTimeOut.aspx
'               Author: RodgerB / 13.08.2004
'               Licence: CPOL > http://www.codeproject.com/info/cpol10.aspx
'--------------------------------------------------------------------------
'Changed by:    Daniel Leykauf (23.09.2010)
'Changes:       - TimeOut can be set to 0 to have no automated closing
'               - If a placeholder ({0}) is used in Text or Caption, the 
'                 remaining time will be shown
'               - Possibility to show a CheckBox and to retrieve its value
'                 (e.g. "Don't remind me again.")
'               - Added of language support: Buttons will be shown in GUI 
'                 language instead of system language
'--------------------------------------------------------------------------

<Assembly: SecurityPermission(SecurityAction.RequestMinimum, UnmanagedCode:=True)> 
Namespace ExDialogs

    Public Enum ExDialogResult
        Abort = 3
        Cancel = 2
        Ignore = 5
        No = 7
        OK = 1
        Retry = 4
        Yes = 6
        TryAgain = 10
        [Continue] = 11
        Save = 12
        Discard = 13
    End Enum

    Public Enum ExMessageBoxButtons
        OK = 0
        OKCancel = 1
        AbortRetryIgnore = 2
        YesNoCancel = 3
        YesNo = 4
        RetryCancel = 5
        CancelTryContinue = 6
        SaveDiscardCancel = 7
    End Enum

    Public Class ExMessageBox

#Region " Show with checkbox "
        Public Shared Function Show(ByVal Text As String, ByVal CheckMsgText As String, ByVal Checked As Boolean, ByVal uTimeout As UInteger) As CheckAndExDialogResult
            _setup([Assembly].GetExecutingAssembly.GetName.Name, uTimeout)
            mChecked = Checked
            mButtons = ExMessageBoxButtons.OK
            mCheckMsgText = CheckMsgText
            Return New CheckAndExDialogResult(_getResult(MessageBox.Show(Text, [Assembly].GetExecutingAssembly.GetName.Name)), Math.Abs(CInt(mChecked)))
        End Function

        Public Shared Function Show(ByVal text As String, ByVal caption As String, ByVal CheckMsgText As String, ByVal Checked As Boolean, ByVal uTimeout As UInteger) As CheckAndExDialogResult
            _setup(caption, uTimeout)
            mButtons = ExMessageBoxButtons.OK
            mChecked = Checked
            mCheckMsgText = CheckMsgText
            Return New CheckAndExDialogResult(_getResult(MessageBox.Show(text, caption)), Math.Abs(CInt(mChecked)))
        End Function

        Public Shared Function Show(ByVal text As String, ByVal caption As String, ByVal CheckMsgText As String, ByVal Checked As Boolean, ByVal buttons As ExMessageBoxButtons, ByVal uTimeout As UInteger) As CheckAndExDialogResult
            _setup(caption, uTimeout)
            mButtons = buttons
            mChecked = Checked
            mCheckMsgText = CheckMsgText
            Return New CheckAndExDialogResult(_getResult(MessageBox.Show(text, caption, _getButtons)), Math.Abs(CInt(mChecked)))
        End Function

        Public Shared Function Show(ByVal text As String, ByVal caption As String, ByVal CheckMsgText As String, ByVal Checked As Boolean, ByVal buttons As ExMessageBoxButtons, ByVal icon As MessageBoxIcon, ByVal uTimeout As UInteger) As CheckAndExDialogResult
            _setup(caption, uTimeout)
            mButtons = buttons
            mChecked = Checked
            mCheckMsgText = CheckMsgText
            Return New CheckAndExDialogResult(_getResult(MessageBox.Show(text, caption, _getButtons, icon)), Math.Abs(CInt(mChecked)))
        End Function

        Public Shared Function Show(ByVal text As String, ByVal caption As String, ByVal CheckMsgText As String, ByVal Checked As Boolean, ByVal buttons As ExMessageBoxButtons, ByVal icon As MessageBoxIcon, ByVal defButton As MessageBoxDefaultButton, ByVal uTimeout As UInteger) As CheckAndExDialogResult
            _setup(caption, uTimeout)
            mButtons = buttons
            mChecked = Checked
            mCheckMsgText = CheckMsgText
            Return New CheckAndExDialogResult(_getResult(MessageBox.Show(text, caption, _getButtons, icon, defButton)), Math.Abs(CInt(mChecked)))
        End Function

        Public Shared Function Show(ByVal text As String, ByVal caption As String, ByVal CheckMsgText As String, ByVal Checked As Boolean, ByVal buttons As ExMessageBoxButtons, ByVal icon As MessageBoxIcon, ByVal defButton As MessageBoxDefaultButton, ByVal uTimeout As UInteger, ByVal displayHelpButton As Boolean) As CheckAndExDialogResult
            _setup(caption, uTimeout)
            mButtons = buttons
            mChecked = Checked
            mCheckMsgText = CheckMsgText
            Return New CheckAndExDialogResult(_getResult(MessageBox.Show(text, caption, _getButtons, icon, defButton, 0, displayHelpButton)), Math.Abs(CInt(mChecked)))
        End Function

        Public Shared Function Show(ByVal text As String, ByVal caption As String, ByVal CheckMsgText As String, ByVal Checked As Boolean, ByVal buttons As ExMessageBoxButtons, ByVal icon As MessageBoxIcon, ByVal defButton As MessageBoxDefaultButton, ByVal options As MessageBoxOptions, _
          ByVal uTimeout As UInteger) As CheckAndExDialogResult
            _setup(caption, uTimeout)
            mButtons = buttons
            mChecked = Checked
            mCheckMsgText = CheckMsgText
            Return New CheckAndExDialogResult(_getResult(MessageBox.Show(text, caption, _getButtons, icon, defButton, options)), Math.Abs(CInt(mChecked)))
        End Function

        Public Shared Function Show(ByVal text As String, ByVal caption As String, ByVal CheckMsgText As String, ByVal Checked As Boolean, ByVal buttons As ExMessageBoxButtons, ByVal icon As MessageBoxIcon, ByVal defButton As MessageBoxDefaultButton, ByVal options As MessageBoxOptions, _
           ByVal uTimeout As UInteger, ByVal displayHelpButton As Boolean) As CheckAndExDialogResult
            _setup(caption, uTimeout)
            mButtons = buttons
            mChecked = Checked
            mCheckMsgText = CheckMsgText
            Return New CheckAndExDialogResult(_getResult(MessageBox.Show(text, caption, _getButtons, icon, defButton, options, displayHelpButton)), Math.Abs(CInt(mChecked)))
        End Function

        Public Shared Function Show(ByVal text As String, ByVal caption As String, ByVal CheckMsgText As String, ByVal Checked As Boolean, ByVal buttons As ExMessageBoxButtons, ByVal icon As MessageBoxIcon, ByVal defButton As MessageBoxDefaultButton, ByVal options As MessageBoxOptions, _
           ByVal uTimeout As UInteger, ByVal HelpFile As String) As CheckAndExDialogResult
            _setup(caption, uTimeout)
            mButtons = buttons
            mChecked = Checked
            mCheckMsgText = CheckMsgText
            Return New CheckAndExDialogResult(_getResult(MessageBox.Show(text, caption, _getButtons, icon, defButton, options, HelpFile)), Math.Abs(CInt(mChecked)))
        End Function

#End Region

#Region " Show default // "
        Public Shared Function Show(ByVal text As String, ByVal uTimeout As UInteger) As ExDialogResult
            _setup([Assembly].GetExecutingAssembly.GetName.Name, uTimeout)
            mButtons = ExMessageBoxButtons.OK
            Return _getResult(MessageBox.Show(text, [Assembly].GetExecutingAssembly.GetName.Name))
        End Function

        Public Shared Function Show(ByVal text As String, ByVal caption As String, ByVal uTimeout As UInteger) As ExDialogResult
            _setup(caption, uTimeout)
            mButtons = ExMessageBoxButtons.OK
            Return _getResult(MessageBox.Show(text, caption))
        End Function

        Public Shared Function Show(ByVal text As String, ByVal caption As String, ByVal buttons As ExMessageBoxButtons, ByVal uTimeout As UInteger) As ExDialogResult
            _setup(caption, uTimeout)
            mButtons = buttons
            Return _getResult(MessageBox.Show(text, caption, _getButtons))
        End Function

        Public Shared Function Show(ByVal text As String, ByVal caption As String, ByVal buttons As ExMessageBoxButtons, ByVal icon As MessageBoxIcon, ByVal uTimeout As UInteger) As ExDialogResult
            _setup(caption, uTimeout)
            mButtons = buttons
            Return _getResult(MessageBox.Show(text, caption, _getButtons, icon))
        End Function

        Public Shared Function Show(ByVal text As String, ByVal caption As String, ByVal buttons As ExMessageBoxButtons, ByVal icon As MessageBoxIcon, ByVal defButton As MessageBoxDefaultButton, ByVal uTimeout As UInteger) As ExDialogResult
            _setup(caption, uTimeout)
            mButtons = buttons
            Return _getResult(MessageBox.Show(text, caption, _getButtons, icon, defButton))
        End Function

        Public Shared Function Show(ByVal text As String, ByVal caption As String, ByVal buttons As ExMessageBoxButtons, ByVal icon As MessageBoxIcon, ByVal defButton As MessageBoxDefaultButton, ByVal uTimeout As UInteger, ByVal displayHelpButton As Boolean) As ExDialogResult
            _setup(caption, uTimeout)
            mButtons = buttons
            Return _getResult(MessageBox.Show(text, caption, _getButtons, icon, defButton, 0, displayHelpButton))
        End Function

        Public Shared Function Show(ByVal text As String, ByVal caption As String, ByVal buttons As ExMessageBoxButtons, ByVal icon As MessageBoxIcon, ByVal defButton As MessageBoxDefaultButton, ByVal options As MessageBoxOptions, _
          ByVal uTimeout As UInteger) As ExDialogResult
            _setup(caption, uTimeout)
            mButtons = buttons
            Return _getResult(MessageBox.Show(text, caption, _getButtons, icon, defButton, options))
        End Function

        Public Shared Function Show(ByVal text As String, ByVal caption As String, ByVal buttons As ExMessageBoxButtons, ByVal icon As MessageBoxIcon, ByVal defButton As MessageBoxDefaultButton, ByVal options As MessageBoxOptions, _
           ByVal uTimeout As UInteger, ByVal displayHelpButton As Boolean) As ExDialogResult
            _setup(caption, uTimeout)
            mButtons = buttons
            Return _getResult(MessageBox.Show(text, caption, _getButtons, icon, defButton, options, displayHelpButton))
        End Function

        Public Shared Function Show(ByVal text As String, ByVal caption As String, ByVal buttons As ExMessageBoxButtons, ByVal icon As MessageBoxIcon, ByVal defButton As MessageBoxDefaultButton, ByVal options As MessageBoxOptions, _
           ByVal uTimeout As UInteger, ByVal HelpFile As String) As ExDialogResult
            _setup(caption, uTimeout)
            mButtons = buttons
            Return _getResult(MessageBox.Show(text, caption, _getButtons, icon, defButton, options, HelpFile))
        End Function

#End Region

#Region " Show with owner "
        Public Shared Function Show(ByVal owner As IWin32Window, ByVal text As String, ByVal uTimeout As UInteger) As ExDialogResult
            _setup([Assembly].GetExecutingAssembly.GetName.Name, uTimeout)
            mButtons = ExMessageBoxButtons.OK
            Return MessageBox.Show(owner, text, [Assembly].GetExecutingAssembly.GetName.Name)
        End Function

        Public Shared Function Show(ByVal owner As IWin32Window, ByVal text As String, ByVal caption As String, ByVal uTimeout As UInteger) As ExDialogResult
            _setup(caption, uTimeout)
            mButtons = ExMessageBoxButtons.OK
            Return MessageBox.Show(owner, text, caption)
        End Function

        Public Shared Function Show(ByVal owner As IWin32Window, ByVal text As String, ByVal caption As String, ByVal buttons As ExMessageBoxButtons, ByVal uTimeout As UInteger) As ExDialogResult
            _setup(caption, uTimeout)
            mButtons = buttons
            Return MessageBox.Show(owner, text, caption, _getButtons)
        End Function

        Public Shared Function Show(ByVal owner As IWin32Window, ByVal text As String, ByVal caption As String, ByVal buttons As ExMessageBoxButtons, ByVal icon As MessageBoxIcon, ByVal uTimeout As UInteger) As ExDialogResult
            _setup(caption, uTimeout)
            mButtons = buttons
            Return MessageBox.Show(owner, text, caption, _getButtons, icon)
        End Function

        Public Shared Function Show(ByVal owner As IWin32Window, ByVal text As String, ByVal caption As String, ByVal buttons As ExMessageBoxButtons, ByVal icon As MessageBoxIcon, ByVal defButton As MessageBoxDefaultButton, _
         Optional ByVal uTimeout As UInteger = 0) As ExDialogResult
            _setup(caption, uTimeout)
            mButtons = buttons
            Return MessageBox.Show(owner, text, caption, _getButtons, icon, defButton)
        End Function

        Public Shared Function Show(ByVal owner As IWin32Window, ByVal text As String, ByVal caption As String, ByVal buttons As MessageBoxButtons, ByVal icon As MessageBoxIcon, ByVal defButton As MessageBoxDefaultButton, _
         ByVal options As MessageBoxOptions, ByVal uTimeout As UInteger) As ExDialogResult
            _setup(caption, uTimeout)
            mButtons = buttons
            Return MessageBox.Show(owner, text, caption, _getButtons, icon, defButton, options)
        End Function
#End Region

#Region "Save Dialog"
        Public Shared Function Save(ByVal text As String) As ExDialogResult
            _setup([Assembly].GetExecutingAssembly.GetName.Name, 0)
            mButtons = ExMessageBoxButtons.SaveDiscardCancel
            Return _getResult(MessageBox.Show(text, [Assembly].GetExecutingAssembly.GetName.Name, _getButtons, MessageBoxIcon.Exclamation))
        End Function

        Public Shared Function Save(ByVal text As String, ByVal defaultButton As MessageBoxDefaultButton) As ExDialogResult
            _setup([Assembly].GetExecutingAssembly.GetName.Name, 0)
            mButtons = ExMessageBoxButtons.SaveDiscardCancel
            Return _getResult(MessageBox.Show(text, [Assembly].GetExecutingAssembly.GetName.Name, _getButtons, MessageBoxIcon.Exclamation, defaultButton))
        End Function

        Public Shared Function Save(ByVal text As String, ByVal caption As String) As DialogResult
            _setup(caption, 0)
            mButtons = ExMessageBoxButtons.SaveDiscardCancel
            Return _getResult(MessageBox.Show(text, caption, _getButtons, MessageBoxIcon.Exclamation))
        End Function

        Public Shared Function Save(ByVal text As String, ByVal caption As String, ByVal defaultButton As MessageBoxDefaultButton) As ExDialogResult
            _setup(caption, 0)
            mButtons = ExMessageBoxButtons.SaveDiscardCancel
            Return _getResult(MessageBox.Show(text, caption, _getButtons, MessageBoxIcon.Exclamation, defaultButton))
        End Function

#End Region



#Region " Delegates "
        Public Delegate Function HookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
        Public Delegate Sub TimerProc(ByVal hWnd As IntPtr, ByVal uMsg As UInteger, ByVal nIDEvent As UIntPtr, ByVal dwTime As UInteger)
#End Region

#Region " Enums "
        <Flags()> _
    Private Enum SetWindowPosFlags As UInteger
            ''' <summary>If the calling thread and the thread that owns the window are attached to different input queues, 
            ''' the system posts the request to the thread that owns the window. This prevents the calling thread from 
            ''' blocking its execution while other threads process the request.</summary>
            ''' <remarks>SWP_ASYNCWINDOWPOS</remarks>
            SynchronousWindowPosition = &H4000
            ''' <summary>Prevents generation of the WM_SYNCPAINT message.</summary>
            ''' <remarks>SWP_DEFERERASE</remarks>
            DeferErase = &H2000
            ''' <summary>Draws a frame (defined in the window's class description) around the window.</summary>
            ''' <remarks>SWP_DRAWFRAME</remarks>
            DrawFrame = &H20
            ''' <summary>Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to 
            ''' the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE 
            ''' is sent only when the window's size is being changed.</summary>
            ''' <remarks>SWP_FRAMECHANGED</remarks>
            FrameChanged = &H20
            ''' <summary>Hides the window.</summary>
            ''' <remarks>SWP_HIDEWINDOW</remarks>
            HideWindow = &H80
            ''' <summary>Does not activate the window. If this flag is not set, the window is activated and moved to the 
            ''' top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter 
            ''' parameter).</summary>
            ''' <remarks>SWP_NOACTIVATE</remarks>
            DoNotActivate = &H10
            ''' <summary>Discards the entire contents of the client area. If this flag is not specified, the valid 
            ''' contents of the client area are saved and copied back into the client area after the window is sized or 
            ''' repositioned.</summary>
            ''' <remarks>SWP_NOCOPYBITS</remarks>
            DoNotCopyBits = &H100
            ''' <summary>Retains the current position (ignores X and Y parameters).</summary>
            ''' <remarks>SWP_NOMOVE</remarks>
            IgnoreMove = &H2
            ''' <summary>Does not change the owner window's position in the Z order.</summary>
            ''' <remarks>SWP_NOOWNERZORDER</remarks>
            DoNotChangeOwnerZOrder = &H200
            ''' <summary>Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to 
            ''' the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent 
            ''' window uncovered as a result of the window being moved. When this flag is set, the application must 
            ''' explicitly invalidate or redraw any parts of the window and parent window that need redrawing.</summary>
            ''' <remarks>SWP_NOREDRAW</remarks>
            DoNotRedraw = &H8
            ''' <summary>Same as the SWP_NOOWNERZORDER flag.</summary>
            ''' <remarks>SWP_NOREPOSITION</remarks>
            DoNotReposition = &H200
            ''' <summary>Prevents the window from receiving the WM_WINDOWPOSCHANGING message.</summary>
            ''' <remarks>SWP_NOSENDCHANGING</remarks>
            DoNotSendChangingEvent = &H400
            ''' <summary>Retains the current size (ignores the cx and cy parameters).</summary>
            ''' <remarks>SWP_NOSIZE</remarks>
            IgnoreResize = &H1
            ''' <summary>Retains the current Z order (ignores the hWndInsertAfter parameter).</summary>
            ''' <remarks>SWP_NOZORDER</remarks>
            IgnoreZOrder = &H4
            ''' <summary>Displays the window.</summary>
            ''' <remarks>SWP_SHOWWINDOW</remarks>
            ShowWindow = &H40
        End Enum

        Private Enum DialogStyles
            [Default]
            Save
        End Enum


#End Region

#Region " User32.dll "
        <DllImport("User32.dll")> _
        Public Shared Function SetTimer(ByVal hWnd As IntPtr, ByVal nIDEvent As UIntPtr, ByVal uElapse As UInteger, ByVal lpTimerFunc As TimerProc) As UIntPtr
        End Function

        <DllImport("User32.dll")> _
        Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
        End Function

        <DllImport("user32.dll")> _
        Public Shared Function SetWindowsHookEx(ByVal idHook As Integer, ByVal lpfn As HookProc, ByVal hInstance As IntPtr, ByVal threadId As Integer) As IntPtr
        End Function

        <DllImport("user32.dll")> _
        Public Shared Function UnhookWindowsHookEx(ByVal idHook As IntPtr) As Integer
        End Function

        <DllImport("user32.dll")> _
        Public Shared Function CallNextHookEx(ByVal idHook As IntPtr, ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
        End Function

        <DllImport("user32.dll")> _
        Public Shared Function GetWindowTextLength(ByVal hWnd As IntPtr) As Integer
        End Function

        <DllImport("user32.dll")> _
        Public Shared Function GetWindowText(ByVal hWnd As IntPtr, ByVal text As StringBuilder, ByVal maxLength As Integer) As Integer
        End Function

        <DllImport("user32.dll")> _
        Public Shared Function EndDialog(ByVal hDlg As IntPtr, ByVal nResult As IntPtr) As Integer
        End Function

        <DllImport("kernel32.dll")> _
        Private Shared Function GetCurrentThreadId() As Integer
        End Function

        <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
        Private Shared Function SetWindowText(ByVal hwnd As IntPtr, ByVal lpString As String) As Boolean
        End Function

        <DllImport("user32.dll")> _
         Private Shared Function SetDlgItemText(ByVal hWnd As IntPtr, ByVal nIDDlgItem As Integer, ByVal lpString As String) As Boolean
        End Function

        <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
        Private Shared Function GetDlgItemText(ByVal hDlg As IntPtr, ByVal nIDDlgItem As Integer, <Out()> ByVal lpString As StringBuilder, ByVal nMaxCount As Integer) As UInteger
        End Function

        <DllImport("user32.dll", SetLastError:=True)> _
        Private Shared Function SetWindowPos(ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As SetWindowPosFlags) As Boolean
        End Function

        <DllImport("user32.dll")> _
        Private Shared Function GetWindowRect(ByVal hWnd As IntPtr, ByRef lpRect As RECT) As Boolean
        End Function

        <DllImport("user32.dll", CharSet:=CharSet.Auto)> _
        Private Shared Function CreateWindowEx(ByVal dwExStyle As Integer, ByVal lpClassName As String, ByVal lpWindowName As String, ByVal dwStyle As UInteger, ByVal x As Integer, ByVal y As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal hWndParent As Integer, ByVal hMenu As Integer, ByVal hInstance As Integer, ByVal lpParam As Integer) As Integer
        End Function

        <DllImport("user32.dll")> _
        Private Shared Function DestroyWindow(ByVal hwnd As Integer) As Boolean
        End Function

#End Region

#Region " Structures "
        <StructLayout(LayoutKind.Sequential)> _
        Public Structure CWPRETSTRUCT
            Public lResult As IntPtr
            Public lParam As IntPtr
            Public wParam As IntPtr
            Public message As UInteger
            Public hwnd As IntPtr
        End Structure

        <StructLayout(LayoutKind.Sequential)> _
    Public Structure RECT
            Private _Left As Integer, _Top As Integer, _Right As Integer, _Bottom As Integer

            Public Sub New(ByVal Rectangle As Rectangle)
                Me.New(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom)
            End Sub
            Public Sub New(ByVal Left As Integer, ByVal Top As Integer, ByVal Right As Integer, ByVal Bottom As Integer)
                _Left = Left
                _Top = Top
                _Right = Right
                _Bottom = Bottom
            End Sub

            Public Property X() As Integer
                Get
                    Return _Left
                End Get
                Set(ByVal value As Integer)
                    _Left = value
                End Set
            End Property
            Public Property Y() As Integer
                Get
                    Return _Top
                End Get
                Set(ByVal value As Integer)
                    _Top = value
                End Set
            End Property
            Public Property Left() As Integer
                Get
                    Return _Left
                End Get
                Set(ByVal value As Integer)
                    _Left = value
                End Set
            End Property
            Public Property Top() As Integer
                Get
                    Return _Top
                End Get
                Set(ByVal value As Integer)
                    _Top = value
                End Set
            End Property
            Public Property Right() As Integer
                Get
                    Return _Right
                End Get
                Set(ByVal value As Integer)
                    _Right = value
                End Set
            End Property
            Public Property Bottom() As Integer
                Get
                    Return _Bottom
                End Get
                Set(ByVal value As Integer)
                    _Bottom = value
                End Set
            End Property
            Public Property Height() As Integer
                Get
                    Return _Bottom - _Top
                End Get
                Set(ByVal value As Integer)
                    _Bottom = value - _Top
                End Set
            End Property
            Public Property Width() As Integer
                Get
                    Return _Right - _Left
                End Get
                Set(ByVal value As Integer)
                    _Right = value + _Left
                End Set
            End Property
            Public Property Location() As Point
                Get
                    Return New Point(Left, Top)
                End Get
                Set(ByVal value As Point)
                    _Left = value.X
                    _Top = value.Y
                End Set
            End Property
            Public Property Size() As Size
                Get
                    Return New Size(Width, Height)
                End Get
                Set(ByVal value As Size)
                    _Right = value.Width + _Left
                    _Bottom = value.Height + _Top
                End Set
            End Property

            Public Shared Widening Operator CType(ByVal Rectangle As RECT) As Rectangle
                Return New Rectangle(Rectangle.Left, Rectangle.Top, Rectangle.Width, Rectangle.Height)
            End Operator
            Public Shared Widening Operator CType(ByVal Rectangle As Rectangle) As RECT
                Return New RECT(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom)
            End Operator
            Public Shared Operator =(ByVal Rectangle1 As RECT, ByVal Rectangle2 As RECT) As Boolean
                Return Rectangle1.Equals(Rectangle2)
            End Operator
            Public Shared Operator <>(ByVal Rectangle1 As RECT, ByVal Rectangle2 As RECT) As Boolean
                Return Not Rectangle1.Equals(Rectangle2)
            End Operator

            Public Overrides Function ToString() As String
                Return "{Left: " & _Left & "; " & "Top: " & _Top & "; Right: " & _Right & "; Bottom: " & _Bottom & "}"
            End Function

            Public Overloads Function Equals(ByVal Rectangle As RECT) As Boolean
                Return Rectangle.Left = _Left AndAlso Rectangle.Top = _Top AndAlso Rectangle.Right = _Right AndAlso Rectangle.Bottom = _Bottom
            End Function
            Public Overloads Overrides Function Equals(ByVal [Object] As Object) As Boolean
                If TypeOf [Object] Is RECT Then
                    Return Equals(DirectCast([Object], RECT))
                ElseIf TypeOf [Object] Is Rectangle Then
                    Return Equals(New RECT(DirectCast([Object], Rectangle)))
                End If

                Return False
            End Function
        End Structure
#End Region

#Region " Consts "
        Private Const TimerID As Integer = 42
        Private Const WH_CALLWNDPROCRET As Integer = 12
        Private Const WM_DESTROY As Integer = &H2
        Private Const WM_INITDIALOG As Integer = &H110
        Private Const WM_TIMER As Integer = &H113
        Private Const WM_USER As Integer = &H400
        Private Const DM_GETDEFID As Integer = WM_USER + 0
        Private Const WM_COMMAND As UInteger = &H111
        Private Const WS_VISIBLE As UInteger = &H10000000
        Private Const WS_CHILD As UInteger = &H40000000
        Private Const WS_TABSTOP As UInteger = &H10000
        Private Const WM_SETFONT As Integer = &H30
        Private Const WM_GETFONT As Integer = &H31
        Private Const BS_AUTOCHECKBOX As UInteger = &H3
        Private Const WM_NOTIFY As Integer = &H4E
        Private Const CB_SETCURSEL As Integer = &H14E
        Private Const CB_GETCURSEL As Integer = &H147
        Private Const BM_GETCHECK As Integer = &HF0
        Private Const BM_SETCHECK As Integer = &HF1
        Private Const BST_CHECKED As Integer = &H1
        Private Const BST_INDETERMINATE As Integer = &H2
        Private Const BST_UNCHECKED As Integer = &H0
#End Region

#Region " Variables "
        Private Shared mHookProc As HookProc
        Private Shared mHookTimer As TimerProc
        Private Shared mHookTimeout As Integer
        Private Shared mHookCaption As String
        Private Shared mHook As IntPtr
        Private Shared mHandle As Long
        Private Shared WithEvents mTimer As New Timer
        Private Shared mCaption As String = String.Empty
        Private Shared mdteStart As Date
        Private Shared mCheckBoxHandle As IntPtr
        Private Shared mCheckMsgText As String = String.Empty
        Private Shared mButtons As ExMessageBoxButtons
        Private Shared ReadOnly HWND_BOTTOM As New IntPtr(1)
        Private Shared ReadOnly HWND_NOTOPMOST As New IntPtr(-2)
        Private Shared ReadOnly HWND_TOP As New IntPtr(0)
        Private Shared ReadOnly HWND_TOPMOST As New IntPtr(-1)
        Private Shared mChecked As Boolean
        Private Shared mText As String = ""
#End Region

#Region " Public methods "
        Shared Sub New()
            mHookProc = New HookProc(AddressOf _messageBoxHookProc)
            mHookTimer = New TimerProc(AddressOf _messageBoxTimerProc)
            mHookTimeout = 0
            mHookCaption = Nothing
            mHook = IntPtr.Zero
        End Sub
#End Region

#Region " Private methods "
        Private Shared Function _getResult(ByVal r As DialogResult) As ExDialogResult
            Select Case mButtons
                Case ExMessageBoxButtons.SaveDiscardCancel
                    Select Case r
                        Case DialogResult.Yes
                            Return ExDialogResult.Save
                        Case DialogResult.No
                            Return ExDialogResult.Discard
                        Case Else
                            Return ExDialogResult.Cancel
                    End Select
                Case ExMessageBoxButtons.CancelTryContinue
                    Select Case r
                        Case DialogResult.Yes
                            Return ExDialogResult.Cancel
                        Case DialogResult.No
                            Return ExDialogResult.TryAgain
                        Case Else
                            Return ExDialogResult.Continue
                    End Select
                Case Else
                    Return CType(CInt(r), ExDialogResult)
            End Select
        End Function

        Private Shared Function _getButtons() As MessageBoxButtons
            Select Case mButtons
                Case ExMessageBoxButtons.AbortRetryIgnore
                    Return MessageBoxButtons.AbortRetryIgnore
                Case ExMessageBoxButtons.CancelTryContinue
                    Return MessageBoxButtons.YesNoCancel
                Case ExMessageBoxButtons.OK
                    Return MessageBoxButtons.OK
                Case ExMessageBoxButtons.OKCancel
                    Return MessageBoxButtons.OKCancel
                Case ExMessageBoxButtons.RetryCancel
                    Return MessageBoxButtons.RetryCancel
                Case ExMessageBoxButtons.SaveDiscardCancel
                    Return MessageBoxButtons.YesNoCancel
                Case ExMessageBoxButtons.YesNo
                    Return MessageBoxButtons.YesNo
                Case ExMessageBoxButtons.YesNoCancel
                    Return MessageBoxButtons.YesNoCancel
            End Select
        End Function

        Private Shared Sub _setup(ByVal caption As String, ByVal uTimeout As UInteger)
            If mHook <> IntPtr.Zero Then
                Throw New NotSupportedException("multiple calls are not supported")
            End If

            mCaption = caption
            If uTimeout > 0 Then mHookTimeout = uTimeout
            mHookCaption = If(caption IsNot Nothing, caption, "")
            mdteStart = Now

            mHook = SetWindowsHookEx(WH_CALLWNDPROCRET, mHookProc, IntPtr.Zero, GetCurrentThreadId())
            If mHookTimeout > 0 Then
                mTimer.Interval = 10
                mTimer.Enabled = True
            End If
        End Sub

        Private Shared Function _messageBoxHookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
            If nCode < 0 Then
                Return CallNextHookEx(mHook, nCode, wParam, lParam)
            End If

            Dim msg As CWPRETSTRUCT = CType(Marshal.PtrToStructure(lParam, GetType(CWPRETSTRUCT)), CWPRETSTRUCT)
            Dim hook As IntPtr = mHook

            mHandle = msg.hwnd


            If mHookCaption IsNot Nothing AndAlso msg.message = WM_INITDIALOG Then
                Dim nLength As Integer = GetWindowTextLength(msg.hwnd)
                Dim text As New StringBuilder(nLength + 1)

                GetWindowText(msg.hwnd, text, text.Capacity)

                If mHookCaption = text.ToString() AndAlso mHookTimeout > 0 Then
                    mHookCaption = Nothing
                    SetTimer(msg.hwnd, CType(TimerID, UIntPtr), mHookTimeout, mHookTimer)
                    UnhookWindowsHookEx(mHook)
                    mHook = IntPtr.Zero
                End If

                'set button language
                _setLanguage(msg.hwnd)



                If mCheckMsgText.Length > 0 Then
                    Dim r As RECT
                    GetWindowRect(msg.hwnd, r)
                    SetWindowPos(msg.hwnd, HWND_TOP, r.X, r.Y, r.Width, r.Height + 30, SetWindowPosFlags.FrameChanged)
                    Dim intWidth As Integer = TextRenderer.MeasureText(mCheckMsgText, SystemFonts.DialogFont).Width + 10

                    'create checkbox
                    Dim chkHandle As Integer = CreateWindowEx(0, "BUTTON", "myCheckBox", BS_AUTOCHECKBOX Or WS_VISIBLE Or WS_CHILD Or WS_TABSTOP, 10, r.Height - 30, _
                      intWidth, 20, msg.hwnd, 0, 0, 0)
                    SetWindowText(chkHandle, mCheckMsgText)
                    Dim fontHandle As Integer = SendMessage(msg.hwnd, WM_GETFONT, 0, 0)
                    SendMessage(chkHandle, WM_SETFONT, fontHandle, 0)
                    mCheckBoxHandle = chkHandle

                    'set checkstate
                    If mChecked Then
                        SendMessage(mCheckBoxHandle, BM_SETCHECK, BST_CHECKED, 0&)
                    Else
                        SendMessage(mCheckBoxHandle, BM_SETCHECK, BST_UNCHECKED, 0&)
                    End If
                End If

            ElseIf msg.message = WM_DESTROY Then
                If mCheckBoxHandle <> 0 Then DestroyWindow(mCheckBoxHandle)
            ElseIf msg.message = WM_COMMAND Then
                'get checkstate
                mChecked = SendMessage(mCheckBoxHandle, BM_GETCHECK, 0&, 0&)
            End If

            Return CallNextHookEx(hook, nCode, wParam, lParam)
        End Function

        Private Shared Sub _messageBoxTimerProc(ByVal hWnd As IntPtr, ByVal uMsg As UInteger, ByVal nIDEvent As UIntPtr, ByVal dwTime As UInteger)
            If nIDEvent = CType(TimerID, UIntPtr) Then
                mTimer.Enabled = False
                mTimer.Dispose()
                'get checkstate
                mChecked = SendMessage(mCheckBoxHandle, BM_GETCHECK, 0&, 0&)
                EndDialog(hWnd, CType(_getLowWord(SendMessage(hWnd, DM_GETDEFID, IntPtr.Zero, IntPtr.Zero)), IntPtr))
            End If
        End Sub

        Private Shared mTextTemp As String = String.Empty
        Private Shared Sub _timer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles mTimer.Tick
            If mTimer.Interval = 10 Then mTimer.Interval = 250

            Dim intSec As Integer = Math.Round(mHookTimeout / 1000 - CType(Now - mdteStart, TimeSpan).TotalSeconds, 0)
            Dim str As String = String.Format(mCaption, intSec)
            If mCaption.Contains("{0}") Then SetWindowText(mHandle, str)

            Static intStart As Integer = 0

            If mHandle <> IntPtr.Zero Then
                If intStart = 0 Then
                    'get original text 
                    Dim sb As New StringBuilder(256)
                    GetDlgItemText(mHandle, &HFFFF, sb, sb.MaxCapacity)
                    If sb.ToString.Length > 0 Then mText = sb.ToString
                    intStart += 1
                End If

                If mText.Contains("{0}") Then
                    If Not mTextTemp = String.Format(mText, intSec) Then
                        SetDlgItemText(mHandle, &HFFFF, String.Format(mText, intSec))
                    End If
                    mTextTemp = String.Format(mText, intSec)
                End If
            End If

            mChecked = SendMessage(mCheckBoxHandle, BM_GETCHECK, 0&, 0&)

        End Sub

        Private Shared Function _getLowWord(ByRef pintValue As Int32) As Int32
            Return pintValue And &HFFFF
        End Function

        Private Shared Function _getLowWord(ByRef pudtValue As IntPtr) As Int32
            Return _getLowWord(pudtValue.ToInt32)
        End Function

        Private Shared Function _getHighWord(ByRef pintValue As Int32) As Int32
            If (pintValue And &H80000000) = &H80000000 Then
                Return ((pintValue And &H7FFF0000) \ &H10000) Or &H8000&
            Else
                Return (pintValue And &HFFFF0000) \ &H10000
            End If
        End Function

        Private Shared Sub _setLanguage(ByVal hwd As IntPtr)
            Dim ty As Type = GetType(en)
            Select Case System.Threading.Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.ToLower
                Case "de"
                    ty = GetType(de)
                Case "fr"
                    ty = GetType(fr)
                Case "pl"
                    ty = GetType(pl)
                Case "cs"
                    ty = GetType(cs)
                Case "es"
                    ty = GetType(es)
                Case "pt"
                    ty = GetType(pt)
                Case "nl"
                    ty = GetType(nl)
            End Select

            Select Case mButtons
                Case ExMessageBoxButtons.SaveDiscardCancel
                    SetDlgItemText(hwd, 6, "&" & Replace(Split([Enum].GetName(ty, 12), "__")(1), "_", " "))
                    SetDlgItemText(hwd, 7, "&" & Replace(Split([Enum].GetName(ty, 13), "__")(1), "_", " "))
                    SetDlgItemText(hwd, 2, "&" & Replace(Split([Enum].GetName(ty, 2), "__")(1), "_", " "))
                Case ExMessageBoxButtons.CancelTryContinue
                    SetDlgItemText(hwd, 6, "&" & Replace(Split([Enum].GetName(ty, 2), "__")(1), "_", " "))
                    SetDlgItemText(hwd, 7, "&" & Replace(Split([Enum].GetName(ty, 10), "__")(1), "_", " "))
                    SetDlgItemText(hwd, 2, "&" & Replace(Split([Enum].GetName(ty, 11), "__")(1), "_", " "))
                Case Else
                    For Each i As Integer In [Enum].GetValues(ty)
                        If Not mButtons = ExMessageBoxButtons.OK Then
                            SetDlgItemText(hwd, i, "&" & Replace(Split([Enum].GetName(ty, i), "__")(1), "_", " "))
                        Else
                            'if there is only the ok button then is dlgid 2 instead 1
                            SetDlgItemText(hwd, 2, "&" & Replace(Split([Enum].GetName(ty, 1), "__")(1), "_", " "))
                        End If
                    Next
            End Select


        End Sub
#End Region

#Region " Languages "
        Enum de
            Abort__Abbrechen = 3
            Cancel__Abbrechen = 2
            Ignore__Ignorieren = 5
            No__Nein = 7
            OK__OK = 1
            Retry_Wiederholen = 4
            Yes__Ja = 6
            Help__Hilfe = 9
            TryAgain__Wiederholen = 10
            Continue__Fortsetzen = 11
            Save__Speichern = 12
            Discard__Verwerfen = 13
        End Enum

        Enum en
            Abort__Abort = 3
            Cancel__Cancel = 2
            Ignore__Ignore = 5
            No__No = 7
            OK__OK = 1
            Retry__Retry = 4
            Yes__Yes = 6
            Help__Help = 9
            TryAgain__Try_Again = 10
            Continue__Continue = 11
            Save__Save = 12
            Discard__Discard = 13
        End Enum

        Enum fr
            Abort__Arrêt = 3
            Cancel__Annuler = 2
            Ignore__Ignorer = 5
            No__Non = 7
            OK__OK = 1
            Retry__Réessayer = 4
            Yes__Oui = 6
            Help__Aide = 9
            TryAgain__Réessayer = 10
            Continue__Continuer = 11
            Save__Sauver = 12
            Discard__Jeter = 13
        End Enum

        Enum cs
            Abort__Potratit = 3
            Cancel__Zrušit = 2
            Ignore__Ignorovat = 5
            No__Ne = 7
            OK__OK = 1
            Retry__Opakovat = 4
            Yes__Ano = 6
            Help__Pomoc = 9
            TryAgain__Zkusit = 10
            Continue__Pokračovat = 11
            Save__Uložit = 12
            Discard__Odhodit = 13
        End Enum

        Enum pl
            Abort__Przerwij = 3
            Cancel__Anulować = 2
            Ignore__Zignorować = 5
            No__Nie = 7
            OK__OK = 1
            Retry__Powtarzanie = 4
            Yes__Tak = 6
            Help__Pomoc = 9
            TryAgain__Próbować = 10
            Continue__Kontynuować = 11
            Save__Zaoszczędzić = 12
            Discard__Odrzuć = 13
        End Enum

        Enum es
            Abort__Abortar = 3
            Cancel__Cancelar = 2
            Ignore__Pasar = 5
            No__No = 7
            OK__Aceptar = 1
            Retry_Intentar = 4
            Yes__Sí = 6
            Help__Ayuda = 9
            TryAgain__Intentar = 10
            Continue__Continuar = 11
            Save__Guardar = 12
            Discard__Descartar = 13
        End Enum

        Enum pt
            Abort__Abortar = 3
            Cancel__Cancelar = 2
            Ignore__Ignorar = 5
            No__Não = 7
            OK__OK = 1
            Retry__Tentar = 4
            Yes__Sim = 6
            Help__Ajuda = 9
            TryAgain__Intentar = 10
            Continue__Continuar = 11
            Save__Guardar = 12
            Discard__Descartar = 13
        End Enum

        Enum nl
            Abort__Afbreken = 3
            Cancel__Annuleren = 2
            Ignore__Negeren = 5
            No__Nee = 7
            OK__OK = 1
            Retry__Herhaal = 4
            Yes__Ja = 6
            Help__Help = 9
            TryAgain__Proberen = 10
            Continue__Voortzetten = 11
            Save__Besparen = 12
            Discard__Ontdoen = 13
        End Enum
#End Region

#Region " CheckAndExDialogResult "
        Public Class CheckAndExDialogResult
            Private mChecked As CheckState
            Private mResult As ExDialogResult

            ReadOnly Property CheckState() As CheckState
                Get
                    Return mChecked
                End Get
            End Property

            ReadOnly Property ExDialogResult() As ExDialogResult
                Get
                    Return mResult
                End Get
            End Property

            Sub New(ByVal dResult As ExDialogResult, ByVal cResult As CheckState)
                mResult = dResult
                mChecked = cResult
            End Sub
        End Class
#End Region
    End Class
End Namespace

GeneralMy vote of 5 Pin
Tom Chantler22-Sep-10 4:59
professionalTom Chantler22-Sep-10 4:59 
GeneralThis isn't working in win7, Visual Studio 2008 Pin
Mr C P9-Mar-10 23:10
Mr C P9-Mar-10 23:10 
GeneralRe: This isn't working in win7, Visual Studio 2008 Pin
Mr C P9-Mar-10 23:15
Mr C P9-Mar-10 23:15 
GeneralRe: This isn't working in win7, Visual Studio 2008 Pin
Tom Chantler22-Sep-10 5:00
professionalTom Chantler22-Sep-10 5:00 
Generalgood article Pin
Donsw17-Jan-09 17:51
Donsw17-Jan-09 17:51 
GeneralVery very very good code, but... Pin
seb.4924-Apr-08 5:20
seb.4924-Apr-08 5:20 
QuestionDoes this support multi threading calls Pin
Kanna22-Mar-08 5:23
Kanna22-Mar-08 5:23 
GeneralRe: Does this support multi threading calls Pin
RodgerB31-Mar-08 13:00
RodgerB31-Mar-08 13:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.