【问题标题】:Any CPU dependent on C++/CLI dependent on native C dll (any cpu for c++/cli)任何依赖于 C++/CLI 的 CPU 依赖于本机 C dll(用于 c++/cli 的任何 cpu)
【发布时间】:2011-12-05 09:16:15
【问题描述】:

这是我的问题。 我在 C# 中包装了一个 C dll。为此,我首先编写了一个 C++/CLI 包装器。本机 C 库链接到 C++/CLI 包装器。 (C++/cli 项目中的链接器属性)。

现在所有的组织方式如下: - 原生 C .lib:x86 和 64 位。

  • 1 解决方案包含 2 个项目:
    • 与本机 C .lib 链接的 C++/CLI 包装器项目
    • C# 项目引用 C++/CLI 项目

我的问题来自于我需要 C# 来定位“任何 CPU”。但此选项在 C++/CLI 中不可用,因为它直接编译为本机代码。

我解决这个问题的想法是: - 在 x86 中编译 C++/CLI 包装器,然后更改配置并编译为 64 位。当它编译时,我想告诉它根据平台取哪个dll。即:如果在 64 位中编译,则链接 64 位原生 C dll,否则如果是 x86,则链接 x86 原生 C。 - 完成此操作后,我应该能够在我的 C# 平台中拥有任何 CPU 目标。在这里,我不会引用我的 C++/CLI 包装器项目,而是引用基于目标平台所需的 dll。

我的问题是:

  • 如何根据目标平台告诉 C++/CLI 项目要链接到哪个 .lib?
  • 如何根据目标平台告诉 C# 项目引用哪个 C++/CLI dll?

让我补充一点,C# 项目是一个 CLASS LIBRARY,供 x86 或 x64 客户端使用。

我希望我的问题足够清楚。任何帮助将不胜感激!

更新基于:Conditional references in .NET project, possible to get rid of warning?...

所以现在我编辑了我的 .csproj 文件,使用条件来引用 dll,如下所示:

<ItemGroup>
    <Reference Include="AlibCppWrapper, Version=1.0.4303.21410, Culture=neutral, PublicKeyToken=c0c17a53adc44091, processorArchitecture=AMD64"
               Condition="$(Platform) == 'x64'">
      <SpecificVersion>False</SpecificVersion>
      <HintPath>..\x64\Debug\AlibCppWrapper.dll</HintPath>
    </Reference>
    <Reference Include="AlibCppWrapper, Version=1.0.4303.21410, Culture=neutral, PublicKeyToken=c0c17a53adc44091, processorArchitecture=x86"
               Condition="$(Platform) == 'x86'">
      <SpecificVersion>False</SpecificVersion>
      <HintPath>..\Debug\AlibCppWrapper.dll</HintPath>
    </Reference>
  </ItemGroup>

不幸的是,这不起作用,因为 $(Platform) 设置为 AnyCPU...

【问题讨论】:

  • 我没有看到任何问题。如果要针对 x64 和 x86,您需要为每个平台 (C/C++) 编译单独的文件,并根据它所在的平台在 C# 应用程序中引用正确的库。您还可以决定您只想通过使用对 x86 或 x64 编译库的引用来强制某个平台。我没有看到“?”随时编辑您的问题并明确您的问题。
  • “任何 CPU”是硬性要求吗?懒惰的程序员对此的解决方案只是为 x86 编译,因为它运行在 x64 中。
  • 是的,这是一个硬性要求。 C# 项目实际上是一个供客户端和服务器使用的库,可以安装在 64 位或 x86 上
  • 这是一个部署问题。本机 DLL 不是问题,您可以给它们不同的名称并在链接器的 Additional Dependencies 设置中指定它们。问题是 C++/CLI 程序集。 CLR 可以根据 processorArchitecture 属性自动选择正确的程序集,但这需要将它们部署到 GAC。这需要两个安装程序。由于无论如何您都需要它们,简单的解决方案是只提供两种不同的安装程序,一种用于 32 位机器,另一种用于 64 位机器。每个都部署了正确风格的 DLL。
  • @IlianPinzon - 如果我的 C# 库是 x86,那么它不能被在 x64 架构上编译的客户端程序调用,任何 CPU...并且无法将此客户端更改为 x86。

