Where to place dlls for unmanaged libraries? - dll

I am trying to create a Nuget package for a library that depends on ghostscript and therefore references gsdll32.dll - an unmanaged library. I can't just included that a standard dll reference. Where do I put this in the nuget directory structure?

Add a build folder to the package and, if the package for example has the id MyPackage, add a MSBuild target file called MyPackage.targets to this folder. It is important that the .targets file has the same name as the .nuspec file. In the .nuspec file you must have a section like this:
<files>
<file src="lib\*.*" target="lib" />
<file src="build\MyPackage.targets" target="build" />
</files>
This will add an MSBuild element in the project file pointing to the .targets file.
Furthermore, to only register the managed dlls, add a section like this:
<references>
<reference file="MyManaged.dll" />
</references>
The .targets file should look something like this:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CopyMyPackageFiles" AfterTargets="AfterBuild">
<ItemGroup>
<MyPackageFiles Include="$(MSBuildThisFileDirectory)..\lib\*.*"/>
</ItemGroup>
<Copy SourceFiles="#(MyPackageFiles)" DestinationFolder="$(OutputPath)" >
</Copy>
</Target>
</Project>
Now, all files - including unmanaged files - will be copied to the project output folder (e.g. \bin\debug) after the build.

The above reference can work, but it actually modifies your post build event to push files over, which may not actually fix your issue if you have the situation we did.
The issue we were having was a dependent DLL could not be registered, but had to exist side by side with another DLL which needed to be registered by nuget so it needed to exist in the lib directory but not be registered.
The nuspec reference now allows you to specify which DLLs in the lib directory get explicitly registered in the visual studio project now, you simply need to add into your nuspec file in the metadata area an explicit references list (if this does not exist the default behavior of nuget is to attempt to register everything under lib).
Here is an example nuspec file of what I mean:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>SomePackageID</id>
<version>1.0.1</version>
<title>Some Package Title</title>
<authors>Some Authors</authors>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Blah blah blah.</description>
<references>
<reference file="ceTe.DynamicPDF.Rasterizer.20.x86.dll" />
</references>
</metadata>
<files>
<file src="\\SomeNetworkLocation\ceTe.DynamicPDF.Rasterizer.20.x86.dll" target="lib\ceTe.DynamicPDF.Rasterizer.20.x86.dll" />
<file src="\\SomeNetworkLocation\DPDFRast.x86.dll" target="lib\DPDFRast.x86.dll" />
</files>
</package>
As you can see, ceTe.DynamicPDF.Rasterizer.20.x86.dll needs to be registered, but DPDFRast.x86.dll simply needs to exist in that directory to support the other DLL and won't be registered but through some dynamic referencing magic will ultimately be copied over into the destination bin directory anyway because visual studio sees that the first DLL is dependent upon the second.
Here is the original nuspec reference.

Response on the Nuget forum: http://nuget.codeplex.com/discussions/352689
pranavkm:
The SQLCE package has a similar issue that we handle via PS
scripts. Checkout out the scripts at
https://bitbucket.org/davidebbo/nugetpackages/src/1cba18b864f7/SqlServerCompact/Tools.

I largely got this to work using Lars Michael's method, but one thing I needed to add comes from James Eby's answer. Visual Studio was trying to register all the dll's in my lib directory, so I added a references element to the metadata in the nuspec file to tell it to only register the managed dll:
<references>
<reference file="FANNCSharp.dll" />
</references>
Also in
<MyPackageFiles Include="$(MSBuildProjectDirectory)\..\Packages\MyPackage\lib\*.*"/>
I first tried the id of my package FANNCSharp-x64, but it needed the full package name: FANNCSharp-x64.0.1.4.

