Unwanted characters included in pinvoke WM_GETTEXT

I have a method that uses pinvoke to call WM_GETTEXT in another program text field - and it works quite well, but often I just return the full junk text added to the end. (ORIGINAL text is always intact.)

This is a random case, I can not play it on demand, but often enough to stop.

Here is the text to get information.

System.Text.StringBuilder strBuffer = new System.Text.StringBuilder();

int nLen = 0;

bool nUpdated = false;

try
{
    this.isOpen = false;

    if (ptrHandle == null)
        return;

    if (ptrHandle == IntPtr.Zero)
        return;

    nLen =
        Converter.SendMessage(ptrHandle, Converter.WM_GETTEXTLENGTH, 0, 0);

    if (nLen <= 0)
        return;

    if (nPreviousLen != nLen)
        nUpdated = true;

    if (nUpdated)
    {
        System.Diagnostics.Debug.WriteLine("nLen:\t{0}", nLen);

        strBuffer = new System.Text.StringBuilder(null, nLen + 1);

        System.Diagnostics.Debug.WriteLine("strBuffer:\t{0}", strBuffer.ToString());

        int sLen = Converter.SendMessageByString(ptrHandle, Converter.WM_GETTEXT, nLen
            , strBuffer);

        System.Diagnostics.Debug.WriteLine("sLen:\t{0}", sLen);

        System.Diagnostics.Debug.WriteLine("\n\nstrBuffern\n\n{0}", strBuffer.ToString());

        strBuffer = new System.Text.StringBuilder(strBuffer.ToString().Left(sLen));

        System.Diagnostics.Debug.WriteLine("\n\nsLenBuffer\n\n{0}", strBuffer.ToString());

source = new Special.IO.TextReader( 
                    new System.IO.MemoryStream(  System.Text.Encoding.Default.GetBytes(strBuffer.ToString() ) ), nUpdated );
        }
    }
}


    /// <summary>
    /// Sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message.
    /// <br />
    /// To send a message and return immediately, use the SendMessageCallback or SendNotifyMessage function. To post a message to a thread message queue and return immediately, use the PostMessage or PostThreadMessage function.
    /// </summary>
    /// <param name="hWnd">
    /// Handle to the window whose window procedure will receive the message. 
    /// If this parameter is HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.
    /// </param>
    /// <param name="Msg">
    /// [in] Specifies the message to be sent.
    /// </param>
    /// <param name="wParam">
    /// [in] Specifies additional message-specific information.
    /// </param>
    /// <param name="lParam">
    /// [in] Specifies additional message-specific information.
    /// </param>
    /// <returns>
    /// The return value specifies the result of the message processing; it depends on the message sent.
    /// </returns>
    [DllImport("user32.dll", EntryPoint = "SendMessageA", CharSet = CharSet.Ansi, SetLastError = false)]
    internal static extern int SendMessageByString(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);

    /// <summary>
    /// Sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message.
    /// <br />
    /// To send a message and return immediately, use the SendMessageCallback or SendNotifyMessage function. To post a message to a thread message queue and return immediately, use the PostMessage or PostThreadMessage function.
    /// </summary>
    /// <param name="hWnd">
    /// Handle to the window whose window procedure will receive the message. 
    /// If this parameter is HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.
    /// </param>
    /// <param name="Msg">
    /// [in] Specifies the message to be sent.
    /// </param>
    /// <param name="wParam">
    /// [in] Specifies additional message-specific information.
    /// </param>
    /// <param name="lParam">
    /// [in] Specifies additional message-specific information.
    /// </param>
    /// <returns>
    /// The return value specifies the result of the message processing; it depends on the message sent.
    /// </returns>
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    internal static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
+5
source share
4 answers

, - , , , P/Invoke WM_GETTEXT ... , , , ...

try{
    int nLineCount = Converter.SendMessage(ptrHandle, Converter.EM_GETLINECOUNT, 0, 0);
    int nIndex = Converter.SendMessage(ptrHandle, Converter.EM_LINEINDEX, nLineCount, 0);
    int nLineLen = Converter.SendMessage(ptrHandle, Converter.EM_LINELENGTH, nIndex, 0);
    //
    strBuffer = new System.Text.StringBuilder(nLineLen);
    strBuffer.Append(Convert.ToChar(nLineLen));
    strBuffer.Length = nLineLen;
    int nCharCnt = Converter.SendMessage(ptrHandle, Converter.EM_GETLINE, new IntPtr(nLineCount),     strBuffer).ToInt32();
    nLen = nCharCnt;
    if (nLen <= 0) return;
    if (nPreviousLen != nLen) nUpdated = true;
}finally{
    source = new TextReader(strBuffer.ToString(), nUpdated, isOpen ? true : false);
    this.isOpen = true;
    nPreviousLen = nLen;
}

, :

  • - nLineCount
  • , nLineCount - nIndex
  • , , nIndex - nLineLen

nLineLen, StringBuilder, EM_GETLINE - MUST, char - strBuffer.Append(Convert.ToChar(nLineLen)) stringbuilder Length.

, P/Invoke

  • const int EM_GETLINECOUNT = 0xBA;
  • const int EM_LINEINDEX = 0xBB;
  • const int EM_LINELENGTH = 0xC1;
+1

WM_GETTEXT. MSDN:

- , .

( - ) WM_GETTEXTLENGTH WM_GETTEXT, , : WM_GETTEXT ( ) 5 20- StringBuilder, undefined. ( , ANSI- SendMessage, , , ), , , .