标签: c# c c++-cli 64-bit x86


【解决方案1】:

您所描述的称为“并行程序集”(同一程序集的两个版本,一个 32 位,另一个 64 位)...我认为您会发现这些很有帮助:

编辑 - 根据评论:

您可以在此处找到适合您的场景的演练:.NET DLL wrapping C++/CLI DLL referencing a native DLL

【讨论】:

  • @nche - 这是您应该接受的答案。这将完全符合您的要求,并且是一个优雅的解决方案。使应用程序同时支持 x64 和 x86 平台的正确方法是制作单独的程序集。如果您的应用程序引用了 32 位库程序集,则它不能是 x64 进程。
  • 第一个链接中的并行解决方案似乎适合我的问题,但问题是我的 C# 项目是 dll,而不是 exe。因此,如果我可以通过编程方式定义要加载的 dll 相对于体系结构,我没有任何主要内容。例如,是否可以使用条件引用?即:在我的 C++/cli 项目中,根据体系结构链接了足够的 C dll(x86 或 x64)...对于 C# 项目也是如此(根据体系结构链接的足够的 c++/cli 参考)...跨度>
  • 如果我的 C# 项目是一个 dll,这个解决方案将是完美的。然后我会动态加载dll。但就我而言,它是一个类库。所以我不能动态加载所需的底层 dll 我可以吗?...
  • 对不起 - 你想要不可能的事情......比上面描述的更多是不可能的......如果上面有任何帮助,那么请投票/标记为接受......
  • hmm.. 抱歉 - 你想要不可能这个答案接受作为答案的原因是什么?因为,如果您无视 cmets,我会认为 16 人和 OP 正在投票并接受一个解决明显不同的问题/考虑/问题的答案。
【解决方案2】:

对我来说,解决方案如下:

  1. 构建 x64 位版本的 C++ 库以输出文件 xxx.x64.dll

  2. 构建x86位(Win32平台)版本的C++库输出文件xxx.x86.dll

  3. 将它们作为内容文件添加到我的包装 C# 项目中。例如:

    <ItemGroup>
      <Content Include="..\..\$(Configuration)\xxx.x86.dll" Link="xxx.x86.dll">
        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      </Content>
      <Content Include="..\..\$(Configuration)\xxx.x64.dll" Link="xxx.x64.dll">
        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      </Content>
    </ItemGroup>
    
  4. 在 C# 中从 x86 和 x64 库版本导入函数。例如:

        [DllImport("xxx.x86.dll", EntryPoint = "FunctionName", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
        public static extern void FunctionNamex86();
        [DllImport("xxx.x64.dll", EntryPoint = "FunctionName", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
        public static extern void FunctionNamex64();
    
  5. 在 C# 中实现基于当前平台调用正确重载的函数。例如:

        public static void FunctionName()
        {
            if (Environment.Is64BitProcess)
                FunctionNamex64();
            else
                FunctionNamex86();
        }
    
  6. 现在 C# 项目可以构建为“任何 CPU”并被其他多平台项目使用。

  7. 为了将它作为 NuGet 包分发,我使用以下 NuSpec 配置:

    <?xml version="1.0"?>
    <package>
        <metadata>
            <contentFiles>
                <files include="any/any/xxx.x64.dll" buildAction="None" copyToOutput="true" />
                <files include="any/any/xxx.x86.dll" buildAction="None" copyToOutput="true" />
            </contentFiles>
        </metadata>
        <files>
            <file src="Release/C#Wrapper.dll" target="lib" /> 
            <file src="Release/xxx.x64.dll" target="content" /> 
            <file src="Release/xxx.x86.dll" target="content" /> 
            <file src="Release/xxx.x64.dll" target="contentFiles/any/any" /> 
            <file src="Release/xxx.x86.dll" target="contentFiles/any/any" /> 
        </files>
    </package>
    

答案主要基于:Using a 32bit or 64bit dll in C# DllImport

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-14
    • 2014-02-20
    • 2023-03-17
    • 2013-07-25
    • 2013-05-27
    • 2017-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多