show running applications (alt-tab program list) - c#

Found the solution here: http://blogs.msdn.com/b/oldnewthing/archive/2007/10/08/5351207.aspx
I'm trying to go a list of running applications, i found on several forums this solution:
Process[] processes = Process.GetProcesses();
foreach (var proc in processes)
{
if (!string.IsNullOrEmpty(proc.MainWindowTitle))
Console.WriteLine(proc.MainWindowTitle);
}
exept this is not giving me the same list as when you press alt-tab. For example: firefox, explorer, and iexplore all return an empty/null MainWindowTitle. Is there another way to access this list? Maybe thru a windowsAPI?
I'm am using Windows 7 32bit
Thank you in advanced.

There are no hidden processes on Windows. Only processes you do not have (security) rights to see.
have a look at the below:
Retrieve a complete processes list using C#

Try this (taken from here), but I'm not sure it solves your problem:
static void Main(string[] args)
{
GetProcesses();
GetApplications();
Console.Read();
}
public static void GetProcesses()
{
StringBuilder sb = new StringBuilder();
ManagementClass MgmtClass = new ManagementClass("Win32_Process");
foreach (ManagementObject mo in MgmtClass.GetInstances())
Console.WriteLine("Name:" + mo["Name"] + "ID:" + mo["ProcessId"]);
Console.WriteLine();
}
public static void GetApplications()
{
StringBuilder sb = new StringBuilder();
foreach (Process p in Process.GetProcesses("."))
try
{
if (p.MainWindowTitle.Length > 0)
{
Console.WriteLine("Window Title:" + p.MainWindowTitle.ToString());
Console.WriteLine("Process Name:" + p.ProcessName.ToString());
Console.WriteLine("Window Handle:" + p.MainWindowHandle.ToString());
Console.WriteLine("Memory Allocation:" + p.PrivateMemorySize64.ToString());
}
}
catch { }
}

Related

How to close outlook after automating it in c#

