在将程序安装到Program Files时使用pywin32

时间:2012-08-20 19:47:24

标签: python py2exe pywin32 program-files

我正在尝试为使用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绑定用作临时文件位置的位置。

2 个答案:

答案 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")