我正在尝试为使用pywin32绑定编辑某些Excel电子表格的程序创建安装程序。我使用py2exe创建了一个可执行文件,当从桌面上的文件夹中运行可执行文件时,一切正常。但是,我希望能够分发一个安装程序文件,该文件将程序安装到任何系统上的C:\ Program Files \或等效文件夹中。我也成功了,但是,当使用pywin32绑定时,它们会在工作目录所在的位置创建临时文件。
这是非常有问题的,因为较新版本的Windows使得只有管理员才有权写入这些目录。因此,当从这些目录运行应用程序时,它失败并显示错误:
WindowsError: [Error 5] Access is denied: 'C:\\Program Files (x86)\\DataPlotter\\.\\win32com\\gen_py\
\00020813-0000-0000-C000-000000000046x0x1x6'
将应用程序更改为以管理员权限运行是一个糟糕的解决方案,因为它可能会引入漏洞。
是否有人知道此问题的修复程序或如何更改pywin32绑定用作临时文件位置的位置。
答案 0 :(得分:1)
我在关于如何使用contextlib.contextmanager
装饰器将代码转换为上下文管理器的答案的评论中描述的方式稍微过于简单,如果您希望恢复上一个当前目录,即使发生了未处理的异常。要实现这一目标,还需要在try
周围添加finally
... yield
条款(见下文)。
另外,我认为将它作为独立函数而不是某个类的方法以及将其作为参数切换到的目录传递它会更好 - 这两者都使它更通用且更容易重复使用。我称它为pushd()
,因为它具有同名的Windows和Unix shell命令的similarities。
from contextlib import contextmanager
import os
import tempfile
@contextmanager
def pushd(dir=None):
""" Context manager which saves the current working directory before
changing either to the one passed or the default folder for temporary
files and then restores the former after the controlled suite of
statements have executed. This will happened even if an unhandled
exception occurs within the block. """
cwd = os.getcwd()
os.chdir(dir if dir is not None else tempfile.gettempdir())
try:
yield
finally:
os.chdir(cwd)
# sample usage
with pushd():
self.xl = win32com.client.gencache.EnsureDispatch("Excel.Application")
执行yield cwd
而不是任何允许任何可选as
变量接收指示前一个当前工作目录的值的内容可能也很有用,以便在块内进行可能的引用。
答案 1 :(得分:0)
这是一个愚蠢的hack-y解决方案,但可以通过在pywin32上执行一个解决方法来避免这个问题。
通过将当前工作目录切换为保证可以安全写入的目录,例如临时目录,可以避免此问题。
#Save the current working directory and then switch back once
#excel has been started. This is so pywin32 does not ruin everything
#by trying to write in the current directory without the proper
#permission. This mainly happens (for me) when the program is installed in
#program files which requires administrator permissions to write to.
import os
import tempfile
import win32com.client
cwd = os.getcwd()
tdir = tempfile.gettempdir()
os.chdir(tdir)
self.xl = win32com.client.gencache.EnsureDispatch("Excel.Application")
os.chdir(cwd)
N.B。最后的开关回到原始工作目录是没有必要的,但是如果你需要的话它会起作用(就像我一样)。
martineau使用上下文管理器提出了一种更强大的方法:
from contextlib import contextmanager
@contextmanager
def tempManager(self):
cwd = os.getcwd()
tdir = tempfile.gettempdir()
os.chdir(tdir)
yield
os.chdir(cwd)
with self.tempManager():
self.xl = win32com.client.gencache.EnsureDispatch("Excel.Application")