Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion MsmqFastView/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
using System.Windows;
using System;
using System.Windows;

namespace MsmqFastView
{
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
}

private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
MessageBox.Show(
string.Concat(
"An unexpected error has occured. Please notify the developers.",
Environment.NewLine,
Environment.NewLine,
"Details:",
Environment.NewLine,
e.ExceptionObject.ToString()),
"Unhandled exception");
}
}
}
77 changes: 34 additions & 43 deletions MsmqFastView/Infrastructure/MsmqExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Globalization;
using System.Linq;
using System.Messaging;
using System.Runtime.InteropServices;

Expand All @@ -9,12 +10,12 @@ public static class MsmqExtensions
{
public static int GetNumberOfSubqueues(this MessageQueue messageQueue)
{
return GetNumberOfSubqueues(messageQueue.FormatName);
return GetNumberOfSubqueues(messageQueue.MachineName, messageQueue.FormatName);
}

public static string[] GetSubqueueNames(this MessageQueue messageQueue)
{
return GetSubqueueNames(messageQueue.FormatName);
return GetSubqueueNames(messageQueue.MachineName, messageQueue.FormatName);
}

/// <summary>
Expand All @@ -25,48 +26,37 @@ public static string[] GetSubqueueNames(this MessageQueue messageQueue)
/// <returns>Number of messages.</returns>
public static int GetNumberOfMessages(this MessageQueue messageQueue)
{
return GetNumberOfMessages(messageQueue.FormatName);
return GetNumberOfMessages(messageQueue.MachineName, messageQueue.FormatName);
}

public static int GetNumberOfSubqueues(string queueFormatName)
public static int GetNumberOfMessages(string machineName, string queueFormatName)
{
int[] propertyIds = new int[1]
{
MsmqNativeMethods.PROPID_MGMT_QUEUE.SUBQUEUE_COUNT,
};
GCHandle aPropId = GCHandle.Alloc(propertyIds, GCHandleType.Pinned);

MsmqNativeMethods.MQPROPVARIANT[] propertyValues = new MsmqNativeMethods.MQPROPVARIANT[1]
{
new MsmqNativeMethods.MQPROPVARIANT() { vt = (short)VarEnum.VT_NULL }
};
GCHandle aPropVar = GCHandle.Alloc(propertyValues, GCHandleType.Pinned);

MsmqNativeMethods.MQQUEUEPROPS queueProperties = new MsmqNativeMethods.MQQUEUEPROPS()
{
cProp = 1,
aPropID = aPropId.AddrOfPinnedObject(),
aPropVar = aPropVar.AddrOfPinnedObject(),
aStatus = IntPtr.Zero
};

uint returnCode = MsmqNativeMethods.MQMgmtGetInfo(Environment.MachineName, "QUEUE=" + queueFormatName, queueProperties);

aPropId.Free();
aPropVar.Free();

if (returnCode == MsmqNativeMethods.MQ_ERROR.QUEUE_NOT_ACTIVE)
{
return 0;
}
return GetIntProperty(
machineName,
queueFormatName,
MsmqNativeMethods.PROPID_MGMT_QUEUE.MESSAGE_COUNT,
new[] { MsmqNativeMethods.MQ_ERROR.QUEUE_NOT_ACTIVE });
}

MsmqException.Assert(returnCode == 0, string.Format(CultureInfo.InvariantCulture, "MQMgmtGetInfo returned error: {0:x8}", returnCode));
MsmqException.Assert(((VarEnum)propertyValues[0].vt) == VarEnum.VT_UI4, "Unexpected type returned, should be " + VarEnum.VT_UI4 + ", but was " + ((VarEnum)propertyValues[0].vt) + ".");
public static int GetNumberOfMessagesInJournal(string machineName, string queueFormatName)
{
return GetIntProperty(
machineName,
queueFormatName,
MsmqNativeMethods.PROPID_MGMT_QUEUE.JOURNAL_MESSAGE_COUNT,
new[] { MsmqNativeMethods.MQ_ERROR.QUEUE_NOT_ACTIVE });
}

return (int)propertyValues[0].union.ulVal;
public static int GetNumberOfSubqueues(string machineName, string queueFormatName)
{
return GetIntProperty(
machineName,
queueFormatName,
MsmqNativeMethods.PROPID_MGMT_QUEUE.SUBQUEUE_COUNT,
new[] { MsmqNativeMethods.MQ_ERROR.QUEUE_NOT_ACTIVE, MsmqNativeMethods.MQ_ERROR.ILLEGAL_PROPID });
}

public static string[] GetSubqueueNames(string queueFormatName)
public static string[] GetSubqueueNames(string machineName, string queueFormatName)
{
int[] propertyIds = new int[1]
{
Expand All @@ -88,12 +78,13 @@ public static string[] GetSubqueueNames(string queueFormatName)
aStatus = IntPtr.Zero
};

uint returnCode = MsmqNativeMethods.MQMgmtGetInfo(Environment.MachineName, "QUEUE=" + queueFormatName, queueProperties);
uint returnCode = MsmqNativeMethods.MQMgmtGetInfo(machineName, "QUEUE=" + queueFormatName, queueProperties);

aPropId.Free();
aPropVar.Free();

if (returnCode == MsmqNativeMethods.MQ_ERROR.QUEUE_NOT_ACTIVE)
if (returnCode == MsmqNativeMethods.MQ_ERROR.QUEUE_NOT_ACTIVE
|| returnCode == MsmqNativeMethods.MQ_ERROR.ILLEGAL_PROPID)
{
return new string[0];
}
Expand All @@ -116,11 +107,11 @@ public static string[] GetSubqueueNames(string queueFormatName)
return subQueueNames;
}

public static int GetNumberOfMessages(string queueFormatName)
private static int GetIntProperty(string machineName, string queueFormatName, int propId, uint[] allowedReturnCodes)
{
int[] propertyIds = new int[1]
{
MsmqNativeMethods.PROPID_MGMT_QUEUE.MESSAGE_COUNT,
propId,
};
GCHandle aPropId = GCHandle.Alloc(propertyIds, GCHandleType.Pinned);

Expand All @@ -138,12 +129,12 @@ public static int GetNumberOfMessages(string queueFormatName)
aStatus = IntPtr.Zero
};

uint returnCode = MsmqNativeMethods.MQMgmtGetInfo(Environment.MachineName, "QUEUE=" + queueFormatName, queueProperties);
uint returnCode = MsmqNativeMethods.MQMgmtGetInfo(machineName, "QUEUE=" + queueFormatName, queueProperties);

aPropId.Free();
aPropVar.Free();

if (returnCode == MsmqNativeMethods.MQ_ERROR.QUEUE_NOT_ACTIVE)
if (allowedReturnCodes != null && allowedReturnCodes.Contains(returnCode))
{
return 0;
}
Expand Down
2 changes: 2 additions & 0 deletions MsmqFastView/Infrastructure/MsmqNativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,15 @@ public struct CALPWSTR
public static class PROPID_MGMT_QUEUE
{
public const int MESSAGE_COUNT = 7;
public const int JOURNAL_MESSAGE_COUNT = 9;
public const int SUBQUEUE_COUNT = 26;
public const int QUEUE_SUBQUEUE_NAMES = 27;
}

public static class MQ_ERROR
{
public const uint QUEUE_NOT_ACTIVE = 0xC00E0004;
public const uint ILLEGAL_PROPID = 0xC00E0039;
}

[StructLayout(LayoutKind.Sequential)]
Expand Down
124 changes: 124 additions & 0 deletions MsmqFastView/MachineModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
using System;
using System.ComponentModel;
using System.Messaging;
using System.Windows;
using System.Windows.Input;
using MsmqFastView.Infrastructure;

namespace MsmqFastView
{
public class MachineModel : INotifyPropertyChanged
{
private string machineName;

private string candidateMachineName;

private bool editingMachineName;

public MachineModel()
{
this.MachineName = Environment.MachineName;

this.ChangeMachine = new DelegateCommand(_ => this.OnChangeMachine());
this.ConnectToMachine = new DelegateCommand(_ => this.CanConnectToMachine(), _ => this.OnConnectToMachine());
this.CancelChangeMachine = new DelegateCommand(_ => this.OnCancelChangeMachine());
}

public string MachineName
{
get
{
return this.machineName;
}
private set
{
this.machineName = value;
this.PropertyChanged.Raise(this, "MachineName");
}
}

public string CandidateMachineName
{
get
{
return this.candidateMachineName;
}
set
{
this.candidateMachineName = value;
this.PropertyChanged.Raise(this, "CandidateMachineName");
this.ConnectToMachine.RaiseCanExecuteChanged();
}
}

public Visibility MachineNameVisibility
{
get
{
return this.editingMachineName ? Visibility.Collapsed : Visibility.Visible;
}
}

public Visibility EditMachineNameVisibility
{
get
{
return this.editingMachineName ? Visibility.Visible : Visibility.Collapsed;
}
}

public ICommand ChangeMachine { get; private set; }

public DelegateCommand ConnectToMachine { get; private set; }

public ICommand CancelChangeMachine { get; private set; }

public event PropertyChangedEventHandler PropertyChanged;

private void ToggleMachineNameEditor(bool editing)
{
this.editingMachineName = editing;
this.PropertyChanged.Raise(this, "MachineNameVisibility");
this.PropertyChanged.Raise(this, "EditMachineNameVisibility");
}

private void OnChangeMachine()
{
this.CandidateMachineName = this.MachineName;
this.ToggleMachineNameEditor(true);
}

private void OnCancelChangeMachine()
{
this.ToggleMachineNameEditor(false);
}

private bool CanConnectToMachine()
{
return !string.IsNullOrEmpty(this.CandidateMachineName);
}

private void OnConnectToMachine()
{
try
{
MessageQueue.GetPrivateQueuesByMachine(this.CandidateMachineName);
}
catch (MessageQueueException ex)
{
MessageBox.Show(
"Unable to obtain queue list from machine " + this.CandidateMachineName + ". Make sure the machine name is correct. To check if the machine is properly configured for remote MSMQ administration, try connecting to it using the MSMQ node in Computer Management/Server Manager.\n"
+ "\n"
+ "Details:\n"
+ ex.ToString(),
"Error during reading queues",
MessageBoxButton.OK,
MessageBoxImage.Error);
return;
}

this.MachineName = this.CandidateMachineName;
this.ToggleMachineNameEditor(false);
}
}
}
23 changes: 22 additions & 1 deletion MsmqFastView/MainWindow.xaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Window x:Class="MsmqFastView.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="600" Width="800">
Title="{Binding Title}" Height="600" Width="800">
<Window.InputBindings>
<KeyBinding Key="F5" Command="{Binding Refresh}" />
<KeyBinding Key="F6" Command="{Binding SelectedItem.Refresh, ElementName=QueuesTreeView}" />
Expand Down Expand Up @@ -82,6 +82,8 @@
<DataGridTextColumn Header="Response queue" Binding="{Binding ResponseQueue}" />
<DataGridTextColumn Header="Id" Binding="{Binding Id}" />
<DataGridTextColumn Header="Correlation Id" Binding="{Binding CorrelationId}" />
<DataGridTextColumn Header="Message type" Binding="{Binding MessageType}" />
<DataGridTextColumn Header="Acknowledgement" Binding="{Binding Acknowledgement}" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
Expand Down Expand Up @@ -138,6 +140,25 @@
<Hyperlink Command="{Binding OpenHomepage}">https://github.com/whut/MsmqFastView</Hyperlink>
</TextBlock>
</StatusBarItem>
<StatusBarItem>
<StackPanel Orientation="Horizontal" DataContext="{Binding Machine}">
<TextBlock>
<Span>Machine: </Span>
</TextBlock>
<TextBlock Visibility="{Binding MachineNameVisibility}">
<Hyperlink Command="{Binding ChangeMachine}">
<Run Text="{Binding MachineName, Mode=OneWay}" />
</Hyperlink>
</TextBlock>
<StackPanel Visibility="{Binding EditMachineNameVisibility}" Orientation="Horizontal" IsVisibleChanged="OnEditMachineNameIsVisibleChanged">
<TextBox Text="{Binding CandidateMachineName}" Name="tbCandidateMachineName" FontSize="10" Padding="0,0,0,0" />
<TextBlock>
<Hyperlink Command="{Binding ConnectToMachine}">Connect</Hyperlink>
<Hyperlink Command="{Binding CancelChangeMachine}">Cancel</Hyperlink>
</TextBlock>
</StackPanel>
</StackPanel>
</StatusBarItem>
</StatusBar>
</Grid>
</Window>
19 changes: 19 additions & 0 deletions MsmqFastView/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
using System.Windows;
using MsmqFastView.Infrastructure;
Expand Down Expand Up @@ -30,5 +32,22 @@ protected override void OnClosing(CancelEventArgs e)
Settings.Default.MainWindowPlacement = new JavaScriptSerializer().Serialize(this.GetPlacement());
Settings.Default.Save();
}

private void OnEditMachineNameIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue)
{
// must be deferred, otherwise Focus() will not work
Task.Factory.StartNew(
() =>
{
this.tbCandidateMachineName.Focus();
this.tbCandidateMachineName.SelectAll();
},
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
}
}
}
}
Loading