Configuring UAC on requireAdministrator using the onefile and PyNstaller options

Well, I was going around and trying to figure it out. I am creating an application called GraphicScriptWizard.exe using PyInstaller version 2.0 using the -i -F -w and -m options.

The manifest file that I defined for 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 command line options, I am not getting an executable file that asks for a raise.

For completeness, the spec file that is generated using Pyinstaller:

 # -*- 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')) 

I tried compiling with pyinstaller without the -m option and nesting with mt using the command:

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

and when I do this, the application asks me to upgrade, but I get an error message when the program starts:

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

I really am at my end and hope that someone who is more familiar with Windows resources and the manifest can shed some light on this for me. Is my XML manifest incorrect? Is my technique wrong with Pyinstaller?

+4
source share
2 answers

I just went this way, and here are my observations and experiences.

The first thing you need to know is that there are two valid places for the manifest:

  • Embeds in an executable file (or dll) as a resource

  • Next to the executable (or dll) as you are doing now.

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

In my experience, you can use both at the same time, but if there is any coincidence, the inline manifest takes precedence. This is what hurts you. The executable created by Pyinstaller has a built-in manifest that sets the required runlevel to "asInvoker", which overrides the level in the manifest that you are using.

The -manifest parameter (or manifest for EXE ()) simply changes the manifest that Pyinstaller places next to the / dll executable, rather than the built-in manifest.

So, we can refer to mt.exe to change the built-in manifest, but as you have found, this leads to the fact that the application does not start. This is because the application created by Pyinstaller really consists of two parts; a small executable file that extracts the archive, then configures and runs your code in the python environment associated with it, as well as the archive in which the executable works. This works because the specification of the executable allows you to add arbitrary data to the end of the executable, but outside the executable itself, as determined by the size recorded in the executable header. When we run the mt.exe file from the created Pyinstaller executable, it looks at the header to get the size and ignores everything outside it, thereby discarding the archive data when it saves your executable with a new manifest, which leads they saw a mistake.

The solution I'm using is to change the manifest before adding archive data to the executable, which requires modifying the source code of Pyinstaller. The Pyinstaller source has utilities for updating resources in the / dll executable, which it uses as part of the build process. You need to look at build.py , winmanifest.py, and possibly winresource.py in your Pyinstaller location. I added a parameter to the EXE class, and then a step in the build method of this class to update the manifest, I do this right before adding the archive. The meat of what I added looks like this:

 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) 

I placed this right in front of the line that says: exe = checkCache(exe, ... and it should be higher, but close to print "Appending archive to EXE"...

This solution works for me, but I'm not very happy with it. I would prefer to override the default manifest to be implemented, rather than updating it, but my efforts have so far been fruitless.

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

+8
source

Not a complete solution, but perhaps a useful hint.

Python 2.7.5 AMD64 does not work with manifest file on top Python 2.7.5 32-bit works fine.

So maybe this is just a limitation due to the Python version.

0
source

All Articles