Announcement

Collapse
No announcement yet.

EM_GetLine Question

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • EM_GetLine Question

    In MSDN, it says the lParam content of the EM_GetLine message should be:

    lParam A pointer to the buffer that receives a copy of the line. Before sending the message, set the first word of this buffer to the size, in TCHARs, of the buffer. For ANSI text, this is the number of bytes; for Unicode text, this is the number of characters. The size in the first word is overwritten by the copied line.
    But in all the examples I've found, lParam is always listed as just a pointer to the variable, with no code that shows insertion of the size in the first word of buffer, like this:

    Code:
     lnLen = SendMessage(hEdit, %EM_GETLINE, ln, STRPTR(Buf)) 'Get line
    Why is that?
    Last edited by Gary Beene; 19 Jul 2009, 09:13 PM.

  • #2
    I don't know why your examples don't do this correctly, but here is a snippet from one of my programs..
    Code:
    LOCAL pLW          AS LONG PTR
    ....
    pLW            = VARPTR(szTextLine)   ' so we can set length word of buffer for EM_GETTEXTLINE
    
    ...
    FOR iLineidx = 0 TO nTextLine-1
                      szTextline    = STRING$(SIZEOF(szTextLine),0)  ' null out the line
                      @pLW = SIZEOF(szTextLine) -1
    
                       CONTROL SEND hWnd, iCtrlId, %EM_GETLINE, iLineidx, pLW  TO lLineLen
    ..which works just ducky.

    MCM
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com

    Comment


    • #3
      Good question I am assuming that it has some default value if size=0. This may be documented elsewhere, but I am only guessing about this. It would appear that you would have to call it something like this.

      Code:
          MyBuff As Asciiz * 256
          
          MyBuff = MkWrd$(SizeOf(MyBuff))  ' Store buffer's size in first WORD
          
          lnLen = SendMessage(hEdit, %EM_GETLINE, ln, VarPtr(MyBuff))
      Scott Slater
      Summit Computer Networks, Inc.
      www.summitcn.com

      Comment


      • #4
        You have to watch out for a gotcha here...
        Code:
          MyBuff = MkWrd$(SizeOf(MyBuff))  ' Store buffer's size in first WORD
          lnLen = SendMessage(hEdit, %EM_GETLINE, ln, VarPtr(MyBuff))
        Note that you need to clear that buffer out ("RESET") before sending EM_GETLINE if it had data in it and you are using a regular edit control rather than a richedit control (code not shown) because...
        Remarks

        Edit controls: The copied line does not contain a terminating null character.
        .. and the way the compiler handles assigments to an ASCIIZ target is to move the string data ("MKWRD$(SIZEOF(MyBuff))"" and then moves a single $NUL character. Any data previously in MyBUff beyond the $NUL added by the compiler is unaffected.

        Since EM_GETLINE does not add a termintating $NUL when using a standard edit control, you won't know how much of MyBuff is valid unless you use the "InLen" returned by EM_GETLINE to limit how much of the string you get for other purposes.

        MCM
        PS: The RESET statement was not available when my code was written.
        Michael Mattias
        Tal Systems (retired)
        Port Washington WI USA
        [email protected]
        http://www.talsystems.com

        Comment


        • #5
          I thought that maybe the code below for a textbox might be helpful in trying to digest this problem. Method 2 shown in GetLineText() illustrates MM's concern of residual text as can be demonstrated by using FUNCTION = buf2, leaving off the LEFT$ part. Method 1 is the one I found referenced the most in POFFS, and its earliest reference seems to be by Borje Hagsten.

          Although method 2 adheres closest to the MSDN help, method 1 is my favorite. To be honest, I'm not sure how the %EM_GETLINE recognizes the extent of the buffer, unless a $NUL character is added to the end of the buffer, or if it is returned when a $LF is found. Maybe MM can give us his thoughts.

          Code:
          '[keywords] %EM_GETLINE
          #COMPILE EXE
          #DIM ALL
          #INCLUDE "win32api.INC"
          DECLARE CALLBACK FUNCTION dlgProc()
          
          FUNCTION PBMAIN
             LOCAL hDlg AS LONG
             DIALOG NEW 0, "Textbox Line Number", , , 150, 140, %WS_SYSMENU + %WS_CAPTION TO hDlg
             CONTROL ADD BUTTON, hDlg, 100, "&LineNo", 5, 10, 50, 14
             CONTROL ADD TEXTBOX, hDlg, 101, "", 5, 30, 120, 80, %ES_WANTRETURN + %ES_MULTILINE
             DIALOG SHOW MODAL hDlg CALL dlgProc
          END FUNCTION
          
          CALLBACK FUNCTION dlgProc()
             LOCAL s AS STRING, i AS INTEGER
             STATIC lineNo AS LONG
             SELECT CASE CBMSG
             CASE %WM_INITDIALOG
                FOR i = 1 TO 7
                   s = s + "This is line" + STR$(i) + $CRLF
                NEXT i
                CONTROL SET TEXT CBHNDL, 101, s
             CASE %WM_COMMAND
                SELECT CASE CBCTL
                   CASE 100
                      MSGBOX "Line number =" + STR$(lineNo + 1) + $CRLF + $CRLF _
                             + GetLineText(GetDlgItem(CBHNDL, 101), lineNo)
                   CASE 101
                      CONTROL SEND CBHNDL, 101, %EM_LINEFROMCHAR, -1, %NULL TO lineNo
                   END SELECT
             CASE %WM_DESTROY
             END SELECT
          END FUNCTION
          
          FUNCTION GetLineText(BYVAL hEdit AS LONG, BYVAL ln AS LONG) AS STRING
             'Two methods for getting a line from text box
             LOCAL lnStart, lnLen, methodNo AS LONG
             methodNo = 2
             lnStart = SendMessage(hEdit, %EM_LINEINDEX, ln, 0)       'line start
             lnLen   = SendMessage(hEdit, %EM_LINELENGTH, lnStart, 0) 'line length 
             IF lnLen THEN
                IF methodNo = 1 THEN
                   STATIC buf1 AS STRING
                   buf1 = "Here is a left over string"
                   buf1 = SPACE$(lnLen)
                   lnLen = SendMessage(hEdit, %EM_GETLINE, ln, STRPTR(buf1)) 'Get line
                   FUNCTION = buf1         
                ELSEIF methodNo = 2 THEN   
                   STATIC buf2 AS ASCIIZ * 80
                   buf2 = "Here is a left over string"
                   buf2 = MKWRD$(lnLen)
                   lnLen = SendMessage(hEdit, %EM_GETLINE, ln, VARPTR(buf2)) 'Get line
                   FUNCTION = LEFT$(buf2, lnLen)
                END IF   
             END IF
          END FUNCTION

          Comment


          • #6
            MCM's thoughts are, you don't know how lucky you are that EITHER 'method' has been providing more-or-less correct info.

            In Method One... since you intitialized buf1 to SPACE$(), the message will be interpreted as providing buffer length of CVL ($SPC + $SPC), or 0x2020, which I think is about 8,224d. In this case you get away with it because the actual length of the string is less than 8224. However, if the actual length of the string were greater than 8224d I think you would get an immediate 0x0005 Protection Fault, since Windows would try writing string data until it had provided 8224 bytes.

            OTOH, Method two is flawed because you have told Windows the buffer len is 'InLen'... except it is not. It is LEN("Here is a left over string").

            Care to try for a Method Three? Or may just throw both of these on scrap heap and start with a new Method One?

            MCM
            Michael Mattias
            Tal Systems (retired)
            Port Washington WI USA
            [email protected]
            http://www.talsystems.com

            Comment


            • #7
              Care to try for a Method Three? Or may just throw both of these on scrap heap and start with a new Method One?
              No need... both of those methods are fine as presented. It is true that method 1 is limited to a maximum of 8224 bytes, however. But that's more than enough for any textbox. I believe the %EM_GETLINE function returns as soon as a chr$(0) or a chr$(10) is detected.

              As for method 2, the variable 'lnLen' is the length of the textbox line, not the buffer length. It is the number of characters in the buffer to return, as long as no chr$(0) or chr$(10) is detected first.

              Comment


              • #8
                >It is true that method 1 is limited to a maximum of 8224 bytes

                Oops my error. The actual buffer size in method one is LEN(inLen), which means you won't overrun it. However, if the actual line length is GREATER than 8224d, I don't know and doc does not say if EM_GETLINE will fail on 'Insufficient buffer size" or will return ONLY the first 8224 characters.

                >As for method 2, the variable 'lnLen' is the length of the textbox line, not the buffer >length. It is the number of characters in the buffer to return, as long as no chr$(0) or >chr$(10) is detected first

                Yes, inlen is the number of characters in the line; but when you pass the address of the target string, the target string "Buf2" is only four bytes long: the size of the last assignment to it.

                This should be GPFing whenever the target line is > 4 bytes. It probably WONT under Windows 9x, and may not under XP as long as the retrieved text is less than the allocation granularity of an OLE string (64 bytes?)

                But these don't bother me anywhere near as much as the unprofessional approach you are taking... "good enough, I've never been caught." Especially when there are TWO postings above showing the right way to do it.

                Pride in ownership is necessary for success.

                MCM
                Michael Mattias
                Tal Systems (retired)
                Port Washington WI USA
                [email protected]
                http://www.talsystems.com

                Comment

                Working...
                X