通常,当使用PInvoke引用封装了非托管DLL的托管DLL时,您必须分别引用这两个DLL-csproj中的托管DLL作为标准<Reference/>
,非托管的DLL链接为链接{{1} }(如here所述)。但是,我最近遇到了一个托管包装器库,它不仅在构建过程中自动复制了非托管DLL,而且在同一目录中不存在非托管DLL时,实际上会产生一个构建错误!这是Microsoft.Z3 library,它具有一个托管DLL(Microsoft.Z3.dll),该托管DLL用PInvoke包裹了一个非托管DLL(libz3.dll),因此您可以在C#中使用该库。
如果将两个Z3 DLL放在一个目录中,仅引用Microsoft.Z3.dll,然后使用msbuild编译项目,则将在输出目录中获得这两个DLL,而根本不引用libz3.dll!在<content/>
产生的输出中,我看到以下对libz3.dll的引用:
msbuild /verbosity:diag
...
Primary reference "Microsoft.Z3, Version=4.7.1.0, Culture=neutral, PublicKeyToken=9c8d792caae602a2". (TaskId:9)
Resolved file path is "C:\Users\ahelwer\source\test\Framework\lib\z3\Microsoft.Z3.dll". (TaskId:9)
Reference found at search path location "{HintPathFromItem}". (TaskId:9)
Found embedded scatter file "libz3.dll". (TaskId:9)
The ImageRuntimeVersion for this reference is "v4.0.30319". (TaskId:9)
以某种方式导致其被复制:
Output Item(s):
_ReferenceScatterPaths=
C:\Users\ahelwer\source\test\Framework\lib\z3\libz3.dll
CopyLocal=true
FusionName=
HintPath=lib\z3\Microsoft.Z3.dll
OriginalItemSpec=C:\Users\ahelwer\source\test\Framework\lib\z3\Microsoft.Z3.dll
ResolvedFrom={HintPathFromItem}
Version=4.7.1.0 (TaskId:9)
它变得更加神秘,因为如果我将libz3.dll移出目录,构建将失败并显示以下错误:
Task "Copy" (TaskId:22)
Task Parameter:
SourceFiles=
C:\Users\ahelwer\source\test\Framework\lib\z3\Microsoft.Z3.dll
CopyLocal=true
FusionName=Microsoft.Z3, Version=4.7.1.0, Culture=neutral, PublicKeyToken=9c8d792caae602a2
HintPath=lib\z3\Microsoft.Z3.dll
ImageRuntime=v4.0.30319
OriginalItemSpec=Microsoft.Z3
ReferenceSourceTarget=ResolveAssemblyReference
ResolvedFrom={HintPathFromItem}
Version=4.7.1.0
C:\Users\ahelwer\source\test\Framework\lib\z3\libz3.dll
CopyLocal=true
FusionName=
HintPath=lib\z3\Microsoft.Z3.dll
OriginalItemSpec=C:\Users\ahelwer\source\test\Framework\lib\z3\Microsoft.Z3.dll
ResolvedFrom={HintPathFromItem}
Version=4.7.1.0 (TaskId:22)
Task Parameter:
DestinationFiles=
bin\Debug\Microsoft.Z3.dll
CopyLocal=true
FusionName=Microsoft.Z3, Version=4.7.1.0, Culture=neutral, PublicKeyToken=9c8d792caae602a2
HintPath=lib\z3\Microsoft.Z3.dll
ImageRuntime=v4.0.30319
OriginalItemSpec=Microsoft.Z3
ReferenceSourceTarget=ResolveAssemblyReference
ResolvedFrom={HintPathFromItem}
Version=4.7.1.0
bin\Debug\libz3.dll
CopyLocal=true
FusionName=
HintPath=lib\z3\Microsoft.Z3.dll
OriginalItemSpec=C:\Users\ahelwer\source\test\Framework\lib\z3\Microsoft.Z3.dll
ResolvedFrom={HintPathFromItem}
Version=4.7.1.0 (TaskId:22)
即使我在csproj中使用"C:\Users\ahelwer\source\test\Framework\FrameworkTest.csproj" (default target) (1) ->
(_CopyFilesMarkedCopyLocal target) ->
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\bin\Microsoft.Common.CurrentVersion.targe
ts(4358,5): error MSB3030: Could not copy the file "C:\Users\ahelwer\source\test\Framework\lib\z3\libz3.dll" because it
was not found. [C:\Users\ahelwer\source\test\Framework\FrameworkTest.csproj]
以标准方式引用libz3.dll!
问题:
答案 0 :(得分:1)
这就是CSC(C#编译器)所称的"link resource"。它适用于任何类型的文件。
例如,如果您在DLL项目中有这种代码:
using System.Runtime.InteropServices;
namespace Microsoft.Z3
{
public static class DoSomething
{
[DllImport("libz3.dll")]
public static extern int ReturnValue(int value);
}
}
这是从Windows DLL导出的C代码:
#include "stdafx.h"
STDAPI ReturnValue(HRESULT value)
{
return value;
}
您可以这样构建.NET DLL:
"<path to csc.exe>\csc.exe" DoSomething.cs -out:Microsoft.Z3.dll -target:library -linkresource:<path to libz3.dll>\libz3.dll
现在,当您引用此新的Microsoft.Z3.dll时,它的行为与真实的Z3事物相同,它将自动将libz3.dll复制到一边。
请注意AFAIK,Visual Studio不支持此链接资源。
另外一个缺点是,如果要支持多个位,则必须附带两个.NET DLL,一个用于x64,一个用于x86,每个嵌入其本机副本(否则您必须复制所有DllImport等等。