Search code examples
c#c++.netc++-cliclr

C# references to C++ CLR x32 and x64


I created a C++ project in Visual Studio Class library CLR (.NET Framework):

#pragma once
using namespace System;

#ifdef _M_X64
namespace MyDLL64 {
#else
namespace MyDLL32 {
#endif
    public ref class MyClass 
    {
        public: static String^ Foo(String^ arg) 
        {
            String^ str = arg->ToUpper();
            return str;
        }
    };
}

Then I compiled two libraries(x86 and x64). Thereafter I add them to references in my C# project

enter image description here

and added their methods to the code:

String res = "";
if (IntPtr.Size == 8)
{
    res = MyDLL64.MyClass.Foo("test string");
}
else
{
    res = MyDLL32.MyClass.Foo("test string");
}
Console.WriteLine(res);

But I am getting this error:

System.BadImageFormatException: "Could not load file or assembly 'MyDLL64, Version=1.0.8197.24341, Culture=neutral, PublicKeyToken=null', or one of their dependencies. An attempt was made to load a program with an invalid format."(or MyDLL32... if arch is 64 bit).

By the way, this code starts correctly without exceptions:

String res = "";
if (IntPtr.Size == 8)
{
    res = MyDLL64.MyClass.Foo("test string");
}
if (1 > 2)
{
    res = MyDLL32.MyClass.Foo("test string");
}
Console.WriteLine(res);

So how properly add x32 and x64 C++CLR dlls to my Any CPU C# DLL?


Solution

  • So how properly add x32 and x64 C++CLR dlls to my Any CPU C# DLL?

    You can't. AnyCPU just means that the self process can be executed either as a 32 or 64 bit one depending on the architecture but once a 64 bit process is spawned it cannot access 32 bit images and vice versa.

    If your C# project references native images, then instead of building one AnyCPU image you must create two separate images just like in case of the C++ project.

    Specify x86 and x84 targets for the solution. And then if your 32/64-bit C++ dlls are named differently, then you can edit your .csproj file like this:

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
      </PropertyGroup>
    
      <PropertyGroup Condition="'$(Platform)'=='x86'">
        <PlatformTarget>x86</PlatformTarget>
        <DefineConstants>$(DefineConstants);X86</DefineConstants>
      </PropertyGroup>
      <ItemGroup Condition="'$(Platform)'=='x86'">
        <Reference Include="MyDLL32"/>
      </ItemGroup>
    
      <PropertyGroup Condition="'$(Platform)'=='x64'">
        <PlatformTarget>x64</PlatformTarget>
        <DefineConstants>$(DefineConstants);X64</DefineConstants>
      </PropertyGroup>
      <ItemGroup Condition="'$(Platform)'=='x64'">
        <Reference Include="MyDLL64"/>
      </ItemGroup>
    </Project>
    

    And then the C# code can have similar #if directives than the C++ one:

    String res = "";
    #if X64
        res = MyDLL64.MyClass.Foo("test string");
    #else
        res = MyDLL32.MyClass.Foo("test string");
    #endif
    Console.WriteLine(res);
    

    But IMHO it would be nicer if the C++ images used the same namespaces so the C# code does not need the #if directives and the different images could be handled purely in the .csproj file (in which case you don't need the DefineConstants either).