0

I've spent the last I don't even know how long troubleshooting this, and I finally found it out. I've been trying to run this line of code:

system("C:\\Users\\Public\\automate.bat");

But instead of executing the script once, it repeatedly executed the first line of my script (in an infinite loop). I found that the path it was using for windows CMD was C:\Windows\SysWOW64\cmd.exe while the windows default is C:\Windows\System32\cmd.exe. I went to the SysWOW cmd and ran my script and the looping issue happened, while the same script worked flawlessly on the System32 CMD. (I suspect because of some incompatibility in my code that caused the SysWOW cmd to fail). I would like to know how to change the cmd.exe path on C so that it points to windows' default cmd, and not the one in SysWOW.

Currently, the only thing I've tried is:

system("C:\\Windows\\System32\\cmd.exe /c C:\\Users\\Public\\automate.bat");

Which is not working.



EDIT: The first action of my BAT file is to ask for administrator perms, which is where the window seems to close, and reopen itself:

@echo off

:: BatchGotAdmin
:-------------------------------------
REM  --> Check for permissions
    IF "%PROCESSOR_ARCHITECTURE%" EQU "amd64" (
>nul 2>&1 "%SYSTEMROOT%\SysWOW64\cacls.exe" "%SYSTEMROOT%\SysWOW64\config\system"
) ELSE (
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"
)

REM --> If error flag set, we do not have admin.
if '%errorlevel%' NEQ '0' (
    echo Requesting administrative privileges...
    goto UACPrompt
) else ( goto gotAdmin )

:UACPrompt
    echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
    set params= %*
    echo UAC.ShellExecute "cmd.exe", "/c ""%~s0"" %params:"=""%", "", "runas", 1 >> "%temp%\getadmin.vbs"

    "%temp%\getadmin.vbs"
    del "%temp%\getadmin.vbs"
    exit /B

:gotAdmin
    pushd "%CD%"
    CD /D "%~dp0"
:--------------------------------------
cd "C:\Users\Public"
:: more stuff here
Ken White
  • 123,280
  • 14
  • 225
  • 444
hi im lost
  • 11
  • 3
  • 2
    The intriguing thing here is why `automate.bat` behaves differently - please edit that file into your post. The version of `cmd` used by default is the first instance of `cmd` located in your `path`. You should be able to run the `system32` version in preference by altering your path such the `system32` appears earlier than `syswow64`. – Magoo Apr 23 '22 at 19:06
  • 1
    The function [system](https://learn.microsoft.com/en-us/cpp/c-language/system-function) makes use of the environment variable `ComSpec` which is defined as system environment variable with the value `%SystemRoot%\System32\cmd.exe`. See also the Microsoft documentation for [system, _wsystem](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/system-wsystem) for more detailed information. – Mofi Apr 23 '22 at 19:16
  • 2
    The Windows [File System Redirector](https://learn.microsoft.com/en-us/windows/win32/winprog64/file-system-redirector) redirects on 64-bit Windows from 64-bit `%SystemRoot%\System32\cmd.exe` to 32-bit `%SystemRoot%\SysWOW64\cmd.exe` if the executable compiled from C code is a 32-bit x86 application. A batch file required to be executed by 64-bit `cmd.exe` on 64-bit Windows could contain a line to make sure this requirement is fulfilled like with `if exist %SystemRoot%\Sysnative\cmd.exe %SystemRoot%\Sysnative\cmd.exe /C %0 %* & exit /B` to give here just one example. – Mofi Apr 23 '22 at 19:21
  • 1
    Don't use the function `system` if your C code is just for a Windows application. It would be better to use the Windows kernel library function [CreateProcess](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa) with the [STARTUPINFO](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfoa) structure as that is the function finally used also by `system` to start `cmd.exe`. – Mofi Apr 23 '22 at 19:35
  • I recommend to get in C code the string value of environment variable `PUBLIC` and use `"C:\\Users\\Public"` just in case of this predefined environment variable does very unlikely not exist at all. That can happen only if this environment variable was deleted before running your program or your program was started with `CreateProcess` with a special list of environment variables. There should be used also the predefined Windows environment variable `SystemRoot` for the Windows directory with the string `"C:\\Windows"` in case of `SystemRoot` is very unlikely not defined at all. – Mofi Apr 23 '22 at 19:36
  • Well, even better would be using the function [GetSystemDirectory](https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemdirectory) to get the path of the real Windows system directory containing `cmd.exe` and the function [SHGetKnownFolderPath](https://docs.microsoft.com/es-es/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath) with the [KNOWNFOLDERID](https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid) `FOLDERID_Public` to get the path of the public folder. Then your program would never fail to work with the correct directories. – Mofi Apr 23 '22 at 19:43
  • why do you compile a 32-bit app nowadays? – phuclv Apr 24 '22 at 03:54
  • I turn UAC off as a matter of course, so I'm no permissions expert. It appears this "get admin" routine appeared in https://stackoverflow.com/a/10052222/2128947 and has been endlessly regurgitated since. I'm puzzled by (but not interested in) the inial command - to run `cackles` from SYSWOW for `amd64` otherwise from SYSTEM32. The way I read it, the batch is resubmitted by the `UAC.ShellExecute "cmd.exe", "/c ""%~s0"" %params:"=""%"` which has VBS execute cmd with the original command line for the batch. I'd suggest changing `"cmd.exe"` here to `"%SYSTEMROOT%\system32\cmd.exe"` forcing Sys32 – Magoo Apr 24 '22 at 06:10
  • @Magoo The explicit usage of `%SystemRoot%\system32\cmd.exe` is of no help here. The program compiled from the C code is an x86 application. For that reason the usage of `system()` results in starting `%ComSpec% /c ` with the command line in the string in the C code appended as arguments. `%ComSpec%` is defined with `%SystemRoot%\System32\cmd.exe` and __system__ `PATH` contains as first path usually also `%SystemRoot%\System32`. But Windows on Windows 64 is active for x86 applications. For that reason the File System Redirector makes its job and executed is `%SystemRoot%\SysWOW64\cmd.exe`. – Mofi Apr 24 '22 at 11:04
  • The 32-bit version of `cmd.exe` processes the batch file. The __IF__ condition `IF "%PROCESSOR_ARCHITECTURE%" EQU "amd64"` evaluates to `false` in this case because of the environment variable `PROCESSOR_ARCHITECTURE` is defined in 32-bit execution environment on 64-bit Windows with `x86` as described by Microsoft on the documentation page [WOW64 Implementation Details](https://docs.microsoft.com/en-us/windows/win32/winprog64/wow64-implementation-details). The environment variable `PROCESSOR_ARCHITECTURE` cannot be used to find out if a batch file is executed on 32-bit or 64-bit Windows. – Mofi Apr 24 '22 at 11:07
  • So the batch file is processed by x86 version of `cmd.exe` independent on using just `cmd` or `cmd.exe` or `%SystemRoot%\System32\cmd.exe`. `"%temp%\getadmin.vbs"` results in searching by `cmd.exe` for the application to run the VBScript. There is registered to use either `%SystemRoot%\System32\wscript.exe` (default) or `%SystemRoot%\System32\cscript.exe` (on user changed the default). 32-bit version of `cmd.exe` runs this executable, but the file system redirector redirects to `%SystemRoot%\SysWOW64\wscript.exe` or `%SystemRoot%\SysWOW64\cscript.exe`. So started is 32-bit Windows Script Host. – Mofi Apr 24 '22 at 11:12
  • The execution of `%SystemRoot%\System32\cmd.exe` by the x86 version of Windows Script Host is redirected by the File System Redirector to `%SystemRoot%\SysWOW64\cmd.exe` and the batch file is again processed by the x86 version of `cmd.exe` on 64-bit Windows AMD in elevated x86 execution environment. So there is either used in C code the function [Wow64DisableWow64FsRedirection](https://docs.microsoft.com/en-us/windows/win32/api/wow64apiset/nf-wow64apiset-wow64disablewow64fsredirection) before using `system()` or the batch file code is rewritten to switch explicitly to 64-bit `cmd.exe`. – Mofi Apr 24 '22 at 11:17
  • Please read my long answer on [Can't run as Admin](https://stackoverflow.com/a/41493926/3074564) with much better code to run a batch file in an elevated execution environment with always being interpreted finally by 64-bit `cmd.exe` on batch file processed initially by 32-bit `cmd.exe` on 64-bit Windows because of an x86 application started `cmd.exe` for processing the batch file. The batch file code looks very long, but after removal of all lines starting with `rem` (all comments/remarks), the code is very small and really works in all cases in comparison to most similar solutions. – Mofi Apr 24 '22 at 11:21

1 Answers1

0

Finally found a solution to this! After tinkering around with my environment variables, I found that there was a conflict between user and system variables with different ComSpec paths. After changing them both to the system32 folder, they worked flawlessly. Thanks for all the helpful comments everyone!

hi im lost
  • 11
  • 3