从C#调用C DLL导致尝试读取或写入受保护的内存

时间:2016-04-21 19:44:02

标签: c# marshalling

我正在尝试在zabbix_sender程序中使用c#函数。这是我的c#代码:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct zabbix_sender_value_t
{
    [MarshalAs(UnmanagedType.LPStr)] public String host;
    [MarshalAs(UnmanagedType.LPStr)] public String key;
    [MarshalAs(UnmanagedType.LPStr)] public String value;
}

[DllImport("zabbix_sender.dll", CharSet = CharSet.Ansi)]
[return: MarshalAs(UnmanagedType.U4)]
public static extern int zabbix_sender_send_values(
    [param: MarshalAs(UnmanagedType.LPStr)] String address,
    [param: MarshalAs(UnmanagedType.U2)] ushort port, 
    [param: MarshalAs(UnmanagedType.LPStr)] String source, 
    [param: MarshalAs(UnmanagedType.Struct)] zabbix_sender_value_t values,
    [param: MarshalAs(UnmanagedType.U4)] int count,
    [param: MarshalAs(UnmanagedType.LPStr)] String result
);

static void Main()
{
    zabbix_sender_value_t values;
    values.host = "some_hostname";
    values.key = "agent.version";
    values.value = "2.0.0";
    string res = "";
    zabbix_sender_send_values("172.16.1.1", 10051, "127.0.0.1", values, 1, res);
}

这是C函数的定义,我试图从DLL调用:

int zabbix_sender_send_values(
    const char *address, 
    unsigned short port,
    const char *source, 
    const zabbix_sender_value_t *values, 
    int count,
    char **result);

typedef struct
{
    char    *host;
    char    *key;
    char    *value;
}
zabbix_sender_value_t;

执行我的C#代码以“尝试读取或写入受保护的内存”结束异常。这通常表明其他内存已损坏。

我使用编组参数玩了很多但没有运气。

这是我第一次使用DLL程序使用原生c#代码,我真的不知道我现在要做什么。

请任何帮助,意见,踢到哪里找出线索?

由于

4 个答案:

答案 0 :(得分:0)

Just an off-the-cuff guess but did you enable "allow unsafe code" in your project properties and trying wrapping the call in an unsafe { } clause?

答案 1 :(得分:0)

当您发送ByVal字符串作为此参数时,函数接受char**作为结果(最后一个)参数。字符串对象wwill marshal为char*所以你应该将它声明为ref IntPtrout string(在这种情况下推荐)将字符串指针发送到函数。
但主要问题是因为您发送ByVal zabbix_sender_value_t作为values参数,而函数接受此结构的数组。如果只想发送一个实例,可以将其声明为数组或ref参数。

答案 2 :(得分:0)

非常感谢你所有的消遣。

我试过这个

\tmp

并调用这样的函数:

[DllImport("zabbix_sender.dll", CharSet = CharSet.Ansi)]
[return: MarshalAs(UnmanagedType.U4)]
public static extern int zabbix_sender_send_values(
     [param: MarshalAs(UnmanagedType.LPStr)] String address,
     [param: MarshalAs(UnmanagedType.U2)] ushort port, 
     [param: MarshalAs(UnmanagedType.LPStr)] String source, 
     ref zabbix_sender_value_t values,
     [param: MarshalAs(UnmanagedType.U4)] int count,
     out IntPtr result
);

它可以工作,但如果我尝试在调试模式下运行,则抛出异常PInvokeStackImbalance。它不适合在生产中使用,不是吗?

谢谢

答案 3 :(得分:0)

Well, thank You again. I finish with this code without any exception even in Debug mode. The problem with exception appeared only when i try build program in x86 platform. When i use x64 or AnyCPU ( 64 bit DLL ), everything works well. Maybe misconfiguration?

Here is my final code:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct zabbix_sender_value_t
{
    [MarshalAs(UnmanagedType.LPStr)] public string host;
    [MarshalAs(UnmanagedType.LPStr)] public string key;
    [MarshalAs(UnmanagedType.LPStr)] public string value;
}

[DllImport("zabbix_sender.dll", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.U4)]
public static extern int zabbix_sender_send_values(
    [param: MarshalAs(UnmanagedType.LPStr)] string address,
    [param: MarshalAs(UnmanagedType.U4)] int port, 
    [param: MarshalAs(UnmanagedType.LPStr)] string source, 
    [param: MarshalAs(UnmanagedType.Struct)] ref zabbix_sender_value_t values,
    [param: MarshalAs(UnmanagedType.U4)] int count,
    out IntPtr result
);

static void Main()
{
    zabbix_sender_value_t values;
    values.host = "some_hostname";
    values.key = "zbx.trap";
    values.value = "99";
    IntPtr res ;
    unsafe {
        try
        {
            zabbix_sender_send_values("10.0.236.1", 10051, "10.0.236.12", ref values, 1, out res);
            string output = Marshal.PtrToStringAnsi(res);
            Console.WriteLine(output);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }
}