How to write and send text to mIRC in C#/Win32? - c#

In a previous question, I asked how to send text to Notepad. It helped me immensely. For part 2, here's a simplified version of the same applied mIRC:
[DllImport("User32.dll", EntryPoint = "FindWindow")]
public static extern IntPtr FindWindow(String lpClassName, String lpWindowName);
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
IntPtr mainHandle = FindWindow("mIRC", null);
IntPtr serverHandle = FindWindowEx(mainHandle, new IntPtr(0), "MDIClient", null);
IntPtr chanHandle = FindWindowEx(serverHandle, new IntPtr(0), "mIRC_Channel", null);
IntPtr editHandle = FindWindowEx(chanHandle, new IntPtr(0), "Edit", null);
SendMessage(editHandle, 0x000C, 0, textBox1.Text);
This seems correct to me, except that it doesn't work! Is it that the window names are incorrect (MDIClient, mIRC_Channel, and Edit)? These are values I found on a web site by googling "FindWindowEx mIRC".
1.) What am I doing wrong in the above?
2.) For reference, in general is there an easy way to find all the Window names for use with FindWindowEx()?

This code works for me (mirc 6.31):
IntPtr mainHandle = FindWindow("mIRC", null);
IntPtr serverHandle = FindWindowEx(mainHandle, new IntPtr(0), "MDIClient", null);
IntPtr chanHandle = FindWindowEx(serverHandle, new IntPtr(0), "mIRC_Channel", null);
IntPtr editHandle = FindWindowEx(chanHandle, new IntPtr(0), "richEdit20A", null);
SendMessage(editHandle, 0x000C, 0, "Hello World");
Notice the changed window class (richedit20A instead of edit). Just found the correct class by using Spy++.
As for the window handles, one possibility is to use the EnumWindows or EnumChildWindows API.

Related

Capture events from other windows applications

I have a third party application which I did not create myself. I need to create an application which is able to listen for button clicks and read data from tables in that application. I believe that the third party application is made in C# but I do not know for sure. Is there a way to know when UI buttons are pressed and to harvest data from the application? I do not mind which programming language the solution must be written in, as long as it fulfils the above tasks.
You can use few dlls like user32.dll, to get data from other apps.
Find parent handle of a window:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
public static IntPtr FindWindow(string windowName)
{
var hWnd = FindWindow(windowName, null);
return hWnd;
}
After that, find handle of a child window
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
private IntPtr FindSomeElement(IntPtr parent)
{
IntPtr childHandle;
childHandle = FindWindowEx(
parent,
IntPtr.Zero,
"WindowsForms10.EDIT.app21",
IntPtr.Zero);
return childHandle;}
and get text from it:
private static string GetText(IntPtr childHandle)
{
const uint WM_GETTEXTLENGTH = 0x000E;
const uint WM_GETTEXT = 0x000D;
var length = (int)SendMessage(handle, WM_GETTEXTLENGTH, IntPtr.Zero, null);
var sb = new StringBuilder(length + 1);
SendMessage(handle, WM_GETTEXT, (IntPtr)sb.Capacity, sb);
return sb.ToString();
}
//I didnt test this code, just gave an idea.
Visit www.pinvoke.net/default.aspx/ for more information. You can find alot about user32.dll

Notepad - force to show save dialog when content provided by SendMessage pinvoke

I have simple helper method which allows me to open notepad.exe and fill it by provided text.
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", EntryPoint = "SendMessageW")]
public static extern IntPtr SendMessageW(IntPtr hWnd, UInt32 msg, IntPtr wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam);
public static void OpenNotepadWithText(string text)
{
var process = Process.Start("notepad.exe");
if (process == null)
throw new Exception("Unable to run notepad.exe process!");
process.WaitForInputIdle();
IntPtr child = FindWindowEx(process.MainWindowHandle, new IntPtr(0), "Edit", null);
SendMessageW(child, 0x000C, IntPtr.Zero, text);
}
When I click on close button of notepad, notepad is closed without asking for save. It seems that used approach does not set "need_to_save" flag in notepad and thus notepad thinks that there is no changed content to save. Can someone help me with setting this flag?

