Skip to content

Latest commit

 

History

History
248 lines (193 loc) · 16.5 KB

developer-guide.md

File metadata and controls

248 lines (193 loc) · 16.5 KB

Developer Guide

The following document describes the setup and workflow that is recommended for working on the WPF project. It assumes that you have read the contributing guide.

The Issue Guide describes our approach to using GitHub issues.

Machine Setup

WPF requires the following workloads and components be selected when installing Visual Studio 2022 (17.0.0):

Workflow

We use the following workflow for building and testing features and fixes.

You first need to Fork and Clone this WPF repository. This is a one-time task.

Running DRTs locally

In order to run the set of DRTs on your local machine, pass the -test parameter to the build.cmd script. At the end of the run, you should see something like this:

  A total of 1 test Infos were processed, with the following results.
   Passed: 1
   Failed (need to analyze): 0
   Failed (with BugIDs): 0
   Ignore: 0

If there were any failures, you can cd into $(RepoRoot)\artifacts\test$(Configuration)$(Platform)\Test and run the tests manually with the /debugtests flag using the RunDrts.cmd script. Note that you do not run the RunDrtsDebug script, as this will debug the test infrastructure, QualityVault. When you pass the /debugtests flag, a cmd window will open where you can open the test executable in Visual Studio and debug it. When the cmd pops up, you will see instructions for debugging using a few different commands, however these commands will enable you to debug the Simple Test Invocation executable, sti.exe, which simply launches the test executable you are most likely interested in debugging. Using DrtXaml.exe as an example, this is how you can debug the test executable. Any MSBuild style properties should be replaced with actual values:

  1. $(RepoRoot)\artifacts\test\$(Configuration)\$(Platform)\Test\RunDrts.cmd /name=DrtXaml /debugtests
  2. Enter following command into the cmd window that pops up: "%ProgramFiles%\Microsoft Visual Studio\2019\Preview\Common7\IDE\devenv.exe" DrtXaml.exe
  3. Once Visual Studio is open, go to Debug-> DrtXaml Properties and do the following:
    • Manually change the Debugger Type from Auto to Mixed (CoreCLR).
    • Change the Environment from Default to a custom one that properly defines the DOTNET_ROOT variable so that the host is able to locate the install of Microsoft.NETCore.App.
      • x86 (Default): Name: DOTNET_ROOT(x86) Value: $(RepoRoot).dotnet\x86
      • x64 (/p:Platform=x64): Name: DOTNET_ROOT Value: $(RepoRoot).dotnet
  4. From there you can F5 and the test will execute.

Note: To run a specific test, you can pass the name of the test like this: /name=DrtXaml. The names of these tests are contained in DrtList.xml.

NOTE: This requires being run from an admin window at the moment. Removing this restriction is tracked by #816.

Debugging locally built WPF assemblies with WPF Application

This section is intended to simplify the steps needed to be able to debug the locally built WPF Assemblies, with any sample app. Configure the project to build x86 or x64, as per the platform architecture you have selected while performing the build for WPF assemblies. Go to the csproj file and append this line at the bottom of it. <Import Project="$(WpfRepoRoot)\eng\wpf-debug.targets" />. The resultant csproj will look like this:

    <PropertyGroup>
      <OutputType>WinExe</OutputType>
      <TargetFramework>net6.0-windows</TargetFramework>
      <UseWPF>true</UseWPF>
    </PropertyGroup>

    <PropertyGroup>
      <WpfRepoRoot>C:\wpf</WpfRepoRoot>
    </PropertyGroup>
    <Import Project="$(WpfRepoRoot)\eng\wpf-debug.targets" />

Testing Locally built WPF assemblies (excluding PresentationBuildTasks)

This section of guide is intended to discuss the different approaches for ad-hoc testing of WPF assemblies, and not automated testing. For automated testing, see the Running DRTs locally section above. There are a few different ways this can be done, and for the most part, it depends on what you are trying to accomplish. This section tries to lay out which scenarios require which workflow.

NOTE: You should build locally with the -pack param to ensure the binaries are put in the correct location for manual testing.

Copying binaries to publish location of a self-contained application

The simplest approach is to publish your sample app using dotnet publish -r <rid> --self-contained. You can add the <SelfContained>true</SelfContained> and <RuntimeIdentifer>rid</RuntimeIdentifier> properties to your .csproj or .vbproj file and then you can simply execute dotnet publish. We recommend always supplying a runtime identifier, as many of the WPF assemblies are architecture dependent. The values you can choose here are win-x86 or win-x64.

Then to copy the WPF assemblies to this published location, simply run the copy-wpf.ps1 script located in the eng folder of the repo and point it to the location of your test application:

eng\copy-wpf.ps1 -destination "c:\mysampleproj"

Copying binaries to test host installation of dotnet

