I'm trying to remove a Silverlight Out Of Browser app programatically passing the arguments to sllauncher in following this post: http://timheuer.com/blog/archive/2010/03/25/using-sllauncher-for-silent-install-silverlight-application.aspx However it won't uninstall the app when given the origin.
It turns out that when you have an automatically updating Out-Of-Browser application, Silverlight stamps each application Uri with a time stamp that can be found in the application's folder in the C:\Users\Trevor\AppData\Local\Microsoft\Silverlight\OutOfBrowser(AppFolderName) metadata file. So to facilitate the removal of our app in preparation for our new one, I implemented the following:
UninstallExisting(GetInstalledAppUri()); // This is how it's called
//This is the two method's implementation
// TODO: Change to your app name.
const string appName = "YourAppNameHere";
static string silverlightOutOfBrowserFolder =
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
+ #"\Microsoft\Silverlight\OutOfBrowser";
private static string GetInstalledAppUri()
{
string xapFolderPath = Path.Combine(silverlightOutOfBrowserFolder, GetXapFolder());
string[] lines = File.ReadAllLines(Path.Combine(xapFolderPath, "metadata"), Encoding.Unicode);
string finalAppUriLine = lines.First(i => i.Contains("FinalAppUri="));
return "\"" + finalAppUriLine.Replace("FinalAppUri=", "") + "\"";
}
private static string GetXapFolder()
{
string AppXapFolder = "";
foreach (var dir in Directory.GetDirectories(silverlightOutOfBrowserFolder))
{
if (dir.Contains(appName))
{
AppXapFolder = dir;
}
}
return AppXapFolder ;
}
private static string silverlightExe
{
get
{
return Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
#"Microsoft Silverlight\sllauncher.exe");
}
}
private static void UninstallExisting(string xapUriToRemove)
{
string installArgs = "/uninstall" + " /origin:" + xapUriToRemove;
ProcessStartInfo pstart = new ProcessStartInfo(silverlightExe, installArgs);
Process p = new Process();
pstart.UseShellExecute = false;
p.StartInfo = pstart;
p.Start();
p.WaitForExit();
}
I hope this serves to save someone else the hours of time it took me to figure out about the metadata file and all the peculiarities of sllauncher.exe
Related
I am working with files on C# and I got to a point where I don't know how to continue anymore.
The scenario is this: If I upload 3 or more files with the same name at the same time, I want to handle them and change their name to from "myfile.pdf" to "myfile.pdf(1)/(2)/(3)..." depending on how much files I upload.
This is what I have tried so far and in this case, this only works for only the second file because when the third one comes, it will check there is any file with the same - yes, okay name it "myfile.pdf(2) - but this exists too so it will go to another place.
How can I achieve having the same three files in the same folder with this naming convention?
Here's what I have tried so far:
string FileName = "MyFile.pdf";
string path = #"C:\Project\MyPdfFiles\"
if (File.Exists(path))
{
int i = 1;
var FileExists = false;
while (FileExists==false)
{
if (FileExists == false)
{
FileName = FileName + "(" + i + ")";
}
else
return;
i++;
}
}
And the result of this code is: "MyFile.pdf", "MyFile.pdf(1)" And the third one doesn't load here.
I think I'm missing something in the loop or idk :(.
Can someone help me?
I have tried also this:
if(File.Exists(path) || File.Exists(path+"(")
//because when the second file its uploaded, its name will be SecondFile.pdf(1), so this will return true and will proceed running, but still the iteration will "always" start from 0 since everytime I upload a file, I have to refresh the process.
Don't use return inside your while loop, better set 'FileExists = true' whenever you want you loop to stop. A return statement will exit your current method.
I think your problem can be easily solved using recursion, something like this (untested):
public class Program
{
public string FileName { get; set; }
public Program() {
string fileName = "MyFile.pdf";
string path = #"C:\Project\MyPdfFiles\";
FileName = CheckFileName(path, fileName);
}
public string CheckFileName(string path, string fileName, int iteration = 0) {
if (File.Exists($"{path}{fileName}")) {
iteration++;
CheckFileName(path, $"{fileName}({iteration})", iteration);
}
return fileName;
}
}
What this does is: it CheckFileName method will keep calling itself until it finds a name that doesn't exist yet.
This should do the job.
public class Program
{
public static string GetUnusedFilePath(string directorypath, string filename, string ext)
{
string fullPath = $"{directorypath}{filename}{ext}";
int inc = 0;
// check until you have a filepath that doesn't exist
while (File.Exists(fullPath))
{
fullPath = $"{directorypath}{filename}{inc}{ext}";
inc++;
}
return fullPath;
}
public static void UploadFile(string filepath)
{
using (FileStream fs = File.Create(filepath))
{
// Add some text to file
Byte[] title = new UTF8Encoding(true).GetBytes("New Text File");
fs.Write(title, 0, title.Length);
}
}
public static void Main()
{
string[] filestoUpload = { "file", "file", "file", "anotherfile", "anotherfile", "anotherfile" };
string directorypath = #"D:\temp\";
string ext = ".txt";
foreach(var file in filestoUpload)
{
var filePath = GetUnusedFilePath(directorypath, file, ext);
UploadFile(filePath);
}
}
}
I solved this by creating new folders with special names using the code below:
DirectoryInfo hdDirectoryInWhichToSearch = new DirectoryInfo(FileDirectory);
FileSystemInfo[] filesAndDirs = hdDirectoryInWhichToSearch.GetFileSystemInfos("*" + FullFileName + "*");
int i = filesAndDirs.Length;
if (i>1)
{
FileName = Filename + "(" + i ")";
}
So what this does is that it will count how many files we have in that folder with the same name, so I have to check if we have more than 1 file, then change it's name to file(1).
Thank you to everyone that tried to help me, much appreciated.
my application is in C# MVC with framework 4.5.2 and want to run external file(.m) and get output from that and it is written in Octave.
Note: Output result is in a string, so I have to show that output in C# html page.
Algorithm is written in octave and also in algorithm excel file is there to read data and external parameters are also passing through C#.
I tried the things which is already posted, the main concern is that my application is hosted in azure cloud. So, I can not install octave in cloud.
Can you suggest me any other way that directly run external file(.m) with dynamic excel file and parameters.
I can show my code what I have done. Its work in local with all but I can not install Octave in Azure cloud..
I put my installed folder to root path on server but its also not working.
public Octave(string pathToOctaveBinaries, bool createWindow)
{
StartOctave(pathToOctaveBinaries, createWindow);
}
private void StartOctave(string pathToOctaveBinaries, bool createWindow)
{
_ptob = pathToOctaveBinaries;
cw = createWindow;
this.OctaveEchoString = Guid.NewGuid().ToString();
OctaveProcess = new Process();
ProcessStartInfo pi = new ProcessStartInfo();
if (pathToOctaveBinaries[pathToOctaveBinaries.Length - 1] != '\\')
pathToOctaveBinaries = pathToOctaveBinaries + "\\";
pi.FileName = pathToOctaveBinaries + "octave-cli.exe";
pi.RedirectStandardInput = true;
pi.RedirectStandardOutput = true;
pi.RedirectStandardError = true;
pi.UseShellExecute = false;
pi.CreateNoWindow = !createWindow;
pi.Verb = "open";
//
pi.WorkingDirectory = ".";
OctaveProcess.StartInfo = pi;
OctaveProcess.Start();
OctaveProcess.OutputDataReceived += new DataReceivedEventHandler(OctaveProcess_OutputDataReceived);
OctaveProcess.BeginOutputReadLine();
OctaveEntryText = ExecuteCommand(null);
}
public string ExecuteCommand(string command, int timeout)
{
if (OctaveProcess.HasExited)
{
StartOctave(_ptob, cw);
if (OctaveRestarted != null) OctaveRestarted(this, EventArgs.Empty);
}
_exitError = false;
Thread tmp = new Thread(new ParameterizedThreadStart(WorkThread));
tmp.Start(command);
if (!tmp.Join(timeout))
{
tmp.Abort();
throw new Exception("Octave timeout");
}
if (_exitError)
{
throw new Exception(_errorMessage);
}
return SharedBuilder.ToString();
}
This above is Octave class file. Where I dynamically pass the path of .exe to be run as thread.
Controller Code:
Octave octave = new Octave(OctaveFilePath, false);
string fileData = result.Data.ToString();
fileData = fileData.Replace("#ExcelFilePath#", excelFilePath);
fileData = fileData.Replace("#ABCD#", historyData);
string rasp = octave.ExecuteCommand(fileData, 30000);
From here I get string and that I show into html page.
I use a tool's binaries in a C# project called GraphViz.
The problem is I must include the binaries path as hard-coded and I don't want to do that.
IRenderer renderer = new Renderer("C:\\Program Files (x86)\\Graphviz2.38\\bin"); // todo: remove hardcoded GraphViz path
I want to mimic the linux which command.
Simply passing the binary name (e.g dot) and get the path.
GetBinaryPath("dot"); // return the above path
I'd appreciate any ideas or topics to start searching.
Note
Target OS: Windows
.NET version : 4
If you need to find path given only executable name (and installation directory is in your PATH environment variable)
Option 1:
Using where command with Process class. (test for exit code, parse the output)
Option 2:
You can get environment PATH environment variable, split it by ';' and test for your executable name existence.
First you need to find all directories where windows search for a exectuable file and that is from the environment variable %PATH%.
Then you need to find all extensions (.com, .exe, .bat etc) from %PATHEXT%.
Then you just check them like this:
internal class Program {
private static void Main(string[] args) {
if (args.Length != 1) {
Console.WriteLine("Incorrect usage!");
return;
}
var extensions = GetExecutableExtensions(args[0]);
var paths = GetPaths();
var exeFile = GetFirstExecutableFile(args[0], extensions, paths);
if (exeFile == null) {
Console.WriteLine("No file found!");
}
else {
Console.WriteLine(exeFile);
}
}
private static string GetFirstExecutableFile(string file, string[] extensions, string[] paths) {
foreach (var path in paths) {
var filename = Path.Combine(path, file);
if (extensions.Length == 0) {
if (File.Exists(filename)) {
return filename;
}
}
else {
foreach (var ext in extensions) {
filename = Path.Combine(path, file + ext);
if (File.Exists(filename)) {
return filename;
}
}
}
}
return null;
}
private static string[] GetExecutableExtensions(string file) {
var data = GetCmdOutput("echo %PATHEXT%");
var arr = data.TrimEnd('\n', '\r').Split(new [] {';'}, StringSplitOptions.RemoveEmptyEntries);
//If the command passed in ends with a executable extension then we dont need to test all extensions so set it to emtpy array
foreach (var ext in arr) {
if (file.EndsWith(ext, StringComparison.OrdinalIgnoreCase)) {
return new string[0];
}
}
return arr;
}
private static string[] GetPaths() {
var data = GetCmdOutput("echo %PATH%");
return data.TrimEnd('\n', '\r').Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
}
private static string GetCmdOutput(string cmd) {
using (var proc = new Process {
StartInfo = new ProcessStartInfo {
FileName = "cmd.exe",
Arguments = "/c " + cmd,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
}) {
proc.Start();
return proc.StandardOutput.ReadToEnd();
}
}
}
I was trying to automate server patch installation for my product and I came to know about Wix Toolset.
I was hoping to get the JBoss Version in my installer. The command to get the same is standalone.bat --version from cmd.
So from my installer I created one CustomAction where I tried to run it and get the output.
public static string runRunnableBatch(string path){
Process exploitVersionService = new Process();
string runnableBinPath = path;
exploitVersionService.StartInfo.WorkingDirectory = path + "bin";
exploitVersionService.StartInfo.FileName = path + "bin\\standalone.bat";
exploitVersionService.StartInfo.CreateNoWindow = false;
exploitVersionService.StartInfo.Arguments = string.Format("--version");
exploitVersionService.StartInfo.UseShellExecute = false;
exploitVersionService.StartInfo.RedirectStandardOutput = true;
exploitVersionService.StartInfo.RedirectStandardInput = false;
exploitVersionService.Start();
exploitVersionService.WaitForExit();
// /*
string opt = "";
while (!exploitVersionService.StandardOutput.EndOfStream){
opt += exploitVersionService.StandardOutput.ReadLine();
}
// */
//using (StreamWriter writer = new StreamWriter("D:\\_log.txt"))
//using (StreamReader reader = exploitVersionService.StandardOutput){
// writer.AutoFlush = true;
// for (; ; ){
// string textLine = reader.ReadLine();
// if (textLine == null)
// break;
// writer.WriteLine(textLine);
// }
//}
//StreamReader exploitVersionFeed = exploitVersionService.StandardOutput;
//string output = exploitVersionFeed.ReadToEnd();
return opt;
}
When I was doing that, all I got as output was the first line of the whole output string.
I needed the whole string in my code so that from regular expression I could extract the version.
Also tried with
public static string runRunnableBatch(string path){
string executableBinPath = path + "bin";
string executableBinPath_BatchCmd = "cd " + "\"" + executableBinPath + "\"";
string outputFileName = "TempVerInfoHolder.txt";
string outputFilePath = executableBinPath+#"\TempVerInfoHolder1.txt";
string versionRetriever_BatchCmd = #"standalone.bat --version > " + "\""+outputFilePath+"\"";
string partitionName_BatchCmd = #Strings.Utils.getPartitionFromPath(path);
// Creating command sequence
SortedList<int, string> commandSequence = new SortedList<int, string>();
// ~ d:
commandSequence.Add(1, partitionName_BatchCmd);
// ~ cd %path%
commandSequence.Add(2, executableBinPath_BatchCmd);
// ~ standalone.bat --version > %filename%
commandSequence.Add(3, versionRetriever_BatchCmd);
runCommandFromSequence(commandSequence);
// Run together
return "";
}
private static void runCommandFromSequence(SortedList<int, string> commandSequence){
Process seqCmdExecHost = new Process();
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "cmd.exe";
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.UseShellExecute = false;
psi.CreateNoWindow = false;
seqCmdExecHost.StartInfo = psi;
seqCmdExecHost.Start();
using (StreamWriter writer = seqCmdExecHost.StandardInput) {
if (writer.BaseStream.CanWrite) {
foreach (int item in commandSequence.Keys){
MessageBox.Show(seqCmdExecHost.Id.ToString());
MessageBox.Show(commandSequence[item]);
writer.WriteLine(commandSequence[item]);
}
}
string opt = "";
while (!seqCmdExecHost.StandardOutput.EndOfStream){
opt += seqCmdExecHost.StandardOutput.ReadLine();
}
MessageBox.Show("Exited? " + seqCmdExecHost.HasExited);
MessageBox.Show("O/P? " + opt);
}
}
I have tried some other way as well. Switching the commented code of the above function was one of them.
Output getting while doing it from code level
Calling "D:\Servers\VA\XYZ\JBoss-7.1.1-Final\bin\standalone.conf.bat
Output while running the same command manually from cmd
Calling D:\Servers\VA\XYZ\JBoss-7.1.1-Final\bin\standalone.conf.bat
======================================================================
JBoss Bootstrap Environment
JBOSS_HOME: D:\Servers\VA\XYZ\JBoss-7.1.1-Final
JAVA: C:\Program Files\Java\jdk1.7.0_67\bin\java
JAVA_OPTS
======================================================================
Listening for transport dt_socket at address: 8787
19:08:08,333 INFO [org.jboss.modules] JBoss Modules version 1.1.1.GA
JBoss AS 7.1.1.Final "Brontes"
Press any key to continue . . .
My observation is, the stream is getting closed once the nested standalone.conf.bat is getting called from standalone.bat.
If any workaround available to get the full output in string/buffer/stream, would be appreciated.
Thanks
What you could do is call the Command line Application instead of calling the batch file
exploitVersionService.StartInfo.WorkingDirectory = path + "bin";
exploitVersionService.StartInfo.FileName = "cmd.exe";
exploitVersionService.StartInfo.CreateNoWindow = false;
exploitVersionService.StartInfo.Arguments = string.Format(" /c \"{0}\" --version",path + "bin\\standalone.bat");
I found one work around to do achieve this.
I created the batch file programmatically and ran it with cmd.
public static void createBatchToGetVersion(string path)
{
CustomLogger.getInstance().debug("Started creating batch file");
BatchOps.executableBinPath = path + "bin";
CustomLogger.getInstance().debug("Ëxecutable bin path: " + BatchOps.executableBinPath);
BatchOps.tempBatchFileName = "JBossVerCmd.bat";
BatchOps.holderFileName = #"JBossVerHolder.txt";
BatchOps.absoluteHolderPath = Strings.Utils.normalize(executableBinPath) + holderFileName;
CustomLogger.getInstance().debug("Normalized absoluteHolderPath: " + BatchOps.absoluteHolderPath);
CustomLogger.getInstance().debug("Checking if JBOSS_HOME entered by user actuallty points to JBOSS");
if (!File.Exists(Strings.Utils.normalize(executableBinPath) + "standalone.bat"))
{
CustomLogger.getInstance().error("standalone.bat not found. JBOSS_HOME Dir is not correctly entered");
throw new CustomExceptions.DirectoryNotAcceptableException("Bad directory is assigned to JBOSS_HOME or JBOSS_HOME structure corrupted");
}
/*
* Batch file formation.
* Contains:
* Start file
* D:
* cd D:\Fusion Server\jboss 7.1.1\bin
* #echo | call standalone.bat --version > sample.txt
* #echo Done
* End file
* #echo is required here because it exits the cmd when completed whithout having the user pressing any key
*/
string changePartition_cmd = Strings.Utils.getPartitionFromPath(path);
string changeDirectory_cmd = #"cd " + BatchOps.executableBinPath;
string getVersion_cmd = #"#echo | call standalone.bat --version > " + holderFileName;
string exitCmd = #"#echo Done";
CustomLogger.getInstance().debug("Command to be written on batch file");
CustomLogger.getInstance().debug("\r\n" + changePartition_cmd + "\r\n" + changeDirectory_cmd + "\r\n" + getVersion_cmd + "\r\n" + exitCmd);
SortedList<int, string> commandSequence = new SortedList<int, string>();
CustomLogger.getInstance().debug("Initializing command sequence.");
commandSequence.Add(1, changePartition_cmd);
commandSequence.Add(2, changeDirectory_cmd);
commandSequence.Add(3, getVersion_cmd);
commandSequence.Add(4, exitCmd);
// Will create one if file never existed and open one delete the content and set the pointer to the begnning
// if already existed
StreamWriter batchFileWriter = null;
try
{
CustomLogger.getInstance().debug("Establishing stream to and from temp batch file");
batchFileWriter = new StreamWriter(tempBatchFileName);
CustomLogger.getInstance().debug("Command sequence ready to be written on temp batch file.");
Perform.writeToStreamFromSequence(batchFileWriter, commandSequence);
CustomLogger.getInstance().debug("Command sequence successfully written");
}
catch (IOException ex)
{
CustomLogger.getInstance().error("Error while writing command sequence.\n" + ex.ToString());
// throw exception to CustomAction
throw new IOException("Error while writing commandSequence");
}
finally
{
// Not required. Stream already closed in writeToStreamFromSequence
}
}
public static void runTempBatchFile()
{
Process seqCmdExecHost = new Process();
ProcessStartInfo procStartInfo = new ProcessStartInfo("cmd", #"/c " + BatchOps.tempBatchFileName);
procStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
seqCmdExecHost.StartInfo = procStartInfo;
seqCmdExecHost.Start();
seqCmdExecHost.WaitForExit();
seqCmdExecHost.Close();
}
I found the moment i was doing
procStartInfo.UseShellExecute=true;
procStartInfo.RedirectStandardOutput=true
It was giving the first line of output. Dont know why?. If anyone has any idea about it please explain.
Thanks
I am developing a multi store web application in ASP.NET where multiple stores with different domain can be created. I have a wizard to create a store to fill the information. what i want when i clik on finish button of wizard, i want to add the particular store site on IIS. how can i do that pragmatically using C#.
private void ConfigureSiteInIis()
{
string strWebsitename = txtStoreName.Text; // abc
const string strApplicationPool = "DefaultAppPool"; // set your deafultpool :4.0 in IIS
string strhostname = txtDomainName.Text; //abc.com
const string stripaddress = "localhost:40411"; // ip address
string bindinginfo = stripaddress + ":80:" + strhostname;
var serverMgr=new ServerManager();
//Site mySite = serverMgr.Sites.Add(txtStoreName.Text, "http", bindinginfo, "C:\\inetpub\\wwwroot\\yourWebsite");
Site mySite = serverMgr.Sites.Add(txtStoreName.Text, "http", "*:80:" + strhostname , Server.InetPath+txtDomainName.Text);
mySite.ApplicationDefaults.ApplicationPoolName = strApplicationPool;
mySite.TraceFailedRequestsLogging.Enabled = true;
mySite.TraceFailedRequestsLogging.Directory = "C:\\inetpub\\customfolder\\site";
serverMgr.CommitChanges();
lblMessage.Text = "New website " + strWebsitename + " added sucessfully";
lblMessage.ForeColor = System.Drawing.Color.Green;
}
I have got this code from stackoverflow but it is throwing exception "The specified HTTPS binding is invalid".
I've wrote this one time ago, works perfectly(IIS7 and later):
public static Application CreateApplicaiton(string siteName, string path, string physicalPath, string appPoolName)
{
ServerManager iisManager = ServerManager.OpenRemote(Environment.MachineName.ToLower());
// should start with "/" also not to end with this symbol
string correctApplicationPath = string.Format("{0}{1}", Path.AltDirectorySeparatorChar, path.Trim(Path.AltDirectorySeparatorChar));
int indexOfApplication = correctApplicationPath.LastIndexOf(Path.AltDirectorySeparatorChar);
if (indexOfApplication > 0)
{
// create sequence of virtual directories if the path is not a root level (i.e. test/beta1/Customer1/myApplication)
string virtualDirectoryPath = correctApplicationPath.Substring(0, indexOfApplication);
iisManager.CreateVirtualDirectory(siteName, virtualDirectoryPath, string.Empty);
}
Application application = iisManager.Sites[siteName].Applications.Add(correctApplicationPath, physicalPath);
application.ApplicationPoolName = appPoolName;
return application;
}
to host an application at localhost/test/beta1/Customer1/myApplication, use following parameters:
siteName - name of your site in IIS |Default Web Site
path - virtual directory |test/beta1/Customer1/myApplication
public static void CreateVirtualDirectory(this ServerManager iisManager, string siteName, string path, string physicalPath)
{
Site site = iisManager.Sites[siteName];
//remove '/' at the beginning and at the end
List<string> pathElements = path.Trim(Path.AltDirectorySeparatorChar).Split(Path.AltDirectorySeparatorChar).ToList();
string currentPath = string.Empty;
List<string> directoryPath = pathElements;
//go through applications hierarchy and find the deepest one
Application application = site.Applications.First(a => a.Path == Path.AltDirectorySeparatorChar.ToString());
for (int i = 0; i < pathElements.Count; i++)
{
string pathElement = pathElements[i];
currentPath = string.Join(Path.AltDirectorySeparatorChar.ToString(), currentPath, pathElement);
if (site.Applications[currentPath] != null)
{
application = site.Applications[currentPath];
if (i != pathElements.Count - 1)
{
directoryPath = pathElements.GetRange(i + 1, pathElements.Count - i - 1);
}
}
}
currentPath = string.Empty;
foreach (string pathElement in directoryPath)
{
currentPath = string.Join(Path.AltDirectorySeparatorChar.ToString(), currentPath, pathElement);
//add virtual directories
if (application.VirtualDirectories[currentPath] == null)
{
//assign physical path of application root folder by default
string currentPhysicalPath = Path.Combine(application.VirtualDirectories[0].PhysicalPath, pathElement);
//if this is last element of path, use physicalPath specified on method call
if (pathElement == pathElements.Last() && !string.IsNullOrWhiteSpace(physicalPath))
{
currentPhysicalPath = physicalPath;
}
currentPhysicalPath = Environment.ExpandEnvironmentVariables(currentPhysicalPath);
if (!Directory.Exists(currentPhysicalPath))
{
Directory.CreateDirectory(currentPhysicalPath);
}
application.VirtualDirectories.Add(currentPath, currentPhysicalPath);
}
}
}