One problem I had was that the packages path wasn't always in the same place relative to the project file. The following worked for me:
Within the NuGet package, place your unmanaged DLLs in the lib\native folder.
Add the following script to the tools folder:
install.ps1
#This script creates or updates a PackagesPath property in the project file
param($installPath, $toolsPath, $package, $project)
$project.Save()
#Load the csproj file into an xml object
[xml] $xml = Get-Content -path $project.FullName
#grab the namespace from the project element
$nsmgr = New-Object System.Xml.XmlNamespaceManager -ArgumentList $xml.NameTable
$nsmgr.AddNamespace('a',$xml.Project.GetAttribute("xmlns"))
#find or create the property
$property = $xml.Project.SelectSingleNode("//a:PropertyGroup//a:PackagesPath", $nsmgr)
if (!$property)
{
$property = $xml.CreateElement("PackagesPath", $xml.Project.GetAttribute("xmlns"))
$propertyGroup = $xml.CreateElement("PropertyGroup", $xml.Project.GetAttribute("xmlns"))
$propertyGroup.AppendChild($property)
$xml.Project.InsertBefore($propertyGroup, $xml.Project.ItemGroup[0])
}
#find the relative path to the packages folder
$absolutePackagesPath = (get-item $installPath).parent.FullName
push-location (split-path $project.FullName)
$relativePackagesPath = Resolve-Path -Relative $absolutePackagesPath
pop-location
#set the property value
$property.InnerText = $relativePackagesPath
#save the changes.
$xml.Save($project.FullName)
Add a targets file to the build folder. (Change "MyPackage" to the name of your package). Using a unique name for the target, like "CopyMyPackage", avoids conflicts with other packages trying to define the "AfterBuild" target. This targets file makes use of the $(PackagesPath) property defined by the above script.
MyPackage.targets
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CopyMyPackage" AfterTargets="AfterBuild">
<ItemGroup>
<MyPackageSourceFiles Include="$(PackagesPath)\MyPackage.*\lib\native\*.*"/>
</ItemGroup>
<Copy SourceFiles="#(MyPackageSourceFiles)" DestinationFolder="$(OutputPath)" >
</Copy>
</Target>
</Project>
Finally, add a "MyPackageReadMe.txt" to the Content folder. This will enable the package to install.
See also: http://alski.net/post/2013/05/23/Using-NuGet-25-to-deliver-unmanaged-dlls.aspx

For .NET Core this is pretty straightforward if you know what runtime platform your native code targets. You might notice a folder called "runtimes" in the .NET Core build folder under the bin tree when you build. It looks something like this:
These folders are designed to hold any platform specific stuff, including unmanaged/native DLLs.
In your NuGet package add a the following under the "Files" section:
<file src="[source path for file in package]" target="runtimes\[platform]\native\[file name]" />
When executing the application, the runtime environment will look for unmanaged dlls in the corresponding platform directory.
If you want to target multiple platforms, just add another file entry for each platform.

Related

MSBuild: How may I access built-in properties while defining my own custom properties?

