Unmanaged DLL from managed code => Error

shadow7256
Уже с Приветом
Posts: 9392
Joined: 18 Mar 2004 15:11
Location: New York -> FL

Unmanaged DLL from managed code => Error

Post by shadow7256 »

Уважаемые,

Подсунули мне 32битную С++ либу, в ней такая фукнция:

Code: Select all

int __declspec(dllexport) DeserializePersonJob( string strValidationFile, string strPersonBuffer, string strOutFile ) 
{
}
Я сделал тестовое 32битное консольное приложение и пытаюсь вызвать эту функцию (эта функция мне почему то видна как mangled поэтому пришлос явно указать EntryPoint):

Code: Select all

[DllImport("BioSubSNFD.dll", EntryPoint = "_Z20DeserializePersonJobSsSsSs")]
private static extern int DeserializePersonJob(string strValidationFile, string strPersonBuffer, string strOutFile);

static void Main(string[] args)
{
    var res = DeserializePersonJob("Sentry_RPIS", "RPIS_IR00_POS.xml", "C:\\Temp\\Test.ftt");
}
Все параметры валидны, создатель библиотеки сказал что все правильно вызывается, но почему падает он не знает.

И на вызове фукнции вылетает AccessViolationException и пишет что "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

Может кто сталкивался, ткните куда смотреть?:(
User avatar
Medium-rare
Уже с Приветом
Posts: 9195
Joined: 04 Mar 2011 03:04
Location: SFBA

Re: Unmanaged DLL from managed code => Error

Post by Medium-rare »

Отлаживать unmanaged DLL в контексте вашего managed EXE. Открываете проект DLL, объясняете отладчику, что запускает эту DLL (тот самый EXE), ставите breakpoint на интересующую функцию, и понеслась.
... and even then it's rare that you'll be going there...
User avatar
Boriskin
Уже с Приветом
Posts: 18906
Joined: 30 Aug 2001 09:01
Location: 3rd planet

Re: Unmanaged DLL from managed code => Error

Post by Boriskin »

А строки маршаллить в dll за вас Пушкин будет?
Тупизна как Энтропия. Неумолимо растет.
User avatar
Medium-rare
Уже с Приветом
Posts: 9195
Joined: 04 Mar 2011 03:04
Location: SFBA

Re: Unmanaged DLL from managed code => Error

Post by Medium-rare »

Да тут прямой вызов из дотнетовского стека. И компилятор ему это разрешил. Вы о чём, Борискин? Если что, сам давно не ковырял такое, но маршаллинг есть, но для COM, неявный.
... and even then it's rare that you'll be going there...
Sheriff
Уже с Приветом
Posts: 660
Joined: 21 Dec 1999 10:01

Re: Unmanaged DLL from managed code => Error

Post by Sheriff »

Medium-rare wrote:Да тут прямой вызов из дотнетовского стека. И компилятор ему это разрешил. Вы о чём, Борискин? Если что, сам давно не ковырял такое, но маршаллинг есть, но для COM, неявный.
Ну наверное вопрос в том что std::string != C#::string и параметры нужно маршалить явно.
Но проблема в том что у вас тип параметра std::string. Попробуйте использовать C++ function wrapper с типом параметра const char* и потом уже его использовать через P/Invoke из С#. Это самый простой путь:
http://stackoverflow.com/questions/1586 ... p-p-invoke

Более сложный - читайте:
http://www.xinterop.com/index.php/2013/ ... ng-in-c-1/
shadow7256
Уже с Приветом
Posts: 9392
Joined: 18 Mar 2004 15:11
Location: New York -> FL

Re: Unmanaged DLL from managed code => Error

Post by shadow7256 »

Medium-rare wrote:Открываете проект DLL, объясняете отладчику, что запускает эту DLL (тот самый EXE), ставите breakpoint на интересующую функцию, и понеслась.
у меня нету проекта DLL у меня просто уже скомпиленые либы С++ :(
shadow7256
Уже с Приветом
Posts: 9392
Joined: 18 Mar 2004 15:11
Location: New York -> FL

Re: Unmanaged DLL from managed code => Error

Post by shadow7256 »

Sheriff wrote:Ну наверное вопрос в том что std::string != C#::string и параметры нужно маршалить явно.
Но проблема в том что у вас тип параметра std::string. Попробуйте использовать C++ function wrapper с типом параметра const char* и потом уже его использовать через P/Invoke из С#. Это самый простой путь:
http://stackoverflow.com/questions/1586 ... p-p-invoke
ну вот навеврное как то так и придется, Спасибо всем. завтра расскажу что и как...
User avatar
Medium-rare
Уже с Приветом
Posts: 9195
Joined: 04 Mar 2011 03:04
Location: SFBA

Re: Unmanaged DLL from managed code => Error

Post by Medium-rare »

Sheriff wrote: Ну наверное вопрос в том что std::string != C#::string и параметры нужно маршалить явно.
Что там за C++ string не видно, в грамотных определениях было бы std::, значит using namespace std в хидер, что "ваще". Такой вульгарщины даже трудно ожидать вовсе. И выставлять std::string для экспортной функции? А какая именно у вызывающей стороны STL тогда? Точно совместимая? Это очень суровая DLL.
... and even then it's rare that you'll be going there...
shadow7256
Уже с Приветом
Posts: 9392
Joined: 18 Mar 2004 15:11
Location: New York -> FL

Re: Unmanaged DLL from managed code => Error

Post by shadow7256 »

то есть мой прототип должен выглядеть вот так?

Code: Select all

private static extern int DeserializePersonJob([MarshalAs(UnmanagedType.LPStr)] string strValidationFile,
                                                       [MarshalAs(UnmanagedType.LPStr)] string strPersonBuffer,
                                                       [MarshalAs(UnmanagedType.LPStr)]string strOutFile);
А тому человечку я так понял придется поменять параметры в его С++ функции на char* ?
User avatar
Medium-rare
Уже с Приветом
Posts: 9195
Joined: 04 Mar 2011 03:04
Location: SFBA

Re: Unmanaged DLL from managed code => Error

Post by Medium-rare »

Ну, там где вызов, std::string конструктор может быть неявно вызван, скушав char* как свой параметр, и создать объект. Если оно так сработает (?)
... and even then it's rare that you'll be going there...
User avatar
Boriskin
Уже с Приветом
Posts: 18906
Joined: 30 Aug 2001 09:01
Location: 3rd planet

Re: Unmanaged DLL from managed code => Error

Post by Boriskin »

Medium-rare wrote:Да тут прямой вызов из дотнетовского стека. И компилятор ему это разрешил. Вы о чём, Борискин?
Как сказали выше, я о том, что дотнетовские/си-диез string строки не имеют ничего общего с С++ std::string строками. И если написано "херня" в дотнете, она не является "херня" в С++. А что компилятор глотает - дык мало ли что ему в определении функции подсунули. А длл внутри на эти данные сблевывает (и правильно делает).

Я год назад на билде пытался докопаться до того, будет ли в будущем грамотный (читай - ленивый для девелопера) маршаллинг сложных типов типа структур, в ответ получил только что все надо маршалить по отдельности и ничего нового в этой сфере не предвидится.
Тупизна как Энтропия. Неумолимо растет.
User avatar
Medium-rare
Уже с Приветом
Posts: 9195
Joined: 04 Mar 2011 03:04
Location: SFBA

Re: Unmanaged DLL from managed code => Error

Post by Medium-rare »

Boriskin wrote: Как сказали выше, я о том, что дотнетовские/си-диез string строки не имеют ничего общего с С++ std::string строками.
В этом не было откровения какого-то. Это не ожидалось, поскольку std::string просто дичь какая-то для взаимодействия между внешней DLL и непонятно каким EXE. И объявлена без std:: что указывает на ещё большую дичь. Либо это... что-то ещё.
Я год назад на билде пытался докопаться до того, будет ли в будущем грамотный (читай - ленивый для девелопера) маршаллинг сложных типов типа структур, в ответ получил только что все надо маршалить по отдельности и ничего нового в этой сфере не предвидится.
Вот. Потому интересно, чем это закончится.
... and even then it's rare that you'll be going there...
Andriy777
Уже с Приветом
Posts: 1486
Joined: 28 Jan 2002 10:01

Re: Unmanaged DLL from managed code => Error

Post by Andriy777 »

Исходя из этого:

>
А тому человечку я так понял придется поменять параметры в его С++ функции на char* ?
>

мне кажется что эта DLL не "на продажу" а написана своими же парнями. Если так, то ничего ужасного обмениваться C++ std::string между различными dll и EXE модулями. Главное, чтобы была binary совместимость и без финтов с аллокаторами. Это достигается одними и теми же флажками переданными компиллятору и линкеру для всех модулей (задача построения правильного билда). Используется командами сплошь и рядом для "компонентизации".

Не совсем понятно, правда, где еще эта функция из dll вызывается. Если только Вами, то, действительно, "тому человеку" надо было бы договориться с Вами и сделать C# удобоваримый интероп-интерфейс.

Если же "тот человек" делал библиотеку для C++ пользователей, и они рады тому интерфейсу, а Вы - единственный вызывающий из C#, то это уже Ваша проблема. Можно написать переходничок на C++ или даже на Managed C++ (CLI). На managed C++ вы сделаете .NET assembly с функцией принимающей и возвращающей нормальные .NET string объекты. А в теле фунцкции позовете ту DLL передавая std::string. При этом за-пините .NET строки при создании std::string. Этот язык позволяет "все смешивать в кучу".

Ну, или PInvoke с переходничком на нормальном C++. Managed, вроде, должен быть быстрее. Все зависит как Вам удобнее и какие запросы по скорости.
shadow7256
Уже с Приветом
Posts: 9392
Joined: 18 Mar 2004 15:11
Location: New York -> FL

Re: Unmanaged DLL from managed code => Error

Post by shadow7256 »

Andriy777 wrote:Не совсем понятно, правда, где еще эта функция из dll вызывается. Если только Вами, то, действительно, "тому человеку" надо было бы договориться с Вами и сделать C# удобоваримый интероп-интерфейс.
Если же "тот человек" делал библиотеку для C++ пользователей, и они рады тому интерфейсу, а Вы - единственный вызывающий из C#, то это уже Ваша проблема.
Совершенно верно, та команда написала большой проект на С++ (ни один из них с .NET ни разу в глаза не видел вообще). А нам, те которые работают с .NET, понадобилась одна приблуда, которая у той команды уже есть, но только на С++. Писать ее на .NET это будет очень долго. Вот мы и попросили ту команду выделить приблуду в отдельную DLL.

Я сам с P/Invoke не работал, а та команда понятния не имеет про .NET как я уже сказал, вот и пытаемся решить вместе (с помощью привета тоже) что и как и куда :)
Sheriff
Уже с Приветом
Posts: 660
Joined: 21 Dec 1999 10:01

Re: Unmanaged DLL from managed code => Error

Post by Sheriff »

shadow7256 wrote:то есть мой прототип должен выглядеть вот так?

Code: Select all

private static extern int DeserializePersonJob([MarshalAs(UnmanagedType.LPStr)] string strValidationFile,
                                                       [MarshalAs(UnmanagedType.LPStr)] string strPersonBuffer,
                                                       [MarshalAs(UnmanagedType.LPStr)]string strOutFile);
А тому человечку я так понял придется поменять параметры в его С++ функции на char* ?
Примерно так. Также если он добавит extern "C", то в качестве EntryPoint в C# выступает обычное название функции (non mangled).

Code: Select all

extern "C" int __declspec(dllexport) DeserializePersonJob(
    const char* strValidationFile,
    const char* strPersonBuffer,
    const char* strOutFile )
{
}
Соответствующий C#:

Code: Select all

/// Return Type: int
///strValidationFile: char*
///strPersonBuffer: char*
///strOutFile: char*
[DllImportAttribute("BioSubSNFD.dll", EntryPoint="DeserializePersonJob")]
public static extern  int DeserializePersonJob(
    [In] [MarshalAs(UnmanagedType.LPStr)] string strValidationFile, 
    [In] [MarshalAs(UnmanagedType.LPStr)] string strPersonBuffer, 
    [In] [MarshalAs(UnmanagedType.LPStr)] string strOutFile
);
Одно замечание. Судя по именам параметров, они представляют собой имена файлов. По хорошему для этого нужно использовать Unicode.
Использовать Unicode для имен файлов или нет - это зависит от ваших требований.

Для использования Unicode в приведенном коде выше нужно заменить:

Code: Select all

const char* => const wchar_t* 
UnmanagedType.LPStr => UnmanagedType.LPWStr
А также использовать соответствующие Unicode функции для работы с файлами в C++ коде.
----------

Облегчить задачу генерации PInvoke сигнатуры может PInvoke Interop Assistant:
https://clrinterop.codeplex.com/releases/view/14120

Используйте "SigImp Translate Snippet" tab для перевода деклараций С++ в C#.
Используйте "SigImp Search" tab для генерации PInvoke для стандартных Windows функций, типов и констант.
shadow7256
Уже с Приветом
Posts: 9392
Joined: 18 Mar 2004 15:11
Location: New York -> FL

Re: Unmanaged DLL from managed code => Error

Post by shadow7256 »

Cпасибо. Новая C# сигнатура выглядит так:

Code: Select all

[DllImport("BioSubSNFD.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern int DeserializePersonJob([MarshalAs(UnmanagedType.LPStr)] string strValidationFile,
                                                                  [MarshalAs(UnmanagedType.LPStr)] string strPersonBuffer,
                                                                  [MarshalAs(UnmanagedType.LPStr)] string strOutFile);
Почему то пришлось добавить "CallingConvention = CallingConvention.Cdecl", без этого вылетала ошибка - PInvokeStackImbalance

Другой девелопер поменял параметры у себя на char*.

Теперь все работает.

Return to “Вопросы и новости IT”