4

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);
    }
Kirschstein
  • 14,570
  • 14
  • 61
  • 79

4 Answers4

8

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);
Gregyski
  • 1,707
  • 3
  • 18
  • 26
  • WinSpector returns base 10 numbers. I've made a little test application with Visual Studio and this technique works fine, but it doesn't work for real application I'm working with. – Kirschstein Jul 09 '09 at 13:51
  • When you step through the code w/ the real application, does GetDlgItem() return a non-zero value? – Gregyski Jul 09 '09 at 14:21
  • 1
    Yes, it does, and I can grab existing text from it using WM_GETTEXT. It's just WM_SETTEXT that isn't working. – Kirschstein Jul 09 '09 at 16:41
  • 1
    Sorry if I'm suggesting obvious things, but sometimes it's good to just talk these things out. I think the next thing I would try would be to alter something like the title bar text of the main window (if it has one), and see if I can change that - in other words, change the window text of a window that is most likely not being modified by the program. If that works, then try some text of a static control, like a label, in the window. If both of those work, it would indicate to me that the program is handling that textbox in an unusual manner. continued... – Gregyski Jul 09 '09 at 17:16
  • I would also try watching the textbox control w/ Spy++ (or whatever tool you prefer) to see what messages it is receiving. You should be able to verify that the textbox is receiving your WM_SETTEXT and if the program is sending something that may be overriding your actions. – Gregyski Jul 09 '09 at 17:18
  • The textbox is never receiving a WM_SETTEXT message, it receives something else, I can't remember off the top of my head what this is, but it's on a char by char basis. What I've decided to do instead (because I just want this thing _working_) is to click over the input box and send a series of keybd_events with the desired string in. Cheers for your help Greg, although it doesn't answer my specific problem, it works in general, so I'm marking it as the answer. – Kirschstein Jul 09 '09 at 20:58
  • @Greg: Thanks for that gem! SetLastError = false huh... WTF! :D – Jörgen Sigvardsson Jul 03 '11 at 01:19
  • where in spy++ do you get the control ID...I am having this same problem and need to debug it more. – Dean Hiller Jan 17 '12 at 01:18
  • There are two ways: 1) Find the window manually in the list provided (or use `Window Search` in the newer Spy++) and then right-click and choose `Properties`. 2) Use the `Find Window` tool (don't confuse it with the `Log` or `Log Messages` command which also has a window picker control). Click on the control and then click `OK`. In either event you will get the window's properties dialog and the `Control ID` will show between `Instance Handle` and `User Data`. – Gregyski Jan 17 '12 at 18:32
2

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);
}
0

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).

Community
  • 1
  • 1
smok1
  • 2,940
  • 26
  • 35
0

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.

Gautam Jain
  • 6,789
  • 10
  • 48
  • 67