WindowsAppSDK icon indicating copy to clipboard operation
WindowsAppSDK copied to clipboard

Proposal: Support creating CoreWindow desktop apps and enable the CoreWindow related apis in Windows App SDK

Open EP012014 opened this issue 4 years ago • 20 comments

Discussed in https://github.com/microsoft/WindowsAppSDK/discussions/1990

Originally posted by EP012014 January 15, 2022 Because desktop apps in Windows App SDK only supports the legacy HWND window model instead of the modern CoreWindow model, many features related to CoreWindow(e.g SplashScreen before window content actually loaded, Win+Shift+Enter for full screen) are missing. So is it possible to bring back CoreWindow in WinUI3 desktop apps?

EP012014 avatar Jan 15 '22 10:01 EP012014

the legacy HWND window model the modern CoreWindow model

What ? CoreWindow is based on HWND, not the other way round.

If you want SplashScreen support for WinUI 3 propose it and same goes for Win + Shift + Enter full screen. (yes, not all UI framework need splash screen and Win + Shift + Enter)

Dup of https://github.com/microsoft/WindowsAppSDK/issues/1573 , https://github.com/microsoft/microsoft-ui-xaml/issues/4055


You Microsoft, This is the result of your false marketing narrative regarding the whole ""UWP"" saga and abstracting away too much details from the developer so much so that they even don't know what's really going on under the hood.

ghost avatar Jan 15 '22 16:01 ghost

the legacy HWND window model the modern CoreWindow model

What ? CoreWindow is based on HWND, not the other way round.

If you want SplashScreen support for WinUI 3 propose it and same goes for Win + Shift + Enter full screen. (yes, not all UI framework need splash screen and Win + Shift + Enter)

Dup of #1573 , microsoft/microsoft-ui-xaml#4055

You Microsoft, This is the result of your false marketing narrative regarding the whole ""UWP"" saga and abstracting away too much details from the developer so much so that they even don't know what's really going on under the hood.

What we want actually is the UX of CoreWindow(e.g immediate response of app launching with a splash screen). Due to the terrible startup speed of WinUI3, displaying a SplashScreen is only possible after a few seconds while the window is actually displayed, and not immediately after the user clicked on the app icon in the start menu to start the app. The former behavior hurts the user experience and may cause multiple attempts to start the app, which results in multiple instances of the app created and an even worse performance due to many instances eating up system resources.

EP012014 avatar Jan 16 '22 03:01 EP012014

Immediate response of CoreWindow are drawn by the OS itself. Even if you were to propose one for AppWindow that still will require shiny new APIs to be provided by the OS.

Add your proposals here on this official Splash Screen API discussion thread : https://github.com/microsoft/WindowsAppSDK/discussions/500

Due to the terrible startup speed of WinUI3 .... even worse performance due to many instances eating up system resources.

terrible startup speed ? Where did you get this information from ? if 3-5 seconds of delay is considered terrible, then by that definition all WPF apps from 2006 to this date are also terrible and "hurts user experience" too.

ghost avatar Jan 16 '22 04:01 ghost

terrible startup speed

Compared to UWP CoreWindow application which gives immediate response and a blank app loads in less than a second in production environment.

EP012014 avatar Jan 16 '22 04:01 EP012014

Immediate response of CoreWindow are drawn by the OS itself. Even if you were to propose one for AppWindow that still will require shiny new APIs to be provided by the OS.

Add your proposals here on this official Splash Screen API discussion thread : #500

Due to the terrible startup speed of WinUI3 .... even worse performance due to many instances eating up system resources.

terrible startup speed ? Where did you get this information from ? if 3-5 seconds of delay is considered terrible, then by that definition all WPF apps from 2006 to this date are also terrible and "hurts user experience" too.

So is it really THAT hard to bring CoreWindow model to WinUI3 in desktop as a option for developers?

EP012014 avatar Jan 16 '22 10:01 EP012014

a blank app loads in less than a second in production environment.

except when you do NOT deliver an actual blank app in a real production environment.

Compared to UWP CoreWindow application which gives immediate response So is it really THAT hard to bring CoreWindow model to WinUI3 in desktop as a option for developers?

whole point of AppWindow is to sugercoat the underlying win32 APIs as less as possible and give you unmanaged access to those underlying APIs contrary to managed CoreWindow.

When AppWindow will not suffice, Use underlying APIs to create "Instant Window" for custom loading splash screen.


Before having another assumption or two, learn win32 programming first. It won't take much longer to understand why CoreWindow is unnecessary for anything including cases like this.

Readymade libraries WinUIEx provided by dotMorten maybe allows that functionality.

