Configuración de UAC a requireAdministrator mediante la opción de archivo único de PyInstaller y el manifiesto

Bien, he estado dando vueltas y vueltas tratando de resolver esto. Estoy creando una aplicación llamada GraphicScriptWizard.exe usando PyInstaller versión 2.0 usando las opciones -i -F -w y -m.

El archivo de manifiesto que he definido para usar con la opción -m se llama GraphicScriptWizard.exe.manifest y tiene el siguiente contenido:

             

Al usar este manifiesto y las opciones de la línea de comando, no obtengo un ejecutable que solicite la elevación.

En aras de la integridad, el archivo de especificaciones generado por Pyinstaller es:

 # -*- mode: python -*- a = Analysis(['GraphicScriptWizard.py'], pathex=[], 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')) 

He intentado comstackr con pyinstaller sin la opción -m e incrustar con mt usando el comando:

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

y cuando hago eso, la aplicación me pide una elevación, pero me sale un error cuando el progtwig se ejecuta:

"Cannot open self \GraphicScriptWizard.exe or archive..."

Estoy realmente al final de mi ingenio y espero que alguien con más familiaridad con los recursos y manifiestos de Windows pueda arrojar algo más de luz sobre esto para mí. ¿Mi manifiesto XML está mal? ¿Mi metodología con Pyinstaller es incorrecta?

Acabo de recorrer este camino yo mismo, y aquí están mis observaciones y mi experiencia.

Lo primero que debe saber es que hay dos ubicaciones válidas para el manifiesto:

  1. Incrustado en el ejecutable (o dll) como un recurso

  2. Junto al ejecutable (o dll), como lo está haciendo actualmente.

Lea acerca de los manifiestos aquí: http://msdn.microsoft.com/en-us/library/windows/desktop/aa374191(v=vs.85).aspx

En mi experiencia, puede usar ambos al mismo tiempo, pero si hay alguna superposición, el manifiesto incrustado tiene prioridad. Esto es lo que te está jodiendo. El ejecutable creado por Pyinstaller tiene un manifiesto incrustado que establece el nivel de ejecución solicitado en “asInvoker”, que anula el nivel en el manifiesto que está utilizando.

El –manifest (o el parámetro de manifiesto a EXE ()) simplemente modifica el manifiesto que Pyinstaller coloca al lado del ejecutable / dll, en lugar del manifiesto incrustado.

Por lo tanto, podríamos recurrir a mt.exe para cambiar el manifiesto incrustado, pero como ha encontrado, esto se traduce en una aplicación que no se ejecuta. Esto se debe a que la aplicación creada por Pyinstaller es en realidad dos partes; un pequeño archivo ejecutable que extrae un archivo luego configura e inicia su código en su entorno Python incluido, y ese archivo sobre el que opera el archivo ejecutable. Esto funciona porque la especificación para un ejecutable permite que se agreguen datos arbitrarios al final del archivo ejecutable, pero fuera del ejecutable en sí, según lo definido por el tamaño registrado en el encabezado del ejecutable. Cuando ejecutamos mt.exe en el ejecutable creado por Pyinstaller, mira el encabezado para obtener el tamaño, e ignora cualquier cosa más allá de eso, descartando esos datos de archivo cuando guarda su ejecutable con el nuevo manifiesto, lo que resulta en el error que tiene. visto

La solución que estoy usando es modificar el manifiesto antes de adjuntar los datos de archivo al ejecutable, lo que requiere la modificación del código fuente de Pyinstaller. La fuente de Pyinstaller tiene utilidades para actualizar los recursos en un ejecutable / dll, que utiliza como parte de su proceso de comstackción. Querrá ver build.py , winmanifest.py y tal vez winresource.py en su ubicación de Pyinstaller. Agregué un parámetro a la clase EXE y luego un paso en el método de ensamblaje de esa clase para actualizar el manifiesto, lo hago bien antes de agregar el archivo. La carne de lo que agregué es así:

 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) 

He colocado esto justo antes de la línea que dice: exe = checkCache(exe, ... y debería estar arriba, pero cerca de una print "Appending archive to EXE"...

Esta solución me ha funcionado, pero no estoy muy feliz con ella. Preferiría anular el manifiesto predeterminado que se incrusta, en lugar de actualizarlo, pero mis esfuerzos han sido infructuosos hasta ahora.

Lo siento por la pared de texto, pero hay mucho que hacer aquí.

No es una solución completa, pero tal vez una sugerencia útil.

Python 2.7.5 AMD64 no funciona con el archivo Manifest desde arriba Python 2.7.5 de 32 bits funciona bien.

Entonces tal vez esto sea solo una limitación debido a la versión de Python.