Skip to content

Instantly share code, notes, and snippets.

@rhom6us
Last active May 22, 2024 04:23
Show Gist options
  • Save rhom6us/04dd29c46aee53489cc4a8827af6e2e0 to your computer and use it in GitHub Desktop.
Save rhom6us/04dd29c46aee53489cc4a8827af6e2e0 to your computer and use it in GitHub Desktop.
WinForms
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
internal static class MessageBoxHelper
{
internal static void PrepToCenterMessageBoxOnForm(Form form)
{
MessageBoxCenterHelper helper = new MessageBoxCenterHelper();
helper.Prep(form);
}
private class MessageBoxCenterHelper
{
private int messageHook;
private IntPtr parentFormHandle;
public void Prep(Form form)
{
NativeMethods.CenterMessageCallBackDelegate callBackDelegate = new NativeMethods.CenterMessageCallBackDelegate(CenterMessageCallBack);
GCHandle.Alloc(callBackDelegate);
parentFormHandle = form.Handle;
messageHook = NativeMethods.SetWindowsHookEx(5, callBackDelegate, new IntPtr(NativeMethods.GetWindowLong(parentFormHandle, -6)), NativeMethods.GetCurrentThreadId()).ToInt32();
}
private int CenterMessageCallBack(int message, int wParam, int lParam)
{
NativeMethods.RECT formRect;
NativeMethods.RECT messageBoxRect;
int xPos;
int yPos;
if (message == 5)
{
NativeMethods.GetWindowRect(parentFormHandle, out formRect);
NativeMethods.GetWindowRect(new IntPtr(wParam), out messageBoxRect);
xPos = (int)((formRect.Left + (formRect.Right - formRect.Left) / 2) - ((messageBoxRect.Right - messageBoxRect.Left) / 2));
yPos = (int)((formRect.Top + (formRect.Bottom - formRect.Top) / 2) - ((messageBoxRect.Bottom - messageBoxRect.Top) / 2));
NativeMethods.SetWindowPos(wParam, 0, xPos, yPos, 0, 0, 0x1 | 0x4 | 0x10);
NativeMethods.UnhookWindowsHookEx(messageHook);
}
return 0;
}
}
private static class NativeMethods
{
internal struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
internal delegate int CenterMessageCallBackDelegate(int message, int wParam, int lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool UnhookWindowsHookEx(int hhk);
[DllImport("user32.dll", SetLastError = true)]
internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("kernel32.dll")]
internal static extern int GetCurrentThreadId();
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr SetWindowsHookEx(int hook, CenterMessageCallBackDelegate callback, IntPtr hMod, int dwThreadId);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SetWindowPos(int hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
}
}
// http://burnignorance.com/vc-application-development-tips/hooking-a-message-box-in-vc/
HHOOK hMsgBoxHook;
LRESULT CALLBACK MsgBoxProc(int nCode, WPARAM wParam, LPARAM lParam)
{
TCHAR ach[140];
HWND hwnd;
HWND YES;
HWND NO;
HWND CANCEL;
if(nCode < 0)
return CallNextHookEx(hMsgBoxHook, nCode, wParam, lParam);
switch(nCode)
{
case HCBT_ACTIVATE:
// Get handle to the message box!
hwnd = (HWND)wParam;
//Set the window title
SetWindowText(hwnd, _T("Activator"));
//Get IDYES button handle
YES = GetDlgItem(hwnd, IDYES);
SetWindowText(YES, _T("Full License"));
//Get IDNO button handle
NO = GetDlgItem(hwnd, IDNO);
//Set Button position, width and height
MoveWindow(NO, 185, 60, 100, 23, TRUE);
SetWindowText(NO, _T("Cancel"));
//Get IDCANCEL button handle
CANCEL = GetDlgItem(hwnd, IDCANCEL);
//Set Button position, width and height
MoveWindow(CANCEL, 290, 60, 100, 23, TRUE);
SetWindowText(CANCEL, _T("Cancel"));
return 0;
}
return CallNextHookEx(hMsgBoxHook, nCode, wParam, lParam);
}
int MsgBoxEx(HWND hwnd, TCHAR *szText, TCHAR *szCaption, UINT uType)
{
int retval;
// Install a window hook, so we can intercept the message-box
// creation, and customize it
hMsgBoxHook = SetWindowsHookEx(
WH_CBT,
MsgBoxProc,
NULL,
GetCurrentThreadId()
);
// Display a standard message box
retval = MessageBox(hwnd, szText, szCaption, uType);
// remove the window hook
UnhookWindowsHookEx(hMsgBoxHook);
return retval;
}
The function will be called as follows :
MsgBoxEx(hWnd, "Message test" , "title", MB_YESNOCANCEL | MB_ICONINFORMATION);
public static class VisualExtensions
{
public static void SaveImage(this System.Windows.Media.Visual visual, System.IO.Stream writeStream, int width, int height) => visual.SaveImage(writeStream, width, height, 96);
public static void SaveImage(this System.Windows.Media.Visual visual, System.IO.Stream writeStream, int width, int height, double dpi) => visual.SaveImage(writeStream, width, height, dpi, dpi);
public static void SaveImage(this System.Windows.Media.Visual visual, System.IO.Stream writeStream, int width, int height, double dpiX, double dpiY) => visual.SaveImage(writeStream, width, height, dpiX, dpiY, System.Windows.Media.PixelFormats.Pbgra32);
public static void SaveImage(this System.Windows.Media.Visual visual, System.IO.Stream writeStream, int width, int height, double dpiX, double dpiY, System.Windows.Media.PixelFormat pixelFormat)
{
var renderTarget = new System.Windows.Media.Imaging.RenderTargetBitmap(width, height, dpiX, dpiY, pixelFormat);
renderTarget.Render(visual);
var encoder = new System.Windows.Media.Imaging.PngBitmapEncoder
{
Frames = {
System.Windows.Media.Imaging.BitmapFrame.Create(renderTarget)
}
};
encoder.Save(writeStream);
}
}
Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Distribution: You can freely use this code in your own
' applications, but you may not reproduce
' or publish this code on any web site,
' online service, or distribute as source
' on any media without express permission.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Option Explicit
'the three declares and five constants
'below are just used in creating the demo
Private Declare Function DrawIcon Lib "user32" _
(ByVal hdc As Long, ByVal x As Long, _
ByVal Y As Long, ByVal hIcon As Long) As Long
Private Declare Function LoadIcon Lib "user32" _
Alias "LoadIconA" _
(ByVal hInstance As Long, _
ByVal lpIconName As Any) As Long
Private Declare Function DestroyIcon Lib "user32" _
(ByVal hIcon As Long) As Long
'icon display values for LoadIcon/DrawIcon
Private Const IDI_APPLICATION = 32512&
Private Const IDI_HAND = 32513&
Private Const IDI_QUESTION = 32514&
Private Const IDI_EXCLAMATION = 32515&
Private Const IDI_ASTERISK = 32516&
Private Type MSGBOXPARAMS 'for MessageBoxIndirect (not shown in this demo)
'Specifies the structure size,
'in bytes.
cbSize As Long
'Identifies the owner window. This
'member can be null
hwndOwner As Long
'Identifies the instance containing the
'icon resource identified by the lpszIcon
'member, and the string resource identified
'by the lpszText or lpszCaption member.
hInstance As Long
'Pointer to a null-terminated string, or
'the identifier of a string resource, that
'contains the message to be displayed.
lpszText As String
'Pointer to a null-terminated string, or
'the identifier of a string resource, that
'contains the message box title. If this
'member is NULL, the default title Error is used.
lpszCaption As String
'Specifies a set of bit flags that determine
'the contents and behaviour of the dialog box.
'This member can be a combination of flags
'described for the uType parameter of the
'MessageBoxEx function. In addition, you can
'specify the MB_USERICON flag if you want the
'message box to display the icon specified
'by the lpszIcon member.
dwStyle As Long
'Identifies an icon resource. This parameter
'can be either a null-terminated string or an
'integer resource identifier passed to the
'MAKEINTRESOURCE macro.
'
'To load one of the standard system-defined
'icons, set the hInstance member to NULL and
'set lpszIcon to one of the values listed with
'the LoadIcon function.
'
'This member is ignored if the dwStyle member
'does not specify the MB_USERICON flag.
lpszIcon As String
'Identifies a Help context. If a Help event occurs,
'this value is specified in the HELPINFO structure
'that the message box sends to the owner window
'or callback function.
dwContextHelpId As Long
'Pointer to the callback function that processes
'Help events for the message box. The callback
'function has the following form:
'
' VOID CALLBACK MsgBoxCallback(LPHELPINFO lpHelpInfo);
'
'If this member is NULL, the message box sends WM_HELP
'messages to the owner window when help events occur.
lpfnMsgBoxCallback As Long
'Specifies the language in which to display the text
'contained in the predefined push buttons. This value
'must be in the form returned by the MAKELANGID macro.
'For a list of the language identifiers supported by
'Win32, see Language Identifiers in the msdn. Note
'that each localized release of Windows and Windows NT
'typically contains resources only for a limited set
'of languages. Thus, for example, the U.S. version
'offers LANG_ENGLISH, the French version offers LANG_FRENCH,
'the German version offers LANG_GERMAN, and the Japanese
'version offers LANG_JAPANESE. Each version offers
'LANG_NEUTRAL. This limits the set of values that
'can be used with the wLanguageId parameter. Before
'specifying a language identifier, you should enumerate
'the locales that are installed on a system.
dwLanguageId As Long
End Type
'MessageBoxEx function creates, displays,
'and operates a message box. The message box
'contains an application-defined message and
'title, plus any combination of predefined icons
'and push buttons. The wLanguageId parameter
'specifies which set of language resources is
'used for the predefined push buttons. Note that
'Windows identifies this as a reserved parameter.
Private Declare Function MessageBoxEx Lib "user32" _
Alias "MessageBoxExA" _
(ByVal hwnd As Long, _
ByVal lpText As String, _
ByVal lpCaption As String, _
ByVal uType As Long, _
ByVal wLanguageId As Long) As Long
'MessageBoxIndirect function creates, displays,
'and operates a message box. The message box contains
'application-defined message text and title, any icon,
'and any combination of predefined push buttons.
Private Declare Function MessageBoxIndirect Lib "user32" _
Alias "MessageBoxIndirectA" _
(lpMsgBoxParams As MSGBOXPARAMS) As Long
'wLanguageId parameter IDs
Private Const LANG_ENGLISH As Long = &H9
'uType parameters
'Icon IDs
Private Const MB_ICONHAND As Long = &H10&
Private Const MB_ICONQUESTION As Long = &H20&
Private Const MB_ICONEXCLAMATION As Long = &H30&
Private Const MB_ICONASTERISK As Long = &H40&
Private Const MB_ICONINFORMATION As Long = MB_ICONASTERISK
Private Const MB_ICONSTOP As Long = MB_ICONHAND
'Button IDs
Private Const MB_OK As Long = &H0&
Private Const MB_OKCANCEL As Long = &H1&
Private Const MB_ABORTRETRYIGNORE As Long = &H2&
Private Const MB_YESNOCANCEL As Long = &H3&
Private Const MB_YESNO As Long = &H4&
Private Const MB_RETRYCANCEL As Long = &H5&
Private Const MB_DEFBUTTON1 As Long = &H0&
Private Const MB_DEFBUTTON2 As Long = &H100&
Private Const MB_DEFBUTTON3 As Long = &H200&
Private Const MB_DEFBUTTON4 As Long = &H300&
'Msgbox style IDs
'modality
Private Const MB_APPLMODAL As Long = &H0&
Private Const MB_SYSTEMMODAL As Long = &H1000&
Private Const MB_TASKMODAL As Long = &H2000&
'misc
'Adds a Help button to the message box. Choosing
'the Help button or pressing F1 generates a Help event.
Private Const MB_HELP As Long = &H4000
'The message box becomes the foreground window. Internally,
'the system calls the SetForegroundWindow function for
'the message box.
Private Const MB_SETFOREGROUND As Long = &H10000
'The desktop currently receiving input must be a
'default desktop; otherwise, the function fails.
'A default desktop is one an application runs on
'after the user has logged on.
Private Const MB_DEFAULT_DESKTOP_ONLY As Long = &H20000
'The message box is created with the WS_EX_TOPMOST
'window style.
Private Const MB_TOPMOST As Long = &H40000
'The text is right-justified.
Private Const MB_RIGHT As Long = &H80000
'Displays message and caption text using
'right-to-left reading order on Hebrew and
'Arabic systems.
Private Const MB_RTLREADING As Long = &H100000
'Windows NT: The caller is a service notifying the user
'of an event. The function displays a message box on the
'current active desktop, even if there is no user logged
'on to the computer. If this flag is set, the hWnd
'parameter must be NULL. This is so the message box
'can appear on a desktop other than the desktop
'corresponding to the hWnd.
'WINVER > = 0x0400; less than 4 uses &H400000
Private Const MB_SERVICE_NOTIFICATION As Long = &H200000
'misc masks
Private Const MB_TYPEMASK As Long = &HF&
Private Const MB_ICONMASK As Long = &HF0
Private Const MB_DEFMASK As Long = &HF00&
Private Const MB_MODEMASK As Long = &H3000&
Private Const MB_NOFOCUS As Long = &H8000&
Private Const MB_MISCMASK As Long = &HC000&
'Return values
Private Const IDOK = 1
Private Const IDCANCEL = 2
Private Const IDABORT = 3
Private Const IDRETRY = 4
Private Const IDIGNORE = 5
Private Const IDYES = 6
Private Const IDNO = 7
'Help Callback structures
Private Type POINTAPI
x As Long
Y As Long
End Type
Private Type HELPINFO
cbSize As Long
iContextType As Long
iCtrlId As Long
hItemHandle As Long
dwContextId As Long
MousePos As POINTAPI
End Type
'used in the demo to display appropriate
'button captions in order to provide a
'means to pick a default button
Private btnCaptions(0 To 5, 0 To 3) As String
'vars set in the option and button click
'routines and used to track the flags
'in order to display the messagebox
Private msgButtons As Long
Private msgDefButton As Long
Private msgIcon As Long
Private Sub Form_Load()
'this loads a two-dimensional array with
'button captions. The first array index corresponds
'to the option button index (setting the captions
'to display on the form buttons), while the second
'parameter is the defButton control array index.
btnCaptions(0, 0) = "OK"
btnCaptions(0, 1) = ""
btnCaptions(0, 2) = ""
btnCaptions(1, 0) = "OK"
btnCaptions(1, 1) = "Cancel"
btnCaptions(1, 2) = ""
btnCaptions(2, 0) = "Abort"
btnCaptions(2, 1) = "Retry"
btnCaptions(2, 2) = "Ignore"
btnCaptions(3, 0) = "Yes"
btnCaptions(3, 1) = "No"
btnCaptions(3, 2) = "Cancel"
btnCaptions(4, 0) = "Yes"
btnCaptions(4, 1) = "No"
btnCaptions(4, 2) = ""
btnCaptions(5, 0) = "Retry"
btnCaptions(5, 1) = "Cancel"
btnCaptions(5, 2) = ""
'this sets up the controls ....
'populate the buttons with the built-in
'icon resources. NOTE: After completing
'this demo, I found info in the MSDN stating
'that LoadIcon is obsolete, replaced with
'LoadImage. This code continues to work.
'
'Since this is to demo using the MessageBoxEx API,
'and not how to obtain a system icon, I will
'post using LoadIcon and revise at a future date.
Dim hIcon As Long
With Picture1
.AutoRedraw = True
.BorderStyle = 0
.Width = 32 * Screen.TwipsPerPixelX
.Height = 32 * Screen.TwipsPerPixelY
End With
With Shape1
.BorderColor = RGB(255, 255, 0)
End With
With Shape2
.BorderColor = RGB(255, 0, 0)
End With
With Command1(0)
.Width = 1335
.Height = 345
End With
With Command1(1)
.Width = 1335
.Height = 345
End With
With Command1(2)
.Width = 1335
.Height = 345
End With
Command2(0).Caption = "None"
Command2(1).Caption = ""
Command2(2).Caption = ""
Command2(3).Caption = ""
Command2(4).Caption = ""
With Command3
.Width = 1815
.Height = 345
.Caption = "Show Message"
End With
Option1(0).Caption = "OK"
Option1(1).Caption = "OK Cancel"
Option1(2).Caption = "Abort Retry Ignore"
Option1(3).Caption = "Yes No Cancel"
Option1(4).Caption = "Yes No"
Option1(5).Caption = "Retry Cancel"
Text1.Text = "VBnet MessageBoxEx Demo"
Text2.Text = "The license key you entered was invalid. Please try again."
Text3.Text = ""
hIcon = LoadIcon(0&, IDI_HAND)
Call DrawIcon(Picture1.hdc, 0, 0, hIcon)
Command2(1).Picture = Picture1.Image
Set Picture1.Picture = LoadPicture("")
Call DestroyIcon(hIcon)
hIcon = LoadIcon(0&, IDI_QUESTION)
Call DrawIcon(Picture1.hdc, 0, 0, hIcon)
Command2(2).Picture = Picture1.Image
Set Picture1.Picture = LoadPicture("")
Call DestroyIcon(hIcon)
hIcon = LoadIcon(0&, IDI_EXCLAMATION)
Call DrawIcon(Picture1.hdc, 0, 0, hIcon)
Command2(3).Picture = Picture1.Image
Set Picture1.Picture = LoadPicture("")
Call DestroyIcon(hIcon)
hIcon = LoadIcon(0&, IDI_ASTERISK)
Call DrawIcon(Picture1.hdc, 0, 0, hIcon)
Command2(4).Picture = Picture1.Image
Set Picture1.Picture = LoadPicture("")
Call DestroyIcon(hIcon)
Option1(0).Value = True
Command1(0).Value = True
Command2(0).Value = True
End Sub
Private Sub Command1_Click(Index As Integer)
'the default button values are multiples of 256
msgDefButton = Index * 256
'this just highlights the current selection
Shape1.Move Command1(Index).Left - 35, _
Command1(Index).Top - 35, _
Command1(Index).Width + 70, _
Command1(Index).Height + 70
End Sub
Private Sub Command2_Click(Index As Integer)
'the icon button values are multiples of 16
msgIcon = Index * 16
'this just highlights the current selection
Shape2.Move Command2(Index).Left - 35, _
Command2(Index).Top - 35, _
Command2(Index).Width + 70, _
Command2(Index).Height + 70
End Sub
Private Sub Command3_Click()
Dim sMessage As String
Dim sTitle As String
Dim dwFlags As Long
sTitle = Text1.Text
sMessage = Text2.Text
Text3.Text = ""
dwFlags = msgButtons Or msgDefButton Or msgIcon
'called as a function
Select Case MessageBoxEx(Me.hwnd, _
sMessage, _
sTitle, _
dwFlags, _
LANG_ENGLISH)
Case IDOK: Text3.Text = "IDOK selected"
Case IDCANCEL: Text3.Text = "IDCANCEL selected"
Case IDABORT: Text3.Text = "IDABORT selected"
Case IDRETRY: Text3.Text = "IDRETRY selected"
Case IDIGNORE: Text3.Text = "IDIGNORE selected"
Case IDYES: Text3.Text = "IDYES selected"
Case IDNO: Text3.Text = "IDNO selected"
End Select
End Sub
Private Sub Option1_Click(Index As Integer)
'reset the highlight to the first button
Command1(0).Value = True
'reset the captions and visibility of the
'available default buttons
Command1(0).Visible = btnCaptions(Index, 0) > ""
Command1(1).Visible = btnCaptions(Index, 1) > ""
Command1(2).Visible = btnCaptions(Index, 2) > ""
Command1(0).Caption = btnCaptions(Index, 0)
Command1(1).Caption = btnCaptions(Index, 1)
Command1(2).Caption = btnCaptions(Index, 2)
'the default button style is directly mapped
'to the index
msgButtons = Index
End Sub
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment