WOW64 woes (.lnk shortcuts) - windows

I'm using Windows 7 (x64) and Delphi 2010.
I'm writing a component that will emulate the start menu. However, I've run into the following problems:
If I attempt to open a shortcut (.lnk file) with ShellExecute, this will fail whenever %ProgramFiles% is part of the target path of the shortcut (it will then look at the C:\Program Files (x86) folder instead of C:\Program Files);
ShGetFileInfo fails to extract the correct index of the icon in the system image list if %ProgramFiles% is part of the path to the icon file (same problem as above).
Is there any workaround to the above issues or do I have to wait for native 64-bit Delphi to become available for this to work?

I think you should call Wow64DisableWow64FsRedirection before and Wow64RevertWow64FsRedirection aftyer.

Ok, a small example that demonstrates the problem.
I invoke ShellExecute with the following parameters:
ShellExecute(Handle, 'open', 'C:\Users\...\Internet Explorer (64-bit).lnk', nil, nil, SW_SHOWNORMAL);
The target of Internet Explorer (64-bit).lnk is:
C:\Program Files\Internet Explorer\iexplore.exe
However, the 32-bit version of iexplore.exe is opened nonetheless. In this case the path doesn't even use %ProgramFiles%, so somehow ShellExecute will translate C:\Program Files to C:\Program Files (x86) internally. I have no idea how to make it open the 64-bit version of iexplore.exe instead.
Another problem, after calling Wow64DisableWow64FsRedirection, ShellExecute will no longer open folders.

The following environment variables will always point to the right direction on a 64-bit machine, and will be undefined on a 32-bit machine:
from a 32-bit shell on a 32-bit architecture:
C:\>echo %processor_architecture%
x86
C:\>echo %programfiles(x86)%
%programfiles(x86)%
C:\>echo %programw6432%
%programw6432%
C:\>echo %programfiles%
C:\Program Files
from a 32-bit shell on a 64-bit architecture:
C:\>echo %processor_architecture%
x86
C:\>echo %programfiles(x86)%
C:\Program Files (x86)
C:\>echo %programw6432%
C:\Program Files
C:\>echo %programfiles%
C:\Program Files (x86)
from a 64-bit shell:
C:\>echo %processor_architecture%
AMD64
C:\>echo %programfiles(x86)%
C:\Program Files (x86)
C:\>echo %programw6432%
C:\Program Files
C:\>echo %programfiles%
C:\Program Files
Try substituting them before running the application.

Related

Environment variable only works for elevated (admin) command prompt but does not for normal command prompt

I am using Windows 11 Pro Version: 21H2 (Build: 22000.978)
So I have OpenSSH on my device which is also added to system path variable as shown below in the command prompt snippet.
C:\Windows\System32>set path
Path=C:\oraclexe\app\oracle\product\11.
\VMware Workstation\bin\;C:\WINDOWS\sys
1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Pr
\ProgramData\nvm;C:\Program Files\nodej
m Files\dotnet\;C:\Android\android-sdk\
in;C:\Program Files\Git\cmd;C:\Program
I'm inside System32 folder in my command prompt (normal window | non-admin) and I opened the Explorer in the current directory by entering:
explorer .
I do see OpenSSH folder, but when I try to go inside (change directory) to OpenSSH, the command prompt throws an error denoting that the path does not exist. But it does exist on the drive!
C:\Windows\System32>cd OpenSSH
The system cannot find the path specified.
And obviously I cannot access ssh.exe which is located inside OpenSSH directory.
But interestingly, when I elevate the shell (open CMD as administrator) and try to access the OpenSSH directory or even the file ssh.exe, it worked! When I use the where command for ssh, it points to that right directory as shown below:
Command prompt as standard user:
C:\Windows\System32>ssh
'ssh' is not recognized as an internal or external command,
operable program or batch file.
Command prompt as administrator:
C:\Users\Admin>where ssh
C:\Windows\System32\OpenSSH\ssh.exe
It just does not work for cmd in normal window but works when cmd is opened as administrator.
Please read first at least the Microsoft documentation about the Windows File System Redirector and best also the documentation pages WOW64 Implementation Details and Registry Keys Affected by WOW64.
When a 32-bit application on 64-bit Windows starts cmd.exe either with %SystemRoot%\System32\cmd.exe or with %ComSpec% or with cmd.exe or in worst case with just cmd, there is started the 32-bit version of the Windows Command Processor in directory %SystemRoot%\SysWOW64 because of the file system redirector.
The file system redirector is also responsible for redirecting each access of %SystemRoot%\System32\OpenSSH to %SystemRoot%\SysWOW64\OpenSSH which does not exist on 64-bit Windows because of the OpenSSH package is available only as 64-bit application suite on 64-bit Windows on being available at all (depends on version of Windows).
The usage of Run as administrator results on 64-bit Windows in starting 64-bit cmd.exe in %SystemRoot%\System32 and therefore no file system redirection is done on any access to files and directories in %SystemRoot%\System32. For more details see Why does 'Run as administrator' change (sometimes) batch file's current directory?
In a Windows batch file can be used the following code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Expect ssh.exe in OpenSSH in Windows system directory by default.
set "ExeSSH=%SystemRoot%\System32\OpenSSH\ssh.exe"
if exist "%ExeSSH%" goto RunSSH
rem Expect ssh.exe in OpenSSH in native Windows system directory
rem on batch file processed by 32-bit cmd.exe on 64-bit Windows.
set "ExeSSH=%SystemRoot%\Sysnative\OpenSSH\ssh.exe"
if exist "%ExeSSH%" goto RunSSH
rem Search for OpenSSH using environment variable PATH.
rem The environment variable ExeSSH is undefined by the
rem next command line on no file ssh.exe found by cmd.exe.
for %%I in (ssh.exe) do set "ExeSSH=%%~$PATH:I"
if defined ExeSSH goto RunSSH
rem There could not be found the executable ssh.exe anywhere.
echo ERROR: Could not find ssh.exe in any directory.
echo/
pause
exit /B 1
:RunSSH
rem Use here "%ExeSSH%" ... to run this executable.
echo Found: "%ExeSSH%"
endlocal
This batch file can be used on Windows XP and all newer Windows versions whereby on the older Windows versions is most likely output just the error message that the executable ssh.exe could not be found because of not being installed by default.

