"Attempted to read or write protected memory. This is often an indication that other memory is corrupt" DllImporting C#
Asked Answered
L

3

2

I am getting this weird error while trying to marshal data to my DLL function and back to the C# code. I don't see where I am passing null or reading invalid memory and this error is so vague. Any clues??

Code below:

The FeeCalculation function is exported as follows in the 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);

With John's suggestion:

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);
Lanna answered 27/2, 2010 at 1:57 Comment(0)
L
2

To fix it, I added a try / catch block around the memmove() code in the .DLL. Then, I had to make sure I was using the ref keyword on all parameters because otherwise the memory addresses were not being referred properly to the DLL. Once I did that, it works now with no access violation. I did not need the MarshalAs declarations nor any pack statements. I simply was able to use LayoutKind.Sequential.

Lanna answered 1/3, 2010 at 16:54 Comment(0)
A
2

Your problem is most likely that you havent finished the interop declaration. As I said before, most of your 'string' parameters are really out byte[] parameters, (or out struct)

So you need to do something more like this

    [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);

You may not care about the other arguments, but the function is still going to try and write to them so you have to supply dummy buffers and the buffers have to be large enough to hold the output. (so you may need to change SizeConst).

If your function tolerates NULL pointers to outputs, then you could declare the values you don't want as IntPtr and pass IntPtr.Zero for those.

In the long run, you really need to declare all of the structs that this function wants to see and pass them all in properly.

Edit: ok you want to use IntPtr, or MarshalAs/byte[] but not both.

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, ...
Audieaudience answered 27/2, 2010 at 2:10 Comment(9)
Yes, I know I will have to declare them.. this is just a test to see if calling my dll from C# will work for a project I am working on.. I will try your suggestion and see if it works! Right now the function ignores the rest but fans and freqLanna
The other possible problem is that the packing on the structures may not match what the C++ expects. You might try pack=4 instead of pack=1 on cin. do you know what the C++ structure packing is?Audieaudience
The structure isn't packed via the pack pragma if that's what you are asking... I did your suggested answer and it complained about having the SizeConst parameter on ByRef so I took it out and get the AccessViolation againLanna
Changed the unwanted parameters to IntPtr, removed out modifier except for second parameter and passed IntPtr.Zero for rest now I get the following error:Lanna
Cannot marshal 'parameter #10': Invalid managed/unmanaged type combination (Int/UInt must be paired with SysInt or SysUInt).Lanna
@Changeling: please post your current code, you could post as an answer if you don't want to change your question.Audieaudience
@John: Now I am getting AccessViolation again with the edit.. strangeLanna
@Changeling: are you using pack=4 ?Audieaudience
time to set a breakpoint in the C++ code to see which param its faulting onAudieaudience
L
2

To fix it, I added a try / catch block around the memmove() code in the .DLL. Then, I had to make sure I was using the ref keyword on all parameters because otherwise the memory addresses were not being referred properly to the DLL. Once I did that, it works now with no access violation. I did not need the MarshalAs declarations nor any pack statements. I simply was able to use LayoutKind.Sequential.

Lanna answered 1/3, 2010 at 16:54 Comment(0)
S
0

Sometimes it may help to set stack size with editbin!, when you dealing with unmanaged code with marshalling. Try setting 16MB for instance run follwing
editbin.exe /stack:16777216 binary_

Sokul answered 26/8, 2018 at 11:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.