Plan
The plan is to disable and subsequently enable a device from inside a windows forms application. To test the first building block of my plan, I open cmd with admin privileges and the following works perfectly:
> devcon hwids =ports
> devcon hwids *VID_10C4*
> devcon disable *VID_10C4*
> devcon enable *VID_10C4*
I can see the device being disabled and enabled again in device manager.
I can also achieve all of this by putting the commands into a batch file and running it from cmd with admin privileges. The above tells me that my plan is essentially good.
Application
However, what I actually want to do is achieve the same thing from inside a windows forms application:
I've set the following in the app manifest:
requestedExecutionLevel level="requireAdministrator" uiAccess="false"
For the sake of baby steps, I have checked this, just to ensure that there are no stupid mistakes in paths and whatnot. And it works just fine. The log file shows me the expected output from the dir command.
// Build String
string strCmdText =
"'/c cd " + prodPath +
" && dir " +
" > logs\\logFileEnablePrt.txt \"'";
// Run command
var p = new System.Diagnostics.Process();
var psi = new ProcessStartInfo("CMD.exe", strCmdText);
psi.Verb = "runas"; // admin rights
p.StartInfo = psi;
p.Start();
p.WaitForExit();
However, this does not work. It always returns an empty log file and does not change the device as expected:
// Build String
string strCmdText =
"'/c cd " + prodPath +
" && devcon hwids =ports " +
" > logs\\logFileEnablePrt.txt \"'";
// Run command
var p = new System.Diagnostics.Process();
var psi = new ProcessStartInfo("CMD.exe", strCmdText);
psi.Verb = "runas"; // admin rights
p.StartInfo = psi;
p.Start();
p.WaitForExit();
Error from cmd window is :
'devcon' is not recognized as an internal or external command,
operable program or batch file.
What's going on?
The above has me stumped. I've proved the commands work. I've proved my C# code works. But when I join the 2 together, it doesn't work...
NB: My C# program is running on my D: drive, if that makes any difference...
Updates Based on Comments
#Compo
Using your code, it does exactly the same as with mine. I see an empty log file & no changes made to the device. I've altered the /c to /k so I can see what going on the cmd terminal and I see this:
I've even tried your code C:\\Windows\\System32\\devcon hwids =usb pointing directly at devcon. Also tried \devcon.exe for completeness. The inexplicable error is :
I can see the flipping devcon.exe file sitting right there in the folder! Is there any reason it would not recognise it?
Also, with the command as you wrote it, the log file name is actually named logFileEnablePrt.txt'. I agree that your command looks right, so don't ask me why this happens!
#Panagiotis Kanavos
using your code, I get the following error:
This is at the line p.Start();. I tried putting in devcon.exe, and even the whole path (I checked the folder was in my PATH, and it is). Can't get past this. I actually stumbled on that answer you shared and arrived at this brick wall already.
Here is the code works for me, I don't have ports devices so I change it to usb.
public static void Main()
{
string prodPath = #"c:\devcon\x64";
// Build String
string strCmdText =
"/c \"cd /d " + prodPath +
" && devcon hwids =usb " +
" > log.txt \"";
// Run command
var p = new Process();
var psi = new ProcessStartInfo("CMD.exe", strCmdText);
psi.Verb = "runas"; // admin rights
p.StartInfo = psi;
p.Start();
p.WaitForExit();
}
Worked through a few steps and think I may have an answer...
Just specifying devcon fails as expected...windows cant find the exe as the folder it is in is not in the %PATH% variable in windows..
IF I specify the full path however it works...
It wasnt clear from your original code but if your copy of devcon is sitting in either System32 or Syswow directories you may be hitting an emulation issue as well...see here....
EDIT1:: A way to prove this would be to do Direcory.GetFiles(directory containing devcon) and see if the results line up with what you expect
As for passing arguments through to devcon I'd try something like this as opposed to trying to concatenate one giant cmd line..
A similar example but with netstat:
EDIT 2::Another example but with devcon:
The target platform here for the build was x64
EDIT3::
With my application build set to x86:
After working through the answers and comments above, I seem to have something that reliably works, which obviously I'd like to share back for scrutiny and future use.
So, my function ended up looking like this:
private int enablePort(string action)
{
while (true)
{
// Command Arg
string devconPath = #"c:\Windows\SysNative";
string strCmdText =
"'/c \"cd /d \"" +
devconPath +
"\" && c:\\Windows\\SysNative\\devcon " + action + " *VID_10C4* " +
"> \"" + prodPath + "\\logs\\logFileEnablePrt.txt\"\"";
// Process
var p = new Process();
var psi = new ProcessStartInfo()
{
Arguments = strCmdText,
Verb = "runas",
FileName = "CMD.exe",
UseShellExecute = true
};
p.StartInfo = psi;
p.Start();
p.WaitForExit();
// Grab log output
string logPath = prodPath + "\\logs\\logFileEnablePrt.txt";
Console.WriteLine("logPath = " + logPath);
string tempFile = System.IO.File.ReadAllText(logPath);
System.Console.WriteLine("Contents of WriteText.txt = \n{0}", tempFile);
// Check if it worked
var success = false;
if (tempFile.Contains(action))
{
success = true;
return 0;
}
// Error -> Allow user to try again!
if (MessageBox.Show("Was unable to " + action + " Test Jig COM port. Unlug & Replug USB. Check COM port is enabled if not working.", "COM Port Problem", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
{
return -1;
}
}
}
And the calling code was:
this.enablePort("disable");
int milliseconds = 3000;
await Task.Delay(milliseconds);
this.enablePort("enable");
As you can see in the code above, I've logged everything to see what was going on... Stepping through with the debugger, I can now see after the disable:
USB\VID_10C4&PID_EA60\0001 : Disabled
1 device(s) disabled.
And then after the enable:
USB\VID_10C4&PID_EA60\0001 : Enabled
1 device(s) are enabled.
The one extra thing I need to stress is that during testing, I thought I could hook a serial peripheral onto the port and determine whether it could disable and enable successfully by checking the connection. THIS DOES NOT WORK. The above code only works when the port is idle. Perhaps someone who understands the underlying software could hazard an explanation of why this is.
Related
I have an audio converter .exe that i want to wrap in a C# program, for UI and inputs etc.
To use the AudioConverter.exe, it is ran from the console with the suffix " < inputFile > ouputFile".
So the full line reads something like
C:\\User\Audioconverter.exe < song.wav > song.ogg
So far i have been able to start the converter succesfully outside of C#, I have managed to have the converter run via create process in C# in a hang state (without input and output files).
My code in C# thus far is pretty similar to the answers given on this site:
using System;
using System.Diagnostics;
namespace ConverterWrapper2
{
class Program
{
static void Main()
{
LaunchCommandLineApp();
}
static void LaunchCommandLineApp()
{
// For the example
const string ex1 = "C:\\Users\\AudioConverter.exe";
const string ex2 = "C:\\Users\\res\\song.wav";
const string ex3 = "C:\\Users\\out\\song.ogg";
// Use ProcessStartInfo class
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
startInfo.FileName = "AudioConverter2.exe";
startInfo.WindowStyle = ProcessWindowStyle.Normal;
startInfo.Arguments = ex1 + " < " + ex2 + " > " + ex3; \\Process is ran successfully without the addition of input and output files, but hangs waiting for files.
try
{
using (Process exeProcess = Process.Start(startInfo))
{
exeProcess.WaitForExit();
}
}
catch
{
// Log error.
}
}
}
}
So far the converter exe hasnt been able to start up correctly, this leads me to ask the question are inputs for stdin different from arguments?
Regardless i need to mimic this style of input and would appreciate any information. I had assumed that i could just pass the input and output files as arguments but i havent had much luck.
startInfo.Arguments = ex1 + " < " + ex2 + " > " + ex3; \\Process is ran successfully without the addition of input and output files, but hangs waiting for files.
That won't work.
A.exe < B > C is not process A.exe called with arguments < B > C. It's rather a shell instruction to:
start A.exe without arguments,
read file B and redirect its contents to the new process' stdin and
write the new process' stdout to file C.
You have two options to do that in C#:
You can use the help of the shell, i.e., you can start cmd.exe with arguments /c C:\User\Audioconverter.exe < song.wav > song.ogg or
you can re-implement what the shell is doing in C#. A code example for that can be found in this related question:
redirecting output to the text file c#
I have the following code for converting xml to csv by using perl script. When I run the perl script through c# but there is no files are created and string output become empty.
What is the problem?
I have the perl script with .txt extention, Is this ok or not?
string filePath = Path.GetDirectoryName(Path.GetDirectoryName(Directory.GetCurrentDirectory())) + "/Files/SAVVIS_CDR_1806012231.XML";
if (Path.GetExtension(filePath) != "csv")
{
ProcessStartInfo perlStartInfo = new ProcessStartInfo(#"C:\Strawberry\perl\bin\perl.exe");
string perlScriptFilePath = Path.GetDirectoryName(Path.GetDirectoryName(Directory.GetCurrentDirectory())) + "/PerlScript/formatter_savvis.pl.txt";
string csvFilePath = Path.GetDirectoryName(Path.GetDirectoryName(Directory.GetCurrentDirectory())) + "/PerlScript/";
perlStartInfo.Arguments = perlScriptFilePath + " " + filePath + " " + csvFilePath;
perlStartInfo.UseShellExecute = false;
perlStartInfo.RedirectStandardOutput = true;
perlStartInfo.RedirectStandardError = true;
perlStartInfo.CreateNoWindow = false;
Process perl = new Process();
perl.StartInfo = perlStartInfo;
perl.Start();
perl.WaitForExit();
string output = perl.StandardOutput.ReadToEnd();
}
Could you please anyone help me to solve this problem?
Thanks in advance.
First, to find out what went wrong:
string error = perl.StandardError.ReadToEnd();
Also, make sure you have necessary permissions to create files in the output directory. You may try to run your process with Admin privileges to find out if it's a permission issue:
perlStartInfo.Verb = "runas";
You may want to run your entire host process with elevated permissions for this.
(This is only to figure out if it's a permission issue! If it's the case, grant the output directory the necessary permissions, and if possible don't automatically run scripts with admin privileges in production environment)
There also may be errors in the perl script itself.
I would like to execute a cqlsh copy command from c# source code. I would like to execute a Python script, which exists under the folowing path:
C:\Program Files\DataStax Community\python\python.exe" "C:\Program Files\DataStax Community\apache-cassandra\bin\cqlsh.py
That will give me this screenshot:
Once in cqlsh, I can then run the command "copy emp to emp.csv"
The idea, is that I would like to execute all this from c# code. Here is what I did:
try
{
Process p = new Process(); // create process (i.e., the python program
p.StartInfo.FileName = #"C:\Python27\python.exe";
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false; // make sure we can read the output from stdout
p.StartInfo.Arguments = #"C:\Program Files\DataStax Community\apache-cassandra\bin\cqlsh.py" + " " + "-e copy key_space.emp to 'D:/emp.csv'"; // start the python program with two parameters
p.Start(); // start the process (the python program)
p.WaitForExit();
}catch(Exception ex)
{
Console.WriteLine(ex.Message);
string strError = ex.Message;
}
There is no exception caught but also there is nothing happened in term of result.
Any help would be appreciated .
I'm pretty sure your problem is with this line:
bin\cqlsh.py" + " " + "copy emp to D:/emp.csv";
If you were to run this from the command line, cqlsh would require the -e flag to execute a command. In Windows it'd look something like this (assuming a keyspace name of "your_keyspace":
python bin\cqlsh.py -e "copy your_keyspace.emp to d:\emp.csv"
So to actually call that from your process, you would either have to escape the double quotes or just use single quotes:
bin\cqlsh.py" + " " + "-e 'copy your_keyspace.emp to d:\emp.csv'";
I have an application that dumps a lot of files to a directory. I want to copy these files to a Hadoop cluster using the hadoop command. I use the following code to run the command.
System.Diagnostics.ProcessStartInfo export = new System.Diagnostics.ProcessStartInfo();
export.RedirectStandardOutput = false;
export.RedirectStandardError = false;
export.UseShellExecute = false;
export.WorkingDirectory = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
export.FileName = "hadoop";
export.Arguments = "fs -copyFromLocal " + Path.Combine(dumpDirectory, "*.txt") + " " + hadoopPath));
Console.WriteLine("Copying data: hadoop " + export.Arguments);
System.Diagnostics.Process proc = System.Diagnostics.Process.Start(export);
proc.WaitForExit();
if (proc.ExitCode == 0)
{
IEnumerable<string> files = Directory.EnumerateFiles(dumpDirectory);
foreach (string file in files)
File.Delete(file);
}
else
Console.WriteLine("Error copying to Hadoop: " + proc.ExitCode);
The program writes the following message:
Copying data: hadoop fs -copyFromLocal local/directory/*.txt /user/remote/directory/
copyFromLocal: `local/directory/*.txt': No such file or directory
Error copying to Hadoop: 1
Interestingly, when I run the command manually, the files copy without error.
Also, if the program runs the command without using *.txt and instead calls the command for each file individually, the command succeeds.
Can anyone shed some light on this?
I partially resolved the problem by creating a bash script containing the given command. I ran the bash script programmatically and it worked.
However, I still do not know why the original did not work.
I have a jar file which I want to run from within C#.
Here's what I have so far:
clientProcess.StartInfo.FileName = #"java -jar C:\Users\Owner\Desktop\myJarFile.jar";
clientProcess.StartInfo.Arguments = "[Something]";
clientProcess.Start();
clientProcess.WaitForExit();
int exitCode = clientProcess.ExitCode;
Unfortunatly I get "System could not find specified file", which makes sense since its not a file its a command.
I've seen code online which tells you to use:
System.Diagnostics.Process.Start("java -jar myprog.jar");
However I need the return codes AND I need to wait for it to exit.
Thanks.
Finally solved it. The filename has to be java and the arguments has to contain the location of the jar file (and anything arguments you want to pass that)
System.Diagnostics.Process clientProcess = new Process();
clientProcess.StartInfo.FileName = "java";
clientProcess.StartInfo.Arguments = #"-jar "+ jarPath +" " + argumentsFortheJarFile;
clientProcess.Start();
clientProcess.WaitForExit();
int code = clientProcess.ExitCode;
You need to set environment variable Path of java.exe executable or specify the full path of java.exe.
ProcessStartInfo ps = new ProcessStartInfo(#"c:\Program Files\java\jdk1.7.0\bin\java.exe",#"-jar C:\Users\Owner\Desktop\myJarFile.jar");
Process.Start(ps);