使用PyInstaller onefile选项和清单将UAC设置为requireAdministrator [英] Setting UAC to requireAdministrator using PyInstaller onefile option and manifest

查看:168
本文介绍了使用PyInstaller onefile选项和清单将UAC设置为requireAdministrator的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,我一直在四处寻找这个问题.我正在使用-i -F -w和-m选项使用PyInstaller 2.0版构建名为GraphicScriptWizard.exe的应用程序.

Okay, I've been going around and around trying to figure this one out. I'm building an application called GraphicScriptWizard.exe using PyInstaller version 2.0 using the -i -F -w and -m options.

我已定义与-m选项一起使用的清单文件称为GraphicScriptWizard.exe.manifest,其内容如下:

The manifest file that I've defined to use with the -m option is called GraphicScriptWizard.exe.manifest and has the following content:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
  <assemblyIdentity version="1.0.0.0"
     processorArchitecture="x86"
     name="GraphicScriptWizard"
     type="win32"/> 

  <!-- Identify the application security requirements. -->
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel
          level="requireAdministrator"
          uiAccess="false"/>
        </requestedPrivileges>
       </security>
  </trustInfo>
</assembly>

使用此清单和命令行选项,我没有得到提示提升的可执行文件.

Using this manifest and the command line options, I'm not getting an executable that prompts for elevation.

出于完整性考虑,Pyinstaller生成的规范文件为:

For the sake of completeness, the spec file that gets generated by Pyinstaller is :

# -*- mode: python -*-
a = Analysis(['GraphicScriptWizard.py'],
             pathex=[<Full Development Path>],
             hiddenimports=[],
             hookspath=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name=os.path.join('dist', 'GraphicScriptWizard.exe'),
          debug=False,
          strip=None,
          upx=True,
          console=False , icon='SP.ico', manifest='GraphicScriptWizard.exe.manifest')
app = BUNDLE(exe,
             name=os.path.join('dist', 'GraphicScriptWizard.exe.app'))

我尝试使用不带-m选项的pyinstaller进行编译,并使用以下命令嵌入mt:

I've tried compiling with pyinstaller without the -m option and embedding with mt using the command:

mt.exe -manifest GraphicScriptWizard.exe.manifest -outputresource:GraphicScriptWizard.exe;#1

当我这样做时,应用程序会提示我进行海拔提升,但是程序运行时出现错误:

and when I do that, the application prompts me for elevation, but I get an error when the program runs:

"Cannot open self <Full path to exe>\GraphicScriptWizard.exe or archive..."

我真的很精疲力尽,并希望对Windows资源和清单更加熟悉的人可以为我提供更多启示.我的清单XML错误吗?我在Pyinstaller中使用的方法是否错误?

I'm really at my wit's end and am hoping that someone with more familiarity with Windows resources and manifests can shed some more light on this for me. Is my manifest XML wrong? Is my methodology with Pyinstaller wrong?

推荐答案

我本人就是走这条路,这是我的观察和经验.

I've just gone down this road myself, and here are my observations and experience.

首先要知道的是清单有两个有效位置:

The first thing to know is that there are two valid locations for the manifest:

  1. 作为资源嵌入可执行文件(或dll)

  1. Embedded in the executable (or dll) as a resource

可执行文件(或dll)旁边的当前操作.

Next to the executable (or dll), as you are currently doing.

在此处阅读有关清单的信息: http://msdn.microsoft.com/zh-CN/library/windows/desktop/aa374191(v=vs.85).aspx

Read up about manifests here: http://msdn.microsoft.com/en-us/library/windows/desktop/aa374191(v=vs.85).aspx

根据我的经验,您可以同时使用两者,但是如果有任何重叠,则嵌入式清单优先.这就是让您烦恼的原因.由Pyinstaller创建的可执行文件具有嵌入式清单,该清单将请求的执行级别设置为"asInvoker",它将覆盖您正在使用的清单中的级别.

