c# - "Attempted to read or write protected memory. This is often an indication that other memory is corrupt"Dll导入C#

标签 c# dll dllimport access-violation

我在尝试将数据编码(marshal)到 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);

最佳答案

您的问题很可能是您尚未完成互操作声明。正如我之前所说,大多数“字符串”参数实际上都是 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, ...

关于c# - "Attempted to read or write protected memory. This is often an indication that other memory is corrupt"Dll导入C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2345945/

相关文章:

C#:将字符串数组传递给 C++ DLL

c++ - 将 DLL 中的 C++ 函数导出为 C 时 Debug 和 Release 之间的区别

.net - 如何使用.Net MSI在GAC中注册dll

c# - 无法将字符串从托管 c# 传递到非托管 c

c# - 如何从 C# 中的子文件夹导入 .dll 库

c# - 在映射中使用 Linq 查询

c# - 如何提交sql server中的所有事务?

c# - 在 C# 中创建具有边容量的有向图的库

c# - 从 C# 调用 C DLL 函数 - 参数结构太大或太复杂而无法编码(marshal)

c# - 机器人程序/蜘蛛程序可以使用 Cookies 吗?