MessageBox.Show is called without a MessageBoxOptions argument

ID

vbnet.portability.specify_message_box_options

Severity

low

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Globalization

Language

VB.NET

Description

Reports a call to MessageBox.Show, written either unqualified or through a qualified type name such as System.Windows.Forms.MessageBox, that passes no MessageBoxOptions value. Any overload is reported when no MessageBoxOptions member appears among the arguments, including the owner-window overloads. A call that supplies options - a single member or several combined with Or - is not reported. The member has to be named at the call site for that: options passed through a variable or a field, as in MessageBox.Show(text, caption, buttons, icon, defaultButton, opts), are not recognised and the call is still reported, because the type of the argument is not available to this analysis.

Rationale

The overload without options accepts the machine’s defaults for two decisions that the defaults get wrong in exactly the environments that are hardest to test. The first is reading order. A message box laid out left-to-right inside a right-to-left application does not merely look inconsistent: the buttons appear in the mirror of the order the user expects, so the button under the pointer is not the one that was under it in every other dialog in the application, and "Yes" and "No" swap places on a confirmation prompt. Windows does not infer this from the thread’s culture, so a fully localised application still shows unmirrored message boxes until RtlReading and RightAlign are passed explicitly. The second is the desktop the box appears on. Code that also runs without an interactive desktop - a Windows service, a scheduled task, an IIS worker - displays the box on a desktop nobody is looking at, and because Show is modal the calling thread blocks on a dialog that can never be dismissed. The symptom is a hung service rather than an error, which is why this is usually diagnosed from a process dump long after deployment.

The following code illustrates the pattern detected by this rule:

Public Sub ReportSaved()
    ' FLAGGED: MessageBox.Show is called without a MessageBoxOptions argument
    MessageBox.Show("The invoice was saved.")
End Sub

Remediation

Pass a MessageBoxOptions value on every Show call. For a localised UI, derive it from the current culture or the form’s RightToLeft setting and pass MessageBoxOptions.RtlReading Or MessageBoxOptions.RightAlign when reading order is right-to-left. For code that may run without an interactive desktop, pass MessageBoxOptions.ServiceNotification, or better, do not raise a dialog at all from a service - write to the log or the event log and let the caller decide how to present the failure.

' Before: unmirrored in a right-to-left UI, invisible and blocking in a service
MessageBox.Show("The invoice was saved.", "Billing")

' After
Dim options As MessageBoxOptions = If(RightToLeft = RightToLeft.Yes,
                                      MessageBoxOptions.RtlReading Or MessageBoxOptions.RightAlign,
                                      CType(0, MessageBoxOptions))
MessageBox.Show("The invoice was saved.", "Billing", MessageBoxButtons.OK,
                MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, options)

Configuration

This detector does not need any configuration.