In my experience, you can use both at the same time, but if there is any overlap, the embedded manifest takes precedence. This is what is screwing you up. The executable created by Pyinstaller has an embedded manifest that sets the requested execution level to "asInvoker" which overrides the level in the manifest you are using.

-manifest(或EXE()的清单参数)仅修改Pyinstaller放置在可执行文件/dll旁边的清单,而不是嵌入式清单.

The --manifest (or manifest parameter to EXE() ) merely modifies the manifest that Pyinstaller places next to the executable/dll, rather than the embedded manifest.

因此,我们可以转到mt.exe来更改嵌入式清单,但是正如您所发现的,这将导致应用程序无法运行.这是因为Pyinstaller创建的应用程序实际上是两个部分.一个小的可执行文件,它将提取档案,然后在其捆绑的python环境中设置并启动您的代码,并对该可执行文件进行操作.之所以可行,是因为可执行文件的规范允许将任意数据附加到可执行文件的末尾,但可以在可执行文件本身之外,这由可执行文件头中记录的大小定义.当我们在Pyinstaller创建的可执行文件上运行mt.exe时,它将查看标头以获取大小,并忽略该大小以外的任何内容,因此当它使用新清单保存可执行文件时会丢弃该存档数据,这将导致您遇到错误见过.

So, we could turn to mt.exe to change the embedded manifest, but as you have found, this results in an application that doesn't run. This is because the application created by Pyinstaller are really two parts; a small executable that extracts an archive then sets up and launches your code in its bundled python environment, and that archive that the executable operates on. This works because the specification for an executable allows there to be arbitrary data appended to the end of the executable file, but outside of the executable itself, as defined by the size recorded in the executable's header. When we run mt.exe on the Pyinstaller created executable, it looks at the header to get the size, and ignores anything beyond that, thus discarding that archive data when it saves your executable with the new manifest, which results in the error you have seen.

我正在使用的解决方案是在将存档数据附加到可执行文件之前修改清单,这需要修改Pyinstaller源代码. Pyinstaller源代码具有实用程序来更新可执行文件/dll中的资源,并将其用作构建过程的一部分.您需要在Pyinstaller位置中查看 build.py winmanifest.py 以及 winresource.py .我在EXE类中添加了一个参数,然后在该类的assemble方法中添加了一个步骤来更新清单,我在添加档案之前进行了此操作.我添加的肉是这样的:

The solution I am using is to modify the manifest before the archive data gets appended to the executable, which requires modification of the Pyinstaller source code. The Pyinstaller source has utilities to update the resources in an executable/dll, which it uses as part of its build process. You'll want to look at build.py, winmanifest.py and maybe winresource.py in your Pyinstaller location. I added a parameter to the EXE class and then a step in the assemble method of that class to update the manifest, I do this right before it appends the archive. The meat of what I added is like so:

if self.manifest_override != None:
        print "Overriding default manifest"
        tmpnm = tempfile.mktemp()
        shutil.copy2(exe, tmpnm)
        os.chmod(tmpnm, 0755)
        winmanifest.UpdateManifestResourcesFromXMLFile(tmpnm, self.manifest_override, names=[1], languages=[1033])
        exe = tmpnm
        trash.append(tmpnm)

我将其放置在以下行之前:exe = checkCache(exe, ... 它应该在上方,但要靠近print "Appending archive to EXE"...

I have this placed right before the line that reads: exe = checkCache(exe, ... and it should be above, but close to a print "Appending archive to EXE"...

此解决方案一直在为我工作,但我对此并不感到非常满意.我宁愿重写嵌入的默认清单,而不是对其进行更新,但是到目前为止,我的努力一直没有成果.

This solution has been working for me, but I am not super happy with it. I would rather override the default manifest that gets embedded, instead of updating it, but my efforts have been fruitless thus far.

对不起,我的意思是,但是这里发生了很多事.

Sorry for the wall of text, but there is a lot going on here.

这篇关于使用PyInstaller onefile选项和清单将UAC设置为requireAdministrator的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