public string Play()
        {
            if (!SteamUtil.IsSteamRunning())
            {
                MessageBox.Show("If you own the Steam Version, please open Steam, then click OK");
            }

            var options = profile.Options;
            bool playerKeyboard = (bool)profile.Options["keyboardPlayer"];

            IniFile file = new IniFile(saveFile);
            file.IniWriteValue("SystemSettings", "WindowedFullscreen", "False");
            file.IniWriteValue("SystemSettings", "Fullscreen", "False");
            file.IniWriteValue("Engine.Engine", "bMuteAudioWhenNotInFocus", "False");
            file.IniWriteValue("Engine.Engine", "bPauseOnLossOfFocus", "False");
            file.IniWriteValue("WillowGame.WillowGameEngine", "bPauseLostFocusWindowed", "False");
            file.IniWriteValue("WillowGame.WillowGameEngine", "bMuteAudioWhenNotInFocus", "False");

            Screen[] all = Screen.AllScreens;

            // minimize everything
            //User32.MinimizeEverything();
            List<PlayerInfo> players = profile.PlayerData;

            for (int i = 0; i < players.Count; i++)
            {
                PlayerInfo player = players[i];
                // Set Borderlands 2 Resolution and stuff to run

                Rectangle playerBounds = player.monitorBounds;

                // find the monitor that has this screen
                Screen owner = null;
                for (int j = 0; j < all.Length; j++)
                {
                    Screen s = all[j];
                    if (s.Bounds.Contains(playerBounds))
                    {
                        owner = s;
                        break;
                    }
                }

                int width = playerBounds.Width;
                int height = playerBounds.Height;

                if (owner == null)
                {
                    // log
                    // screen doesn't exist
                    //continue;
                }
                else
                {
                    Rectangle ob = owner.Bounds;
                    if (playerBounds.X == ob.X &&
                        playerBounds.Y == ob.Y &&
                        playerBounds.Width == ob.Width &&
                        playerBounds.Height == ob.Height)
                    {
                        // borderlands 2 has a limitation for max-screen size, we can't go up to the monitor's bounds
                        // in windowed mode
                        file.IniWriteValue("SystemSettings", "WindowedFullscreen", "True");
                    }
                    else
                    {
                        file.IniWriteValue("SystemSettings", "WindowedFullscreen", "False");
                    }
                }

                file.IniWriteValue("SystemSettings", "ResX", width.ToString(CultureInfo.InvariantCulture));
                file.IniWriteValue("SystemSettings", "ResY", height.ToString(CultureInfo.InvariantCulture));

                ProcessStartInfo startInfo = new ProcessStartInfo();
                startInfo.FileName = executablePlace;
                startInfo.WindowStyle = ProcessWindowStyle.Hidden;

                // NEW
                object option = options["saveid" + i];
                //object option = 11;
                int id = (int)option;

                if (playerKeyboard)
                {
                    startInfo.Arguments = "-AlwaysFocus -NoController -ControllerOffset=" + (i - 1).ToString(CultureInfo.InvariantCulture) + " -SaveDataId=" + id.ToString(CultureInfo.InvariantCulture);
                }
                else
                {
                    startInfo.Arguments = "-AlwaysFocus -ControllerOffset=" + i.ToString(CultureInfo.InvariantCulture) + " -SaveDataId=" + id.ToString(CultureInfo.InvariantCulture);
                }

                startInfo.UseShellExecute = true;
                startInfo.WorkingDirectory = Path.GetDirectoryName(executablePlace);

                Process proc = Process.Start(startInfo);

                ScreenData data = new ScreenData();
                data.Position = new Point(playerBounds.X, playerBounds.Y);
                data.Size = new Size(playerBounds.Width, playerBounds.Height);
                player.Process = proc;
                player.Tag = data;
            }

            return string.Empty;
        }
        public string Play()
        {
            List<PlayerInfo> players = profile.PlayerData;

            Screen[] all = Screen.AllScreens;

            string backupDir = GameManager.Instance.GetBackupFolder(this.userGame.Game);
            string binFolder = Path.GetDirectoryName(userGame.ExePath);
            string rootFolder = ReplaceCaseInsensitive(binFolder, gen.BinariesFolder, "");

            int gamePadId = 0;

            for (int i = 0; i < players.Count; i++)
            {
                PlayerInfo player = players[i];
                if (i > 0 && gen.KillMutex.Length > 0)
                {
                    PlayerInfo before = players[i - 1];
                    for (;;)
                    {
                        if (exited > 0)
                        {
                            return "";
                        }
                        Thread.Sleep(100);
                        if (before.screenData.KilledMutexes)
                        {
                            break;
                        }
                    }
                }

                Rectangle playerBounds = player.monitorBounds;

                // find the monitor that has this screen
                Screen owner = null;
                for (int j = 0; j < all.Length; j++)
                {
                    Screen s = all[j];
                    if (s.Bounds.Contains(playerBounds))
                    {
                        owner = s;
                        break;
                    }
                }

                int width = playerBounds.Width;
                int height = playerBounds.Height;
                bool isFullscreen = false;

                if (owner != null)
                {
                    Rectangle ob = owner.Bounds;
                    if (playerBounds.X == ob.X &&
                        playerBounds.Y == ob.Y &&
                        playerBounds.Width == ob.Width &&
                        playerBounds.Height == ob.Height)
                    {
                        isFullscreen = true;
                    }
                }

                engine.SetValue("Id", i.ToString(CultureInfo.InvariantCulture));
                engine.SetValue("Width", width.ToString(CultureInfo.InvariantCulture));
                engine.SetValue("Height", height.ToString(CultureInfo.InvariantCulture));
                engine.SetValue("IsFullscreen", isFullscreen);

                // symlink the game folder
                // find out the folder that contains the game executable
                string root = GetRootFolder(gen.BinariesFolder);

                string linkFolder = Path.Combine(backupDir, "Instance" + i);
                Directory.CreateDirectory(linkFolder);
                int exitCode;
                CmdUtil.LinkDirectories(rootFolder, linkFolder, out exitCode, root.ToLower());

                string linkBin = Path.Combine(linkFolder, gen.BinariesFolder);

                if (!string.IsNullOrEmpty(gen.BinariesFolder))
                {
                    // this needs fixing, if there are several folder to the exe and they have important files inside, this won't work! TODO
                    Directory.CreateDirectory(linkBin);
                    CmdUtil.LinkDirectories(binFolder, linkBin, out exitCode);
                }

                string exePath = Path.Combine(linkBin, this.userGame.Game.ExecutableName);

                if (gen.SymlinkExe)
                {
                    CmdUtil.LinkFiles(binFolder, linkBin, out exitCode, "xinput");
                }
                else
                {
                    CmdUtil.LinkFiles(binFolder, linkBin, out exitCode, "xinput", Path.GetFileNameWithoutExtension(gen.ExecutableName.ToLower()));
                    File.Copy(userGame.ExePath, exePath, true);
                }

                // some games have save files inside their game folder, so we need to access them inside the loop
                this.data[NucleusFolderEnum.GameFolder.ToString()] = linkFolder;

                string saveFile = ProcessPath(gen.SavePath);
                IniFile file = new IniFile(saveFile);

                switch (gen.SaveType)
                {
                    case GenericGameSaveType.INI:
                        foreach (var modPair in gen.ModifySave)
                        {
                            string key = modPair.Key;
                            string[] keys = key.Split('/');

                            engine.Execute(modPair.Value);
                            string val = engine.GetCompletionValue().ToString();

                            file.IniWriteValue(keys[0], keys[1], val);
                        }
                        break;
                }

                string startArgs = gen.StartArguments;

                byte[] xdata = null;

                if (gen.SupportsKeyboard && i == (int)profile.Options["KeyboardPlayer"])
                {
                    engine.SetValue("Keyboard", true);

                    // need to make an xinput that answers to no gamepad?
                    xdata = Properties.Resources.xinput4;
                }
                else
                {
                    engine.SetValue("Keyboard", false);

                    switch (gamePadId)
                    {
                        case 0:
                            xdata = Properties.Resources.xinput1;
                            break;
                        case 1:
                            xdata = Properties.Resources.xinput2;
                            break;
                        case 2:
                            xdata = Properties.Resources.xinput3;
                            break;
                        case 3:
                            xdata = Properties.Resources.xinput4;
                            break;
                        default:
                            xdata = Properties.Resources.xinput4;
                            break;
                    }
                    gamePadId++;
                }

                using (Stream str = File.OpenWrite(Path.Combine(linkBin, "xinput1_3.dll")))
                {
                    str.Write(xdata, 0, xdata.Length);
                }

                if (!string.IsNullOrEmpty(startArgs))
                {
                    startArgs = engine.Execute(startArgs).GetCompletionValue().AsString();
                }

                if (gen.NeedsSteamEmulation)
                {
                    string steamEmu = GameManager.Instance.ExtractSteamEmu();
                    string emuExe = Path.Combine(steamEmu, "SmartSteamLoader.exe");

                    string emuIni = Path.Combine(steamEmu, "SmartSteamEmu.ini");
                    IniFile emu = new IniFile(emuIni);

                    emu.IniWriteValue("Launcher", "Target", exePath);
                    emu.IniWriteValue("Launcher", "StartIn", Path.GetDirectoryName(exePath));
                    emu.IniWriteValue("Launcher", "CommandLine", startArgs);
                    emu.IniWriteValue("Launcher", "SteamClientPath", Path.Combine(steamEmu, "SmartSteamEmu.dll"));
                    emu.IniWriteValue("Launcher", "SteamClientPath64", Path.Combine(steamEmu, "SmartSteamEmu64.dll"));
                    emu.IniWriteValue("Launcher", "InjectDll", "0");
                    emu.IniWriteValue("SmartSteamEmu", "AppId", gen.SteamID);

                    Process proc;
                    if (gen.KillMutex.Length > 0)
                    {
                        // to kill the mutexes we need to orphanize the process
                        proc = ProcessUtil.RunOrphanProcess(emuExe);
                    }
                    else
                    {
                        ProcessStartInfo startInfo = new ProcessStartInfo();
                        startInfo.FileName = emuExe;
                        proc = Process.Start(startInfo);
                    }

                    player.Process = proc;
                    player.SteamEmu = true;
                }
                else
                {
                    Process proc;
                    if (gen.KillMutex.Length > 0)
                    {
                        proc = Process.GetProcessById(StartGameUtil.StartGame(exePath, startArgs));
                    }
                    else
                    {
                        ProcessStartInfo startInfo = new ProcessStartInfo();
                        startInfo.FileName = exePath;
                        startInfo.WindowStyle = ProcessWindowStyle.Hidden;
                        startInfo.Arguments = startArgs;
                        startInfo.UseShellExecute = true;
                        startInfo.WorkingDirectory = Path.GetDirectoryName(exePath);
                        proc = Process.Start(startInfo);
                    }
                    if (proc == null)
                    {
                        for (int times = 0; times < 200; times++)
                        {
                            Thread.Sleep(50);

                            Process[] procs = Process.GetProcesses();
                            string proceName = Path.GetFileNameWithoutExtension(gen.ExecutableName).ToLower();
                            string launcherName = Path.GetFileNameWithoutExtension(gen.LauncherExe).ToLower();

                            for (int j = 0; j < procs.Length; j++)
                            {
                                Process p = procs[j];
                                string lowerP = p.ProcessName.ToLower();
                                if (((lowerP == proceName) || lowerP ==launcherName) &&
                                    !attached.Contains(p))
                                {
                                    attached.Add(p);
                                    proc = p;
                                    break;
                                }
                            }

                            if (proc != null)
                            {
                                break;
                            }
                        }
                    }
                    else
                    {
                        attached.Add(proc);
                    }
                    player.Process = proc;
                }

                ScreenData data = new ScreenData();
                data.Position = new Point(playerBounds.X, playerBounds.Y);
                data.Size = new Size(playerBounds.Width, playerBounds.Height);
                data.KilledMutexes = gen.KillMutex.Length == 0;
                player.screenData = data;
            }

            return string.Empty;
        }
        public void Update(int delayMS)
        {
            if (profile == null)
            {
                return;
            }

            exited = 0;
            List <PlayerInfo> players = profile.PlayerData;

            timer += delayMS;

            for (int i = 0; i < players.Count; i++)
            {
                PlayerInfo p = players[i];
                if (p.screenData == null || p.Process == null)
                {
                    continue;
                }

                if (p.SteamEmu)
                {
                    List <int> children = ProcessUtil.GetChildrenProcesses(p.Process);
                    if (children.Count > 0)
                    {
                        for (int j = 0; j < children.Count; j++)
                        {
                            int     id    = children[j];
                            Process child = Process.GetProcessById(id);
                            try
                            {
                                if (child.ProcessName.Contains("conhost"))
                                {
                                    continue;
                                }
                            }
                            catch
                            {
                                continue;
                            }

                            p.Process  = child;
                            p.SteamEmu = child.ProcessName.Contains("SmartSteamLoader") || child.ProcessName.Contains("cmd");
                        }
                    }
                }
                else
                {
                    ScreenData data = p.screenData;

                    if (data.Set)
                    {
                        if (p.Process.HasExited)
                        {
                            exited++;
                            continue;
                        }

                        if (!p.screenData.KilledMutexes && gen.KillMutex.Length > 0)
                        {
                            StartGameUtil.KillMutex(p.Process, gen.KillMutex);
                            p.screenData.KilledMutexes = true;
                        }

                        uint lStyle = User32Interop.GetWindowLong(data.HWND.Hwnd, User32_WS.GWL_STYLE);
                        if (lStyle != data.RegLong)
                        {
                            uint toRemove = User32_WS.WS_CAPTION;
                            lStyle = lStyle & (~toRemove);

                            User32Interop.SetWindowLong(data.HWND.Hwnd, User32_WS.GWL_STYLE, lStyle);
                            data.RegLong       = lStyle;
                            data.HWND.Location = data.Position;
                        }
                    }
                    else
                    {
                        p.Process.Refresh();

                        if (p.Process.HasExited)
                        {
                            if (p.GotLauncher)
                            {
                                if (p.GotGame)
                                {
                                    exited++;
                                }
                                else
                                {
                                    List <int> children = ProcessUtil.GetChildrenProcesses(p.Process);
                                    if (children.Count > 0)
                                    {
                                        for (int j = 0; j < children.Count; j++)
                                        {
                                            int     id  = children[j];
                                            Process pro = Process.GetProcessById(id);

                                            if (!attached.Contains(pro))
                                            {
                                                attached.Add(pro);
                                                data.HWND = null;
                                                p.GotGame = true;
                                                p.Process = pro;
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                // Steam showing a launcher, need to find our game process
                                string launcher = gen.LauncherExe;
                                if (launcher.ToLower().EndsWith(".exe"))
                                {
                                    launcher = launcher.Remove(launcher.Length - 4, 4);
                                }

                                Process[] procs = Process.GetProcessesByName(launcher);
                                for (int j = 0; j < procs.Length; j++)
                                {
                                    Process pro = procs[j];
                                    if (!attached.Contains(pro))
                                    {
                                        attached.Add(pro);
                                        p.Process     = pro;
                                        p.GotLauncher = true;
                                    }
                                }
                            }
                        }
                        else
                        {
                            if (data.HWNDRetry || data.HWND == null || data.HWND.Hwnd != p.Process.MainWindowHandle)
                            {
                                data.HWND = new HwndObject(p.Process.MainWindowHandle);
                                Point pos = data.HWND.Location;

                                if (String.IsNullOrEmpty(data.HWND.Title) || pos.X == -32000 || data.HWND.Title.ToLower() == gen.LauncherTitle.ToLower())
                                {
                                    data.HWNDRetry = true;
                                }
                                else
                                {
                                    Size s = data.Size;
                                    data.Set           = true;
                                    data.HWND.TopMost  = true;
                                    data.HWND.Size     = data.Size;
                                    data.HWND.Location = data.Position;
                                }
                            }
                        }
                    }
                }

                if (exited == players.Count)
                {
                    if (!hasEnded)
                    {
                        hasEnded = true;
                        GameManager.Instance.ExecuteBackup(this.userGame.Game);

                        if (Ended != null)
                        {
                            Ended();
                        }
                    }
                }
            }
        }
        public string Play()
        {
            List <PlayerInfo> players = profile.PlayerData;

            Screen[] all = Screen.AllScreens;

            string backupDir  = GameManager.Instance.GetBackupFolder(this.userGame.Game);
            string binFolder  = Path.GetDirectoryName(userGame.ExePath);
            string rootFolder = ReplaceCaseInsensitive(binFolder, gen.BinariesFolder, "");

            int gamePadId = 0;

            for (int i = 0; i < players.Count; i++)
            {
                PlayerInfo player = players[i];
                if (i > 0 && gen.KillMutex.Length > 0)
                {
                    PlayerInfo before = players[i - 1];
                    for (;;)
                    {
                        if (exited > 0)
                        {
                            return("");
                        }
                        Thread.Sleep(100);
                        if (before.screenData.KilledMutexes)
                        {
                            break;
                        }
                    }
                }

                Rectangle playerBounds = player.monitorBounds;

                // find the monitor that has this screen
                Screen owner = null;
                for (int j = 0; j < all.Length; j++)
                {
                    Screen s = all[j];
                    if (s.Bounds.Contains(playerBounds))
                    {
                        owner = s;
                        break;
                    }
                }

                int  width        = playerBounds.Width;
                int  height       = playerBounds.Height;
                bool isFullscreen = false;

                if (owner != null)
                {
                    Rectangle ob = owner.Bounds;
                    if (playerBounds.X == ob.X &&
                        playerBounds.Y == ob.Y &&
                        playerBounds.Width == ob.Width &&
                        playerBounds.Height == ob.Height)
                    {
                        isFullscreen = true;
                    }
                }

                engine.SetValue("Id", i.ToString(CultureInfo.InvariantCulture));
                engine.SetValue("Width", width.ToString(CultureInfo.InvariantCulture));
                engine.SetValue("Height", height.ToString(CultureInfo.InvariantCulture));
                engine.SetValue("IsFullscreen", isFullscreen);

                // symlink the game folder
                // find out the folder that contains the game executable
                string root = GetRootFolder(gen.BinariesFolder);

                string linkFolder = Path.Combine(backupDir, "Instance" + i);
                Directory.CreateDirectory(linkFolder);
                int exitCode;
                CmdUtil.LinkDirectories(rootFolder, linkFolder, out exitCode, root.ToLower());

                string linkBin = Path.Combine(linkFolder, gen.BinariesFolder);

                if (!string.IsNullOrEmpty(gen.BinariesFolder))
                {
                    // this needs fixing, if there are several folder to the exe and they have important files inside, this won't work! TODO
                    Directory.CreateDirectory(linkBin);
                    CmdUtil.LinkDirectories(binFolder, linkBin, out exitCode);
                }

                string exePath = Path.Combine(linkBin, this.userGame.Game.ExecutableName);

                if (gen.SymlinkExe)
                {
                    CmdUtil.LinkFiles(binFolder, linkBin, out exitCode, "xinput");
                }
                else
                {
                    CmdUtil.LinkFiles(binFolder, linkBin, out exitCode, "xinput", Path.GetFileNameWithoutExtension(gen.ExecutableName.ToLower()));
                    File.Copy(userGame.ExePath, exePath, true);
                }


                // some games have save files inside their game folder, so we need to access them inside the loop
                this.data[NucleusFolderEnum.GameFolder.ToString()] = linkFolder;

                string  saveFile = ProcessPath(gen.SavePath);
                IniFile file     = new IniFile(saveFile);

                switch (gen.SaveType)
                {
                case GenericGameSaveType.INI:
                    foreach (var modPair in gen.ModifySave)
                    {
                        string   key  = modPair.Key;
                        string[] keys = key.Split('/');

                        engine.Execute(modPair.Value);
                        string val = engine.GetCompletionValue().ToString();

                        file.IniWriteValue(keys[0], keys[1], val);
                    }
                    break;
                }

                string startArgs = gen.StartArguments;

                byte[] xdata = null;

                if (gen.SupportsKeyboard && i == (int)profile.Options["KeyboardPlayer"])
                {
                    engine.SetValue("Keyboard", true);

                    // need to make an xinput that answers to no gamepad?
                    xdata = Properties.Resources.xinput4;
                }
                else
                {
                    engine.SetValue("Keyboard", false);

                    switch (gamePadId)
                    {
                    case 0:
                        xdata = Properties.Resources.xinput1;
                        break;

                    case 1:
                        xdata = Properties.Resources.xinput2;
                        break;

                    case 2:
                        xdata = Properties.Resources.xinput3;
                        break;

                    case 3:
                        xdata = Properties.Resources.xinput4;
                        break;

                    default:
                        xdata = Properties.Resources.xinput4;
                        break;
                    }
                    gamePadId++;
                }

                using (Stream str = File.OpenWrite(Path.Combine(linkBin, "xinput1_3.dll")))
                {
                    str.Write(xdata, 0, xdata.Length);
                }

                if (!string.IsNullOrEmpty(startArgs))
                {
                    startArgs = engine.Execute(startArgs).GetCompletionValue().AsString();
                }

                if (gen.NeedsSteamEmulation)
                {
                    string steamEmu = GameManager.Instance.ExtractSteamEmu();
                    string emuExe   = Path.Combine(steamEmu, "SmartSteamLoader.exe");

                    string  emuIni = Path.Combine(steamEmu, "SmartSteamEmu.ini");
                    IniFile emu    = new IniFile(emuIni);

                    emu.IniWriteValue("Launcher", "Target", exePath);
                    emu.IniWriteValue("Launcher", "StartIn", Path.GetDirectoryName(exePath));
                    emu.IniWriteValue("Launcher", "CommandLine", startArgs);
                    emu.IniWriteValue("Launcher", "SteamClientPath", Path.Combine(steamEmu, "SmartSteamEmu.dll"));
                    emu.IniWriteValue("Launcher", "SteamClientPath64", Path.Combine(steamEmu, "SmartSteamEmu64.dll"));
                    emu.IniWriteValue("Launcher", "InjectDll", "0");
                    emu.IniWriteValue("SmartSteamEmu", "AppId", gen.SteamID);

                    Process proc;
                    if (gen.KillMutex.Length > 0)
                    {
                        // to kill the mutexes we need to orphanize the process
                        proc = ProcessUtil.RunOrphanProcess(emuExe);
                    }
                    else
                    {
                        ProcessStartInfo startInfo = new ProcessStartInfo();
                        startInfo.FileName = emuExe;
                        proc = Process.Start(startInfo);
                    }

                    player.Process  = proc;
                    player.SteamEmu = true;
                }
                else
                {
                    Process proc;
                    if (gen.KillMutex.Length > 0)
                    {
                        proc = Process.GetProcessById(StartGameUtil.StartGame(exePath, startArgs));
                    }
                    else
                    {
                        ProcessStartInfo startInfo = new ProcessStartInfo();
                        startInfo.FileName         = exePath;
                        startInfo.WindowStyle      = ProcessWindowStyle.Hidden;
                        startInfo.Arguments        = startArgs;
                        startInfo.UseShellExecute  = true;
                        startInfo.WorkingDirectory = Path.GetDirectoryName(exePath);
                        proc = Process.Start(startInfo);
                    }
                    if (proc == null)
                    {
                        for (int times = 0; times < 200; times++)
                        {
                            Thread.Sleep(50);

                            Process[] procs        = Process.GetProcesses();
                            string    proceName    = Path.GetFileNameWithoutExtension(gen.ExecutableName).ToLower();
                            string    launcherName = Path.GetFileNameWithoutExtension(gen.LauncherExe).ToLower();

                            for (int j = 0; j < procs.Length; j++)
                            {
                                Process p      = procs[j];
                                string  lowerP = p.ProcessName.ToLower();
                                if (((lowerP == proceName) || lowerP == launcherName) &&
                                    !attached.Contains(p))
                                {
                                    attached.Add(p);
                                    proc = p;
                                    break;
                                }
                            }

                            if (proc != null)
                            {
                                break;
                            }
                        }
                    }
                    else
                    {
                        attached.Add(proc);
                    }
                    player.Process = proc;
                }

                ScreenData data = new ScreenData();
                data.Position      = new Point(playerBounds.X, playerBounds.Y);
                data.Size          = new Size(playerBounds.Width, playerBounds.Height);
                data.KilledMutexes = gen.KillMutex.Length == 0;
                player.screenData  = data;
            }

            return(string.Empty);
        }
        public string Play()
        {
            if (!SteamUtil.IsSteamRunning())
            {
                MessageBox.Show("If you own the Steam Version, please open Steam, then click OK");
            }

            var options = profile.Options;
            KeyboardPlayer playerKeyboard = (KeyboardPlayer)profile.Options["keyboardPlayer"];
            int pKeyboard = (int)playerKeyboard;

            IniFile file = new IniFile(saveFile);
            file.IniWriteValue("SystemSettings", "WindowedFullscreen", "False");
            file.IniWriteValue("SystemSettings", "Fullscreen", "False");
            file.IniWriteValue("Engine.Engine", "bMuteAudioWhenNotInFocus", "False");
            file.IniWriteValue("Engine.Engine", "bPauseOnLossOfFocus", "False");
            file.IniWriteValue("WillowGame.WillowGameEngine", "bPauseLostFocusWindowed", "False");
            file.IniWriteValue("WillowGame.WillowGameEngine", "bMuteAudioWhenNotInFocus", "False");

            Screen[] all = Screen.AllScreens;

            // minimize everything
            //User32.MinimizeEverything();
            List<PlayerInfo> players = profile.PlayerData;

            string backupDir = GameManager.Instance.GetBackupFolder(this.userGame.Game);
            string binFolder = Path.GetDirectoryName(executablePlace);
            string rootFolder = Path.GetDirectoryName(
                                    Path.GetDirectoryName(binFolder));

            int gamePadId = 0;

            for (int i = 0; i < players.Count; i++)
            {
                string linkFolder = Path.Combine(backupDir, "Instance" + i);

                PlayerInfo player = players[i];
                // Set Borderlands 2 Resolution and stuff to run

                Rectangle playerBounds = player.monitorBounds;

                // find the monitor that has this screen
                Screen owner = null;
                for (int j = 0; j < all.Length; j++)
                {
                    Screen s = all[j];
                    if (s.Bounds.Contains(playerBounds))
                    {
                        owner = s;
                        break;
                    }
                }

                int width = playerBounds.Width;
                int height = playerBounds.Height;

                if (owner == null)
                {
                    // log
                    // screen doesn't exist
                    //continue;
                }
                else
                {
                    Rectangle ob = owner.Bounds;
                    if (playerBounds.X == ob.X &&
                        playerBounds.Y == ob.Y &&
                        playerBounds.Width == ob.Width &&
                        playerBounds.Height == ob.Height)
                    {
                        // borderlands 2 has a limitation for max-screen size, we can't go up to the monitor's bounds
                        // in windowed mode
                        file.IniWriteValue("SystemSettings", "WindowedFullscreen", "True");
                    }
                    else
                    {
                        file.IniWriteValue("SystemSettings", "WindowedFullscreen", "False");
                    }
                }

                file.IniWriteValue("SystemSettings", "ResX", width.ToString(CultureInfo.InvariantCulture));
                file.IniWriteValue("SystemSettings", "ResY", height.ToString(CultureInfo.InvariantCulture));

                // Link-making
                Directory.CreateDirectory(linkFolder);
                int exitCode;
                CmdUtil.LinkDirectories(rootFolder, linkFolder, out exitCode, "binaries");

                string linkBin = Path.Combine(linkFolder, @"Binaries\Win32");
                Directory.CreateDirectory(linkBin);
                CmdUtil.LinkDirectories(binFolder, linkBin, out exitCode);
                CmdUtil.LinkFiles(binFolder, linkBin, out exitCode, "xinput", "borderlands");

                string exePath = Path.Combine(linkBin, this.userGame.Game.ExecutableName);
                File.Copy(this.executablePlace, exePath, true);
                // Link-end


                ProcessStartInfo startInfo = new ProcessStartInfo();
                startInfo.FileName = exePath;
                startInfo.WindowStyle = ProcessWindowStyle.Hidden;

                // NEW
                object option = options["saveid" + i];
                //object option = 11;
                int id = (int)option;

                if (i == pKeyboard)
                {
                    startInfo.Arguments = "-AlwaysFocus -NoController -SaveDataId=" + id.ToString(CultureInfo.InvariantCulture);
                }
                else
                {
                    byte[] xdata = null;
                    switch (gamePadId)
                    {
                        case 0:
                            xdata = Nucleus.Coop.Games.GamesResources.xinput1;
                            break;
                        case 1:
                            xdata = Nucleus.Coop.Games.GamesResources.xinput2;
                            break;
                        case 2:
                            xdata = Nucleus.Coop.Games.GamesResources.xinput3;
                            break;
                        case 3:
                            xdata = Nucleus.Coop.Games.GamesResources.xinput4;
                            break;
                        default:
                            xdata = Nucleus.Coop.Games.GamesResources.xinput4;
                            break;
                    }

                    using (Stream str = File.OpenWrite(Path.Combine(linkBin, "xinput1_3.dll")))
                    {
                        str.Write(xdata, 0, xdata.Length);
                    }

                    startInfo.Arguments = "-AlwaysFocus -nostartupmovies -SaveDataId=" + id.ToString(CultureInfo.InvariantCulture);
                    gamePadId++;
                }

                startInfo.UseShellExecute = true;
                startInfo.WorkingDirectory = Path.GetDirectoryName(exePath);

                Process proc = Process.Start(startInfo);

                ScreenData data = new ScreenData();
                data.Position = new Point(playerBounds.X, playerBounds.Y);
                data.Size = new Size(playerBounds.Width, playerBounds.Height);
                player.Process = proc;
                player.Tag = data;
            }

            return string.Empty;
        }
        public string Play()
        {
            if (!SteamUtil.IsSteamRunning())
            {
                return "Steam must be opened to play Left 4 Dead splitscreen";
            }

            using (Stream videoStream = new FileStream(videoFile, FileMode.Open))
            {
                videoCfg = new SourceCfgFile(videoStream);
            }
            string originalCFG = String.Copy(videoCfg.RawData);

            // minimize everything
            User32.MinimizeEverything();
            Screen[] allScreens = Screen.AllScreens;

            string folder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
            string l4dFolder = Path.GetDirectoryName(executablePlace);
            int gamePadId = 0;


            if (instances)
            {
                for (int i = 0; i < players.Count; i++)
                {
                    PlayerInfo p = players[i];

                    Screen screen = allScreens[p.ScreenIndex];
                    int width = 0;
                    int height = 0;
                    Rectangle bounds = screen.Bounds;
                    Point location = new Point();

                    ViewportUtil.GetPlayerViewport(p, 0, out width, out height, out location);

                    CultureInfo c = CultureInfo.InvariantCulture;
                    UpdateVideoCfg(width.ToString(c), height.ToString(c), "0", "1");

                    if (i == 0)
                    {
                        MakeAutoExecServer();
                    }
                    else
                    {
                        MakeAutoExecClient();
                    }
                    MakeMakeSplit();

                    string execPlace = executablePlace;
                    string l4dBinFolder = Path.Combine(l4dFolder, "bin");

                    if (i != 0)
                    {
                        string l4d = Path.Combine(folder, "L4D_" + (i + 1));
                        Directory.CreateDirectory(l4d);

                        FolderUtil.MkLink(l4dFolder, l4d, "bin", "left4dead.exe");

                        // copy executable
                        execPlace = Path.Combine(l4d, "left4dead.exe");
                        File.Copy(Path.Combine(l4dFolder, "left4dead.exe"), execPlace, true);

                        // make bin folder now
                        l4dBinFolder = Path.Combine(l4d, "bin");
                        string originalBinFolder = Path.Combine(l4dFolder, "bin");
                        Directory.CreateDirectory(l4dBinFolder);

                        FolderUtil.MkLink(originalBinFolder, l4dBinFolder, "xinput1_3.dll");

                        // add exec to firewall
                        FirewallUtil.AuthorizeProgram("Left 4 Dead", execPlace);
                    }

                    // copy the correct xinput to the bin folder
                    byte[] xdata = null;
                    if (firstKeyboard)
                    {
                        switch (gamePadId)
                        {
                            case 0:
                                xdata = GamesResources._4_xinput1_3;
                                break;
                            case 1:
                                xdata = GamesResources._1_xinput1_3;
                                break;
                            case 2:
                                xdata = GamesResources._2_xinput1_3;
                                break;
                            case 3:
                                xdata = GamesResources._3_xinput1_3;
                                break;
                        }
                    }
                    else
                    {
                        switch (gamePadId)
                        {
                            case 0:
                                xdata = GamesResources._1_xinput1_3;
                                break;
                            case 1:
                                xdata = GamesResources._2_xinput1_3;
                                break;
                            case 2:
                                xdata = GamesResources._3_xinput1_3;
                                break;
                            case 3:
                                xdata = GamesResources._4_xinput1_3;
                                break;
                        }
                    }
                    string xinputPath = Path.Combine(l4dBinFolder, "xinput1_3.dll");
                    using (MemoryStream stream = new MemoryStream(xdata))
                    {
                        // write to bin folder
                        using (FileStream file = new FileStream(xinputPath, FileMode.Create))
                        {
                            stream.WriteTo(file);
                        }
                    }
                    gamePadId++;


                    int pid = StartGameUtil.StartGame(execPlace,
                        "-novid -insecure", delayTime, "hl2_singleton_mutex", "steam_singleton_mutext");
                    Process proc = Process.GetProcessById(pid);

                    HwndObject hwnd = new HwndObject(proc.Handle);
                    ScreenData data = new ScreenData();
                    data.Position = location;
                    data.HWND = hwnd;
                    data.Size = new Size(width, height);
                    p.Process = proc;
                    p.Tag = data;

                    Thread.Sleep(delayTime);
                }

                loaded = true;
            }
            else
            {
                int screenIndex = -1;
                int fullWidth = 0;
                int fullHeight = 0;
                for (int i = 0; i < players.Count; i++)
                {
                    PlayerInfo player = players[i];
                    Screen scr = allScreens[player.ScreenIndex];

                    if (screenIndex == -1)
                    {
                        screenIndex = player.ScreenIndex;
                        fullWidth = scr.Bounds.Width;
                        fullHeight = scr.Bounds.Height;
                    }
                    else
                    {
                        if (screenIndex != player.ScreenIndex)
                        {
                            //twoScreens = true;
                            // Add 2nd monitor
                            fullWidth += scr.Bounds.Width;
                        }
                    }
                }

                loaded = true;

                string fWidth = fullWidth.ToString();
                string fHeight = fullHeight.ToString();
                string fullScr = (0).ToString();
                string noWindowBorderStr = (1).ToString();

                int splitMode = 1;
                for (int i = 0; i < players.Count; i++)
                {
                    PlayerInfo player = players[i];
                    if (player.ScreenType == ScreenType.HorizontalBottom ||
                        player.ScreenType == ScreenType.HorizontalTop)
                    {
                        splitMode = 1;
                    }
                    else
                    {
                        splitMode = 2;
                    }
                }

                MakeAutoExecSplitscreen(splitMode.ToString(CultureInfo.InvariantCulture));
                MakeMakeSplit();

                StartGameUtil.StartGame(executablePlace, "-novid -insecure", delayTime, "hl2_singleton_mutex", "steam_singleton_mutext");
            }

            return string.Empty;
        }