Попытка чтения или записи защищенной памяти. Это часто указывает на то, что другая память повреждена DllImporting C#

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

Код ниже:

Функция 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);

person Community    schedule 27.02.2010    source источник


Ответы (3)


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

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

    [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, ...
person John Knoeller    schedule 27.02.2010
comment
Да, я знаю, что мне придется их объявить. Это всего лишь тест, чтобы увидеть, будет ли вызов моей dll из С# работать для проекта, над которым я работаю. Я попробую ваше предложение и посмотрю, работает ли оно! Сейчас функция игнорирует все остальное, кроме вентиляторов и частоты. - person ; 27.02.2010
comment
Другая возможная проблема заключается в том, что упаковка структур может не соответствовать тому, что ожидает C++. Вы можете попробовать pack=4 вместо pack=1 на cin. Вы знаете, что такое упаковка структуры C++? - person John Knoeller; 27.02.2010
comment
Структура не упакована с помощью прагмы пакета, если это то, о чем вы спрашиваете... Я сделал предложенный вами ответ, и он жаловался на наличие параметра SizeConst в ByRef, поэтому я вынул его и снова получил AccessViolation - person ; 27.02.2010
comment
Изменил нежелательные параметры на IntPtr, удалил модификатор out, кроме второго параметра, и передал IntPtr.Zero для отдыха, теперь я получаю следующую ошибку: - person ; 27.02.2010
comment
Невозможно маршалировать «параметр № 10»: недопустимая комбинация управляемого и неуправляемого типов (Int/UInt должен быть связан с SysInt или SysUInt). - person ; 27.02.2010
comment
@Changeling: пожалуйста, опубликуйте свой текущий код, вы можете опубликовать его как ответ, если не хотите менять свой вопрос. - person John Knoeller; 27.02.2010
comment
@John: Теперь я снова получаю AccessViolation с правкой... странно - person ; 27.02.2010
comment
@Changeling: ты используешь pack=4 ? - person John Knoeller; 27.02.2010
comment
пора установить точку останова в коде C++, чтобы увидеть, в каком параметре он ошибается - person John Knoeller; 27.02.2010

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

person Community    schedule 01.03.2010

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

person haltunbay    schedule 26.08.2018