ghost avatar Jan 16 '22 15:01 ghost

There's an undocumented function to associate an existing HWND to a new CoreWindow instance and you'll be able to use GetForCurrentView after calling it however you don't get a splash screen since that's created by the system even before your app starts. Under UWP, the initial window is created automatically which isn't how desktop apps work.

jaigak avatar Jan 19 '22 12:01 jaigak

There's an undocumented function to associate an existing HWND to a new CoreWindow instance and you'll be able to use GetForCurrentView after calling it however you don't get a splash screen since that's created by the system even before your app starts. Under UWP, the initial window is created automatically which isn't how desktop apps work.

What's the function?

EP012014 avatar Jan 19 '22 13:01 EP012014

There's an undocumented function to associate an existing HWND to a new CoreWindow instance and you'll be able to use GetForCurrentView after calling it however you don't get a splash screen since that's created by the system even before your app starts. Under UWP, the initial window is created automatically which isn't how desktop apps work.

What's the function?

@ahmed605 knows about it.

jaigak avatar Jan 19 '22 13:01 jaigak

There's an undocumented function to associate an existing HWND to a new CoreWindow instance and you'll be able to use GetForCurrentView after calling it however you don't get a splash screen since that's created by the system even before your app starts. Under UWP, the initial window is created automatically which isn't how desktop apps work.

What's the function?

@ahmed605 knows about it.

PrivateCreateCoreWindow(WINDOW_TYPE, const wchar_t* title, int x, int y, int width, int height, int attributes, HWND owner, const IID& guid, void** ppv);
enum WINDOW_TYPE
{
    IMMERSIVE_BODY,
    IMMERSIVE_DOCK,
    IMMERSIVE_HOSTED,
    IMMERSIVE_TEST,
    IMMERSIVE_BODY_ACTIVE,
    IMMERSIVE_DOCK_ACTIVE,
    NOT_IMMERSIVE
};

HMODULE uiCore = LoadLibrary(L"Windows.UI.dll");
auto privateCreateCoreWindow = (PrivateCreateCoreWindow)GetProcAddress(uiCore, MAKEINTRESOURCEA(1500));
ComPtr<CoreWindow> coreWindow;
...
if (coreWindow == nullptr)
    {
        GUID iid;
        IIDFromString(L"{79B9D5F2-879E-4B89-B798-79E47598030C}", &iid);
        privateCreateCoreWindow(NOT_IMMERSIVE, L"Title", 0, 0, 1, 1, 0, window, iid, (void**)coreWindow.GetAddressOf());
    }

Credits to @ADeltaX

not sure if it would work in WinUI 3 Desktop/WASDK or not tho

ahmed605 avatar Jan 19 '22 14:01 ahmed605

Thanks! Will try out in my project

EP012014 avatar Jan 19 '22 23:01 EP012014

There's an undocumented function to associate an existing HWND to a new CoreWindow instance and you'll be able to use GetForCurrentView after calling it however you don't get a splash screen since that's created by the system even before your app starts. Under UWP, the initial window is created automatically which isn't how desktop apps work.

What's the function?

@ahmed605 knows about it.

PrivateCreateCoreWindow(WINDOW_TYPE, const wchar_t* title, int x, int y, int width, int height, int attributes, HWND owner, const IID& guid, void** ppv);
enum WINDOW_TYPE
{
    IMMERSIVE_BODY,
    IMMERSIVE_DOCK,
    IMMERSIVE_HOSTED,
    IMMERSIVE_TEST,
    IMMERSIVE_BODY_ACTIVE,
    IMMERSIVE_DOCK_ACTIVE,
    NOT_IMMERSIVE
};
HMODULE uiCore = LoadLibrary(L"Windows.UI.dll");
auto privateCreateCoreWindow = (PrivateCreateCoreWindow)GetProcAddress(uiCore, MAKEINTRESOURCEA(1500));
ComPtr<CoreWindow> coreWindow;
...
if (coreWindow == nullptr)
    {
        GUID iid;
        IIDFromString(L"{79B9D5F2-879E-4B89-B798-79E47598030C}", &iid);
        privateCreateCoreWindow(NOT_IMMERSIVE, L"Title", 0, 0, 1, 1, 0, window, iid, (void**)coreWindow.GetAddressOf());
    }

Credits to @ADeltaX

not sure if it would work in WinUI 3 Desktop/WASDK or not tho

Any example to do it in C#?

SLI9X22R113 avatar Jan 21 '22 12:01 SLI9X22R113

