C#/.NET console applications that behave like normal Unix tools - c#

This question is regarding designing console applications in .NET that behave like normal Unix tools. The basic fundamental of Unix tools is that they can be chained together with 1 tool being able to take input from any compatible stream and giving output to any compatible stream.
If I'm writing console applications in .NET for Windows, what are the general things I need to follow for my tools to be of the same type?

"Do only one thing" is definitely one, but there are more:
Do only one thing and do it well
Output nothing on success (other than the result, of course)
Use stdin for the input, stdout for the output, and stderr for errors
Use non-zero exit codes to communicate failure
With this in mind, here's what is, in my opinion, a more "unixy" "to-uppercase" program in C#:
using System;
class Program
{
static int Main(string[] args)
{
try
{
var buf = new char[4096];
while (true)
{
int read = Console.In.Read(buf, 0, buf.Length);
if (read == 0)
break;
for (int i = 0; i < read; i++)
buf[i] = char.ToUpper(buf[i]);
Console.Out.Write(buf, 0, read);
}
return 0;
}
catch (Exception e)
{
Console.Error.WriteLine("ERROR: " + e.Message);
return 1;
}
}
}
Like a typical unixy program, you can run it without arguments and then it will be interactive, allowing you to type input manually on the console, terminated with Ctrl+Z, printing output whenever it receives a chunk of your input. Or you could pass it a file to process: uppercase.exe <input.txt and it will print the output to the console. Or you could redirect the output to a file too. Or you could pipe the input into it. Etc.

The main principle behind *nix tools is do one thing, and do it well.
Let's say I set out to create a *nix style tool that converted the input to uppercase. It's a trivial example, but that allows me to post the whole program here.
Here's the source code:
using System;
using System.Diagnostics.Contracts;
namespace Upperc {
class Program {
static void Main(string[] args) {
var input = Console.ReadLine();
Contract.Assert(input != null);
Console.WriteLine(input.ToUpperInvariant());
}
}
}
I took advantage of the fact that Console methods handle input and output and the standard streams. Example usage is:
> type example.txt | Upperc.exe > uppercased.txt
The input file is a plain text file:
example text file before processing
and the output file:
EXAMPLE TEXT FILE BEFORE PROCESSING

Related

Convert from console to string for return [duplicate]

What I really want to do is this
static string Main(string[] args)
but that doesn't work, your only options are void and int. So, What are some different ways to return the string that I need to return to the calling application?
Background
I need to write a console app that is specifically designed to be called from another application
Process.Start("MyCode.exe -Option 12aaa1234");
How can this calling program receive a string returned from that executable?
Research
From what I can tell, at this point in time my only option is to have the calling application attach a listening stream to the Standard Output stream of the process before starting it, and send the "return" using Console.Out.Write from inside my executable. Is this in fact the ONLY way to do this, or is there something different/better I can use?
Is this in fact the ONLY way to do this, or is there something different/better I can use?
This isn't the only way to do this, but it is the most common.
The other options would involve some form of interprocess communication, which is likely going to be significantly more development effort for a single string.
Note that, if the calling application is a .NET application, and you have control over both applications, it might make more sense to just write a class library instead of a console application. This would allow you to keep the code completely separate, but have the executable "call into" your library to get the string data.
Idea 1:
Using MyCode.exe, create an encrypted text file, which is saved in a specified path, which can then be decrypted in the current app and read.
In the app: "MyCode.exe", add this code:
public void ReturnToOther()
{
string ToReturn = "MyString";
System.IO.File.WriteAllText("Path", Encrypt(ToReturn));
}
public String Encrypt(string ToEncrypt)
{
string Encrypted = null
char[] Array = ToEncrypt.ToCharArray();
for (int i = 0; i < Array.Length; i++)
{
Encrypted += Convert.ToString(Convert.ToChar(Convert.ToInt32(Array[i]) + 15));
}
return Encrypted;
}
In the app you are making now:
public void GetString()
{
string STR = Decrypt(System.IO.File.ReadAllText("Path"));
Console.WriteLine("The string is: {0}", STR);
}
// If you want to keep this running before the file exists, use this:
/*
public void GetString()
{
for(int i = 0; i > -1; ++i)
{
if(System.IO.File.Exists("Path"))
{
string STR = Decrypt(System.IO.File.ReadAllText("Path"));
Console.WriteLine("The string is: {0}", STR);
break;
}
else
{
//Do something if you want
}
}
} */
public String Decrypt(string ToDecrypt)
{
string Decrypted = null
char[] Array = ToDecrypt.ToCharArray();
for (int i = 0; i < Array.Length; i++)
{
Decrypted += Convert.ToString(Convert.ToChar(Convert.ToInt32(Array[i]) - 15));
}
return Decrypted;
}
Idea 2:
Use TCP to upload the string to a port, e.g. LocalHost (127.0.0.1), and then receive the string on the app you are developing, using a TCP Listener
An article on TCP - http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.aspx
Hope this helps :)
EDIT:
Have a look at Sockets too: http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.aspx

