Skip to content
This repository was archived by the owner on Aug 23, 2025. It is now read-only.

Commit 7f99564

Browse files
committed
Version 1.3 (minor feature update)
Added the Kill VM option from issue #26 Added additional tooltips to controls from issue #27 Added the option to close all running VM before quiting from issue #28 Improved the code for detecting running instances of Manager from issue #32 Various minor UI and code adjustments
1 parent f07fcb6 commit 7f99564

File tree

7 files changed

+383
-123
lines changed

7 files changed

+383
-123
lines changed

86BoxManager/Program.cs

Lines changed: 106 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System;
22
using System.Diagnostics;
3+
using System.Runtime.InteropServices;
4+
using System.Threading;
35
using System.Windows.Forms;
46

57
namespace _86boxManager
@@ -8,20 +10,118 @@ static class Program
810
{
911
public const bool PRERELEASE = false; //Is this a pre-release version?
1012
public static string[] args = Environment.GetCommandLineArgs(); //Get command line arguments
11-
/// <summary>
12-
/// The main entry point for the application.
13-
/// </summary>
13+
14+
private enum ShowWindowEnum
15+
{
16+
Hide = 0,
17+
ShowNormal = 1, ShowMinimized = 2, ShowMaximized = 3,
18+
Maximize = 3, ShowNormalNoActivate = 4, Show = 5,
19+
Minimize = 6, ShowMinNoActivate = 7, ShowNoActivate = 8,
20+
Restore = 9, ShowDefault = 10, ForceMinimized = 11
21+
};
22+
23+
[StructLayout(LayoutKind.Sequential)]
24+
public struct COPYDATASTRUCT
25+
{
26+
public IntPtr dwData;
27+
public int cbData;
28+
public IntPtr lpData;
29+
}
30+
31+
[DllImport("user32.dll")]
32+
[return: MarshalAs(UnmanagedType.Bool)]
33+
static extern bool ShowWindow(IntPtr hWnd, ShowWindowEnum flags);
34+
35+
[DllImport("user32.dll")]
36+
private static extern int SetForegroundWindow(IntPtr hwnd);
37+
38+
[DllImport("user32.dll")]
39+
public static extern IntPtr FindWindow(string className, string windowTitle);
40+
41+
public const int WM_COPYDATA = 0x004A;
42+
43+
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
44+
public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, ref COPYDATASTRUCT lParam);
45+
46+
private static Mutex mutex = null;
47+
1448
[STAThread]
1549
static void Main()
1650
{
51+
const string name = "86Box Manager";
52+
bool firstInstance;
53+
54+
//Use a mutex to check if this is the first instance of Manager
55+
mutex = new Mutex(true, name, out firstInstance);
56+
57+
//If it's not, we need to restore and focus the existing window, as well as pass on any potential command line arguments
58+
if (!firstInstance)
59+
{
60+
//Finds the existing window, unhides it, restores it and sets focus to it
61+
IntPtr hWnd = FindWindow(null, "86Box Manager");
62+
ShowWindow(hWnd, ShowWindowEnum.Show);
63+
ShowWindow(hWnd, ShowWindowEnum.Restore);
64+
SetForegroundWindow(hWnd);
65+
66+
//If this second instance comes from a VM shortcut, we need to pass on the command line arguments so the VM will start
67+
//in the existing instance.
68+
//NOTE: This code will have to be modified in case more command line arguments are added in the future.
69+
if (args.Length == 3 && args[1] == "-S" && args[2] != null)
70+
{
71+
string message = args[2];
72+
COPYDATASTRUCT cds;
73+
cds.dwData = IntPtr.Zero;
74+
cds.lpData = Marshal.StringToHGlobalAnsi(message);
75+
cds.cbData = message.Length;
76+
SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, ref cds);
77+
}
78+
79+
return;
80+
}
81+
else
82+
{
83+
//Then check if any instances of 86Box are already running and warn the user
84+
Process[] pname = Process.GetProcessesByName("86box");
85+
if (pname.Length > 0)
86+
{
87+
DialogResult result = MessageBox.Show("At least one instance of 86box is already running. It's not recommended that you run 86Box.exe directly outside of Manager. Do you want to continue at your own risk?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
88+
if (result == DialogResult.No)
89+
{
90+
return;
91+
}
92+
}
93+
Application.EnableVisualStyles();
94+
Application.SetCompatibleTextRenderingDefault(false);
95+
Application.Run(new frmMain());
96+
}
97+
98+
/*
1799
//Check if Manager is already running
18100
Process[] pname = Process.GetProcessesByName("86manager");
19101
if (pname.Length > 1)
20102
{
21-
MessageBox.Show("86Box Manager is already running. You can only run one instance at a time.\n\nIf you tried to run a virtual machine from a shortcut, you may use the open Manager window instead.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
103+
//Find the window of the first instance and restore it
104+
IntPtr hWnd = FindWindow(null, "86Box Manager");
105+
ShowWindow(hWnd, ShowWindowEnum.Show);
106+
ShowWindow(hWnd, ShowWindowEnum.Restore);
107+
SetForegroundWindow(hWnd);
108+
109+
//If the second instance was started with the -S command line argument for starting a VM, we must send
110+
//the arguments to the first instance
111+
if (args.Length == 3 && args[1] == "-S" && args[2] != null)
112+
{
113+
CopyDataStruct DataStruct = new CopyDataStruct();
114+
DataStruct.ID = "1";
115+
DataStruct.Data = args[2];
116+
DataStruct.Length = DataStruct.Data.Length;
117+
if (!hWnd.Equals(IntPtr.Zero))
118+
{
119+
SendMessage(hWnd, WM_COPYDATA, 0, ref DataStruct);
120+
}
121+
}
22122
}
23123
else
24-
{ //Then check if any instances of 86box are already running and warn the user
124+
{ //Then check if any instances of 86Box are already running and warn the user
25125
pname = Process.GetProcessesByName("86box");
26126
if (pname.Length > 0)
27127
{
@@ -34,7 +134,7 @@ static void Main()
34134
Application.EnableVisualStyles();
35135
Application.SetCompatibleTextRenderingDefault(false);
36136
Application.Run(new frmMain());
37-
}
137+
}*/
38138
}
39139
}
40140
}

86BoxManager/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,5 @@
3131
//
3232
// You can specify all the values or you can default the Build and Revision Numbers
3333
// by using the '*' as shown below:
34-
// [assembly: AssemblyVersion("1.0.*")]
35-
[assembly: AssemblyVersion("1.2.0.0")]
36-
[assembly: AssemblyFileVersion("1.2.0.0")]
34+
[assembly: AssemblyVersion("1.3.0.0")]
35+
[assembly: AssemblyFileVersion("1.3.0.0")]

86BoxManager/dlgSettings.Designer.cs

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

86BoxManager/dlgSettings.cs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ private void btnCancel_Click(object sender, EventArgs e)
4444
private void btnApply_Click(object sender, EventArgs e)
4545
{
4646
SaveSettings();
47-
btnApply.Enabled = false;
4847
}
4948

5049
private void btnOK_Click(object sender, EventArgs e)
@@ -57,12 +56,11 @@ private void txt_TextChanged(object sender, EventArgs e)
5756
{
5857
if (string.IsNullOrWhiteSpace(txtCFGdir.Text) || string.IsNullOrWhiteSpace(txtEXEdir.Text))
5958
{
60-
btnApply.Enabled = false;
6159
btnOK.Enabled = false;
6260
}
6361
else
6462
{
65-
btnApply.Enabled = true;
63+
//btnApply.Enabled = true;
6664
settingsChanged = true;
6765
btnOK.Enabled = true;
6866
}
@@ -90,7 +88,7 @@ private void SaveSettings()
9088
regkey.Close();
9189
settingsChanged = false;
9290
}
93-
catch(Exception ex)
91+
catch (Exception ex)
9492
{
9593
MessageBox.Show("An error has occurred. Please provide the following information to the developer:\n" + ex.Message + "\n" + ex.StackTrace, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
9694
}
@@ -121,14 +119,13 @@ private void LoadSettings()
121119
cbxMinimizeTray.Checked = Convert.ToBoolean(regkey.GetValue("MinimizeToTray"));
122120
cbxCloseTray.Checked = Convert.ToBoolean(regkey.GetValue("CloseToTray"));
123121

124-
//These two lines are needed because storing the values into the textboxes (above code) triggers textchanged event
122+
//This line is needed because storing the values into the textboxes (above code) triggers textchanged event
125123
settingsChanged = false;
126-
btnApply.Enabled = false;
127124

128125
regkey.Close();
129126
}
130127
}
131-
catch(Exception ex)
128+
catch (Exception ex)
132129
{
133130
txtCFGdir.Text = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\86Box Virtual Machines";
134131
txtEXEdir.Text = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) + @"\86Box";
@@ -172,13 +169,11 @@ private void btnBrowse2_Click(object sender, EventArgs e)
172169
private void cbxMinimize_CheckedChanged(object sender, EventArgs e)
173170
{
174171
settingsChanged = true;
175-
btnApply.Enabled = true;
176172
}
177173

178174
private void cbxShowConsole_CheckedChanged(object sender, EventArgs e)
179175
{
180176
settingsChanged = true;
181-
btnApply.Enabled = true;
182177
}
183178

184179
private void btnDefaults_Click(object sender, EventArgs e)
@@ -194,7 +189,7 @@ private void ResetSettings()
194189
RegistryKey regkey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE", true); //Open the key as read only
195190
Registry.CurrentUser.DeleteSubKeyTree(@"86Box");
196191
}
197-
catch(Exception ex){/*Do nothing, key doesn't exist anyway*/}
192+
catch (Exception ex) {/*Do nothing, key doesn't exist anyway*/}
198193

199194
txtCFGdir.Text = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + @"\86Box VMs";
200195
txtEXEdir.Text = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) + @"\86Box";
@@ -207,13 +202,11 @@ private void ResetSettings()
207202
private void cbxCloseTray_CheckedChanged(object sender, EventArgs e)
208203
{
209204
settingsChanged = true;
210-
btnApply.Enabled = true;
211205
}
212206

213207
private void cbxMinimizeTray_CheckedChanged(object sender, EventArgs e)
214208
{
215209
settingsChanged = true;
216-
btnApply.Enabled = true;
217210
}
218211
}
219212
}

0 commit comments

Comments
 (0)