How to create a command line application - c#

With VisualStudio it is easy to create application types for Console, Forms, etc, but I see no option for a command line application. I intend to install the small program below as a simple .exe in c:\windows\system32. If I open a command terminal and CD to the bin\debug dir of the VS project, I can type DateTime and get nice output. However, if I copy the DateTime.exe to c:\windows\system32 and open another command terminal, the command DateTime gives an error saying that the application could not be started, because of .Net Shim errors.
Should I do something different to create a commandline application rather than a Console app?
Should I install more files from the bin\debug directory in c:\windows\system32 ?
using System;
namespace DateTime
{
class Program
{
static void Main()
{
Console.Write(System.DateTime.Now.ToString("o"));
}
}
}
NB: reason for the above command line app is that the system commands Date/T and Time/T do not provide seconds output. My app shows e.g. 2015-07-13T10:58:29.7329261+02:00 (, and you can get other formats with an argument, see previous edits of this question)

Console project is a command line project.
You can use the args [] to track command line parameters.
Your executable may have dependencies: You can use something like obfuscator or another tool to package them into the .exe so you don't need external files.
Alternatively, install your project into its own folder, and modify the PATH variable to include the path to the directory - this will let you run your .exe from any folder, much like you can run 'dir' in any folder.
I'm not clear what your DateTime problem is, but you can use the .ToString() overload to adjust the formatting, and .Parse() to interpret the date from a variety of formats.
var dt = new DateTime();
dt.ToString("dd/MM/yyyy hh:mm:ss");

As advised by SLC, I tried to write this app in C++. It turns out that VisualStudio offers a choice for C++ Console apps: with CLR, or as Win32, where CLR stands for the dot-Net Framework. Indeed the Win32 project builds as a simple .EXE file that can be installed in any directory mentioned in %PATH%, e.g., C:\Windows\System32\ .
VisualStudio does not offer this choice for C# Console apps.
Unfortunately, C++ is a step backwards from C#: it is more complex. It should run faster for certain types of apps, but cost more time to develop. Compare this C++ code with the C# source above:
#include "stdafx.h"
#include <iostream>
#include <ctime>
int main()
{
// get current time
time_t time_now = time(0);
// convert to local time struct
struct tm tstruct;
localtime_s(&tstruct, &time_now);
// format to string
char str_time[80];
strftime(str_time, sizeof(str_time), "%Y-%m-%d %H:%M:%S", &tstruct);
// to stdout
std::cout << str_time << std::endl;
return 0;
}
As said, the above C++ code, as a Win32 Console project, will run as a single .EXE file from a directory in %PATH%.
For completeness, here is a nicer source code in C++, as a CLR Console project, i.e., with the .Net Framework, that will code comparably fast as C#, but will also NOT run as a single .EXE file from a directory in %PATH%.
#include "stdafx.h"
using namespace System;
int main()
{
Console::WriteLine(DateTime::Now);
Console::WriteLine(DateTime::Now.ToString(L"o"));
Console::WriteLine(DateTime::Now.ToString(L"yyyy-MM-dd HH:mm:ss"));
return 0;
}
Output is, e.g.:
14-7-2015 16:23:27
2015-07-14T16:23:27.6978497+02:00
2015-07-14 16:23:27
The above apps are also tested from PowerShell, but then the CLR/.Net based apps can also not be run from %PATH%.

There is a simple NuGet package that helps you to create your own command-line application without handling many things line parsing the arguments and mapping the types etc.,
https://www.nuget.org/packages/CommandLineTool/

Related

Accessing Published Version Number In .Net6 Windows Forms App [duplicate]

