web-dev-qa-db-fra.com

C ++ géré avec .NET Core 2.1

Nous avons une bibliothèque écrite en C++. Pour la rendre plus compatible avec nos projets .NET plus modernes, nous avons encapsulé cette bibliothèque C++ dans un autre projet .NET. Il fonctionne correctement lors du référencement à partir de projets .NET Framework complets (4.5, 4.6, etc.).

Je crée une nouvelle application à l'aide de .NET Core 2.1 et j'essaie de référencer cette "bibliothèque C++ wrapped-in-.NET". À ma première tentative, il a échoué en disant que l'Assemblée ne pouvait pas être chargée. J'ai résolu ce problème en installant .NET Core SDK x86 et en forçant mon application à utiliser x86, pas Any CP.

Je ne reçois aucune erreur de génération, mais lorsque j'essaie d'instancier une classe dans cette bibliothèque, j'obtiens l'exception suivante:

<CrtImplementationDetails>.ModuleLoadException: The C++ module failed to load.
 ---> System.EntryPointNotFoundException: A library name must be specified in a DllImport attribute applied to non-IJW methods.
   at _getFiberPtrId()
   at <CrtImplementationDetails>.LanguageSupport._Initialize(LanguageSupport* )
   at <CrtImplementationDetails>.LanguageSupport.Initialize(LanguageSupport* )
   --- End of inner exception stack trace ---
   at <CrtImplementationDetails>.ThrowModuleLoadException(String errorMessage, Exception innerException)
   at <CrtImplementationDetails>.LanguageSupport.Initialize(LanguageSupport* )
   at .cctor()

.NET Core 2.1 prend-il en charge ce scénario?

7
AndreFeijo

Comme d'autres l'ont souligné, .NET Core ne prend actuellement pas en charge C++/CLI (alias "C++ managé"). Si vous souhaitez appeler des assemblys natifs dans .NET Core, vous devez utiliser PInvoke (comme vous l'avez découvert).

Vous pouvez également compiler votre projet .NET Core dans AnyCPU, tant que vous conservez dans les versions 32 et 64 bits votre bibliothèque native et ajoutez une logique de branchement spéciale autour de vos appels PInvoke:

using System;

public static class NativeMethods
{
    public static Boolean ValidateAdminUser(String username, String password)
    {
        if (Environment.Is64BitProcess)
        {
            return NativeMethods64.ValidateAdminUser(String username, String password);
        }
        else
        {
            return NativeMethods32.ValidateAdminUser(String username, String password);
        }
    }

    private static class NativeMethods64
    {
        [DllImport("MyLibrary.AMD64.dll", EntryPoint = "ValidateAdminUser", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern Boolean ValidateAdminUser(String username, String password);
    }

    private static class NativeMethods32
    {
        [DllImport("MyLibrary.x86.dll", EntryPoint = "ValidateAdminUser", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern Boolean ValidateAdminUser(String username, String password);
    }
}

Où vous avez vos assemblys MyLibrary.AMD64.dll et MyLibrary.x86.dll dans le même répertoire. Ce serait bien si vous pouviez mettre des chemins relatifs dans DllImport et avoir des sous-répertoires x86/AMD64, mais je n'ai pas compris comment faire cela.

7
ahelwer

Non. Le noyau .NET est multiplateforme, mais pas C++/CLI, le compilateur Microsoft C++ nécessite Windows.

5
ADG

PInvoke semble être la seule voie à suivre.

Placez la bibliothèque DLL dans le dossier de la solution (la DLL C++ réelle, pas un wrapper .NET).

REMARQUE: Ne faites pas référence au DLL dans la solution, placez simplement le DLL dans le même dossier).

Utilisez ensuite DLL Import pour accéder aux méthodes:

static class NativeMethods
{
    [DllImport("MyLibrary.dll", EntryPoint = "ValidateAdminUser", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
    public static extern Boolean ValidateAdminUser(String username, String password);
}

NOTE 2: Il nécessite toujours que le projet .NET Core s'exécute dans l'architecture x86.

1
AndreFeijo