Inserting text with SendMessage - c#

When I try to paste text in textbox another program, the text is inserted, but the program does not recognize it.
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
const uint WM_SETTEXT = 0x000C;
IntPtr text = Marshal.StringToCoTaskMemUni("100");
IntPtr thisWindow = FindWindow(null, "AnotherWindow");
IntPtr handle = FindWindowEx(thisWindow, IntPtr.Zero, "AnotherTextBox", null);
SendMessage(handle, WM_SETTEXT, IntPtr.Zero, text);
Marshal.FreeCoTaskMem(text);
Maybe I should send to the parent a message that the textbox is updated?
Like this:
//Wrong code, because I do not know how correctly send a message
SendMessage(handle, WM_COMMAND, EM_SETMODIFY, handle);

And again...help came from another site
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
//...
IntPtr boo = new IntPtr(1);
SendMessage(handle, EM_SETMODIFY, boo, IntPtr.Zero);

You'd be looking to do something like:
PostMessage(GetParent(handle), WM_COMMAND, MAKEWPARAM(GetWindowLong(handle, GWL_ID), EN_CHANGE), (LPARAM)handle);

some Textboxes have been set so that you can not set your text by WM_SETTEXT immediately, especially those which accept digits and perform calculation according these digits. I had similar problem and solved it by bellow code. I applied WM_PASTE, EM_REPLACESEL to conquer that.
SendMessage(child, WM_SETFOCUS,0 , IntPtr.Zero); // go to text box
System.Windows.Forms.Clipboard.SetText("1"); // set something in clipboard. it does not matter what it is.
SendMessage(child, WM_PASTE, 0, IntPtr.Zero); // paste to get control of text box
SendMessage(child, WM_SETTEXT, IntPtr.Zero, string.Empty); // clear textbox to insert your desired text.
SendMessage(child, EM_REPLACESEL, IntPtr.Zero, "your text"); // insert your desired text. i inserted digits as text.
you need to Import user32.dll file at first:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
private static extern int SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, string lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
private static extern int SendMessage(IntPtr hWnd, uint msg,int wParam, IntPtr lParam);

Related

Send text to another process in C# [duplicate]

Using Winspector I've found out the ID of the child textbox I want to change is 114. Why isn't this code changing the text of the TextBox?
[DllImport("user32.dll")]
static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem);
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int msg, int Param, string s);
const int WM_SETTEXT = 0x000c;
private void SetTextt(IntPtr hWnd, string text)
{
IntPtr boxHwnd = GetDlgItem(hWnd, 114);
SendMessage(boxHwnd, WM_SETTEXT, 0, text);
}
The following is what I've used successfully for that purpose w/ my GetLastError error checking removed/disabled:
[DllImport("user32.dll", SetLastError = false)]
public static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(HandleRef hWnd, uint Msg, IntPtr wParam, string lParam);
public const uint WM_SETTEXT = 0x000C;
private void InteropSetText(IntPtr iptrHWndDialog, int iControlID, string strTextToSet)
{
IntPtr iptrHWndControl = GetDlgItem(iptrHWndDialog, iControlID);
HandleRef hrefHWndTarget = new HandleRef(null, iptrHWndControl);
SendMessage(hrefHWndTarget, WM_SETTEXT, IntPtr.Zero, strTextToSet);
}
I've tested this code and it works, so if it fails for you, you need to be sure that you are using the right window handle (the handle of the Dialog box itself) and the right control ID. Also try something simple like editing the Find dialog in Notepad.
I can't comment yet in the post regarding using (char *) but it's not necessary. See the second C# overload in p/Invoke SendMessage. You can pass String or StringBuilder directly into SendMessage.
I additionally note that you say that your control ID is 114. Are you certain WinSpector gave you that value in base 10? Because you are feeding it to GetDlgItem as a base 10 number. I use Spy++ for this and it returns control IDs in base 16. In that case you would use:
IntPtr boxHwnd = GetDlgItem(hWnd, 0x0114);
Please convert your control id (obtained from spy ++) from Hexdecimal Number to Decimal Number and pass that value to the GetDlgItem function.With this
you will get the handle of Text box.This worked for me.
[DllImport("user32.dll")]
static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem);
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int msg, int Param, string s);
const int WM_SETTEXT = 0x000c;
private void SetTextt(IntPtr hWnd, string text)
{
IntPtr boxHwnd = GetDlgItem(hWnd, 114);
SendMessage(boxHwnd, WM_SETTEXT, 0, text);
}
Are you sure you are passing text right? SendMessage last param should be a pointer to char* containing text you want to set.
Look at my "crude hack" of setting text in
How to get selected cells from TDBGrid in Delphi 5
this is done in Delphi 5, where PChar is char* alias, and I simply cast it as int (Integer in Delphi).
You must make sure that "text" is allocated in the external app's memory space. You will not be able to allocate text in the caller app and pass it to another app as each of them will have their own private memory space.

