高分求教:如何做一个命令行程序壳?

sworddx 2008-03-14 09:01:28
我以前见过用到这种技术的软件,但是我不知道这种技术确切来说叫什么,以及怎么实现。

比如说我现在有一个命令行程序a.exe,我现在要执行它。在VB里可以用shell语句执行。那么现在会跳出一个命令行窗口。
然而这样的用户界面显然是不友善的,我需要的是执行a.exe,不会出现这个窗口,同时我可以获得a.exe在命令行窗口的所有信息。
换言之,a.exe之前从键盘接受数据(input),输出数据到命令行窗口(output),而我现在希望它把我的程序当成I/O,由我的程序接管它的输入输出。

查了好久MSDN都没头绪……还请各位高手赐教。
...全文
733 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
wdtcom 2011-12-20
  • 打赏
  • 举报
回复
哦 。vbs隐藏 谢谢myjian
wdtcom 2011-12-20
  • 打赏
  • 举报
回复
myjian 代码好用 可是能不能不用cmd窗口
superNANA_MUMU 2010-10-07
  • 打赏
  • 举报
回复
看都看不懂~怎么学习啊?越看越伤心
sworddx 2008-04-09
  • 打赏
  • 举报
回复
谢谢老马,我找到一个C的例子,苦于基础薄弱翻成VB没执行通,你这个帮了大忙了^^
用户 昵称 2008-03-17
  • 打赏
  • 举报
回复
这应该叫重定向吧,比如1.exe ,然后手工输入一些东西,最简单的在dos下,可以用

debug < 1.asm > a.com
lcsfxs 2008-03-17
  • 打赏
  • 举报
回复
关注
onetiger1243 2008-03-15
  • 打赏
  • 举报
回复
学习了
HighRugal 2008-03-15
  • 打赏
  • 举报
回复
mark
有兴趣学习。
舉杯邀明月 2008-03-15
  • 打赏
  • 举报
回复
路过,学习...............
嗷嗷叫的老马 2008-03-14
  • 打赏
  • 举报
回复
'上面是公共部分.

Private Sub Form_Load()
txtCommand.Text = ""
txtMessage.Text = ""
txtMessage.Locked = True

' 创建管道
CreatePipe hReadPipe, hWritePipe, ByVal 0, ByVal 0
CreatePipe hChildReadPipe, hChildWritePipe, ByVal 0, ByVal 0
SetHandleInformation hWritePipe, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT
SetHandleInformation hChildReadPipe, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT
Dim dwMode As Long
dwMode = PIPE_NOWAIT
SetNamedPipeHandleState hReadPipe, dwMode, ByVal 0, ByVal 0

' 创建CMD进程
Dim stProcessInfo As PROCESS_INFORMATION
Dim stStartInfo As STARTUPINFO
stStartInfo.cb = LenB(stStartInfo)
stStartInfo.dwFlags = STARTF_USESTDHANDLES
stStartInfo.hStdError = hWritePipe
stStartInfo.hStdOutput = hWritePipe
stStartInfo.hStdInput = hChildReadPipe

Dim strExe As String
strExe = "cmd"
If False = CreateProcess(ByVal vbNullString, ByVal strExe, ByVal 0, ByVal 0, ByVal True, ByVal DETACHED_PROCESS, ByVal 0, ByVal vbNullString, stStartInfo, stProcessInfo) Then
MsgBox "启动进程失败!"
Exit Sub
Else
CloseHandle stProcessInfo.hThread
CloseHandle stProcessInfo.hProcess
End If
ReadFromChildPipe
End Sub

Private Sub Form_Unload(Cancel As Integer)
CloseHandle hReadPipe
CloseHandle hWritePipe
CloseHandle hChildReadPipe
CloseHandle hChildWritePipe
End Sub

Private Sub txtCommand_KeyPress(KeyAscii As Integer)
If KeyAscii = vbKeyReturn Then
Dim nWrite As Long
Dim strBuffer As String
strBuffer = txtCommand.Text & vbCrLf
Dim bResult As Boolean
bResult = WriteFile(ByVal hChildWritePipe, ByVal strBuffer, ByVal Len(strBuffer), nWrite, ByVal 0)
If bResult = True Then
ReadFromChildPipe
Else
MsgBox "写入失败."
End If
txtCommand.Text = ""
End If
End Sub

