围绕非托管 DLL 的 C# 包装器库要求非托管 DLL 在构建期间位于同一目录中
C# wrapper library around unmanaged DLL requires unmanaged DLL to be in same directory during build
通常,当引用一个用 PInvoke 包装非托管 DLL 的托管 DLL 时,您必须分别引用这两个 DLL - 托管一个作为标准 <Reference/>
在您的 csproj 中,非托管一个作为链接 <content/>
(如 here). However, I recently came across a managed wrapper library which not only auto-copies the unmanaged DLL along with it during the build, but actually produces a build error when the unmanaged DLL is not present in the same directory! This is the Microsoft.Z3 library 所述,它有一个托管 DLL (Microsoft.Z3.dll),用 PInvoke 包装了一个非托管 DLL (libz3.dll),因此您可以在 C# 中使用该库。
如果您将两个 Z3 DLL 放在一个目录中,仅引用 Microsoft.Z3.dll,然后使用 msbuild 编译您的项目,您将在输出目录中获得两个 DLL 而无需引用 [=42= 】 根本!查看 msbuild /verbosity:diag
生成的输出,我看到以下对 libz3.dll:
的引用
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)
以某种方式导致它被复制:
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)
它变得更加神秘,因为如果我从目录中取出 libz3.dll,构建将失败并出现以下错误:
"C:\Users\ahelwer\source\test\Framework\FrameworkTest.csproj" (default target) (1) ->
(_CopyFilesMarkedCopyLocal target) ->
C:\Program Files (x86)\Microsoft Visual Studio17\Enterprise\MSBuild.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]
即使我在我的 csproj 中以 <content/>
的标准方式引用 libz3.dll!
问题:
- Microsoft.Z3.dll 有什么特别之处,可以要求 libz3.dll 在构建期间位于同一目录中?它是用某些标志编译的吗?
- 如何将此效果添加到我自己的托管包装器库中?
- 是否有任何方法可以从 Microsoft 中删除此效果。Z3.dll,或者我是否必须以不同的方式重新编译它?
这就是 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);
}
}
此 C 代码从 Windows DLL 导出:
#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 内容等)。
通常,当引用一个用 PInvoke 包装非托管 DLL 的托管 DLL 时,您必须分别引用这两个 DLL - 托管一个作为标准 <Reference/>
在您的 csproj 中,非托管一个作为链接 <content/>
(如 here). However, I recently came across a managed wrapper library which not only auto-copies the unmanaged DLL along with it during the build, but actually produces a build error when the unmanaged DLL is not present in the same directory! This is the Microsoft.Z3 library 所述,它有一个托管 DLL (Microsoft.Z3.dll),用 PInvoke 包装了一个非托管 DLL (libz3.dll),因此您可以在 C# 中使用该库。
如果您将两个 Z3 DLL 放在一个目录中,仅引用 Microsoft.Z3.dll,然后使用 msbuild 编译您的项目,您将在输出目录中获得两个 DLL 而无需引用 [=42= 】 根本!查看 msbuild /verbosity:diag
生成的输出,我看到以下对 libz3.dll:
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)
以某种方式导致它被复制:
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)
它变得更加神秘,因为如果我从目录中取出 libz3.dll,构建将失败并出现以下错误:
"C:\Users\ahelwer\source\test\Framework\FrameworkTest.csproj" (default target) (1) ->
(_CopyFilesMarkedCopyLocal target) ->
C:\Program Files (x86)\Microsoft Visual Studio17\Enterprise\MSBuild.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]
即使我在我的 csproj 中以 <content/>
的标准方式引用 libz3.dll!
问题:
- Microsoft.Z3.dll 有什么特别之处,可以要求 libz3.dll 在构建期间位于同一目录中?它是用某些标志编译的吗?
- 如何将此效果添加到我自己的托管包装器库中?
- 是否有任何方法可以从 Microsoft 中删除此效果。Z3.dll,或者我是否必须以不同的方式重新编译它?
这就是 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);
}
}
此 C 代码从 Windows DLL 导出:
#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 内容等)。