Wind_Explorer
Wind_Explorer

Reputation: 35

automatically create desktop shortcut for my exe file with python

I know how there is a post on the same question but it is for Java. I am working with Python and so far I see no posts similar but I made an app and have a custom installer for it. The download install procedure all went well but the only issue is with the fact that after installation ends the desktop shortcut is not there for users to use. For me I tried manually creating a desktop shortcut, upload to the resource server and the installer should use wget to drop it on the user's desktop. I used Powershell to fetch desktop location with

desktopLocation=str(os.system('powershell.exe [Environment]::GetFolderPath(""""Desktop"""")'))

but wget seems to not get it and asks user to enter desktop directory everytime. So my question will be if there is any way to make wget understand my plan here or is there other ways to locally build a desktop shortcut based on the user's desktop location. Problem with just inserting "%userprofile%\Desktop" can be found here.

Upvotes: 1

Views: 1158

Answers (1)

mklement0
mklement0

Reputation: 438153

os.system() doesn't allow you to capture output from the shell command launched (only the command's exit code is returned) - instead, the output streams are passed through to the console.

Use subprocess.run() instead (Python v3.5+; the command below is v3.6+ due to use of encoding identifier 'oem'), which gives you detailed control over the call:

import subprocess

# ...

desktopLocation = subprocess.run(
  [ 'powershell.exe', '-noprofile', '-c', '[Environment]::GetFolderPath("Desktop")' ], 
  capture_output=True,
  encoding='oem'
).stdout.strip()

Note:

  • By passing the arguments individually, Python takes care of synthesizing the command line for you (on Windows), including any required escaping; you may alternatively specify a single command-line string as shown below, but then you'll have to do embedded quoting and escaping yourself.

  • No shell (cmd.exe) is involved in the call by default; use shell=True if you do want to call via cmd.exe.

  • An object is returned whose .stdout property contains the captured stdout output, which - thanks to the encoding argument -is already decoded into a string (by default, you'd get a byte array on which you'd have to call .decode() later to convert it to a string).

    • Character-encoding caveat:
      • PowerShell uses the console's OEM code page (as reported by chcp) for encoding its output, which in turn defaults to the system's active OEM code page, as determined by the system locale (language for non-Unicode programs).
      • This means that only those 256 characters supported by the OEM code page can be represented in the output; for full Unicode support, the OEM code page must be set to UTF-8 (chcp 65001) first, and decoded with .decode('utf8') in Python. Windows 10 now allows you set both the OEM and the ANSI code page to UTF-8 system-wide, but this has far-reaching consequences; also, the feature is still in beta as of this writing - see this answer.
  • .strip() is used to trim the trailing newline from the output.


In older Python versions and in simple cases, you can use a legacy method such as subprocess.check_output():

import subprocess

# ...

desktopLocation = subprocess.check_output(
   'powershell.exe -noprofile -c [Environment]::GetFolderPath(\'Desktop\')'
).decode('oem')

Note:

  • As with subprocess.run(), no shell is involved, unless shell=True is also specified, and you may alternatively pass the executable and its arguments individually, as the elements of an array, as shown above.

  • The trailing newline is automatically stripped.

  • The merged stdout and stderr output is returned; the exit code cannot be examined; however, a nonzero exit code causes the call to fail.

  • Character-encoding caveat:

    • Encoding identifier 'oem' requires v3.6+; in earlier 3.x versions, use an explicit code-page name (e.g., '437 on US-English systems) or determine the active OEM code page programmatically.

    • In v2.x, this decoding doesn't work, resulting in misinterpreted non-ASCII characters, presumably, because .check_output() directly returns a string, which is where the misinterpretation happens. I don't know how to fix this problem.

Upvotes: 1

Related Questions