1

I have a WPF application I built for the company I work for. The whole things works great on my machine and other machines in the branch network.

However, we have a user here at head office who cannot use it. The application immediately closes upon startup. I tried to monitor it in Task Manager, and it appears, and then closes right away.

So, I decided to put some message boxes in the startup form to see where it fails:

    public LoginWindow()
    {
        MessageBox.Show("CHECKING FOR UPDATES");
        var updated = Jmis.IsUpdated();
        MessageBox.Show("UPDATES CHECKED");
        if (updated)
        {
            MessageBox.Show("LOADING SETTINGS");
            Settings = FileManager.LoadSettings();
            MessageBox.Show("SETTINGS LOADED");
            this.DataContext = Settings;
            InitializeComponent();
            Password.Password = Settings.Password;
        }
        else
        {
            MessageBox.Show("A new version is available!", "Update", MessageBoxButton.OK, MessageBoxImage.Information);
            new UpdateWindow().Show();
            Close();
        }
        InitializeComponent();
    }

It shows me the CHECKING FOR UPDATES message, and then closes.

So again, I put some more messageboxes inside the Jmis.IsUpdated() method:

    public static bool IsUpdated()
    {
        try
        {
            MessageBox.Show("Sending request");
            var response = Http.GetAsync($"{JmisUri}/toasterNotification/version.php").Result;
            MessageBox.Show("Ensuring success");
            response.EnsureSuccessStatusCode();
            MessageBox.Show("Getting version string");
            var version = response.Content.ReadAsStringAsync().Result;
            MessageBox.Show("Checking version");
            return version == Assembly.GetExecutingAssembly().GetName().Version.ToString();
        } 
        catch(Exception ex)
        {
            return true;
        }
    }

I was at least expecting Sending request to come up. But it didn't. I still get the CHECKING FOR UPDATES, but nothing else.

It's as if that method isn't being called at all.

I'm genuinely stumped.

Is there any reason this might happen?

EDIT

After looking at the Event Log, I found this:

Application: JMIS Notifier.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IO.FileNotFoundException
   at JMIS_Notifier.JMIS.Jmis..cctor()

Exception Info: System.TypeInitializationException
   at JMIS_Notifier.JMIS.Jmis.IsUpdated()
   at JMIS_Notifier.LoginWindow..ctor()

Exception Info: System.Windows.Markup.XamlParseException
   at System.Windows.Markup.WpfXamlLoader.Load(System.Xaml.XamlReader, System.Xaml.IXamlObjectWriterFactory, Boolean, System.Object, System.Xaml.XamlObjectWriterSettings, System.Uri)
   at System.Windows.Markup.WpfXamlLoader.LoadBaml(System.Xaml.XamlReader, Boolean, System.Object, System.Xaml.Permissions.XamlAccessLevel, System.Uri)
   at System.Windows.Markup.XamlReader.LoadBaml(System.IO.Stream, System.Windows.Markup.ParserContext, System.Object, Boolean)
   at System.Windows.Application.LoadBamlStreamWithSyncInfo(System.IO.Stream, System.Windows.Markup.ParserContext)
   at System.Windows.Application.LoadComponent(System.Uri, Boolean)
   at System.Windows.Application.DoStartup()
   at System.Windows.Application.<.ctor>b__1_0(System.Object)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Int32)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(System.Object, System.Delegate, System.Object, Int32, System.Delegate)
   at System.Windows.Threading.DispatcherOperation.InvokeImpl()
   at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(System.Object)
   at MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(System.Object)
   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
   at MS.Internal.CulturePreservingExecutionContext.Run(MS.Internal.CulturePreservingExecutionContext, System.Threading.ContextCallback, System.Object)
   at System.Windows.Threading.DispatcherOperation.Invoke()
   at System.Windows.Threading.Dispatcher.ProcessQueue()
   at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef)
   at MS.Win32.HwndWrapper.WndProc(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(System.Object)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Int32)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(System.Object, System.Delegate, System.Object, Int32, System.Delegate)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority, System.TimeSpan, System.Delegate, System.Object, Int32)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr, Int32, IntPtr, IntPtr)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(System.Windows.Interop.MSG ByRef)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame)
   at System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame)
   at System.Windows.Application.RunDispatcher(System.Object)
   at System.Windows.Application.RunInternal(System.Windows.Window)
   at System.Windows.Application.Run(System.Windows.Window)
   at System.Windows.Application.Run()
   at JMIS_Notifier.App.Main()

What's interesting is the exception occurs at JMIS_Notifier.JMIS.Jmis..cctor() but is a static class.

ThePerplexedOne
  • 2,920
  • 15
  • 30
  • 4
    Look in the System Event Log. There should be an error message there. – NineBerry Nov 12 '19 at 15:08
  • Why are you calling `InitializeComponent();` in `LoginWindow`? From the looks of it, there can be many things wrong. Have you properly stepped through `Jmis.IsUpdated();`? – Trevor Nov 12 '19 at 15:08
  • Do you [catch unhandled exceptions](https://stackoverflow.com/q/1472498/1997232)? Remote debugger is a better option to consider. – Sinatr Nov 12 '19 at 15:08
  • @Çöđěxěŕ I'm using the messageboxes to try and determine where it breaks, as I cannot debug from his computer. None of the messageboxes in `Jmis.IsUpdated()` are being fired. – ThePerplexedOne Nov 12 '19 at 15:12
  • off-topic comment: Do you know that you are calling `InitializeComponent()` twice when update is true? – Selvin Nov 12 '19 at 15:13
  • Ah, yes. I didn't see that. But I don't think that's the issue. – ThePerplexedOne Nov 12 '19 at 15:14
  • @ThePerplexedOne That means you do not log or expose enough debug information. While it is very common to not expose all the exception details to a random user, *also not logging* them is a critical mistake. | Once you fix that, you propably instantly realize what is wrong. – Christopher Nov 12 '19 at 15:16
  • 4
    Most common cause for this behaviour is that a referenced assembly cannot be loaded because either a) it is not installed b) it depends on other dlls that are not installed or c) it requires the operating system to be 64bit but the operating system is 32bit or vice versa – NineBerry Nov 12 '19 at 15:17
  • @NineBerry All of those should throw a very clear, very unambigious expcetion message. Wich means he swallows exceptions there too. Wich is why fixing that is my Answer. – Christopher Nov 12 '19 at 15:19
  • @NineBerry I have updated my question with a message I retrieved from the Event Log. – ThePerplexedOne Nov 12 '19 at 15:37
  • @ThePerplexedOne If you want to say "I know it causes no issue", you would say so. Meaining you do not know and it is porpably a mistake. It can be the one causing the issue, or the one hiding hte information telling you want even *is* the issue. – Christopher Nov 12 '19 at 15:48
  • @ThePerplexedOne If you look again in the event log, there might be other entries immediately before or after the one you found that contain the actual error message of the FileNotFound Exception. As I said previously, this is most likely a failure to load a referenced assembly. Try to use [Fusion Logging](https://learn.microsoft.com/en/dotnet/framework/tools/fuslogvw-exe-assembly-binding-log-viewer) to get a detailed log of that is going wrong. – NineBerry Nov 12 '19 at 16:01
  • 1
    @NineBerry I have posted an answer that seems to have solved the issue for one of our users. I will be testing it for other users soon. – ThePerplexedOne Nov 12 '19 at 17:07

2 Answers2

3

When I have run into problems like this before it is usually a missing library. I can only guess here without more information, but I'm guessing that when you call IsUpdated it is loading additional libraries at that point from your using statements.

It may be possible that there is software that is expected to be installed that is not installed on this person's machine.

You can use a dependency walker http://www.dependencywalker.com/ to see if you are missing a library.

Edit

The TypeInitializationException Is just telling you that the class failed to initialize. Since Jmis is a static class, or depends on static classes, the static constructors and initializers get called before your IsUpdated method is called, and somewhere in the initialization of the Jmis class it is failing to find a file.

So, most likely something related to Jmis is not installed, or there is some resource that Jmis is looking for that is not available on the machine that is failing.

TJ Rockefeller
  • 3,178
  • 17
  • 43
  • 1
    Besides using dependency walker, when the problem is loading managed assemblies instead of native dlls, you can use [Fusion Logging](https://learn.microsoft.com/en/dotnet/framework/tools/fuslogvw-exe-assembly-binding-log-viewer) to analyze the problem. – NineBerry Nov 12 '19 at 15:33
  • @Christopher The application gave no indication of such an exception, hence my confusion. Even in the method you pointed out, where I return true after catching, if I put messageboxes showing `ex.Message`, it never gets shown. – ThePerplexedOne Nov 12 '19 at 15:55
  • 2
    @Christopher it is throwing an Exception which is now included in the question, but it was being thrown before `IsUpdated` was ever called, so his try catch was not swallowing it at all because it was never making it to his try catch block. – TJ Rockefeller Nov 12 '19 at 15:56
  • IIRC, when a Framework Application runs into an Exception without a debugger attached, the Framework itself will catch it and display it in a giant Message box. The Framework itself is the ultimative fallback exposer. | Something seems incredibly off, if he only found it in the Event Log - rather then having the Framework shove Exception details in the face of the user. | But yes, a FileNotFound is usually a indicator for a missing Library. (Again, the linked example is *literally that* situation) – Christopher Nov 12 '19 at 16:05
  • You were correct. I just had to install the .NET Framework my application was targeting. It was the only thing I could think of, since I was using `Costura.Fody` to merge the other dependencies into the executable. I just find it odd that I received no indication that it was missing the proper framework. – ThePerplexedOne Nov 12 '19 at 17:19
1

Okay, so I figured that because the user was running Windows 8.1, and because my assembly targets .NET Framework 4.7.2, that I might have to install that version of .NET Framework.

So I have done that and it seems to have solved the issue.

I just find it strange, usually the application will tell you that you need a certain .NET Framework version when you try to open it.

Perhaps it has something to do with the fact that I'm using Costura.Fody to merge the dependencies into the executable.

ThePerplexedOne
  • 2,920
  • 15
  • 30