There's an undocumented function to associate an existing HWND to a new CoreWindow instance and you'll be able to use GetForCurrentView after calling it however you don't get a splash screen since that's created by the system even before your app starts. Under UWP, the initial window is created automatically which isn't how desktop apps work.

What's the function?

@ahmed605 knows about it.

PrivateCreateCoreWindow(WINDOW_TYPE, const wchar_t* title, int x, int y, int width, int height, int attributes, HWND owner, const IID& guid, void** ppv);
enum WINDOW_TYPE
{
    IMMERSIVE_BODY,
    IMMERSIVE_DOCK,
    IMMERSIVE_HOSTED,
    IMMERSIVE_TEST,
    IMMERSIVE_BODY_ACTIVE,
    IMMERSIVE_DOCK_ACTIVE,
    NOT_IMMERSIVE
};
HMODULE uiCore = LoadLibrary(L"Windows.UI.dll");
auto privateCreateCoreWindow = (PrivateCreateCoreWindow)GetProcAddress(uiCore, MAKEINTRESOURCEA(1500));
ComPtr<CoreWindow> coreWindow;
...
if (coreWindow == nullptr)
    {
        GUID iid;
        IIDFromString(L"{79B9D5F2-879E-4B89-B798-79E47598030C}", &iid);
        privateCreateCoreWindow(NOT_IMMERSIVE, L"Title", 0, 0, 1, 1, 0, window, iid, (void**)coreWindow.GetAddressOf());
    }

Credits to @ADeltaX

not sure if it would work in WinUI 3 Desktop/WASDK or not tho

Any example to do it in C#?

