The problem
Did you ever think about putting several TVs/monitors to the wall and show there some dashboards? Current status, some pie charts and trends, alerts or advertisements. Or much like an arrival/departure tables in airport?
So, how would you do it?
- “IT’s quite straightforward, isn’t it” – you would answer originally – “simply take a PC with necessary video slots, connect all monitors/TVs… and the thing’s done.”
- Really?
- “Ok, we would need some apps to show the information and most probably the is a portal will all that available, so simply launch several Chrome instances in full screen mode and that’s it“.
But if you are reading this blog post probably you’ve already realized that isn’t really so simple.
- First, because you want all instances to start in full screen mode automatically
- Second, you want them on certain monitors.
And when the first part is not really complicated – you may find chrome command line options allowing to start Chrome in full screen on even in kiosk mode – you will definitely face problems with the second one. Although Chrome command line has option for specifying window position, you will find out it doesn’t work in full screen, here is what you’ll find on the issue while googling:
- http://stackoverflow.com/questions/29294045/how-to-open-two-instances-of-chrome-kiosk-mode-in-different-displays-windows
- http://stackoverflow.com/questions/3750113/launch-an-application-and-send-it-to-second-monitor
- http://superuser.com/questions/879898/how-to-run-many-instances-of-google-chrome-in-full-screen-on-multi-monitor-syste?answertab=votes#tab-top
- http://superuser.com/questions/720917/starting-multiple-chrome-full-screen-instances-on-multiple-monitors-from-batch
But besides Chrome, you may want to launch some other app. Like video monitoring software (to ensure all slaves work hard J)
Enough Words, Give Me a Solution
A good start for the solution is given by the Stack Overflow answer.
As we need to be able to modify easily the apps, URL and entire solution easily, I’ve decided to create a script on PowerShell. But helper functions wrapping WinApi are put into a .NET dll.
A .NET/C# Library
Expose necessary WinApi functions:
public static class WinApi { [DllImport("user32.dll", SetLastError = true)] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommands nCmdShow); [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd); }
I will not provide Enums referenced, you may find them on http://www.pinvoke.net/ on the respective functions description page, or download entirely in my code sample. (Link at the bottom)
Assuming we can start the process from a script easily, then next function we need is actually moving the window:
public static bool MoveToMonitor(IntPtr windowHandle, int monitor) { monitor = monitor - 1; return WinApi.SetWindowPos(windowHandle, IntPtr.Zero, Screen.AllScreens[monitor].WorkingArea.Left, Screen.AllScreens[monitor].WorkingArea.Top, 1000, 800, SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOREDRAW); }
But we cannot move full screen window easily this way. That’s why we will start Chrome in regular not full screen mode, and then send F11 (full Screen shortkey) to it via
public static void SendKey(IntPtr windowHandle, string keys) { WinApi.SetForegroundWindow(windowHandle); SendKeys.SendWait(keys); SendKeys.Flush(); }
PowerShell Part
Before you start, ensure you have enabled scripts execution:
Run PowerShell as Administrator and execute the following, confirm when prompted.
Set-ExecutionPolicy RemoteSigned
Now let’s write a script implementing this logic:
First, let’s reference our assembly with helper functions described above. (These are class names from my real example, in your case names could be different.):
Add-Type -Path Tomin.Tools.KioskMode.dll $WinAPI = [Tomin.Tools.KioskMode.WinApi] $Helpers = [Tomin.Tools.KioskMode.Helper]
Second, here is the code
function Chrome-Kiosk($Url, $MonitorNum) { Write-Output "starting chrome $Url , monitor: $MonitorNum" Start-Process $chromePath "$chromeArguments $Url" Start-Sleep -Seconds $ChromeStartDelay $window = (Get-Process -Name chrome | where MainWindowHandle -ne ([IntPtr]::Zero) | select -First 1).MainWindowHandle $WinAPI::ShowWindow($window, [Tomin.Tools.KioskMode.Enums.ShowWindowCommands]::Restore) $Helpers::MoveToMonitor($window, $MonitorNum) $Helpers::SendKey($window, '{F11}') Start-Sleep -Seconds $ChromeStartDelay }
We moved it into a function to easy start several instances.
Let me explain what it does:
- First we start a chrome instance with some command line parameters, an easy part.
- Then we need a window handle to manipulate it. But Chrome is special, main window of the stated process is not the one we want. The good part – the is only one ManWindow set for all Chrome processes – that is one currently active. Thus we wait a second for chrome to create a window,
- And look for that window handle, based on the above described criteria. Once window handle is know you are the master of it.
- But as mentioned above there could be a problem trying to move full screened window, thus we restore it to normal
- Move to required monitor (numbering starts from 1)
- And send F11 key to it.
- Last delay command is to wait for F11 to take effect, because otherwise next consequent function execution may fail, as Chrome did not switch his process to new window in time
Of course you will need also to initialize couple of variables:
$chromePath = 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe' $chromeArguments = '--new-window --incognito' # if Window not moved (especially on machine start) - try increaing the delay. $ChromeStartDelay = 3
And the final calls would then look like:
# &taskkill /im chrome* /F Chrome-Kiosk 'http://google.com' -MonitorNum 1 Chrome-Kiosk 'http://http://www.bbc.com/' -MonitorNum 2
The first command is optional and commented, but could be useful when somebody played with your kiosk and you want quickly to restore everything back by a single click.
Final Step
Create a link to your PowerShell script:
And put it into your Startup folder.
Entire Solution, No Programming
You may download already compiled solution with sample script.
Prerequisites
Windows 8.1
- No
Windows 7
- PowerShell 4: http://social.technet.microsoft.com/wiki/contents/articles/21016.how-to-install-windows-powershell-4-0.aspx
- .NET Framework 4.5: https://www.microsoft.com/en-US/download/details.aspx?id=42643
All you need to do:
1 Download and Extract
Download link is at the bottom.
Extract contents to C:\Kiosk-Mode.
You may put into another folder – but ensure you renamed path in all places.
2. Modify Ciklum-Kiosk.ps1
Put necessary URLs and Monitor Numbers (starting from 1)
3. Enable Scripts Execution
Run PowerShell as Administrator and execute the following, confirm when prompted.
Set-ExecutionPolicy RemoteSigned
4. Launch Shortcut
Double click on link (Start – Kios – modifypath.lnk) to ensure browsers are started and opened on necessary displays.
Note: youi may need to modify your link if you put file not into C:\Kiosk-Mode. Right click on it -> properties and fill it accordingly:
5. Autostart
Copy the link to desktop for easy access and to your startup folder:
6. Troubleshooting
If window is not moved to another desktop – try increasing the delay in script ($ChromeStartDelay) variable.
Script has been tested on Windows 8.1 machine.
Links
GitHub page: https://github.com/alex-tomin/Tomin.Tools.KioskMode
Binaries: https://github.com/alex-tomin/Tomin.Tools.KioskMode/releases/download/1.0/Tomin.Tools.KioskMode.zip
This solution is the missing link in a multi-screen project I’m looking at. However, I can’t get it to work (Windows 7), after doing the necessary adjustments for paths, URLs and monitor disposition, when running, it stumbles at the dll call with “Add-Type : Could not load file or assembly ‘file:///C:\kiosk-mode\Tomin.Tools.KioskMode.dll’ or one of its dependencies. This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.”.
Is the solution in fact only Win 8.1? Is there an easy adaptation to Win 7?
Hi, Iain. Theoretically it should work for windows 7 as well. I will check as soon as find a windows 7 machine. Meanwhile could you check you have a .Net Framework 4.5 installed. (it comes out of the box in windows 8.1, but not in windows 7.)
https://www.microsoft.com/en-us/download/details.aspx?id=42642
Yes, version 4.5.2 installed.
Another Idea – Powershell is running on old .NET.
Could you run $PSVersionTable in powershell and check its version and CLRVersion. Perhaps you have PowerShell 3.0 which uses CLR 2.0
If that’s the case – easiest way to update to powershell 4. Or here is another hack: http://stackoverflow.com/questions/2094694/how-can-i-run-powershell-with-the-net-4-runtime
OK – that’s got it working. Many thanks, nice solution!
Assume there’s not a way to get “true” Kiosk mode (rather than Full Screen)? I guess not, as that requires starting Chrome with a switch in the command line, rather than sending a key sequence.
It is possible to specify command line switches in my solution. Variable $chromeArguments in the script.
But the problem is – we cannot move FullScreen window. That’s why I start it normally move to the necessary Display, and then turn full screen by sending a keystroke.
Chrome has command line argument for window position and fullscreen (or kiosk mode), but they don’t work together.
In fact, it is possible to move even fullscreen window, but it is much more complicated.
Thank you for this! I managed to combine your C# into the powershell script so I go the entire thing in one file I can just execute from command line. No DLLs to compile and copy to the right place. Basically involves putting all the C# code in as a string and then using Add-Type to compile it. I’ll send if you are interested.
Can you please post the script here?
I know several years has passed but I’d also be interested in this please Garr G.
Awesome! It does exactly what I needed. I did struggle to get it working on windows 7 though, turns out that the “HelperFunctions.ps1” and the “Tomin.Tools.KioskMode.dll” files were blocked by windows causing the powerscript to fail on a ‘not digitally signed’ error. In order to remove the block, right click the files, go to properties and click “Unblock”. Hope this helps someone else 🙂
@Bram, you’re right, I noticed the unblock button under properties. I find this button using Win 8.1 but not in win7.
Where is the dll file. It does not show in the file list.
This is a great article, thank you so much for sharing. I just found a solution on how to make this a real kiosk mode. Just add “–kiosk” at the end of this line:
$chromeArguments = ‘–new-window –incognito –kiosk
But the problem is, the second browser is not moving at the second monitor. Can you help me on this sir?
Your help will greatly appreciated.
Hi, I’m glad you find it useful.
I started my journey with Chrome “–kiosk” switch. But I didn’t find a way to move a window in that mode.
Though it wasn’t strongly necessary for my purposes, full screen was enough.
Oleksandr,
I can’t find the .dll file. It does not show in the list. Do I need to generate it??
Thanks
Glen
Tomin Oleksandr Congratulations, your work is amazing !! But I doubt has arisen, we need the status bar is hidden chrome and do not know how. We thought about using Firefox (if you can hide the bar) but we are not able to release it. Could you guide?
Thank you
Best regards
Hi, not sure I understand your problem. By default Chrome hides its status bar. If you mean favorites bar – you can configure it in Chrome settings, but again it should be hidden by default…
Hello again. First, sorry for my English. I put a trap to explain what is the bar to which I refer. In Firefox you can hide, but you can only Chrome hide the –kiosk mode. That is why we would like to use Firefox instead of Chrome.
https://drive.google.com/file/d/0B4RPE7wzFIFJWGxfWnZQQ201elE/view?usp=sharing
Thank you very much again
Best regards
On Windows 10 the Chrome windows do not get moved to the designated monitors. All instances open without error, but they don’t get moved.
Mr. Tomin,
Thanks for publishing this, very useful. One question, we’re trying to communicate between these windows via JavaScript but we’re not sure how to reference each window. Any insights would be greatly appreciated. Thanks!
Tomin
I am trying to set it up in Windows 10 Pro and I am having difficulties. First the Set-ExecutionPolicy RemoteSigned does not work. When I set it and try to execute the PS Script, I get a signature error. When I set it to unrestricted, I can run it once. But when I run it, I get lots of error message:
Add-Type : Could not load file or assembly ‘file:///C:\Kiosk-Mode\Tomin.Tools.KioskMode.dll’
Any idea on what the issue might be ?
I have all the files in C:\Kiosk-Mode folder
It’s just what I need but I have a little bug:
It opens the n.1 link on the n.1 display. Then it goes full screen BUT when it opens the second window upon the primary, it goes also full screen but it leaves a ghost image on the primary window. I think it’s like a refresh issue because if I click on the primary window, the ghost image disappears.
What can I do?
Maybe sending the full screen mode to the secondary window first?
Thank you
Thanks for your good work, I tried it on and W8.1 & W10, works perfectly.
I wanted to ask if there is the possibility to set the resolution of the various monitors; would import for viewing photos.
Thank you very much again
Best regards
Fabio
Thank you for sharing this. A life-saver. On Windows 10 is there a issue?
what an awesome script! thanks
Not sure if this is still monitored. I’m using this script which is excellent but I have a problem in that the pages I’m using prompt for a username/password. If I launch the pages manually it uses the stored Chrome credentials
I have a slightly different use case where I’m using 4 separate chrome windows over two displays and having them tiled vertically, 2 up on each monitor.
I’ve been using just a single monitor with two chrome apps with the following command and it’s been great:
…\Google\Chrome\Application\chrome.exe” –profile-directory=Default –app-id=
and then using the “objShell.TileVertically” vbscript command to run the two windows side-by-side.
But now I want to add a monitor and a further two chrome apps and having great difficulty ensuring the apps open on the appropriate monitors.
I came across your powershell script which looks like it would work but yours is designed to push each to a monitor and full screen where I’m looking to tile them. Also, you work with the Chrome window where I need them to be apps to make better use of the screen real estate.
Do you think your script could be manipulated to work with chrome apps instead?
Hi, how are you? I am pretty amazed with this solution because simplify really long the process to run two instances in kiosk mode for terminal equipments.
But, I tried to use it to run to windows of Internet Explorer instead of Chrome. Can you give me a hand to find why the two instances are opening in the same screen? It´´s like the selection of the monitors does not work for this app.
Thank you so much in advance!
Hi, Sometimes i have a problem with 3 : InvalidCastArguments
$WinAPI::ShowWindow($window, [Tomin.Tools.KioskMode.Enums.ShowWindowCommands]::Restore)
$Helpers::MoveToMonitor($window, $MonitorNum)
$Helpers::SendKey($window, ‘{F11}’)
solution ?
I ask for your help: You need to do the same, but open 1 window in –kiosk mode, and open the second window through F11 in full screen.
Hey, great work and very helpful.
How to get numbers of monitors as integer?
Example: I want to create three if statements, so
if number of monitors is 2 – to open two urls,
if number of monitors is three – to open three urls and
if number of monitors is four – to open four urls
May I know if it is possible to show 4 different pages in kiosk mode on a single large display with this?
Hi there. I have little modified starting script to have compartibility with microsoft edge chromium. Main problem was that first window was not refresh after second window opened on top an next moved to second screen. Here is a difference:
===============ciklum-kiosk.ps1============
$chromePath = ‘C:\Program Files (x86)\Microsoft\Edge Beta\Application\msedge.exe’
$chromeArguments = ‘–new-window –kiosk –disable-infobars –disable-session-crashed-bubble’
$wnd1 = Chrome-Kiosk ‘http://ya.ru’ -MonitorNum 1
$wnd2 = Chrome-Kiosk ‘http://rambler.ru’ -MonitorNum 2
$temp1 = Chrome-Refresh $wnd1
$temp1 = Chrome-Refresh $wnd2
===============ciklum-kiosk.ps1============
===============HelperFunctions.ps1=========
function Chrome-Kiosk($Url, $MonitorNum)
{
Write-Host “starting MSEdge “$Url” , monitor: “$MonitorNum
Start-Process $chromePath “$chromeArguments $Url”
$temp1 = Start-Sleep -Seconds $ChromeStartDelay
$window = (Get-Process -Name msedge | where MainWindowHandle -ne ([IntPtr]::Zero) | select -First 1).MainWindowHandle
$temp1 = $WinAPI::ShowWindow($window, [Tomin.Tools.KioskMode.Enums.ShowWindowCommands]::Restore)
$temp1 = $Helpers::MoveToMonitor($window, $MonitorNum)
$temp1 = $Helpers::SendKey($window, ‘{F11}’)
$temp1 = Start-Sleep -Seconds $ChromeStartDelay
return $window
}
function Chrome-Refresh($window)
{
Write-Host “refreshing window value =” $window
$Helpers::SendKey($window, ‘{F5}’)
Start-Sleep -Seconds $ChromeStartDelay
}
===============HelperFunctions.ps1=========