machine_1
machine_1

Reputation: 4454

How to embed manifest into C++/WinAPI app with VS2022?

For my app to function properly and display running processes, it requires elevated permissions. I embed the manifest file for this purpose using the mt.exe tool.

If I make changes to the code and rebuild, I would have to reuse the manifest tool to embed the manifest into the new executable. How can I embed the manifest into the executable during the build process in Visual Studio 2022?

display_running_processes.manifest

<?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>

mt.exe (command prompt; path: c:\Program Files (x86)\Windows Kits\10\bin<VER>\x64\mt.exe):

mt.exe -manifest display_running_processes.manifest -outputresource:display_running_processess.exe;1

Resource.h

#pragma once

#define IDD_DIALOG1 101
#define ID_LISTBOX 1001
#define IDOK 1
#define IDCANCEL 2

Resource.rc

#include <Windows.h>
#include "resource.h"

IDD_DIALOG1 DIALOGEX 0, 0, 600, 200
STYLE DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Process List"
FONT 8, "MS Shell Dlg"
BEGIN
LISTBOX         ID_LISTBOX, 10, 10, 580, 150, LBS_NOTIFY | WS_VSCROLL | WS_BORDER | WS_TABSTOP
DEFPUSHBUTTON   "OK", IDOK, 50, 170, 50, 14
PUSHBUTTON      "Cancel", IDCANCEL, 110, 170, 50, 14
END

WinMain.cpp

#include <windows.h>
#include <psapi.h>
#include <tchar.h>

#define ID_LISTBOX 1001
#define IDD_DIALOG1 101
#define IDOK 1
#define IDCANCEL 2

void PopulateProcessList(HWND hwndListBox) {
    DWORD processes[1024], cbNeeded;
    if (EnumProcesses(processes, sizeof(processes), &cbNeeded)) {
        int numProcesses = cbNeeded / sizeof(DWORD);
        for (int i = 0; i < numProcesses; ++i) {
            TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
            HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processes[i]);
            if (hProcess) {
                if (GetModuleFileNameEx(hProcess, NULL, szProcessName, MAX_PATH)) {
                    SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)szProcessName);
                }
                else {
                    DWORD error = GetLastError();
                    TCHAR szError[MAX_PATH];
                    _stprintf_s(szError, TEXT("GetModuleFileNameEx error %lu"), error);
                    SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)szError);
                }
                CloseHandle(hProcess);
            }
            else {
                DWORD error = GetLastError();
                if (error == ERROR_ACCESS_DENIED) {
                    HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processes[i]);
                    if (hProcess) {
                        if (GetProcessImageFileName(hProcess, szProcessName, MAX_PATH) > 0) {
                            SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)szProcessName);
                        }
                        else {
                            _stprintf_s(szProcessName, TEXT("PID %u: Access Denied, Unable to get name"), processes[i]);
                            SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)szProcessName);
                        }
                        CloseHandle(hProcess);
                    }
                    else {
                        _stprintf_s(szProcessName, TEXT("PID %u: Access Denied"), processes[i]);
                        SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)szProcessName);
                    }
                }
                else {
                    TCHAR szError[MAX_PATH];
                    _stprintf_s(szError, TEXT("OpenProcess error %lu"), error);
                    SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)szError);
                }
            }
        }
    }
    else {
        MessageBox(hwndListBox, TEXT("Failed to enumerate processes"), TEXT("Error"), MB_OK | MB_ICONERROR);
    }
}

INT_PTR CALLBACK DialogProc(
    HWND hwndDlg,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam) 
{
    switch (uMsg) {
    case WM_INITDIALOG:
    {
        HWND hwndListBox = GetDlgItem(hwndDlg, ID_LISTBOX);
        PopulateProcessList(hwndListBox);
    }
    return TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
            EndDialog(hwndDlg, LOWORD(wParam));
            return TRUE;
        }
        break;
    }
    return FALSE;
}

int WINAPI WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow) 
{
    DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DialogProc);
    return 0;
}

Upvotes: 0

Views: 152

Answers (1)

RbMm
RbMm

Reputation: 33754

manifest this is only resouce in your PE. so correct solution - include direct it in .rc file. not need any external tools, like mt.exe

we can add next line to Resource.rc:

CREATEPROCESS_MANIFEST_RESOURCE_ID  RT_MANIFEST "display_running_processes.manifest"

(this is in case exe, if you have dll - use ISOLATIONAWARE_MANIFEST_RESOURCE_ID instead CREATEPROCESS_MANIFEST_RESOURCE_ID )

also possible not direct include this line to Resource.rc, because it autogenerated by VS, but add it to *.rc2 file

using the Resource Includes dialog box

add in Compile-time directives: box .rc2 file and in this file put line

CREATEPROCESS_MANIFEST_RESOURCE_ID  RT_MANIFEST "display_running_processes.manifest"

this file never auto edited my VS

also in this case you need set /MANIFEST:NO for linker (Linker > Manifest File tab) and Embed Manifest: No for Manifest Tool > Input and Output

Upvotes: 0

Related Questions