I have a file named Common.targets defined like so:
<Project>
<PropertyGroup>
<TlbExpPath>"c:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\x64\tlbexp"</TlbExpPath>
<TlbOutPath>"$(OutDir)..\TLB\$(TargetName).tlb"</TlbOutPath>
</PropertyGroup>
<Target Name="TlbExp" AfterTargets="CopyFilesToOutputDirectory" Inputs="$(TargetPath)" Outputs="$(TlbOutPath)">
<Exec Command='$(TlbExpPath) "$(TargetPath)" /nologo /win64 /out:$(TlbOutPath) /verbose' />
</Target>
</Project>
When I inspect the output of the TlbOutPath property, it looks like:
"..\TLB\.tlb"
Apparently, $(OutDir) and $(TargetName) produce nothing when used within a PropertyGroup. I'm not sure why. How can I make these paths/values reusable while still having access to built-in properties when they are defined?
I'm using MSBuild that comes bundled with Visual Studio 2019. I add an Import element to my actual .csproj projects to include this target where I need it. The csproj projects use the SDK format for the projects, e.g. <Project Sdk="Microsoft.NET.Sdk">.
Here is an example of what the import looks like:
<Project Sdk="Microsoft.NET.Sdk">
<!-- etc -->
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<!-- etc -->
</ItemGroup>
<Import Project="$(RepositoryRoot)\Common.targets" />
</Project>
MSBuild: How may I access built-in properties while defining my own
custom properties?
This is quite an issue in the new sdk format project. I have tested it and got the same issue as you said which quite bother me a lot. Like $(OutDir),$(TargetName),$(OutputPath),$(TargetPath) and some other common system properties cannot be used in a new property while $(Configuration) and $(AssemblyName) works well.
And not only us but also someone else also face the same issue about it.See this thread.
For the traditional old csproj format project, there was no problem with these properties being used this way, but in the new SDK format project, it is impossible to assign some common properties such as $(OutDir),$(TargetName) and $(TargetPath) to a new property. As we know, most of the common properties are defined in the Microsoft.Common.props file(old csproj format) which is quite different from the new sdk format project which does not have such file.
In order to get an answer,l have reported this issue to DC Forum. See this.You can enter this link and add any detailed comments to describe this issue. And anyone who interested in this issue will also vote it so that it will get more Microsoft staff's attention. All these efforts will speed up and get the final answer.
This process may take a while or you could try my suggestion.
Suggestion
1) You can customize this property $(OutDir) in Common.targets file, and use $(TargetFramework) instead of $(TargetName) since $(TargetFramework) is defined in the xxxx.csproj file.
<Project>
<PropertyGroup>
<OutDir>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName)\</OutDir>
<TlbExpPath>"c:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\x64\tlbexp"</TlbExpPath>
<TlbOutPath>"$(OutDir)..\TLB\$(TargetName).tlb"</TlbOutPath>
<TargetPath>xxxx\xxxx.dll(exe)</TargetPath>--------the absolute path of the output file
</PropertyGroup>
<Target Name="TlbExp" AfterTargets="CopyFilesToOutputDirectory" Inputs="$(TargetPath)" Outputs="$(TlbOutPath)">
<Exec Command='$(TlbExpPath) "$(TargetPath)" /nologo /win64 /out:$(TlbOutPath) /verbose' />
</Target>
</Project>
2) use Directory.Build.targets file rather than a custom targets file.
A) You should add a file named Directory.Build.targets(it must be named this and have its own rule to be imported into xxx.csproj) under the project folder.
B) add the content of Common.targets into it without any changes and then build your project directly. The Directory.Build.targets will be imported into your project automatically while build.
This function works well and will not lose any properties. However, l stil bother why it works.
Conclusion
I think #2 is more suitable and easier for you to achieve your goal.

MSBuild multiple dll in a single NuGet package

