1

When I try to use unmanaged code in WPF. e.g. SendMessage(IntPtr hWnd, int Msg, int wParam, ref TOOLINFO toolInfo), this function may return the 0XFFFF for lpszText in TOOLINFO and application crash directly. I have referred MSDN and found that it is a ERROR_ILLEGAL_CHARACTER error. So I want to ask: How can I catch this kind of error in managed code, or how can I return TOOLINFO a good result.

    struct TOOLINFO
    {
        public int cbSize;
        public int uFlags;
        public IntPtr hwnd;
        public IntPtr uId;
        public RECT rect;
        public IntPtr hinst;
        [MarshalAs(UnmanagedType.LPStr)]
        public string lpszText;
        public IntPtr lParam;
    }
[DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, ref TOOLINFO toolInfo);
Qiao
  • 11
  • 2
  • What message are you sending? Still the solution is easy: `public string lpszText;` make it `public IntPtr lpszText;` and then marshal the string with `Marshal.PtrToStringAuto()` (inside a try/catch) – xanatos Feb 07 '21 at 14:08
  • 1
    I see in the description of [ToolInfo](https://learn.microsoft.com/en-us/windows/win32/api/commctrl/ns-commctrl-tttoolinfoa) that YOU have to allocate the buffer. You could try with a `StringBuilder()` with preallocated length (`StringBuilder lpszText;` and then BEFORE sending the message `lpszText = new StringBuilder(200)` – xanatos Feb 07 '21 at 14:11
  • 1
    `wParam` should be `IntPtr` – Charlieface Feb 07 '21 at 14:29

1 Answers1

0

What message are you sending?

Still the solution is easy:

public string lpszText; 

change it to:

public IntPtr lpszText; 

and then marshal the string with Marshal.PtrToStringAuto() (inside a try/catch)

But I see in the description of ToolInfo that YOU have to allocate the buffer. You could try with a StringBuilder() with preallocated length:

public StringBuilder lpszText;

and then BEFORE sending the message

tt.lpszText = new StringBuilder(200);
xanatos
  • 109,618
  • 12
  • 197
  • 280
  • Thanks for your anwser. The message I send was TTM_ENUMTOOLSA, which is used to enumunate all the tools in a tooltip ctrl. And the following is my solution: `StringBuilder builder = new StringBuilder(1024); builder.Append('\0'); builder.Append('*', builder.Capacity - 8); TOOLINFO ti = new TOOLINFO(); ti.lpszText = builder.ToString(); ti.cbSize = Marshal.SizeOf(ti); WIN32API.SendMessage(wnd, TTM_ENUMTOOLSA, i, ref ti);` As for your "Intptr lpszText" solution, I have tried it before. It will return 0XFFFFFFFF so the string can't be read in some cases. – Qiao Feb 09 '21 at 01:29
  • And if I used string to lpszText in TOOLINFO, the application will crash directly in some cases because the location of lpszText is corrupted(0XFFFFFFFF). WPF can't catch the exception because this exception is native. I don't know how to catch WIN32 exceptions in managed code. – Qiao Feb 09 '21 at 01:37
  • @Qiao You have to use a `StringBuilder`, not a `string`. Note still that you can't use those messages to get infos about toolbars of other processes (see comments here: https://stackoverflow.com/questions/24395786/trying-to-get-text-from-tooltips-not-working) – xanatos Feb 09 '21 at 08:28