If you want/need to test an existing application that targets the shared installation, it is safest to setup a test host, rather than trying to copy assemblies over the shared installation. A test host is a complete install of dotnet (host and runtimes) used for testing applications and can be setup by using the dotnet install script. This method is also effective for internal contributors who are working on porting our current test corpus from .NET Framework to .NET Core and wants to run the tests against locally built assemblies. Note that there is nothing fundamentally different between a testhost installation of dotnet and the one installed in $env:ProgramFiles. However the dotnet host dll won't be able to find the testhost install if the appropriate environment variables aren't set. Note that these environment variables are set for you by copy-wpf.ps1

You can run the copy-wpf.ps1 script again and be sure to pass in the -testhost parameter:

eng\copy-wpf.ps1 -testhost -destination "c:\testhost\x86"

If your testhost directory has multiple versions of the Microsoft.WindowsDesktop.App shared runtime in it, you can use the -version parameter to specify which one you want:

eng\copy-wpf.ps1 -testhost -destination "c:\testhost\x86" -version "3.0.0-preview6-27728-04"

If there are multiple versions, you will see a warning and the last installed runtime will be selected. You can backup the folder by creating a copy of it, and the script will ensure that this folder isn't touched as long as the word "Copy" is in the path. This was chosen because the default for Windows Explorer is to append "- Copy" to the folder. This allows you to easily backup folders containing the runtime assemblies knowing you can restore them to their original state if needed.

If you are installing to a special test host location, you will see output from the script that confirms the appropriate environment variables are set:

** Setting env:DOTNET_ROOT(x86) to c:\testhost\x86 **
** Setting env:DOTNET_MULTILEVEL_LOOKUP to 0 **

How to find location of the exe to test? If you are testing an application and don't know where the executable is located, the easiest thing to do is use Process Explorer (from SysInternals) or attach to the process with a debugger like Visual Studio.

Testing API changes

The above instructions imply that you are testing assemblies that don't have any changes to the public API surface that the test application needs to use. If you need to test some API changes you are making, the C# team has done some great work to make this relatively straightforward. When the C# compiler detects a collision with assembly references, the assembly with the higher version number is chosen. Assuming our locally built binaries are newer than what is installed, we can then simply reference those local binaries directly from the project file, like this:

  <PropertyGroup>
    <!-- Change this value based on where your local repo is located -->
    <WpfRepoRoot>d:\dev\src\dotnet\wpf</WpfRepoRoot>
    <!-- Change based on which assemblies you build (Release/Debug) -->
    <WpfConfig>Debug</WpfConfig>
    <WpfOuputFolder>Microsoft.DotNet.Wpf.GitHub.Debug</WpfOuputFolder>
    <!-- Publishing a self-contained app ensures our binaries are used. -->
    <SelfContained>true</SelfContained>
    <!-- The runtime identifier needs to match the architecture you built WPF assemblies for. -->
    <RuntimeIdentifier>win-x86</RuntimeIdentifier>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="$(WpfRepoRoot)\artifacts\packaging\$(WpfConfig)\$(WpfOuputFolder)\lib\net6.0\*.dll" />
    <ReferenceCopyLocalPaths Include="$(WpfRepoRoot)\artifacts\packaging\$(WpfConfig)\$(WpfOuputFolder)\lib\$(RuntimeIdentifier)\*.dll" />
    <ReferenceCopyLocalPaths Include="$(WpfRepoRoot)\artifacts\packaging\$(WpfConfig)\$(WpfOuputFolder)\runtimes\$(RuntimeIdentifier)\native\*.dll" />
  </ItemGroup>

Testing specific versions of the Microsoft.WindowsDesktop.App runtime

At times, it is necessary to install and test specific versions of the runtime. This can be helpful if you are trying to root cause when an issue started occuring, or need to compare functionality between two different versions.

For testing different versions of the runtime, you can install a specific version of the runtimes via the dotnet install script. Below is an example powershell script of how you can use the dotnet-install.ps1 script that will install both 32-bit and 64-bit versions of the Microsoft.WindowsDesktop.App runtime into the specified folder:

$dotnet_install = "$env:TEMP\dotnet-install.ps1"
$x64InstallDir  = "$env:ProgramFiles\dotnet"
$x86InstallDir  = "${env:ProgramFiles(x86)}\dotnet"

Invoke-WebRequest https://dot.net/v1/dotnet-install.ps1 -OutFile $dotnet_install

.$dotnet_install -Channel master -Version 3.0.0-preview5-27619-18 -Runtime windowsdesktop -Architecture x64 -InstallDir $x64InstallDir
.$dotnet_install -Channel master -Version 3.0.0-preview5-27619-18 -Runtime windowsdesktop -Architecture x86 -InstallDir $x86InstallDir

