Setting default debug commandline arguments by code? - c#

There is a way to set the default debug commandline arguments or the default application arguments without setting the arguments in the Debug tab of the project settings?
I'll mean if I can do something like this:
Module Main
#If DEBUG Then
' Debug Commandline arguments for my application:
My.Application.CommandLineArgs = "-Sleep 5 -Interval 50 -Key CTRL+C"
#End If
...Sub main()
GetArguments() ' A function wich gets the arguemnts that I've set.
...etc...
End module

You can create a class that will abstract your other code from command line. For debug compilation it will return fixed string, otherwise it will return real Enviroment.CommandLine.
public static class CommandLineHelper
{
public static string GetCommandLine()
{
#if DEBUG
return "my command line string";
#else
return Enviroment.CommandLine;
#endif
}
}

Related

How to set variables for `dotnet new`?

Standard template for command
dotnet new console
contains #if for the preprocessor:
#if (csharpFeature_TopLevelProgram)
// See https://aka.ms/new-console-template for more information
#endif
#if (!csharpFeature_ImplicitUsings)
using System;
#endif
#if (csharpFeature_TopLevelProgram)
Console.WriteLine("Hello, World!");
#else
namespace Company.ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
}
#endif
What command line switches should I specify to dotnet new so that the variable "csharpFeature_TopLevelProgram" is not defined and so that when I execute dotnet new console the file is generated not for Net6 but without TopLevelProgram as before in the good old Net5?
If you use the -h command line option, it tells you how to use the template and that you can specify the --use-program-main parameter:
For example:
dotnet new console --use-program-main true
Note: You may need to update to a newer version of .NET 6 for this command line option to exist. This was tested with v6.0.401

Initializing base class member variables in the body of derived class's constructor

I have a C++ code which I need to rewrite to C# and looks like this:
class dppServerError: public dppBaseError
{
public :
dppServerError(DWORD ActionCode, const TCHAR* Desciption)
#ifdef POSTER_VER
: dppBaseError(Desciption)
#else
: dppBaseError(TEXT("Server text response: \"%s\""), Desciption)
#endif
, m_AC(ActionCode), m_ErrorCode(dppERR_SERVER)
{
};
Problem is I am not using #defines in my C# code and instead using public const Enums. Now, how can I duplicate above code in C#? the #ifdefs part?
Can't I normally initialize member variables of base class in the body of the constructor of derived class? (without : syntax). Then I could do (in C#):
dppServerError(uint ActionCode, string Desciption)
{
// Initialize base class member
if(Globals.ConfigEnum == POSTER_VER)
dppBaseError = Desciption; // Can I initialize this base class ivar like this? without : syntax?
else
dppBaseError = "Smth else" + Desciption;
// These are just ivars from This class
m_AC = ActionCode;
m_ErrorCode = dppERR_SERVER;
};
PS. Someone told me this about #defines in C#
"Be aware though: there is no guarantee that the conditional
compilation symbol is the same for all projects in your solution. This
will hinder reuse of your DLLs by other solutions that want different
conditional compilation symbols."
And I decided to move to enums because I didn't really get what this meant. I am a bit new to .NET.
To get the same c++ behaviour in c#, use this:
#if POSTER_VER
dppBaseError = Desciption;
#else
dppBaseError = "Smth else" + Desciption;
#endif
or also:
dppServerError(uint ActionCode, string Desciption)
#if POSTER_VER
:base(Desciption)
#else
:base("Smth else" + Desciption)
#endif
Use a #define POSTER_VER directive, or better, define the symbol in project properties -> build -> Conditional compilation symbols.
Usually a source file is included only in one project (unless you use "add as link " in visual studio to add same file to two or more projects), so the remarks "be aware" does not apply. if it does, use the same care you would use for c++ code.
In you c# code , the variable Global.ConfigEnum is evaulated at runtime, in my c# code, as in your c++, the symbol POSTER_VER is checked at complile time, resulting in different compiled binary files.
see #if, #define and ProjectProperties on MSDN
If dppBaseError is a field, you can initialize it as you have shown in your code.
If it's a base class constructor, you could do this:
dppServerError(uint ActionCode, string Desciption)
: base( (Globals.ConfigEnum == POSTER_VER) ? Desciption : "Smth else" + Desciption)
{
...

Using Pre-Compiler Directives in C# to toggle Debug Functionality

I am attempting to use Pre-compiler directives to toggle certain features in my application. I am using Pre-compiler directives as opposed to const static variables because these features will not occur in the release version of the application.
Is it true that C# does not allow for all C Pre-compiler commands, ie, #if X > Y & etc.? My below code is throwing compiler errors. Is it possible to use Pre-compiler directives to toggle functionality in my application?
My solution is a very 'C++/C' way of achieving this functionality. What is the C# way of achieving this functionality?
#define DEBUG 1 // Not allowed to assign values to constants?
#define USE_ALTERNATE_METHOD 0
public class MyApplication
{
public MyApplication()
{
#if DBEUG > 0 // Not allowed these kinds of directives?
RegressionTests.Run();
#endif // DEBUG > 0
}
public void myMethod
{
#if USE_ALTERNATE_METHOD > 0
// Do alternate stuff
#else
// Do regular stuff
#endif // USE_ALTERNATE_METHOD > 0
}
}
Specifying just #if DEBUG does the work.
You cannot use pre-processor definitives like #define DEBUG 1 .
However you can just specify #define DEBUG or #define CustomDefinition and use it with the Conditional attribute.
Eg,
You can just do this:
#if DEBUG
Console.WriteLine("This will work in DEBUG mode alone");
#endif
Or you can specify conditional-attributes on top of the method that you wanna execute only in the debug mode.
Eg,
[Conditional("DEBUG")]
void ExecuteOnlyInDebugMode()
{
// do stuff you wanna do.
}
For your example it has to be like this:
#define DEBUG
#define USE_ALTERNATE_METHOD
public class MyApplication
{
public MyApplication()
{
#if DEBUG
RegressionTests.Run();
#endif
}
public void myMethod
{
#if USE_ALTERNATE_METHOD
// Do alternate stuff
//do not execute the following. just return.
#endif
// Do regular stuff
}
}
You can find more info here . Beautifully explained.
Also, read more that Conditional attribute, here.

C# Preprocessor for 32BitProcess running on 64BitOperatingSystem

How do find 32BitProcess running on 64BitOperatingSystem using C# Preprocessor directivies.
For More info, i need to declare the dll name(based on the bit) to access the extern function. I need the following code using Preprocessor way.
public String WABDll;
if (64Bit)
{
WABDll = "Win-64.dll";
}
else if(32Bit Process on 64BitOS)
{
WABDll = "Win-32on64.dll";
}
else if(32Bit)
{
WABDll = "Win-32.dll";
}
i tried the following way
#if _64BIT
public const String WABDll = "Win-64.dll";
#elif _32BIT
public const String WABDll = "Win-32on64.dll";
#else
public const String WABDll = "Win-32.dll";
#endif
Any Suggestions.
Don't do this with preprocessor directives; determine the environment at runtime using the Environment class. The Is64BitOperatingSystem and Is64BitProcess properties should give you the information you need.
You can't solve this:
else if(32Bit Process on 64BitOS)
{
WABDll = "Win-32on64.dll";
}
compile time, since compiler does not know in advance where the program will run.
I can suggest you creating more solution "paltform", declaring some custom compiler flag and using them accordingly. Of course you need to know deploy time which executable must run on which platform.

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

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).

Categories

Resources