Question

Get a vb label caption using WinApi

Asked by: BobLamberson


I'm running a vb application exe and need to get the caption of a Label in another vb application exe. Have no access to the second application. Any help greatly appreciated.

This Question has been solved and asker verified All Experts Exchange premium technology solutions are available to subscription members.

Subscribe now for full access to Experts Exchange and get

Instant Access to this Solution

  • Plus...
  • 30 Day FREE access, no risk, no obligation
  • Collaborate with the world's top tech experts
  • Unlimited access to our exclusive solution database
  • Never be left without tech help again

Subscribe Now

Asked On
2004-06-08 at 12:56:58ID21018080
Tags

label

,

get

,

vb

Topic

Visual Basic Programming

Participating Experts
6
Points
500
Comments
55

Trusted by hundreds of thousands everyday for fast, accurate and reliable tech support.

  • "The time we save is the biggest benefit of Experts Exchange to Warner Bros. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange." Mike Kapnisakis, Warner Bros.
  • "Our team likes having a resource that is more secure than just using Google and most experts using this service really know their stuff. It's nice to look here first versus using Google." Dayna Sellner, Lockheed Martin
  • "Anytime that I've been stumped with a problem, 9 out of 10 times Experts Exchange has either the accepted solution or an open discussion of the potential solution to the problem." Kenny Red, eBay Inc.

See what Experts Exchange can do for you.

Got a question?

We've got the answer.

Experts Exchange has been collecting answers to technology questions since 1996…3 million and counting! If you have a question, chances are we already have your answer.

Screenshot of Experts Exchange Knowledgebase

Need individual assistance?

Our experts are ready to help.

If you can't find the exact answer you're looking for, ask our exclusive community of 50,000 experts. You’ll get a personalized answer from a trusted professional.

Screenshot of Experts Exchange Knowledgebase

Want to learn from the best?

Read articles from industry experts.

Thousands of free tech tips, tricks, how-to’s and tutorials are available in our peer reviewed articles section. See for yourself how smart our experts are, no login required.

Screenshot of an Article

Working on a long term project?

Store your work and research.

Save solutions to your questions, answers you’ve discovered through searching plus helpful articles in your personal knowledgebase for easy future access.

Screenshot of Experts Exchange Knowledgebase

Access the answers to your technology questions today.

Subscribe Now

30-day free trial. Register in 60 seconds.

What Makes Experts Exchange Unique?

Members of the expert community talk about why the experience at Experts Exchange is different than what you will find anywhere else.

Trusted by the world's most respected brands.

image of each brand's logo

Faithfully serving IT professionals since 1996.

Experts Exchange Logo

Try it out and discover for yourself.

Subscribe Now

30-day free trial. Register in 60 seconds.

Related Solutions

  1. scrolling and captions
    Hi, is there any way I can make a screen scrollable as in webpages?. The second question is that im using this command "Label2.BackColor" to change the backcolours of my labels but now my caption is missing (I entered the caption in the properties window). What is ...
  2. Saving caption of Label in form on button press
    Right then... I have a form which is not based on any tables/queries etc, and is only for printing sections of reports. The Report ID is taken from an underlying form, that's fine. if a user selects checkboxes 1, 2 & 3 (i.e. they want to print the pages for Section1, S...

Free Tech Articles

  1. WARNING: 5 Reasons why you should NEVER fix a computer for free.
    It is in our nature to love the puzzle. We are obsessed. The lot of us. We love puzzles. We love the challenge. We thrive on finding the answer. We hate disarray. It bothers us deep in our soul. W...
  2. SCCM OSD Basic troubleshooting
    SCCM 2007 OSD is a fantastic way to deploy operating systems, however, like most things SCCM issues can sometimes be difficult to resolve due to the sheer volume of logs to sift through and the dispe...
  3. Migrate Small Business Server 2003 to Exchange 2010 and Windows 2008 R2
    This guide is intended to provide step by step instructions on how to migrate from Small Business Server 2003 to Windows 2008 R2 with Exchange 2010. For this migration to work you will need the fo...
  4. Create a Win7 Gadget
    This article shows you how to create a simple "Gadget" -- a sort of mini-application supported by Windows 7 and Vista. Gadgets can be dropped anywhere on the desktop to provide instant information, ...
  5. Outlook continually prompting for username and password
    There have been a lot of questions recently regarding Outlook prompting for a username and password whilst using Exchange 2007. There are a few reasons why this would happen and I will try to cover t...
  6. Backup Exchange 2010 Information Store using Windows Backup
    There seems to be quite a lot of confusion around the ability to backup Exchange 2010 using the built in Windows Backup feature. This stems from the omission of this feature prior to Exchange 2007 s...

Cloud Class Webinars

  1. Avoiding Bugs in Microsoft Access
    Alison Balter takes and in-depth look at avoiding bugs in Access. In this webinar you will learn about using the immediate window to debug your applications, invoking the debugger, using breakpoints to troubleshoot, stepping through code, setting the next statement to execute, ...
  2. Top 10 Best New Features in Visio 2010
    Scott Helmers gives live demonstrations of the top 10 new features in Visio 2010. This webinar will teach you how to create compelling diagrams by adding shapes to the page with a single click, linking the shapes in a diagram to data in Excel (or SQL Server, or SharePoint), ...
  3. IT Consultant Business Secrets Revealed
    Michael Munger, Experts Exchange tech pro and IT consultant, pulls back the curtain on his very successful businesses and answers question on every IT consultant and business owner should know about. He shares secrets on what he did to solve the 5 most common problems in IT, ...
  4. Disaster Recovery and Business Continuity
    Quest CTO, Mike Billon, gives an overview of the steps involved in building a dunamic disaster recovery plan. Through case studies and an examination of software/hardware tooles for monitoring and testing, you'll gain a better understandin of where you are, where you want ...
  5. Organize Your Visio Diagrams with Containers and Lists
    Scott Helmers uses cross functional flowcharts, wireframe diagrams, data graphic legends and seating charts to teach you: how to ustilize all three new structured diagram components in Visio 2010, the best practices for organizeing shapes in previous version of Visio, how to organize ...
  6. How to Us Objects, Properties, Events and Methods in Microsoft Access
    Alison Dalter gives an in-depbth look at objects, properties, events and methods in Microsoft Access. In this webinar you will learn about using the object browser, referring to objects, working with properties and methods, working with object variables, understanding the ...

Join the Community

Give a Little. Get a Lot.

Join the community of experts here and help other tech pros by answering question in your area of expertise. You can earn FREE access to all Experts Exchange's premium features and resources.

Join the Community

Answers

 

by: BlueDevilFanPosted on 2004-06-08 at 13:45:17ID: 11264133

I believe you can do what you need to using the SendMessage API function.  Here's a link to a sample app that demonstrates passing data bewtween two apps.  In your case when the data arrives in the receiving application you'll change the appropriate label caption instead of inserting the string to a listbox.

http://www.thescarms.com/vbasic/PassString.asp

 

by: jkozeePosted on 2004-06-08 at 14:05:26ID: 11264308

