Diagnosing why a custom shell on Windows 10 IoT gives black screen - winforms

I am configuring Windows 10 Enterprise (IoT) to run a custom shell, but running into the "Black screen with nothing other than a cursor" phenomena.
My application - a .Net4 Winforms app - is installed and runs fine from the desktop.
I can launch it as a custom shell via a batch file as per the comments here: How to run an application as shell replacement on Windows 10 Enterprise
But setting my app as a custom shell, I just get the black screen.
I note the comments in the above link about applications being signed, but I have tried two mini test applications (also .net winforms), one signed, one not, and both run fine as custom shells. (My application has several dependencies, not all of which are signed, so to sign it would mean going through the ILMerge mill or similar which I would rather avoid if I can.)
I don't expect people to be able to tell me why my app doesn't run (although that would be nice!) but I am looking for ways of diagnosing this. Looking in event logs, etc, is yielding no information whatsoever. My app keeps its own event log, which is not showing any evidence of the app starting.
Thanks in advance

Problem solved:
If a shell application requires elevated permissions, UAC must be turned off. Turning off notifications via the control panel is NOT sufficient, as UAC is still running in the background - it just doesn't notify you! To completely turn off UAC, edit registry entry:
HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System and set the DWORD value EnableLUA to 0
Evidence of UAC behaviour can be found in the windows event log at:
Applications And Services Logs -> Microsoft -> Windows ->UAC

Related

Packaged shell extension killing application

I have a WPF application. To give it an identity to consume UWP APIs, I've added sparse package support. This installs / uninstalls / updates (we're not using MSIX) with my WPF application fine, and my app is running with an identity. It shows in task manager with a Package Name listed on my process.
Now I'm attempting to add context menu support following Microsoft's docs.
I've created a shell extension which will show when opening the context menu for any file and folder, which is pretty much a copy of their sample with different GetIcon(), GetTitle() and Invoke() implementations for IExplorerCommand.
I'm specifying this in the AppxManifest.xml (values anonymised):
<desktop4:Extension Category="windows.fileExplorerContextMenus">
<desktop4:FileExplorerContextMenus>
<desktop5:ItemType Type="*">
<desktop5:Verb Id="MyFileCommand" Clsid="file-guid"/>
</desktop5:ItemType>
<desktop5:ItemType Type="Directory">
<desktop5:Verb Id="MyFolderCommand" Clsid="folder-guid"/>
</desktop5:ItemType>
</desktop4:FileExplorerContextMenus>
</desktop4:Extension>
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:SurrogateServer DisplayName="SSVerbHandler">
<com:Class Id="file-guid" Path="my-shell-extension.dll" ThreadingModel="STA"/>
</com:SurrogateServer>
<com:SurrogateServer DisplayName="SSVerbHandler">
<com:Class Id="folder-guid" Path="my-shell-extension.dll" ThreadingModel="STA"/>
</com:SurrogateServer>
</com:ComServer>
</com:Extension>
This works, my context menu entry is listed and performs the action as expected. But here's the issue: each time the context menu is opened for the first time, it kills the already running instance of my WPF application. By first time, I mean restarting explorer.exe and right clicking on a file or folder.
My gut feeling is this is related to UWP side of things. This is because originally it would always kill my application when right clicking to open a context menu. But with a little trial and error I solved this by configuring multi-instance support in my AppxManifest.xml:
<Package
...
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
xmlns:iot2="http://schemas.microsoft.com/appx/manifest/iot/windows10/2"
IgnorableNamespaces="uap mp desktop4 iot2">
...
<Applications>
<Application Id="App"
...
desktop4:SupportsMultipleInstances="true"
iot2:SupportsMultipleInstances="true">
...
</Application>
</Applications>
...
</Package>
I'm hoping someone can suggest any troubleshooting ideas as I'm now struggling.
I've sprinkled some ol' trusty MessageBox functions within the shell extension in DllMain, DllCanUnloadNow and DllGetClassObject. But for that first load attempt, no message boxes are shown, no context menu item listed and my application is still killed.
I've poked around in the event viewer hoping to see any errors or warnings listed recently, plus in Applications and Service Logs\Microsoft\Windows\Appx* and Applications and Service Logs\Microsoft\Windows\AppModel-Runtime. Nothing has jumped out at me.
According to this SO anwser, if there's an error with the shell extension itself, it may not show. That does fit, but I'm sceptical as it always works on subsequent attempts, and the previously solved UWP killing issue.
In the scenario where my application stops, using these powershell commands I get:
$process = Start-Process .\MyApp.exe -PassThru -Wait
$process.ExitCode
1
I do have crash logging in my app, but nothing gets logged. This is the only place Environment.Exit(1) is called within the WPF application.
I did try the silent monitoring detection in GFlags on the WPF application, but couldn't seem to trigger it. Only when I manually closed the application. (Ignore Self Exits unchecked for testing). I'm not sure if that's because the exit code is 1.
When the error occurs with process monitor running, I can see lots of ThreadExit before a final ProcessExit with the exit code 1. That would imply it's exiting cleanly with my application itself returning 1?
It's also worth mentioning I've lived in managed / .NET land for the last decade or so, I don't have much experience with C++ (or unmanaged languages in general) or UWP, and the first time I've attempted to write a shell extension.

