×
INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Contact US

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Students Click Here

Sendmessage and GETTEXTEX in vb/vba

Sendmessage and GETTEXTEX in vb/vba

Sendmessage and GETTEXTEX in vb/vba

(OP)
Could someone have a look at the following code and suggest where I am going wrong in adapting to vb/vba.

As is, the code crashes the application on:

SendMessageRef(m_hWnd, EM_GETTEXTEX, tGTT, sBuff)

C Datatypes and all the fun stuff like memory management are a new experience to me and a prickly introduction.

Thanks, Bill

CODE:

Private Declare Function apiSendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal msg As Long, ByRef tGTT As Any, ByRef lp As Any) As Long

Dim tGTL As GETTEXTLENGTHEX
Dim tGTT As GETTEXTEX
Dim lRet As Long '
Dim lRet1 As Long
Dim sBuff As String
Dim sRTText As String

Call apiZeroMemory(tGTL, Len(tGTL))
        tGTL.flags = GTL_NUMCHARS
        tGTL.codepage = CP_ACP
        'return number of TChars in RtichText control
        lRet = SendMessageRef(m_hWnd, EM_GETTEXTLENGTHEX, tGTL, 0&)

Call apiZeroMemory(tGTT, Len(tGTT))
    tGTT.cb = lRet + 1
    tGTT.flags = GT_DEFAULT
    tGTT.codepage = CP_ACP
    tGTT.lpDefaultChar = Chr(164)   '0&
    tGTT.lpUsedDefChar = 0&
       sBuff = String$(lRet + 1, 0)
    lRet1 = SendMessageRef(m_hWnd, EM_GETTEXTEX, tGTT, sBuff)   'CRASH!!
      
    If (lRet1 > 0) Then
         sRTText = Left$(sBuff, lRet1)
    End If

RE: Sendmessage and GETTEXTEX in vb/vba

You need to pass sBuff string buffer by value instead of by reference as you are currently doing.

VB string variable is a pointer to the memory location holding the string data. When you pass a string by reference, the API function actually receives a pointer to pointer and things go wrong. Modify the SendMessage call as follows.

lRet1 = SendMessageRef(m_hWnd, EM_GETTEXTEX, tGTT, ByVal sBuff)

Note that same thing applies to the first SendMessage call. You are passing 0 to lParam argument by reference. Although it is working in this case, as this value is not used, the correct way is to pass this 0 by value, as required.

lRet = SendMessageRef(m_hWnd, EM_GETTEXTLENGTHEX, tGTL, ByVal 0&)

Hope this helps.

RE: Sendmessage and GETTEXTEX in vb/vba

(OP)
Thank you Hypetia for the response.  Making the suggested correction has resolved the crashing application.  And I appreciate the explanation on “pointer to a pointer”.  If I am following it correctly, then both of the following lParam variations should be functionally equivalent  in this situation.

1.    Declare ByRef and pass ByVal

Private Declare Function apiSendMessageGTT Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal msg As Long, wp As GETTEXTEX, ByRef lp As Long) As Long

lRet1 = apiSendMessageGTT(m_hWnd, EM_GETTEXTEX, tGTT, ByVal sBuff)

2.    Declare ByVal and pass ByRef

Private Declare Function apiSendMessageGTT Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal msg As Long, wp As GETTEXTEX, ByVal lp As Long) As Long

    lRet1 = apiSendMessageGTT(m_hWnd, EM_GETTEXTEX, tGTT, sBuff)


That brings a new difficulty – “type mismatch” when calling the SendMessage function.  My arguments seem appropriately typed and I assume that the return value will come back as a long (“The return value is the number of TCHARs copied into the output buffer”).  Everything compiles.  In the meantime I've come across EM_GETTEXTRANGE and beat a tactical retreat.  But I'd like to try both approaches and compare performance, so if you are still outthere and have any further suggestions, I'd like to hear them.

Cheers, Bill

Current CODE:


Dim tGTL As GETTEXTLENGTHEX
Dim tGTT As GETTEXTEX
Dim lRet As Long
Dim lRet1 As Long
Dim sBuff As String
Call apiZeroMemory(tGTL, Len(tGTL))
        tGTL.flags = GTL_NUMCHARS
        tGTL.codepage = CP_ACP
        lRet = apiSendMessage(m_hWnd, EM_GETTEXTLENGTHEX, tGTL, ByVal 0&)
        sBuff = Space$(lRet + 1)
    tGTT.cb = Len(sBuff)   
    tGTT.flags = GT_DEFAULT
    tGTT.codepage = CP_ACP
    tGTT.lpDefaultChar = 0&
    tGTT.lpUsedDefChar = 0&
lRet1 = apiSendMessageGTT(m_hWnd, EM_GETTEXTEX, tGTT, ByVal sBuff)    ‘TYPE MISMATCH!!!

RE: Sendmessage and GETTEXTEX in vb/vba

Bill,

I did not get online after my last above post. So thats the cause of the delay.

1. When you put the ByVal keyword in an API function call, it instructs the compiler to pass this argument by value, even if it is declared by reference, in the Declare statement.
The converse of this is not true. You cannot use ByRef keyword in an API function call to pass a ByVal argument by reference. Use of ByRef keyword gives a compile error.

2. You get the Type mismatch error not because of the return value of the function, but because you are passing a String (sBuff) when the function is expecting a Long (ByVal lp As Long).

I have seen many programmers using various forms of an API function using multiple Declare statements when they want to pass different kinds or arguments.

I also see this in your code, having various versions of SendMessage function: apiSendMessage, SendMessageRef, apiSendMessageGTT.
Sometimes I see: SendMessageRef, SendMessageVal, SendMessageStr, SendMessageLong etc.

I strongly oppose this practice. It creates obfuscation and repetition of same function with different names.

The VB's Declare statement is powerful enough that even a single function signature, if written properly, can handle all variations in its argument types.

Below is the declare statement I always use in my programs.

Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Look at the declaration of last two parameters. When both ByVal and ByRef are missing, the argument is considered ByRef. Note the type of lParam is declared as Any. "Any" is a special keyword which disables type checking in a declare statement, thus eliminating the need to have so many variations of the same function. This allows you to pass a String, a Long, a UDT or an array using the same function declaration. Furthermore, the lParam argument is declared ByRef. This allows you to modify its status on the fly using the ByVal keyword wherever needed.

One question arises, how to pass tGTL user-defined type in place of wParam argument which is declared as Long? If you pass plain tGTL in place of wParam, it will give a "Type mismatch" compile error.

The answer is VarPtr() function. As the name implies, it returns the pointer (address) of the variable passed to it. This returned pointer (which is a Long value) can be passed as wParam without any problem.

So, both of your above function calls can be made using the same function declaration mentioned above.

lRet = SendMessage(m_hWnd, EM_GETTEXTLENGTHEX, VarPtr(tGTL), ByVal 0&)
...
lRet1 = SendMessage(m_hWnd, EM_GETTEXTEX, VarPtr(tGTT), ByVal sBuff)

Note that you can also declare wParam as Any which will give you more liberty allowing you to pass tGTL and tGTT directly, instead of using their pointers.

RE: Sendmessage and GETTEXTEX in vb/vba

(OP)
Hypetia

Just a quick thanks for the excellent reply before I sit down to experiment and tinker.

Cheers, Bill

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members! Already a Member? Login

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close