How to get active window app name as shown in task manager - c#

I am trying to get the active window's name as shown in the task manager app list (using c#).
I had the same issue as described here.
I tried to do as they described but I have issue while the focused application is the picture library I get exception.
I also tried this, but nothing gives me the results I expect.
For now I use:
IntPtr handle = IntPtr.Zero;
handle = GetForegroundWindow();
const int nChars = 256;
StringBuilder Buff = new StringBuilder(nChars);
if (GetWindowText(handle, Buff, nChars) > 0)
{
windowText = Buff.ToString();
}
and delete what is not relevant based on a table I created for most common apps, but I don't like this workaround.
Is there a way to get the app name as it is in the task manager for all running app?

After reading a lot, I separated my code into two cases, for metro application and all other applications.
My solution handle the exception I got for metro applications and exceptions I got regarding the platform.
This is the code that finally worked:
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
public string GetActiveWindowTitle()
{
var handle = GetForegroundWindow();
string fileName = "";
string name = "";
uint pid = 0;
GetWindowThreadProcessId(handle, out pid);
Process p = Process.GetProcessById((int)pid);
var processname = p.ProcessName;
switch (processname)
{
case "explorer": //metro processes
case "WWAHost":
name = GetTitle(handle);
return name;
default:
break;
}
string wmiQuery = string.Format("SELECT ProcessId, ExecutablePath FROM Win32_Process WHERE ProcessId LIKE '{0}'", pid.ToString());
var pro = new ManagementObjectSearcher(wmiQuery).Get().Cast<ManagementObject>().FirstOrDefault();
fileName = (string)pro["ExecutablePath"];
// Get the file version
FileVersionInfo myFileVersionInfo = FileVersionInfo.GetVersionInfo(fileName);
// Get the file description
name = myFileVersionInfo.FileDescription;
if (name == "")
name = GetTitle(handle);
return name;
}
public string GetTitle(IntPtr handle)
{
string windowText = "";
const int nChars = 256;
StringBuilder Buff = new StringBuilder(nChars);
if (GetWindowText(handle, Buff, nChars) > 0)
{
windowText = Buff.ToString();
}
return windowText;
}

