هل هناك طريقة لإرجاع قيمة dotNetObject من مكون إضافي مخصص لـ 3ds Max؟

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

  •  05-07-2019
  •  | 
  •  

سؤال

لدي مكون إضافي مخصص لـ 3ds Max يتفاعل مع بعض التعليمات البرمجية المُدارة في النهاية الخلفية.في بعض الظروف، أرغب في إعادة توجيه كائن مُدار إلى MAXScript للتفاعل المباشر، على سبيل المثال.إرجاع كائن ملفوف من إحدى وظائفي.

MAXScript قادر على التعامل مع الكائنات المُدارة بشكل مباشر نسبيًا من خلال مكون إضافي آخر (msxdotNet) مضمن في Max (أنا أستخدم 3ds Max 2008).إنه يغلف بشكل أساسي كائنًا ويستخدم الانعكاس للمكالمات المرتبطة المتأخرة، ولكنه مكتفٍ ذاتيًا تمامًا ولا يحتوي على أي تعرض لـ SDK.لا يكشف البرنامج المساعد dll نفسه أيضًا عن أي شيء أكثر من الحد الأدنى من الواجهة التي يتطلبها Max لإضافة عدد قليل من الفئات النصية ذات المستوى الأعلى.

تسمح الفئات المكتوبة بإنشاء كائن جديد عبر المُنشئ

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

في حالتي لدي بالفعل مثيل لكائن أرغب في استخدامه.

هل هناك طريقة لإنشاء مثيل لبرنامج تغليف dotNetObject من داخل المكون الإضافي الخاص بي للعودة إلى Max؟


من الناحية المثالية، أرغب في الحصول على وظيفة مساعدة بتوقيع (C++/CLI) مشابه لما يلي:

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

بعض الضمانات الأساسية التي يمكنني تقديمها:

  • تم بالفعل تحميل البرنامج المساعد msxdotNet.
  • المكوّن الإضافي msxdotNet والتجمعات المُدارة موجودة في نفس AppDomain.

مصدر البرنامج المساعد msxdotNet يكون تم تضمينه كعينة sdk، ولكن من أجل الإدارة/العقلانية، فإن تعديله وإعادة ترجمته ليس خيارًا.

هل كانت مفيدة؟

المحلول

لقد قمت بحل هذه المشكلة من خلال الاستفادة من حقيقة أن أي كائن CLR مغلف بواسطة dotNetObject سوف يقوم تلقائيًا بتغليف قيم الإرجاع (نتائج الطريقة وقيم الخصائص) باستخدام غلاف آخر.ينطبق هذا أيضًا على الأساليب والخصائص الثابتة في أنواع CLR المغلفة بـ dotNetClass.

لنفترض أن لدي بالفعل طريقة في المكون الإضافي الخاص بي تتيح لي تنفيذ MAXScript عشوائيًا:

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

الآن أنا فقط بحاجة إلى إجراء تسلسل لكائن ما في سلسلة والعودة مرة أخرى إلى كائن نشط (إشارة إلى نفس الكائن، وليس مجرد نسخة!).

أفعل هذا عن طريق الاستيلاء على GCHandle للكائن باستخدام GCHandle::ToIntPtr لتحويله إلى شيء blittable واستخدام GCHandle::FromIntPtr لتجسيد نفس الكائن في سياق مختلف.بالطبع أفعل هذا قيد التنفيذ (وفي نفس مجال التطبيق)، ولن ينجح هذا بطريقة أخرى.

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

التعليق الذي أوضحت فيه هذا في الكود الحقيقي يزيد عن 10 أضعاف طول الكود الفعلي.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top