velcrow
asked on
SendMessage WM_GETTEXT will not get the text of the 'File name:' edit box on the 'save as' dialog box
In VBA I'm using the SendMessage function of the user32.dll windows API with the WM_GETTEXT parameter as follows to retrieve the text from the 'File name' edit box on the windows 'Save As' dialog box. I can successfully post a file name to the box and get the length of the text in the box, but I cannot for the life of me figure out why I can't get the text.
comboBox32win = FindWindowEx(SaveAsDialog, 0, "ComboBoxEx32", vbNullString)
ComboBoxwin = FindWindowEx(comboBox32win , 0, "ComboBox", vbNullString)
EditBox = FindWindowEx(ComboBoxwin, 0, "Edit", vbNullString)
txtlen = SendMessage(EditBox, WM_GETTEXTLENGTH, vbNullString, vbNullString)
txtlen = txtlen + 1
txt = Space$(txtlen)
retval = SendMessage(EditBox, WM_GETTEXT, txtlen, ByVal txt)
comboBox32win = FindWindowEx(SaveAsDialog,
ComboBoxwin = FindWindowEx(comboBox32win
EditBox = FindWindowEx(ComboBoxwin, 0, "Edit", vbNullString)
txtlen = SendMessage(EditBox, WM_GETTEXTLENGTH, vbNullString, vbNullString)
txtlen = txtlen + 1
txt = Space$(txtlen)
retval = SendMessage(EditBox, WM_GETTEXT, txtlen, ByVal txt)
ASKER
I had already tried that, and it does not work. Here is my declaration:
Public Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
(ByVal hwnd As Long, ByVal Msg As Long, wParam As Any, ByVal lParam As String) As Long
Public Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
(ByVal hwnd As Long, ByVal Msg As Long, wParam As Any, ByVal lParam As String) As Long
ASKER
The purpose for wanting the read the ‘File name’ text box is because I’m sending the file name to that text box using SendMessage(EditBox, WM_SETTEXT, vbNullString, fileName), but for some reason the ‘save as’ dialog box is found using FindWindow("#32770", "Save As") before it as actually finished loading and so when I send the file name it succeeds but it hasn’t really posted the file name to the dialog box and so I’ve created a loop to continue sending the file name until it has actually been posted. So, if you know of another way to delay after finding the ‘Save as’ dialog until it has actually finished loading then that would work as well.
ASKER
Here is the code for the loop I've described above:
Do
retval = SendMessage(EditBox, WM_SETTEXT, vbNullString, fileName)
DoEvents
txtlen = SendMessage(EditBox, WM_GETTEXTLENGTH, vbNullString, vbNullString)
txtlen = txtlen + 1
txt = Space$(txtlen)
Call SendMessage(EditBox, WM_GETTEXT, txtlen, txt)
Loop While txt <> fileName
Do
retval = SendMessage(EditBox, WM_SETTEXT, vbNullString, fileName)
DoEvents
txtlen = SendMessage(EditBox, WM_GETTEXTLENGTH, vbNullString, vbNullString)
txtlen = txtlen + 1
txt = Space$(txtlen)
Call SendMessage(EditBox, WM_GETTEXT, txtlen, txt)
Loop While txt <> fileName
*Shot in the dark*
Try using PostMessage() instead of SendMessage().
Try using PostMessage() instead of SendMessage().
ASKER
tried that too
ASKER
just for clarification, the 'save as' dialog in this case is the one that appears when downloading a file from a website using internet explorer.
Is the actual edit field getting updated with your desired value? (...and it's just not getting returned back?)
ASKER
that is correct.
Ohhh...I remember a similar issue cropped up when I was helping another expert awhile back.
We ended up sending the desired filename char by char with PostMessage() and then following it up with the Enter key to make it "update" itself.
This is VB.Net code so it'll need tweaking for VB6:
For Each c As Char In TargetFileName
PostMessage(EditHandle, WM_CHAR, Microsoft.VisualBasic.AscW (c), IntPtr.Zero)
Next
PostMessage(EditHandle, WM_KEYDOWN, Keys.Enter, &H0)
The PAQ it came from: https://www.experts-exchange.com/questions/24693216/Urgent-FindWindow-issue-can't-find-the-handle-of-the-2nd-popup-that-is-triggered-from-1st.html#25223150
(read point #1 in my post at the very top too)
We ended up sending the desired filename char by char with PostMessage() and then following it up with the Enter key to make it "update" itself.
This is VB.Net code so it'll need tweaking for VB6:
For Each c As Char In TargetFileName
PostMessage(EditHandle, WM_CHAR, Microsoft.VisualBasic.AscW
Next
PostMessage(EditHandle, WM_KEYDOWN, Keys.Enter, &H0)
The PAQ it came from: https://www.experts-exchange.com/questions/24693216/Urgent-FindWindow-issue-can't-find-the-handle-of-the-2nd-popup-that-is-triggered-from-1st.html#25223150
(read point #1 in my post at the very top too)
ASKER
Back to my earlier post; if you know how to determine when the dialog box has finished loading and its controls can be accessed, that would work too. One would think that once the SaveAsDialog = FindWindow("#32770", "Save As") had received a handle it would be save to send file name and click save, but that is not the case.
ASKER
I'm not having a problem posting to the edit box, I'm having a problem reading it.
The standard windows dialog should have the same control ID for the edit box so it would be easier to just get the dialog handle and then use the dialog ID in your case the edit control. The control ID is 0000047C
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
I understand...it ~LOOKS~ like your posting to it but the value being read back is different because the control is actually a ComboBox control. You have to hit the Enter key to make it update itself...
ASKER
eql1044,
Fantastic, your code worked. Any idea why SendDlgItemMessageW works and SendMessage to the specific control does not?
Fantastic, your code worked. Any idea why SendDlgItemMessageW works and SendMessage to the specific control does not?
I didn't look to much into your code but it's probrably just a minor issue of declerations but I wouldn't know unless we had your full code to test all your declerations and variables when posting helps solves these kinds of issues. I just tossed out a better approach for finding the control ID.
Can you post your full code with declerations maybe we can find out what the problem had been?
Can you post your full code with declerations maybe we can find out what the problem had been?
ASKER
here is my declaration for SendMessage
ASKER
ooops, forgot the code
Public Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
(ByVal hwnd As Long, ByVal Msg As Long, wParam As Any, ByVal lParam As String) As Long
Public Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
(ByVal hwnd As Long, ByVal Msg As Long, wParam As Any, ByVal lParam As String) As Long
I know I seen that one but everything like your constants and FindWindow() + variable :)
ASKER
Dim hwndDialog As Long ' handle to the dialog box
Dim hwndButton As Long ' handle to the button
Dim retval As Long ' return value
SaveAsDialog = FindWindow("#32770", "Save As")
comboBox32win = FindWindowEx(SaveAsDialog, 0, "ComboBoxEx32", vbNullString)
ComboBoxwin = FindWindowEx(comboBox32win , 0, "ComboBox", vbNullString)
EditBox = FindWindowEx(ComboBoxwin, 0, "Edit", vbNullString)
retval = SendMessage(comboBox32win, WM_SETTEXT, vbNullString, "fileName")
txtlen = SendMessage(EditBox, WM_GETTEXTLENGTH, vbNullString, vbNullString)
txtlen = txtlen + 1
' txt = Space$(txtlen)
Call SendMessageGETTEXT(EditBox , WM_GETTEXT, 260, txt)
Dim hwndButton As Long ' handle to the button
Dim retval As Long ' return value
SaveAsDialog = FindWindow("#32770", "Save As")
comboBox32win = FindWindowEx(SaveAsDialog,
ComboBoxwin = FindWindowEx(comboBox32win
EditBox = FindWindowEx(ComboBoxwin, 0, "Edit", vbNullString)
retval = SendMessage(comboBox32win,
txtlen = SendMessage(EditBox, WM_GETTEXTLENGTH, vbNullString, vbNullString)
txtlen = txtlen + 1
' txt = Space$(txtlen)
Call SendMessageGETTEXT(EditBox
ASKER
the last line of the code I just should have been
Call SendMessage(EditBox, WM_GETTEXT, 260, txt)
the SendMessageGETTEXT was just another test i was trying
here are my constants and other declarations, but I don't think there is a problem here because everything else worked fine
Public Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
(ByVal hwnd As Long, ByVal Msg As Long, wParam As Any, ByVal lParam As String) As Long
Public Declare Function SendMessageGETTEXT Lib "user32.dll" Alias "SendMessageA" _
(ByVal hwnd As Long, ByVal Msg As Long, wParam As Any, ByVal lParam As Long) As Long
Public Declare Function SetActiveWindow Lib "user32.dll" (ByVal hwnd As Long) As Long
Public Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal _
lpClassName As Any, ByVal lpWindowName As Any) As Long
Public Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal _
hwndParent As Long, ByVal hwndChildAfter As Long, ByVal lpszClass As Any, _
ByVal lpszWindow As Any) As Long
Public Declare Function GetActiveWindow Lib "user32" () As Long
Public Declare Function GetWindowLong Lib "user32.dll" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Public Declare Function GetWindowInfo Lib "user32.dll" Alias "GetWindowInfoA" (ByVal hwnd, ByVal PWINDOWINFO)
Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Public Declare Function WaitForSingleObject Lib "Kernel32.dll" (ByVal hProcess As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function SendDlgItemMessageW Lib "user32" (ByVal hDlg As Long, ByVal nIDDlgItem As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Const GWL_ID As Long = -12
Public Const WM_GETTEXTLENGTH = &HE
Public Const CB_INSERTSTRING = &H14A
Public Const WM_GETTEXT = &HD
Private Const WM_SETTEXT = &HC
Public Const BM_CLICK = &HF5
Private Const BM_SETSTATE = &HF3
Private Const WM_LBUTTONDOWN = &H201
Private Const WM_LBUTTONUP = &H202
Private Const GW_HWNDFIRST = 0
Private Const GW_HWNDNEXT = 2
Call SendMessage(EditBox, WM_GETTEXT, 260, txt)
the SendMessageGETTEXT was just another test i was trying
here are my constants and other declarations, but I don't think there is a problem here because everything else worked fine
Public Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
(ByVal hwnd As Long, ByVal Msg As Long, wParam As Any, ByVal lParam As String) As Long
Public Declare Function SendMessageGETTEXT Lib "user32.dll" Alias "SendMessageA" _
(ByVal hwnd As Long, ByVal Msg As Long, wParam As Any, ByVal lParam As Long) As Long
Public Declare Function SetActiveWindow Lib "user32.dll" (ByVal hwnd As Long) As Long
Public Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal _
lpClassName As Any, ByVal lpWindowName As Any) As Long
Public Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal _
hwndParent As Long, ByVal hwndChildAfter As Long, ByVal lpszClass As Any, _
ByVal lpszWindow As Any) As Long
Public Declare Function GetActiveWindow Lib "user32" () As Long
Public Declare Function GetWindowLong Lib "user32.dll" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Public Declare Function GetWindowInfo Lib "user32.dll" Alias "GetWindowInfoA" (ByVal hwnd, ByVal PWINDOWINFO)
Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Public Declare Function WaitForSingleObject Lib "Kernel32.dll" (ByVal hProcess As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function SendDlgItemMessageW Lib "user32" (ByVal hDlg As Long, ByVal nIDDlgItem As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Const GWL_ID As Long = -12
Public Const WM_GETTEXTLENGTH = &HE
Public Const CB_INSERTSTRING = &H14A
Public Const WM_GETTEXT = &HD
Private Const WM_SETTEXT = &HC
Public Const BM_CLICK = &HF5
Private Const BM_SETSTATE = &HF3
Private Const WM_LBUTTONDOWN = &H201
Private Const WM_LBUTTONUP = &H202
Private Const GW_HWNDFIRST = 0
Private Const GW_HWNDNEXT = 2
Okay thats a start and it looks like your issue is SendMessage() decleration which I suspected already but had to see other parts. You passing wParam as Any but you need to pass it Byval your problem is the defined buffer size was always zero so no data is returned.
ASKER
egl1044,
I'm going to accept your solution and award points because it did accomplish what I was trying to do (read the text box), but I've just discovered that what I was trying to do will still not solve my problem... so, I'm hoping you can help me with that as well.
I'm going to accept your solution and award points because it did accomplish what I was trying to do (read the text box), but I've just discovered that what I was trying to do will still not solve my problem... so, I'm hoping you can help me with that as well.
Sure but only if you give Idle_Mind some points. Share the wealth :)D
Haha...no worries bud. Lots of fish in the sea... =)
ASKER
I changed to Byval, but I still get nothing.
velcrow,
In your code you posted you had the buffer marked as a comment only thing I did was uncommect txt = Space$(txtlen) and change the call : Call SendMessage(EditBox, WM_GETTEXT, ByVal 260, txt)
In your code you posted you had the buffer marked as a comment only thing I did was uncommect txt = Space$(txtlen) and change the call : Call SendMessage(EditBox, WM_GETTEXT, ByVal 260, txt)
ASKER
Idle_Mind:
I'm new at this. I intended on assigning you some ponts but I guess I screwed it up.
eql1044:
Call SendMessage(EditBox, WM_GETTEXT, ByVal 260, txt) working for you? it does not work for me.
I'm new at this. I intended on assigning you some ponts but I guess I screwed it up.
eql1044:
Call SendMessage(EditBox, WM_GETTEXT, ByVal 260, txt) working for you? it does not work for me.
Yup working for me I had to declare some missing variables but this is what I just copied into VB. BTW make sure that the title is correct
Option Explicit
Public Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
(ByVal hwnd As Long, ByVal Msg As Long, wParam As Any, ByVal lParam As String) As Long
Public Declare Function SendMessageGETTEXT Lib "user32.dll" Alias "SendMessageA" _
(ByVal hwnd As Long, ByVal Msg As Long, wParam As Any, ByVal lParam As Long) As Long
Public Declare Function SetActiveWindow Lib "user32.dll" (ByVal hwnd As Long) As Long
Public Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal _
lpClassName As Any, ByVal lpWindowName As Any) As Long
Public Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal _
hwndParent As Long, ByVal hwndChildAfter As Long, ByVal lpszClass As Any, _
ByVal lpszWindow As Any) As Long
Public Declare Function GetActiveWindow Lib "user32" () As Long
Public Declare Function GetWindowLong Lib "user32.dll" Alias "GetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Public Declare Function GetWindowInfo Lib "user32.dll" Alias "GetWindowInfoA" (ByVal hwnd, ByVal PWINDOWINFO)
Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Public Declare Function WaitForSingleObject Lib "Kernel32.dll" (ByVal hProcess As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function SendDlgItemMessageW Lib "user32" (ByVal hDlg As Long, ByVal nIDDlgItem As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Const GWL_ID As Long = -12
Public Const WM_GETTEXTLENGTH = &HE
Public Const CB_INSERTSTRING = &H14A
Public Const WM_GETTEXT = &HD
Private Const WM_SETTEXT = &HC
Public Const BM_CLICK = &HF5
Private Const BM_SETSTATE = &HF3
Private Const WM_LBUTTONDOWN = &H201
Private Const WM_LBUTTONUP = &H202
Private Const GW_HWNDFIRST = 0
Private Const GW_HWNDNEXT = 2
Public Sub Test()
Dim hwndDialog As Long ' handle to the dialog box
Dim hwndButton As Long ' handle to the button
Dim retval As Long ' return value
' Added this stuff...
Dim SaveAsDialog As Long
Dim comboBox32win As Long
Dim ComboBoxwin As Long
Dim txtlen As Long
Dim txt As String
Dim EditBox As Long
SaveAsDialog = FindWindow("#32770", "Save As")
comboBox32win = FindWindowEx(SaveAsDialog, 0, "ComboBoxEx32", vbNullString)
ComboBoxwin = FindWindowEx(comboBox32win, 0, "ComboBox", vbNullString)
EditBox = FindWindowEx(ComboBoxwin, 0, "Edit", vbNullString)
Debug.Print EditBox
retval = SendMessage(comboBox32win, WM_SETTEXT, vbNullString, "eeName")
txtlen = SendMessage(EditBox, WM_GETTEXTLENGTH, vbNullString, vbNullString)
Debug.Print txtlen
txtlen = txtlen + 1
txt = Space$(txtlen)
Call SendMessage(EditBox, WM_GETTEXT, ByVal 260, txt)
Debug.Print txt
End Sub
ASKER
Ok, the problem was I had not declared the txt as String, because I though VBA was automatically changing it to a string upon assigning the value Space$(txtlen). I should stop being a lazy programmer. : )
Anyway, I was able to successfully get the text box value by both methods, but now back to the original problem. If I post another question will you be available to help me with that?
Anyway, I was able to successfully get the text box value by both methods, but now back to the original problem. If I post another question will you be available to help me with that?
ASKER
egl1044:
The original problem was that the calls I was making to the ‘save as’ dialog box were occurring immediately after getting the handle to the dialog, box through SaveAsDialog = FindWindow("#32770", "Save As") but apparently before it had completely load. Such that when it does appear on the screen it did not have the filename I sent and upon clicking save by retval = SendMessage(hwndButton, BM_CLICK, ByVal CLng(0), ByVal CLng(0)) it crashes and closes the browser that opened it.
Therefore, I was attempting to loop until the return value equaled the filename being sent; but, just as the filename was being accepted before the dialog had finished loading, so to does the return value come back as the filename that was sent and when the dialog does appear it still has the default filename.
The original problem was that the calls I was making to the ‘save as’ dialog box were occurring immediately after getting the handle to the dialog, box through SaveAsDialog = FindWindow("#32770", "Save As") but apparently before it had completely load. Such that when it does appear on the screen it did not have the filename I sent and upon clicking save by retval = SendMessage(hwndButton, BM_CLICK, ByVal CLng(0), ByVal CLng(0)) it crashes and closes the browser that opened it.
Therefore, I was attempting to loop until the return value equaled the filename being sent; but, just as the filename was being accepted before the dialog had finished loading, so to does the return value come back as the filename that was sent and when the dialog does appear it still has the default filename.
retval = SendMessage(EditBox, WM_GETTEXT, txtlen, ByVal txt)
So it's:
retval = SendMessage(EditBox, WM_GETTEXT, txtlen, txt)
Can we see your declaration for SendMessage()?