سؤال

ويبدو أن هذا الأكثر شيوعا وطلب C # مسألة إمكانية التشغيل المتداخل وبعد ويبدو أن من الصعب العثور على حل عمل ل.

وأنا في حاجة إلى تخصيص مجموعة من بنية بيانات مصفوفة في C # تمريرها إلى DLL C التي تملأ البيانات ويعود ذلك إلى الطالب للتعامل معها.

وبناء على الصفحات المختلفة على شبكة الإنترنت، ويبدو لي أن تمكن من الحصول على البيانات والذاكرة من C # إلى C ++ ولكن لا، على ما يبدو، إلى الوراء ...

ورمز يتبع.

ويرجع الفضل في ذلك مسبقا لأية مساعدة شيامال


ولدي بنية C ++ كما يلي

typedef struct tagTMatrix
{
   int   Id;
   int   NumColumns;
   int   NumRows;
   double*  aData;
} TMatrix;

والذي أعلن في C # ك

[StructLayout(LayoutKind.Sequential)]
unsafe public struct TMatrix
{
public Int32 id;
public Int32 NumCols;
public Int32 NumRows;
public Int32 NumPlanes;
public IntPtr aData;
};



[DllImport("kernel32.dll")]
internal static extern IntPtr LoadLibrary(String dllname);
[DllImport("kernel32.dll")]
internal static extern IntPtr GetProcAddress(IntPtr hModule, String 
procname);

unsafe internal delegate void FillMatrices(IntPtr mats, long num);

