Гость
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / LPSTR from DLL into NET / 21 сообщений из 21, страница 1 из 1
29.07.2015, 17:20
    #39018924
vjut
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
Добрый день, Коллеги.

Много постов перичитано но проблема все равно не поддается.
Есть native dll (черный ящик). Функция со следующим объявлением в качестве параметра должна принимать строку и возвращать тоже строку.

Код: plaintext
1.
2.
3.
#define EXPORTAPI(TYPE) extern "C" TYPE _declspec(dllexport) 

EXPORTAPI (LPSTR) func(LPSTR IniPsw) 



Пытаемся подключить это к нашему проекту на C#

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
class Program
    {
        [DllImport("native.dll", EntryPoint = "func", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
        [return: MarshalAs(UnmanagedType.LPStr)]
        static extern unsafe IntPtr func([MarshalAs(UnmanagedType.LPStr)] string IniPsw);

        static void Main(string[] args)
        {              
            string strHashedPsw = Marshal.PtrToStringAnsi(func("aaa"));
            Console.WriteLine(strHashedPsw);
            Console.ReadKey();
        }
    }



Вот и на этом этапе и получаем:
Cannot marshal 'return value': Invalid managed/unmanaged type combination (Int/UInt must be paired with SysInt or SysUInt).

Вообщем не можем разобраться как же в итоге привести выходной параметр процедуры к строке.
...
Рейтинг: 0 / 0
29.07.2015, 18:00
    #39018971
vjut
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
Добавлю что если убрать
[return: MarshalAs(UnmanagedType.LPStr)]

то вылетает с ошибкой
Unable to load DLL 'c:\native.dll': Invalid access to memory location.
(Exception from HRESULT: 0x800703E6)
...
Рейтинг: 0 / 0
29.07.2015, 18:03
    #39018976
Сон Веры Павловны
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
vjut,

по аналогии с FormatMessage
которая определена как
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
DWORD WINAPI FormatMessage(
  _In_     DWORD   dwFlags,
  _In_opt_ LPCVOID lpSource,
  _In_     DWORD   dwMessageId,
  _In_     DWORD   dwLanguageId,
  _Out_    LPTSTR  lpBuffer,
  _In_     DWORD   nSize,
  _In_opt_ va_list *Arguments
);


и импортируется как
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
static extern int FormatMessage(
  int dwFlags,
  IntPtr lpSource,
  int dwMessageId,
  int dwLanguageId,
  StringBuilder lpBuffer,
  int nSize,
  IntPtr vaListArguments);


попробуйте маршалить строковый параметр через StringBuilder
(LPTSTR определяется как
Код: plaintext
1.
2.
3.
4.
5.
#ifdef UNICODE
 typedef LPWSTR LPTSTR;
#else
 typedef LPSTR LPTSTR;
#endif


если что, т.е. и LPSTR, и LPSTR - оба представляют из себя строковые указатели).
...
Рейтинг: 0 / 0
29.07.2015, 18:26
    #39018991
vjut
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
Сон Веры Павловныvjut,

по аналогии с FormatMessage
попробуйте маршалить строковый параметр через StringBuilder

Так проблемма не в параметре функции (тут C# не ругается), а в return параметре.

А как маршалить через StringBuilder и в чем же разница?
...
Рейтинг: 0 / 0
29.07.2015, 18:26
    #39018992
bazile
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
vjut, попробуй заменить IntPtr на string. И убери unsafe.
...
Рейтинг: 0 / 0
29.07.2015, 18:37
    #39019004
Алексей К
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
bazilevjut, попробуй заменить IntPtr на string. И убери unsafe.+ если заработает, то нужно будет ответить на вопрос, как освобождать память, выделенную под возвращаемую строку внутри метода

LPSTR func(LPSTR IniPsw) .
...
Рейтинг: 0 / 0
29.07.2015, 18:37
    #39019007
vjut
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
bazilevjut, попробуй заменить IntPtr на string. И убери unsafe.
пробовал, тогда падает на ошибке доступа к памяти.
unsafe же нужен когда библиотека на C++ или Delphi.
В лубом случае я пробовал убирать - не помогает.
...
Рейтинг: 0 / 0
29.07.2015, 18:39
    #39019009
vjut
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
Еще вариант попробовал оставить только чисто IntPtr:

Код: c#
1.
2.
3.
4.
static extern unsafe IntPtr func(IntPtr IniPsw);
IntPtr message = Marshal.AllocHGlobal(1000);
IntPtr out2 = Marshal.AllocHGlobal(1000);
out2 = HashPasswordAFW(message);



И сново валится на доступе к памяти.
...
Рейтинг: 0 / 0
29.07.2015, 18:41
    #39019011
vjut
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
vjut,

out2 = func(message);
...
Рейтинг: 0 / 0
29.07.2015, 18:42
    #39019013
Алексей К
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
vjutЕще вариант попробовал оставить только чисто IntPtr:

Код: c#
1.
2.
3.
4.
static extern unsafe IntPtr func(IntPtr IniPsw);
IntPtr message = Marshal.AllocHGlobal(1000);
IntPtr out2 = Marshal.AllocHGlobal(1000);
out2 = HashPasswordAFW(message);



И сново валится на доступе к памяти.Вероятно неправильное описание нативного метода. Ну не возвращают так строки в нативе. Только в рамках стандарта COM, но там BSTR.
...
Рейтинг: 0 / 0
29.07.2015, 18:46
    #39019016
Алексей К
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
+ ерунда написана
vjut
Код: c#
1.
2.
3.
...
IntPtr out2 = Marshal.AllocHGlobal(1000);
out2 = HashPasswordAFW(message);
...
Рейтинг: 0 / 0
29.07.2015, 18:50
    #39019021
Сон Веры Павловны
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
vjut,

есть несколько утилит, генерирующих код импорта нативных методов - см. например, обсуждение здесь - попробуйте воспользоваться ими. Я в свое время пользовался P/Invoke Interop Assistant'ом, он несколько раз вполне помог.
...
Рейтинг: 0 / 0
29.07.2015, 18:54
    #39019024
vjut
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
Вариант со StringBuilder
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
class Program
    {
        [DllImport("c:\\native.dll", EntryPoint = "func", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
       //[return: MarshalAs(UnmanagedType.LPStr)]
        static extern StringBuilder func(StringBuilder IniPsw);

        static void Main(string[] args)
        {

            try
            {
                StringBuilder message = new StringBuilder("aaa");
                StringBuilder out2 = new StringBuilder(1000);
                out2 = func(message);
                String strHashedPsw = out2.ToString();
                Console.WriteLine(strHashedPsw);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }                       
            Console.ReadKey();
        }
    }



выпадает с ошибкой:
System.DllNotFoundException: Unable to load DLL 'c:\native.dll': Invalid access to memory location. (Exception from HRESULT: 0x800703E6)

Поменяв StringBuilder на string - тот же результат.
...
Рейтинг: 0 / 0
29.07.2015, 19:05
    #39019031
Алексей К
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
vjutВариант со StringBuilder.Зачем задавать вопросы и не читать ответы?
...
Рейтинг: 0 / 0
29.07.2015, 19:13
    #39019039
vjut
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
Алексей КvjutВариант со StringBuilder.Зачем задавать вопросы и не читать ответы?
Не совсем понял. Какой вариант Вы предлагаете еще попробовать?

Вариант с Interop Assistant'ом пока тоже проверить не могу. Пытался качнуть утилиту, но в нашей сети заблокирован ресурс.
И к тому же непонятно, как ему заголовочный файл рисовать.
...
Рейтинг: 0 / 0
29.07.2015, 19:21
    #39019046
Алексей К
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
vjutАлексей Кпропущено...
Зачем задавать вопросы и не читать ответы?
Не совсем понял. Какой вариант Вы предлагаете еще попробовать?Я вообще не вижу ни одного разумного варианта с указанным прототипом метода. В лучшем случае будет работать с утечкой памяти, поскольку не описано, как освобождать память, выделенную под возвращаемую строку.

Я предлагаю сделать тестовый проект на C++, там попробовать вызвать указанный метод. Обратить внимание на возможную утечку памяти. Когда оно заработает, опубликовать C++ код вызова тут, тогда будет о чём говорить.

Перед всем этим лучше уточнить, правильно ли описан прототип метода: обычно в нативном C++ API память под возвращаемую строку выделяется в вызывающем методе, а не в вызываемом. Такой вызов в .Net PInvoke описывается с использованием StringBuilder, с указанием соответствующего размера буфера под строку.
...
Рейтинг: 0 / 0
29.07.2015, 19:31
    #39019049
vjut
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
Алексей Кvjutпропущено...

Не совсем понял. Какой вариант Вы предлагаете еще попробовать?Я вообще не вижу ни одного разумного варианта с указанным прототипом метода. В лучшем случае будет работать с утечкой памяти, поскольку не описано, как освобождать память, выделенную под возвращаемую строку.

Я предлагаю сделать тестовый проект на C++, там попробовать вызвать указанный метод. Обратить внимание на возможную утечку памяти. Когда оно заработает, опубликовать C++ код вызова тут, тогда будет о чём говорить.

Перед всем этим лучше уточнить, правильно ли описан прототип метода: обычно в нативном C++ API память под возвращаемую строку выделяется в вызывающем методе, а не в вызываемом. Такой вызов в .Net PInvoke описывается с использованием StringBuilder, с указанием соответствующего размера буфера под строку.

В варианте с IntPtr как раз память можно освободить через Marshal.FreeHGlobal.

Попробовать собрать свою библиотеку с теми же типами это конечно мысль, но я плюсы уже давно в руках не держал, даже не знаю есть ли где компилятор под рукой. И если вдруг с собственной библиотекой все заработает, то никак не поможет решить проблему с черным ящиком. Стороннюю библиотеку я никак переписать не смогу.
...
Рейтинг: 0 / 0
29.07.2015, 20:05
    #39019058
Алексей К
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
vjutАлексей Кпропущено...
Я вообще не вижу ни одного разумного варианта с указанным прототипом метода. В лучшем случае будет работать с утечкой памяти, поскольку не описано, как освобождать память, выделенную под возвращаемую строку.

Я предлагаю сделать тестовый проект на C++, там попробовать вызвать указанный метод. Обратить внимание на возможную утечку памяти. Когда оно заработает, опубликовать C++ код вызова тут, тогда будет о чём говорить.

Перед всем этим лучше уточнить, правильно ли описан прототип метода: обычно в нативном C++ API память под возвращаемую строку выделяется в вызывающем методе, а не в вызываемом. Такой вызов в .Net PInvoke описывается с использованием StringBuilder, с указанием соответствующего размера буфера под строку.

В варианте с IntPtr как раз память можно освободить через Marshal.FreeHGlobal.Откуда такая уверенность? Или есть информация об используемом менеджере памяти внутри нативной библиотеки?

Конечно можно попробовать так, но гарантий никаких:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
static extern IntPtr func([MarshalAs(UnmanagedType.LPStr)] string IniPsw);

....


IntPtr r = func("aaa");
Console.WriteLine(Marshal.PtrToStringAnsi(r));
Marshal.FreeHGlobal(r);
...
Рейтинг: 0 / 0
30.07.2015, 02:06
    #39019158
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
vjutВ варианте с IntPtr как раз память можно освободить через Marshal.FreeHGlobal.
а может быть ворона, а может быть лисица....

а может быть FreeCoTaskMem, а может FreeBSTR
как вариант - возвёрнутая память не должна освобождаться вызывающим
...
Рейтинг: 0 / 0
30.07.2015, 08:33
    #39019219
vjut
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
Изопропил,
Для начала хотелось бы разобраться с доступом к памяти, а потом уже подумаем об ее освобождении.
Сейчас же все что мы получаем - это ошибка доступа.
...
Рейтинг: 0 / 0
02.09.2015, 16:34
    #39041713
vjut
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
LPSTR from DLL into NET
В качестве закрытия топика...
Вендор пересобрал DLL, после чего все заработало (подробности переделок не раскрываются).
Все же с DLL в качестве черного ящика работать сущий ад. :(
...
Рейтинг: 0 / 0
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / LPSTR from DLL into NET / 21 сообщений из 21, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]