I have a Visual Studio 2017 solution that contains two projects:
Foo.csproj
Foo.Core.csproj
Both of these projects target multiple frameworks: net452;netstandard1.2
Foo.csproj includes a project reference to Foo.Core.csproj:
<ItemGroup>
<ProjectReference Include="..\Foo.Core\Foo.Core.csproj" />
</ItemGroup>
When I generate a NuGet package for Foo.csproj, I want the nupkg file to include both of these assemblies.
What is currently happening is that the NuGet package that gets created has Foo.dll and then a NuGet dependency on Foo.Core (which doesn't exist).
How can I generate a single NuGet package using msbuild that will include both assemblies?
For reference this is the command I am currently using (which is not working how I want it to):
msbuild /p:restore,pack Foo.csproj
This is currently not directly supported by NuGet out of the box. You can follow this GitHub issue for updates.
However, there are a few ways to create such NuGet package.
Use the "Nugetizer 3000"
This is an newly developed tool to build NuGet packages from projects and works by installing the NuGet.Build.Packaging nuget package. You can find some documentation on it on its GitHub wiki page but since it is a very new project, there isn't much documentation or community knowledge around it yet(!) (but the team developing it is very helpful, you could file GitHub issues if you get stuck).
Adding a custom target in the project (2.0.0 tooling / VS 2017 15.3+): Create an item in the csproj that will include the referenced project's output DLL
This approach is very hacky as it relies on an internal MSBuild item that the pack targets use. It works by first marking the <ProjectReference> to not be referenced from the created nuget package like this:
<ProjectReference Include="..\libA\libA.csproj" PrivateAssets="All"/>
Then you can add this to the project to include the generated libA.dll in the nuget package:
<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);IncludeP2PAssets</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<Target Name="IncludeP2PAssets">
<ItemGroup>
<BuildOutputInPackage Include="$(OutputPath)\testprivatelib.dll" />
</ItemGroup>
</Target>
Note that this requires you to add all the <PackageReference> items of the referenced project to the project you generate the package from since they would be missing from the generated package since you effectively disabled the transitive reference behaviour.
Create a custom .nuspec file
At the time of writing, this is probably the most "supported" way, but also the most complex. NuGet allows you to disable the automatic generation of the resulting .nuspec file and automatic collection of files by setting the <NuspecFile> property in your project, along with a <NuspecProperties> property that allows you to pass replacement tokens for parsing the .nuspec file.
This works by modifying the project file like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
<NuspecFile>$(MSBuildThisFileDirectory)$(MSBuildProjectName).nuspec</NuspecFile>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\LibB\LibB.csproj" />
</ItemGroup>
<Target Name="SetNuspecProperties" BeforeTargets="GenerateNuspec">
<PropertyGroup>
<NuspecProperties>$(NuspecProperties);id=$(AssemblyName)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);config=$(Configuration)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);version=$(PackageVersion)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);description=$(Description)</NuspecProperties>
<NuspecProperties>$(NuspecProperties);authors=$(Authors)</NuspecProperties>
</PropertyGroup>
</Target>
</Project>
This will automatically look for a .nuspec file with the same name as the project (somelib.csproj => somelib.nuspec) and pass some properties along to it. The properties are created in a target in order to be able to access fully resolved and defaulted properties like PackageVersion.
The .nuspec file could look like this:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>$id$</id>
<version>$version$</version>
<authors>$authors$</authors>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>$description$</description>
<dependencies>
<group targetFramework=".NETStandard1.4">
<dependency id="NETStandard.Library" version="1.6.1" exclude="Build,Analyzers" />
</group>
</dependencies>
</metadata>
<files>
<file src="bin\$config$\netstandard1.4\*.dll" target="lib\netstandard1.4\" />
</files>
</package>
Note that you must add all referenced NuGet packages as a <dependency> element in the .nuspec file since these are no longer automatically generated from the <PackageReference> items in your project file. Refer to the NuSpec Reference for more details.
I have recently created an example project on GitHub demonstrating the use of a custom .nuspec file for exactly this purpose.
The second option that Martin Ullrich mentioned is the only one that works out of the box with .NET Standard that allows to "Generate NuGet package on build" as an integral part of the build.
However like he mentions it has a "hard coded" dependency on a dll with an exact name that you expect to be there (on the output folder) which might bite you in the future. I've found a better alternative which worked for me in .NET Standard without the need of any other modification on this post.
I'll quote it here for completeness.
First you edit your csproj and define the PrivateAssets tag for the reference that you'd like to include:
<ItemGroup>
<ProjectReference Include="..\ClassLibrary1\ClassLibrary1.csproj">
<PrivateAssets>all</PrivateAssets>
</ProjectReference>
</ItemGroup>
Then you add this to your csproj:
<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences">
<ItemGroup>
<BuildOutputInPackage Include="#(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'all'))" />
</ItemGroup>
</Target>
That post also shows how to include the PDBs in the NuGet package option if necessary (which I omitted here).
Been struggling with the same issue and none of the suggested workarounds worked (https://github.com/NuGet/Home/issues/3891) and I couldn't change the csproj to use the new SDK coming with .netcore.
Luckily the nuget pack command comes with the -IncludeReferencedProjects option (ref: https://learn.microsoft.com/en-us/nuget/tools/cli-ref-pack) which does exactly that:
"Indicates that the built package should include referenced projects either as dependencies or as part of the package. If a referenced project has a corresponding .nuspec file that has the same name as the project, then that referenced project is added as a dependency. Otherwise, the referenced project is added as part of the package."
Regardless of the *.nuspec file (not needed here) , add -IncludeReferencedProjects to the pack command and the referenced project dlls will be included along with the nuget dll.
nuget.exe pack yourProject.csproj -IncludeReferencedProjects
I have recently discovered that you CANNOT set defaults for the Nuspec Properties you want to replace in the msbuild command line e.g. if a metadata value is set in the .csproj file of "<Version>2.0.0</Version>" and you run:
msbuild myproject.csproj -t:pack -p:Configuration=Release -p:NuspecProperties=Configuration=Release;PackageVersion=1.2.3
Your .nupgk file will have the version 2.0.0 still. Annoyingly the MS documentation is not clear on this and no error is displayed.

Create NuGet package for C++/CLI (mixed) assembly

I have created a C++/CLI (mixed) assembly which has a managed wrapper class around some unmanaged C++ code. The managed part targets .NET 4.6.1, I got a file entry.cpp with just this line to do that:
[assembly:System::Runtime::Versioning::TargetFrameworkAttribute(L".NETFramework,Version=v4.6.1", FrameworkDisplayName = L".NET Framework 4.6.1")];
When I now manually include the compiled assembly in a .NET 4.6.1 project I can use the managed class as expected.
This project can be build four ways: x86 or x64 as either debug or release build. It has no managed dependencies.
Now I want one (or if required multiple) NuGet packages which I can upload to my feed and use the wrapper assembly easily in every .NET 4.6.1 compatible project I would like. How do I achieve this?
So far I tried two approaches:
First, I created a .autopkg file which is according to this blog post the way to provide native DLLs. The files section of that file looks like this:
files {
// include: { *.h };
[x86,v120,release] {
symbols: { ..\Release\*.pdb; }
bin: { ..\Release\*.dll; }
};
[x86,v120,debug] {
symbols: { ..\Debug\*.pdb; }
bin: { ..\Debug\*.dll; }
};
};
This process results in three .nupkg files which I can upload to my feed. But when I try to install that package to a .NET 4.6.1 project I get this error message:
Could not install package 'MyCppCliWrapper.redist 1.0.0.2'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.6.1', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.
So I rethought if I should not use the way for managed assembly to create the .nupkg because the assembly has a managed class I want to use from managed code. I created a .nuspec (using nuget spec) and provided the metadata. Then I try to create my package like this:
nuget pack MyCppCliWrapper.nuspec -Prop Configuration=Release -Prop Platform=x86 -Build
But that results in a package which contains the whole project with all source files and temporary files, just like a zip file of that folder.
Obviously there is also missing the meta information about targeted framework.
When I try to use the project file to create the package (like with C# assemblies) this fails too:
Please specify a nuspec, project.json, or project file to use
The C++ project files, .vcxproj, seem to be unsupported by NuGet (I am using the NuGet 3.5.0.1938 command line utility).
Will I need to build manually and provide all files in the files section of the .nuspec? If yes, how would he know from this line which DLL is for which .NET framework plus platform?
<file src="bin\**\*.dll" target="lib" />
I believe Hans Passant is right, this is just a regular managed nuget package but the packager does not handle the .vcxproj files so I made up my own .nuspec:
<?xml version="1.0"?>
<package >
<metadata>
...
</metadata>
<files>
<file src="readme.txt" target="" />
<file src="bin\Win32\Release\*.dll" target="lib\net461" />
<file src="bin\Win32\Release\*.pdb" target="lib\net461" />
</files>
</package>
The package generated this ways works.
There is one question remaining: This way, do I have to do two packages, one for 32bit and one for 64bit - or is it possible to include them in one package (which I would prefer) and have the consuming project use one or another depending on the target architecture (any-cpu is mostly 32bit)?
I don't know if this could still help you, but I've managed to pack both x64 and x86 C++ code, and a C# wrapper that was compiled on AnyCPU.
On My C# project, I have two Platforms: "x86" and "x64".
On my Nuget folder, I have the following structure:
\Project
\Project.1.0.nuspec
\build
\x64
\*.dll
\*.pdb
\x86
\*.dll
\*.pdb
\Project.targets
\lib
\net452
\Wrapper.dll
\Wrapper.pdb
Project.nuspec:
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>Project</id>
<version>1.0</version>
<authors>nilsonneto</authors>
<owners>nilsonneto</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Example.</description>
<references>
<reference file="Wrapper.dll" />
</references>
</metadata>
<files>
<file src="build\Project.targets" target="build\Project.targets" />
<file src="build\x64\**" target="build\x64" />
<file src="build\x86\**" target="build\x86" />
<file src="lib\net452\Wrapper.dll" target="lib\net452\Wrapper.dll" />
<file src="lib\net452\Wrapper.pdb" target="lib\net452\Wrapper.pdb" />
</files>
</package>
Project.targets:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<NativeLibs Include="$(MSBuildThisFileDirectory)\$(Platform)\*.*" />
<Content Include="#(NativeLibs)">
<Link>%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
Notice the $(Platform), which is where the name of the Platform being build on Visual Studio will be placed, which is why I separated the C++ DLLs in folders with the same name as the Platforms in Visual Studio.
And according to the documentation (https://learn.microsoft.com/en-us/nuget/create-packages/native-packages), all native DLLs have to be placed in the \build directory.
Native NuGet packages targeting native then provide files in \build, \content, and \tools folders; \lib is not used in this case (NuGet cannot directly add references to a C++ project). A package may also include targets and props files in \build that NuGet will automatically import into projects that consume the package. Those files must be named the same as the package ID with the .targets and/or .props extensions.
So, just adjust the folder names based on the Platforms you support on the .NET project and your set.

Use MSBuild Targets to copy files recursively from NuGet package

I have a .targets file in my NuGet package build folder which is then automatically included in the project that consumes the NuGet package.
I want this .targets file to copy some folders on post-build. The following script shows how that is done, but the output I get is wrong because %(RecursiveDir) starts at the first wild-card which I used for the version number of the package.
My question: How can I specify the version of MyPackage in the .targets file dynamically so that I can remove the first wildcard?
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="AfterBuild">
<ItemGroup>
<!-- MyPackage.* should be replaced by MyPackage.1.0.0.4534. But the version is set by NuGet.exe pack -Version -->
<FilesToCopy Include="$(SolutionDir)packages\MyPackage.*\myfolder\**\*.*"/>
</ItemGroup>
<Copy SourceFiles="#(FilesToCopy)" DestinationFolder="$(SolutionDir)bin\$(Configuration)\myfolder\%(RecursiveDir)"/>
</Target>
</Project>
To avoid having to the package version you could use the MSBuildThisFileDirectory property instead.
The MSBuildThisFileDirectory property gives you the directory where the .targets file is so you can change the <FilesToCopy> element to use a path relative to that directory and you do not have to use the version number.
<FilesToCopy Include="$(MSBuildThisFileDirectory)myfolder\**\*.*"/>

How do I use my .targets file in Visual Studio with custom build actions?

I am a beginner with MSBuild. So far I have been able to create a custom task called 'MakeTextFile' which creates a text file in C:\ based on the contents property you pass it. This works running from a command line prompt.
I have also included this in my .targets file (under the project tag):
<ItemGroup>
<AvailableItemName Include="CreateTextFileAction" />
</ItemGroup>
When I use the Import tag on my client applications .csproj I can now set items build actions to 'CreateTextFileAction', however the action never triggers (as no text file on C:\ is created)
How do I get all the file paths of items that were marked with my build action 'CreateTextFileAction' and pass them onto my custom task?
For reference, my .targets file:
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<AvailableItemName Include="CreateTextFileAction" />
</ItemGroup>
<UsingTask AssemblyFile="CustomMSBuildTask.dll" TaskName="CustomMSBuildTask.MakeTextFile" />
<Target Name="MyTarget">
<MakeTextFile Contents="TODO HOW DO I GRAB MARKED FILES?" />
</Target>
</Project>
A csproj file has a defined set of targets. The three main entry points are Build, Rebuild and Clean. These targets each have a set of dependencies. If you write your own targets to be part of the standard csproj build you need to find a suitable injection point within these dependencies.
For ease of use there are two standard targets for you to override called BeforeBuild and AfterBuild. If you define this in the csproj file (after the import of the csharp targets file) and call your custom task in there then it should work (or at least move further along).
<Target Name="BeforeBuild">
<MakeTextFile Contents="TODO HOW DO I GRAB MARKED FILES?" />
</Target>