SendMessageByString StringBuilder , .

+1

, WM_GETTEXT. nLen + 1 nLen wParam.

WM_GETTEXTLENGTH nLen, TCHAR, , . nLen + 1 . , WM_GETTEXT nLen wParam, , http://msdn.microsoft.com/en-us/library/ms632627.aspx wParam , , . WM_GETTEXT nLen + 1 nLen.

, nLen, . 2 nLen, WM_GETTEXTLENGTH, nLen + 2 WM_GETTEXT (, ). WM_GETTEXT nLen , , , . WM_GETTEXT nLen + 1, WM_GETTEXTLENGTH WM_GETTEXT, , WM_GETTEXTLENGTH, , .

+1

Well, at your suggestion, I changed my pinvokes to look like this.

I think the most unpleasant part of all this is that it is completely random. I have problems reproducing the problem. Some of my clients will be on 64-bit, some on 32-bit. What should I do about this? I am testing it now, and I still have the same problem. I'm losing back.

    /// <summary>
    /// Sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message.
    /// <br />
    /// To send a message and return immediately, use the SendMessageCallback or SendNotifyMessage function. To post a message to a thread message queue and return immediately, use the PostMessage or PostThreadMessage function.
    /// </summary>
    /// <param name="hWnd">
    /// Handle to the window whose window procedure will receive the message. 
    /// If this parameter is HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.
    /// </param>
    /// <param name="Msg">
    /// [in] Specifies the message to be sent.
    /// </param>
    /// <param name="wParam">
    /// [in] Specifies additional message-specific information.
    /// </param>
    /// <param name="lParam">
    /// [in] Specifies additional message-specific information.
    /// </param>
    /// <returns>
    /// The return value specifies the result of the message processing; it depends on the message sent.
    /// <br />
    /// If you use '[Out] StringBuilder', initialize the string builder with proper length first.
    /// </returns>
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    internal static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, StringBuilder lParam);

    /// <summary>
    /// Sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message.
    /// <br />
    /// To send a message and return immediately, use the SendMessageCallback or SendNotifyMessage function. To post a message to a thread message queue and return immediately, use the PostMessage or PostThreadMessage function.
    /// </summary>
    /// <param name="hWnd">
    /// Handle to the window whose window procedure will receive the message. 
    /// If this parameter is HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.
    /// </param>
    /// <param name="Msg">
    /// [in] Specifies the message to be sent.
    /// </param>
    /// <param name="wParam">
    /// [in] Specifies additional message-specific information.
    /// </param>
    /// <param name="lParam">
    /// [in] Specifies additional message-specific information.
    /// </param>
    /// <returns>
    /// The return value specifies the result of the message processing; it depends on the message sent.
    /// <br />
    /// If you use '[Out] StringBuilder', initialize the string builder with proper length first.
    /// </returns>
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    internal static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);

    /// <summary>
    /// Sends the specified message to a window or windows. The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message.
    /// <br />
    /// To send a message and return immediately, use the SendMessageCallback or SendNotifyMessage function. To post a message to a thread message queue and return immediately, use the PostMessage or PostThreadMessage function.
    /// </summary>
    /// <param name="hWnd">
    /// Handle to the window whose window procedure will receive the message. 
    /// If this parameter is HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.
    /// </param>
    /// <param name="Msg">
    /// [in] Specifies the message to be sent.
    /// </param>
    /// <param name="wParam">
    /// [in] Specifies additional message-specific information.
    /// </param>
    /// <param name="lParam">
    /// [in] Specifies additional message-specific information.
    /// </param>
    /// <returns>
    /// The return value specifies the result of the message processing; it depends on the message sent.
    /// </returns>
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    internal static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

Now, my passcode looks like this.

    private void CreateStream(object sender, EventArgs e)
    {
        System.Text.StringBuilder strBuffer = new System.Text.StringBuilder();

        System.Text.StringBuilder strDebug = new System.Text.StringBuilder();

        // nLen is the length of the text recovered
        int nLen = 0;

        // nUpdated determines whether the text has changed since we last looked at it
        bool nUpdated = false;

        try
        {
            //
            // close the stream so that it can be processed
            //
            this.isOpen = false;

            if (ptrHandle == null)
                return;

            if (ptrHandle == IntPtr.Zero)
                return;

            nLen =
                Converter.SendMessage(ptrHandle, Converter.WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero).ToInt32();

            // if the length is 0 or negative, just exit. Something went wrong.
            if (nLen <= 0)
                return;

            if (nPreviousLen != nLen)
                nUpdated = true;

            if (nUpdated)
            {
                strDebug.AppendFormat("nLen:\t{0}", nLen);

                strBuffer = new System.Text.StringBuilder(null, nLen + 1);

                strBuffer.Length = Converter.SendMessage(ptrHandle, Converter.WM_GETTEXT, new IntPtr(nLen)
                    , strBuffer).ToInt32();

                strDebug.AppendFormat("\nsLen:\t{0}", strBuffer.Length);
            }
        }
        finally
        {
            source = new SPECIAL.IO.TextReader(
                strBuffer.ToString(), nUpdated);

            source.Debugging = strDebug.ToString() ;
            //
            // open the stream so that it can be processed
            //
            this.isOpen = true;
            //
            // if we get this far, specify this length as the 'previous length'
            //
            nPreviousLen = nLen;
        }
    }
0
source

All Articles