Форум программистов, компьютерный форум, киберфорум
Наши страницы

C# .NET

Войти
Регистрация
Восстановить пароль
 
EVG-1980
189 / 196 / 46
Регистрация: 11.04.2013
Сообщений: 1,078
#1

DllImport из с++ подскажите непонятные моменты - C#

25.12.2014, 14:39. Просмотров 649. Ответов 11
Метки нет (Все метки)

C#
1
2
3
4
5
6
7
8
[DllImport("myLib.dll", CharSet = CharSet.Ansi, EntryPoint = "Print", CallingConvention = CallingConvention.Cdecl)]
        
        private extern static IntPtr Print(string a, string b);
      
        public static string Print2(string a, string b) 
        {
            return Marshal.PtrToStringAnsi(Print(a, b));
        }
Вариант №1:

C++
1
2
3
4
5
6
7
8
9
extern "C" __declspec(dllexport) const char* Print(char* a, char* b) 
{
    int len =(int)malloc((strlen(a)+strlen(b)+1));
    char *tmp = new char[len] ;
    strcpy_s(tmp, len,a);
    strcat_s(tmp, len,b);
    cout <<len<<"\n";//что то дохрена как то памяти выделяется при Print2("123aв", "456апв") len = 68 000 000  где я ошибся?
    return tmp;        
}
1. Что то дохрена как то памяти выделяется при Print2("123aв", "456апв") len = 68 000 000 где я ошибся?
2. Что делать с памятью ведь ее очистить как то надо (delete []tmp)?

Вариант №2:

C++
1
2
3
4
5
6
7
8
9
extern "C" __declspec(dllexport) const char* Print(char* a, char* b) 
{
    //setlocale(LC_ALL, "rus");
    //SetConsoleCP(1251);
       //SetConsoleOutputCP(1251);
    std::string tmp1(a);
    std::string tmp2(b);
    return (tmp1 + tmp2).c_str();
}
В варианте №2 никак не могу добиться вывода текста нормально, одни кракозябры получаю как поправить?