What version of vb and os are you running.  

 

by: jkozeePosted on 2004-06-08 at 14:07:35ID: 11264325

How will you identify the app that you want the label from?  PID, Caption, etc.

 

by: AzraSoundPosted on 2004-06-08 at 14:46:01ID: 11264658

A true label has no associated window handle, meaning you will not be able to grab its caption via API.

 

by: BobLambersonPosted on 2004-06-08 at 14:49:03ID: 11264691

BlueDevilFan,
Thanks, I'm checking the code out now.

 

by: BobLambersonPosted on 2004-06-08 at 14:50:28ID: 11264703

jkozee,
I'm using vb6 in vs6 enterprise and win2k with (hopefully) all the latest sps.

 

by: BobLambersonPosted on 2004-06-08 at 14:57:39ID: 11264752

AzraSound,
Yeah exactly, that's what makes it a complicated question.

Do you know of anyway to do it with these conditions:
     The second application's form has a frame (could be any window with a handle) that contains the label.
     We can get the win handle for the frame.
     We can get a device context handle for the RECT of the frame.
        But, Can't figure out how to pull the caption of the label out of the frame.
Maybe this stirs an idea?

 

by: BlueDevilFanPosted on 2004-06-08 at 15:01:22ID: 11264778

Ooops, I think I misread the question in which case my post is useless.  I thought I read "set the caption" when instead it is "get the caption".  Sorry!

 

by: BobLambersonPosted on 2004-06-08 at 15:25:06ID: 11264893

BlueDevilFan,

No problem.

Either get or set works for me if I can find an api function(s) that will just somehow deal with the information in the label caption. The problem seems to be communication with the label itself, since it has no handle.

 

by: AzraSoundPosted on 2004-06-08 at 16:14:18ID: 11265154

Again, no handle, no direct solution.  You know those websites that show some image of a word you must type in to register, for example?  The same idea would have to apply here...you would need some type of image/character recognition functionality because about the best you could do with a label is pull it as an image.

 

by: BobLambersonPosted on 2004-06-08 at 16:52:57ID: 11265370


AzraSound,

Thanks for the ideas. I guess I think that there is some way to accomplish this for my client, other than a com dll that would have to be on each users machine.

SnagIt 6 at http://www.techsmith.com/ has some way of getting the caption of a label inside a frame that is selected by outlining the frame with the mouse (I've used it), but I don't know how they are doing it.
I suspect that the API graphic library plays a part, hence my suggestion that maybe using the device context handle for the RECT of the frame might help.

Anyway, if you think of something I would appreciate hearing.

 

by: AzraSoundPosted on 2004-06-08 at 17:01:15ID: 11265417

I can see it could get the caption of the frame itself (the frame has a window handle) but not a label within the frame.  SnagIt admits it cannot retrieve text from a pdf or image file, which, I imagine, is similar to what would need to be done to get the text from a label control.

 

by: BobLambersonPosted on 2004-06-08 at 18:55:55ID: 11265891

AzraSound,

You might want to actually try SnagIt's trial and see it return the caption of a label in a frame, before you itellectually argue that it's not likely.
 
I'm just looking for answers, but here's some of what I have picked up so far.
Using windows GDI API lib provides graphical functions that relate to any rectangular area of the display, such as a frame or 'drawing context', that might be drawn to.
This area is considered an object and has a handle seperate from the window handle that is assigned to the frame, which is referred to as a Device Context handle (hDC).
There is also a Memory handle (hMem) that facilitates access to a block of memory, which I suppose could hold the caption of the label or contents of the frame.
It's possible that SnagIt's ability to return what is inside that frame, might have to do with either of these, I don't know and I'm hoping to find someone who knows the magic.

 

by: jkozeePosted on 2004-06-08 at 22:41:32ID: 11266764

BobLamberson:

I have downloaded SnagIt v7 demo and I am unable to get the demo to capture text from a VB label in Win 2000 and Win XP.  Can you confirm that it works in those OS's.

 

by: BobLambersonPosted on 2004-06-08 at 23:22:36ID: 11266913

jkozee,

Yes, I can confirm that SnagIt 6 works on win2k and will retrieve the captionof a VB Label control inside a frame using the mouse to outline the frame. I just tried it again and it works fine.
I will see if I can get trial v7 and try it.

 

by: BobLambersonPosted on 2004-06-08 at 23:51:22ID: 11267042

jkozee,

I just installed v7 and it is quite different looking but works the same way. I have a compiled vb app that is just a form with a frame, a textbox inside the frame, and a label inside the frame. The form also has a label that is not contained by a frame.
Using the text capture, I can get and save the text of the label inside the frame. Using the image capture, I can get and save the an image of the label on the form, outside the frame.
I also created an exe that has two different frames with a label in each and using the text setting on snagit, I am able to save capture and saave the label caption to a text file as ordinary text.
Snagit is set to
        Text
        Input: Region
        Output: File
        Filters: Space Formatted
These are just the default settings that came up when I opened SnagIt.

 

by: jkozeePosted on 2004-06-09 at 05:55:57ID: 11269201

Ark:

I have been working on getting this code working on XP/2K but so far no go.  It does however work on win 98.

 

by: BobLambersonPosted on 2004-06-09 at 09:53:53ID: 11271986

Ark and jkozee,

Ark's link looks like the answer, but jkozee, what happens on xp and 2k? The fact that it works on 98 is very encouraging. I will work with it and see what I can find also.

Thank you both for all your time and effort.   - Bob

 

by: ArkPosted on 2004-06-09 at 14:42:54ID: 11274689

Seems this is due to different heap organization in 9x/NT. IMHO there can be another way for both platforms - scaning process memory for ControlProgID("VB.Label"), and then get controlname (offset 16) and controlcaption(offset 88). I'll try this a bit later.

 

by: BobLambersonPosted on 2004-06-09 at 22:13:25ID: 11276309


I've pasted the code from Ark's link, into a vb form and module, but don't understand how to run it. Do I call one of the vb functions, or? They all seem to require parameters and I don't know how to enter them.

 

by: BobLambersonPosted on 2004-06-11 at 19:15:14ID: 11294036

Ark,

Have you not had a chance to try your idea of scanning process memory, or did it just not work? I am encouraged by your apparent knowledge of using the api and hope you can help me get this working on win2k.

 

by: jkozeePosted on 2004-06-11 at 23:09:27ID: 11294613

BobLamberson and ARK,

