C'è un modo per restituire un valore dotNetObject da un plug-in 3ds Max personalizzato?

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

  •  05-07-2019
  •  | 
  •  

Domanda

Ho un plugin personalizzato per 3ds Max che si interfaccia con un po 'di codice gestito sul back-end. In alcune circostanze, vorrei inoltrare un oggetto gestito a MAXScript per l'interazione diretta, ovvero restituire un oggetto avvolto da una delle mie funzioni.

MAXScript è in grado di manipolare gli oggetti gestiti direttamente relativamente bene attraverso un altro plugin (msxdotNet) incluso in Max (sto usando 3ds Max 2008). In sostanza avvolge un oggetto e usa la riflessione per le chiamate associate in ritardo, ma è totalmente autonomo e non ha alcuna esposizione SDK. Il plugin dll stesso non espone altro che l'interfaccia minima richiesta da Max per l'aggiunta di alcune classi di script di livello superiore.

Le classi con script consentono di creare un'istanza di un nuovo oggetto tramite un costruttore

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

Nel mio caso ho già un'istanza di un oggetto che mi piacerebbe usare.

Esiste un modo per costruire un'istanza di un wrapper dotNetObject dal mio plug-in per tornare a Max?


In teoria, vorrei avere una funzione di supporto con una firma (C ++ / CLI) simile a:

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

Alcune garanzie di base che posso fare:

  • Il plug-in msxdotNet è già caricato.
  • Il plug-in msxdotNet e i miei assembly gestiti si trovano nello stesso AppDomain.

Il sorgente per il plugin msxdotNet è incluso come esempio sdk, ma per amor di gestione / sanità mentale, modificarlo e ricompilarlo non è un'opzione.

È stato utile?

Soluzione

L'ho risolto sfruttando il fatto che qualsiasi oggetto CLR avvolto da dotNetObject avvolgerà automaticamente i valori di ritorno (risultati del metodo e valori delle proprietà) con un altro wrapper. Questo vale anche per i metodi e le proprietà statici sui tipi CLR racchiusi con dotNetClass.

Diciamo che ho già un metodo nel mio plugin che mi permette di eseguire MAXScript arbitrario:

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

Ora ho solo bisogno di serializzare un oggetto in una stringa e di nuovo su un oggetto attivo (un riferimento allo stesso oggetto, non solo una copia!).

Faccio questo afferrando il GCHandle dell'oggetto, usando GCHandle :: ToIntPtr per convertirlo in qualcosa di accessibile e usando GCHandle :: FromIntPtr per materializzare lo stesso oggetto in un contesto diverso. Ovviamente lo sto facendo nel processo (e nello stesso dominio dell'app), altrimenti non funzionerebbe.

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();
    }
}

Il commento che ho spiegato nel codice reale è più di 10 volte più lungo del codice reale.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top