Application.Restart not passing arguments back - c#

This is a ClickOnce application. According to the documentation, "If your application was originally supplied command-line options when it first executed, Restart will launch the application again with the same options.". But I don't know if this is supposed to work or not with ClickOnce applications. If so, what am I doing wrong?
Here is my code:
public Form1()
{
InitializeComponent();
textBox1.Text = string.Join(Environment.NewLine, GetCommandLineFile());
}
private static string[] GetCommandLineFile()
{
if (AppDomain.CurrentDomain != null &&
AppDomain.CurrentDomain.SetupInformation != null &&
AppDomain.CurrentDomain.SetupInformation.ActivationArguments != null &&
AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData != null &&
AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData.Any())
{
return AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData;
}
else return new string[] { };
}
private void button1_Click(object sender, EventArgs e)
{
Application.Restart();
}
I associated my application with the .abc extension and when I double click my .abc file, the application will launch with the file name as the only argument, but then when I restart (by pressing my button1), GetCommandLineFile() will return an empty array.

I believe Application.Restart was designed for standard command line arguments instead of how ClickOnce applications handle it.
Looking at Microsoft's code for Application.Restart, they explicitly check if the application is a ClickOnce application and then restart it without any arguments being passed. Any other application, gets Environment.GetCommandLineArgs() parsed and sent to a new process.
I think a better solution, instead of writing arguments to a file, is to simply start a new process as such :
"path\Application Name.appref-ms" arg1,arg2,arg3
That way, when your application starts up, GetCommandLineFile() should grab the arguments again.

Related

Condition Process.Start to the number of Instances of a given Process

In a WPF C# app, users can launch the "explorer.exe" process from a given menu.
This is achieved as usual, with
Process.Start("explorer.exe");
However, I need to restrict the explorer quantity of simultaneous processes to one instance, instead of as many instances as the user starts by clicking on a button.
So the usual way is to count how many instance of the given process, "explorer.exe" are actually running and if there is more than one, then block the Process.Start().
The issue is that I'm stucked in the counting function. here is what I wrote:
static bool CountProcess(string name) {
return false; // by defualt it returns false.
int counter = 0;
while(true) {
counter = Process.GetProcessesByName(name).length; // get the quantity of processes for a given name.
if(counter > 1) {
return true;
break;
}
}
}
Then I invoke the function as this:
if(countProcess("explorer")) {
// Do nothing.
} else {
Process p = Process.Start("explorer.exe");
}
However after build and execute, the app gets stucked when opening the given process. Indeed, Visual Studio does not give any debug feedback.
How can this function be refactored to be 1) operational, 2) efficient.
Why there is while loop in CountProcess method? It should be simple if.
if(Process.GetProcessByName("explorer").Length == 0)
{
Process.Start("explorer.exe");
}
=== UPDATE ===
Ok, I'm starting to realize what is your problem.
If this wasn't explorer.exe - this code should work:
private static Process proc { get; set; }
private void button1_Click(object sender, EventArgs e)
{
if (proc == null || proc.HasExited)
{
proc = Process.Start("explorer.exe");
}
}
It checks whether Process was ever created (if first time - allow processing, if not - deny starting a new one) If he clicks for the second time, the process is not null but it SHOULD BE as proc.HasExited == false (if you didn't close it)
But if you run this code - probably starting new explorer window will be possible because this newly created process is being closed immediately. And this is because:
The reason that WaitForSingleObject returns immediately is that Explorer is a single-instance program (well, limited-instance)
You can try modifying the registry as proposed here :
Open explorer window and wait for it to close
But if this to be client application to be installed on others computer, I wouldn't advise changing programmatically someone registry.
=== UPDATE 2 ====
This solution below works - but with some restrictions (You must add com reference: "Microsoft Internet Controls") It allows to open one explorer window - and then checks whether window with the same "start folder path" as the base is already opened (watch out for slash and backslash difference in two different places of the code)
using SHDocVw;
public bool ExistOpenedWindow()
{
ShellWindows _shellWindows = new SHDocVw.ShellWindows();
string processType;
foreach (InternetExplorer ie in _shellWindows)
{
//this parses the name of the process
processType = Path.GetFileNameWithoutExtension(ie.FullName).ToLower();
//this could also be used for IE windows with processType of "iexplore"
if (processType.Equals("explorer") && ie.LocationURL.Contains("C:/"))
{
return true;
}
}
return false;
}
private void button1_Click(object sender, EventArgs e)
{
if (proc == null || !ExistOpenedWindow())
{
proc = Process.Start("explorer.exe", #"C:\");
}
}
So if you choose your base path (which will be sent as argument to explorer.exe") to be C:/, after clicking button once again, it will check whether there is ANY explorer window containing such path (opened by you or not)
Compare here: Start explorer.exe without creating a window C#
And here: Is there a way to close a particular instance of explorer with C#?
=== UPDATE 3 ====
After some thoughts - i've managed to come to working solution:
public bool ExistOpenedWindow()
{
var currentlyOpenedWindows = GetAllOpenedExplorerWindow();
return currentlyOpenedWindows.Any(t => t.HWND == ActiveOpenedWindowHwnd);
}
public List<InternetExplorer> GetAllOpenedExplorerWindow()
{
List<InternetExplorer> windows = new List<InternetExplorer>();
ShellWindows _shellWindows = new SHDocVw.ShellWindows();
string processType;
foreach (InternetExplorer ie in _shellWindows)
{
//this parses the name of the process
processType = Path.GetFileNameWithoutExtension(ie.FullName).ToLower();
//this could also be used for IE windows with processType of "iexplore"
if (processType.Equals("explorer"))
{
windows.Add(ie);
}
}
return windows;
}
public static int ActiveOpenedWindowHwnd;
private void button1_Click(object sender, EventArgs e)
{
var currentlyOpenedWindows = GetAllOpenedExplorerWindow();
if (ActiveOpenedWindowHwnd == 0 || !ExistOpenedWindow())
{
Process.Start("explorer.exe");
ShellWindows windows;
while ((windows = new SHDocVw.ShellWindows()).Count <= currentlyOpenedWindows.Count)
{
Thread.Sleep(50);
}
var currentlyOpenedWindowsNew = GetAllOpenedExplorerWindow();
var openedWindow = currentlyOpenedWindowsNew.Except(currentlyOpenedWindows).Single();
ActiveOpenedWindowHwnd = openedWindow.HWND;
}
}

get the exit code of a wpf application in powershell

I'm trying to get the exit code of my wpf application called in a Powershell script.
My main in WPF :
[STAThread]
public static int Main(string[] args)
{
if (args != null && args.Length > 0)
{
NB_ERRORS = AutomaticTests.Program.Main(args);
return NB_ERRORS;
//Application.Current.Shutdown(NB_ERRORS);
}
else
{
App app = new App();
app.Run(new MainWindow());
//Application.Current.Shutdown(NB_ERRORS);
return NB_ERRORS;
}
}
And in powershell I call it like this :
& $PathToExeTests 0 $LogTestsStagging
$nbFailed = $LASTEXITCODE
But it always contains 0.
I've tried to manually set the Environment.ExitCode, to shutdown the application with the code, to override OnExit like this :
protected override void OnExit(ExitEventArgs e)
{
e.ApplicationExitCode = AutomaticTests.GUI.Program.NB_ERRORS;
base.OnExit(e);
}
But I always have 0 in the LastExitCode.
By default, when you start a GUI app, PowerShell (just like cmd.exe) will not wait for the app to exit; it'll just tell Windows to start loading the app, and then continue running the script.
There are a couple of ways to wait for a GUI app to exit.
Option 1: Start the app using Start-Process, and then pass the resulting Process object to Wait-Process. This can be easily written as a pipeline:
Start-Process $PathToExeTests -ArgumentList #(0, $LogTestsStaging) | Wait-Process
Option 2: If you do something with the app's standard output (assign it into a variable, or pipe it into another command), then PowerShell will automatically wait for the process to exit.
& $PathToExeTests 0 $LogTestsStaging | Out-Null
Option 1 is probably going to be a lot more readable if someone else is ever going to maintain your code, but occasionally you'll see option 2 as well.

Problems when starting application with files from Explorer

I just added the feature where I can make my program the default-program for multiple music filetypes by following this question on Stackoverflow
It seemed to work fine, since all of the mp3 files etc has my icon on them in Explorer.
But when I tried starting one (I have handled the arguments just fine) the process itself starts (it shows up in Task Manager) but nothing happens. I even tried adding a Messagebox in the beginning of the "Window.Initialized"-event, but no messagebox came up.
What might be the cause of this problem? I have literally no idea what's wrong.
If you need code or anything, just ask for it since I don't know what to include in this question.
Thank you.
Here's the code for Window_Initialied
private void Window_Initialized(object sender, EventArgs e)
{
MessageBox.Show("asd");
HandleInstances(); // Checks if multiple instances of the program is running. Exits it if there's more than one instance (tried commenting this out, didn't work)
if (Properties.Settings.Default.HasRegisteredFiletypes == false) // Checks if theres a need to add the filetypes
AddExec();
StartWithMusic(Environment.GetCommandLineArgs().ToList()); // Here I call for the arguments. Checks if there are valid files in the arguments (.mp3, .flac etc)
SettingsLoadBGs.IsChecked = Properties.Settings.Default.LoadBGs;
// set accentcolor box
List<AccentColor> ac = new List<AccentColor>();
string userAccent = Mplayer.Properties.Settings.Default.Accent.ToLower();
foreach (Accent c in ThemeManager.DefaultAccents)
{
AccentColor acEnt = new AccentColor();
acEnt.Name = c.Name;
ac.Add(acEnt);
if (c.Name.ToLower() == userAccent)
ThemeManager.ChangeTheme(this, c, Theme.Dark);
}
ThemeManager.IsThemeChanged += new EventHandler<OnThemeChangedEventArgs>(ThemeChanged);
accentChooserBox.ItemsSource = ac;
}

What causes Winforms to silently discard unhandled exceptions (with no try/Catches)?

I'm in the middle of adding new functionality to my winforms controls, and part of that requires that a variable that was once always used to now be optional (if it's null, get the data from a second source). I made some changes and ran my form, only to find out nothing was happening, even functionality that previously worked. Confused I stepped through the code and found out that my Winforms user control was throwing a NullReferenceException when it encountered my variable, but in the UI no errors were being thrown.
My setup is I have a UserControl with a combo box. When the user changes that combo box it loads a secondary UserControl in a panel the first control has. The second control is what is throwing the exception.
Here are the code paths:
private void cmbActionType_SelectedIndexChanged(object sender, EventArgs e)
{
if (_loading)
return;
// ActionType was changed, update the action.ActionType value
if (cmbActionType.SelectedItem != null)
{
if (cmbActionType.SelectedItem.ToString() == SETVALUE_OPTION)
_action.ActionType = ActionTypes.SetValue;
else if (cmbActionType.SelectedItem.ToString() == CHECKVALUE_OPTION)
_action.ActionType = ActionTypes.CheckValue;
else
_action.ActionType = ActionTypes.CustomAction;
}
RefreshActionPanel();
_editor.DataModified();
}
private void RefreshActionPanel()
{
// Control defaults
AnchorStyles styles = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
UserControl subControl = null;
// Clear the currently active control
pnlActionDetails.Controls.Clear();
// Determine what type of control to load in the panel
if (cmbActionType.SelectedItem != null && cmbCaseType.SelectedItem != null)
{
// SetValue or CheckValue actions
if (cmbActionType.SelectedItem.ToString() == CHECKVALUE_OPTION || cmbActionType.SelectedItem.ToString() == SETVALUE_OPTION)
{
if (_caseTypeMap.ContainsKey(cmbCaseType.SelectedItem.ToString()))
subControl = new SetCheckActionControl(_action, _editor, _caseTypeMap[cmbCaseType.SelectedItem.ToString()]);
}
// CustomAction action type
else
{
// Check if the requested case is a type or defined in a script
if (_caseTypeMap.ContainsKey(cmbCaseType.SelectedItem.ToString()))
{
subControl = new CustomActionControl(_action, _editor, _caseTypeMap[cmbCaseType.SelectedItem.ToString()]);
}
else if (_editor.ScriptDefinitions.Any(x => x.CaseName == cmbCaseType.SelectedItem.ToString()))
{
var definitions = _editor.ScriptDefinitions.Where(x => x.CaseName == cmbCaseType.SelectedItem.ToString()).ToList();
subControl = new CustomActionControl(_action, _editor, definitions);
}
}
}
if (subControl != null)
{
subControl.Anchor = styles;
subControl.Height = pnlActionDetails.Height;
subControl.Width = pnlActionDetails.Width;
pnlActionDetails.Controls.Add(subControl);
}
}
public CustomActionControl(TestAction action, fmEditor editor, IList<TcScriptDefinition> scriptDefinitions) : base(action, editor)
{
_loading = true;
InitializeComponent();
_scriptDefinitions = scriptDefinitions;
PopulateActionList();
SetupDataGrid();
_loading = false;
}
private void SetupDataGrid()
{
// Clear the current contents of the datagrid
grdParameters.Rows.Clear();
if (cmbAction.SelectedItem == null)
return;
// Retrieve the action code from the drop down
string actionCode = cmbAction.SelectedValue.ToString();
// Check if any paramters are available for this action
if (!_availableActionParameters.ContainsKey(actionCode))
return;
// Add a new row for each parameter available for this action
foreach (string param in _availableActionParameters[actionCode])
{
string display = param;
// Determine if the parameter has a display string
if (_formInstance.CodeDisplayMap.ContainsCode(param))
display = _formInstance.CodeDisplayMap.GetDisplayStringFromCode(param);
// Create the array for the row, with an empty string as the current value
string[] row = { display, string.Empty };
// Check if the current action uses this action code.
// If so, retrieve the value for this parameter and use it in the row
// Note: Case-INsensitive comparison must be performed here
if (_action.Attributes["action"].Equals(actionCode, StringComparison.CurrentCultureIgnoreCase))
if (_action.Attributes.ContainsKey(param))
row[1] = _action.Attributes[param];
grdParameters.Rows.Add(row);
}
}
The NullReferenceException is coming from the SetupDataGrid() method where _formInstance is being called. However, usually when an application encounters an unhandled exception the JIT system throws an error message saying such (and as you can see, there's no try/catch statements used unless I am blind).
Why does my winforms application show no signs of an exception occurring. I'd rather an unhandled exception message occur rather than nothing happening, as that makes it harder for users to know something critical went wrong (as opposed to it not responding to their commands)
Edit: To clarify since there seems to be some confusion, I do NOT care about breaking on this exception in visual studio when debugging. The fact of the matter is that the application should not be hiding unhandled exceptions, and my application should crash (or rather show the JIT message that an unhandled exception occurred), even when not in debug mode outside of visual studio.
This is not a debug time question but a production run time question. If this code throws an OutOfMemoryException for instance, I need it to not be silently ignored. Right now it is being ignored.
Go to Debug->Exceptions... (Ctrl-D, E if you are using default shortcuts) from your menu bar in Visual Studio and check the box for Thrown under Common Language Runtime Exceptions. This will cause your program to break on exceptions even if they are in a try/catch block. You can then do a step forward and see where the code is jumping to for the next instruction. That should bring you to the catch block that is hiding your exception.
It may be jumping in to .NET code for the catch, you can go to Debug->Options and Settings.. and turn on Enable .NET framework Source Stepping to see what it is jumping in to.
Here is a example of catching the unhandeled execptions in code
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.Run(new Form1());
MessageBox.Show("0");
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
MessageBox.Show("1");
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
throw new ArgumentNullException();
}
}
Click the button and 1 appears, the program should still run afterwards.
However as I said in my last comment, check that user-unhandeled is checked (maybe uncheck and recheck) in Debug->Exceptions first it may solve your initial issue..
They can be caught if you have a try/catch in your Main, or if you have a ThreadException handler. Also check out SetUnhandledExceptionMode.
Note that if they're caught in Main, your program will just exit silently. ThreadException can "catch" and ignore them.
EDIT: Since the debugger doesn't break when you uncheck the box for Thrown under Common Language Runtime Exceptions, it's being caught by the code for Windows Forms. This is not ideal, but a lot of the BCL does this. You don't need to worry about it catching OutOfMemoryException or anything like that; the BCL should only be catching exceptions that it expects (vexing exceptions).
To be clear, the exception is not "unhandled". It is handled by the BCL code.

Detecting design mode from a Control's constructor

Following-on from this question, is it possible to detect whether one is in design or runtime mode from within an object's constructor?
I realise that this may not be possible, and that I'll have to change what I want, but for now I'm interested in this specific question.
You can use the LicenceUsageMode enumeration in the System.ComponentModel namespace:
bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
Are you looking for something like this:
public static bool IsInDesignMode()
{
if (Application.ExecutablePath.IndexOf("devenv.exe", StringComparison.OrdinalIgnoreCase) > -1)
{
return true;
}
return false;
}
You can also do it by checking process name:
if (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv")
return true;
Component ... as far as I know does not have the DesignMode property. This property is provided by Control. But the problem is when CustomControl is located in a Form in the designer, this CustomControl is running in runtime mode.
I have experienced that the DesignMode property works correct only in Form.
Controls(Forms, UserControls etc.) inherit Component class which has bool property DesignMode so:
if(DesignMode)
{
//If in design mode
}
IMPORTANT
There is a difference of using Windows Forms or WPF!!
They have different designers and and need different checks.
Additionally it's tricky when you mix Forms and WPF controls. (e.g. WPF controls inside of a Forms window)
If you have Windows Forms only, use this:
Boolean isInWpfDesignerMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
If you have WPF only, use this check:
Boolean isInFormsDesignerMode = (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv");
If you have mixed usage of Forms and WPF, use a check like this:
Boolean isInWpfDesignerMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
Boolean isInFormsDesignerMode = (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv");
if (isInWpfDesignerMode || isInFormsDesignerMode)
{
// is in any designer mode
}
else
{
// not in designer mode
}
To see the current mode you can show a MessageBox for debugging:
// show current mode
MessageBox.Show(String.Format("DESIGNER CHECK: WPF = {0} Forms = {1}", isInWpfDesignerMode, isInFormsDesignerMode));
Remark:
You need to add the namespaces System.ComponentModel and System.Diagnostics.
You should use Component.DesignMode property. As far as I know, this shouldn't be used from a constructor.
You can use this
if (DesignerProperties.GetIsInDesignMode(this))
{
...
}
Like many others, I have had this problem several times already when designing Windows Forms UserControls.
But today, I had a situation where none of the mentioned solutions worked for me.
The problem is, that LicenseManager.UsageMode only works reliably in the constructor, while DesignMode only works outside the constructor and not always. This is my experience, and this is what is said in a discussion on GitHub.
And another problem comes with inheritance, and embedding user controls in another user controls in another user controls. At the latest in the 2nd level of embedding a user controls, both ways fail!
This can be shown in the UserControls that I created for this test. Every UC has 3 labels:
its (project name) and type name
The values of
DesignMode (true: "DM=1"),
LicenseManager.UsageMode == LicenseUsageMode.Designtime, queried locally, (true: "local_LM-DT=1")
LicenseManager.UsageMode == LicenseUsageMode.Designtime, queried from a private field that was written in the constructor (true: "ctor_LM-DT=1")
all taken inside the constructor ("CTOR") and inside a method that was called from the constructor ("CFCtor")
The same values as in 2)
all taken inside the Load event ("Load()") and inside a method that was called from the Load event ("CFLoad")
The UserControls and the Form that I created are (all screenshots shown them in the WinForms Designer):
UserControl1:
contains 3 labels
The Designer does not execute the construtor or events, therefore the labels are not filled.
UserControl1a:
inherits from UserControl1
contains 2 more labels
The Designer executes the construtor and events of the parent UserControl.
UserControl2: contains
contains 3 labels
contains 1 UserControl1
contains 1 UserControl1a
The Designer executes the construtors and events of the embedded UserControls.
Only 1 level of embedding.
UserControl3:
contains 3 labels
contains 1 UserControl2
The Designer executes the construtors and events of the embedded UserControls.
2 level of embedding: The values inside the UserControl at 2nd embedding level are wrong.
Form1:
contains 3 labels
contains 1 UserControl1
contains 1 UserControl1a
contains 1 UserControl2
contains 1 UserControl3.
The Designer executes the construtors and events of the embedded UserControls.
3 level of embedding: The values inside the UserControl at 2nd and 3rd embedding level are wrong.
As you can see from the screenshots, "ctor_LM-DT" is always 1.
This means, that storing the value from the LicenseManager in a member field is necessary to get a valid status of the Designer usage:
private LicenseUsageMode m_ctorLMUsageMode = LicenseManager.UsageMode;
For the sake of completeness, here's some of my code that can be used to reproduce the test:
public static string CreateText(bool i_isInDesignMode, LicenseUsageMode i_localLicenseUsageMode, LicenseUsageMode i_ctorLicenseUsageMode)
{
return $"DM={(i_isInDesignMode ? 1 : 0)} local_LM-DT={(i_localLicenseUsageMode == LicenseUsageMode.Designtime ? 1 : 0)} ctor_LM-DT={(i_ctorLicenseUsageMode == LicenseUsageMode.Designtime ? 1 : 0)}";
}
The other UserControls are identical or similar:
public partial class UserControl1 : UserControl
{
private LicenseUsageMode m_ctorLMUsageMode = LicenseManager.UsageMode;
public UserControl1()
{
InitializeComponent();
label2.Text = $"CTOR: {CInitTester.CreateText (DesignMode, LicenseManager.UsageMode, m_ctorLMUsageMode)}";
CalledFromCtor();
}
private void UserControl1_Load(object sender, EventArgs e)
{
label3.Text = $"Load(): {CInitTester.CreateText(DesignMode, LicenseManager.UsageMode, m_ctorLMUsageMode)}";
CalledFromLoad();
}
private void CalledFromCtor()
{
label2.Text += $"\r\nCFCtor: {CInitTester.CreateText (DesignMode, LicenseManager.UsageMode, m_ctorLMUsageMode)}";
}
private void CalledFromLoad()
{
label3.Text += $"\r\nCFLoad: {CInitTester.CreateText (DesignMode, LicenseManager.UsageMode, m_ctorLMUsageMode)}";
}
}
Another interesting method is described on that blog: http://www.undermyhat.org/blog/2009/07/in-depth-a-definitive-guide-to-net-user-controls-usage-mode-designmode-or-usermode/
Basically, it tests for the executing assembly being statically referenced from the entry assembly. It circumvents the need to track assembly names ('devenv.exe', 'monodevelop.exe'..).
However, it does not work in all other scenarios, where the assembly is dynamically loaded (VSTO being one example).
With cooperation of the designer... It can be used in Controls, Components, in all places
private bool getDesignMode()
{
IDesignerHost host;
if (Site != null)
{
host = Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
if (host != null)
{
if (host.RootComponent.Site.DesignMode) MessageBox.Show("Design Mode");
else MessageBox.Show("Runtime Mode");
return host.RootComponent.Site.DesignMode;
}
}
MessageBox.Show("Runtime Mode");
return false;
}
MessageBox.Show( lines should be removed. It only makes me sure it works correctly.
This is the method I used in my project:
//use a Property or Field for keeping the info to avoid runtime computation
public static bool NotInDesignMode { get; } = IsNotInDesignMode();
private static bool IsNotInDesignMode()
{
/*
File.WriteAllLines(#"D:\1.log", new[]
{
LicenseManager.UsageMode.ToString(), //not always reliable, e.g. WPF app in Blend this will return RunTime
Process.GetCurrentProcess().ProcessName, //filename without extension
Process.GetCurrentProcess().MainModule.FileName, //full path
Process.GetCurrentProcess().MainModule.ModuleName, //filename
Assembly.GetEntryAssembly()?.Location, //null for WinForms app in VS IDE
Assembly.GetEntryAssembly()?.ToString(), //null for WinForms app in VS IDE
Assembly.GetExecutingAssembly().Location, //always return your project's output assembly info
Assembly.GetExecutingAssembly().ToString(), //always return your project's output assembly info
});
//*/
//LicenseManager.UsageMode will return RunTime if LicenseManager.context is not present.
//So you can not return true by judging it's value is RunTime.
if (LicenseUsageMode.Designtime == LicenseManager.UsageMode) return false;
var procName = Process.GetCurrentProcess().ProcessName.ToLower();
return "devenv" != procName //WinForms app in VS IDE
&& "xdesproc" != procName //WPF app in VS IDE/Blend
&& "blend" != procName //WinForms app in Blend
//other IDE's process name if you detected by log from above
;
}
Attention!!!: The code returned bool is indicating NOT in design mode!
I wasn't able to get any of these solutions to work for me in Visual Studio 2019 when creating a WinForms app on .NET Core 3.1.
Both Appllication.ProcessName and Process.ProcessName are returning "DesignToolsServer" for me and LicenseManager.UsageMode returns LicenseUsageMode.Runtime when the Control is in another control or just on a form itself.
I did get it to work using Application.ProcessName == "DesignToolsServer".
Yes, you can check for whether you're in "design mode" from within an object's constructor. But using the WinForms DesignMode property doesn't always work as expected. An alternative:
This is my technique to check DesignMode in C# using Visual Studio and it does work in constructors.
// add this class...
public static class Globals
{
static Globals() => DesignMode = true;
public static bool DesignMode { get; set; }
}
// and modify your existing class...
public static class Program
{
public static void Main()
{
Globals.DesignMode = false;
// ...
// ... and then the rest of your program
//
// in any of your code you can check Globals.DesignMode for
// the information you want.
}
}
This solution is lightweight and simple. The downside is that you have to remember to clear the flag in your Main code.
When checking for "design mode," we're essentially checking for whether our code is being executed because our whole program is being run or because parts of our code are being executed by the VS designer. With this solution, the flag only gets set to false when the whole program is being run.
The LicenseManager solution does not work inside OnPaint, neither does this.DesignMode. I resorted to the same solution as #Jarek.
Here's the cached version:
private static bool? isDesignMode;
private static bool IsDesignMode()
{
if (isDesignMode == null)
isDesignMode = (Process.GetCurrentProcess().ProcessName.ToLower().Contains("devenv"));
return isDesignMode.Value;
}
Be aware this will fail if you're using any third party IDE or if Microsoft (or your end-user) decide to change the name of the VS executable to something other than 'devenv'. The failure rate will be very low, just make sure you deal with any resulting errors that might occur in the code that fails as a result of this and you'll be fine.
If you want to run some lines when it is running but not in the Visual Studio designer, you should implement the DesignMode property as follows:
// this code is in the Load of my UserControl
if (this.DesignMode == false)
{
// This will only run in run time, not in the designer.
this.getUserTypes();
this.getWarehouses();
this.getCompanies();
}
private void CtrlSearcher_Load(object sender, EventArgs e)
{
if(!this.DesignMode) InitCombos();
}
Timers that are enabled by default can cause crash when using custom/user controls. Disable them by default, and enable only after design mode check
public chartAdapter()
{
try
{
//Initialize components come here
InitializeComponent();
//Design mode check
bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
if (designMode)
return;
//Enable timers ONLY after designmode check, or else crash
timerAutoConnect.Enabled = timerDraw.Enabled = true;

Categories