Skip to content
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

does not restore window size and pos after OS restart. #98

Closed
torum opened this issue Jan 13, 2023 · 20 comments
Closed

does not restore window size and pos after OS restart. #98

torum opened this issue Jan 13, 2023 · 20 comments
Labels
bug Something isn't working help wanted Extra attention is needed

Comments

@torum
Copy link

torum commented Jan 13, 2023

Hi, thank you for the very usuful tool.

I've been trying to save & restore window size and position on app start up. Using WinUIEx, it works like a charm.
However, once I restart my PC, the size and position are gone back to initial size and position.

I've tried the sample app, but it also show the same behaviour.
Is this something designed? or...

Sorry about the English. It's not my native language.

WinUIEx v2.1
WinUI3 (both packaged/unpackaged).
Windows App SDK v1.2.2
Visual Studio v17.4.4
Windows 11

@dotMorten
Copy link
Owner

To clarify the app restores fine between runs without restarting but then doesn't after a PC restart?

@torum
Copy link
Author

torum commented Jan 13, 2023

Correct!

@dotMorten
Copy link
Owner

If would be awesome if you could run through the sample app and step through this code and observe what happens :

private void LoadPersistence()

@torum
Copy link
Author

torum commented Jan 13, 2023

I'll try, but it may take some time especially you have to restart PC to observe what is going on... ^^

@torum
Copy link
Author

torum commented Jan 13, 2023

Strainge... after a couple of test using the sample project, I realized that my app is working as expected... I need to test more with another fresh PC and get some more information. Meanwhile, I'll close the issue. Thank you for your time. I'll report it if I find anything. Thank you again.

@torum torum closed this as completed Jan 13, 2023
@dotMorten
Copy link
Owner

Could it be the app got reinstalled? That would clear old stored settings. Also changes to monitor layout will also ignore saved settings (so window doesn't end up at a location outside where a monitor is)

@torum
Copy link
Author

torum commented Jan 13, 2023

I don't think it is re-installed because my app is unpackaged. (I've tested with packaged version as well)
By the way, the symptom is back. When I restart my PC just now, the sample app and my app are back to initial position. Very strange.

@dotMorten
Copy link
Owner

If it's unpacked you're responsible for setting up the storage. Did you do that?

@torum
Copy link
Author

torum commented Jan 13, 2023

Yes. I mean I just copied and pasted the sample you posted somewhere. ^^

WinUIEx.WindowManager.PersistenceStorage = new FilePersistence(Path.Combine(AppDataFolder, "WinUIExPersistence.json"));
and
private class FilePersistence : IDictionary<string, object>
...

@torum
Copy link
Author

torum commented Jan 14, 2023

OK, so far, what I found is that it happens infrequently and I don't know what exactly causes it. But it does happen and it seems not only PC restart but also sleep and waking up from it causes this as well.

So, I decided to add bunch of debug codes to the sample project and see what is going on. And finaly, I get this message "Monitor layout changed."!

The thing is I did nothing with monitor.

                    for (int i = 0; i < monitorCount; i++)
                    {
                        var pMonitor = monitors[i];
                        if (pMonitor.Name != br.ReadString() ||
                            pMonitor.RectMonitor.Left != br.ReadDouble() ||
                            pMonitor.RectMonitor.Top != br.ReadDouble() ||
                            pMonitor.RectMonitor.Right != br.ReadDouble() ||
                            pMonitor.RectMonitor.Bottom != br.ReadDouble()) {

                            System.Diagnostics.Debug.WriteLine("Monitor layout changed.");
                            return; // Don't restore - Monitor layout changed
                        }
                    }

@dotMorten dotMorten reopened this Jan 14, 2023
@dotMorten
Copy link
Owner

Thanks for doing this! That was my suspected culprit. Did you happen to notice which bit was changed?

@torum
Copy link
Author

torum commented Jan 14, 2023

I've been trying but I can't reproduce the problem.. yet. ^^

I changed the code like below. So next time it happens, I'll know.

                    var pMonitor = monitors[i];

                    var pMonitorName = br.ReadString();
                    var pMonitorLeft = br.ReadDouble();
                    var pMonitorTop = br.ReadDouble();
                    var pMonitorRight = br.ReadDouble();
                    var pMonitorBottom = br.ReadDouble();

                    if (pMonitor.Name != pMonitorName ||
                        pMonitor.RectMonitor.Left != pMonitorLeft ||
                        pMonitor.RectMonitor.Top != pMonitorTop ||
                        pMonitor.RectMonitor.Right != pMonitorRight ||
                        pMonitor.RectMonitor.Bottom != pMonitorBottom) {

                        System.Diagnostics.Debug.WriteLine("Monitor layout changed.");
                        System.Diagnostics.Debug.WriteLine($"Current values are: {pMonitor.Name}, {pMonitor.RectMonitor.Left}, {pMonitor.RectMonitor.Top}, {pMonitor.RectMonitor.Right}, {pMonitor.RectMonitor.Bottom}");
                        System.Diagnostics.Debug.WriteLine($"Saved values are: {pMonitorName}, {pMonitorLeft}, {pMonitorTop}, {pMonitorRight}, {pMonitorBottom}");

                        return; // Don't restore - Monitor layout changed
                    }

@torum
Copy link
Author

torum commented Jan 14, 2023

