Re[13]: Приоритет вызова перегруженных методов
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 22.06.16 07:22
Оценка:
Здравствуйте, Serginio1, Вы писали:

Добавил простенький список для хранения объектов

 public struct ЭлементХранилища
    {
        internal AutoWrap Объект;
        internal int Next;


       internal ЭлементХранилища(AutoWrap Объект)
        {

            this.Объект = Объект;
            Next = -1;
        }

        internal ЭлементХранилища(AutoWrap Объект, int next)
        {

            this.Объект = Объект;
            Next = next;
        }
    }

   internal class ХранилищеОбъектов
    {
     
         List<ЭлементХранилища> Элементы= new List<ЭлементХранилища>();
         int FirstDeleted = -1;

        public int Add(AutoWrap Объект)
        {



            var элемент = new ЭлементХранилища(Объект);




            if (FirstDeleted == -1)
            { Элементы.Add(элемент);
                return Элементы.Count-1;
            }
            else
            {
               int newPos = FirstDeleted;
                FirstDeleted = Элементы[newPos].Next;
                Элементы[newPos] = элемент;
                return newPos;

            }
 
        }

        public void RemoveKey(int Pos)
        {
            if (Pos > -1 && Pos < Элементы.Count && Элементы[Pos].Объект != null)
            {
               
                var Элемент = new ЭлементХранилища(null, FirstDeleted);
                Элементы[Pos] =Элемент;
            
                FirstDeleted = Pos;
            }
                           


        }

        public AutoWrap GetValue(int Pos)
        {

            if (!(Pos > -1 && Pos < Элементы.Count && Элементы[Pos].Объект != null))
                return null;

            return Элементы[Pos].Объект;

        }

    }



Создал класс обертку