Private Sub ReadFromChildPipe()
Dim nRead As Long
Dim strBuffer As String
Dim nBufferLen As Long
nRead = -1
Do While nRead <> 0
nBufferLen = 65536
strBuffer = String(nBufferLen, Chr(0))
Sleep 10
ReadFile hReadPipe, ByVal strBuffer, ByVal nBufferLen, nRead, ByVal 0
Sleep 10
If nRead <> 0 Then
strBuffer = Left(strBuffer, nRead)
txtMessage.Text = txtMessage.Text & strBuffer
txtMessage.SelStart = Len(txtMessage.Text)
End If
Loop
End Sub


代码在我这里可以直接运行.

运行后,在第二个文本框里输入命令行的指令试下看.

比如dir,cd,start notepad等.

关键就在于CreateProcess函数的lpStartupInfo参数,在这个结构里把输入输出管道设定为自己的管道即可.

管道用CreatePipe建立.

具体看代码吧....其实说穿了还是比较简单的.
嗷嗷叫的老马 2008-03-14
  • 打赏
  • 举报
回复
'新建工程,添加两个文本框txtMessage与txtCommand.
'前者的MultLine=True,用于显示命令行程序的回显;
'后者用于输入命令.
Option Explicit

Private Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, lpProcessAttributes As Any, lpThreadAttributes As Any, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, lpEnvironment As Any, ByVal lpCurrentDriectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function CreatePipe Lib "kernel32" (phReadPipe As Long, phWritePipe As Long, lpPipeAttributes As Any, ByVal nSize As Long) As Long
Private Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As Any) As Long
Private Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Any) As Long
Private Declare Function SetHandleInformation Lib "kernel32" (ByVal hObject As Long, ByVal dwMask As Long, ByVal dwFlags As Long) As Long
Private Declare Function SetNamedPipeHandleState Lib "kernel32" (ByVal hNamedPipe As Long, lpMode As Long, lpMaxCollectionCount As Long, lpCollectDataTimeout As Long) As Long
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Private 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

Private Type PROCESS_INFORMATION
hProcess As Long
hThread As Long
dwProcessId As Long
dwThreadId As Long
End Type

Private Const STARTF_USESTDHANDLES = &H100
Private Const HANDLE_FLAG_INHERIT = 1
Private Const DETACHED_PROCESS = &H8
Private Const PIPE_NOWAIT = &H1

Dim hReadPipe As Long
Dim hWritePipe As Long
Dim hChildReadPipe As Long
Dim hChildWritePipe As Long
嗷嗷叫的老马 2008-03-14
  • 打赏
  • 举报
回复
这就是管道重定向.

正好我这里有个例子,你可以参考下.
aohan 2008-03-14
  • 打赏
  • 举报
回复
是不是类似这种的?


Option Explicit

Private Sub Command1_Click()

Call GetMacAddress

End Sub

Function GetMacAddress() As String

Dim i&, j&, OutChar$
Dim fn As Byte, pos1&, pos2&, ArrayChar$(1)

'输出IP信息
Shell "cmd /c ipconfig/all > C:\Ping", vbHide
fn = FreeFile

RETRY:

Open "c:\ping" For Binary Access Read As #fn

OutChar$ = Space$(FileLen("c:\ping"))
'读取IP信息
Get #fn, , OutChar$

Close #fn

If Len(OutChar$) = 0 Then GoTo RETRY

'搜索Physical Address
pos1 = InStr(OutChar$, "Physical Address")

Do While pos1 <> 0

'搜索:标志
pos2 = InStr(pos1, OutChar$, ":")
'取MAC Address, 长度18
ArrayChar(j) = Mid$(OutChar$, pos2 + 1, 18)
'判断是否有多个网卡
pos1 = InStr(pos2, OutChar$, "Physical Address")
If pos1 <> 0 Then j = j + 1

Loop

For i = 1 To j + 1

MsgBox "第" & i & "个网卡的MAC ADDRESS 是" & ArrayChar(i - 1)

Next

Kill "C:\Ping"

End Function

东方之珠 2008-03-14
  • 打赏
  • 举报
回复
UP
sworddx 2008-03-14
  • 打赏
  • 举报
回复
正在参考:
http://support.microsoft.com/kb/190351

7,763

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