简体   繁体   中英

Get Desktop Size from Windows Service?

I'm trying to get the size of the Windows' desktop (the whole thing, not just a single screen) from inside a service that I've written.

In WinForms -- the standard C# method of:

SystemInformation.VirtualScreen.Width   
SystemInformation.VirtualScreen.Height

seems to work (if you import the Winforms DLL, which I want to avoid) -- but it returns the wrong value. The desktop size is 2048x768 (2 screens), but the service reports 1024x768 (presumably it only picks up on one of the screens.)

Checking the option for the service to interact with the desktop has no effect.

Any thoughts?

Edit:

The solutions posted at C#: Get complete desktop size? don't work inside of a service. They all report the wrong value.

Interestingly, it seems like the value that is reported varies and is of no relation to the actual desktop size (some machines report 800x600 even though a single display on that machine is a much higher resolution.)

So -- any more ideas? Dropping into the registry and/or to the command line is OK. The only restriction is that I can't launch a winforms app to figure it out.

You cannot do this inside the service. Services run in session 0, where no GDI functions work. Once the process is created, you cannot change sessions, and cannot use UI in different session.

One of the possible solutions for you is to launch a new process in user session. You can start looking at this SO question . The other pre-requisites for this method is that your service has to be running as Local System, so that you can enable SE_TCB_NAME privilege (by calling AdjustTokenPrivilegies). Since you are saying you already hooked up to the user logon notification, you should be able to extract session ID of the session that you are interested in.

Once you have a process lauched in user session, you have to pass the result from the new process back to your service process. For that any kind of IPC mechanism could be used.

You could add the size of all screens to determine the total desktop size, as described by P Daddy in this post .

Rectangle rect = new Rectangle(int.MaxValue, 
                               int.MaxValue,
                               int.MinValue,
                               int.MinValue); 

foreach (Screen screen in Screen.AllScreens) 
{
    rect = Rectangle.Union(rect, screen.Bounds); 
}

Console.WriteLine("(w, h) = ({0}, {1})", rect.Width, rect.Height); 

While I haven't encountered this exact problem myself I suspect that working with multiple monitors may require you to delve down to the Win32API level (a lot of edge cases do).

Have a look at the EnumDisplayMonitors function from user32 , and specifically an example in C# .

Alternatively you can use Screen.AllScreens (as part of the Winforms DLL you don't want to import) as a quick check to see if what you want to do will be possible as a Windows Service. I am almost certain that this WinForms method relies on EnumDisplayMonitors internally.

The following code works in a service which I found in sharpAvi: https://sharpavi.codeplex.com/

        System.Windows.Media.Matrix toDevice;
        using (var source = new HwndSource(new HwndSourceParameters()))
        {
            toDevice = source.CompositionTarget.TransformToDevice;
        }
        screenWidth = (int)Math.Round(SystemParameters.PrimaryScreenWidth * toDevice.M11);
        screenHeight = (int)Math.Round(SystemParameters.PrimaryScreenHeight * toDevice.M22);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM