Skip to content

Bug: having only non-WinRT .idl files in a project causes MdMerge to fail #1509

@bugale

Description

@bugale

Version

2.0.250303.1

Summary

If a project has an .idl file that isn't "modern", WinMD merging fails.
To reproduce the issue:

  1. Create a simple C++ project in Visual Studio
  2. Add a simple non-WinRT .idl file to the project, it doesn't have to contain anything
  3. Add the metadata <OutputDirectory>$(MSBuildThisFileDirectory)</OutputDirectory> to the Midl item of the .idl file
  4. Set CppWinRTModernIDL and CppWinRTGenerateWindowsMetadata properties to false in the project.

I attached a sample solution that does exactly this here: CppWinRtTest.zip

Reproducible example

Simple C++ project with:

  <PropertyGroup>
    <CppWinRTModernIDL>false</CppWinRTModernIDL>
    <CppWinRTGenerateWindowsMetadata>false</CppWinRTGenerateWindowsMetadata>
  </PropertyGroup>
  <ItemGroup>
    <Midl Include="test.idl">
      <OutputDirectory>$(MSBuildThisFileDirectory)</OutputDirectory>
    </Midl>
  </ItemGroup>

Sample `test.idl`:
import "oaidl.idl";
import "ocidl.idl";

[object, uuid(93242F75-651F-42FA-8C60-9B7DAD8A163D), local]
interface Test: IUnknown {};

Expected behavior

Project builds successfully

Actual behavior

Project build fails with: MDMERGE : error MDM2025: The input directory or file C:\Users\Bugaleb\source\repos\CppWinRtTest" -o CppWinRtTest\x64\Debug\Merged -partial is not valid.

Additional comments

The issue seems to be with the GetCppWinRTMdMergeInputs target doing this:

            <_MdMergeInputs Include="@(Midl)" Condition="'%(Midl.ExcludedFromBuild)' != 'true'">
                <WinMDPath>%(Midl.OutputDirectory)%(Midl.MetadataFileName)</WinMDPath>
                <MdMergeOutputFile>$(CppWinRTProjectWinMD)</MdMergeOutputFile>
            </_MdMergeInputs>

basically, unconditionally adding all Midl items to _MdMergeInputs.

A potential solution would be to have a Midl.ExcludedFromWinMD metadata or something similar, though since CppWinRTModernIDL is a global property anyway, it can probably be used here as well to avoid attempting to merge anything.

A potential workaround is to add the following target in the project:

  <Target Name="WorkaroundCppWinRtBug" AfterTargets="GetCppWinRTMdMergeInputs" BeforeTargets="CppWinRTMergeProjectWinMDInputs">
    <ItemGroup>
      <CppWinRTMdMergeInputs Remove="@(CppWinRTMdMergeInputs)" />
    </ItemGroup>
  </Target>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions