Announcement

Collapse
No announcement yet.

EM_GetLine Question

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

  • Michael Mattias
    replied
    >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

    Leave a comment:


  • Charles Dietz
    replied
    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.

    Leave a comment:


  • Michael Mattias
    replied
    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

    Leave a comment:


  • Charles Dietz
    replied
    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

    Leave a comment:


  • Michael Mattias
    replied
    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.

    Leave a comment:


  • Scott Slater
    replied
    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))

    Leave a comment:


  • Michael Mattias
    replied
    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

    Leave a comment:


  • Gary Beene
    started a topic EM_GetLine Question

    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, 08:13 PM.
Working...
X