Results 1 to 33 of 33

Thread: Need to start a command line window and send a string to it

  1. #1

    Thread Starter
    Hyperactive Member BrianPaul's Avatar
    Join Date
    Aug 2007
    Posts
    294

    Need to start a command line window and send a string to it

    I have a VB6 program that sends a command to the command line. The command line window then stays open asking for username. I think what I need to do is launch the command and grab the pid, then use the pid to send the string to the command window. Is this possible?

  2. #2

    Thread Starter
    Hyperactive Member BrianPaul's Avatar
    Join Date
    Aug 2007
    Posts
    294

    Re: Need to start a command line window and send a string to it

    I can launch the code, get the process id and even the process handle, but not sure how to send to the command window once I know that info.

    vb Code:
    1. Dim retVal As Long, pID As Long, pHandle As Long
    2. pID = Shell(cmdLine, vbNormalFocus)
    3. pHandle = OpenProcess(&H100000, True, pID)

    Can I somehow send a string to this process id or process handle?

  3. #3
    Frenzied Member
    Join Date
    Dec 2007
    Posts
    1,072

    Re: Need to start a command line window and send a string to it


  4. #4

    Thread Starter
    Hyperactive Member BrianPaul's Avatar
    Join Date
    Aug 2007
    Posts
    294

    Re: Need to start a command line window and send a string to it

    I looked at the link, but I can't really make sense of that code. I'm guessing maybe the command window needs to be in focus and then maybe that will work. I'm sure there is a simple way to do this. I tried this, but it didn't work.

    vb Code:
    1. Option Explicit
    2. Private Const INFINITE = &HFFFF      '  Infinite timeout
    3. Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
    4. Private Declare Function OpenProcess Lib "kernel32" (ByVal dwAccess As Long, ByVal fInherit As Integer, ByVal hObject As Long) As Long
    5. Private Declare Function WriteConsole Lib "kernel32" Alias "WriteConsoleA" (ByVal hConsoleOutput As Long, ByVal lpBuffer As String, ByVal nNumberOfCharsToWrite As Long, lpNumberOfCharsWritten As Long, lpReserved As Any) As Long
    6.  
    7. Private Sub Command1_Click()
    8.    Dim retVal As Long, pID As Long, pHandle As Long
    9.    Dim txt As String
    10.    Dim num_written As Long
    11.    txt = "a"
    12.    
    13.    pID = Shell("cmd /c pause", vbNormalFocus)
    14.    pHandle = OpenProcess(&H100000, True, pID)
    15.    MsgBox pHandle
    16.    WriteConsole pID, txt, Len(txt), num_written, vbNullString
    17.    WriteConsole pHandle, txt, Len(txt), num_written, vbNullString
    18. End Sub

    I was trying to send text using first pID (process id) and then pHandle (process handle), but maybe WriteConsole doesn't work like this.

  5. #5

    Thread Starter
    Hyperactive Member BrianPaul's Avatar
    Join Date
    Aug 2007
    Posts
    294

    Re: Need to start a command line window and send a string to it

    Ok, I have this working with SendKeys, but SendKeys can be very iffy so please let me know if anyone has a better solution. Here's my code...

    vb Code:
    1. pID = Shell("C:\Program Files\Cisco\Cisco AnyConnect VPN Client\vpncli.exe connect xyz.org", vbMinimizedFocus)
    2.     Sleep (1000)
    3.  
    4.     AppActivate pID             'activate vpncli.exe command window
    5.     DoEvents                    'do events is needed to allow Windows to switch focus
    6.     SendKeys Text1.Text, True   'send username to vpncli.exe
    7.     DoEvents
    8.     AppActivate pID
    9.     DoEvents                    'do events is needed to allow Windows to switch focus
    10.     SendKeys "{Enter}"          'hit enter after username
    11.     DoEvents
    12.     AppActivate pID
    13.     DoEvents                    'do events is needed to allow Windows to switch focus
    14.     SendKeys Text2.Text, True   'send password to vpncli.exe
    15.     DoEvents
    16.     AppActivate pID
    17.     DoEvents                    'do events is needed to allow Windows to switch focus
    18.     SendKeys "{Enter}"          'hit enter after password
    19.     DoEvents

  6. #6
    PowerPoster
    Join Date
    Dec 2004
    Posts
    25,618

    Re: Need to start a command line window and send a string to it

    there is a better method, search on named pipes

    or use a shell object
    i do my best to test code works before i post it, but sometimes am unable to do so for some reason, and usually say so if this is the case.
    Note code snippets posted are just that and do not include error handling that is required in real world applications, but avoid On Error Resume Next

    dim all variables as required as often i have done so elsewhere in my code but only posted the relevant part

    come back and mark your original post as resolved if your problem is fixed
    pete

  7. #7
    Hyperactive Member
    Join Date
    Jul 2009
    Posts
    489

    Re: Need to start a command line window and send a string to it

    first you can open the command line as an object in your vb project
    i found this class on P-S-C
    Code:
    VERSION 1.0 CLASS
    BEGIN
      MultiUse = -1  'True
      Persistable = 0  'NotPersistable
      DataBindingBehavior = 0  'vbNone
      DataSourceBehavior  = 0  'vbNone
      MTSTransactionMode  = 0  'NotAnMTSObject
    END
    Attribute VB_Name = "clsConsole"
    Attribute VB_GlobalNameSpace = False
    Attribute VB_Creatable = True
    Attribute VB_PredeclaredId = False
    Attribute VB_Exposed = False
    Attribute VB_Ext_KEY = "SavedWithClassBuilder6" ,"Yes"
    Attribute VB_Ext_KEY = "Top_Level" ,"Yes"
    Option Explicit
    
    'based upon the DOS Console posted on http://www.planet-source-code.com/  by Loreno Heer
    
    Private Declare Function AllocConsole Lib "kernel32" () As Long
    Private Declare Function FreeConsole Lib "kernel32" () As Long
    Private Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As Long) As Long
    Private Declare Function ReadConsole Lib "kernel32" Alias "ReadConsoleA" (ByVal hConsoleInput As Long, ByVal lpBuffer As String, ByVal nNumberOfCharsToRead As Long, lpNumberOfCharsRead As Long, lpReserved As Any) As Long
    Private Declare Function SetConsoleMode Lib "kernel32" (ByVal hConsoleOutput As Long, dwMode As Long) As Long
    Private Declare Function SetConsoleTextAttribute Lib "kernel32" (ByVal hConsoleOutput As Long, ByVal wAttributes As Long) As Long
    Private Declare Function SetConsoleTitle Lib "kernel32" Alias "SetConsoleTitleA" (ByVal lpConsoleTitle As String) As Long
    Private Declare Function WriteConsole Lib "kernel32" Alias "WriteConsoleA" (ByVal hConsoleOutput As Long, ByVal lpBuffer As Any, ByVal nNumberOfCharsToWrite As Long, lpNumberOfCharsWritten As Long, lpReserved As Any) As Long
    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
    Private Declare Function ShowWindow Lib "user32" (ByVal hWnd As Long, ByVal nCmdShow As Long) As Long
    Private Declare Function SetWindowPos Lib "user32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
    
    Private Const STD_INPUT_HANDLE = -10&
    Private Const STD_OUTPUT_HANDLE = -11&
    Private Const STD_ERROR_HANDLE = -12&
    Private Const FOREGROUND_RED = &H4
    Private Const FOREGROUND_GREEN = &H2
    Private Const FOREGROUND_BLUE = &H1
    Private Const FOREGROUND_INTENSITY = &H8
    Private Const BACKGROUND_RED = &H40
    Private Const BACKGROUND_GREEN = &H20
    Private Const BACKGROUND_BLUE = &H10
    Private Const BACKGROUND_INTENSITY = &H80
    Private Const ENABLE_LINE_INPUT = &H2
    Private Const ENABLE_ECHO_INPUT = &H4
    Private Const ENABLE_MOUSE_INPUT = &H10
    Private Const ENABLE_PROCESSED_INPUT = &H1
    Private Const ENABLE_WINDOW_INPUT = &H8
    Private Const ENABLE_PROCESSED_OUTPUT = &H1
    Private Const ENABLE_WRAP_AT_EOL_OUTPUT = &H2
    
    Private hConsoleIn As Long
    Private hConsoleOut As Long
    Private hConsoleErr As Long
    
    Private Const SWP_NOMOVE = 2
    Private Const SWP_NOSIZE = 1
    Private Const FLAGS = SWP_NOMOVE Or SWP_NOSIZE
    Private Const HWND_TOPMOST = -1
    Private Const HWND_NOTOPMOST = -2
    Private Const SWP_SHOWWINDOW = &H40
    
    Private Const WM_CLOSE = &H10
    Private Const SW_HIDE = 0
    Private Const SW_SHOWNORMAL = 1
    Private Const SW_MAXIMIZE = 3
    Private Const SW_SHOW = 5
    Private Const SW_MINIMIZE = 6
    Private Const SW_RESTORE = 9
    
    'local variable(s) to hold property value(s)
    Private mvarLogFilePathName As String 'local copy
    Private mvarConsoleWindowTitle As String 'local copy
    
    Public Property Let ConsoleWindowTitle(ByVal vData As String)
    
        mvarConsoleWindowTitle = vData
    
    End Property
    
    
    Public Property Get ConsoleWindowTitle() As String
    
        ConsoleWindowTitle = mvarConsoleWindowTitle
    
    End Property
    
    
    Public Sub WriteOut(ByVal Msg As String, Optional ByVal LogIt As Boolean = False)
    
      Msg = Format(Now, "hh:nn:ss") & " " & Msg
      
      Msg = Msg & vbCrLf
      
      WriteConsole hConsoleOut, Msg, Len(Msg), vbNull, vbNull
      
      If LogIt Then WriteLog Msg
        
    End Sub
    
    
    Public Sub Important(ByVal Msg As String, Optional ByVal LogIt As Boolean = False)
      
      SetConsoleTextAttribute hConsoleOut, FOREGROUND_RED Or FOREGROUND_INTENSITY
      
      WriteOut "---------------------------------------------------------------------", LogIt
      WriteOut Msg, LogIt
      WriteOut "---------------------------------------------------------------------", LogIt
      
      SetConsoleTextAttribute hConsoleOut, FOREGROUND_RED Or FOREGROUND_GREEN Or FOREGROUND_BLUE
      
    End Sub
    
    
    Public Property Let LogFilePathName(ByVal vData As String)
        
      mvarLogFilePathName = vData
    
    End Property
    
    
    Public Property Get LogFilePathName() As String
        
      LogFilePathName = mvarLogFilePathName
    
    End Property
    
    
    Private Function CGet() As String
       
      Dim sUserInput As String * 256
      Call ReadConsole(hConsoleIn, sUserInput, Len(sUserInput), vbNull, vbNull)
      CGet = Left$(sUserInput, InStr(sUserInput, Chr$(0)) - 3)
    
    End Function
    
    
    Public Sub CloseConsole()
       
      FreeConsole
       
    End Sub
    
    
    Public Sub LoadConsole()
       
      Dim lHwnd As Long
      Dim ConsoleTitle As String
      
      ConsoleTitle = ConsoleWindowTitle()
      
      AllocConsole
      SetConsoleTitle ConsoleTitle
      hConsoleIn = GetStdHandle(STD_INPUT_HANDLE)
      hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE)
      hConsoleErr = GetStdHandle(STD_ERROR_HANDLE)
    
      lHwnd = FindWindow("ConsoleWindowClass", ConsoleTitle)
      
      ShowWindow lHwnd, SW_SHOWNORMAL
      Call SetWindowPos(lHwnd, HWND_TOPMOST, 0, 0, 0, 0, FLAGS)
      Call SetWindowPos(lHwnd, HWND_NOTOPMOST, 0, 0, 0, 0, FLAGS)
        
    End Sub
    
    
    Private Sub WriteLog(sMsg As String)
    
      If LogFilePathName = "" Then Exit Sub
      
      Dim intFile As Integer   ' FreeFile variable
      
      intFile = FreeFile()
      
      Open LogFilePathName For Append As #intFile
      Print #intFile, sMsg
      Close #intFile
      
    End Sub
    
    
    Private Function FileExists(FullPathandFile As String) As Boolean
    
      On Error Resume Next
      
      If FileLen(FullPathandFile) > 0& Then
        If Err = 0 Then FileExists = True
      End If
    
    End Function
    
    
    Private Sub Class_Terminate()
    
      CloseConsole
      
    End Sub

  8. #8
    Hyperactive Member
    Join Date
    Jul 2009
    Posts
    489

    Re: Need to start a command line window and send a string to it

    second, you can try these functions to get/set the command line window text.
    you need to find the Hwnd of the command line, first.
    i didn't try them though, so i'll be happy if you have the time to test them and report the results.

    Code:
    Const WM_SETTEXT = &HC
    Const WM_GETTEXT = &HD
    
    Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String) As Long
    Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
    Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long
    Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
    
    'Example Use of get window text
        Dim Buf As String
        Buf = Space(512)
        ' the hwnd should be the command line Window Handler
        Call SendMessage(hWnd,WM_GETTEXT,Len(Buf),ByVal Buf)
    in case this will give only the title,
    you can use PSpy (on my signature), to see the name and window handler
    of the object inside the command line (if there is any,)
    and use this handler, instead.


    Code:
    'Example Use of set window text
        Dim Buf As String
        Buf = "this text is sended to command line window"
        ' the hwnd should be the command line Window Handler or
        ' the object handler inside command line, if there is any.
        Call SendMessage(hWnd,WM_SETTEXT,Len(Buf),ByVal Buf)

  9. #9

    Thread Starter
    Hyperactive Member BrianPaul's Avatar
    Join Date
    Aug 2007
    Posts
    294

    Re: Need to start a command line window and send a string to it

    I would rather use SendMessage as you suggested, but I couldn't figure out the window handle for the command line window. I thought this would get me the handle, but it didn't...

    vb Code:
    1. pID = Shell("cmd /c pause", vbNormalFocus)
    2.    pHandle = OpenProcess(&H100000, True, pID)

    Any ideas on how I can get the handle of the command line window?

  10. #10
    Hyperactive Member
    Join Date
    Jul 2009
    Posts
    489

    Re: Need to start a command line window and send a string to it

    Quote Originally Posted by BrianPaul View Post
    I would rather use SendMessage as you suggested, but I couldn't figure out the window handle for the command line window. I thought this would get me the handle, but it didn't...

    vb Code:
    1. pID = Shell("cmd /c pause", vbNormalFocus)
    2.    pHandle = OpenProcess(&H100000, True, pID)

    Any ideas on how I can get the handle of the command line window?
    there is a program on my signature called PSpy
    you can see everything you want
    it comes in source code.

    EDIT: i just checked this, this only changed the title text,
    and i looked in PSpy, and couldn't find any other object inside command line.

    so i think the only solution (if you don't want the class) to use send keys.
    if send keys doesn't work well for you, you better try the API version.

    ofcourse don't forget to set focus on command line, first.
    the handle you can find by class:
    Code:
    Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
    
    hWnd = FindWindow("ConsoleWindowClass", vbNullString)
    the code below show how to use API sendkey
    Code:
            Const KEYEVENTF_EXTENDEDKEY = &H1
            Const KEYEVENTF_KEYUP = &H2
    
            Declare Sub keybd_event Lib "user32" Alias "keybd_event" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
            'Simulate Key Press>
            keybd_event VK_CAPITAL, &H45, KEYEVENTF_EXTENDEDKEY, 0
            'Simulate Key Release
            keybd_event VK_CAPITAL, &H45, KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0

  11. #11
    Frenzied Member
    Join Date
    Dec 2007
    Posts
    1,072

    Re: Need to start a command line window and send a string to it


  12. #12
    Hyperactive Member
    Join Date
    Jul 2009
    Posts
    489

    Re: Need to start a command line window and send a string to it

    i made a little research
    and this is a working tested example
    Code:
    'put all the code below in a form
    
    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
    Const KEYEVENTF_EXTENDEDKEY = &H1
    Const KEYEVENTF_KEYUP = &H2
    
    Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
    Private Declare Function SetForegroundWindow Lib "user32" (ByVal Hwnd As Long) As Long
    Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
    
    
    Private Const VK_BACK = &H08
    Private Const VK_TAB = &H09
    Private Const VK_RETURN = &H0D
    Private Const VK_SHIFT = &H10
    Private Const VK_CONTRL = &H11
    Private Const VK_MENU = &H12
    Private Const VK_PAUSE = &H13
    Private Const VK_CAPITAL = &H14
    Private Const VK_ESCAPE = &H1B
    
    Private Const VK_OEM_PLUS = &HBB
    Private Const VK_OEM_COMMA = &HBC
    Private Const VK_OEM_MINUS = &HBD
    Private Const VK_OEM_PERIOD = &HBE
    
    ' :
    Private Const VK_OEM_1 = &HBA
    ' /?
    Private Const VK_OEM_2 = &HBF
    ' \|
    Private Const VK_OEM_5 = &HDC
    
    
    Private Sub SendKey(ByVal k As Byte)
      'Simulate Key Press
      Call keybd_event(k, 0, KEYEVENTF_EXTENDEDKEY, 0)
      'Simulate Key Release
      Call keybd_event(k, 0, KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0)
    End Sub
    
    
    Private Sub apiSendKeys(ByVal Str1)
      Dim Str2 As String
      Dim i1 As Integer, i2 As Integer
      Dim flag As Boolean
      Dim k As Byte
    
      i2 = Len(Str1)
    
      For i1 = 1 To i2
        flag = False
        Str2 = Mid(Str1, i1, 1)
        k = Asc(Str2)
        Select Case k
        Case Asc("\")
          k = VK_OEM_5
        Case Asc(".")
          k = VK_OEM_PERIOD
        Case Asc(":")
          GoSub SendShift0000
          k = VK_OEM_1
        Case Asc("?")
          GoSub SendShift0000
          k = VK_OEM_2
        Case Else
          If k >= Asc("A") And k <= Asc("Z") Then GoSub SendShift0000
          k = Asc(UCase$(Str2))
        End Select
        Call SendKey(k)
        If flag Then Call keybd_event(VK_SHIFT, 0, KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0)
      Next
      Exit Sub
    
    SendShift0000:
      Call keybd_event(VK_SHIFT, 0, KEYEVENTF_EXTENDEDKEY, 0)
      flag = True
      Return
    End Sub
    
    Private Sub form_load()
        Dim Hwnd As Long
        Dim Buf As String
        Hwnd = FindWindow("ConsoleWindowClass", vbNullString)
        Call SetForegroundWindow(Hwnd)
        Call Sleep(500)
        Call apiSendKeys("AaBbCd?\.:1234" + vbCr)
        Unload Me
    End Sub

  13. #13

    Thread Starter
    Hyperactive Member BrianPaul's Avatar
    Join Date
    Aug 2007
    Posts
    294

    Re: Need to start a command line window and send a string to it

    Thanks whatsup, but the problem that I have is with this line...

    Call SetForegroundWindow(Hwnd)

    This line is setting putting the command line window in focus, but with other apps can steal that focus away, which is the big downfall of SendKeys. Right now I am using SendKeys with AppActivate to get the focus and it works, but know it's not a foolproof way to do it. The other issue is that I cannot hide the window. If I use vbHide, it will not work, but with SendMessage, it will work even if the window is hidden.

    I tried using SendMessage in this way...

    vb Code:
    1. h = FindWindow(vbNullString, CStr("c:\windows\cisco\vpncli.exe"))
    2. h = CStr(h)
    3. Dim Buf As String
    4. Buf = "this text is sent to command line window"
    5. Call SendMessage(h, WM_SETTEXT, Len(Buf), ByVal 0)

    It ends up changing the title of the command line window instead of entering the text at the command prompt. Now the last post here seems to be saying it can't be done...

    http://www.vbforums.com/showthread.php?t=238185

    But I found if I do this, it will send the letter 'a' to the command prompt.

    vb Code:
    1. h = FindWindow(vbNullString, CStr("c:\windows\cisco\vpncli.exe"))
    2. h = CStr(h)
    3. Call SendMessageBynum(h, WM_CHAR, 97, ByVal 0)

    I think there must be a way to do this using WM_SETTEXT. I can do it a letter at a time, but it just seems that WM_SETTEXT should work.

  14. #14
    VB For Fun Edgemeal's Avatar
    Join Date
    Sep 2006
    Location
    WindowFromPoint
    Posts
    4,255

    Re: Need to start a command line window and send a string to it

    Quote Originally Posted by BrianPaul View Post
    But I found if I do this, it will send the letter 'a' to the command prompt.
    If the window is accepting the one character then you could just create a sub to send each character of the string for you, see the SendTxt Function in the example...

    Code:
    Option Explicit
    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
    Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Private Const WM_CHAR = &H102
    
    Private Sub Form_Load()
        'open a hidden dos prompt window (WinXP).
        Shell "c:\windows\system32\cmd.exe", vbHide
    End Sub
    
    Private Sub Command1_Click()
        Dim h As Long
        Dim result As Boolean
        ' find dos prompt window
        h = FindWindow(vbNullString, "c:\windows\system32\cmd.exe")
        If h Then
            ' send "calc.exe" followed by carraige return
            result = SendTxt(h, "calc.exe" & vbCr)
            ' optional, check postmessage result
            If result = False Then MsgBox "postmessage failed!"
            'close the hidden dos prompt window
            SendTxt h, "exit" & vbCr
        Else
            MsgBox "dos prompt window not found"
        End If
    End Sub
    
    Private Function SendTxt(ByVal Handle As Long, ByVal sText As String) As Boolean
        Dim i As Integer
        Dim lngReturn As Long
        For i = 1 To Len(sText)
            lngReturn = PostMessage(Handle, WM_CHAR, Asc(Mid$(sText, i, 1)), 0&)
            If lngReturn <> 1 Then Exit Function ' failed
        Next i
        SendTxt = True ' passed
    End Function
    btw, Look up WM_SETTEXT on MSDN, I believe its mainly used for edit controls and title text.
    Last edited by Edgemeal; May 17th, 2010 at 12:11 PM.

  15. #15
    Hyperactive Member
    Join Date
    Jul 2009
    Posts
    489

    Re: Need to start a command line window and send a string to it

    h = FindWindow(vbNullString, CStr("c:\windows\cisco\vpncli.exe"))
    h = CStr(h)
    Call SendMessageBynum(h, WM_CHAR, 97, ByVal 0)
    this is very good to know.
    so as Edgemeal said, just send char by char, shouldn't be a problem.

  16. #16

    Thread Starter
    Hyperactive Member BrianPaul's Avatar
    Join Date
    Aug 2007
    Posts
    294

    Re: Need to start a command line window and send a string to it

    Edgemeal, that's awesome and very much appreciated! I do seem to have a strange issue with the code though. If there are duplicate letters, it seems to strip them out. It works fine in your program, but when I put it into my program, it seems to strip out duplicate characters... like MILLER would show up as MILER. Here's my code...

    vb Code:
    1. Private Sub Command1_Click()
    2.     Dim Result As Integer   'ping result
    3.     Dim cnt As Integer      'loop counter
    4.     Dim hwnd As Long        'handle of command window
    5.     Dim username As String: username = Text1.Text
    6.     Dim pwd As String: pwd = Text2.Text
    7.    
    8.     Call Shell("C:\Program Files\Cisco\Cisco AnyConnect VPN Client\vpncli.exe connect myDomain", vbNormalFocus)
    9.     Sleep (1000)
    10.     hwnd = FindWindow(vbNullString, "C:\Program Files\Cisco\Cisco AnyConnect VPN Client\vpncli.exe") 'find VPN commandline window
    11.    
    12.     If hwnd Then    'Check if commandline window was found
    13.         Result = SendTxt(hwnd, Text1.Text & vbCr) 'Send username to command line
    14.         If Result = False Then MsgBox "postmessage failed!" 'check if postmessage failed
    15.     Else
    16.         MsgBox "VPN Connection failed, commandline window not found!"
    17.         Exit Sub
    18.     End If
    19.  
    20.     hwnd = FindWindow(vbNullString, "C:\Program Files\Cisco\Cisco AnyConnect VPN Client\vpncli.exe") 'find VPN commandline window
    21.    
    22.     If hwnd Then    'Check if commandline window was found
    23.         Result = SendTxt(hwnd, Text2.Text & vbCr) 'Send password to command line
    24.         If Result = False Then MsgBox "postmessage failed!" 'check if postmessage failed
    25.     Else
    26.         MsgBox "VPN Connection failed"
    27.         Exit Sub
    28.     End If
    End Sub

    vb Code:
    1. Private Function SendTxt(ByVal Handle As Long, ByVal sText As String) As Boolean
    2.     Dim i As Integer
    3.     Dim lngReturn As Long
    4.     For i = 1 To Len(sText)
    5.         lngReturn = PostMessage(Handle, WM_CHAR, Asc(Mid$(sText, i, 1)), 0&)
    6.         If lngReturn <> 1 Then Exit Function ' failed
    7.     Next i
    8.     SendTxt = True ' passed
    9. End Function

  17. #17

    Thread Starter
    Hyperactive Member BrianPaul's Avatar
    Join Date
    Aug 2007
    Posts
    294

    Re: Need to start a command line window and send a string to it

    Ok, got it... put a sleep statement right after it posts a letter and it fixed the problem. Now it looks like this...

    Code:
    Private Function SendTxt(ByVal Handle As Long, ByVal sText As String) As Boolean
        Dim i As Integer
        Dim lngReturn As Long
        For i = 1 To Len(sText)
            lngReturn = PostMessage(Handle, WM_CHAR, Asc(Mid$(sText, i, 1)), 0&)
            Sleep 25
            If lngReturn <> 1 Then Exit Function ' failed
        Next i
        SendTxt = True ' passed
    End Function

  18. #18
    VB For Fun Edgemeal's Avatar
    Join Date
    Sep 2006
    Location
    WindowFromPoint
    Posts
    4,255

    Re: Need to start a command line window and send a string to it

    Quote Originally Posted by BrianPaul View Post
    Ok, got it... put a sleep statement right after it posts a letter and it fixed the problem.
    You might want to try using SendMessage instead of Postmessage?....

    The SendMessage function calls the window procedure for the specified window and does not return until the window procedure has processed the message.

    PostMessage Function: Places (posts) a message in the message queue associated with the thread that created the specified window and returns without waiting for the thread to process the message.

    SendMessageTimeOut might also be worth a look as you can set a max wait time to return, Sendmesssage can hang your program (or make it appear hung) if the program the message is sent is busy in say a loop.
    Last edited by Edgemeal; May 18th, 2010 at 02:24 AM.

  19. #19

    Thread Starter
    Hyperactive Member BrianPaul's Avatar
    Join Date
    Aug 2007
    Posts
    294

    Re: Need to start a command line window and send a string to it

    Ok, I tried SendMessageTimeout and got the same results... if there are same characters in a row, the duplicate character(s) are omitted. It seems like this command line program doesn't agree very well with SendMessage or PostMessage. SendKeys seems to be more reliable in this application, which shocks me. I won't be able to hide the command line window if I use SendKeys, but I'm willing to give in on that if it makes the program more reliable.

  20. #20
    Hyperactive Member
    Join Date
    Jul 2009
    Posts
    489

    Re: Need to start a command line window and send a string to it

    a little improve to Edgemeal code and it works as you wanted.

    Code:
    Option Explicit
    
    
    Private Const WM_CHAR = &H102
    
    
    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
    Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    
    
    Private Sub Form_Load()
        'open a hidden dos prompt window (WinXP).
        Shell "c:\windows\system32\cmd.exe"
    End Sub
    
    
    Private Sub Command1_Click()
        Dim h As Long
        Dim result As Boolean
        ' find dos prompt window
        h = FindWindow(vbNullString, "c:\windows\system32\cmd.exe")
        If h Then
            ' send "calc.exe" followed by carraige return
            result = SendTxt(h, "calc.exe" & vbCr)
            result = SendTxt(h, "echo tteesstt" & vbCr)
            ' optional, check postmessage result
            If result = False Then MsgBox "postmessage failed!"
            'close the hidden dos prompt window
            'SendTxt h, "exit" & vbCr
        Else
            MsgBox "dos prompt window not found"
        End If
    End Sub
    
    
    Private Function SendTxt(ByVal Handle As Long, ByVal sText As String) As Boolean
        Dim i As Integer
        Dim lngReturn As Long
        Dim i1 As Long, last1 As Long
    
        For i = 1 To Len(sText)
            i1 = Asc(Mid$(sText, i, 1))
            If i1 = last1 Then Call PostMessage(Handle, WM_CHAR, 0, 0&)
            lngReturn = PostMessage(Handle, WM_CHAR, i1, 0&)
            If lngReturn <> 1 Then Exit Function ' failed
            last1 = i1
        Next i
        SendTxt = True ' passed
    End Function

  21. #21
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,487

    Re: Need to start a command line window and send a string to it

    If the old vpncli supports the stdin command line option there is a better way. You can send commands to the program via an anonymous pipe.

  22. #22

    Thread Starter
    Hyperactive Member BrianPaul's Avatar
    Join Date
    Aug 2007
    Posts
    294

    Re: Need to start a command line window and send a string to it

    Sounds promising! How would I do that, dilettante?

  23. #23
    Hyperactive Member
    Join Date
    Jul 2009
    Posts
    489

    Re: Need to start a command line window and send a string to it

    BrianPaul i hope you didn't miss my last post, because it's working very well,
    and IMO, this is the most correct way to do what you want.

  24. #24
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,487

    Re: Need to start a command line window and send a string to it

    Quote Originally Posted by BrianPaul View Post
    Sounds promising! How would I do that, dilettante?
    When you started this thread there was an almost identical one posted next to it. I provided a possible answer there that you might look at:

    How to create a front end in VB for a C code?


    Of course this only works for a console subsystem program that was written with the intent of being scripted. In other words the program needs to use the Standard I/O streams instead of interacting through Console Device APIs.

    The important question is whether or not your vpncli.exe supports "scripting" via pipes.

    The newer vpnclient.exe from Cisco seems to, if I can believe the many anguished posts on this subject I found when Googling. But the only advice for vpncli.exe users I found went something like "well try it!" In other words try running vpncli.exe /? to see what options it supports.

    This should also be clearly documented in your Cisco manual. I couldn't find an answer by checking the online version of the manual for vpncli.exe though.


    If your older VPN client doesn't support I/O redirection then of course you're back to the flaky "window hijacking" techniques (SendKeys, SendMessage/PostMessage, etc.) you've been struggling with.

  25. #25

    Thread Starter
    Hyperactive Member BrianPaul's Avatar
    Join Date
    Aug 2007
    Posts
    294

    Re: Need to start a command line window and send a string to it

    Unfortunately vpncli.exe doesn't support switches like vpnclient.exe. With vpnclient.exe, you can do...

    vpnclient connect <profile> [user <username>][eraseuserpwd | pwd <password>]

    The only thing vpncli.exe supports is sending commands like connect with the IP address, stats and disconnect, but there is no switch for username and password. I spoke with a Cisco engineer to verify this. I can use vpnclient.exe, but the Cisco engineer recommended using vpncli.exe. He explained that Cisco AnyConnect is the direction that Cisco is moving customers toward and that it has more functionality. I might need to consider if the added functions are anything we would be using. Maybe using vpnclient.exe would be a better fit for us since I would be able send the entire command (including username and password) to the command line.

  26. #26
    Hyperactive Member
    Join Date
    Mar 2006
    Posts
    282

    Re: Need to start a command line window and send a string to it

    Quote Originally Posted by Edgemeal View Post
    If the window is accepting the one character then you could just create a sub to send each character of the string for you, see the SendTxt Function in the example...

    Code:
    Option Explicit
    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
    Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Private Const WM_CHAR = &H102
    
    Private Sub Form_Load()
        'open a hidden dos prompt window (WinXP).
        Shell "c:\windows\system32\cmd.exe", vbHide
    End Sub
    
    Private Sub Command1_Click()
        Dim h As Long
        Dim result As Boolean
        ' find dos prompt window
        h = FindWindow(vbNullString, "c:\windows\system32\cmd.exe")
        If h Then
            ' send "calc.exe" followed by carraige return
            result = SendTxt(h, "calc.exe" & vbCr)
            ' optional, check postmessage result
            If result = False Then MsgBox "postmessage failed!"
            'close the hidden dos prompt window
            SendTxt h, "exit" & vbCr
        Else
            MsgBox "dos prompt window not found"
        End If
    End Sub
    
    Private Function SendTxt(ByVal Handle As Long, ByVal sText As String) As Boolean
        Dim i As Integer
        Dim lngReturn As Long
        For i = 1 To Len(sText)
            lngReturn = PostMessage(Handle, WM_CHAR, Asc(Mid$(sText, i, 1)), 0&)
            If lngReturn <> 1 Then Exit Function ' failed
        Next i
        SendTxt = True ' passed
    End Function
    btw, Look up WM_SETTEXT on MSDN, I believe its mainly used for edit controls and title text.
    I found this code very usefull for my project, only one thing missing,
    how to get output from cmd promt ?

    I use this code for sending commands to running proces, but I would also
    like to capture answer to a rtf.text from console!

    B.R
    Last edited by VB Client/Server; May 10th, 2011 at 09:21 AM.

  27. #27
    Lively Member
    Join Date
    Jan 2012
    Posts
    80

    Re: Need to start a command line window and send a string to it

    bump

  28. #28
    Addicted Member Witis's Avatar
    Join Date
    Jan 2011
    Location
    VB Forums Online Freedom Mode: Operational
    Posts
    213

    Re: Need to start a command line window and send a string to it

    Try this example from Planet Source Code, I checked it and it seems to work.
    "This is User-Friendly, CPU-Friendly, NON-BLOCKING Standard Input-Output code to grab output of a command line interface program, AND, for the first time ever (in open source in VB), to send input to it as well."
    http://www.planet-source-code.com/vb...61262&lngWId=1
    All men have an inherent right to life, the right to self determination including freedom from forced or compulsory labour, a right to hold opinions and the freedom of expression, and the right to a fair trial and freedom from torture. Be aware that these rights are universal and inalienable (cannot be given, taken or otherwise transferred or removed) although you do risk losing the aforementioned rights should you fail to uphold them e.g Charles Taylor; United Nations sources: http://www.un.org/en/documents/udhr/, http://www.ohchr.org/EN/Professional...ages/CCPR.aspx. Also Charles I was beheaded on the 30th of January of 1649 for trying to replace parliamentary democracy with an absolute monarchy, the same should happen to Dr Phil and Stephen Fry; source: http://www.vbforums.com/showthread.p...ute-Monarchism.

    The plural of sun is stars you Catholic turkeys.

  29. #29
    PowerPoster
    Join Date
    Feb 2012
    Location
    West Virginia
    Posts
    14,206

    Re: Need to start a command line window and send a string to it

    What about redirecting input?

    program.exe < keys.txt

    where program.exe is the program to run and keys.txt contains the input for the program.

    I haven't tried it but I would expect it would work via shell

  30. #30
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,487

    Re: Need to start a command line window and send a string to it

    The POS Code thing is a sort of defective example of the sort of thing I already posted a link to. Amazing how much the guy drools on his shoes over something with Sleep() calls sapping performance and uncontrolled DoEvents() calls along with those.

  31. #31
    Addicted Member Witis's Avatar
    Join Date
    Jan 2011
    Location
    VB Forums Online Freedom Mode: Operational
    Posts
    213

    Re: Need to start a command line window and send a string to it

    dilettante, I checked the example you referred to here: http://www.vbforums.com/showthread.php?t=614897; however, it doesn't look like it was designed for the command line interface. I tested the example I posted from PSC and did not notice any defects; what seems to be the problem with it?
    Last edited by Witis; Feb 21st, 2012 at 06:31 AM.
    All men have an inherent right to life, the right to self determination including freedom from forced or compulsory labour, a right to hold opinions and the freedom of expression, and the right to a fair trial and freedom from torture. Be aware that these rights are universal and inalienable (cannot be given, taken or otherwise transferred or removed) although you do risk losing the aforementioned rights should you fail to uphold them e.g Charles Taylor; United Nations sources: http://www.un.org/en/documents/udhr/, http://www.ohchr.org/EN/Professional...ages/CCPR.aspx. Also Charles I was beheaded on the 30th of January of 1649 for trying to replace parliamentary democracy with an absolute monarchy, the same should happen to Dr Phil and Stephen Fry; source: http://www.vbforums.com/showthread.p...ute-Monarchism.

    The plural of sun is stars you Catholic turkeys.

  32. #32
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,487

    Re: Need to start a command line window and send a string to it

    I think you need to look closer. The example I provided does exactly that.

    The one you linked to has the problem that once you call its run/execute method it never returns to the caller until the program it runs gets done. All of the rest of your program is trapped there, waiting on a slow and costly DoEvents + Sleep loop. I'm not even sure how you'd use it to run two or more parallel child processes.

    Not to mention the code is full of slow String operations and slower Variant operations, does silly things like adding NULs where there are already NULs. The code is of very poor quality, and even haphazardly uses the silly Call statement making the style something best described as "ransom note." It looks like a typical example of the bad programming you find at that site.

  33. #33
    Addicted Member Witis's Avatar
    Join Date
    Jan 2011
    Location
    VB Forums Online Freedom Mode: Operational
    Posts
    213

    Re: Need to start a command line window and send a string to it

    dilettante, I looked at your example again, and again I was unable to use it to interact with the command line; it looks like it would need a substantial amount of work to get it to the level of functionality provided in the example from PSC.

    The one you linked to has the problem that once you call its run/execute method it never returns to the caller until the program it runs gets done. All of the rest of your program is trapped there, waiting on a slow and costly DoEvents + Sleep loop.
    These examples are just about reading from and writing to pipes attached to processes to allow a Vb6 application to interact with external applications, which is relatively easy to implement (if you have a good example to work from) and happens to work nicely in the case of cmd.exe. Writing to a pipe is not very difficult, reading data from a pipe means programatically checking the pipe for any new data that arrives, and one method to do this involves using a timer. In the PSC example he uses a do loop containing sleep 30 to emulate a timer with the the interval set to 30 milliseconds which checks for new data. Your version uses a timer with the interval set to 300 milliseconds which also calls doevents, so for me there is not any fundamental difference between your approaches in this regard.

    Additionally the programmer states it was only a couple of days work: "It took me a few days (with the help of two friends Zak and Espen w/ debugging and C++ testing, etc) to code this", which also needs to be factored into any criticism.

    After looking at both examples, I can indicate that the PSC code is a working example of how to use pipes to fully interact with the command line which contains clear and easy to read code which is extensively documented and that it is definitely a good place to start for anyone trying to establish full interactivity with the command line from their vb6 application. By contrast your example doesn't include a working example showing how to use pipes to interact with the command line, and contains almost no code documentation, which makes it much more difficult to understand, and essentially impossible to use as the basis for a cmd line interface if the developer has no prior knowledge of pipe IPC. As a result the PSC example certainly does not deserve to be called bad programming much less a ransom note especially given the charitable nature of the example. In fact, taking all factors into account, I think that these attacks might actually be deemed libelous and that you should be much more careful with your use of language in the future. For example Article 17 of the International Covenant on Civil and Political Rights states that: "1. No one shall be subjected to [...] unlawful attacks on his honour and reputation. 2. Everyone has the right to the protection of the law against such interference or attacks." http://www2.ohchr.org/english/law/ccpr.htm
    All men have an inherent right to life, the right to self determination including freedom from forced or compulsory labour, a right to hold opinions and the freedom of expression, and the right to a fair trial and freedom from torture. Be aware that these rights are universal and inalienable (cannot be given, taken or otherwise transferred or removed) although you do risk losing the aforementioned rights should you fail to uphold them e.g Charles Taylor; United Nations sources: http://www.un.org/en/documents/udhr/, http://www.ohchr.org/EN/Professional...ages/CCPR.aspx. Also Charles I was beheaded on the 30th of January of 1649 for trying to replace parliamentary democracy with an absolute monarchy, the same should happen to Dr Phil and Stephen Fry; source: http://www.vbforums.com/showthread.p...ute-Monarchism.

    The plural of sun is stars you Catholic turkeys.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width