Get tooltips text from C# with PInvoke - c#

I'm using PInvoke in C#, trying to read tooltips visible in a window with a known handler, but the apps who's windows I try to inspect in this manner crash with memory access violation errors, or simply don't reveal the tooltip text in the lpszText TOOLINFO member.
I'm calling EnumWindows with a callback and then sending a message to the tooltip window in that function:
public delegate bool CallBackPtr(IntPtr hwnd, IntPtr lParam);
static void Main(string[] args)
{
callBackPtr = new CallBackPtr(Report);
IntPtr hWnd = WindowFromPoint(<mouse coordinates point>);
if (hWnd != IntPtr.Zero)
{
Console.Out.WriteLine("Window with handle " + hWnd +
" and class name " +
getWindowClassName(hWnd));
EnumWindows(callBackPtr, hWnd);
Console.Out.WriteLine();
}
public static bool Report(IntPtr hWnd, IntPtr lParam)
{
String windowClassName = getWindowClassName(hWnd);
if (windowClassName.Contains("tool") &&
GetParent(hWnd) == lParam)
{
string szToolText = new string(' ', 250);
TOOLINFO ti = new TOOLINFO();
ti.cbSize = Marshal.SizeOf(typeof(TOOLINFO));
ti.hwnd = GetParent(hWnd);
ti.uId = hWnd;
ti.lpszText = szToolText;
SendMessage(hWnd, TTM_GETTEXT, (IntPtr)250, ref ti);
Console.WriteLine("Child window handle is " + hWnd + " and class name " + getWindowClassName(hWnd) + " and value " + ti.lpszText);
}
return true;
}
Here's how I defined the TOOLINFO structure:
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
private int _Left;
private int _Top;
private int _Right;
private int _Bottom;
}
struct TOOLINFO
{
public int cbSize;
public int uFlags;
public IntPtr hwnd;
public IntPtr uId;
public RECT rect;
public IntPtr hinst;
[MarshalAs(UnmanagedType.LPTStr)]
public string lpszText;
public IntPtr lParam;
}
the TTM_GETTEXT value
private static UInt32 WM_USER = 0x0400;
private static UInt32 TTM_GETTEXT = (WM_USER + 56);
and the SendMessage overload
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, ref TOOLINFO lParam);
So, is there any obvious error that I'm missing in my code, what should I change so that this situation is resolved?
Edit: Here is the whole code, so you could test.

You are sending a private message across processes, which requires manual marshaling. Here's another stackoverflow question on the same topic. Better would be to change direction entirely and use Active Accessibility and/or UI Automation, which are designed for this sort of thing.

I ended up using UI Automation, as Raymond suggested. AutomationElement, who's Name property value contains the text in case of tooltips, proved to be exactly what the code required. I'm cycling through all the Desktop's child windows, where all the tooltips reside and I only display those that belong to the process that owns the window under the mouse:
public static bool Report(IntPtr hWnd, IntPtr lParam)
{
if (getWindowClassName(hWnd).Contains("tool"))
{
AutomationElement element = AutomationElement.FromHandle(hWnd);
string value = element.Current.Name;
if (value.Length > 0)
{
uint currentWindowProcessId = 0;
GetWindowThreadProcessId(currentWindowHWnd, out currentWindowProcessId);
if (element.Current.ProcessId == currentWindowProcessId)
Console.WriteLine(value);
}
}
return true;
}
static void Main(string[] args)
{
callBackPtr = new CallBackPtr(Report);
do
{
System.Drawing.Point mouse = System.Windows.Forms.Cursor.Position; // use Windows forms mouse code instead of WPF
currentWindowHWnd = WindowFromPoint(mouse);
if (currentWindowHWnd != IntPtr.Zero)
EnumChildWindows((IntPtr)0, callBackPtr, (IntPtr)0);
Thread.Sleep(1000);
}
while (true);
}

Related

How to find message only window in C# by using FindWindowEx?

