I have read that Win32 will not allow remote invocation of a process that is interactive and I suspect a Console Application is considered to be interactive by Windows and so instead, if I could convert the following code in to a batch file then I am hoping I can remotely run the batch file on the server computer from a client. Feel free to correct this logic if I'm wrong.
The code is:
namespace PRIMEWebFlyControl
{
class Program
{
// name of the process we will retrieve a handle to
private const string PROCESS_NAME = "PRIMEPipeLine";
private static Process ProgramHandle;
private static string command;
static void Main(string[] args)
{
//Console.WriteLine("This program has been launched remotely!");
TextReader tr = new StreamReader("C:\\inetpub\\wwwroot\\PRIMEWeb\\Executables\\FlyCommand.txt");
command = tr.ReadLine();
tr.Close();
ExecuteCommand();
}
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr handle);
private static void ExecuteCommand() {
if (AssignProcessHandle()) {
IntPtr p = ProgramHandle.MainWindowHandle;
SetForegroundWindow(p);
SendKeys.SendWait(command + "~"); // "~" is equivalent to pressing Enter
}
}
private static bool AssignProcessHandle()
{
// ask the system for all processes that match the name we are looking for
Process[] matchingProcesses = Process.GetProcessesByName(PROCESS_NAME);
// if none are returned then we haven't found the program so return false;
if (matchingProcesses.Length == 0) return false;
// else, set our reference to the running program
ProgramHandle = matchingProcesses[0];
// return true to indicate we have assigned the ref sucessfully
return true;
}
}
}
As you will notice the code contains method calls of Windows library methods like SetForegroundWindow() and as I am unfamiliar with batch files, I wondered how the same thing might be achieved.
Many thanks
If I understand well, you are looking for a command line that will execute a bunch of commands that exist inside a text file named (C:\inetpub\wwwroot\PRIMEWeb\Executables\FlyCommand.txt)
Here is what you need to do:
cmd < C:\inetpub\wwwroot\PRIMEWeb\Executables\FlyCommand.txt
In case the path contains spaces, use the following command:
cmd < "C:\inetpub\wwwroot\PRIMEWeb\Executables\FlyCommand.txt"
Related
A customer wants an overlay program that's always on top and that has 2 buttons that opens their programs.
If one of their programs is already open then my program should set their program on top of everything else (i.e switch to it and not open a new instance).
Essentially I find a process by the processname, then try to set it on top using the process, but it doesn't work for everything. For things like Notepad++ it works fine, but other programs that have have subprocesses it doesn't work, most likely because the main program starts child processes that I don't have access to?
I got the following code to find a process by processname, and send it on top in windows.
static Process FindProcess(string ProcessName)
{
Process[] targetProcesses = Process.GetProcessesByName(ProcessName);
Process targetProgram = null;
if(targetProcesses.Count() > 0)
{
targetProgram = targetProcesses[0];
}
return targetProgram;
}
Then in a later section I take the process, and try to put it on top using this code:
static void SendWindowToFront(Process SProcess)
{
try
{
AutomationElement aelement = AutomationElement.FromHandle(SProcess.MainWindowHandle);
if (aelement != null)
{
ShowWindow(SProcess.MainWindowHandle, SW_SHOWWINDOWED);
aelement.SetFocus();
}
}
catch (Exception ex)
{
Console.WriteLine("SendWindowToFront error: " + ex.Message);
}
}
But as I said, it doesn't work for all programs.
For example, the above program have processname "QuickDesign" (excuse the Swedish), but I can't use my code to switch to it, most likely because it creates a subprocess when starting that I don't have access to?
What I want to do with my program is essentially just the "Place above".
It's not specifically for that program in the picture, that's just an example I have to work.
I tried this code to find childprocesses, but it only returns an empty list:
public static class ProcessExtensions
{
public static IList<Process> GetChildProcesses(this Process process)
=> new ManagementObjectSearcher(
$"Select * From Win32_Process Where ParentProcessID={process.Id}")
.Get()
.Cast<ManagementObject>()
.Select(mo =>
Process.GetProcessById(Convert.ToInt32(mo["ProcessID"])))
.ToList();
}
Is this something that can be solved?
So I found an alternate way for this problem by following this guide:
http://weimenglee.blogspot.com/2007/01/programmatically-switch-to-another.html
Using the following code:
[DllImport("user32.dll")]
private static extern bool
SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindowAsync(
IntPtr hWnd, int nCmdShow);
private const int SW_RESTORE = 9;
private void SwitchToProgram(string programName)
{
Process[] procs = Process.GetProcesses();
if (procs.Length != 0)
{
for (int i = 0; i < procs.Length; i++)
{
try
{
if (procs[i].MainModule.ModuleName ==
programName)
{
IntPtr hwnd =
procs[i].MainWindowHandle;
ShowWindowAsync(hwnd, SW_RESTORE);
SetForegroundWindow(hwnd);
return;
}
}
catch(Exception e)
{
Console.WriteLine("ERROR SwitchToProgram in loop: " + e.Message);
}
}
}
else
{
Console.WriteLine("ERROR SwitchToProgram: No processes running.");
return;
}
Console.WriteLine("ERROR SwitchToProgram: " + programName + " isn't running.");
}
I can just give a pathname like "programname.start" to the function and it will send it to the front if it finds it.
It works perfect on the customer computer, while slow at my own. But that's because my work computer has a bunch of restrictions that slows down everything a bit.
Can anyone help me output a message to a console box when my .exe is called with the wrong parameters?
Yesterday, some very kind people helped me work out how to call my app without a UI
Here is the thread
command line to make winforms run without UI
So, I have told my app to respond to "/silent archive=true transcode=true" and runs without a UI. Great!
Is it possible to output a message to the command window if they get the command incorrect?
as in "Parameters must be specified like this: /silent archive=true transcode=true"
I have tried this but nothing displays in the dos window..
static void Main(string[] args)
{
if (args.Length > 0)
{
if (args[0] == "/silent")
{
bool archive = false;
bool transcode = false;
try
{
if (args[1] == "transcode=true") { transcode = true; };
if (args[2] == "archive=true") { archive = true; };
Citrix_API_Tool.Engine.DownloadFiles(transcode, archive);
}
catch
{
Console.Write ("Hello");
Console.ReadLine();
return;
}
}
}
else
internal sealed class Program
{
[DllImport("kernel32.dll")]
private static extern bool AttachConsole(int dwProcessId);
private const int ATTACH_PARENT_PROCESS = -1;
[STAThread]
private static void Main(string[] args)
{
if(false)//This would be the run-silent check.
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
try
{
throw new Exception("Always throw, as this tests exception handling.");
}
catch(Exception e)
{
if(AttachConsole(ATTACH_PARENT_PROCESS))
{
//Note, we write to Console.Error, not Console.Out
//Partly because that's what error is for.
//Mainly so if our output were being redirected into a file,
//We'd write to console instead of there.
//Likewise, if error is redirected to some logger or something
//That's where we should write.
Console.Error.WriteLine();//Write blank line because of issue described below
Console.Error.WriteLine(e.Message);
Console.Error.WriteLine();//Write blank line because of issue described below
}
else
{
//Failed to attach - not opened from console, or console closed.
//do something else.
}
}
}
}
A problem is that the console would have already returned to taking input from the user. Hence you really want to try to have your exception as fast as you can if you're going to have it, so a fast validation check rather than an exception that might happen down the line, is preferable.
Is there a way for a Console app know whether it has been called from a batch file as opposed to directly at the command prompt?
The reason for asking is to find a way to decide whether to initiate a Console.ReadLine loop or similar to await further input, or whether to exit immediately.
Alternatively, is there a way for a batch file to continue sending input to a Console App that is awaiting further input via ReadLine?
Yes, I know - that's 2 questions. If anyone comments that there's an answer to the second question I'll ask that separately.
Why not pass in a commandline argument to the console app to determine whether to quit immediately or wait.
The batch file can set an environment variable and you can check that in your console application:
in the batch file:
set waitOnDone=0
yourExeFile -arguments
in your Console Application:
var env = System.Environment.GetEnvironmentVariable("waitOnDone");
if (String.IsNullOrEmpty(env) || env != "0")
{
// do something
}
If the batch file knows the input then save the input to a file and feed that to your program like
prog.exe <argument.txt
in the batch file. I think you need not change the source code for this.
Possibly your problem is to read only from stdin if there is a redirecton (from your batch file).
This can also be solved (with dotnet) by detecting if there is an input stream.
Solution from #Hans Passant, SO: how to detect if console in stdin has been redirected
using System.Runtime.InteropServices;
public static class ConsoleEx
{
public static bool OutputRedirected
{
get { return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stdout)); }
}
public static bool InputRedirected
{
get { return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stdin)); }
}
public static bool ErrorRedirected
{
get { return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stderr)); }
}
// P/Invoke:
private enum FileType { Unknown, Disk, Char, Pipe };
private enum StdHandle { Stdin = -10, Stdout = -11, Stderr = -12 };
[DllImport("kernel32.dll")]
private static extern FileType GetFileType(IntPtr hdl);
[DllImport("kernel32.dll")]
private static extern IntPtr GetStdHandle(StdHandle std);
}
And it can be used like this
if (ConsoleEx.InputRedirected)
{
string strStdin = Console.In.ReadToEnd();
}
I am getting strange behvior of my application only on Windows Vista (SP1).
Calling the static extern method of dll on random occasions makes application stop working and suddenly shows CPU usage become 00 in task manager, while Memory (Private Working Set) remains static.
On Windows XP and Windows 7 application behvior is normal.
I will show some example code here.
DllWrapper.cs
public class DLLWrapper
{
private const string dllTest = #"DLLTEST.dll";
[DllImport(dllTest)]
internal static extern bool DoSomething(string sPath1, string sPath2);
}
CallingClass.cs
//CallingClass Method
private void MoveFile(string sInputPath, string sOutputPath)
{
try
{
//get all xml at input
string[] arrFiles = Directory.GetFiles(sInputPath, "*.xml");
//loop: through all xmls in directory
foreach (string sFile in arrFiles)
{
//cond: check dosmething successful
//calls extrenal dll method
if (DLLWrapper.DoSomething(sFile, sOutputPath))
{
//add something to log
}
//cond: dosomething false
else
{
//add log failure
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
}
Now the log file records sometimes a success but application progress stops on random xml file (may be on 5th xml file or may be on 120th in the Directory).
Please let me know how to identify problem in this situation.
I am writing a url shortener app and I would like to also create a console app with C# to push the URLs to a WCF service which I have also created.
WCF app will shorten the url on this URI;
http://example.com/shorten/http://exaple.com
so what I want is just that.
My console exe file will be sitting inside c:\dev folder and on Windows command line, I would like to do this;
c:\dev>myapp -throw http://example.com
with this method I would like to talk to that service. there is no problem on talking part. But the problem is how can I supply this -throw thing on the command line and get a response and put that response on the command line and supply a method to copy that to the clipboard. Am I asking too much here? :S I don't know.
Could you direct me somewhere that I can find information on that or could u please give me an example code of this?
Thanks.
EDIT :
I have tried the following code;
class Program {
static void Main(string[] args) {
if (args[0] == "-throw") {
System.Windows.Forms.Clipboard.SetDataObject(args[1]);
Console.WriteLine(args[1] + " has been added to clipboard !");
Console.ReadLine();
}
}
}
and I received the following error;
C:\Apps\ArgsTry\ArgsTry\bin\Debug>ArgsTry
-throw man
Unhandled Exception:
System.Threading.ThreadStateException:
Current thread must be set to single
thread apartment (STA) mode before OLE
calls can be made. Ensur e that your
Main function has STAThreadAttribute
marked on it. at
System.Windows.Forms.Clipboard.SetDataObject(Object
data, Boolean copy, In t32 retryTimes,
Int32 retryDelay) at
System.Windows.Forms.Clipboard.SetDataObject(Object
data) at
ArgsTry.Program.Main(String[] args) in
c:\apps\ArgsTry\ArgsTry\Program.cs:
line 14
C:\Apps\ArgsTry\ArgsTry\bin\Debug>
Passing arguments to a console application is easy:
using System;
public class CommandLine
{
public static void Main(string[] args)
{
for(int i = 0; i < args.Length; i++)
{
if( args[i] == "-throw" )
{
// call http client args[i+1] for URL
}
}
}
}
As for the clipboard, see:
http://msdn.microsoft.com/en-us/library/system.windows.forms.clipboard.aspx
See the args below, you can use it to read all the values passed when you run your exe file.
static void Main(string[] args) {