Program Files Environment Variables giving different results in Windows

When I run the command set programfiles in the command prompt, I get
ProgramFiles=C:\Program Files (x86)
ProgramFiles(x86)=C:\Program Files (x86)
However, the following code in python
import os
print os.getenv("programfiles")
or
msgbox %A_ProgramFiles% and %ProgramFiles%
in Autohotkey
or
$env:ProgramFiles
in PowerShell
all results in C:\Program Files
I cannot understand why I'm getting different results for the Program Files Environment Variables in Windows
What you see is the difference between a 32-bit and 64-bit application.
32-bit cmd.exe (%SystemRoot%\SysWOW64\cmd.exe)
C:\>set programfiles
ProgramFiles=C:\Program Files (x86)
ProgramFiles(x86)=C:\Program Files (x86)
64-bit cmd.exe (%SystemRoot%\System32\cmd.exe)
C:\>set programfiles
ProgramFiles=C:\Program Files
ProgramFiles(x86)=C:\Program Files (x86)
32-bit powershell.exe (%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe)
PS C:\> dir env:\programfiles*
Name Value
---- -----
ProgramFiles(x86) C:\Program Files (x86)
ProgramFiles C:\Program Files (x86)
64-bit powershell.exe (%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe)
PS C:\> dir env:\programfiles*
Name Value
---- -----
ProgramFiles(x86) C:\Program Files (x86)
ProgramFiles C:\Program Files

Adding Native Tools Command Prompt on VS2015 RC

Since I cannot locate Native Tools CMD under the Tools menu, I try to manually add it in External Tools. Few questions:
Regardless of what I choose for Command (ARM, x86 or x64 etc.), Command is always C:\Windows\System32\cmd.exe. Why the different CMDs end up having the same path to the native System32's CMD?
Referring to this answer, I should insert /k "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\VsDevCmd.bat" to the arguments - what is the /k and what is the bat for this argument? Why do I need to pass a path as an argument to the command prompt?
What is Initial Directory?
Why the different CMDs end up having the same path to the native System32's CMD?
The VS2015* CMDs are just cmd.exe with some environment variables already set up for you. so for example instead of typing "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe" to run InstallUtil.exe you will just type InstallUtil and it will work. if you didn't set up the environment variables you will get an error message saying that 'installutil' is not recognized as an internal or external command, operable program or batch file.
what is the /k and what is the bat for this argument? Why do I need to pass a path as an argument to the command prompt?
/k is a parameter for cmd.exe and what it does is run the commands specified by the string that follows (in this case it will execute what's inside "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\VsDevCmd.bat" and will carry out).
What is Initial Directory?
Initial directory is used to specify the working directory that your cmd.exe instance will start in
So in the end you'll have something like this for Visual Studio 2015:
The "arguments" for VS2015 is :
/k "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\VsDevCmd.bat"
I took a look at my start menu and right clicked on Developer Command Prompt for VS2015. Copied target %comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\VsDevCmd.bat""
MSBuild Command Prompt for VS2015
Copied target %comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\VsMSBuildCmd.bat""
https://connect.microsoft.com/VisualStudio/feedback/details/747807/vs2012-x64-native-tools-command-prompt

What is the location of FINDSTR on all Windows OS from Windows XP to Windows server 2012?

Is the directory of findstr always C:\Windows\system32\ for all OS from Windows XP to server 2012?
Or in other words is it safe to replace the following expression in a windows batch file:
findstr
to
C:\Windows\system32\findstr
Extra information just for completeness.
Environment variable windir exists since Windows 95 and contains the path to Windows directory independent on which drive it is located and which name it has.
For NT based Windows (NT4, Windows 2000, Windows XP, Vista, Windows 7 / 8 / 8.1) there is additionally the environment variable SystemRoot which contains also the path to Windows directory as this is the parent directory for the system directories
System32
Sysnative (only Windows x64 and only for 32-bit applications)
SysWOW64 (only Windows x64)
For details about file system redirection read the File System Redirector page of Microsoft.
It is not only safe to use either
%windir%\System32\findstr.exe
or
%SystemRoot%\System32\findstr.exe
I would highly recommend using always one of those two strings in batch files as then it does not depend which folders are in environment variable PATH and which file extensions in environment variable PATHEXT.
There are some bad installers which add the folder path of the installed application to system environment variable PATH at beginning instead of appending at end and contain in the application's folder also find.exe or findstr.exe which are portings from Unix and therefore work completely different than find.exe and findstr.exe of Windows. AVRStudio is (or perhaps was as not verified with latest version of AVRStudio) an example breaking batch files of IT administrators not using always complete file name for Windows commands after installation.
Rather %windir%\system32\findstr.exe as its possible windows to be installed on different than C:\ drive.
I am afraid I don't understand the purpose of your question, so I rephrase it in a slightly different way.
If you type findstr in a computer and the FINDSTR command run, then you may know the location of such findstr command this way:
for %%a in (findstr.exe) do echo %%~$PATH:a
So you may replace the following expression:
findstr
... by the next two lines:
for %%a in (findstr.exe) do set "findstrPath=%~$PATH:a"
%findstrPath%
... in a Windows Batch file and you will get exactly the same result.
So, the question arises: if you get the same result in both cases, why do you want to use the second, more complicated one?
Note also that the same point apply with any other external command like find, xcopy, forfiles, etc. Why findstr would be special in this point?
As I said before, I don't understand the purpose of your question...

I cannot use the msg command in cmd (or batch for that matter). How can I fix this?

While in cmd or making a batch file, I cannot use the command msg. When I try to use it, it returns the error msg is not recognized as an internal or external command, operable program or batch file." I'm pretty sure the error is that im missing a msg.exe in system32, so could someone show how to obtain that? I'm running windows 8.1.
msg.exe is not available on all Windows platforms in all environments.
There is just %SystemRoot%\System32\msg.exe (64-bit), but no %SystemRoot%\SysWOW64\msg.exe (32-bit) on Windows 7 x64 Enterprise whereby 64-bit msg.exe must be accessed from within a 32-bit command process by using %SystemRoot%\Sysnative\msg.exe.
For details about System32, SysWOW64 and Sysnative see the Microsoft documentation page File System Redirector.
What does this mean?
A batch file being executed on 32-bit Windows needs to run %SystemRoot%\System32\msg.exe.
A batch file being executed on 64-bit Windows by 64-bit cmd.exe needs to run %SystemRoot%\System32\msg.exe.
A batch file being executed on 64-bit Windows by 32-bit cmd.exe needs to run %SystemRoot%\Sysnative\msg.exe.
It depends on architecture of parent process starting cmd.exe or the batch file which implicitly results in starting cmd.exe for execution of the batch file if the batch file is executed in 32-bit or 64-bit environment on 64-bit Windows.
So a batch file is called with using explicitly %SystemRoot%\Sysnative\cmd.exe from a 32-bit application on Windows x64 or inside the batch file %SystemRoot%\Sysnative\msg.exe is used on a Windows x64 machine while on a Windows x86 machine %SystemRoot%\System32\cmd.exe respectively %SystemRoot%\System32\msg.exe must be used.
Demo example for first variant with using 64-bit command line interpreter:
Batch file with name MsgDemo.bat:
#echo off
%SystemRoot%\System32\msg.exe /?
pause
is called from 32-bit process running on Windows x64 with:
%SystemRoot%\Sysnative\cmd.exe /C MsgDemo.bat
Demo example for second variant with referencing msg.exe correct:
#echo off
set "AppMsg=%SystemRoot%\System32\msg.exe"
if not "%ProgramFiles(x86)%" == "" (
rem Explicitly reference 64-bit version on Windows x64 as there is
rem no 32-bit version. But use Sysnative redirector only if the batch
rem file was started with 32-bit cmd.exe as otherwise System32 contains
rem msg.exe if it is not missing at all like on Windows 7 Home Premium.
if exist %SystemRoot%\Sysnative\* set "AppMsg=%SystemRoot%\Sysnative\msg.exe"
)
%AppMsg% /?
set "AppMsg="
pause
The redirector %SystemRoot%\Sysnative doesn´t exist for 64-bit processes, just for 32-bit processes.
%SystemRoot%\Sysnative is not a directory. Therefore if exist %SystemRoot%\Sysnative does not work, just if exist %SystemRoot%\Sysnative\*.
Copy msg.exe from any windows 7 PC from system32 and past target PC system32 directory.
Work fine for me

Resources