I don't recommend doing so in C# (.NET 5+) because CsWinRT types mostly won't be understood by the function (that's why the built-in WinRT interop was always better) but you can try...

private enum WINDOW_TYPE
{
     IMMERSIVE_BODY,
     IMMERSIVE_DOCK,
     IMMERSIVE_HOSTED,
     IMMERSIVE_TEST,
     IMMERSIVE_BODY_ACTIVE,
     IMMERSIVE_DOCK_ACTIVE,
     NOT_IMMERSIVE
}


[DllImport("Windows.UI.dll", CharSet=CharSet.None, EntryPoint="#1500", ExactSpelling=false, SetLastError=true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
private static extern int PrivateCreateCoreWindow(WINDOW_TYPE WindowType, string pWindowTitle, int X, int Y, uint uWidth, uint uHeight, int dwAttributes, IntPtr hOwnerWindow, Guid riid, out object ppv);


public static ICoreWindow CreateCoreWindow(string coreWindowTitle, IntPtr ownerHwnd)
{
     object obj;
     PrivateCreateCoreWindow(WINDOW_TYPE.NOT_IMMERSIVE, coreWindowTitle, 0, 0, 1, 1, 0, ownerHwnd, new Guid("79B9D5F2-879E-4B89-B798-79E47598030C"), out obj);
     return (ICoreWindow)obj;
}

ahmed605 avatar Jan 21 '22 12:01 ahmed605

private enum WINDOW_TYPE
{
     IMMERSIVE_BODY,
     IMMERSIVE_DOCK,
     IMMERSIVE_HOSTED,
     IMMERSIVE_TEST,
     IMMERSIVE_BODY_ACTIVE,
     IMMERSIVE_DOCK_ACTIVE,
     NOT_IMMERSIVE
}


[DllImport("Windows.UI.dll", CharSet=CharSet.None, EntryPoint="#1500", ExactSpelling=false, SetLastError=true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
private static extern int PrivateCreateCoreWindow(WINDOW_TYPE WindowType, string pWindowTitle, int X, int Y, uint uWidth, uint uHeight, int dwAttributes, IntPtr hOwnerWindow, Guid riid, out object ppv);


public static ICoreWindow CreateCoreWindow(string coreWindowTitle, IntPtr ownerHwnd)
{
     object obj;
     PrivateCreateCoreWindow(WINDOW_TYPE.NOT_IMMERSIVE, coreWindowTitle, 0, 0, 1, 1, 0, ownerHwnd, new Guid("79B9D5F2-879E-4B89-B798-79E47598030C"), out obj);
     return (ICoreWindow)obj;
}

We got an AccessViolationException.

SLI9X22R113 avatar Jan 21 '22 12:01 SLI9X22R113

private enum WINDOW_TYPE
{
     IMMERSIVE_BODY,
     IMMERSIVE_DOCK,
     IMMERSIVE_HOSTED,
     IMMERSIVE_TEST,
     IMMERSIVE_BODY_ACTIVE,
     IMMERSIVE_DOCK_ACTIVE,
     NOT_IMMERSIVE
}


[DllImport("Windows.UI.dll", CharSet=CharSet.None, EntryPoint="#1500", ExactSpelling=false, SetLastError=true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
private static extern int PrivateCreateCoreWindow(WINDOW_TYPE WindowType, string pWindowTitle, int X, int Y, uint uWidth, uint uHeight, int dwAttributes, IntPtr hOwnerWindow, Guid riid, out object ppv);


public static ICoreWindow CreateCoreWindow(string coreWindowTitle, IntPtr ownerHwnd)
{
     object obj;
     PrivateCreateCoreWindow(WINDOW_TYPE.NOT_IMMERSIVE, coreWindowTitle, 0, 0, 1, 1, 0, ownerHwnd, new Guid("79B9D5F2-879E-4B89-B798-79E47598030C"), out obj);
     return (ICoreWindow)obj;
}

We got an AccessViolationException.

I guess WinUI 3/WASDK doesn't allow it then, it works in normal Win32 apps What happens when you create a normal window using CreateWindow(Ex) in WinUI 3 and use it to create the CoreWindow instead?

ahmed605 avatar Jan 21 '22 15:01 ahmed605

I tried the function provided by @ahmed605 but sadly, it doesn't works. We really need to get the CoreWindow object to access the related apis, like managing the pointer by CoreWindow.PointerCursor related things. We tried the traditional Win32 methods but no use. We couldn't hide the cursor or manage it.

EP012014 avatar Jan 25 '22 02:01 EP012014

I tried the function provided by @ahmed605 but sadly, it doesn't works. We really need to get the CoreWindow object to manage the pointer by CoreWindow.PointerCursor related things. We tried the traditional Win32 methods but no use. We couldn't hide the cursor or manage it.

Ok, I'm hearing three asks in this thread so far:

Splash Screen support - currently Windows handles putting up a splash screen during app activation for UWPs. With the move to Desktop Apps, you want a way to get the same "show a Window while the rest of the runtime is loading" behavior. Seems like something the AppLifecycle group (@andreww-msft) could look into, under #1573

CoreWindow.PointerCursor - like https://docs.microsoft.com/uwp/api/windows.ui.core.corewindow.pointercursor?view=winrt-22000 ? Or are there other needs? Maybe @feisu or @rkarman could route.

Fullscreen presenter - Definitely something @rkarman can look at. Handling a key combination to initiate fullscreen presentation mode would be a Really Great Sample.

jonwis avatar Jan 25 '22 04:01 jonwis

Yes. In conclusion, all we need was a CoreWindow instance, or alternative apis for the same behaviors.

EP012014 avatar Jan 25 '22 04:01 EP012014

Splash Screen support - currently Windows handles putting up a splash screen during app activation for UWPs. With the move to Desktop Apps, you want a way to get the same "show a Window while the rest of the runtime is loading" behavior. Seems like something the AppLifecycle group (@andreww-msft) could look into, under #1573

This really needs to be done. These new WinUI 3 apps with a disconnected Splash screens are insufferable. They are terrible with Multitasking. They really need to be like or mimic UWP splash screens..

shaheedmalik avatar Jun 15 '22 13:06 shaheedmalik

Splash Screen support - currently Windows handles putting up a splash screen during app activation for UWPs. With the move to Desktop Apps, you want a way to get the same "show a Window while the rest of the runtime is loading" behavior. Seems like something the AppLifecycle group (@andreww-msft) could look into, under #1573

This really needs to be done. These new WinUI 3 apps with a disconnected Splash screens are insufferable. They are terrible with Multitasking. They really need to be like or mimic UWP splash screens..

Totally agree with you, looking forward for splash screen support for WinUI 3 Like UWP splash screen

AathifMahir avatar Jun 16 '22 20:06 AathifMahir

private enum WINDOW_TYPE
{
     IMMERSIVE_BODY,
     IMMERSIVE_DOCK,
     IMMERSIVE_HOSTED,
     IMMERSIVE_TEST,
     IMMERSIVE_BODY_ACTIVE,
     IMMERSIVE_DOCK_ACTIVE,
     NOT_IMMERSIVE
}


[DllImport("Windows.UI.dll", CharSet=CharSet.None, EntryPoint="#1500", ExactSpelling=false, SetLastError=true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
private static extern int PrivateCreateCoreWindow(WINDOW_TYPE WindowType, string pWindowTitle, int X, int Y, uint uWidth, uint uHeight, int dwAttributes, IntPtr hOwnerWindow, Guid riid, out object ppv);


public static ICoreWindow CreateCoreWindow(string coreWindowTitle, IntPtr ownerHwnd)
{
     object obj;
     PrivateCreateCoreWindow(WINDOW_TYPE.NOT_IMMERSIVE, coreWindowTitle, 0, 0, 1, 1, 0, ownerHwnd, new Guid("79B9D5F2-879E-4B89-B798-79E47598030C"), out obj);
     return (ICoreWindow)obj;
}

We got an AccessViolationException.

    [LibraryImport("Windows.UI.dll", EntryPoint = "#1500", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    private static partial int PrivateCreateCoreWindow(WINDOW_TYPE WindowType, string pWindowTitle, int X, int Y, int uWidth, int uHeight, int dwAttributes, IntPtr hOwnerWindow, Guid riid, out IntPtr ppv);

        _ = PrivateCreateCoreWindow(WINDOW_TYPE.IMMERSIVE_HOSTED, "CoreWindowTest", AppWindow.Position.X, AppWindow.Position.Y, AppWindow.Size.Width, AppWindow.Size.Height, 0, WinRT.Interop.WindowNative.GetWindowHandle(this), typeof(ICoreWindow).GUID, out _);

        coreWindow = CoreWindow.GetForCurrentThread();

        if (coreWindow != null)
        {
            coreWindow.Activate();
        }

Instead of using the window handle returned by PrivateCreateCoreWindow, you can use CoreWindow.GetForCurrentThread() to get a CoreWindow instance

Gaoyifei1011 avatar Oct 13 '23 13:10 Gaoyifei1011

This is how I achieve this (Some types are generated by CsWin32)

internal static class PrivatePInvoke
{
    private enum WINDOW_TYPE : uint
    {
        IMMERSIVE_BODY,
        IMMERSIVE_DOCK,
        IMMERSIVE_HOSTED,
        IMMERSIVE_TEST,
        IMMERSIVE_BODY_ACTIVE,
        IMMERSIVE_DOCK_ACTIVE,
        NOT_IMMERSIVE
    }

    [DllImport("Windows.UI.dll", CharSet = CharSet.None, EntryPoint = "#1500", ExactSpelling = false, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    private static extern HRESULT CreateCoreWindow(WINDOW_TYPE WindowType, PWSTR pWindowTitle, int x, int y, uint uWidth, uint uHeight, uint dwAttributes, HWND hOwnerWindow, Guid riid, out nint ppv);

    public static unsafe CoreWindow CreateCoreWindow(string title, HWND hOwnerWindow)
    {
        fixed(char* pTitle = title)
        {
            CreateCoreWindow(WINDOW_TYPE.NOT_IMMERSIVE, pTitle, 0, 0, 1, 1, 0, hOwnerWindow, typeof(ICoreWindow).GUID, out nint thisPtr);
            return CoreWindow.FromAbi(thisPtr);
        }
    }
}

Lightczx avatar Oct 17 '23 03:10 Lightczx

This is how I achieve this (Some types are generated by CsWin32)

internal static class PrivatePInvoke
{
    private enum WINDOW_TYPE : uint
    {
        IMMERSIVE_BODY,
        IMMERSIVE_DOCK,
        IMMERSIVE_HOSTED,
        IMMERSIVE_TEST,
        IMMERSIVE_BODY_ACTIVE,
        IMMERSIVE_DOCK_ACTIVE,
        NOT_IMMERSIVE
    }

    [DllImport("Windows.UI.dll", CharSet = CharSet.None, EntryPoint = "#1500", ExactSpelling = false, SetLastError = true)]
    [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
    private static extern HRESULT CreateCoreWindow(WINDOW_TYPE WindowType, PWSTR pWindowTitle, int x, int y, uint uWidth, uint uHeight, uint dwAttributes, HWND hOwnerWindow, Guid riid, out nint ppv);

    public static unsafe CoreWindow CreateCoreWindow(string title, HWND hOwnerWindow)
    {
        fixed(char* pTitle = title)
        {
            CreateCoreWindow(WINDOW_TYPE.NOT_IMMERSIVE, pTitle, 0, 0, 1, 1, 0, hOwnerWindow, typeof(ICoreWindow).GUID, out nint thisPtr);
            return CoreWindow.FromAbi(thisPtr);
        }
    }
}

This looks pretty good. But there is still a problem with the Windows App SDK, when the CoreWindow is created, the application uses the SystemBackdrop property to fail, and does not show any system backdrop, do you know how to solve this problem?

Gaoyifei1011 avatar Oct 17 '23 10:10 Gaoyifei1011

I create the CoreWindow before WinUI window ever Activate once the window is Created the HWND is already available

Lightczx avatar Oct 17 '23 12:10 Lightczx