我有一个NT
服务,它调用了一个用 Delphi 7编写的控制台程序,让我们称之为failover.exe
,然后使用我找到的一个过程调用NETSH
:
procedure ExecConsoleApp(CommandLine: ansistring; Output, Errors: TStringList);
注意:ExecConsoleApp使用了Windows Process,请参阅以下链接以获取完整代码:http://www.delphisources.ru/pages/faq/base/createprocess_console.html
在调用ExecConsoleApp
之前,我会将以下内容传递给命令行:
cmd.exe /c "C:\Windows\system32\netsh.exe interface delete address "Wireless Network Connection" 192.168.0.36"
ExecConsoleApp
将返回错误:
系统找不到指定的文件
但如果我在命令提示符下运行它,它运行得很完美。
奇怪的是,我记得它在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);
我已经研究了一天,但没有线索,希望有人能帮助。谢谢.
补充说明-
1.服务器是32位Win 2K 3。
1.尝试域管理员,不工作。
1.代码片段:
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;
1.尝试直接运行netsh.exe而不是“Netsh. exe/c C:\Windows\system32\netsh.exe...",并得到相同的“系统无法找到指定的文件。”错误。我还意外地发现,如果我发出一个错误的netsh命令,netsh实际上会返回一个错误,例如。
netsh接口ip删除地址“LocalArea Connection”10.40.201.65
指定的接口LocalArea Connection无效。
如果我将输入错误“LocalArea”更正为“Local Area”,则返回以下内容。netsh接口ip删除地址“本地连接”10.40.201.65
系统找不到指定的文件。
我必须再次重申,如果我通过命令提示符而不是从应用程序发出相同的命令,那么它可以正常工作。
3条答案
按热度按时间osh3o9ms1#
你试过这个吗?
当然,最好在运行时检测
C:\Windows\system32
的路径,因为它可能在另一个驱动程序或另一个目录中。当你以这种方式运行它时,你可以在Windows进程之后使用
GetLastError
调用从Windows获得一条错误消息。ExecConsoleApp
过程是有缺陷的,因为它不返回GetLastError
,甚至不返回任何CreateProcess
失败的指示。你应该先把这个修好。可以在
Exit
之前添加raise EExecConsoleAppCreateProcessFailed.Create(SysErrorMessage(GetLastError))
。你不应该使用
cmd.exe /c
作为前缀。它是冗余的,这使得错误诊断更加困难。GetLastError
可能没有反映正确的错误代码,因为您正在将实际netsh.exe
进程的创建委托给cmd
。66bbxpm52#
运行
netsh interface portproxy delete v4tov4 ...
时,如果我试图删除的内容不存在,则会出现此错误。如果我尝试执行netsh interface portproxy delete v4tov4 all
,也会得到此错误。然后唯一的事情是,如果我指定都端口和地址的项目存在:netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=80
。如果我只使用listenaddress
或listenport
,即使项目存在,我也会得到错误The system cannot find the file specified.
。使用进程监视器,如果您使用除这两个参数之外的任何其他参数,netsh.exe
似乎将向RegDeleteValue
Win32 API传递无效参数。vc6uscn93#
如果可执行文件所需的隐式加载的DLL不可用,也可能发生“找不到指定的文件”错误。在这种情况下,这是最有可能的原因-当netsh.exe在非交互式上下文中运行时,找不到某些必要的DLL。
使用进程监视器(可从Microsoft网站下载)记录尝试期间发生的文件系统操作。在服务进程或netsh.exe进程的上下文中查找文件未找到错误。