在C#中调试的DllImportDllImport

2023-09-06 19:00:55 作者:尸体会不会疼!

我一直在试图获取的MySQL嵌入式图书馆工作在我的C#应用​​程序在过去的12个小时左右,并一直坚持了一段时间。我收到以下错误,当我打电话 mysql_server_init() ...

  

未处理的异常:System.AcessViolationException:尝试读取   或写入受保护的内存。

C ++的方法采用 INT 和两个字符** 作为参数,但是我被告知终止空的String [] 阵列就足够用C#。由于这是你应该调用的第一个方法,我有些茫然,这个问题的。

下面是我的code ...

 公共类MySQLServer
{
    [的DllImport(libmysqld.dll)]
    静态外部INT mysql_server_init(INT ARGC,串[] argv的,字符串[]组);

    [的DllImport(libmysqld.dll)]
    静态外部无效mysql_server_end();

    公共静态布尔开始()
    {
        字符串[]的argv =新的字符串[3];
        的argv [0] =mysql_test;
        的argv [1] =--datadir = C:/ MYSQLTEST;
        的argv [2] =无效;

        字符串[] =组新的字符串[3];
        基[0] =libmysqd_server;
        基[1] =libmysqd_client;
        基[2] =无效;

        INT资源;

        如果((RES = mysql_server_init(3,argv的,团体))== 1)
        {
            Console.WriteLine(MySQL库初始化失败,出现错误code:%D,RES);
            返回false;
        }

        Console.WriteLine(MySQL的图书馆已成功启动!);
        返回true;
    }
}
 

解决方案

在我看来,你有一个小小的错误,导致 mysql_server_init 读取数组边界之外。替换 3 2 并删除第三个数组项。默认封送将做休息。

 公共静态布尔开始()
{
    字符串[]的argv =新的字符串[3];
    的argv [0] =mysql_test;
    的argv [1] =--datadir = C:/ MYSQLTEST;

    字符串[] =组新的字符串[3];
    基[0] =libmysqd_server;
    基[1] =libmysqd_client;

    INT资源;

    如果((RES = mysql_server_init(2,argv的,团体))== 1)
    {
        Console.WriteLine(MySQL库初始化失败,出现错误code:%D,RES);
        返回false;
    }
}
 
VS 调试技巧

更新

从这个线程< /一>,你不应该使用 mysql_server_init 所有,但 mysql_library_init 来代替:

     两者'的argv'和'基团'是由库存储和使用后。这是一个严重的问题,因为如果你使用的P / Invoke封送处理时,   .NET的指针传递给函数,将变得无效,尽快   作为函数返回。当库稍后尝试参阅ARGV   或团体,它会发现什么,但垃圾在那里,从而导致意外   行为或崩溃。         

如果你使用MySQL 5.0.3或更高版本,请尝试使用mysql_library_init   而是 - 它使argv的和群体的内部副本,这样你就可以   继续使用P / Invoke,没有麻烦编组(只要你添加   空条目到组的端部)。否则,你将不得不分配   自己的存储器阵列,每个串,以确保   指针仍然有效,只要你的程序正在运行。

所以,如果你的可以的开关,使用 mysql_library_init ,我建议这样做。通过手封送处理不是一个简单的任务(但不要太用力要么)。

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. I am getting the following error when I call mysql_server_init()...

Unhandled Exception: System.AcessViolationException: Attempted to read or write protected memory.

The C++ method takes an int and two char** as parameters, but I was told a null terminated string[] array would suffice in 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;
    }
}

解决方案

It seems to me that you have a tiny error, causing mysql_server_init to read beyond the array boundaries. Replace 3 with 2 and remove the third array entry. 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:

Both 'argv' and 'groups' are stored by the library and used later. 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. When the library later tries to refer to argv or groups, it'll find nothing but garbage there, causing unexpected behavior or a crash.

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). 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. By-hand marshaling is not a trivial undertaking (but not too hard either).