I am using this below code to print my bill. I am getting the following error "Filesystem.Print has invalid arguments",Please Help in overcoming this error.
using Microsoft.Visualbasic;
.......................
public void PrintHeader()
{
FileSystem.Print(eInit + eCentre + "My Shop","");
FileSystem.Print("Tel:0123 456 7890","");
FileSystem.Print("Web: www.ame.com");
FileSystem.Print("sales#ame.com");
FileSystem.Print("VAT Reg No:123 4567 89" + eLeft);
PrintDashes();
}
public static void Print(
int FileNumber,
params Object[] Output
)
This is obviously a Visual Basic function. FileNumber is the handle of a file opened with FileOpen (which is a remnant of OPEN from Visual Basic 6.0 and older).
Example:
int myFileHandle = 1;
FileSystem.FileOpen(myFileHandle, "log.txt", OpenMode.Output);
FileSystem.Print(myFileHandle, "Hello", " ", "World!");
FileSystem.FileClose(myFileHandle);
You need to open a file with a specified handle first, and pass it into FileNumber.
Another better solution is to not use these API's as they are extremely outdated. Prefer the System.IO namespace.
edit:
To use the System.IO namespace instead you would open a StreamWriter:
var writer = new StreamWriter("mybill.txt");
And your PrintHeader method would take a TextWriter input (StreamWriter extends TextWriter)
public void PrintHeader(TextWriter output)
{
output.WriteLine(eInit + eCentre + "My Shop");
output.WriteLine("Tel:0123 456 7890","");
output.WriteLine("Web: www.ame.com");
output.WriteLine("sales#ame.com");
output.WriteLine("VAT Reg No:123 4567 89" + eLeft);
output.WriteLine(new string('-', 20));
}
If you're feeling adventurous you can make it async as well
public async Task PrintHeaderAsync(TextWriter output)
{
await output.WriteLineAsync(eInit + eCentre + "My Shop");
await output.WriteLineAsync("Tel:0123 456 7890","");
await output.WriteLineAsync("Web: www.ame.com");
await output.WriteLineAsync("sales#ame.com");
await output.WriteLineAsync("VAT Reg No:123 4567 89" + eLeft);
await output.WriteLineAsync(new string('-', 20));
}
FileSystem.Print method looks like this:
public static void Print(
int FileNumber,
params Object[] Output
)
So you have to pass two arguments in the Print method, but in some cases you are passing only one argument, and thus you are getting that error.
The question seems to be "how do I print this?"
The solution would be that you would use System.Drawing.Printing namespace.
I however took it as a little challenge, so I made a PrinterWriter class which you use as a normal textwriter.
The source code can be found in this gist and its usage is simple:
using(var myPrinter = new PrinterWriter())
{
myPrinter.WriteLine("Hello World!");
}
You can give parameters to the constructor if you want to write to another printer or change the font (which defaults to Consolas 10pt).
The using is important because it starts printing when Dispose() is called.
Note: it doesn't do word wrap.
Related
In terminal or cmd, you can write commands, in which there is a main command and then sub-commands, or arguments and stuff...like this:
cd Desktop\Folder
lst
Format E: /fs:FAT32
I want to create a C# console application that could execute predefined commands like this, but which could also split up main commands and sub-commands, in which some could be optional and some not. I have tried just taking all as string and then splitting it to array and creating if(s) and switch and cases, but it looks really bad and hardly manageable. I'm sure that in the OS's terminal or cmd it's build in another way. Could you help me understand the basic structure of such an application?
Here, have a look at this concept.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SharpConsole
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Welcome to SharpConsole. Type in a command.");
while (true)
{
Console.Write("$ ");
string command = Console.ReadLine();
string command_main = command.Split(new char[] { ' ' }).First();
string[] arguments = command.Split(new char[] { ' ' }).Skip(1).ToArray();
if (lCommands.ContainsKey(command_main))
{
Action<string[]> function_to_execute = null;
lCommands.TryGetValue(command_main, out function_to_execute);
function_to_execute(arguments);
}
else
Console.WriteLine("Command '" + command_main + "' not found");
}
}
private static Dictionary<string, Action<string[]>> lCommands =
new Dictionary<string, Action<string[]>>()
{
{ "help", HelpFunc },
{ "cp" , CopyFunc }
};
private static void CopyFunc(string[] obj)
{
if (obj.Length != 2) return;
Console.WriteLine("Copying " + obj[0] + " to " + obj[1]);
}
public static void HelpFunc(string[] args)
{
Console.WriteLine("===== SOME MEANINGFULL HELP ==== ");
}
}
}
The basic idea is to generalize the idea of a command. We have a Dictionary, where the key is a string (the command's name), and the value you get from the dictionary is a function of type Action<string[]>. Any function which has the signature void Function(string[]) can be used as this type. Then, you can set up this dictionary with a bunch of commands and route them to the functions you want. Each of these functions will receive an array of optional arguments. So here, the command "help" will be routed to the HelpFunc(). And the "cp" command e.g. will receive an array of filenames. The parsing of the command is always the same. We read a line, split it a space. The first string is the program's name, command_main here. If you skip the first string, you'll get an enumeration of all the other subcommands or switches you typed in. Then, a lookup in the dictionary is being done to see if there is such a command. If yes, we get the function and execute it with the arguments. If not, you should display "command not found" or something. All in all, this exercise can be minimized to looking up a function in a dictionary of possible command strings, then executing it. So a possible output is
Welcome to SharpConsole. Type in a command.
$ help
===== SOME MEANINGFULL HELP ====
$ cp file1 otherfile2
Copying file1 to otherfile2
$ python --version
Command 'python' not found
$ ...
LXSH
It's a command interpreter similar to CMD or Bash.
We've distributed it under MIT license, a shell with some functionalities in C# (.NET Core). You can contribute if you wish on
GitHub.
To solve the problem of matching a given token (part of the command line) with a builtin or a command, we use a dictionary.
However, we don't index the programs in the path for the moment. We just combine the name of the program with all the paths in the %PATH% variable.
Capture input
Expand environment variables, expand aliases
Try to match a builtin and run it if there is a match
Try to match with a program in %PATH% / $PATH
Run the program or display error
While you are unlikely to find the internal working of CMD (because it's closed source), you can find easily unix shell (bash, sh, zsh, etc..) information.
Links:
Bash Reference
Zsh Reference
TCSH Reference
Using MSDN I got the class to write a wrapper for my command line tool.
I now am facing a problem, if I execute the exe through the command line with arguments, it works perfect without any errors.
But when I try to pass the arguments from the Wrapper it crashes the program.
Wanted to know if I am passing the arguments properly and if I am wrong, could somebody point out please.
This is the LaunchEXE class from MSDN
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
namespace SPDB
{
/// <summary>
/// Class to run any external command line tool with arguments
/// </summary>
public class LaunchEXE
{
internal static string Run(string exeName, string argsLine, int timeoutSeconds)
{
StreamReader outputStream = StreamReader.Null;
string output = "";
bool success = false;
try
{
Process newProcess = new Process();
newProcess.StartInfo.FileName = exeName;
newProcess.StartInfo.Arguments = argsLine;
newProcess.StartInfo.UseShellExecute = false;
newProcess.StartInfo.CreateNoWindow = true; //The command line is supressed to keep the process in the background
newProcess.StartInfo.RedirectStandardOutput = true;
newProcess.Start();
if (0 == timeoutSeconds)
{
outputStream = newProcess.StandardOutput;
output = outputStream.ReadToEnd();
newProcess.WaitForExit();
}
else
{
success = newProcess.WaitForExit(timeoutSeconds * 1000);
if (success)
{
outputStream = newProcess.StandardOutput;
output = outputStream.ReadToEnd();
}
else
{
output = "Timed out at " + timeoutSeconds + " seconds waiting for " + exeName + " to exit.";
}
}
}
catch (Exception e)
{
throw (new Exception("An error occurred running " + exeName + ".", e));
}
finally
{
outputStream.Close();
}
return "\t" + output;
}
}
}
This is the way I am passing arguments from my main program (Form1.cs)
private void button1_Click(object sender, EventArgs e)
{
string output;
output = LaunchEXE.Run(#"C:\Program Files (x86)\MyFolder\MyConsole.exe", "/BACKUP C:\\MyBackupProfile.txt", 100);
System.Windows.Forms.MessageBox.Show(output);
}
The command line tool accepts the following command and works perfectly:
C:\Program Files (x86)\MyFolder>MyConsole.exe /BACKUP C:\MyBackupProfile.txt
I have two options for you -
1) Please try running your Visual Studio on "administrator mode".
or 2) Try to implement this instead. https://github.com/commandlineparser/commandline.
"The Command Line Parser Library offers to CLR applications a clean and concise API for manipulating command line arguments and related tasks. It allows you to display an help screen with an high degree of customization and a simple way to report syntax errors to the user. Everything that is boring and repetitive to be programmed stands up on library shoulders, letting you concentrate yourself on core logic. This library provides hassle free command line parsing with a constantly updated API since 2005."
Worked great for me.
I have a feeling it doesn't like the spaces in your path. See this post: C# How to use Directory White Spaces into process.arguements?
Is there any way to retrieve the current source filename and linenumber in C# code and print that value in the console output? Like LINE and FILE in C?
Please advise.
Many thanks
Anders Hejlsberg presented new API for that in BUILD keynote:
Print current file name, method name and line number
private static void Log(string text,
[CallerFilePath] string file = "",
[CallerMemberName] string member = "",
[CallerLineNumber] int line = 0)
{
Console.WriteLine("{0}_{1}({2}): {3}", Path.GetFileName(file), member, line, text);
}
Test:
Log(".NET rocks!");
Output:
Program.cs_Main(11): .NET rocks!
What's going on here?
You define a method with optional parameters and decorate them with special attributes. If you call method without passing actual arguments (leave defaults) - the Framework populates them for you.
This answer is outdated! See #taras' answer for more recent information.
No constant :(
What you can do is a lot uglier :
string currentFile = new System.Diagnostics.StackTrace(true).GetFrame(0).GetFileName();
int currentLine = new System.Diagnostics.StackTrace(true).GetFrame(0).GetFileLineNumber();
Works only when PDB files are available.
You can use the StackTrace object from the System.Diagnostics namespace but the information will only be available if the PDB files are there.
PDB files are generated by default for both the Debug and Release builds the only difference is that Debug is setup to generate a full debug info where as the Release build is setup to only generate a pdb (full/pdb-only).
Console.WriteLine(new StackTrace(true).GetFrame(0).GetFileName());
Console.WriteLine(new StackTrace(true).GetFrame(0).GetFileLineNumber());
There are no constants defined for that as of now.
The .NET way of doing it is using StackTrace class.
It however works only for Debug builds. So in case you use it, you can have the code using StackTrace between
#if DEBUG
//your StackTrace code here
#endif
You can read about using #if preprocessors for your DEBUG vs. RELEASE builds in the following Stackoverflow thread.
C# if/then directives for debug vs release
EDIT: Just in case you still need this debugging information in release builds, read the following answer on Stackoverflow:
Display lines number in Stack Trace for .NET assembly in Release mode
If you want some more internal detail, but you don't specifically need filename and line number, you can do something like this:
System.Diagnostics.Debug.Print(this.GetType().ToString() + " My Message");
This has an advantage over printing out the filename in that if you put this in a parent class, it will print out the child class name that is actually running the code.
If you wanted to write your own version of Debug.Assert, then here's a more complete answer:
// CC0, Public Domain
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System;
public static class Logger {
[Conditional("DEBUG")]
public static void Assert(bool condition, string msg,
[CallerFilePath] string file = "",
[CallerMemberName] string member = "",
[CallerLineNumber] int line = 0
)
{
// Debug.Assert opens a msg box and Trace only appears in
// a debugger, so implement our own.
if (!condition)
{
// Roughly follow style of C# error messages:
// > ideone.cs(14,11): error CS1585: Member modifier 'static' must precede the member type and name
Console.WriteLine($"{file}({line}): assert: in {member}: {msg}");
// Or more precisely match style with a fake error so error-parsing tools will detect it:
// Console.WriteLine($"{file}({line}): warning CS0: {msg}");
}
}
}
class Program {
static void Main(string[] args) {
Logger.Assert(1+1 == 4, "Why not!");
}
}
Try it online.
I have a TextBox that is eventually saved in a xml node. I am using the SecurityElement.Escape(string2Escape) to escape the invalid characters before saving the xml.
Problem: I tried using the IsValidText to test if i need to run the escape method, but it returns ''' and '&' as valid but then when you save the xml the system barfs because they are, in fact, not valid. It seems to only return false on '<' or '>'.
Simple solution, remove the check, but my question is why would this be the case?
The following is my failing code:
private string EscapeXML(string nodeText)
{
if (!SecurityElement.IsValidText(nodeText))
{
return SecurityElement.Escape(nodeText);
}
return nodeText;
}
Here's what I got from Reflector.
This can explain why it's behaving the way it's behaving. I don't see any method in SecurityElement that does what your are looking for but it is simple enough to implement one yourself, maybe as an extension method.
The SecurityElement constructor is apparently already doing some escaping on its own (including the "&" character), so the IsValidText seems to be only checking for the characters the constructor is not already taking care of.
As a consequence, it doesn't look safe to use the SecurityElement's IsValidText/Escape combo, unless you're using SecurityElement to build the whole xml.
I'll try to explain better with an example:
using System;
using System.Diagnostics;
using System.Security;
class MainClass
{
public static void Main (string[] args)
{
// the SecurityElement constructor escapes the & all by itself
var xmlRoot =
new SecurityElement("test","test &");
// the & is escaped without SecurityElement.Escape
Console.WriteLine (xmlRoot.ToString());
// this would throw an exception (the SecurityElement constructor
// apparently can't escape < or >'s
// var xmlRoot2 =
// new SecurityElement("test",#"test & > """);
// so this text needs to be escaped before construction
var xmlRoot3 =
new SecurityElement("test",EscapeXML(#"test & > """));
Console.WriteLine (xmlRoot3.ToString());
}
private static string EscapeXML(string nodeText)
{
return (SecurityElement.IsValidText(nodeText))?
nodeText :
SecurityElement.Escape(nodeText);
}
}
Current best practice is to use Environment.NewLine in your code to, well, start a new line. I would like to be able to use an alias or overloaded operator in my code so that it is more concise.
Instead of this:
MessageBox.Show("My first line here" + Environment.NewLine + "My second line here");
I would like to have something like this:
MessageBox.Show("My first line here" + NL + "My second line here");
How can I easily set this up one time as an IDE setting, or for a whole project/namespace?
An alias or overloaded operator is that comes to mind, but not sure if there is a good way of doing a global alias that is more concise than Environment.NewLine, and I've never done an overloaded operator before, so not familiar with the ins and outs of that.
Simple shortening method. Pop this class in one of your utility assemblies:
namespace MyCompany
{
public static class E
{
public static readonly string NL = System.Environment.NewLine;
}
}
then you can happily use it as such:
using MyCompany;
MessageBox.Show("My first line here" + E.NL + "My second line here");
Might I suggest that you use an extension method instead?
public static class StringExtensions
{
public static string NextLine(this string s, string next)
{
return s + Environment.NewLine + next;
}
public static string NextLine(this string s)
{
// just add a new line with no text
return s + Environment.NewLine;
}
}
Usage:
var lines = "My first line here".NextLine("My second line here.")
.NextLine("third line").NextLine();
Of course, you can call it NL if you wish -- might not be clear, though.
use StringBuilder.AppendLine() in cases with few Environment.NewLine:
var sb = new StringBuilder();
sb.AppendLine("My first line here");
sb.AppendLine("My second line here");
MessageBox.Show(sb.ToString());
Write a class to provide the value of Environment.NewLine as a member, as Jesse C. Slicer has already suggested:
namespace MyNamespace
{
public static class Env
{
public static readonly string NL = Environment.NewLine;
}
}
Then write the following using directive:
using E = MyNamespace.Env;
You can add this using directive to your default new class template and any other templates you use (new struct, new interface, etc.).
Here's where the new class template is on my machine, as an example to get you started:
C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\ItemTemplates\CSharp\Code\1033
Once this is done, you should be able to write E.NL in place of Environment.NewLine everywhere you want.
using static System.Environment;
Then you can just use it as NewLine
Alias won't work - you can alias a namespace or a type, but not a property of a type. So this works:
using NL = System.Environment;
class Program
{
static void Main(string[] args)
{
var s = NL.NewLine;
}
}
But this doesn't:
// returns: The type name 'NewLine' does not
// exist in the type 'System.Environment' error
using NL = System.Environment.NewLine;
Overloaded operator is an interesting idea, but then you'll have to use something other than a String. Usually people create a struct which can take a base string value and then overload the operators. Not worth the pain if all you want to do is replace the Environment.NewLine. You're better off to use a static extension as suggested by others.
Another alternative (if you're dead set on using NL) is to descend all the classes in your framework off of a common parent class which can have the following property:
public class BaseParentClass
{
public string NL
{
get { return System.Environment.NewLine; }
}
}
Then in the code for all the descendant classes, your code will look simply like:
public class ChildOfBaseParent
{
public void Show_A_Message()
{
MessageBox.Show("My first line here" + NL + "My second line here");
}
}
Of course if your classes do not descend off of a common parent, you will have to refactor the code base for this piece of convenience. You will need to create a parallel System.Windows.Forms.Form parent for winform classes to have this same behavior.
But definitely worth the pain if you have a lot of string concatenations involving NL...
Adding to #abatishchev response you can do nice things with the StringBuilder Class.
StringBuilder builder = new StringBuilder();
builder.Append("List:");
builder.AppendLine();
builder.Append("1. Boat")
builder.Append("2. Car").AppendLine();
builder.Replace("Boat", "Jet");