Add native files from NuGet package to project out

2019-01-04 16:42发布

I'm trying to create NuGet package for a .Net assembly which does pinvoke to a native win32 dll. I need to pack both the assembly and the native dll with the assembly added to the project references (no problem at this part) and the native dll should be copied into the project output directory or some other relative directory.

My questions are:

  1. How do I pack the native dll without visual studio trying to add it into the references list?
  2. Do I have to write an install.ps1 for copying the native dll? If so how can I access the package content for copying it?

9条回答
孤傲高冷的网名
2楼-- · 2019-01-04 17:05

It's a bit late but I've created a nuget package exaclty for that.

The idea is to have an additional special folder in your nuget package. I'm sure you already know Lib and Content. The nuget package I've created looks for a Folder named Output and will copy everything which is in there to the projects output folder.

The only thing you have to do is add a nuget dependency to the package http://www.nuget.org/packages/Baseclass.Contrib.Nuget.Output/

I've written a blog post about it: http://www.baseclass.ch/blog/Lists/Beitraege/Post.aspx?ID=6&mobile=0

查看更多
来,给爷笑一个
3楼-- · 2019-01-04 17:07

There's a pure C# solution which I find rather easy to use and I don't have to bother with NuGet limitations. Follow these steps:

Include the native library in your project and set its Build Action property to Embedded Resource.

Paste the following code into class where you PInvoke this library.

private static void UnpackNativeLibrary(string libraryName)
{
    var assembly = Assembly.GetExecutingAssembly();
    string resourceName = $"{assembly.GetName().Name}.{libraryName}.dll";

    using (var stream = assembly.GetManifestResourceStream(resourceName))
    using (var memoryStream = new MemoryStream(stream.CanSeek ? (int)stream.Length : 0))
    {
        stream.CopyTo(memoryStream);
        File.WriteAllBytes($"{libraryName}.dll", memoryStream.ToArray());
    }
}

Call this method from the static constructor like as follows UnpackNativeLibrary("win32"); and it will unpack the library to disk just before you need it. Of course, you need to be sure that you have write permissions to that part of the disk.

查看更多
forever°为你锁心
4楼-- · 2019-01-04 17:09

I can't solve your exact problem, but I can give you a suggestion.

Your key requirement is : "And have it not auto-register the reference".....

So you'll have to to become familiar with "solution items"

See reference here:

Adding solution-level items in a NuGet package

You'll have to write some powershell voodoo to get the copy of your native dll into its home (again, because you do NOT want the auto-add-reference voodoo to fire)

Here is a ps1 file I wrote.....to put files in a third party references folder.

There is enough there for you to figure out how to copy your native dll to some "home"...without having to start from scratch.

Again, its not a direct-hit, but its better than nothing.

param($installPath, $toolsPath, $package, $project)
if ($project -eq $null) {
$project = Get-Project
}

Write-Host "Start Init.ps1" 

<#
The unique identifier for the package. This is the package name that is shown when packages are listed using the Package Manager Console. These are also used when installing a package using the Install-Package command within the Package Manager Console. Package IDs may not contain any spaces or characters that are invalid in an URL.
#>
$separator = " "
$packageNameNoVersion = $package -split $separator | select -First 1

Write-Host "installPath:" "${installPath}"
Write-Host "toolsPath:" "${toolsPath}"
Write-Host "package:" "${package}"
<# Write-Host "project:" "${project}" #>
Write-Host "packageNameNoVersion:" "${packageNameNoVersion}"
Write-Host " "

<# Recursively look for a .sln file starting with the installPath #>
$parentFolder = (get-item $installPath)
do {
        $parentFolderFullName = $parentFolder.FullName

        $latest = Get-ChildItem -Path $parentFolderFullName -File -Filter *.sln | Select-Object -First 1
        if ($latest -ne $null) {
            $latestName = $latest.name
            Write-Host "${latestName}"
        }

        if ($latest -eq $null) {
            $parentFolder = $parentFolder.parent    
        }
}
while ($parentFolder -ne $null -and $latest -eq $null)
<# End recursive search for .sln file #>


if ( $parentFolder -ne $null -and $latest -ne $null )
{
    <# Create a base directory to store Solution-Level items #>
    $thirdPartyReferencesDirectory = $parentFolder.FullName + "\ThirdPartyReferences"

    if ((Test-Path -path $thirdPartyReferencesDirectory))
    {
        Write-Host "--This path already exists: $thirdPartyReferencesDirectory-------------------"
    }
    else
    {
        Write-Host "--Creating: $thirdPartyReferencesDirectory-------------------"
        New-Item -ItemType directory -Path $thirdPartyReferencesDirectory
    }

    <# Create a sub directory for only this package.  This allows a clean remove and recopy. #>
    $thirdPartyReferencesPackageDirectory = $thirdPartyReferencesDirectory + "\${packageNameNoVersion}"

    if ((Test-Path -path $thirdPartyReferencesPackageDirectory))
    {
        Write-Host "--Removing: $thirdPartyReferencesPackageDirectory-------------------"
        Remove-Item $thirdPartyReferencesPackageDirectory -Force -Recurse
    }

    if ((Test-Path -path $thirdPartyReferencesPackageDirectory))
    {
    }
    else
    {
        Write-Host "--Creating: $thirdPartyReferencesPackageDirectory-------------------"
        New-Item -ItemType directory -Path $thirdPartyReferencesPackageDirectory
    }

    Write-Host "--Copying all files for package : $packageNameNoVersion-------------------"
    Copy-Item $installPath\*.* $thirdPartyReferencesPackageDirectory -recurse
}
else
{
        Write-Host "A current or parent folder with a .sln file could not be located."
}


Write-Host "End Init.ps1" 
查看更多
登录 后发表回答