从C#应用程序调用C ++函数。尝试读取或写入受保护的内存

时间:2010-03-05 10:43:12

标签: c# c++ dll

以下问题与我之前的问题相关

Converting static link library to dynamic dll

我的第一步是开发一个dll,这已经完成了。 (感谢John Knoeller prakash。您的意见很有帮助)

现在,当我从c#应用程序调用dll中的函数时,我收到错误

“尝试读取或写入受保护的内存。这通常表示其他内存已损坏。”

这是C ++定义

 extern "C" DEMO2_API void Decompress(char* inp_buff, unsigned short* 
 inp_len, char* buffer_decomp,unsigned *output_len,unsigned short* errorCode);

我的C#Converstion p / Involke

   private static extern void Decompress(
        byte[] inp_buff,
        ref ushort inp_len,
        byte[] buffer_decomp,
        ref int output_len,
        ref ushort errorCode
        );        

我称之为

    byte[] dst = new byte[2048];
    int outlen = 2048;
    ushort errorCode = 0;
    Decompress(src, (ushort )src.Length, dst, ref outlen,ref errorCode);
    return dst;

有什么问题?

7 个答案:

答案 0 :(得分:0)

我在inp_len参数上看到签名不匹配。在C ++定义中,您使用指向short unsigned int的指针,而在C#方法中,您使用ushort。

答案 1 :(得分:0)

指针必须使用IntPtr .net type

答案 2 :(得分:0)

@necrostaz

我们没有必要使用IntPtr作为指针。

看下面所有这四个声明都是有效的,目前我正在使用它。

[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, String lParam);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(IntPtr hWnd, Int32 Msg, IntPtr wParam, IntPtr lParam);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(IntPtr hWnd, Int32 Msg, IntPtr wParam, StringBuilder lParam);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(IntPtr hWnd, Int32 Msg, IntPtr wParam, String lParam);

问题仍然存在

答案 3 :(得分:0)

除了Maurits指出的inp_len声明中缺少“ref”之外,还需要确保指针大小匹配。

如果您在32位操作系统上运行,那么您应该没问题,但如果您的代码也运行在64位,那么您需要确保:

  • 您将.net条目程序集标记为x86(不是任何CPU)
  • 您提供了一个32位和64位的C ++ dll版本,并为要调用的互操作安装正确的版本。

答案 4 :(得分:0)

两年前我遇到过同样的问题。在我的情况下,访问冲突的原因是内存是在DLL外部分配的。作为解决方案,我添加了两个用于内存分配和释放到DLL的函数。

另一种解决方案可能是更改.net安全设置。一些关键字是“代码访问安全警察工具”(caspol.exe)和“.NET Framework配置工具”(mscorcfg.msc)。在VS中,项目属性对话框中还有一个安全选项卡。我不是.net安全方面的专家,所以其他人应该了解更多细节。

答案 5 :(得分:0)

以下代码运行没有任何问题。它与你的非常相似:

C ++:

extern "C" __declspec(dllexport) void TestFunction(char* inp_buff,
               unsigned short* inp_len,
               char* buffer_decomp,
               unsigned *output_len,
               unsigned short* errorCode)
{
    //copy input buffer to output buffer
    int size = min(*inp_len,*output_len);
    for(int i=0; i<size; i++)
        buffer_decomp[i] = inp_buff[i];

    errorCode = 0;
}

C#:

using System;
using System.Runtime.InteropServices;

class Program
{
    [DllImport("TEST.DLL")]
    public static extern void TestFunction(byte[] inp_buff,
                                           ref ushort inp_len,
                                           byte[] out_buff,
                                           ref int out_len,
                                           ref ushort errorCode);

    static void Main(string[] args)
    {
        //prepare input buffer
        byte[] inp_buff = new byte[20];
        inp_buff[0] = (byte)'T';
        inp_buff[1] = (byte)'E';
        inp_buff[2] = (byte)'S';
        inp_buff[3] = (byte)'T';
        ushort inp_len = (ushort)inp_buff.Length;

        //prepare output buffer
        byte[] out_buff = new byte[20];
        int out_len = out_buff.Length;

        ushort errorCode = 0;
        TestFunction(inp_buff, ref inp_len, out_buff, ref out_len, ref errorCode);

        //see if copying was successful
        for(int i=0; i<out_len; i++)
            Console.Out.Write(out_buff[i]);
    }
}

试一试。我看了一下你正在使用的库的开放部分。以下是函数lzo_decomp的直接摘录:

   in = lzo_malloc(IN_LEN);
      out = lzo_malloc(OUT_LEN);
   wrkmem = lzo_malloc(LZO1Z_999_MEM_COMPRESS);
   if (in == NULL || out == NULL || wrkmem == NULL)    
    {

     printf("out of memory\n");

    }


   in_len = IN_LEN;
   lzo_memset(in,0,in_len );
   lzo_memset ( out, 0, OUT_LEN );  


   memcpy ( out, &input_buffer, inp_buff_len);

lzo_free(wrkmem);
lzo_free(out);
lzo_free(in);  


r = lzo1z_decompress(out,*inp_len,in,&out_len,NULL );

对于宁静:“in”和“out”不是输入和输出缓冲区的函数参数,而是临时指针。你能看到什么(除了格式错误的代码)?调用lzo1z_decompress的唯一两个缓冲区是“in”和“out”。在调用之前释放这两个缓冲区。有一个访问冲突我并不感到惊讶。我只能强调nobugz的建议:联系作者。

答案 6 :(得分:0)

需要使用out模式而不是ref传递第4个参数。这解决了这个问题。