I think I've searched all of related topics on this planet by using Chinese and English but cannot find the solution.
I've created one message only window to receive and process the data from WM_COPYDATA, but I cannot find the window in send side, below is demo (WPF of C#):
Receive:
public partial class MainWindow : Window
{
private readonly IntPtr sourceHandle;
private const int WM_COPYDATA = 0x004A;
[StructLayout(LayoutKind.Sequential)]
public struct CopyDataStruct
{
public IntPtr dwData;
public int cbData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
public MainWindow()
{
InitializeComponent();
sourceHandle = this.CreateMessageOnlyWindow();
this.btnReceive.Content = sourceHandle;
}
private IntPtr CreateMessageOnlyWindow()
{
IntPtr HWND_MESSAGE = new IntPtr(-3);
HwndSourceParameters sourceParam = new HwndSourceParameters() { ParentWindow = HWND_MESSAGE };
var source = new HwndSource(sourceParam);
source.AddHook(WndProc);
return source.Handle;
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
{
if (msg == WM_COPYDATA)
{
MessageBox.Show(lparam.ToInt32().ToString());
handled = true;
return new IntPtr(20);
}
return IntPtr.Zero;
}
}
Send:
public partial class MainWindow : Window
{
IntPtr WM_COPYDATA = new IntPtr(0x004A);
IntPtr HWND_MESSAGE = new IntPtr(-3);
[DllImport("User32.dll")]
public static extern IntPtr SendMessage(IntPtr hwnd, IntPtr msg, IntPtr wParam, ref COPYDATASTRUCT IParam);
[DllImport("User32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cData;
[MarshalAs(UnmanagedType.LPStr)]
public string lpData;
}
public MainWindow()
{
InitializeComponent();
}
private void BtnSend_Click(object sender, RoutedEventArgs e)
{
//Here cannot find the target message only window in receiving
IntPtr WINDOW_HANDLE = FindWindowEx(HWND_MESSAGE, IntPtr.Zero, null, null);
if (WINDOW_HANDLE != IntPtr.Zero)
{
byte[] arr = System.Text.Encoding.Default.GetBytes(txtMessage.Text);
int len = arr.Length;
COPYDATASTRUCT cdata;
cdata.dwData = (IntPtr)100;
cdata.lpData = txtMessage.Text;
cdata.cData = len + 1;
SendMessage(WINDOW_HANDLE, WM_COPYDATA, IntPtr.Zero, ref cdata);
}
}
}
BtnSend_Click method in Send, cannot find the right window handle here, could someone in this pallet can help?
PS: I should describe my requirement first: I want to create a windows service in C#, which is receiver and deal with the data from WM_COPYDATA, so I think message only window is necessary because there is NO window in windows service.
So in Sender, I need to find this message only window to pass the window handle into SendMessage at first, here is the point.
Thanks guys

Use GetForegroundWindow result in an if statement to check user's current window

I need to check what window the user currently has selected, and do stuff if they have a specific program selected.
I haven't used the GetForegroundWindow function before, and can't find any information on how to use it in this manner.
I simply need an if comparing the current window to see if its a specific program. However the GetForegroundWindow function doesn't give back a string or int it seems. So mainly I don't know how to find out the value of the program window I want to compare it to.
I currently have the code to get the current window:
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
IntPtr selectedWindow = GetForegroundWindow();
I need to be able to apply it as follows ideally:
If (selectedWindow!="SpecificProgram")
{
<Do this stuff>
}
I'm hoping the GetForegroundWindow value/object is unique to each program and doesn't function in some way that each specific program/window has different values each-time.
I'm also doing this as part of a windows form though I doubt it matters.
-Thanks for any help
Edit: This way works, and uses the tile of the current window, which makes it perfect for checking if the window is right easily:
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
private string GetActiveWindowTitle()
{
const int nChars = 256;
StringBuilder Buff = new StringBuilder(nChars);
IntPtr handle = GetForegroundWindow();
if (GetWindowText(handle, Buff, nChars) > 0)
{
return Buff.ToString();
}
return null;
}
and then I can just do:
if (GetActiveWindowTitle()=="Name of Window")
{
DoStuff.jpg
}
It has some code but it works:
#region Retrieve list of windows
[DllImport("user32")]
private static extern int GetWindowLongA(IntPtr hWnd, int index);
[DllImport("USER32.DLL")]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("USER32.DLL")]
private static extern bool EnumWindows(EnumWindowsProc enumFunc, int lParam);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
private const int GWL_STYLE = -16;
private const ulong WS_VISIBLE = 0x10000000L;
private const ulong WS_BORDER = 0x00800000L;
private const ulong TARGETWINDOW = WS_BORDER | WS_VISIBLE;
internal class Window
{
public string Title;
public IntPtr Handle;
public override string ToString()
{
return Title;
}
}
private List<Window> windows;
private void GetWindows()
{
windows = new List<Window>();
EnumWindows(Callback, 0);
}
private bool Callback(IntPtr hwnd, int lParam)
{
if (this.Handle != hwnd && (GetWindowLongA(hwnd, GWL_STYLE) & TARGETWINDOW) == TARGETWINDOW)
{
StringBuilder sb = new StringBuilder(100);
GetWindowText(hwnd, sb, sb.Capacity);
Window t = new Window();
t.Handle = hwnd;
t.Title = sb.ToString();
windows.Add(t);
}
return true; //continue enumeration
}
#endregion
And to check user window:
IntPtr selectedWindow = GetForegroundWindow();
GetWindows();
for (i = 0; i < windows.Count; i++)
{
if(selectedWindow == windows[i].Handle && windows[i].Title == "Program Title X")
{
//Do stuff
break;
}
}
Valter

Drawing a circle outside the Winform

I am creating a Screen Recording app using Windows media encoder, i Can record the video and save it to a disk,now i need to draw a filled circle around the mouse click area when ever the mouse click event Fire( to high light the area that mouse press event occur), is there a way to do that? any code sample? thank you!!! sorry for not inserting the code here is my code
public void CaptureMoni()
{
string dateTime = DateTime.Now.ToString("yyyy.MM.dd _ HH.mm");
var dir = #"C:\VIDEOS\" + dateTime;
try
{
System.Drawing.Rectangle _screenRectangle = Screen.PrimaryScreen.Bounds;
_screenCaptureJob = new ScreenCaptureJob();
_screenCaptureJob.CaptureRectangle = _screenRectangle;
_screenCaptureJob.ShowFlashingBoundary = true;
_screenCaptureJob.ScreenCaptureVideoProfile.FrameRate = 10;
_screenCaptureJob.CaptureMouseCursor = true;
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
_screenCaptureJob.OutputScreenCaptureFileName = string.Format(Path.Combine(dir, dateTime + ".wmv"));
}
}
catch (Exception)
{
MessageBox.Show("Screnn Capturing Failed!" );
}
string temPath = (_screenCaptureJob.OutputScreenCaptureFileName.ToString());
// MessageBox.Show(temPath);
}
public ScreenCaptureJob _screenCaptureJob { get; set; }
finally i did what i need Special thanks to PacMani he direct me the right way,
NOTE : this is not a full code which include red circle in the video, this is only for having a red circle and making the transparent form on top of the all the other forms (sorry for the language mistakes)) thank you for the Help # PacMAni
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
WindowState = FormWindowState.Maximized;
this.TopMost = true;
}
protected override void WndProc(ref Message m)
{
if (m.Msg == (int)RMouseListener.WM.WM_NCHITTEST)
m.Result = (IntPtr)RMouseListener.WM.HTTRANSPARENT;
else
base.WndProc(ref m);
}
public void draw_circle()
{
int x = MousePosition.X;
int y = MousePosition.Y;
System.Drawing.SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Salmon);
System.Drawing.Graphics formGraphics = this.CreateGraphics();
formGraphics.FillEllipse(myBrush, new Rectangle(x - 60, y - 60, 60, 60));
myBrush.Dispose();
formGraphics.Dispose();
Thread.Sleep(200);
this.Invalidate();
}
RMouseListener _native;
private void button1_Click(object sender, EventArgs e)
{
//_native = new RMouseListener();
//_native.RButtonClicked += new EventHandler<SysMouseEventInfo>(_native_RButtonClicked);
//_native.LButtonClicked += new EventHandler<SysMouseEventInfo>(_native_LButtonClicked);
}
private void button2_Click(object sender, EventArgs e)
{
_native.Close();
this.Dispose();
}
void _native_RButtonClicked(object sender, SysMouseEventInfo e)
{
// listBox1.Items.Add(e.WindowTitle);
draw_circle();
}
void _native_LButtonClicked(object sender, SysMouseEventInfo e)
{
// listBox2.Items.Add(e.WindowTitle);
draw_circle();
}
// }
public class SysMouseEventInfo : EventArgs
{
public string WindowTitle { get; set; }
}
public class RMouseListener
{
Form1 frm = new Form1();
public RMouseListener()
{
this.CallBack += new HookProc(MouseEvents);
//Module mod = Assembly.GetExecutingAssembly().GetModules()[0];
//IntPtr hMod = Marshal.GetHINSTANCE(mod);
using (Process process = Process.GetCurrentProcess())
using (ProcessModule module = process.MainModule)
{
IntPtr hModule = GetModuleHandle(module.ModuleName);
_hook = SetWindowsHookEx(WH_MOUSE_LL, this.CallBack, hModule, 0);
}
}
int WH_MOUSE_LL = 14;
int HC_ACTION = 0;
HookProc CallBack = null;
IntPtr _hook = IntPtr.Zero;
public event EventHandler<SysMouseEventInfo> RButtonClicked;
public event EventHandler<SysMouseEventInfo> LButtonClicked;
int MouseEvents(int code, IntPtr wParam, IntPtr lParam)
{
//Console.WriteLine("Called");
//MessageBox.Show("Called!");
if (code < 0)
return CallNextHookEx(_hook, code, wParam, lParam);
if (code == this.HC_ACTION)
{
// Left button pressed somewhere
if (wParam.ToInt32() == (uint)WM.WM_RBUTTONDOWN || wParam.ToInt32() == (uint)WM.WM_LBUTTONDOWN)
{
MSLLHOOKSTRUCT ms = new MSLLHOOKSTRUCT();
ms = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
IntPtr win = WindowFromPoint(ms.pt);
string title = GetWindowTextRaw(win);
if (RButtonClicked != null || LButtonClicked != null)
{
RButtonClicked(this, new SysMouseEventInfo { WindowTitle = title });
LButtonClicked(this, new SysMouseEventInfo { WindowTitle = title });
}
}
}
return CallNextHookEx(_hook, code, wParam, lParam);
}
public void Close()
{
if (_hook != IntPtr.Zero)
{
UnhookWindowsHookEx(_hook);
}
}
public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SetWindowsHookEx", SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[System.Runtime.InteropServices.DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll")]
static extern IntPtr WindowFromPoint(int xPoint, int yPoint);
[DllImport("user32.dll")]
static extern IntPtr WindowFromPoint(POINT Point);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool UnhookWindowsHookEx(IntPtr hhk);
[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, (int)WM.WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
StringBuilder sb = new StringBuilder(65535);//THIS COULD BE BAD. Maybe you shoudl get the length
SendMessage(hwnd, (int)WM.WM_GETTEXT, (IntPtr)sb.Capacity, sb);
return sb.ToString();
}
[StructLayout(LayoutKind.Sequential)]
public struct MSLLHOOKSTRUCT
{
public POINT pt;
public int mouseData;
public int flags;
public int time;
public UIntPtr dwExtraInfo;
}
public enum WM : uint
{//all windows messages here
WM_LBUTTONDOWN = 0x0201,
WM_RBUTTONDOWN = 0x0204,
WM_GETTEXT = 0x000D,
WM_GETTEXTLENGTH = 0x000E,
WM_MOUSE = 0x0200,
WM_NCHITTEST = 0x84,
HTTRANSPARENT
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int X;
public int Y;
public POINT(int x, int y)
{
this.X = x;
this.Y = y;
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
_native = new RMouseListener();
_native.RButtonClicked += new EventHandler<SysMouseEventInfo>(_native_RButtonClicked);
_native.LButtonClicked += new EventHandler<SysMouseEventInfo>(_native_LButtonClicked);
}
Screen recording applications add this circle in their video file, not on the desktop.
If you still want to create a circle window, you need a form with the two things you have to implement:
Click-through window (otherwise the cursor could not click on things behind it anymore). See here for the solution: Click through transparency for Visual C# Window Forms?
Transparent window (transparency key might be enough here already, if you want alpha-blended transparency, things get more exciting, there are many examples for that on CodeProject, for example http://www.codeproject.com/Articles/20758/Alpha-Blended-Windows-Forms). Without this, you would have a rectangular window and not just a circle.
Also you need to register a global mouse hook to detect global mouse clicks. I think you already did this, but your question does not show what you've done and what not.
If you received a mouse click, create a borderless window around the mouse coordinates and (with the background color being the same as the transparency key to make it invisible where the circle isn't drawn) draw an ellipse on it (hook the Paint-event and use the Graphics objects DrawEllipse method).
Start a timer after which this window disappears again (or the circle would be visible forever). If you want this circle to animate as in other screen recording apps, use the timer to animate the drawing.

Get list of selected files from Windows Desktop

I am trying to get a list of selected files from the Windows Desktop and the Explorer Windows.
The requirement is that I should be able to retrieve the current selection from the active explorer window or the Desktop.
I have managed to put together the following code, after going through online resources, but it does not provide a list of selected items from the Desktop.
ArrayList selected = new ArrayList();
var shell = new Shell32.Shell();
IntPtr handle = IntPtr.Zero;
handle = GetForegroundWindow();
int intHandle = handle.ToInt32();
//For each explorer
foreach (InternetExplorer window in new ShellWindowsClass())
{
if (window.HWND == (int)handle)
{
Shell32.FolderItems items = ((Shell32.IShellFolderViewDual2)window.Document).SelectedItems();
foreach (Shell32.FolderItem item in items)
{
selected.Add(item.Path);
}
}
}
Other than that, I tried the following but it just gives a list of all selected elements in all open explorer windows while ignoring the Desktop.
string filename; = Path.GetFileNameWithoutExtension(window.FullName).ToLower();
if (filename.ToLowerInvariant() == "explorer")
{
Shell32.FolderItems items = ((Shell32.IShellFolderViewDual2)window.Document).SelectedItems();
foreach (Shell32.FolderItem item in items)
{
//MessageBox.Show(item.Path.ToString());
selected.Add(item.Path);
}
}
So I just always end up with a list from the explorer windows and get no results even when no explorer windows are open. The current techniques seem to be ignoring the Desktop altogether.
I would really appreciate it if someone could help me out to get a list of selected files from the currently active window/desktop.
Thank You.
It is easy for desktop since it is still a listview, just find the correct handle. list view is a child of the desktop handle.
Desktop
+- Progman (for backward compatibility)
+- Shell Def View
+- SysListView32 (even under 64 bit)
then you can do all listview operations on the list view. but other explorer windows does not contain a list view. Instead they use window with class DirectUIHWND which is a mystery to many. I've just found a post that describes a way to the unravel that mystery.
http://smartbear.com/forums?forumid=81&threadid=68427#68428
I hope it helps.
I think you should communicate between processes.
Following topics will help.
This is an example of retrieving icons from desktop. List of desktop items and their current positions are fetched.
http://social.msdn.microsoft.com/Forums/windows/en-US/d7df8a4d-fc0f-4b62-80c9-7768756456e6/how-can-i-get-desktops-icons-information-?forum=winforms
Here the parameter LVM_GETITEMSTATE can be used within the sample code from the link above.
http://msdn.microsoft.com/en-us/library/windows/desktop/bb761053(v=vs.85).aspx
Good luck..
using System.Runtime.InteropServices;
public class ShellItems
{
[StructLayoutAttribute(LayoutKind.Sequential)]
private struct LVITEM
{
public uint mask;
public int iItem;
public int iSubItem;
public uint state;
public uint stateMask;
public IntPtr pszText;
public int cchTextMax;
public int iImage;
public IntPtr lParam;
}
const int LVM_FIRST = 0x1000;
const int LVM_GETSELECTEDCOUNT = 4146;
const int LVM_GETNEXTITEM = LVM_FIRST + 12;
const int LVNI_SELECTED = 2;
const int LVM_GETITEMCOUNT = LVM_FIRST + 4;
const int LVM_GETITEM = LVM_FIRST + 75;
const int LVIF_TEXT = 0x0001;
[DllImport("user32.dll", EntryPoint = "GetShellWindow")]
public static extern System.IntPtr GetShellWindow();
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
public static extern int SendMessagePtr(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
[DllImport("User32.DLL")]
public static extern int SendMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, Int32 lParam);
public int SelectedItemCount
{
get
{
return SendMessage(ShellListViewHandle, LVM_GETSELECTEDCOUNT, IntPtr.Zero.ToInt32(), IntPtr.Zero.ToInt32());
}
}
public int Count
{
get
{
return SendMessage(ShellListViewHandle, LVM_GETITEMCOUNT, IntPtr.Zero.ToInt32(), IntPtr.Zero.ToInt32());
}
}
public string GetItemText(int idx)
{
// Declare and populate the LVITEM structure
LVITEM lvi = new LVITEM();
lvi.mask = LVIF_TEXT;
lvi.cchTextMax = 512;
lvi.iItem = idx; // the zero-based index of the ListView item
lvi.iSubItem = 0; // the one-based index of the subitem, or 0 if this
// structure refers to an item rather than a subitem
lvi.pszText = Marshal.AllocHGlobal(512);
// Send the LVM_GETITEM message to fill the LVITEM structure
IntPtr ptrLvi = Marshal.AllocHGlobal(Marshal.SizeOf(lvi));
Marshal.StructureToPtr(lvi, ptrLvi, false);
try
{
SendMessagePtr(ShellListViewHandle, LVM_GETITEM, IntPtr.Zero, ptrLvi);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
// Extract the text of the specified item
string itemText = Marshal.PtrToStringAuto(lvi.pszText);
return itemText;
}
IntPtr ShellListViewHandle
{
get
{
IntPtr _ProgMan = GetShellWindow();
IntPtr _SHELLDLL_DefViewParent = _ProgMan;
IntPtr _SHELLDLL_DefView = FindWindowEx(_ProgMan, IntPtr.Zero, "SHELLDLL_DefView", null);
IntPtr _SysListView32 = FindWindowEx(_SHELLDLL_DefView, IntPtr.Zero, "SysListView32", "FolderView");
return _SysListView32;
}
}
public int GetSelectedItemIndex(int iPos = -1)
{
return SendMessage(ShellListViewHandle, LVM_GETNEXTITEM, iPos, LVNI_SELECTED);
}
}

C# How to wait for a pop up window and select it for input

I am basically writing a specialized macro player/recorder in C#. One thing I need to be able to do is wait for a pop up window (something like a Save As... dialog box) that I can then select to continue playing macro input into. Ideally, I would like to be able to poll for open windows and search through their titles for a matching window title.
Obviously I can't use Processes.GetProcesses() because a dialog most likely will not show up as a new process.
Where do I look to get open windows and their titles?
If you want to poll all open windows, you might use EnumWindows(). I didn't compile this code, but it should be pretty close to functional.
public class ProcessWindows
{
List<Window> visibleWindows = new List<Window>();
List<IntPtr> allWindows = new List<IntPtr>();
/// <summary>
/// Contains information about visible windows.
/// </summary>
public struct Window
{
public IntPtr Handle { get; set; }
public string Title { get; set; }
}
[DllImport("user32.dll")]
static extern int EnumWindows(EnumWindowsCallback lpEnumFunc, int lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern void GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
delegate bool EnumWindowsCallback(IntPtr hwnd, int lParam);
public ProcessWindows()
{
int returnValue = EnumWindows(Callback, 0);
if (returnValue == 0)
{
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error(), "EnumWindows() failed");
}
}
private bool Callback(IntPtr hwnd, int lParam)
{
const int WS_BORDER = 0x800000;
const int WS_VISIBLE = 0x10000000;
const int GWL_STYLE = (-16);
// You'll have to figure out which windows you want here...
int visibleWindow = WS_BORDER | WS_VISIBLE;
if ((GetWindowLong(hwnd, GWL_STYLE) & visibleWindow) == visibleWindow)
{
StringBuilder sb = new StringBuilder(100);
GetWindowText(hwnd, sb, sb.Capacity);
this.visibleWindows.Add(new Window()
{
Handle = hwnd,
Title = sb.ToString()
});
}
return true; //continue enumeration
}
public ReadOnlyCollection<Window> GetVisibleWindows()
{
return this.visibleWindows.AsReadOnly();
}
}
}
I think you want FindWindow().

Categories