簡體   English   中英

“嘗試讀取或寫入受保護的內存。 這通常表明其他內存已損壞。” DllImporting C#

[英]“Attempted to read or write protected memory. This is often an indication that other memory is corrupt” DllImporting C#

嘗試將數據封送至我的DLL函數並返回C#代碼時,出現了這個奇怪的錯誤。 我看不到我在哪里傳遞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);

您的問題很可能是您尚未完成互操作聲明。 如前所述,您的大多數“字符串”參數實際上都是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, ...

為了解決這個問題,我在.DLL中的memmove()代碼周圍添加了一個try / catch block 然后,我必須確保在所有參數上都使用ref關鍵字,因為否則,內存地址將無法正確地引用到DLL。 一旦執行完此操作,它現在就可以正常工作了,而且沒有訪問沖突。 我不需要MarshalAs聲明或任何pack語句。 我只是能夠使用LayoutKind.Sequential

有時,在通過編組處理非托管代碼時,可以使用editbin !設置堆棧大小。 嘗試為實例運行設置16MB
editbin.exe / stack:16777216 binary_

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM