We have a third party winforms software that we need to run as a batch
I need to monitor if a certain form for a certain process (we run several processes at the same time) is shown.
I have used this method to get all window handles for a process
public IEnumerable<int> EnumerateProcessWindowHandles(int processId)
{
var handles = new List<IntPtr>();
try
{
foreach (ProcessThread thread in Process.GetProcessById(processId).Threads)
Win32.EnumThreadWindows(thread.Id,
(hWnd, lParam) => { handles.Add(hWnd); return true; }, IntPtr.Zero);
}
catch(Exception e) {}
return handles.Select(h => (int)h);
}
Then this method to get the window caption from the hwnd
public string GetTitle(int hwnd)
{
int length = Win32.SendMessage((IntPtr)hwnd, Win32.WM_GETTEXTLENGTH, 0, IntPtr.Zero);
var sb = new StringBuilder(length + 1);
Win32.SendMessage((IntPtr)hwnd, Win32.WM_GETTEXT, (IntPtr)sb.Capacity, sb);
return sb.ToString();
}
Each second I poll the process with above methods, but sometimes it fails to detected a window shown. The window in question is opened more than a second so its not the pol frequency.
Is there a more reliable way of getting callbacks when a window is closed/opened?
Probably the cleanest way to listen to window creation and destruction is using a CBT hook. Listen for HCBT_CREATEWND and HCBT_DESTROYWND. This MSDN article, Windows Hooks in the .NET Framework, covers the subject from a .net perspective.
maybe that can help
[1] http://spradip.wordpress.com/category/programming-c/page/2/
and this any ms C++ example
[2] http://msdn.microsoft.com/en-us/library/windows/desktop/ms686701(v=vs.85).aspx
Related
The documentation on EnumWindows underscores:
Note For Windows 8 and later, EnumWindows enumerates only top-level windows of desktop apps.
What is the difference between "desktop apps" and "non desktop apps"?
Is this related to metro apps?
I ask because EnumWindows is behaving somewhat different in Win10 compared with Win7.
Another solution is to use the undocumented api from win32u.dll, it has the prototype:
NTSTATUS WINAPI NtUserBuildHwndList
(
HDESK in_hDesk,
HWND in_hWndNext,
BOOL in_EnumChildren,
BOOL in_RemoveImmersive,
DWORD in_ThreadID,
UINT in_Max,
HWND *out_List,
UINT *out_Cnt
);
Pass it in a HWND list with Max entries, set all other parameters to zero, the output Cnt gives the number of returned entries. If the resultcode is STATUS_BUFFER_TOO_SMALL then reallocate the list with more entries and try again.
Compared to pre-Win10 versions a parameter RemoveImmersive is added. If TRUE then the same list is returned as EnumWindows (without immersive windows). If FALSE then the full list is returned.
The first entry of the list is 0x00000001 as a handle and must be ignored.
The advantage of this api is that the is no posibility of changing of the window list during calls to FindWIndowEx (a lock is set during building of the list)
The EnumWindows, EnumDesktopWindows, EnumChildWindows, FindWindow, FindWindowEx all use this api.
Hereby a request to Microsoft to add a public api EnumWindowsEx or EnumAllWindows so developers have a safe method to enumerate all windows. I understand they added the filter to EnumWindows to fix custom tasklists out there which display visible but cloaked immersive/metro/uwp windows. But a method should be supported for developers to get the full list.
UPDATE: Example on how to use this api, InitWin32uDLL does a runtime load of win32u.dll, and lib_NtUserBuildHwndListW10 is the GetProcAddress pointer
/********************************************************/
/* enumerate all top level windows including metro apps */
/********************************************************/
BOOL Gui_RealEnumWindows(WNDENUMPROC in_Proc, LPARAM in_Param)
{
/* locals */
INT lv_Cnt;
HWND lv_hWnd;
BOOL lv_Result;
HWND lv_hFirstWnd;
HWND lv_hDeskWnd;
HWND *lv_List;
// only needed in Win8 or later
if (gv_SysInfo.Basic.OsVersionNr < OSVER_WIN8)
return EnumWindows(in_Proc, in_Param);
// no error yet
lv_Result = TRUE;
// first try api to get full window list including immersive/metro apps
lv_List = _Gui_BuildWindowList(0, 0, 0, 0, 0, &lv_Cnt);
// success?
if (lv_List)
{
// loop through list
while (lv_Cnt-- > 0 && lv_Result)
{
// get handle
lv_hWnd = lv_List[lv_Cnt];
// filter out the invalid entry (0x00000001) then call the callback
if (IsWindow(lv_hWnd))
lv_Result = in_Proc(lv_hWnd, in_Param);
}
// free the list
MemFree(lv_List);
}
else
{
// get desktop window, this is equivalent to specifying NULL as hwndParent
lv_hDeskWnd = GetDesktopWindow();
// fallback to using FindWindowEx, get first top-level window
lv_hFirstWnd = FindWindowEx(lv_hDeskWnd, 0, 0, 0);
// init the enumeration
lv_Cnt = 0;
lv_hWnd = lv_hFirstWnd;
// loop through windows found
// - since 2012 the EnumWindows API in windows has a problem (on purpose by MS)
// that it does not return all windows (no metro apps, no start menu etc)
// - luckally the FindWindowEx() still is clean and working
while (lv_hWnd && lv_Result)
{
// call the callback
lv_Result = in_Proc(lv_hWnd, in_Param);
// get next window
lv_hWnd = FindWindowEx(lv_hDeskWnd, lv_hWnd, 0, 0);
// protect against changes in window hierachy during enumeration
if (lv_hWnd == lv_hFirstWnd || lv_Cnt++ > 10000)
break;
}
}
// return the result
return lv_Result;
}
HWND *_Gui_BuildWindowList
(
HDESK in_hDesk,
HWND in_hWnd,
BOOL in_EnumChildren,
BOOL in_RemoveImmersive,
UINT in_ThreadID,
INT *out_Cnt
)
{
/* locals */
UINT lv_Max;
UINT lv_Cnt;
UINT lv_NtStatus;
HWND *lv_List;
// is api not supported?
if (!InitWin32uDLL())
return NULL;
// initial size of list
lv_Max = 512;
// retry to get list
for (;;)
{
// allocate list
if ((lv_List = (HWND*)MemAlloc(lv_Max*sizeof(HWND))) == NULL)
break;
// call the api
lv_NtStatus = lib_NtUserBuildHwndListW10(
in_hDesk, in_hWnd,
in_EnumChildren, in_RemoveImmersive, in_ThreadID,
lv_Max, lv_List, &lv_Cnt);
// success?
if (lv_NtStatus == NOERROR)
break;
// free allocated list
MemFree(lv_List);
// clear
lv_List = NULL;
// other error then buffersize? or no increase in size?
if (lv_NtStatus != STATUS_BUFFER_TOO_SMALL || lv_Cnt <= lv_Max)
break;
// update max plus some extra to take changes in number of windows into account
lv_Max = lv_Cnt + 16;
}
// return the count
*out_Cnt = lv_Cnt;
// return the list, or NULL when failed
return lv_List;
}
You are correct. EnumWindows will only find windows that belong to programs that aren't Modern (Metro) apps. It will get windows that belong to traditional (desktop) programs. FindWindowEx, according to several sources, does work all kinds of windows, including those from Modern apps.
I am developing a tray icon based application in C++ CLI. I am using Mutex to ensure single instance of my application running at a time. But each time a new instance starts, the current instance's window should go active.
I am sending a message to the window using PostMessage(Pinvoke). But after 3 or 4 successive run, my application crashes.
Any ideas why that happen. please help!!
The code I have written in the main() function is,
Mutex ^mutex = gcnew Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}");
if (mutex->WaitOne(TimeSpan::Zero, true))
{
// New Instance. Proceed......................
}
else// An instance is already running. Activate it and return
{
// send our Win32 message to make the currently running instance
// jump on top of all the other windows
try
{
HWND hWindow = FindWindow( nullptr, "MyWindow" );
if(hWindow)
PostMessage(hWindow, WM_ACTIVATE_APP, nullptr,nullptr);
}
catch(Exception^ Ex)
{
}
return -1;
}
Thanks & Regards,
Rohini
Try this instead of PostMessage():
ShowWindowAsync(hWindow, 1); // SW_SHOWNORMAL
SetForegroundWindow(hWindow);
There's a well-known problem that Skype on Windows 8 takes up 100% of one CPU core on some users' PCs. Including mine! There's a workaround courtesy of techfreak in Skype Community:
Download and run the latest version of process explorer. (http://download.sysinternals.com/files/ProcessExplorer.zip)
With Skype running search for Skype.exe in the list of active programs and double click on it.
Go to the threads tab and Suspend or Kill the Skype thread that is consuming the highest resources when IDLE. (like 50%+ CPU)
I'm getting annoyed with manually doing this after every reboot, so I'd like to automate the steps above, to write a simple C++ or C# "Skype launcher" program that does the following:
launch SKYPE.EXE
wake up every 1 second and look to see if one particular Skype thread is taking up over 98% of the CPU cycles in the process
if found, suspend that thread and exit the launcher process
otherwise loop up to 10 times until the bad thread is found.
After a quick Google search I got intimidated by the Win32 thread-enumeration APIs, and this "find and kill/suspend evil thread" problem seems to be fairly generic, so I'm wondering if there's an existing sample out there that I could re-purpose. Any pointers?
After much more googling and some dead ends with powershell (too many security hassles, too confusing for a newbie) and WMI (harder than needed), I finally found a great C# sample on MSDN Forums that will enumerate and suspend threads. This was easy to adapt to first check CPU time of each thread before suspending the culprit.
Here's code. Just compile and drop into your startup menu and Skype will no longer heat your office!
// code adapted from
// http://social.msdn.microsoft.com/Forums/en-US/d51efcf0-7653-403e-95b6-bf5fb97bf16c/suspend-thread-of-a-process
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;
using System.ComponentModel;
namespace SkypeLauncher
{
class Program
{
static void Main(string[] args)
{
Process[] procs = Process.GetProcessesByName("skype");
if (procs.Length == 0)
{
Console.WriteLine("Skype not loaded. Launching. ");
Process.Start(Environment.ExpandEnvironmentVariables(#"%PROGRAMFILES(X86)%\Skype\Phone\Skype.exe"));
Thread.Sleep(8000); // wait to allow skype to start up & get into steady state
}
// wait to allow skype to start up & get into steady state, where "steady state" means
// a lot of threads created
Process proc = null;
for (int i = 0; i < 50; i++)
{
procs = Process.GetProcessesByName("skype");
if (procs != null)
{
proc = procs[0];
if (proc.Threads.Count > 10)
break;
}
Thread.Sleep(1000); // wait to allow skype to start up & get into steady state
}
// try multiple times; if not hanging after a while, give up. It must not be hanging!
for (int i = 0; i < 50; i++)
{
// must reload process to get updated thread time info
procs = Process.GetProcessesByName("skype");
if (procs.Length == 0)
{
Console.WriteLine("Skype not loaded. Exiting. ");
return;
}
proc = procs[0];
// avoid case where exception thrown if thread is no longer around when looking at its CPU time, or
// any other reason why we can't read the time
var safeTotalProcessorTime = new Func<ProcessThread, double> (t =>
{
try { return t.TotalProcessorTime.TotalMilliseconds; }
catch (InvalidOperationException) { return 0; }
}
);
var threads = (from t in proc.Threads.OfType<ProcessThread>()
orderby safeTotalProcessorTime(t) descending
select new
{
t.Id,
t.ThreadState,
TotalProcessorTime = safeTotalProcessorTime(t),
}
).ToList();
var totalCpuMsecs = threads.Sum(t => t.TotalProcessorTime);
var topThread = threads[0];
var nextThread = threads[1];
var topThreadCpuMsecs = topThread.TotalProcessorTime;
var topThreadRatio = topThreadCpuMsecs / nextThread.TotalProcessorTime;
// suspend skype thread that's taken a lot of CPU time and
// and it has lots more CPU than any other thread.
// in other words, it's been ill-behaved for a long time!
// it's possible that this may sometimes suspend the wrong thread,
// but I haven't seen it break yet.
if (topThreadCpuMsecs > 10000 && topThreadRatio > 5)
{
Console.WriteLine("{0} bad thread. {0:N0} msecs CPU, {1:N1}x CPU than next top thread.",
topThread.ThreadState == System.Diagnostics.ThreadState.Wait ? "Already suspended" : "Suspending",
topThreadCpuMsecs,
topThreadRatio);
Thread.Sleep(1000);
IntPtr handle = IntPtr.Zero;
try
{
//Get the thread handle & suspend the thread
handle = OpenThread(2, false, topThread.Id);
var success = SuspendThread(handle);
if (success == -1)
{
Win32Exception ex = new Win32Exception(Marshal.GetLastWin32Error());
Console.WriteLine(ex.Message);
}
Console.WriteLine("Exiting");
Thread.Sleep(1000);
return;
}
finally
{
if (handle != IntPtr.Zero)
CloseHandle(handle);
};
}
Console.WriteLine("Top thread: {0:N0} msecs CPU, {1:N1}x CPU than next top thread. Waiting.",
topThreadCpuMsecs,
topThreadRatio);
Thread.Sleep(2000); // wait between tries
}
Console.WriteLine("No skype thread is ill-behaved enough. Giving up.");
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern int SuspendThread(IntPtr hThread);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr handle);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern
IntPtr OpenThread(int dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)]bool bInheritHandle, int dwThreadId);
}
}
Does somebody know how to unload a dll or any other type of module loaded by an external process?
I tried to do GetModuleHandle and then FreeLibrary with no result...
Thank you for all your replies
Thank you for all your replies. I found an interesting msdn article here :
http://blogs.msdn.com/b/jmstall/archive/2006/09/28/managed-create-remote-thread.aspx
The problem is that when i try to do a OpenProcess the external process crashes.
What are the minimum process access rights to unload a module from it ?
Here is what i am trying to do in c# :
[code]
protected const int PROCESS_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF);
protected const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
protected const int SYNCHRONIZE = 0x100000;
public static bool UnloadRemoteModule(FileEntry le)
{
try
{
Process process = System.Diagnostics.Process.GetProcessById(le.ProcessID);
if (process == null) return false;
StringBuilder sb = new StringBuilder(le.File);
UnloadModuleThreadProc umproc = new UnloadModuleThreadProc(UnloadModule);
IntPtr fpProc = Marshal.GetFunctionPointerForDelegate(umproc);
SafeProcessHandle processHandle = null;
IntPtr currentProcess = NativeMethods.GetCurrentProcess();
int processId = le.ProcessID;
bool remote = (processId != NativeMethods.GetProcessId(currentProcess));
try
{
if (remote)
{
MessageBox.Show("OPENING PROCESS !");
processHandle = NativeMethods.OpenProcess(PROCESS_ALL_ACCESS, true, processId);
System.Threading.Thread.Sleep(200);
uint dwThreadId;
if (processHandle.DangerousGetHandle() == IntPtr.Zero)
{
MessageBox.Show("COULD NOT OPEN HANDLE !");
}
else
{
// Create a thread in the first process.
IntPtr hThread = CreateRemoteThread(
processHandle.DangerousGetHandle(),
IntPtr.Zero,
0,
fpProc, IntPtr.Zero,
0,
out dwThreadId);
System.Threading.Thread.Sleep(200);
WaitForThreadToExit(hThread);
}
}
return true;
}
finally
{
if (remote)
{
if (processHandle != null)
{
processHandle.Close();
}
}
}
return false;
}
catch (Exception ex)
{
//Module.ShowError(ex);
return false;
}
}
public delegate int UnloadModuleThreadProc(IntPtr sb_module_name);
static int UnloadModule(IntPtr sb_module_name2)
{
using (StreamWriter sw = new StreamWriter(#"c:\a\logerr.txt"))
{
sw.AutoFlush = true;
sw.WriteLine("In Unload Module");
StringBuilder sb_module_name =new StringBuilder(#"C:\Windows\System32\MyDll.dll");
IntPtr mh = DetectOpenFiles.GetModuleHandle(sb_module_name.ToString());
sw.WriteLine("LAST ERROR="+Marshal.GetLastWin32Error().ToString());
sw.WriteLine("POINTER="+mh.ToInt32());
if (mh != IntPtr.Zero)
{
return (FreeLibrary(mh) ? 1 : 0);
}
sw.WriteLine("LAST ERROR 2 =" + Marshal.GetLastWin32Error().ToString());
sw.WriteLine("EXIT " + mh.ToInt32());
}
return 0;
}[/code]
You can do it, but honestly I must ask why? You're most likely going to screw things up beyond what you realize. Seriously, there's nothing that can go right if you do this. Don't read the rest of this post, close your browser, do some meditation, and figure out what you're doing wrong that made you ask this question.
HERE BE DRAGONS
That said, it can be done, and rather easily too.
All you have to do is use CreateRemoteThread, pass a handle to the process you want to force unload in, and a function pointer to a function that calls GetModuleHandle and FreeLibrary. Easy as pie.
Sample code (untested, written in vi, and not to be used no matter what):
DWORD WINAPI UnloadNamedModule(void *)
{
//If you value your life, don't use this code
LPCTSTR moduleName = _T("MYMODULE.DLL");
HMODULE module = GetModuleHandle(moduleName);
if (module != NULL)
{
UnloadModule(hModule);
//All hell breaks loose. Not even this comment will be reached.
//On your own head be it. Don't say I didn't warn you.
}
}
//Warning: this function should never be run!
void UnloadRemoteModule(HANDLE hProcess)
{
CreateRemoteThread(hProcess, NULL, 0, UnloadNamedModule, NULL, 0);
}
You cannot force an external process to unload it's modules. You would need to run that code from inside the external process. The best you can hope for is to kill the process that owns the external DLL. It would be extremely dangerous if you could unload a dll from an external process, the code could be running at the time that you pull it out of RAM.
If you are looking to replace the DLL, the best you can do is to rename the DLL and save the new one. That way, the DLL will get use the next time the external process loads it.
Correction to italics above: You can do it but you are asking for big trouble if you do. I still think the best approach is to do what I listed above, rename the DLL and put the new one in it's place for the next time the external process starts. It's a far safer approach if you would like to replace a DLL.
I'm having to back port some software from Windows Mobile 6.5 to Windows CE 5.0, the software currently detects when the unit is in the base unit (ActiveSync running).
I need to know when ActiveSync is running on the unit so that I can prepare the unit to send and receive files.
I've found an article on using PINVOKE methods such as CeRunAppAtEvent but I am clueless on how that would work.
bool terminateDeviceEventThreads = false;
IntPtr handleActiveSyncEndEvent;
while (!terminateDeviceEventThreads)
{
handleActiveSyncEndEvent = NativeMethods.CreateEvent (IntPtr.Zero,
true, false, "EventActiveSync");
if (IntPtr.Zero != handleActiveSyncEndEvent)
{
if (NativeMethods.CeRunAppAtEvent ("\\\\.\\Notifications\\NamedEvents\\EventActiveSync",
(int) NOTIFICATION_EVENT.NOTIFICATION_EVENT_RS232_DETECTED))
{
NativeMethods.WaitForSingleObject (handleActiveSyncEndEvent, 0);
//
NativeMethods.ResetEvent (handleActiveSyncEndEvent);
if (!NativeMethods.CeRunAppAtEvent ("\\\\.\\Notifications\\NamedEvents\\EventActiveSync",
(int) NOTIFICATION_EVENT.NOTIFICATION_EVENT_NONE))
{
break;
}
handleActiveSyncEndEvent = IntPtr.Zero;
}
}
}
The code you have here is waiting on the system notification NOTIFICATION_EVENT_RS232_DETECTED. By using CeRunAppAtEvent (a bit of a misnomer, as it's not going to run an app but instead set an event) they've registered a named system event with the name "EventActiveSync" to be set when the notification occurs.
In essence, when the device is docked, the named system event will get set.
Your code has got some of the wait code in there, but not fully - it's calls WaitForSingleObject, but never looks at the result and then unhooks the event. I'd think it would look more like this
event EventHandler OnConnect = delegate{};
void ListenerThreadProc()
{
var eventName = "OnConnect";
// create an event to wait on
IntPtr #event = NativeMethods.CreateEvent (IntPtr.Zero, true, false, eventName);
// register for the notification
NativeMethods.CeRunAppAtEvent (
string.Format("\\\\.\\Notifications\\NamedEvents\\{0}", eventName),
(int) NOTIFICATION_EVENT.NOTIFICATION_EVENT_RS232_DETECTED);
while(!m_shutdown)
{
// wait for the event to be set
// use a 1s timeout so we don't prevent thread shutdown
if(NativeMethods.WaitForSingleObject(#event, 1000) == 0)
{
// raise an event
OnConnect(this, EventArgs.Empty);
}
}
// unregister the notification
NativeMethods.CeRunAppAtEvent (
string.Format("\\\\.\\Notifications\\NamedEvents\\{0}", eventName),
(int) NOTIFICATION_EVENT.NOTIFICATION_EVENT_NONE);
// clean up the event handle
NativeMethods.CloseHandle(#event);
}
Your app would create a thread that uses this proc at startup and wire up an event handler for the OnConnect event.
FWIW, the SDF has this already done, so it would be something like this in your code:
DeviceManagement.SerialDeviceDetected += DeviceConnected;
...
void DeviceConnected()
{
// handle connection
}
Here's an ActiveSync document on MSDN. A little old but should still be relevant. Also take a look at this
As for the CeRunAppAtEvent you need to create a wrapper to the Native method as below
[DllImport("coredll.dll", EntryPoint="CeRunAppAtEvent", SetLastError=true)]
private static extern bool CeRunAppAtEvent(string pwszAppName, int lWhichEvent);
You can find PInvode resources here and on MSDN