我有一个调用用 Delphi 7 编写的控制台程序的 NT
服务,我们称它为 failover.exe
,它又调用 NETSH
使用我发现的程序:
procedure ExecConsoleApp(CommandLine: ansistring; Output, Errors: TStringList);
注意:ExecConsoleApp 使用 CreateProcess,完整代码见以下链接:http://www.delphisources.ru/pages/faq/base/createprocess_console.html
在调用 ExecConsoleApp
之前,我会将以下内容传递给 CommandLine:
cmd.exe /c "C:\Windows\system32\netsh.exe interface delete address "Wireless Network Connection" 192.168.0.36"
ExecConsoleApp
将返回错误:
The system cannot find the file specified
但如果我在命令提示符下运行它,它运行完美。
奇怪的是,我记得它在 2003 服务器上的第一次尝试中工作,但在那之后,无论我尝试了多少次,它都失败了。在其中一次尝试中,我还尝试将以管理员用户身份登录分配给该服务,但无济于事。摆弄文件安全性也无济于事。
我没有 Win 2003 服务器可以在办公室进行测试,但我已经在 XP 和 Win7 上对其进行了测试,ExecConsoleApp
运行完美,尽管在 XP 上,我不得不修改 ExecConsoleApp
从 system32\wbem
执行以使其正常工作:
Res := CreateProcess(nil, PChar(CommandLine), nil, nil, True,
// **** Attention: Amended by to point current directory to system32\wbem, this is to solve an error returned by netsh.exe if not done otherwise.
// CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, @env, nil, si, pi);
CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, @env, pchar(GetSystemPath(WindRoot) + 'system32\wbem'), si, pi);
我研究了一天,没有任何线索,希望有人能提供帮助。谢谢。
补充说明-
服务器是 32 位 Win2k3。
尝试过域管理员,但没有用。
代码片段:
Procedure ExecConsoleApp(CommandLine: ansistring; Output, Errors: TStringList); var sa: TSECURITYATTRIBUTES; si: TSTARTUPINFO; pi: TPROCESSINFORMATION; hPipeOutputRead: THANDLE; hPipeOutputWrite: THANDLE; hPipeErrorsRead: THANDLE; hPipeErrorsWrite: THANDLE; Res, bTest: boolean; env: array[0..100] of char; szBuffer: array[0..256] of char; dwNumberOfBytesRead: DWORD; Stream: TMemoryStream; begin sa.nLength := sizeof(sa); sa.bInheritHandle := True; sa.lpSecurityDescriptor := nil; CreatePipe(hPipeOutputRead, hPipeOutputWrite, @sa, 0); CreatePipe(hPipeErrorsRead, hPipeErrorsWrite, @sa, 0); ZeroMemory(@env, SizeOf(env)); ZeroMemory(@si, SizeOf(si)); ZeroMemory(@pi, SizeOf(pi)); si.cb := SizeOf(si); si.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; si.wShowWindow := SW_HIDE; si.hStdInput := 0; si.hStdOutput := hPipeOutputWrite; si.hStdError := hPipeErrorsWrite; (* Remember that if you want to execute an app with no parameters you nil the second parameter and use the first, you can also leave it as is with no problems. *) Res := CreateProcess(nil, PChar(CommandLine), nil, nil, True, CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, @env, nil, si, pi); // Procedure will exit if CreateProcess fail if not Res then begin CloseHandle(hPipeOutputRead); CloseHandle(hPipeOutputWrite); CloseHandle(hPipeErrorsRead); CloseHandle(hPipeErrorsWrite); Exit; end; CloseHandle(hPipeOutputWrite); CloseHandle(hPipeErrorsWrite); //Read output pipe Stream := TMemoryStream.Create; try while True do begin bTest := ReadFile(hPipeOutputRead, szBuffer, 256, dwNumberOfBytesRead, nil); if not bTest then begin break; end; OemToAnsi(szBuffer, szBuffer); Stream.Write(szBuffer, dwNumberOfBytesRead); end; Stream.Position := 0; Output.LoadFromStream(Stream); finally Stream.Free; end; //Read error pipe Stream := TMemoryStream.Create; try while True do begin bTest := ReadFile(hPipeErrorsRead, szBuffer, 256, dwNumberOfBytesRead, nil); if not bTest then begin break; end; OemToAnsi(szBuffer, szBuffer); Stream.Write(szBuffer, dwNumberOfBytesRead); end; Stream.Position := 0; Errors.LoadFromStream(Stream); finally Stream.Free; end; WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); CloseHandle(hPipeOutputRead); CloseHandle(hPipeErrorsRead); end; cmdstring := 'cmd.exe /c "' + GetSystemPath(WindRoot) + 'system32\netsh.exe interface ' + ip + ' delete address "' + NetworkInterfaceName + '" ' + VirtualFailoverIPAddress + '"'; logstr('cmdstring: ' + cmdstring); ExecConsoleApp(cmdstring, OutP, ErrorP); if OutP.Text <> '' then begin logstr('Delete IP Result: ' + OutP.Text); end else begin logstr('Delete IP Error: ' + ErrorP.Text); end;
尝试直接运行 netsh.exe 而不是“cmd.exe/c C:\Windows\system32\netsh.exe...”,得到同样的“系统找不到指定的文件”。错误。我还无意中发现,如果我发出错误的 netsh 命令,netsh 实际上会返回一个错误,例如
netsh interface ip delete address "LocalArea Connection"10.40.201.65
Invalid interface LocalArea Connection specified.
如果我将拼写错误“LocalArea”更正为“Local Area”,则会返回以下内容。 netsh接口(interface)ip删除地址“本地连接”10.40.201.65
The system cannot find the file specified.
我必须再次强调,如果我通过命令提示符而不是从我的应用程序发出相同的命令,它会工作得很好。
最佳答案
你试过吗?
if not CreateProcess(PChar('C:\Windows\system32\netsh.exe'), PChar(Arguments), ...) then
begin
// Do somehting with `GetLastError`
end;
当然最好在运行时检测C:\Windows\system32
的路径,因为这可能在另一个驱动程序或另一个目录中。
当您以这种方式运行它时,您可以在 CreateProcess 之后立即使用 GetLastError
调用从 Windows 获取错误消息。
ExecConsoleApp
过程是有缺陷的,因为它没有返回 GetLastError
,甚至没有任何指示 CreateProcess
失败。
你应该先解决这个问题。也许在代码的 Exit
之前添加 raise EExecConsoleAppCreateProcessFailed.Create(SysErrorMessage(GetLastError))
。
您不应使用 cmd.exe/c
作为前缀。它是多余的,并且使错误诊断更加困难。 GetLastError
可能不会反射(reflect)正确的错误代码,因为您将创建实际 netsh.exe
进程委托(delegate)给 cmd
。
关于windows - 当我从 CreateProcess 运行 NETSH 时得到 "The system cannot find the file specified"但它在命令提示符下工作正常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8166840/