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

4
以下问题与我之前的问题相关: 将静态链接库转换为动态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# 转换 p/调用

   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

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

问题仍然未解决


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的建议:联系作者。

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

0

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


0

对于指针,您必须使用IntPtr .net类型


0
除了 Maurits 指出的 inp_len 声明缺少 "ref" 之外,您还需要确保指针大小匹配。
如果您在 32 位操作系统上运行,那么应该没问题,但是如果您的代码也在 64 位上运行,则需要确保以下两种情况之一:
  • 将 .net 入口程序集标记为 x86(而不是 Any CPU)
  • 或者
  • 提供 C++ dll 的 32 位和 64 位版本,并安装正确的版本供互操作调用。

我明白。但是我正在运行Win XP Professional 32位,并且我已经尝试使用IntPtr。仍然出现相同的错误。 - Manjoor
你确定已经将签名更改为“ref ushort inp_len”了吗? - marklam

0

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

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


有趣..我不想处理 .Net 安全问题。 你能提供你的解决方案吗? - Manjoor
以下是两个可能会对你有帮助的链接:http://ask.metafilter.com/79680/Calling-unmanaged-DLL-functions-from-C 和 http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/6e843243-baf4-4eb1-8a20-c691ad47762c - user287715
@alexj,这似乎是原因。但不幸的是,我无法理解他们在做什么以及如何在我的函数中实现它。如果您能稍微描述一下,我将不胜感激。谢谢。 - Manjoor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接