Application won't crash on purpose while in another thread - c#

I'm trying to crash my Console application after a certain amount of time (this is due to me testing whether the application will start itself after crashing. Following this tutorial)
What I have for this is this piece of code:
static class WebSocket
{
static int Main(string[] args)
{
Recovery.RegisterForAutostart();
Recovery.RegisterForRestart();
Test.Run();
// some more code
}
}
public static class Recovery
{
[Flags]
public enum RestartRestrictions
{
None = 0,
NotOnCrash = 1,
NotOnHang = 2,
NotOnPatch = 4,
NotOnReboot = 8
}
public delegate int RecoveryDelegate(RecoveryData parameter);
public static class ArrImports
{
[DllImport("kernel32.dll")]
public static extern void ApplicationRecoveryFinished(
bool success);
[DllImport("kernel32.dll")]
public static extern int ApplicationRecoveryInProgress(
out bool canceled);
[DllImport("kernel32.dll")]
public static extern int GetApplicationRecoveryCallback(
IntPtr processHandle,
out RecoveryDelegate recoveryCallback,
out RecoveryData parameter,
out uint pingInterval,
out uint flags);
[DllImport("KERNEL32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int GetApplicationRestartSettings(
IntPtr process,
IntPtr commandLine,
ref uint size,
out uint flags);
[DllImport("kernel32.dll")]
public static extern int RegisterApplicationRecoveryCallback(
RecoveryDelegate recoveryCallback,
RecoveryData parameter,
uint pingInterval,
uint flags);
[DllImport("kernel32.dll")]
public static extern int RegisterApplicationRestart(
[MarshalAs(UnmanagedType.BStr)] string commandLineArgs,
int flags);
[DllImport("kernel32.dll")]
public static extern int UnregisterApplicationRecoveryCallback();
[DllImport("kernel32.dll")]
public static extern int UnregisterApplicationRestart();
}
public class RecoveryData
{
string currentUser;
public RecoveryData(string who)
{
currentUser = who;
}
public string CurrentUser
{
get { return currentUser; }
}
}
// Restart after crash
public static void RegisterForRestart()
{
// Register for automatic restart if the application was terminated for any reason.
ArrImports.RegisterApplicationRestart("/restart",
(int)RestartRestrictions.None);
}
// Start app when PC starts
public static void RegisterForAutostart()
{
#if (!DEBUG)
RegistryKey key = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
key.SetValue("websocket", #"c:\websocket\run.bat");
#endif
}
public static class Test
{
public static void Run()
{
crash();
}
static void crash()
{
double crashAfter = 1.5 * 60; // seconds
int secondsPassed = 0;
int waitSeconds = 1;
Console.WriteLine("\nCrash test startet, crash will occour in " + crashAfter + " seconds");
Timer timer = new Timer(
delegate (object seconds) {
secondsPassed += int.Parse(seconds.ToString());
if (secondsPassed > crashAfter)
{
Console.WriteLine("Crashing");
Environment.FailFast("Test - intentional crash."); // Error happens here
}
else
{
double timeUntilCrash = (crashAfter - secondsPassed);
Console.WriteLine("Time until crash = " + timeUntilCrash + " seconds");
}
},
waitSeconds,
TimeSpan.FromSeconds(waitSeconds),
TimeSpan.FromSeconds(waitSeconds));
}
}
When it's time to crash I get this message:
Cannot evaluate expression because a thread is stopped at a point
where garbage collection is impossible, possibly because the code is
optimized.
The checkbox for code optimization is unchecked.
I surpose this is because it's not in the main thread, if this is the case how do I return to the main thread. And if not, what might be the cause?

I created an application based on your code & found that everything runs as expected when the application is run from the command-line - it is only in Visual Studio debugger the restart does not work.

Thanks to PaulF we found the problem. I was testing in Debug mode, running the application in release mode outside of Visual Studio fixed the problem. The following NullReferenceException was caused by missing command line arguments upon restart.

Related

Debugging a C# .NET custom component / control in VS(10) during design time

I saw a lot of questions (in so) and topics anywhere else where people try to debug a component using MesssageBox.Show (including myself at the beginning). That is definitely a bad approach. The reason is, that functions like Debug.Write or Console.Write do not work at design time. So you do the next best thing that works to output a string.
Another point is that I've never really looked at components before. When I wrote a program, I usually did it directly as code / class and tested it at runtime.
If you are interested (or confused or both) in what I write feel free to correct me if I'm wrong and / or add your suggestions.
My question should actually be: "What is the best way to debug a component during design time?". But stack overflow does't like questions like this.
Or just to the problem below: "Problem with debug / console output during design time".
What I tried first: MS docs guide to debug components at design time 👎
I use the same practise as mentioned in this question to debug a component at design time.
Breakpoint works but I still don't get any output text using Console/Debug text:
While in a normal runtime debug session the console and/or debug output is passed to the VS pane. Just to notice the debug pane outputs anything at all.
Of course, in such a scenario you should use Debug and not the Console. But since Debug.WriteLine didn't work, I still tried to output something directly in the console.
After some deeper tests I came to the conclusion that the particle from MS Docs is garbage and I gave up because:
Too much time and effort hooking into other session every time.
It's cluttered and confusing
It actually doesn't do the same debug routine as it would in runtime.
Unhandled errors causes the designer to deactivate the component which leads into restart (both) VS sessions.
And as said I didn't found a clue why I don't get debug / console output.
Which further led me to the following conclusions:
For me it is basically enough to output something in the console at critical points. What is extremely annoying is that I cannot delete the components and insert them again because Visual Studio gets stuck internally somewhere. That would be the next thing I want to tackle.
It is definitely not necessary and logically wrong to attach the VS process to another instance of VS. The session of VS already does that with the component. And generates a temp exe inside appdata.
A custom or extended error handler (logger) is a good idea. Like you do when you make a public exe where other people can send you the debug text. In this case you send it back to yourself. ;)
Next step: What options do stack overflow and other pages offer? 📌
Related topics on stack overflow
How to debug winforms designer - The same as MS docs, but the accepted answer is interesting:
How does the Winforms Designer instantiate my form?
How can I debug at design time? - XDesProc.exe VS12++ Same procedure we know already, maybe it's just me but I don't like it.
Visual Studio 2015 Debugging Custom Control - This one just confuses me and seems to be a different type of programming than what I prefer.
How to troubleshoot and debug Visual Studio design mode errors? - Just another duplicate of scheme f
How do you debug a WPF user control in design mode? - Just another duplicate of scheme f
DesignMode with nested Controls
This one is interesting. But they somehow have problems with the iDesignerHost and thus to set a readonly in the component class. I have already solved both problems before I started reading. See my answer later. And this.
Good Way to Debug Visual Studio Designer Errors - This one is nice.
Related topics on other sites
Visual Studio 2013 and Blend design-time exception debugging
How to debug C# Winforms User controls at Design Time
Design-Time Support for Custom Controls - Not yet read through
Designer Debugging in WinRT
My current goals 🏆
Get away from MS docs "solution"
Set up a simple debug output system for the designer
What I've done so far is a simple message system that seems to work so far. I don't want to output the debug content inside a designer generated window. I could create a Form Window, I know. Or even better I could create an other application to communicate with the designer. For the moment I'm satisfied with a very simple solution. Just to get any output at all.
I made a few interesting experiences, e.g. to get the solution / project folder at design time.
It's a bit of a tinker, but I'm pretty happy with it. So I had the absurd idea to simply output the text internally into a notepad window. I have no "using" namespaces to make it more flexible and clearly expressed. There is also a dispose implementation. I'm not sure if that makes sense. But my idea was to avoid a persistent thread if the class is deconstructed during design time. Or just to be prepared for the case. Here's the code:
public class SendToNotepad : System.IDisposable
{
private bool _disposed;
public SendToNotepad() { }
public static void Text(string text, bool d) { Send.SendText(text, d); }
~SendToNotepad() { Dispose(false); }
public void Dispose()
{
Dispose(true);
System.GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed) { return; }
if (disposing)
{
// Dispose managed state
}
Send.Dispose();
_disposed = true;
}
private static class Send
{
private const int STARTF_USESHOWWINDOW = 1;
private const int SW_SHOWNOACTIVATE = 4;
private const int SW_SHOWMINNOACTIVE = 7;
private const int CREATE_NEW_CONSOLE = 0x000010;
private const int EM_SETSEL = 0x00B1;
private const int EM_REPLACESEL = 0x00C2;
private const int WM_SETTEXT = 0x000C;
private const int WM_GETTEXTLENGTH = 0x000E;
private const int WM_COMMAND = 0x0111;
private const int WM_APPCOMMAND = 0x0319;
private const int WM_QUIT = 0x0012;
private const int APPCOMMAND_SAVE = 0x201000;
private const int SleepTime = 10;
private static UnsafeNativeMethods.STARTUPINFO _si;
private static UnsafeNativeMethods.PROCESS_INFORMATION _pi;
private static System.Diagnostics.Process _p;
private static System.Threading.Timer _timer;
private static bool _isWaiting;
private static string _waitingCatcher;
private static string _debugFileName;
private static readonly string Namespace = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace;
private static readonly string[] TitleLoopAniChars = new[] { "|", "/", "––", "\\" };
private static readonly int TitleLoopAniCharsLength = TitleLoopAniChars.Length - 1;
public static void Dispose()
{
if (_p != null)
{
try
{
UnsafeNativeMethods.CloseHandle(_pi.hProcess);
UnsafeNativeMethods.CloseHandle(_pi.hThread);
}
catch { }
_p.Dispose();
_p = null;
}
if (_timer != null)
{
_timer.Dispose();
_timer = null;
}
}
public static void SendText(string text, bool d)
{
if (!d) { return; }
text = System.DateTime.Now.TimeOfDay + ": " + text + System.Environment.NewLine;
if (_isWaiting)
{
_waitingCatcher += text;
return;
}
_isWaiting = true;
int maxWait = 200; // Max timeout over all (* SleepTime)
if (_p == null)
{
_debugFileName = GetDebugFileName();
if (System.String.IsNullOrEmpty(_debugFileName))
{
_waitingCatcher += text;
_isWaiting = false;
return;
}
if (!System.IO.File.Exists(_debugFileName))
{
try { System.IO.File.Create(_debugFileName).Dispose(); }
catch { }
}
if (!System.IO.File.Exists(_debugFileName))
{
_waitingCatcher += text;
_isWaiting = false;
return;
}
_si = new UnsafeNativeMethods.STARTUPINFO
{
dwFlags = STARTF_USESHOWWINDOW,
wShowWindow = SW_SHOWMINNOACTIVE,
cb = System.Runtime.InteropServices.Marshal.SizeOf(_si)
};
bool success = UnsafeNativeMethods.CreateProcess(null, "notepad /W \"" + _debugFileName + "\"", System.IntPtr.Zero, System.IntPtr.Zero, true, 0, System.IntPtr.Zero, null, ref _si, out _pi);
while (maxWait-- > 0 && success)
{
System.Threading.Thread.Sleep(SleepTime);
try { _p = System.Diagnostics.Process.GetProcessById(_pi.dwProcessId); } // grab Process to handle WaitForExit()
catch { }
if (_p != null) { break; }
}
if (_p == null)
{
_waitingCatcher += text;
_isWaiting = false;
return;
}
while (maxWait-- > 0 && (!_p.Responding || !_p.WaitForInputIdle())) { System.Threading.Thread.Sleep(SleepTime); }
_timer = new System.Threading.Timer(NotifyOnProcessExits);
_timer.Change(0, 0);
}
else
{
while (maxWait-- > 0 && (!_p.Responding || !_p.WaitForInputIdle())) { System.Threading.Thread.Sleep(SleepTime); }
}
System.IntPtr fwx = UnsafeNativeMethods.FindWindowEx(_p.MainWindowHandle, System.IntPtr.Zero, "Edit", null);
UnsafeNativeMethods.SendMessage(fwx, EM_SETSEL, 0, -1);
UnsafeNativeMethods.SendMessage(fwx, EM_SETSEL, -1, -1);
UnsafeNativeMethods.SendMessageW(fwx, EM_REPLACESEL, 1, text);
if (!System.String.IsNullOrEmpty(_waitingCatcher))
{
UnsafeNativeMethods.SendMessage(fwx, EM_SETSEL, 0, -1);
UnsafeNativeMethods.SendMessage(fwx, EM_SETSEL, -1, -1);
UnsafeNativeMethods.SendMessageW(fwx, EM_REPLACESEL, 1, _waitingCatcher);
_waitingCatcher = "";
}
UnsafeNativeMethods.SendMessage(_p.MainWindowHandle, WM_COMMAND, 0x0003, 0x0); // first menu, item 3 (save)
_isWaiting = false;
}
private static void NotifyOnProcessExits(object timer)
{
if (_p == null) { return; }
// _p.WaitForExit();
// This is just for fun as response feedback
int i = 0;
while (!_p.HasExited)
{
System.Threading.Thread.Sleep(500);
UnsafeNativeMethods.SetWindowText(_p.MainWindowHandle, Namespace + " –> " + _debugFileName + " " + TitleLoopAniChars[i]);
i = i == TitleLoopAniCharsLength ? 0 : i + 1;
}
Dispose();
}
private static string GetDebugFileName() // Hack to get solution path while design time
{
string s;
try
{
var trace = new System.Diagnostics.StackTrace(true);
var frame = trace.GetFrame(0);
s = System.IO.Path.GetDirectoryName(frame.GetFileName());
}
catch { return null; }
return s == null ? null : s + "Debug.txt";
}
[System.Security.SuppressUnmanagedCodeSecurity]
private static class UnsafeNativeMethods
{
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct STARTUPINFO
{
public System.Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public System.Int32 dwX;
public System.Int32 dwY;
public System.Int32 dwXSize;
public System.Int32 dwYSize;
public System.Int32 dwXCountChars;
public System.Int32 dwYCountChars;
public System.Int32 dwFillAttribute;
public System.Int32 dwFlags;
public System.Int16 wShowWindow;
public System.Int16 cbReserved2;
public System.IntPtr lpReserved2;
public System.IntPtr hStdInput;
public System.IntPtr hStdOutput;
public System.IntPtr hStdError;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
internal struct PROCESS_INFORMATION
{
public System.IntPtr hProcess;
public System.IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
public static extern bool CreateProcess(
string lpApplicationName,
string lpCommandLine,
System.IntPtr lpProcessAttributes,
System.IntPtr lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
System.IntPtr lpEnvironment,
string lpCurrentDirectory,
[System.Runtime.InteropServices.In] ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation
);
[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
[return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
public static extern bool CloseHandle(System.IntPtr hObject);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int SendMessage(System.IntPtr hWnd, int uMsg, int wParam, int lParam);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern System.IntPtr SendMessage(System.IntPtr hWnd, int uMsg, System.IntPtr wParam, System.IntPtr lParam);
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
public static extern int SendMessageW(System.IntPtr hWnd, int uMsg, int wParam, string lParam);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern System.IntPtr DefWindowProc(System.IntPtr hWnd, int msg, System.IntPtr wParam, System.IntPtr lParam);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern System.IntPtr FindWindowEx(System.IntPtr hwndParent, System.IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int SetWindowText(System.IntPtr hWnd, string text);
}
}
}
And inside a component class:
private static readonly bool DesignTime = LicenseManager.UsageMode == LicenseUsageMode.Designtime;
SendToNotepad.Text("Debug text", DesignTime);
That has the nice (unexcepted) side effect that if VS crashes the debug content is retained.
And now I have the still more absurd idea of hooking into the vs process and sending the text back. I think I'm digging myself in a hole deeper and deeper. ;)

C#: Microsoft.VisualBasic.Interaction.AppActivate no effect

My code is very simple:
using Microsoft.VisualBasic;
namespace HelloWorld {
class MyClass {
static void Main(string[] args) {
Interaction.AppActivate(6156); // the PID of notepad++
}
}
}
When I execute this program, nothing happens. I would expect 6156 (PID from Task Manager) aka Notepad++ to get focused. What's wrong here?
I'm trying to find the equivalent to Pythons pywin32 code of shell = win32com.client.Dispatch("WScript.Shell") and shell.AppActivate(6156)
The Interaction.AppActivate code will not work if the app is minimized.
Use the following code to active the app:
public const int SW_RESTORE = 9;
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
static extern public bool ShowWindow(IntPtr hWnd, int nCmdShow);
static void Main(string[] args)
{
var process = Process.GetProcessById(18036);
ShowWindow(process.MainWindowHandle, SW_RESTORE);
SetForegroundWindow(process.MainWindowHandle);
}
This works fine for me.
static void Main(string[] args)
{
var process = Process.GetProcessById(13004);//the pid
if (process == null) return;
SwitchToThisWindow(process.MainWindowHandle, true);
}
[DllImport("user32.dll", SetLastError = true)]
static extern void SwitchToThisWindow(IntPtr hWnd, bool turnOn);

Gracefully restarting explorer.exe as of Windows 10 1709, Fall Creators Update aka Redstone 3

For the current version of Windows 10, 1703, the Creators Update, I have this little C# app getting called to restart explorer.exe during an installation sequence. This is to help refresh the taskbar/registry entries, so that one of the virtual peripherals will appear on the taskbar after installation without rebooting.
using System;
using System.Diagnostics;
namespace RestartExplorer
{
class Program
{
static int Main(string[] args)
{
var process = Process.GetProcessesByName("explorer")[0];
process.Kill();
Process.Start("explorer");
return 0;
}
}
}
This was working fine in Redstone 2, but in the current Insiders Preview Windows 10 1709 Redstone 3 build of 16294.1.170916-2023, it doesn't just kill the explorer shell, it kills all the open file explorer windows too. That's super invasive, and if I had a couple dozen windows open while working when that happened, I don't think I'd be very happy about the UX.
I verified that CTRL+SHIFTRight-Click on the Taskbar for Exit Explorer also shows the same diverging behavior, not just my little app.
So, if I want to make sure my users' windows aren't all lost, how should I now be restarting explorer, or better yet, is there an even better way to get the end-result for what I'm looking to do?
Use the restart manager API to close all open explorers. It will restart any that were closed. Only downside is that restarted apps will be activated so you have to code around your app losing focus.
See https://msdn.microsoft.com/en-us/library/windows/desktop/aa373649(v=vs.85).aspx
var sessionKey = Guid.NewGuid().ToString();
NativeMethods.RmStartSession(out IntPtr session, 0, sessionKey).CheckError();
try
{
NativeMethods.RmRegisterResources(session, 1, new[] { Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "explorer.exe") }, 0, null, 0, null).CheckError();
NativeMethods.RmShutdown(session, 0, null).CheckError();
NativeMethods.RmRestart(session, 0, null).CheckError();
}
finally
{
NativeMethods.RmEndSession(session);
}
You will also need the following NativeMethods
public static class NativeMethods
{
[StructLayout(LayoutKind.Sequential)]
internal struct RM_UNIQUE_PROCESS
{
public int dwProcessId;
public com.FILETIME ProcessStartTime;
}
[Flags]
internal enum RM_SHUTDOWN_TYPE : uint
{
RmForceShutdown = 0x1,
RmShutdownOnlyRegistered = 0x10
}
internal delegate void RM_WRITE_STATUS_CALLBACK(UInt32 nPercentComplete);
[DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)]
internal static extern int RmStartSession(out IntPtr pSessionHandle, int dwSessionFlags, string strSessionKey);
[DllImport("rstrtmgr.dll")]
internal static extern int RmEndSession(IntPtr pSessionHandle);
[DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)]
internal static extern int RmRegisterResources(IntPtr pSessionHandle, UInt32 nFiles, string[] rgsFilenames, UInt32 nApplications, RM_UNIQUE_PROCESS[] rgApplications, UInt32 nServices, string[] rgsServiceNames);
[DllImport("rstrtmgr.dll")]
internal static extern int RmShutdown(IntPtr pSessionHandle, RM_SHUTDOWN_TYPE lActionFlags, RM_WRITE_STATUS_CALLBACK fnStatus);
[DllImport("rstrtmgr.dll")]
internal static extern int RmRestart(IntPtr pSessionHandle, int dwRestartFlags, RM_WRITE_STATUS_CALLBACK fnStatus);
[DllImport("kernel32.dll")]
internal static extern bool GetProcessTimes(IntPtr hProcess, out com.FILETIME lpCreationTime, out com.FILETIME lpExitTime, out com.FILETIME lpKernelTime, out com.FILETIME lpUserTime);
}
Based on the #Tim code and for providing a more usable example here is the class I just wrote for interacting with Restart Manager:
https://gist.github.com/falahati/34b23831733151460de1368c5fba8e93
Here is an example:
using RestartManager;
public static class Test
{
public static void Main()
{
using (var rm = new RestartManagerSession())
{
// add all processes having the name `explorer`
rm.RegisterProcess(Process.GetProcessesByName("explorer"));
// you can also add explorer.exe specifically by
// using the `RegisterProcessFile()` method
//rm.RegisterProcessFile(new FileInfo(Path.Combine(
// Environment.GetFolderPath(Environment.SpecialFolder.Windows),
// "explorer.exe"
//)));
rm.Shutdown(RestartManagerSession.ShutdownType.Normal);
rm.Restart();
}
}
}
You can also use the following piece of code to get Explorer's main process in case you want to be more specific:
[DllImport("user32")]
private static extern IntPtr GetShellWindow();
[DllImport("user32", SetLastError = true)]
private static extern uint GetWindowThreadProcessId(IntPtr windowHandle, out uint processId);
public static Process GetShellProcess()
{
try
{
var shellWindowHandle = GetShellWindow();
if (shellWindowHandle != IntPtr.Zero)
{
GetWindowThreadProcessId(shellWindowHandle, out var shellPid);
if (shellPid > 0)
{
return Process.GetProcessById((int) shellPid);
}
}
}
catch (Exception)
{
// ignored
}
return null;
}
And later on, use the same class to restart it with Restart Manager. It is better than Process.GetProcessesByName("explorer")[0] anyway.

Connecting UWP apps hosted by ApplicationFrameHost to their real processes

I am working on an WPF application to monitor my activities on my computer. I use Process.GetProcesses() and some filtering to get the processes I am interested in (example:Calculator) then I record their StartTime. I am also using WIN32/USER32 API method GetForegroundWindow() to get the window the user is using.
The problem is that when the windows are Windows/UWP applications they are always hosted by the process ApplicationFrameHost. So the GetForegroundWindow() method returns that window with a title (example:Calculator), but not the real process being hosted.
What I need is either another way to get the foreground window that includes the real process being hosted, or some way to connect the window to process.
Anyone that knows how to accomplish this? All help would be really appreciated.
I eventually found a way to do this, so I am going answer my own question so maybe someone in the future with the same problem could find it useful.
This is the class with the WinApiFunctions:
public class WinAPIFunctions
{
//Used to get Handle for Foreground Window
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr GetForegroundWindow();
//Used to get ID of any Window
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
public delegate bool WindowEnumProc(IntPtr hwnd, IntPtr lparam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc callback, IntPtr lParam);
public static int GetWindowProcessId(IntPtr hwnd)
{
int pid;
GetWindowThreadProcessId(hwnd, out pid);
return pid;
}
public static IntPtr GetforegroundWindow()
{
return GetForegroundWindow();
}
}
And this is the class I used to test if it would work. I used it in a simple console program that just writes out the name of the process that has current focus:
class FindHostedProcess
{
public Timer MyTimer { get; set; }
private Process _realProcess;
public FindHostedProcess()
{
MyTimer = new Timer(TimerCallback, null, 0, 1000);
Console.ReadKey();
}
private void TimerCallback(object state)
{
var foregroundProcess = Process.GetProcessById(WinAPIFunctions.GetWindowProcessId(WinAPIFunctions.GetforegroundWindow()));
if (foregroundProcess.ProcessName == "ApplicationFrameHost")
{
foregroundProcess = GetRealProcess(foregroundProcess);
}
Console.WriteLine(foregroundProcess.ProcessName);
}
private Process GetRealProcess(Process foregroundProcess)
{
WinAPIFunctions.EnumChildWindows(foregroundProcess.MainWindowHandle, ChildWindowCallback, IntPtr.Zero);
return _realProcess;
}
private bool ChildWindowCallback(IntPtr hwnd, IntPtr lparam)
{
var process = Process.GetProcessById(WinAPIFunctions.GetWindowProcessId(hwnd));
if (process.ProcessName != "ApplicationFrameHost")
{
_realProcess = process;
}
return true;
}
}
Chris, there is the alternative way which I have discovered trying to apply your solution to a related problem. While trying to analyse how the ApplicationFrameHost.exe-related stuff worked, I have stumbled upon the documented way of getting the true foreground window / thread and its process by passing 0 instead of the actual thread ID to GetGUIThreadInfo.
It might not fully work for the edge-case scenarios of your problem, but I felt that this might be a useful contribution for people of the future who might face the same problems ;-)
Here is the example of how this can be applied (pseudo C++'ish code):
GUITHREADINFO gti = { sizeof(GUITHREADINFO) };
GetGUIThreadInfo(0, &gti); // <- note the `0`
DWORD processId = 0;
GetWindowThreadProcessId(gti.hwndFocus, &processId);
const auto procName = Util::GetProcessName(processId);
It solved my problem (obtaining the actual keyboard layout + finding the real foreground window) for all more-or-less common apps I have tested it against.
Basically, the answer you provided will also fail if the active window is in full screen mode,
for example if you have Skype app opened along with Microsoft Remote Desktop, which is the
active one and on full screen mode, EnumChildWindows would return SkypeApp not RDPClient.
and to get this fixed, you should follow the workaround suggested by Ivanmoskalev,
check this out:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetGUIThreadInfo(uint idThread, ref GUITHREADINFO lpgui);
public static IntPtr getThreadWindowHandle(uint dwThreadId)
{
IntPtr hWnd;
// Get Window Handle and title from Thread
var guiThreadInfo = new GUITHREADINFO();
guiThreadInfo.cbSize = Marshal.SizeOf(guiThreadInfo);
GetGUIThreadInfo(dwThreadId, ref guiThreadInfo);
hWnd = guiThreadInfo.hwndFocus;
//some times while changing the focus between different windows, it returns Zero so we would return the Active window in that case
if (hWnd == IntPtr.Zero)
{
hWnd = guiThreadInfo.hwndActive;
}
return hWnd;
}
[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern int GetWindowThreadProcessId(IntPtr windowHandle, out int processId);
static void Main(string[] args)
{
var current = getThreadWindowHandle(0);
int processId = 0;
GetWindowThreadProcessId(current, out processId);
var foregroundProcess = GetActiveProcess(processId);
}
private static Process GetActiveProcess(int activeWindowProcessId)
{
Process foregroundProcess = null;
try
{
foregroundProcess = Process.GetProcessById(activeWindowProcessId);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
if (string.IsNullOrWhiteSpace(GetProcessNameSafe(foregroundProcess)))
{
var msg = "Process name is empty.";
Console.WriteLine(msg);
}
return foregroundProcess;
}
About the same code from Chris Johnsson except that I'm not using Process because it doesn't work very well on the UWP app.
Code for start:
new Timer(TimerCallback, null, 0, 1000);
void TimerCallback(object state)
{
var process = new ProcessUtils.FindHostedProcess().Process;
string name = string.Empty;
if (process.IsPackaged)
{
var apps = process.GetAppDiagnosticInfos();
if (apps.Count > 0)
name = apps.First().AppInfo.DisplayInfo.DisplayName;
else
name = System.IO.Path.GetFileNameWithoutExtension(process.ExecutableFileName);
}
else
name = System.IO.Path.GetFileNameWithoutExtension(process.ExecutableFileName);
Debug.WriteLine(name);
}
And the FindHostedProcess class where I use ProcessDiagnosticInfo instead of Process
public class FindHostedProcess
{
public ProcessDiagnosticInfo Process { get; private set; }
public FindHostedProcess()
{
var foregroundProcessID = WinAPIFunctions.GetforegroundWindow();
Process = ProcessDiagnosticInfo.TryGetForProcessId((uint)WinAPIFunctions.GetWindowProcessId(foregroundProcessID));
// Get real process
if (Process.ExecutableFileName == "ApplicationFrameHost.exe")
WinAPIFunctions.EnumChildWindows(foregroundProcessID, ChildWindowCallback, IntPtr.Zero);
}
private bool ChildWindowCallback(IntPtr hwnd, IntPtr lparam)
{
var process = ProcessDiagnosticInfo.TryGetForProcessId((uint)WinAPIFunctions.GetWindowProcessId(hwnd));
if (process.ExecutableFileName != "ApplicationFrameHost.exe")
Process = process;
return true;
}
}
Finally reuse Chris Johnson's WinAPIFunctions class.

Get total amount of memory from WinXP and above

There are already many answers about this topic, but is there a single way to get the the total amount of memory on a windows system from XP and above including Windows Server 2003?
What I have found:
Win32_LogicalMemoryConfiguration (Deprecated)
Win32_ComputerSystem (Minimum supported client: Vista)
Microsoft.VisualBasic.Devices.ComputerInfo (no XP support according to platforms)
thx
Add reference to Microsoft.VisualBasic and
var info = new Microsoft.VisualBasic.Devices.ComputerInfo();
Debug.WriteLine(info.TotalPhysicalMemory);
Debug.WriteLine(info.AvailablePhysicalMemory);
Debug.WriteLine(info.TotalVirtualMemory);
Debug.WriteLine(info.AvailableVirtualMemory);
edit : How can I get the total physical memory in C#?
or
You can make use of GlobalMemoryStatusEx : Example Here
private void DisplayMemory()
{
// Consumer of the NativeMethods class shown below
long tm = System.GC.GetTotalMemory(true);
NativeMethods oMemoryInfo = new NativeMethods();
this.lblMemoryLoadNumber.Text = oMemoryInfo.MemoryLoad.ToString();
this.lblIsMemoryTight.Text = oMemoryInfo.isMemoryTight().ToString();
if (oMemoryInfo.isMemoryTight())
this.lblIsMemoryTight.Text.Font.Bold = true;
else
this.lblIsMemoryTight.Text.Font.Bold = false;
}
Native class wrapper.
[CLSCompliant(false)]
public class NativeMethods {
private MEMORYSTATUSEX msex;
private uint _MemoryLoad;
const int MEMORY_TIGHT_CONST = 80;
public bool isMemoryTight()
{
if (_MemoryLoad > MEMORY_TIGHT_CONST )
return true;
else
return false;
}
public uint MemoryLoad
{
get { return _MemoryLoad; }
internal set { _MemoryLoad = value; }
}
public NativeMethods() {
msex = new MEMORYSTATUSEX();
if (GlobalMemoryStatusEx(msex)) {
_MemoryLoad = msex.dwMemoryLoad;
//etc.. Repeat for other structure members
}
else
// Use a more appropriate Exception Type. 'Exception' should almost never be thrown
throw new Exception("Unable to initalize the GlobalMemoryStatusEx API");
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
private class MEMORYSTATUSEX
{
public uint dwLength;
public uint dwMemoryLoad;
public ulong ullTotalPhys;
public ulong ullAvailPhys;
public ulong ullTotalPageFile;
public ulong ullAvailPageFile;
public ulong ullTotalVirtual;
public ulong ullAvailVirtual;
public ulong ullAvailExtendedVirtual;
public MEMORYSTATUSEX()
{
this.dwLength = (uint) Marshal.SizeOf(typeof( MEMORYSTATUSEX ));
}
}
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool GlobalMemoryStatusEx( [In, Out] MEMORYSTATUSEX lpBuffer);
}

Categories