3

in one simple Python program for testing users environment, I should also get version of installed Word (example: WinWord 16, 64-bit). Any idea how to do that? I'm sure, that different GUIDs should exist, but where can I find them :-)

**** edit

I checked both suggestions, but it isn't enough. I have to get an information if Word is 32- or 64-bit. Until now, I have checked location of "winword.exe". For example: 1. location for 64-bit Office 15 c:\program files\microsoft office\office15\winword.exe 2. location for 32-bit Office 15 c:\program files (x86)\microsoft office\office15\winword.exe

I'm sure that M$ has list of GUIDs (used in registry) for latest versions of Word. But I can't find the list :-) With suggested solutions, I can't check 32- or 64- technology.

JanezKranjski
  • 225
  • 3
  • 15
  • Just wanted to make sure you saw my updated version. It detects the architecture as well as what version. – Neil Nov 15 '17 at 09:15
  • Tnx "nfn neil" ... but it is even more complicated. I have many computers with 64-bit OS, but with 32-bit Office. In my case, all information (Word version) are important. – JanezKranjski Nov 15 '17 at 10:04
  • That's exactly what it does, let me know if you find a better way. – Neil Nov 15 '17 at 10:44
  • Sorry, I didn't check your code carefully. Now I understand. But after I tried, I have found that many computers don't use the same folder for Start shortcut (there can be a shortcut for Word in subfolders for example). But otherwise it should work. My current solution is checking a list of standard winword.exe folders. From location you can see if Office is 32 or 64-bit. I know that this also isn't perfect solution, but it works for now. – JanezKranjski Nov 15 '17 at 16:14
  • But to be honest, I like your solution. As I'm a Python noob - what should I change in for loop to check all subfolders and find a shortcut there? – JanezKranjski Nov 15 '17 at 16:20
  • Updated the code with a recursive method of finding the directory. – Neil Nov 15 '17 at 19:59
  • Super, it works on all tested computers. Neil, you are the MAN :-) This checking inside subfolders was too complicated for someone who don't know Python ... – JanezKranjski Nov 16 '17 at 04:59
  • Hey, if you could mark as solution and upvote, it'd help a lot. And thanks! This was one of the more fun problems I've run into. – Neil Nov 16 '17 at 05:12
  • Done. Thank you. – JanezKranjski Nov 16 '17 at 06:01
  • Now, suddenly (without any changes in this function), I get an error: The term './SamplePowershell' is not recognized as the name of a cmdlet, function, script file, or operable program . Check the spelling of the name, or if a path was included, verify that the path is correct and try again. At line:1 char:3 + . "./SamplePowershell"; (New-Object -ComObject WScript.Shell).CreateS ... + ~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (./SamplePowershell:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException – JanezKranjski Nov 16 '17 at 07:48
  • I updated it, it should now work. It actually runs substantially faster now too. – Neil Nov 16 '17 at 08:16
  • Super, it works now. I searched for "SamplePowershell" parameter, but I didn't find anything (what can help me :-)). – JanezKranjski Nov 16 '17 at 10:19
  • I simply removed it. Come to find out the code didn't need it. I guess my initial interpretation of the code was wrong. – Neil Nov 16 '17 at 19:53

2 Answers2

2

Searching shorcuts with architecture detection (32-bit or 64-bit)

I figured the additional information would be useful, but you can reduce it to just 32-bit and 64-bit.

import subprocess, os, struct

def getWordVersion():
    directory = "C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs"
    wordFile = ""
    wordVersion = ""

    def recursiveSearch(directory):
        for root, dirs, filenames in os.walk(directory):
            for dire in dirs:
                result = recursiveSearch(root + "\\" + dire)
                if result:
                    return result
            for filename in filenames:
                if filename.endswith(".lnk") and filename.startswith("Word "):
                    wordFile = root + "\\" + filename
                    wordVersion = filename[:-4]
                    return wordFile, wordVersion
        return False

    wordFile, wordVersion = recursiveSearch(directory)

    lnkTarget = subprocess.check_output(["C:\\WINDOWS\\system32\\WindowsPowerShell\\v1.0\\powershell.exe",
                      "(New-Object -ComObject WScript.Shell).CreateShortcut('" + wordFile + "').TargetPath"],shell=True)
    locationOfLnk = lnkTarget.strip()

    IMAGE_FILE_MACHINE_I386=332
    IMAGE_FILE_MACHINE_IA64=512
    IMAGE_FILE_MACHINE_AMD64=34404
    f=open(locationOfLnk, "rb")

    f.seek(60)
    s=f.read(4)
    header_offset=struct.unpack("<L", s)[0]
    f.seek(header_offset+4)
    s=f.read(2)
    machine=struct.unpack("<H", s)[0]
    architecture = ""

    if machine==IMAGE_FILE_MACHINE_I386:
        architecture = "IA-32 (32-bit x86)"
    elif machine==IMAGE_FILE_MACHINE_IA64:
        architecture = "IA-64 (Itanium)"
    elif machine==IMAGE_FILE_MACHINE_AMD64:
        architecture = "AMD64 (64-bit x86)"
    else:
        architecture = "Unknown architecture"

    f.close()
    return wordVersion + " "  + architecture

print(getWordVersion())

Registry Method

A method is to loop through all registry keys under Office and find the most recent one. Unfortunately, Microsoft decided it was a great idea to change the install directory in nearly every version. So, if you want to compile a complete list of all install locations, that'd work to (unless they installed it at a custom location).

Note: This is Python 3 code, if you need Python 2, then change winreg to _winreg.

import winreg

def getMicrosoftWordVersion():
    key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Office", 0, winreg.KEY_READ)
    versionNum = 0
    i = 0
    while True:
        try:
            subkey = winreg.EnumKey(key, i)
            i+=1
            if versionNum < float(subkey):
                versionNum = float(subkey)
        except: #relies on error handling WindowsError as e as well as type conversion when we run out of numbers
            break
    return versionNum


print(getMicrosoftWordVersion())
Neil
  • 14,063
  • 3
  • 30
  • 51
  • Tnx, I will check. – JanezKranjski Nov 15 '17 at 08:48
  • Program shortcut method relies on standard shortcut place and name which could be changed by the user. Registry method is quite low-level (imho) – lospejos Nov 15 '17 at 08:54
  • Yeah, I do agree. But, generally speaking, people do not modify the shortcuts that are created by the installation of Word into a folder that is predesignated for start menu shortcuts. Honestly, its kind of like saying 'a user could have changed that registry key'. Could they? Yes. Would they? Probably not. I tried to get yours working and I didn't have much luck with `win32com`. So, I'll leave my solution up. – Neil Nov 15 '17 at 08:55
0

Another way is using OLE/ActiveX/COM technology. This is a some kind of high-level version of provided "registry method". Assuming you're on Windows machine since this will not work on Linux in most cases:

#!/usr/bin/env python3
from win32com.client.dynamic import Dispatch

word = Dispatch('Word.Application')
print (word)
word_version = word.version
print (word_version)
  1. Create virtualenv: $ python -m venv ve
  2. Activate virtualenv: $ ve\Scripts\activate.bat
  3. Install pypiwin32: (ve)$ pip install pypiwin32
  4. Execute: (ve)$ python detect_msword_version.py

On my Windows machine output was:

Microsoft Word

16.0

lospejos
  • 1,976
  • 3
  • 19
  • 35