Configure MAUI Project to Start with Administrator Privileges

2022年11月10日 58点热度 0人点赞 0条评论
内容目录

Background

In Windows, applications can use the app.manifest asset file to configure the role permissions used when the program is launched.

The effect is as follows:

file

Under normal circumstances, adding the following configuration to app.manifest is sufficient:

If the project does not have this file, you can create a new item - Manifest File in the project.

  <trustInfo xmlns='urn:schemas-microsoft-com:asm.v2'>
    <security>
      <requestedPrivileges xmlns='urn:schemas-microsoft-com:asm.v3'>
        <requestedExecutionLevel level='requireAdministrator' uiAccess='false' />
      </requestedPrivileges>
    </security>
  </trustInfo>

file

However, in MAUI applications, it cannot be added. If attempted, an error occurs.

Platforms\Windows\app.manifest : manifest authoring error c1010001: Values of attribute "level" not equal in different manifest snippets. 

This is because the .NET compiler already generates a default app.manifest file that includes the trustInfo configuration.

If the project has <WindowsAppSDKSelfConatined>true</WindowsAppSDKSelfConatined> enabled, you should check the Microsoft.WindowsAppSDK.SelfContained.targets file:
file
file

Therefore, if you want to customize app.manifest, you either need to modify Microsoft.WindowsAppSDK.SelfContained.targets, which is not ideal.

Customizing the Build Process

If you observe the build process, you will find that the manifest file is generated in the obj directory.
file

Here, mergeapp.manifest is the app.manifest from the project, renamed by the .NET compiler during the build process.

During the build, the default app.manifest is generated first from Microsoft.WindowsAppSDK.SelfContained.targets. Then, the developer's app.manifest is copied to mergeapp.manifest, which is subsequently merged into app.manifest.

If the configuration already exists in app.manifest, then the duplicate records in mergeapp.manifest will lead to compilation errors.

Since we understand the build process, we can manipulate it.
We can replace the configuration in app.manifest after it has been generated but before the main program is compiled, using the following command:

powershell -Command "(gc app.manifest) -replace 'level=''asInvoker''', 'level=''requireAdministrator''' | Out-File -encoding ASCII app.manifest";

file

The steps used by MSBuild during compilation can refer to the official documentation:
https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-targets?view=vs-2022

During compilation, there are two important environment variables:
_DeploymentManifestFiles: Directory where the manifest files are located;
ApplicationManifest: Path of the app.manifest file.

You can add the following script in the .csproj file, which will automatically modify the manifest file during the program compilation.

    <Target Name="RequireAdministrator" BeforeTargets="GenerateManifests" Condition="'$(PublishDir)' != ''">
        <Exec WorkingDirectory="./" Command="echo $(ApplicationManifest)" />
        <Exec WorkingDirectory="./" Command="echo $(_DeploymentManifestFiles)" />
        <Exec WorkingDirectory="$(_DeploymentManifestFiles)" Command="dir" />
        <Exec WorkingDirectory="$(_DeploymentManifestFiles)" Command="powershell -Command "(gc app.manifest) -replace 'level=''asInvoker''', 'level=''requireAdministrator''' | Out-File -encoding ASCII app.manifest"" />
    </Target>

BeforeTargets="GenerateManifests" indicates that the custom command is executed before GenerateManifests.

Condition="'$(PublishDir)' != ''" indicates the trigger condition. In MAUI, this variable only exists when publishing, but it could be modified to Condition="'$(Release)' != ''".

Note that in some cases, the _DeploymentManifestFiles directory may not exist, so multiple tests might be needed.

Of course, the safest method:

    <Target Name="RequireAdministrator" BeforeTargets="GenerateManifests" Condition="'$(PublishDir)' != ''">
        <Exec WorkingDirectory="./" Command=" powershell -Command "(gc $(ApplicationManifest)) -replace 'level=''asInvoker''', 'level=''requireAdministrator''' | Out-File -encoding UTF8 $(ApplicationManifest)"" />
    </Target>

The build process mainly consists of the following three steps, where only GenerateManifests can be used in .csproj.

<Target Name="GenerateManifests"
        Condition="'$(GenerateClickOnceManifests)'=='true' or '@(NativeReference)'!='' or '@(ResolvedIsolatedComModules)'!='' or '$(GenerateAppxManifest)' == 'true'"
        DependsOnTargets="$(GenerateManifestsDependsOn)"/>

===================================================
GenerateApplicationManifest
Generates a ClickOnce or native application manifest.
An application manifest specifies declarative application identity, dependency and security information.
===================================================
<Target Name="GenerateApplicationManifest"
        DependsOnTargets="
                _DeploymentComputeNativeManifestInfo;
                _DeploymentComputeClickOnceManifestInfo;
                ResolveComReferences;
                ResolveNativeReferences;
                _GenerateResolvedDeploymentManifestEntryPoint"
        Inputs="
                $(MSBuildAllProjects);
                @(AppConfigWithTargetPath);
                $(_DeploymentBaseManifest);
                @(ResolvedIsolatedComModules);
                @(_DeploymentManifestDependencies);
                @(_DeploymentResolvedManifestEntryPoint);
                @(_DeploymentManifestFiles)"
        Outputs="@(ApplicationManifest)">

The following parameters can be retrieved:

                $(_DeploymentBaseManifest);
                @(ResolvedIsolatedComModules);
                @(_DeploymentManifestDependencies);
                @(_DeploymentResolvedManifestEntryPoint);
                @(_DeploymentManifestFiles)
                @(ApplicationManifest)

痴者工良

高级程序员劝退师

文章评论