public class AutoWrap
    {
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        internal delegate IntPtr ВыделитьПамятьDelegate(int КоличествоБайтов);

        internal static ХранилищеОбъектов СписокОбъектов;
        internal static int ХэшДляСсылки=new Guid().GetHashCode();


        protected internal object O = null;
        protected internal Type T = null; // Тип может быть и интерфейсом
        protected internal int ИндекасВСписке;


        internal bool ЭтоТип;
        internal bool IsEnum;
        internal bool ЭтоExpandoObject;
        internal static bool ЭтоСемерка = false;
        internal static bool ВыводитьСообщениеОбОшибке = true;
        internal static Exception ПоследняяОшибка = null;

        internal static ВыделитьПамятьDelegate ВыделитьПямять;

        public static void SetDelegate(IntPtr ДляВыделенияПамяти)
        {
            ВыделитьПямять = Marshal.GetDelegateForFunctionPointer<ВыделитьПамятьDelegate>(ДляВыделенияПамяти);

        }
        static AutoWrap()
        {
            СписокОбъектов = new ХранилищеОбъектов();
            var первый = new AutoWrap(typeof(NetObjectToNative));

        }


        public AutoWrap(object obj)
        {

            ИндекасВСписке = СписокОбъектов.Add(this);
            O = obj;
            if (O is Type)
            {
                T = O as Type;
                ЭтоТип = true;
            }
            else
            {
                T = O.GetType();
                ЭтоТип = false;
                ЭтоExpandoObject = O is System.Dynamic.ExpandoObject;
                IsEnum = T.GetTypeInfo().IsEnum;


            }



Экспортируются функции
 public static bool CallAsFunc(int Target, IntPtr ИмяМетодаPtr, IntPtr ReturnValue, IntPtr МассивПараметров, int РазмерМассива)
        {
            var AW = СписокОбъектов.GetValue(Target);

            if (AW == null) return false;

            bool IsReturnValue = ReturnValue != IntPtr.Zero;

            string ИмяМетода = Marshal.PtrToStringUni(ИмяМетодаPtr);
            var параметры = ПолучитьМассивПараметров(МассивПараметров, РазмерМассива);

            object result = null;
            List<int> ИзмененныеПараметры = new List<int>();

           

            var res = AW.TryInvokeMember(ИмяМетода, параметры, out result, ИзмененныеПараметры);
            if (!res) return false;

            foreach( var i in ИзмененныеПараметры)
            {
                РаботаСВариантами.УстановитьОбъектВIntPtr(параметры[i], МассивПараметров+48*i);

            }

            if (IsReturnValue) РаботаСВариантами.УстановитьОбъектВIntPtr(ОбернутьОбъект(result), ReturnValue);

            return true;

        }

      public static   int GetNParams(int Target, IntPtr ИмяМетодаPtr)
{
            var AW = СписокОбъектов.GetValue(Target);
            if (AW == null) return -1;

            string ИмяМетода = Marshal.PtrToStringUni(ИмяМетодаPtr);
            return ИнформацияПоТипам.КоличествоПараметровДляМетода(AW.T, ИмяМетода);

        }

    public static  bool SetPropVal(int Target, IntPtr ИмяСвойстваPtr, IntPtr pvarPropVal)
{

            var AW = СписокОбъектов.GetValue(Target);
            if (AW == null) return false;

            string ИмяСвойства = Marshal.PtrToStringUni(ИмяСвойстваPtr);

            object result = РаботаСВариантами.ПолучитьОбъекИзIntPtr(pvarPropVal);

            var res = AW.TrySetMember(ИмяСвойства,result);
            

            return res;
}
        //---------------------------------------------------------------------------//
        public static bool GetPropVal(int Target, IntPtr ИмяСвойстваPtr, IntPtr varPropVal)
{
            var AW = СписокОбъектов.GetValue(Target);
            if (AW == null) return false;

            string ИмяСвойства = Marshal.PtrToStringUni(ИмяСвойстваPtr);

            object result = null;
            var res = AW.TryGetMember(ИмяСвойства, out result);
            if (!res) return false;

            РаботаСВариантами.УстановитьОбъектВIntPtr(ОбернутьОбъект(result), varPropVal);

            return true;
}

        public static void DeleteObject(int Target)
        {
            СписокОбъектов.RemoveKey(Target);

        }




Код на C#
var sB= new System.Text.StringBuilder();
sB.Append("Новая Строка");
var str=sB.ToString();
sB.Capacity=40;
var capacity=sB.Capacity


На С++ выглядит так

// Загрузим Core CLR
    // И создадим домен
    //Первый параметр это путь к папке с coreclr.dll
    NetObjectToNative::ManagedDomainLoader* mD = NetObjectToNative::ManagedDomainLoader::InitManagedDomain(L"c:\\Program Files\\DNX\\runtimes\\dnx-coreclr-win-x86.1.0.0-rc1-update1\\bin\\", L"", L"");

    if (!mD)  return 0;

    tVariant Params[4];
    tVariant RetVal;
    tVariant* paParams = Params;

    paParams->vt = VTYPE_PWSTR;
    paParams->pwstrVal = L"System.Text.StringBuilder";

    cout << "Press Key";
    cin.get();

    // 0 это индекс вспомогательного класса для получения типов объектов и прочих удобный методов
   bool res=mD->pCallAsFunc(0, L"Новый", &RetVal, paParams, 1);
   if(!res) return 0;


   // Так как в 1С нет возможности установить пользовательский тип
   // то возвращаем byte[12] который будет ID объекта
   // первые четыре байта ХэшДляСсылки=new Guid().GetHashCode(); одинаковый для всех .Net объектов
   // вторые 4 байта это хэш объекта
   // третьи это индекс в списке экспортируемых объектов
   // Можно его передавать в качестве параметра типа BLOB
   byte ref[12];
   memcpy(ref, RetVal.pstrVal, 12);
   // Теперь мы можем передавать ссылку ref в параметрах;
   long* target =(long*)RetVal.pstrVal;

   long Target = target[2]; // Получили индекс в списке
   
   wprintf_s(L"index : %d\n", Target);

   // Память выделяется на стороне натива. Нам и удалять.
   delete[] RetVal.pstrVal;

   paParams->vt = VTYPE_PWSTR;
   paParams->pwstrVal = L"Новая Строка";

// 0 так как вызывается как void даже если метод что то и возвращает, что бы не оборачивать результат
    res = mD->pCallAsFunc(Target, L"Append", 0, paParams, 1);

    res = mD->pCallAsFunc(Target, L"ToString", &RetVal, paParams, 0);
    wprintf_s(L"index : %S\n", RetVal.pwstrVal);

    delete[] RetVal.pstrVal;

    paParams->vt = VTYPE_I4;
    paParams->lVal =40;
    res = mD->pSetPropVal(Target, L"Capacity", paParams);


    res = mD->pGetPropVal(Target, L"Capacity", &RetVal);
    wprintf_s(L"Capacity : %d\n", RetVal.lVal);

    // Удалим объект из списка. Теперь его может собрать GC
    mD->pDeleteObject(Target);
    
    // Создадим объект через тип

    paParams->vt = VTYPE_PWSTR;
    paParams->pwstrVal = L"System.Text.StringBuilder";
// Получим ID оббъекта typeof(System.Text.StringBuilder)
    res = mD->pCallAsFunc(0, L"ПолучитьТип", &RetVal, paParams, 1);

    //paParams[0] = RetVal;

    // Скопируем ID оббъекта typeof(System.Text.StringBuilder)
    memcpy(ref, RetVal.pstrVal, 12);

    // Установим ссылку в параметрах
    paParams->vt = VTYPE_BLOB;
    paParams->pstrVal =(char*) ref;
    paParams->strLen = 12;


    // И создадим экземпляр StringBuilder
    res = mD->pCallAsFunc(0, L"Новый", &RetVal, paParams, 1);
    if (!res) return 0;


    // Выгрузим домен
    delete mD;

    return 0;


Думаю статью написать. Как для C++ лучше сделать обертку. Для 1С думаю доделать на этой неделе
и солнце б утром не вставало, когда бы не было меня
Отредактировано 23.06.2016 6:38 Serginio1 . Предыдущая версия . Еще …
Отредактировано 22.06.2016 7:30 Serginio1 . Предыдущая версия .
Отредактировано 22.06.2016 7:25 Serginio1 . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.