IMHO the thread referenced will not work on Win 2k/XP.  When I happened on this question (I'm new here), I knew that I had some code in my asrenal to accomplish this, but I couldn't lay my hands on it immediately.  I had an OCX which did exactly what was requested given a PID, hence my original questions about how the caller would request the label info.  I have since found my code, which is very similar to the proposed solution, and probably originated from it.  After trying to port it to Win XP, I strongly feel that it will not work.

There are a couple of problems.  Even if you account for any heap differences, the calls to ToolHelp functions in NT are unreliable at best.  There are a couple of notes from MS regarding a memory leaks when calling it from Win2k, and from my tests it is safe to assume that the same holds true in XP.  Also, when trying to walk the Heap in 2k/XP it is most likely that you will enter an endless loop, which is never acceptable.

The only viable solution is to accomplish this is to abandon this and revert to reading the process memory directly.  Unfortunately, this is very cumbersome and doesn't make for easy coding, but it is still possible. Without the HeapEntries of ToolHelp, you will have a lot of work to do.

I will post an example shortly that should work in both Win98, XP, 2k, etc.....

Good luck!!!!!!!!

 

by: jkozeePosted on 2004-06-11 at 23:11:36ID: 11294620

BobLamberson,

Back to my oringinal question.  How will you be coming after the info, PID, hwnd, exe name????

 

by: jkozeePosted on 2004-06-11 at 23:30:07ID: 11294667

This code should work on Win98,2k,XP,....  

It is nearly complete, but may need some tweaking.  It should get you exactly what you are after.  Keep in mind that the problem you have posed is very complex, so this solution may seem convaluted, but it should get you well on your way.  I assume that you can get at the hWnd of the form you are after so add this code to a module and call:

call GetFormLabels(hwnd)

It is currently not returning anything, but it should print out all of the goodies to the immediate window that you are after.  Let me know if this will work for you.  Again, good luck!!!!

'Author: John Kozee
'Purpose: Enumerate Label captions given a known hWnd
'Date: June 12, 2004
Option Explicit

Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Const VBM_WINDOWTITLEADDR = &H1091
Private Declare Function SendMessage Lib "USER32.DLL" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, wParam As Any, lParam As Any) As Long

Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal blnheritHandle As Long, ByVal dwAppProcessId As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

Private Const PROCESS_VM_READ = (&H10)
Private Const PROCESS_VM_WRITE = (&H20)
Private Const PROCESS_VM_OPERATION = (&H8)
Private Const PROCESS_QUERY_INFORMATION = (&H400)
Private Const PROCESS_READ_WRITE_QUERY = PROCESS_VM_READ + PROCESS_VM_WRITE + PROCESS_VM_OPERATION + PROCESS_QUERY_INFORMATION

Private Type MEMORY_BASIC_INFORMATION ' 28 bytes
    BaseAddress As Long
    AllocationBase As Long
    AllocationProtect As Long
    RegionSize As Long
    State As Long
    Protect As Long
    lType As Long
End Type
Private Declare Function VirtualQueryEx& Lib "kernel32" (ByVal hProcess As Long, lpAddress As Any, lpBuffer As MEMORY_BASIC_INFORMATION, ByVal dwLength As Long)
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
 
Private abBuffer() As Byte 'Heap Buffer
Private lBaseAddress As Long
Private hProcess As Long

Public Sub GetFormLabels(hwnd As Long)
    Dim sClass As String
    Dim lRet As Long
    Dim pid As Long
    Dim hProcess As Long
    Dim lFormCaptionHeapAddress As Long
   
    Dim lpMem As Long
    Dim lLenMBI As Long
    Dim lBytesRead As Long
    Dim mbi As MEMORY_BASIC_INFORMATION
   
    'Make sure we are working with a VB Form hWnd
    sClass = Space(256)
    lRet = GetClassName(hwnd, sClass, 255)
    sClass = Left(sClass, lRet)
    If Not sClass = "ThunderRT6FormDC" Then
        MsgBox "This function only works on VB RunTime 6 Forms ThunderFormRT6DC"
        Exit Sub
    End If
   
    'Now get the internal heap address of the form caption.  All that we need can be found in this heap (hopefully!)
    'This is done with a little undocumented SendMessage magic
    lFormCaptionHeapAddress = SendMessage(hwnd, VBM_WINDOWTITLEADDR, ByVal 0&, ByVal 0&)
   
    'Get a handle on the process with required access
    lRet = GetWindowThreadProcessId(hwnd, pid)
    If pid = 0 Then
        MsgBox "Unable to determine pid of this hwnd."
        Exit Sub
    End If
    hProcess = OpenProcess(PROCESS_READ_WRITE_QUERY, False, pid)
   
    'Get the Heap at the caption point
    lLenMBI = Len(mbi)
    lpMem = lFormCaptionHeapAddress
    mbi.AllocationBase = lpMem
    mbi.BaseAddress = lpMem
    lRet = VirtualQueryEx(hProcess, ByVal lpMem, mbi, lLenMBI)
    If lRet <> lLenMBI Then GoTo Finished
   
    'Now go back and get the entire heap
    lBaseAddress = mbi.AllocationBase
    lpMem = lBaseAddress
    mbi.BaseAddress = lBaseAddress
    mbi.RegionSize = 0
    lRet = VirtualQueryEx(hProcess, ByVal lpMem, mbi, lLenMBI)
    If lRet <> lLenMBI Then GoTo Finished
   
    'A couple of sanity checks, just to be safe
    If Not ((mbi.lType = MEM_PRIVATE) And (mbi.State = MEM_COMMIT) And mbi.RegionSize > 0) Then
        MsgBox "Unexpected Heap Type, State, or Size."
        GoTo Finished
    End If
   
     'Allocate a buffer and read it in
    ReDim abBuffer(0 To mbi.RegionSize - 1)
    ReadProcessMemory hProcess, ByVal mbi.BaseAddress, abBuffer(LBound(abBuffer)), mbi.RegionSize, lBytesRead
   
    'So far, so good.  Things get messy from here.  We have to
    'do some manual parsing of the buffer to get what we are after.  To
    'make things easier, I'll will get every label on every form in the
    'exe.  Otherwise, you will need to first find the form that is
    'reference the caption.  Then find every label between it and the next
    'form.
   
    Dim iCnt As Integer
    Dim al() As Long
   
    'Print all of the label captions
    If EnumVBObjectPtrs("VB.Label", 44, al) > 0 Then
        For iCnt = LBound(al) To UBound(al)
            Debug.Print "Hit at: " & Hex(al(iCnt) + lBaseAddress + 44), "Object At: " & Hex(al(iCnt) + lBaseAddress), "Caption =: " & GetLabelCaption(al(iCnt))
        Next iCnt
    End If
   
Finished:
    CloseHandle hProcess
    abBuffer() = ""
End Sub

Private Function GetLabelCaption(lpLocalObjPtr As Long) As String
    Dim lStrPtr As Long

    'Get local pointer to caption
    CopyMemory lStrPtr, abBuffer(lpLocalObjPtr + 136), 4
    lStrPtr = lStrPtr - lBaseAddress
   
    'Get caption
    If lStrPtr <> 0 Then
        GetLabelCaption = StrConv(MidB(abBuffer, lStrPtr + 1, 260), vbUnicode)
    End If
    GetLabelCaption = Left$(GetLabelCaption, InStr(GetLabelCaption, vbNullChar) - 1)
End Function

'This function will search the buffer for a given VBObjectIDString, then
'find the start of that control by searching for a refence to it in the 600
'bytes prior.
'It then finds any object of that type by searching the buffer for any
'references to the Heap Location of that control, and adds it to the enumeration
'if the reference hit position is at the correct offset (pos-offset = lBaseAddress)
'setting the EnumObj entry to the start location (local buffer address) and
'returns the counrt
Private Function EnumVBObjectPtrs(VBObjectIDString As String, _
                                  lOffset As Long, _
                                  EnumObj() As Long) As Integer
    Dim abObjectPtr(0 To 3) As Byte 'LittleEndian byte array of the Heap Address of the VBObject
    Dim abBaseAddress(0 To 3) As Byte 'LittleEndian byte array of the Heap Base Memory Address
    Dim abLong(0 To 3) As Byte 'Byte array for ptr manipulation
    Dim lPtr As Long 'Local Buffer pointer for search hits
    Dim lHeapPtr As Long 'Heap pointer (lPtr + lBaseAddress)
    Dim iCnt As Integer
    Dim alRet() As Long
   
    'Find the location of the VBObjectIDString string
    lPtr = InStrB(1, abBuffer, StrConv(VBObjectIDString, vbFromUnicode)) - 1
    lHeapPtr = lBaseAddress + lPtr
    If lPtr = 0 Then Exit Function
   
    'We now need to find the location that points to the start of the object
    'which should be 244 bytes prior (on XP at least) we go back 300 just in
    'case.  This is at offset 36, so we'll need to adjust back to the beginning
    'of the object
    CopyMemory abLong(0), lHeapPtr, 4
    lPtr = InStrB(lPtr - 600, abBuffer, abLong) - 1
    If lPtr = 0 Then Exit Function
    lPtr = lPtr - 36 'Adjust back to the beginning of the object
    lHeapPtr = lBaseAddress + lPtr
    CopyMemory abObjectPtr(0), lHeapPtr, 4
   
    'Turn the lBaseAddress into LittleEndian byte array for searching
    CopyMemory abBaseAddress(0), lBaseAddress, 4
   
    'Loop through the buffer
    lPtr = 1
    Do Until lPtr = 0
        'Find a reference to this object
        lPtr = InStrB(lPtr, abBuffer, abObjectPtr)
        If lPtr > 0 Then
            'make sure that this is really a VB object
            'move back from the offset of the object
            'and make sure that it has the correct base memory value
            If InStrB(lPtr - lOffset - 1, abBuffer, abBaseAddress) = lPtr - lOffset Then
                ReDim Preserve alRet(0 To iCnt)
                alRet(iCnt) = lPtr - lOffset - 1
                iCnt = iCnt + 1
            End If
            'Keep searching from the next byte
            lPtr = lPtr + 1
        End If
    Loop
   
    EnumVBObjectPtrs = iCnt
    EnumObj = alRet

End Function

 

by: jkozeePosted on 2004-06-11 at 23:39:48ID: 11294688

I have confirmed that this code works (for me) on 98/ME/2K/XP.  Let me know if you have any problems.

 

by: BobLambersonPosted on 2004-06-12 at 08:04:39ID: 11295826

jkozee,
Greatly appreciate the time and effort you have put in here. I will work with this today and let you know the result.

 

by: BobLambersonPosted on 2004-06-12 at 13:56:02ID: 11297127

jkozee,
I get an error on this line

    'A couple of sanity checks, just to be safe
        If Not ((mbi.lType = MEM_PRIVATE) And (mbi.State = MEM_COMMIT) And mbi.RegionSize > 0) Then

saying that MEM_PRIVATE is an undefined variable. I assume it is a type that should be defined in the declarations - right?

 

by: BobLambersonPosted on 2004-06-12 at 15:25:13ID: 11297470

john,
    This is exactly what I needed. The errors in the sanity checks if statement are the only glitch. It seems to work fine if I just comment out that statement.
    1. If I remove MEM_PRIVATE, I then get the var undefined for MEM_COMMIT.
    2. I commented out the entire if stmt
            'A couple of sanity checks, just to be safe
            '    If Not ((mbi.lType = MEM_PRIVATE) And (mbi.State = MEM_COMMIT) And mbi.RegionSize > 0) Then
'                   MsgBox "Unexpected Heap Type, State, or Size."
            '        GoTo Finished
            '    End If
        then it appears to work perfectly!!!
Is this something that can be easily remedied or can it just be left out without compromise?

Also, how difficult would it be to identify which label the caption is for, by the name of the label (or some other means). Like if we have two labels on a form, one is named lblVehicleNumber with a caption of 3554611243, and the second is named lblMilage with a caption of 12448?

Thanks, Bob

 

by: BobLambersonPosted on 2004-06-12 at 16:46:12ID: 11297767

jkozee,
> Back to my oringinal question.  How will you be coming after the info,
> PID, hwnd, exe name????
Sorry I missed this question along the way, but you guessed right using hwnd. What I am doing is using  EnumWindows(AddressOf enumTop, 0)  

and my function  

Public Function enumTop(ByVal lhwnd As Long, ByVal lParam As Long) As Long

If lParam = 0 Then      'enum windows
         Dim retval As Long
         Dim WinClassBuf As String * 255, WinTitleBuf As String * 255
         Dim WinClass As String, WinTitle As String
         
         retval = GetClassName(lhwnd, WinClassBuf, 255)
         WinClass = Left(WinClassBuf, Len("ThunderRT6FormDC"))  ' remove extra Nulls & spaces
         retval = GetWindowText(lhwnd, WinTitleBuf, 255)
         WinTitle = Left(WinTitleBuf, Len("Capture From"))
   If WinClass = "ThunderRT6FormDC" And WinTitle = "Capture From" Then
      thisHandle = lhwnd
        Debug.Print "winclass is " & WinClass
        Debug.Print "winTitle at top level  " & WinTitle
        Dim si As Form
        Dim d As Integer
        Dim addr As String
    End If
    enumTop = 1
End If
End Function

to find a window with the text name I need and getting the hwnd from that.

 

by: jkozeePosted on 2004-06-12 at 21:01:14ID: 11298527

It looks like I missed these to constants in the decalration.  This should clear up the error you received.

Private Const MEM_PRIVATE = &H20000
Private Const MEM_COMMIT = &H1000

As for gettiing the name, there is a pointer to it but it is not in the same heap, so you'll have to read in a new process memory from the running EXE.  When I get a few minutes I'll post the code, if you haven't already figured it out.  BTW, the pointer to the Name can be found at Offset 4 of the location pointed to from Offset 60 of the Label Object (lpLocalObjPtr).  Also, keep in mind that if the EXE has been obfuscated then the label may have no meaningful name.

 

by: BobLambersonPosted on 2004-06-12 at 21:20:22ID: 11298570


Great. the two constants did the trick. I'll try to get it figured out but would appreciate your back up with the real thing.
Thanks again for all your effort.

 

by: jkozeePosted on 2004-06-12 at 23:19:30ID: 11298855

Here are my changes.  I change the local buffer boundaries to match the heap, so here's the entire code.  You should now be able to get the caption and name.  

Option Explicit

Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Const VBM_WINDOWTITLEADDR = &H1091
Private Declare Function SendMessage Lib "USER32.DLL" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, wParam As Any, lParam As Any) As Long

Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal blnheritHandle As Long, ByVal dwAppProcessId As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

Private Const PROCESS_VM_READ = (&H10)
Private Const PROCESS_VM_WRITE = (&H20)
Private Const PROCESS_VM_OPERATION = (&H8)
Private Const PROCESS_QUERY_INFORMATION = (&H400)
Private Const PROCESS_READ_WRITE_QUERY = PROCESS_VM_READ + PROCESS_VM_WRITE + PROCESS_VM_OPERATION + PROCESS_QUERY_INFORMATION
Private Const MEM_PRIVATE = &H20000
Private Const MEM_COMMIT = &H1000

Private Type MEMORY_BASIC_INFORMATION ' 28 bytes
    BaseAddress As Long
    AllocationBase As Long
    AllocationProtect As Long
    RegionSize As Long
    State As Long
    Protect As Long
    lType As Long
End Type
Private Declare Function VirtualQueryEx& Lib "kernel32" (ByVal hProcess As Long, lpAddress As Any, lpBuffer As MEMORY_BASIC_INFORMATION, ByVal dwLength As Long)
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
 
Private abBuffer() As Byte 'Heap Buffer
Private hProcess As Long
Private lBaseAddress As Long

Public Sub GetFormLabels(hwnd As Long)
    Dim sClass As String
    Dim lRet As Long
    Dim pid As Long
    Dim lFormCaptionHeapAddress As Long
   
    Dim lpMem As Long
    Dim lLenMBI As Long
    Dim lBytesRead As Long
    Dim mbi As MEMORY_BASIC_INFORMATION
   
    'Make sure we are working with a VB Form hWnd
    sClass = Space(256)
    lRet = GetClassName(hwnd, sClass, 255)
    sClass = Left(sClass, lRet)
    If Not sClass = "ThunderRT6FormDC" Then
        MsgBox "This function only works on VB RunTime 6 Forms ThunderFormRT6DC"
        Exit Sub
    End If
   
    'Now get the internal heap address of the form caption.  All that we need can be found in this heap (hopefully!)
    'This is done with a little undocumented SendMessage magic
    lFormCaptionHeapAddress = SendMessage(hwnd, VBM_WINDOWTITLEADDR, ByVal 0&, ByVal 0&)
   
    'Get a handle on the process with required access
    lRet = GetWindowThreadProcessId(hwnd, pid)
    If pid = 0 Then
        MsgBox "Unable to determine pid of this hwnd."
        Exit Sub
    End If
    hProcess = OpenProcess(PROCESS_READ_WRITE_QUERY, False, pid)
   
    'Get the Heap at the caption point
    lLenMBI = Len(mbi)
    lpMem = lFormCaptionHeapAddress
    mbi.AllocationBase = lpMem
    mbi.BaseAddress = lpMem
    lRet = VirtualQueryEx(hProcess, ByVal lpMem, mbi, lLenMBI)
    If lRet <> lLenMBI Then GoTo Finished
   
    'Now go back and get the entire heap
    lBaseAddress = mbi.AllocationBase
    lpMem = lBaseAddress
    mbi.BaseAddress = lBaseAddress
    mbi.RegionSize = 0
    lRet = VirtualQueryEx(hProcess, ByVal lpMem, mbi, lLenMBI)
    If lRet <> lLenMBI Then GoTo Finished
   
    'A couple of sanity checks, just to be safe
    If Not ((mbi.lType = MEM_PRIVATE) And (mbi.State = MEM_COMMIT) And mbi.RegionSize > 0) Then
        MsgBox "Unexpected Heap Type, State, or Size."
        GoTo Finished
    End If
   
     'Allocate a buffer and read it in
    ReDim abBuffer(mbi.AllocationBase To mbi.AllocationBase + mbi.RegionSize - 1)
    ReadProcessMemory hProcess, ByVal mbi.BaseAddress, abBuffer(LBound(abBuffer)), mbi.RegionSize, lBytesRead
   
    'So far, so good.  Things get messy from here.  We have to
    'do some manual parsing of the buffer to get what we are after.  To
    'make things easier, I'll will get every label on every form in the
    'exe.  Otherwise, you will need to first find the form that is
    'reference the caption.  Then find every label between it and the next
    'form.
   
    Dim iCnt As Integer
    Dim al() As Long
   
    'Print all of the label captions
    If EnumVBObjectPtrs("VB.Label", 44, al) > 0 Then
        For iCnt = LBound(al) To UBound(al)
            Debug.Print "Hit at: " & Hex(al(iCnt) + 44), "Object At: " & Hex(al(iCnt)), GetLabelCaption(al(iCnt)), GetLabelName(al(iCnt))
        Next iCnt
    End If
   
Finished:
    CloseHandle hProcess
    abBuffer() = ""
End Sub

Private Function GetLabelName(lpObjPtr As Long) As String
    Dim lpMem As Long
    Dim lLenMBI As Long
    Dim lBytesRead As Long
    Dim mbi As MEMORY_BASIC_INFORMATION
    Dim lRet As Long
    Dim ab() As Byte
    Dim lStrPtr As Long
    Dim lInfoPtr As Long

    'Get the local pointer to object info
    CopyMemory lInfoPtr, abBuffer(lpObjPtr + 60), 4
   
    'Get the pointer to label name
    CopyMemory lStrPtr, abBuffer(lInfoPtr + 4), 4

    'Get the EXE at the name point
    lLenMBI = Len(mbi)
    lpMem = lStrPtr
    mbi.AllocationBase = lpMem
    mbi.BaseAddress = lpMem
    lRet = VirtualQueryEx(hProcess, ByVal lpMem, mbi, lLenMBI)
    If lRet <> lLenMBI Then Exit Function
   
    'Read in the EXE Heap
    ReDim ab(0 To mbi.RegionSize - 1)
    ReadProcessMemory hProcess, ByVal mbi.BaseAddress, ab(LBound(ab)), mbi.RegionSize, lBytesRead
   
    GetLabelName = StrConv(MidB(ab, lStrPtr - mbi.BaseAddress + 1, 260), vbUnicode)
    GetLabelName = Left$(GetLabelName, InStr(GetLabelName, vbNullChar) - 1)
End Function

Private Function GetLabelCaption(lpObjPtr As Long) As String
    Dim lStrPtr As Long

    'Get local pointer to caption
    CopyMemory lStrPtr, abBuffer(lpObjPtr + 136), 4
   
    'Get caption
    If lStrPtr <> 0 Then
        GetLabelCaption = StrConv(MidB(abBuffer, lStrPtr - lBaseAddress + 1, 260), vbUnicode)
    End If
    GetLabelCaption = Left$(GetLabelCaption, InStr(GetLabelCaption, vbNullChar) - 1)
End Function

