2
votes

I have some native dll which must be copied in the bin folder with platform conditions. And I want them to be copied to the bin folder of projects referencing this project.

If I set the build action to Content, they will be copied to the bin folder but with the folder structure kept so they will not be in the bin folder but in sub folders. So when running the program, it will not be able to resolve the dll because they are in a subfolder.

For example if I have this code in the project file

<Choose>
    <When Condition=" '$(Platform)'=='x86' ">
      <ItemGroup>
        <Content Include="nativedll\somelib\x86\somelib.dll">
          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </Content>
      </ItemGroup>
    </When>
    <When Condition=" '$(Platform)'=='x64' ">
      <ItemGroup>
        <Content Include="nativedll\somelib\x64\somelib.dll">
          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </Content>
      </ItemGroup>
    </When>
  </Choose>

The dll will be in the folder bin\nativedll\somelib\x86\somelib.dll in the case of x86.

So I tried to use Post build script

<PostBuildEvent>

            IF "$(Platform)" == "x86" (
            xcopy /s /y "$(ProjectDir)\nativedll\somelib\x86" "$(TargetDir)"
            )
            IF "$(Platform)" == "x64" (
            xcopy /s /y "$(ProjectDir)\nativedll\somelib\x64" "$(TargetDir)"
            )
</PostBuildEvent>

But the dll are copied in the bin folder of the project but not in the bin folder of projects referencing it.

So my solution right now is to add a post build script in all projects using this one.

Is there a better way to do this in Visual Studio?

2
If you want something rock-solid you can embedd the DLL's as embedded resources, when your library is initialized it checks if the dll's exist on the right folder, if not then it writes them from the embedded resources to the disk. In this way you can not include at all the files on the package and those will be reconstructed, even in the case of an accidental delete.Gusman
Not so rock-solid, a properly deployed program lives in a directory that has no write-access. Like c:\program files\yadayada. Allowing anybody to arbitrarily add or replace DLLs is not a solid feature.Hans Passant

2 Answers

4
votes

Try using this for each file that has to be copied (csproj file - make an item group):

<ItemGroup>
   <ContentWithTargetPath Include="mySourcePath\myFile.dll">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <TargetPath>myFile.dll</TargetPath>
 </ContentWithTargetPath >
</ItemGroup>

The referencing project should also contain the copied files.


The following may help as well:

Copy native dependencies locally in a Visual Studio project

Add native files from NuGet package to project output directory @kjbartel

0
votes

I give the solution I used before I got @dajuric anwser. I prefer dajuric solution because it doesn't involve code looking in an other folder.

I used conditional Content in the csproj.

<When Condition=" '$(Platform)'=='x86' ">
      <ItemGroup>
        <Content Include="nativedll\somelib\x86\somelib.dll">
          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </Content>
      </ItemGroup>
    </When>
//same for x64
    ...

Then before initialising the library using the native dll, I added the folder to the dll lookup folder list with kernel32 SetDllDirectory.

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool SetDllDirectory(string lpPathName);

 SetDllDirectory(@".\nativedll\somelib\x"+ (Environment.Is64BitProcess ? "64" : "32"));