Recently, I created a new WinUI 3 (v1.2) desktop app using Template Studio for WinUI. Because starting unpackaged apps in Debug is so much faster than packaged apps, I chose an unpackaged app in the setup wizard. The resulting barebones code created an app that always crashed when closed using the Close method or the Close button on the System Menu.
The app throws an unhandled exception which VS 2022 catches in App.g.i.cs in the following section:
#if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
UnhandledException += (sender, e) =>
{
if (global::System.Diagnostics.Debugger.IsAttached) global::System.Diagnostics.Debugger.Break();
};
#endif
You can disable this by setting the DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION variable in the project Properties (under Build -> Conditional compilation symbols) but the program will still throw the error (this code simply gives you a convenient way to trap unexpected errors).
Can anyone explain why this is happening with an unmodified new project and how to correct it, please?
The template code generates a MainWindow that is of the class WindowEx. This nifty extension of the Window class adds quite a few helpful features (see: WinUIEx Wiki) but some of them aren't completely documented yet. The WindowEx class creates a WinUIEx.WindowManager to manage the WindowEx window. When the WindowEx is closed, WinUIEx.WindowManager.Window_Closed() is called which then calls WinUIEx.WindowManager.SavePersistence() which is the cause of the crash mentioned above.
SavePersistence() tries to save some of the window characteristics so they can be restored when the app restarts. However, the persistence services are only enabled for packaged apps, not unpackaged (which I used). To turn this behavior off, set the PersistenceId property of the WinUIEx.WindowManager instance to either null, string.Empty, or "" (the template sets PersistenceId = "MainWindow" by default). Just add
var manager = WinUIEx.WindowManager.Get(MainWindow);
manager.PersistenceId = string.Empty;
somewhere after MainWindow has been instantiated (I put it in App.OnLaunched). I hope this helps.
Related
Question:
Why does my unpackaged C# application show its icon when I launch it but not when my Windows service launches it? How can I make my app's toasts always show the app's icon?
Details:
I have a C++ Windows Service that launches a C# Win32 application for toast functionality, since toasts cannot be launched directly from a service to a user. It is an absolute requirement that the service launches the toast app. To my frustration, however, the app's icon (i.e. the icon shown on the .exe in Explorer) refuses to show only when launched by my service. Here is an example of what I see when my service launches the app (Note the three squares. This is the Windows 10 default icon):
When I manually launch the app (i.e. click it), this is what I see instead:
The only difference between the above two screenshots is the launch method. The most succinct way I can describe my issue is that I want the launch method (launched from a service) that yields the first screenshot to yield the second screenshot instead.
I can provide the code snippet I used to generate these toasts, although I doubt its usefulness for finding a solution:
var notifier = ToastNotificationManagerCompat.CreateToastNotifier();
var xml = new Windows.Data.Xml.Dom.XmlDocument();
xml.LoadXml("<toast><visual><binding template=\"ToastGeneric\"><text>Foo</text<text>Bar</text></binding></visual></toast>");
var notif = new Windows.UI.Notifications.ToastNotification(xml);
notifier.Show(notif);
The most useful code sample I believe I can provide is the code that the service uses to launch the app:
void SpawnToastApp()
{
constexpr int nProcFlags = DETACHED_PROCESS | NORMAL_PRIORITY_CLASS;
constexpr wchar_t* wcsDesktop = L"WinSta0\\Default";
constexpr wchar_t* wcsToastApp = L"ToastApp\\Toast App (WIP).exe";
HANDLE hUser = NULL;
STARTUPINFOW si{ 0 };
wchar_t wcsCmdLine[MAX_PATH]{ 0 };
_snwprintf_s(wcsCmdLine, _TRUNCATE, L"\"%S\\%s\" %lu", _strInstallDir, wcsToastApp, GetCurrentProcessId());
_sessionCanToast = WTSQueryUserToken(_sessionId, &hUser);
if (_sessionCanToast)
{
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.lpDesktop = wcsDesktop;
_sessionCanToast = CreateProcessAsUserW(hUser, NULL, wcsCmdLine, NULL, NULL, FALSE,
nProcFlags, NULL, NULL,
&si, &_toastHandlerProcessInformation);
}
if(!_sessionCanToast)
{
/// Log it
}
if (hUser) { CloseHandle(hUser); };
}
I include the C++ code because I believe that I have narrowed the problem down to the launch method but am unsure the specific cause beyond that.
Additional Information:
These screenshots utilize Windows.UI.Notifications.ToastNotifications created from raw XML, but I have also tried using the Microsoft.Toolkit.Uwp.Notifications NuGet Package as recommended by Microsoft to the same effect.
I believe this project is a Windows Form App.
I am not using any sort of package--no APPX, MSIX, or sparse package. This is meant to be a lightweight app whose sole function is for toasts. While using a package isn't out of the question, suffice it to say that the number of hurdles and implementation issues make packaging this app undesirable. Indeed, the only reason I would want to package this app is for the icon in the upper left-hand corner of it, which it evidently does already, just not in the way I desire.
Similar to but NOT a duplicate of:
Change toast notification icon in wpf
I have already done this. My issue pertains to the icon's inconsistency rather than the lack of it entirely.
Why is app icon missing for toast notifications in action center on desktop?
I am using a Release build of my app
Cannot override notification app logo for Windows 10/11 VSTO app
Using AppOverrideLogo gets my icon to show under all circumstances, but it's more like a picture in the body of the toast rather than the small icon in the upper left-hand corner of the toast. Essentially, it's not the style I want.
EDIT 1:
I followed a sparse packaging guide found here to more or less the same result, the main difference being that now no icon not shows up at all anywhere. I used the asset generator in Visual Studio and then used the MSIX unpackaging tool to inspect the contents of the sparse package and confirmed it contained the generated assets. I had to comment out the reference to the splash screen because the app failed to register with that line included in the manifest.
EDIT 2:
I have decided to proceed with this app as if I am not having this issue, and so I used Visual Studio's Performance Profiler to analyze my app's resources. The Performance Profiler launched my toast app, and the toasts had the correct icon, so at this point I am 100% certain it has something to do with my service's launch method. Unfortunately, I am no closer to understanding why the icon does not show only when launched from my service.
I am designing a Windows Form app. I have an MDIParent form that loads in a maximized state, and loads its child forms in a maximized state as well. However, when I open an OpenFileDialog, or any datareader object, the MDIParent shrinks to a smaller size with all its forms and controls.
This solution Opening child form is causing mdiform to change size and shrink does not apply/work in my situation.
Also this solution https://support.microsoft.com/en-nz/help/967173/restoring-a-maximized-or-minimized-mdi-parent-form-causes-its-height-t did not work for me.
Some background: I have seen this behaviour in almost all my WinForm applications but I have never been keen to sort it out. I was able to narrow down to the causes as highlighted above when I started investigate it. Some posts are describing it as a windows bug, but it has existed for as long as the screen resolutions started going above 1024 (VS 2010) for my case. I hoped it is not just a windows bug...
I hoped it is not just a windows bug...
Feature, not a bug, but it is not one that Winforms programmers like very much. Notable is that there have been several questions about mystifying window shrinkage in the past few months. I think it is associated with the release of Win10 Fall Creators edition. It has deep changes to the legacy Win32 api layer and they've caused plenty of upheaval.
In your specific case, the "feature" is enabled by a shell extension. They get injected into your process when you use OpenFileDialog. The one that does this is very, very evil and does something that a shell extension must absolutely never do. It calls SetProcessDPIAware(). Notable is that it might have been written in WPF, it has a very sneaky backdoor to declare itself dpiAware. Just loading the PresentationCore assembly is enough. But not otherwise limited to WPF code, any code can do this and that might have been undetected for a long time.
One way to chase down this evil extension is by using SysInternals' AutoRuns utility. It lets you selectively disable extensions. But there is also a programmer's way, you can debug this in VS.
Use Project > Properties > Debug tab > tick the "Enable native code debugging" checkbox. Named slightly different in old VS versions btw. Then Debug > New Breakpoint > Function Breakpoint. Function name = user32!SetProcessDPIAware, Language = C. You can exercise this in a do-nothing WPF app to ensure that everything is set correctly. For completeness you can also add the breakpoint for SetProcessDPIAwareness, the new flavor.
Press F5 to start debugging and trigger the OpenFileDialog.ShowDialog() call. The breakpoint should now hit, use Debug > Windows > Call Stack to look at the stack trace. You typically will not see anything very recognizable in your case since the evil code lives in a DLL that you don't have a PDB for. But the DLL name and location (visible in Debug > Windows > Modules) ought to be helpful to identify the person you need to file a bug with. Uninstall it if you can live without it.
Last but not least, it is getting pretty important to start creating Winforms apps that are dpiAware so such a bug can never byte. You kick this off by declaring your app to be dpiAware so DPI virtualization is disabled. Plus whatever you need to do in your code to ensure the UI design scales properly.
I recently got the request to fix a bug in a tool which was created by a co-worker which has left the company.
This tool is basically a WinForms-application based on .NET-Framework 4. It works fine in general but the following situation will lead to random crashes:
If the program is in the background (doesn't have the focus) and is brought to the foreground (focused / activated) by the user after a while, it crashes with the message "ToolName has stopped working".
ToolName is replaced with "vshost.exe" if it's executed under a debugger. There is no additional error message displayed. I don't know which line of the code causes the error.
Some additional information:
If I try to force this error by activating the window, activate another Window (for example Outlook), then activate the window of my tool again, this will rarely crash the tool (there must be some other leverage).
The MainForm has no assigned event-handlers except Form_Load and Form_SizeChanged
The application uses the WeifenLuo-Docking-Library and ZedGraph-Library.
I have the impression that this error appears only if the application runned for a while.
The crash appears at least on two computers which run Windows 7 x64. (I haven't tried any other so far)
I can't attach a debbuger to the crashing process (neither Visual Studio 2010 nor 2013 will work!). I get the message
"The current debugger is configured to debug code that uses Microsoft .NET Framework v 1.0, 1.1, or 2.0. An unhandled exception is being thrown from .NET Framework v4.0 code."
I tried to obtain more information about the crash by adding global exception handlers which should create a MessageBox with the stack-trace but they don't fire:
[STAThread]
static void Main()
{
AppDomain currentDomain = default(AppDomain);
currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += GlobalUnhandledExceptionHandler;
System.Windows.Forms.Application.ThreadException += GlobalThreadExceptionHandler;
// ...
}
private static void GlobalUnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = default(Exception);
ex = (Exception)e.ExceptionObject;
MessageBox.Show(ex.Message + "\n" + ex.StackTrace);
}
private static void GlobalThreadExceptionHandler(object sender, System.Threading.ThreadExceptionEventArgs e)
{
Exception ex = default(Exception);
ex = e.Exception;
MessageBox.Show(ex.Message + "\n" + ex.StackTrace);
}
In my desparation I added a try-catch-Block around Application.Run which won't fire as well:
try
{
Application.Run(new MainForm());
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
When I run into issues like this, I usually start with the Event Viewer. Windows will log application crashes to the Event Viewer, even if they are silent. Sometimes, it is able to spit out a stack trace which can make things even easier. From my experience, the application is silently crashing because it is trying to load some dependency that is missing and it is getting a TypeInitializationException.
It is hard for me to tell you what the root cause without known more information about the application. Is the application loading any 3rd party libraries? Any custom control drawing happening in the application? I believe .NET lazy loads types. If a type isn't needed until the application tries to draw itself, then it may not get loaded until the application is first shown. At that point, if the type is missing the application will crash. Does the app start minimized? Are the crashes random or consistent? Meaning, if you show the application on start up, does it work? Or does it ALWAYS crash when you first display the app?
What version of Visual Studio are you using? Is your project file set to .NET 4? You can select what code type to attach with when you attach to a process. In the Attach to Process dialog, press "Select" to the right of Attach to (default should be Automatic: Native code). Then select the desired code type. This option is in the same place for VS 2010 and 2013.
I got rid of the crashes:
The application created an instance of a 3rd-party COM-Object implemented in a native language. This instance was created in a thread (propably to avoid a Loader Lock-Error which would appear if created on the main thread).
In the event log (found in the control panel) there where more information about the crash. There was a hint to the name of the DLL which caused the crash (Thanks to Tom for the tip!).
I changed the creation of the COM-object from early binding (via dynamic and Activator.CreateInstance()) to late-binding (I added a reference to the COM-object in Visual Studio). This allows me to create an instance of the COM-object on the main thread during startup.
I didn't experienced any crashes since then.
I have taken over support of a VB.Net WinForms application. I am actually a c# developer and am more familiar with the setup of visual studio projects in c# projects. Now I am trying to determine why my application is crashing on a specific XP installation, and I read the suggestion here
http://social.msdn.microsoft.com/forums/en-US/winformssetup/thread/53c2de93-ab33-41d0-b5dd-7ca5fbfa5c24/
to add a try catch block in the main function. This is suggested in about the 5th post from the bottom. (I will quote it below) However, if I look in the VB.Net visual studio project, I do not find a Main() procedure. What I do find is a grey folder called "My project" with a "Application.myapp" file inside it. This file has an associated designer file, but if I click on it I see the following xml:
<?xml version="1.0" encoding="utf-8"?>
<MyApplicationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MySubMain>true</MySubMain>
<MainForm>MDIMain</MainForm>
<SingleInstance>false</SingleInstance>
<ShutdownMode>0</ShutdownMode>
<EnableVisualStyles>true</EnableVisualStyles>
<AuthenticationMode>0</AuthenticationMode>
<SaveMySettingsOnExit>true</SaveMySettingsOnExit>
</MyApplicationData>
So can anyone enlighten me to where the actual main procedure call is for this VB.Net project so that I can try catch the exception that is occurring. If, as I suspect, there isn't actually a Main procedure in my VB.Net project, can someone maybe let me know how I can go about doing the following in my project:
[STAThread]
static void Main()
{
try
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
catch (System.IO.FileNotFoundException ex)
{
MessageBox.Show(ex.Message + " \n\n\n" + ex.StackTrace);
}
}
VB has a special mode called “Application Framework” (which can be found under the main options).
If this mode is enabled, the compiler auto-generates a Main method and some fluff around it. You can disable this option; however, this may cause problems in the project since the application framework functionality might actually be used by the project.
Alternatively, you can register an event handler for uncaught exceptions (UnhandledExceptions) using this same application framework.
The more VB way to do this is to open the Application properties and click on the ViewApplicationEvents button. This will open the Application.xaml.vb file where you can add custom event handlers for the application. Select Application Events from the left drop-down and you can easily access a bunch of events including DispatcherUnhandledException, Activated, Navigating, Startup, Exit, etc. You can also add the Main method here by selecting Applciation from the left drop-down and selecting Main from the right drop down.
In the case of WindowsForms applications, the process is similar. However when you select the Applciation Events button, the file that is shown is the ApplicationEvents.vb file. In here, to add a global error handler, select the left drop-down and select MyApplication Events. Then in the right drop-down, add the UnhandledException handler. You can also create your Main method here as well.
It is generated automatically by the compiler when it can't find one, but you can create one yourself.
http://msdn.microsoft.com/en-us/library/ms235406%28v=VS.100%29.aspx
http://msdn.microsoft.com/en-us/library/y4bwckbb.aspx
I came to this page today in search of answers, and I found some good ones, both here and in The Code Project.
By the time I satisfied myself that I knew what to do, I also had in hand a simplified approach that leaves the project properties virtually untouched. (You must turn off the Application Framework, or the VB runtime won't run your Main routine!) In a nutshell, if you define your Main routine in the class module that defines your startup form, the Visual Basic runtime engine will find and execute it.
As is stated above, your routine must be defined as Shared. You can see my example, along with a few other notes, at How to Run a Particular Form in VB.NET
Caveat
When you disable the Application Framework, you lose the Single Instance check box. I just finished updating the cited example to include the code that I developed and tested to enforce single instance.
You can create that method anywhere, as long as it's Shared. To wire it up, you have to go into the project settings and set the entry point to be your Main method.
If you have IE8, you may have noticed a really handy feature that MS has added. Hit F12 and Developer Tools, a firebug like debugger, pops up. This is extremely useful for debugging purposes, and i'm wondering if there is a way to pop up the Developer Tools from a WebBrowser control inside a .NET application.
My situation is this: I have a C# application that has an embedded WebBrowser control. The C# app and the DHTML web browser contents communicate with each other using the ObjectForScripting (C# side) and window.external (DHTML side) interfaces, so in order to test/debug/troubleshoot the full functionality, i need a way to trigger Developer Tools from within the WebBrowser control. Up to now we've been limited to using Firebug Lite which is severely limited or triggering a step debug session of the javascript using the 'debugger;' js, but now we're getting to the point where those options becoming a real hassle and don't allow the full features that we would get out of having something like Firebug or Developer Tools at our disposal.
What I'd really love to do is to be able to pop up Developer Tools from inside my WebBrowser control while the app is running, but I haven't found a way to accomplish this yet.
Has anybody else ran into this issue and found out if there's a way to make it happen?
No, as others have said this is not possible. However there is a way you can wire most of the window errors through to a custom handler.
Once the document has finished loading you can attach a listener to the window. e.g.
webBrowser.DocumentCompleted += (o, e) =>
{
webBrowser.Document.Window.Error += (w, we) =>
{
we.Handled = true;
// Do something with the error...
Debug.WriteLine(
string.Format(
"Error: {1}\nline: {0}\nurl: {2}",
we.LineNumber, //#0
we.Description, //#1
we.Url)); //#2
};
};
I believe the developer tools are implemented in the IE host (iexplore.exe), not in MSHTML itself. Obviously the hooks are there for it, but I don't think you can get to the UI and stuff from the control.
There isn't a way for the embedded hosts to use the built-in developer tools. But if you want to debug you should still be able to, you can attach visual studio / windbg to your app, at worse you could insert breakpoints with the "debugger" keyword. In VS you might have to select script from the "select..." menu under "debug these code types".
One option is to open a child window from the embedded page, the child window opens in IE and the Developer Tools work, you can then do
window.opener
in the console to refer to the parent and manipulate the page.
Or replace the parents console with the child's and redirect to it.
var logWindow = window.open();
logWindow.document.write('<html><head><title>Child Log Window</title></head>\x3Cscript>window.opener.console = console;\x3C/script><body><h1>Child Log Window</h1></body></html>');
window.onunload = function () {
if (logWindow && !logWindow.closed) {
logWindow.close();
}
};
Not an ideal solution, but you can use Visual Studio to attach and debug your app in Script mode. You shouldn't debugging the application and / or launch another instance of Visual Studio:
DEBUG > Attach To Process ...
Attach to must be Script and select your running instance of the application
And finally Attach