获取cmd程序的输出结果(vb模块)

作者在 2008-09-20 20:42:15 发布以下内容
    cmd命令有很多具有强大的功能的,如果我们自己编码实现这些的功能,往往比较复杂。因此我们会想到在自己的程序通过调用这些命令以实现这些复杂的功能。比如修改目录的NTFS权限,如果通过自己编码来实现就很复杂,但是如果使用cacls.exe命令就很简单了。
   如何获取到cmd命令执行的结果呢?网上有可以看到两种解决方案,一种是通过">>"管道操作符将输出数据写入文件,然后通过读取文件获取命令执行结果(实现简单,但时效性较差)。第二种是通过管道实现的(实现复杂,但时效性强)。
 
    下面是第二种方案的实现(大部分是老外写的,我略作修改,放到一个VB模块中,方便使用):
 

Option Explicit
Public Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" _
    (ByVal lpApplicationName As String, _
     ByVal lpCommandLine As String, _
     lpProcessAttributes As SECURITY_ATTRIBUTES, _
     lpThreadAttributes As SECURITY_ATTRIBUTES, _
     ByVal bInheritHandles As Long, _
     ByVal dwCreationFlags As Long, _
     lpEnvironment As Any, _
     ByVal lpCurrentDirectory As String, _
     lpStartupInfo As STARTUPINFO, _
     lpProcessInformation As PROCESS_INFORMATION) As Long
    
Public Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long
    
Public Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, _
     lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, _
     lpOverlapped As Long) As Long
    
Public Declare Function WaitForSingleObject Lib "kernel32" _
     (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
    
Public Declare Function CreatePipe Lib "kernel32" (phReadPipe As Long, _
     phWritePipe As Long, lpPipeAttributes As SECURITY_ATTRIBUTES, _
     ByVal nSize As Long) As Long
    
Public Type STARTUPINFO
     cb As Long
     lpReserved As String
     lpDesktop As String
     lpTitle As String
     dwX As Long
     dwY As Long
     dwXSize As Long
     dwYSize As Long
     dwXCountChars As Long
     dwYCountChars As Long
     dwFillAttribute As Long
     dwFlags As Long
     wShowWindow As Integer
     cbReserved2 As Integer
     lpReserved2 As Long
     hStdInput As Long
     hStdOutput As Long
     hStdError As Long
End Type
    
Public Type PROCESS_INFORMATION
     hProcess As Long
     hThread As Long
     dwProcessId As Long
     dwThreadId As Long
End Type
    
Public Type SECURITY_ATTRIBUTES
     nLength As Long
     lpSecurityDescriptor As Long
     bInheritHandle As Long
End Type
    
Public Const NORMAL_PRIORITY_CLASS As Long = &H20&
    
Public Const STARTF_USESTDHANDLES As Long = &H100&
Public Const STARTF_USESHOWWINDOW As Long = &H1&
Public Const SW_HIDE As Long = 0&
    
Public Const INFINITE As Long = &HFFFF&
    
    
Public Function RunCommand(commandline As String) As String
     Dim si As STARTUPINFO 'used to send info the CreateProcess
     Dim pi As PROCESS_INFORMATION 'used to receive info about the created process
     Dim retval As Long 'return value
     Dim hRead As Long 'the handle to the read end of the pipe
     Dim hWrite As Long 'the handle to the write end of the pipe
     Dim sBuffer(0 To 63) As Byte 'the buffer to store data as we read it from the pipe
     Dim lgSize As Long 'returned number of bytes read by readfile
     Dim sa As SECURITY_ATTRIBUTES
     Dim strResult As String 'returned results of the command line
    
     'set up security attributes structure
     With sa
       .nLength = Len(sa)
       .bInheritHandle = 1& 'inherit, needed for this to work
       .lpSecurityDescriptor = 0&
     End With
    
     'create our anonymous pipe an check for success
     ' note we use the default buffer size
     ' this could cause problems if the process tries to write more than this buffer size
     retval = CreatePipe(hRead, hWrite, sa, 0&)
     If retval = 0 Then
        MsgBox "错误提示:创建管道失败!"
        RunCommand = ""
        Exit Function
     End If
    
     'set up startup info
     With si
       .cb = Len(si)
       .dwFlags = STARTF_USESTDHANDLES Or STARTF_USESHOWWINDOW 'tell it to use (not ignore) the values below
       .wShowWindow = SW_HIDE
       .hStdOutput = hWrite 'pass the write end of the pipe as the processes standard output
     End With
    
     'run the command line and check for success
     retval = CreateProcess(vbNullString, _
            commandline & vbNullChar, _
            sa, _
            sa, _
            1&, _
            NORMAL_PRIORITY_CLASS, _
            ByVal 0&, _
            vbNullString, _
            si, _
            pi)
     If retval Then
        'wait until the command line finishes
        ' trouble if the app doesn't end, or waits for user input, etc
        WaitForSingleObject pi.hProcess, INFINITE
    
        'read from the pipe until there's no more (bytes actually read is less than what we told it to)
        Do While ReadFile(hRead, sBuffer(0), 64, lgSize, ByVal 0&)
           'convert byte array to string and append to our result
           strResult = strResult & StrConv(sBuffer(), vbUnicode)
           'TODO = what's in the tail end of the byte array when lgSize is less than 64???
           Erase sBuffer()
           If lgSize <> 64 Then Exit Do
           DoEvents
        Loop
    
       'close the handles of the process
        CloseHandle pi.hProcess
        CloseHandle pi.hThread
     Else
        MsgBox "错误提示:创建进程失败!" & vbCrLf
     End If
    
     'close pipe handles
     CloseHandle hRead
     CloseHandle hWrite
    
     'return the command line output
     RunCommand = Replace(strResult, vbNullChar, "")
End Function
 
 
本博客于即日起(2009.2.26)停止更新,

新博客地址:http://www.redicecn.cn ,

本博客的大部分文章已经转移到新博客中...


 
默认分类 | 阅读 13192 次
文章评论,共2条
vfdff
2008-09-20 20:57
1
由没有c方式实现的<br />
VB看不懂
redice(作者)
2008-09-24 10:42
2
C实现的 有很多呀&nbsp;&nbsp;例如著名的socket管道木马
游客请输入验证码
浏览585010次