I have a windows forms application that is deployed to two different locations.
Intranet - ClickOnce
Internet - Installed on a citrix farm through Windows installer
I display ClickOnce version number for click-once deployed versionApplicationDeployment.IsNetworkDeployed.
if (ApplicationDeployment.IsNetworkDeployed)
return ApplicationDeployment.CurrentDeployment.CurrentVersion;
But for the non-click application, I am not sure how to retrieve clickonce version unless I hardcode the version number in assembly info.
Is there an automatic way of retrieve ClickOnce version number for non-clickonce deployed version?
Add an assembly reference to System.Deployment to your project.
Import the namespace in your class file:
VB.NET:
Imports System.Deployment.Application
C#:
using System.Deployment.Application;
Retrieve the ClickOnce version from the CurrentVersion property.
You can obtain the current version from the ApplicationDeployment.CurrentDeployment.CurrentVersion property. This returns a System.Version object.
Note (from MSDN):
CurrentVersion will differ from UpdatedVersion if a new update has
been installed but you have not yet called Restart. If the deployment
manifest is configured to perform automatic updates, you can compare
these two values to determine if you should restart the application.
NOTE: The CurrentDeployment static property is only valid when the application has been deployed with ClickOnce. Therefore before you access this property, you should check the ApplicationDeployment.IsNetworkDeployed property first. It will always return a false in the debug environment.
VB.NET:
Dim myVersion as Version
If ApplicationDeployment.IsNetworkDeployed Then
myVersion = ApplicationDeployment.CurrentDeployment.CurrentVersion
End If
C#:
Version myVersion;
if (ApplicationDeployment.IsNetworkDeployed)
myVersion = ApplicationDeployment.CurrentDeployment.CurrentVersion;
Use the Version object:
From here on you can use the version information in a label, say on an "About" form, in this way:
VB.NET:
versionLabel.Text = String.Concat("ClickOnce published Version: v", myVersion)
C#:
versionLabel.Text = string.Concat("ClickOnce published Version: v", myVersion);
(Version objects are formatted as a four-part number (major.minor.build.revision).)
No I do not believe that there is a way. I believe the ClickOnce information comes from the manifest which will only be available in a ClickOnce deployment. I think that hard coding the version number is your best option.
I would simply make the assembly version of the main assembly the same as the CLickOnce version every time you put out a new version. Then when it runs as a non-clickonce application, just use Reflection to pick up the assembly version.
Try thread verification:
if (ApplicationDeployment.IsNetworkDeployed)
{
if (ApplicationDeployment.CurrentDeployment.CurrentVersion != ApplicationDeployment.CurrentDeployment.UpdatedVersion)
{
Application.ExitThread();
Application.Restart();
}
}
not that it matters three years later, but I ended up just parsing the manifest file with xml reader.
To expand on RobinDotNet's solution:
Protip: You can automatically run a program or script to do this for you from inside the .csproj file MSBuild configuration every time you build. I did this for one Web application that I am currently maintaining, executing a Cygwin bash shell script to do some version control h4x to calculate a version number from Git history, then pre-process the assembly information source file compiled into the build output.
A similar thing could be done to parse the ClickOnce version number out of the project file i.e., Project.PropertyGroup.ApplicationRevision and Project.PropertyGroup.ApplicationVersion (albeit I don't know what the version string means, but you can just guess until it breaks and fix it then) and insert that version information into the assembly information.
I don't know when the ClickOnce version is bumped, but probably after the build process so you may need to tinker with this solution to get the new number compiled in. I guess there's always /*h4x*/ +1.
I used Cygwin because *nix scripting is so much better than Windows and interpreted code saves you the trouble of building your pre-build program before building, but you could write the program using whatever technology you wanted (including C#/.NET). The command line for the pre-processor goes inside the PreBuildEvent:
<PropertyGroup>
<PreBuildEvent>
$(CYGWIN_ROOT)bin\bash.exe --login -c refresh-version
</PreBuildEvent>
</PropertyGroup>
As you'd imagine, this happens before the build stage so you can effectively pre-process your source code just before compiling it. I didn't want to be automatically editing the Properties\AssemblyInfo.cs file so to play it safe what I did was create a Properties\VersionInfo.base.cs file that contained a text template of a class with version information and was marked as BuildAction=None in the project settings so that it wasn't compiled with the project:
using System.Reflection;
using EngiCan.Common.Properties;
[assembly: AssemblyVersion("0.$REVNUM_DIV(100)$.$REVNUM_MOD(100)$.$DIRTY$")]
[assembly: AssemblyRevisionIdentifier("$REVID$")]
(A very dirty, poor-man's placeholder syntax resembling Windows' environment variables with some additional h4x thrown in was used for simplicity's/complexity's sake)
AssemblyRevisionIdentifierAttribute was a custom attribute that I created to hold the Git SHA1 since it is much more meaningful to developers than a.b.c.d.
My refresh-version program would then copy that file to Properties\VersionInfo.cs, and then do the substitution of the version information that it already calculated/parsed (I used sed(1) for the substitution, which was another benefit to using Cygwin). Properties\VersionInfo.cs was compiled into the program. That file can start out empty and you should ignore it by your version control system because it is automatically changing and the information to generate it is already stored elsewhere.
Hard code, or... Keep track on your versions (File, Assembly, Deploy) in a database. Make a call to the database with your Assembly and get the Deploy version.
This assumes that you are incrementing your versions in a logical way such that each version type has a relationship. It's a lot of work for such a minor problem. I'd personally go with Jared's solution; although I hate hard coding anything.
Using a build component, you could read the click-once version from the project file and write it automatically to the assembly info so both of them are in sync.
Solution for .NET (Core) 7 and higher
On .net Core, you can read the version number from the environment variable ClickOnce_CurrentVersion.
string versionString = Environment.GetEnvironmentVariable("ClickOnce_CurrentVersion") ?? "0.0.0.0";
Version version= Version.Parse(versionString);
MessageBox.Show(version.ToString());
See documentation

Generate a CIL executable not EXE then execute it

I have a c# project that generates an EXE file. Now, I'm in a "secure" corporate environment, where I can compile my project, but I cannot execute the EXE file.
As a Java programmer, I'm wondering if there is not a way to compile the c# project into something that would not be an EXE file, but a CIL file and then execute the CIL file by something that corresponds to java.exe in the dotnet world.
EDIT in response to comments:
I can run exe files that have been installed by a package manager
Yes, I know the corporate policy is stupid.
Well, this should be pretty easy.
.NET executables are simply DLLs like any other - the main difference being the executable format itself, and the fact that EXE files have an entry point, while DLLs don't.
It also means that you can load the EXE into memory exactly the same way as you would with a DLL:
Assembly.LoadFrom("SomeExe.exe");
You're already half way there - now we just need to find and execute the entry point. And unsurprisingly, this is also pretty trivial:
var assembly = Assembly.LoadFrom("SomeExe.exe");
assembly.EntryPoint.Invoke(null, null);
For most applications, this should work perfectly fine; for some, you'll have to make sure the thread you're using to invoke the entry point has STAThread or MTAThread respectively (Thread.TrySetThreadApartment if you're starting a new thread).
It might need tweaking for some applications, but it shouldn't be too hard to fix.
So you can just make some bootstrap application ("interpreter") that only really contains these two lines of code. If you can't get even that approved, and you really need something as an "official package", try some .NET application that allows you to execute arbitrary code - for example, LINQPad, or PowerShell.
EDIT:
This does have limitations, of course, and it does introduce some extra setup work:
The bootstrapper has to target the same or higher version of .NET Framework. .NET Portable might be particularly tricky, but I assume you have that well under control. It also has to have the same bitness (if specified explicitly).
You need to run the debugging through the bootstrapper. That actually isn't all too hard - just go to project properties, debug and select "Start external program".
The bootstrapper has to run under full trust conditions - it's necessary for reflection to work. On most systems, this simply means you have to have the exe as a local file (e.g. not from a network share). Tools like LINQPad will run under full trust by default.
The application must not depend on Assembly.GetEntryAssembly. This isn't used all that often, so it shouldn't be a problem. Quite a few similar issues should also be fine since you build the application you're trying to run yourself.

DllNotFoundException with DllImport in Mono on Mac

I'm trying to use DLLImport in my Mono Mac project in order to use my own .dylib but I get the DllNotFoundException. I'm guessing it has something to do with my .dylib since I'm able to do this with existing .dylib files such as the libmojoshader.dylib.
Here's how I use DLLImport
[DllImport("libtestDylib.dylib")]
static extern int libsum(int a, int b);
I then call the libsum function in order to see if it works.
I've found that running the app through the terminal with the MONO_LOG_LEVEL="debug" MONO_LOG_MASK="dll" mono myGame.exe command is a great way to debug issues like this, however I can't get my app .exe to run. I've tried using both the .exe in build folder and the one in the .app/contents/MonoBundle, I've also tried running file in .app/contents/MacOs as this is referenced in some places I've found while researching.
The last file throws a "File does not contain a valid CIL image." and the two others "No Info.plist file in application bundle or no NSPrincipalClass in the Info.plist file".
So, I would guess that the first step is to manage to run the app through the terminal in order to get proper debug information as for why my .dylib can't be found.
The .dylib I made is an empty BSD C lib made in XNA4.
Edit
I can't even seem to get the existing dylibs to work now.
I found the problem by making a new Mono Mac project with a single c# file which I then compiled through the terminal and ran it with the debug command. With the terminal feedback found out where the program was searching for the .dylib, and that the lib I made was built with the wrong architecture which was simply solved by building for 32-bit systems.

Start C# program from command line on Linux

What command should I use to start this C# program from the command line in Linux? I've already compiled it (using Monodevelop), but I don't know how to start it from the command line.
using System;
class ExampleClass
{
static void Main()
{
Console.WriteLine("Hello, world!");
}
}
The command line you need to start a C# (or any other .NET) program on Linux depends on how you have your Linux system configured.
The standard answer is to run the mono program, and pass the name of your executable assembly as a parameter. The name of your executable assembly is typically the same as the name of your project file, though you can easily change it; just look for a file ending in .exe after you're done compiling. It will be found in a folder named bin\Debug, or bin\Release or something similar (it depends on how you have your project build settings set up). So, if you built a program called hello.exe you would go into your project folder and run:
~/projects/hello $ mono bin\Debug\hello.exe
The reason you need to run the mono program is because Linux does not know, by default, how to run the .NET runtime automatically. When you install .NET on Windows, it actually changes the part of the OS that loads programs, so Windows just automatically recognizes a .NET program and loads the runtime. On Linux, you need to do that yourself, by running the mono program first.
If you run a lot of managed code on Linux, you can also configure the Linux kernel to work the same way that Windows does. Linux has support for "miscellaneous binary formats" that allows you to tell Linux how to execute binaries that are not native Linux format. This is somewhat advanced - it likely requires you to build a custom kernel, though I would not be surprised if your Linux distribution had a better way to do it. More information on this process can be found here:
http://www.kernel.org/doc/Documentation/mono.txt

How do you use the standard library in IronPython?

I'll prefix this question with: No, Setting IRONPYTHONPATH is not the answer.
Anyway...
I was planning on using IronPython as a replacement for Powershell for a project, but I've been stumped before I've even started.
The very first thing I tried to do was use os.path, resulting in:
Traceback (most recent call last):
File "<string>", line 1, in <module>
ImportError: No module named os
After messing around I finally discovered I could use the standard library by adding it manually to the path:
import sys
sys.path.append(r"C:\Program Files\IronPython 2.7\Lib")
import os
However, this is a daft idea. Hard coding the path to the python library inside my scripts is a 100% guaranteed way of making them not work at some point.
I discovered this almost immediately when I tried to use the script on a windows 7 machine and the path was slightly different ('Program Files (x86)').
So, a couple of questions here:
1) Why is it so hard to use the standard library? At the very least I would have thought the interactive prompt in VS and basic ipy.exe would have this.
2) How can I determine the directory that iron python is installed in regardless of the system I'm using? (IronPython installer setting a var perhaps?)
Just a note here; yes, I have seen some other posts saying "set your IRONPYTHONPATH". This in unhelpful. If I have a blank machine that means I have to:
1) Install IronPython
2) Run some crazy powershell script to search out where-ever-the-heck the standard library was installed and set a global IRONPYTHONPATH variable to it.
3) Run python scripts
I'm looking for a better way.
--
Edit:
The fact I'm using this to do powershell like things is basically irrelevant, but I'm trying to achieve something like:
import clr
from System.Management.Automation import RunspaceInvoke
import os
scriptRoot = os.getcwd()
runSpace = RunspaceInvoke()
cmdPath64 = os.join(scriptRoot, "..\java\...")
cmdPath32 = os.join(scriptRoot, "..\java\...")
proc = runSpace.Invoke("Get-WmiObject Win32_Processor ... ")
if proc.AddressWidth == 32:
runSpace.Invoke(cmdPath32)
else:
runSpace.Invoke(cmdPath64)
I find that for ensuring that everything works for non-developer third parties, it's usually better to use pyc.py to create DLL's and and executable. I routinely create a DLL of the python standard modules and reference that in code. See my previous answer at this question IronPython: EXE compiled using pyc.py cannot import module "os"
It's a bit workaroundish but, given that the LIB directory of ironpython is installed under the x86 program files folder in 64bit systems and on the usual program files path on 32bit systems, you could do in this way:
import sys
import System
if System.IntPtr.Size * 8 == 32: # detect if we are running on 32bit process
sys.path.append(System.Environment.GetEnvironmentVariable("ProgramFiles") + "\IronPython 2.7\Lib")
else:
sys.path.append(System.Environment.GetEnvironmentVariable("ProgramFiles(x86)") + "\IronPython 2.7\Lib")
import os # it works !!
Here we use %ProgramFiles% and %ProgramFiles(x86)% to determine the path where IronPython is installed.
Quoting wikipedia about %ProgramFiles% variable (link):
%ProgramFiles%
This variable points to Program Files directory, which stores all the
installed program of Windows and others. The default on
English-language systems is C:\Program Files. In 64-bit editions of
Windows (XP, 2003, Vista), there are also %ProgramFiles(x86)% which
defaults to C:\Program Files (x86) and %ProgramW6432% which defaults
to C:\Program Files. The %ProgramFiles% itself depends on whether the
process requesting the environment variable is itself 32-bit or 64-bit
(this is caused by Windows-on-Windows 64-bit redirection).
This is very odd, because if you run the the IronPython installer, and then run C:\Program Files\IronPython 2.7\ipy.exe or C:\Program Files (x86)\IronPython 2.7\ipy.exe, you shouldn't need to do anything to have the stdlib available.
My guess is that you have more than one IronPython and you're running the wrong one, but only because I can't think of another reason this would happen. It's supposed to Just Work.

Categories

Resources