Отладка DLLImport в C # - PullRequest
       17

Отладка DLLImport в C #

1 голос
/ 19 октября 2011

Я пытался заставить MySQL Embedded Library работать в моем приложении C # в течение последних 12 часов или около того, и застрял в течение довольно долгого времени.Я получаю следующую ошибку при вызове mysql_server_init() ...

Необработанное исключение: System.AcessViolationException: Попытка чтения или записи защищенной памяти.

C ++Метод принимает int и два char** в качестве параметров, но мне сказали, что в C # будет достаточно массива string[] с нулевым символом в конце.Поскольку это первый метод, который вы должны вызывать, я несколько растерялся из-за этой проблемы.

Вот мой код ...

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;
    }
}

Ответы [ 3 ]

2 голосов
/ 19 октября 2011

Если строки читаются из, вы должны быть в состоянии передать в виде массива строк.

Если они записываются, вам придется объявить параметры как IntPtrs, выделить для них память, а затем выполнить маршалинг данных самостоятельно (плюс вам также необходимо будет выделить память). *

что произойдет, если вы позвоните так (argc: = 2):

    if ((res = mysql_server_init(2, argv, groups)) == 1) 
    { 
        Console.WriteLine("MySQL Library Init Failed with error code: %d", res); 
        return false; 
    } 
1 голос
/ 19 октября 2011

Мне кажется, что у вас есть маленькая ошибка, заставляющая mysql_server_init читать за пределами массива.Замените 3 на 2 и удалите третью запись массива.Маршалер по умолчанию сделает все остальное.

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;
    }
}

Обновление

С этот поток , вы не должны использовать mysql_server_init вообще, но вместо этого mysql_library_init:

  1. И argv, и groups хранятся в библиотеке и используются позже.Это серьезная проблема, потому что если вы используете маршалинг P / Invoke, указатели, которые .NET передает функции, станут недействительными, как только функция вернется.Когда библиотека позже попытается обратиться к argv или группам, она не найдет ничего, кроме мусора, что приведет к непредвиденному поведению или аварийному завершению.вместо этого используется mysql_library_init - он создает внутреннюю копию argv и групп, поэтому вы можете без проблем использовать маршалинг P / Invoke (до тех пор, пока вы добавляете нулевую запись в конец групп).В противном случае вам придется самостоятельно выделить память для массивов и каждой строки, чтобы убедиться, что указатели остаются в силе до тех пор, пока ваша программа работает.

Итак, если вы можете перейти на использование mysql_library_init, я бы предложил сделать это.Маршалинг вручную не является тривиальным делом (но не слишком сложным).

0 голосов
/ 19 октября 2011

Метод C ++ принимает в качестве параметров int и два char **, но я был сказал, что в C # будет достаточно массива string []. Как это первый метод, который вы должны вызвать, я в некоторой степени потеря по вопросу.

Кто именно тебе это сказал?

Я верю, что вы могли бы просто использовать ссылку на char []

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

Убедитесь, что соглашение о вызовах совпадает, иначе вы столкнетесь с проблемами.

Ответ Митча Уита может быть улучшен этой веткой: Распределение символа ** в C #

Некоторая дополнительная информация: C # Marshalling char ** и unsigned char **

...