-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Visual Styles not enabled when app published as 'Self-contained' + 'Produce Single File' #4145
Comments
Here is the relevant docs entry: https://docs.microsoft.com/en-us/dotnet/core/deploying/single-file#api-incompatibility Some of the related issues. dotnet/runtime#40087 Need to look for any of these problematic APIs in the code base. |
Presumably using the manifest to enable styles (comctl6) should work in single file, should validate that this is the case. |
Code in question:
|
The only way to create the required ActivationContext to enable Visual Styles is via System.Windows.Forms.ThemingScope.CreateActivationContext which is on an internal class. |
@marknn3 The only practical workaround is to add a manifest file to your project and enable the 6.0 common controls section. Uncomment this section after adding a manifest item to your project: <!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency> I'm investigating a possible fix. |
When I publish 'Self-contained' + 'Produce Single File' the manifest is included and the code above is already there and not commented out. The publish still fails with
I am publishing a 64 bit app |
@paul1956 I don't see that error. I created a new 5.0 WinForms application, added a button to the form to see the styles, and added an "app.manifest" and uncommented as above. Publishing as follows: |
@agocke I've run into a bit of a wall here. I can't seem to get the Note that |
@JeremyKuhne not sure what the difference is, except mine is a real project. I get the error above and my project already had a manifest from framework and the XML above was already uncommented. |
This does indeed re-enable Visual Styles! And for me this workaround is completely acceptable. But since this is a regression it must indeed be fixed. Might not be trivial. Thanks for the quick response! |
@JeremyKuhne Have you already loaded the assembly? Either by cc @vitek-karas. Context is trying to get an |
@paul1956 Your issue should be tracked separately. Can you open a new issue with detailed repro steps? Note that I am currently:
As much detail as you can put in the new issue would be great. Please try to minimize the repro as well. This will help us reproduce the error. |
@agocke Yes, the assembly is loaded already. It shows in the assemblies debugger window and the code that is trying to get the CreateActCtx is the API we have to use to "inject" the manifest. It requires a manifest file or a native resource from a PE image. The fix I'm attempting is to use I'll try and dump the manifest file to the temp folder to see if that works, but that is something I'd rather not do if possible. |
I've looking into this couple of weeks ago and this will need a different solution. My understanding of the problem:
The core issue here is that in .NET 5 Single-File none of the assemblies loaded directly from the bundle have an HMODULE - we map them into memory basically like a random piece of data - we don't go through LoadLibrary (can't, Windows can't load library from an offset in a file). Since there's really only one true file (and thus also only one true HMODULE) - the bundle itself, the app.exe - we need to work with that. One possible solution would be to:
|
Ah, I didn't know that there was only one |
@vitek-karas Your solution seems plausible and likely would end up useful in other scenarios too. What is the the prescribed way to detect that we're in single file mode? |
It's a windows limitation (as far as I know) - HMODULE == something loaded via LoadLibrary (or similar). Detect single-file - for this case checking We intentionally don't have a specific API to detect single-file - we kind of hope that people will be able to write code which works in either case. Unfortunately native Win32 resources are... weird. |
We could/should take this a step further and probably have a more general solution for Win32 resources - SDK could pretty easily go over all assemblies which will be bundled and extract native resources and add them to the .exe. The problem will be collisions - but maybe something along those lines. Or have an item metadata which would tell SDK to do this. Just like we have one to exclude it from the bundle, we could have CopyWin32ResourcesToBundle (better name obviously). |
I think that may be the better choice, we would need to know what the identifier would be in code and I don't know how we would do that if there was auto collision renaming. |
I wasn't thinking about auto-rename - that's just asking for trouble. Either it would work, or fail. But I agree it's better to have this opt-in. The managed code will have to react to this anyway, since the way to get the HMODULE/FileName is different for single-file. So the code owner must be aware of this and thus it's better to make it opt-in. |
@vitek-karas I'm going to try the temp folder solution to see if that works so we can know what our options are. This is something we're going to want to service as default WinForms projects don't work properly with single file. |
Reminder that we have a back-compat flag for extraction |
Creating a temporary manifest in the Temp directory works, I've created a PR #4149 for master (6.0) that does this. For servicing 5.0 this may be what we want to do as I presume adding infra for native resources is out of scope for a servicing fix. I'll get our testers to specifically look at the single file publish scenario and scour the code for usage of other impacted APIs. https://docs.microsoft.com/en-us/dotnet/core/deploying/single-file#api-incompatibility |
I think it's worth considering what @agocke mentions above. Using the |
Note that for native resource manifests the WinForms manifest is not the same as the manifest the main application may carry by itself. You may very well have a scenario where the main application has a manifest not declaring v6 support and relying on using the WinForms API call to enable v6 support. Propagating the manifest from the WinForms assembly into the single file application will conflict the native resource ID in a way not resolvable unless WinForms understands that scenario and looks at a different resource index for single file scenarios.
Aren't native resources exclusively accessed via native APIs? That means the calling code will fail anyways, just like WinForms failed. Not much point remapping native resources if you can't access them without being specially coded for it (and at that point you probably should use something else than native resources). I'd propagate the native resources only of the main application and emit warnings for any embedded libraries that have custom native resources, because its very likely those libraries won't work if they try to access their resources. |
@JeremyKuhne the difference I am using ClickOnce |
WinForms code can use any resource ID, so the idea is to put the WinForms manifest into the .exe under some unique name/ID definitely not under "1". The original app's manifest should still be the "1". I do agree that code wanting to consume native resource will have to be aware of single-file and as noted in such case it would be ideal if it changed to not use native resource. But given this example it might not always be possible. So having an opt-in mechanism seems reasonable. |
.NET Core Version:
5.0.100-rc.2.20479.15
Have you experienced this same bug with .NET Framework?:
No
Problem description:
Application.EnableVisualStyles() does not enable Visual Styles when the application is published as 'Self-contained' + 'Produce Single File'.
The probable root cause is that
typeof(Application).Assembly.Location
returns an empty string for this scenario on .NET 5.Note that on .NET Core 3.1 it returns a temporary file location.
Minimal repro:
Create simplest WinForms .NET 5 App.
In Form1 ctor add following sample code to show the result:
Text = "UseVisualStyles=" + Application.UseVisualStyles.ToString() + "; " + typeof(Application).Assembly.Location;
Publish app:
The text was updated successfully, but these errors were encountered: