вторник, 18 марта 2014 г.

Qt: Внедрение манифеста в исполняемый файл

Вначале хочется отметить, что встраивать манифест в exe файл вовсе не обязательно. Сам файл манифеста можно положить рядом с exe и все будет отлично работать. Как это делается - можно почитать в статье UAC манифест. Тем не менее, иногда приходится внедрять UAC манифест в exe файл. В данной статье будет описан способ внедрения UAC манифеста на примере приложения созданного в Qt.

Типичное Qt приложения имеет два режима: режим разработки (исполняемый файл и созданные библиотеки содержат отладочную информацию, и потому больше размером) и режим продукта. При этом, файловая структура простого приложения имеет, примерно, такой вид:
temp /
    temp /
        main.cpp
        mainwindow.cpp
        mainwindow.h
        mainwindow.ui
        temp.pro
        temp.pro.user
    temp_debug /
        debug /
        release /
        Makefile
        Makefile.Debug
        Makefile.Release
        ui_mainwindow.h
    temp_prod /
        debug /
        release /
        Makefile
        Makefile.Debug
        Makefile.Release
        ui_mainwindow.h
В данном примере, манифест нужно внедрить в продукт, поэтому работа будет производится в каталоге temp\temp_prod. В консоли нужно перейти в эту директорию.

1. Создание манифеста

Для начала, в рабочей директории, нужно создать сам файл манифеста manifest.xml (название файла не имеет значения) с таким содержимым:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="requireAdministrator" uiAccess="False"/>
      </requestedPrivileges>
    </security>
  </trustInfo>
</assembly>

2. Создание файла ресурсов

Далее, в рабочей директории, необходимо создать файл ресурсов manifest.rc со следующим содержимым:
1 24 ".\\manifest.xml"
и скомпилировать этот ресурс. Чтобы скомпилировать ресурс, нужно выполнить в консоли такую команду:
...\temp\temp_prod>windres -i manifest.rc -o manifest.o
При этом, в той же рабочей директории, должен появится файл manifest.o.

3. Создание цели для мейкфайла