I am creating a program which converts Msg outlook file into pdf. What I did was export the Msg file into Html then convert the Html output to pdf. This is my code:
Microsoft.Office.Interop.Outlook.Application app = new Microsoft.Office.Interop.Outlook.Application();
string filename = System.IO.Path.GetFileNameWithoutExtension(msgLocation) + ".html";
string attachmentFiles = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetFileNameWithoutExtension(msgLocation) + "_files");
string extractLocation = System.IO.Path.Combine(System.IO.Path.GetTempPath(), filename);
Console.WriteLine(filename);
Console.WriteLine(attachmentFiles);
Console.WriteLine(extractLocation);
var item = app.Session.OpenSharedItem(msgLocation) as Microsoft.Office.Interop.Outlook.MailItem;
item.SaveAs(extractLocation, Microsoft.Office.Interop.Outlook.OlSaveAsType.olHTML);
int att = item.Attachments.Count;
if (att > 0)
{
for (int i = 1; i <= att; i++)
{
item.Attachments[i].SaveAsFile(System.IO.Path.Combine(attachmentFiles, item.Attachments[i].FileName));
}
}
app.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
The MSG file convertion to HTML is working perfectly, but why is outlook.exe is still running? I want to close it, but app.Quit() doesn't close the app.
The issue is that the outlook com object is holding on to references and stopping the app from closing. Use the following function and pass your "app" object to it:
private void ReleaseObj(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
}
finally
{
obj = null;
}
}
See https://blogs.msdn.microsoft.com/deva/2010/01/07/best-practices-how-to-quit-outlook-application-after-automation-from-visual-studio-net-client/
This should work for any and App by referencing the App Name and it will kill all instances of the application. For instance if you have 5 instances of Notepad, it will kill them all...
To Kill the app, use the following:
KillProcessByPID.KillProcessByName("OUTLOOK");
Create the following static class (c# .net Core 6.0 is my weapon of choice in this case, but it should be fairly universal).
using System.Management;
using System.Diagnostics;
public static class KillProcessByPID
{
public static void KillProcessByName(string ProcessName)
{
string OutlookProcessName = "";
foreach (Process otlk in Process.GetProcesses())
{
if (otlk.ProcessName.ToLower().Contains(ProcessName.ToLower())) //OUTLOOK is the one I am seeking - yours may vary
{
OutlookProcessName = otlk.ProcessName;
}
}
//Get process ID by Name
var processes = Process.GetProcessesByName(OutlookProcessName);
foreach (var process in processes)
{
Console.WriteLine("PID={0}", process.Id);
Console.WriteLine("Process Handle={0}", process.Handle);
PortfolioTrackerXML.KillProcessByPID.KillProcessAndChildren(process.Id);
}
}
/// <summary>
/// Kill a process, and all of its children, grandchildren, etc.
/// </summary>
/// <param name="pid">Process ID.</param>
public static void KillProcessAndChildren(int pid)
{
// Cannot close 'system idle process'.
if (pid == 0)
{
return;
}
ManagementObjectSearcher searcher = new ManagementObjectSearcher
("Select * From Win32_Process Where ParentProcessID=" + pid);
ManagementObjectCollection moc = searcher.Get();
foreach (ManagementObject mo in moc)
{
KillProcessAndChildren(Convert.ToInt32(mo["ProcessID"]));
}
try
{
Process proc = Process.GetProcessById(pid);
proc.Kill();
}
catch (ArgumentException)
{
// Process already exited.
}
}
}
I borrowed from many and I'm not sure where, but I thank you all and give you all credit... apologies for not referencing you directly, but this was instrumental.

c# - Add terminal process output to a list to use on other classes

I read this post to start a terminal process and modified a little code to get terminal output and use that output in other classes.
My code
using System;
using System.Diagnostics;
namespace runTerminal
{
class MainClass
{
public static List<string> ExecuteCommand(string command)
{
List<string> output = new List<string>();
Process proc = new System.Diagnostics.Process ();
proc.StartInfo.FileName = "/bin/bash";
proc.StartInfo.Arguments = "-c \" " + command + " \"";
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.Start();
while (!proc.StandardOutput.EndOfStream) {
Console.WriteLine(proc.StandardOutput.ReadLine());
output.Add(proc.StandardOutput.ReadLine());
}
return output;
}
public static void Main (string[] args)
{
List<string> result = ExecuteCommand("sudo nginx -t");
Console.WriteLine(result); // return null
}
}
}
But the output I got after executing commands is always null. Do I miss something?
while (!proc.StandardOutput.EndOfStream) {
Console.WriteLine(proc.StandardOutput.ReadLine());
output.Add(proc.StandardOutput.ReadLine());
}
That's a double read. You call proc.StandardOutput.ReadLine() two times in sequence. The first line will be printed, but then you attempt to read another line and store it in output. Do the following:
while (!proc.StandardOutput.EndOfStream) {
var read = proc.StandardOutput.ReadLine();
Console.WriteLine(read);
output.Add(read);
}
You also print it wrong. Since output is List<string>() you could do
Console.WriteLine(string.Join("\n", result));
To print it.
I believe you need to iterate over the List of strings:
public static void Main (string[] args)
{
List<string> result = ExecuteCommand("sudo nginx -t");
foreach (string output in result)
{
Console.WriteLine(output);
}
}

Listing of detailed COM port names using VisualStudio 2013 C#

I want to list the active COM ports with detailed names (like in Windows Device Manager).
I'm using this code and it works, but it is very slow. It can take up to 45 seconds to get a list of 5 COM ports!
Am I doing anything wrong here or is there a faster way to do this?
I know there are several postings about this, but I haven't found the right answer yet.
private void UpdateSerialPorts(RichTextBox _txtBox)
{
foreach (string portName in System.IO.Ports.SerialPort.GetPortNames())
{
string query = String.Format("SELECT * FROM Win32_PnPEntity WHERE Caption LIKE '%{0}%'", portName);
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", query);
ManagementObjectCollection coll = searcher.Get();
if (coll.Count > 0)
{
foreach (ManagementBaseObject collObj in coll)
{
ManagementBaseObject obj = collObj;
_txtBox.AppendText(portName + " " + obj.GetPropertyValue("Caption").ToString() + "\r\n");
}
}
else
{
_txtBox.AppendText(new SerialPort(portName).ToString() + "\r\n");
}
}
}

Set Image Name and Description for a process using System.Diagnostics.Process()

How to set Image Name and Description for a process when using System.Diagnostics.Process() to start a process?
So that it appears in the Windows task manager with desired name and description.
For Example currently I am invoking some console application as shown below:
static void Main(string[] args)
{
int incVal = 0;
Process[] process = null;
try
{
process = new Process[Properties.Settings.Default.TargetLayers.Length];
for (incVal = 0; incVal < Properties.Settings.Default.TargetLayers.Split(',').Length; incVal++)
{
process[incVal] = new Process();
process[incVal].StartInfo.FileName = "PMSchedulerTask.exe";
process[incVal].StartInfo.Arguments = "\"" + Properties.Settings.Default.TargetLayers.Split(',')[incVal] + "$" + Properties.Settings.Default.TableMVRelation.Split('|')[incVal] + "\"";
process[incVal].Start();
}
for (incVal = 0; incVal < Properties.Settings.Default.TargetLayers.Split(',').Length; incVal++)
{
process[incVal].WaitForExit();
}
}
catch (Exception ex)
{
throw ex;
}
}
Now I would like to have each process shown in the task manager with different Image Name and Description.
These names are extracted by task manager from the executable image the process was started from. There is no setting to override this. Windows doesn't even know these strings exist. They are just part of the PE structure of the executable used to launch the process.
You could create a wrapper executable if you really need to do this.

How to get the full path of running process?

I am having an application that is changing some settings of another application (it is a simple C# application that run by double clicking (no setup required)).
After changing the settings I need to restart the other application so that it reflects the changed settings.
So to do, I have to kill the running process and start the process again, But the problem is after killing I am not able to find the process. (Reason is system do not know where the exe file is..)
Is there any way to find out the path of running process or exe, if it is running?
I do not want to give path manually, i.e. if it is running get the path, kill the process and start again else .... I will handle later
using System.Diagnostics;
var process = Process.GetCurrentProcess(); // Or whatever method you are using
string fullPath = process.MainModule.FileName;
//fullPath has the path to exe.
There is one catch with this API, if you are running this code in 32 bit application, you'll not be able to access 64-bit application paths, so you'd have to compile and run you app as 64-bit application (Project Properties → Build → Platform Target → x64).
What you can do is use WMI to get the paths. This will allow you to get the path regardless it's a 32-bit or 64-bit application. Here's an example demonstrating how you can get it:
// include the namespace
using System.Management;
var wmiQueryString = "SELECT ProcessId, ExecutablePath, CommandLine FROM Win32_Process";
using (var searcher = new ManagementObjectSearcher(wmiQueryString))
using (var results = searcher.Get())
{
var query = from p in Process.GetProcesses()
join mo in results.Cast<ManagementObject>()
on p.Id equals (int)(uint)mo["ProcessId"]
select new
{
Process = p,
Path = (string)mo["ExecutablePath"],
CommandLine = (string)mo["CommandLine"],
};
foreach (var item in query)
{
// Do what you want with the Process, Path, and CommandLine
}
}
Note that you'll have to reference the System.Management.dll assembly and use the System.Management namespace.
For more info on what other information you can grab out of these processes such as the command line used to start the program (CommandLine), see the Win32_Process class and WMI .NET for for more information.
A solution for:
Both 32-bit AND 64-bit processes
System.Diagnostics only (no System.Management)
I used the solution from Russell Gantman and rewritten it as an extension method you can use like this:
var process = Process.GetProcessesByName("explorer").First();
string path = process.GetMainModuleFileName();
// C:\Windows\explorer.exe
With this implementation:
internal static class Extensions {
[DllImport("Kernel32.dll")]
private static extern bool QueryFullProcessImageName([In] IntPtr hProcess, [In] uint dwFlags, [Out] StringBuilder lpExeName, [In, Out] ref uint lpdwSize);
public static string GetMainModuleFileName(this Process process, int buffer = 1024) {
var fileNameBuilder = new StringBuilder(buffer);
uint bufferLength = (uint)fileNameBuilder.Capacity + 1;
return QueryFullProcessImageName(process.Handle, 0, fileNameBuilder, ref bufferLength) ?
fileNameBuilder.ToString() :
null;
}
}
I guess you already have the process object of the running process (e.g. by GetProcessesByName()).
You can then get the executable file name by using:
Process p;
string filename = p.MainModule.FileName;
By combining Sanjeevakumar Hiremath's and Jeff Mercado's answers you can actually in a way get around the problem when retrieving the icon from a 64-bit process in a 32-bit process.
using System;
using System.Management;
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int processID = 6680; // Change for the process you would like to use
Process process = Process.GetProcessById(processID);
string path = ProcessExecutablePath(process);
}
static private string ProcessExecutablePath(Process process)
{
try
{
return process.MainModule.FileName;
}
catch
{
string query = "SELECT ExecutablePath, ProcessID FROM Win32_Process";
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
foreach (ManagementObject item in searcher.Get())
{
object id = item["ProcessID"];
object path = item["ExecutablePath"];
if (path != null && id.ToString() == process.Id.ToString())
{
return path.ToString();
}
}
}
return "";
}
}
}
This may be a bit slow and doesn't work on every process which lacks a "valid" icon.
Here is a reliable solution that works with both 32bit and 64bit applications.
Add these references:
using System.Diagnostics;
using System.Management;
Add this method to your project:
public static string GetProcessPath(int processId)
{
string MethodResult = "";
try
{
string Query = "SELECT ExecutablePath FROM Win32_Process WHERE ProcessId = " + processId;
using (ManagementObjectSearcher mos = new ManagementObjectSearcher(Query))
{
using (ManagementObjectCollection moc = mos.Get())
{
string ExecutablePath = (from mo in moc.Cast<ManagementObject>() select mo["ExecutablePath"]).First().ToString();
MethodResult = ExecutablePath;
}
}
}
catch //(Exception ex)
{
//ex.HandleException();
}
return MethodResult;
}
Now use it like so:
int RootProcessId = Process.GetCurrentProcess().Id;
GetProcessPath(RootProcessId);
Notice that if you know the id of the process, then this method will return the corresponding ExecutePath.
Extra, for those interested:
Process.GetProcesses()
...will give you an array of all the currently running processes, and...
Process.GetCurrentProcess()
...will give you the current process, along with their information e.g. Id, etc. and also limited control e.g. Kill, etc.*
You can use pInvoke and a native call such as the following. This doesn't seem to have the 32 / 64 bit limitation (at least in my testing)
Here is the code
using System.Runtime.InteropServices;
[DllImport("Kernel32.dll")]
static extern uint QueryFullProcessImageName(IntPtr hProcess, uint flags, StringBuilder text, out uint size);
//Get the path to a process
//proc = the process desired
private string GetPathToApp (Process proc)
{
string pathToExe = string.Empty;
if (null != proc)
{
uint nChars = 256;
StringBuilder Buff = new StringBuilder((int)nChars);
uint success = QueryFullProcessImageName(proc.Handle, 0, Buff, out nChars);
if (0 != success)
{
pathToExe = Buff.ToString();
}
else
{
int error = Marshal.GetLastWin32Error();
pathToExe = ("Error = " + error + " when calling GetProcessImageFileName");
}
}
return pathToExe;
}
private void Test_Click(object sender, System.EventArgs e){
string path;
path = System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase );
Console.WriiteLine( path );
}
Try:
using System.Diagnostics;
ProcessModuleCollection modules = Process.GetCurrentProcess().Modules;
string processpathfilename;
string processmodulename;
if (modules.Count > 0) {
processpathfilename = modules[0].FileName;
processmodulename= modules[0].ModuleName;
} else {
throw new ExecutionEngineException("Something critical occurred with the running process.");
}
using System;
using System.Diagnostics;
class Program
{
public static void printAllprocesses()
{
Process[] processlist = Process.GetProcesses();
foreach (Process process in processlist)
{
try
{
String fileName = process.MainModule.FileName;
String processName = process.ProcessName;
Console.WriteLine("processName : {0}, fileName : {1}", processName, fileName);
}catch(Exception e)
{
/* You will get access denied exception for system processes, We are skiping the system processes here */
}
}
}
static void Main()
{
printAllprocesses();
}
}
For others, if you want to find another process of the same executable, you can use:
public bool tryFindAnotherInstance(out Process process) {
Process thisProcess = Process.GetCurrentProcess();
string thisFilename = thisProcess.MainModule.FileName;
int thisPId = thisProcess.Id;
foreach (Process p in Process.GetProcesses())
{
try
{
if (p.MainModule.FileName == thisFilename && thisPId != p.Id)
{
process = p;
return true;
}
}
catch (Exception)
{
}
}
process = default;
return false;
}
As of .NET 6, you can use Environment.ProcessPath.
In a test, you can see that it gives the same result as Process.GetCurrentProcess().MainModule.FileName:
It's possible to implement process query path using PInvoke on OpenProcess, GetModuleFileNameEx.
See full answer in here.
using System.Management;
ManagementObjectSearcher search = new ManagementObjectSearcher("SELECT * FROM
Win32_Process");
foreach (ManagementObject currentObj in search.Get())
{
if (currentObj["Caption"].ToString() == "sqlservr.exe")
MessageBox.Show(currentObj["ExecutablePath"].ToString());
}
The Process class has a member StartInfo that you should check out:
http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo_members(v=VS.71).aspx
I got to this thread while looking for the current directory of an executing process. In .net 1.1 Microsoft introduced:
Directory.GetCurrentDirectory();
Seems to work well (but doesn't return the name of the process itself).

Categories

Resources