SendMessageW WM_SetText usage for Multilanguage

[DllImport("user32.dll", EntryPoint = "SendMessageW", CharSet = CharSet.Unicode)]
public static extern int SendMessage(IntPtr hwnd, SendMessageFlags msg, IntPtr wParam, IntPtr lParam);
public static void SetByHwnd(IntPtr hwnd, string text)
{
IntPtr a = Marshal.StringToHGlobalUni(text);
SendMessage(hwnd, SendMessageFlags.WM_SETTEXT, IntPtr.Zero, a);
}
When i try to change any objects text to Japanese, Russian, Greek, Arabic etc.. text im changing my controls text to meaningless question marks.
There is no problem with the "a-Z" "0-9" but i need to use other languages alphabets too.
i need this to work SetByHwnd(hwnd, "कार्यकारी")
I tried to use SendMessageA and SendMessage, changed parameters like
SendMessage(IntPtr hwnd, SendMessageFlags msg, IntPtr wParam, StringBuilder strBuffer);
SendMessage(IntPtr hwnd, SendMessageFlags msg, IntPtr wParam, string lParam);
But didnt help. Always seeing the question marks "????" in my control.

How do I scrape controls on an Windows Forms application which doesn't have an handle?

I have a Windows application. Where can I find the handle of the window?
I am unable to find the handle of the controls placed within that window. How can I scrape such controls? If it's a textbox or a button, I can automate it using the move position and send message. How does this work with a data grid/ table?
You have to go to the Win32 API for that.
Import EnumChildWindows like this:
[DllImport("user32.dll")]
private static extern bool EnumChildWindows(Intptr parent, EnumWindowsProc enumProc, IntPtr lParam);
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
And then call it from you main windows with this.Handle as the parent's windows handle. It will call the delegate for every child control in the form. This will show a messagebox for every control in the window:
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
private static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder lpString, int nMaxCount);
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
static extern int GetWindowTextLength(IntPtr hWnd);
EnumChildWindows(this.Handle, (handle, b) => {
int length = GetWindowTextLength(handle);
System.Text.StringBuilder sb = new System.Text.StringBuilder(length + 1);
GetWindowText(handle, sb, sb.Capacity);
MessageBox.Show(sb.ToString()); return true;
}, IntPtr.Zero);

Open/Change IE9 Tabs Using SendMessage/PostMessage

I'm trying basically SendKey's to IE9 to change tabs. I have 3 tabs so I'd need to Send keys Ctrl+1, Ctrl+2, Ctrl+3 and also Ctrl+T to open a new tab.
I start by adding the import dlls and constants
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg,
IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg,
IntPtr wParam, IntPtr lParam);
const int WM_KEYDOWN = 0x100;
const int WM_KEYUP = 0x101;
I get the instance of Internet Explorer by opening a new process.
Process p = Process.Start("iexplorer.exe");
Use the process handle to PostMessage to IE9 instance
IntPtr handle = p.MainWindowHandle; //p.Handle (doesn't work either)
//Change to Tab2 using PostMessage
PostMessage(handle, WM_KEYDOWN, ((IntPtr)Keys.LControlKey), (IntPtr)0);
PostMessage(handle, WM_KEYDOWN, ((IntPtr)Keys.D2), (IntPtr)0);
PostMessage(handle, WM_KEYUP, ((IntPtr)Keys.D2), (IntPtr)0);
PostMessage(handle, WM_KEYUP, ((IntPtr)Keys.LControlKey), (IntPtr)0);
No response. I've also tried using SendMessage to no avail as well.
Am I doing anything obviously wrong?
How about SendKeys("^1");
as seen here

