3F / DllExport

.NET DllExport with .NET Core support (aka 3F/DllExport aka DllExport.bat)
MIT License
937 stars 131 forks source link

DllExport doesn't compile when duplicate _ are present #203

Closed CoenraadS closed 1 year ago

CoenraadS commented 2 years ago

Steps to reproduce:

. . .

Visual Studio 2022 Preview
MSBuild: 17.1.0-preview-22055-02+797fd829a for .NET Framework

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net472</TargetFramework>
    <LangVersion>latest</LangVersion>
    <PlatformTarget>x86</PlatformTarget>
    <RuntimeIdentifier>win-x86</RuntimeIdentifier>
    <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
    <RootNamespace>InnoSetup.dotnet</RootNamespace>
  </PropertyGroup>
  <PropertyGroup>
    <DllExportIdent>30367779-E45B-48EF-8852-9E7195430789</DllExportIdent>
    <DllExportMetaLibName>DllExport.dll</DllExportMetaLibName>
    <DllExportNamespace>System.Runtime.InteropServices</DllExportNamespace>
    <DllExportDDNSCecil>true</DllExportDDNSCecil>
    <DllExportSkipOnAnyCpu>false</DllExportSkipOnAnyCpu>
    <DllExportPlatform>Auto</DllExportPlatform>
    <DllExportOrdinalsBase>1</DllExportOrdinalsBase>
    <DllExportGenExpLib>false</DllExportGenExpLib>
    <DllExportOurILAsm>false</DllExportOurILAsm>
    <DllExportSysObjRebase>false</DllExportSysObjRebase>
    <DllExportLeaveIntermediateFiles>false</DllExportLeaveIntermediateFiles>
    <DllExportTimeout>30000</DllExportTimeout>
    <DllExportPeCheck>2</DllExportPeCheck>
    <DllExportPatches>0</DllExportPatches>
    <DllExportPreProcType>0</DllExportPreProcType>
    <DllExportPostProcType>0</DllExportPostProcType>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="DllExport" Version="1.7.4" />
  </ItemGroup>
  <ImportGroup Label=".NET DllExport">
    <Import Project="$(SolutionDir)packages\DllExport.1.7.4\tools\net.r_eg.DllExport.targets" Condition="Exists($([MSBuild]::Escape('$(SolutionDir)packages\DllExport.1.7.4\tools\net.r_eg.DllExport.targets')))" Label="8337224c9ad9e356" />
  </ImportGroup>
  <Target Name="DllExportRestorePkg" BeforeTargets="PrepareForBuild">
    <Error Condition="!Exists('$(SolutionDir)DllExport.bat')" Text="DllExport.bat is not found. Path: '$(SolutionDir)' - https://github.com/3F/DllExport" />
    <Exec Condition="('$(DllExportModImported)' != 'true' Or !Exists('$(SolutionDir)packages\DllExport.1.7.4\tools\net.r_eg.DllExport.targets')) And Exists('$(SolutionDir)DllExport.bat')" Command=".\DllExport.bat  -action Restore" WorkingDirectory="$(SolutionDir)" />
    <MSBuild Condition="'$(DllExportModImported)' != 'true'" Projects="$(SolutionDir)packages\DllExport.1.7.4\tools\net.r_eg.DllExport.targets" Targets="DllExportMetaXBaseTarget" Properties="TargetFramework=$(TargetFramework)">
      <Output TaskParameter="TargetOutputs" PropertyName="DllExportMetaXBase" />
    </MSBuild>
    <ItemGroup>
      <Reference Include="DllExport, PublicKeyToken=8337224c9ad9e356">
        <HintPath>$(SolutionDir)packages\DllExport.1.7.4\gcache\$(DllExportMetaXBase)\$(DllExportNamespace)\$(DllExportMetaLibName)</HintPath>
        <Private>False</Private>
        <SpecificVersion>False</SpecificVersion>
      </Reference>
    </ItemGroup>
  </Target>
  <Target Name="DllExportRPkgDynamicImport" BeforeTargets="PostBuildEvent" DependsOnTargets="GetFrameworkPaths" Condition="'$(DllExportModImported)' != 'true' And '$(DllExportRPkgDyn)' != 'false'">
    <MSBuild BuildInParallel="true" UseResultsCache="true" Projects="$(MSBuildProjectFullPath)" Properties="DllExportRPkgDyn=true" Targets="Build" />
  </Target>
</Project>
using System;
using System.Runtime.InteropServices;

namespace InnoSetup.dotnet
{
    public static class InnoSetup
    {
        public static Func<string, int, int> MessageBox { get; private set; } = (_, _) => throw new Exception(nameof(MessageBox));
        public static void SetMessageBoxCallback(Func<string, int, int> callback) => MessageBox = callback;
    }

    public static class Exports
    {
        public delegate int MessageBoxDelegate([MarshalAs(UnmanagedType.LPWStr)] string message, int options);
        [DllExport(nameof(RegisterMessageBoxCallback), CallingConvention = CallingConvention.StdCall)]
        public static void RegisterMessageBoxCallback(MessageBoxDelegate callback)
        {
            InnoSetup.SetMessageBoxCallback((message, options) => callback(message, options));
        }
    }
}

Hi, so interestingly it doesn't like the (_, _) => ...

If I change it to (a, b) => ... it's ok

Error message:

dotnet.il(121) : warning : Duplicate param name '_' in method '<.cctor>b__15_2' dotnet ...\packages\DllExport.1.7.4\tools\net.r_eg.DllExport.targets 76

CoenraadS commented 2 years ago

I then removed this nuget package and tried again and it succeeded. It seems DLLExport only supports up to LangVersion 7.3

My feeling in the .bat file picks up old msbuild. VSWhere is a better way to determine latest MSBuild:

set VSWHERE="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe

@REM VSWhere command only returns one line as output, but cmd requires a loop to capture it..
for /f "delims=" %%i in ('%VSWHERE%') do set MSBUILD="%%i"

echo Using MSBuild: %MSBUILD%
3F commented 2 years ago

In log you can find what instance is actually selected, for example

[Debug] Instance: 'C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\amd64\MSBuild.exe'

Also,

VSWhere is a better way to determine latest MSBuild:

hMSBuild is better due to backward compatibility with all products.

Since DllExport.bat was based on GetNuTool + hMSBuild, see related keys:

DllExport -h

-msb {path}           - Full path to specific msbuild.
-hMSBuild {args}      - Access to hMSBuild tool (packed) https://github.com/3F/hMSBuild
-GetNuTool {args}     - Access to GetNuTool (integrated) https://github.com/3F/GetNuTool
-debug                - To show additional information.

Tl;dr

(, ) => throw new Exception(nameof(MessageBox)); ... dotnet.il(121) : warning : Duplicate param name '_' in method '<.cctor>b__15_2' dotnet ...\packages\DllExport.1.7.4\tools\net.r_eg.DllExport.targets 76

I think this is expected behavior since I don't remember implementing any support for _ discards in a lambda. Thus, only if in future releases. Thanks for the report!