423,688 Members | 1,889 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 423,688 IT Pros & Developers. It's quick & easy.

VBA Get text from "Edit" Control in Application outside of MA

P: 7
I have usually been able to research what I need to do, especially with a lot of help from this website. Unfortunately I am drawing a blank on how to retrieve the value in an "Edit" control in an application outside of Access. I have been able to do a few versions that even go through every open window and get all the child windows but am only able to return that text in a label.

I located another script that did the same thing but it too doesn't return the values for all "Edit" controls. I have tried various SendMessage functions with no luck. Can anyone please show me the missing piece to make it all work? Here is the code of someones script that shows the same issue I am having. Any help would be greatly appreciated.


Expand|Select|Wrap|Line Numbers
  1. Option Explicit
  2.  
  3. Private Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
  4. (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
  5. Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" _
  6. (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
  7. Private Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" _
  8. (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
  9. Public Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" _
  10.  (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _
  11.  lParam As Any) As Long
  12.  
  13.  
  14. Private Const WM_GETTEXT              As Long = &HD
  15. Private Const WM_GETTEXTLENGTH As Long = &HE&
  16. Private X As Integer
  17.  
  18.  
  19.  'Used a user defined type here rather than Enum so that it works on 97
  20. Private Type winEnum
  21.     winHandle As Integer
  22.     winClass As Integer
  23.     winTitle As Integer
  24.     winHandleClass As Integer
  25.     winHandleTitle As Integer
  26.     winHandleClassTitle As Integer
  27. End Type
  28. Dim winOutputType As winEnum
  29.  
  30. Public Sub GetWindows()
  31.     X = 0
  32.     winOutputType.winHandle = 0
  33.     winOutputType.winClass = 1
  34.     winOutputType.winTitle = 2
  35.     winOutputType.winHandleClass = 3
  36.     winOutputType.winHandleTitle = 4
  37.     winOutputType.winHandleClassTitle = 5
  38.  
  39.     GetWinInfo 0&, 0, winOutputType.winHandleClassTitle
  40. End Sub
  41.  
  42.  
  43. Private Sub GetWinInfo(hParent As Long, intOffset As Integer, OutputType As Integer)
  44.      'Sub to recursively obtain window handles, classes and text
  45.      'given a parent window to search
  46.      'Written by Mark Rowlinson
  47.      'www.markrowlinson.co.uk - The Programming Emporium
  48.     Dim hwnd As Long, lngRet As Long, y As Integer
  49.     Dim strText As String
  50.     Dim L As Long
  51.     hwnd = FindWindowEx(hParent, 0&, vbNullString, vbNullString)
  52.     While hwnd <> 0
  53.         Select Case OutputType
  54.         Case winOutputType.winClass
  55.             strText = String$(100, Chr$(0))
  56.             lngRet = GetClassName(hwnd, strText, 100)
  57.             Range("a1").Offset(X, intOffset) = Left$(strText, lngRet)
  58.         Case winOutputType.winHandle
  59.             Range("a1").Offset(X, intOffset) = hwnd
  60.         Case winOutputType.winTitle
  61.             strText = String$(100, Chr$(0))
  62.             lngRet = GetWindowText(hwnd, strText, 100)
  63.             If lngRet > 0 Then
  64.                 Range("a1").Offset(X, intOffset) = Left$(strText, lngRet)
  65.             Else
  66.                 Range("a1").Offset(X, intOffset) = "N/A"
  67.             End If
  68.         Case winOutputType.winHandleClass
  69.             Range("a1").Offset(X, intOffset) = hwnd
  70.             strText = String$(100, Chr$(0))
  71.             lngRet = GetClassName(hwnd, strText, 100)
  72.             Range("a1").Offset(X, intOffset + 1) = "Left$(strText, lngRet)"
  73.         Case winOutputType.winHandleTitle
  74.             Range("a1").Offset(X, intOffset) = hwnd
  75.             strText = String$(100, Chr$(0))
  76.             lngRet = GetWindowText(hwnd, strText, 100)
  77.             If lngRet > 0 Then
  78.                 Range("a1").Offset(X, intOffset + 1) = "D " & Left$(strText, lngRet)
  79.             Else
  80.                 Range("a1").Offset(X, intOffset + 1) = "N/A"
  81.             End If
  82.         Case winOutputType.winHandleClassTitle
  83.             Range("a1").Offset(X, intOffset) = hwnd
  84.             strText = String$(100, Chr$(0))
  85.             lngRet = GetClassName(hwnd, strText, 100)
  86.  
  87.             Range("a1").Offset(X, intOffset + 1) = Left$(strText, lngRet)
  88.             strText = String$(100, Chr$(0))
  89.             lngRet = GetWindowText(hwnd, strText, 100)
  90.             If lngRet > 0 Then
  91.                 Range("a1").Offset(X, intOffset + 2) = Left$(strText, lngRet)
  92.                 '& SendMessage(hwnd, WM_GETTEXT, 100, hParent)
  93.             Else
  94.                 Range("a1").Offset(X, intOffset + 2) = "N/A"
  95.  
  96.  
  97.             End If
  98.         End Select
  99.          'check for children
  100.         y = X
  101.         Select Case OutputType
  102.         Case Is > 4
  103.             GetWinInfo hwnd, intOffset + 3, OutputType
  104.         Case Is > 2
  105.             GetWinInfo hwnd, intOffset + 2, OutputType
  106.         Case Else
  107.             GetWinInfo hwnd, intOffset + 1, OutputType
  108.         End Select
  109.          'increment by 1 row if no children found
  110.         If y = X Then
  111.             X = X + 1
  112.         End If
  113.          'now get next window
  114.         hwnd = FindWindowEx(hParent, hwnd, vbNullString, vbNullString)
  115.     Wend
  116.  
  117. End Sub
2 Weeks Ago #1
Share this Question
Share on Google+
11 Replies


P: 7
Well, I am not off to a good start. I copied the version from Excel not Access but it does the same thing. Sorry about that. I can resubmit if this will cause confusion.
2 Weeks Ago #2

twinnyfo
Expert Mod 2.5K+
P: 2,667
DesktopFlyer,

Welcome to Bytes!

It seems like your code is doing a lot of searching for something when it "seems" that you already know what you are looking for. But, I may not completely understand exactly what you are trying to do.

If you know the application that you are trying to target, then, you should be able to go directly to it:

Expand|Select|Wrap|Line Numbers
  1. Call AppActivate(Title:="Document1 - Word", _
  2.                  Wait:=False)
The example above would activate the Word application, but if you had multiple instances of Word open, just the one with Document1 open in it.

Then, there are some ways to navigate another application from within MS Access--none are terribly reliable--but they do work.

I think I would need more information to work anything further on this.

Hope this hepps!
2 Weeks Ago #3

P: 7
Thank you for the welcome and the feedback, I'm usually too stubborn to ask for help but this one has killed several days now. I am able to have it go to the one application that I need the data from but this way it scrolls through every open window and all of their child windows/controls. I am able to see all the controls but its the "Edit" controls text or value that I cannot retrieve.

Once I get the script to return the text I will then store it in a table.
2 Weeks Ago #4

twinnyfo
Expert Mod 2.5K+
P: 2,667
So far, I've understood that much. Again, if you know which app you are going to, just go to the app. No need to scroll through "everything" to find "one thing" if you already know what it is you are looking for.

Perhaps you can provide more specifics....

Just tell us the application you are looking at and tell us what the "Edit" control is that you are looking for. Speaking in abstracts when trying to provide specific solutions can be time-consuming and not very productive.
2 Weeks Ago #5

P: 7
I was worried that I wasn't going through all the controls so I went overboard and went through everything. Wasn't trying to be vague, simply didn't think it was a well known program. My bad (again).

The application is Q-Pulse. Attached is a screen shot of one of the windows. I would need to get the text in each of the fields. Also if a radio button or checkbox is used. Fairly simple the name field is simply named txtName, the Account Manager combobox is cbxAcMa. Hope that helps.

Attached Images
File Type: jpg QP3.jpg (119.8 KB, 170 views)
2 Weeks Ago #6

twinnyfo
Expert Mod 2.5K+
P: 2,667
So, the only way I know of to work through this is to simulate executing keystrokes in the system (using keybd_event from the user32.dll).

The number one challenge that you will come across is that this method does not (and can not) return the value of a check box. This is because even though a check box returns a value within its own system, the check box as a control has no value, only a "state". So, if you were to simulate navigating to a text box, the "value" that you can add to your clipboard is whatever is in that text box--it is a value that can be copied pasted, changed, etc. The check box simply has a state. Simulating a movement to the check box, there is no data to receive. Simulating a press of the space bar will only change the state of the check box, but not generate any data on its current state.

This also assumes that each of the requisite fields has a specific tab order and that navigation can occur.

I hope this makes sense.

Now, if, based upon some of your previous code (that no one here will be able to test or reproduce--because you have an application that is foreign to probably every other user here), you are able to go directly to the application and identify the names of controls, you may be able to glean the values of those controls. But, that is a guess. I have no idea how to go beyond that. It is very difficult to accurately and reliably automate running in this fashion.

This is quite outside of specific areas of expertise, although I have dabbled in it enough to know this will be a challenge.

Is there a particular reason that you must access the data this way, rather than some form of export? It is a highly irregular means of getting data into a db.
2 Weeks Ago #7

P: 7
Glad to know its a bit of a challenge and that I wasn't simply overlooking something. The gui almost looks like it was generated out of Filemaker.

Thanks again for your time and assistance. To start off with I'll try getting the text box information. If I am successful there I will go after the really fun items.
2 Weeks Ago #8

P: 7
As far as doing a simple export, the data changes hourly and the backend is behind a firewall that cannot be accessed. I need to consolidate the data from here with other applications. An export to Excel causes even more complications as the format produced is not user friend to bring into a db.
2 Weeks Ago #9

twinnyfo
Expert Mod 2.5K+
P: 2,667
Non-user friendly data is better than the method you describe. As long as the export is "consistently" non-user friendly, you can work with that. Just link to the spreadsheet and it's unfriendly data, then, as you inport it, manipulate it so that it is more friendly.

It will put a smile on everyone's face!

:-)
2 Weeks Ago #10

P: 7
I was hoping to then control the app from Access to make my life easier. One can dream.
2 Weeks Ago #11

twinnyfo
Expert Mod 2.5K+
P: 2,667
Trust me.... I am a data guy and an automation guy, but I'll take data over automation every time. Data usually doesn't kick back!

:-P
2 Weeks Ago #12

Post your reply

Sign in to post your reply or Sign up for a free account.