Which process did I start? - c#

I want to get a handle to the main window of the process I just started by calling Process.Start().
This is easy when the process is not already running as the result of Process.Start() is not null:
var process = Process.Start(fileName);
if (process != null)
{
var handle = process.MainWindowHandle;
}
However if the process is already running then the result is null. In this case is there any way (managed or otherwise) to tell where the request was routed and which process consumed the start request?

For me, this seems like an XY-problem.
Before you start your own process, I would check if there already is a process running from the fileName you specified. If so, then use the handle of the process you found, otherwise start your own process.
If your fileName is an exe or bat or some other kind of executable, the method below should work. If it as a document or something like a document, I'm quite sure this method won't work without further adjustments.
Basically, the code would look like this (pseudo-code!):
//see below for method definition
List<Process> runningProcesses = ProcessUtil.GetProcessesForExecutable(fileName);
Process process;
if(runningProcesses.Count == 0)
{
process = Process.Start(fileName);
} else
{
process = runningProcesses[0];
// maybe some more code to handle more than one running process
}
var handle = process.MainWindowHandle;
All that is left is the implementation of ProcessUtil.GetProcessesForExecutable.
There are three possibillities to get a process by name resp. by executable name, but two of them have major downsides:
Process.GetProcessesByName(string)
Downside here is, that the process name may differ from the executable name. Thus you might not find a running process by giving this method a filename.
Process.GetProcesses() with either iterating over the whole array or some LINQ-select
Is safe in terms of executable name vs. process name, but quite slow with 700-800ms per execution in my tests.
The last possibility is using P/Invoke. Why P/Invoke? Turns out it was the fastest one with 5-6ms per execution in my tests.
I implemented this once in a project using P/Invoke, being inspired by pinvoke.net:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
namespace Util
{
/// <summary>
/// Utility methods for processes
/// </summary>
public static class ProcessUtil
{
//Code is inspired by http://www.pinvoke.net/default.aspx/kernel32.createtoolhelp32snapshot
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
static extern IntPtr CreateToolhelp32Snapshot([In]UInt32 dwFlags, [In]UInt32 th32ProcessID);
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool Process32First([In]IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool Process32Next([In]IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
[DllImport("kernel32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle([In] IntPtr hObject);
//inner enum used only internally
[Flags]
private enum SnapshotFlags : uint
{
HeapList = 0x00000001,
Process = 0x00000002,
Thread = 0x00000004,
Module = 0x00000008,
Module32 = 0x00000010,
Inherit = 0x80000000,
All = 0x0000001F,
NoHeaps = 0x40000000
}
//inner struct used only internally
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct PROCESSENTRY32
{
const int MAX_PATH = 260;
internal UInt32 dwSize;
internal UInt32 cntUsage;
internal UInt32 th32ProcessID;
internal IntPtr th32DefaultHeapID;
internal UInt32 th32ModuleID;
internal UInt32 cntThreads;
internal UInt32 th32ParentProcessID;
internal Int32 pcPriClassBase;
internal UInt32 dwFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
internal string szExeFile;
}
/// <summary>
/// Returns a list with running processes for a given executable path.
/// </summary>
/// <param name="exec">full path to the executable</param>
/// <returns>a list containing all processes currently run by the given executable</returns>
public static List<Process> GetProcessesForExecutable(string exec)
{
List<Process> toReturn = new List<Process>();
IntPtr handleToSnapShot = IntPtr.Zero;
FileInfo fi = new FileInfo(exec);
if (!fi.Exists)
{
return toReturn;
}
try
{
PROCESSENTRY32 procEntry = new PROCESSENTRY32();
procEntry.dwSize = (UInt32)Marshal.SizeOf(typeof(PROCESSENTRY32));
handleToSnapShot = CreateToolhelp32Snapshot((uint)SnapshotFlags.Process, 0);
if (Process32First(handleToSnapShot, ref procEntry))
{
do
{
if (fi.Name.Equals(procEntry.szExeFile))
{
Process p = Process.GetProcessById((int)procEntry.th32ProcessID);
if (p.MainModule.FileName.Equals(fi.FullName))
toReturn.Add(p);
}
} while (Process32Next(handleToSnapShot, ref procEntry));
}
}
catch (Exception ex)
{
//some error handling would be neccessary here
}
finally
{
CloseHandle(handleToSnapShot);
}
return toReturn;
}
}
}

Related

How to find list of JobObjects that are assigned to the current process?

I'm running a program in C#, and I want to know the list of JobObjects that are assigned to the current process. Is there a way to do this?
To be more specific about my use-case, I'm trying to find the memory limit of the current process. The problem is that the function that returns the limits, returns the limits of the last one. So, if 1 JobObject is assigned to the current process, it is simple, but otherwise I don't understand how do it. It is demonstrated in the example below:
[DllImport("kernel32.dll", SetLastError = true), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateJobObjectW(IntPtr securityAttrs, [MarshalAs(UnmanagedType.LPWStr)] string name);
[DllImport("kernel32.dll", SetLastError = true), SuppressUnmanagedCodeSecurity]
public static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool QueryInformationJobObject(IntPtr hJob, JobObjectInfoType infoClass, IntPtr info, UInt32 infoLength, IntPtr returnLength);
public static IntPtr CreateAndAssignJobObject(string name)
{
var jobObjectHandle = CreateJobObjectW(securityAttrs: IntPtr.Zero, name);
var processHandle = Process.GetCurrentProcess().Handle;
AssignProcessToJobObject(jobObjectHandle, processHandle);
return jobObjectHandle;
}
public static void LimitJobObjectMemory(IntPtr jobObjectHandle, ulong memoryLimit)
{
// Set the memory limit of the JobObject to 'memoryLimit'
}
/// <summary>
/// Gets a struct containing the extended limit information for the job object.
/// </summary>
private static JOBOBJECT_EXTENDED_LIMIT_INFORMATION GetExtendedLimitInformation()
{
var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION();
int infoSize = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
IntPtr extendedInfoPtr = Marshal.AllocHGlobal(infoSize);
try
{
Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);
if (!QueryInformationJobObject(
IntPtr.Zero,
JobObjectInfoType.ExtendedLimitInformation,
extendedInfoPtr,
(UInt32)infoSize,
IntPtr.Zero))
{
throw new UtilsException($"QueryInformationJobObject failed; err={Marshal.GetLastWin32Error()}");
}
extendedInfo = (JOBOBJECT_EXTENDED_LIMIT_INFORMATION)Marshal.PtrToStructure(extendedInfoPtr, typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
}
finally
{
Marshal.FreeHGlobal(extendedInfoPtr);
}
return extendedInfo;
}
public static void Main()
{
var job1Handle = CreateAndAssignJobObject("job1");
LimitJobObjectMemory(job1Handle, 4_000_000_000);
var job2Handle = CreateAndAssignJobObject("job2");
}
I'll explain what happens in the code: I create the first JobObject (job1Handle), limit its memory, and then create the second JobObject. Now, when I request the limits of the current process, I get the limits defined in the last JobObject. How can I get an aggregation (minimum, for instance) of the memory limit in all JobObjects of the process? Or more generally, how to enumerate the JobObjects assigned to the process?

Getting Symbols from debugged process MainModule

I started writing a debugger in C#, to debug any process on my operating system. For now, it only can handle breakpoints (HW, SW, and Memory), but now I wanted to show the opcode of the process.
My first attempt was with nidsasm (NASM), but this is not suitable, because after startup a.Net Application assembler instructions are different from ndisasm (tested with CheatEngine).
So I searched a while and found some methods from the dbghelp.dll which can be called to list all loaded modules and symbols (plus the base address). Ok, my attempt is, to disassemble all modules separately with SharpDisasm.
I use ProcessModuleCollection modules = ProcessData.Instance.MPMR.ReadProcess.Modules; to get all loaded modules of the process. This works perfectly.
Now I tried to load the symbols of the MainModule, but at this point, I stuck with the implementation. I implemented the SymEnumSymbols Function with p/Invoke and other necessary functions like SymInitialize.
When I call it with a BaseAddress of for example the "User32.dll", all symbols are printed perfectly, but for the MainModule, I didn't get any symbols.
This is a screenshot from CheatEngine:
Symbols gained from Cheat Engine
As you can see, there are symbols like "Form1_Load", which I don't get with my implementation.
This is the necessary code sample:
if (!DebugApi.SymInitialize(ProcessData.Instance.MPMR.M_hProcess, null, false))
{
var err = Marshal.GetLastWin32Error();
//throw new Exception("GetMemoryInfo failed : GetLastError() : " + new Win32Exception(err).Message);
Console.WriteLine("GetMemoryInfo failed : GetLastError() : " + new Win32Exception(err).Message);
return;
}
if (!DebugApi.SymEnumSymbols(ProcessData.Instance.MPMR.M_hProcess, (ulong)ProcessData.Instance.MPMR.ReadProcess.MainModule.BaseAddress, "!", DebugApi.EnumSyms, IntPtr.Zero))
{
var err = Marshal.GetLastWin32Error();
//throw new Exception("GetMemoryInfo failed : GetLastError() : " + new Win32Exception(err).Message);
Console.WriteLine("GetMemoryInfo failed : GetLastError() : " + new Win32Exception(err).Message);
return;
}
DebugApi.SymCleanup(ProcessData.Instance.MPMR.M_hProcess);
And my DebugApi, with all necessary p/Invoke functions.
public class DebugApi
{
[DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SymInitialize(IntPtr hProcess, string UserSearchPath, [MarshalAs(UnmanagedType.Bool)]bool fInvadeProcess);
[DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SymCleanup(IntPtr hProcess);
[DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern ulong SymLoadModuleEx(IntPtr hProcess, IntPtr hFile, string ImageName, string ModuleName, long BaseOfDll, int DllSize, IntPtr Data, int Flags);
[DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SymEnumSymbols(IntPtr hProcess, ulong BaseOfDll, string Mask, PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, IntPtr UserContext);
public delegate bool PSYM_ENUMERATESYMBOLS_CALLBACK(ref SYMBOL_INFO pSymInfo, uint SymbolSize, IntPtr UserContext);
public static bool EnumSyms(ref SYMBOL_INFO pSymInfo, uint SymbolSize, IntPtr UserContext)
{
Console.Out.WriteLine("Name: " + pSymInfo.Name);
return true;
}
[Flags]
public enum SymFlag : uint
{
VALUEPRESENT = 0x00000001,
REGISTER = 0x00000008,
REGREL = 0x00000010,
FRAMEREL = 0x00000020,
PARAMETER = 0x00000040,
LOCAL = 0x00000080,
CONSTANT = 0x00000100,
EXPORT = 0x00000200,
FORWARDER = 0x00000400,
FUNCTION = 0x00000800,
VIRTUAL = 0x00001000,
THUNK = 0x00002000,
TLSREL = 0x00004000,
}
[Flags]
public enum SymTagEnum : uint
{
Null,
Exe,
Compiland,
CompilandDetails,
CompilandEnv,
Function,
Block,
Data,
Annotation,
Label,
PublicSymbol,
UDT,
Enum,
FunctionType,
PointerType,
ArrayType,
BaseType,
Typedef,
BaseClass,
Friend,
FunctionArgType,
FuncDebugStart,
FuncDebugEnd,
UsingNamespace,
VTableShape,
VTable,
Custom,
Thunk,
CustomType,
ManagedType,
Dimension
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SYMBOL_INFO
{
public uint SizeOfStruct;
public uint TypeIndex;
public ulong Reserved1;
public ulong Reserved2;
public uint Reserved3;
public uint Size;
public ulong ModBase;
public SymFlag Flags;
public ulong Value;
public ulong Address;
public uint Register;
public uint Scope;
public SymTagEnum Tag;
public int NameLen;
public int MaxNameLen;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string Name;
}
}
My Functions should be ok, because it works with other Modules (loaded dll's for example). Maybe I don't understand the concept of symbols of a .Net Executable or missing something.
can it be that you are looking for System.Diagnostics.SymbolStore.ISymbolScope.
Have a look at the class SymbolAccess, you can use it to gain access to ISymbolScope.GetLocals() that returns ISymbolVariable[] and GetChildren() again returning in this time an array called ISymbolVariable[]
Now another interesting set of reference code samples is the Debugger extension lets you "snif" the values as shown here

Set existing service to "Auto (Delayed start)"

I'm trying to set an already installed windows service to automatic delayed start in C#. How do I set a windows service to
Automatic (Delayed Start)
Can't find that value in the ServiceStartMode enum.
Edit:1
public class ServiceAutoStartInfo
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct SERVICE_DELAYED_AUTO_START_INFO
{
public bool fDelayedAutostart;
}
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ChangeServiceConfig2(IntPtr hService, int dwInfoLevel, IntPtr lpInfo);
// Service configuration parameter
const int SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3;
public bool ChangeDelayedAutoStart(IntPtr hService, bool delayed)
{
// Validate service handle
if (hService != IntPtr.Zero)
{
// Create
SERVICE_DELAYED_AUTO_START_INFO info = new SERVICE_DELAYED_AUTO_START_INFO();
// Set the DelayedAutostart property
info.fDelayedAutostart = delayed;
// Allocate necessary memory
IntPtr hInfo = Marshal.AllocHGlobal(Marshal.SizeOf(
typeof(SERVICE_DELAYED_AUTO_START_INFO)));
// Convert structure to pointer
Marshal.StructureToPtr(info, hInfo, true);
// Change the configuration
bool result = ChangeServiceConfig2(hService, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, hInfo);
// Release memory
Marshal.FreeHGlobal(hInfo);
return result;
}
return false;
}
}
This is how I call it:
var controller = new ServiceController(s.ServiceName);
var autoDelay = new ServiceAutoStartInfo();
autoDelay.ChangeDelayedAutoStart(controller.ServiceHandle.DangerousGetHandle(), true);
But with no result.
Look into calling the Windows ChangeServiceConfig2 function, with dwInfoLevel of SERVICE_CONFIG_DELAYED_AUTO_START_INFO and a SERVICE_DELAYED_AUTO_START_INFO struct with fDelayedAutostart set to TRUE.
Or, you can do this with the command line:
sc.exe config <servicename> start= delayed-auto
I'm using the following, which works for me on Windows 7 (when run as admin):
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.ServiceProcess;
namespace ServiceManager
{
/// <summary>
/// Extensions to the ServiceController class.
/// </summary>
public static class ServiceControlerExtensions
{
/// <summary>
/// Set the start mode for the service.
/// </summary>
/// <param name="serviceController">The service controller.</param>
/// <param name="mode">The desired start mode.</param>
public static void SetStartMode(this ServiceController serviceController, ServiceStartModeEx mode)
{
IntPtr serviceManagerHandle = OpenServiceManagerHandle();
IntPtr serviceHandle = OpenServiceHandle(serviceController, serviceManagerHandle);
try
{
if (mode == ServiceStartModeEx.DelayedAutomatic)
{
ChangeServiceStartType(serviceHandle, ServiceStartModeEx.Automatic);
ChangeDelayedAutoStart(serviceHandle, true);
}
else
{
// Delayed auto-start overrides other settings, so it must be set first.
ChangeDelayedAutoStart(serviceHandle, false);
ChangeServiceStartType(serviceHandle, mode);
}
}
finally
{
if (serviceHandle != IntPtr.Zero)
{
CloseServiceHandle(serviceHandle);
}
if (serviceHandle != IntPtr.Zero)
{
CloseServiceHandle(serviceManagerHandle);
}
}
}
private static IntPtr OpenServiceHandle(ServiceController serviceController, IntPtr serviceManagerHandle)
{
var serviceHandle = OpenService(
serviceManagerHandle,
serviceController.ServiceName,
SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG);
if (serviceHandle == IntPtr.Zero)
{
throw new ExternalException("Open Service Error");
}
return serviceHandle;
}
private static IntPtr OpenServiceManagerHandle()
{
IntPtr serviceManagerHandle = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS);
if (serviceManagerHandle == IntPtr.Zero)
{
throw new ExternalException("Open Service Manager Error");
}
return serviceManagerHandle;
}
private static void ChangeServiceStartType(IntPtr serviceHandle, ServiceStartModeEx mode)
{
bool result = ChangeServiceConfig(
serviceHandle,
SERVICE_NO_CHANGE,
(uint)mode,
SERVICE_NO_CHANGE,
null,
null,
IntPtr.Zero,
null,
null,
null,
null);
if (result == false)
{
ThrowLastWin32Error("Could not change service start type");
}
}
private static void ChangeDelayedAutoStart(IntPtr hService, bool delayed)
{
// Create structure that contains DelayedAutoStart property.
SERVICE_DELAYED_AUTO_START_INFO info = new SERVICE_DELAYED_AUTO_START_INFO();
// Set the DelayedAutostart property in that structure.
info.fDelayedAutostart = delayed;
// Allocate necessary memory.
IntPtr hInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SERVICE_DELAYED_AUTO_START_INFO)));
// Convert structure to pointer.
Marshal.StructureToPtr(info, hInfo, true);
// Change the configuration.
bool result = ChangeServiceConfig2(hService, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, hInfo);
// Release memory.
Marshal.FreeHGlobal(hInfo);
if (result == false)
{
ThrowLastWin32Error("Could not set service to delayed automatic");
}
}
private static void ThrowLastWin32Error(string messagePrefix)
{
int nError = Marshal.GetLastWin32Error();
var win32Exception = new Win32Exception(nError);
string message = string.Format("{0}: {1}", messagePrefix, win32Exception.Message);
throw new ExternalException(message);
}
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr OpenService(
IntPtr hSCManager,
string lpServiceName,
uint dwDesiredAccess);
[DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode,
SetLastError = true)]
private static extern IntPtr OpenSCManager(
string machineName,
string databaseName,
uint dwAccess);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern Boolean ChangeServiceConfig(
IntPtr hService,
UInt32 nServiceType,
UInt32 nStartType,
UInt32 nErrorControl,
String lpBinaryPathName,
String lpLoadOrderGroup,
IntPtr lpdwTagId,
[In] char[] lpDependencies,
String lpServiceStartName,
String lpPassword,
String lpDisplayName);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ChangeServiceConfig2(
IntPtr hService,
int dwInfoLevel,
IntPtr lpInfo);
[DllImport("advapi32.dll", EntryPoint = "CloseServiceHandle")]
private static extern int CloseServiceHandle(IntPtr hSCObject);
private const uint SERVICE_NO_CHANGE = 0xFFFFFFFF;
private const uint SERVICE_QUERY_CONFIG = 0x00000001;
private const uint SERVICE_CHANGE_CONFIG = 0x00000002;
private const uint SC_MANAGER_ALL_ACCESS = 0x000F003F;
private const int SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct SERVICE_DELAYED_AUTO_START_INFO
{
public bool fDelayedAutostart;
}
}
}
namespace ServiceManager
{
public enum ServiceStartModeEx
{
Automatic = 2,
Manual = 3,
Disabled = 4,
DelayedAutomatic = 99
}
}
You call it like this:
var serviceController = new ServiceController("Windows Update");
try
{
serviceController.SetStartMode(ServiceStartModeEx.DelayedAutomatic);
}
finally
{
serviceController.Close();
}
Update: This only works for setting up new services and is not what the OP asked for:
You can use the DelayedAutoStart property of the ServiceInstaller.
installer.DelayedAutoStart = true;
I believe you need to combine both methods ChangeServiceConfig and ChangeServiceConfig2.
pseudo-code follows:
public static void ChangeServiceStartupType(ServiceStartupType type, ...)
{
if (type == AutomaticDelayed)
{
if (ChangeServiceConfig2(.., DelayedAutoStart, ..))
{
ChangeServiceConfig(.., Automatic, ..);
}
}
else
{
ChangeServiceConfig2(.., !DelayedAutoStart, ..)
ChangeServiceConfig(.., type, ..)
}
}
edit: you also need to remove "delayed-automatic" when requesting non-delayed startup-type. Otherwise it won't be possible to set "automatic" type. ("automatic-delayed" overrides "automatic")
SERVICE_DELAYED_AUTO_START_INFO structure documentation states:
fDelayedAutostart
If this member is TRUE, the service is started after other auto-start
services are started plus a short delay. Otherwise, the service is
started during system boot.
This setting is ignored unless the service is an auto-start service.
https://learn.microsoft.com/en-us/windows/win32/api/winsvc/ns-winsvc-service_delayed_auto_start_info?redirectedfrom=MSDN#members
So I think if the service is not auto-start it won't change it to auto delayed, you would have to use sc.exe

How do Asynchronous Procedure Calls handle marshaled delegates when you P/Invoke from C#?

I am wondering if it is possible to fall victim to issues around the management of managed threads in the native world when you marshal a callback delegate to a DLL through P/Invoke in my particular case below (see example code).
This MSDN article on Managed and Unmanaged Threading in Windows states:
"An operating-system ThreadId has no fixed relationship to a managed thread, because an unmanaged host can control the relationship between managed and unmanaged threads. Specifically, a sophisticated host can use the Fiber API to schedule many managed threads against the same operating system thread, or to move a managed thread among different operating system threads."
First of all, who or what is the unmanaged host this article describes? If you use marshaling like in the example code I give below, then who or what is the unmanaged host there?
Also, this StackOverflow question's accepted answer states:
"It's perfectly legal from a CLR perspective for a single managed thread to be backed by several different native threads during it's lifetime. This means the result of GetCurrentThreadId can (and will) change throughout the course of a thread's lifetime."
So, does this mean my APC will be queued in a native thread, or delegated directly to my managed thread because of the marshaling layer?
Here is the example. Let's say I use the following class to P/Invoke the NotifyServiceStatusChange function in managed code to check when a service is stopped:
using System;
using System.Runtime.InteropServices;
namespace ServiceStatusChecking
{
class QueryServiceStatus
{
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public class SERVICE_NOTIFY
{
public uint dwVersion;
public IntPtr pfnNotifyCallback;
public IntPtr pContext;
public uint dwNotificationStatus;
public SERVICE_STATUS_PROCESS ServiceStatus;
public uint dwNotificationTriggered;
public IntPtr pszServiceNames;
};
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct SERVICE_STATUS_PROCESS
{
public uint dwServiceType;
public uint dwCurrentState;
public uint dwControlsAccepted;
public uint dwWin32ExitCode;
public uint dwServiceSpecificExitCode;
public uint dwCheckPoint;
public uint dwWaitHint;
public uint dwProcessId;
public uint dwServiceFlags;
};
[DllImport("advapi32.dll")]
static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);
[DllImport("advapi32.dll")]
static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);
[DllImport("advapi32.dll")]
static extern uint NotifyServiceStatusChange(IntPtr hService, uint dwNotifyMask, IntPtr pNotifyBuffer);
[DllImportAttribute("kernel32.dll")]
static extern uint SleepEx(uint dwMilliseconds, bool bAlertable);
[DllImport("advapi32.dll")]
static extern bool CloseServiceHandle(IntPtr hSCObject);
delegate void StatusChangedCallbackDelegate(IntPtr parameter);
/// <summary>
/// Block until a service stops or is found to be already dead.
/// </summary>
/// <param name="serviceName">The name of the service you would like to wait for.</param>
public static void WaitForServiceToStop(string serviceName)
{
IntPtr hSCM = OpenSCManager(null, null, (uint)0xF003F);
if (hSCM != IntPtr.Zero)
{
IntPtr hService = OpenService(hSCM, serviceName, (uint)0xF003F);
if (hService != IntPtr.Zero)
{
StatusChangedCallbackDelegate changeDelegate = ReceivedStatusChangedEvent;
SERVICE_NOTIFY notify = new SERVICE_NOTIFY();
notify.dwVersion = 2;
notify.pfnNotifyCallback = Marshal.GetFunctionPointerForDelegate(changeDelegate);
notify.ServiceStatus = new SERVICE_STATUS_PROCESS();
GCHandle notifyHandle = GCHandle.Alloc(notify, GCHandleType.Pinned);
IntPtr pinnedNotifyStructure = notifyHandle.AddrOfPinnedObject();
NotifyServiceStatusChange(hService, (uint)0x00000001, pinnedNotifyStructure);
SleepEx(uint.MaxValue, true);
notifyHandle.Free();
CloseServiceHandle(hService);
}
CloseServiceHandle(hSCM);
}
}
public static void ReceivedStatusChangedEvent(IntPtr parameter)
{
}
}
}
Is the APC queued onto whichever native thread was hosting my managed thread, or is the APC delegated directly to my managed thread? I thought the delegate was there to handle exactly this case, so that we don't need to worry about how managed threads are handled natively, but I could be wrong!
Edit: I guess this is a more agreeable answer.
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace ServiceAssistant
{
class ServiceHelper
{
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public class SERVICE_NOTIFY
{
public uint dwVersion;
public IntPtr pfnNotifyCallback;
public IntPtr pContext;
public uint dwNotificationStatus;
public SERVICE_STATUS_PROCESS ServiceStatus;
public uint dwNotificationTriggered;
public IntPtr pszServiceNames;
};
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct SERVICE_STATUS_PROCESS
{
public uint dwServiceType;
public uint dwCurrentState;
public uint dwControlsAccepted;
public uint dwWin32ExitCode;
public uint dwServiceSpecificExitCode;
public uint dwCheckPoint;
public uint dwWaitHint;
public uint dwProcessId;
public uint dwServiceFlags;
};
[DllImport("advapi32.dll")]
static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);
[DllImport("advapi32.dll")]
static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);
[DllImport("advapi32.dll")]
static extern uint NotifyServiceStatusChange(IntPtr hService, uint dwNotifyMask, IntPtr pNotifyBuffer);
[DllImportAttribute("kernel32.dll")]
static extern uint SleepEx(uint dwMilliseconds, bool bAlertable);
[DllImport("advapi32.dll")]
static extern bool CloseServiceHandle(IntPtr hSCObject);
delegate void StatusChangedCallbackDelegate(IntPtr parameter);
/// <summary>
/// Block until a service stops or is found to be already dead.
/// </summary>
/// <param name="serviceName">The name of the service you would like to wait for.</param>
/// <param name="timeout">An amount of time you would like to wait for. uint.MaxValue is the default, and it will force this thread to wait indefinitely.</param>
public static void WaitForServiceToStop(string serviceName, uint timeout = uint.MaxValue)
{
Thread.BeginThreadAffinity();
GCHandle? notifyHandle = null;
StatusChangedCallbackDelegate changeDelegate = ReceivedStatusChangedEvent;
IntPtr hSCM = OpenSCManager(null, null, (uint)0xF003F);
if (hSCM != IntPtr.Zero)
{
IntPtr hService = OpenService(hSCM, serviceName, (uint)0xF003F);
if (hService != IntPtr.Zero)
{
SERVICE_NOTIFY notify = new SERVICE_NOTIFY();
notify.dwVersion = 2;
notify.pfnNotifyCallback = Marshal.GetFunctionPointerForDelegate(changeDelegate);
notify.ServiceStatus = new SERVICE_STATUS_PROCESS();
notifyHandle = GCHandle.Alloc(notify, GCHandleType.Pinned);
IntPtr pinnedNotifyStructure = ((GCHandle)notifyHandle).AddrOfPinnedObject();
NotifyServiceStatusChange(hService, (uint)0x00000001, pinnedNotifyStructure);
SleepEx(timeout, true);
CloseServiceHandle(hService);
}
CloseServiceHandle(hSCM);
}
GC.KeepAlive(changeDelegate);
if (notifyHandle != null)
{
((GCHandle)notifyHandle).Free();
}
Thread.EndThreadAffinity();
}
public static void ReceivedStatusChangedEvent(IntPtr parameter)
{
}
}
}
Edit again! I guess THIS is an even MORE agreeable answer:
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace ServiceAssistant
{
class ServiceHelper
{
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public class SERVICE_NOTIFY
{
public uint dwVersion;
public IntPtr pfnNotifyCallback;
public IntPtr pContext;
public uint dwNotificationStatus;
public SERVICE_STATUS_PROCESS ServiceStatus;
public uint dwNotificationTriggered;
public IntPtr pszServiceNames;
};
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct SERVICE_STATUS_PROCESS
{
public uint dwServiceType;
public uint dwCurrentState;
public uint dwControlsAccepted;
public uint dwWin32ExitCode;
public uint dwServiceSpecificExitCode;
public uint dwCheckPoint;
public uint dwWaitHint;
public uint dwProcessId;
public uint dwServiceFlags;
};
[DllImport("advapi32.dll")]
static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);
[DllImport("advapi32.dll")]
static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);
[DllImport("advapi32.dll")]
static extern uint NotifyServiceStatusChange(IntPtr hService, uint dwNotifyMask, IntPtr pNotifyBuffer);
[DllImportAttribute("kernel32.dll")]
static extern uint SleepEx(uint dwMilliseconds, bool bAlertable);
[DllImport("advapi32.dll")]
static extern bool CloseServiceHandle(IntPtr hSCObject);
delegate void StatusChangedCallbackDelegate(IntPtr parameter);
/// <summary>
/// Block until a service stops, is killed, or is found to be already dead.
/// </summary>
/// <param name="serviceName">The name of the service you would like to wait for.</param>
/// <param name="timeout">An amount of time you would like to wait for. uint.MaxValue is the default, and it will force this thread to wait indefinitely.</param>
public static void WaitForServiceToStop(string serviceName, uint timeout = uint.MaxValue)
{
// Ensure that this thread's identity is mapped, 1-to-1, with a native OS thread.
Thread.BeginThreadAffinity();
GCHandle notifyHandle = default(GCHandle);
StatusChangedCallbackDelegate changeDelegate = ReceivedStatusChangedEvent;
IntPtr hSCM = IntPtr.Zero;
IntPtr hService = IntPtr.Zero;
try
{
hSCM = OpenSCManager(null, null, (uint)0xF003F);
if (hSCM != IntPtr.Zero)
{
hService = OpenService(hSCM, serviceName, (uint)0xF003F);
if (hService != IntPtr.Zero)
{
SERVICE_NOTIFY notify = new SERVICE_NOTIFY();
notify.dwVersion = 2;
notify.pfnNotifyCallback = Marshal.GetFunctionPointerForDelegate(changeDelegate);
notify.ServiceStatus = new SERVICE_STATUS_PROCESS();
notifyHandle = GCHandle.Alloc(notify, GCHandleType.Pinned);
IntPtr pinnedNotifyStructure = notifyHandle.AddrOfPinnedObject();
NotifyServiceStatusChange(hService, (uint)0x00000001, pinnedNotifyStructure);
SleepEx(timeout, true);
}
}
}
finally
{
// Clean up at the end of our operation, or if this thread is aborted.
if (hService != IntPtr.Zero)
{
CloseServiceHandle(hService);
}
if (hSCM != IntPtr.Zero)
{
CloseServiceHandle(hSCM);
}
GC.KeepAlive(changeDelegate);
if (notifyHandle != default(GCHandle))
{
notifyHandle.Free();
}
Thread.EndThreadAffinity();
}
}
public static void ReceivedStatusChangedEvent(IntPtr parameter)
{
}
}
}
Yes, it is possible to fall victim to these issues. In this particular case it is difficult. The host can't switch the managed thread to a different OS thread while a native frame is on the managed thread's stack, and since you immediately p/invoke SleepEx, the window for the host to switch the managed thread is between the two p/invoke calls. Still, it is sometimes a disagreeable possibility when you need to p/invoke on the same OS thread and Thread.BeginThreadAffinity() exists to cover this scenario.
Now for the APC question. Remember that the OS knows nothing about managed threads. So the APC will be delivered into the original native thread when it does something alertable. I don't know how the CLR host creates managed contexts in these cases, but if managed threads are one-to-one with OS threads the callback will probably use the managed thread's context.
UPDATE Your new code is much safer now, but you went a bit too far in the other direction:
1) There is no need to wrap the whole code with thread affinity. Wrap just the two p/invokes that do need to run on the same OS thread (Notify and Sleep). It does not matter whether you use a finite timeout, because the problem you're solving with thread affinity is a managed-to-OS thread migration between the two p/invokes. The callback should not assume it is running on any particular managed thread anyway, because there is little it can safely do, and little it should do: interlocked operations, setting events and completing TaskCompletionSources is about it.
2) GCHandle is a simple, IntPtr-sized struct, and can be compared for equality. Instead of using GCHandle?, use plain GCHandle and compare to default(GCHandle). Besides, GCHandle? looks fishy to me on general principles.
3) Notification stops when you close the service handle. The SCM handle can stay open, you might want to keep it around for the next check.
// Thread.BeginThreadAffinity();
// GCHandle? notifyHandle = null;
var hSCM = OpenSCManager(null, null, (uint)0xF003F);
if (hSCM != IntPtr.Zero)
{
StatusChangedCallbackDelegate changeDelegate = ReceivedStatusChangedEvent;
var notifyHandle = default(GCHandle);
var hService = OpenService(hSCM, serviceName, (uint)0xF003F);
if (hService != IntPtr.Zero)
{
...
notifyHandle = GCHandle.Alloc(notify, GCHandleType.Pinned);
var addr = notifyHandle.AddrOfPinnedObject();
Thread.BeginThreadAffinity();
NotifyServiceStatusChange(hService, (uint)0x00000001, addr);
SleepEx(timeout, true);
Thread.EndThreadAffinity();
CloseServiceHandle(hService);
}
GC.KeepAlive(changeDelegate);
if (notifyHandle != default(GCHandle))
notifyHandle.Free();
CloseServiceHandle(hSCM);
}
Also, to be as safe as possible, if your code is going to run for a long time, or if you're writing a library, you must use constrained regions and/or SafeHandles to ensure your cleanup routines run even if the thread is aborted. Look at all the hoops BCL code jumps through in, e.g., System.Threading.Mutex (use Reflector or the CLR source). At the very least, use SafeHandles and try/finally to free the GCHandle and end thread affinity.
As for callback-related problems, these are just a bad case of normal multi-threading sort of problems: deadlocks, livelocks, priority inversion etc. The worst thing about this sort of APC callback is that (unless you block the whole thread yourself until it happens, in which case it's easier just to block in native code) you don't control when it happens: your thread might be deep inside BCL waiting for I/O, for an event to be signaled, etc., and it is very difficult to reason about the state the program might be in.
Asynchronous procedure calls exist completely on the native side. APC's know nothing of managed threads nor of marshaling. NotifyServiceStatusChange would have to call (or use the equivalent of) QueueUserAPC to dispatch the APC, which only takes an native thread handle. So, the APC will be queued to the native thread that calls NotifyServiceStatusChange.
So this APC being queued and dispatched correctly rely on two things:
The CLR keeps the native thread that it called NotifyServiceStatusChange.
The CLR puts that native thread into an alterable wait.
You control neither of these two things.

C# Process Killing

I need to write a program in c# that would just start, kill one process\exe that it is supposed to kill and end itself.
The process I need to kill is another C# application so it is a local user process and I know the path to the exe.
Check out Process.GetProcessesByName and Process.Kill
// Get all instances of Notepad running on the local
// computer.
Process [] localByName = Process.GetProcessesByName("notepad");
foreach(Process p in localByName)
{
p.Kill();
}
First search all processes for the process you want to kill, than kill it.
Process[] runningProcesses = Process.GetProcesses();
foreach (Process process in runningProcesses)
{
// now check the modules of the process
foreach (ProcessModule module in process.Modules)
{
if (module.FileName.Equals("MyProcess.exe"))
{
process.Kill();
}
}
}
Killing processes by their name can be easily done in C# (as the other answers already showed perfectly). If you however want to kill processes based on the full path of the executable things get more tricky. One way to do that would be to use WMI, another way would be to use the Module32First Windows API function.
The sample below uses the latter approach. It first selects a subset of the running processes by their name and then queries each of these processes for their full executable path. Note that this path will be the actual path of the image being executed, which is not necessarily the executable that was launched (e.g. on x64 systems the actual path to calc.exe will be C:\Windows\SysWOW64\calc.exe even if the file C:\Windows\system32\calc.exe was started). All processes with a matching path are returned by GetProcessesByPath:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
class Program
{
static void Main(string[] args)
{
Process[] processList = GetProcessesByPath(#"C:\Program Files\MyCalculator\calc.exe");
foreach (var process in processList)
{
if (!process.HasExited)
process.Kill();
}
}
static Process[] GetProcessesByPath(string path)
{
List<Process> result = new List<Process>();
string processName = Path.GetFileNameWithoutExtension(path);
foreach (var process in Process.GetProcessesByName(processName))
{
ToolHelpHandle hModuleSnap = NativeMethods.CreateToolhelp32Snapshot(NativeMethods.SnapshotFlags.Module, (uint)process.Id);
if (!hModuleSnap.IsInvalid)
{
NativeMethods.MODULEENTRY32 me32 = new NativeMethods.MODULEENTRY32();
me32.dwSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(me32);
if (NativeMethods.Module32First(hModuleSnap, ref me32))
{
if (me32.szExePath == path)
{
result.Add(process);
}
}
hModuleSnap.Close();
}
}
return result.ToArray();
}
}
//
// The safe handle class is used to safely encapsulate win32 handles below
//
public class ToolHelpHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private ToolHelpHandle()
: base(true)
{
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
return NativeMethods.CloseHandle(handle);
}
}
//
// The following p/invoke wrappers are used to get the list of process and modules
// running inside each process.
//
public class NativeMethods
{
[DllImport("kernel32.dll", SetLastError = true)]
static public extern bool CloseHandle(IntPtr hHandle);
[DllImport("kernel32.dll")]
static public extern bool Module32First(ToolHelpHandle hSnapshot, ref MODULEENTRY32 lpme);
[DllImport("kernel32.dll")]
static public extern bool Module32Next(ToolHelpHandle hSnapshot, ref MODULEENTRY32 lpme);
[DllImport("kernel32.dll")]
static public extern bool Process32First(ToolHelpHandle hSnapshot, ref PROCESSENTRY32 lppe);
[DllImport("kernel32.dll")]
static public extern bool Process32Next(ToolHelpHandle hSnapshot, ref PROCESSENTRY32 lppe);
[DllImport("kernel32.dll", SetLastError = true)]
static public extern ToolHelpHandle CreateToolhelp32Snapshot(SnapshotFlags dwFlags, uint th32ProcessID);
public const short INVALID_HANDLE_VALUE = -1;
[Flags]
public enum SnapshotFlags : uint
{
HeapList = 0x00000001,
Process = 0x00000002,
Thread = 0x00000004,
Module = 0x00000008,
Module32 = 0x00000010,
Inherit = 0x80000000,
All = 0x0000001F
}
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct PROCESSENTRY32
{
public uint dwSize;
public uint cntUsage;
public uint th32ProcessID;
public IntPtr th32DefaultHeapID;
public uint th32ModuleID;
public uint cntThreads;
public uint th32ParentProcessID;
public int pcPriClassBase;
public uint dwFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szExeFile;
};
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct MODULEENTRY32
{
public uint dwSize;
public uint th32ModuleID;
public uint th32ProcessID;
public uint GlblcntUsage;
public uint ProccntUsage;
IntPtr modBaseAddr;
public uint modBaseSize;
IntPtr hModule;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string szModule;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szExePath;
};
}
Some of the code is based on an article by Jason Zander which can be found here.
you can call the Process.Kill method
you can use the Process.GetProcesses to get all processes or Process.GetProcessByName or Process.GetProcessById so you can get the process to call Kill on.
Process[] processes = Process.GetProcesses();
foreach (Process pr in processes){
if (pr.ProcessName=="vfp")
if (pr.MainWindowTitle.Contains("test"))
pr.CloseMainWindow();
}`enter code here`
Here vfp is process name. and test is setup title name.
You can achieve it by using Process Class class but why would you want to kill another process?
Process class has Kill() method
I wanted to define my own list of applications to close so I made this based on some of the examples I've seen listed. It's simple and effective.
string[] Process_name_list = {"chrome","notepad"};
foreach (string Process_name in Process_name_list)
{
foreach (var process in Process.GetProcessesByName(Process_name))
{
process.Kill();
}
}

Categories

Resources