سؤال

أحاول تمرير مجموعة من الواجهات من C# إلى C ++/CLI. هنا هو الرمز:

// *** SafeArrayTesting_PlusPlus.cpp  ***
#include "stdafx.h"  
#include <comdef.h>

using namespace System;    
using namespace System::Runtime::InteropServices;

namespace SafeArrayTesting_PlusPlus {

public ref class MyCppClass
{       
    public:
    MyCppClass();
    ~MyCppClass();
    void SetMyInterfaces(
        array<SafeArrayTesting_Sharp::MyInterface^>^ myInterfaces);
};

MyCppClass::MyCppClass(){}
MyCppClass::~MyCppClass(){}

void MyCppClass::SetMyInterfaces(array<SafeArrayTesting_Sharp::MyInterface^>^ 
     myInterfaces)
{
    // Create safearray
    SAFEARRAY  *safeArrayPointer;
    SAFEARRAYBOUND arrayDim[1];    // one dimensional array
    arrayDim[0].lLbound= 0;
    arrayDim[0].cElements= myInterfaces->Length;

    safeArrayPointer = SafeArrayCreate(VT_UNKNOWN,1,arrayDim);

    // copy ints to safearray
    for (long lo= 0;lo<myInterfaces->Length;lo++)
    {           
        IntPtr myIntPtr = Marshal::GetIUnknkownForObject(myInterfaces[lo]);
        SafeArrayPutElement(
            safeArrayPointer, 
            &lo, 
            static_cast<void*>(myIntPtr)
            ); 
    }

    // do something with the safearray here - area XX
}}

// *** SafeArrayTesting_Main.cs ***
using SafeArrayTesting_PlusPlus;
using SafeArrayTesting_Sharp;

namespace SafeArrayTesting_Main
{

class SafeArrayTesting_Main
{
    static void Main()
    {
        var myCppClass = new MyCppClass();
        MyInterface myInterface = new MyClass();
        myCppClass.SetMyInterfaces(new[]{ myInterface });
    }
}}  

// *** SafeArrayTesting_Sharp.cs ***
using System;
using System.Runtime.InteropServices;

namespace SafeArrayTesting_Sharp
{
    [ComVisible(true)]
    public interface MyInterface
    {
        int MyInt { get; set; }
        string MyString { get; set; }
        DateTime MyDateTime { get; set; }
    }

    [ComVisible(true)]
    public class MyClass : MyInterface
    {
        public int MyInt{get;set;}
        public string MyString{get;set;}
        public DateTime MyDateTime{get; set;}
    }

// Just to please the compiler; bear with me. 
class DummyClass { static void Main() { } }
}

كما هو مكتوب هنا ، يتم تشغيل الرمز وتجمع بشكل نظيف. ومع ذلك ، عند تشغيل جزء "المنطقة XX" ، أحصل على ملف System.Runtime.InteropServices.SEHException.

رمز XX هو مجرد سطر واحد يستدعي طريقة تم إنشاؤها تلقائيًا تقبل مؤشر SafeArray. فيما يلي إعلان هذه الطريقة (من ملف .tlh):

virtual HRESULT __stdcall put_SafeArray (
        /*[in]*/ SAFEARRAY * pRetVal ) = 0;

أعتقد في الواقع أن هذه الطريقة تحول SafeArray إلى مجموعة .NET - كل ذلك جزء من مشروع تحويل تعمل شركتي في ذلك الوقت. لذلك لا يوجد بديل لاستخدام SafeArray.

على أي حال ، سوف يفاجئني حقًا إذا كان الكود بدون جزء XX خاليًا من الأخطاء ؛ أنا مبتدئ تمامًا عندما يتعلق الأمر بـ C ++. هل يمكنك مساعدتي في اكتشاف بعض المشاكل؟ إذا كان بإمكان أي شخص اقتراح طريقة أفضل لاختبار صحة SafeArray التي ستكون أيضًا مساعدة.

(بالمناسبة ، هذا تباين أكثر تعقيدًا في السؤال طريقة SafeArrayputelement رمي النظام. AccessViolationException ، حيث كنت فقط اجتياز مجموعة من ints من C# إلى C ++/CLI.)

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

المحلول

العديد من المشاكل. لأحد ، أنت لا تخزن بالفعل متغيرًا في الصفيف. هذا في النهاية لا يذهب إلى أي مكان ، لا يمكن لـ SafeArray تخزين الإشارات إلى الكائنات المدارة. يقوم جامع القمامة بنقل الكائنات حوله ، ولا يمكنه رؤية المراجع التي يحتفظ بها الرمز غير المُدار بحيث لا يمكن تحديث المرجع.

في أحسن الأحوال ، يمكنك إنشاء مجموعة من vt_unknown أو vt_dispatch. لكن لا يمكنك الحصول على مؤشر واجهة COM لهذه الكائنات المدارة ، فهي ليست [comvisible]. عندما تقوم بإصلاح ذلك ، يمكنك استخدام Marshal.getIdispatChforObject () أو Marshal.getIunkNownForObject () للحصول على مؤشر الواجهة للتخزين في الصفيف.

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