TranslateAccelerator succeeds, but WM_COMMAND messages are not showing up

I am writing a .NET wrapper around Win32 hooks which buffers WM_CHAR messages and allows events such as key presses, key releases, and accelerator keystrokes to be subscribed to. Everything is in working order except apparently my call to TranslateAccelerator. It returns true when I expect it to (when it finds an accelerator in the given table which I constructed earlier) but the WM_COMMAND messages don't seem to be showing up ever. Here is some relevant code.
[StructLayout(LayoutKind.Sequential)]
struct MSG {
IntPtr hWnd;
WindowsMessages message;
IntPtr wParam;
IntPtr lParam;
UInt32 time;
POINT pt;
}
delegate IntPtr HOOKPROC(HookCodes nCode, IntPtr wParam, ref MSG lParam);
[DllImport("user32.dll")]
extern IntPtr CallNextHookEx(IntPtr hhk, HookCodes nCode, IntPtr wParam, ref MSG lParam);
IntPtr HookProcedure(HookCodes nCode, IntPtr wParam, ref MSG lParam) {
IntPtr result = IntPtr.Zero;
if(nCode < HookCodes.ACTION) {
result = CallNextHookEx(hHook, nCode, wParam, ref lParam);
} else if(nCode == HookCodes.ACTION && (PeekMessageOptions)wParam == PeekMessageOptions.REMOVE) {
/*
* Under these conditions, each message will only be passed onto the switch below once.
*/
switch(lParam.message) {
case WindowsMessages.KEYDOWN:
//fire keydown events and call TranslateAccelerator/TranslateMessage
break;
case WindowsMessages.KEYUP:
//fire keyup events
break;
case WindowsMessages.COMMAND:
//fire accelerator events Ex: Ctrl+F, ALT+M, SHIFT+L
break;
case WindowsMessages.CHAR:
//place char in buffer
break;
default:
break;
}
}
return result; //Will be zero if action was taken on the message by this procedure.
}
}
In KeyPressed(MSG), messages are translated like so:
[DllImport("user32.dll")]
extern bool TranslateAccelerator(IntPtr hWnd, IntPtr hAccTable, ref MSG lpMsg);
[DllImport("user32.dll")]
extern bool TranslateMessage(ref MSG lpMsg);
if(!TranslateAccelerator(hWnd, hAccel, ref msg)){
TranslateMessage(ref msg);
}
The hook and accelerator table are created like this:
[StructLayout(LayoutKind.Sequential)]
struct ACCEL {
byte fVirt;
ushort key;
ushort cmd;
}
[DllImport("user32.dll")]
extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr lpdwProcessId);
[DllImport("user32.dll")]
extern IntPtr SetWindowsHookEx(WindowsHooks hook, HookProcedure lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll")]
extern IntPtr CreateAcceleratorTable(ACCEL[] lpaccl, int cEntries);
HOOKPROC proc = HookProcedure;
uint pid = GetWindowThreadProcessId(/*IntPtr*/hWnd, IntPtr.Zero);
IntPtr hHook = SetWindowsHookEx(WindowsHooks.GETMESSAGE, proc, IntPtr.Zero, pid);
IntPtr hAccel = CreateAcceleratorTable(/*ACCEL[]*/accelerators, accelerators.Length);
Everything works fine (such as attaching events to key-downs and buffering WM_CHAR messages) except I can't find WM_COMMAND or WM_SYSCOMMAND messages anywhere in the queue. They just don't seem to be visible to my hook procedure, even though TranslateAccelerator returns true when I expect it to. Note that I am really pretty clueless when it comes to Win32 so I'm probably missing something fairly obvious to the trained eye. But I am at my wits end. I've tried attaching the hook to an XNA window and a Windows Form without success.
You won't catch those WM_COMMAND messages with a GETMESSAGE hook.
TranslateAccelerator "sends the WM_COMMAND or WM_SYSCOMMAND message directly to the specified window procedure" (see the documentation) and hence bypasses the message queue.
You'll need a CALLWNDPROC hook instead.

Categories