Why does the console close after my last input?

My program allows the user to put in 20 prices and to display the average of those values. Why does the console close after I enter my last input? Below is the code I'm running:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace machineproblem4
{
class Program
{
static void Main(string[] args)
{
int sum = 0;
double average = 0;
Console.WriteLine("\t\t\t INPUT PRICES \n");
int[] price = new int[20];
Console.WriteLine("\t\t\t Please enter 20 prices \n");
for (int ctr = 0; ctr < 20; ctr++)
{
Console.Write("Enter price {0} : ", ctr + 1);
price[ctr] = Convert.ToInt32(Console.ReadLine());
}
// [...calculate sum...]
//average
Console.WriteLine("\n----------------------------");
Console.WriteLine("||average of the prices||");
average = sum / 20;
Console.WriteLine("average of the prices: {0}", average);
//more code that outputs statistics about the inputs
//exit
//Edit: This is what fixed my problem
Console.WriteLine("press any key to exit ..");
Console.ReadKey();
}
}
}
use Console.Readline();
Read(), ReadLine() and ReadKey() are basically static methods, and they comes under the Console class. That's why we use these methods like:
Console.Read():-- method accept the String and return the integer.
Console.ReadLine():--method accept the String and return string .
Console.ReadKey():--method accept the Character and also return Character.
That's why we mostly use the Console.ReadKey() method, for come back to source code from output window .
Because when we only press the character we directly come on source code. If you will use the Console.Read() and Console.ReadLine method then
you need to press Enter, come back to the source code rather then any character.
You can place a Console.Read() at the last statement. You can also place a breakpoint at your last statement
Generally, it is not a good idea to wait for user input from a console application. This is okay for debugging, but not definitely for release.
So, first find out if your application is in debug or release config using
private static bool IsDebug()
{
object[] customAttributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(DebuggableAttribute), false);
if ((customAttributes != null) && (customAttributes.Length == 1))
{
DebuggableAttribute attribute = customAttributes[0] as DebuggableAttribute;
return (attribute.IsJITOptimizerDisabled && attribute.IsJITTrackingEnabled);
}
return false;
}
Then use,
if (IsDebug())
Console.Readline();
This eliminates the need to edit the code for different build configurations. Alternative is to put a breakpoint and debug the console app, as suggested by #Erwin
Put:
Console.Readline();
at the end of your main function, so it waits until you press enter before it closes.
None of the previous answers actually directly answer the question of why this is happening. The reason why the console is closing after your last input is that the rest of the code runs very quickly and when it reaches the end of your program, the console closes. This is correct behavior and should be expected when running a console application. As the other answers have stated, you can work around this by requiring a final input before closing the console, but that is all it is, a work around.
If you were to output to a text file rather than just the console, you would see that all of the output is generated as you would expect. The console output and close is just too fast for you to see it without some sort of pause in the code.
Additionally, a solution that has not been mentioned yet is to run the project from Visual Studio without debugging, which will automatically output "Press any key to continue..." when it finishes processing before closing the console. That way you can see what it is outputting without extraneous code that you wouldn't want to have in production code.

C# console application design like htop

