-Warn when used in Visual Studio 2017 when using portable PDBs

-Fix Exporter not using correct output path
This commit is contained in:
lordmilko
2023-07-23 13:57:05 +10:00
parent 01f2f14907
commit 21201adb32
5 changed files with 22 additions and 18 deletions

View File

@@ -17,13 +17,9 @@
Unlike other libraries that rely on a wacky series of external dependencies, DllExports has everything it needs to do its job built in. Unlike other libraries that rely on a wacky series of external dependencies, DllExports has everything it needs to do its job built in.
DllExports is entirely driven by its MSBuild task, and provides a number of knobs you can adjust to customize the resulting assemblies, DllExports is entirely driven by its MSBuild task, and provides a number of knobs you can adjust to customize the resulting assemblies, including converting AnyCPU assemblies into both x86 and x64 outputs.
including converting AnyCPU assemblies into both x86 and x64 outputs.
Note that when using IDA Pro, load the file as "Portable executable for 80386 (PE)" instead of "Microsoft.NET assembly" in order to see the exports. In order to be able to debug your exports in Visual Studio you must be targeting .NET Framework and be using Visual Studio 2019 or newer. .NET Standard exports work but you can't debug them. .NET Core applications can't truly have unmanaged exports as you can't use mscoree to load their runtime. Consider using a library such as DNNE for proper .NET Core support.</PackageReleaseNotes>
In order to be able to debug your exports in Visual Studio you must be targeting .NET Framework. .NET Standard exports work but you can't debug them.
.NET Core applications can't truly have unmanaged exports as you can't use mscoree to load their runtime. Consider using a library such as DNNE for proper .NET Core support.</PackageReleaseNotes>
</PropertyGroup> </PropertyGroup>

View File

@@ -24,6 +24,12 @@
<DllExportsRemoveInputFile Condition="'$(DllExportsRemoveInputFile)' == ''">false</DllExportsRemoveInputFile> <DllExportsRemoveInputFile Condition="'$(DllExportsRemoveInputFile)' == ''">false</DllExportsRemoveInputFile>
</PropertyGroup> </PropertyGroup>
<Error
Text="Visual Studio 2017 will crash when attempting to debug Portable PDB files that have been modified by DllExports.
Consider setting &quot;&lt;DebugType&gt;full&lt;/DebugType&gt;&quot; or using a newer version of Visual Studio."
Condition="$(DllExportsEnabled) And '$(VisualStudioVersion)' == '15.0' And ('$(DebugType.ToLower())' == 'portable' Or '$(DebugType.ToLower())' == 'embedded')"
/>
<GenerateDllExports <GenerateDllExports
Enabled="$(DllExportsEnabled)" Enabled="$(DllExportsEnabled)"
InputFile="$(DllExportsInputFile)" InputFile="$(DllExportsInputFile)"

View File

@@ -131,7 +131,7 @@ namespace DllExports
moduleOptions.WritePdb = true; moduleOptions.WritePdb = true;
module.Write(options.OutputFile, moduleOptions); module.Write(output.Path, moduleOptions);
} }
} }

View File

