diff --git a/MsmqFastView/App.xaml.cs b/MsmqFastView/App.xaml.cs index 1ea424d..f6e145c 100755 --- a/MsmqFastView/App.xaml.cs +++ b/MsmqFastView/App.xaml.cs @@ -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"); + } } } diff --git a/MsmqFastView/Infrastructure/MsmqExtensions.cs b/MsmqFastView/Infrastructure/MsmqExtensions.cs index 702a6bc..a0a0c42 100644 --- a/MsmqFastView/Infrastructure/MsmqExtensions.cs +++ b/MsmqFastView/Infrastructure/MsmqExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Globalization; +using System.Linq; using System.Messaging; using System.Runtime.InteropServices; @@ -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); } /// @@ -25,48 +26,37 @@ public static string[] GetSubqueueNames(this MessageQueue messageQueue) /// Number of messages. 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] { @@ -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]; } @@ -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); @@ -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; } diff --git a/MsmqFastView/Infrastructure/MsmqNativeMethods.cs b/MsmqFastView/Infrastructure/MsmqNativeMethods.cs index a3e256d..8b63d4c 100644 --- a/MsmqFastView/Infrastructure/MsmqNativeMethods.cs +++ b/MsmqFastView/Infrastructure/MsmqNativeMethods.cs @@ -40,6 +40,7 @@ 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; } @@ -47,6 +48,7 @@ public static class PROPID_MGMT_QUEUE public static class MQ_ERROR { public const uint QUEUE_NOT_ACTIVE = 0xC00E0004; + public const uint ILLEGAL_PROPID = 0xC00E0039; } [StructLayout(LayoutKind.Sequential)] diff --git a/MsmqFastView/MachineModel.cs b/MsmqFastView/MachineModel.cs new file mode 100644 index 0000000..7b871cf --- /dev/null +++ b/MsmqFastView/MachineModel.cs @@ -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); + } + } +} diff --git a/MsmqFastView/MainWindow.xaml b/MsmqFastView/MainWindow.xaml index 43921c4..9e134ec 100755 --- a/MsmqFastView/MainWindow.xaml +++ b/MsmqFastView/MainWindow.xaml @@ -1,7 +1,7 @@  + Title="{Binding Title}" Height="600" Width="800"> @@ -82,6 +82,8 @@ + + @@ -138,6 +140,25 @@ https://github.com/whut/MsmqFastView + + + + Machine: + + + + + + + + + + Connect + Cancel + + + + diff --git a/MsmqFastView/MainWindow.xaml.cs b/MsmqFastView/MainWindow.xaml.cs index 5f72f50..f6fc151 100755 --- a/MsmqFastView/MainWindow.xaml.cs +++ b/MsmqFastView/MainWindow.xaml.cs @@ -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; @@ -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()); + } + } } } diff --git a/MsmqFastView/MainWindowModel.cs b/MsmqFastView/MainWindowModel.cs index d4dc7b6..c986762 100755 --- a/MsmqFastView/MainWindowModel.cs +++ b/MsmqFastView/MainWindowModel.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Linq; using System.Messaging; +using System.Reflection; using System.Windows; using System.Windows.Input; using MsmqFastView.Infrastructure; @@ -16,8 +17,10 @@ public class MainWindowModel : INotifyPropertyChanged public MainWindowModel() { - this.ApplicationVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); + this.ApplicationVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); this.ShowOnlyNonempty = true; + this.Machine = new MachineModel(); + this.Machine.PropertyChanged += (sender, e) => { if (e.PropertyName == "MachineName") { this.OnMachineNameChanged(); } }; this.Refresh = new DelegateCommand(o => { this.queues = null; @@ -25,7 +28,7 @@ public MainWindowModel() }); this.Purge = new DelegateCommand(o => { - foreach (MessageQueue queue in MessageQueue.GetPrivateQueuesByMachine(Environment.MachineName)) + foreach (MessageQueue queue in MessageQueue.GetPrivateQueuesByMachine(this.MachineName)) { queue.Purge(); } @@ -34,7 +37,7 @@ public MainWindowModel() }); this.PurgeAll = new DelegateCommand(o => { - foreach (MessageQueue queue in MessageQueue.GetPrivateQueuesByMachine(Environment.MachineName) + foreach (MessageQueue queue in MessageQueue.GetPrivateQueuesByMachine(this.MachineName) .SelectMany(q => GetQueueWithSubQueues(q))) { queue.Purge(); @@ -56,6 +59,24 @@ public MainWindowModel() public string ApplicationVersion { get; private set; } + public string MachineName + { + get + { + return this.Machine.MachineName; + } + } + + public MachineModel Machine { get; private set; } + + public string Title + { + get + { + return "MsmqFastView - " + this.MachineName; + } + } + public IEnumerable Queues { get @@ -81,7 +102,11 @@ private void InitializeQueues() this.queues = new List(); try { - foreach (MessageQueue queue in MessageQueue.GetPrivateQueuesByMachine(Environment.MachineName) + IEnumerable queueSource = MessageQueue.GetPrivateQueuesByMachine(this.MachineName); + + queueSource = ApplyNet45WorkaroundIfNeeded(queueSource); + + foreach (MessageQueue queue in queueSource .Where(q => !this.ShowOnlyNonempty || q.GetNumberOfMessages() != 0) .OrderBy(mq => mq.QueueName)) { @@ -107,6 +132,77 @@ private void InitializeQueues() } } + private static IEnumerable ApplyNet45WorkaroundIfNeeded(IEnumerable queueSource) + { + // 4.0 RTM -> 4.0.30319.1 + // 4.0.1 -> 4.0.30319.232 + // 4.0.2 -> 4.0.30319.245 + // 4.0.3 -> 4.0.30319.276 + // 4.5 Dev -> 4.0.30319.17020 + // 4.5 Beta -> 4.0.30319.17379 + // 4.5 RC -> 4.0.30319.17626 + // 4.5 RTM -> 4.0.30319.17929 + + // we want to do it only on 4.5 (all releases) + if (Environment.Version.Major == 4 + && Environment.Version.Minor == 0 + && Environment.Version.Build == 30319 + && Environment.Version.Revision >= 17000) + { + queueSource = queueSource.Select(mq => WorkAroundNet45FormatNameBug(mq)); + } + return queueSource; + } + + private static MessageQueue WorkAroundNet45FormatNameBug(MessageQueue mq) + { + if (mq == null) + { + return mq; + } + + // In .NET 2.0 and 4.0, if queue is constructed from format name ("FormatName:...."), + // accessing the FormatName property results in a simple substring operation (to trim the "FormatName:" prefix). + + // In .NET 4.5, some overzealous Microsoft programmer thought it was insufficient, + // and if the private queuePath field is set, the FormatName property calls ResolveFormatNameFromQueuePath, + // which calls the native MQPathNameToFormatName API, which does not support remote paths on workgroup (non-domain joined) machines. + // If the private queuePath field is NOT set, the old string manipulation code path is used. + // The computed format name is then cached in a field. + + // (MessageQueue.GetPrivateQueuesByMachine DOES set this field. The MessageQueue constructor does NOT.) + + // The workaround is to clear the queuePath field, then access FormatName to cause the format name to be cached. + // Afterwards, queuePath may be restored. + // This effectively simulates .NET 4.0 behavior. + + var field = mq.GetType().GetMember("queuePath", MemberTypes.Field, BindingFlags.Instance | BindingFlags.NonPublic).SingleOrDefault() as FieldInfo; + + // no field? apparently we are running on a future framework; the internals have changed -> don't touch anything + if (field == null) + { + return mq; + } + + // save existing queuePath value + var savedPath = field.GetValue(mq); + if (savedPath == null) + { + // huh? nothing we can do + return mq; + } + + // clear the field + field.SetValue(mq, null); + + // trigger caching of format name + var formatName = mq.FormatName; + + // restore queuePath value + field.SetValue(mq, savedPath); + return mq; + } + private IEnumerable GetQueueWithSubQueues(MessageQueue queue) { if (this.ShowOnlyNonempty && queue.GetNumberOfMessages() == 0) @@ -127,5 +223,11 @@ private IEnumerable GetQueueWithSubQueues(MessageQueue queue) } } } - } + + private void OnMachineNameChanged() + { + this.Refresh.Execute(null); + this.PropertyChanged.Raise(this, "Title"); + } + } } diff --git a/MsmqFastView/MessageModel.cs b/MsmqFastView/MessageModel.cs index bc6ec95..6171470 100755 --- a/MsmqFastView/MessageModel.cs +++ b/MsmqFastView/MessageModel.cs @@ -8,7 +8,7 @@ public class MessageModel private MessageDetailsModel details; - public MessageModel(string queuePath, string id, string label, DateTime sent, string responseQueue, string correlationId) + public MessageModel(string queuePath, string id, string label, DateTime sent, string responseQueue, string correlationId, string messageType, string acknowledgement) { this.queuePath = queuePath; this.Id = id; @@ -16,6 +16,8 @@ public MessageModel(string queuePath, string id, string label, DateTime sent, st this.Sent = sent; this.ResponseQueue = responseQueue; this.CorrelationId = correlationId; + this.MessageType = messageType; + this.Acknowledgement = acknowledgement; } public string Id { get; private set; } @@ -28,6 +30,10 @@ public MessageModel(string queuePath, string id, string label, DateTime sent, st public string CorrelationId { get; private set; } + public string MessageType { get; private set; } + + public string Acknowledgement { get; private set; } + public MessageDetailsModel Details { get diff --git a/MsmqFastView/MsmqFastView.csproj b/MsmqFastView/MsmqFastView.csproj index 4f727fb..1a5474d 100755 --- a/MsmqFastView/MsmqFastView.csproj +++ b/MsmqFastView/MsmqFastView.csproj @@ -69,6 +69,7 @@ + diff --git a/MsmqFastView/QueueModel.cs b/MsmqFastView/QueueModel.cs index 746acd7..1b41fff 100755 --- a/MsmqFastView/QueueModel.cs +++ b/MsmqFastView/QueueModel.cs @@ -11,6 +11,8 @@ namespace MsmqFastView { public class QueueModel : INotifyPropertyChanged { + private const string JournalQueueName = @"JOURNAL"; + private string path; private List messages; @@ -19,8 +21,17 @@ public QueueModel(MessageQueue queue) : this() { this.path = queue.Path; - this.Name = GetFriendlyName(queue); List subqueues = new List(); + + var messageCount = queue.GetNumberOfMessages(); + this.Name = GetFriendlyName(queue) + (0 < messageCount ? string.Format(" ({0})", messageCount) : null); + + // queue properties (e.g. UseJournalQueue) are only accessible from the local machine + if (!queue.MachineName.Equals(Environment.MachineName, StringComparison.OrdinalIgnoreCase) || queue.UseJournalQueue) + { + subqueues.Add(new QueueModel(queue, JournalQueueName)); + } + if (queue.GetNumberOfSubqueues() > 0) { foreach (string subQueueName in queue.GetSubqueueNames()) @@ -36,7 +47,16 @@ public QueueModel(MessageQueue queue, string subQueueName) : this() { this.path = queue.Path + ";" + subQueueName; - this.Name = subQueueName; + + if (subQueueName.Equals(JournalQueueName, StringComparison.OrdinalIgnoreCase)) + { + var messageCount = MsmqExtensions.GetNumberOfMessagesInJournal(queue.MachineName, queue.FormatName); + this.Name = "Journal" + (0 < messageCount ? string.Format(" ({0})", messageCount) : null); + } + else + { + this.Name = subQueueName; + } } private QueueModel() @@ -79,13 +99,27 @@ public IEnumerable Messages private static string GetFriendlyName(MessageQueue queue) { - string prefix = "private$\\"; - if (queue.QueueName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) + var formatName = queue.FormatName; + + // QueueName is unavailable on remote queue with DIRECT FormatName when the following conditions are met: + // * this machine is not joined to a domain, so MSMQ path translation mechanisms work only on local queues + // * the MessageQueue object does not have its private field queuePath set + // (note: queues obtained from GetPrivateQueuesByMachine DO have this field set, but those returned by e.g. Message.ResponseQueue, or constructed from format name string, DO NOT) + // in case of exception, better to display raw FormatName than fail to display the entire message list + try { - return queue.QueueName.Substring(prefix.Length); - } + string prefix = "private$\\"; + if (queue.QueueName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) + { + return queue.QueueName.Substring(prefix.Length); + } - return queue.QueueName; + return queue.QueueName; + } + catch (MessageQueueException) + { + return queue.FormatName; + } } private void InitMessages() @@ -102,6 +136,8 @@ private void InitMessages() messageQueue.MessageReadPropertyFilter.SentTime = true; messageQueue.MessageReadPropertyFilter.ResponseQueue = true; messageQueue.MessageReadPropertyFilter.CorrelationId = true; + messageQueue.MessageReadPropertyFilter.MessageType = true; + messageQueue.MessageReadPropertyFilter.Acknowledgment = true; this.messages = messageQueue .Cast() @@ -112,7 +148,9 @@ private void InitMessages() m.Label, m.SentTime, m.ResponseQueue != null ? GetFriendlyName(m.ResponseQueue) : string.Empty, - m.CorrelationId)) + m.CorrelationId, + m.MessageType.ToString(), + m.Acknowledgment.ToString())) .ToList(); } } diff --git a/README b/README index e13e48a..63c90a1 100755 --- a/README +++ b/README @@ -3,9 +3,21 @@ MSMQFastView is very, very simple MSMQ queues viewer. Its UI is optimized for sp It supports subqueues and showing body of arbitrary large messages. Requirements: - - Windows 7 or Windows Server 2008 R2 + - Windows XP / Windows Server 2003 (or higher) - MSMQ - .NET 4.0 +Remote connection notes: + - with both machines in the same domain, no special configuration is needed + - domain client -> workgroup server: + * only queue names will be shown, viewing messages will fail (Vista+ OS limitation; MSMQ MMC snap-in has the same problem) + * requires accounts with matching names and passwords on both computers, the client may use a domain or local account + - workgroup client -> domain server: + * viewing messages requires: + + turning off RPC security (uncheck "Disable un-authenticated RPC calls" in MSMQ properties on the server) + + for each queue, granting "Receive Message" and/or "Receive Journal Message" to "ANONYMOUS LOGON" pseudo-user (on the other hand, MSMQ MMC snap-in requires only "Peek" permission) + * requires accounts with matching names and passwords on both computers, must be a local account on the server + - works for accounts with administrative privileges on the server; not tested with limited accounts + Homepage: https://github.com/whut/MsmqFastView License: MIT diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt index d7cd3b0..6091e7d 100644 --- a/ReleaseNotes.txt +++ b/ReleaseNotes.txt @@ -1,3 +1,11 @@ +HEAD + - showing message type (normal/report/acknowledgement) and acknowledgement type + - fixed error while parsing response queue name + - ability to connect to remote machines (domain->domain or workgroup->domain; domain->workgroup will connect but will not display messages) + - journal queues shown (local machine: when enabled, remote: always) with message count + - total message count shown in tree view + - support for MSMQ 3.0 (without subqueues) - Windows XP/2003 + MsmqFastView 0.3.0 2011-10-09 "Agile Viewer" - added application icon - added extensibility point to add additional message details diff --git a/TODO.txt b/TODO.txt index c810727..6f73b5a 100755 --- a/TODO.txt +++ b/TODO.txt @@ -1,4 +1,3 @@ - - journal queue - dead-letter queue - outgoing queue - click once ? @@ -13,6 +12,5 @@ - last refresh date in status bar - build script - disable "Refresh/Purge this queue" by default, to have them disabled before selecting queue - - support for older MSMQ (without subqueues) - detect when MSMQ is not installed - config option to disable RSB integration \ No newline at end of file