«Попытка чтения или записи защищенной памяти. Это часто указывает на повреждение другой памяти» DllImporting C # - PullRequest
2 голосов
/ 27 февраля 2010

Я получаю эту странную ошибку при попытке упорядочить данные в моей функции DLL и вернуться к коду C #. Я не вижу, где я передаю ноль или читаю недопустимую память, и эта ошибка настолько расплывчата. Какие-либо подсказки ??

Код ниже:

Функция FeeCalculation экспортируется в DLL следующим образом:

extern "C" __declspec(dllexport) void __stdcall FeeCalculation(char *cin, 
char *cout, char *flimit, char *frate,
char *fwindow, char *fincrement, char *fbird,
char *fparameter, char *fvalidation, char *fcoupon);

[StructLayout(LayoutKind.Sequential)]
        public struct feeAnswer
        {
            public uint fee;
            public uint tax1;
            public uint tax2;
            public uint tax3;
            public uint tax4;
            public uint surcharge1;
            public uint surcharge2;
            public uint validationFee;
            public uint couponFee1;
            public uint couponFee2;
            public uint couponFee3;
            public uint couponFee4;
            public ushort dstay;
            public ushort mstay;
        };

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct feeRequest
        {
            public byte day;
            public byte month;
            public uint year;
            public byte hour;
            public byte minute;
            public byte rate;
            public byte validation;
            public byte coupon1;
            public byte coupon2;
            public byte coupon3;
            public byte coupon4;
        };

        [DllImport("FeeCalculation.dll", CallingConvention = CallingConvention.StdCall,
           CharSet = CharSet.Ansi)]
        public static extern void FeeCalculation(feeRequest cin,
            out feeAnswer cout, string flimit,
            string frate, string fwindow, string fincrement, string fbird,
            string fparameter, 
            string fvalidation, string fcoupon);

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            feeRequest freq = new feeRequest();
            feeAnswer fans = new feeAnswer();

            string flim = "";
            string frat = "";
            string fwin = "";
            string finc = "";
            string fbir = "";
            string fpar = "";
            string fval = "";
            string fcoup = "";

            freq.day = 26;

            freq.month = 2;

            freq.year = 2010;   //2000 ~ 2099

            freq.hour = 20;

            freq.minute = 47;

            freq.rate = 15;

            freq.validation = 1;

            freq.coupon1 = 2;

            freq.coupon2 = 3;

            freq.coupon3 = 4;

            freq.coupon4 = 5;


            FeeCalculation(freq, out fans, flim, frat, fwin, finc, fbir, fpar, fval, fcoup);

С предложением Джона:

public static extern void FeeCalculation(feeRequest cin,
            out feeAnswer cout, 
            [MarshalAs(UnmanagedType.LPArray)]
            IntPtr flimit,
           [MarshalAs(UnmanagedType.LPArray)]
            IntPtr frate,
           [MarshalAs(UnmanagedType.LPArray)]
            IntPtr fwindow,
           [MarshalAs(UnmanagedType.LPArray)]
            IntPtr fincrement,
           [MarshalAs(UnmanagedType.LPArray)]
            IntPtr fbird,
           [MarshalAs(UnmanagedType.LPArray)]
            IntPtr fparameter,
           [MarshalAs(UnmanagedType.LPArray)]
            IntPtr fvalidation,
           [MarshalAs(UnmanagedType.LPArray)]
            IntPtr fcoupon);

...

FeeCalculation(freq, out fans, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);

Ответы [ 3 ]

2 голосов
/ 01 марта 2010

Чтобы исправить это, я добавил try / catch block вокруг кода memmove() в .DLL. Затем я должен был убедиться, что использовал ключевое слово ref для всех параметров, потому что в противном случае адреса памяти не были должным образом отнесены к DLL. Как только я это сделал, теперь он работает без нарушения прав доступа. Мне не нужны были заявления MarshalAs или какие-либо заявления на пачках. Я просто смог использовать LayoutKind.Sequential.

2 голосов
/ 27 февраля 2010

Скорее всего, ваша проблема в том, что вы не завершили объявление взаимодействия. Как я уже говорил, большинство ваших «строковых» параметров действительно являются параметрами out byte [], (или out struct)

Так что вам нужно сделать что-то похожее на это

    [DllImport("FeeCalculation.dll", CallingConvention = CallingConvention.StdCall,
       CharSet = CharSet.Ansi)]
    public static extern void FeeCalculation(feeRequest cin,
        out feeAnswer cout, 
        [MarshalAs(UnmanagedType.LPArray, SizeConst=100)]
        out byte[] flimit,
        [MarshalAs(UnmanagedType.LPArray, SizeConst=100)]
        out byte[] frate, 
        [MarshalAs(UnmanagedType.LPArray, SizeConst=100)]
        out byte[] fwindow, 
        [MarshalAs(UnmanagedType.LPArray, SizeConst=100)]
        out byte[] fincrement, 
        [MarshalAs(UnmanagedType.LPArray, SizeConst=100)]
        out byte[] fbird,
        [MarshalAs(UnmanagedType.LPArray, SizeConst=100)]
        out byte[] fparameter, 
        [MarshalAs(UnmanagedType.LPArray, SizeConst=100)]
        out byte[] fvalidation, 
        [MarshalAs(UnmanagedType.LPArray, SizeConst=100)]
        out byte[]fcoupon);

Вы можете не заботиться о других аргументах, но функция все еще будет пытаться записать их, поэтому вы должны предоставить фиктивные буферы, а буферы должны быть достаточно большими, чтобы содержать выходные данные. (поэтому вам может потребоваться изменить SizeConst).

Если ваша функция допускает указатели NULL на выходные данные, вы можете объявить значения, которые вам не нужны, как IntPtr и передать для них IntPtr.Zero.

В долгосрочной перспективе вам действительно нужно объявить все структур, которые эта функция хочет видеть, и передать их все должным образом.

Редактировать: хорошо, вы хотите использовать IntPtr или MarshalAs / byte [], но не оба одновременно.

public static extern void FeeCalculation(feeRequest cin,
        out feeAnswer cout, 
        IntPtr flimit,
        IntPtr frate,
        IntPtr fwindow,
        IntPtr fincrement,
        IntPtr fbird,
        IntPtr fparameter,
        IntPtr fvalidation,
        IntPtr fcoupon);

FeeCalculation(freq, out fans, IntPtr.Zero, ...
0 голосов
/ 26 августа 2018

Иногда это может помочь установить размер стека с помощью editbin !, когда вы имеете дело с неуправляемым кодом с маршаллингом. Попробуйте установить 16 МБ, например, запустите follwing
editbin.exe / stack: 16777216 binary_

...