0

I've made a script (called isPA64.bat) to determine if the executing system is 64-bit (based on this Bear's Log tip):

@echo off
setlocal
set str1=%PROCESSOR_ARCHITECTURE%
set/A sixty4=0
if not x%str1:64=%==x%str1% set/A sixty4=1
endlocal & exit/B %sixty4%

It gets called from another simple batch, named callpa.bat (it could be called directly, too, but this proves that ERRORLEVEL does, indeed, get set appropriately):

@echo off
ver>nul & (call isPA64.bat & if ERRORLEVEL 1 (echo 64-bit & exit/B 1) else (echo not 64-bit & exit/B 0))

Up to this point, this all works fine; however, I must call one of these two from a Python 3.7.2 program. I do this:

import subprocess
print(subprocess.run(["callpa.bat"]))

Simple enough, right? But I haven't been able to figure out how to get a valid return code back, in the python code... Is there a way to assign a variable in the python code to either the "exit"/return code or to the value of ERRORLEVEL, from the cmd.exe shell which executes the outer-level script? ...I can't find a way in the python doc's to do that.

Rob F.
  • 13
  • 3
  • Are you saying that `print(subprocess.run(["callpa.bat"]))` doesn't show you the right return code, or that it does and you just don't know how to programmatically get at it? – Joseph Sible-Reinstate Monica Jan 02 '20 at 01:56
  • Why not have just one batch file, `callpa.bat`, _there's no need for `isPA64`_: `@If %PROCESSOR_ARCHITECTURE:~-2% Equ 86 (If Defined PROCESSOR_ARCHITEW6432 (Exit /B 0)Else Exit /B 1)Else Exit /B 0`. You'll also note that I've used more robust code too, as a 64-bit system running under a 32-bit process will incorrectly return x86 without the additional check. – Compo Jan 02 '20 at 03:31
  • You might even find that disposing of both batch files and doing a similar thing by directly reading the environment variables, after `import`ing `os` and reading `os.environ['PROCESSOR_ARCHITECTURE']` and `os.environ['PROCESSOR_ARCHITEW6432']` works for you. – Compo Jan 02 '20 at 03:41
  • Why not trying to detect the "bitness" directly in Python? Refer to [Detect 64bit OS (windows) in Python](https://stackoverflow.com/q/2208828) as well as [How to detect whether the OS supports 16-bit exes in Python?](https://stackoverflow.com/q/9456171) – aschipfl Jan 02 '20 at 10:14
  • Tried rc=subprocess.call("callpa.bat", shell=True)--tried Shell=False, too--but I always get a 0 ('echo %ERRORLEVEL%') on 64-bit machine (running 32-bit python--but w/ my code, that shouldn't matter); I should get a 1, as that is also what "callpa.bat" gives, when run directly from same Command Prompt window as Python app. I do plan to use a single Batch file, eventually--or even a better solution--however, the outer-level app is co-maintained in Batch _and_ Python, so am hoping to re-use isPA64.bat (or an improved .bat, like Compo's)....want to keep 2 versions of app similar, for ease. – Rob F. Jan 02 '20 at 14:01
  • The value of environment variable `PROCESSOR_ARCHITECTURE` depends on 64-bit Windows if a 32-bit or a 64-bit application is accessing it. The environment variable value is `x86` and not `AMD64` as most likely expected by you if the Python script is interpreted by 32-bit `python.exe` running on 64-bit Windows. See the Microsoft article about [WOW64 Implementation Details](https://learn.microsoft.com/en-us/windows/desktop/WinProg64/wow64-implementation-details). It is better to check if environment variable `ProgramFiles(x86)` is defined at all which is the case only on 64-bit Windows. – Mofi Jan 02 '20 at 17:53
  • It is next possible to find out if the current process is a 32-bit process running on 64-bit Windows by checking if the file with path `%SystemRoot%\Sysnative\cmd.exe` exists whereby `SystemRoot` is also a predefined environment variable which contains the path to Windows directory. `%SystemRoot%\Sysnative\cmd.exe` exists only for 32-bit processes running on 64-bit Windows, see the Microsoft article about [File System Redirector](https://docs.microsoft.com/en-us/windows/desktop/WinProg64/file-system-redirector). There is no batch file needed to find out all that from within a Python script. – Mofi Jan 02 '20 at 17:53
  • @Joseph Sible-Reinstate Monica Your first comment/question get's to the heart of the _real_, ongoing problem: that my call `print(subprocess.run(["callpa.bat"]))` always returns a 0, even when I expect a 1. Am I interpreting the return value of this python function in the wrong way? Do I need to look elsewhere, like at some kind of CalledProcessError object? ...Or (unlikely?) is there a bug in the python subprocess.run() and/or subprocess.call() functions' return-value code? – Rob F. Jan 03 '20 at 03:21
  • I see the problem now:: Compo's first comment, above, identifies the issue. I did not realize that, even though my 32-bit python runs from the same Command Prompt as the raw is64PA.bat, they will give different results _because_ (I think) the python runs in a 32-bit mode, while running the batch direct will execute it in a 64-bit mode. It seems I made a bad assumption there. ...Thanks everyone for the kind discussion and various solutions, some more robust than others, but all beneficial in some way. – Rob F. Jan 03 '20 at 03:47
  • After some [much simpler] experimentation, I see that Mofi's recommendation to check if environment variable `ProgramFiles(x86)` is defined, is a much better way to achieve what I want. It works on my 32-bit machine running xp batch; it works on my 64-bit machine running Win 8.1 with 32-bit python installed (and the raw batch-file check runs and works fine there, too, of course). Here's my new "isPFx86defined.bat" batch: `@if defined ProgramFiles(x86) (echo Programfiles^(x86^) is defined & exit/B 1) else (echo undefined & exit/B 0)` I consider this to be a full and adequate solution. – Rob F. Jan 03 '20 at 04:39

1 Answers1

0

No need of creating other batch files:

import os
arch = os.environ['PROCESSOR_ARCHITECTURE']
if arch == 'x86':
    print("x86")
    exit(0)
else:
    print("x64")
    exit(1)

Then import it be errorlevel variable.

WMI can be also used:

import sys
import win32com.client
wmiservice = win32com.client.dispatch("WbemScripting.SWbemLocator")
swbemservice = wmiservice.ConnectServer(., "root/cimv2")
items = swbemservice.ExecQuery("Select * From Win32_OperatingSystem")
for item in items:
    if item.OSArchitecture == 'x86':
        print("x86")
        exit(0)
    else:
        print("x64")
        exit(1)

You need to download python for windows extensions from http://sourceforge.net/projects/pywin32/files/

Wasif
  • 14,755
  • 3
  • 14
  • 34
  • 1
    I thought you said you were going to reduce these kind of answers! The ones where you take other people's comments and put them as answers. Anyhow your code is either incomplete or only valid from python x64 and incorrect/backwards too. The reason for that was clearly explained in my comments too. You also should be checking for a defined variable named `PROCESSOR_ARCHITEW6432`, when `os.environ['PROCESSOR_ARCHITECTURE']` returns x86. _Of course if you knew you were running python x64, you'd already know it was an x64 system so you should assume that the architecture of python.exe is unknown._ – Compo Jan 02 '20 at 13:09
  • I've read, "The modern way, since Python 2.4, is using subprocess module" (rather than using os), so I am trying to implement something like subprocess.call(), instead......but thanks, because I did not know about os.environ, which looks like a possible fall-back solution. – Rob F. Jan 02 '20 at 13:38
  • Actually, Mofi (in my original post's comments) hit upon what I really want: to programmatically set the correct path to another program on which my app depends, i.e., is that program installed in "...\Program Files (x86)\..." or is it in "...\Program Files\..."? (Using `ProgramFiles(x86)` seems a good detector, too.) ...All good discussion, but we digress: I've yet to determine why my python `rc=subprocess.call("isPA64.bat")` gives the _wrong_ rc on a 64-bit system, running 32 mode, when the straight call of `isPA64.bat` from the same Command Prompt _does_ give the correct rc. – Rob F. Jan 03 '20 at 03:13
  • Sorry for the late reply Mofi your observation is 100% correct. It was a very miserable misunderstanding. And I can't test it on 64-bit pc as i have 32-bit. And Compo I am including other way. I retain that I copied your comment several times but this time I extended your comment and turned it into full code. – Wasif Jan 03 '20 at 09:28