'This function will search the buffer for a given VBObjectIDString, then
'find the start of that control by searching for a refence to it in the 600
'bytes prior.
'It then finds any object of that type by searching the buffer for any
'references to the Heap Location of that control, and adds it to the enumeration
'if the reference hit position is at the correct offset (pos-offset = lBaseAddress)
'setting the EnumObj entry to the start location (local buffer address) and
'returns the counrt
Private Function EnumVBObjectPtrs(VBObjectIDString As String, _
                                  lOffset As Long, _
                                  EnumObj() As Long) As Integer
    Dim abObjectPtr(0 To 3) As Byte 'LittleEndian byte array of the Heap Address of the VBObject
    Dim abBaseAddress(0 To 3) As Byte 'LittleEndian byte array of the Heap Base Memory Address
    Dim abLong(0 To 3) As Byte 'Byte array for ptr manipulation
    Dim lPtr As Long 'Buffer pointer for search hits
    Dim iCnt As Integer
    Dim alRet() As Long
   
    'Find the location of the VBObjectIDString string
    lPtr = InStrB(1, abBuffer, StrConv(VBObjectIDString, vbFromUnicode)) - 1
    If lPtr = -1 Then Exit Function
    lPtr = lBaseAddress + lPtr
   
    'We now need to find the location that points to the start of the object
    'which should be 244 bytes prior (on XP at least) we go back 600 just in
    'case.  This is at offset 36, so we'll need to adjust back to the beginning
    'of the object
    CopyMemory abLong(0), lPtr, 4
    lPtr = InStrB(lPtr - lBaseAddress - 600, abBuffer, abLong) - 1
    If lPtr = -1 Then Exit Function
    lPtr = lPtr + lBaseAddress - 36 'Adjust back to the beginning of the object
    CopyMemory abObjectPtr(0), lPtr, 4
   
    'Turn the lBaseAddress into LittleEndian byte array for searching
    CopyMemory abBaseAddress(0), lBaseAddress, 4
   
    'Loop through the buffer
    lPtr = 1
    Do Until lPtr = 0
        'Find a reference to this object
        lPtr = InStrB(lPtr, abBuffer, abObjectPtr)
        If lPtr > 0 Then
            'make sure that this is really a VB object
            'move back from the offset of the object
            'and make sure that it has the correct base memory value
            If InStrB(lPtr - lOffset - 1, abBuffer, abBaseAddress) = lPtr - lOffset Then
                ReDim Preserve alRet(0 To iCnt)
                alRet(iCnt) = lPtr + lBaseAddress - lOffset - 1
                iCnt = iCnt + 1
            End If
            'Keep searching from the next byte
            lPtr = lPtr + 1
        End If
    Loop
   
    EnumVBObjectPtrs = iCnt
    EnumObj = alRet

End Function

 

by: BobLambersonPosted on 2004-06-13 at 08:40:48ID: 11300250

John,
 The revisions work exactly. I will link with some code and do some tweaking to allow a user to save caption of a specific label, but you have done all the difficult part for me. This will also give me a very good basis to learn/understand some of the indepth workings of windows and the api.  Thanks again. Bob

 

by: job_sPosted on 2004-07-20 at 01:30:43ID: 11590862

hi jkozee,

I tried to use the same source code which you have provided in this question for finding the label caption. but the string search is failing in the EnumVBObjectPtrs function

lPtr = InStrB(1, abBuffer, StrConv(VBObjectIDString, vbFromUnicode)) - 1
    If lPtr = -1 Then Exit Function

always getting return as -1 what could be the reason ??

if you can give me a solution within 12 hrs I'll give u 500 more points

Thanks & regards
Jobs

 

by: jkozeePosted on 2004-07-20 at 07:16:37ID: 11593059

Jobs,

What OS are you running on?
Are you trying to get the lable from a compiled VB exe?

John

 

by: job_sPosted on 2004-07-22 at 21:31:31ID: 11618774

