Search Unity

[SOLVED] How to set windowed game to be "Always on top" in C#?

Discussion in 'Scripting' started by asperatology, May 25, 2015.

  1. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    981
    Debugging and testing network games using Unity on a single laptop makes a lot of mouse clicking and dragging. I thought of simplifying this by having windowed builds of the game be set to "Always on Top".

    Does anyone know how to do this in C#? Or there's a setting I can set in Unity editor?

    Thanks.
     
  2. krougeau

    krougeau

    Joined:
    Jul 1, 2012
    Posts:
    455
    Unity doesn't have such an option, unfortunately. If, however, you're building for the Windows OS alone, you can use code from within user32.dll to achieve this.
     
  3. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    981
    Is this how I need to do it?
     
  4. krougeau

    krougeau

    Joined:
    Jul 1, 2012
    Posts:
    455
    Yeah, that's pretty much the gist of it :) I'd offer to put together a working example for you, but I'm a bit pressed for time at the moment, so it would have to be later. In the meantime though, you can probably glean the important usage bits from the following thread where I was trying to get a transparent, always-on-top window to work. Hope it helps!
    http://forum.unity3d.com/threads/so...dow-with-opaque-contents-lwa_colorkey.323057/
     
  5. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    981
    Don't worry, I mimicked the codes in the links above.

    1. First thing I did was to find System.Drawing.dll from
      Code (csharp):
      1. %Unity Installation Directory%
      and do a quick search.
    2. Then I put the copied DLL into the Assets/Plugins folder in the Unity project.
    3. And then I added the reference to the DLL in the Unity solution and adding an entry in the References node in Solution Explorer in Visual Studio 2013.
    4. Finally, I used the following code below:

    Code (CSharp):
    1. #if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
    2.  
    3. using UnityEngine;
    4. using System;
    5. using System.Collections;
    6. using System.Collections.Generic;
    7. using System.Drawing;
    8. using System.Diagnostics;
    9. using System.Runtime.InteropServices;
    10.  
    11.  
    12. public class AlwaysOnTop : MonoBehaviour {
    13.     #region WIN32API
    14.  
    15.     public static readonly System.IntPtr HWND_TOPMOST = new System.IntPtr(-1);
    16.     public static readonly System.IntPtr HWND_NOT_TOPMOST = new System.IntPtr(-2);
    17.     const System.UInt32 SWP_SHOWWINDOW = 0x0040;
    18.  
    19.     [StructLayout(LayoutKind.Sequential)]
    20.     public struct RECT {
    21.         public int Left, Top, Right, Bottom;
    22.  
    23.         public RECT(int left, int top, int right, int bottom) {
    24.             Left = left;
    25.             Top = top;
    26.             Right = right;
    27.             Bottom = bottom;
    28.         }
    29.  
    30.         public RECT(System.Drawing.Rectangle r)
    31.             : this(r.Left, r.Top, r.Right, r.Bottom) {
    32.         }
    33.  
    34.         public int X {
    35.             get {
    36.                 return Left;
    37.             }
    38.             set {
    39.                 Right -= (Left - value);
    40.                 Left = value;
    41.             }
    42.         }
    43.  
    44.         public int Y {
    45.             get {
    46.                 return Top;
    47.             }
    48.             set {
    49.                 Bottom -= (Top - value);
    50.                 Top = value;
    51.             }
    52.         }
    53.  
    54.         public int Height {
    55.             get {
    56.                 return Bottom - Top;
    57.             }
    58.             set {
    59.                 Bottom = value + Top;
    60.             }
    61.         }
    62.  
    63.         public int Width {
    64.             get {
    65.                 return Right - Left;
    66.             }
    67.             set {
    68.                 Right = value + Left;
    69.             }
    70.         }
    71.  
    72.         public static implicit operator System.Drawing.Rectangle(RECT r) {
    73.             return new System.Drawing.Rectangle(r.Left, r.Top, r.Width, r.Height);
    74.         }
    75.  
    76.         public static implicit operator RECT(System.Drawing.Rectangle r) {
    77.             return new RECT(r);
    78.         }
    79.     }
    80.  
    81.     [DllImport("user32.dll", SetLastError = true)]
    82.     private static extern System.IntPtr FindWindow(String lpClassName, String lpWindowName);
    83.  
    84.     [DllImport("user32.dll")]
    85.     [return: MarshalAs(UnmanagedType.Bool)]
    86.     public static extern bool GetWindowRect(HandleRef hWnd, out RECT lpRect);
    87.  
    88.     [DllImport("user32.dll")]
    89.     [return: MarshalAs(UnmanagedType.Bool)]
    90.     private static extern bool SetWindowPos(System.IntPtr hWnd, System.IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
    91.  
    92.     #endregion
    93.  
    94.  
    95.     // Use this for initialization
    96.     void Start() {
    97.         AssignTopmostWindow(CONSTANT_WINDOW_TITLE_FROM_GAME, true);
    98.     }
    99.  
    100.     public bool AssignTopmostWindow(string WindowTitle, bool MakeTopmost) {
    101.         UnityEngine.Debug.Log("Assigning top most flag to window of title: " + WindowTitle);
    102.  
    103.         System.IntPtr hWnd = FindWindow((string)null, WindowTitle);
    104.  
    105.         RECT rect = new RECT();
    106.         GetWindowRect(new HandleRef(this, hWnd), out rect);
    107.  
    108.         return SetWindowPos(hWnd, MakeTopmost ? HWND_TOPMOST : HWND_NOT_TOPMOST, rect.X, rect.Y, rect.Width, rect.Height, SWP_SHOWWINDOW);
    109.     }
    110.  
    111.     private string[] GetWindowTitles() {
    112.         List<string> WindowList = new List<string>();
    113.  
    114.         Process[] ProcessArray = Process.GetProcesses();
    115.         foreach (Process p in ProcessArray) {
    116.             if (!IsNullOrWhitespace(p.MainWindowTitle)) {
    117.                 WindowList.Add(p.MainWindowTitle);
    118.             }
    119.         }
    120.  
    121.         return WindowList.ToArray();
    122.     }
    123.  
    124.     public bool IsNullOrWhitespace(string Str) {
    125.         if (Str.Equals("null")) {
    126.             return true;
    127.         }
    128.         foreach (char c in Str) {
    129.             if (c != ' ') {
    130.                 return false;
    131.             }
    132.         }
    133.         return true;
    134.     }
    135. }
    136. #endif
    137.  
     
    KarloCvike, tjPark, Alex-CG and 9 others like this.
  6. krougeau

    krougeau

    Joined:
    Jul 1, 2012
    Posts:
    455
    Fantastic! And thanks so much for posting your code! :) It will be a great help to anyone (myself included) who'd like to know more about how to do this, and to incorporate external DLLs in general. So glad you got it working!
     
  7. TashaSkyUp

    TashaSkyUp

    Joined:
    Dec 29, 2016
    Posts:
    6
    I get:
    error CS0234: The type or namespace name `Drawing' does not exist in the namespace `System'. Are you missing `System.Drawing' assembly reference?

    From unity but not from visual studio. Visual studio has no error but Unity insists that it does. any ideas?
     
  8. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    981
    It's been a while, and I haven't touched Unity for at least half a year ago.

    Follow this checklist:
    1. Are you creating a game for Unity Player / Unity WebPlayer / Unity HTML5 / Android / iPhone / other non-PC systems?
    2. If #1 is yes, loading DLLs are not supported.
    3. If #1 is no, check to see if the System.Drawing.dll is directly from Unity's installation folder. This DLL uses the Mono C# implementation that Unity recognizes.
    4. If #3 is affirmative, check to see if the DLL is referenced from within the Unity Editor itself, such as the DLL is placed inside the Assets/Plugins folder that the Editor can see.
    5. If #4 is affirmative, check to see if your project configurations allow you to load the DLL into the project.
    I think that's all there is to it. If you still have any more problems, keep posting here, with more, detailed, information of what's going on, even if you don't know anything about it.
     
  9. tonemcbride

    tonemcbride

    Joined:
    Sep 7, 2010
    Posts:
    1,089
    It does sound like you might be using the wrong DLL - I've been running the code on 5.4.2p4 and it works really well. I got the DLL from:

    Program Files\Unity542p4\Editor\Data\Mono\lib\mono\2.0
     
  10. rlogan

    rlogan

    Joined:
    Oct 2, 2013
    Posts:
    16
    Did this work on Windows 10? Windows 10 seems to ignore most Window calls that I have tried...it just flashes the icon in the taskbar instead of bringing it to the front.
     
  11. SunixDev

    SunixDev

    Joined:
    Mar 1, 2014
    Posts:
    49
    hey
    I have this errorn on unity 5.5.2
    could you fix it pls
    Assets/AlwaysOnTop.cs(100,23): error CS0103: The name `CONSTANT_WINDOW_TITLE_FROM_GAME' does not exist in the current context
     
  12. tonemcbride

    tonemcbride

    Joined:
    Sep 7, 2010
    Posts:
    1,089
    You need to replace 'CONSTANT_WINDOW_TITLE_FROM_GAME' with the name of your game project so it knows which window it runs in. For example, if you run your standalone build and at the top left of the window it says "My Game" then that's what you need to replace it with.
     
    SunixDev likes this.
  13. SunixDev

    SunixDev

    Joined:
    Mar 1, 2014
    Posts:
    49
    Woow thank you , that work and its epic
     
  14. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    981
    Yeah, I thought it was apparent enough for coders to rename that constant variable. :eek:
     
  15. laurelhach

    laurelhach

    Joined:
    Dec 1, 2013
    Posts:
    229
    I know this is quite old, but anyone was able to make it work with windows 10 ?
    I can't make the window stays on top ...
     
  16. soranhanmul

    soranhanmul

    Joined:
    Aug 21, 2017
    Posts:
    6
    me too;; i changed not start, be awake. put it when first scene awake. but it can't be stay on top...
     
  17. Tanoshimi2000

    Tanoshimi2000

    Joined:
    Feb 10, 2014
    Posts:
    46
    Bumping this because, for me, in W10, it works, but it won't bring the window to the front. By that, I mean, when it starts, it stays on top (this is a menu program). Once it runs another program and I toggle it off, it doesn't stay on top. That's fine. When the other program ends it reactivates the Stay On Top, but I have to manually restore it. Once I manually restore it, it stays on top, but it won't restore it from minimized or behind other windows.
     
  18. Ikaro88

    Ikaro88

    Joined:
    Jun 6, 2016
    Posts:
    300
    On windows 10 with Unity 2018.3.4f not work for me, can anyone help me?
     
  19. Boegi

    Boegi

    Joined:
    Dec 6, 2014
    Posts:
    19
    F.Y.I. Works for me on Win10.
     
  20. GreenCubeGames

    GreenCubeGames

    Joined:
    Jan 9, 2015
    Posts:
    19
    AssignTopmostWindow(CONSTANT_WINDOW_TITLE_FROM_GAME, true); on update?
     
  21. zxx001

    zxx001

    Joined:
    Jul 15, 2020
    Posts:
    3
    Which Unity version are you using? I got this error when I try to build my project with 2019.3.6f1.
    Build completed with a result of 'Failed'
    UnityEngine.GUIUtility:processEvent(Int32, IntPtr)
     
  22. Boegi

    Boegi

    Joined:
    Dec 6, 2014
    Posts:
    19
    Sorry... I did not read your question and I did not write the unity version to my post :confused:... I'm 70% sure I tested it with unity 2019.1.2f1
     
  23. Kadir-

    Kadir-

    Joined:
    Mar 24, 2020
    Posts:
    14
  24. Munchy2007

    Munchy2007

    Joined:
    Jun 16, 2013
    Posts:
    1,735
    This isn't a programming solution it's a Windows utility program.
     
    kmowers and Lohoris-U like this.
  25. julienrobert

    julienrobert

    Joined:
    Sep 15, 2014
    Posts:
    65
    It works on 2019.4 Windows 10.

    I also need the window to be focus, so Unity takes all the graphic resources possible. Is it possible to do that with that dll?
     
  26. painsad

    painsad

    Joined:
    Nov 23, 2021
    Posts:
    1
    Sorry, it doesn't seem to work.
     
  27. ruudvangaal

    ruudvangaal

    Joined:
    May 15, 2017
    Posts:
    27
    Indeed, getting the focus seems required. I tried a bunch like:
    Code (CSharp):
    1. BringWindowToTop(hWnd);
    2. SetForegroundWindow(hWnd);
    3. SetActiveWindow(hWnd);
    4. ShowWindow(hWnd, SW_SHOW);
    But it seems like the creator of the Unity player window must have focus before this is really allowed.
     
  28. quanghieupro

    quanghieupro

    Joined:
    May 7, 2022
    Posts:
    1
    I am also interested in this, did you solve it? This is my website. FNF
     
  29. G21studio

    G21studio

    Joined:
    Nov 28, 2021
    Posts:
    2
  30. G21studio

    G21studio

    Joined:
    Nov 28, 2021
    Posts:
    2
    i have posted the solution now