I'm Using Process.Start from my website to open a windows form application I made in c#.
I want send to the application my username.
So how can I do that?
You can do this by assigning arguments in start info, e.g.:
var process = new Process
{
StartInfo =
{
FileName = processName,
Arguments = "-username=Alice"
}
};
process.Start();
If your process fails to start you might want to check permissions, as far as I am aware code running on IIS is not allowed to do that.
Process.Start() has several overloads, one of them is for specifying the command-line arguments along with the path to the executable.
For example:
Process.Start("app.exe", "parameter(s)");
You can use this:
Process.Start("MyExe.exe", "arguments");
Here you go, should be working
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
namespace SSHPit
{
public partial class MainForm : Form
{
[DllImportAttribute("user32.dll")]
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
public MainForm()
{
InitializeComponent();
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.FileName = "L:\\Program Files\\putty\\putty.exe";
p.StartInfo.Arguments = "-load \"mysession\" -ssh 127.0.0.1";
p.Start();
p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Maximized;
p.WaitForInputIdle();
while (p.MainWindowHandle == IntPtr.Zero)
{
Thread.Sleep(100);
p.Refresh();
}
SetParent(p.MainWindowHandle, panel1.Handle);
}
}
}
Related
I'm trying to make a program that opens a browser on each multi-display.
When I did it with a notepad, it worked. However, when it's a browser didn't work and showed the error "System.InvalidOperationException: Process must exit before requested information can be determined". I will appreciate your help with this situation.
This is my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp5
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern int MoveWindow(IntPtr hwnd, int x, int y,
int nWidth, int nHeight, int bRepaint);
private void Form1_Load(object sender, EventArgs e)
{
foreach (Screen item in Screen.AllScreens)
{
//Open a web browser
System.Diagnostics.Process process1 = System.Diagnostics.Process.Start("C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe");
//System.Diagnostics.Process process2 = System.Diagnostics.Process.Start("notepad.exe");
process1.WaitForInputIdle();
//process2.WaitForInputIdle();
//Move the browser window
MoveWindow(process1.MainWindowHandle, item.Bounds.X, item.Bounds.Y, item.Bounds.Width, item.Bounds.Height, 1);
//MoveWindow(process2.MainWindowHandle, item.Bounds.X, item.Bounds.Y, item.Bounds.Width, item.Bounds.Height, 1);
}
}
}
}
It seems that msedge.exe use a host process to start different tabs, so we can't use the created process ID to handle it.
Compare created process ID with processes in the Task Manager, the
process 38756 is missing.
Another tool to browse edge relative processes is the built-in task manager of edge.
We can't find process 38756 as well.
So re-search the target edge process is necessary.
This repo https://github.com/alex-tomin/Tomin.Tools.KioskMode demostrate how to move chrome window into different monitors and set as full screen.
I tried to extract the necessary and modify your code like below, hope it helps:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace TestWinFormsApp
{
// Get full definition of SetWindowPosFlags here:
// https://www.pinvoke.net/default.aspx/Enums/SetWindowPosFlags.html
[Flags]
public enum SetWindowPosFlags : uint
{
SWP_NOREDRAW = 0x0008,
SWP_NOZORDER = 0x0004
}
// Get full definition of ShowWindowCommands here:
// https://www.pinvoke.net/default.aspx/Enums/ShowWindowCommand.html
public enum ShowWindowCommands
{
Maximize = 3,
Restore = 9,
}
public static class WinApi
{
[DllImport("user32.dll", SetLastError = true)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommands nCmdShow);
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load_1(object sender, EventArgs e)
{
var ignoreHandles = new List<IntPtr>();
foreach (Screen item in Screen.AllScreens)
{
this.StartEdgeProcess();
var windowHandle = this.GetWindowHandle("msedge", ignoreHandles);
ignoreHandles.Add(windowHandle);
WinApi.ShowWindow(windowHandle, ShowWindowCommands.Restore);
WinApi.SetWindowPos(windowHandle, IntPtr.Zero, item.Bounds.Left, item.Bounds.Top, 800, 600, SetWindowPosFlags.SWP_NOZORDER | SetWindowPosFlags.SWP_NOREDRAW);
WinApi.ShowWindow(windowHandle, ShowWindowCommands.Maximize);
}
}
private void StartEdgeProcess()
{
var process = new Process();
process.StartInfo.FileName = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe";
process.StartInfo.Arguments = "about:blank" + " --new-window -inprivate ";
process.Start();
process.WaitForInputIdle();
}
private IntPtr GetWindowHandle(string processName, List<IntPtr> ignoreHandlers)
{
IntPtr? windowHandle = null;
while (windowHandle == null)
{
windowHandle = Process.GetProcesses()
.FirstOrDefault(process => process.ProcessName == processName
&& process.MainWindowHandle != IntPtr.Zero
&& !string.IsNullOrWhiteSpace(process.MainWindowTitle)
&& !ignoreHandlers.Contains(process.MainWindowHandle))
?.MainWindowHandle;
}
return windowHandle.Value;
}
}
}
I'm making a program to show another program fullscreen programmatically. To do this, I use MoveWindow() from WinAPI, but it needs a Window Handler. I tried to get it using FindWindow(), but since it uses the window name, I often had situations where the name was in a different language and it didn't work (or it didn't exist at all). So now I need to somehow get the Window Handler of the desired program by PID or even more conveniently by the name of the process. In C++, I found EnumWindows(), but I completely don't understand how to rewrite it in C#.
Question: How do I get the Window Handler using the PID or the program name?
Use EnumWindows to enumerate the handles of all windows and pass the window handle as a parameter to the GetWindowThreadProcessId function.
After obtaining the pid, compare the value with the pid of another program you provided. If it is the same, use MoveWindow to move it.
C# example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace EnumPTW
{
class Program
{
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
// Callback Declaration
public delegate bool EnumWindowsCallback(IntPtr hwnd, int lParam);
[DllImport("user32.dll")]
private static extern int EnumWindows(EnumWindowsCallback callPtr, int lParam);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
public static bool ReportWindow(IntPtr hwnd, int lParam)
{
uint processId = 0;
uint threadId = GetWindowThreadProcessId(hwnd, out processId);
if(processId == 23272) //23272: another program pid
{
Console.WriteLine(string.Format("Enumerated Window Handle 0x{0:X8}, Process {1}, Thread {2}", hwnd.ToInt32(), processId, threadId));
MoveWindow(hwnd, 100, 100, 800, 600, true);
}
return true;
}
static void Main(string[] args)
{
// Have to declare a delegate so that a thunk is created, so that win32 may call us back.
EnumWindowsCallback callBackFn = new EnumWindowsCallback(ReportWindow);
EnumWindows(callBackFn, 0);
Console.WriteLine("Finished. Press any key to continue.");
Console.ReadKey();
}
}
}
You can also use OpenProcess to get the handle of the process based on the pid, then use GetModuleFileNameEx to get the name of the process, and then compare the name with the process name you provided.
Sample: The using of OpenProcess and GetModuleFileNameEx
I am using trance32, and want to launch this process through Jenkins.
When I am launching T32mppc.exe, it is running as system process because of which it is running in background.
I want to launch this process with current user to see it on foreground without inserting username and password.
My system is having only 2 kind of process. System and User. No other users are there.
Attaching my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.IO;
using System.Globalization;
using System.Xml.Linq;
using System.Diagnostics;
using System.Threading;
using System.Configuration;
namespace Console_Startapps
{
class Program
{
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr handle);
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern bool ShowWindow(IntPtr handle, int nCmdShow);
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern bool IsIconic(IntPtr handle);
[DllImport("User32.dll", SetLastError = true)]
static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
[DllImport("TRACE32\t32api64.dll")]
public static extern int T32_ResetCPU();
private void startT32app()
{
IntPtr handle;
try
{
Console.WriteLine("T32 launching");
string path = #"C:\T32\bin\windows64\t32mppc.exe";
string args = #"C:\T32\config.t32";
ProcessStartInfo procInfo = new ProcessStartInfo(path, args);
procInfo.CreateNoWindow = false;
procInfo.UseShellExecute = true;
procInfo.WindowStyle = ProcessWindowStyle.Normal;
Process[] targetProcess = Process.GetProcessesByName("t32mppc.exe");
//if (targetProcess.Length > 1)
if (this.IsProcessOpen("t32mppc") == 1)
{
Console.WriteLine("TC32 already running");
}
else
{
Process procRun = Process.Start(procInfo);
handle = procRun.MainWindowHandle;
SwitchToThisWindow(handle, true);
}
//SetForegroundWindow(handle);
}
catch
{
Console.WriteLine("Failed to launch T32");
}
}
private int IsProcessOpen(string name)
{
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.ToLower().Contains(name.ToLower()))
{
return 1;
}
}
return 0;
}
static void Main(string[] args)
{
Program Beginapps = new Program();
Beginapps.startT32app();
}
}
}
Have you tried to impersonate another user?
https://msdn.microsoft.com/en-us/library/w070t6ka(v=vs.110).aspx
Basically, you can run another process with a given credential
How do you do Impersonation in .NET?
I am working on an WPF application to monitor my activities on my computer. I use Process.GetProcesses() and some filtering to get the processes I am interested in (example:Calculator) then I record their StartTime. I am also using WIN32/USER32 API method GetForegroundWindow() to get the window the user is using.
The problem is that when the windows are Windows/UWP applications they are always hosted by the process ApplicationFrameHost. So the GetForegroundWindow() method returns that window with a title (example:Calculator), but not the real process being hosted.
What I need is either another way to get the foreground window that includes the real process being hosted, or some way to connect the window to process.
Anyone that knows how to accomplish this? All help would be really appreciated.
I eventually found a way to do this, so I am going answer my own question so maybe someone in the future with the same problem could find it useful.
This is the class with the WinApiFunctions:
public class WinAPIFunctions
{
//Used to get Handle for Foreground Window
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr GetForegroundWindow();
//Used to get ID of any Window
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
public delegate bool WindowEnumProc(IntPtr hwnd, IntPtr lparam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc callback, IntPtr lParam);
public static int GetWindowProcessId(IntPtr hwnd)
{
int pid;
GetWindowThreadProcessId(hwnd, out pid);
return pid;
}
public static IntPtr GetforegroundWindow()
{
return GetForegroundWindow();
}
}
And this is the class I used to test if it would work. I used it in a simple console program that just writes out the name of the process that has current focus:
class FindHostedProcess
{
public Timer MyTimer { get; set; }
private Process _realProcess;
public FindHostedProcess()
{
MyTimer = new Timer(TimerCallback, null, 0, 1000);
Console.ReadKey();
}
private void TimerCallback(object state)
{
var foregroundProcess = Process.GetProcessById(WinAPIFunctions.GetWindowProcessId(WinAPIFunctions.GetforegroundWindow()));
if (foregroundProcess.ProcessName == "ApplicationFrameHost")
{
foregroundProcess = GetRealProcess(foregroundProcess);
}
Console.WriteLine(foregroundProcess.ProcessName);
}
private Process GetRealProcess(Process foregroundProcess)
{
WinAPIFunctions.EnumChildWindows(foregroundProcess.MainWindowHandle, ChildWindowCallback, IntPtr.Zero);
return _realProcess;
}
private bool ChildWindowCallback(IntPtr hwnd, IntPtr lparam)
{
var process = Process.GetProcessById(WinAPIFunctions.GetWindowProcessId(hwnd));
if (process.ProcessName != "ApplicationFrameHost")
{
_realProcess = process;
}
return true;
}
}
Chris, there is the alternative way which I have discovered trying to apply your solution to a related problem. While trying to analyse how the ApplicationFrameHost.exe-related stuff worked, I have stumbled upon the documented way of getting the true foreground window / thread and its process by passing 0 instead of the actual thread ID to GetGUIThreadInfo.
It might not fully work for the edge-case scenarios of your problem, but I felt that this might be a useful contribution for people of the future who might face the same problems ;-)
Here is the example of how this can be applied (pseudo C++'ish code):
GUITHREADINFO gti = { sizeof(GUITHREADINFO) };
GetGUIThreadInfo(0, >i); // <- note the `0`
DWORD processId = 0;
GetWindowThreadProcessId(gti.hwndFocus, &processId);
const auto procName = Util::GetProcessName(processId);
It solved my problem (obtaining the actual keyboard layout + finding the real foreground window) for all more-or-less common apps I have tested it against.
Basically, the answer you provided will also fail if the active window is in full screen mode,
for example if you have Skype app opened along with Microsoft Remote Desktop, which is the
active one and on full screen mode, EnumChildWindows would return SkypeApp not RDPClient.
and to get this fixed, you should follow the workaround suggested by Ivanmoskalev,
check this out:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetGUIThreadInfo(uint idThread, ref GUITHREADINFO lpgui);
public static IntPtr getThreadWindowHandle(uint dwThreadId)
{
IntPtr hWnd;
// Get Window Handle and title from Thread
var guiThreadInfo = new GUITHREADINFO();
guiThreadInfo.cbSize = Marshal.SizeOf(guiThreadInfo);
GetGUIThreadInfo(dwThreadId, ref guiThreadInfo);
hWnd = guiThreadInfo.hwndFocus;
//some times while changing the focus between different windows, it returns Zero so we would return the Active window in that case
if (hWnd == IntPtr.Zero)
{
hWnd = guiThreadInfo.hwndActive;
}
return hWnd;
}
[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern int GetWindowThreadProcessId(IntPtr windowHandle, out int processId);
static void Main(string[] args)
{
var current = getThreadWindowHandle(0);
int processId = 0;
GetWindowThreadProcessId(current, out processId);
var foregroundProcess = GetActiveProcess(processId);
}
private static Process GetActiveProcess(int activeWindowProcessId)
{
Process foregroundProcess = null;
try
{
foregroundProcess = Process.GetProcessById(activeWindowProcessId);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
if (string.IsNullOrWhiteSpace(GetProcessNameSafe(foregroundProcess)))
{
var msg = "Process name is empty.";
Console.WriteLine(msg);
}
return foregroundProcess;
}
About the same code from Chris Johnsson except that I'm not using Process because it doesn't work very well on the UWP app.
Code for start:
new Timer(TimerCallback, null, 0, 1000);
void TimerCallback(object state)
{
var process = new ProcessUtils.FindHostedProcess().Process;
string name = string.Empty;
if (process.IsPackaged)
{
var apps = process.GetAppDiagnosticInfos();
if (apps.Count > 0)
name = apps.First().AppInfo.DisplayInfo.DisplayName;
else
name = System.IO.Path.GetFileNameWithoutExtension(process.ExecutableFileName);
}
else
name = System.IO.Path.GetFileNameWithoutExtension(process.ExecutableFileName);
Debug.WriteLine(name);
}
And the FindHostedProcess class where I use ProcessDiagnosticInfo instead of Process
public class FindHostedProcess
{
public ProcessDiagnosticInfo Process { get; private set; }
public FindHostedProcess()
{
var foregroundProcessID = WinAPIFunctions.GetforegroundWindow();
Process = ProcessDiagnosticInfo.TryGetForProcessId((uint)WinAPIFunctions.GetWindowProcessId(foregroundProcessID));
// Get real process
if (Process.ExecutableFileName == "ApplicationFrameHost.exe")
WinAPIFunctions.EnumChildWindows(foregroundProcessID, ChildWindowCallback, IntPtr.Zero);
}
private bool ChildWindowCallback(IntPtr hwnd, IntPtr lparam)
{
var process = ProcessDiagnosticInfo.TryGetForProcessId((uint)WinAPIFunctions.GetWindowProcessId(hwnd));
if (process.ExecutableFileName != "ApplicationFrameHost.exe")
Process = process;
return true;
}
}
Finally reuse Chris Johnson's WinAPIFunctions class.
I'm trying to write some automation to open a close a series of windows (non-hidden, non-malicious) and I don't want them to steal focus as they open. The problem is that when each window opens, it steals focus preventing me from working while it runs in the background.
Here's the code that I execute in a loop to open the various windows:
using (Process proc = new Process())
{
proc.StartInfo.FileName = filename;
proc.StartInfo.Arguments = arguments;
proc.Start();
Thread.Sleep(1000);
if (!proc.HasExited)
{
proc.Kill();
}
}
How do I make these open without focus so I can do other things while this automation runs?
Addenda:
The program that is executing the above code is a simple console app. The processes I'm starting are GUI apps. For testing/designing purposes, I'm currently attempting this with repeated instances of Internet Explorer (iexplore.exe) with different arguments.
I will be running this and carrying on with other unrelated work while this runs in the background. I don't want focus returned to the parent app, either. Essentially, I'll run this .exe when I get to my desk, and switch to other windows to do other work, ignoring the original program and its child processes until it's finished.
This is possible but only via pinvoke, which unfortunately requires about 70 lines of code:
[StructLayout(LayoutKind.Sequential)]
struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
internal struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[DllImport("kernel32.dll")]
static extern bool CreateProcess(
string lpApplicationName,
string lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
[In] ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation
);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);
const int STARTF_USESHOWWINDOW = 1;
const int SW_SHOWNOACTIVATE = 4;
const int SW_SHOWMINNOACTIVE = 7;
public static void StartProcessNoActivate(string cmdLine)
{
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWMINNOACTIVE;
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
CreateProcess(null, cmdLine, IntPtr.Zero, IntPtr.Zero, true,
0, IntPtr.Zero, null, ref si, out pi);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
Set si.wShowWindow to SW_SHOWNOACTIVATE to show the window normally but without stealing focus, and SW_SHOWMINNOACTIVE to start the app minimised, again without stealing focus.
A full list of options is available here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx
You can move focus to your app
[DllImport("User32")]
private static extern int SetForegroundWindow(IntPtr hwnd);
[DllImportAttribute("User32.DLL")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
Process.Start("");
Thread.Sleep(100);
var myWindowHandler = Process.GetCurrentProcess().MainWindowHandle;
ShowWindow(myWindowHandler, 5);
SetForegroundWindow(myWindowHandler);
SetForegroundWindow
ShowWindow
Solved.
The solution I ended up using circumvents any attributes or reassigning focus. Since the task was automated and stand-alone, I just used the Windows Task Scheduler to run the application. For whatever reason, as long as the "parent" console window isn't in focus, the "child" GUI windows open normally but not in focus—allowing me to continue working in another window while the application runs.
SetForegroundWindow do the trick also in console apps.
Tested code:
Create a simple class:
public class MyClass
{
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
public void doProcess(string filename, string arguments){
using (Process proc = new Process())
{
proc.StartInfo.FileName = filename;
proc.StartInfo.Arguments = arguments;
proc.Start();
SetForegroundWindow(proc.MainWindowHandle);
}
}
}
Then in the main method of your console app:
class Program
{
static void Main(string[] args)
{
MyClass mc = new MyClass();
mc.doProcess("iexplore.exe", "http://www.stackoverflow.com");
Console.ReadKey();
}
}
Use a combination of Process.StartInfo.CreateNoWindow = true and Process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden.
It might also be worth using Process.StartInfo.UseShellExecute = false, and redirecting StdIn/StdOut/StdErr.
See http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.aspx
I haven't tried this, but I believe if you set proc.StartInfo.WindowStyle = WindowStyle.Minimized that should do the trick.