Следующим этапом будет создание цели для мейкфайла и компиляция проекта с использованием этой цели. Чтобы среда разработки не перезаписала внесенные изменения в файл Makefile.Release, лучше создать его копию, например Makefile.Manifest.Release и добавить туда новую цель, например embeddedmanifest. На деле это будет выглядеть следующим образом:
Открыть спойлер
############################################################################# # Makefile for building: temp # Generated by qmake (2.01a) (Qt 4.8.4) on: ?? 18. ??? 14:40:44 2014 # Project: ..\temp\temp.pro # Template: app ############################################################################# ####### Compiler, tools and options CC = gcc CXX = g++ DEFINES = -DUNICODE -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_HAVE_MMX -DQT_HAVE_3DNOW -DQT_HAVE_SSE -DQT_HAVE_MMXEXT -DQT_HAVE_SSE2 -DQT_THREAD_SUPPORT -DQT_NEEDS_QMAIN CFLAGS = -pipe -O2 -Wall -Wextra $(DEFINES) CXXFLAGS = -pipe -O2 -frtti -fexceptions -mthreads -Wall -Wextra $(DEFINES) INCPATH = -I"c:\Qt\qt-4.8.4\include\QtCore" -I"c:\Qt\qt-4.8.4\include\QtGui" -I"c:\Qt\qt-4.8.4\include" -I"c:\Qt\qt-4.8.4\include\ActiveQt" -I"release" -I"." -I"..\temp" -I"." -I"c:\Qt\qt-4.8.4\mkspecs\win32-g++" LINK = g++ LFLAGS = -Wl,-s -mthreads -Wl,-subsystem,windows LIBS = -L"c:\Qt\qt-4.8.4\lib" -lmingw32 -lqtmain -lQtGui4 -lQtCore4 QMAKE = c:\Qt\qt-4.8.4\bin\qmake.exe IDC = c:\Qt\qt-4.8.4\bin\idc.exe IDL = midl ZIP = zip -r -9 DEF_FILE = RES_FILE = COPY = copy /y SED = COPY_FILE = $(COPY) COPY_DIR = xcopy /s /q /y /i DEL_FILE = del DEL_DIR = rmdir MOVE = move CHK_DIR_EXISTS= if not exist MKDIR = mkdir INSTALL_FILE = $(COPY_FILE) INSTALL_PROGRAM = $(COPY_FILE) INSTALL_DIR = $(COPY_DIR) ####### Output directory OBJECTS_DIR = release ####### Files SOURCES = ..\temp\main.cpp \ ..\temp\mainwindow.cpp release\moc_mainwindow.cpp OBJECTS = release/main.o \ release/mainwindow.o \ release/moc_mainwindow.o DIST = QMAKE_TARGET = temp DESTDIR = release\ #avoid trailing-slash linebreak TARGET = temp.exe DESTDIR_TARGET = release\temp.exe DESTDIR_TARGET_MANIFEST = release\temp_manifest.exe ####### Implicit rules .SUFFIXES: .cpp .cc .cxx .c .cpp.o: $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< .cc.o: $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< .cxx.o: $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $< .c.o: $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $< ####### Build rules first: all all: Makefile.Release $(DESTDIR_TARGET) $(DESTDIR_TARGET): ui_mainwindow.h $(OBJECTS) $(LINK) $(LFLAGS) -o $(DESTDIR_TARGET) $(OBJECTS) $(LIBS) embeddedmanifest: Makefile.Release $(DESTDIR_TARGET_MANIFEST) $(DESTDIR_TARGET_MANIFEST): ui_mainwindow.h $(OBJECTS) $(LINK) $(LFLAGS) manifest.o -o $(DESTDIR_TARGET_MANIFEST) $(OBJECTS) $(LIBS) qmake: FORCE @$(QMAKE) -spec c:\Qt\qt-4.8.4\mkspecs\win32-g++ CONFIG+=release -o Makefile.Release ..\temp\temp.pro dist: $(ZIP) temp.zip $(SOURCES) $(DIST) ..\temp\temp.pro c:\Qt\qt-4.8.4\mkspecs\features\device_config.prf c:\Qt\qt-4.8.4\mkspecs\qconfig.pri c:\Qt\qt-4.8.4\mkspecs\modules\qt_webkit_version.pri c:\Qt\qt-4.8.4\mkspecs\features\qt_functions.prf c:\Qt\qt-4.8.4\mkspecs\features\qt_config.prf c:\Qt\qt-4.8.4\mkspecs\features\exclusive_builds.prf c:\Qt\qt-4.8.4\mkspecs\features\default_pre.prf c:\Qt\qt-4.8.4\mkspecs\features\win32\default_pre.prf c:\Qt\qt-4.8.4\mkspecs\features\release.prf c:\Qt\qt-4.8.4\mkspecs\features\debug_and_release.prf c:\Qt\qt-4.8.4\mkspecs\features\default_post.prf c:\Qt\qt-4.8.4\mkspecs\features\win32\default_post.prf c:\Qt\qt-4.8.4\mkspecs\features\build_pass.prf c:\Qt\qt-4.8.4\mkspecs\features\win32\rtti.prf c:\Qt\qt-4.8.4\mkspecs\features\win32\exceptions.prf c:\Qt\qt-4.8.4\mkspecs\features\win32\stl.prf c:\Qt\qt-4.8.4\mkspecs\features\shared.prf c:\Qt\qt-4.8.4\mkspecs\features\warn_on.prf c:\Qt\qt-4.8.4\mkspecs\features\qt.prf c:\Qt\qt-4.8.4\mkspecs\features\win32\thread.prf c:\Qt\qt-4.8.4\mkspecs\features\moc.prf c:\Qt\qt-4.8.4\mkspecs\features\win32\windows.prf c:\Qt\qt-4.8.4\mkspecs\features\resources.prf c:\Qt\qt-4.8.4\mkspecs\features\uic.prf c:\Qt\qt-4.8.4\mkspecs\features\yacc.prf c:\Qt\qt-4.8.4\mkspecs\features\lex.prf c:\Qt\qt-4.8.4\mkspecs\features\include_source_dir.prf c:\Qt\qt-4.8.4\lib\qtmain.prl HEADERS RESOURCES IMAGES SOURCES OBJECTIVE_SOURCES FORMS YACCSOURCES YACCSOURCES LEXSOURCES clean: compiler_clean -$(DEL_FILE) release\main.o release\mainwindow.o release\moc_mainwindow.o distclean: clean -$(DEL_FILE) $(DESTDIR_TARGET) -$(DEL_FILE) Makefile.Release check: first mocclean: compiler_moc_header_clean compiler_moc_source_clean mocables: compiler_moc_header_make_all compiler_moc_source_make_all compiler_moc_header_make_all: release/moc_mainwindow.cpp compiler_moc_header_clean: -$(DEL_FILE) release\moc_mainwindow.cpp release/moc_mainwindow.cpp: ../temp/mainwindow.h C:\Qt\qt-4.8.4\bin\moc.exe $(DEFINES) $(INCPATH) -D__GNUC__ -DWIN32 ..\temp\mainwindow.h -o release\moc_mainwindow.cpp compiler_rcc_make_all: compiler_rcc_clean: compiler_image_collection_make_all: qmake_image_collection.cpp compiler_image_collection_clean: -$(DEL_FILE) qmake_image_collection.cpp compiler_moc_source_make_all: compiler_moc_source_clean: compiler_uic_make_all: ui_mainwindow.h compiler_uic_clean: -$(DEL_FILE) ui_mainwindow.h ui_mainwindow.h: ../temp/mainwindow.ui c:\Qt\qt-4.8.4\bin\uic.exe ..\temp\mainwindow.ui -o ui_mainwindow.h compiler_yacc_decl_make_all: compiler_yacc_decl_clean: compiler_yacc_impl_make_all: compiler_yacc_impl_clean: compiler_lex_make_all: compiler_lex_clean: compiler_clean: compiler_moc_header_clean compiler_uic_clean ####### Compile release/main.o: ../temp/main.cpp ../temp/mainwindow.h $(CXX) -c $(CXXFLAGS) $(INCPATH) -o release\main.o ..\temp\main.cpp release/mainwindow.o: ../temp/mainwindow.cpp ../temp/mainwindow.h \ ui_mainwindow.h $(CXX) -c $(CXXFLAGS) $(INCPATH) -o release\mainwindow.o ..\temp\mainwindow.cpp release/moc_mainwindow.o: release/moc_mainwindow.cpp $(CXX) -c $(CXXFLAGS) $(INCPATH) -o release\moc_mainwindow.o release\moc_mainwindow.cpp ####### Install install: FORCE uninstall: FORCE FORCE:
Добавленные строки отмечены синим цветом.

После создания цели нужно откомпилировать проект. Для этого, в консоли нужно запустить команду:
...\temp\temp_prod>make -f Makefile.Manifest.Release embeddedmanifest
Если ошибок нет, то в папке temp\release появится исполняемый файл temp_manifest.exe, который будет реализовывать поставленную задачу, а именно - запускаться только под администратором.

Удачи!

Комментариев нет:

Отправить комментарий