This would install version 3.0.0-preview5-27619-18 of the Microsoft.WindowsDesktop.App shared runtime. You can pass "Latest" to get the latest version of the runtime. You can also use this script to install the runtimes as well as the SDK. If you know a particular SDK version and are curious to know what Microsoft.WindowsDesktop.App version is associated with it, there is a file called Microsoft.NETCoreSdk.BundledVersions.props contained inside the SDK folder. Inside that file, you will find an entry that looks like this:

    <KnownFrameworkReference Include="Microsoft.WindowsDesktop.App"
                              TargetFramework="netcoreapp3.0"
                              RuntimeFrameworkName="Microsoft.WindowsDesktop.App"
                              DefaultRuntimeFrameworkVersion="3.0.0-preview4-27613-28"
                              LatestRuntimeFrameworkVersion="3.0.0-preview4-27613-28"
                              TargetingPackName="Microsoft.WindowsDesktop.App.Ref"
                              TargetingPackVersion="3.0.0-preview4-27615-11"
                              RuntimePackNamePatterns="runtime.**RID**.Microsoft.WindowsDesktop.App"
                              RuntimePackRuntimeIdentifiers="win-x64;win-x86"
                              />

In this example, the version of Microsoft.WindowsDesktop.App associated with this SDK is 3.0.0-preview4-27613-28.

Note: The ability to install the WindowsDesktop runtime via the dotnet install script is being tracked by: https://github.com/dotnet/cli/issues/11115

Specifying which version of the runtime to use

If you can build directly from source, and want to test your application against a certain version of the Microsoft.WindowsDesktop.App shared runtime, you can add this to your project file to pick up the version of the shared runtime you want to test:

 <PropertyGroup>
    <MicrosoftWindowsDesktopAppVersion>3.0.0-preview5-27619-18</MicrosoftWindowsDesktopAppVersion>
 </PropertyGroup>
 <ItemGroup>
   <FrameworkReference Update="Microsoft.WindowsDesktop.App">
      <TargetingPackVersion>$(MicrosoftWindowsDesktopAppVersion)</TargetingPackVersion>
   </FrameworkReference>
 </ItemGroup>

If you don't have the ability to build from source, you can update the *.runtimeconfig.json file located next to the executable to pick up your version:

{
  "runtimeOptions": {
    "tfm": "netcoreapp3.0",
    "framework": {
      "name": "Microsoft.WindowsDesktop.App",
      "version": "3.0.0-preview5-27619-18"
    }
  }
}

Finding a specific version of Microsoft.WindowsDesktop.App that interests you

Follow the steps defined here to get setup for swagger API. Note that you need to authorize each time you login, so keep note of your token or you'll have to generate a new one. Assuming you have a commit (and therefore an Azure DevOps build id) that you are interested in, you can enter the build id into your query.

Testing PresentationBuildTasks

Debugging Presentation Build Task

Debugging Presentation Build Task(hereafter called PBT) can be required for various reasons. One of them can be if there is something you wanted to know about markup compilation. In this section you will learn how to debug PBT.

For the sake of explaining the debugging steps, we will try to stop the debugger at execute (public function) of markupCompilatonPass2.

Follow the following steps sequentially.

  1. Replace thePresentationBuildTasks.dll located at C:\Program Files\dotnet\sdk\<your sdk version>\Sdks\Microsoft.NET.Sdk.WindowsDesktop\tools\net472 with your binaries (<wpf clone directory>\artifacts\packaging\Debug\Microsoft.NET.Sdk.WindowsDesktop.Debug\tools\net472).
  2. Launch Visual Studio and open the Msbuild.exe (generally located at C:\Program Files\Microsoft Visual Studio\2022\Preview\MSBuild\Current\Bin\MSBuild.exe)
  3. Go to Debug->Options->Symbols
  4. Check option - Load only specified modules and click on Specify included modules
  5. Symbols to Load automatically dialog box will pop up
  6. Click on + button on top right and add PresentationBuildTasks.dll.
  7. Click OK.
  8. Right click on MsBuild.exe in solution explorer and select Properties.
  9. In the Parameters textbox enter the fullpath to a solution file (.sln ||.csproj) of a test repo.
  10. Click Save.
  11. Open "<wpf clone directory>\src\Microsoft.DotNet.Wpf\src\PresentationBuildTasks\Microsoft\Build\Tasks\Windows\MarkupCompilePass2.cs" (File -> Open -> File) in editor
  12. Insert a breakpoint at start of execute function.
  13. Hit F5 to start debugging.

Commonly Encountered Errors

The specified RuntimeIdentifier win- is not recognized (Code: NETSDK1083)

If you are seeing this error it means you are possibly missing <PlatformTarget> tag from your .csproj file. Please add the tag with apropriate value.

For example:- if your wpf binaries are build for platform x86 you should add <PlatformTarget>x86</PlatformTarget> to your .csproj file. Your final csproj file should look like as below:

    <PropertyGroup>
      <OutputType>WinExe</OutputType>
      <TargetFramework>net6.0-windows</TargetFramework>
      <UseWPF>true</UseWPF>
      <PlatformTarget>x86</PlatformTarget>
    </PropertyGroup>

    <PropertyGroup>
      <WpfRepoRoot>C:\wpf</WpfRepoRoot>
    </PropertyGroup>
    <Import Project="$(WpfRepoRoot)\eng\wpf-debug.targets" />

More Information