Why is [PrtSc] button not working in Intellij-Idea or Microsoft SQL Server Management Studio?

I'm using a thrid-party screen capturing application (Screenpresso). It's configured to start screen-capturing when I press PrtSc. And indeed it works except when Intellij has Windows focus. In fact, to screen capture code I have to focus on any other window press PrtSc and then select the area within Intellij.
I've looked through all the settings, and especially the Keymap settings, and I can't see anything else that has been assigned to PrtSc. Of course, I'm not really sure; when I try to find a setting via nothing happens, as pressing PrtSc has no effect.
I know this used to work for me in previous versions of Intellij (though I can't remember what versions). But PrtSc used to work in Intellij just like every other application.
So I guess the question is, why is Intellij eating the PrtSc keypress event? And can I turn it off so that the event gets correctly passed to my dedicated screen capturing application.
Intellij 2019.2.4
Windows 10, 64b
This turned out to be an issue with Screenpresso:
https://www.screenpresso.com/support/hot-keys/
Why shortcut [print screen] key does not always work?
This must be because you run your application with elevated
privileges (with admin rights) (the UAC must have displayed a popup
at startup).
For security reasons, Screenpresso can handle shortcuts
from Windows running with elevated privileges only when it is
installed in Program Files folder.
To fix this, you should install
Screenpresso in Program Files folder which is not the default
behavior:
Uninstall Screenpresso
Run again Screenpresso: Right click Screenpresso.exe and select Run as administrator
Click on the INSTALL on this computer button while holding the Control key or click on the sub-menu Install for all users:
Some users have this problem, first reported 5 years ago: Find here
Crash dumps (java_error_in_*.log in the user's home directory) can help to understand it better.

RDP / MSTSC Ignores highdpi manifest fix when launched from windows form application

I'm using VS2017 and have made a very simple 'launcher' for various RDP settings files using a Windows Forms application. This just calls Process.Start with a direct link to a .rdp file, or alternatively just straight to mstsc.exe
The application (and RDP sessions) displays and works correctly on standard PCs. However I have run into a problem on high DPI devices such as Surface Books/pros.
The RDP client not scaling correctly is a fairly well known issue, and we have fixed this problem using the manifest/reg change method. This is confirmed working. Double clicking a .rdp config file works correctly too.
( https://www.blackforce.co.uk/2016/04/18/remote-desktop-rdp-resolution-on-a-surface-book )
My own application also displays correctly at the correct scale. However, when I launch RDP using Process.Start, RDP client is scaled badly, as it always was before the manifest fix. I've tried opening the client alone, and with a .rdp file and result is the same. I open the same .rdp file manually, not via my app, and the client is scaled correctly.
Can anyone replicate this, or advise why the mstsc manifest file is ignored when started this way? I've also tried the using ProcessStartInfo to set UseShellExecute but still the same result.
Windows desktop apps, such as RDP, can specify a DPI-scaling mode ("DPI awareness mode") either through a manifest setting or via API calls during initialization. Applications will behave differently whenever the scale factor of the display that they're on changes. You can read more about this here.
I'd speculate (I haven't tried this to confirm this speculation) that the RDP process is using a manifest to declare it's DPI awareness (as Per Monitor DPI aware) and that when you're launching a process through Process.Start that the specified DPI awareness of the app is getting changed... possibly to the DPI awareness of the calling process?
I'd use System Internals Process Explorer to determine the DPI awareness of the RDP app when it runs as expected, and then compare that to the DPI awareness of the RDP app when it's launched from your app. If that is the case, look it to whether you can specify the DPI awareness of the process that you want to start in Process.Start. Another thing that you can try is to set the DPI awareness of your WinForms app to the same DPI awareness of the RDP app (per-Monitor) to see if that helps.
Also, I'm assuming that you're running on an OS > 8.1 as Per-Monitor support was introduced in 8.1.

Batch process does not print with correct font

A WinForms program I have developed prints fine and as expected when run as an interactive user. Using the same account but as a scheduled task, the process will run correctly however it prints part of the output in the incorrect font.
The program is a label printer that prints updated pricing labels. It has an option (-s) that the Task Scheduler calls which does not present the GUI but does an update and prints. Executing this as an interactive user through run works correctly (i.e. the correct font is used).
Any clues as to what's happening here? The font that isn't printing correctly is a non-standard system font.
This runs on a server and I thought it might be due to printer redirection but I did a console logon and it worked fine as an interactive process on the console just as it does as interactive through remote desktop.
Interesting problem. Presumably, Windows doesn't load fonts into the non-interactive logon sessions in order to conserve resources.
See this answer for one approach, using the ps tool to create an interactive session when running the task.
I had a very similar issue to yours (running an application through a scheduled task would use the default font but when running locally it would find the custom font I installed) and I found a solution; On Server 2008, there is an issue where custom fonts are not registered immediately after installing for non-interactive users, whereas regular users (i.e. when running on a user actually logged in to the machine) do have the font registered immediately.
The solution that worked for me was to simply restart the machine the font was installed on and the font started working under the non-interactive accounts, as when the computer is turned on it registers correctly. It appears the font installation has a bug where it doesn't register the font correctly for non-interactive users until a reboot.

How do I launch a WPF app from command.com. I'm getting a FontCache error

I know this is not ideal, but my constraint is that I have a legacy application written in Clipper.
I want to launch a new, WinForms/WPF application from inside the application (to ease transition). This legacy application written in Clipper launches using:
SwpRunCmd("C:\MyApp\MyBat.bat",0)
The batch file contains something like this command:
C:\PROGRA~1\INTERN~1\iexplore "http://QASVR/MyApp/AppWin/MyCompany.MyApp.AppWin.application#MyCompany.MyApp.AppWin.application"
It is launching a WinForms/WPF app that is we deploy via ClickOnce. Everything has been going well until we introduced WPF into the application. We were able to easily launch from the legacy application.
Since we have introduced WPF, however, we have the following behavior. If we launch via the Clipper application first, we get an exception when launching the application. The error text is:
The type initializer for 'System.Windows.FrameworkElement' threw an exception.
at System.Windows.FrameworkElement..ctor()
at System.Windows.Controls.Panel..ctor()
at System.Windows.Controls.DockPanel..ctor()
at System.Windows.Forms.Integration.AvalonAdapter..ctor(ElementHost hostControl)
at System.Windows.Forms.Integration.ElementHost..ctor()
at MyCompany.MyApp.AppWin.Main.InitializeComponent()
at MyCompany.MyApp.AppWin.Main..ctor(String[] args)
at MyCompany.MyApp.AppWin.Program.Main(String[] args)
The type initializer for 'System.Windows.Documents.TextElement' threw an exception.
at System.Windows.FrameworkElement..cctor()
The type initializer for 'System.Windows.Media.FontFamily' threw an exception.
at System.Windows.Media.FontFamily..ctor(String familyName)
at System.Windows.SystemFonts.get_MessageFontFamily()
at System.Windows.Documents.TextElement..cctor()
The type initializer for 'MS.Internal.FontCache.Util' threw an exception.
at MS.Internal.FontCache.Util.get_WindowsFontsUriObject()
at System.Windows.Media.FontFamily.PreCreateDefaultFamilyCollection()
at System.Windows.Media.FontFamily..cctor()
Invalid URI: The format of the URI could not be determined.
at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)
at System.Uri..ctor(String uriString, UriKind uriKind)
at MS.Internal.FontCache.Util..cctor()
If we launch the application via the URL (in IE) or via the icon on the desktop first, we do not get the exception and application launches as expected.
The neat thing is that whatever we launch with first determines whether the app will launch at all. So, if we launch with legacy first, it breaks right away and we can't get the app to run even if we launch with the otherwise successful URL or icon. To get it to work, we have to logout and log back in and start it from the URL or icon.
If we first use the URL or the icon, we have no problem launching from the legacy application from that point forward (until we logout and come back in).
One other piece of information is that we are able to simulate the problem in the following fashion. If we enter a command prompt using "cmd.exe" and execute a statement to launch from a URL, we are successful. If, however, we enter a command prompt using "command.com" and we execute that same statement, we experience the breaking behavior.
We assume it is because the legacy application in Clipper uses the equivalent of command.com to create the shell to spawn the other app. We have tried a bunch of hacks like having command.com run cmd.exe or psexec and then executing, but nothing seems to work.
We have some ideas for workarounds (like making the app launch on startup so we force the successful launch from a URL, making all subsequent launches successful), but they all are sub-optimal even though we have a great deal of control over our workstations.
To reduce the chance that this is related to permissions, we have given the launching account administrative rights (as well as non-administrative rights in case that made a difference).
Any ideas would be greatly-appreciate. Like I said, we have some work arounds, but I would love to avoid them.
Thanks!
It sounds like the Presentation Font Cache service has trouble starting when the app is launched in this way.
If you have control over the client environment, you could try setting the Windows Presentation Font Cache startup to automatic instead of manual.
This is a shot in the dark made with incomplete information:
command.com and cmd.exe are quite different. AFAIK, command.com exists for legacy compatibility, so applications you run from it will run differently. I can't test anything to complete my post because I believe that command.com runs in 16-bit mode and 64bit versions of Windows (on which I'm running) don't support that mode anymore so no more command.com for me.
That being said, there should be no difference when trying to run 32-bit applications (including managed applications).
I'm not aware of what are the limitations of your environment, but some things you may try are:
Rename you .bat into .cmd to make sure it starts with cmd.exe rather than command.com
Make your .bat start the program using the start console command
Have a non-WPF program to invoke your WPF one with a more sane environment
The problem is that the windir environmental variable is not set when using command.com.
So, in your case, adding the line set windir=C:\Windows to the beginning of the bat file will solve the problem (assuming that you have your Windows instalation in C:\Windows.
An additional issue might be that the host application is running command.com in compatibility mode. The best is to list all the environmental variables after running cmd.exe (using the set command) and comparing it to the output of the set command that you set in your bat file

Resources