Got it.
Current values are: \.\DISPLAY2, 0, 0, 3840, 2160
Saved values are: \.\DISPLAY1, 0, 0, 3840, 2160

I only have one display setup. I checked Windows setting and it says I have "Display 1" and says nothing about "Display 2".

As I dig depper, I found EnumDisplayMonitors() seems to be very tricky thing...

@torum
Copy link
Author

torum commented Jan 14, 2023

Since a display monitor name is irrelevant here, could we omit the "pMonitor.Name != br.ReadString()" check?

"Most applications have no use for a display monitor name, and so can save some bytes by using a MONITORINFO structure." https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-monitorinfoexw

@dotMorten
Copy link
Owner

@torum awesome! Thank you for tracking this down. I'll have a think about the best way to handle this. Odd the name changes but 🤷‍♂️

@torum
Copy link
Author

torum commented Jan 14, 2023

Odd indeed. A quick google search did not turn out to be fruitful..., except "From my experience there's no rhyme or reason to the numbering scheme for the monitor device names"
https://stackoverflow.com/questions/9829083/how-does-windows-assign-display-device-names-eg-display1-and-determine-di

Only thing that might be related is that my display is connected to a different PC (Ubuntu) which is off with a different display port. But that shouldn't affect at all, right?

@torum
Copy link
Author

torum commented Jan 14, 2023

I think WinUIEx is very important project since WinUI3 lacks very basic functionalities such as ability to set width and height of a window.
About a year and half ago, I evaluated WinUI3 as an alternative to WPF and found out about the lack of this very basic functionality of WinUI3 within a 5 minutes and decided that WinUI3 is not ready at all.
When I gave a second try a few weeks ago, I found WinUIEx through Template Studio and I was delighted.
WinUI3 needs projects such as WinUIEx to be widely used and become popular. (WinUI3 does not even allow us to change mouse cousor to wait! Could WinUIEx implement that?)
So, I'm glad to do whatever I can to help.

@dotMorten
Copy link
Owner

❤️

@dotMorten dotMorten added bug Something isn't working help wanted Extra attention is needed labels Apr 13, 2023
@dotMorten
Copy link
Owner

Now available in v2.3 release

@rocksdanister
Copy link

rocksdanister commented Sep 15, 2023

You can use DISPLAY_DEVICE DeviceID which is what I am using for my application Lively Wallpaper.

DeviceID is unique and does not change like the name because its based on EDID, so persistence will work regardless of rect values.
In the event DeviceID does not exist you can switch back to rect checks.

Sample Code:

private static DISPLAY_DEVICE GetDisplayDevice(string deviceName)
{
    var result = new DISPLAY_DEVICE();

    var displayDevice = new DISPLAY_DEVICE();
    displayDevice.cb = Marshal.SizeOf(displayDevice);
    try
    {
        for (uint id = 0; EnumDisplayDevices(deviceName, id, ref displayDevice, EDD_GET_DEVICE_INTERFACE_NAME); id++)
        {
            if (displayDevice.StateFlags.HasFlag(DisplayDeviceStateFlags.AttachedToDesktop)
                && !displayDevice.StateFlags.HasFlag(DisplayDeviceStateFlags.MirroringDriver))
            {
                result = displayDevice;
                break;
            }

            displayDevice.cb = Marshal.SizeOf(displayDevice);
        }
    }
    catch { }

    if (string.IsNullOrEmpty(result.DeviceID)
        || string.IsNullOrWhiteSpace(result.DeviceID))
    {
        result.DeviceID = GetDefaultDisplayDeviceId();
    }

    return result;
}

private static string GetDefaultDisplayDeviceId() => GetSystemMetrics(SM_REMOTESESSION) != 0 ?
    "\\\\?\\DISPLAY#REMOTEDISPLAY#" : "\\\\?\\DISPLAY#LOCALDISPLAY#";
    
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
public static extern int GetSystemMetrics(int nIndex);

const int EDD_GET_DEVICE_INTERFACE_NAME = 0x00000001;
const int SM_REMOTESESSION = 0x1000;

[Flags]
public enum DisplayDeviceStateFlags : int
{
    /// <summary>The device is part of the desktop.</summary>
    AttachedToDesktop = 0x1,

    MultiDriver = 0x2,

    /// <summary>The device is part of the desktop.</summary>
    PrimaryDevice = 0x4,

    /// <summary>
    /// Represents a pseudo device used to mirror application drawing for remoting or other purposes.
    /// </summary>
    MirroringDriver = 0x8,

    /// <summary>The device is VGA compatible.</summary>
    VGACompatible = 0x10,

    /// <summary>
    /// The device is removable; it cannot be the primary display.
    /// </summary>
    Removable = 0x20,

    /// <summary>
    /// The device has more display modes than its output devices support.
    /// </summary>
    ModesPruned = 0x8000000,

    Remote = 0x4000000,
    Disconnect = 0x2000000
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DISPLAY_DEVICE
{
    [MarshalAs(UnmanagedType.U4)]
    public int cb;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string DeviceName;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
    public string DeviceString;

    [MarshalAs(UnmanagedType.U4)]
    public DisplayDeviceStateFlags StateFlags;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
    public string DeviceID;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
    public string DeviceKey;
}

const int EDD_GET_DEVICE_INTERFACE_NAME = 0x00000001;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants