Debugging: Attach to Process for Console App running inside cmd.exe - c#

How do you "Attach to Process..." for a console application thats running from a CMD window and not launched by F5? The reason I ask is because the application takes command line arguments and I want to have a genuine experience.
I've even attaching to CMD.exe, but no luck, or setting a break-point using Console.ReadKey() with also no luck. I'm kind of at a loss here.
Is this possible?

You have some options:
Use "Debug -> Command line arguments" option in Visual Studio;
Use "Debug -> Attach to process" and find your process; it is not cmd.exe, but a process with executable name like "MyProject.exe". You can use Process Explorer or another task manager with "tree view" support to easily find the Process ID - just look for the processes started by your cmd.exe.
On Windows (as of 2022), put Debugger.Launch() or Debugger.Break() into your code - with this executed, the system will launch a dialog asking you to choose what instance of Visual Studio to use for debugging (you can choose the one with your project already open).

To debug from the command line rather than using the VS GUI maze:
Launch the Visual Studio Command Prompt
type vsjitdebugger/? which gives you the command example like :
c:> vsjitdebugger [AppName] [Args] : Launch the specified executable and attach to debugger
typing tlist or tasklist will give you PIDs for attaching to existing processes. example:
c:> tasklist | find /i "web"

It's possible, sure. Try one of these two:
Start the process, then go to Debug->Attach and find the process. You may have to refresh to see it.
Add a "Debugger.Break()" statement in the code, if possible; that will break automatically (but be sure to remove it or surround it with preprocessor directives so it doesn't get into production code).

2020 UPDATE: to #VladV answer
Debugger.Break() doesn't work anymore.
Try using Debugger.Launch() instead, also put breakpoints after this line, or VS will start complaining.

As others have said, you can specify the stratup command line arguments from within the project and just start debugging within Visual Studio.
If you still want to attach to the running application, you need to attach the debugger to MyApp.exe (whatever your application is called - the exe that gets compiled to the bin\debug directory) and not cmd.exe. Attaching to cmd.exe it attaching to the command process, not the process of your application.

In the projects settings "Debug" section there's a textbox for "Command line arguments:". When the VS debugger starts the C# program, it'll pass those arguments to the process just as if the program had been started form the command line with those arguments.
The alternative is to use a command line debugger. There are a few options here, but in all honesty they're probably not what you want to use instead of VS unless you're getting into some really hairy debugging scenarios. If you're interested in checking them out, there's a good summary in this SO answer:
MSIL debuggers - Mdbg, Dbgclr, Cordbg
You can also try the techique of putting a call to System.Diagnostics.Debugger.Break() early in your initialization - if the program is running under a debugger, it'll break, it it's not running under a debugger you should be asked if you want to attach one. You can make the call conditionally depending on a configuration file or environment variable setting so you only get the break if you're really interested in it (somewhat intrusive, but not too bad).

Just add an registry entry for your exe's name in "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\currentversion\image file execution options", adding a "debugger" key valued with "vsjitdebugger.exe" under it, you can see a dialog pops up asking you to choose a VS version to debug when the exe starts up.
see MSDN "How to: Launch the Debugger Automatically" for more information.

I thought I would find some better solutions here but it seem the one I already have is the best. Debugger.Break() just simply don't work for me at all. But some time ago I found VisualStudioAttacher class on GitHub. Can't find the rep right now, but I'm posting my slightly modified version.
You will use it like this.
class Program {
static void Main(string[] args) {
VSAttacher.attachDebugger("SolutionFileContainingThisCode.sln");
Console.WriteLine("Hello World"); //set a brakepoint here
//...
}
}
This will just attach to currently opened instance of visual studio and it doesn't require you to choose the debugger.
Setup
Create new class library project named VSAttacher, or whatever you like.
Add reference to VSAttacher project in the project you want to debug.
In VSAttacher project, add reference to envdte library
Paste following code to VSAttacher project :
code:
using System.IO;
using EnvDTE;
using DTEProcess = EnvDTE.Process;
using System;
using System.Collections.Generic;
using Process = System.Diagnostics.Process;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace AppController {
#region Classes
/// <summary>Visual Studio attacher.</summary>
public static class VSAttacher {
public static Action<object> log = (o) => Console.WriteLine(o);
//Change following variables depending on your version of visual studio
//public static string VSProcessName = "WDExpress";
//public static string VSObjectName = "!WDExpress";
public static string VSProcessName = "devenv";
public static string VSObjectName = "!VisualStudio";
/// <summary>
/// Tries to attach the program to Visual Studio debugger.
/// Returns true is the attaching was successful, false is debugger attaching failed.
/// </summary>
/// <param name="sln">Solution file containing code to be debugged.</param>
public static bool attachDebugger(string sln) {
if (System.Diagnostics.Debugger.IsAttached) return true;
log("Attaching to Visual Studio debugger...");
var proc = VSAttacher.GetVisualStudioForSolutions(
new List<string>() { Path.GetFileName(sln) });
if (proc != null) VSAttacher.AttachVSToProcess(
proc, Process.GetCurrentProcess());
else {
try { System.Diagnostics.Debugger.Launch(); }
catch (Exception e) { }
} // try and attach the old fashioned way
if (System.Diagnostics.Debugger.IsAttached) {
log(#"The builder was attached successfully. Further messages will displayed in ""Debug"" output of ""Output"" window.");
return true;
}
log("Could not attach to visual studio instance.");
return false;
}
#region Public Methods
#region Imports
[DllImport("User32")]
private static extern int ShowWindow(int hwnd, int nCmdShow);
/// <summary>Returns a pointer to an implementation of <see cref="IBindCtx"/> (a bind context object). This object stores information about a particular moniker-binding operation.</summary>
/// <param name="reserved">This parameter is reserved and must be 0.</param>
/// <param name="ppbc">Address of an <see cref="IBindCtx"/>* pointer variable that receives the interface pointer to the new bind context object. When the function is successful, the caller is responsible for calling Release on the bind context. A NULL value for the bind context indicates that an error occurred.</param>
/// <returns></returns>
[DllImport("ole32.dll")]
public static extern int CreateBindCtx(int reserved, out IBindCtx ppbc);
/// <summary>Returns a pointer to the <see cref="IRunningObjectTable"/> interface on the local running object table (ROT).</summary>
/// <param name="reserved">This parameter is reserved and must be 0.</param>
/// <param name="prot">The address of an IRunningObjectTable* pointer variable that receives the interface pointer to the local ROT. When the function is successful, the caller is responsible for calling Release on the interface pointer. If an error occurs, *pprot is undefined.</param>
/// <returns>his function can return the standard return values E_UNEXPECTED and S_OK.</returns>
[DllImport("ole32.dll")]
public static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SetFocus(IntPtr hWnd);
#endregion
public static string GetSolutionForVisualStudio(Process visualStudioProcess) {
var vsi = getVSInstance(visualStudioProcess.Id);
try { return vsi?.Solution.FullName;}
catch (Exception) {} return null;
}
public static Process GetAttachedVisualStudio(Process ap) {
var vsps = getVSProcess();
foreach (Process vsp in vsps) {
var vsi = getVSInstance(vsp.Id);
if (vsi == null) continue;
try {
foreach (Process dp in vsi.Debugger.DebuggedProcesses)
if (dp.Id == ap.Id) return dp;
} catch (Exception) {}
}
return null;
}
public static void AttachVSToProcess(Process vsp, Process applicationProcess) {
var vsi = getVSInstance(vsp.Id);
if (vsi == null) return;
//Find the process you want the VS instance to attach to...
DTEProcess tp = vsi.Debugger.LocalProcesses.Cast<DTEProcess>().FirstOrDefault(process => process.ProcessID == applicationProcess.Id);
//Attach to the process.
if (tp != null) {
tp.Attach();
ShowWindow((int)vsp.MainWindowHandle, 3);
SetForegroundWindow(vsp.MainWindowHandle);
} else {
throw new InvalidOperationException("Visual Studio process cannot find specified application '" + applicationProcess.Id + "'");
}
}
public static Process GetVisualStudioForSolutions(List<string> sns) {
foreach (string sn in sns) {
var vsp = GetVSProc(sn);
if (vsp != null) return vsp;
}
return null;
}
public static Process GetVSProc(string name) {
var vsps = getVSProcess(); var e = false;
foreach (Process vsp in vsps) {
_DTE vsi = getVSInstance(vsp.Id);
if (vsi == null) { e = true; continue; }
try {
string sn = Path.GetFileName(vsi.Solution.FullName);
if (string.Compare(sn, name, StringComparison.InvariantCultureIgnoreCase)
== 0) return vsp;
} catch (Exception) { e = true; }
}
if (!e) log($#"No running Visual Studio process named ""{VSProcessName}"" were found.");
return null;
}
#endregion
#region Private Methods
private static IEnumerable<Process> getVSProcess() {
Process[] ps = Process.GetProcesses();
//var vsp = ps.Where(p => p.Id == 11576);
return ps.Where(o => o.ProcessName.Contains(VSProcessName));
}
private static _DTE getVSInstance(int processId) {
IntPtr numFetched = IntPtr.Zero;
IMoniker[] m = new IMoniker[1];
GetRunningObjectTable(0, out var rot);
rot.EnumRunning(out var ms); ms.Reset();
var rons = new List<string>();
while (ms.Next(1, m, numFetched) == 0) {
IBindCtx ctx;
CreateBindCtx(0, out ctx);
m[0].GetDisplayName(ctx, null, out var ron);
rons.Add(ron);
rot.GetObject(m[0], out var rov);
if (rov is _DTE && ron.StartsWith(VSObjectName)) {
int currentProcessId = int.Parse(ron.Split(':')[1]);
if (currentProcessId == processId) {
return (_DTE)rov;
}
}
}
log($#"No Visual Studio _DTE object was found with the name ""{VSObjectName}"" that resides in given process (PID:{processId}).");
log("The processes exposes following objects:");
foreach (var ron in rons) log(ron);
return null;
}
#endregion
}
#endregion
}
If you use express version of visual studio, you should change VSProcessName and VSObjectName (this was tested only with express and community versions).

Related

FolderBrowserDialog won't show in a single .cs file without Form

I am trying to code a program which is executed when a file is right clicked in windows, and then a context menu feature named 'Move to' executes a file in the windows registry HKEY ClASSES. It ought to parse in "%1" as argument when it executes, so that my program knows where the file is located. However, when I compile my single .cs file, the FolderBrowserDialog won't show. I am suspecting that it is because I haven't initialized some kind of form before I call it. Is it possible in some way to choose a folder from a single c# file without including Forms?
using System;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
public class MoveTo : Form
{
public static string current_file_path;
public static string new_file_path;
public static string file_name;
public static void Main(string[] args){
if (args.Length > 0)
{
current_file_path = (string) args[0];
file_name = (string) current_file_path.Replace(Path.GetDirectoryName(Environment.GetCommandLineArgs()[1]), "");
var browser = new FolderBrowserDialog();
if (browser.ShowDialog()==DialogResult.OK)
{
new_file_path = browser.SelectedPath + file_name;
}else
{
Environment.Exit(1);
}
try
{
File.Move(current_file_path, new_file_path);
}catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
}
If you bypass the argument check and try to show the FBD in a debugger, with this exact code, you will see System.Threading.ThreadStateException: 'Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it. This exception is only raised if a debugger is attached to the process.'
As per the error message, this exception won't be raised if no debugger is attached. Put an [STAThread] attribute on your Main method, like you normally see in any windows forms app:
[STAThread]
public static void Main(string[] args)
{
...
I also recommend you add an else for your outer if, to show an error if no arguments are passed (otherwise your app will exit silently

How do I know if my app was opened from console or windows in C#

I have an application that is both gui and console.
Console: It executes from a windows schedule to do some automated tasks, so its called with an argument
GUI: Used for entering config parameters, a much nicer way for the user to do this than console.
All this works great. its primarily a console app, the console is hidden if its opened with no arguments and the configuration form is shown.
Problem:
If I open it FROM the console with NO arguments, the console is hidden and the form is shown.
how can i detect what or where i opened the app from, if it was opened from windows then hide the console, if it was opened from console then leave the console shown.
If you really want to know "where" your application has been started you have to know what is your parent process. In order to know your parent process you can read the solution of How to get parent process in .NET in managed way
Then you can for example check if your parent process name is explorer(windows) to open your application as a GUI.
sample code based on the solution provided in How to get parent process in .NET in managed way
namespace ConsoleApp1
{
public static class ProcessExtensions
{
private static string FindIndexedProcessName(int pid)
{
var processName = Process.GetProcessById(pid).ProcessName;
var processesByName = Process.GetProcessesByName(processName);
string processIndexdName = null;
for (var index = 0; index < processesByName.Length; index++)
{
processIndexdName = index == 0 ? processName : processName + "#" + index;
var processId = new PerformanceCounter("Process", "ID Process", processIndexdName);
if ((int)processId.NextValue() == pid)
{
return processIndexdName;
}
}
return processIndexdName;
}
private static Process FindPidFromIndexedProcessName(string indexedProcessName)
{
var parentId = new PerformanceCounter("Process", "Creating Process ID", indexedProcessName);
return Process.GetProcessById((int)parentId.NextValue());
}
public static Process Parent(this Process process)
{
return FindPidFromIndexedProcessName(FindIndexedProcessName(process.Id));
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Process.GetCurrentProcess().Parent().ProcessName);
Console.ReadKey();
}
}
}
This code will outputs:
debug in visual studio: devenv
start from windows: explorer
start from cmd: cmd
start from powershell console: powershell
...
One way to do this is to separate your cli version and gui version into 2 executable (like 7z do with 7z.exe a command line tool and 7zG the Gui version)
You could have 3 projects in visual studio:
MyApp.Console (console app)
MyApp.WindowsGui (winform/wpf app)
MyApp.Logic (all the logic)
Console and WindowsGui have a reference to your Logic project
This will give you cleaner code as each "Frontend" project will handle only their purpose (handling GUI or console stuff) and your Logic are callable by both frontends
I am unclear as to what you're trying to achieve. From my understanding, the application will launch as a console application regardless of having arguments or not. To prevent it from disappearing, you can utilize a Boolean to prevent the window from closing while the user is inputting configuration. For example (syntax may not be 100% at DialogResult):
using System;
using System.Windows.Forms;
// Allows you to access the static objects of Console
// without having to repeatedly type Console.Something.
using static System.Console;
static bool configured = false;
static bool showForm = false;
static void Main(string[] args) {
showForm = args.Length < 1;
if (showForm) {
WriteLine("The application needs to be configured.");
using (ConfigForm config = new ConfigForm()) {
if (config.ShowDialog() == DialogResult.OK) {
showForm = false;
configured = true;
// Set your configured arguments here.
}
}
}
// Prevents the console from closing.
while (showForm)
ReadKey();
// Do your processing in this condition.
if (!showForm && configured)
WriteLine("Thanks for playing. Press any key to exit.");
else // Retry or exit in this one.
WriteLine("An error occurred. Press any key to exit.");
ReadKey();
}
If your application is set as a console application then it will launch the console window by default. Now, if you need to show and hide your console at different times, you can look into this post where the accepted answer provides a proper way to utilize Windows API to achieve this without having to perform some shady logic to find the window by title or identity.
using System.Runtime.InteropServices;
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
const int SW_HIDE = 0;
const int SW_SHOW = 5;
var handle = GetConsoleWindow();
// Hide
ShowWindow(handle, SW_HIDE);
// Show
ShowWindow(handle, SW_SHOW);
If this doesn't solve what you need, feel free to be more thorough in your post and include some code to give more definition to your issue. I am unable to comment and ask questions so I gave a basic solution. If you have any questions, feel free to ask.
This might help:
using System;
using System.Diagnostics;
static class IsRanFromConsole
{
private static readonly string[] consoleNames = {
"cmd", "bash", "ash", "dash", "ksh", "zsh", "csh",
"tcsh", "ch", "eshell", "fish", "psh", "pwsh", "rc",
"sash", "scsh", "powershell", "tcc"
};
private static bool isCache = false;
private static bool isConsole;
public static bool IsConsole()
{
if (!isCache)
{
string parentProc = Process.GetCurrentProcess().Parent().ProcessName;
isConsole = Array.IndexOf(consoleNames, parentProc) > -1;
}
return isConsole;
}
}
Usage:
Console.WriteLine(IsRanFromConsole.IsConsole());
For the .Parent() function, you need to add this code.

Determine whether assembly is a gui application

I am trying to determine whether a C# assembly is a GUI or a Console application in order to build a tool which will automatically recreate lost short cuts.
Currently, I have a routine which recursively steps all directories in Program Files (and the x86 directory).
For each EXE it finds, the tool calls IsGuiApplication, passing the name of the EXE.
From there, I create an Assembly object using LoadFrom.
I want to check whether this assembly is has a GUI output, but I'm unsure how to test this in C#.
My current idea is to use GetStdHandle, but I'm not sure how to apply this to an assembly outside of the running application.
My experience with reflection in C# is limited, so any help would be appreciated.
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace BatchShortcutBuild
{
class Program
{
//I'm uncertain that I need to use this method
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetStdHandle(int nStdHandle);
static void Main(string[] args) {
BuildShortcuts();
Console.ReadLine();
}
public static void BuildShortcuts() {
String dirRoot = "C:\\Program Files\\";
processRoot(dirRoot);
dirRoot = "C:\\Program Files (x86)\\";
processRoot(dirRoot);
Console.WriteLine("Finished enumerating files");
Console.ReadLine();
}
public static void processRoot(String path) {
try {
foreach (String theDir in Directory.EnumerateDirectories(path)) {
processRoot(theDir);
}
foreach (String theFile in Directory.EnumerateFiles(path, "*.exe")) {
if (IsGuiApplication(theFile)) {
//I would generate a shortcut here
}
}
} catch { }
}
public static bool IsGuiApplication(String filePath) {
Console.WriteLine(filePath);
Assembly a = Assembly.LoadFrom(filePath);
//How to get the program type from the assembly?
return false;
}
}
}
Just to be safe here, the method suggested by #Killany and #Nissim suggest is not 100% accurate, as console applications can reference the System.Windows.* dlls (either by mistake or by a need of other functionality given by the 'System.Windows' assembly).
I'm not sure a 100% method exist, as some applications can be given a parameter to run with/without ui (i.e. silently)
As several times mentioned before, you can read the Subsystem Field.
private PEFileKinds GetFileType(string inFilename)
{
using (var fs = new FileStream(inFilename, FileMode.Open, FileAccess.Read))
{
var buffer = new byte[4];
fs.Seek(0x3C, SeekOrigin.Begin);
fs.Read(buffer, 0, 4);
var peoffset = BitConverter.ToUInt32(buffer, 0);
fs.Seek(peoffset + 0x5C, SeekOrigin.Begin);
fs.Read(buffer, 0, 1);
if (buffer[0] == 3)
{
return PEFileKinds.ConsoleApplication;
}
else if (buffer[0] == 2)
{
return PEFileKinds.WindowApplication;
}
else
{
return PEFileKinds.Dll;
}
}
}
Use GetReferencedAssemblies() to get all referenced assemblies and look for the system.windows.forms assembly
AssemblyName[] referencedAssemblies = assm.GetReferencedAssemblies();
foreach (var assmName in referencedAssemblies)
{
if (assmName.Name.StartsWith("System.Windows"))
//bingo
}
A basic idea to detect GUI apps is that GUI apps always use assembly System.Windows.*.
bool isGui(Assembly exeAsm) {
foreach (var asm in exeAsm.GetReferencedAssemblies()) {
if (asm.FullName.Contains("System.Windows"))
return true;
}
return false;
}
This will detect all .NET applications that are windows forms, or even WPF
One thing you could check is the .subsystem of the file's PE header. If you open up the file in ILDASM and check the manifest, you'll see this if it uses the Windows GUI subsystem:
I don't think there's any method in the Assembly class to check this, so you'll probably need to check the file itself.
Another way to check would be to go through the types in the assembly and see if any of them derive from System.Windows.Forms.Form (Windows Forms) or System.Windows.Window (WPF):
private static bool HasGui(Assembly a)
{
return a.DefinedTypes
.Any(t => typeof(System.Windows.Forms.Form).IsAssignableFrom(t) ||
typeof(System.Windows.Window).IsAssignableFrom(t));
}
Note that you'll need to add references to System.Windows.Forms.dll and PresentationFramework.dll to gain access to these types.
You can use Assembly.LoadFrom(string) to load the assembly. I tested this method myself and it seemed a bit slow so perhaps you can make it faster by involving Parallel.ForEach.

Call Method between classes

I need to call addDownload() method that is inside the main application class MainWindow.xaml.cs from App.xaml.cs
Some info about the Application:
In my App.xaml.cs i have code to run only one instance of the application. (Not my Code. I found it)
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;
using DownloadManager;
namespace DownloadManager
{
public partial class App : Application
{
private static readonly Semaphore singleInstanceWatcher;
private static readonly bool createdNew;
static App()
{
// Ensure other instances of this application are not running.
singleInstanceWatcher = new Semaphore(
0, // Initial count.
1, // Maximum count.
Assembly.GetExecutingAssembly().GetName().Name,
out createdNew);
if (createdNew)
{
// This thread created the kernel object so no other instance
// of this application must be running.
}
else
{
// This thread opened an existing kernel object with the same
// string name; another instance of this app must be running now.
// Gets a new System.Diagnostics.Process component and the
// associates it with currently active process.
Process current = Process.GetCurrentProcess();
foreach (Process process in
Process.GetProcessesByName(current.ProcessName))
{
if (process.Id != current.Id)
{
NativeMethods.SetForegroundWindow(
process.MainWindowHandle);
NativeMethods.ShowWindow(process.MainWindowHandle,
WindowShowStyle.Restore);
break;
}
}
// Terminate this process and gives the underlying operating
// system the specified exit code.
Environment.Exit(-2);
}
}
private static class NativeMethods
{
[DllImport("user32.dll")]
internal static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
internal static extern bool ShowWindow(IntPtr hWnd,
WindowShowStyle nCmdShow);
}
/// <summary>
/// Enumeration of the different ways of showing a window.</summary>
internal enum WindowShowStyle : uint
{
Hide = 0,
ShowNormal = 1,
ShowMinimized = 2,
ShowMaximized = 3,
Maximize = 3,
ShowNormalNoActivate = 4,
Show = 5,
Minimize = 6,
ShowMinNoActivate = 7,
ShowNoActivate = 8,
Restore = 9,
ShowDefault = 10,
ForceMinimized = 11
}
}
}
I need to pass Command Line Parameters to addDownload() method every time, whether the application is already running or not.
What i've tried so far:
First, i deleted the Startup entry point in App.xaml, so i can manage it inside code-behind
Then, if the Application is not running, create a new instance of MainWindow, and show it:
MainWindow MW = new MainWindow();
MW.Show();
Get Command Line Parameters, and pass it to the addDownload() method:
string[] args = Environment.GetCommandLineArgs();
if(args.Length > 1)
{
MW.addDownload(args[1]);
}
Ok, this part work perfectly.
But as i say, i need to pass Command Line Parameters also if the application is already running. Getting the command line parameters it's the same as before, but passing it to the addDownload() method of the current MainWindow instance, is not, and i have troubles to find a working way;
I tried:
try
{
var main = App.Current.MainWindow as MainWindow;
string[] args = Environment.GetCommandLineArgs();
if (args.Length > 1)
{
main.addDownload(args[1]);
}
}
catch(Exception ex)
{
MessageBox.Show(String.Format("{0}\n{1}", ex.GetType().ToString(), ex.Message));
}
But i get a NullReferenceException.. i think on the main declaration.. I don't know how to debug this particular situation inside Visual Studio.
Any help? What i'm doing wrong?
You get a NullReferenceException because you are wanting to access an instance of an object (MainWindow) that exists in a different process, and you can't do that. What you need to do is some sort of InterProcess communication, there are many ways to do this, one of which is to use .NET remoting (probably not the best way).
Here are a few links that turned up with a quick search:
http://www.codeproject.com/Articles/17606/NET-Interprocess-Communication
What is the best choice for .NET inter-process communication?
http://msdn.microsoft.com/en-us/library/kwdt6w2k(v=vs.100).aspx

How to start Azure Storage Emulator from within a program

I have some unit tests that use Azure Storage. When running these locally, I want them to use the Azure Storage emulator which is part of the Azure SDK v1.5. If the emulator isn't running, I want it to be started.
To start the emulator from the command line, I can use this:
"C:\Program Files\Windows Azure SDK\v1.5\bin\csrun" /devstore
This works fine.
When I try to start it using this C# code, it crashes:
using System.IO;
using System.Diagnostics;
...
ProcessStartInfo processToStart = new ProcessStartInfo()
{
FileName = Path.Combine(SDKDirectory, "csrun"),
Arguments = "/devstore"
};
Process.Start(processToStart);
I've tried fiddling with a number of ProcessStartInfo settings, but nothing seems to work. Is anybody else having this problem?
I've checked the Application Event Log and found the following two entries:
Event ID: 1023
.NET Runtime version 2.0.50727.5446 - Fatal Execution Engine Error (000007FEF46B40D2) (80131506)
Event ID: 1000
Faulting application name: DSService.exe, version: 6.0.6002.18312, time stamp: 0x4e5d8cf3
Faulting module name: mscorwks.dll, version: 2.0.50727.5446, time stamp: 0x4d8cdb54
Exception code: 0xc0000005
Fault offset: 0x00000000001de8d4
Faulting process id: 0x%9
Faulting application start time: 0x%10
Faulting application path: %11
Faulting module path: %12
Report Id: %13
Updated 7/12/2022:
If you are running Visual Studio 2022, azurite.exe is the replacement for the now-deprecated AzureStorageEmulator.exe which can be found here:
C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\Extensions\Microsoft\Azure Storage Emulator\azurite.exe
NB: if you are running Professional (or another) Edition, you'll need to replace Community with Professional (or the appropriate edition name) in the path.
Updated 1/19/2015:
After doing more testing (i.e., running several builds), I've discovered that WAStorageEmulator.exe's status API is actually broken in a couple of significant ways (which may or may not have impact on how you use it).
The status reports False even when an existing process is running if the user differs between the existing running process and the user used to launch the status process. This incorrect status report will lead to a failure to launch the process that looks like this:
C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator>WAStorageEmulator.exe status
Windows Azure Storage Emulator 3.4.0.0 command line tool
IsRunning: False
BlobEndpoint: http://127.0.0.1:10000/
QueueEndpoint: http://127.0.0.1:10001/
TableEndpoint: http://127.0.0.1:10002/
C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator>WAStorageEmulator.exe start
Windows Azure Storage Emulator 3.4.0.0 command line tool
Error: Port conflict with existing application.
Additionally, the status command appears only to report the endpoints specified in WAStorageEmulator.exe.config, not those of the existing running process. I.e., if you start the emulator, then make a change to the config file, and then call status, it will report the endpoints listed in the config.
Given all of these caveats, it may, in fact, simply be better to use the original implementation as it appears to be more reliable.
I will leave both so others can choose whichever solution works for them.
Updated 1/18/2015:
I have fully rewritten this code to properly leverage WAStorageEmulator.exe's status API per #RobertKoritnik's request.
public static class AzureStorageEmulatorManager
{
public static bool IsProcessRunning()
{
bool status;
using (Process process = Process.Start(StorageEmulatorProcessFactory.Create(ProcessCommand.Status)))
{
if (process == null)
{
throw new InvalidOperationException("Unable to start process.");
}
status = GetStatus(process);
process.WaitForExit();
}
return status;
}
public static void StartStorageEmulator()
{
if (!IsProcessRunning())
{
ExecuteProcess(ProcessCommand.Start);
}
}
public static void StopStorageEmulator()
{
if (IsProcessRunning())
{
ExecuteProcess(ProcessCommand.Stop);
}
}
private static void ExecuteProcess(ProcessCommand command)
{
string error;
using (Process process = Process.Start(StorageEmulatorProcessFactory.Create(command)))
{
if (process == null)
{
throw new InvalidOperationException("Unable to start process.");
}
error = GetError(process);
process.WaitForExit();
}
if (!String.IsNullOrEmpty(error))
{
throw new InvalidOperationException(error);
}
}
private static class StorageEmulatorProcessFactory
{
public static ProcessStartInfo Create(ProcessCommand command)
{
return new ProcessStartInfo
{
FileName = #"C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator\WAStorageEmulator.exe",
Arguments = command.ToString().ToLower(),
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
}
}
private enum ProcessCommand
{
Start,
Stop,
Status
}
private static bool GetStatus(Process process)
{
string output = process.StandardOutput.ReadToEnd();
string isRunningLine = output.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).SingleOrDefault(line => line.StartsWith("IsRunning"));
if (isRunningLine == null)
{
return false;
}
return Boolean.Parse(isRunningLine.Split(':').Select(part => part.Trim()).Last());
}
private static string GetError(Process process)
{
string output = process.StandardError.ReadToEnd();
return output.Split(':').Select(part => part.Trim()).Last();
}
}
And the corresponding tests:
[TestFixture]
public class When_starting_process
{
[Test]
public void Should_return_started_status()
{
if (AzureStorageEmulatorManager.IsProcessRunning())
{
AzureStorageEmulatorManager.StopStorageEmulator();
Assert.That(AzureStorageEmulatorManager.IsProcessRunning(), Is.False);
}
AzureStorageEmulatorManager.StartStorageEmulator();
Assert.That(AzureStorageEmulatorManager.IsProcessRunning(), Is.True);
}
}
[TestFixture]
public class When_stopping_process
{
[Test]
public void Should_return_stopped_status()
{
if (!AzureStorageEmulatorManager.IsProcessRunning())
{
AzureStorageEmulatorManager.StartStorageEmulator();
Assert.That(AzureStorageEmulatorManager.IsProcessRunning(), Is.True);
}
AzureStorageEmulatorManager.StopStorageEmulator();
Assert.That(AzureStorageEmulatorManager.IsProcessRunning(), Is.False);
}
}
Original post:
I took Doug Clutter's and Smarx's code one step further and created a utility class:
The code below has been updated to work on both Windows 7 and 8 and now points at the new storage emulator path as of SDK 2.4.**
public static class AzureStorageEmulatorManager
{
private const string _windowsAzureStorageEmulatorPath = #"C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator\WAStorageEmulator.exe";
private const string _win7ProcessName = "WAStorageEmulator";
private const string _win8ProcessName = "WASTOR~1";
private static readonly ProcessStartInfo startStorageEmulator = new ProcessStartInfo
{
FileName = _windowsAzureStorageEmulatorPath,
Arguments = "start",
};
private static readonly ProcessStartInfo stopStorageEmulator = new ProcessStartInfo
{
FileName = _windowsAzureStorageEmulatorPath,
Arguments = "stop",
};
private static Process GetProcess()
{
return Process.GetProcessesByName(_win7ProcessName).FirstOrDefault() ?? Process.GetProcessesByName(_win8ProcessName).FirstOrDefault();
}
public static bool IsProcessStarted()
{
return GetProcess() != null;
}
public static void StartStorageEmulator()
{
if (!IsProcessStarted())
{
using (Process process = Process.Start(startStorageEmulator))
{
process.WaitForExit();
}
}
}
public static void StopStorageEmulator()
{
using (Process process = Process.Start(stopStorageEmulator))
{
process.WaitForExit();
}
}
}
This program worked fine for me. Give it a try, and if it works for you too, work backwards from there. (What about your app is different from this?)
using System.Diagnostics;
public class Program
{
public static void Main() {
Process.Start(#"c:\program files\windows azure sdk\v1.5\bin\csrun", "/devstore").WaitForExit();
}
}
The file name in v4.6 is "AzureStorageEmulator.exe". The full path is: "C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator\AzureStorageEmulator.exe"
For Windows Azure Storage Emulator v5.2, the following helper class can be used to start the emulator:
using System.Diagnostics;
public static class StorageEmulatorHelper {
/* Usage:
* ======
AzureStorageEmulator.exe init : Initialize the emulator database and configuration.
AzureStorageEmulator.exe start : Start the emulator.
AzureStorageEmulator.exe stop : Stop the emulator.
AzureStorageEmulator.exe status : Get current emulator status.
AzureStorageEmulator.exe clear : Delete all data in the emulator.
AzureStorageEmulator.exe help [command] : Show general or command-specific help.
*/
public enum StorageEmulatorCommand {
Init,
Start,
Stop,
Status,
Clear
}
public static int StartStorageEmulator() {
return ExecuteStorageEmulatorCommand(StorageEmulatorCommand.Start);
}
public static int StopStorageEmulator() {
return ExecuteStorageEmulatorCommand(StorageEmulatorCommand.Stop);
}
public static int ExecuteStorageEmulatorCommand(StorageEmulatorCommand command) {
var start = new ProcessStartInfo {
Arguments = command.ToString(),
FileName = #"C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator\AzureStorageEmulator.exe"
};
var exitCode = executeProcess(start);
return exitCode;
}
private static int executeProcess(ProcessStartInfo startInfo) {
int exitCode = -1;
try {
using (var proc = new Process {StartInfo = startInfo}) {
proc.Start();
proc.WaitForExit();
exitCode = proc.ExitCode;
}
}
catch {
//
}
return exitCode;
}
}
[Thanks to huha for the boilerplate code to execute a shell command.]
FYI - The 1.6 default location is C:\Program Files\Windows Azure Emulator\emulator as stated on the MSDN docs.
We are running into the same issue. We have the concept of a "smoke test" which runs between groups of tests, and which ensure the environment is in a good state before the next group starts. We have a .cmd file that kicks off the smoke tests, and it works just fine starting the devfabric emulator, but the devstore emulator only runs as long as the .cmd process runs.
Apparently the implementation of the DSServiceSQL.exe is different than DFService.exe. DFService seems to run like a windows service - kick it off, and it keeps running. DSServiceSQL dies as soon as the process that started it dies.
I uninstalled all of the Windows Azure bits:
WA SDK v1.5.20830.1814
WA Tools for Visual Studio: v1.5.40909.1602
WA AppFabric: v1.5.37
WA AppFabric: v2.0.224
Then, I downloaded and installed everything using the unified installer. Everything came back except the AppFabric v2. All the version numbers are the same. Reran my tests and still having a problem.
And then...(this is weird)...it would work every now and then. Rebooted the machine and now it works. Have shutdown and rebooted a number of times now...and it just works. (sigh)
Thanks to everyone who provided feedback and/or ideas!
The final code is:
static void StartAzureStorageEmulator()
{
ProcessStartInfo processStartInfo = new ProcessStartInfo()
{
FileName = Path.Combine(SDKDirectory, "csrun.exe"),
Arguments = "/devstore",
};
using (Process process = Process.Start(processStartInfo))
{
process.WaitForExit();
}
}
maybe caused by file not found?
try this
FileName = Path.Combine(SDKDirectory, "csrun.exe")
Here we go: Pass the string "start" to the method ExecuteWAStorageEmulator().
The NUnit.Framework is used for the Assert only.
using System.Diagnostics;
using NUnit.Framework;
private static void ExecuteWAStorageEmulator(string argument)
{
var start = new ProcessStartInfo
{
Arguments = argument,
FileName = #"c:\Program Files (x86)\Microsoft SDKs\Windows Azure\Storage Emulator\WAStorageEmulator.exe"
};
var exitCode = ExecuteProcess(start);
Assert.AreEqual(exitCode, 0, "Error {0} executing {1} {2}", exitCode, start.FileName, start.Arguments);
}
private static int ExecuteProcess(ProcessStartInfo start)
{
int exitCode;
using (var proc = new Process { StartInfo = start })
{
proc.Start();
proc.WaitForExit();
exitCode = proc.ExitCode;
}
return exitCode;
}
See also my new self-answered question
There's now a neat little NuGet package to assist with starting/stopping the Azure Storage Emulator programmatically: RimDev.Automation.StorageEmulator.
The source code is available in this GitHub repository, but you can essentially do things like this:
if(!AzureStorageEmulatorAutomation.IsEmulatorRunning())
{
AzureStorageEmulatorAutomation emulator = new AzureStorageEmulatorAutomation();
emulator.Start();
// Even clear some things
emulator.ClearBlobs();
emulator.ClearTables();
emulator.ClearQueues();
emulator.Stop();
}
It feels like the cleanest option to me.

Categories

Resources