My purpose want to catch TASKKILL event in Command Prompt, and use this event.
Maybe, I think need to use kernel32.dll but I can't find a handler for this.
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode);
Update
Follow ways #Ben Voigt suggest:
_Using WMI:
Step 1: Run the command mgmtclassgen Win32_Process /n root\cimv2 /o WMI.Win32 to generate the class Process. And then renaming the class Process to Win32_Process.
http://notepad.cc/share/3SQfeJgEQR
Step 2: Create a class with name ProcessWatcher
http://notepad.cc/share/UIR1Tw5twy
Step 3: Using this class with while loop for waiting my application status.
This is easy way but not my choice.
http://notepad.cc/share/JXLGogGbai
_Using Window Hook:
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle,
ushort hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle,
uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions);
But TerminateProcess and DuplicateHandle, I can't find a handler for this.
From some other process, which we shall call the watchdog, you must get a handle to the process you will monitor for termination (the target process). You can have a handle created using DuplicateHandle and communicated via an IPC mechanism. If you know the PID of the target process, you can use OpenProcess or System.Diagnostics.Process.GetProcessById. If the target process is spawned by the watchdog, you get a handle from CreateProcess or System.Diagnostics.Process.Start. Or you can enumerate running processes, for example using System.Diagnostics.Process.GetProcessesByName.
In any case, once you have a handle to the process, you can pass it to one of the wait functions such as WaitForSingleObject, WaitForMultipleObjects, or MsgWaitForMultipleObjectsEx. When the process ceases running, for example because TASKKILL terminated it, the process handle becomes signaled and the wait will complete.
If you use the .NET Process class and its WaitForExit method, be aware that unlike the Win32 wait functions, there is no multi-handle version; you'll need to dedicate an entire thread.
A possibly easier way is to use WMI and subscribe to process events. I tend not to use WMI myself, but it could be useful if you don't have a parent/child relationship between watchdog and target, making the handle otherwise difficult to get. You can read about it on this blog:
Using WMI to monitor process creation, deletion and modification in .NET
Related
What's the best way to programmatically cause a Windows XP (or above) machine to wake up at a specific time. (Ideally a lot like how Media Center can start up automatically to record a particular TV program)
I've got a Windows service (written in C#) and I'd like this service to be able to cause the machine it is hosted on to start up at predetermined times.
Are there any BIOS settings or prerequisites (eg. ACPI) that need to be configured for this to work correctly?
This machine would be using dialup or 3G wireless modem, so unfortunately it can't rely on Wake on LAN.
You can use waitable timers to wake from a suspend or hibernate state. From what I can find, it is not possible to programmatically wake from normal shut down mode (soft off/S5), in that case, you need to specify a WakeOnRTC alarm in BIOS. To use waitable timers from C#, you need pInvoke. The import declarations are:
public delegate void TimerCompleteDelegate();
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateWaitableTimer(IntPtr lpTimerAttributes, bool bManualReset, string lpTimerName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetWaitableTimer(IntPtr hTimer, [In] ref long pDueTime, int lPeriod, TimerCompleteDelegate pfnCompletionRoutine, IntPtr pArgToCompletionRoutine, bool fResume);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CancelWaitableTimer(IntPtr hTimer);
You can use those functions in the following way:
public static IntPtr SetWakeAt(DateTime dt)
{
TimerCompleteDelegate timerComplete = null;
// read the manual for SetWaitableTimer to understand how this number is interpreted.
long interval = dt.ToFileTimeUtc();
IntPtr handle = CreateWaitableTimer(IntPtr.Zero, true, "WaitableTimer");
SetWaitableTimer(handle, ref interval, 0, timerComplete, IntPtr.Zero, true);
return handle;
}
You can then cancel the waitable timer with CancelWaitableTimer, using the returned handle as an argument.
Your program can hibernate and sleep using pInvoke:
[DllImport("powrprof.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetSuspendState(bool hibernate, bool forceCritical, bool disableWakeEvent);
public static bool Hibernate()
{
return SetSuspendState(true, false, false);
}
public static bool Sleep()
{
return SetSuspendState(false, false, false);
}
Your system may not allow programs to let the computer enter hibernation. You can call the following method to allow hibernation:
public static bool EnableHibernate()
{
Process p = new Process();
p.StartInfo.FileName = "powercfg.exe";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo.Arguments = "/hibernate on"; // this might be different in other locales
return p.Start();
}
The task scheduler program in Win7, taskschd.msc (and I beleive XP as well) can be set to wake the system on different triggers. Those triggers can be schedule, time, event, etc.
In at least Win7, you need to set "Allow Wake Timers" to 'Enabled' for this to work. This setting is found under...
--> Control Panel\Hardware and Sound\Power Options
click - "Edit Plan Settings"
click - "Change advanced power setting"
expand - "Sleep"
Expand - "Allow Wake timers"
Your best bet is using Wake on LAN capability. This will require another machine to send a packet of a special kind to wake your machine up.
This will not be helpful if your machine is not connected to the network or you for some reason don't wasnt to move this logic onto another machine. But it's useful for some configurations where you have multiple machines and want to wake them up programmatically.
Some machines have a BIOS alarm clock that can be set to wake up the computer at a certain hour. It should be possible to program this clock, but I don't know the specific details.
Edit: I found this program that should let you set the time. It's in C, under Linux, but maybe it can give you some hints.
A warning though: before trying anything that changes the BIOS settings directly be sure to write down every setting from BIOS screens, because in case of an error the BIOS might revert to factory default and you might need to set it up again as it was.
I want my program to trigger an action only when certain other programs are currently being used. I get the current foreground HWND with GetForegroundWindow(). But HWNDs change over time, so that's not a way to identify those programs. The same goes for Process IDs and handles. What is a way to identify the foreground program over reboots?
I first thought GetModuleFileNameExA should work, but my code crashes because it is not found:
Handle handle = GetProcessHandleFromHwnd(hWID);
String Name = null;
GetModuleFileNameExA(
handle,
null,
Name,
2147483647
);
[DllImport("Kernel32.dll", CharSet = CharSet.Ansi)]
private static extern IntPtr GetModuleFileNameExA(
Handle hProcess,
Object hModule,
String lpFilename,
Int32 nSize
);
You need to use GetWindowThreadProcessId. This is explained better in the answers to this question: Find process id by window's handle.
You should then be able to use System.Diagnostics.Process.GetProcesses() to match the pid to a process and its modules. You may find that you cannot access the details of 64 bit processes from a 32 bit process, or that security blocks access to some information.
I am trying to call WaitForSingleObject method from C#, as documented here:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx
In order to call this function I need to create a Handle, or I need to get a Handle of type IntPtr, how can it be done?
I've tried this function that I found:
http://www.pinvoke.net/default.aspx/kernel32.WaitForSingleObject
[DllImport("coredll.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto)]
public static extern IntPtr CreateEvent(HANDLE lpEventAttributes, [In, MarshalAs(UnmanagedType.Bool)] bool bManualReset, [In, MarshalAs(UnmanagedType.Bool)] bool bIntialState, [In, MarshalAs(UnmanagedType.BStr)] string lpName);
Or for instance, when I am getting handle from console:
IntPtr handle = Process.GetCurrentProcess().MainWindowHandle;
It throws a DllNotFoundException.
What's the issue here?
I need it in order to run the process with this function call, and to take a dump form its process, for my ClrMd library learning.
Any help will be appreciated.
Code sample:
static void Main(string[] args)
{
var autoEvent = new AutoResetEvent(false);
//this is where I get the DllNotFoundException
WaitForSingleObject(autoEvent.Handle, WAIT_TIMEOUT );
}
[DllImport("kernel32.dll")]
static extern uint WaitForMultipleObjects(uint nCount, IntPtr[] lpHandles, bool bWaitAll, uint dwMilliseconds);
public const Int32 WAIT_TIMEOUT = 0x102;
I would not go through WinApi to get this from C#: you have EventWaitHandler and other synchronization objects in C#, use them:
WaitHandle wh = new EventWaitHandler();
//do whatever you need
...
WaitHandler.WaitOne(wh); // equivalent to WaitForSingleObject in WinApi
you can use wh.SafeWaitHandle if you really need to interop with WinApi
Also I suspect Process.GetCurrentProcess().MainWindowHandle cannot work in a Console Application, that has not any window at all
I want to call native method (WaitForMultipleObjects) which waits for some handle (don't really mind which one), then I want to see it on thread stack using ClrMd library, from dump file
OK, so what about new ManualResetEvent(false).WaitOne()? This should show up in the dump file. And it's reliable.
Just picking any existing handle is not reliable because it might be signaled or be destroyed at any time. Or, you might change its state by waiting. There is no need, a ManualResetEvent can create you a fresh handle.
My mistake I've posted WaitForMultipleObjects instead of WaitForSingleObject, the main issue was that WaitForSingleObject stayed with DllImport("coredll.dll"...) I don't know where did I found it but I did...
Sorry for the confusion
I'm trying to develop a WPF C# application that captures mouse clicks even (especially) if it's in background in order to start another task.
On MSDN documentation ( http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx ) I can read that WH_MOUSE should have either a global or thread scope.
I instantiate my hook handle this way:
hHook = SetWindowsHookEx(WH_MOUSE,
MouseHookProcedure,
(IntPtr)0,
AppDomain.GetCurrentThreadId());
where MouseHookProcedure is the delegate of my callback function and WH_MOUSE value is 7 (following Winuser.h).
The code works but it can only catch local clicks (I just need WM_LBUTTONDOWN messages), the clicks inside the window. I need to catch clicks also outside the window, and when the window is in background.
I tried hooking to WH_MOUSE_LL (with a value of 14), but it's not working.
For the most part I followed this:
http://support.microsoft.com/kb/318804
with some changes since I am using WPF and not WinForms.
The documentation about Hooks is a bit confusing.
All in all I'd like to know:
Can WH_MOUSE detect mouse messages globally? If yes, what am I doing wrong?
Can I hook from a .NET C# code to a WH_MOUSE_LL? If yes, how?
Thanks in advance.
It's possible with WH_MOUSE_LL and you need it.
In my case I developed a global keyboard maybe this could help you.
I needed to call LoadLibrary in the third parameters.
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr LoadLibrary(string fileName);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, KeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
void MyFunction(){
[...]
SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, LoadLibrary("user32.dll"), 0);
}
Technically you should be able to have a global mouse hook implemented in C#. You would then pass zero as the last arguments to SetWindowsHookEx and your hook procedure must reside in a DLL, not an EXE. That's because the DLL will be injected into every process that has windows belonging to the same desktop as the hooking application. For this same reason writing global hooks in .NET is not actually recommended by most because it causes the CLR to be loaded into every desktop process, which can carry substantial overhead.
I will prevent a window from iTunes to be opened.
I googled a lot but can't find an iTunes library that allows me to control such things, so I think I must get back to basics and close it after it opens, but how?
I think:
Tick a timer every 500 ms
Check if the window handle is opened
Close it
Is that possible?
How can I recognize a window from this application on other computers (I will give away my application)?
Language is C#.Net 2.0.
Yes it's an option to find the window and close it. However the user will still see it.
You can do the PInvoke method of FindWindow or use the C# ones (prefer those)
using System.Diagnostics;
Process[] processes = Process.GetProcessesByName("notepad");
foreach (Process p in processes)
{
p.CloseMainWindow();
}
From here
This is only for closing the top application, I dont know if you can find the subwindow with Process.
I know you can with PInvoke, see example here
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
or
[DllImport("user32.dll", EntryPoint="FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
Sure there are ways to do this, an approach I used before was based on the win32APIs, you'll want to look at the following:
FindWindow
SendMessage
In short you can use the timer, and when it fires use FindWindow (either using the window title bar, or the application "class") to get the handle, once you have that you SendMessage to the window of at least a WM_CLOSE or WM_DESTROY