Est-il possible de renvoyer une valeur dotNetObject à partir d'un plug-in personnalisé 3ds Max?

StackOverflow https://stackoverflow.com/questions/421566

  •  05-07-2019
  •  | 
  •  

Question

J'ai un plugin personnalisé pour 3ds Max qui s'interface avec du code géré à l'arrière-plan. Dans certaines circonstances, je souhaite transférer un objet géré vers MAXScript pour une interaction directe, c'est-à-dire renvoyer un objet encapsulé depuis l'une de mes fonctions.

MAXScript est capable de manipuler les objets gérés directement relativement bien via un autre plugin (msxdotNet) inclus avec Max (j'utilise 3ds Max 2008). Fondamentalement, il enveloppe un objet et utilise la réflexion pour les appels tardifs, mais il est totalement autonome et n’a aucune exposition au SDK. Le plugin dll lui-même n’expose rien de plus que l’interface minimale requise par Max pour l’ajout de quelques classes de scripts de niveau supérieur.

Les classes scriptées permettent d'instancier un nouvel objet via un constructeur

local inst = (dotNetObject "MyPlugin.MyClass" 0 0 "arg3")

Dans mon cas, j'ai déjà une instance d'objet que j'aimerais utiliser.

Existe-t-il un moyen de construire une instance d'un wrapper dotNetObject à partir de mon plug-in pour revenir à Max?

Idéalement, j'aimerais une fonction d'assistance avec une signature (C ++ / CLI) similaire à:

Value* WrapObject(System::Object ^obj);

Quelques garanties de base que je peux faire:

  • Le plug-in msxdotNet est déjà chargé.
  • Le plug-in msxdotNet et mes assemblages gérés sont dans le même AppDomain.

La source du plug-in msxdotNet est incluse dans un exemple sdk, mais pour des raisons de gestion / santé, le modifier et le recompiler ne constitue pas une option.

Était-ce utile?

La solution

J'ai résolu ce problème en tirant parti du fait que tout objet CLR enveloppé par dotNetObject encapsule automatiquement les valeurs de retour (résultats de méthode et valeurs de propriété) dans un autre wrapper. Ceci s’applique même aux méthodes et propriétés statiques sur les types CLR encapsulés avec dotNetClass.

Disons que j'ai déjà une méthode dans mon plugin qui me permet d'exécuter MAXScript arbitraire:

Value* EvalScript(System::String ^script);

Il ne me reste plus qu'à sérialiser un objet dans une chaîne puis à un objet actif (une référence au même objet, pas seulement une copie!).

Je le fais en saisissant le GCHandle de l'objet, en utilisant GCHandle :: ToIntPtr pour le convertir en quelque chose de blittable et en utilisant GCHandle :: FromIntPtr pour matérialiser le même objet dans un contexte différent. Bien sûr, je suis en train de le faire (et dans le même domaine d'application), cela ne fonctionnerait pas autrement.

Value* WrapObject(System::Object ^obj)
{
    GCHandle handle = GCHandle::Alloc(obj)
    try
    {
        return EvalScript(System::String::Format(
            L"((dotNetClass \"System.Runtime.InteropServices.GCHandle\").FromIntPtr (dotNetObject \"System.IntPtr\" {0})).get_Target()",
            GCHandle::ToIntPtr(handle));
    }
    finally
    {
        handle.Free();
    }
}

Le commentaire que j'ai expliqué dans le code réel dépasse 10 fois le code réel.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top