@@ -23,9 +23,7 @@ Thus hopefully ensuring it continues to work into the future.
exports as you can't use mscoree to load their runtime. Consider using a library such as [DNNE](https://github.com/AaronRobinsonMSFT/DNNE) for proper .NET Core support exports as you can't use mscoree to load their runtime. Consider using a library such as [DNNE](https://github.com/AaronRobinsonMSFT/DNNE) for proper .NET Core support
(however this will require C++ tooling to be properly installed).** (however this will require C++ tooling to be properly installed).**
Note that when using IDA Pro, load the file as `Portable executable for 80386 (PE)` instead of `Microsoft.NET assembly` in order to see the exports. Please see [Tips](#tips) below for some important gotchas to be aware of.
See [Tips](#tips) for some important gotchas to be aware of.
## Usage ## Usage
@@ -66,25 +64,25 @@ for seamless support with legacy style projects. You can easily inject the requi
1. Insert the `props` import after all other props imports at the top of the file 1. Insert the `props` import after all other props imports at the top of the file
```xml ```xml
<Import Project="..\..\packages\DllExports.0.1.0\build\DllExports.props" Condition="Exists('..\..\packages\DllExports.0.1.0\build\DllExports.targets')" /> <Import Project="..\..\packages\DllExports.0.1.1\build\DllExports.props" Condition="Exists('..\..\packages\DllExports.0.1.1\build\DllExports.targets')" />
``` ```
2. Add a package reference, with `Private = False` so DllExports does not get emitted to your output directory 2. Add a package reference, with `Private = False` so DllExports does not get emitted to your output directory
```xml ```xml
<Reference Include="DllExports"> <Reference Include="DllExports">
<HintPath>..\..\packages\DllExports.0.1.0\lib\netstandard2.0\DllExports.dll</HintPath> <HintPath>..\..\packages\DllExports.0.1.1\lib\netstandard2.0\DllExports.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
``` ```
3. Import the `targets` at the end of the file and add a `Target` to warn when NuGet packages have not been restored 3. Import the `targets` at the end of the file and add a `Target` to warn when NuGet packages have not been restored
```xml ```xml
<Import Project="..\..\packages\DllExports.0.1.0\build\DllExports.targets" Condition="Exists('..\..\packages\DllExports.0.1.0\build\DllExports.targets')" /> <Import Project="..\..\packages\DllExports.0.1.1\build\DllExports.targets" Condition="Exists('..\..\packages\DllExports.0.1.1\build\DllExports.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup> </PropertyGroup>
<Error Condition="!Exists('..\..\packages\DllExports.0.1.0\build\DllExports.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\DllExports.0.1.0\build\DllExports.targets'))" /> <Error Condition="!Exists('..\..\packages\DllExports.0.1.1\build\DllExports.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\DllExports.0.1.1\build\DllExports.targets'))" />
</Target> </Target>
``` ```
@@ -92,8 +90,12 @@ Adjust the version number in the above snippets as necessary. The [NetFramework]
## Tips ## Tips
* You cannot use projects that generate Portable PDB files together with DllExports in Visual Studio 2017. Something about the modifications that dnlib (which DllExports uses internally) makes upsets Visual Studio when it goes to load
the modified PDB file, and crashes the entire program. As such, DllExports will throw an error if it detects you are using portable/embedded PDB files in Visual Studio 2017, and recommend you use `<DebugType>full</DebugType>` instead.
Newer versions of Visual Studio do not have this issue. It's not clear whether Visual Studio 2017 or dnlib is failing to follow the Portable PDB file format properly. Legacy style projects default to *full* PDB files, while SDK style projects
default to *portable*.
* Don't use types types external to your assembly or the CLR in the method signature of your exports. e.g. do not use the `HRESULT` type from [ClrDebug](https://github.com/lordmilko/ClrDebug). The runtime is not in a position to load * Don't use types types external to your assembly or the CLR in the method signature of your exports. e.g. do not use the `HRESULT` type from [ClrDebug](https://github.com/lordmilko/ClrDebug). The runtime is not in a position to load
external assemblies when your export is called. You can however use types defined in the same assembly that your export is defined in external assemblies when your export is called. You can however use types defined in the same assembly that your export is defined in.
* Once an external assembly has been loaded, it is safe to use types in external external assemblies in subsequently called exports * Once an external assembly has been loaded, it is safe to use types in external external assemblies in subsequently called exports
* You can force architecture specific files to be placed in an architecture specific subdirectory by setting `DllExportsArchitectureNameFormat` to something like `{arch}\{name}.{arch}` i.e. `Foo.dll` compiled for AMD64 will go to `x64\Foo.x64.dll` * You can force architecture specific files to be placed in an architecture specific subdirectory by setting `DllExportsArchitectureNameFormat` to something like `{arch}\{name}.{arch}` i.e. `Foo.dll` compiled for AMD64 will go to `x64\Foo.x64.dll`
* When multi-targeting, you can conditionally generate unmanaged exports for compatible assemblies as follows * When multi-targeting, you can conditionally generate unmanaged exports for compatible assemblies as follows

View File

@@ -1,8 +1,8 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<Version>0.1.0</Version> <Version>0.1.1</Version>
<AssemblyVersion>0.1.0.0</AssemblyVersion> <AssemblyVersion>0.1.0.0</AssemblyVersion>
<FileVersion>0.1.0.0</FileVersion> <FileVersion>0.1.1.0</FileVersion>
<InformationalVersion>0.1.0</InformationalVersion> <InformationalVersion>0.1.1</InformationalVersion>
</PropertyGroup> </PropertyGroup>
</Project> </Project>