Option Explicit
'the last param was changed from Any to Long
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public Declare Function GetWindowDC Lib "user32" (ByVal hWnd As Long) As Long
Public Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal hDC As Long) As Long
Public Declare Function GetTextExtentPoint32 Lib "gdi32" Alias "GetTextExtentPoint32A" (ByVal hDC As Long, ByVal lpzText As String, ByVal nLength As Long, lpSize As SIZE) As Long
Public Type SIZE
cX As Long
cY As Long
End Type
Public Const EM_GETLINECOUNT As Long = &HBA
Public Const EM_LINEINDEX As Long = &HBB
Public Const EM_LINELENGTH As Long = &HC1
Public Const EM_GETLINE As Long = &HC4
Public Const EM_GETFIRSTVISIBLELINE As Long = &HCE
Public Function GetLine(ByVal hWnd As Long, ByVal lngLineNumber As Long) As String
Dim lngLineCount As Long
Dim lngFirstChar As Long
Dim lngLineLength As Long
Dim abyteBuffer() As Byte
GetLine = ""
'get total number of lines
lngLineCount = SendMessage(hWnd, EM_GETLINECOUNT, 0, 0)
'exit if the requested value is outside the range
If (lngLineNumber < 0) Or (lngLineNumber > (lngLineCount - 1)) Then Exit Function
'get the number of characters that preceed the requested line
lngFirstChar = SendMessage(hWnd, EM_LINEINDEX, lngLineNumber, 0)
'get the length of the line containing character number lngFirstChar
lngLineLength = SendMessage(hWnd, EM_LINELENGTH, lngFirstChar, 0)
'exit if there's nothing in the line
If lngLineLength = 0 Then Exit Function
'resize the buffer
ReDim abyteBuffer(0 To (lngLineLength - 1))
'put the first byte of the size into the buffer (this is just how it's expected)
abyteBuffer(0) = lngLineLength And &HFF
'if the size is larger than a byte, place the next byte into the next position
If lngLineLength > 255 Then abyteBuffer(1) = (lngLineLength And &HFF00) \ &H100
'extract the line
SendMessage hWnd, EM_GETLINE, lngLineNumber, VarPtr(abyteBuffer(0))
'convert the byte array to a string
GetLine = StrConv(abyteBuffer, vbUnicode)
End Function
Public Function VisibleLines(ByVal hWnd As Long, ByVal lngHeight As Long) As String
Dim hDC As Long, i As Long
Dim lngFirstLine As Long, lngNumLines As Long
Dim strLine As String
Dim lpSize As SIZE
'get the DC of the edit control
hDC = GetWindowDC(hWnd)
'get the index of the first visible line
lngFirstLine = SendMessage(hWnd, EM_GETFIRSTVISIBLELINE, 0, 0)
'get the text of that line
strLine = GetLine(hWnd, lngFirstLine)
'determine the width/height of that text with the current font of the DC
GetTextExtentPoint32 hDC, strLine, Len(strLine), lpSize
'release the DC
ReleaseDC hWnd, hDC
'estimate the number of lines shown based on the visible height and the height of a row
lngNumLines = lngHeight \ lpSize.cY
'if only one is visible, you already have it
If lngNumLines = 1 Then
VisibleLines = strLine
Exit Function
End If
'otherwise, go through the rest of the lines grabbing their text
For i = (lngFirstLine + 1) To (lngFirstLine + lngNumLines - 1)
strLine = strLine & vbCrLf & GetLine(hWnd, i)
Next i
'return it
VisibleLines = strLine
End Function