为什么ShellExecute找不到文件?

时间:2012-01-12 14:53:50

标签: c++ c windows winapi

从* nix世界来的时候,我对Windows的行为以及它的安全系统非常困惑。

我只是想在我的应用程序中执行外部程序。我发现WinAPI函数ShellExecute按预期工作,除非在%windir%\ System32 子目录中启动某些程序。

  • 执行ping.exe成功

    ShellExecute(NULL, "open", "c:\\Windows\\System32\\ping.exe', NULL, NULL, SW_SHOW) );
    // ^^^ OK, retcode == 42
    
  • 执行java.exe失败

    ShellExecute(NULL, "open", "c:\\Windows\\System32\\java.exe', NULL, NULL, SW_SHOW) );
    // ^^^ ERROR_FILE_NOT_FOUND, retcode == 2
    

这很奇怪,因为 java.exe确实存在于System32 中,具有对用户组的读取/执行权限,可以从cmd调用。

C:\>dir /q c:\Windows\System32\java.exe
 Volume in drive C has no label.
 Volume Serial Number is 56E3-0868

 Directory of c:\Windows\System32

11.01.2012  23:40           172 320 NT AUTHORITY\SYSTEM    java.exe
               1 File(s)        172 320 bytes
               0 Dir(s)  226 127 564 800 bytes free

C:\>cacls c:\Windows\System32\java.exe
c:\Windows\System32\java.exe NT AUTHORITY\SYSTEM:F
                             BUILTIN\Administrators:F
                             BUILTIN\Users:R

我在这里缺少什么?

操作系统是Windows 7家庭版。

更新:如果我将c:\ Windows \ Sytem32 \ calc.exe复制到c:\ Windows \ Sytem32 \ calc2.exe, ShellExecute可以运行原始calc.exe但是会失败calc2.exe虽然文件相同!! 唯一的区别是TrustedInstaller组的附加权限,其中缺少calc2.exe和java.exe。巧合?

3 个答案:

答案 0 :(得分:10)

您运行的是64位操作系统吗?

如果是这样,C:\Windows\System32将包含64位二进制文​​件,而C:\Windows\SysWOW64将包含32位二进制文​​件(是的,它实际上就是这样)。出于向后兼容性原因,在运行32位进程时,Windows会将C:\Windows\System32的访问权限重定向到C:\Windows\SysWOW64

因此,如果您使用32位进程查看C:\Windows\System32,您实际上会看到C:\Windows\SysWOW64中的内容。

您可以调用Wow64DisableWow64FsRedirection函数来禁用此行为。请注意文档中的警告,并仔细考虑它是否适用于您的情况:

  

注意: Wow64DisableWow64FsRedirection函数会影响当前线程执行的所有文件操作,如果在任何时间长度内禁用文件系统重定向,则可能会产生意外后果。例如,DLL加载取决于文件系统重定向,因此禁用文件系统重定向将导致DLL加载失败。此外,许多功能实现使用延迟加载,并且在禁用重定向时将失败。初始延迟加载操作的失败状态是持久的,因此即使在重新启用文件系统重定向之后,延迟加载功能的任何后续使用也将失败。要避免这些问题,请在调用不能重定向的特定文件I / O函数(例如CreateFile)之前立即禁用文件系统重定向,然后使用Wow64RevertWow64FsRedirection立即重新启用文件系统重定向。

答案 1 :(得分:1)

使用ProcessMonitor确定正在访问哪些文件以及哪些文件操作失败以及原因。

答案 2 :(得分:0)

检查环境设置,例如“路径”。 Windows为系统和用户保留了单独的环境。可能是Java.exe所需的DLL仅在一个环境中列出,当您通过ShellExecute运行它时,它正在使用其他环境。