hi,
I'm using win2k but I'm able to read from serveral other labels from other exes. but I don't know why i'm not getting the label from the required exe. Its having lot of custom controls and its a huge exe :(.

Failing during the vb.Label searh in the memory as i mentioned in the previous comment.

waiting for reply
Thanks
Jobs

 

by: Raven65Posted on 2004-10-25 at 12:28:30ID: 12403893

When running this program I notice that it requries the form be a: ThunderFormRT6DC

Im needing a very similar solution (got this one to work on a differnet app)
but the form type is: ThunderRT6Main

Is there a way to do this ?

 

by: BobLambersonPosted on 2004-10-25 at 19:04:59ID: 12406842

Raven65
I'm not positive, but I think the following is just checking to be sure it is a VB form and could be any form class in VB that contains labels. Try changing it to ThunderRT6Main and see if that works. Maybe jkozee is around and could comment on this.
>    'Make sure we are working with a VB Form hWnd
>     sClass = Space(256)
>     lRet = GetClassName(hwnd, sClass, 255)
>     sClass = Left(sClass, lRet)
>     If Not sClass = "ThunderRT6FormDC" Then
>         MsgBox "This function only works on VB RunTime 6 Forms ThunderFormRT6DC"
>         Exit Sub
>     End If


Bob

 

by: Raven65Posted on 2004-10-26 at 05:28:01ID: 12409967

Thanks Bob, that seems to have gotten me past problem 1.

Problem2: (Always another one..)
Turns out I need to be reading the text boxes on my target application. I can get the labels, their
names and captions, but I need to get the content of several text boxes (and their names/labels if possible). Has any one worked with this code to achieve that goal ? I see a few areas in it that give me hope but I am not the greatest vb programmer and need a little guidance here..

Thanks again,
chrisj

 

by: BobLambersonPosted on 2004-10-26 at 07:22:10ID: 12411173

You can find the properties of the text boxes by just using a for each loop on the Form.Controls collection until you find the control you want. Just create a seperate function to do that part.

Bob

 

by: Raven65Posted on 2004-10-26 at 11:22:51ID: 12414006

Bob,

Thanks for the quick response. Im starting to look at the information you gave there but in the mean time:

Since the app in question is external, can I use this Form.Controls to do this ? (I don't necessarily know the number of items, or their names on the form)

Can you post an example of this code ?

Thanks again for helping a rising coder,
chrisj

 

by: BobLambersonPosted on 2004-10-26 at 17:26:39ID: 12417153

Sorry - you are right, I was a little quick on the trigger there. Since it is a seperate app you would have to use the Win API, but you can work with the window handles and properties instead of having to get into the memory stuff.

I have some code that will probably help you but can't lay my hands on it right now. Will get back to you in a day or two if you haven't gotten your answer by then. Meanwhile take a look at

Declare Function EnumWindows Lib "user32.dll" ( _
     ByVal lpEnumFunc As Long, _
     ByVal lParam As Long) As Long
Declare Function EnumChildWindows Lib "user32.dll" ( _
     ByVal hWndParent As Long, _
     ByVal lpEnumFunc As Long, _
     ByVal lParam As Long) As Long

and the API info http://www.winhelp-world.com/winapi_3.htm
and especially the APIViewer at http://www.activevb.de/rubriken/apiviewer/index-apiviewereng.html  - it is a must.

Bob

 

by: Raven65Posted on 2004-10-27 at 05:21:57ID: 12420988

I will be looking at this in the mean time, but I would love to see that code if you can get ahold on it.

(Plus is would be a great addition to this thread anyway.)

Thanks for all your help Bob,

-chrisj

 

by: Raven65Posted on 2004-10-27 at 10:11:27ID: 12424477

Bob, just an update here. Made a lot of progress with those hints you gave and have been able to get some data off the page in App2 (external).

There are a few text boxes on the page, and those are what I want but cannot get (so far I have been able to get labels and button captions.

I have been able to find some help using  " FindWindowEx" to get what I think is the textboxes handle, and this would work for me I think, if I can use that handle, to get the content of the box.

Any help in this direction would be great,

Just to recap. New App1 needs to get data from inside textboxes in external App2 (no access to source, or any ability to change anything about App2)
Thanks a ton,
chrisj

 

by: BobLambersonPosted on 2004-10-27 at 21:23:41ID: 12430261

Chris,
Try the following;

In a new vbp add a couple of text boxes to a form, name it "Capture From" and compile the app. Run the exe.

In a second new app add a command button to the form and add this code to the click event of the button;
      Private Sub cmdCaptureId_Click()
         Dim lRet As Long
         Dim lParam As Long

         'enumerate the list
         lRet = EnumWindows(AddressOf EnumWinProc, lParam)
      End Sub

    Add a module to this second app and paste this code into it.
Option Explicit

      Declare Function EnumWindows Lib "user32" _
         (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long

      Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent _
         As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long

      Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _
         (ByVal hwnd As Long, ByVal lpClassName As String, _
         ByVal nMaxCount As Long) As Long

      Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" _
         (ByVal hwnd As Long, ByVal lpString As String, _
         ByVal cch As Long) As Long

     
     
    Public Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As Long) As Long
    Public Declare Function SetActiveWindow Lib "user32" (ByVal hwnd As Long) As Long
    Public f As Form
    Private y As Integer
    Private stextName As String
    Private sPatientID As String
Public Declare Function GetActiveWindow Lib "user32" () As Long
Public Declare Function GetForegroundWindow Lib "user32" () As Long
   
      Function EnumWinProc(ByVal lhWnd As Long, ByVal lParam As Long) _
         As Long
         Dim RetVal As Long, ProcessID As Long, ThreadID As Long
         Dim WinClassBuf As String * 255, WinTitleBuf As String * 255
         Dim WinClass As String, WinTitle As String
 
         RetVal = GetClassName(lhWnd, WinClassBuf, 255)
         WinClass = StripNulls(WinClassBuf)  ' remove extra Nulls & spaces
         RetVal = GetWindowText(lhWnd, WinTitleBuf, 255)
         WinTitle = StripNulls(WinTitleBuf)
         Debug.Print "Top level Class = "; WinClass; ", Title = "; WinTitle

         If WinClass = "ThunderRT6FormDC" And WinTitle = "Capture From" Then
            RetVal = EnumChildWindows(lhWnd, AddressOf EnumChildProc, lParam)
           
            EnumWinProc = False
         Else
            EnumWinProc = True
         End If
      End Function


'loop the forms control collection to find the control that has string patientidnumber in name and a caption property.
Function getID(f As Form)
Do While y < f.Controls.Count
    stextName = f.Controls(y).Name
   
    On Error Resume Next        'if not a label it will error on caption and skip it
    If InStr(1, stextName, "lblPatientIDNumber") > 0 Then   'if not the patient id it will skip it
        getID = f.Controls(y).Caption
        frmTestCallingCapture.txtCallingCapture.Text = f.Controls(y).Caption
        y = 0
        Exit Do
    End If
   y = y + 1
Loop
On Error GoTo 0
End Function
     
     
      Function EnumChildProc(ByVal lhWnd As Long, ByVal lParam As Long) _
         As Long
         Dim RetVal As Long
         Dim WinClassBuf As String * 255, WinTitleBuf As String * 255
         Dim WinClass As String, WinTitle As String

         RetVal = GetClassName(lhWnd, WinClassBuf, 255)
         WinClass = StripNulls(WinClassBuf)  ' remove extra Nulls & spaces
         RetVal = GetWindowText(lhWnd, WinTitleBuf, 255)
         WinTitle = StripNulls(WinTitleBuf)
         ' see the Windows Class and Title for each Child Window enumerated
         Debug.Print "   Child Class = "; WinClass; ", Title = "; WinTitle
         ' You can find any type of Window by searching for its WinClass
'         If WinTitle = "lblPatientIdCaption" Then
         If WinTitle = "txtPatientId" Then
              frmTestCallingCapture.txtCallingCapture.Text = WinTitle
            EnumChildProc = False
         Else
            EnumChildProc = True
         End If
      End Function
 

      Public Function StripNulls(OriginalStr As String) As String
         ' This removes the extra Nulls so String comparisons will work
         If (InStr(OriginalStr, Chr(0)) > 0) Then
            OriginalStr = Left(OriginalStr, InStr(OriginalStr, Chr(0)) - 1)
         End If
         StripNulls = OriginalStr
      End Function

This will enum through all the top level windows you have open until it finds the one you want to see the child windows for (controls on it). In ThunderRT6FormDC as the triggering class, but you could use anything. Debug.print lists all the top level windows, then the child windows for the selected class in the immediate window. By working through this you should be able to come up with the right combination of top level window and child window for your purposes.

Also remember that classes have different class names in compiled exe and in .vbp when run, for example;
    ThunderFormDC   is the class of a form in uncompiled .vbp
    ThunderRT6FormDC   is the same class of a form in compiled exe

Hope this is helpful. If you get stuck, post again and we can go from there.

Bob

 

by: Raven65Posted on 2004-10-28 at 05:56:42ID: 12433082

Bob,

Thanks for that code, Im working with it now but had a question after a few initial tests.

This works the way I think I will want it to in the developer, but when I try to compile it,
the line:

frmTestCallingCapture.txtCallingCapture.Text = f.Controls(y).Caption

Halts with frmTestCallingCapture highlighted and a variable not defined.

[The target app is not on the development machine, so I'm testing on other apps and this appears to work, but I cannot compile and find out due to this error. Im researching this item now, but thought I would ask and see if you had a quick hint.]

Thanks again for all your help,
I feel like you gotten me on the right track here,
chrisj

 

by: Raven65Posted on 2004-10-28 at 06:31:16ID: 12433456

Please ignore that last comment, I think I was trying to make that line be more complex than
it was. I just added another text box and named it with that name so I think I got that right. Sorry for the extra post, but as I said, Im still new to VB and I think I just misread that statement.

I have done some more research into my form and would like to try to lay the scinerio out for you:

The form is laid out like this:

Label1 TxtBox1
Label2 TxtBox2
Label3 TxtBox3

     Button1
     Button2


This is apparently NOT a true VB app, but a 'vb' app developed through a simplified designer our company uses (long story). I was able to do an EnumWindows and find the window and then I did an EnumChild on it and got the following out to a text file:



"Child Class = ","ThunderRT6FormDC",",Title = ","CHS Scanning Page",",Hwind = ",983584

'This appears to be the proper window for my targeting. The ThunderRT6 name makes me think I can do this even though like I said, the app is not 'really' straight from the vb developer.



"Child Class = ","AfxWnd40",",Title = ","Corporate number:",",Hwind = ",853224
"Child Class = ","AfxWnd40",",Title = ","Unit number:",",Hwind = ",1442864
"Child Class = ","AfxWnd40",",Title = ","Account number:",",Hwind = ",1377380

'These are Label1-3 I just mention. As you can see, I can retrieve their data in this manner.



"Child Class = ","ThunderRT6TextBox",",Title = ","",",Hwind = ",656682

'Then there are several more of these. But as you can see, the title returns blank...In the application these textboxes are 'locked' and cannot be edited, but there is data in them.


I can also get the buttons, and their captions.


I know this is hard to diagnose without being able to sit down @ it, but I really appreciate the help. If I can get any more/better information please let me know. (Screenshots ?)

Thank you again,
chrisj

 

by: BobLambersonPosted on 2004-10-28 at 07:03:14ID: 12433849

did you try adding the DC to the end of the ThunderRT6TextBox ?

Bob

 

by: Raven65Posted on 2004-10-28 at 07:17:40ID: 12434019

Im not sure I follow you here... Add the DC where ?

In the EnumAll app I wrote to crawl everything (using your hints) I just have it pull whatever is there and list it for me, the ones in the target app appear to be "ThunderRT6TextBox" as you can see in that file export.

The main form is comming across as a RT6FormDC, so that should be good by the code you posted just now, as that is what it looks for now.


One very interesting observation to go with what I said earlier about the fields being "locked" or something.

I wrote an additional "spy" program so that when I mouse over a given item, it gives me its hWnd and WinClass...

When I mouse over the labels, I get the appropriate address and the "AfxWnd40" but when I then move over the textboxes the return changes to the "RT6FormDC", as if Im pointing at any given blank spot on the form..almost like the boxes aren't there (?) though I can plainly see them...


chrisj

 

by: BobLambersonPosted on 2004-10-28 at 20:31:54ID: 12441057

What I was thinking was that the class name you would find would be ThunderRT6TextBoxDC, but it appears the the app you are working with has subclassed some of the vb classes and given them different names?
What is the "AfxWnd40" in the Child Class =.............  line? It appears that it's the class name.
Another thought is that your problem with the mousing over the control might be that the boxes you are looking at and thinking are text boxes are actually graphics like the labels are.


Bob

 

by: Raven65Posted on 2004-10-28 at 20:46:27ID: 12441160

I believe you are right that they have done something to rename the standard controls.

The AfxWnd40 appears to be what they call a label, as when I pull those, its the text
from the labels beside the text boxes I want...

Im not @ the application now, but thinking back, I believe you may be onto something
with saying those "textboxes" may really be graphics, because yes, as I mentioned mousing
over them dosen't get the identifier "textbox" in my spy application..

If that is the case, would there be a way to identify that graphic and gets its content ?

Thanks again for your dedicated help to my effort here,
chrisj

 

by: BobLambersonPosted on 2004-10-28 at 21:22:49ID: 12441278

That's what jkozee's code is doing in the first part of this thread by finding the memory area that holds the information. Maybe check that out and see if you can make that work with the controls you are trying to capture.

 

by: Raven65Posted on 2004-11-02 at 07:51:04ID: 12473855

Bob, that seems to be VERY close to what I need. I have been able to take jkozee's code and your suggestions and get several pieces of information off the target app, which makes me very excited that what I want, can be done.

So far, I have been able to capture lables, and buttons on that page, which is a start (as I do need that later) but I cannot seem to get the text boxes still. I developed a second fake app, and made several textboxes on it, some with Enabled set to False. This generated the same look as the locked boxes i mentioned, so I think perhaps they are text boxes, but I still cannot get them (and using the same code, I can get the locked ones on the fake app)

Do you have a list, or know where one exists, of the names of the VB Controls (i.e. Vb.Label, Vb.Textbox) ? I have been able to get those two, as mentioned, but wanted to try the others that exist and see if my target boxes are something I've just not tried (like a graphic you had mentioned) but I cannot find a list of these things..

Thanks again for all your help,
That list, or ANY other hints/ideas would be most welcomed (your help so far is the only reason Im able to get to the point to even ask this question, so..),

chrisj

 

by: BobLambersonPosted on 2004-11-02 at 17:57:49ID: 12479509

If you can get a copy of Dan Appleman's "Visual Basic Programmers Guide to the Win32 API" book, you will find the list you mention and a wealth of other info that is invaluable. This book is considered the final authority on the Win32 API by most. Here's a list of the classes from the cd that comes with the book.

Visual Basic Class Names

Control         Class Name                  Windows Base Class

Check           ThunderCheckBox         BUTTON
Combo           ThunderComboBox         COMBOBOX
Command       ThunderCommandButton    BUTTON
Dir                 ThunderDirListBox           LISTBOX
Drive               ThunderDriveListBox     COMBOBOX
File                ThunderFileListBox          LISTBOX
Form            ThunderForm                     —
Frame           ThunderFrame                    BUTTON
Label           ThunderLabel                     —
List                ThunderListBox                  LISTBOX
MDIForm    ThunderMDIForm                   —
Option          ThunderOptionButton          BUTTON
Picture         ThunderPictureBox            —
Scroll (Horiz)    ThunderHScrollBar         SCROLLBAR
Scroll (Vert)    ThunderVScrollBar          SCROLLBAR
Text                ThunderTextBox               EDIT
Timer               ThunderTimer                —
Note: Visual Basic class names shown above are for design time. At runtime VB class names have a prefix depending on the version of Visual Basic,  for example: ThunderCheckBox might become ThunderRTCheckBox at runtime. You can use the GetClassName API function described in chapter 5 to determine the class name for a window.

Bob

20120131-EE-VQP-002

3 Ways to Join

30-Day Free Trial

The Experts

98% positive feedback on 31,087 answers since March 2000. angeliii is a Microsoft Most Valuable Professional for his work with MS SQL Server & Develoment.

He has also proven his knowledge of Visual Basic Programming, PHP Scripting and Oracle Databases.

The Experts

97% positive feedback on 10,752 answers since July 2000. lrmoore has more than 18 years experience in the networking industry.

The six-time Mircosoft MVPs specialties include firewalls, virtual private networking, and network management.

Testimonials

"...and excellent source for support... Kind of like having your very own IT dept." Electriciansnet

Testimonials

"I was apprehensive at signing up at first. However... it has already made my life as an IT administrator much easier." JaCrews

Testimonials

"WOW! You guys have great, active, and knowledgeable people on here." moore50

Business Clients

Business Clients

In the Press

"If you’ve got a question... Experts Exchange can supply an answer.”

In the Press

"...an invaluable aid for both IT professionals and those who require tech support."

In the Press

"where IT professionals provide quick answers on just about any topic"

Business Account Plans

Loading Advertisement...