On 2/19/19, Chris Angelico <ros...@gmail.com> wrote: > > I guess you have to define the question better for Windows, since > there's no single definition of "executable". If you mean "typing just > the base name of this file at the shell will result in it being run", > then PATHEXT is the correct answer. If you mean "this thing is
PATHEXT is the list of extensions that the shell appends automatically when searching PATH. Otherwise it has nothing to do with executability. I think older versions of PowerShell confused this. But I just checked PowerShell in Windows 10, and I can run a .txt file found in PATH without requiring .TXT in PATHEXT so long as I search for the name including the extension. CMD has worked like this forever. Where CMD and PowerShell differ is with respect to execute access. In CMD, when CreateProcess fails due to access denied, it gives up instead of trying ShellExecuteEx. PowerShell tries ShellExecuteEx even if CreateProcess fails with access denied. What CMD does makes more sense to me. But neither is as sensible as a POSIX shell, which continues searching PATH if a match doesn't have execute access. > actually inherently executable", then you probably want to check if it > begins MZ, but that's not certain (COM files still seem to be > supported, and they have no header whatsoever). If you mean PE executables can have any extension. CreateProcess doesn't care, but when searching for the executable, it only tries appending .EXE if we omit the extension. In other words, if we run "spam", it will find "spam.exe" but not "spam.com". Note that the extensions in PATHEXT are a high-level shell feature, as discussed above. This variable isn't used by the base Windows API. Windows comes with a few programs that use the .COM extension for backward compatibility: chcp.com, format.com, mode.com, more.com, and tree.com. In 64-bit Windows, these are 64-bit PE executables. Actual 16-bit MS-DOS files cannot run in vanilla 64-bit Windows since the NT Virtual DOS Machine (ntvdm.exe) isn't supported. If we want to know whether CreateProcess will succeed without actually calling it, then we need to check for execute access via AccessCheck, which requires the security descriptor from GetNamedSecurityInfo (OWNER, DACL and LABEL info) and current access token from OpenProcessToken, or OpenThreadToken if impersonating. Call GetTokenInformation on the token to determine whether we have admin access, which may be required. Verify that it's a valid image via GetBinaryType. Once we know we have a PE image, map it as a data file via LoadLibraryEx and get the embedded manifest via FindResource/LoadResource in order to determine whether admin access is required (i.e. requestedExecutionLevel, requireAdministrator). If there's no embedded manifest, check for one beside it named <exename>.manifest, e.g. "spam.exe.,manifest". Or we can simply call CreateProcess with the flag CREATE_SUSPENDED (4). Let the OS do all of the work for us. If it succeeds, call TerminateProcess, and close the process and thread handles. > "double-clicking this thing will run it", I think there are tools that > allow you to do the registry lookup conveniently to see if something's > associated. Call AssocQueryString to have the shell comb through the rat's nest of registry definitions to determine the ASSOCSTR_COMMAND template. (Whatever we think we know about the shell's use of the registry, we probably don't know the half of it. It is a nightmare.) Use the flag ASSOCF_INIT_IGNOREUNKNOWN to prevent returning the "unknown" progid that runs openwith.exe. We can split the template into the CreateProcess parameters lpApplicationName and lpCommandLine via SHEvaluateSystemCommandTemplate. We still have to implement our own template parameter substitution for the "%1" (i.e. "%l" or "%L") target and the %* remaining command-line arguments. -- https://mail.python.org/mailman/listinfo/python-list