[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")] // Saw this 
mentioned somewhere
static extern void CopyMemory(IntPtr dest, IntPtr[] src, int cb);

unsafe private void butTest_Click(object sender, EventArgs e)
{
    IntPtr library = LoadLibrary("TestDLL.dll");
    IntPtr procaddr = GetProcAddress(library, "FillMatrices");
    FillMatrices fm = 
(FillMatrices)Marshal.GetDelegateForFunctionPointer(procaddr, 
typeof(FillMatrices));
    TMatrix[] mats = new TMatrix[2];
    mats[0]=new TMatrix();
    mats[1]=new TMatrix();
    mats[0].id=1;
    mats[0].NumCols=2;mats[0].NumRows=1;mats[0].NumPlanes=0;
    mats[0].aData = Marshal.AllocHGlobal(sizeof(double) * 2);
    double [] array=new double[2];
    array[0]=12.5;array[1]=2.3;
    fixed (double* a = array)
{
IntPtr intPtr = new IntPtr((void*)a);
mats[1].aData = Marshal.AllocHGlobal(sizeof(double) * 2);
//mats[1].aData = 13;
mats[1].aData = intPtr;
mats[1].id = 2;
mats[1].NumCols = 1; mats[1].NumRows = 2; mats[1].NumPlanes = 0;
}
IntPtr[] ptrs = new IntPtr[2];
int total=0;
for (int i = 0; i < ptrs.Length; i++)
{
total = total + sizeof(IntPtr) * (4 + mats[i].NumCols * mats[i].NumRows);
ptrs[i] = 
Marshal.AllocHGlobal(sizeof(IntPtr)*(4+mats[i].NumCols*mats[i].NumRows));
}
Marshal.StructureToPtr(mats[0], ptrs[0], false);
Marshal.StructureToPtr(mats[1], ptrs[1], false);
//_list.test_list =
IntPtr pointer=Marshal.AllocHGlobal(total);
CopyMemory(pointer, ptrs, 2 * IntPtr.Size);
//TMatrix m1=new TMatrix();
//mats[0].aData = 10;// new double[20];
//TMatrix m2 = new TMatrix();
// mats[1].aData = 20;// new double[9];
//Marshal.StructureToPtr(m2, p1, false);
//mats.Add(m2);
//Marshal.StructureToPtr(mats, p1, false);
//IntPtr p2=Marshal.AllocHGlobal(270);
//Marshal.StructureToPtr(mats.ToArray(),p2,false);
fm(pointer,2);
// Now I want to get back this data ???
}


// C++ function
extern "C" void FillMatrices(TMatrix** mats, int matcount)
{
 FILE* fp=fopen("C:\\mats.txt","w+");
 fprintf(fp,"Number of matrices = %d\n",matcount);
 fflush(fp);
 for(int i=0;i<matcount;++i)
 {
  TMatrix* m=mats[i];
  fprintf(fp,"id = %d rows %d cols %d \n",m->Id,m->NumRows,m->NumColumns);
  fflush(fp);

  for(int j=0;j<m->NumRows;++j)
  {
   fprintf(fp,"%d ",j);
   fflush(fp);
   for(int k=0;k<m->NumColumns;++k)
   {
    fprintf(fp,"%f ", m->aData[k*m->NumRows+j]);
    // modify the data - it should be available back in C#
    m->aData[k*m->NumRows+j]=k;
    fflush(fp);
   }
   fprintf(fp,"\n");
   fflush(fp);
  }
  fprintf(fp,"--------------------------\n");

  fflush(fp);
 }
 fclose(fp);
}
هل كانت مفيدة؟

المحلول

وهنا نسخة معدلة من قانون بلدي الأولي الذي يعمل مع مجموعة من المصفوفات:

typedef struct Matrix
{
    int rowsCount;
    int colsCount;
    int* data;
} TMatrix;

extern "C" __declspec(dllexport) void InitializeMatrix(TMatrix** matrices, int count) 
{
    srand(time(NULL));
    printf("<unmanaged>\n");
    for(int i = 0; i < count; i++)
    {
        TMatrix* m = matrices[i];
        printf("rows %d cols %d\n", m->rowsCount, m->colsCount);

        for(int j = 0; j < m->rowsCount; j++)
        {
            for(int k = 0; k < m->colsCount; k++)
            {
                printf("%d ", m->data[k * m->rowsCount + j]);
                // modify the data - it should be available back in C#
                m->data[k * m->rowsCount + j] = rand() % 10;
            }
            printf("\n");
        }
    }
    printf("</unmanaged>\n\n");
}

والجزء تمكن:

[StructLayout(LayoutKind.Sequential)]
struct Matrix
{
    public int RowsCount;
    public int ColsCount;
    public IntPtr Data;
}

class Program
{
    [DllImport("TestLib.dll")]
    private static extern void InitializeMatrix(IntPtr ptr, int count);

    static void Main(string[] args)
    {
        const int count = 3;

        // Allocate memory
        IntPtr ptr = Marshal.AllocHGlobal(count * Marshal.SizeOf(typeof(IntPtr)));
        IntPtr[] matrices = new IntPtr[count];
        for (int i = 0; i < count; i++)
        {
            Matrix matrix = new Matrix();
            // Give some size to the matrix
            matrix.RowsCount = 4;
            matrix.ColsCount = 3;
            int size = matrix.RowsCount * matrix.ColsCount;
            int[] data = new int[size];
            matrix.Data = Marshal.AllocHGlobal(size * Marshal.SizeOf(typeof(int)));
            Marshal.Copy(data, 0, matrix.Data, size);

            matrices[i] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Matrix)));
            Marshal.StructureToPtr(matrix, matrices[i], true);
        }
        Marshal.Copy(matrices, 0, ptr, count);


        // Call unmanaged routine
        InitializeMatrix(ptr, count);

        Console.WriteLine("<managed>");
        // Read data back
        Marshal.Copy(ptr, matrices, 0, count);
        for (int i = 0; i < count; i++)
        {
            Matrix m = (Matrix)Marshal.PtrToStructure(matrices[i], typeof(Matrix));
            int size = m.RowsCount * m.ColsCount;
            int[] data = new int[size];
            Marshal.Copy(m.Data, data, 0, size);

            // Pretty-print the matrix
            Console.WriteLine("rows: {0} cols: {1}", m.RowsCount, m.ColsCount);
            for (int j = 0; j < m.RowsCount; j++)
            {
                for (int k = 0; k < m.ColsCount; k++)
                {
                    Console.Write("{0} ", data[k * m.RowsCount + j]);
                }
                Console.WriteLine();
            }
        }
        Console.WriteLine("</managed>");


        // Clean the whole mess (try...finally block omitted for clarity)
        for (int i = 0; i < count; i++)
        {
            Matrix m = (Matrix)Marshal.PtrToStructure(matrices[i], typeof(Matrix));
            Marshal.FreeHGlobal(m.Data);
            Marshal.FreeHGlobal(matrices[i]);
        }
        Marshal.FreeHGlobal(ptr);
    }
}

وHTH

نصائح أخرى