I want to build console application with similar interface like htop's one (fixed console design). Here is a link to htop console design: http://upload.wikimedia.org/wikipedia/commons/b/b1/Htop.png. I wanted to ask how can I build application like this as I only know C#'s Console.Write() method. I am writing simple program that is starting up applications via Process.Start() and then I am monitoring for example their RAM usage via Process.WorkingSet64 and outputing it via simple Console.WriteLine() each line to console. But how could I design C# console application like htop so it has fixed design that will be for example refreshing every 1 second. By fixed designed I mean that I it will be fixed position on the console where I will print out process names, ram usage, application name, etc. Here is my code of the program:
class Program
{
static void Main(string[] args)
{
string[] myApps = { "notepad.exe", "calc.exe", "explorer.exe" };
Thread w;
ParameterizedThreadStart ts = new ParameterizedThreadStart(StartMyApp);
foreach (var myApp in myApps)
{
w = new Thread(ts);
w.Start(myApp);
Thread.Sleep(1000);
}
}
public static void StartMyApp(object myAppPath)
{
ProcessStartInfo myInfoProcess = new ProcessStartInfo();
myInfoProcess.FileName = myAppPath.ToString();
myInfoProcess.WindowStyle = ProcessWindowStyle.Minimized;
Process myProcess = Process.Start(myInfoProcess);
do
{
if (!myProcess.HasExited)
{
myProcess.Refresh(); // Refresh the current process property values.
Console.WriteLine(myProcess.ProcessName+" RAM: " + (myProcess.WorkingSet64 / 1024 / 1024).ToString() + "\n");
Thread.Sleep(1000);
}
}
while (!myProcess.WaitForExit(1000));
}
}
EDIT: Thanks for pointing to Console.SetCursorPosition #Jim Mischel. I want to use that in my application but now I have another problem. How could I pass to my StartMyApp method, the index number from myApps array so I could do something like:
Console.WriteLine((Array.IndexOf(myApps, myAppPath) + " " + myProcess.ProcessName+" RAM: "+ (myProcess.WorkingSet64 / 1024 / 1024).ToString() + "\n");
That is inside my StartMyApp method. Any method I use I end up getting The name 'myApps' does not exist in the current context. This is very important for me so I could design my application later using Console.SetCursorPosition but I need that index number. So my output would be for example:
0 notepad RAM: 4
1 calc RAM: 4
2 explorer RAM: 12
You want to call Console.SetCursorPosition to set the position where the next write will occur. The linked MSDN topic has a basic example that will get you started.
You'll also be interested in the BackgroundColor, ForegroundColor, and possibly other properties. See the Console class documentation for details.

Search String takes a long time the first time only?

No shortage of search for string performance questions out there yet I still can not make heads or tails out of what the best approach is.
Long story short, I have committed to moving from 4NT to PowerShell. In leaving the 4NT I am going to miss the console super quick string searching utility that came with it called FFIND. I have decided to use my rudimentary C# programming skills to try an create my own utility to use in PowerShell that is just as quick.
So far search results on a string search in 100's of directories across a few 1000 files, some of which are quite large, are FFIND 2.4 seconds and my utility 4.4 seconds..... after I have ran mine at least once????
The first time I run them FFIND does it near the same time but mine takes over a minute? What is this? Loading of libraries? File indexing? Am I doing something wrong in my code? I do not mind waiting a little longer but the difference is extreme enough that if there is a better language or approach I would rather start down that path now before I get too invested.
Do I need to pick another language to write a string search that will be lighting fast
I have the need to use this utility to search through 1000 of files for strings in web code, C# code, and another propitiatory language that uses text files. I also need to be able to use this utility to find strings in very large log files, MB size.
class Program
{
public static int linecounter;
public static int filecounter;
static void Main(string[] args)
{
//
//INIT
//
filecounter = 0;
linecounter = 0;
string word;
// Read properties from application settings.
string filelocation = Properties.Settings.Default.FavOne;
// Set Args from console.
word = args[0];
//
//Recursive search for sub folders and files
//
string startDIR;
string filename;
startDIR = Environment.CurrentDirectory;
//startDIR = "c:\\SearchStringTestDIR\\";
filename = args[1];
DirSearch(startDIR, word, filename);
Console.WriteLine(filecounter + " " + "Files found");
Console.WriteLine(linecounter + " " + "Lines found");
Console.ReadKey();
}
static void DirSearch(string dir, string word, string filename)
{
string fileline;
string ColorOne = Properties.Settings.Default.ColorOne;
string ColorTwo = Properties.Settings.Default.ColorTwo;
ConsoleColor valuecolorone = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), ColorOne);
ConsoleColor valuecolortwo = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), ColorTwo);
try
{
foreach (string f in Directory.GetFiles(dir, filename))
{
StreamReader file = new StreamReader(f);
bool t = true;
int counter = 1;
while ((fileline = file.ReadLine()) != null)
{
if (fileline.Contains(word))
{
if (t)
{
t = false;
filecounter++;
Console.ForegroundColor = valuecolorone;
Console.WriteLine(" ");
Console.WriteLine(f);
Console.ForegroundColor = valuecolortwo;
}
linecounter++;
Console.WriteLine(counter.ToString() + ". " + fileline);
}
counter++;
}
file.Close();
file = null;
}
foreach (string d in Directory.GetDirectories(dir))
{
//Console.WriteLine(d);
DirSearch(d,word,filename);
}
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
If you want to speed up your code run a performance analysis and see what is taking the most time. I can almost guaruntee the longest step here will be
fileline.Contains(word)
This function is called on every line of the file, on every file. Naively searching for a word in a string can taken len(string) * len(word) comparisons.
You could code your own Contains method, that uses a faster string comparison algorithm. Google for "fast string exact matching". You could try using a regex and seeing if that gives you a performance enhancement. But I think the simplest optimization you can try is :
Don't read every line. Make a large string of all the content of the file.
StreamReader streamReader = new StreamReader(filePath, Encoding.UTF8);
string text = streamReader.ReadToEnd();
Run contains on this.
If you need all the matches in a file, then you need to use something like Regex.Matches(string,string).
After you have used regex to get all the matches for a single file, you can iterate over this match collection (if there are any matches). For each match, you can recover the line of the original file by writing a function that reads forward and backward from the match object index attribute, to where you find the '\n' character. Then output that string between those two newlines, to get your line.
This will be much faster, I guarantee it.
If you want to go even further, some things I've noticed are :
Remove the try catch statement from outside the loop. Only use it exactly where you need it. I would not use it at all.
Also make sure your system is running, ngen. Most setups usually have this, but sometimes ngen is not running. You can see the process in process explorer. Ngen generates a native image of the C# managed bytecode so the code does not have to be interpreted each time, but can be run natively. This speeds up C# a lot.
EDIT
Other points:
Why is there a difference between first and subsequent run times? Seems like caching. The OS could have cached the requests for the directories, for the files, for running and loading programs. Usually one sees speedups after a first run. Ngen could also be playing a part here, too, in generating the native image after compilation on the first run, then storing that in the native image cache.
In general, I find C# performance too variable for my liking. If the optimizations suggested are not satisfactory and you want more consistent performance results, try another language -- one that is not 'managed'. C is probably the best for your needs.

Modify Emdeded String in C# compiled exe

I have an issue where I need to be able to have a compiled exe ( .net 3.5 c# ) that I will make copies of to distribute that will need to change a key for example before the exe is sent out.
I cannot compile each time a new exe is needed. This is a thin client that will be used as part of a registration process.
Is it possible to add a entry to a resource file with a blank value then when a request comes in have another application grab the blank default thin client, copy it, populate the blank value with the data needed.
If yes how? If no do you have any ideas? I have been scratching my head for a few days now and the limitation as due to the boundaries I am required to work in.
The other idea I has was to inject the value into a method, which I have no idea how I would even attempt that.
Thanks.
Convert the assembly to IL, do a textual search and replace, recompile the IL to an assembly again. Use the standard tools from the .NET SDK.
Instead of embedding the key in the assembly, put it in the app.config file (or another file delivered with the application) and prevent your application from running if the key is not present and valid. To protect it against modification by users, also add an RSA signature the config file.
This code could be used to generate XML containing your key.
public static void Main()
{
Console.WriteLine(GenerateKey());
}
public static Byte[] Transform(Byte[] bytes, ICryptoTransform xform)
{
using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
{
using (CryptoStream cstream = new CryptoStream(stream, xform, CryptoStreamMode.Write))
{
cstream.Write(bytes, 0, bytes.Length);
cstream.Close();
stream.Close();
return stream.ToArray();
}
}
}
public static string GenerateKey()
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
// This is the private key and should never be shared.
// Generate your own with RSA.Create().ToXmlString(true).
String rsaPrivateKey = "<RSAKeyValue><Modulus>uPCow37yEzlKQXgbqO9E3enSOXY1MCQB4TMbOZyk9eXmc7kuiCMhJRbrwild0LGO8KE3zci9ETBWVVSJEqUqwtZyfUjvWOLHrf5EmzribtSU2e2hlsNoB2Mu11M0SaGd3qZfYcs2gnEnljfvkDAbCyJhUlxmHeI+35w/nqSCjCk=</Modulus><Exponent>AQAB</Exponent><P>4SMSdNcOP0qAIoT2qzODgyl5yu9RubpIU3sSqky+85ZqJHXLUDjlgqAZvT71ROexJ4tMfMOgSWezHQwKWpz3sw==</P><Q>0krr7cmorhWgwCDG8jmzLMo2jafAy6tQout+1hU0bBKAQaPTGGogPB3hTnFIr84kHcRalCksI6jk4Xx/hiw+sw==</Q><DP>DtR9mb60zIx+xkdV7E8XYaNwx2JeUsqniwA3aYpmpasJ0N8FhoJI9ALRzzp/c4uDiuRNJIbKXyt6i/ZIFFH0qw==</DP><DQ>mGCxlBwLnhkN4ind/qbQriPYY8yqZuo8A9Ggln/G/IhrZyTOUWKU+Pqtx6lOghVdFjSxbapn0W8QalNMFGz7AQ==</DQ><InverseQ>WDYfqefukDvMhPHqS8EBFJFpls/pB1gKsEmTwbJu9fBxN4fZfUFPuTnCIJsrEsnyRfeNTAUFYl3hhlRYZo5GiQ==</InverseQ><D>qB8WvAmWFMW67EM8mdlReI7L7jK4bVf+YXOtJzVwfJ2PXtoUI+wTgH0Su0IRp9sR/0v/x9HZlluj0BR2O33snQCxYI8LIo5NoWhfhkVSv0QFQiDcG5Wnbizz7w2U6pcxEC2xfcoKG4yxFkAmHCIkgs/B9T86PUPSW4ZTXcwDmqU=</D></RSAKeyValue>";
rsa.FromXmlString(rsaPrivateKey);
String signedData = "<SignedData><Key>Insert your key here</Key></SignedData>";
Byte[] licenseData = System.Text.Encoding.UTF8.GetBytes(signedData);
Byte[] sigBytes = rsa.SignData(licenseData, new SHA1CryptoServiceProvider());
String sigText = System.Text.Encoding.UTF8.GetString(Transform(sigBytes, new ToBase64Transform()));
System.Text.StringBuilder sb = new StringBuilder();
using (System.Xml.XmlWriter xw = System.Xml.XmlTextWriter.Create(sb))
{
xw.WriteStartElement("License");
xw.WriteRaw(signedData);
xw.WriteElementString("Signature", sigText);
xw.WriteEndElement();
}
return sb.ToString();
}
Example output from this code:
<?xml version="1.0" encoding="utf-16"?>
<License>
<SignedData>
<Key>Insert your key here</Key>
</SignedData>
<Signature>cgpmyqaDlHFetCZbm/zo14NEcBFZWaQpyHXViuDa3d99AQ5Dw5Ya8C9WCHbTiGfRvaP4nVGyI+ezAAKj287dhHi7l5fQAggUmh9xTfDZ0slRtvYD/wISCcHfYkEhofXUFQKFNItkM9PnOTExZvo75pYPORkvKBF2UpOIIFvEIU=</Signature>
</License>
Then you can use code like this to verify it. You never have to distribute the private key:
public static Boolean CheckLicenseSignature(String licXml)
{
try
{
System.Xml.XmlDocument xd = new System.Xml.XmlDocument();
xd.LoadXml(licXml);
String licSig = xd.SelectSingleNode("/License/Signature").InnerText;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
String rsaPublicKey = "<RSAKeyValue><Modulus>uPCow37yEzlKQXgbqO9E3enSOXY1MCQB4TMbOZyk9eXmc7kuiCMhJRbrwild0LGO8KE3zci9ETBWVVSJEqUqwtZyfUjvWOLHrf5EmzribtSU2e2hlsNoB2Mu11M0SaGd3qZfYcs2gnEnljfvkDAbCyJhUlxmHeI+35w/nqSCjCk=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
rsa.FromXmlString(rsaPublicKey);
Byte[] licenseData = System.Text.Encoding.UTF8.GetBytes(xd.SelectSingleNode("/License/SignedData").OuterXml);
return rsa.VerifyData(licenseData, new SHA1CryptoServiceProvider(), Transform(System.Text.Encoding.UTF8.GetBytes(licSig), new FromBase64Transform()));
}
catch (System.Xml.XmlException ex)
{
return false;
}
catch (InvalidOperationException ex)
{
return false;
}
}
From within the capability of the .NET code itself, I'm not sure if this is doable. But it is possible to dynamically generate a .NET DLL which contains some key that can be referred from the main application. That is, if you wouldn't mind a second file in the distribution.
Or if you don't mind to use Ildasm to disassemble the .exe, change the key, then use Ilasm to reassemble, then you can do something to automate that.
The accepted answer is GARBAGE!
I HAVE DONE THIS SUCCESSFULLY. MUCH EASIER
Just put your base application (.net) that needs the key somewhere with a string resource FILLED WITH "XXXXXXXXXXXXXXX" (more than you'll need)
.Net resources are usually kept at the top of the code so you will find them fast skipping the first 100,000 bytes in my case.
Then you just read it in and look for those XXXXXX's. When you find them you replace them with the real API key and replace the rest of the X's with spaces you just trim off in code. This is the answer. It works and it works well.
ApiToken at = new ApiToken(UserId, SelectedCID);
at.MakeToken();
byte[] app = System.IO.File.ReadAllBytes(Path.Combine(AppDomain.CurrentDomain.GetData("DataDirectory").ToString(), "notkeyedapp.exe"));
for (int i = 100000; i < app.Length; i++)
{
if (app[i] == 0x58 && app[i + 1] == 0x58 && app[i + 2] == 0x58)
{
for (int j = 0; j < 128; j++)
{
if (at.Token.Length >= j + 1)
app[i + j] = System.Text.Encoding.ASCII.GetBytes(at.Token[j].ToString())[0];
else
app[i + j] = 0x20;
}
break;
}
}
string filename = "SoftwareProduct for - " + BaseModel.CompanyName.Replace(".", "") + ".exe";
return File(app, System.Net.Mime.MediaTypeNames.Application.Octet, filename);
I don't think You can get away without recompiling Your .exe and having key embedded into said .exe. The compilation process can be automated though via use of ildasm.exe and ilasm.exe as Daniel Earwicker suggested in his response https://stackoverflow.com/a/2742902/2358659
I'd like to expand on that if anyone else stumbles across this topic in the future.
I recently was facing similar problem due to my poor source code version control habits. In a nutshell I had an executable that was supposed to write some data to a Google Spreadsheet by referencing it's ID. Long after executable was released came another request from a different team to use the tool, but it had to write same information into a different spreadsheet in order to keep data separate for two teams. At the time I did not have the original source code, hence I was not able to change the static variable holding the original spreadsheet ID. What I did was as follows:
Using CMD.exe → call "C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\ildasm.exe" "myApplication.exe" /out="myApplication.il"
Using Notepad++ → Find and replace original ID to new ID inside myApplication.il file. This action can also be automated by writing own C# application to do this, or using PowerShell, or using vb/j-script or using some other find and replace tool available off-the-shelf, like FART (using CMD.exe → call fart.exe myApplication.il "OldKey" "NewKey")
Using CMD.exe → call "C:\Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe" "myApplication.il" /res="myApplication.res" /key="myApplicationKeyFile.snk"
As You see, all of these steps can be put into one .bat file that takes "NewKey" as an input and produces new .exe with NewKey embedded.
I hope that helps.
What comes to my mind, but not tried yet: Create a default String in your program, for example as
static public string regGuid = "yourguidhere";
Then, search the compiled EXE with any decent hex editor. If you find the string, replace it with another test. If you still can execute the program, you could try to automate this process and voila! Here you are.

Categories

Resources