Repeat FindWindow function everytime the window appears/opens

The title says it all, I have this code:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
const UInt32 WM_CLOSE = 0x0010;
and here's what I added to Form1_Load:
IntPtr windowPtr = FindWindowByCaption(IntPtr.Zero, "Untitled - Notepad");
if (windowPtr == IntPtr.Zero)
{
MessageBox.Show("Window not found");
return;
}
SendMessage(windowPtr, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
so I added the code above to the Form1_Load function, and it actually works, it closes notepad when I open my program, but my question is, how to make the function repeat, like close notepad whenever it opens and not only on Form1_Load ?
You have to enumerate the windows yourself: EnumWindows and in the return procedure check if the title is the same as what you want (hardcoding 'Untitled' might not be the best way by the way). Alternatively traverse the window graph yourself with GetWindow, starting at the first desktop child and iterate the siblings from there.
Also you don't need the IntPtr version of FindWindow, you can pass null as a string parameter and it accomplishes the same.

Alt+F,S not working in sendKeys C#

I want to save and close all kinds of application which is opened. The specific application is identified from Process command. with this I can kill it.
For saving I tried SendKeys class, First I set the SetForegroundWindow(h), and succeeded with ctrl+s by using
SendKeys.Send("^s"); //Ctrl+s
but, user defined applications are there, and also I have a situation to save a new(not existing file) which has to be saved by Alt+F+S.
So that it saves with default name
How do I achieve this,
I tried,
SendKeys.Send("%(fs)");
SendKeys.Send("%f"+"s"); //Alt+F
SendKeys.Send("%f" + "%s)"); //Alt+F
SendKeys.Send("%fs");
Please guide me, If its not possible with SendKeys, what else should I try.
Always use the breakets and you can avoid errors.
SendKeys.Send("%{f}"); //Alt+F
SendKeys.Send("{A}"); //A
or try
SendKeys.Send("%{f}{A}"); //Alt+F And A
What APP? SendKeys will send key strokes but under the hood most things use the good old message loop.
SendMessage(hWnd, WM_SETTEXT, wParam, lParam);
c#
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, String lpWindowName);
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);
IntPtr hwnd= FindWindow(null, "Window Title");
SendMessage(hwnd, id, IntPtr.Zero, IntPtr.Zero);
To get notepad to save it would be
const int WM_COMMAND = 0x111;
SendMessage(hwnd, WM_COMMAND,777 , NULL);

Finding status of GoogleTalk

I am trying to create a program which will show me the status of my Gtalk (online/offline).
I can find the Status View 2 class, but how can I find the text within it.
Here's my code.
API decleration :
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
Code that calls Api :
IntPtr hwnd = IntPtr.Zero;
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Google Talk - Google Xmpp Client GUI Window", "Google Talk");
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Main View", "#main");
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Status View 2", "Status Box");
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "RichEdit20W", "String.Empty");
MessageBox.Show(hwnd.ToString());
Thanks.
I found a solution my self. Thanks to abazabam.
If you look at the figure, there is a panel whose class name is "#32770" and Window Caption is "Sign In Dialogue"
When the user is offline then this panel is visible, and when the user goes online the panel is not visible.
So the main logic is to detect the visibility of the panel.
You can use Spy++ to find the class name.
API decleration :
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool IsWindowVisible(IntPtr hWnd);
Code :
IntPtr hwnd = IntPtr.Zero;
bool check;
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Google Talk - Google Xmpp Client GUI Window", "Google Talk");
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "Main View", "#main");
hwnd = FindWindowEx(hwnd, IntPtr.Zero, "#32770", "Sign In Dialogue");
check = IsWindowVisible(hwnd);
if (check == true)
{
MessageBox.Show("User is offline.");
}
else
{
MessageBox.Show("User is online.");
}
Anyways thanks for reading my problem.

Categories