وهنا بضعة طرق اعتدت على حشد C ++ البنيات الشبكة على تطبيق C # العميل:

    public static T Get<T>(byte[] msg, int offset)
    {

        T[] t = new T[] { default(T) };
        int len = Marshal.SizeOf(typeof(T));
        GCHandle th = GCHandle.Alloc(t, GCHandleType.Pinned);
        GCHandle mh = GCHandle.Alloc(msg, GCHandleType.Pinned);
        try
        {
            unsafe
            {
                byte* pb = (byte*)mh.AddrOfPinnedObject();
                byte* srcptr = pb + offset;
                byte* dest = ((byte*)th.AddrOfPinnedObject());
                for (int i = 0; i < len; i++)
                {
                    dest[i] = srcptr[i];
                }
            }
        }
        finally
        {
            mh.Free();
            th.Free();
        }


        return t[0];
    }


    public static string GetString(byte[] msg, int offset, int length)
    {
        StringBuilder retVal = new StringBuilder(length);
        unsafe
        {
            fixed (byte* pb = msg)
            {
                byte* pc = (byte*)(pb + offset);
                for (int x = 0; x < length; x++)
                {
                    if (pc[x] == 0) break;
                    retVal.Append((char)pc[x]);
                }
            }
        }
        return retVal.ToString(0, retVal.Length);
    }

وهنا هو كيف فعلت ذلك في مشروع القديم الذي كان لي لتمرير مصفوفة من الأعداد الصحيحة إلى روتين C التي من شأنها ملء مع القيم وثم اضطررت للحصول على دعم القيم في التعليمات البرمجية المدارة.

وكان لدي روتين في التعليمات البرمجية غير المدارة التي من شأنها أن تملأ مصفوفة من الأعداد الصحيحة مع بعض القيم:

#include "stdafx.h"
#include "TestLib.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

extern "C" __declspec(dllexport) void InitializeMatrix(int** matrix, int rows, int cols) 
{
    srand(time(NULL));
    printf("rows: %d\ncols: %d\n", rows, cols);
    for (int i = 0; i < rows; i++) 
    {
        for (int j = 0; j < cols; j++)
        {
            matrix[i][j] = rand() % 10;
        }
    }
}

وبعد ذلك في التعليمات البرمجية المدارة فعلت شيئا بين السطور:

class Program
{
    [DllImport(@"TestLib.dll")]
    private static extern void InitializeMatrix(IntPtr ptr, int rows, int cols);

    static void Main(string[] args)
    {
        const int rowsCount = 3;
        const int colsCount = 4;

        // Allocate memory for the matrix: (rowsCount * sizeof(IntPtr)) * (colsCount * sizeof(int))
        IntPtr ptr = AllocateMatrix(rowsCount, colsCount);
        try
        {
            // Call unmanaged routine to fill the allocated memory with data
            InitializeMatrix(ptr, rowsCount, colsCount);

            // Marshal back data
            int[][] matrix = GetMatrixFromPointer(ptr, rowsCount, colsCount);

            // Pretty-print the matrix
            for (int i = 0; i < rowsCount; i++)
            {
                for (int j = 0; j < colsCount; j++)
                {
                    Console.Write("{0} ", matrix[i][j]);
                }
                Console.WriteLine();
            }
        }
        finally
        {
            // Release allocated memory
            FreeMatrix(ptr, rowsCount, colsCount);
        }
    }

    private static IntPtr AllocateMatrix(int rowsCount, int colsCount)
    {
        IntPtr ptr = Marshal.AllocHGlobal(rowsCount * Marshal.SizeOf(typeof(IntPtr)));
        IntPtr[] rows = new IntPtr[rowsCount];
        for (int i = 0; i < rowsCount; i++)
        {
            int[] cols = new int[colsCount];
            rows[i] = Marshal.AllocHGlobal(colsCount * Marshal.SizeOf(typeof(int)));
            Marshal.Copy(cols, 0, rows[i], colsCount);
        }
        Marshal.Copy(rows, 0, ptr, rows.Length);
        return ptr;
    }

    private static int[][] GetMatrixFromPointer(IntPtr ptr, int rowsCount, int colsCount)
    {
        int[][] result = new int[rowsCount][];
        IntPtr[] rows = new IntPtr[rowsCount];
        Marshal.Copy(ptr, rows, 0, rowsCount);
        for (int i = 0; i < rowsCount; i++)
        {
            int[] cols = new int[colsCount];
            Marshal.Copy(rows[i], cols, 0, colsCount);
            result[i] = cols;
        }
        return result;
    }

    private static void FreeMatrix(IntPtr ptr, int rowsCount, int colsCount)
    {
        IntPtr[] rows = new IntPtr[rowsCount];
        Marshal.Copy(ptr, rows, 0, rowsCount);
        for (int i = 0; i < rowsCount; i++)
        {
            Marshal.FreeHGlobal(rows[i]);
        }
        Marshal.FreeHGlobal(ptr);
    }
}

وP / استدعاء هو PITA. وأود أن نوصي بشدة لك لتجنب ذلك قدر الإمكان وفي الحالات التي لا يكون ذلك ممكنا في محاولة لتنظيم المهام الخاصة بك في طريقة للحد من التعبئة البيانات.

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