简体   繁体   English

在C#中调试DLLImport

[英]Debugging DLLImport in C#

I have been attempting to get the MySQL Embedded Library working in my C# application for the past 12 hours or so, and have been stuck for quite some time. 在过去的12个小时左右的时间里,我一直在尝试让MySQL嵌入式库在我的C#应用​​程序中运行,并且已经停滞了很长时间。 I am getting the following error when I call mysql_server_init() ... 调用mysql_server_init()时出现以下错误...

Unhandled Exception: System.AcessViolationException: Attempted to read or write protected memory. 未处理的异常:System.AcessViolationException:尝试读取或写入受保护的内存。

The C++ method takes an int and two char** as parameters, but I was told a null terminated string[] array would suffice in C#. C ++方法采用一个int和两个char**作为参数,但是有人告诉我,以空终止的string[]数组在C#中就足够了。 As this is the first method that you're supposed to call, I am somewhat at a loss as to this issue. 由于这是您应该调用的第一种方法,因此我对此问题有些茫然。

Here's my code... 这是我的代码......

public class MySQLServer
{
    [DllImport("libmysqld.dll")]
    static extern int mysql_server_init(int argc, string[] argv, string[] groups);

    [DllImport("libmysqld.dll")]
    static extern void mysql_server_end();

    public static bool Start()
    {
        string[] argv = new string[3];
        argv[0] = "mysql_test";
        argv[1] = "--datadir=C:/MYSQLTEST";
        argv[2] = null;

        string[] groups = new string[3];
        groups[0] = "libmysqd_server";
        groups[1] = "libmysqd_client";
        groups[2] = null;

        int res;

        if ((res = mysql_server_init(3, argv, groups)) == 1)
        {
            Console.WriteLine("MySQL Library Init Failed with error code: %d", res);
            return false;
        }

        Console.WriteLine("MySQL Library Started Successfully!");
        return true;
    }
}

If the strings are being read from, you should be able to pass as an array of strings. 如果正在读取字符串,您应该能够作为字符串数组传递。

If they are being written to, then you will have to declare the parameters as IntPtrs , allocate the memory for them, and then marshal the data yourself (plus you will need to unallocate the memory as well). 如果要编写它们,则必须将参数声明为IntPtrs ,为它们分配内存,然后自己编组数据(此外,您还需要IntPtrs分配内存)。

what happens if you call like so (argc := 2): 如果您这样调用会发生什么情况(argc:= 2):

    if ((res = mysql_server_init(2, argv, groups)) == 1) 
    { 
        Console.WriteLine("MySQL Library Init Failed with error code: %d", res); 
        return false; 
    } 

It seems to me that you have a tiny error, causing mysql_server_init to read beyond the array boundaries. 在我看来,你有一个小错误,导致mysql_server_init读取超出数组边界。 Replace 3 with 2 and remove the third array entry. 3替换为2并删除第三个数组条目。 The default marshaler will do the rest. 默认封送程序将完成剩下的工作。

public static bool Start()
{
    string[] argv = new string[3];
    argv[0] = "mysql_test";
    argv[1] = "--datadir=C:/MYSQLTEST";

    string[] groups = new string[3];
    groups[0] = "libmysqd_server";
    groups[1] = "libmysqd_client";

    int res;

    if ((res = mysql_server_init(2, argv, groups)) == 1)
    {
        Console.WriteLine("MySQL Library Init Failed with error code: %d", res);
        return false;
    }
}

Update 更新

From this thread , you should not use mysql_server_init at all, but mysql_library_init instead: 此线程中 ,您根本不应使用mysql_server_init ,而应使用mysql_library_init

  1. Both 'argv' and 'groups' are stored by the library and used later. “ argv”和“ groups”都由库存储并在以后使用。 This is a serious problem, because if you use P/Invoke marshaling, the pointers that .NET passes to the function will become invalid as soon as the function returns. 这是一个严重的问题,因为如果使用P / Invoke封送处理,则函数返回后,.NET传递给该函数的指针将变得无效。 When the library later tries to refer to argv or groups, it'll find nothing but garbage there, causing unexpected behavior or a crash. 当库稍后尝试引用argv或组时,除了在那里,它什么也找不到,这会导致意外行为或崩溃。

If you're using MySQL 5.0.3 or later, try using mysql_library_init instead - it makes an internal copy of argv and groups, so you can keep using P/Invoke marshaling with no trouble (as long as you add a null entry to the end of groups). 如果您使用的是MySQL 5.0.3或更高版本,请尝试使用mysql_library_init - 它会生成argv和groups的内部副本,因此您可以毫无困难地继续使用P / Invoke编组(只要您向其添加空条目)组末尾)。 Otherwise, you'll have to allocate the memory yourself for the arrays and each string, to make sure the pointers stay valid as long as your program is running. 否则,您必须为数组和每个字符串自己分配内存,以确保只要程序正在运行,指针就保持有效。

So, if you can switch to using mysql_library_init , I'd suggest doing so. 所以,如果你可以切换到使用mysql_library_init ,我建议这样做。 By-hand marshaling is not a trivial undertaking (but not too hard either). 副手编组不是一项微不足道的工作(但也不是太难)。

The C++ method takes an int and two char** as parameters, but I was told a null terminated string[] array would suffice in C#. C ++方法采用一个int和两个char **作为参数,但是有人告诉我,以空终止的string []数组在C#中就足够了。 As this is the first method that your supposed to call, I am at somewhat of a loss as to the issue. 由于这是您应该调用的第一种方法,因此我对该问题有些茫然。

Who exactly told you this? 到底是谁告诉你的?

I do believe you could just use a reference to a char[] 我确实相信您可以使用对char []的引用

[DllImport("libmysqld.dll")] static extern int mysql_server_init(int argc, ref char[] argv, ref char[] groups); [DllImport(“libmysqld.dll”)] static extern int mysql_server_init(int argc,ref char [] argv,ref char [] groups);

Be sure the calling convention matches otherwise you will run into issues. 确保调用约定匹配否则您将遇到问题。

Mitch Wheat's answer can be enchanced by this thread: Marshalling a char** in C# 米奇·惠特(Mitch Wheat)的答案可以通过以下线程来增强: 在C#中编组char **

Some Additional Information: C# Marshalling char** and unsigned char** 一些附加信息: C#编组char **和unsigned char **

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM