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
Consider providing a "GUI" version of the shared host #2455
Comments
Can you share more details on what needs this? |
This is just motivated by my own uses currently, but I expect that this will become more common now that RTM is out. The only alternative right now is to build a host yourself. The complexity of the shared host (and its friends), and the size of our runtime support list is high enough that forking is a pretty daunting task. Anyways, I mainly just wanted to poke at our thoughts here for future use cases. If we expect that we want most apps to be using the shared host, for servicing, etc., then it probably makes sense to invest in something for this scenario eventually. |
👍 I need this for my projects as well. I would recommend copying the functionality in @mellinoe @gkhanna79 Would this work? I used to do something much like this when I built a GUI CoreCLR-based application way back when (before .NET CLI existed in its current form). |
Do note that copying hostfxr.dll into the application is only supported for standalone apps its related invariants - runtime is next to it, so is the jit and so on. Hostfxr.dll, when not used in standalone scenario, expects the layout in which Microsoft.NETCore.App is installed to do the same lookup. I think what you are looking for the following:
This will allow your GUI app to look like a native host but not get into the business of copy fundamental components all over and remain in the main supported activation scenario. |
@gkhanna79 Yes, this is exactly what I need. As long as I have a solid, future-proofed, hopefully Linux-compatible way of finding hostfxr.dll, that technique will work great. |
@gkhanna79 I'm developing a GUI framework so the built application should be a window application. I have done that before on .NET 4.5.
Here is a short example of the window applicaiton from pinvoke.net. using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using WindowsInterop;
namespace HelloWin
{
class Program
{
static void Main(string[] args)
{
IntPtr hInstance = Process.GetCurrentProcess().Handle;
string szAppName = "HelloWin";
WNDCLASS wndclass;
wndclass.style = ClassStyles.HorizontalRedraw | ClassStyles.VerticalRedraw;
wndclass.lpfnWndProc = (WndProc)((hWnd, message, wParam, lParam ) => {
IntPtr hdc;
PAINTSTRUCT ps;
RECT rect;
switch ((WM)message)
{
case WM.PAINT:
hdc = Win32.BeginPaint (hWnd, out ps) ;
Win32.GetClientRect (hWnd, out rect) ;
Win32.DrawText (hdc, "Hello, Windows 98!", -1, ref rect,
Win32.DT_SINGLELINE | Win32.DT_CENTER | Win32.DT_VCENTER );
Win32.EndPaint(hWnd, ref ps);
return IntPtr.Zero;
break;
case WM.DESTROY:
Win32.PostQuitMessage(0);
return IntPtr.Zero;
break;
}
return Win32.DefWindowProc(hWnd, (WM)message, wParam, lParam);
});
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = Win32.LoadIcon(IntPtr.Zero, new IntPtr((int)SystemIcons.IDI_APPLICATION));
wndclass.hCursor = Win32.LoadCursor(IntPtr.Zero,(int)IdcStandardCursors.IDC_ARROW);
wndclass.hbrBackground = Win32.GetStockObject(StockObjects.WHITE_BRUSH);
wndclass.lpszMenuName = null;
wndclass.lpszClassName = szAppName;
ushort regResult = Win32.RegisterClass(ref wndclass);
if (regResult == 0)
{
Win32.MessageBox(0, "This program requires Windows NT!", szAppName, MessageBoxOptions.IconError);
return;
}
IntPtr hwnd = Win32.CreateWindowEx(
WindowStylesEx.WS_EX_OVERLAPPEDWINDOW,
new IntPtr((int)(uint)regResult),
//szAppName, // window class name
"The Hello Program", // window caption
WindowStyles.WS_OVERLAPPEDWINDOW, // window style
Win32.CW_USEDEFAULT, // initial x position
Win32.CW_USEDEFAULT, // initial y position
Win32.CW_USEDEFAULT, // initial x size
Win32.CW_USEDEFAULT, // initial y size
IntPtr.Zero, // parent window handle
IntPtr.Zero, // window menu handle
hInstance, // program instance handle
IntPtr.Zero); // creation parameters
if( hwnd == IntPtr.Zero )
{
int lastError = Marshal.GetLastWin32Error();
string errorMessage = new Win32Exception(lastError).Message;
}
Win32.ShowWindow(hwnd, ShowWindowCommands.Normal );
Win32.UpdateWindow(hwnd);
MSG msg;
while (Win32.GetMessage( out msg, IntPtr.Zero, 0, 0) != 0)
{
Win32.TranslateMessage( ref msg);
Win32.DispatchMessage( ref msg);
}
return;
}
}
} As for .NET Core, I thought I can run the dll as a window application like |
Current POR is for .NET Core to be targeted to enable console and cloud scenarios. While supporting GUI applications is not in the cards for now, this is good datapoint nonetheless that we should account for in our planning. |
Even if it isn't our main focus currently, I think we ought to come up with a plan for how this will work. With the MSBuild SDK being designed right now, and with knowledge of the host being baked into that, we should at least come up with some sort of plan for how you would override it with your own host, even if that isn't one that we directly provide (although I still think we should do that). My fear is that we'll just ignore this and end up with a system that can't accommodate this scenario cleanly when we do want it in the future. Adding a GUI version of the host nuget package would be very simple, FWIW. It would probably just be a single-line CMake change and then the associated packaging project additions. |
I am not sure what is being baked into MSBuild about the host, but that does not sound right to me. Can you share more details?
The current design does support the flexibility to enable overriding the defaults or changing them. I think it would be prudent to first understand the various implications and needs of the GUI scenario before determining the solutions to make that happen. The key here is exposing the API from hostFXR, which is currently an internal implementation detail of the host. |
I don't know how the new SDK stuff handles this. At the very least, it's always possible to create post-publish targets that rearrange things for a custom host, but things like that are always a bit fragile and hacky. Since the SDK is still being designed and worked on, I was just suggesting that we consider this scenario so that something nicer than "make a post-publish target" is an option. I was talking with @nguerrera and it sounded like this should already be manageable with the current targets that we have.
"Not creating a console window" is the only thing I'm really interested in here. I'm not really aware of other specific needs, but they could be considered separately. |
Me too, currently working around it using |
I was discussing this problem a bit more in the context of Avalonia who have a working (but still in-progress) version of their GUI toolkit for .NET Core. One option that's worth considering is:
This would just leave us with one single host which could behave correctly in both scenarios. The problem with linking with the console subsystem by default is that there is no way to hide the console before it becomes visible.
For what it's worth, this is what I am doing in my project as well. It is an okay workaround, but it means that I can only publish my self-contained stuff from Windows; when I do so from Ubuntu, for example, the Windows version will spawn a console window. |
@mellinoe That still won't quite hit all my required feature boxes, though. I would also need a Win32 common control manifest, an icon, and a In addition, while a dual-mode EXE as you described might seem like it would work well, I beg to differ. Your idea of creating the console window at runtime breaks a key scenario for console apps: Being able to interact with the app in the console window you launched it from, as well as having the command interpreter block waiting for it to exit. Doing it this way would always spawn a new console window, which would then need to be interacted with separately, even if the user did not intend that; it would also cause the command prompt (both cmd.exe and PowerShell) to think that the command had exited immediately, breaking scripts that assume its commands always run synchronously. |
@wjk Yes, you're absolutely correct. Upon further research my idea does not actually work, although it would have been simple and clean if possible. |
This has been a hard-to-solve problem on windows for a long time and this is the reason java ships In order to publish for GUI applications from any platform for both self-contained and shared framework scenarios, there'd probably be a need to introduce an additional property to the msbuild SDK and For mac, it is enough to create a correct bundle layout on publish - meaning a folder ending in |
@dasMulli I think it would be sufficient (at least IMO) to just provide alternative versions of The real important feature here (again, IMO) is being able to invoke the application directly, either as a "shared" app, or a fully standalone app, without creating a console window. It seems like that can be accomplished by just having a separate version of apphost.exe (call it "apphostw.exe" like you suggested) and baking some knowledge of that into the SDK regarding when it should be deployed. You can imagine that there could be a |
I'm happy to consider this scenario. As @gkhanna79 suggests, the team is focused on scenarios that don't require this, however, I appreciate and love the experimentation and productization we are seeing with .NET Core. I want to encourage that more and part of doing that is developing a track record of helping people do cool stuff. If we can find a good solution that doesn't add significant complication or cost to the mainline .NET Core project, I'm all for it. Do we have a concrete proposal on how to get there? |
I am supportive too. Seems like the leading proposals are:
Thoughts? I'd be happy to see a community PR along these lines and as @richlander said, would like to take something like this in a way that doesn't impact any critical dates for the project. |
"2." is something I think could be easily accomplished, assuming we agree on the particulars. There's a couple of additional things discussed above which are not necessarily restricted to GUI apps:
I can imagine that the two things above can be readily accomplished with a post-build MSBuild task. On the other hand, which native host we deploy into the project output seems like a more "baked-in" part of the SDK, and therefore could warrant special treatment (e.g. a special property that we define and interpret). |
Clarification -- Is this soley for self-contained apps? The "always dotnet" is a shared fx scenario but then you wouldn't be copying. |
I would start with self-contained. @mellinoe , do you agree? The shared scenario I think would neccesitate something more like dotnet/core-setup#1. |
I'm interested in the native host which is published next to all applications, both portable and standalone. I'm not really as interested in having a version of the "global dotnet" host, because the use of that implies to me that you are running from a command line in the first place. |
Hi guys, @mellinoe, thanks for bringing this up. I am currently developing a purely managed, CPU-based graphics toolkit for .NET and running into the same problem that @zwcloud described with Core (console window is showing and output type 'Windows Application' does not work). This might be OT, but I would like to propose an approach that might be better in terms of user experience for GUI applications (especially on Windows): Greetings |
So i guess this would mean a new "branch" of RIDs? |
@yzrmn @mellinoe I have already accomplished what is being discussed (mark as GUI subsystem, add resources to entry point) with an MSBuild task in a private repo of mine. No modifications to .NET Core itself are required, and Visual Studio still debugs the application just fine. I will work on moving the code into a public repo sometime in the near future. Thanks! |
I don't think we need anything so complicated. I was anticipating we could just ship
Could you outline how you are doing this? Using Win32 API's to accomplish it is kind of a non-starter, because they can't be used outside of Windows. |
@mellinoe Cool!
I'm thinking we should use OutputType=WinExe, which controls this for .NET framework exectuables. We have some bugs around it in the SDK (see dotnet/sdk#1176), but we're going to get those fixed. The nice things there beyond consistency with .NET Framework is that we can get VS property page support for free. |
It would be great if we "just worked" with the existing It would be even better if we respected this flag on all platforms and not just on Windows. |
@nguerrera Yeah, OutputType=WinExe is probably the obvious choice here. My only hangup is the fact that it makes you put a "windows-ism" into your project file. That's just a small problem, though; it's probably overcome by the fact that years of tooling understand "WinExe". @tannergooding What would respecting this flag look like on other platforms? As far as I can tell, there is no such distinction for executables on other systems, only Windows. There is some discussion about producing a macOS bundle above, but I'm not as familiar with those. It seems like they are only tangentially related. Was there something concrete you were thinking of with respect to other platforms? |
@mellinoe, I would imagine it would do (or attempt to do) the same thing that Windows does. Launching a "regular" executable would cause a terminal window to appear for all output (or use the current terminal if launched from there). Launching a "WinExe" executable would not cause any terminal window to appear and would require the end user to construct and display a window, if desired. Also, I think "WinExe" should be fine, as you could say it stands for "Windowed Executable" (that is an executable which has a graphical window) rather than "Windows Executable" (which is an executable specific to the Windows Operating System) |
Sadly, I think a lot of tools/"SDKs" picked up conditioning on |
@tannergooding I think this console-window experience is pretty much a vs-specific thing.. most other IDEs have integrated console windows and route the stdin/out through it. Even for "Gui type" apps, or mobile apps that run in simulators or attached devices. Furthermore, I believe the ability to select a different app host is more a deployment-time choice than an app model selection - just like |
I am also in need of this feature 👍 |
@mellinoe and I had a discussion on this, using an approach similar to what he has already prototyped. Tentatively flagging this as 2.1 until we can fully prioritize and schedule that work. |
Moving to 2.2; a custom build task to re-write the peheader in the exe is probably the least intrusive. |
See also https://github.com/dotnet/core-setup/issues/230 which requested version, icon and SxS manifest |
@steveharter Note that since I posted in dotnet/core-setup#230, I have figured out how to insert the required resources using the Win32 resource-modification APIs. (I also use |
Linking issue https://github.com/dotnet/cli/issues/6237 because that also has a need for a app-specific named exe (not the shared Having a named exe for a GUI app (v.s. |
I'm also super interested by this feature! (Mostly for AOT and Standalone apps) As suggested earlier by @nguerrera I would be in favor of |
With the 3.0 proposed support for WPF and WinForms, setting 3.0 milestone. Basic functionality would include (on Windows):
Optional \ TBD: |
See also dotnet/sdk#1899 |
The plan is to have apphost .exe by default for GUI apps. It makes the GUI shared host unnecessary. |
@jkotas Could we close the loop on this one with some instructions on how to enable the new functionality? For example -- I have existing projects that should be GUI projects. What do I need to change to make that happen? |
You will get an apphost by default, and it will be GUI if OutputType is WinExe. This is already happening in 3.0 daily builds, which you can try from https://github.com/dotnet/core-sdk |
As Nick said, you need to update to netcoreapp3.0 and build. That's all. |
Thanks, that worked like a charm. |
Shouldn't it even work with netcoreapp < 3.0? AFAIK there is code in the SDK that just flips the subsystem bit after copying the apphost and embedding the dll name |
Yes, I believe so, as long as you use the 3.0 sdk. Cc @peterhuene |
I believe building with a 3.0 SDK with an |
If you want a dotnetw.exe today that has the WinApp bit flipped and are still on 2.x SDK, you can use the awesome project Vittel/RunHiddenConsole and move the output assembly to |
Currently, dotnet.exe unconditionally spawns a console window on Windows. This can be annoying / problematic if you are building an app which creates its own UI, or for some other reason do not want a console window to be created. It's possible to "dismiss" the console after it is spawned, but this results in an undesirable "flicker" on app startup.
In practice, this simply means linking against the WINDOWS subsystem. With CMake, this means just adding "WIN32" to the add_executable call.
As far as I'm aware, this is only a meaningful distinction on Windows. Other platforms need not change anything.
The text was updated successfully, but these errors were encountered: