是否可以从 Python 可执行文件访问启动快捷方式目录?

Posted

技术标签:

【中文标题】是否可以从 Python 可执行文件访问启动快捷方式目录?【英文标题】:Is it possible to access the launching shortcut directory from a Python executalbe? 【发布时间】:2018-02-26 23:01:13 【问题描述】:

我目前有一个 Python 脚本,它遍历当前目录中的所有 Excel 文件并生成 PDF 报告。

它现在工作正常,但我不希望用户靠近冻结的 Python 脚本。我使用 cxFreeze 创建了一个 MSI,它将 EXE 和脚本放在 Program Files 目录中。

我想做的是为这个可执行文件创建一个快捷方式,并将运行快捷方式的目录传递给 Python 程序,以便可以将其设置为工作目录。这将允许用户将快捷方式移动到 Excel 文件的任何文件夹并在那里生成报告。

Windows 是否将打开的快捷方式的位置发送到可执行文件,有没有办法从 Python 访问它?

【问题讨论】:

您想要运行 .LNK 快捷方式的父进程的工作目录吗?如果是这样,请将“开始于”字段留空以继承该父级的工作目录。从命令行运行快捷方式时,我有时会使用这种方法。我在PATHEXT 中有 .LNK,因此我不必显式键入 .lnk 文件扩展名。 但是你问“[d]oes Windows 发送打开的快捷方式的位置”?那不是工作目录。但是您也可以获得这些信息。拨打GetStartupInfo获取进程启动信息。如果dwFlags 包含STARTF_TITLEISLINKNAME,则lpTitle 字段是.LNK 快捷方式文件的路径。请记住,您的快捷方式应该直接运行调用GetStartupInfo 的进程的可执行文件。如果解包并执行另一个程序,这可能与冻结的脚本不兼容。 【参考方案1】:

当您启动快捷方式时,Windows 会将工作目录更改为快捷方式中指定的目录,在 Start in 字段中。此时,Windows 不知道快捷方式的存储位置。

您可以更改 Start in 字段以指向快捷方式所在的目录。但您必须对每个快捷方式都这样做,并且永远不要出错。

更好的方法是使用脚本,而不是快捷方式。将您的实际 Python 脚本(例如,我们将其称为 doit.py)放在您的 PYTHONPATH 中的某个位置。然后创建一个导入它的单行 Python 脚本:

import doit

保存它(但不要将其命名为doit.py)并将其复制到您希望能够从中调用主脚本的每个目录中。在doit.py 中,您可以使用os.getcwd() 找出您正在从哪个目录调用。

您也可以使用批处理文件来完成。这更灵活一点,因为您可以指定脚本的确切名称以及应该使用哪个 Python 解释器,并且不需要将脚本存储在 PYTHONPATH 的目录中。此外,您不必担心文件名与 Python 模块的名称冲突。只需将这一行放在一个文件中:

C:\path\to\your\python.exe C:\path\to\your\script.py

将其保存为(例如)doit.bat 并将其复制到您要从中调用它的目录中。和以前一样,您的 Python 脚本可以调用 os.getcwd() 来获取目录。或者您可以编写它,以便您的 Python 脚本接受它作为第一个参数,然后编写您的批处理文件,如下所示:

C:\path\to\your\python.exe C:\path\to\your\script.py %cd%

您可以使用批处理文件方法做的另一件事是在末尾添加一个pause 命令,以便在脚本运行后要求用户按下一个键,让他们有机会读取脚本生成的任何输出.您甚至可以将此设置为有条件的,以便仅在发生错误时发生(这需要从脚本返回正确的退出代码)。我会把它留作练习。 :-)

【讨论】:

目标机器将没有 Python,这主要是我使用 cxFreeze 来简化事情的原因。这仍然有效吗?我需要将参数传递给exe,对吗?没想到bat文件,比快捷方式好多了。 我不确定冻结它会对工作目录产生什么影响,但是通过冻结只打印工作目录的脚本来检查很容易...... “此时,Windows 不知道快捷方式的存储位置”。不,是进程启动信息的lpTitle字段。 " 在 doit.py 中,您可以使用 os.getcwd() 找出您正在从哪个目录调用"。 os.getcwd() 与脚本的位置无关。它是 Python 进程的当前工作目录,它要么继承自父进程,要么由父进程显式设置。当您从资源管理器窗口运行文件时,它会将工作目录更改为该文件。如果从 Win+R 对话框运行它,则工作目录是用户配置文件目录。在其他情况下,它是 System32 目录 - 或几乎任何取决于父级的目录。 批处理脚本的位置是%~dp0(即参数0的驱动器和路径)。【参考方案2】:

修改脚本以将要处理的目录作为命令行参数是否有问题?

然后您可以配置不同的快捷方式以传递到相应的目录。

【讨论】:

【参考方案3】:

在批处理文件中键入以下内容(即script.bat):

python \absolute\path\to\your\script.py %~dp0
pause

然后将这些导入添加到您的 python 文件 script.py 的顶部(如果尚未包含):

import os
import sys

并将其添加到python文件的底部(或将其与类似的语句结合起来):

if __name__ == "__main__":
    # set current working directory:
    if len(sys.argv) > 1:
        os.chdir(sys.argv[1])

    main()

main() 替换为您要调用的任何函数或要运行的代码。


以下是我的答案:

我尝试使用kindall's answer 并遇到以下问题:

将脚本存储在PYTHONPATH 某处的第一个建议不适用于我的情况,因为我的脚本将在服务器上使用并且需要独立于客户端计算机的 python 环境(除了具有所需的 pip 安装) .

我尝试从可以移动到不同位置的 Windows 批处理文件中调用我的 python 脚本。不是将批处理文件的位置用作当前工作目录,而是 C:\Windows

我尝试将%cd% 作为参数传递给我的python 脚本,然后将其设置为我的CWD。这仍然导致 CWD 为 C:\Windows

在查看了 cmets 之后,我尝试了 Eryk Sun's suggestion,而不是将 %~dp0 作为参数传递给 python 脚本。这导致 CWD 被正确设置为批处理文件的位置。

我希望这可以帮助其他面临类似困难的人。

【讨论】:

以上是关于是否可以从 Python 可执行文件访问启动快捷方式目录?的主要内容,如果未能解决你的问题,请参考以下文章

Vista启动时访问冲突

是否可以访问可执行 JAR 之外的 SQLite 数据库文件?

编辑 PE 可执行文件以使其在启动时加载指定的 DLL 的最简单快捷的方法是啥?

从 iOS 可操作通知交叉启动其他应用程序

从 python 源构建 Windows 可执行文件

Python更改使用startfile打开的exe的工作目录