2010-02-03 3 views
2

У меня есть эта процедура api, которую я использую регулярно, чтобы захватить вывод dos. Недавно была обнаружена странная ошибка, когда она, похоже, не разрешает вызовы DNS. Например, nslookup вернет ошибку «Нет ответа от сервера» на сервере: UnKnown. Ping будет работать, если вы предоставите ему IP-адрес, но не если он должен выполнить вызов DNS. Эта проблема полностью изолирована от этого кода.CreateProcess и странная ошибка nslookup

Любое понимание этой проблемы будет оценено по достоинству. 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 
+0

Вы уверены, что ваш DNS-кеш не загрязнен? Что произойдет, если вы выполните ping из строки commnad, используя IP-адрес, а затем имя сервера? –

+0

Является ли этот код VB6 или VB.NET? –

+0

Это VB6. Я могу выполнить ping и nslookup из командной строки, и утилиты работают нормально. Это было проверено на многочисленных машинах в разных местах, и каждый раз получаю одинаковые результаты. Даже если я установил DNS-сервер с помощью «nslookup google.com server», он все равно не сработает. Проблема должна заключаться в том, как процесс создается. Я не могу понять это ... – dmaruca

ответ

1

Неверный lpEnvironment As Any Параметр. Add ByVal

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

, который работает как шарм. Я не могу поверить, что это было так просто. Благодаря! – dmaruca