Windows Hwnd Handle Choose File - vb.net

I have a web app that successfully gets to a page and clicks an "Upload File" button.
My app also successfully handles pop-up windows by monitoring and hooking them. For the most part, it's just to click "OK" or "Cancel" buttons. Buttons are easy.
What I need help with is the Choose-File dialog. I'm hooking it fine, but there are a lot of controls on it and I need some direction.
These are the child controls on it:
DUIViewWndClassName,DirectUIHWND,CtrlNotifySink,NamespaceTreeControl,Static,SysTreeView32,CtrlNotifySink,Shell Preview Extension Host,CtrlNotifySink,SHELLDLL_DefView,DirectUIHWND,CtrlNotifySink,ScrollBar,CtrlNotifySink,ScrollBar,Static,Static,Static,ListBox,Static,Static,ComboBoxEx32,ComboBox,Edit,Static,ComboBox,Button,Button,Button,ScrollBar,WorkerW,ReBarWindow32,TravelBand,ToolbarWindow32,Address Band Root,msctls_progress32,Breadcrumb Parent,ToolbarWindow32,ToolbarWindow32,UniversalSearchBand,Search Box,SearchEditBoxWrapperClass,DirectUIHWND
I would be happy with sticking an exact path/file into the File-Name textbox/combobox and clicking "Open". The button part is easy, but I don't know either how to select files in the window, and/or how to put my path into the File-Name entry field.
Right now I have something like this:
<DllImport("user32.dll")> _
Private Shared Function GetClassName(ByVal hWnd As IntPtr, ByVal lpClassName As StringBuilder, ByVal nMaxCount As Int32) As Int32
End Function
<DllImport("user32.dll")> _
Private Shared Function GetWindowText(ByVal hWnd As IntPtr, ByVal text As StringBuilder, ByVal maxLength As Int32) As Int32
End Function
<DllImport("user32.dll")> _
Private Shared Function GetDlgCtrlID(ByVal hwndCtl As IntPtr) As Integer
End Function
....
Private Shared Function hwndHandler() As Int32
Dim ptrButtonhwnd As IntPtr
For Each pChild As IntPtr In Interop.ChildWindows(pPopup.hwnd)
Dim sbControl As New StringBuilder(255)
GetClassName(pChild, sbControl, sbControl.Capacity)
If "Button".Equals(sbControl.ToString()) Then
Dim sbText As New StringBuilder(255)
GetWindowText(pChildOfDialog, sbText, sbText.Capacity)
If "&Open".Equals(sbText.ToString()) Then
ptrButtonHwnd = pChild
End If
End If
Next
If ptrButtonHwnd <> IntPtr.Zero Then
Dim ctrlId As Int32 = GetDlgCtrlID(ptrButtonHwnd)
SendMessage(pPopup.hwnd, WM_COMMAND, New IntPtr(ctrlId), ptrButtonHwnd)
Return 1
End If
Return 0
End Function
This works fine, but I need to add something to select a file to open either by inputting it into the text/combo field, or by selecting it in the window.

I found the answer was to look for a control with the text of "Edit", which was one of the controls listed in my original list.
So according to my code posted above, I made a new pointer ptrEdit, and assigned it the control where "Edit".Equals(sbControl.ToString()).
Then to manipulate it, I used one of the DLLs:
If ptrEdit <> IntPtr.Zero Then
SetWindowText(pEditHwnd, strFilePath)
If ptrButtonHwnd <> IntPtr.Zero Then
Dim ctrlId As Int32 = GetDlgCtrlID(ptrButtonHwnd)
SendMessage(cwp.hwnd, WM_COMMAND, New IntPtr(ctrlId), ptrButtonHwnd)
Return 1
End If
End If
And so I was able to control the "Choose File To Upload" Dialog Box.

Related

In Visual Basic, how can I force a newline in a textbox after wordwrap?

In Visual Basic, when typing in a multilines textbox (WordWrap = true) and when reaching the end of the (width) textbox, it automatically forces a new line. However, it looks like it did add (vbNewLine). But that's not the case.
How do I force vbNewLine when wordwrap have been reached? In a simple why.
Since you mentioned setting the WordWrap property I will assume that you are using the Windows Forms TextBox control. This control is a wrapper around the native EDIT control. The native control supports soft-line breaks that are inserted as two carriage returns and a line feed when the text wraps.
This feature can be enabled by sending the control the EM_FMTLINES message.
Const EM_FMTLINES As Int32 = &HC8
Const softLineBreak As String = ChrW(13) & ChrW(13) & ChrW(10)
<DllImport("user32.dll", CharSet:=CharSet.Auto)>
Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As Boolean, ByVal lParam As IntPtr) As IntPtr
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
SendMessage(TextBox1.Handle, EM_FMTLINES, True, IntPtr.Zero)
End Sub
You could just replace the soft-line break character sequence with Environment.Newline to convert them to hard-line breaks.
Dim textWithHardBreaks As String = TextBox1.Text.Replace(softLineBreak, Environment.NewLine)

Capture Text from CMD Window That Is Already Running (VB.NET)

There is an application that runs pretty much 24/7 on this computer. It is run inside a command prompt Window. I would like to be able to capture all of the text currently displayed in the window.
The application is already running (and for unrelated reasons, can't be launched from within VB), so I can't just redirect the output of the process to save the text.
My current method for capturing the text is with the following code:
SendKeys.SendWait("^(a)")
SendKeys.SendWait("^(a)")
SendKeys.SendWait("{enter}")
Dim CmdText As String = Clipboard.GetText
Clipboard.Clear()
The above code sends a select all command to the window (it sends it twice, otherwise the entire windows text isn't captured). It then hits the enter key to load it into the clipboard. I then save the clipboard contents to a variable. It works well, but the major problem is that it requires the window to be in focus.
Is there anyway to capture the text from the CMD window if it is currently out of focus?
Edit: I think I'm getting close to finding a workaround using sendmessage/postmessage. Here is the current code:
Private Declare Function PostMessage Lib "user32.dll" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long
Private Const WM_CHAR As Long = &H102
Private Const VK_CONTROL = &H11
Private Const VK_RETURN = &HD
Public Function GetWindowHandle(ByVal processName As String) As IntPtr
processName = System.IO.Path.GetFileNameWithoutExtension(processName)
Dim p() = Process.GetProcessesByName(processName)
Return If(p.Length > 0, p(0).MainWindowHandle, IntPtr.Zero)
End Function
Private Sub GetText()
Dim h As Long = GetWindowHandle("programname.exe")
SendMessage(h, WM_CHAR, 1, 0) 'suppose to simulate Ctrl + A
SendMessage(h, WM_CHAR, 1, 0) 'suppose to simulate Ctrl + A
PostMessage(h, WM_KEYDOWN, VK_RETURN, 0) 'sends enter key to load text into clipboard
End Sub
The problem is that instead of sending Ctrl + A to the command window, it just sends the text ^A. Any ideas?
I've written a library called InputHelper which could come in handy here. It includes different methods of performing input simulation, one being sending it to a specific window.
Download from GitHub:
https://github.com/Visual-Vincent/InputHelper/releases
Its wiki is sadly far from complete, but the library itself includes XML documentation describing every method inside it (which is automatically shown by Visual Studio's IntelliSense when you select a method or member in the members list that pops up while typing).
The library currently consists of four main categories:
InputHelper.Hooks: Classes for capturing system-wide (some times referred to as global) mouse and keyboard input. Can be used to make for instance hot keys.
InputHelper.Keyboard: Methods for simulating real keyboard input/key strokes.
InputHelper.Mouse: Methods for simulating real mouse input.
InputHelper.WindowMessages: Methods for simulating mouse and keyboard input at a more virtual level, for instance targeting specific windows. This utilizes window messages (thus SendMessage() and PostMessage()).
The last one mentioned would be the one of your interest. Using InputHelper.WindowMessages.SendKeyPress() you can send a specific key stroke to a window of your choice or, if omitted, the currently active window.
Something like this should work:
Dim hWnd As IntPtr = GetWindowHandle("programname.exe")
'Send CTRL + A twice.
InputHelper.WindowMessages.SendKeyPress(hWnd, Keys.Control Or Keys.A)
InputHelper.WindowMessages.SendKeyPress(hWnd, Keys.Control Or Keys.A)
'Send ENTER.
InputHelper.WindowMessages.SendKeyPress(hWnd, Keys.Enter)
Note that doing Keys.Control Or Keys.A sends the combination CTRL + A, however this works only when using either Keys.Control, Keys.Shift or Keys.Alt (or a combination of them). Using any other keys (for instance Keys.A Or Keys.B or Keys.ControlKey Or Keys.A) won't work.

Get focused window title and use it in if statement

I found this code around the net but I don't know how to use it. I just want to build a code that will execute if a desired window is active.
This is for API as i read about my research,
<DllImport("USER32.DLL", EntryPoint:="GetActiveWindow", SetLastError:=True,
CharSet:=CharSet.Unicode, ExactSpelling:=True,
CallingConvention:=CallingConvention.StdCall)>
Public Shared Function GetActiveWindowHandle() As System.IntPtr
End Function
<DllImport("USER32.DLL", EntryPoint:="GetWindowText", SetLastError:=True,
CharSet:=CharSet.Unicode, ExactSpelling:=True,
CallingConvention:=CallingConvention.StdCall)>
Public Shared Function GetActiveWindowText(ByVal hWnd As System.IntPtr, ByVal lpString As System.Text.StringBuilder, ByVal cch As Integer) As Integer
End Function
He used this to get the text,
Dim caption As New System.Text.StringBuilder(256)
Dim hWnd As IntPtr = GetActiveWindowHandle()
GetActiveWindowText(hWnd, caption, caption.Capacity)
MsgBox(caption.ToString)
I put that code in the form_load() but it doesn't display anything. Like nothing happens. Where should I put it or how to make it work. I want to get the window title and put it in an If statement. I also found some programmers that used this code:
Dim hWnd As IntPtr = GetForegroundWindow()
I just want to determine the window on focus, get the text and put it in an If statement. Can you please simplify this code more. What is the difference of a FOCUS window and ACTIVE window? i guess ACTIVE are the open windows but FOCUS is the only one that the user is using. I want to know the title of the FOCUS one.
For example,
If "title of the window on focus" = "notepad" Then
MsgBox("notepad")
Else
MsgBox("not notepad")
End If
And where there is 2 windows open, if the notepad is focused it will display the notepad on message box and when the user change its focus to the other window the message box will automatically display the not notepad message.

VB.Net Close window by title

I'm searching a method to close a specific window by the title.
I tried with Process.GetProcessesByName; but not is working by this case particulary.
I'm searching a method with APIs or similar (Not in C#, I see several code but not work fine in vb.net)
Thanks!
UPDATE
Thanks for the reply. But I'm still have a problem with the solution that you describe me below.
I'm have an only process that's control two windows. Then, if I close (or kill) the Window #2, instantly close the first one (See the image).
By this reason I think in using an API method from the begging.
I'm only want close the second window.
Try using something like this. using Process.MainWindowTitle to get the Title Text and Process.CloseMainWindow to close down the UI, its a little more graceful than killing the Process.
Note: Contains does a case-sensitive search
Imports System.Diagnostics
Module Module1
Sub Main()
Dim myProcesses() As Process = Process.GetProcesses
For Each p As Process In myProcesses
If p.MainWindowTitle.Contains("Notepad") Then
p.CloseMainWindow()
End If
Next
End Sub
End Module
As far as Win API functions try something like this. Be aware if you close the parent window you will close the children also.
Module Module1
Private Declare Auto Function FindWindowEx Lib "user32" (ByVal parentHandle As Integer, _
ByVal childAfter As Integer, _
ByVal lclassName As String, _
ByVal windowTitle As String) As Integer
Private Declare Auto Function PostMessage Lib "user32" (ByVal hwnd As Integer, _
ByVal message As UInteger, _
ByVal wParam As Integer, _
ByVal lParam As Integer) As Boolean
Dim WM_QUIT As UInteger = &H12
Dim WM_CLOSE As UInteger = &H10
Sub Main()
Dim handle As Integer = FindWindowEx(0, 0, Nothing, "YourFormsTitle")
PostMessage(handle, WM_CLOSE, 0, 0)
End Sub
End Module
You haven't showed us your code snippet. Perhaps you can try this one.
Dim processList() As Process
processList = Process.GetProcessesByName(ListBox1.Items(ListBox1.SelectedIndex).ToString)
For Each proc As Process In processList
If MsgBox("Terminate " & proc.ProcessName & "?", MsgBoxStyle.YesNo, "Terminate?") = MsgBoxResult.Yes Then
Try
proc.Kill()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End If
Next
In the snippet above, i have a list of window title on the listBox. The snippet will iterate the listbox for window titles, and if the title has been found, it asks a message to terminate the process or not.

Create a service to execute an exe after one screen opens in different exe ( VB.NET)

My question maybe not be very clear, but I just want to know how this process is called or references needed to create something similar, so I can investigate on my own ( but if you have code is welcome.. LOL...)
Basically I have 2 desktop programs ( A and B). For A, I do not have the source code, for B I do. What I need is to create some service/program that after a screen pops up from program A, automatically runs B. IN other words, capture the moment a specific screen is shown in A and execute B.
My real life scenario is that I have a very basic POS where I can't collect customer demographics ( zip code, etc), so I created a second application to capture that but my cashiers are always forgetting to run the program and I need to find a way to run it after a screen is shown ( let's say the "Change Due" in the POS, so they don't forget to run it.
Any pointings will be appreciated!
Thanks
So here's a very quick example of how you can do this with VB which should be very easy to convert to C# if needed. The code search visible windows by title. If your open window doesn't have a title you'll have to work a little more. You can probably find the title of your main app and just enumerate its child windows.
First, some unmanaged code to talk to Win32 directly:
Option Strict On
Option Explicit On
Imports System.Runtime.InteropServices
Imports System.Text
Public Class Unmanaged
<DllImport("user32.dll")>
Public Shared Function EnumWindows(ByVal lpEnumFunc As CallBack, ByVal lParam As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("user32.dll", SetLastError:=True)>
Public Shared Function GetWindowLong(ByVal hWnd As IntPtr, ByVal nIndex As Integer) As Integer
End Function
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Public Shared Function GetWindowText(ByVal hwnd As IntPtr, ByVal lpString As StringBuilder, ByVal cch As Integer) As Integer
End Function
<DllImport("user32.dll", SetLastError:=True)> _
Public Shared Function IsWindowVisible(ByVal hWnd As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
Public Const SW_SHOW = 5
Public Const SW_RESTORE = 9
Public Const GW_OWNER = 4
Public Const GWL_HWNDPARENT = (-8)
Public Const GWL_EXSTYLE = (-20)
Public Const WS_EX_TOOLWINDOW = &H80
Public Const WS_EX_APPWINDOW = &H40000
Public Delegate Function CallBack(ByVal hwnd As IntPtr, ByVal lParam As Integer) As Boolean
End Class
Then a non-GUI module which should be set as the startup object:
Option Explicit On
Option Strict On
Module Module1
''//Code loosely base on http://msdntracker.blogspot.com/2008/03/list-currently-opened-windows-with.html
''//This is the title of the window that we are looking for
Public ReadOnly WatchForTitle As String = "About Mozilla Firefox"
''//This is the form that we will show when we find the above
Private MainForm As Form1
<STAThread()>
Public Sub Main()
''//Create the form but don not show it
MainForm = New Form1()
''//Create an infinite loop that checks to see if the target window is open and sleeps for a bit between checks
Do While True
Unmanaged.EnumWindows(AddressOf fEnumWindowsCallBack, IntPtr.Zero)
''//Sleep for a bit
System.Threading.Thread.Sleep(500)
Loop
End Sub
Private Function fEnumWindowsCallBack(ByVal hwnd As IntPtr, ByVal lParam As Integer) As Boolean
''//Ignore our own handle
If hwnd <> Form1.Handle Then
''//Make sure its visible
If Unmanaged.IsWindowVisible(hwnd) Then
Dim lExStyle = Unmanaged.GetWindowLong(hwnd, Unmanaged.GWL_EXSTYLE)
''//We probably want to ignore tool windows, but remove this if needed
If (((lExStyle And Unmanaged.WS_EX_TOOLWINDOW) = 0)) Then
''//Create a buffer to store the title of the window
Dim sWindowText As New System.Text.StringBuilder(256)
''//Get the title of the window
Dim lReturn = Unmanaged.GetWindowText(hwnd, sWindowText, sWindowText.Length - 1)
''//When you are looking for window title uncomment this line
'Trace.WriteLine(sWindowText)
''//Sanity check, make sure we found a window title
If lReturn <> 0 Then
''//See if it matches what we are looking for
If sWindowText.ToString() = WatchForTitle Then
''//If so, show our form
Form1.ShowDialog()
End If
End If
End If
End If
End If
fEnumWindowsCallBack = True
End Function
End Module
Lastly create a regular Windows Form called Form1 (or whatever you want, you'll just need to change it in the Module above).
If you test this it will pop open the form if you go to Firefox's Help->About menu.
I should point out, this is just a start. You'll want to perform better error checking and handle when the program closes or exists or whatever.
It's very unlikely that there is any 'good' way to interact with program A. There won't be a traditional 'event' that fires or anything like that.
Your best bet is going to be looking at some WIN32 API calls. For example, you can use GetPixel() to return the color at a specific location on the screen. So, if program A displays a particular image or screen that is measurably different from any other screen, you can write code that monitors the screen and checks for a match. When the match is found you can execute any code you want, including launching B.