CreateProcess 和奇怪的 nslookup 错误

Posted

技术标签:

【中文标题】CreateProcess 和奇怪的 nslookup 错误【英文标题】:CreateProcess and strange nslookup error 【发布时间】:2010-02-03 00:36:20 【问题描述】:

我有这个 api 例程,我经常使用它来捕获 dos 输出。最近发现了一个奇怪的错误,它似乎不允许 dns 调用。例如,nslookup 将返回“服务器无响应”错误,服务器:未知。如果您为其提供 IP 地址,Ping 将起作用,但如果它必须进行 dns 调用,则不会。此问题与此代码完全隔离。

对此问题的任何见解将不胜感激。 Winapi 不是我最擅长的领域。

编辑:很抱歉添加了所有常量和类型,但我把它做成了一些东西,你可以粘贴到模块中并运行自己测试,以使问题更容易解决。

' STARTUPINFO flags
Private Const STARTF_USESHOWWINDOW = &H1
Private Const STARTF_USESTDHANDLES = &H100

' ShowWindow flag
Private Const SW_HIDE = 0

'CreatePipe buffer size
Private Const BUFSIZE = 1024

Private Type SECURITY_ATTRIBUTES
    nLength As Long
    lpSecurityDescriptor As Long
    bInheritHandle As Long
End Type

Private Type STARTUPINFO
    cb As Long
    lpReserved As Long
    lpDesktop As Long
    lpTitle As Long
    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 Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long
Private Declare Function CreatePipe Lib "kernel32.dll" (ByRef phReadPipe As Long, ByRef phWritePipe As Long, ByRef lpPipeAttributes As SECURITY_ATTRIBUTES, ByVal nSize As Long) As Long
Private Declare Function CreateProcess Lib "kernel32.dll" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, ByRef lpProcessAttributes As SECURITY_ATTRIBUTES, ByRef lpThreadAttributes As SECURITY_ATTRIBUTES, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, ByRef lpEnvironment As Any, ByVal lpCurrentDriectory As String, ByRef lpStartupInfo As STARTUPINFO, ByRef lpProcessInformation As PROCESS_INFORMATION) As Long
Private Declare Sub GetStartupInfo Lib "kernel32.dll" Alias "GetStartupInfoA" (ByRef lpStartupInfo As STARTUPINFO)
Private Declare Function PeekNamedPipe Lib "kernel32.dll" (ByVal hNamedPipe As Long, ByRef lpBuffer As Any, ByVal nBufferSize As Long, ByRef lpBytesRead As Long, ByRef lpTotalBytesAvail As Long, ByRef lpBytesLeftThisMessage As Long) As Long
Private Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, ByVal lpBuffer As String, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Any) As Long

Sub CreateprocessApiTest()
    On Error GoTo errHandler
    Dim pa As SECURITY_ATTRIBUTES
    Dim pra As SECURITY_ATTRIBUTES
    Dim tra As SECURITY_ATTRIBUTES
    Dim si As STARTUPINFO
    Dim pi As PROCESS_INFORMATION
    Dim retVal As Long
    Dim command As String
    Dim ErrorDesc As String
    Dim hRead As Long     ' stdout + stderr
    Dim hWrite As Long
    Dim bAvail As Long    ' pipe bytes available (PeekNamedPipe)
    Dim bRead As Long     ' pipe bytes fetched   (ReadFile)
    Dim bString As String    ' our buffer
    Dim s As String

    command = "nslookup google.com"

    pa.nLength = Len(pa)
    pa.bInheritHandle = 1

    pra.nLength = Len(pra)
    tra.nLength = Len(tra)

    retVal = CreatePipe(hRead, hWrite, pa, BUFSIZE)

    With si
        .cb = Len(si)
        GetStartupInfo si
        .dwFlags = STARTF_USESHOWWINDOW Or STARTF_USESTDHANDLES
        .wShowWindow = SW_HIDE
        .hStdOutput = hWrite
        .hStdError = hWrite
    End With

    retVal = CreateProcess(vbNullString, command, pra, tra, 1, 0&, 0&, vbNullString, si, pi)

    Do While PeekNamedPipe(hRead, ByVal 0, 0, ByVal 0, bAvail, ByVal 0)
        DoEvents
        If bAvail Then
            bString = String(bAvail, 0)
            ReadFile hRead, bString, bAvail, bRead, ByVal 0&
            bString = Left(bString, bRead)
            s = s & bString
            CloseHandle hWrite
        End If
    Loop
    CloseHandle hRead
    CloseHandle pi.hThread
    CloseHandle pi.hProcess

    MsgBox s

exitRoutine:
    Exit Sub
errHandler:
    Debug.Print Err.Number, Err.Description
    Resume exitRoutine
End Sub

【问题讨论】:

您确定您的 DNS 缓存没有被污染吗?如果您从命令行使用 IP 地址和服务器名称 ping 会发生什么? 这是 VB6。我可以从命令提示符 ping 和 nslookup 并且实用程序正常工作。这已经在不同位置的多台机器上进行了测试,我每次都得到相同的结果。即使我使用“nslookup google.com 服务器”设置 dns 服务器,它仍然无法正常工作。问题必须出在创建过程的方式上。我想不通... 【参考方案1】:

lpEnvironment As Any 参数错误。像这样添加ByVal

retVal = CreateProcess(vbNullString, command, pra, tra, 1, 0&, ByVal 0&, vbNullString, si, pi)

【讨论】:

这就像一个魅力。我不敢相信这是这么简单的事情。谢谢!

以上是关于CreateProcess 和奇怪的 nslookup 错误的主要内容,如果未能解决你的问题,请参考以下文章

使用 CreateProcess 启动子程序时,不会在父程序的工作目录中搜索 DLL

forking() 和 CreateProcess()

CreateProcess 和命令行参数

(C) Windows 句柄和 Createprocess

调整使用 createprocess 创建的应用程序的大小和位置?

不直接使用字符串时CreateProcess@Unhandled异常