Модераторы поправте BB коды пожалуйста с Code на С++ и C# а то у меня панель не пашет что то
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
25.12.2014, 14:39
Здравствуйте! Я подобрал для вас темы с ответами на вопрос DllImport из с++ подскажите непонятные моменты (C#):

DllImport - C#
Я создал проект и в нем использую библиотеку directX.AudioVideoPlayback. Как мне в коде это указать?

DllImport (Из С++ в С#) - C#
Добрый день, уважаемые господа! Есть такая проблема импорта dll написанной на С++ в C#. Перерыл кучу форумов, но так ничего и не понял... ...

DllImport из Delphi - C#
Доброго времени суток, уважаемые форумчане, имеется библиотека, написанная на Delphi, а в ней нужная функция. Сама бибилотека тут...

.NET 4.x Ahead-ды от DllImport и extern - C#
Ну на самом то деле заголовок говорящий ;) Меня интересует чем конкретном мы платим за использования плюсовых библиотек в дотНет...

Загрузка/выгрузка DllImport - C#
У меня вопрос когда происходит Загрузка/выгрузка dll при использовании DllImport. Допустим у меня есть класс: public class MyClass ...

Подключение библиотеки DLL на C++ через DllImport - C#
Здравствуйте! Подключаю библиотеку к проету, называю функцию const string _dllLocation = @&quot;library.dll&quot;; internal static...

11
NickoTin
Почетный модератор
Эксперт .NET
8244 / 3526 / 239
Регистрация: 14.06.2010
Сообщений: 4,510
Записей в блоге: 9
25.12.2014, 15:59 #2
Цитата Сообщение от EVG-1980 Посмотреть сообщение
где я ошибся?
Здесь
Цитата Сообщение от EVG-1980 Посмотреть сообщение
int len =(int)malloc((strlen(a)+strlen(b)+1));
Вы выделяете участок памяти длиной strlen(a)+strlen(b)+1, malloc вам возвращает адрес этого участка, вы его конвертируете в int и выдаете (!) за длину строки. Это адрес буфера, а не длина строки.
Должно быть приблизительно так:
C++
1
2
3
4
size_t len = strlen(a)+strlen(b)+1;
char* pBuff = (char*)malloc(len);
 
// и дальше работаете с буфером pBuff, а не tmp
Но, использовать malloc нежелательно, т.к. это не системный аллокатор, его деаллокатор это free. Используйте LocalAlloc(Free), CoTaskMemAlloc(Free), HeapAlloc(Free) функции. В случае же LocalAlloc можно использовать Marshal.FreeHGlobal, в случае использования CoTaskMemAlloc стандартный маршалер сможет самостоятельно управлять память и можно использовать string как возвращаемое значение в C#. В идеале же, имхо, следует самостоятельно выделять буфер и передавать его функции, а она уже пусть с ним работает.
1
EVG-1980
189 / 196 / 46
Регистрация: 11.04.2013
Сообщений: 1,078
25.12.2014, 19:15  [ТС] #3
NickoTin, мы выделили память в неуправляемом коде и передаем в управляемый
C++
1
2
char* pBuff = (char*)malloc(len);
return pBuff;
Следовательно в управляемом коде ее надо убить после того метод отработает
C#
1
Console.Write(Print2(a, b));
Как это сделать?

Добавлено через 36 минут
Все сообразил как это сделать заранее не выделяя память в С#

нужно еще 1 функциию на с++ дописать в dll
C++
1
2
3
void freString(char* IntPtr) {
   free(IntPtr);
}
C#
1
2
3
IntPtr temp= Print(a, b);
var srt=Marshal.PtrToStringAnsi(temp);
freString(temp);
Так корректно делать?
0
NickoTin
Почетный модератор
Эксперт .NET
8244 / 3526 / 239
Регистрация: 14.06.2010
Сообщений: 4,510
Записей в блоге: 9
25.12.2014, 23:44 #4
Цитата Сообщение от EVG-1980 Посмотреть сообщение
Так корректно делать?
Да.
В общем главное чтобы использовались аллокатор и соответствующий ему деаллокатор.
0
EVG-1980
189 / 196 / 46
Регистрация: 11.04.2013
Сообщений: 1,078
26.12.2014, 08:46  [ТС] #5
NickoTin , решил попробывать остальные способы

C++
1
2
3
4
5
6
7
8
9
10
extern "C" __declspec(dllexport)  wchar_t* PrintUni(wchar_t* a, wchar_t* b) 
{
    ULONG  size = (wcslen(a)+wcslen(b)+1)  * sizeof(wchar_t);
    wchar_t* pszReturn = NULL;
    pszReturn = (wchar_t*)::CoTaskMemAlloc(size);
    wcscpy_s(pszReturn, size, a);
    wcscat_s(pszReturn, size, b);   
    //wprintf(L"%s",pszReturn);
    return pszReturn;
}
C#
1
2
3
4
5
[DllImport("myLib.dll", CharSet = CharSet.Unicode, EntryPoint = "PrintUni", CallingConvention = CallingConvention.Cdecl)]
        [return: MarshalAs(UnmanagedType.LPWStr)]
        private extern static String PrintUni(string a, string b); 
        string src = "123aвв™Ђв•џ";
        Console.WriteLine(PrintUni(src, src));

Че за глюк в режиме отладки нормально работает

C#
1
2
3
4
5
6
string src = "123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ";
            for (int i = 0; i < 9999999; i++)
            {
                string temp = PrintUni(src + i.ToString(), i.ToString());
                Console.WriteLine(temp);
            }
При запуске без отладки падает через секунду : Process is terminated due StackOverFlowException
0
maxillion
273 / 183 / 38
Регистрация: 25.12.2012
Сообщений: 616
26.12.2014, 09:55 #6
1. Использовать strlen для определения длины с# строк не правильно.
C#
1
2
string s = new string(new char[] { '5', '\x0', 'g' });
Console.WriteLine(s.Length);
2. Если указан CallingConvention.Cdecl то EntryPoint можно не писать.

Добавлено через 4 минуты
3. В с# тип string это не просто указатель на char.
0
EVG-1980
189 / 196 / 46
Регистрация: 11.04.2013
Сообщений: 1,078
26.12.2014, 10:12  [ТС] #7
maxillion, напиши как правильно?

Тест №2 с использованием malloc

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
extern "C" __declspec(dllexport) const char* Print(char* a, char* b) 
{
    size_t len = strlen(a)+strlen(b)+1;
    char* pBuff = (char*)malloc(len);
    strcpy_s(pBuff, len,a);
    strcat_s(pBuff, len,b);
    //cout <<len<<"\n";
    return pBuff;
}
 
extern "C" __declspec(dllexport) void freString(char* IntPtr) 
{
   free(IntPtr);
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[DllImport("myLib.dll", CharSet = CharSet.Ansi, EntryPoint = "Print", CallingConvention = CallingConvention.Cdecl)]
        private extern static IntPtr Print(string a, string b);
 
        [DllImport("myLib.dll", CharSet = CharSet.Ansi, EntryPoint = "freString", CallingConvention = CallingConvention.Cdecl)]
        private extern static void freString(IntPtr mem);
 
        public static string Print2(string a, string b) 
        {
            IntPtr freemem= Print(a, b);
            string str = Marshal.PtrToStringAnsi(Print(a, b));
            freString(freemem);
            return str;
        }
       string src = "123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ123aвв™Ђв•џ";
 
                for (int i = 0; i < 199999; i++)
                {
                    string temp = Print2(src + i.ToString(), i.ToString());
                    Console.WriteLine(temp);
                }
               // GC.Collect();
freString(freemem) - работает не коректно память растет не переставая (смотрю в диспетчере задач уже 600 метров) хотя походу это из за Console.WriteLine(temp);
0
MrCold
855 / 753 / 71
Регистрация: 11.01.2012
Сообщений: 1,942
26.12.2014, 11:14 #8
EVG-1980, хотел спросить еще вчера, а зачем память в .dll выделять?
Неверный какой-то подход.Легче отправить пустую строку третьим параметром (StringBuilder ).
Не проверял, но типа того
C#
1
2
3
4
5
6
[DllImport("myLib.dll")]
  private extern static void NativeFunc(string a, string b,  StringBuilder result);
 
StringBuilder sb = new StringBuilder(256);
NativeFunc(str1, str2, sb);
Console.WriteLine(sb.ToString());
0
maxillion
273 / 183 / 38
Регистрация: 25.12.2012
Сообщений: 616
26.12.2014, 11:29 #9
CoTaskMemAlloc и malloc возвращают мусор, и для использования strcat_s (strcpy) наверно стоит сначала очистить эту память.
Если передать строку такого рода
C#
1
new string(new char[] { '5', '\x0', 'g' })
то код обработает её не корректно.
Какова цель данной задачи ? Может её можно решить более рационально, не используя с++.
0
EVG-1980
189 / 196 / 46
Регистрация: 11.04.2013
Сообщений: 1,078
26.12.2014, 11:41  [ТС] #10
MrCold, да уже прочитал об этом способе пока не трогал, хотелось бы сначала разобраться с первыми двумя

maxillion, целей у задачи нету просто изучаю С++ ну и заодно маршалинг , буду благодарен любой помощи
0
Konctantin
926 / 730 / 64
Регистрация: 12.04.2009
Сообщений: 1,700
26.12.2014, 12:24 #11
Если изучаете, то не придумывайте задачу для кода.
А лучше примените на практике, так будет намного полезней.
0
EVG-1980
189 / 196 / 46
Регистрация: 11.04.2013
Сообщений: 1,078
26.12.2014, 12:29  [ТС] #12
Konctantin, я не ищу легких путей на данный момент меня интересует передача данных из неуправляемого кода в управляемый и наоборот рассматриваю все способы , а не какой то конкретный "лишь бы работало"
0
26.12.2014, 12:29
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
26.12.2014, 12:29
Привет! Вот еще темы с ответами:

Объявление DllImport функций с указателями и ссылками - C#
Есть статическая библиотека С++. Нужно импортировать в С# ее метод если функция с простой сигнатурой - примерно так получается ...

помогите плз с DLLImport все мозги сломал( - C#
упорно не работает элементарная программа. using System; using System.Collections.Generic; using System.ComponentModel; using...

Компиляция и атрибуты: как создать атрибут наподобие DllImport - C#
Атрибуты Net Framework известным образом влияют на компиляцию. Например: DllImport,Extension ... и т.д. Влияние на компиляцию с помощью...

Непонятные моменты языка - Fortran
Тут нужно переписать программу с Фортрана-77 на Си, котелок уже не варит. Вот несколько вопросов (не думаю, что они могут вызвать проблемы...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru