delphi 得到“系统无法找到指定的文件”当我运行NETSH从安装过程中,但它的工作正常的命令提示符?

ig9co6j1  于 2023-10-18  发布在  其他
关注(0)|答案(3)|浏览(187)

我有一个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上,我不得不修改ExecConsoleAppsystem32\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
系统找不到指定的文件。
我必须再次重申,如果我通过命令提示符而不是从应用程序发出相同的命令,那么它可以正常工作。

osh3o9ms

osh3o9ms1#

你试过这个吗?

if not CreateProcess(PChar('C:\Windows\system32\netsh.exe'), PChar(Arguments), ...) then
begin
  // Do somehting with `GetLastError`
end;

当然,最好在运行时检测C:\Windows\system32的路径,因为它可能在另一个驱动程序或另一个目录中。
当你以这种方式运行它时,你可以在Windows进程之后使用GetLastError调用从Windows获得一条错误消息。
ExecConsoleApp过程是有缺陷的,因为它不返回GetLastError,甚至不返回任何CreateProcess失败的指示。
你应该先把这个修好。可以在Exit之前添加raise EExecConsoleAppCreateProcessFailed.Create(SysErrorMessage(GetLastError))
你不应该使用cmd.exe /c作为前缀。它是冗余的,这使得错误诊断更加困难。GetLastError可能没有反映正确的错误代码,因为您正在将实际netsh.exe进程的创建委托给cmd

66bbxpm5

66bbxpm52#

运行netsh interface portproxy delete v4tov4 ...时,如果我试图删除的内容不存在,则会出现此错误。如果我尝试执行netsh interface portproxy delete v4tov4 all,也会得到此错误。然后唯一的事情是,如果我指定端口和地址的项目存在:netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=80。如果我只使用listenaddresslistenport,即使项目存在,我也会得到错误The system cannot find the file specified.。使用进程监视器,如果您使用除这两个参数之外的任何其他参数,netsh.exe似乎将向RegDeleteValue Win32 API传递无效参数。

vc6uscn9

vc6uscn93#

如果可执行文件所需的隐式加载的DLL不可用,也可能发生“找不到指定的文件”错误。在这种情况下,这是最有可能的原因-当netsh.exe在非交互式上下文中运行时,找不到某些必要的DLL。
使用进程监视器(可从Microsoft网站下载)记录尝试期间发生的文件系统操作。在服务进程或netsh.exe进程的上下文中查找文件未找到错误。

相关问题