It sounds like you need to go through each top level window (direct children of the desktop window, use EnumWindows via pinvoke http://msdn.microsoft.com/en-us/library/windows/desktop/ms633497(v=vs.85).aspx) and then call your GetWindowText pinvoke function.
EnumWindows will 'Enumerates all top-level windows on the screen by passing the handle to each window, in turn, to an application-defined callback function.'

Related

Using "Inspect.exe" can't find some elements, why?

I want to use c # write a UI Automation program, but I can't find some elements with "Inspect.exe", Can't find pictures of text labels(eg. image1), why?
image1: https://i.stack.imgur.com/NqpKA.png
image2: https://i.stack.imgur.com/2PIuj.png
Code sample:
var desktop = AutomationElement.RootElement;
var condition = new PropertyCondition(AutomationElement.NameProperty, "Customer Register");
var window = desktop.FindFirst(System.Windows.Automation.TreeScope.Children, condition);
The code you posted for getting the elements is correct from what I can see in your screen shot from inspect. I have a feeling that the UI Automation is not getting the name back because of the text encoding. Unless you have access to the source and can mess with how it gets and sets text for those labels it won't be possible to retrieve the text through UI Automation.
You could use the code you have and use the native window handle for the window with the win32 api to get the text.
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, [Out] StringBuilder lParam);
public static string GetWindowTextRaw(IntPtr hwnd)
{
// Allocate correct string length first
int length = (int)SendMessage(hwnd, WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
StringBuilder sb = new StringBuilder(length + 1);
SendMessage(hwnd, WM_GETTEXT, (IntPtr)sb.Capacity, sb);
return sb.ToString();
}
public static void YourMethod()
{
var desktop = AutomationElement.RootElement;
var process = Process.Start("Path/To/Your/Process.exe");
var condition = new PropertyCondition(AutomationElement.ProcessId, process.Id);
var window = desktop.FindFirst(System.Windows.Automation.TreeScope.Children, condition);
var windowTitle = GetWindowTextRaw(window.NativeWindowHandle)
}
Sources:
GetWindowText
SendMessage

Setting PIN prompt in Smart Card Crypto Provider's dialog box

I want to change the text that shows when invoking CryptoApi operation that requires smart card PIN. Current prompt is pretty generic (and in system's language), "Please enter your authentication PIN":
This dialog shows when calling CryptSignMessage in COM object, but the call is made from C# WPF desktop app (.NET 4.5). How can I customize the dialog? I've found PP_PIN_PROMPT_STRING parameter for CryptSetProvParam function, but the function requires HCRYPTPROV and I don't have that handle. All I have is reader's name and signing certificate. Just can't wrap my head around it.
Is it possible to customize PIN dialog from either C++ or C# (preferably C#)?
I believe the following should work. As I don't have anything setup to test collecting the information I can't verify.
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptAcquireContext(out IntPtr phProv, string pszContainer, string pszProvider, uint dwProvType, uint dwFlags);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CryptSetProvParam(IntPtr hProv, uint dwParam, [In] byte[] pbData, uint dwFlags);
[DllImport("advapi32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptReleaseContext(IntPtr hProv, uint dwFlags);
const string MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0";
const uint NTE_BAD_KEYSET = 0x80090016;
const uint PROV_RSA_FULL = 1;
const uint CRYPT_VERIFYCONTEXT = 0xF0000000;
const uint CRYPT_NEWKEYSET = 0x00000008;
const uint PP_PIN_PROMPT_STRING = 0x2C;
public void SetPinText(string text)
{
byte[] data = Encoding.UTF8.GetBytes(text);
IntPtr hCryptProv = IntPtr.Zero;
try
{
if (!CryptAcquireContext(out hCryptProv, null, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
{
if (Convert.ToUInt32(Marshal.GetLastWin32Error()) == NTE_BAD_KEYSET)
{
if (!CryptAcquireContext(out hCryptProv, null, null, PROV_RSA_FULL, CRYPT_NEWKEYSET))
throw new Exception("Unable to acquire crypt context.");
}
else
{
throw new Exception("Unable to acquire crypt context.");
}
}
if (!CryptSetProvParam(hCryptProv, PP_PIN_PROMPT_STRING, data, 0))
throw new Exception("Unable to set prompt string.");
}
finally
{
if (hCryptProv != IntPtr.Zero)
{
CryptReleaseContext(hCryptProv, 0);
}
}
}

Determine if process has finished opening file

I have a C# form (WPF/XAML) that triggers a new process to open a file using a 3rd party application (SAS JMP) by the default file association:
System.Diagnostics.Process myProcess = new System.Diagnostics.Process();
myProcess.StartInfo.FileName = #"C:\temp\test.jsl";
myProcess.Start();
I'm looking for a way to report back to my application that the process has started and the file has finished opening, or at least, the application window for the new process has appeared.
I tried to wait for myProcess.Responding to return true, but that happens instantly before I even see the application window appear.
Solution based on input from Marcos Vqz de Rdz:
bool alreadyOpen = Process.GetProcesses().Where(p => p.MainWindowHandle != IntPtr.Zero && p.ProcessName == "jmp").Count() > 0;
Process myProcess = new Process();
myProcess.StartInfo.FileName = #"C:\temp\test.jsl";
myProcess.Start();
if (!alreadyOpen)
{
bool wait = true, timeout = false;
DateTime start = DateTime.Now;
while (!timeout && wait)
{
timeout = (DateTime.Now - start).TotalSeconds > 10;
var window = Process.GetProcesses().Where(p => p.Id == myProcess.Id).FirstOrDefault();
if (window != null)
wait = string.IsNullOrEmpty(window.MainWindowTitle);
}
}
Have you tried using Process.WaitForInputIdle Method?
myProcess.WaitForInputIdle();
UPDATE
OK, the only thing I can think of right now, is search for the new application window to show up.
You can find something useful here.
UPDATE
Found this:
var openWindowProcesses = System.Diagnostics.Process.GetProcesses().Where(p => p.MainWindowHandle != IntPtr.Zero);
Use that with a timer right before you start the process to wait for the 3rd party app window to show up.
UPDATE
foreach (var item in openWindowProcesses)
{
Console.WriteLine(GetWindowTitle(item.MainWindowHandle));
}
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam, uint fuFlags, uint uTimeout, out IntPtr lpdwResult);
private static string GetWindowTitle(IntPtr windowHandle)
{
uint SMTO_ABORTIFHUNG = 0x0002;
uint WM_GETTEXT = 0xD;
int MAX_STRING_SIZE = 32768;
IntPtr result;
string title = string.Empty;
IntPtr memoryHandle = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(MAX_STRING_SIZE);
System.Runtime.InteropServices.Marshal.Copy(title.ToCharArray(), 0, memoryHandle, title.Length);
SendMessageTimeout(windowHandle, WM_GETTEXT, (IntPtr)MAX_STRING_SIZE, memoryHandle, SMTO_ABORTIFHUNG, (uint)1000, out result);
title = System.Runtime.InteropServices.Marshal.PtrToStringAuto(memoryHandle);
System.Runtime.InteropServices.Marshal.FreeCoTaskMem(memoryHandle);
return title;
}
Source: c# Get process window titles

Why IEGetProtectedModeCookie() always return 0x80070057?

According the function description in "http://msdn.microsoft.com/en-us/library/cc196998%28v=VS.85%29.aspx", I wrote the following code to try to get IE protected cookies:
public static string GetProtectedModeCookie(string lpszURL, string lpszCookieName, uint dwFlags)
{
var size = 255;
var sb = new System.Text.StringBuilder(size);
var acturalSize = sb.Capacity;
var code = IEGetProtectedModeCookie(lpszURL, lpszCookieName, sb, ref acturalSize, dwFlags);
if ((code & 0x80000000) > 0) return string.Empty;
if (acturalSize > size)
{
sb.EnsureCapacity(acturalSize);
IEGetProtectedModeCookie(lpszURL, lpszCookieName, sb, ref acturalSize, dwFlags);
}
return sb.ToString();
}
[DllImport("ieframe.dll", SetLastError = true)]
public static extern uint IEGetProtectedModeCookie(string lpszURL, string lpszCookieName, System.Text.StringBuilder pszCookieData, ref int pcchCookieData, int dwFlags);
to test this function:
var cookies = GetProtectedModeCookie("http://bbs.pcbeta.com/", null, 0);
But the api IEGetProtectedModeCookie always return 0x80070057 which indicates that one or more arguments are invalid.
I was confused, after a lot of try finally failed, only get this result. Can anybody help me?
IEGetProtectedModeCookie will return E_INVALIDARG if it thinks that the URL isn't meant to open in Protected Mode. It determines this using the IEIsProtectedModeURL API. So if you've put that URL in the Trusted Zone or whatnot, then you'll hit this error. The underlying InternetGetCookie API will return E_INVALIDARG if you fail to pass a URL or fail to pass a pointer to an integer for the size of the buffer.
Also note that the IEGetProtectedModeCookie API will not work from a high integrity (e.g. Admin) process; it will return ERROR_INVALID_ACCESS (0x8000000C).
Here's the code I use:
[DllImport("ieframe.dll", CharSet = CharSet.Unicode, EntryPoint = "IEGetProtectedModeCookie", SetLastError = true)]
public static extern int IEGetProtectedModeCookie(String url, String cookieName, StringBuilder cookieData, ref int size, uint flag);
private void GetCookie_Click(object sender, EventArgs e)
{
int iSize = 4096;
StringBuilder sbValue = new StringBuilder(iSize);
int hResult = IEAPI.IEGetProtectedModeCookie("http://www.google.com", "PREF", sbValue, ref iSize, 0);
if (hResult == 0)
{
MessageBox.Show(sbValue.ToString());
}
else
{
MessageBox.Show("Failed to get cookie. HRESULT=0x" + hResult.ToString("x") + "\nLast Win32Error=" + Marshal.GetLastWin32Error().ToString(), "Failed");
}
}
Charset parameter must be exist in DllImport attribute. Change the API declartion to follow will works well:
[DllImport("ieframe.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint IEGetProtectedModeCookie(string lpszURL, string lpszCookieName, System.Text.StringBuilder pszCookieData, ref int pcchCookieData, uint dwFlags);
If Charset parameter missed, this API will always return 0x80070057 which indicates one or more arguments are invalid.

Manipulate Registry Hive files from C#

1.)
How do Load, Edit and Save binary Hive files for registry from C#?
I found this Win32 api.
http://msdn.microsoft.com/en-us/library/ee210770%28VS.85%29.aspx
This guy shared the code to dump the content of binary Hive files to text.
http://www.codeproject.com/KB/recipes/RegistryDumper.aspx
2.)
In addition to manipulating the Hive files, I also search for a method to load the Hive file into registry at runtime using C#
(similar to the Load Hive and Unload Hive commands on the File many in regedit)
/Thanks
Have you looked at the Registry and RegistryKey classes in Microsoft.Win32?
http://msdn.microsoft.com/en-us/library/microsoft.win32.aspx
It sounds like you may need to create your own representation to read the hive file and either queue up or immediately make the corresponding registry changes. Likewise you would need to write your own converter back to disk.
The article below explains how to analyze the registry file without using WinAPI (advapi32.dll). In this particular case the guy is using Mono:
http://volatile-minds.blogspot.com/2011/01/analyzing-windows-nt-registry-without.html
using (FileStream fs = File.OpenRead (path)) {
var data = new byte[checked((int)fs.Length)];
int i = 0;
int read;
using (var ms = new MemoryStream (checked((int)fs.Length))) {
while ((read = fs.Read (data, 0, data.Length)) > 0) {
ms.Write (data, 0, read);
i += read;
}
byte[] hive = ms.ToArray ();
char[] cList = new char[fs.Length];
i = 0;
foreach (byte b in hive)
cList[i++] = (char)b;
string d = new string (cList);
int all = 0;
foreach (Match mx in lf.Matches (d)) { //you can change out the regex you want here.
byte[] bb = new byte[mx.Value.Length];
char[] cb = new char[mx.Value.Length];
for (int k = 0; k < mx.Value.Length; k++) {
bb[k] = (byte)mx.Value[k];
cb[k] = (char)bb[k];
}
all++;
//Console.WriteLine (new string (cb));
}
Console.WriteLine (all.ToString ());
all = 0;
}
}
This is 9 years old, but I figured this could help someone else. I wrote this class that allows you to do something like this:
Hive.AcquirePrivileges() // Acquires the privileges necessary for loading the hive
Hive myregistryhive = Hive.LoadFromFile("hivepathhere") // Loads the hive
// use myregistryhive.RootKey (a RegistryKey), read and/or write to it and its sub keys
myregistryhive.SaveAndUnload() // Unloads the hive
Hive.ReturnPrivileges() // De-elevate back to normal privileges.
The code for the class:
class Hive
{
[DllImport("advapi32.dll", SetLastError = true)]
static extern int RegLoadKey(IntPtr hKey, string lpSubKey, string lpFile);
[DllImport("advapi32.dll", SetLastError = true)]
static extern int RegSaveKey(IntPtr hKey, string lpFile, uint securityAttrPtr = 0);
[DllImport("advapi32.dll", SetLastError = true)]
static extern int RegUnLoadKey(IntPtr hKey, string lpSubKey);
[DllImport("ntdll.dll", SetLastError = true)]
static extern IntPtr RtlAdjustPrivilege(int Privilege, bool bEnablePrivilege, bool IsThreadPrivilege, out bool PreviousValue);
[DllImport("advapi32.dll")]
static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, ref UInt64 lpLuid);
[DllImport("advapi32.dll")]
static extern bool LookupPrivilegeValue(IntPtr lpSystemName, string lpName, ref UInt64 lpLuid);
private RegistryKey parentKey;
private string name;
private string originalPath;
public RegistryKey RootKey;
private Hive() { }
public static Hive LoadFromFile(string Path)
{
Hive result = new Hive();
result.parentKey = RegistryKey.OpenBaseKey(RegistryHive.Users, RegistryView.Default);
result.name = Guid.NewGuid().ToString();
result.originalPath = Path;
IntPtr parentHandle = result.parentKey.Handle.DangerousGetHandle();
RegLoadKey(parentHandle, result.name, Path);
//Console.WriteLine(Marshal.GetLastWin32Error());
result.RootKey = result.parentKey.OpenSubKey(result.name, true);
return result;
}
public static void AcquirePrivileges()
{
ulong luid = 0;
bool throwaway;
LookupPrivilegeValue(IntPtr.Zero, "SeRestorePrivilege", ref luid);
RtlAdjustPrivilege((int)luid, true, false, out throwaway);
LookupPrivilegeValue(IntPtr.Zero, "SeBackupPrivilege", ref luid);
RtlAdjustPrivilege((int)luid, true, false, out throwaway);
}
public static void ReturnPrivileges()
{
ulong luid = 0;
bool throwaway;
LookupPrivilegeValue(IntPtr.Zero, "SeRestorePrivilege", ref luid);
RtlAdjustPrivilege((int)luid, false, false, out throwaway);
LookupPrivilegeValue(IntPtr.Zero, "SeBackupPrivilege", ref luid);
RtlAdjustPrivilege((int)luid, false, false, out throwaway);
}
public void SaveAndUnload()
{
RootKey.Close();
RegUnLoadKey(parentKey.Handle.DangerousGetHandle(), name);
parentKey.Close();
}
}
Edit: Note that this requires administrator privileges.
please see: https://github.com/brandonprry/volatile_reader
It reads offline hives in C# with a GTK interface. No write support yet though.

Categories

Resources